aboutsummaryrefslogtreecommitdiff
path: root/engines/saga
diff options
context:
space:
mode:
Diffstat (limited to 'engines/saga')
-rw-r--r--engines/saga/actor.cpp1966
-rw-r--r--engines/saga/actor.h33
-rw-r--r--engines/saga/actor_walk.cpp1942
-rw-r--r--engines/saga/animation.cpp332
-rw-r--r--engines/saga/animation.h25
-rw-r--r--engines/saga/console.cpp96
-rw-r--r--engines/saga/console.h6
-rw-r--r--engines/saga/detection.cpp18
-rw-r--r--engines/saga/detection_tables.h364
-rw-r--r--engines/saga/displayinfo.h31
-rw-r--r--engines/saga/events.cpp38
-rw-r--r--engines/saga/events.h27
-rw-r--r--engines/saga/font.cpp26
-rw-r--r--engines/saga/font.h7
-rw-r--r--engines/saga/gfx.cpp80
-rw-r--r--engines/saga/gfx.h1
-rw-r--r--engines/saga/ihnm_introproc.cpp530
-rw-r--r--engines/saga/input.cpp4
-rw-r--r--engines/saga/interface.cpp286
-rw-r--r--engines/saga/interface.h9
-rw-r--r--engines/saga/ite_introproc.cpp41
-rw-r--r--engines/saga/itedata.h3
-rw-r--r--engines/saga/module.mk1
-rw-r--r--engines/saga/music.cpp17
-rw-r--r--engines/saga/music.h3
-rw-r--r--engines/saga/palanim.cpp2
-rw-r--r--engines/saga/render.cpp9
-rw-r--r--engines/saga/render.h9
-rw-r--r--engines/saga/rscfile.cpp19
-rw-r--r--engines/saga/saga.cpp11
-rw-r--r--engines/saga/saga.h10
-rw-r--r--engines/saga/sagaresnames.h4
-rw-r--r--engines/saga/saveload.cpp27
-rw-r--r--engines/saga/scene.cpp132
-rw-r--r--engines/saga/scene.h14
-rw-r--r--engines/saga/script.cpp14
-rw-r--r--engines/saga/script.h3
-rw-r--r--engines/saga/sfuncs.cpp703
-rw-r--r--engines/saga/sndres.cpp9
39 files changed, 3369 insertions, 3483 deletions
diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp
index c2ecff4a1a..6d996d2d40 100644
--- a/engines/saga/actor.cpp
+++ b/engines/saga/actor.cpp
@@ -29,18 +29,12 @@
#include "saga/animation.h"
#include "saga/console.h"
#include "saga/events.h"
-#include "saga/gfx.h"
-#include "saga/interface.h"
#include "saga/isomap.h"
-#include "saga/itedata.h"
#include "saga/objectmap.h"
#include "saga/sagaresnames.h"
#include "saga/rscfile.h"
#include "saga/script.h"
#include "saga/sndres.h"
-#include "saga/sprite.h"
-#include "saga/stream.h"
-#include "saga/font.h"
#include "saga/sound.h"
#include "saga/scene.h"
@@ -48,24 +42,6 @@
namespace Saga {
-enum ActorFrameIds {
-//ITE
- kFrameITEStand = 0,
- kFrameITEWalk = 1,
- kFrameITESpeak = 2,
- kFrameITEGive = 3,
- kFrameITEGesture = 4,
- kFrameITEWait = 5,
- kFrameITEPickUp = 6,
- kFrameITELook = 7,
-//IHNM
- kFrameIHNMStand = 0,
- kFrameIHNMSpeak = 1,
- kFrameIHNMWait = 2,
- kFrameIHNMGesture = 3,
- kFrameIHNMWalk = 4
-};
-
static int commonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
int p1 = obj1->_location.y - obj1->_location.z;
int p2 = obj2->_location.y - obj2->_location.z;
@@ -76,6 +52,16 @@ static int commonObjectCompare(const CommonObjectDataPointer& obj1, const Common
return 1;
}
+static int commonObjectCompareIHNM(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
+ int p1 = obj1->_location.y;
+ int p2 = obj2->_location.y;
+ if (p1 == p2)
+ return 0;
+ if (p1 < p2)
+ return -1;
+ return 1;
+}
+
static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
int p1 = -obj1->_location.u() - obj1->_location.v() - obj1->_location.z;
int p2 = -obj2->_location.u() - obj2->_location.v() - obj2->_location.z;
@@ -89,140 +75,6 @@ static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const Co
return 1;
}
-inline int16 int16Compare(int16 i1, int16 i2) {
- return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0));
-}
-
-inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) {
- Point delta;
- delta.x = ABS(point1.x - point2.x) / compressX;
- delta.y = ABS(point1.y - point2.y);
- return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2));
-}
-
-inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) {
-
- delta.x = point2.x - point1.x;
- if (delta.x == 0) {
- s.x = 0;
- } else {
- if (delta.x > 0) {
- s.x = 1;
- } else {
- s.x = -1;
- delta.x = -delta.x;
- }
- }
-
-
- delta.y = point2.y - point1.y;
- if (delta.y == 0) {
- s.y = 0;
- } else {
- if (delta.y > 0) {
- s.y = 1;
- } else {
- s.y = -1;
- delta.y = -delta.y;
- }
- }
-}
-
-// Lookup table to convert 8 cardinal directions to 4
-static const int actorDirectectionsLUT[8] = {
- ACTOR_DIRECTION_BACK, // kDirUp
- ACTOR_DIRECTION_RIGHT, // kDirUpRight
- ACTOR_DIRECTION_RIGHT, // kDirRight
- ACTOR_DIRECTION_RIGHT, // kDirDownRight
- ACTOR_DIRECTION_FORWARD,// kDirDown
- ACTOR_DIRECTION_LEFT, // kDirDownLeft
- ACTOR_DIRECTION_LEFT, // kDirLeft
- ACTOR_DIRECTION_LEFT, // kDirUpLeft
-};
-
-static const PathDirectionData pathDirectionLUT[8][3] = {
- { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } },
- { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } },
- { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } },
- { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } },
- { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } },
- { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } },
- { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } },
- { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } }
-};
-
-static const int pathDirectionLUT2[8][2] = {
- { 0, -1 },
- { 1, 0 },
- { 0, 1 },
- { -1, 0 },
- { 1, -1 },
- { 1, 1 },
- { -1, 1 },
- { -1, -1 }
-};
-
-static const int angleLUT[16][2] = {
- { 0, -256 },
- { 98, -237 },
- { 181, -181 },
- { 237, -98 },
- { 256, 0 },
- { 237, 98 },
- { 181, 181 },
- { 98, 237 },
- { 0, 256 },
- { -98, 237 },
- { -181, 181 },
- { -237, 98 },
- { -256, 0 },
- { -237, -98 },
- { -181, -181 },
- { -98, -237 }
-};
-
-static const int directionLUT[8][2] = {
- { 0 * 2, -2 * 2 },
- { 2 * 2, -1 * 2 },
- { 3 * 2, 0 * 2 },
- { 2 * 2, 1 * 2 },
- { 0 * 2, 2 * 2 },
- { -2 * 2, 1 * 2 },
- { -4 * 2, 0 * 2 },
- { -2 * 2, -1 * 2 }
-};
-
-static const int tileDirectionLUT[8][2] = {
- { 1, 1 },
- { 2, 0 },
- { 1, -1 },
- { 0, -2 },
- { -1, -1 },
- { -2, 0 },
- { -1, 1 },
- { 0, 2 }
-};
-
-struct DragonMove {
- uint16 baseFrame;
- int16 offset[4][2];
-};
-
-static const DragonMove dragonMoveTable[12] = {
- { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
- { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
- { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
- { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
- { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } },
- { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } },
- { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } },
- { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } },
- { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } },
- { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } },
- { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } },
- { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } }
-};
-
Actor::Actor(SagaEngine *vm) : _vm(vm) {
int i;
byte *stringsPointer;
@@ -268,8 +120,6 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
_pathRect.top = _vm->getDisplayInfo().pathStartY;
_pathRect.bottom = _vm->_scene->getHeight();
- _showActors = true;
-
// Get actor resource file context
_actorContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
if (_actorContext == NULL) {
@@ -723,76 +573,6 @@ void Actor::stepZoneAction(ActorData *actor, const HitZone *hitZone, bool exit,
}
}
-void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) {
- int angle;
- int distance;
- ActorData *actor;
- ObjectData *obj;
- debug (8, "Actor::realLocation objectId=%i", objectId);
- if (walkFlags & kWalkUseAngle) {
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- angle = (location.x + 2) & 15;
- distance = location.y;
-
- location.u() = (angleLUT[angle][0] * distance) >> 8;
- location.v() = -(angleLUT[angle][1] * distance) >> 8;
- } else {
- angle = location.x & 15;
- distance = location.y;
-
- location.x = (angleLUT[angle][0] * distance) >> 6;
- location.y = (angleLUT[angle][1] * distance) >> 6;
- }
- }
-
- if (objectId != ID_NOTHING) {
- if (validActorId(objectId)) {
- actor = getActor(objectId);
- location.addXY(actor->_location);
- } else if (validObjId(objectId)) {
- obj = getObj(objectId);
- location.addXY(obj->_location);
- }
- }
-}
-
-void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) {
- ActorData *actor;
- Location delta;
- //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId);
- actor = getActor(actorId);
-
- toLocation.delta(actor->_location, delta);
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- if (delta.u() > 0) {
- actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight;
- } else {
- actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown;
- }
- } else {
- if (ABS(delta.y) > ABS(delta.x * 2)) {
- actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp;
- } else {
- actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft;
- }
- }
-}
-
-void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) {
- ActorData *actor;
- ObjectData *obj;
-
- if (validActorId(objectId)) {
- actor = getActor(objectId);
- actorFaceTowardsPoint(actorId, actor->_location);
- } else if (validObjId(objectId)) {
- obj = getObj(objectId);
- actorFaceTowardsPoint(actorId, obj->_location);
- }
-}
-
-
ObjectData *Actor::getObj(uint16 objId) {
ObjectData *obj;
@@ -830,18 +610,6 @@ ActorData *Actor::getActor(uint16 actorId) {
return actor;
}
-bool Actor::validFollowerLocation(const Location &location) {
- Point point;
- location.toScreenPointXY(point);
-
- if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) ||
- (point.y < 0) || (point.y > _vm->_scene->getHeight())) {
- return false;
- }
-
- return (_vm->_scene->canWalk(point));
-}
-
void Actor::setProtagState(int state) {
_protagState = state;
@@ -855,149 +623,6 @@ void Actor::setProtagState(int state) {
}
}
-void Actor::updateActorsScene(int actorsEntrance) {
- int i, j;
- int followerDirection;
- ActorData *actor;
- Location tempLocation;
- Location possibleLocation;
- Point delta;
- const SceneEntry *sceneEntry;
-
- if (_vm->_scene->currentSceneNumber() == 0) {
- error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0");
- }
-
- _vm->_sound->stopVoice();
- _activeSpeech.stringsCount = 0;
- _activeSpeech.playing = false;
- _protagonist = NULL;
-
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
- actor->_inScene = false;
- actor->_spriteList.freeMem();
- if (actor->_disabled) {
- continue;
- }
- if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) {
- if (actor->_flags & kProtagonist) {
- actor->_finalTarget = actor->_location;
- _centerActor = _protagonist = actor;
- } else if (_vm->getGameType() == GType_ITE &&
- _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) {
- continue;
- }
-
- actor->_sceneNumber = _vm->_scene->currentSceneNumber();
- }
- if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) {
- actor->_inScene = true;
- actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance
- }
- }
-
- // _protagonist can be null while loading a game from the command line
- if (_protagonist == NULL)
- return;
-
- if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) {
- if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) {
- actorsEntrance = 0; //OCEAN bug
- }
-
- sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance);
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- _protagonist->_location = sceneEntry->location;
- } else {
- _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT;
- _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT;
- _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT;
- }
- // Workaround for bug #1328045:
- // "When entering any of the houses at the start of the
- // game if you click on anything inside the building you
- // start walking through the door, turn around and leave."
- //
- // After steping of action zone - Rif trying to exit.
- // This piece of code shift Rif's entry position to non action zone area.
- if (_vm->getGameType() == GType_ITE) {
- if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66))
- _protagonist->_location.y += 10;
- }
-
- _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing;
- }
-
- _protagonist->_currentAction = kActionWait;
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- //nothing?
- } else {
- _vm->_scene->initDoorsState(); //TODO: move to _scene
- }
-
- followerDirection = _protagonist->_facingDirection + 3;
- calcScreenPosition(_protagonist);
-
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
- if (actor->_flags & (kFollower)) {
- actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection;
- actor->_currentAction = kActionWait;
- actor->_walkStepsCount = actor->_walkStepIndex = 0;
- actor->_location.z = _protagonist->_location.z;
-
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07);
- } else {
- followerDirection &= 0x07;
-
- possibleLocation = _protagonist->_location;
-
-
- delta.x = directionLUT[followerDirection][0];
- delta.y = directionLUT[followerDirection][1];
-
-
- for (j = 0; j < 30; j++) {
- tempLocation = possibleLocation;
- tempLocation.x += delta.x;
- tempLocation.y += delta.y;
-
- if (validFollowerLocation(tempLocation)) {
- possibleLocation = tempLocation;
- } else {
- tempLocation = possibleLocation;
- tempLocation.x += delta.x;
- if (validFollowerLocation(tempLocation)) {
- possibleLocation = tempLocation;
- } else {
- tempLocation = possibleLocation;
- tempLocation.y += delta.y;
- if (validFollowerLocation(tempLocation)) {
- possibleLocation = tempLocation;
- } else {
- break;
- }
- }
- }
- }
-
- actor->_location = possibleLocation;
- }
- followerDirection += 2;
- }
-
- }
-
- handleActions(0, true);
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- _vm->_isoMap->adjustScroll(true);
- }
-}
-
int Actor::getFrameType(ActorFrameTypes frameType) {
if (_vm->getGameType() == GType_ITE) {
@@ -1235,413 +860,6 @@ void Actor::handleSpeech(int msec) {
_activeSpeech.playing = true;
}
-void Actor::handleActions(int msec, bool setup) {
- int i;
- ActorData *actor;
- ActorFrameRange *frameRange;
- int state;
- int speed;
- int32 framesLeft;
- Location delta;
- Location addDelta;
- int hitZoneIndex;
- const HitZone *hitZone;
- Point hitPoint;
- Location pickLocation;
-
- for (i = 0; i < _actorsCount; i++) {
- actor = _actors[i];
- if (!actor->_inScene)
- continue;
-
- if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) {
- moveDragon(actor);
- continue;
- }
-
- switch (actor->_currentAction) {
- case kActionWait:
- if (!setup && (actor->_flags & kFollower)) {
- followProtagonist(actor);
- if (actor->_currentAction != kActionWait)
- break;
- }
-
- if (actor->_targetObject != ID_NOTHING) {
- actorFaceTowardsObject(actor->_id, actor->_targetObject);
- }
-
- if (actor->_flags & kCycle) {
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
- if (frameRange->frameCount > 0) {
- actor->_actionCycle++;
- actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount;
- } else {
- actor->_actionCycle = 0;
- }
- actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
- break;
- }
-
- if ((actor->_actionCycle & 3) == 0) {
- actor->cycleWrap(100);
-
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait));
- if ((frameRange->frameCount < 1 || actor->_actionCycle > 33))
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
-
- if (frameRange->frameCount) {
- actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1);
- } else {
- actor->_frameNumber = frameRange->frameIndex;
- }
- }
- actor->_actionCycle++;
- break;
-
- case kActionWalkToPoint:
- case kActionWalkToLink:
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- actor->_partialTarget.delta(actor->_location, delta);
-
- while ((delta.u() == 0) && (delta.v() == 0)) {
-
- if ((actor == _protagonist) && (_vm->mouseButtonPressed())) {
- _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation);
-
- if (!actorWalkTo(_protagonist->_id, pickLocation)) {
- break;
- }
- } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) {
- break;
- }
-
- actor->_partialTarget.delta(actor->_location, delta);
- actor->_partialTarget.z = 0;
- }
-
- if (actor->_flags & kFastest) {
- speed = 8;
- } else if (actor->_flags & kFaster) {
- speed = 6;
- } else {
- speed = 4;
- }
-
- if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) {
- speed = 2;
- }
-
- if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) {
- speed = speed / 2;
- }
-
- if (ABS(delta.v()) > ABS(delta.u())) {
- addDelta.v() = clamp(-speed, delta.v(), speed);
- if (addDelta.v() == delta.v()) {
- addDelta.u() = delta.u();
- } else {
- addDelta.u() = delta.u() * addDelta.v();
- addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2);
- addDelta.u() /= delta.v();
- }
- } else {
- addDelta.u() = clamp(-speed, delta.u(), speed);
- if (addDelta.u() == delta.u()) {
- addDelta.v() = delta.v();
- } else {
- addDelta.v() = delta.v() * addDelta.u();
- addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2);
- addDelta.v() /= delta.u();
- }
- }
-
- actor->_location.add(addDelta);
- } else {
- actor->_partialTarget.delta(actor->_location, delta);
-
- while ((delta.x == 0) && (delta.y == 0)) {
-
- if (actor->_walkStepIndex >= actor->_walkStepsCount) {
- actorEndWalk(actor->_id, true);
- break;
- }
-
- actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]);
- if (_vm->getGameType() == GType_ITE) {
- if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) {
- actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT;
- }
- } else {
- if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) {
- actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT;
- }
- }
-
- actor->_partialTarget.delta(actor->_location, delta);
-
- if (ABS(delta.y) > ABS(delta.x)) {
- actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp;
- } else {
- actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft;
- }
- }
-
- if(_vm->getGameType() == GType_ITE)
- speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256;
- else
- speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8;
-
- if (speed < 1)
- speed = 1;
-
- if(_vm->getGameType() == GType_IHNM)
- speed = speed / 2;
-
- if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) {
- addDelta.y = clamp(-speed, delta.y, speed);
- if (addDelta.y == delta.y) {
- addDelta.x = delta.x;
- } else {
- addDelta.x = delta.x * addDelta.y;
- addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2);
- addDelta.x /= delta.y;
- actor->_facingDirection = actor->_actionDirection;
- }
- } else {
- addDelta.x = clamp(-2 * speed, delta.x, 2 * speed);
- if (addDelta.x == delta.x) {
- addDelta.y = delta.y;
- } else {
- addDelta.y = delta.y * addDelta.x;
- addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2);
- addDelta.y /= delta.x;
- actor->_facingDirection = actor->_actionDirection;
- }
- }
-
- actor->_location.add(addDelta);
- }
-
- if (actor->_actorFlags & kActorBackwards) {
- actor->_facingDirection = (actor->_actionDirection + 4) & 7;
- actor->_actionCycle--;
- } else {
- actor->_actionCycle++;
- }
-
- frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
-
- if (actor->_actionCycle < 0) {
- actor->_actionCycle = frameRange->frameCount - 1;
- } else if (actor->_actionCycle >= frameRange->frameCount) {
- actor->_actionCycle = 0;
- }
-
- actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
- break;
-
- case kActionWalkDir:
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0];
- actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1];
-
- frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
-
- actor->_actionCycle++;
- actor->cycleWrap(frameRange->frameCount);
- actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
- } else {
- if (_vm->getGameType() == GType_ITE) {
- actor->_location.x += directionLUT[actor->_actionDirection][0] * 2;
- actor->_location.y += directionLUT[actor->_actionDirection][1] * 2;
- } else {
- // FIXME: The original does not multiply by 8 here, but we do
- actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8;
- actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8;
- }
-
- frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
- actor->_actionCycle++;
- actor->cycleWrap(frameRange->frameCount);
- actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
- }
- break;
-
- case kActionSpeak:
- actor->_actionCycle++;
- actor->cycleWrap(64);
-
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture));
- if (actor->_actionCycle >= frameRange->frameCount) {
- if (actor->_actionCycle & 1)
- break;
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak));
-
- state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount);
-
- if (state == 0) {
- frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
- } else {
- state--;
- }
- } else {
- state = actor->_actionCycle;
- }
-
- actor->_frameNumber = frameRange->frameIndex + state;
- break;
-
- case kActionAccept:
- case kActionStoop:
- break;
-
- case kActionCycleFrames:
- case kActionPongFrames:
- if (actor->_cycleTimeCount > 0) {
- actor->_cycleTimeCount--;
- break;
- }
-
- actor->_cycleTimeCount = actor->_cycleDelay;
- actor->_actionCycle++;
-
- frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence);
-
- if (actor->_currentAction == kActionPongFrames) {
- if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) {
- if (actor->_actorFlags & kActorContinuous) {
- actor->_actionCycle = 0;
- } else {
- actor->_currentAction = kActionFreeze;
- break;
- }
- }
-
- state = actor->_actionCycle;
- if (state >= frameRange->frameCount) {
- state = frameRange->frameCount * 2 - 2 - state;
- }
- } else {
- if (actor->_actionCycle >= frameRange->frameCount) {
- if (actor->_actorFlags & kActorContinuous) {
- actor->_actionCycle = 0;
- } else {
- actor->_currentAction = kActionFreeze;
- break;
- }
- }
- state = actor->_actionCycle;
- }
-
- if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) {
- state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1);
- }
-
- if (actor->_actorFlags & kActorBackwards) {
- actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state;
- } else {
- actor->_frameNumber = frameRange->frameIndex + state;
- }
- break;
-
- case kActionFall:
- if (actor->_actionCycle > 0) {
- framesLeft = actor->_actionCycle--;
- actor->_finalTarget.delta(actor->_location, delta);
- delta.x /= framesLeft;
- delta.y /= framesLeft;
- actor->_location.addXY(delta);
- actor->_fallVelocity += actor->_fallAcceleration;
- actor->_fallPosition += actor->_fallVelocity;
- actor->_location.z = actor->_fallPosition >> 4;
- } else {
- actor->_location = actor->_finalTarget;
- actor->_currentAction = kActionFreeze;
- _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
- }
- break;
-
- case kActionClimb:
- actor->_cycleDelay++;
- if (actor->_cycleDelay & 3) {
- break;
- }
-
- if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) {
- actor->_location.z -= ACTOR_CLIMB_SPEED;
- actor->_actionCycle--;
- } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) {
- actor->_location.z += ACTOR_CLIMB_SPEED;
- actor->_actionCycle++;
- } else {
- actor->_location.z = actor->_finalTarget.z;
- actor->_currentAction = kActionFreeze;
- _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
- }
-
- frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence);
-
- if (actor->_actionCycle < 0) {
- actor->_actionCycle = frameRange->frameCount - 1;
- }
- actor->cycleWrap(frameRange->frameCount);
- actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
- break;
- }
-
- if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) {
- hitZone = NULL;
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- actor->_location.toScreenPointUV(hitPoint);
- } else {
- actor->_location.toScreenPointXY(hitPoint);
- }
- hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint);
- if (hitZoneIndex != -1) {
- hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex);
- }
-
- if (hitZone != actor->_lastZone) {
- if (actor->_lastZone)
- stepZoneAction(actor, actor->_lastZone, true, false);
- actor->_lastZone = hitZone;
- // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves
- // (room 51) to avoid the glitch
- if (hitZone && !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51))
- stepZoneAction(actor, hitZone, false, false);
- }
- }
- }
- // Update frameCount for sfWaitFrames in IHNM
- _vm->_frameCount++;
-}
-
-void Actor::direct(int msec) {
-
- if (_vm->_scene->_entryList.entryListCount == 0) {
- return;
- }
-
- if (_vm->_interface->_statusTextInput) {
- return;
- }
-
- // FIXME: HACK. This should be turned into cycle event.
- _lastTickMsec += msec;
-
- if (_lastTickMsec > 1000 / _handleActionDiv) {
- _lastTickMsec = 0;
- //process actions
- handleActions(msec, false);
- }
-
-//process speech
- handleSpeech(msec);
-}
-
-
bool Actor::calcScreenPosition(CommonObjectData *commonObjectData) {
int beginSlope, endSlope, middle;
bool result;
@@ -1738,7 +956,10 @@ void Actor::createDrawOrderList() {
if (_vm->_scene->getFlags() & kSceneFlagISO) {
compareFunction = &tileCommonObjectCompare;
} else {
- compareFunction = &commonObjectCompare;
+ if (_vm->getGameType() == GType_ITE)
+ compareFunction = &commonObjectCompare;
+ else
+ compareFunction = &commonObjectCompareIHNM;
}
_drawOrderList.clear();
@@ -1814,10 +1035,6 @@ void Actor::drawActors() {
return;
}
- if (!_showActors) {
- return;
- }
-
CommonObjectOrderList::iterator drawOrderIterator;
CommonObjectDataPointer drawObject;
int frameNumber;
@@ -1891,382 +1108,6 @@ void Actor::drawSpeech(void) {
free(outputString);
}
-bool Actor::followProtagonist(ActorData *actor) {
- Location protagonistLocation;
- Location newLocation;
- Location delta;
- int protagonistBGMaskType;
- Point prefer1;
- Point prefer2;
- Point prefer3;
- int16 prefU;
- int16 prefV;
- int16 newU;
- int16 newV;
-
- assert(_protagonist);
-
- actor->_flags &= ~(kFaster | kFastest);
- protagonistLocation = _protagonist->_location;
- calcScreenPosition(_protagonist);
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
- prefU = 60;
- prefV = 60;
-
-
- actor->_location.delta(protagonistLocation, delta);
-
- if (actor->_id == actorIndexToId(2)) {
- prefU = prefV = 48;
- }
-
- if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) {
-
- if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) {
- actor->_flags |= kFaster;
-
- if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) {
- actor->_flags |= kFastest;
- }
- }
-
- prefU /= 2;
- prefV /= 2;
-
- newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u();
- newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v();
-
- newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2;
- newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2;
- newLocation.z = 0;
-
- return actorWalkTo(actor->_id, newLocation);
- }
-
- } else {
- prefer1.x = (100 * _protagonist->_screenScale) >> 8;
- prefer1.y = (50 * _protagonist->_screenScale) >> 8;
-
- if (_protagonist->_currentAction == kActionWalkDir) {
- prefer1.x /= 2;
- }
-
- if (prefer1.x < 8) {
- prefer1.x = 8;
- }
-
- if (prefer1.y < 8) {
- prefer1.y = 8;
- }
-
- prefer2.x = prefer1.x * 2;
- prefer2.y = prefer1.y * 2;
- prefer3.x = prefer1.x + prefer1.x / 2;
- prefer3.y = prefer1.y + prefer1.y / 2;
-
- actor->_location.delta(protagonistLocation, delta);
-
- protagonistBGMaskType = 0;
- if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) {
- protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition);
- }
-
- if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance
- actor->_actorFlags &= ~kActorNoFollow;
-
- if (actor->_actorFlags & kActorNoFollow) {
- return false;
- }
-
- if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) ||
- (delta.y > prefer2.y) || (delta.y < -prefer2.y) ||
- ((_protagonist->_currentAction == kActionWait) &&
- (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) &&
- (delta.y < prefer1.y) && (delta.y > -prefer1.y))) {
-
- if (ABS(delta.x) > ABS(delta.y)) {
-
- delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x;
-
- newLocation.x = delta.x + protagonistLocation.x;
- newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y;
- } else {
- delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y;
-
- newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x;
- newLocation.y = delta.y + protagonistLocation.y;
- }
- newLocation.z = 0;
-
- if (protagonistBGMaskType != 3) {
- newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2;
- newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2;
- }
-
- newLocation.x = clamp(-31*4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4); //fixme
-
- return actorWalkTo(actor->_id, newLocation);
- }
- }
- return false;
-}
-
-bool Actor::actorEndWalk(uint16 actorId, bool recurse) {
- bool walkMore = false;
- ActorData *actor;
- const HitZone *hitZone;
- int hitZoneIndex;
- Point testPoint;
-
- actor = getActor(actorId);
- actor->_actorFlags &= ~kActorBackwards;
-
- if (_vm->getGameType() == GType_ITE) {
-
- if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) {
- actor->_actorFlags |= kActorNoCollide;
- return actorWalkTo(actorId, actor->_finalTarget);
- }
- }
-
- actor->_currentAction = kActionWait;
- if (actor->_actorFlags & kActorFinalFace) {
- actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //?
- }
-
- actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask);
- actor->_flags &= ~(kFaster | kFastest);
-
- if (actor == _protagonist) {
- _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
- if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) {
- if (_vm->getGameType() == GType_ITE)
- actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE
- else
- actor->_location.toScreenPointXY(testPoint);
-
- hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint);
- if (hitZoneIndex != -1) {
- hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex);
- stepZoneAction(actor, hitZone, false, true);
- } else {
- _vm->_script->setNoPendingVerb();
- }
- } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) {
- _vm->_script->doVerb();
- }
- } else {
- if (recurse && (actor->_flags & kFollower))
- walkMore = followProtagonist(actor);
-
- _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
- }
- return walkMore;
-}
-
-bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
- ActorData *actor;
- ActorData *anotherActor;
- int i;
-
- Rect testBox;
- Rect testBox2;
- Point anotherActorScreenPosition;
- Point collision;
- Point pointFrom, pointTo, pointBest, pointAdd;
- Point delta, bestDelta;
- Point tempPoint;
- bool extraStartNode;
- bool extraEndNode;
-
- actor = getActor(actorId);
-
- if (actor == _protagonist) {
- _vm->_scene->setDoorState(2, 0xff);
- _vm->_scene->setDoorState(3, 0);
- } else {
- _vm->_scene->setDoorState(2, 0);
- _vm->_scene->setDoorState(3, 0xff);
- }
-
- if (_vm->_scene->getFlags() & kSceneFlagISO) {
-
- if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) {
- return false;
- }
-
- actor->_finalTarget = toLocation;
- actor->_walkStepsCount = 0;
- _vm->_isoMap->findTilePath(actor, actor->_location, toLocation);
-
-
- if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) {
- actor->_actorFlags |= kActorNoCollide;
- _vm->_isoMap->findTilePath(actor, actor->_location, toLocation);
- }
-
- actor->_walkStepIndex = 0;
- if (_vm->_isoMap->nextTileTarget(actor)) {
- actor->_currentAction = kActionWalkToPoint;
- actor->_walkFrameSequence = getFrameType(kFrameWalk);
- } else {
- actorEndWalk(actorId, false);
- return false;
- }
- } else {
-
- actor->_location.toScreenPointXY(pointFrom);
- pointFrom.x &= ~1;
-
- extraStartNode = _vm->_scene->offscreenPath(pointFrom);
-
- toLocation.toScreenPointXY(pointTo);
- pointTo.x &= ~1;
-
- extraEndNode = _vm->_scene->offscreenPath(pointTo);
-
- if (_vm->_scene->isBGMaskPresent()) {
-
- if ((((actor->_currentAction >= kActionWalkToPoint) &&
- (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) &&
- !_vm->_scene->canWalk(pointFrom)) {
-
- int max = _vm->getGameType() == GType_ITE ? 8 : 4;
-
- for (i = 1; i < max; i++) {
- pointAdd = pointFrom;
- pointAdd.y += i;
- if (_vm->_scene->canWalk(pointAdd)) {
- pointFrom = pointAdd;
- break;
- }
- pointAdd = pointFrom;
- pointAdd.y -= i;
- if (_vm->_scene->canWalk(pointAdd)) {
- pointFrom = pointAdd;
- break;
- }
- if (_vm->getGameType() == GType_ITE) {
- pointAdd = pointFrom;
- pointAdd.x += i;
- if (_vm->_scene->canWalk(pointAdd)) {
- pointFrom = pointAdd;
- break;
- }
- pointAdd = pointFrom;
- pointAdd.x -= i;
- if (_vm->_scene->canWalk(pointAdd)) {
- pointFrom = pointAdd;
- break;
- }
- }
- }
- }
-
- _barrierCount = 0;
- if (!(actor->_actorFlags & kActorNoCollide)) {
- collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2);
- collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2);
-
-
- for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) {
- anotherActor = _actors[i];
- if (!anotherActor->_inScene)
- continue;
- if (anotherActor == actor)
- continue;
-
- anotherActorScreenPosition = anotherActor->_screenPosition;
- testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1;
- testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1;
- testBox.top = anotherActorScreenPosition.y - collision.y;
- testBox.bottom = anotherActorScreenPosition.y + collision.y + 1;
- testBox2 = testBox;
- testBox2.right += 2;
- testBox2.left -= 2;
- testBox2.top -= 1;
- testBox2.bottom += 1;
-
- if (testBox2.contains(pointFrom)) {
- if (pointFrom.x > anotherActorScreenPosition.x + 4) {
- testBox.right = pointFrom.x - 1;
- } else if (pointFrom.x < anotherActorScreenPosition.x - 4) {
- testBox.left = pointFrom.x + 2;
- } else if (pointFrom.y > anotherActorScreenPosition.y) {
- testBox.bottom = pointFrom.y;
- } else {
- testBox.top = pointFrom.y + 1 ;
- }
- }
-
- if ((testBox.width() > 0) && (testBox.height() > 0)) {
- _barrierList[_barrierCount++] = testBox;
- }
- }
- }
-
-
- pointBest = pointTo;
- actor->_walkStepsCount = 0;
- findActorPath(actor, pointFrom, pointTo);
-
- if (actor->_walkStepsCount == 0) {
- error("actor->_walkStepsCount == 0");
- }
-
- if (extraStartNode) {
- actor->_walkStepIndex = 0;
- } else {
- actor->_walkStepIndex = 1;
- }
-
- if (extraEndNode) {
- toLocation.toScreenPointXY(tempPoint);
- actor->_walkStepsCount--;
- actor->addWalkStepPoint(tempPoint);
- }
-
-
- pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1];
-
- pointBest.x &= ~1;
- delta.x = ABS(pointFrom.x - pointTo.x);
- delta.y = ABS(pointFrom.y - pointTo.y);
-
- bestDelta.x = ABS(pointBest.x - pointTo.x);
- bestDelta.y = ABS(pointBest.y - pointTo.y);
-
- if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) {
- actor->_actorFlags |= kActorNoFollow;
- }
-
- if (pointBest == pointFrom) {
- actor->_walkStepsCount = 0;
- }
- } else {
- actor->_walkStepsCount = 0;
- actor->addWalkStepPoint(pointTo);
- actor->_walkStepIndex = 0;
- }
-
- actor->_partialTarget = actor->_location;
- actor->_finalTarget = toLocation;
- if (actor->_walkStepsCount == 0) {
- actorEndWalk(actorId, false);
- return false;
- } else {
- if (actor->_flags & kProtagonist) {
- _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2
- _actors[2]->_actorFlags &= ~kActorNoFollow;
- }
- actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint;
- actor->_walkFrameSequence = getFrameType(kFrameWalk);
- }
- }
- return true;
-}
-
void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount, int sampleResourceId, int speechFlags) {
ActorData *actor;
int i;
@@ -2303,11 +1144,11 @@ void Actor::actorSpeech(uint16 actorId, const char **strings, int stringsCount,
_activeSpeech.speechBox.right = _vm->getDisplayWidth() - 10;
}
- // WORKAROUND for the compact disk in Ellen's chapter
+ // HACK for the compact disk in Ellen's chapter
// Once Ellen starts saying that "Something is different", bring the compact disk in the
// scene. After speaking with AM, the compact disk is visible. She always says this line
// when entering room 59, after speaking with AM, if the compact disk is not picked up yet
- // Check Script::sfDropObject for the other part of this workaround
+ // Check Script::sfDropObject for the other part of this hack
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 3 &&
_vm->_scene->currentSceneNumber() == 59 && _activeSpeech.sampleResourceId == 286) {
for (i = 0; i < _objsCount; i++) {
@@ -2383,759 +1224,6 @@ void Actor::abortSpeech() {
_activeSpeech.playingTime = 0;
}
-void Actor::moveDragon(ActorData *actor) {
- int16 dir0, dir1, dir2, dir3;
- int16 moveType;
- Event event;
- const DragonMove *dragonMove;
-
- if ((actor->_actionCycle < 0) ||
- ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) {
-
- moveType = kDragonMoveInvalid;
- if (actor->_location.distance(_protagonist->_location) < 24) {
- if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) {
- event.type = kEvTOneshot;
- event.code = kScriptEvent;
- event.op = kEventExecNonBlocking;
- event.time = 0;
- event.param = _vm->_scene->getScriptModuleNumber(); // module number
- event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number
- event.param3 = -1; // Action
- event.param4 = -1; // Object
- event.param5 = -1; // With Object
- event.param6 = -1; // Actor
-
- _vm->_events->queue(&event);
- _dragonHunt = false;
- }
- } else {
- _dragonHunt = true;
- }
-
- if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) {
-
- _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection);
-
- if (actor->_walkStepsCount == 0) {
- _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0);
- }
-
- if (actor->_walkStepsCount < 2) {
- return;
- }
-
- actor->_partialTarget = actor->_location;
- actor->_finalTarget = _protagonist->_location;
- actor->_walkStepIndex = 0;
- }
-
- dir0 = actor->_actionDirection;
- dir1 = actor->_tileDirections[actor->_walkStepIndex++];
- dir2 = actor->_tileDirections[actor->_walkStepIndex];
- dir3 = actor->_tileDirections[actor->_walkStepIndex + 1];
-
- if (dir0 != dir1){
- actor->_actionDirection = dir0 = dir1;
- }
-
- actor->_location = actor->_partialTarget;
-
- if ((dir1 != dir2) && (dir1 == dir3)) {
- switch (dir1) {
- case kDirUpLeft:
- actor->_partialTarget.v() += 16;
- moveType = kDragonMoveUpLeft;
- break;
- case kDirDownLeft:
- actor->_partialTarget.u() -= 16;
- moveType = kDragonMoveDownLeft;
- break;
- case kDirDownRight:
- actor->_partialTarget.v() -= 16;
- moveType = kDragonMoveDownRight;
- break;
- case kDirUpRight:
- actor->_partialTarget.u() += 16;
- moveType = kDragonMoveUpRight;
- break;
- }
-
- switch (dir2) {
- case kDirUpLeft:
- actor->_partialTarget.v() += 16;
- break;
- case kDirDownLeft:
- actor->_partialTarget.u() -= 16;
- break;
- case kDirDownRight:
- actor->_partialTarget.v() -= 16;
- break;
- case kDirUpRight:
- actor->_partialTarget.u() += 16;
- break;
- }
-
- actor->_walkStepIndex++;
- } else {
- switch (dir1) {
- case kDirUpLeft:
- actor->_partialTarget.v() += 16;
- switch (dir2) {
- case kDirDownLeft:
- moveType = kDragonMoveUpLeft_Left;
- actor->_partialTarget.u() -= 16;
- break;
- case kDirUpLeft:
- moveType = kDragonMoveUpLeft;
- break;
- case kDirUpRight:
- actor->_partialTarget.u() += 16;
- moveType = kDragonMoveUpLeft_Right;
- break;
- default:
- actor->_actionDirection = dir1;
- actor->_walkStepsCount = 0;
- break;
- }
- break;
- case kDirDownLeft:
- actor->_partialTarget.u() -= 16;
- switch (dir2) {
- case kDirDownRight:
- moveType = kDragonMoveDownLeft_Left;
- actor->_partialTarget.v() -= 16;
- break;
- case kDirDownLeft:
- moveType = kDragonMoveDownLeft;
- break;
- case kDirUpLeft:
- moveType = kDragonMoveDownLeft_Right;
- actor->_partialTarget.v() += 16;
- break;
- default:
- actor->_actionDirection = dir1;
- actor->_walkStepsCount = 0;
- break;
- }
- break;
- case kDirDownRight:
- actor->_partialTarget.v() -= 16;
- switch (dir2) {
- case kDirUpRight:
- moveType = kDragonMoveDownRight_Left;
- actor->_partialTarget.u() += 16;
- break;
- case kDirDownRight:
- moveType = kDragonMoveDownRight;
- break;
- case kDirDownLeft:
- moveType = kDragonMoveDownRight_Right;
- actor->_partialTarget.u() -= 16;
- break;
- default:
- actor->_actionDirection = dir1;
- actor->_walkStepsCount = 0;
- break;
- }
- break;
- case kDirUpRight:
- actor->_partialTarget.u() += 16;
- switch (dir2) {
- case kDirUpLeft:
- moveType = kDragonMoveUpRight_Left;
- actor->_partialTarget.v() += 16;
- break;
- case kDirUpRight:
- moveType = kDragonMoveUpRight;
- break;
- case kDirDownRight:
- moveType = kDragonMoveUpRight_Right;
- actor->_partialTarget.v() -= 16;
- break;
- default:
- actor->_actionDirection = dir1;
- actor->_walkStepsCount = 0;
- break;
- }
- break;
-
- default:
- actor->_actionDirection = dir1;
- actor->_walkStepsCount = 0;
- break;
- }
- }
-
- actor->_dragonMoveType = moveType;
-
- if (moveType >= ACTOR_DRAGON_TURN_MOVES) {
- actor->_dragonStepCycle = 0;
- actor->_actionCycle = 4;
- actor->_walkStepIndex++;
- } else {
- actor->_actionCycle = 4;
- }
- }
-
- actor->_actionCycle--;
-
- if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) {
- return;
- }
-
- if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) {
-
- actor->_dragonStepCycle++;
- if (actor->_dragonStepCycle >= 7) {
- actor->_dragonStepCycle = 0;
- }
-
- actor->_dragonBaseFrame = actor->_dragonMoveType * 7;
-
- if (actor->_location.u() > actor->_partialTarget.u() + 3) {
- actor->_location.u() -= 4;
- } else if (actor->_location.u() < actor->_partialTarget.u() - 3) {
- actor->_location.u() += 4;
- } else {
- actor->_location.u() = actor->_partialTarget.u();
- }
-
- if (actor->_location.v() > actor->_partialTarget.v() + 3) {
- actor->_location.v() -= 4;
- } else if (actor->_location.v() < actor->_partialTarget.v() - 3) {
- actor->_location.v() += 4;
- } else {
- actor->_location.v() = actor->_partialTarget.v();
- }
- } else {
- dragonMove = &dragonMoveTable[actor->_dragonMoveType];
- actor->_dragonBaseFrame = dragonMove->baseFrame;
-
-
- actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0];
- actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1];
-
- actor->_dragonStepCycle++;
- if (actor->_dragonStepCycle >= 3) {
- actor->_dragonStepCycle = 3;
- }
- }
-
- actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle;
-}
-
-void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) {
- Point iteratorPoint;
- Point bestPoint;
- int maskType;
- int i;
- Rect intersect;
-
-#ifdef ACTOR_DEBUG
- _debugPointsCount = 0;
-#endif
-
- actor->_walkStepsCount = 0;
- if (fromPoint == toPoint) {
- actor->addWalkStepPoint(toPoint);
- return;
- }
-
- for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) {
- for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) {
- if (_vm->_scene->validBGMaskPoint(iteratorPoint)) {
- maskType = _vm->_scene->getBGMaskType(iteratorPoint);
- setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty);
- } else {
- setPathCell(iteratorPoint, kPathCellBarrier);
- }
- }
- }
-
- for (i = 0; i < _barrierCount; i++) {
- intersect.left = MAX(_pathRect.left, _barrierList[i].left);
- intersect.top = MAX(_pathRect.top, _barrierList[i].top);
- intersect.right = MIN(_pathRect.right, _barrierList[i].right);
- intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom);
-
- for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) {
- for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) {
- setPathCell(iteratorPoint, kPathCellBarrier);
- }
- }
- }
-
-#ifdef ACTOR_DEBUG
- for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) {
- for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) {
- if (getPathCell(iteratorPoint) == kPathCellBarrier) {
- addDebugPoint(iteratorPoint, 24);
- }
- }
- }
-#endif
-
- if (scanPathLine(fromPoint, toPoint)) {
- actor->addWalkStepPoint(fromPoint);
- actor->addWalkStepPoint(toPoint);
- return;
- }
-
- i = fillPathArray(fromPoint, toPoint, bestPoint);
-
- if (fromPoint == bestPoint) {
- actor->addWalkStepPoint(bestPoint);
- return;
- }
-
- if (i == 0) {
- error("fillPathArray returns zero");
- }
-
- setActorPath(actor, fromPoint, bestPoint);
-}
-
-bool Actor::scanPathLine(const Point &point1, const Point &point2) {
- Point point;
- Point delta;
- Point s;
- Point fDelta;
- int16 errterm;
-
- calcDeltaS(point1, point2, delta, s);
- point = point1;
-
- fDelta.x = delta.x * 2;
- fDelta.y = delta.y * 2;
-
- if (delta.y > delta.x) {
-
- errterm = fDelta.x - delta.y;
-
- while (delta.y > 0) {
- while (errterm >= 0) {
- point.x += s.x;
- errterm -= fDelta.y;
- }
-
- point.y += s.y;
- errterm += fDelta.x;
-
- if (!validPathCellPoint(point)) {
- return false;
- }
- if (getPathCell(point) == kPathCellBarrier) {
- return false;
- }
- delta.y--;
- }
- } else {
-
- errterm = fDelta.y - delta.x;
-
- while (delta.x > 0) {
- while (errterm >= 0) {
- point.y += s.y;
- errterm -= fDelta.x;
- }
-
- point.x += s.x;
- errterm += fDelta.y;
-
- if (!validPathCellPoint(point)) {
- return false;
- }
- if (getPathCell(point) == kPathCellBarrier) {
- return false;
- }
- delta.x--;
- }
- }
- return true;
-}
-
-int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) {
- int bestRating;
- int currentRating;
- int i;
- Point bestPath;
- int pointCounter;
- int startDirection;
- PathDirectionData *pathDirection;
- PathDirectionData *newPathDirection;
- const PathDirectionData *samplePathDirection;
- Point nextPoint;
- int directionCount;
- int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1;
-
- _pathDirectionListCount = 0;
- pointCounter = 0;
- bestRating = quickDistance(fromPoint, toPoint, compressX);
- bestPath = fromPoint;
-
- for (startDirection = 0; startDirection < 4; startDirection++) {
- newPathDirection = addPathDirectionListData();
- newPathDirection->coord = fromPoint;
- newPathDirection->direction = startDirection;
- }
-
- if (validPathCellPoint(fromPoint)) {
- setPathCell(fromPoint, kDirUp);
-
-#ifdef ACTOR_DEBUG
- addDebugPoint(fromPoint, 24+36);
-#endif
- }
-
- i = 0;
-
- do {
- pathDirection = &_pathDirectionList[i];
- for (directionCount = 0; directionCount < 3; directionCount++) {
- samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount];
- nextPoint = pathDirection->coord;
- nextPoint.x += samplePathDirection->coord.x;
- nextPoint.y += samplePathDirection->coord.y;
-
- if (!validPathCellPoint(nextPoint)) {
- continue;
- }
-
- if (getPathCell(nextPoint) != kPathCellEmpty) {
- continue;
- }
-
- setPathCell(nextPoint, samplePathDirection->direction);
-
-#ifdef ACTOR_DEBUG
- addDebugPoint(nextPoint, samplePathDirection->direction + 96);
-#endif
- newPathDirection = addPathDirectionListData();
- newPathDirection->coord = nextPoint;
- newPathDirection->direction = samplePathDirection->direction;
- ++pointCounter;
- if (nextPoint == toPoint) {
- bestPoint = toPoint;
- return pointCounter;
- }
- currentRating = quickDistance(nextPoint, toPoint, compressX);
- if (currentRating < bestRating) {
- bestRating = currentRating;
- bestPath = nextPoint;
- }
- pathDirection = &_pathDirectionList[i];
- }
- ++i;
- } while (i < _pathDirectionListCount);
-
- bestPoint = bestPath;
- return pointCounter;
-}
-
-void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) {
- Point nextPoint;
- int8 direction;
- int i;
-
- _pathListIndex = -1;
- addPathListPoint(toPoint);
- nextPoint = toPoint;
-
- while (!(nextPoint == fromPoint)) {
- direction = getPathCell(nextPoint);
- if ((direction < 0) || (direction >= 8)) {
- error("Actor::setActorPath error direction 0x%X", direction);
- }
- nextPoint.x -= pathDirectionLUT2[direction][0];
- nextPoint.y -= pathDirectionLUT2[direction][1];
- addPathListPoint(nextPoint);
-
-#ifdef ACTOR_DEBUG
- addDebugPoint(nextPoint, 0x8a);
-#endif
- }
-
- pathToNode();
- removeNodes();
- nodeToPath();
- removePathPoints();
-
- for (i = 0; i <= _pathNodeListIndex; i++) {
- actor->addWalkStepPoint(_pathNodeList[i].point);
- }
-}
-
-void Actor::pathToNode() {
- Point point1, point2, delta;
- int direction;
- int i;
- Point *point;
-
- point= &_pathList[_pathListIndex];
- direction = 0;
-
- _pathNodeListIndex = -1;
- addPathNodeListPoint(*point);
-
- for (i = _pathListIndex; i > 0; i--) {
- point1 = *point;
- --point;
- point2 = *point;
- if (direction == 0) {
- delta.x = int16Compare(point2.x, point1.x);
- delta.y = int16Compare(point2.y, point1.y);
- direction++;
- }
- if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) {
- addPathNodeListPoint(point1);
- direction--;
- i++;
- point++;
- }
- }
- addPathNodeListPoint(*_pathList);
-}
-
-int pathLine(Point *pointList, const Point &point1, const Point &point2) {
- Point point;
- Point delta;
- Point tempPoint;
- Point s;
- int16 errterm;
- int16 res;
-
- calcDeltaS(point1, point2, delta, s);
-
- point = point1;
-
- tempPoint.x = delta.x * 2;
- tempPoint.y = delta.y * 2;
-
- if (delta.y > delta.x) {
-
- errterm = tempPoint.x - delta.y;
- res = delta.y;
-
- while (delta.y > 0) {
- while (errterm >= 0) {
- point.x += s.x;
- errterm -= tempPoint.y;
- }
-
- point.y += s.y;
- errterm += tempPoint.x;
-
- *pointList = point;
- pointList++;
- delta.y--;
- }
- } else {
-
- errterm = tempPoint.y - delta.x;
- res = delta.x;
-
- while (delta.x > 0) {
- while (errterm >= 0) {
- point.y += s.y;
- errterm -= tempPoint.x;
- }
-
- point.x += s.x;
- errterm += tempPoint.y;
-
- *pointList = point;
- pointList++;
- delta.x--;
- }
- }
- return res;
-}
-
-void Actor::nodeToPath() {
- int i;
- Point point1, point2;
- PathNode *node;
- Point *point;
-
- for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) {
- point->x = point->y = PATH_NODE_EMPTY;
- }
-
- _pathListIndex = 1;
- _pathList[0] = _pathNodeList[0].point;
- _pathNodeList[0].link = 0;
- for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) {
- point1 = node->point;
- node++;
- point2 = node->point;
- _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2);
- node->link = _pathListIndex - 1;
- }
- _pathListIndex--;
- _pathNodeList[_pathNodeListIndex].link = _pathListIndex;
-
-}
-
-void Actor::removeNodes() {
- int i, j, k;
- PathNode *iNode, *jNode, *kNode, *fNode;
- fNode = &_pathNodeList[_pathNodeListIndex];
-
- if (scanPathLine(_pathNodeList[0].point, fNode->point)) {
- _pathNodeList[1] = *fNode;
- _pathNodeListIndex = 1;
- }
-
- if (_pathNodeListIndex < 4) {
- return;
- }
-
- for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) {
- if (iNode->point.x == PATH_NODE_EMPTY) {
- continue;
- }
-
- if (scanPathLine(_pathNodeList[0].point, iNode->point)) {
- for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) {
- jNode->point.x = PATH_NODE_EMPTY;
- }
- }
- }
-
- for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) {
- if (iNode->point.x == PATH_NODE_EMPTY) {
- continue;
- }
-
- if (scanPathLine(fNode->point, iNode->point)) {
- for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) {
- jNode->point.x = PATH_NODE_EMPTY;
- }
- }
- }
- condenseNodeList();
-
- for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) {
- if (iNode->point.x == PATH_NODE_EMPTY) {
- continue;
- }
- for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) {
- if (jNode->point.x == PATH_NODE_EMPTY) {
- continue;
- }
-
- if (scanPathLine(iNode->point, jNode->point)) {
- for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) {
- kNode->point.x = PATH_NODE_EMPTY;
- }
- }
- }
- }
- condenseNodeList();
-}
-
-void Actor::condenseNodeList() {
- int i, j, count;
- PathNode *iNode, *jNode;
-
- count = _pathNodeListIndex;
-
- for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) {
- if (iNode->point.x == PATH_NODE_EMPTY) {
- j = i + 1;
- jNode = iNode + 1;
- while (jNode->point.x == PATH_NODE_EMPTY) {
- j++;
- jNode++;
- }
- *iNode = *jNode;
- count = i;
- jNode->point.x = PATH_NODE_EMPTY;
- if (j == _pathNodeListIndex) {
- break;
- }
- }
- }
- _pathNodeListIndex = count;
-}
-
-void Actor::removePathPoints() {
- int i, j, k, l;
- PathNode *node;
- int start;
- int end;
- Point point1, point2;
-
- if (_pathNodeListIndex < 2)
- return;
-
- _newPathNodeListIndex = -1;
- addNewPathNodeListPoint(_pathNodeList[0]);
-
- for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) {
- addNewPathNodeListPoint(*node);
-
- for (j = 5; j > 0; j--) {
- start = node->link - j;
- end = node->link + j;
-
- if (start < 0 || end > _pathListIndex) {
- continue;
- }
-
- point1 = _pathList[start];
- point2 = _pathList[end];
- if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) {
- continue;
- }
-
- if (scanPathLine(point1, point2)) {
- for (l = 1; l <= _newPathNodeListIndex; l++) {
- if (start <= _newPathNodeList[l].link) {
- _newPathNodeListIndex = l;
- _newPathNodeList[_newPathNodeListIndex].point = point1;
- _newPathNodeList[_newPathNodeListIndex].link = start;
- incrementNewPathNodeListIndex();
- break;
- }
- }
- _newPathNodeList[_newPathNodeListIndex].point = point2;
- _newPathNodeList[_newPathNodeListIndex].link = end;
-
- for (k = start + 1; k < end; k++) {
- _pathList[k].x = PATH_NODE_EMPTY;
- }
- break;
- }
- }
- }
-
- addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]);
-
- for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) {
- if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) {
- _pathNodeList[j++] = _newPathNodeList[i];
- }
- }
- _pathNodeListIndex = j - 1;
-}
-
-void Actor::drawPathTest() {
-#ifdef ACTOR_DEBUG
- int i;
- Surface *surface;
- surface = _vm->_gfx->getBackBuffer();
- if (_debugPoints == NULL) {
- return;
- }
-
- for (i = 0; i < _debugPointsCount; i++) {
- *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color;
- }
-#endif
-}
-
void Actor::saveState(Common::OutSaveFile *out) {
uint16 i;
@@ -3156,7 +1244,7 @@ void Actor::loadState(Common::InSaveFile *in) {
int32 i;
int16 protagState = in->readSint16LE();
- if (protagState != 0)
+ if (protagState != 0 || _protagonist->_shareFrames)
setProtagState(protagState);
for (i = 0; i < _actorsCount; i++) {
@@ -3178,24 +1266,4 @@ void Actor::loadState(Common::InSaveFile *in) {
}
}
-// Console wrappers - must be safe to run
-
-void Actor::cmdActorWalkTo(int argc, const char **argv) {
- uint16 actorId = (uint16) atoi(argv[1]);
- Location location;
- Point movePoint;
-
- movePoint.x = atoi(argv[2]);
- movePoint.y = atoi(argv[3]);
-
- location.fromScreenPoint(movePoint);
-
- if (!validActorId(actorId)) {
- _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId);
- return;
- }
-
- actorWalkTo(actorId, location);
-}
-
} // End of namespace Saga
diff --git a/engines/saga/actor.h b/engines/saga/actor.h
index ef62661c6c..7022ef1289 100644
--- a/engines/saga/actor.h
+++ b/engines/saga/actor.h
@@ -94,6 +94,24 @@ enum ActorActions {
kActionClimb = 12
};
+enum ActorFrameIds {
+//ITE
+ kFrameITEStand = 0,
+ kFrameITEWalk = 1,
+ kFrameITESpeak = 2,
+ kFrameITEGive = 3,
+ kFrameITEGesture = 4,
+ kFrameITEWait = 5,
+ kFrameITEPickUp = 6,
+ kFrameITELook = 7,
+//IHNM
+ kFrameIHNMStand = 0,
+ kFrameIHNMSpeak = 1,
+ kFrameIHNMWait = 2,
+ kFrameIHNMGesture = 3,
+ kFrameIHNMWalk = 4
+};
+
enum SpeechFlags {
kSpeakNoAnimate = 1,
kSpeakAsync = 2,
@@ -112,6 +130,18 @@ enum ActorFrameTypes {
kFrameLook
};
+// Lookup table to convert 8 cardinal directions to 4
+static const int actorDirectectionsLUT[8] = {
+ ACTOR_DIRECTION_BACK, // kDirUp
+ ACTOR_DIRECTION_RIGHT, // kDirUpRight
+ ACTOR_DIRECTION_RIGHT, // kDirRight
+ ACTOR_DIRECTION_RIGHT, // kDirDownRight
+ ACTOR_DIRECTION_FORWARD,// kDirDown
+ ACTOR_DIRECTION_LEFT, // kDirDownLeft
+ ACTOR_DIRECTION_LEFT, // kDirLeft
+ ACTOR_DIRECTION_LEFT, // kDirUpLeft
+};
+
enum ActorFlagsEx {
kActorNoCollide = (1 << 0),
kActorNoFollow = (1 << 1),
@@ -612,8 +642,6 @@ public:
void freeObjList();
void loadObjList(int objectCount, int objectsResourceID);
- void showActors(bool flag) { _showActors = flag; }
-
protected:
friend class Script;
bool loadActorResources(ActorData *actor);
@@ -709,7 +737,6 @@ private:
int _xCellCount;
int _yCellCount;
Rect _pathRect;
- bool _showActors;
PathDirectionData *_pathDirectionList;
int _pathDirectionListCount;
diff --git a/engines/saga/actor_walk.cpp b/engines/saga/actor_walk.cpp
new file mode 100644
index 0000000000..47bf804edb
--- /dev/null
+++ b/engines/saga/actor_walk.cpp
@@ -0,0 +1,1942 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "saga/saga.h"
+
+#include "saga/actor.h"
+#include "saga/console.h"
+#include "saga/events.h"
+#include "saga/isomap.h"
+#include "saga/objectmap.h"
+#include "saga/sagaresnames.h"
+#include "saga/script.h"
+#include "saga/sound.h"
+#include "saga/scene.h"
+
+namespace Saga {
+
+static const PathDirectionData pathDirectionLUT[8][3] = {
+ { { 0, Point( 0, -1) }, { 7, Point(-1, -1) }, { 4, Point( 1, -1) } },
+ { { 1, Point( 1, 0) }, { 4, Point( 1, -1) }, { 5, Point( 1, 1) } },
+ { { 2, Point( 0, 1) }, { 5, Point( 1, 1) }, { 6, Point(-1, 1) } },
+ { { 3, Point(-1, 0) }, { 6, Point(-1, 1) }, { 7, Point(-1, -1) } },
+ { { 0, Point( 0, -1) }, { 1, Point( 1, 0) }, { 4, Point( 1, -1) } },
+ { { 1, Point( 1, 0) }, { 2, Point( 0, 1) }, { 5, Point( 1, 1) } },
+ { { 2, Point( 0, 1) }, { 3, Point(-1, 0) }, { 6, Point(-1, 1) } },
+ { { 3, Point(-1, 0) }, { 0, Point( 0, -1) }, { 7, Point(-1, -1) } }
+};
+
+static const int pathDirectionLUT2[8][2] = {
+ { 0, -1 },
+ { 1, 0 },
+ { 0, 1 },
+ { -1, 0 },
+ { 1, -1 },
+ { 1, 1 },
+ { -1, 1 },
+ { -1, -1 }
+};
+
+static const int angleLUT[16][2] = {
+ { 0, -256 },
+ { 98, -237 },
+ { 181, -181 },
+ { 237, -98 },
+ { 256, 0 },
+ { 237, 98 },
+ { 181, 181 },
+ { 98, 237 },
+ { 0, 256 },
+ { -98, 237 },
+ { -181, 181 },
+ { -237, 98 },
+ { -256, 0 },
+ { -237, -98 },
+ { -181, -181 },
+ { -98, -237 }
+};
+
+static const int directionLUT[8][2] = {
+ { 0 * 2, -2 * 2 },
+ { 2 * 2, -1 * 2 },
+ { 3 * 2, 0 * 2 },
+ { 2 * 2, 1 * 2 },
+ { 0 * 2, 2 * 2 },
+ { -2 * 2, 1 * 2 },
+ { -4 * 2, 0 * 2 },
+ { -2 * 2, -1 * 2 }
+};
+
+static const int tileDirectionLUT[8][2] = {
+ { 1, 1 },
+ { 2, 0 },
+ { 1, -1 },
+ { 0, -2 },
+ { -1, -1 },
+ { -2, 0 },
+ { -1, 1 },
+ { 0, 2 }
+};
+
+struct DragonMove {
+ uint16 baseFrame;
+ int16 offset[4][2];
+};
+
+static const DragonMove dragonMoveTable[12] = {
+ { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
+ { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
+ { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
+ { 0, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } } },
+ { 28, { { -0, 0 }, { -1, 6 }, { -5, 11 }, { -10, 15 } } },
+ { 56, { { 0, 0 }, { 1, 6 }, { 5, 11 }, { 10, 15 } } },
+ { 40, { { 0, 0 }, { 6, 1 }, { 11, 5 }, { 15, 10 } } },
+ { 44, { { 0, 0 }, { 6, -1 }, { 11, -5 }, { 15, -10 } } },
+ { 32, { { -0, -0 }, { -6, -1 }, { -11, -5 }, { -15, -10 } } },
+ { 52, { { -0, 0 }, { -6, 1 }, { -11, 5 }, { -15, 10 } } },
+ { 36, { { 0, -0 }, { 1, -6 }, { 5, -11 }, { 10, -15 } } },
+ { 48, { { -0, -0 }, { -1, -6 }, { -5, -11 }, { -10, -15 } } }
+};
+
+inline int16 quickDistance(const Point &point1, const Point &point2, int16 compressX) {
+ Point delta;
+ delta.x = ABS(point1.x - point2.x) / compressX;
+ delta.y = ABS(point1.y - point2.y);
+ return ((delta.x < delta.y) ? (delta.y + delta.x / 2) : (delta.x + delta.y / 2));
+}
+
+inline void calcDeltaS(const Point &point1, const Point &point2, Point &delta, Point &s) {
+
+ delta.x = point2.x - point1.x;
+ if (delta.x == 0) {
+ s.x = 0;
+ } else {
+ if (delta.x > 0) {
+ s.x = 1;
+ } else {
+ s.x = -1;
+ delta.x = -delta.x;
+ }
+ }
+
+
+ delta.y = point2.y - point1.y;
+ if (delta.y == 0) {
+ s.y = 0;
+ } else {
+ if (delta.y > 0) {
+ s.y = 1;
+ } else {
+ s.y = -1;
+ delta.y = -delta.y;
+ }
+ }
+}
+
+inline int16 int16Compare(int16 i1, int16 i2) {
+ return ((i1) > (i2) ? 1 : ((i1) < (i2) ? -1 : 0));
+}
+
+bool Actor::validFollowerLocation(const Location &location) {
+ Point point;
+ location.toScreenPointXY(point);
+
+ if ((point.x < 5) || (point.x >= _vm->getDisplayWidth() - 5) ||
+ (point.y < 0) || (point.y > _vm->_scene->getHeight())) {
+ return false;
+ }
+
+ return (_vm->_scene->canWalk(point));
+}
+
+void Actor::realLocation(Location &location, uint16 objectId, uint16 walkFlags) {
+ int angle;
+ int distance;
+ ActorData *actor;
+ ObjectData *obj;
+ debug (8, "Actor::realLocation objectId=%i", objectId);
+ if (walkFlags & kWalkUseAngle) {
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ angle = (location.x + 2) & 15;
+ distance = location.y;
+
+ location.u() = (angleLUT[angle][0] * distance) >> 8;
+ location.v() = -(angleLUT[angle][1] * distance) >> 8;
+ } else {
+ angle = location.x & 15;
+ distance = location.y;
+
+ location.x = (angleLUT[angle][0] * distance) >> 6;
+ location.y = (angleLUT[angle][1] * distance) >> 6;
+ }
+ }
+
+ if (objectId != ID_NOTHING) {
+ if (validActorId(objectId)) {
+ actor = getActor(objectId);
+ location.addXY(actor->_location);
+ } else if (validObjId(objectId)) {
+ obj = getObj(objectId);
+ location.addXY(obj->_location);
+ }
+ }
+}
+
+void Actor::actorFaceTowardsObject(uint16 actorId, uint16 objectId) {
+ ActorData *actor;
+ ObjectData *obj;
+
+ if (validActorId(objectId)) {
+ actor = getActor(objectId);
+ actorFaceTowardsPoint(actorId, actor->_location);
+ } else if (validObjId(objectId)) {
+ obj = getObj(objectId);
+ actorFaceTowardsPoint(actorId, obj->_location);
+ }
+}
+
+void Actor::actorFaceTowardsPoint(uint16 actorId, const Location &toLocation) {
+ ActorData *actor;
+ Location delta;
+ //debug (8, "Actor::actorFaceTowardsPoint actorId=%i", actorId);
+ actor = getActor(actorId);
+
+ toLocation.delta(actor->_location, delta);
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ if (delta.u() > 0) {
+ actor->_facingDirection = (delta.v() > 0) ? kDirUp : kDirRight;
+ } else {
+ actor->_facingDirection = (delta.v() > 0) ? kDirLeft : kDirDown;
+ }
+ } else {
+ if (ABS(delta.y) > ABS(delta.x * 2)) {
+ actor->_facingDirection = (delta.y > 0) ? kDirDown : kDirUp;
+ } else {
+ actor->_facingDirection = (delta.x > 0) ? kDirRight : kDirLeft;
+ }
+ }
+}
+
+void Actor::updateActorsScene(int actorsEntrance) {
+ int i, j;
+ int followerDirection;
+ ActorData *actor;
+ Location tempLocation;
+ Location possibleLocation;
+ Point delta;
+ const SceneEntry *sceneEntry;
+
+ if (_vm->_scene->currentSceneNumber() == 0) {
+ error("Actor::updateActorsScene _vm->_scene->currentSceneNumber() == 0");
+ }
+
+ _vm->_sound->stopVoice();
+ _activeSpeech.stringsCount = 0;
+ _activeSpeech.playing = false;
+ _protagonist = NULL;
+
+ for (i = 0; i < _actorsCount; i++) {
+ actor = _actors[i];
+ actor->_inScene = false;
+ actor->_spriteList.freeMem();
+ if (actor->_disabled) {
+ continue;
+ }
+ if ((actor->_flags & (kProtagonist | kFollower)) || (i == 0)) {
+ if (actor->_flags & kProtagonist) {
+ actor->_finalTarget = actor->_location;
+ _centerActor = _protagonist = actor;
+ } else if (_vm->getGameType() == GType_ITE &&
+ _vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) {
+ continue;
+ }
+
+ actor->_sceneNumber = _vm->_scene->currentSceneNumber();
+ }
+ if (actor->_sceneNumber == _vm->_scene->currentSceneNumber()) {
+ actor->_inScene = true;
+ actor->_actionCycle = (_vm->_rnd.getRandomNumber(7) & 0x7) * 4; // 1/8th chance
+ }
+ }
+
+ // _protagonist can be null while loading a game from the command line
+ if (_protagonist == NULL)
+ return;
+
+ if ((actorsEntrance >= 0) && (_vm->_scene->_entryList.entryListCount > 0)) {
+ if (_vm->_scene->_entryList.entryListCount <= actorsEntrance) {
+ actorsEntrance = 0; //OCEAN bug
+ }
+
+ sceneEntry = _vm->_scene->_entryList.getEntry(actorsEntrance);
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _protagonist->_location = sceneEntry->location;
+ } else {
+ _protagonist->_location.x = sceneEntry->location.x * ACTOR_LMULT;
+ _protagonist->_location.y = sceneEntry->location.y * ACTOR_LMULT;
+ _protagonist->_location.z = sceneEntry->location.z * ACTOR_LMULT;
+ }
+ // Workaround for bug #1328045:
+ // "When entering any of the houses at the start of the
+ // game if you click on anything inside the building you
+ // start walking through the door, turn around and leave."
+ //
+ // After stepping on an action zone, Rif is trying to exit.
+ // Shift Rif's entry position to a non action zone area.
+ if (_vm->getGameType() == GType_ITE) {
+ if ((_vm->_scene->currentSceneNumber() >= 53) && (_vm->_scene->currentSceneNumber() <= 66))
+ _protagonist->_location.y += 10;
+ }
+
+ _protagonist->_facingDirection = _protagonist->_actionDirection = sceneEntry->facing;
+ }
+
+ _protagonist->_currentAction = kActionWait;
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ //nothing?
+ } else {
+ _vm->_scene->initDoorsState(); //TODO: move to _scene
+ }
+
+ followerDirection = _protagonist->_facingDirection + 3;
+ calcScreenPosition(_protagonist);
+
+ for (i = 0; i < _actorsCount; i++) {
+ actor = _actors[i];
+ if (actor->_flags & (kFollower)) {
+ actor->_facingDirection = actor->_actionDirection = _protagonist->_facingDirection;
+ actor->_currentAction = kActionWait;
+ actor->_walkStepsCount = actor->_walkStepIndex = 0;
+ actor->_location.z = _protagonist->_location.z;
+
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _vm->_isoMap->placeOnTileMap(_protagonist->_location, actor->_location, 3, followerDirection & 0x07);
+ } else {
+ followerDirection &= 0x07;
+
+ possibleLocation = _protagonist->_location;
+
+ delta.x = directionLUT[followerDirection][0];
+ delta.y = directionLUT[followerDirection][1];
+
+ for (j = 0; j < 30; j++) {
+ tempLocation = possibleLocation;
+ tempLocation.x += delta.x;
+ tempLocation.y += delta.y;
+
+ if (validFollowerLocation(tempLocation)) {
+ possibleLocation = tempLocation;
+ } else {
+ tempLocation = possibleLocation;
+ tempLocation.x += delta.x;
+ if (validFollowerLocation(tempLocation)) {
+ possibleLocation = tempLocation;
+ } else {
+ tempLocation = possibleLocation;
+ tempLocation.y += delta.y;
+ if (validFollowerLocation(tempLocation)) {
+ possibleLocation = tempLocation;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ actor->_location = possibleLocation;
+ }
+ followerDirection += 2;
+ }
+
+ }
+
+ handleActions(0, true);
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ _vm->_isoMap->adjustScroll(true);
+ }
+}
+
+void Actor::handleActions(int msec, bool setup) {
+ int i;
+ ActorData *actor;
+ ActorFrameRange *frameRange;
+ int state;
+ int speed;
+ int32 framesLeft;
+ Location delta;
+ Location addDelta;
+ int hitZoneIndex;
+ const HitZone *hitZone;
+ Point hitPoint;
+ Location pickLocation;
+
+ for (i = 0; i < _actorsCount; i++) {
+ actor = _actors[i];
+ if (!actor->_inScene)
+ continue;
+
+ if ((_vm->getGameType() == GType_ITE) && (i == ACTOR_DRAGON_INDEX)) {
+ moveDragon(actor);
+ continue;
+ }
+
+ switch (actor->_currentAction) {
+ case kActionWait:
+ if (!setup && (actor->_flags & kFollower)) {
+ followProtagonist(actor);
+ if (actor->_currentAction != kActionWait)
+ break;
+ }
+
+ if (actor->_targetObject != ID_NOTHING) {
+ actorFaceTowardsObject(actor->_id, actor->_targetObject);
+ }
+
+ if (actor->_flags & kCycle) {
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
+ if (frameRange->frameCount > 0) {
+ actor->_actionCycle++;
+ actor->_actionCycle = (actor->_actionCycle) % frameRange->frameCount;
+ } else {
+ actor->_actionCycle = 0;
+ }
+ actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
+ break;
+ }
+
+ if ((actor->_actionCycle & 3) == 0) {
+ actor->cycleWrap(100);
+
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameWait));
+ if ((frameRange->frameCount < 1 || actor->_actionCycle > 33))
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
+
+ if (frameRange->frameCount) {
+ actor->_frameNumber = frameRange->frameIndex + (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount - 1);
+ } else {
+ actor->_frameNumber = frameRange->frameIndex;
+ }
+ }
+ actor->_actionCycle++;
+ break;
+
+ case kActionWalkToPoint:
+ case kActionWalkToLink:
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ actor->_partialTarget.delta(actor->_location, delta);
+
+ while ((delta.u() == 0) && (delta.v() == 0)) {
+
+ if ((actor == _protagonist) && (_vm->mouseButtonPressed())) {
+ _vm->_isoMap->screenPointToTileCoords(_vm->mousePos(), pickLocation);
+
+ if (!actorWalkTo(_protagonist->_id, pickLocation)) {
+ break;
+ }
+ } else if (!_vm->_isoMap->nextTileTarget(actor) && !actorEndWalk(actor->_id, true)) {
+ break;
+ }
+
+ actor->_partialTarget.delta(actor->_location, delta);
+ actor->_partialTarget.z = 0;
+ }
+
+ if (actor->_flags & kFastest) {
+ speed = 8;
+ } else if (actor->_flags & kFaster) {
+ speed = 6;
+ } else {
+ speed = 4;
+ }
+
+ if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) {
+ speed = 2;
+ }
+
+ if ((actor->_actionDirection == 2) || (actor->_actionDirection == 6)) {
+ speed = speed / 2;
+ }
+
+ if (ABS(delta.v()) > ABS(delta.u())) {
+ addDelta.v() = clamp(-speed, delta.v(), speed);
+ if (addDelta.v() == delta.v()) {
+ addDelta.u() = delta.u();
+ } else {
+ addDelta.u() = delta.u() * addDelta.v();
+ addDelta.u() += (addDelta.u() > 0) ? (delta.v() / 2) : (-delta.v() / 2);
+ addDelta.u() /= delta.v();
+ }
+ } else {
+ addDelta.u() = clamp(-speed, delta.u(), speed);
+ if (addDelta.u() == delta.u()) {
+ addDelta.v() = delta.v();
+ } else {
+ addDelta.v() = delta.v() * addDelta.u();
+ addDelta.v() += (addDelta.v() > 0) ? (delta.u() / 2) : (-delta.u() / 2);
+ addDelta.v() /= delta.u();
+ }
+ }
+
+ actor->_location.add(addDelta);
+ } else {
+ actor->_partialTarget.delta(actor->_location, delta);
+
+ while ((delta.x == 0) && (delta.y == 0)) {
+
+ if (actor->_walkStepIndex >= actor->_walkStepsCount) {
+ actorEndWalk(actor->_id, true);
+ break;
+ }
+
+ actor->_partialTarget.fromScreenPoint(actor->_walkStepsPoints[actor->_walkStepIndex++]);
+ if (_vm->getGameType() == GType_ITE) {
+ if (actor->_partialTarget.x > 224 * 2 * ACTOR_LMULT) {
+ actor->_partialTarget.x -= 256 * 2 * ACTOR_LMULT;
+ }
+ } else {
+ if (actor->_partialTarget.x > 224 * 4 * ACTOR_LMULT) {
+ actor->_partialTarget.x -= 256 * 4 * ACTOR_LMULT;
+ }
+ }
+
+ actor->_partialTarget.delta(actor->_location, delta);
+
+ if (ABS(delta.y) > ABS(delta.x)) {
+ actor->_actionDirection = delta.y > 0 ? kDirDown : kDirUp;
+ } else {
+ actor->_actionDirection = delta.x > 0 ? kDirRight : kDirLeft;
+ }
+ }
+
+ if(_vm->getGameType() == GType_ITE)
+ speed = (ACTOR_LMULT * 2 * actor->_screenScale + 63) / 256;
+ else
+ speed = (ACTOR_SPEED * actor->_screenScale + 128) >> 8;
+
+ if (speed < 1)
+ speed = 1;
+
+ if(_vm->getGameType() == GType_IHNM)
+ speed = speed / 2;
+
+ if ((actor->_actionDirection == kDirUp) || (actor->_actionDirection == kDirDown)) {
+ addDelta.y = clamp(-speed, delta.y, speed);
+ if (addDelta.y == delta.y) {
+ addDelta.x = delta.x;
+ } else {
+ addDelta.x = delta.x * addDelta.y;
+ addDelta.x += (addDelta.x > 0) ? (delta.y / 2) : (-delta.y / 2);
+ addDelta.x /= delta.y;
+ actor->_facingDirection = actor->_actionDirection;
+ }
+ } else {
+ addDelta.x = clamp(-2 * speed, delta.x, 2 * speed);
+ if (addDelta.x == delta.x) {
+ addDelta.y = delta.y;
+ } else {
+ addDelta.y = delta.y * addDelta.x;
+ addDelta.y += (addDelta.y > 0) ? (delta.x / 2) : (-delta.x / 2);
+ addDelta.y /= delta.x;
+ actor->_facingDirection = actor->_actionDirection;
+ }
+ }
+
+ actor->_location.add(addDelta);
+ }
+
+ if (actor->_actorFlags & kActorBackwards) {
+ actor->_facingDirection = (actor->_actionDirection + 4) & 7;
+ actor->_actionCycle--;
+ } else {
+ actor->_actionCycle++;
+ }
+
+ frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
+
+ if (actor->_actionCycle < 0) {
+ actor->_actionCycle = frameRange->frameCount - 1;
+ } else if (actor->_actionCycle >= frameRange->frameCount) {
+ actor->_actionCycle = 0;
+ }
+
+ actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
+ break;
+
+ case kActionWalkDir:
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ actor->_location.u() += tileDirectionLUT[actor->_actionDirection][0];
+ actor->_location.v() += tileDirectionLUT[actor->_actionDirection][1];
+
+ frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
+
+ actor->_actionCycle++;
+ actor->cycleWrap(frameRange->frameCount);
+ actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
+ } else {
+ if (_vm->getGameType() == GType_ITE) {
+ actor->_location.x += directionLUT[actor->_actionDirection][0] * 2;
+ actor->_location.y += directionLUT[actor->_actionDirection][1] * 2;
+ } else {
+ // FIXME: The original does not multiply by 8 here, but we do
+ actor->_location.x += (directionLUT[actor->_actionDirection][0] * 8 * actor->_screenScale + 128) >> 8;
+ actor->_location.y += (directionLUT[actor->_actionDirection][1] * 8 * actor->_screenScale + 128) >> 8;
+ }
+
+ frameRange = getActorFrameRange(actor->_id, actor->_walkFrameSequence);
+ actor->_actionCycle++;
+ actor->cycleWrap(frameRange->frameCount);
+ actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
+ }
+ break;
+
+ case kActionSpeak:
+ actor->_actionCycle++;
+ actor->cycleWrap(64);
+
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameGesture));
+ if (actor->_actionCycle >= frameRange->frameCount) {
+ if (actor->_actionCycle & 1)
+ break;
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameSpeak));
+
+ state = (uint16)_vm->_rnd.getRandomNumber(frameRange->frameCount);
+
+ if (state == 0) {
+ frameRange = getActorFrameRange(actor->_id, getFrameType(kFrameStand));
+ } else {
+ state--;
+ }
+ } else {
+ state = actor->_actionCycle;
+ }
+
+ actor->_frameNumber = frameRange->frameIndex + state;
+ break;
+
+ case kActionAccept:
+ case kActionStoop:
+ break;
+
+ case kActionCycleFrames:
+ case kActionPongFrames:
+ if (actor->_cycleTimeCount > 0) {
+ actor->_cycleTimeCount--;
+ break;
+ }
+
+ actor->_cycleTimeCount = actor->_cycleDelay;
+ actor->_actionCycle++;
+
+ frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence);
+
+ if (actor->_currentAction == kActionPongFrames) {
+ if (actor->_actionCycle >= frameRange->frameCount * 2 - 2) {
+ if (actor->_actorFlags & kActorContinuous) {
+ actor->_actionCycle = 0;
+ } else {
+ actor->_currentAction = kActionFreeze;
+ break;
+ }
+ }
+
+ state = actor->_actionCycle;
+ if (state >= frameRange->frameCount) {
+ state = frameRange->frameCount * 2 - 2 - state;
+ }
+ } else {
+ if (actor->_actionCycle >= frameRange->frameCount) {
+ if (actor->_actorFlags & kActorContinuous) {
+ actor->_actionCycle = 0;
+ } else {
+ actor->_currentAction = kActionFreeze;
+ break;
+ }
+ }
+ state = actor->_actionCycle;
+ }
+
+ if (frameRange->frameCount && (actor->_actorFlags & kActorRandom)) {
+ state = _vm->_rnd.getRandomNumber(frameRange->frameCount - 1);
+ }
+
+ if (actor->_actorFlags & kActorBackwards) {
+ actor->_frameNumber = frameRange->frameIndex + frameRange->frameCount - 1 - state;
+ } else {
+ actor->_frameNumber = frameRange->frameIndex + state;
+ }
+ break;
+
+ case kActionFall:
+ if (actor->_actionCycle > 0) {
+ framesLeft = actor->_actionCycle--;
+ actor->_finalTarget.delta(actor->_location, delta);
+ delta.x /= framesLeft;
+ delta.y /= framesLeft;
+ actor->_location.addXY(delta);
+ actor->_fallVelocity += actor->_fallAcceleration;
+ actor->_fallPosition += actor->_fallVelocity;
+ actor->_location.z = actor->_fallPosition >> 4;
+ } else {
+ actor->_location = actor->_finalTarget;
+ actor->_currentAction = kActionFreeze;
+ _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
+ }
+ break;
+
+ case kActionClimb:
+ actor->_cycleDelay++;
+ if (actor->_cycleDelay & 3) {
+ break;
+ }
+
+ if (actor->_location.z >= actor->_finalTarget.z + ACTOR_CLIMB_SPEED) {
+ actor->_location.z -= ACTOR_CLIMB_SPEED;
+ actor->_actionCycle--;
+ } else if (actor->_location.z <= actor->_finalTarget.z - ACTOR_CLIMB_SPEED) {
+ actor->_location.z += ACTOR_CLIMB_SPEED;
+ actor->_actionCycle++;
+ } else {
+ actor->_location.z = actor->_finalTarget.z;
+ actor->_currentAction = kActionFreeze;
+ _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
+ }
+
+ frameRange = getActorFrameRange(actor->_id, actor->_cycleFrameSequence);
+
+ if (actor->_actionCycle < 0) {
+ actor->_actionCycle = frameRange->frameCount - 1;
+ }
+ actor->cycleWrap(frameRange->frameCount);
+ actor->_frameNumber = frameRange->frameIndex + actor->_actionCycle;
+ break;
+ }
+
+ if ((actor->_currentAction >= kActionWalkToPoint) && (actor->_currentAction <= kActionWalkDir)) {
+ hitZone = NULL;
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ actor->_location.toScreenPointUV(hitPoint);
+ } else {
+ actor->_location.toScreenPointXY(hitPoint);
+ }
+ hitZoneIndex = _vm->_scene->_actionMap->hitTest(hitPoint);
+ if (hitZoneIndex != -1) {
+ hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex);
+ }
+
+ if (hitZone != actor->_lastZone) {
+ if (actor->_lastZone)
+ stepZoneAction(actor, actor->_lastZone, true, false);
+ actor->_lastZone = hitZone;
+ // WORKAROUND for graphics glitch in the rat caves. Don't do this step zone action in the rat caves
+ // (room 51) for hitzone 24577 (the door with the copy protection) to avoid the glitch. This glitch
+ // happens because the copy protection is supposed to kick in at this point, but it's bypassed
+ // (with permission from Wyrmkeep Entertainment)
+ if (hitZone &&
+ !(_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 51 && hitZone->getHitZoneId() == 24577))
+ stepZoneAction(actor, hitZone, false, false);
+ }
+ }
+ }
+ // Update frameCount for sfWaitFrames in IHNM
+ _vm->_frameCount++;
+}
+
+void Actor::direct(int msec) {
+
+ if (_vm->_scene->_entryList.entryListCount == 0) {
+ return;
+ }
+
+ if (_vm->_interface->_statusTextInput) {
+ return;
+ }
+
+ // FIXME: HACK. This should be turned into cycle event.
+ _lastTickMsec += msec;
+
+ if (_lastTickMsec > 1000 / _handleActionDiv) {
+ _lastTickMsec = 0;
+ //process actions
+ handleActions(msec, false);
+ }
+
+//process speech
+ handleSpeech(msec);
+}
+
+bool Actor::followProtagonist(ActorData *actor) {
+ Location protagonistLocation;
+ Location newLocation;
+ Location delta;
+ int protagonistBGMaskType;
+ Point prefer1;
+ Point prefer2;
+ Point prefer3;
+ int16 prefU;
+ int16 prefV;
+ int16 newU;
+ int16 newV;
+
+ assert(_protagonist);
+
+ actor->_flags &= ~(kFaster | kFastest);
+ protagonistLocation = _protagonist->_location;
+ calcScreenPosition(_protagonist);
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+ prefU = 60;
+ prefV = 60;
+
+
+ actor->_location.delta(protagonistLocation, delta);
+
+ if (actor->_id == actorIndexToId(2)) {
+ prefU = prefV = 48;
+ }
+
+ if ((delta.u() > prefU) || (delta.u() < -prefU) || (delta.v() > prefV) || (delta.v() < -prefV)) {
+
+ if ((delta.u() > prefU * 2) || (delta.u() < -prefU * 2) || (delta.v() > prefV * 2) || (delta.v() < -prefV * 2)) {
+ actor->_flags |= kFaster;
+
+ if ((delta.u() > prefU * 3) || (delta.u() < -prefU*3) || (delta.v() > prefV * 3) || (delta.v() < -prefV * 3)) {
+ actor->_flags |= kFastest;
+ }
+ }
+
+ prefU /= 2;
+ prefV /= 2;
+
+ newU = clamp(-prefU, delta.u(), prefU) + protagonistLocation.u();
+ newV = clamp(-prefV, delta.v(), prefV) + protagonistLocation.v();
+
+ newLocation.u() = newU + _vm->_rnd.getRandomNumber(prefU - 1) - prefU / 2;
+ newLocation.v() = newV + _vm->_rnd.getRandomNumber(prefV - 1) - prefV / 2;
+ newLocation.z = 0;
+
+ return actorWalkTo(actor->_id, newLocation);
+ }
+
+ } else {
+ prefer1.x = (100 * _protagonist->_screenScale) >> 8;
+ prefer1.y = (50 * _protagonist->_screenScale) >> 8;
+
+ if (_protagonist->_currentAction == kActionWalkDir) {
+ prefer1.x /= 2;
+ }
+
+ if (prefer1.x < 8) {
+ prefer1.x = 8;
+ }
+
+ if (prefer1.y < 8) {
+ prefer1.y = 8;
+ }
+
+ prefer2.x = prefer1.x * 2;
+ prefer2.y = prefer1.y * 2;
+ prefer3.x = prefer1.x + prefer1.x / 2;
+ prefer3.y = prefer1.y + prefer1.y / 2;
+
+ actor->_location.delta(protagonistLocation, delta);
+
+ protagonistBGMaskType = 0;
+ if (_vm->_scene->isBGMaskPresent() && _vm->_scene->validBGMaskPoint(_protagonist->_screenPosition)) {
+ protagonistBGMaskType = _vm->_scene->getBGMaskType(_protagonist->_screenPosition);
+ }
+
+ if ((_vm->_rnd.getRandomNumber(7) & 0x7) == 0) // 1/8th chance
+ actor->_actorFlags &= ~kActorNoFollow;
+
+ if (actor->_actorFlags & kActorNoFollow) {
+ return false;
+ }
+
+ if ((delta.x > prefer2.x) || (delta.x < -prefer2.x) ||
+ (delta.y > prefer2.y) || (delta.y < -prefer2.y) ||
+ ((_protagonist->_currentAction == kActionWait) &&
+ (delta.x * 2 < prefer1.x) && (delta.x * 2 > -prefer1.x) &&
+ (delta.y < prefer1.y) && (delta.y > -prefer1.y))) {
+
+ if (ABS(delta.x) > ABS(delta.y)) {
+
+ delta.x = (delta.x > 0) ? prefer3.x : -prefer3.x;
+
+ newLocation.x = delta.x + protagonistLocation.x;
+ newLocation.y = clamp(-prefer2.y, delta.y, prefer2.y) + protagonistLocation.y;
+ } else {
+ delta.y = (delta.y > 0) ? prefer3.y : -prefer3.y;
+
+ newLocation.x = clamp(-prefer2.x, delta.x, prefer2.x) + protagonistLocation.x;
+ newLocation.y = delta.y + protagonistLocation.y;
+ }
+ newLocation.z = 0;
+
+ if (protagonistBGMaskType != 3) {
+ newLocation.x += _vm->_rnd.getRandomNumber(prefer1.x - 1) - prefer1.x / 2;
+ newLocation.y += _vm->_rnd.getRandomNumber(prefer1.y - 1) - prefer1.y / 2;
+ }
+
+ newLocation.x = clamp(-31 * 4, newLocation.x, (_vm->getDisplayWidth() + 31) * 4);
+
+ return actorWalkTo(actor->_id, newLocation);
+ }
+ }
+ return false;
+}
+
+bool Actor::actorWalkTo(uint16 actorId, const Location &toLocation) {
+ ActorData *actor;
+ ActorData *anotherActor;
+ int i;
+
+ Rect testBox;
+ Rect testBox2;
+ Point anotherActorScreenPosition;
+ Point collision;
+ Point pointFrom, pointTo, pointBest, pointAdd;
+ Point delta, bestDelta;
+ Point tempPoint;
+ bool extraStartNode;
+ bool extraEndNode;
+
+ actor = getActor(actorId);
+
+ if (actor == _protagonist) {
+ _vm->_scene->setDoorState(2, 0xff);
+ _vm->_scene->setDoorState(3, 0);
+ } else {
+ _vm->_scene->setDoorState(2, 0);
+ _vm->_scene->setDoorState(3, 0xff);
+ }
+
+ if (_vm->_scene->getFlags() & kSceneFlagISO) {
+
+ if ((_vm->getGameType() == GType_ITE) && (actor->_index == ACTOR_DRAGON_INDEX)) {
+ return false;
+ }
+
+ actor->_finalTarget = toLocation;
+ actor->_walkStepsCount = 0;
+ _vm->_isoMap->findTilePath(actor, actor->_location, toLocation);
+
+
+ if ((actor->_walkStepsCount == 0) && (actor->_flags & kProtagonist)) {
+ actor->_actorFlags |= kActorNoCollide;
+ _vm->_isoMap->findTilePath(actor, actor->_location, toLocation);
+ }
+
+ actor->_walkStepIndex = 0;
+ if (_vm->_isoMap->nextTileTarget(actor)) {
+ actor->_currentAction = kActionWalkToPoint;
+ actor->_walkFrameSequence = getFrameType(kFrameWalk);
+ } else {
+ actorEndWalk(actorId, false);
+ return false;
+ }
+ } else {
+
+ actor->_location.toScreenPointXY(pointFrom);
+ pointFrom.x &= ~1;
+
+ extraStartNode = _vm->_scene->offscreenPath(pointFrom);
+
+ toLocation.toScreenPointXY(pointTo);
+ pointTo.x &= ~1;
+
+ extraEndNode = _vm->_scene->offscreenPath(pointTo);
+
+ if (_vm->_scene->isBGMaskPresent()) {
+
+ if ((((actor->_currentAction >= kActionWalkToPoint) &&
+ (actor->_currentAction <= kActionWalkDir)) || (actor == _protagonist)) &&
+ !_vm->_scene->canWalk(pointFrom)) {
+
+ int max = _vm->getGameType() == GType_ITE ? 8 : 4;
+
+ for (i = 1; i < max; i++) {
+ pointAdd = pointFrom;
+ pointAdd.y += i;
+ if (_vm->_scene->canWalk(pointAdd)) {
+ pointFrom = pointAdd;
+ break;
+ }
+ pointAdd = pointFrom;
+ pointAdd.y -= i;
+ if (_vm->_scene->canWalk(pointAdd)) {
+ pointFrom = pointAdd;
+ break;
+ }
+ if (_vm->getGameType() == GType_ITE) {
+ pointAdd = pointFrom;
+ pointAdd.x += i;
+ if (_vm->_scene->canWalk(pointAdd)) {
+ pointFrom = pointAdd;
+ break;
+ }
+ pointAdd = pointFrom;
+ pointAdd.x -= i;
+ if (_vm->_scene->canWalk(pointAdd)) {
+ pointFrom = pointAdd;
+ break;
+ }
+ }
+ }
+ }
+
+ _barrierCount = 0;
+ if (!(actor->_actorFlags & kActorNoCollide)) {
+ collision.x = ACTOR_COLLISION_WIDTH * actor->_screenScale / (256 * 2);
+ collision.y = ACTOR_COLLISION_HEIGHT * actor->_screenScale / (256 * 2);
+
+
+ for (i = 0; (i < _actorsCount) && (_barrierCount < ACTOR_BARRIERS_MAX); i++) {
+ anotherActor = _actors[i];
+ if (!anotherActor->_inScene)
+ continue;
+ if (anotherActor == actor)
+ continue;
+
+ anotherActorScreenPosition = anotherActor->_screenPosition;
+ testBox.left = (anotherActorScreenPosition.x - collision.x) & ~1;
+ testBox.right = (anotherActorScreenPosition.x + collision.x) & ~1 + 1;
+ testBox.top = anotherActorScreenPosition.y - collision.y;
+ testBox.bottom = anotherActorScreenPosition.y + collision.y + 1;
+ testBox2 = testBox;
+ testBox2.right += 2;
+ testBox2.left -= 2;
+ testBox2.top -= 1;
+ testBox2.bottom += 1;
+
+ if (testBox2.contains(pointFrom)) {
+ if (pointFrom.x > anotherActorScreenPosition.x + 4) {
+ testBox.right = pointFrom.x - 1;
+ } else if (pointFrom.x < anotherActorScreenPosition.x - 4) {
+ testBox.left = pointFrom.x + 2;
+ } else if (pointFrom.y > anotherActorScreenPosition.y) {
+ testBox.bottom = pointFrom.y;
+ } else {
+ testBox.top = pointFrom.y + 1 ;
+ }
+ }
+
+ if ((testBox.width() > 0) && (testBox.height() > 0)) {
+ _barrierList[_barrierCount++] = testBox;
+ }
+ }
+ }
+
+
+ pointBest = pointTo;
+ actor->_walkStepsCount = 0;
+ findActorPath(actor, pointFrom, pointTo);
+
+ if (actor->_walkStepsCount == 0) {
+ error("actor->_walkStepsCount == 0");
+ }
+
+ if (extraStartNode) {
+ actor->_walkStepIndex = 0;
+ } else {
+ actor->_walkStepIndex = 1;
+ }
+
+ if (extraEndNode) {
+ toLocation.toScreenPointXY(tempPoint);
+ actor->_walkStepsCount--;
+ actor->addWalkStepPoint(tempPoint);
+ }
+
+
+ pointBest = actor->_walkStepsPoints[actor->_walkStepsCount - 1];
+
+ pointBest.x &= ~1;
+ delta.x = ABS(pointFrom.x - pointTo.x);
+ delta.y = ABS(pointFrom.y - pointTo.y);
+
+ bestDelta.x = ABS(pointBest.x - pointTo.x);
+ bestDelta.y = ABS(pointBest.y - pointTo.y);
+
+ if ((delta.x + delta.y <= bestDelta.x + bestDelta.y) && (actor->_flags & kFollower)) {
+ actor->_actorFlags |= kActorNoFollow;
+ }
+
+ if (pointBest == pointFrom) {
+ actor->_walkStepsCount = 0;
+ }
+ } else {
+ actor->_walkStepsCount = 0;
+ actor->addWalkStepPoint(pointTo);
+ actor->_walkStepIndex = 0;
+ }
+
+ actor->_partialTarget = actor->_location;
+ actor->_finalTarget = toLocation;
+ if (actor->_walkStepsCount == 0) {
+ actorEndWalk(actorId, false);
+ return false;
+ } else {
+ if (actor->_flags & kProtagonist) {
+ _actors[1]->_actorFlags &= ~kActorNoFollow; // TODO: mark all actors with kFollower flag, not only 1 and 2
+ _actors[2]->_actorFlags &= ~kActorNoFollow;
+ }
+ actor->_currentAction = (actor->_walkStepsCount >= ACTOR_MAX_STEPS_COUNT) ? kActionWalkToLink : kActionWalkToPoint;
+ actor->_walkFrameSequence = getFrameType(kFrameWalk);
+ }
+ }
+ return true;
+}
+
+bool Actor::actorEndWalk(uint16 actorId, bool recurse) {
+ bool walkMore = false;
+ ActorData *actor;
+ const HitZone *hitZone;
+ int hitZoneIndex;
+ Point testPoint;
+
+ actor = getActor(actorId);
+ actor->_actorFlags &= ~kActorBackwards;
+
+ if (_vm->getGameType() == GType_ITE) {
+
+ if (actor->_location.distance(actor->_finalTarget) > 8 && (actor->_flags & kProtagonist) && recurse && !(actor->_actorFlags & kActorNoCollide)) {
+ actor->_actorFlags |= kActorNoCollide;
+ return actorWalkTo(actorId, actor->_finalTarget);
+ }
+ }
+
+ actor->_currentAction = kActionWait;
+ if (actor->_actorFlags & kActorFinalFace) {
+ actor->_facingDirection = actor->_actionDirection = (actor->_actorFlags >> 6) & 0x07; //?
+ }
+
+ actor->_actorFlags &= ~(kActorNoCollide | kActorCollided | kActorFinalFace | kActorFacingMask);
+ actor->_flags &= ~(kFaster | kFastest);
+
+ if (actor == _protagonist) {
+ _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
+ if (_vm->_script->_pendingVerb == _vm->_script->getVerbType(kVerbWalkTo)) {
+ if (_vm->getGameType() == GType_ITE)
+ actor->_location.toScreenPointUV(testPoint); // it's wrong calculation, but it is used in ITE
+ else
+ actor->_location.toScreenPointXY(testPoint);
+
+ hitZoneIndex = _vm->_scene->_actionMap->hitTest(testPoint);
+ if (hitZoneIndex != -1) {
+ hitZone = _vm->_scene->_actionMap->getHitZone(hitZoneIndex);
+ stepZoneAction(actor, hitZone, false, true);
+ } else {
+ _vm->_script->setNoPendingVerb();
+ }
+ } else if (_vm->_script->_pendingVerb != _vm->_script->getVerbType(kVerbNone)) {
+ _vm->_script->doVerb();
+ }
+ } else {
+ if (recurse && (actor->_flags & kFollower))
+ walkMore = followProtagonist(actor);
+
+ _vm->_script->wakeUpActorThread(kWaitTypeWalk, actor);
+ }
+ return walkMore;
+}
+
+void Actor::moveDragon(ActorData *actor) {
+ int16 dir0, dir1, dir2, dir3;
+ int16 moveType;
+ Event event;
+ const DragonMove *dragonMove;
+
+ if ((actor->_actionCycle < 0) ||
+ ((actor->_actionCycle == 0) && (actor->_dragonMoveType >= ACTOR_DRAGON_TURN_MOVES))) {
+
+ moveType = kDragonMoveInvalid;
+ if (actor->_location.distance(_protagonist->_location) < 24) {
+ if (_dragonHunt && (_protagonist->_currentAction != kActionFall)) {
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventExecNonBlocking;
+ event.time = 0;
+ event.param = _vm->_scene->getScriptModuleNumber(); // module number
+ event.param2 = ACTOR_EXP_KNOCK_RIF; // script entry point number
+ event.param3 = -1; // Action
+ event.param4 = -1; // Object
+ event.param5 = -1; // With Object
+ event.param6 = -1; // Actor
+ _vm->_events->queue(&event);
+
+ _dragonHunt = false;
+ }
+ } else {
+ _dragonHunt = true;
+ }
+
+ if (actor->_walkStepIndex + 2 > actor->_walkStepsCount) {
+
+ _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, actor->_actionDirection);
+
+ if (actor->_walkStepsCount == 0) {
+ _vm->_isoMap->findDragonTilePath(actor, actor->_location, _protagonist->_location, 0);
+ }
+
+ if (actor->_walkStepsCount < 2) {
+ return;
+ }
+
+ actor->_partialTarget = actor->_location;
+ actor->_finalTarget = _protagonist->_location;
+ actor->_walkStepIndex = 0;
+ }
+
+ dir0 = actor->_actionDirection;
+ dir1 = actor->_tileDirections[actor->_walkStepIndex++];
+ dir2 = actor->_tileDirections[actor->_walkStepIndex];
+ dir3 = actor->_tileDirections[actor->_walkStepIndex + 1];
+
+ if (dir0 != dir1){
+ actor->_actionDirection = dir0 = dir1;
+ }
+
+ actor->_location = actor->_partialTarget;
+
+ if ((dir1 != dir2) && (dir1 == dir3)) {
+ switch (dir1) {
+ case kDirUpLeft:
+ actor->_partialTarget.v() += 16;
+ moveType = kDragonMoveUpLeft;
+ break;
+ case kDirDownLeft:
+ actor->_partialTarget.u() -= 16;
+ moveType = kDragonMoveDownLeft;
+ break;
+ case kDirDownRight:
+ actor->_partialTarget.v() -= 16;
+ moveType = kDragonMoveDownRight;
+ break;
+ case kDirUpRight:
+ actor->_partialTarget.u() += 16;
+ moveType = kDragonMoveUpRight;
+ break;
+ }
+
+ switch (dir2) {
+ case kDirUpLeft:
+ actor->_partialTarget.v() += 16;
+ break;
+ case kDirDownLeft:
+ actor->_partialTarget.u() -= 16;
+ break;
+ case kDirDownRight:
+ actor->_partialTarget.v() -= 16;
+ break;
+ case kDirUpRight:
+ actor->_partialTarget.u() += 16;
+ break;
+ }
+
+ actor->_walkStepIndex++;
+ } else {
+ switch (dir1) {
+ case kDirUpLeft:
+ actor->_partialTarget.v() += 16;
+ switch (dir2) {
+ case kDirDownLeft:
+ moveType = kDragonMoveUpLeft_Left;
+ actor->_partialTarget.u() -= 16;
+ break;
+ case kDirUpLeft:
+ moveType = kDragonMoveUpLeft;
+ break;
+ case kDirUpRight:
+ actor->_partialTarget.u() += 16;
+ moveType = kDragonMoveUpLeft_Right;
+ break;
+ default:
+ actor->_actionDirection = dir1;
+ actor->_walkStepsCount = 0;
+ break;
+ }
+ break;
+ case kDirDownLeft:
+ actor->_partialTarget.u() -= 16;
+ switch (dir2) {
+ case kDirDownRight:
+ moveType = kDragonMoveDownLeft_Left;
+ actor->_partialTarget.v() -= 16;
+ break;
+ case kDirDownLeft:
+ moveType = kDragonMoveDownLeft;
+ break;
+ case kDirUpLeft:
+ moveType = kDragonMoveDownLeft_Right;
+ actor->_partialTarget.v() += 16;
+ break;
+ default:
+ actor->_actionDirection = dir1;
+ actor->_walkStepsCount = 0;
+ break;
+ }
+ break;
+ case kDirDownRight:
+ actor->_partialTarget.v() -= 16;
+ switch (dir2) {
+ case kDirUpRight:
+ moveType = kDragonMoveDownRight_Left;
+ actor->_partialTarget.u() += 16;
+ break;
+ case kDirDownRight:
+ moveType = kDragonMoveDownRight;
+ break;
+ case kDirDownLeft:
+ moveType = kDragonMoveDownRight_Right;
+ actor->_partialTarget.u() -= 16;
+ break;
+ default:
+ actor->_actionDirection = dir1;
+ actor->_walkStepsCount = 0;
+ break;
+ }
+ break;
+ case kDirUpRight:
+ actor->_partialTarget.u() += 16;
+ switch (dir2) {
+ case kDirUpLeft:
+ moveType = kDragonMoveUpRight_Left;
+ actor->_partialTarget.v() += 16;
+ break;
+ case kDirUpRight:
+ moveType = kDragonMoveUpRight;
+ break;
+ case kDirDownRight:
+ moveType = kDragonMoveUpRight_Right;
+ actor->_partialTarget.v() -= 16;
+ break;
+ default:
+ actor->_actionDirection = dir1;
+ actor->_walkStepsCount = 0;
+ break;
+ }
+ break;
+
+ default:
+ actor->_actionDirection = dir1;
+ actor->_walkStepsCount = 0;
+ break;
+ }
+ }
+
+ actor->_dragonMoveType = moveType;
+
+ if (moveType >= ACTOR_DRAGON_TURN_MOVES) {
+ actor->_dragonStepCycle = 0;
+ actor->_actionCycle = 4;
+ actor->_walkStepIndex++;
+ } else {
+ actor->_actionCycle = 4;
+ }
+ }
+
+ actor->_actionCycle--;
+
+ if ((actor->_walkStepsCount < 1) || (actor->_actionCycle < 0)) {
+ return;
+ }
+
+ if (actor->_dragonMoveType < ACTOR_DRAGON_TURN_MOVES) {
+
+ actor->_dragonStepCycle++;
+ if (actor->_dragonStepCycle >= 7) {
+ actor->_dragonStepCycle = 0;
+ }
+
+ actor->_dragonBaseFrame = actor->_dragonMoveType * 7;
+
+ if (actor->_location.u() > actor->_partialTarget.u() + 3) {
+ actor->_location.u() -= 4;
+ } else if (actor->_location.u() < actor->_partialTarget.u() - 3) {
+ actor->_location.u() += 4;
+ } else {
+ actor->_location.u() = actor->_partialTarget.u();
+ }
+
+ if (actor->_location.v() > actor->_partialTarget.v() + 3) {
+ actor->_location.v() -= 4;
+ } else if (actor->_location.v() < actor->_partialTarget.v() - 3) {
+ actor->_location.v() += 4;
+ } else {
+ actor->_location.v() = actor->_partialTarget.v();
+ }
+ } else {
+ dragonMove = &dragonMoveTable[actor->_dragonMoveType];
+ actor->_dragonBaseFrame = dragonMove->baseFrame;
+
+
+ actor->_location.u() = actor->_partialTarget.u() - dragonMove->offset[actor->_actionCycle][0];
+ actor->_location.v() = actor->_partialTarget.v() - dragonMove->offset[actor->_actionCycle][1];
+
+ actor->_dragonStepCycle++;
+ if (actor->_dragonStepCycle >= 3) {
+ actor->_dragonStepCycle = 3;
+ }
+ }
+
+ actor->_frameNumber = actor->_dragonBaseFrame + actor->_dragonStepCycle;
+}
+
+void Actor::findActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) {
+ Point iteratorPoint;
+ Point bestPoint;
+ int maskType;
+ int i;
+ Rect intersect;
+
+#ifdef ACTOR_DEBUG
+ _debugPointsCount = 0;
+#endif
+
+ actor->_walkStepsCount = 0;
+ if (fromPoint == toPoint) {
+ actor->addWalkStepPoint(toPoint);
+ return;
+ }
+
+ for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) {
+ for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) {
+ if (_vm->_scene->validBGMaskPoint(iteratorPoint)) {
+ maskType = _vm->_scene->getBGMaskType(iteratorPoint);
+ setPathCell(iteratorPoint, _vm->_scene->getDoorState(maskType) ? kPathCellBarrier : kPathCellEmpty);
+ } else {
+ setPathCell(iteratorPoint, kPathCellBarrier);
+ }
+ }
+ }
+
+ for (i = 0; i < _barrierCount; i++) {
+ intersect.left = MAX(_pathRect.left, _barrierList[i].left);
+ intersect.top = MAX(_pathRect.top, _barrierList[i].top);
+ intersect.right = MIN(_pathRect.right, _barrierList[i].right);
+ intersect.bottom = MIN(_pathRect.bottom, _barrierList[i].bottom);
+
+ for (iteratorPoint.y = intersect.top; iteratorPoint.y < intersect.bottom; iteratorPoint.y++) {
+ for (iteratorPoint.x = intersect.left; iteratorPoint.x < intersect.right; iteratorPoint.x++) {
+ setPathCell(iteratorPoint, kPathCellBarrier);
+ }
+ }
+ }
+
+#ifdef ACTOR_DEBUG
+ for (iteratorPoint.y = 0; iteratorPoint.y < _yCellCount; iteratorPoint.y++) {
+ for (iteratorPoint.x = 0; iteratorPoint.x < _xCellCount; iteratorPoint.x++) {
+ if (getPathCell(iteratorPoint) == kPathCellBarrier) {
+ addDebugPoint(iteratorPoint, 24);
+ }
+ }
+ }
+#endif
+
+ if (scanPathLine(fromPoint, toPoint)) {
+ actor->addWalkStepPoint(fromPoint);
+ actor->addWalkStepPoint(toPoint);
+ return;
+ }
+
+ i = fillPathArray(fromPoint, toPoint, bestPoint);
+
+ if (fromPoint == bestPoint) {
+ actor->addWalkStepPoint(bestPoint);
+ return;
+ }
+
+ if (i == 0) {
+ error("fillPathArray returns zero");
+ }
+
+ setActorPath(actor, fromPoint, bestPoint);
+}
+
+bool Actor::scanPathLine(const Point &point1, const Point &point2) {
+ Point point;
+ Point delta;
+ Point s;
+ Point fDelta;
+ int16 errterm;
+
+ calcDeltaS(point1, point2, delta, s);
+ point = point1;
+
+ fDelta.x = delta.x * 2;
+ fDelta.y = delta.y * 2;
+
+ if (delta.y > delta.x) {
+
+ errterm = fDelta.x - delta.y;
+
+ while (delta.y > 0) {
+ while (errterm >= 0) {
+ point.x += s.x;
+ errterm -= fDelta.y;
+ }
+
+ point.y += s.y;
+ errterm += fDelta.x;
+
+ if (!validPathCellPoint(point)) {
+ return false;
+ }
+ if (getPathCell(point) == kPathCellBarrier) {
+ return false;
+ }
+ delta.y--;
+ }
+ } else {
+
+ errterm = fDelta.y - delta.x;
+
+ while (delta.x > 0) {
+ while (errterm >= 0) {
+ point.y += s.y;
+ errterm -= fDelta.x;
+ }
+
+ point.x += s.x;
+ errterm += fDelta.y;
+
+ if (!validPathCellPoint(point)) {
+ return false;
+ }
+ if (getPathCell(point) == kPathCellBarrier) {
+ return false;
+ }
+ delta.x--;
+ }
+ }
+ return true;
+}
+
+int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) {
+ int bestRating;
+ int currentRating;
+ int i;
+ Point bestPath;
+ int pointCounter;
+ int startDirection;
+ PathDirectionData *pathDirection;
+ PathDirectionData *newPathDirection;
+ const PathDirectionData *samplePathDirection;
+ Point nextPoint;
+ int directionCount;
+ int16 compressX = (_vm->getGameType() == GType_ITE) ? 2 : 1;
+
+ _pathDirectionListCount = 0;
+ pointCounter = 0;
+ bestRating = quickDistance(fromPoint, toPoint, compressX);
+ bestPath = fromPoint;
+
+ for (startDirection = 0; startDirection < 4; startDirection++) {
+ newPathDirection = addPathDirectionListData();
+ newPathDirection->coord = fromPoint;
+ newPathDirection->direction = startDirection;
+ }
+
+ if (validPathCellPoint(fromPoint)) {
+ setPathCell(fromPoint, kDirUp);
+
+#ifdef ACTOR_DEBUG
+ addDebugPoint(fromPoint, 24+36);
+#endif
+ }
+
+ i = 0;
+
+ do {
+ pathDirection = &_pathDirectionList[i];
+ for (directionCount = 0; directionCount < 3; directionCount++) {
+ samplePathDirection = &pathDirectionLUT[pathDirection->direction][directionCount];
+ nextPoint = pathDirection->coord;
+ nextPoint.x += samplePathDirection->coord.x;
+ nextPoint.y += samplePathDirection->coord.y;
+
+ if (!validPathCellPoint(nextPoint)) {
+ continue;
+ }
+
+ if (getPathCell(nextPoint) != kPathCellEmpty) {
+ continue;
+ }
+
+ setPathCell(nextPoint, samplePathDirection->direction);
+
+#ifdef ACTOR_DEBUG
+ addDebugPoint(nextPoint, samplePathDirection->direction + 96);
+#endif
+ newPathDirection = addPathDirectionListData();
+ newPathDirection->coord = nextPoint;
+ newPathDirection->direction = samplePathDirection->direction;
+ ++pointCounter;
+ if (nextPoint == toPoint) {
+ bestPoint = toPoint;
+ return pointCounter;
+ }
+ currentRating = quickDistance(nextPoint, toPoint, compressX);
+ if (currentRating < bestRating) {
+ bestRating = currentRating;
+ bestPath = nextPoint;
+ }
+ pathDirection = &_pathDirectionList[i];
+ }
+ ++i;
+ } while (i < _pathDirectionListCount);
+
+ bestPoint = bestPath;
+ return pointCounter;
+}
+
+void Actor::setActorPath(ActorData *actor, const Point &fromPoint, const Point &toPoint) {
+ Point nextPoint;
+ int8 direction;
+ int i;
+
+ _pathListIndex = -1;
+ addPathListPoint(toPoint);
+ nextPoint = toPoint;
+
+ while (!(nextPoint == fromPoint)) {
+ direction = getPathCell(nextPoint);
+ if ((direction < 0) || (direction >= 8)) {
+ error("Actor::setActorPath error direction 0x%X", direction);
+ }
+ nextPoint.x -= pathDirectionLUT2[direction][0];
+ nextPoint.y -= pathDirectionLUT2[direction][1];
+ addPathListPoint(nextPoint);
+
+#ifdef ACTOR_DEBUG
+ addDebugPoint(nextPoint, 0x8a);
+#endif
+ }
+
+ pathToNode();
+ removeNodes();
+ nodeToPath();
+ removePathPoints();
+
+ for (i = 0; i <= _pathNodeListIndex; i++) {
+ actor->addWalkStepPoint(_pathNodeList[i].point);
+ }
+}
+
+void Actor::pathToNode() {
+ Point point1, point2, delta;
+ int direction;
+ int i;
+ Point *point;
+
+ point= &_pathList[_pathListIndex];
+ direction = 0;
+
+ _pathNodeListIndex = -1;
+ addPathNodeListPoint(*point);
+
+ for (i = _pathListIndex; i > 0; i--) {
+ point1 = *point;
+ --point;
+ point2 = *point;
+ if (direction == 0) {
+ delta.x = int16Compare(point2.x, point1.x);
+ delta.y = int16Compare(point2.y, point1.y);
+ direction++;
+ }
+ if ((point1.x + delta.x != point2.x) || (point1.y + delta.y != point2.y)) {
+ addPathNodeListPoint(point1);
+ direction--;
+ i++;
+ point++;
+ }
+ }
+ addPathNodeListPoint(*_pathList);
+}
+
+int pathLine(Point *pointList, const Point &point1, const Point &point2) {
+ Point point;
+ Point delta;
+ Point tempPoint;
+ Point s;
+ int16 errterm;
+ int16 res;
+
+ calcDeltaS(point1, point2, delta, s);
+
+ point = point1;
+
+ tempPoint.x = delta.x * 2;
+ tempPoint.y = delta.y * 2;
+
+ if (delta.y > delta.x) {
+
+ errterm = tempPoint.x - delta.y;
+ res = delta.y;
+
+ while (delta.y > 0) {
+ while (errterm >= 0) {
+ point.x += s.x;
+ errterm -= tempPoint.y;
+ }
+
+ point.y += s.y;
+ errterm += tempPoint.x;
+
+ *pointList = point;
+ pointList++;
+ delta.y--;
+ }
+ } else {
+
+ errterm = tempPoint.y - delta.x;
+ res = delta.x;
+
+ while (delta.x > 0) {
+ while (errterm >= 0) {
+ point.y += s.y;
+ errterm -= tempPoint.x;
+ }
+
+ point.x += s.x;
+ errterm += tempPoint.y;
+
+ *pointList = point;
+ pointList++;
+ delta.x--;
+ }
+ }
+ return res;
+}
+
+void Actor::nodeToPath() {
+ int i;
+ Point point1, point2;
+ PathNode *node;
+ Point *point;
+
+ for (i = 0, point = _pathList; i < _pathListAlloced; i++, point++) {
+ point->x = point->y = PATH_NODE_EMPTY;
+ }
+
+ _pathListIndex = 1;
+ _pathList[0] = _pathNodeList[0].point;
+ _pathNodeList[0].link = 0;
+ for (i = 0, node = _pathNodeList; i < _pathNodeListIndex; i++) {
+ point1 = node->point;
+ node++;
+ point2 = node->point;
+ _pathListIndex += pathLine(&_pathList[_pathListIndex], point1, point2);
+ node->link = _pathListIndex - 1;
+ }
+ _pathListIndex--;
+ _pathNodeList[_pathNodeListIndex].link = _pathListIndex;
+
+}
+
+void Actor::removeNodes() {
+ int i, j, k;
+ PathNode *iNode, *jNode, *kNode, *fNode;
+ fNode = &_pathNodeList[_pathNodeListIndex];
+
+ if (scanPathLine(_pathNodeList[0].point, fNode->point)) {
+ _pathNodeList[1] = *fNode;
+ _pathNodeListIndex = 1;
+ }
+
+ if (_pathNodeListIndex < 4) {
+ return;
+ }
+
+ for (i = _pathNodeListIndex - 1, iNode = fNode-1; i > 1 ; i--, iNode--) {
+ if (iNode->point.x == PATH_NODE_EMPTY) {
+ continue;
+ }
+
+ if (scanPathLine(_pathNodeList[0].point, iNode->point)) {
+ for (j = 1, jNode = _pathNodeList + 1; j < i; j++, jNode++) {
+ jNode->point.x = PATH_NODE_EMPTY;
+ }
+ }
+ }
+
+ for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) {
+ if (iNode->point.x == PATH_NODE_EMPTY) {
+ continue;
+ }
+
+ if (scanPathLine(fNode->point, iNode->point)) {
+ for (j = i + 1, jNode = iNode + 1; j < _pathNodeListIndex; j++, jNode++) {
+ jNode->point.x = PATH_NODE_EMPTY;
+ }
+ }
+ }
+ condenseNodeList();
+
+ for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex - 1; i++, iNode++) {
+ if (iNode->point.x == PATH_NODE_EMPTY) {
+ continue;
+ }
+ for (j = i + 2, jNode = iNode + 2; j < _pathNodeListIndex; j++, jNode++) {
+ if (jNode->point.x == PATH_NODE_EMPTY) {
+ continue;
+ }
+
+ if (scanPathLine(iNode->point, jNode->point)) {
+ for (k = i + 1,kNode = iNode + 1; k < j; k++, kNode++) {
+ kNode->point.x = PATH_NODE_EMPTY;
+ }
+ }
+ }
+ }
+ condenseNodeList();
+}
+
+void Actor::condenseNodeList() {
+ int i, j, count;
+ PathNode *iNode, *jNode;
+
+ count = _pathNodeListIndex;
+
+ for (i = 1, iNode = _pathNodeList + 1; i < _pathNodeListIndex; i++, iNode++) {
+ if (iNode->point.x == PATH_NODE_EMPTY) {
+ j = i + 1;
+ jNode = iNode + 1;
+ while (jNode->point.x == PATH_NODE_EMPTY) {
+ j++;
+ jNode++;
+ }
+ *iNode = *jNode;
+ count = i;
+ jNode->point.x = PATH_NODE_EMPTY;
+ if (j == _pathNodeListIndex) {
+ break;
+ }
+ }
+ }
+ _pathNodeListIndex = count;
+}
+
+void Actor::removePathPoints() {
+ int i, j, k, l;
+ PathNode *node;
+ int start;
+ int end;
+ Point point1, point2;
+
+ if (_pathNodeListIndex < 2)
+ return;
+
+ _newPathNodeListIndex = -1;
+ addNewPathNodeListPoint(_pathNodeList[0]);
+
+ for (i = 1, node = _pathNodeList + 1; i < _pathNodeListIndex; i++, node++) {
+ addNewPathNodeListPoint(*node);
+
+ for (j = 5; j > 0; j--) {
+ start = node->link - j;
+ end = node->link + j;
+
+ if (start < 0 || end > _pathListIndex) {
+ continue;
+ }
+
+ point1 = _pathList[start];
+ point2 = _pathList[end];
+ if ((point1.x == PATH_NODE_EMPTY) || (point2.x == PATH_NODE_EMPTY)) {
+ continue;
+ }
+
+ if (scanPathLine(point1, point2)) {
+ for (l = 1; l <= _newPathNodeListIndex; l++) {
+ if (start <= _newPathNodeList[l].link) {
+ _newPathNodeListIndex = l;
+ _newPathNodeList[_newPathNodeListIndex].point = point1;
+ _newPathNodeList[_newPathNodeListIndex].link = start;
+ incrementNewPathNodeListIndex();
+ break;
+ }
+ }
+ _newPathNodeList[_newPathNodeListIndex].point = point2;
+ _newPathNodeList[_newPathNodeListIndex].link = end;
+
+ for (k = start + 1; k < end; k++) {
+ _pathList[k].x = PATH_NODE_EMPTY;
+ }
+ break;
+ }
+ }
+ }
+
+ addNewPathNodeListPoint(_pathNodeList[_pathNodeListIndex]);
+
+ for (i = 0, j = 0; i <= _newPathNodeListIndex; i++) {
+ if (_newPathNodeListIndex == i || (_newPathNodeList[i].point != _newPathNodeList[i+1].point)) {
+ _pathNodeList[j++] = _newPathNodeList[i];
+ }
+ }
+ _pathNodeListIndex = j - 1;
+}
+
+void Actor::drawPathTest() {
+#ifdef ACTOR_DEBUG
+ int i;
+ Surface *surface;
+ surface = _vm->_gfx->getBackBuffer();
+ if (_debugPoints == NULL) {
+ return;
+ }
+
+ for (i = 0; i < _debugPointsCount; i++) {
+ *((byte *)surface->pixels + (_debugPoints[i].point.y * surface->pitch) + _debugPoints[i].point.x) = _debugPoints[i].color;
+ }
+#endif
+}
+
+// Console wrappers - must be safe to run
+
+void Actor::cmdActorWalkTo(int argc, const char **argv) {
+ uint16 actorId = (uint16) atoi(argv[1]);
+ Location location;
+ Point movePoint;
+
+ movePoint.x = atoi(argv[2]);
+ movePoint.y = atoi(argv[3]);
+
+ location.fromScreenPoint(movePoint);
+
+ if (!validActorId(actorId)) {
+ _vm->_console->DebugPrintf("Actor::cmActorWalkTo Invalid actorId 0x%X.\n", actorId);
+ return;
+ }
+
+ actorWalkTo(actorId, location);
+}
+
+} // End of namespace Saga
diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp
index 7b3bdcd665..09b2ba412d 100644
--- a/engines/saga/animation.cpp
+++ b/engines/saga/animation.cpp
@@ -78,92 +78,75 @@ void Anim::freeCutawayList(void) {
_cutawayListLength = 0;
}
-void Anim::playCutaway(int cut, bool fade) {
+int Anim::playCutaway(int cut, bool fade) {
debug(0, "playCutaway(%d, %d)", cut, fade);
+ Event event;
+ Event *q_event = NULL;
bool startImmediately = false;
+ byte *resourceData;
+ size_t resourceDataLength;
+ ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
_cutAwayFade = fade;
- // Chained cutaway, clean up the previous cutaway
- if (_cutawayActive) {
- clearCutaway();
-
- // This is used because when AM is zapping the child's mother in Benny's chapter,
- // there is a cutaway followed by a video. The video needs to start immediately after
- // the cutaway so that it looks like the original
- startImmediately = true;
- }
-
- // WORKAROUND: The IHNM demo deals with chained cutaways in a different manner. Don't save
- // the palette of cutaway 11 (the woman looking at the marble)
- if (!(_vm->getGameId() == GID_IHNM_DEMO && cut == 11))
- _vm->_gfx->savePalette();
+ _vm->_gfx->savePalette();
+ _vm->_gfx->getCurrentPal(saved_pal);
if (fade) {
- _vm->_gfx->getCurrentPal(saved_pal);
- // TODO
- /*
- Event event;
static PalEntry cur_pal[PAL_ENTRIES];
- _vm->_gfx->getCurrentPal(cur_pal);
+ _vm->_interface->setFadeMode(kFadeOut);
+ // Fade to black out
+ _vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalToBlack;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
+ q_event = _vm->_events->queue(&event);
- _vm->_events->queue(&event);
- */
+ // set fade mode
+ event.type = kEvTImmediate;
+ event.code = kInterfaceEvent;
+ event.op = kEventSetFadeMode;
+ event.param = kNoFade;
+ event.time = 0;
+ event.duration = 0;
+ q_event = _vm->_events->chain(q_event, &event);
}
// Prepare cutaway
- _vm->_gfx->showCursor(false);
- _vm->_interface->setStatusText("");
- _vm->_interface->setSaveReminderState(0);
- _vm->_interface->rememberMode();
+ if (!_cutawayActive) {
+ _vm->_gfx->showCursor(false);
+ _vm->_interface->setStatusText("");
+ _vm->_interface->setSaveReminderState(0);
+ _vm->_interface->rememberMode();
+ _cutawayActive = true;
+ } else {
+ // If another cutaway is up, start the next cutaway immediately
+ startImmediately = true;
+ }
+
if (_cutAwayMode == kPanelVideo)
_vm->_interface->setMode(kPanelVideo);
else
_vm->_interface->setMode(kPanelCutaway);
- _cutawayActive = true;
-
- // Set the initial background and palette for the cutaway
- ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
-
- byte *resourceData;
- size_t resourceDataLength;
-
- _vm->_resource->loadResource(context, _cutawayList[cut].backgroundResourceId, resourceData, resourceDataLength);
-
- byte *buf;
- size_t buflen;
- int width;
- int height;
-
- _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height);
-
- const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData, resourceDataLength);
-
- Surface *bgSurface = _vm->_render->getBackGroundSurface();
- const Rect rect(width, height);
-
- bgSurface->blit(rect, buf);
- _vm->_frameCount++;
-
- _vm->_gfx->setPalette(palette);
- // WORKAROUND for a bug found in the original IHNM demo. The palette of cutaway 12 is incorrect (the incorrect
- // palette can be seen in the original demo too, for a split second). Therefore, use the saved palette for this
- // cutaway
- if (_vm->getGameId() == GID_IHNM_DEMO && cut == 12)
- _vm->_gfx->restorePalette();
-
- free(buf);
- free(resourceData);
+ if (fade) {
+ // Set the initial background and palette for the cutaway
+ event.type = kEvTImmediate;
+ event.code = kCutawayEvent;
+ event.op = kEventShowCutawayBg;
+ event.time = 0;
+ event.duration = 0;
+ event.param = _cutawayList[cut].backgroundResourceId;
+ q_event = _vm->_events->chain(q_event, &event);
+ } else {
+ showCutawayBg(_cutawayList[cut].backgroundResourceId);
+ }
// Play the animation
@@ -183,7 +166,7 @@ void Anim::playCutaway(int cut, bool fade) {
if (cutawaySlot == -1) {
warning("Could not allocate cutaway animation slot");
- return;
+ return 0;
}
// Some cutaways in IHNM have animResourceId equal to 0, which means that they only have
@@ -191,48 +174,47 @@ void Anim::playCutaway(int cut, bool fade) {
// An example is the "nightfall" animation in Ben's chapter (fadein-fadeout), the animation
// for the second from the left monitor in Ellen's chapter etc
// Therefore, skip the animation bit if animResourceId is 0 and only show the background
- if (_cutawayList[cut].animResourceId == 0)
- return;
-
- _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength);
-
- load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength);
-
- free(resourceData);
+ if (_cutawayList[cut].animResourceId != 0) {
+ _vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength);
+ load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength);
+ free(resourceData);
- setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles);
- setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate);
+ setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles);
+ setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate);
+ }
if (_cutAwayMode != kPanelVideo || startImmediately)
play(MAX_ANIMATIONS + cutawaySlot, 0);
else {
- Event event;
event.type = kEvTOneshot;
event.code = kAnimEvent;
event.op = kEventPlay;
event.param = MAX_ANIMATIONS + cutawaySlot;
event.time = (40 / 3) * 1000 / _cutawayList[cut].frameRate;
- _vm->_events->queue(&event);
+ if (fade)
+ q_event = _vm->_events->chain(q_event, &event);
+ else
+ _vm->_events->queue(&event);
}
+
+ return MAX_ANIMATIONS + cutawaySlot;
}
void Anim::endCutaway(void) {
- // I believe this is called by scripts after running one cutaway. At
- // this time, nothing needs to be done here.
+ // This is called by scripts after a cutaway is finished. At this time,
+ // nothing needs to be done here.
debug(0, "endCutaway()");
}
void Anim::returnFromCutaway(void) {
- // I believe this is called by scripts after running a cutaway to
- // ensure that we return to the scene as if nothing had happened. It's
- // not called by the IHNM intro, presumably because there is no old
- // scene to return to.
+ // This is called by scripts after a cutaway is finished, to return back
+ // to the scene that the cutaway was called from. It's not called by the
+ // IHNM intro, as there is no old scene to return to.
debug(0, "returnFromCutaway()");
-
if (_cutawayActive) {
Event event;
Event *q_event = NULL;
@@ -240,16 +222,26 @@ void Anim::returnFromCutaway(void) {
if (_cutAwayFade) {
static PalEntry cur_pal[PAL_ENTRIES];
- _vm->_gfx->getCurrentPal(cur_pal);
+ _vm->_interface->setFadeMode(kFadeOut);
+ // Fade to black out
+ _vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalToBlack;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
-
q_event = _vm->_events->queue(&event);
+
+ // set fade mode
+ event.type = kEvTImmediate;
+ event.code = kInterfaceEvent;
+ event.op = kEventSetFadeMode;
+ event.param = kNoFade;
+ event.time = 0;
+ event.duration = 0;
+ q_event = _vm->_events->chain(q_event, &event);
}
// Clear the cutaway. Note that this sets _cutawayActive to false
@@ -272,7 +264,6 @@ void Anim::returnFromCutaway(void) {
event.op = kEventResumeAll;
event.time = 0;
event.duration = 0;
-
q_event = _vm->_events->chain(q_event, &event); // chain with the other events
// Draw the scene
@@ -281,7 +272,6 @@ void Anim::returnFromCutaway(void) {
event.op = kEventDraw;
event.time = 0;
event.duration = 0;
-
q_event = _vm->_events->chain(q_event, &event); // chain with the other events
// Handle fade up, if we previously faded down
@@ -292,22 +282,22 @@ void Anim::returnFromCutaway(void) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = saved_pal;
-
q_event = _vm->_events->chain(q_event, &event);
-
}
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypeWakeUp;
-
q_event = _vm->_events->chain(q_event, &event);
}
}
void Anim::clearCutaway(void) {
+ PalEntry *pal;
+
debug(1, "clearCutaway()");
+
if (_cutawayActive) {
_cutawayActive = false;
@@ -317,18 +307,56 @@ void Anim::clearCutaway(void) {
}
_vm->_interface->restoreMode();
-
- if (_vm->getGameId() != GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) {
- // Don't show the mouse cursor in the non-interactive part of the IHNM demo
- } else {
- _vm->_gfx->showCursor(true);
- }
- } else {
+ _vm->_gfx->showCursor(true);
+
+ if (_vm->getGameId() == GID_IHNM_DEMO) {
// Enable the save reminder state after each cutaway for the IHNM demo
_vm->_interface->setSaveReminderState(true);
}
+
+ // Set the scene's palette
+ _vm->_scene->getBGPal(pal);
+ _vm->_gfx->setPalette(pal);
+ }
+}
+
+void Anim::showCutawayBg(int bg) {
+ ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
+
+ byte *resourceData;
+ size_t resourceDataLength;
+ byte *buf;
+ size_t buflen;
+ int width;
+ int height;
+ Event event;
+ static PalEntry pal[PAL_ENTRIES];
+
+ _vm->_resource->loadResource(context, bg, resourceData, resourceDataLength);
+ _vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height);
+
+ const byte *palPointer = _vm->getImagePal(resourceData, resourceDataLength);
+ memcpy(pal, palPointer, sizeof(pal));
+ Surface *bgSurface = _vm->_render->getBackGroundSurface();
+ const Rect rect(width, height);
+ bgSurface->blit(rect, buf);
+ _vm->_frameCount++;
+
+ if (_cutAwayFade) {
+ // Handle fade up, if we previously faded down
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventBlackToPal;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = pal;
+ _vm->_events->queue(&event);
+ } else {
+ _vm->_gfx->setPalette(pal);
}
+
+ free(buf);
+ free(resourceData);
}
void Anim::startVideo(int vid, bool fade) {
@@ -380,6 +408,12 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource
anim->start += temp;
// Cache frame offsets
+
+ // WORKAROUND: Cutaway with background resource ID 37 (loaded as cutaway #4) is ending credits.
+ // For some reason it has wrong number of frames specified in its header. So we calculate it here:
+ if (animId > MAX_ANIMATIONS && _cutawayListLength > 4 && _cutawayList[4].backgroundResourceId == 37 && anim->maxFrame == 143)
+ anim->maxFrame = fillFrameOffsets(anim, false);
+
anim->frameOffsets = (size_t *)malloc((anim->maxFrame + 1) * sizeof(*anim->frameOffsets));
if (anim->frameOffsets == NULL) {
memoryError("Anim::load");
@@ -388,7 +422,9 @@ void Anim::load(uint16 animId, const byte *animResourceData, size_t animResource
fillFrameOffsets(anim);
// Set animation data
- anim->currentFrame = 0;
+ // HACK: We set currentFrame to -1, as the first frame of the animation is never drawn otherwise
+ // (check Anim::play)
+ anim->currentFrame = -1;
anim->completed = 0;
anim->cycles = anim->maxFrame;
@@ -422,6 +458,13 @@ void Anim::setCycles(uint16 animId, int cycles) {
anim->cycles = cycles;
}
+int Anim::getCycles(uint16 animId) {
+ if (animId >= MAX_ANIMATIONS && _cutawayAnimations[animId - MAX_ANIMATIONS] == NULL)
+ return 0;
+
+ return getAnimation(animId)->cycles;
+}
+
void Anim::play(uint16 animId, int vectorTime, bool playing) {
Event event;
Surface *backGroundSurface;
@@ -440,6 +483,23 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
if (animId < MAX_ANIMATIONS && _cutawayActive)
return;
+ if (animId >= MAX_ANIMATIONS && _cutawayAnimations[animId - MAX_ANIMATIONS] == NULL) {
+ // In IHNM, cutaways without an animation bit are not rendered, but the framecount
+ // needs to be updated
+ _vm->_frameCount++;
+
+ event.type = kEvTOneshot;
+ event.code = kAnimEvent;
+ event.op = kEventFrame;
+ event.param = animId;
+ event.time = 10;
+ _vm->_events->queue(&event);
+
+ // Nothing to render here (apart from the background, which is already rendered),
+ // so return
+ return;
+ }
+
anim = getAnimation(animId);
backGroundSurface = _vm->_render->getBackGroundSurface();
@@ -453,19 +513,28 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
return;
}
+ // HACK: The first frame of the animation is never shown when entering a scene
+ // For now, we initialize currentFrame to be -1 instead of 0 and we draw the
+ // first frame of the animation on the next iteration of Anim::play
+ // FIXME: find out why this occurs and remove this hack. Note that when this
+ // hack is removed, currentFrame should be initialized to 0 again in Anim::load
+ if (anim->currentFrame < 0) {
+ anim->currentFrame = 0;
+ event.type = kEvTOneshot;
+ event.code = kAnimEvent;
+ event.op = kEventFrame;
+ event.param = animId;
+ event.time = 0;
+ _vm->_events->queue(&event);
+
+ return;
+ }
+
if (anim->completed < anim->cycles) {
- frame = anim->currentFrame;
+ if (anim->currentFrame < 0)
+ anim->currentFrame = 0;
- // WORKAROUND for a buggy animation in IHNM. Animation 0 in scene 67 (the mob of angry prisoners) should
- // start from frame 0, not frame 1. Frame 0 is the background of the animation (the mob of prisoners), whereas
- // the rest of the frames are their animated arms. Therefore, in order for the prisoners to appear correctly,
- // frame 0 should be displayed as the first frame, but anim->currentframe is set to 1, which means that the
- // prisoners will never be shown. In the original, the prisoners (first frame in the animation) are shown a
- // bit after the animation is started (which is wrong again, but not that apparent), whereas in ScummVM the
- // first frame is never shown. Therefore, make sure that for this animation, frame 0 is shown first
- if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 4 &&
- _vm->_scene->currentSceneNumber() == 67 && animId == 0 && anim->completed == 1)
- frame = 0;
+ frame = anim->currentFrame;
// FIXME: if start > 0, then this works incorrectly
decodeFrame(anim, anim->frameOffsets[frame], displayBuffer, _vm->getDisplayWidth() * _vm->getDisplayHeight());
@@ -488,6 +557,9 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
_vm->_frameCount += 100; // make sure the waiting thread stops waiting
// Animation done playing
anim->state = ANIM_PAUSE;
+ anim->currentFrame = 0;
+ anim->completed = 0;
+
if (anim->linkId == -1) {
if (anim->flags & ANIM_FLAG_ENDSCENE) {
// This animation ends the scene
@@ -498,9 +570,6 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
_vm->_events->queue(&event);
}
return;
- } else {
- anim->currentFrame = 0;
- anim->completed = 0;
}
}
@@ -521,7 +590,6 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) {
event.op = kEventFrame;
event.param = animId;
event.time = frameTime;
-
_vm->_events->queue(&event);
}
@@ -592,6 +660,22 @@ void Anim::setFrameTime(uint16 animId, int time) {
anim->frameTime = time;
}
+int Anim::getFrameTime(uint16 animId) {
+ AnimationData *anim;
+
+ anim = getAnimation(animId);
+
+ return anim->frameTime;
+}
+
+bool Anim::isPlaying(uint16 animId) {
+ AnimationData *anim;
+
+ anim = getAnimation(animId);
+
+ return (anim->state == ANIM_PLAYING);
+}
+
int16 Anim::getCurrentFrame(uint16 animId) {
AnimationData *anim;
@@ -631,11 +715,12 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_
MemoryReadStream readS(anim->resourceData + frameOffset, anim->resourceLength - frameOffset);
-
+// FIXME: This is thrown when the first video of the IHNM end sequence is shown (the "turn off screen"
+// video), however the video is played correctly and the rest of the end sequence continues normally
#if 1
#define VALIDATE_WRITE_POINTER \
if ((writePointer < buf) || (writePointer >= (buf + screenWidth * screenHeight))) { \
- error("VALIDATE_WRITE_POINTER: writePointer=%p buf=%p", (void *)writePointer, (void *)buf); \
+ warning("VALIDATE_WRITE_POINTER: writePointer=%p buf=%p", (void *)writePointer, (void *)buf); \
}
#else
#define VALIDATE_WRITE_POINTER
@@ -758,8 +843,8 @@ void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_
} while (1);
}
-void Anim::fillFrameOffsets(AnimationData *anim) {
- uint16 currentFrame;
+int Anim::fillFrameOffsets(AnimationData *anim, bool reallyFill) {
+ uint16 currentFrame = 0;
byte markByte;
uint16 control;
uint16 runcount;
@@ -772,12 +857,18 @@ void Anim::fillFrameOffsets(AnimationData *anim) {
readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE
- for (currentFrame = 0; currentFrame <= anim->maxFrame; currentFrame++) {
- anim->frameOffsets[currentFrame] = readS.pos();
+ while (!readS.eos()) {
+ if (reallyFill) {
+ anim->frameOffsets[currentFrame] = readS.pos();
+
+ if (currentFrame == anim->maxFrame)
+ break;
+ }
+ currentFrame++;
// For some strange reason, the animation header is in little
// endian format, but the actual RLE encoded frame data,
- // including the frame header, is in big endian format. */
+ // including the frame header, is in big endian format
do {
markByte = readS.readByte();
// debug(7, "_pos=%x currentFrame=%i markByte=%x", readS.pos(), currentFrame, markByte);
@@ -816,8 +907,7 @@ void Anim::fillFrameOffsets(AnimationData *anim) {
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // (16) 0001 0000
// Long Uncompressed Run
runcount = readS.readSint16BE();
- for (i = 0; i < runcount; i++)
- readS.readByte();
+ readS.seek(runcount, SEEK_CUR);
continue;
break;
case SAGA_FRAME_NOOP: // Does nothing
@@ -855,6 +945,8 @@ void Anim::fillFrameOffsets(AnimationData *anim) {
}
} while (markByte != SAGA_FRAME_END);
}
+
+ return currentFrame;
}
void Anim::animInfo() {
diff --git a/engines/saga/animation.h b/engines/saga/animation.h
index f8cf90425f..4306d8e00d 100644
--- a/engines/saga/animation.h
+++ b/engines/saga/animation.h
@@ -115,10 +115,11 @@ public:
void loadCutawayList(const byte *resourcePointer, size_t resourceLength);
void freeCutawayList(void);
- void playCutaway(int cut, bool fade);
+ int playCutaway(int cut, bool fade);
void endCutaway(void);
void returnFromCutaway(void);
void clearCutaway(void);
+ void showCutawayBg(int bg);
void startVideo(int vid, bool fade);
void endVideo(void);
@@ -140,12 +141,10 @@ public:
void resume(uint16 animId, int cycles);
void resumeAll();
int16 getCurrentFrame(uint16 animId);
- bool hasCutaway(void) {
- return _cutawayActive;
- }
- void setCutAwayMode(int mode) {
- _cutAwayMode = mode;
- }
+ int getFrameTime(uint16 animId);
+ int getCycles(uint16 animId);
+ bool isPlaying(uint16 animId);
+
bool hasAnimation(uint16 animId) {
if (animId >= MAX_ANIMATIONS) {
if (animId < MAX_ANIMATIONS + ARRAYSIZE(_cutawayAnimations))
@@ -154,10 +153,16 @@ public:
}
return (_animations[animId] != NULL);
}
- int cutawayResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; }
+
+ bool hasCutaway(void) { return _cutawayActive; }
+ void setCutAwayMode(int mode) { _cutAwayMode = mode; }
+ int cutawayListLength() { return _cutawayListLength; }
+ int cutawayBgResourceID(int cutaway) { return _cutawayList[cutaway].backgroundResourceId; }
+ int cutawayAnimResourceID(int cutaway) { return _cutawayList[cutaway].animResourceId; }
+
private:
void decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength);
- void fillFrameOffsets(AnimationData *anim);
+ int fillFrameOffsets(AnimationData *anim, bool reallyFill = true);
void validateAnimationId(uint16 animId) {
if (animId >= MAX_ANIMATIONS) {
@@ -168,7 +173,7 @@ private:
}
}
if (_animations[animId] == NULL) {
- error("validateAnimationId: animId=%i unassigned", animId);
+ error("validateAnimationId: animId=%i unassigned.", animId);
}
}
diff --git a/engines/saga/console.cpp b/engines/saga/console.cpp
index 421245ab30..0a6b733e00 100644
--- a/engines/saga/console.cpp
+++ b/engines/saga/console.cpp
@@ -75,6 +75,14 @@ Console::Console(SagaEngine *vm) : GUI::Debugger() {
// Panel commands
DCmd_Register("current_panel_mode", WRAP_METHOD(Console, cmdCurrentPanelMode));
DCmd_Register("set_panel_mode", WRAP_METHOD(Console, cmdSetPanelMode));
+
+ // Font commands
+ DCmd_Register("set_font_mapping", WRAP_METHOD(Console, cmdSetFontMapping));
+
+ // Global flags commands
+ DCmd_Register("global_flags_info", WRAP_METHOD(Console, cmdGlobalFlagsInfo));
+ DCmd_Register("set_global_flag", WRAP_METHOD(Console, cmdSetGlobalFlag));
+ DCmd_Register("clear_global_flag", WRAP_METHOD(Console, cmdClearGlobalFlag));
}
Console::~Console() {
@@ -158,4 +166,92 @@ bool Console::cmdSetPanelMode(int argc, const char **argv) {
return true;
}
+bool Console::cmdSetFontMapping(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Sets font mapping\nUsage: %s <Font mapping flag>\n", argv[0]);
+ DebugPrintf("Mapping flags:\n0 - default game behavior\n1 - force font mapping\n2 - ignore font mapping\n");
+ } else {
+ _vm->_font->setFontMapping(atoi(argv[1]));
+ }
+ return true;
+}
+
+bool Console::cmdGlobalFlagsInfo(int argc, const char **argv) {
+ DebugPrintf("Global flags status for IHNM:\n");
+
+ // Global flags in IHNM:
+ // 00: Unknown
+ // 01: Unknown
+ // 02: Unknown
+ // 03: Unknown
+ // 04: Unknown
+ // 05: Unknown
+ // 06: Unknown
+ // 07: Unknown
+ // 08: Unknown
+ // 09: Unknown
+ // 10: Unknown
+ // 11: Unknown
+ // 12: Unknown
+ // 13: Unknown
+ // 14: Unknown
+ // 15: Unknown
+ // 16: Used in the final chapter. If it's 0 when a character dies, the "bad" ending for that character is shown
+ // 17: Unknown
+ // 18: Unknown
+ // 19: Unknown, used in the final chapter
+ // 20: Unknown
+ // 21: Unknown
+ // 22: Unknown
+ // 23: Unknown
+ // 24: Unknown
+ // 25: Unknown
+ // 26: Unknown
+ // 27: Unknown
+ // 28: Unknown
+ // 29: Unknown
+ // 30: Unknown
+ // 31: Unknown
+
+ int i = 0, k = 0, flagStatus = 0;
+
+ for (i = 0; i < 32; i += 8) {
+ for (k = i; k < i + 8; k ++) {
+ flagStatus = _vm->_globalFlags & (1 << k) ? 1 : 0;
+ _vm->_console->DebugPrintf("%02d: %u |", k, flagStatus);
+ }
+ _vm->_console->DebugPrintf("\n");
+ }
+
+ return true;
+}
+
+bool Console::cmdSetGlobalFlag(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Usage: %s <Global flag number>\nValid flag numbers are 0 - 31\n", argv[0]);
+ } else {
+ int flagNumber = atoi(argv[1]);
+ if (flagNumber >= 0 && flagNumber <= 31) {
+ _vm->_globalFlags |= (1 << flagNumber);
+ } else {
+ DebugPrintf("Valid flag numbers are 0 - 31\n");
+ }
+ }
+ return true;
+}
+
+bool Console::cmdClearGlobalFlag(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Usage: %s <Global flag number>\nValid flag numbers are 0 - 31\n", argv[0]);
+ } else {
+ int flagNumber = atoi(argv[1]);
+ if (flagNumber >= 0 && flagNumber <= 31) {
+ _vm->_globalFlags &= ~(1 << flagNumber);
+ } else {
+ DebugPrintf("Valid flag numbers are 0 - 31\n");
+ }
+ }
+ return true;
+}
+
} // End of namespace Saga
diff --git a/engines/saga/console.h b/engines/saga/console.h
index 3db9833f22..7936d3a959 100644
--- a/engines/saga/console.h
+++ b/engines/saga/console.h
@@ -55,6 +55,12 @@ private:
bool cmdCurrentPanelMode(int argc, const char **argv);
bool cmdSetPanelMode(int argc, const char **argv);
+ bool cmdSetFontMapping(int argc, const char **argv);
+
+ bool cmdGlobalFlagsInfo(int argc, const char **argv);
+ bool cmdSetGlobalFlag(int argc, const char **argv);
+ bool cmdClearGlobalFlag(int argc, const char **argv);
+
private:
SagaEngine *_vm;
};
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index c8918998f1..29ca0e8bbe 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/detection.cpp $
- * $Id:detection.cpp 26949 2007-05-26 20:23:24Z david_corrales $
+ * $URL$
+ * $Id$
*
*/
@@ -49,7 +49,6 @@ struct SAGAGameDescription {
const GameFontDescription *fontDescriptions;
const GameSoundInfo *voiceInfo;
const GameSoundInfo *sfxInfo;
- const GameSoundInfo *musicInfo;
int patchesCount;
const GamePatchDescription *patchDescriptions;
};
@@ -59,7 +58,18 @@ const bool SagaEngine::isMacResources() const { return (getPlatform() == Common:
const GameResourceDescription *SagaEngine::getResourceDescription() { return _gameDescription->resourceDescription; }
const GameSoundInfo *SagaEngine::getVoiceInfo() const { return _gameDescription->voiceInfo; }
const GameSoundInfo *SagaEngine::getSfxInfo() const { return _gameDescription->sfxInfo; }
-const GameSoundInfo *SagaEngine::getMusicInfo() const { return _gameDescription->musicInfo; }
+const GameSoundInfo *SagaEngine::getMusicInfo() const {
+ static GameSoundInfo musicInfo;
+ musicInfo.resourceType = kSoundPCM;
+ musicInfo.frequency = 11025;
+ musicInfo.sampleBits = 16;
+ // The digital music in the ITE Mac demo version is not stereo
+ musicInfo.stereo = _gameDescription->gameType == GID_ITE_MACDEMO2 ? false : true;
+ musicInfo.isBigEndian = false;
+ musicInfo.isSigned = true;
+
+ return &musicInfo;
+}
const GameFontDescription *SagaEngine::getFontDescription(int index) {
assert(index < _gameDescription->fontsCount);
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h
index 0d57adb87d..5bb408e947 100644
--- a/engines/saga/detection_tables.h
+++ b/engines/saga/detection_tables.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/detection_tables.h $
- * $Id:detection_tables.h 26949 2007-05-26 20:23:24Z david_corrales $
+ * $URL$
+ * $Id$
*
*/
@@ -34,6 +34,7 @@ static const GameResourceDescription ITE_Resources = {
RID_ITE_CONVERSE_PANEL,
RID_ITE_OPTION_PANEL,
0, // Warning panel (IHNM only)
+ 0, // Warning panel sprites (IHNM only)
RID_ITE_MAIN_SPRITES,
RID_ITE_MAIN_PANEL_SPRITES,
0, // Option panel sprites (IHNM only)
@@ -50,6 +51,7 @@ static const GameResourceDescription ITEDemo_Resources = {
RID_ITEDEMO_CONVERSE_PANEL,
RID_ITEDEMO_OPTION_PANEL,
0, // Warning panel (IHNM only)
+ 0, // Warning panel sprites (IHNM only)
RID_ITEDEMO_MAIN_SPRITES,
RID_ITEDEMO_MAIN_PANEL_SPRITES,
0, // Option panel sprites (IHNM only)
@@ -59,188 +61,6 @@ static const GameResourceDescription ITEDemo_Resources = {
RID_ITEDEMO_ACTOR_NAMES
};
-// Inherit the Earth - DOS Demo version
-static const GameFontDescription ITEDEMO_GameFonts[] = {
- {0},
- {1}
-};
-
-// Inherit the Earth - Wyrmkeep Win32 Demo version
-
-static const GameFontDescription ITEWINDEMO_GameFonts[] = {
- {2},
- {0}
-};
-
-static const GameSoundInfo ITEWINDEMO1_GameSound = {
- kSoundPCM,
- 22050,
- 8,
- false,
- false,
- false
-};
-
-static const GameSoundInfo ITEWINDEMO2_GameVoice = {
- kSoundVOX,
- 22050,
- 16,
- false,
- false,
- true
-};
-
-static const GameSoundInfo ITEWINDEMO2_GameSound = {
- kSoundPCM,
- 22050,
- 16,
- false,
- false,
- true
-};
-
-// Inherit the Earth - Wyrmkeep Mac Demo version
-static const GameSoundInfo ITEMACDEMO_GameVoice = {
- kSoundVOX,
- 22050,
- 16,
- false,
- false,
- true
-};
-
-static const GameSoundInfo ITEMACDEMO_GameSound = {
- kSoundPCM,
- 22050,
- 16,
- false,
- true,
- true
-};
-
-static const GameSoundInfo ITEMACDEMO_GameMusic = {
- kSoundPCM,
- 11025,
- 16,
- false,
- false,
- true
-};
-
-static const GameSoundInfo ITEMACCD_G_GameSound = {
- kSoundMacPCM,
- 22050,
- 8,
- false,
- false,
- false
-};
-
-// Inherit the Earth - Mac Wyrmkeep version
-static const GameSoundInfo ITEMACCD_GameSound = {
- kSoundPCM,
- 22050,
- 16,
- false,
- true,
- true
-};
-
-static const GameSoundInfo ITEMACCD_GameMusic = {
- kSoundPCM,
- 11025,
- 16,
- true,
- false,
- true
-};
-
-// Inherit the Earth - Diskette version
-static const GameFontDescription ITEDISK_GameFonts[] = {
- {2},
- {0},
- {1}
-};
-
-static const GameSoundInfo ITEDISK_GameSound = {
- kSoundVOC,
- -1,
- -1,
- false,
- false,
- true
-};
-
-static const GameFontDescription ITECD_GameFonts[] = {
- {2},
- {0},
- {1}
-};
-
-static const GameSoundInfo ITECD_GameSound = {
- kSoundPCM,
- 22050,
- 16,
- false,
- false,
- true
-};
-
-// Patch files. Files not found will be ignored
-static const GamePatchDescription ITEPatch_Files[] = {
- { "cave.mid", GAME_RESOURCEFILE, 9, NULL},
- { "intro.mid", GAME_RESOURCEFILE, 10, NULL},
- { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL},
- { "elkhall.mid", GAME_RESOURCEFILE, 12, NULL},
- { "mouse.mid", GAME_RESOURCEFILE, 13, NULL},
- { "darkclaw.mid", GAME_RESOURCEFILE, 14, NULL},
- { "birdchrp.mid", GAME_RESOURCEFILE, 15, NULL},
- { "orbtempl.mid", GAME_RESOURCEFILE, 16, NULL},
- { "spooky.mid", GAME_RESOURCEFILE, 17, NULL},
- { "catfest.mid", GAME_RESOURCEFILE, 18, NULL},
- { "elkfanfare.mid", GAME_RESOURCEFILE, 19, NULL},
- { "bcexpl.mid", GAME_RESOURCEFILE, 20, NULL},
- { "boargtnt.mid", GAME_RESOURCEFILE, 21, NULL},
- { "boarking.mid", GAME_RESOURCEFILE, 22, NULL},
- { "explorea.mid", GAME_RESOURCEFILE, 23, NULL},
- { "exploreb.mid", GAME_RESOURCEFILE, 24, NULL},
- { "explorec.mid", GAME_RESOURCEFILE, 25, NULL},
- { "sunstatm.mid", GAME_RESOURCEFILE, 26, NULL},
- { "nitstrlm.mid", GAME_RESOURCEFILE, 27, NULL},
- { "humruinm.mid", GAME_RESOURCEFILE, 28, NULL},
- { "damexplm.mid", GAME_RESOURCEFILE, 29, NULL},
- { "tychom.mid", GAME_RESOURCEFILE, 30, NULL},
- { "kitten.mid", GAME_RESOURCEFILE, 31, NULL},
- { "sweet.mid", GAME_RESOURCEFILE, 32, NULL},
- { "brutalmt.mid", GAME_RESOURCEFILE, 33, NULL},
- { "shiala.mid", GAME_RESOURCEFILE, 34, NULL},
-
- { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL},
- { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL},
- { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL},
- { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL},
- { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL},
- { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL},
- { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, // Macintosh
- { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL},
- { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, // Macintosh
- { "p2_a.voc", GAME_VOICEFILE, 4, NULL},
- { "p2_a.iaf", GAME_VOICEFILE, 4, &ITECD_GameSound}
-};
-
-static const GamePatchDescription ITEMacPatch_Files[] = {
- { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL},
- { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL},
- { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL},
- { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL},
- { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL},
- { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL},
- { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL},
- { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEMACCD_GameSound}
-};
-
-// IHNM section
-
static const GameResourceDescription IHNM_Resources = {
RID_IHNM_SCENE_LUT, // Scene lookup table RN
RID_IHNM_SCRIPT_LUT, // Script lookup table RN
@@ -248,6 +68,7 @@ static const GameResourceDescription IHNM_Resources = {
RID_IHNM_CONVERSE_PANEL,
RID_IHNM_OPTION_PANEL,
RID_IHNM_WARNING_PANEL,
+ RID_IHNM_WARNING_PANEL_SPRITES,
RID_IHNM_MAIN_SPRITES,
RID_IHNM_MAIN_PANEL_SPRITES,
RID_IHNM_OPTION_PANEL_SPRITES,
@@ -264,6 +85,7 @@ static const GameResourceDescription IHNMDEMO_Resources = {
RID_IHNMDEMO_CONVERSE_PANEL,
RID_IHNMDEMO_OPTION_PANEL,
RID_IHNMDEMO_WARNING_PANEL,
+ RID_IHNMDEMO_WARNING_PANEL_SPRITES,
RID_IHNMDEMO_MAIN_SPRITES,
RID_IHNMDEMO_MAIN_PANEL_SPRITES,
RID_IHNMDEMO_OPTION_PANEL_SPRITES,
@@ -273,29 +95,73 @@ static const GameResourceDescription IHNMDEMO_Resources = {
0 // Actors strings (ITE only)
};
-static const GameFontDescription IHNMDEMO_GameFonts[] = {
- {2},
- {3},
- {4}
-};
+static const GameFontDescription ITEDEMO_GameFonts[] = { {0}, {1} };
+static const GameFontDescription ITEWINDEMO_GameFonts[] = { {2}, {0} };
+static const GameFontDescription ITE_GameFonts[] = { {2}, {0}, {1} };
+static const GameFontDescription IHNMDEMO_GameFonts[] = { {2}, {3}, {4} };
+// Font 6 is kIHNMFont8, font 8 is kIHNMMainFont
+static const GameFontDescription IHNMCD_GameFonts[] = { {2}, {3}, {4}, {5}, {6}, {7}, {8} };
+
+// frequency, sampleBits, stereo, isBigEndian, isSigned
+static const GameSoundInfo ITEPC_GameSound = { kSoundPCM, 22050, 16, false, false, true };
+static const GameSoundInfo ITEMAC_GameSound = { kSoundPCM, 22050, 16, false, true, true };
+static const GameSoundInfo ITEWINDEMO1_GameSound = { kSoundPCM, 22050, 8, false, false, false };
+static const GameSoundInfo ITEMACCD_G_GameSound = { kSoundMacPCM, 22050, 8, false, false, false };
+static const GameSoundInfo ITEDISK_GameSound = { kSoundVOC, -1, -1, false, false, true };
+static const GameSoundInfo ITEDEMO_GameVoice = { kSoundVOX, 22050, 16, false, false, true };
+static const GameSoundInfo IHNM_GameSound = { kSoundWAV, -1, -1, false, false, true };
-static const GameFontDescription IHNMCD_GameFonts[] = {
- {2},
- {3},
- {4},
- {5},
- {6}, // kIHNMFont8
- {7},
- {8} // kIHNMMainFont
+// Patch files. Files not found will be ignored
+static const GamePatchDescription ITEPatch_Files[] = {
+ { "cave.mid", GAME_RESOURCEFILE, 9, NULL},
+ { "intro.mid", GAME_RESOURCEFILE, 10, NULL},
+ { "fvillage.mid", GAME_RESOURCEFILE, 11, NULL},
+ { "elkhall.mid", GAME_RESOURCEFILE, 12, NULL},
+ { "mouse.mid", GAME_RESOURCEFILE, 13, NULL},
+ { "darkclaw.mid", GAME_RESOURCEFILE, 14, NULL},
+ { "birdchrp.mid", GAME_RESOURCEFILE, 15, NULL},
+ { "orbtempl.mid", GAME_RESOURCEFILE, 16, NULL},
+ { "spooky.mid", GAME_RESOURCEFILE, 17, NULL},
+ { "catfest.mid", GAME_RESOURCEFILE, 18, NULL},
+ { "elkfanfare.mid", GAME_RESOURCEFILE, 19, NULL},
+ { "bcexpl.mid", GAME_RESOURCEFILE, 20, NULL},
+ { "boargtnt.mid", GAME_RESOURCEFILE, 21, NULL},
+ { "boarking.mid", GAME_RESOURCEFILE, 22, NULL},
+ { "explorea.mid", GAME_RESOURCEFILE, 23, NULL},
+ { "exploreb.mid", GAME_RESOURCEFILE, 24, NULL},
+ { "explorec.mid", GAME_RESOURCEFILE, 25, NULL},
+ { "sunstatm.mid", GAME_RESOURCEFILE, 26, NULL},
+ { "nitstrlm.mid", GAME_RESOURCEFILE, 27, NULL},
+ { "humruinm.mid", GAME_RESOURCEFILE, 28, NULL},
+ { "damexplm.mid", GAME_RESOURCEFILE, 29, NULL},
+ { "tychom.mid", GAME_RESOURCEFILE, 30, NULL},
+ { "kitten.mid", GAME_RESOURCEFILE, 31, NULL},
+ { "sweet.mid", GAME_RESOURCEFILE, 32, NULL},
+ { "brutalmt.mid", GAME_RESOURCEFILE, 33, NULL},
+ { "shiala.mid", GAME_RESOURCEFILE, 34, NULL},
+
+ { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL},
+ { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL},
+ { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL},
+ { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL},
+ { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL},
+ { "credit3n.dlt", GAME_RESOURCEFILE, 1796, NULL}, // PC
+ { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL}, // Macintosh
+ { "credit4n.dlt", GAME_RESOURCEFILE, 1797, NULL}, // PC
+ { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL}, // Macintosh
+ { "p2_a.voc", GAME_VOICEFILE, 4, NULL},
+ { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEPC_GameSound}
};
-static const GameSoundInfo IHNM_GameSound = {
- kSoundWAV,
- -1,
- -1,
- false,
- false,
- true
+static const GamePatchDescription ITEMacPatch_Files[] = {
+ { "wyrm.pak", GAME_RESOURCEFILE, 1529, NULL},
+ { "wyrm1.dlt", GAME_RESOURCEFILE, 1530, NULL},
+ { "wyrm2.dlt", GAME_RESOURCEFILE, 1531, NULL},
+ { "wyrm3.dlt", GAME_RESOURCEFILE, 1532, NULL},
+ { "wyrm4.dlt", GAME_RESOURCEFILE, 1533, NULL},
+ { "credit3m.dlt", GAME_RESOURCEFILE, 1796, NULL},
+ { "credit4m.dlt", GAME_RESOURCEFILE, 1797, NULL},
+ { "p2_a.iaf", GAME_VOICEFILE, 4, &ITEMAC_GameSound}
};
static const SAGAGameDescription gameDescriptions[] = {
@@ -333,7 +199,6 @@ static const SAGAGameDescription gameDescriptions[] = {
ITEDEMO_GameFonts,
&ITEDISK_GameSound,
&ITEDISK_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
0,
NULL,
},
@@ -363,18 +228,15 @@ static const SAGAGameDescription gameDescriptions[] = {
&ITE_Resources,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
- &ITEMACDEMO_GameVoice,
- &ITEMACDEMO_GameSound,
- &ITEMACDEMO_GameMusic,
+ &ITEDEMO_GameVoice,
+ &ITEMAC_GameSound,
ARRAYSIZE(ITEMacPatch_Files),
ITEMacPatch_Files,
},
- // Note: This version is NOT supported yet
- // Exiting the faire leads to a crash
-
// Inherit the earth - MAC Demo version 1
+ // Non-interactive demo
{
{
"ite",
@@ -393,14 +255,13 @@ static const SAGAGameDescription gameDescriptions[] = {
},
GType_ITE,
GID_ITE_MACDEMO1,
- GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX,
+ GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX | GF_NON_INTERACTIVE,
ITE_DEFAULT_SCENE,
&ITE_Resources,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
- &ITEMACDEMO_GameVoice,
- &ITEMACDEMO_GameSound,
- &ITEMACCD_GameMusic,
+ &ITEDEMO_GameVoice,
+ &ITEMAC_GameSound,
ARRAYSIZE(ITEMacPatch_Files),
ITEMacPatch_Files,
},
@@ -431,18 +292,15 @@ static const SAGAGameDescription gameDescriptions[] = {
&ITE_Resources,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
- &ITEWINDEMO2_GameVoice,
- &ITEWINDEMO2_GameSound,
- &ITEMACCD_GameMusic,
+ &ITEDEMO_GameVoice,
+ &ITEPC_GameSound,
ARRAYSIZE(ITEPatch_Files),
ITEPatch_Files,
},
- // Note: This version is NOT supported yet
- // Exiting the faire leads to a crash
-
// Inherit the earth - Win32 Demo version 1
+ // Non-interactive demo
{
{
"ite",
@@ -460,14 +318,13 @@ static const SAGAGameDescription gameDescriptions[] = {
},
GType_ITE,
GID_ITE_WINDEMO1,
- GF_WYRMKEEP | GF_CD_FX,
+ GF_WYRMKEEP | GF_CD_FX | GF_NON_INTERACTIVE,
ITE_DEFAULT_SCENE,
&ITE_Resources,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
&ITEWINDEMO1_GameSound,
&ITEWINDEMO1_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
ARRAYSIZE(ITEPatch_Files),
ITEPatch_Files,
},
@@ -504,7 +361,6 @@ static const SAGAGameDescription gameDescriptions[] = {
ITEWINDEMO_GameFonts,
&ITEMACCD_G_GameSound,
&ITEMACCD_G_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
0,
NULL,
},
@@ -533,9 +389,8 @@ static const SAGAGameDescription gameDescriptions[] = {
&ITE_Resources,
ARRAYSIZE(ITEWINDEMO_GameFonts),
ITEWINDEMO_GameFonts,
- &ITEMACCD_GameSound,
- &ITEMACCD_GameSound,
- &ITEMACCD_GameMusic,
+ &ITEMAC_GameSound,
+ &ITEMAC_GameSound,
ARRAYSIZE(ITEMacPatch_Files),
ITEMacPatch_Files,
},
@@ -570,11 +425,10 @@ static const SAGAGameDescription gameDescriptions[] = {
GF_WYRMKEEP | GF_CD_FX,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITECD_GameFonts),
- ITECD_GameFonts,
- &ITEMACCD_GameSound,
- &ITECD_GameSound,
- &ITEMACCD_GameMusic,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ &ITEMAC_GameSound,
+ &ITEPC_GameSound,
0,
NULL,
},
@@ -601,11 +455,10 @@ static const SAGAGameDescription gameDescriptions[] = {
GF_CD_FX,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITECD_GameFonts),
- ITECD_GameFonts,
- &ITECD_GameSound,
- &ITECD_GameSound,
- &ITEMACCD_GameMusic,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ &ITEPC_GameSound,
+ &ITEPC_GameSound,
ARRAYSIZE(ITEPatch_Files),
ITEPatch_Files,
},
@@ -631,11 +484,10 @@ static const SAGAGameDescription gameDescriptions[] = {
GF_CD_FX,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITECD_GameFonts),
- ITECD_GameFonts,
- &ITECD_GameSound,
- &ITECD_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ &ITEPC_GameSound,
+ &ITEPC_GameSound,
ARRAYSIZE(ITEPatch_Files),
ITEPatch_Files,
},
@@ -662,11 +514,10 @@ static const SAGAGameDescription gameDescriptions[] = {
GF_CD_FX,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITECD_GameFonts),
- ITECD_GameFonts,
- &ITECD_GameSound,
- &ITECD_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
+ &ITEPC_GameSound,
+ &ITEPC_GameSound,
0,
NULL,
},
@@ -694,11 +545,10 @@ static const SAGAGameDescription gameDescriptions[] = {
0,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITEDISK_GameFonts),
- ITEDISK_GameFonts,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
&ITEDISK_GameSound,
&ITEDISK_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
0,
NULL,
},
@@ -723,11 +573,10 @@ static const SAGAGameDescription gameDescriptions[] = {
0,
ITE_DEFAULT_SCENE,
&ITE_Resources,
- ARRAYSIZE(ITEDISK_GameFonts),
- ITEDISK_GameFonts,
+ ARRAYSIZE(ITE_GameFonts),
+ ITE_GameFonts,
&ITEDISK_GameSound,
&ITEDISK_GameSound,
- &ITEMACCD_GameMusic, // note: this version did not originally have digital music
ARRAYSIZE(ITEPatch_Files),
ITEPatch_Files,
},
@@ -766,7 +615,6 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMDEMO_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
@@ -805,7 +653,6 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
@@ -845,7 +692,6 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
@@ -884,7 +730,6 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
@@ -923,12 +768,12 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
// I Have No Mouth And I Must Scream - Fr CD version
+ // Censored CD version (without Nimdok)
{
{
"ihnm",
@@ -961,11 +806,10 @@ static const SAGAGameDescription gameDescriptions[] = {
IHNMCD_GameFonts,
&IHNM_GameSound,
&IHNM_GameSound,
- NULL,
0,
NULL,
},
- { AD_TABLE_END_MARKER, 0, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, 0, NULL }
+ { AD_TABLE_END_MARKER, 0, 0, 0, 0, NULL, 0, NULL, NULL, NULL, 0, NULL }
};
} // End of namespace Saga
diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h
index 74bbcc4343..d7d51a1e9f 100644
--- a/engines/saga/displayinfo.h
+++ b/engines/saga/displayinfo.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL:https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/branches/gsoc2007-fsnode/engines/saga/displayinfo.h $
- * $Id:displayinfo.h 26949 2007-05-26 20:23:24Z david_corrales $
+ * $URL$
+ * $Id$
*
*/
@@ -280,7 +280,7 @@ static const GameDisplayInfo ITE_DisplayInfo = {
};
-//TODO: ihnm
+// IHNM
#define IHNM_CONVERSE_MAX_TEXT_WIDTH (485 - 8)
#define IHNM_CONVERSE_TEXT_HEIGHT 10
#define IHNM_CONVERSE_TEXT_LINES 11
@@ -330,20 +330,20 @@ static PanelButton IHNM_OptionPanelButtons[] = {
{kPanelButtonOptionText,60,61, 0,0, kTextMusic,'-',0, 0,0,0}, // text: music
{kPanelButtonOptionText,60,86, 0,0, kTextSound,'-',0, 0,0,0}, // text: noise
{kPanelButtonOptionText,56,111, 0,0, kTextVoices,'-',0, 0,0,0}, // text: voices
- {kPanelButtonOption, 153,29, 79,23, kTextReadingSpeed,'r',0, 0,0,0}, //read speed
- {kPanelButtonOption, 153,54, 79,23, kTextMusic,'m',0, 0,0,0}, //music
- {kPanelButtonOption, 153,79, 79,23, kTextSound,'n',0, 0,0,0}, //sound-noise
- {kPanelButtonOption, 153,104,79,23, kTextVoices,'v',0, 0,0,0}, //voices
- {kPanelButtonOption, 19,149, 200,25, kTextQuitGame,'q',0, 0,0,0}, //quit
- {kPanelButtonOption, 19,177, 200,25, kTextContinuePlaying,'c',0, 0,0,0}, //continue
+ {kPanelButtonOption, 154,30, 79,23, kTextReadingSpeed,'r',0, 0,0,0}, //read speed
+ {kPanelButtonOption, 154,55, 79,23, kTextMusic,'m',0, 0,0,0}, //music
+ {kPanelButtonOption, 154,80, 79,23, kTextSound,'n',0, 0,0,0}, //sound-noise
+ {kPanelButtonOption, 154,105,79,23, kTextVoices,'v',0, 0,0,0}, //voices
+ {kPanelButtonOption, 20,150, 200,25, kTextQuitGame,'q',0, 0,0,0}, //quit
+ {kPanelButtonOption, 20,178, 200,25, kTextContinuePlaying,'c',0, 0,0,0}, //continue
{kPanelButtonOptionSaveFiles, 244,18, 170,138, 0,'-',0, 0,0,0}, //savefiles
- {kPanelButtonOption, 242,162, 79,23, kTextLoad,'l',0, 0,0,0}, //load
- {kPanelButtonOption, 333,162, 79,23, kTextSave,'s',0, 0,0,0}, //save
+ {kPanelButtonOption, 243,163, 79,23, kTextLoad,'l',0, 0,0,0}, //load
+ {kPanelButtonOption, 334,163, 79,23, kTextSave,'s',0, 0,0,0}, //save
};
static PanelButton IHNM_QuitPanelButtons[] = {
- {kPanelButtonQuit, 25,79, 80,25, kTextQuit,'q',0, 0,0,0},
- {kPanelButtonQuit, 155,79, 80,25, kTextCancel,'c',0, 0,0,0},
+ {kPanelButtonQuit, 26,80, 80,25, kTextQuit,'q',0, 0,0,0},
+ {kPanelButtonQuit, 156,80, 80,25, kTextCancel,'c',0, 0,0,0},
{kPanelButtonQuitText, 75,30, 0,0, kTextQuitTheGameQuestion,'-',0, 0,0,0},
};
@@ -354,11 +354,10 @@ static PanelButton IHNM_LoadPanelButtons[] = {
};
static PanelButton IHNM_SavePanelButtons[] = {
- // TODO
{kPanelButtonSave, 25,79, 80,25, kTextSave,'s',0, 0,0,0},
{kPanelButtonSave, 155,79, 80,25, kTextCancel,'c',0, 0,0,0},
- {kPanelButtonSaveEdit, 26,57, 209,17, 0,'-',0, 0,0,0},
- {kPanelButtonSaveText, 75,30, 0,0, kTextEnterSaveGameName,'-',0, 0,0,0},
+ {kPanelButtonSaveEdit, 22,56, 216,17, 0,'-',0, 0,0,0},
+ {kPanelButtonSaveText, 74,30, 0,0, kTextEnterSaveGameName,'-',0, 0,0,0},
};
diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp
index 80e6b58595..50297b7ef0 100644
--- a/engines/saga/events.cpp
+++ b/engines/saga/events.cpp
@@ -154,10 +154,12 @@ int Events::handleContinuous(Event *event) {
case kEventBlackToPal:
_vm->_gfx->blackToPal((PalEntry *)event->data, event_pc);
break;
-
case kEventPalToBlack:
_vm->_gfx->palToBlack((PalEntry *)event->data, event_pc);
break;
+ case kEventPalFade:
+ _vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc);
+ break;
default:
break;
}
@@ -237,10 +239,12 @@ int Events::handleImmediate(Event *event) {
case kEventBlackToPal:
_vm->_gfx->blackToPal((PalEntry *)event->data, event_pc);
break;
-
case kEventPalToBlack:
_vm->_gfx->palToBlack((PalEntry *)event->data, event_pc);
break;
+ case kEventPalFade:
+ _vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc);
+ break;
default:
break;
}
@@ -251,6 +255,7 @@ int Events::handleImmediate(Event *event) {
case kSceneEvent:
case kAnimEvent:
case kCutawayEvent:
+ case kActorEvent:
handleOneShot(event);
event_done = true;
break;
@@ -338,11 +343,22 @@ int Events::handleOneShot(Event *event) {
if (event->param == kEvPSetPalette) {
PalEntry *palPointer;
+
+ if (_vm->getGameType() == GType_IHNM) {
+ if (_vm->_spiritualBarometer > 255)
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff);
+ else
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.red / 256,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.green / 256,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.blue / 256);
+ }
+
_vm->_scene->getBGPal(palPointer);
_vm->_gfx->setPalette(palPointer);
}
}
- _vm->_actor->showActors(true);
+ _vm->_render->clearFlag(RF_DISABLE_ACTORS);
}
break;
case kPsychicProfileBgEvent:
@@ -374,7 +390,7 @@ int Events::handleOneShot(Event *event) {
free(buf);
free(resourceData);
- // Draw the scene. It won't be drawn by Render::drawScene(), as the RF_PLACARD is set
+ // Draw the scene. It won't be drawn by Render::drawScene(), as a placard is up
_vm->_scene->draw();
}
break;
@@ -455,6 +471,9 @@ int Events::handleOneShot(Event *event) {
case kEventSetFadeMode:
_vm->_interface->setFadeMode(event->param);
break;
+ case kEventRestoreMode:
+ _vm->_interface->restoreMode();
+ break;
default:
break;
}
@@ -530,6 +549,17 @@ int Events::handleOneShot(Event *event) {
case kEventClear:
_vm->_anim->clearCutaway();
break;
+ case kEventShowCutawayBg:
+ _vm->_anim->showCutawayBg(event->param);
+ break;
+ default:
+ break;
+ }
+ case kActorEvent:
+ switch (event->op) {
+ case kEventMove:
+ // TODO (check Actor::direct)
+ break;
default:
break;
}
diff --git a/engines/saga/events.h b/engines/saga/events.h
index 2486525751..de4d296eab 100644
--- a/engines/saga/events.h
+++ b/engines/saga/events.h
@@ -69,21 +69,20 @@ enum EventOps {
// BG events
kEventDisplay = 1,
// ANIM events
- // kEventPlay = 1, // reused
- // kEventStop = 2, // reused
+ kEventPlay = 1, // used in music and sound events too
+ kEventStop = 2, // used in music and sound events too
kEventFrame = 3,
- kEventSetFlag = 4,
- kEventClearFlag = 5,
+ kEventSetFlag = 4, // used in graphics events too
+ kEventClearFlag = 5, // used in graphics events too
kEventResumeAll = 6,
- // MUISC & SOUND events
- kEventPlay = 1,
- kEventStop = 2,
+ // MUSIC and SOUND events
+ // Reused: kEventPlay, kEventStop
// SCENE events
kEventDraw = 1,
kEventEnd = 2,
// TEXT events
- kEventHide = 2,
kEventRemove = 3,
+ // Reused: kEventHide
// PALANIM events
kEventCycleStart = 1,
kEventCycleStep = 2,
@@ -93,6 +92,7 @@ enum EventOps {
kEventSetStatus = 3,
kEventClearStatus = 4,
kEventSetFadeMode = 5,
+ kEventRestoreMode = 6,
// ACTOR events
kEventMove = 1,
// SCRIPT events
@@ -101,23 +101,24 @@ enum EventOps {
kEventThreadWake = 3,
// CURSOR events
kEventShow = 1,
- // kEventHide = 2, // reused
+ kEventHide = 2, // used in text events too
kEventSetNormalCursor = 3,
kEventSetBusyCursor = 4,
// GRAPHICS events
kEventFillRect = 1,
- // kEventSetFlag = 4, // reused
- // kEventClearFlag = 5, // reused
-
+ // Reused: kEventSetFlag, kEventClearFlag
// CONTINUOUS events
+ //
// PALETTE events
kEventPalToBlack = 1,
kEventBlackToPal = 2,
+ kEventPalFade = 3,
// TRANSITION events
kEventDissolve = 1,
kEventDissolveBGMask = 2,
// CUTAWAY events
- kEventClear = 1
+ kEventClear = 1,
+ kEventShowCutawayBg = 2
};
enum EventParams {
diff --git a/engines/saga/font.cpp b/engines/saga/font.cpp
index 71cd6b0eef..06e51a78e4 100644
--- a/engines/saga/font.cpp
+++ b/engines/saga/font.cpp
@@ -49,6 +49,7 @@ Font::Font(SagaEngine *vm) : _vm(vm), _initialized(false) {
}
_initialized = true;
+ _fontMapping = 0;
}
Font::~Font(void) {
@@ -325,14 +326,29 @@ void Font::outFont(const FontStyle &drawFont, Surface *ds, const char *text, siz
c_code = *textPointer & 0xFFU;
// Translate character
- if (!(flags & kFontDontmap))
+ if (_fontMapping == 0) { // Check font mapping debug flag
+ // Default game behavior
+
+ // It seems that this font mapping causes problems with non-english
+ // versions of IHNM, so it has been changed to apply for ITE only.
+ // It doesn't make any difference for the English version of IHNM.
+ // Fixes bug #1796045: "IHNM: Spanish font wrong".
+ if (!(flags & kFontDontmap) && _vm->getGameType() == GType_ITE)
+ c_code = _charMap[c_code];
+ } else if (_fontMapping == 1) {
+ // Force font mapping
c_code = _charMap[c_code];
+ } else {
+ // In all other cases, ignore font mapping
+ }
assert(c_code < FONT_CHARCOUNT);
// Check if character is defined
if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) {
#if FONT_SHOWUNDEFINED
- if (c_code == FONT_CH_SPACE || c_code == 9) {
+ // A tab character appears in the IHNM demo instructions screen, so filter
+ // it out here
+ if (c_code == FONT_CH_SPACE || c_code == FONT_CH_TAB) {
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
continue;
}
@@ -632,8 +648,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) {
// The demo version of IHNM has 3 font types (like ITE), not 6 (like the full version of IHNM)
if (_vm->getGameType() == GType_ITE || _vm->getGameId() == GID_IHNM_DEMO) {
- switch (font)
- {
+ switch (font) {
case (kKnownFontSmall):
fontId = kSmallFont;
break;
@@ -655,8 +670,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) {
break;
}
} else if (_vm->getGameType() == GType_IHNM && _vm->getGameId() != GID_IHNM_DEMO) {
- switch (font)
- {
+ switch (font) {
case (kKnownFontSmall):
fontId = kSmallFont;
break;
diff --git a/engines/saga/font.h b/engines/saga/font.h
index 5823513e0f..16fdfc22b9 100644
--- a/engines/saga/font.h
+++ b/engines/saga/font.h
@@ -39,6 +39,7 @@ namespace Saga {
// have a valid offset of '0'
#define FONT_FIRSTCHAR 33
+#define FONT_CH_TAB 9
#define FONT_CH_SPACE 32
#define FONT_CH_QMARK 63
@@ -140,8 +141,11 @@ class Font {
}
void textDrawRect(KnownFont font, Surface *ds, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags) {
textDrawRect(knownFont2FontIdx(font), ds, text, rect, color, effectColor, flags);
+ }
+ void setFontMapping(int mapping) {
+ _fontMapping = mapping;
}
-
+
private:
enum FontId {
kSmallFont,
@@ -196,6 +200,7 @@ class Font {
SagaEngine *_vm;
bool _initialized;
+ int _fontMapping;
int _loadedFonts;
FontData **_fonts;
diff --git a/engines/saga/gfx.cpp b/engines/saga/gfx.cpp
index 56ffe04c96..8509da62ed 100644
--- a/engines/saga/gfx.cpp
+++ b/engines/saga/gfx.cpp
@@ -356,8 +356,6 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
// Exponential fade
fpercent = percent * percent;
- fpercent = 1.0 - fpercent;
-
// Use the correct percentage change per frame for each palette entry
for (i = 0, ppal = _currentPal; i < PAL_ENTRIES; i++, ppal += 4) {
if (i < from || i >= from + numcolors)
@@ -365,7 +363,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
else
palE = &srcPal[i];
- new_entry = (int)(palE->red - palE->red * fpercent);
+ new_entry = (int)(palE->red * fpercent);
if (new_entry < 0) {
ppal[0] = 0;
@@ -373,7 +371,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
ppal[0] = (byte)new_entry;
}
- new_entry = (int)(palE->green - palE->green * fpercent);
+ new_entry = (int)(palE->green * fpercent);
if (new_entry < 0) {
ppal[1] = 0;
@@ -381,7 +379,7 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
ppal[1] = (byte) new_entry;
}
- new_entry = (int)(palE->blue - palE->blue * fpercent);
+ new_entry = (int)(palE->blue * fpercent);
if (new_entry < 0) {
ppal[2] = 0;
@@ -402,7 +400,79 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
_system->setPalette(_currentPal, 0, PAL_ENTRIES);
}
+// Used in IHNM only
+void Gfx::palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 numColors, double percent) {
+ int i;
+ int new_entry;
+ byte *ppal;
+ PalEntry *palE;
+ double fpercent;
+
+ from = from > 256 ? 256 : from;
+ from = from < 0 ? 0 : from;
+ to = to > 256 ? 256 : to;
+ to = to < 0 ? 0 : to;
+
+ if (from == 0 || to == 0) {
+ // This case works like palToBlack or blackToPal, so no changes are needed
+ } else {
+ double x = from > to ? from / to : to / from;
+ percent /= x;
+ if (from < to)
+ percent += 1 / x;
+ }
+
+ // Exponential fade
+ percent = percent > 1.0 ? 1.0 : percent;
+ fpercent = percent * percent;
+
+ if (from > to)
+ fpercent = 1.0 - fpercent;
+
+ // Use the correct percentage change per frame for each palette entry
+ for (i = 0, ppal = _currentPal; i < PAL_ENTRIES; i++, ppal += 4) {
+ if (i < start || i >= start + numColors)
+ palE = &_globalPalette[i];
+ else
+ palE = &srcPal[i];
+
+ new_entry = (int)(palE->red * fpercent);
+
+ if (new_entry < 0) {
+ ppal[0] = 0;
+ } else {
+ ppal[0] = (byte) new_entry;
+ }
+
+ new_entry = (int)(palE->green * fpercent);
+
+ if (new_entry < 0) {
+ ppal[1] = 0;
+ } else {
+ ppal[1] = (byte) new_entry;
+ }
+
+ new_entry = (int)(palE->blue * fpercent);
+
+ if (new_entry < 0) {
+ ppal[2] = 0;
+ } else {
+ ppal[2] = (byte) new_entry;
+ }
+ ppal[3] = 0;
+ }
+
+ // Color 0 should always be black in IHNM
+ memset(&_currentPal[0 * 4], 0, 4);
+
+ _system->setPalette(_currentPal, 0, PAL_ENTRIES);
+}
+
void Gfx::showCursor(bool state) {
+ // Don't show the mouse cursor in the non-interactive part of the IHNM demo
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart())
+ state = false;
+
CursorMan.showMouse(state);
}
diff --git a/engines/saga/gfx.h b/engines/saga/gfx.h
index 0fa7aab742..ea1370c79d 100644
--- a/engines/saga/gfx.h
+++ b/engines/saga/gfx.h
@@ -150,6 +150,7 @@ public:
void restorePalette() { setPalette(_savedPalette, true); }
void palToBlack(PalEntry *src_pal, double percent);
void blackToPal(PalEntry *src_pal, double percent);
+ void palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 numColors, double percent);
void showCursor(bool state);
void setCursor(CursorType cursorType = kCursorNormal);
diff --git a/engines/saga/ihnm_introproc.cpp b/engines/saga/ihnm_introproc.cpp
index 631da37e82..fcf69d1bd1 100644
--- a/engines/saga/ihnm_introproc.cpp
+++ b/engines/saga/ihnm_introproc.cpp
@@ -31,154 +31,52 @@
#include "saga/animation.h"
#include "saga/events.h"
#include "saga/interface.h"
+#include "saga/render.h"
#include "saga/rscfile.h"
#include "saga/sndres.h"
#include "saga/music.h"
#include "saga/scene.h"
-namespace Saga {
+#include "common/events.h"
-SceneResourceData IHNM_IntroMovie1RL[] = {
- {30, 2, 0, 0, false},
- {31, 14, 0, 0, false}
-};
-
-SceneDescription IHNM_IntroMovie1Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNM_IntroMovie1RL,
- ARRAYSIZE(IHNM_IntroMovie1RL)
-};
-
-SceneResourceData IHNM_IntroMovie2RL[] = {
- {32, 2, 0, 0, false},
- {33, 14, 0, 0, false}
-};
-
-SceneDescription IHNM_IntroMovie2Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNM_IntroMovie2RL,
- ARRAYSIZE(IHNM_IntroMovie2RL)
-};
-
-SceneResourceData IHNM_IntroMovie3RL[] = {
- {34, 2, 0, 0, false},
- {35, 14, 0, 0, false}
-};
-
-SceneDescription IHNM_IntroMovie3Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNM_IntroMovie3RL,
- ARRAYSIZE(IHNM_IntroMovie3RL)
-};
-
-SceneResourceData IHNM_IntroMovie4RL[] = {
- {1227, 2, 0, 0, false},
- {1226, 14, 0, 0, false}
-};
-
-SceneDescription IHNM_IntroMovie4Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNM_IntroMovie4RL,
- ARRAYSIZE(IHNM_IntroMovie4RL)
-};
-
-// Demo
-SceneResourceData IHNMDEMO_IntroMovie1RL[] = {
- {19, 2, 0, 0, false} // this scene doesn't have an animation
-};
-
-SceneDescription IHNMDEMO_IntroMovie1Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNMDEMO_IntroMovie1RL,
- ARRAYSIZE(IHNMDEMO_IntroMovie1RL)
-};
-
-SceneResourceData IHNMDEMO_IntroMovie2RL[] = {
- {22, 2, 0, 0, false},
- {23, 14, 0, 0, false}
-};
-
-SceneDescription IHNMDEMO_IntroMovie2Desc = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- IHNMDEMO_IntroMovie2RL,
- ARRAYSIZE(IHNMDEMO_IntroMovie2RL)
-};
-
-LoadSceneParams IHNM_IntroList[] = {
- {0, kLoadByDescription, &IHNM_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {0, kLoadByDescription, &IHNM_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc2, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {0, kLoadByDescription, &IHNM_IntroMovie3Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
-};
-
-LoadSceneParams IHNMDEMO_IntroList[] = {
- {0, kLoadByDescription, &IHNMDEMO_IntroMovie1Desc, Scene::SC_IHNMIntroMovieProc1, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
- {0, kLoadByDescription, &IHNMDEMO_IntroMovie2Desc, Scene::SC_IHNMIntroMovieProc3, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE},
-};
+namespace Saga {
// IHNM cutaway intro resource IDs
#define RID_IHNM_INTRO_CUTAWAYS 39
#define RID_IHNMDEMO_INTRO_CUTAWAYS 25
int Scene::IHNMStartProc() {
- size_t n_introscenes;
- size_t i;
-
LoadSceneParams firstScene;
- /*
- // Test code - uses loadCutawayList to load the intro cutaways, like the original
+ IHNMLoadCutaways();
- ResourceContext *resourceContext;
- //ResourceContext *soundContext;
- byte *resourcePointer;
- size_t resourceLength;
-
- resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
- if (resourceContext == NULL) {
- error("Scene::IHNMStartProc() resource context not found");
- }
-
- if (_vm->getGameId() != GID_IHNM_DEMO)
- _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength);
- else
- _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength);
-
- if (resourceLength == 0) {
- error("Scene::IHNMStartProc() Can't load cutaway list");
- }
-
- // Load the cutaways for the title screens
- _vm->_anim->loadCutawayList(resourcePointer, resourceLength);
-
- // Note that the resource ID needed is the returned ID minus one
- printf("%i\n", _vm->_anim->cutawayResourceID(0));
- printf("%i\n", _vm->_anim->cutawayResourceID(1));
- printf("%i\n", _vm->_anim->cutawayResourceID(2));
- */
-
- // The original used the "play video" mechanism for the first part of
- // the intro. We just use that panel mode.
-
- _vm->_anim->setCutAwayMode(kPanelVideo);
- _vm->_interface->setMode(kPanelVideo);
-
- if (_vm->getGameId() != GID_IHNM_DEMO)
- n_introscenes = ARRAYSIZE(IHNM_IntroList);
- else
- n_introscenes = ARRAYSIZE(IHNMDEMO_IntroList);
-
- // Queue the company and title videos
if (_vm->getGameId() != GID_IHNM_DEMO) {
- for (i = 0; i < n_introscenes; i++) {
- _vm->_scene->queueScene(&IHNM_IntroList[i]);
+ int logoLength = -168;
+
+ if (_vm->getLanguage() == Common::DE_DEU || _vm->getLanguage() == Common::ES_ESP)
+ logoLength = -128;
+
+ // Play Cyberdreams logo for 168 frames
+ if (!playTitle(0, logoLength, true)) {
+ // Play Dreamers Guild logo for 10 seconds
+ if (!playLoopingTitle(1, 10)) {
+ // Play the title music
+ _vm->_music->play(1, MUSIC_NORMAL);
+ // Play title screen
+ playTitle(2, 17);
+ }
}
} else {
- for (i = 0; i < n_introscenes; i++) {
- _vm->_scene->queueScene(&IHNMDEMO_IntroList[i]);
- }
+ _vm->_music->play(1, MUSIC_NORMAL);
+ playTitle(0, 10);
+ playTitle(2, 12);
}
+ _vm->_music->setVolume(0, 1000);
+ _vm->_anim->freeCutawayList();
+
+ // Queue first scene
firstScene.loadFlag = kLoadBySceneNumber;
firstScene.sceneDescriptor = -1;
firstScene.sceneDescription = NULL;
@@ -193,241 +91,189 @@ int Scene::IHNMStartProc() {
return SUCCESS;
}
-int Scene::SC_IHNMIntroMovieProc1(int param, void *refCon) {
- return ((Scene *)refCon)->IHNMIntroMovieProc1(param);
-}
+int Scene::IHNMCreditsProc() {
+ IHNMLoadCutaways();
-int Scene::IHNMIntroMovieProc1(int param) {
- Event event;
- Event *q_event;
-
- switch (param) {
- case SCENE_BEGIN:
- // Background for intro scene is the first frame of the
- // intro animation; display it and set the palette
- event.type = kEvTOneshot;
- event.code = kBgEvent;
- event.op = kEventDisplay;
- event.param = kEvPSetPalette;
- event.time = 0;
-
- q_event = _vm->_events->queue(&event);
-
- if (_vm->getGameId() != GID_IHNM_DEMO) {
- _vm->_anim->setFrameTime(0, IHNM_INTRO_FRAMETIME);
- _vm->_anim->setFlag(0, ANIM_FLAG_ENDSCENE);
-
- event.type = kEvTOneshot;
- event.code = kAnimEvent;
- event.op = kEventPlay;
- event.param = 0;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
- } else {
- // Start playing the intro music for the demo version
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = 1;
- event.param2 = MUSIC_NORMAL;
- event.op = kEventPlay;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // The IHNM demo doesn't have an animation at the
- // Cyberdreans logo screen
-
- // Queue end of scene after a while
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- event.time = 8000;
-
- q_event = _vm->_events->chain(q_event, &event);
- }
+ _vm->_music->play(0, MUSIC_NORMAL);
- break;
- default:
- break;
+ if (_vm->getGameId() != GID_IHNM_DEMO) {
+ // Display the credits for 400 frames
+ playTitle(4, -400, true);
+ } else {
+ // Display sales info for 60 seconds
+ playTitle(3, 60, true);
}
- return 0;
-}
+ _vm->_music->setVolume(0, 1000);
+ _vm->_anim->freeCutawayList();
-int Scene::SC_IHNMIntroMovieProc2(int param, void *refCon) {
- return ((Scene *)refCon)->IHNMIntroMovieProc2(param);
+ return SUCCESS;
}
-int Scene::IHNMIntroMovieProc2(int param) {
- Event event;
- Event *q_event;
- PalEntry *pal;
-
- static PalEntry current_pal[PAL_ENTRIES];
-
- switch (param) {
- case SCENE_BEGIN:
- // Fade to black out of the intro CyberDreams logo anim
- _vm->_gfx->getCurrentPal(current_pal);
-
- event.type = kEvTContinuous;
- event.code = kPalEvent;
- event.op = kEventPalToBlack;
- event.time = 0;
- event.duration = IHNM_PALFADE_TIME;
- event.data = current_pal;
-
- q_event = _vm->_events->queue(&event);
-
- // Background for intro scene is the first frame of the
- // intro animation; display it but don't set palette
- event.type = kEvTOneshot;
- event.code = kBgEvent;
- event.op = kEventDisplay;
- event.param = kEvPNoSetPalette;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- _vm->_anim->setCycles(0, -1);
-
- // Unlike the original, we keep the logo spinning during the
- // palette fades. We don't have to, but I think it looks better
- // that way.
-
- event.type = kEvTOneshot;
- event.code = kAnimEvent;
- event.op = kEventPlay;
- event.param = 0;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // Fade in from black to the scene background palette
- _vm->_scene->getBGPal(pal);
-
- event.type = kEvTContinuous;
- event.code = kPalEvent;
- event.op = kEventBlackToPal;
- event.time = 0;
- event.duration = IHNM_PALFADE_TIME;
- event.data = pal;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // Fade to black after looping animation for a while
- event.type = kEvTContinuous;
- event.code = kPalEvent;
- event.op = kEventPalToBlack;
- event.time = IHNM_DGLOGO_TIME;
- event.duration = IHNM_PALFADE_TIME;
- event.data = pal;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // Queue end of scene
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
- break;
- default:
- break;
+void Scene::IHNMLoadCutaways() {
+ ResourceContext *resourceContext;
+ //ResourceContext *soundContext;
+ byte *resourcePointer;
+ size_t resourceLength;
+
+ resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
+ if (resourceContext == NULL) {
+ error("Scene::IHNMStartProc() resource context not found");
}
- return 0;
-}
+ if (_vm->getGameId() != GID_IHNM_DEMO)
+ _vm->_resource->loadResource(resourceContext, RID_IHNM_INTRO_CUTAWAYS, resourcePointer, resourceLength);
+ else
+ _vm->_resource->loadResource(resourceContext, RID_IHNMDEMO_INTRO_CUTAWAYS, resourcePointer, resourceLength);
-int Scene::SC_IHNMIntroMovieProc3(int param, void *refCon) {
- return ((Scene *)refCon)->IHNMIntroMovieProc3(param);
-}
+ if (resourceLength == 0) {
+ error("Scene::IHNMStartProc() Can't load cutaway list");
+ }
-int Scene::IHNMIntroMovieProc3(int param) {
- Event event;
- Event *q_event;
- PalEntry *pal;
- static PalEntry current_pal[PAL_ENTRIES];
+ // Load the cutaways for the title screens
+ _vm->_anim->loadCutawayList(resourcePointer, resourceLength);
+}
- switch (param) {
- case SCENE_BEGIN:
- // Fade to black out of the intro DG logo anim
- _vm->_gfx->getCurrentPal(current_pal);
+bool Scene::checkKey() {
+ Common::Event event;
+ bool res = false;
+
+ while (_vm->_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ _vm->shutDown();
+ // fallthrough
+ case Common::EVENT_KEYDOWN:
+ res = true;
+ break;
+ default:
+ break;
+ }
+ }
- event.type = kEvTContinuous;
- event.code = kPalEvent;
- event.op = kEventPalToBlack;
- event.time = 0;
- event.duration = IHNM_PALFADE_TIME;
- event.data = current_pal;
+ return res;
+}
- q_event = _vm->_events->queue(&event);
+bool Scene::playTitle(int title, int time, int mode) {
+ bool interrupted = false;
+ Surface *backBufferSurface;
+ int startTime = _vm->_system->getMillis();
+ int frameTime = 0;
+ int curTime;
+ int assignedId;
+ int phase = 0;
+ bool done = false;
+ bool playParameter = true;
+ static PalEntry cur_pal[PAL_ENTRIES];
+ static PalEntry pal_cut[PAL_ENTRIES];
+
+ backBufferSurface = _vm->_render->getBackGroundSurface();
+
+ // Load the cutaway
+
+ _vm->_anim->setCutAwayMode(mode);
+ _vm->_frameCount = 0;
+
+ _vm->_gfx->getCurrentPal(cur_pal);
+
+ assignedId = _vm->_anim->playCutaway(title, false);
+
+ _vm->_gfx->getCurrentPal(pal_cut);
+
+ while (!done) {
+ curTime = _vm->_system->getMillis();
+
+ switch (phase) {
+ case 0: // fadeout
+ case 1: // fadeout 100%
+ case 7: // fadeout
+ case 8: // fadeout 100%
+ _vm->_gfx->palToBlack(cur_pal, (double)(curTime - startTime) / kNormalFadeDuration);
+ // fall through
+
+ case 3: // fadein
+ case 4: // fadein 100%
+ if (phase == 3 || phase == 4)
+ _vm->_gfx->blackToPal(pal_cut, (double)(curTime - startTime) / kNormalFadeDuration);
+
+ if (curTime - startTime > kNormalFadeDuration) {
+ phase++;
+ if (phase == 2 || phase == 5 || phase == 9)
+ startTime = curTime;
+ break;
+ }
+ break;
+
+ case 2: // display background
+ _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0,
+ backBufferSurface->w, backBufferSurface->h);
+ phase++;
+ startTime = curTime;
+ break;
+
+ case 5: // playback
+ if (time < 0) {
+ if (_vm->_frameCount >= -time) {
+ phase++;
+ break;
+ }
+ } else {
+ if (curTime - startTime >= time * 1000) {
+ phase++;
+ break;
+ }
+ }
+
+ if (checkKey()) {
+ interrupted = true;
+ done = true;
+ break;
+ }
+
+ if (_vm->_anim->getCycles(assignedId)) { // IHNM demo has 0 frames logo
+ if (curTime - frameTime > _vm->_anim->getFrameTime(assignedId)) {
+ _vm->_anim->play(assignedId, 0, playParameter);
+
+ if (playParameter == true) // Do not loop animations
+ playParameter = false;
+
+ frameTime = curTime;
+
+ _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0,
+ backBufferSurface->w, backBufferSurface->h);
+ }
+
+ }
+ break;
+
+ case 6: // playback end
+ startTime = curTime;
+ _vm->_gfx->getCurrentPal(cur_pal);
+ phase++;
+ break;
+
+ case 9: // end
+ done = true;
+ break;
+ }
- // Music, maestro
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(10);
+ }
- // In the GM file, this music also appears as tracks 7, 13, 19,
- // 25 and 31, but only track 1 sounds right with the FM music.
+ // Clean up
- if (_vm->getGameId() != GID_IHNM_DEMO) {
- event.type = kEvTOneshot;
- event.code = kMusicEvent;
- event.param = 1;
- event.param2 = MUSIC_NORMAL;
- event.op = kEventPlay;
- event.time = 0;
+ _vm->_anim->endVideo();
- q_event = _vm->_events->chain(q_event, &event);
- }
+ memset((byte *)backBufferSurface->pixels, 0, backBufferSurface->w * backBufferSurface->h);
+ _vm->_system->copyRectToScreen((byte *)backBufferSurface->pixels, backBufferSurface->w, 0, 0,
+ backBufferSurface->w, backBufferSurface->h);
- // Background for intro scene is the first frame of the intro
- // animation; display it but don't set palette
- event.type = kEvTOneshot;
- event.code = kBgEvent;
- event.op = kEventDisplay;
- event.param = kEvPNoSetPalette;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // Fade in from black to the scene background palette
- _vm->_scene->getBGPal(pal);
-
- event.type = kEvTContinuous;
- event.code = kPalEvent;
- event.op = kEventBlackToPal;
- event.time = 0;
- event.duration = IHNM_PALFADE_TIME;
- event.data = pal;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- event.type = kEvTOneshot;
- event.code = kAnimEvent;
- event.op = kEventPlay;
- event.param = 0;
- event.time = 0;
-
- q_event = _vm->_events->chain(q_event, &event);
-
- // Queue end of scene after a while
- // The delay has been increased so the speech won't start until the music has ended
- event.type = kEvTOneshot;
- event.code = kSceneEvent;
- event.op = kEventEnd;
- if (_vm->getGameId() != GID_IHNM_DEMO)
- event.time = _vm->_music->hasAdlib() ? IHNM_TITLE_TIME_FM : IHNM_TITLE_TIME_GM;
- else
- event.time = 12000;
-
- q_event = _vm->_events->chain(q_event, &event);
- break;
- default:
- break;
- }
+ return interrupted;
+}
- return 0;
+bool Scene::playLoopingTitle(int title, int seconds) {
+ return playTitle(title, seconds, kPanelCutaway);
}
} // End of namespace Saga
diff --git a/engines/saga/input.cpp b/engines/saga/input.cpp
index 358a225efa..5082ec7aca 100644
--- a/engines/saga/input.cpp
+++ b/engines/saga/input.cpp
@@ -49,7 +49,7 @@ int SagaEngine::processInput() {
_console->attach();
}
if (_interface->_textInput || _interface->_statusTextInput) {
- _interface->processAscii(event.kbd.ascii);
+ _interface->processAscii(event.kbd);
return SUCCESS;
}
@@ -115,7 +115,7 @@ int SagaEngine::processInput() {
_render->toggleFlag(RF_RENDERPAUSE);
break;
default:
- _interface->processAscii(event.kbd.ascii);
+ _interface->processAscii(event.kbd);
break;
}
break;
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index 8cfd993391..e6854b1c05 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -229,6 +229,12 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites);
// Option panel sprites
_vm->_sprite->loadList(_vm->getResourceDescription()->optionPanelSpritesResourceId, _optionPanel.sprites);
+ // Save panel sprites
+ _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _savePanel.sprites);
+ // Load panel sprites
+ _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _loadPanel.sprites);
+ // Quit panel sprites
+ _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _quitPanel.sprites);
if (_vm->getGameType() == GType_ITE) {
_vm->_sprite->loadList(_vm->getResourceDescription()->defaultPortraitsResourceId, _defPortraits);
@@ -342,18 +348,10 @@ int Interface::activate() {
} else if (_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO) {
_saveReminderState = 1;
}
+ _vm->_gfx->showCursor(true);
draw();
}
- if (_vm->getGameId() != GID_IHNM_DEMO) {
- _vm->_gfx->showCursor(true);
- } else {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) {
- // Don't show the mouse cursor in the non-interactive part of the IHNM demo
- } else {
- _vm->_gfx->showCursor(true);
- }
- }
return SUCCESS;
}
@@ -369,7 +367,7 @@ int Interface::deactivate() {
}
void Interface::rememberMode() {
- debug(1, "rememberMode(%d)", _savedMode);
+ debug(1, "rememberMode(%d)", _panelMode);
_savedMode = _panelMode;
}
@@ -400,9 +398,6 @@ void Interface::setMode(int mode) {
if (_vm->getGameId() == GID_IHNM_DEMO) {
_inMainMode = true;
_saveReminderState = 1;
- if ((_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149) ||
- _vm->_scene->currentSceneNumber() == 0 || _vm->_scene->currentSceneNumber() == -1)
- _vm->_gfx->showCursor(false);
}
} else if (mode == kPanelOption) {
// Show the cursor in the IHNM demo
@@ -420,8 +415,8 @@ void Interface::setMode(int mode) {
switch (_panelMode) {
case kPanelMain:
- if (_vm->getGameType() == GType_IHNM)
- warning("FIXME: Implement IHNM differences from ExecuteInventoryPanel");
+ // FIXME: Implement IHNM differences from ExecuteInventoryPanel for IHNM (though I believe they're already
+ // implemented)
_mainPanel.currentButton = NULL;
break;
@@ -481,22 +476,22 @@ void Interface::setMode(int mode) {
draw();
}
-bool Interface::processAscii(uint16 ascii) {
+bool Interface::processAscii(Common::KeyState keystate) {
// TODO: Checking for Esc and Enter below is a bit hackish, and
// and probably only works with the English version. Maybe we should
// add a flag to the button so it can indicate if it's the default or
// cancel button?
-
+ uint16 ascii = keystate.ascii;
int i;
PanelButton *panelButton;
if (_statusTextInput) {
- processStatusTextInput(ascii);
+ processStatusTextInput(keystate);
return true;
}
switch (_panelMode) {
case kPanelNull:
- if (ascii == 27) { // Esc
+ if (keystate.keycode == Common::KEYCODE_ESCAPE) {
if (_vm->_scene->isInIntro()) {
_vm->_scene->skipScene();
} else {
@@ -506,26 +501,22 @@ bool Interface::processAscii(uint16 ascii) {
return true;
}
- if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- _vm->_scene->showIHNMDemoSpecialScreen();
- }
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart())
+ _vm->_scene->showIHNMDemoSpecialScreen();
break;
case kPanelCutaway:
- if (ascii == 27) { // Esc
+ if (keystate.keycode == Common::KEYCODE_ESCAPE) {
if (!_disableAbortSpeeches)
_vm->_actor->abortAllSpeeches();
_vm->_scene->cutawaySkip();
return true;
}
- if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- _vm->_scene->showIHNMDemoSpecialScreen();
- }
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart())
+ _vm->_scene->showIHNMDemoSpecialScreen();
break;
case kPanelVideo:
- if (ascii == 27) { // Esc
+ if (keystate.keycode == Common::KEYCODE_ESCAPE) {
if (_vm->_scene->isInIntro()) {
_vm->_scene->skipScene();
} else {
@@ -536,14 +527,12 @@ bool Interface::processAscii(uint16 ascii) {
return true;
}
- if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- _vm->_scene->showIHNMDemoSpecialScreen();
- }
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart())
+ _vm->_scene->showIHNMDemoSpecialScreen();
break;
case kPanelOption:
// TODO: check input dialog keys
- if (ascii == 27 || ascii == 13) { // Esc or Enter
+ if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) { // Esc or Enter
ascii = 'c'; //continue
}
@@ -558,13 +547,13 @@ bool Interface::processAscii(uint16 ascii) {
}
break;
case kPanelSave:
- if (_textInput && processTextInput(ascii)) {
+ if (_textInput && processTextInput(keystate)) {
return true;
}
- if (ascii == 27) { // Esc
+ if (keystate.keycode == Common::KEYCODE_ESCAPE) {
ascii = 'c'; // cancel
- } else if (ascii == 13) { // Enter
+ } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter
ascii = 's'; // save
}
@@ -579,9 +568,9 @@ bool Interface::processAscii(uint16 ascii) {
}
break;
case kPanelQuit:
- if (ascii == 27) { // Esc
+ if (keystate.keycode == Common::KEYCODE_ESCAPE) {
ascii = 'c'; // cancel
- } else if (ascii == 13) { // Enter
+ } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter
ascii = 'q'; // quit
}
@@ -619,8 +608,7 @@ bool Interface::processAscii(uint16 ascii) {
return true;
}
}
- if (ascii == 15) // ctrl-o
- {
+ if (keystate.keycode == Common::KEYCODE_o && keystate.flags == Common::KBD_CTRL) { // ctrl-o
if (_saveReminderState > 0) {
setMode(kPanelOption);
return true;
@@ -663,7 +651,7 @@ bool Interface::processAscii(uint16 ascii) {
mapPanelClean();
break;
case kPanelSceneSubstitute:
- if (ascii == 13) {
+ if (keystate.keycode == Common::KEYCODE_RETURN) {
_vm->_render->clearFlag(RF_DEMO_SUBST);
_vm->_gfx->setPalette(_mapSavedPal);
setMode(kPanelMain);
@@ -678,11 +666,11 @@ bool Interface::processAscii(uint16 ascii) {
break;
case kPanelProtect:
if (_vm->getGameType() == GType_ITE) {
- if (_textInput && processTextInput(ascii)) {
+ if (_textInput && processTextInput(keystate)) {
return true;
}
- if (ascii == 27 || ascii == 13) { // Esc or Enter
+ if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) {
_vm->_script->wakeUpThreads(kWaitTypeRequest);
_vm->_interface->setMode(kPanelMain);
@@ -725,7 +713,7 @@ void Interface::setStatusText(const char *text, int statusColor) {
assert(text != NULL);
assert(strlen(text) < STATUS_TEXT_LEN);
- if (_vm->_render->getFlags() & (RF_PLACARD | RF_MAP))
+ if (_vm->_render->getFlags() & RF_MAP || _vm->_interface->getMode() == kPanelPlacard)
return;
strncpy(_statusText, text, STATUS_TEXT_LEN);
@@ -801,16 +789,6 @@ void Interface::draw() {
converseDisplayTextLines(backBuffer);
}
- if (_vm->getGameType() == GType_IHNM) {
- if (_vm->_spiritualBarometer > 255)
- _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff);
- else
- _vm->_gfx->setPaletteColor(kIHNMColorPortrait,
- _vm->_spiritualBarometer * _portraitBgColor.red / 256,
- _vm->_spiritualBarometer * _portraitBgColor.green / 256,
- _vm->_spiritualBarometer * _portraitBgColor.blue / 256);
- }
-
if (_panelMode == kPanelMain || _panelMode == kPanelConverse ||
_lockedMode == kPanelMain || _lockedMode == kPanelConverse ||
(_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) {
@@ -841,14 +819,19 @@ void Interface::calcOptionSaveSlider() {
int totalFiles = _vm->getSaveFilesCount();
int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
int height = _optionSaveFileSlider->height;
- int sliderHeight;
+ int sliderHeight = 13; // IHNM's save file list slider has a fixed height
int pos;
if (totalFiles < visibleFiles) {
totalFiles = visibleFiles;
}
- sliderHeight = visibleFiles * height / totalFiles;
+ if (_vm->getGameType() == GType_ITE) {
+ // ITE's save file list slider has a dynamically computed height, depending on
+ // the number of save games
+ sliderHeight = visibleFiles * height / totalFiles;
+ }
+
if (sliderHeight < 7) {
sliderHeight = 7;
}
@@ -931,6 +914,7 @@ void Interface::drawOption() {
PanelButton *panelButton;
Point textPoint;
Point point;
+ Point sliderPoint;
int spritenum = 0;
backBuffer = _vm->_gfx->getBackBuffer();
@@ -959,7 +943,15 @@ void Interface::drawOption() {
backBuffer->drawRect(_optionSaveRectTop, kITEColorDarkGrey);
}
- drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0);
+ if (_vm->getGameType() == GType_ITE) {
+ drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0);
+ } else {
+ panelButton = &_optionPanel.buttons[0];
+ sliderPoint.x = _optionPanel.x + panelButton->xOffset;
+ sliderPoint.y = _optionSaveRectSlider.top;
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _optionPanel.sprites, 0 + _optionSaveFileSlider->state, sliderPoint, 256);
+
+ }
if (_optionSaveRectBottom.height() > 0) {
backBuffer->drawRect(_optionSaveRectBottom, kITEColorDarkGrey);
@@ -970,7 +962,10 @@ void Interface::drawOption() {
rect2 = rect;
fontHeight = _vm->_font->getHeight(kKnownFontSmall);
for (j = 0; j < _vm->getDisplayInfo().optionSaveFileVisible; j++) {
- bgColor = kITEColorDarkGrey0C;
+ if (_vm->getGameType() == GType_ITE)
+ bgColor = kITEColorDarkGrey0C;
+ else
+ bgColor = kIHNMColorBlack;
fgColor = kITEColorBrightWhite;
idx = j + _optionSaveFileTop;
@@ -1052,7 +1047,10 @@ void Interface::setQuit(PanelButton *panelButton) {
setMode(kPanelOption);
break;
case kTextQuit:
- _vm->shutDown();
+ if (_vm->getGameId() == GID_IHNM_DEMO)
+ _vm->_scene->creditsScene(); // display sales info for IHNM demo
+ else
+ _vm->shutDown();
break;
}
}
@@ -1118,20 +1116,20 @@ void Interface::setLoad(PanelButton *panelButton) {
}
}
-void Interface::processStatusTextInput(uint16 ascii) {
+void Interface::processStatusTextInput(Common::KeyState keystate) {
- switch (ascii) {
- case 27: // esc
+ switch (keystate.keycode) {
+ case Common::KEYCODE_ESCAPE:
_statusTextInputState = kStatusTextInputAborted;
_statusTextInput = false;
_vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
break;
- case 13: // return
+ case Common::KEYCODE_RETURN:
_statusTextInputState = kStatusTextInputEntered;
_statusTextInput = false;
_vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
break;
- case 8: // backspace
+ case Common::KEYCODE_BACKSPACE:
if (_statusTextInputPos == 0) {
break;
}
@@ -1141,36 +1139,36 @@ void Interface::processStatusTextInput(uint16 ascii) {
if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) {
break;
}
- if (((ascii >= 'a') && (ascii <='z')) ||
- ((ascii >= '0') && (ascii <='9')) ||
- ((ascii >= 'A') && (ascii <='Z')) ||
- (ascii == ' ')) {
- _statusTextInputString[_statusTextInputPos++] = ascii;
+ if (isalnum(keystate.ascii) || (keystate.ascii == ' ')) {
+ _statusTextInputString[_statusTextInputPos++] = keystate.ascii;
_statusTextInputString[_statusTextInputPos] = 0;
}
}
setStatusText(_statusTextInputString);
}
-bool Interface::processTextInput(uint16 ascii) {
+bool Interface::processTextInput(Common::KeyState keystate) {
char ch[2];
char tempString[SAVE_TITLE_SIZE];
uint tempWidth;
memset(tempString, 0, SAVE_TITLE_SIZE);
ch[1] = 0;
+ // IHNM has a smaller save title size than ITE. We only limit the save title size during text input
+ // in IHNM, to preserve backwards compatibility with older save games
+ uint save_title_size = _vm->getGameType() == GType_ITE ? SAVE_TITLE_SIZE : IHNM_SAVE_TITLE_SIZE;
- switch (ascii) {
- case 13:
+ switch (keystate.keycode) {
+ case Common::KEYCODE_RETURN:
return false;
- case 27: // esc
+ case Common::KEYCODE_ESCAPE:
_textInput = false;
break;
- case 8: // backspace
+ case Common::KEYCODE_BACKSPACE:
if (_textInputPos <= 1) {
break;
}
_textInputPos--;
- case 127: // del
+ case Common::KEYCODE_DELETE:
if (_textInputPos <= _textInputStringLength) {
if (_textInputPos != 1) {
strncpy(tempString, _textInputString, _textInputPos - 1);
@@ -1182,27 +1180,25 @@ bool Interface::processTextInput(uint16 ascii) {
_textInputStringLength = strlen(_textInputString);
}
break;
- case 276: // left
+ case Common::KEYCODE_LEFT:
if (_textInputPos > 1) {
_textInputPos--;
}
break;
- case 275: // right
+ case Common::KEYCODE_RIGHT:
if (_textInputPos <= _textInputStringLength) {
_textInputPos++;
}
break;
default:
- if (((ascii >= 'a') && (ascii <='z')) ||
- ((ascii >= '0') && (ascii <='9')) ||
- ((ascii >= 'A') && (ascii <='Z')) ||
- (ascii == ' ')) {
- if (_textInputStringLength < SAVE_TITLE_SIZE - 1) {
- ch[0] = ascii;
+ if (isalnum(keystate.ascii) || (keystate.ascii == ' ') ||
+ (keystate.ascii == '-') || (keystate.ascii == '_')) {
+ if (_textInputStringLength < save_title_size - 1) {
+ ch[0] = keystate.ascii;
tempWidth = _vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal);
tempWidth += _vm->_font->getStringWidth(kKnownFontSmall, _textInputString, 0, kFontNormal);
if (tempWidth > _textInputMaxWidth) {
- break;
+ break;
}
if (_textInputPos != 1) {
strncpy(tempString, _textInputString, _textInputPos - 1);
@@ -1243,10 +1239,10 @@ void Interface::drawTextInput(Surface *ds, InterfacePanel *panel, PanelButton *p
while ((ch[0] = _textInputString[i++]) != 0) {
rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
if ((i == _textInputPos) && _textInput) {
- fgColor = kITEColorBlack;
- ds->fillRect(rect, kITEColorWhite);
+ fgColor = _vm->KnownColor2ColorId(kKnownColorBlack);
+ ds->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite));
} else {
- fgColor = kITEColorWhite;
+ fgColor = _vm->KnownColor2ColorId(kKnownColorWhite);
}
textPoint.x = rect.left;
textPoint.y = rect.top + 1;
@@ -1257,7 +1253,7 @@ void Interface::drawTextInput(Surface *ds, InterfacePanel *panel, PanelButton *p
if (_textInput && (_textInputPos >= i)) {
ch[0] = ' ';
rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
- ds->fillRect(rect, kITEColorWhite);
+ ds->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite));
}
}
@@ -1468,11 +1464,22 @@ void Interface::handleOptionClick(const Point& mousePoint) {
void Interface::handleChapterSelectionUpdate(const Point& mousePoint) {
uint16 objectId;
+ int hitZoneIndex;
+ const HitZone * hitZone;
// FIXME: Original handled more object types here.
objectId = _vm->_actor->hitTest(mousePoint, true);
+ if (objectId == ID_NOTHING) {
+ hitZoneIndex = _vm->_scene->_objectMap->hitTest(mousePoint);
+
+ if ((hitZoneIndex != -1)) {
+ hitZone = _vm->_scene->_objectMap->getHitZone(hitZoneIndex);
+ objectId = hitZone->getHitZoneId();
+ }
+ }
+
if (objectId != _vm->_script->_pointerObject) {
_vm->_script->_pointerObject = objectId;
}
@@ -1492,12 +1499,12 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) {
switch (objectTypeId(obj)) {
case kGameObjectHitZone:
- hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(obj));
+ hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(obj));
if (hitZone == NULL)
return;
- if (hitZone->getFlags() & kHitZoneExit)
+ if (hitZone->getFlags() & kHitZoneEnabled)
script = hitZone->getScriptNumber();
break;
@@ -1523,7 +1530,6 @@ void Interface::handleChapterSelectionClick(const Point& mousePoint) {
event.param4 = obj; // Object
event.param5 = 0; // With Object
event.param6 = obj; // Actor
-
_vm->_events->queue(&event);
}
}
@@ -1540,11 +1546,8 @@ void Interface::setOption(PanelButton *panelButton) {
} else {
if (_vm->_scene->currentChapterNumber() == 8) {
setMode(kPanelChapterSelection);
- } else if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- setMode(kPanelNull);
- else
- setMode(kPanelMain);
+ } else if (_vm->_scene->isNonInteractiveIHNMDemoPart()) {
+ setMode(kPanelNull);
} else {
setMode(kPanelMain);
}
@@ -1564,11 +1567,9 @@ void Interface::setOption(PanelButton *panelButton) {
}
break;
case kTextSave:
- // Disallow saving in the non-interactive part of the IHNM demo
- if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- return;
- }
+ // Disallow saving in the non-interactive part of the IHNM demo (original demo didn't support saving at all)
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart())
+ return;
if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) {
_textInputString[0] = 0;
@@ -1787,10 +1788,8 @@ void Interface::update(const Point& mousePoint, int updateFlag) {
break;
case kPanelNull:
- if (_vm->getGameId() == GID_IHNM_DEMO && (updateFlag & UPDATE_MOUSECLICK)) {
- if (_vm->_scene->currentSceneNumber() >= 144 && _vm->_scene->currentSceneNumber() <= 149)
- _vm->_scene->showIHNMDemoSpecialScreen();
- }
+ if (_vm->_scene->isNonInteractiveIHNMDemoPart() && (updateFlag & UPDATE_MOUSECLICK))
+ _vm->_scene->showIHNMDemoSpecialScreen();
break;
}
@@ -1808,6 +1807,10 @@ void Interface::drawStatusBar() {
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8)
return;
+ // Don't draw the status bar while fading out
+ if (_fadeMode == kFadeOut)
+ return;
+
backBuffer = _vm->_gfx->getBackBuffer();
// Erase background of status bar
@@ -1921,7 +1924,6 @@ void Interface::handleMainUpdate(const Point& mousePoint) {
if ((panelButton != NULL) && (panelButton->type == kPanelButtonArrow)) {
if (panelButton->state == 1) {
- //TODO: insert timeout catchup
inventoryChangePos(panelButton->id);
}
changed = true;
@@ -1938,11 +1940,14 @@ void Interface::handleMainUpdate(const Point& mousePoint) {
//inventory stuff
void Interface::inventoryChangePos(int chg) {
- if ((chg < 0 && _inventoryStart + chg >= 0) ||
- (chg > 0 && _inventoryStart < _inventoryEnd)) {
- _inventoryStart += chg;
- draw();
+ // Arrows will scroll the inventory up or down up to 4 items
+ for (int i = 1; i <= 4; i++) {
+ if ((chg < 0 && _inventoryStart + chg >= 0) ||
+ (chg > 0 && _inventoryStart < _inventoryEnd)) {
+ _inventoryStart += chg;
}
+ }
+ draw();
}
void Interface::inventorySetPos(int key) {
@@ -2087,18 +2092,19 @@ void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bo
solidColor = down ? kITEColorLightBlue94 : kITEColorLightBlue96;
break;
case kEdit:
- cornerColor = kITEColorLightBlue96;
- frameColor = kITEColorLightBlue96;
- fillColor = kITEColorLightBlue96;
- our = kITEColorDarkBlue8a;
- odl = kITEColorLightBlue94;
- iur = 0x97;
- idl = 0x95;
- if (down) {
- solidColor = kITEColorBlue;
+ if (_vm->getGameType() == GType_ITE) {
+ cornerColor = frameColor = fillColor = kITEColorLightBlue96;
+ our = kITEColorDarkBlue8a;
+ odl = kITEColorLightBlue94;
+ solidColor = down ? kITEColorBlue : kITEColorDarkGrey0C;
} else {
- solidColor = kITEColorDarkGrey0C;
+ cornerColor = frameColor = fillColor = kIHNMColorBlack;
+ our = kIHNMColorBlack;
+ odl = kIHNMColorBlack;
+ solidColor = kIHNMColorBlack;
}
+ iur = 0x97;
+ idl = 0x95;
break;
default:
cornerColor = 0x8b;
@@ -2248,21 +2254,25 @@ void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelBut
litButton = panelButton->state > 0;
if (panel == &_optionPanel) {
- texturePoint.x = _optionPanel.x + panelButton->xOffset;
- texturePoint.y = _optionPanel.y + panelButton->yOffset;
+ texturePoint.x = _optionPanel.x + panelButton->xOffset - 1;
+ texturePoint.y = _optionPanel.y + panelButton->yOffset - 1;
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, spritenum + 2 + litButton, texturePoint, 256);
} else if (panel == &_quitPanel) {
- texturePoint.x = _quitPanel.x + panelButton->xOffset;
- texturePoint.y = _quitPanel.y + panelButton->yOffset;
- _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
+ texturePoint.x = _quitPanel.x + panelButton->xOffset - 3;
+ texturePoint.y = _quitPanel.y + panelButton->yOffset - 3;
+ _vm->_sprite->draw(ds, _vm->getDisplayClip(), _quitPanel.sprites, litButton, texturePoint, 256);
} else if (panel == &_savePanel) {
- texturePoint.x = _savePanel.x + panelButton->xOffset;
- texturePoint.y = _savePanel.y + panelButton->yOffset;
- _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
+ texturePoint.x = _savePanel.x + panelButton->xOffset - 3;
+ texturePoint.y = _savePanel.y + panelButton->yOffset - 3;
+ _vm->_sprite->draw(ds, _vm->getDisplayClip(), _savePanel.sprites, litButton, texturePoint, 256);
+ // Input text box sprite
+ texturePoint.x = _savePanel.x + _saveEdit->xOffset - 2;
+ texturePoint.y = _savePanel.y + _saveEdit->yOffset - 2;
+ _vm->_sprite->draw(ds, _vm->getDisplayClip(), _savePanel.sprites, 2, texturePoint, 256);
} else if (panel == &_loadPanel) {
- texturePoint.x = _loadPanel.x + panelButton->xOffset;
- texturePoint.y = _loadPanel.y + panelButton->yOffset;
- _vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
+ texturePoint.x = _loadPanel.x + panelButton->xOffset - 3;
+ texturePoint.y = _loadPanel.y + panelButton->yOffset - 3;
+ _vm->_sprite->draw(ds, _vm->getDisplayClip(), _loadPanel.sprites, litButton, texturePoint, 256);
} else {
// revert to default behavior
drawButtonBox(ds, rect, kButton, panelButton->state > 0);
@@ -2523,11 +2533,14 @@ void Interface::converseDisplayTextLines(Surface *ds) {
}
void Interface::converseChangePos(int chg) {
- if ((chg < 0 && _converseStartPos + chg >= 0) ||
- (chg > 0 && _converseStartPos < _converseEndPos)) {
- _converseStartPos += chg;
- draw();
+ // Arrows will scroll the converse panel or down up to 4 conversation options
+ for (int i = 1; i <= 4; i++) {
+ if ((chg < 0 && _converseStartPos + chg >= 0) ||
+ (chg > 0 && _converseStartPos < _converseEndPos)) {
+ _converseStartPos += chg;
+ }
}
+ draw();
}
void Interface::converseSetPos(int key) {
@@ -2580,7 +2593,6 @@ void Interface::handleConverseUpdate(const Point& mousePoint) {
if (_conversePanel.currentButton->type == kPanelButtonArrow) {
if (_conversePanel.currentButton->state == 1) {
- //TODO: insert timeout catchup
converseChangePos(_conversePanel.currentButton->id);
}
draw();
diff --git a/engines/saga/interface.h b/engines/saga/interface.h
index 7ae225219a..a8e2d5a647 100644
--- a/engines/saga/interface.h
+++ b/engines/saga/interface.h
@@ -28,6 +28,7 @@
#ifndef SAGA_INTERFACE_H
#define SAGA_INTERFACE_H
+#include "common/keyboard.h"
#include "common/savefile.h"
#include "saga/displayinfo.h"
@@ -225,7 +226,7 @@ public:
void drawStatusBar();
void setVerbState(int verb, int state);
- bool processAscii(uint16 ascii);
+ bool processAscii(Common::KeyState keystate);
void keyBoss();
void keyBossExit();
@@ -341,8 +342,8 @@ private:
void drawVerbPanelText(Surface *ds, PanelButton *panelButton, KnownColor textKnownColor, KnownColor textShadowKnownColor);
void drawVerbPanel(Surface *backBuffer, PanelButton* panelButton);
void calcOptionSaveSlider();
- bool processTextInput(uint16 ascii);
- void processStatusTextInput(uint16 ascii);
+ bool processTextInput(Common::KeyState keystate);
+ void processStatusTextInput(Common::KeyState keystate);
public:
void converseInit(void);
@@ -379,6 +380,7 @@ private:
public:
SpriteList _defPortraits;
+ PalEntry _portraitBgColor;
private:
SagaEngine *_vm;
@@ -416,7 +418,6 @@ private:
int _statusOnceColor;
int _leftPortrait;
int _rightPortrait;
- PalEntry _portraitBgColor;
Point _lastMousePoint;
diff --git a/engines/saga/ite_introproc.cpp b/engines/saga/ite_introproc.cpp
index 1664969644..1b74d41cb7 100644
--- a/engines/saga/ite_introproc.cpp
+++ b/engines/saga/ite_introproc.cpp
@@ -115,7 +115,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventDisplay;
event.data = entry;
event.time = (i == 0) ? 0 : VOICE_PAD;
-
q_event = _vm->_events->chain(q_event, &event);
// Play voice
@@ -124,7 +123,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventPlay;
event.param = dialogue[i].i_voice_rn;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn);
@@ -138,7 +136,6 @@ Event *Scene::ITEQueueDialogue(Event *q_event, int n_dialogues, const IntroDialo
event.op = kEventRemove;
event.data = entry;
event.time = voice_len;
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -265,7 +262,6 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const
event.op = kEventDisplay;
event.data = entry;
event.time = delta_time;
-
q_event = _vm->_events->queue(&event);
// Remove text
@@ -274,7 +270,6 @@ Event *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const
event.op = kEventRemove;
event.data = entry;
event.time = duration;
-
q_event = _vm->_events->chain(q_event, &event);
y += (_vm->_font->getHeight(font) + line_spacing);
@@ -301,7 +296,6 @@ int Scene::ITEIntroAnimProc(int param) {
event.op = kEventDisplay;
event.param = kEvPSetPalette;
event.time = 0;
-
q_event = _vm->_events->queue(&event);
debug(3, "Intro animation procedure started.");
@@ -340,7 +334,6 @@ int Scene::ITEIntroAnimProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue intro music playback
@@ -350,7 +343,6 @@ int Scene::ITEIntroAnimProc(int param) {
event.param2 = MUSIC_LOOP;
event.op = kEventPlay;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
}
break;
@@ -427,7 +419,6 @@ int Scene::ITEIntroCave1Proc(int param) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
-
q_event = _vm->_events->queue(&event);
// Queue narrator dialogue list
@@ -438,8 +429,8 @@ int Scene::ITEIntroCave1Proc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -504,7 +495,6 @@ int Scene::ITEIntroCave2Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event = _vm->_events->queue(&event);
// Begin palette cycling animation for candles
@@ -512,7 +502,6 @@ int Scene::ITEIntroCave2Proc(int param) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue narrator dialogue list
@@ -523,8 +512,8 @@ int Scene::ITEIntroCave2Proc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -588,7 +577,6 @@ int Scene::ITEIntroCave3Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event = _vm->_events->queue(&event);
// Begin palette cycling animation for candles
@@ -596,7 +584,6 @@ int Scene::ITEIntroCave3Proc(int param) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue narrator dialogue list
@@ -607,8 +594,8 @@ int Scene::ITEIntroCave3Proc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -681,7 +668,6 @@ int Scene::ITEIntroCave4Proc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event = _vm->_events->queue(&event);
// Begin palette cycling animation for candles
@@ -689,7 +675,6 @@ int Scene::ITEIntroCave4Proc(int param) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue narrator dialogue list
@@ -700,8 +685,8 @@ int Scene::ITEIntroCave4Proc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = VOICE_PAD;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -747,7 +732,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
-
q_event = _vm->_events->queue(&event);
// Begin ITE title theme music
@@ -759,7 +743,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.param2 = MUSIC_NORMAL;
event.op = kEventPlay;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Pause animation before logo
@@ -768,7 +751,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventStop;
event.param = 0;
event.time = 3000;
-
q_event = _vm->_events->chain(q_event, &event);
// Display logo
@@ -777,7 +759,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventDissolveBGMask;
event.time = 0;
event.duration = LOGO_DISSOLVE_DURATION;
-
q_event = _vm->_events->chain(q_event, &event);
// Remove logo
@@ -786,7 +767,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventDissolve;
event.time = 3000;
event.duration = LOGO_DISSOLVE_DURATION;
-
q_event = _vm->_events->chain(q_event, &event);
// Unpause animation before logo
@@ -795,7 +775,6 @@ int Scene::ITEIntroValleyProc(int param) {
event.op = kEventPlay;
event.time = 0;
event.param = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue game credits list
@@ -806,8 +785,8 @@ int Scene::ITEIntroValleyProc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -870,7 +849,6 @@ int Scene::ITEIntroTreeHouseProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event = _vm->_events->queue(&event);
if (_vm->_anim->hasAnimation(0)) {
@@ -882,7 +860,6 @@ int Scene::ITEIntroTreeHouseProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -895,8 +872,8 @@ int Scene::ITEIntroTreeHouseProc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -950,7 +927,6 @@ int Scene::ITEIntroFairePathProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event = _vm->_events->queue(&event);
// Begin title screen background animation
@@ -961,7 +937,6 @@ int Scene::ITEIntroFairePathProc(int param) {
event.op = kEventPlay;
event.param = 0;
event.time = 0;
-
q_event = _vm->_events->chain(q_event, &event);
// Queue game credits list
@@ -973,8 +948,8 @@ int Scene::ITEIntroFairePathProc(int param) {
event.code = kSceneEvent;
event.op = kEventEnd;
event.time = 1000;
-
q_event = _vm->_events->chain(q_event, &event);
+
break;
case SCENE_END:
break;
@@ -1005,7 +980,6 @@ int Scene::ITEIntroFaireTentProc(int param) {
event.op = kEventDissolve;
event.time = 0;
event.duration = DISSOLVE_DURATION;
-
q_event_start = _vm->_events->queue(&event);
// End scene after momentary pause
@@ -1014,6 +988,7 @@ int Scene::ITEIntroFaireTentProc(int param) {
event.op = kEventEnd;
event.time = 5000;
q_event = _vm->_events->chain(q_event_start, &event);
+
break;
case SCENE_END:
break;
diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h
index d9bd59adc4..3c594b5fec 100644
--- a/engines/saga/itedata.h
+++ b/engines/saga/itedata.h
@@ -41,9 +41,6 @@ enum ActorFlags {
kNoScale = 0x80 // (1<<7) Actor is not scaled
};
-// TODO: This doesn't quite correspond to the original Actor struct, so I'm not
-// sure if I got it right.
-
struct ActorTableData {
byte flags;
byte nameIndex;
diff --git a/engines/saga/module.mk b/engines/saga/module.mk
index 6c1812ad23..68cf91be32 100644
--- a/engines/saga/module.mk
+++ b/engines/saga/module.mk
@@ -2,6 +2,7 @@ MODULE := engines/saga
MODULE_OBJS := \
actor.o \
+ actor_walk.o \
animation.o \
console.o \
detection.o \
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 04e79c174d..6b233e0256 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -92,7 +92,7 @@ DigitalMusicInputStream::DigitalMusicInputStream(SagaEngine *vm, ResourceContext
_compressedStream = NULL;
- if (Common::File::exists("music.cmp")) {
+ if (Common::File::exists("music.cmp") || Common::File::exists("musicd.cmp")) {
// Read compressed header to determine compression type
_file->seek((long)resourceData->offset, SEEK_SET);
_file->read(compressedHeader, 9);
@@ -320,6 +320,8 @@ void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
void MusicPlayer::onTimer(void *refCon) {
MusicPlayer *music = (MusicPlayer *)refCon;
+ Common::StackLock lock(music->_mutex);
+
if (music->_isPlaying)
music->_parser->onTimer();
}
@@ -329,6 +331,8 @@ void MusicPlayer::playMusic() {
}
void MusicPlayer::stopMusic() {
+ Common::StackLock lock(_mutex);
+
_isPlaying = false;
if (_parser) {
_parser->unloadMusic();
@@ -352,6 +356,7 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver, int enable
}
Music::~Music() {
+ _vm->_timer->removeTimerProc(&musicVolumeGaugeCallback);
_mixer->stopHandle(_musicHandle);
delete _player;
xmidiParser->setMidiDriver(NULL);
@@ -561,7 +566,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
_player->_parser = parser;
- _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
if (flags & MUSIC_LOOP)
_player->setLoop(true);
@@ -574,15 +579,17 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
}
void Music::pause(void) {
- //TODO: do it
+ _player->setVolume(-1);
+ _player->setPlaying(false);
}
void Music::resume(void) {
- //TODO: do it}
+ _player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25);
+ _player->setPlaying(true);
}
void Music::stop(void) {
- //TODO: do it
+ _player->stopMusic();
}
} // End of namespace Saga
diff --git a/engines/saga/music.h b/engines/saga/music.h
index b038a25a11..1fbdda53f2 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -34,6 +34,7 @@
#include "sound/mp3.h"
#include "sound/vorbis.h"
#include "sound/flac.h"
+#include "common/mutex.h"
namespace Saga {
@@ -49,6 +50,7 @@ public:
~MusicPlayer();
bool isPlaying() { return _isPlaying; }
+ void setPlaying(bool playing) { _isPlaying = playing; }
void setVolume(int volume);
int getVolume() { return _masterVolume; }
@@ -77,6 +79,7 @@ public:
MidiChannel *getPercussionChannel() { return 0; }
MidiParser *_parser;
+ Common::Mutex _mutex;
protected:
diff --git a/engines/saga/palanim.cpp b/engines/saga/palanim.cpp
index 19c2fc4d40..f318b815cc 100644
--- a/engines/saga/palanim.cpp
+++ b/engines/saga/palanim.cpp
@@ -131,7 +131,6 @@ int PalAnim::cycleStart() {
event.code = kPalAnimEvent;
event.op = kEventCycleStep;
event.time = PALANIM_CYCLETIME;
-
_vm->_events->queue(&event);
return SUCCESS;
@@ -178,7 +177,6 @@ int PalAnim::cycleStep(int vectortime) {
event.code = kPalAnimEvent;
event.op = kEventCycleStep;
event.time = vectortime + PALANIM_CYCLETIME;
-
_vm->_events->queue(&event);
return SUCCESS;
diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp
index 930476b4e2..e006b4a627 100644
--- a/engines/saga/render.cpp
+++ b/engines/saga/render.cpp
@@ -85,11 +85,12 @@ void Render::drawScene() {
// Get mouse coordinates
mousePoint = _vm->mousePos();
- if (!(_flags & (RF_DEMO_SUBST | RF_PLACARD | RF_MAP))) {
- // Display scene background
- _vm->_scene->draw();
-
+ if (!(_flags & (RF_DEMO_SUBST | RF_MAP) || _vm->_interface->getMode() == kPanelPlacard)) {
if (_vm->_interface->getFadeMode() != kFadeOut) {
+ // Display scene background
+ if (!(_flags & RF_DISABLE_ACTORS))
+ _vm->_scene->draw();
+
if (_vm->_puzzle->isActive()) {
_vm->_puzzle->movePiece(mousePoint);
_vm->_actor->drawSpeech();
diff --git a/engines/saga/render.h b/engines/saga/render.h
index 4c6e3ee5b1..95abc2e4df 100644
--- a/engines/saga/render.h
+++ b/engines/saga/render.h
@@ -39,11 +39,10 @@ enum RENDER_FLAGS {
RF_OBJECTMAP_TEST = (1 << 3),
RF_RENDERPAUSE = (1 << 4),
RF_GAMEPAUSE = (1 << 5),
- RF_PLACARD = (1 << 6),
- RF_ACTOR_PATH_TEST = (1 << 7),
- RF_MAP = (1 << 8),
- RF_DISABLE_ACTORS = (1 << 9),
- RF_DEMO_SUBST = (1 << 10)
+ RF_ACTOR_PATH_TEST = (1 << 6),
+ RF_MAP = (1 << 7),
+ RF_DISABLE_ACTORS = (1 << 8),
+ RF_DEMO_SUBST = (1 << 9)
};
class Render {
diff --git a/engines/saga/rscfile.cpp b/engines/saga/rscfile.cpp
index 4d3ff1e47c..ba56e838b7 100644
--- a/engines/saga/rscfile.cpp
+++ b/engines/saga/rscfile.cpp
@@ -330,7 +330,11 @@ bool Resource::loadContext(ResourceContext *context) {
if (resourceData->patchData->_patchFile->open(patchDescription->fileName)) {
resourceData->offset = 0;
resourceData->size = resourceData->patchData->_patchFile->size();
- resourceData->patchData->_patchFile->close();
+ // ITE uses several patch files which are loaded and then not needed
+ // anymore (as they're in memory), so close them here. IHNM uses only
+ // 1 patch file, which is reused, so don't close it
+ if (_vm->getGameType() == GType_ITE)
+ resourceData->patchData->_patchFile->close();
} else {
delete resourceData->patchData;
resourceData->patchData = NULL;
@@ -606,7 +610,11 @@ void Resource::loadResource(ResourceContext *context, uint32 resourceId, byte*&r
if (file->read(resourceBuffer, resourceSize) != resourceSize) {
error("Resource::loadResource() failed to read");
}
- if (resourceData->patchData != NULL)
+
+ // ITE uses several patch files which are loaded and then not needed
+ // anymore (as they're in memory), so close them here. IHNM uses only
+ // 1 patch file, which is reused, so don't close it
+ if (resourceData->patchData != NULL && _vm->getGameType() == GType_ITE)
file->close();
}
@@ -742,6 +750,12 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
if (_metaResource.songTableID > 0) {
_vm->_resource->loadResource(resourceContext, _metaResource.songTableID, resourcePointer, resourceLength);
+ if (chapter == 6) {
+ int32 id = READ_LE_UINT32(&resourcePointer[actorsEntrance * 4]);
+ free(resourcePointer);
+ _vm->_resource->loadResource(resourceContext, id, resourcePointer, resourceLength);
+ }
+
if (resourceLength == 0) {
error("Resource::loadGlobalResources Can't load songs list for current track");
}
@@ -758,6 +772,7 @@ void Resource::loadGlobalResources(int chapter, int actorsEntrance) {
free(resourcePointer);
} else {
// The IHNM demo has a fixed music track and doesn't load a song table
+ _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
_vm->_music->play(3, MUSIC_LOOP);
}
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 76731c201a..01a75f4af1 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -259,10 +259,10 @@ int SagaEngine::go() {
_scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade);
_events->handleEvents(0); // Process immediate events
+ _interface->setMode(kPanelMain);
char *fileName;
fileName = calcSaveFileName(ConfMan.getInt("save_slot"));
load(fileName);
- _interface->setMode(kPanelMain);
} else {
_framesEsc = 0;
_scene->startScene();
@@ -428,6 +428,9 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
case (kKnownColorBrightWhite):
colorId = kITEColorBrightWhite;
break;
+ case (kKnownColorWhite):
+ colorId = kITEColorWhite;
+ break;
case (kKnownColorBlack):
colorId = kITEColorBlack;
break;
@@ -449,8 +452,7 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor);
}
} else if (getGameType() == GType_IHNM) {
- switch (knownColor)
- {
+ switch (knownColor) {
case(kKnownColorTransparent):
colorId = kITEColorTransBlack;
break;
@@ -458,6 +460,9 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
case (kKnownColorBrightWhite):
colorId = kITEColorBrightWhite;
break;
+ case (kKnownColorWhite):
+ colorId = kITEColorBrightWhite;
+ break;
case (kKnownColorBlack):
colorId = kIHNMColorBlack;
break;
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 43952fe564..8016fb9e65 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -69,7 +69,12 @@ struct StringList;
#define MAXPATH 512 //TODO: remove
+// Note that IHNM has a smaller save title size than ITE
+// We allocate the ITE save title size in savegames, to
+// preserve savegame backwards compatibility. We only check
+// for IHNM's save title during text input
#define SAVE_TITLE_SIZE 28
+#define IHNM_SAVE_TITLE_SIZE 22
#define MAX_SAVES 96
#define MAX_FILE_NAME 256
@@ -153,7 +158,8 @@ enum GameFeatures {
GF_WYRMKEEP = 1 << 1,
GF_CD_FX = 1 << 2,
GF_SCENE_SUBSTITUTES = 1 << 3,
- GF_COMPRESSED_SOUNDS = 1 << 4
+ GF_COMPRESSED_SOUNDS = 1 << 4,
+ GF_NON_INTERACTIVE = 1 << 5
};
enum VerbTypeIds {
@@ -297,6 +303,7 @@ struct GameResourceDescription {
uint32 conversePanelResourceId;
uint32 optionPanelResourceId;
uint32 warningPanelResourceId;
+ uint32 warningPanelSpritesResourceId;
uint32 mainSpritesResourceId;
uint32 mainPanelSpritesResourceId;
uint32 optionPanelSpritesResourceId;
@@ -441,6 +448,7 @@ enum ColorId {
enum KnownColor {
kKnownColorTransparent,
kKnownColorBrightWhite,
+ kKnownColorWhite,
kKnownColorBlack,
kKnownColorSubtitleTextColor,
diff --git a/engines/saga/sagaresnames.h b/engines/saga/sagaresnames.h
index 761ac1ab68..b416d85fd8 100644
--- a/engines/saga/sagaresnames.h
+++ b/engines/saga/sagaresnames.h
@@ -108,6 +108,7 @@ namespace Saga {
#define RID_IHNM_OPTION_PANEL 15
#define RID_IHNM_OPTION_PANEL_SPRITES 16
#define RID_IHNM_WARNING_PANEL 17
+#define RID_IHNM_WARNING_PANEL_SPRITES 18
#define RID_IHNM_BOSS_SCREEN 19
#define RID_IHNM_PROFILE_BG 20
#define RID_IHNM_MAIN_STRINGS 21
@@ -122,7 +123,8 @@ namespace Saga {
#define RID_IHNMDEMO_OPTION_PANEL 10
#define RID_IHNMDEMO_OPTION_PANEL_SPRITES 11
#define RID_IHNMDEMO_WARNING_PANEL 12
-#define RID_IHNMDEMO_BOSS_SCREEN 13 // Does not exist in the demo
+#define RID_IHNMDEMO_WARNING_PANEL_SPRITES 13
+#define RID_IHNMDEMO_BOSS_SCREEN 14 // Does not exist in the demo
#define RID_IHNMDEMO_PROFILE_BG 15
#define RID_IHNMDEMO_MAIN_STRINGS 16
diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp
index 77d7816963..6e731de44e 100644
--- a/engines/saga/saveload.cpp
+++ b/engines/saga/saveload.cpp
@@ -187,6 +187,9 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
_saveHeader.type = MKID_BE('SAGA');
_saveHeader.size = 0;
_saveHeader.version = CURRENT_SAGA_VER;
+ // Note that IHNM has a smaller save title size than ITE
+ // We allocate the ITE save title size here, to preserve
+ // savegame backwards compatibility
strncpy(_saveHeader.name, saveName, SAVE_TITLE_SIZE);
out->writeUint32BE(_saveHeader.type);
@@ -255,8 +258,8 @@ void SagaEngine::load(const char *fileName) {
// Some older saves were not written in an endian safe fashion.
// We try to detect this here by checking for extremly high version values.
// If found, we retry with the data swapped.
- // FIXME: Maybe display a warning/error message instead?
if (_saveHeader.version > 0xFFFFFF) {
+ warning("This savegame is not endian safe, retrying with the data swapped");
_saveHeader.version = SWAP_BYTES_32(_saveHeader.version);
}
@@ -276,7 +279,6 @@ void SagaEngine::load(const char *fileName) {
// Surrounding scene
sceneNumber = in->readSint32LE();
- // Protagonist
if (getGameType() != GType_ITE) {
int currentChapter = _scene->currentChapterNumber();
_scene->setChapterNumber(in->readSint32LE());
@@ -286,10 +288,13 @@ void SagaEngine::load(const char *fileName) {
_scene->setCurrentMusicTrack(in->readSint32LE());
_scene->setCurrentMusicRepeat(in->readSint32LE());
_music->stop();
- if (getGameId() != GID_IHNM_DEMO)
+ if (_scene->currentChapterNumber() == 8)
+ _interface->setMode(kPanelChapterSelection);
+ if (getGameId() != GID_IHNM_DEMO) {
_music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL);
- else
+ } else {
_music->play(3, MUSIC_LOOP);
+ }
}
// Inset scene
@@ -323,11 +328,14 @@ void SagaEngine::load(const char *fileName) {
if (getGameType() != GType_ITE) {
if (_scene->currentProtag() != 0 && _scene->currentChapterNumber() != 6) {
ActorData *actor1 = _actor->getFirstActor();
- // Original stores the current protagonist ID from sfSwapActors:
- //ActorData *actor2 = _actor->getActor(_scene->currentProtag());
- // However, we already store the protagonist, so merely getting the saved
- // protagonist is easier and safer, and works without glitches
- ActorData *actor2 = _actor->_protagonist;
+ ActorData *actor2;
+ // The original gets actor2 from the current protagonist ID, but this is sometimes wrong
+ // If the current protagonist ID is not correct, use the stored protagonist
+ if (!_actor->validActorId(_scene->currentProtag())) {
+ actor2 = _actor->_protagonist;
+ } else {
+ actor2 = _actor->getActor(_scene->currentProtag());
+ }
SWAP(actor1->_location, actor2->_location);
@@ -345,6 +353,7 @@ void SagaEngine::load(const char *fileName) {
if (insetSceneNumber != sceneNumber) {
_render->setFlag(RF_DISABLE_ACTORS);
+ _scene->draw();
_render->drawScene();
_render->clearFlag(RF_DISABLE_ACTORS);
_scene->changeScene(insetSceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade);
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index c49fe546ee..a80b482e47 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -205,6 +205,7 @@ Scene::Scene(SagaEngine *vm) : _vm(vm) {
_sceneLoaded = false;
_sceneNumber = 0;
+ _chapterNumber = 0;
_sceneResourceId = 0;
_inGame = false;
_loadDescription = false;
@@ -281,6 +282,9 @@ void Scene::startScene() {
break;
}
+ // Stop the intro music
+ _vm->_music->stop();
+
// Load the head in scene queue
queueIterator = _sceneQueue.begin();
if (queueIterator == _sceneQueue.end()) {
@@ -292,6 +296,31 @@ void Scene::startScene() {
loadScene(sceneQueue);
}
+void Scene::creditsScene() {
+ // End the last game ending scene
+ _vm->_scene->endScene();
+ // We're not in the game anymore
+ _inGame = false;
+
+ // Hide cursor during credits
+ _vm->_gfx->showCursor(false);
+
+ switch (_vm->getGameType()) {
+ case GType_ITE:
+ // Not called by ITE
+ break;
+ case GType_IHNM:
+ IHNMCreditsProc();
+ break;
+ default:
+ error("Scene::creditsScene(): Error: Can't start credits scene... gametype not supported");
+ break;
+ }
+
+ _vm->shutDown();
+ return;
+}
+
void Scene::nextScene() {
SceneQueueList::iterator queueIterator;
LoadSceneParams *sceneQueue;
@@ -561,6 +590,9 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
Event *q_event;
static PalEntry current_pal[PAL_ENTRIES];
+ if (loadSceneParams->transitionType == kTransitionFade)
+ _vm->_interface->setFadeMode(kFadeOut);
+
// Change the cursor to an hourglass in IHNM
event.type = kEvTOneshot;
event.code = kCursorEvent;
@@ -575,19 +607,11 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
error("loadScene wrong usage");
}
- if (loadSceneParams->chapter == 6)
+ if (loadSceneParams->chapter == 6 || loadSceneParams->chapter == 8)
_vm->_interface->setLeftPortrait(0);
_vm->_anim->freeCutawayList();
- // FIXME: Freed script modules are not reloaded correctly when changing chapters.
- // This is apparent when returning back to the character selection screen,
- // where the scene script module is loaded incorrectly
- // Don't free them for now, but free them on game exit, like ITE.
- // This has no impact on the game itself (other than increased memory usage),
- // as each chapter uses a different module slot
- // TODO: Find out why the script modules are not loaded correctly when
- // changing chapters and uncomment this again
- //_vm->_script->freeModules();
+ _vm->_script->freeModules();
// deleteAllScenes();
@@ -612,6 +636,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
_vm->_script->setVerb(_vm->_script->getVerbType(kVerbWalkTo));
if (loadSceneParams->sceneDescriptor == -2) {
+ _vm->_interface->setFadeMode(kNoFade);
return;
}
}
@@ -651,11 +676,11 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
debug(3, "Loading scene number %d:", _sceneNumber);
- if (_vm->getGameId() == GID_IHNM_DEMO && _sceneNumber == 144) {
+ if (isNonInteractiveIHNMDemoPart()) {
// WORKAROUND for the non-interactive part of the IHNM demo: When restarting the
- // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if the
- // starting scene of the non-interactive demo is loaded (scene 144), set panel to null
- // and lock the user interface
+ // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if any
+ // of the scenes of the non-interactive demo are loaded (scenes 144-149), set panel
+ // to null and lock the user interface
_vm->_interface->deactivate();
_vm->_interface->setMode(kPanelNull);
}
@@ -709,15 +734,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
q_event = NULL;
- //fix placard bug
- //i guess we should remove RF_PLACARD flag - and use _interface->getMode()
- event.type = kEvTOneshot;
- event.code = kGraphicsEvent;
- event.op = kEventClearFlag;
- event.param = RF_PLACARD;
-
- q_event = _vm->_events->chain(q_event, &event);
-
if (loadSceneParams->transitionType == kTransitionFade) {
_vm->_interface->setFadeMode(kFadeOut);
@@ -764,7 +780,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.param4 = _sceneNumber; // Object
event.param5 = loadSceneParams->actorsEntrance; // With Object
event.param6 = 0; // Actor
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -786,7 +801,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = _bg.pal;
-
q_event = _vm->_events->chain(q_event, &event);
// set fade mode
@@ -807,11 +821,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
_vm->_sound->stopAll();
- // FIXME: Does IHNM use scene background music, or is all the
- // music scripted? At the very least, it shouldn't try
- // to start song 0 at the beginning of the game, since
- // it's the end credits music.
-
if (_vm->getGameType() == GType_ITE) {
if (_sceneDescription.musicResourceId >= 0) {
event.type = kEvTOneshot;
@@ -820,14 +829,12 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.param2 = MUSIC_DEFAULT;
event.op = kEventPlay;
event.time = 0;
-
_vm->_events->queue(&event);
} else {
event.type = kEvTOneshot;
event.code = kMusicEvent;
event.op = kEventStop;
event.time = 0;
-
_vm->_events->queue(&event);
}
}
@@ -838,7 +845,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.op = kEventDisplay;
event.param = kEvPSetPalette;
event.time = 0;
-
_vm->_events->queue(&event);
// Begin palette cycle animation if present
@@ -846,7 +852,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.code = kPalAnimEvent;
event.op = kEventCycleStart;
event.time = 0;
-
q_event = _vm->_events->queue(&event);
// Start the scene main script
@@ -861,7 +866,6 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
event.param4 = _sceneNumber; // Object
event.param5 = loadSceneParams->actorsEntrance; // With Object
event.param6 = 0; // Actor
-
_vm->_events->queue(&event);
}
@@ -1178,7 +1182,9 @@ void Scene::endScene() {
_sceneProc(SCENE_END, this);
}
- //
+ // Stop showing actors till the next scene's background is drawn from loadScene
+ _vm->_render->setFlag(RF_DISABLE_ACTORS);
+
_vm->_script->abortAllThreads();
_vm->_script->_skipSpeeches = false;
@@ -1308,31 +1314,38 @@ void Scene::clearPlacard() {
Event event;
Event *q_event;
- _vm->_interface->restoreMode();
+ _vm->_interface->setFadeMode(kFadeOut);
+ // Fade to black out
_vm->_gfx->getCurrentPal(cur_pal);
-
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalToBlack;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
-
q_event = _vm->_events->queue(&event);
- event.type = kEvTOneshot;
- event.code = kGraphicsEvent;
- event.op = kEventClearFlag;
- event.param = RF_PLACARD;
-
+ // set fade mode
+ event.type = kEvTImmediate;
+ event.code = kInterfaceEvent;
+ event.op = kEventSetFadeMode;
+ event.param = kNoFade;
+ event.time = 0;
+ event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
event.code = kTextEvent;
event.op = kEventRemove;
event.data = _vm->_script->getPlacardTextEntry();
+ q_event = _vm->_events->chain(q_event, &event);
+ event.type = kEvTImmediate;
+ event.code = kInterfaceEvent;
+ event.op = kEventRestoreMode;
+ event.time = 0;
+ event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
_vm->_scene->getBGPal(pal);
@@ -1343,20 +1356,17 @@ void Scene::clearPlacard() {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
-
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventShow;
-
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -1378,37 +1388,37 @@ void Scene::showPsychicProfile(const char *text) {
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventHide;
-
q_event = _vm->_events->queue(&event);
- _vm->_gfx->getCurrentPal(cur_pal);
+ _vm->_interface->setFadeMode(kFadeOut);
+ // Fade to black out
+ _vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalToBlack;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
-
q_event = _vm->_events->chain(q_event, &event);
- event.type = kEvTOneshot;
+ // set fade mode
+ event.type = kEvTImmediate;
event.code = kInterfaceEvent;
- event.op = kEventClearStatus;
-
+ event.op = kEventSetFadeMode;
+ event.param = kNoFade;
+ event.time = 0;
+ event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
- event.code = kGraphicsEvent;
- event.op = kEventSetFlag;
- event.param = RF_PLACARD;
-
+ event.code = kInterfaceEvent;
+ event.op = kEventClearStatus;
q_event = _vm->_events->chain(q_event, &event);
// Set the background and palette for the psychic profile
event.type = kEvTOneshot;
event.code = kPsychicProfileBgEvent;
-
q_event = _vm->_events->chain(q_event, &event);
_vm->_scene->_textList.clear();
@@ -1432,7 +1442,6 @@ void Scene::showPsychicProfile(const char *text) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -1444,22 +1453,21 @@ void Scene::showPsychicProfile(const char *text) {
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
-
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
-
q_event = _vm->_events->chain(q_event, &event);
}
void Scene::clearPsychicProfile() {
if (_vm->_interface->getMode() == kPanelPlacard || _vm->getGameId() == GID_IHNM_DEMO) {
+ _vm->_interface->restoreMode();
_vm->_scene->clearPlacard();
_vm->_scene->_textList.clear();
- _vm->_actor->showActors(false);
+ _vm->_render->setFlag(RF_DISABLE_ACTORS);
_vm->_gfx->restorePalette();
_vm->_scene->restoreScene();
_vm->_interface->activate();
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index da97bddff5..aca3f910e0 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -221,6 +221,7 @@ class Scene {
void cmdSceneChange(int argc, const char **argv);
void startScene();
+ void creditsScene();
void nextScene();
void skipScene();
void endScene();
@@ -345,6 +346,10 @@ class Scene {
void clearPsychicProfile();
void showIHNMDemoSpecialScreen();
+ bool isNonInteractiveIHNMDemoPart() {
+ return _vm->getGameId() == GID_IHNM_DEMO && (_sceneNumber >= 144 && _sceneNumber <= 149);
+ }
+
private:
void loadScene(LoadSceneParams *loadSceneParams);
void loadSceneDescriptor(uint32 resourceId);
@@ -391,17 +396,26 @@ class Scene {
private:
int IHNMStartProc();
+ int IHNMCreditsProc();
int ITEStartProc();
+ void IHNMLoadCutaways();
+ bool checkKey();
+
+ bool playTitle(int title, int time, int mode = kPanelVideo);
+ bool playLoopingTitle(int title, int seconds);
+
public:
static int SC_IHNMIntroMovieProc1(int param, void *refCon);
static int SC_IHNMIntroMovieProc2(int param, void *refCon);
static int SC_IHNMIntroMovieProc3(int param, void *refCon);
+ static int SC_IHNMCreditsMovieProc(int param, void *refCon);
private:
int IHNMIntroMovieProc1(int param);
int IHNMIntroMovieProc2(int param);
int IHNMIntroMovieProc3(int param);
+ int IHNMCreditsMovieProc(int param);
public:
static int SC_ITEIntroAnimProc(int param, void *refCon);
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp
index 82fcb352c0..611975f471 100644
--- a/engines/saga/script.cpp
+++ b/engines/saga/script.cpp
@@ -204,6 +204,7 @@ void Script::freeModules() {
for (i = 0; i < _modulesCount; i++) {
if (_modules[i].loaded) {
_modules[i].freeMem();
+ _modules[i].loaded = false;
}
}
_staticSize = 0;
@@ -359,8 +360,6 @@ int Script::getVerbType(VerbTypes verbType) {
}
}
else {
- // TODO: This is ugly and needs rewriting, but
- // it works for now
switch (verbType) {
case kVerbNone:
return kVerbIHNMNone;
@@ -507,7 +506,6 @@ void Script::doVerb() {
event.param4 = _pendingObject[0]; // Object
event.param5 = _pendingObject[1]; // With Object
event.param6 = (objectType == kGameObjectActor) ? _pendingObject[0] : ID_PROTAG; // Actor
-
_vm->_events->queue(&event);
} else {
@@ -773,7 +771,13 @@ void Script::whichObject(const Point& mousePoint) {
objectId = newObjectId;
if (_vm->getGameType() == GType_ITE)
objectFlags = kObjUseWith;
+ // Note: for IHNM, the default right button action is "Look at" for actors,
+ // but "Talk to" makes much more sense
newRightButtonVerb = getVerbType(kVerbTalkTo);
+ // Slight hack because of the above change: the jukebox in Gorrister's chapter
+ // is an actor, so change the right button action to "Look at"
+ if (_vm->getGameType() == GType_IHNM && objectId == 8199)
+ newRightButtonVerb = getVerbType(kVerbLookAt);
if ((_currentVerb == getVerbType(kVerbPickUp)) ||
(_currentVerb == getVerbType(kVerbOpen)) ||
@@ -827,6 +831,10 @@ void Script::whichObject(const Point& mousePoint) {
if (newRightButtonVerb >= getVerbType(kVerbOptions)) {
newRightButtonVerb = getVerbType(kVerbNone);
}
+ } else {
+ if (newRightButtonVerb >= getVerbType(kVerbOptions)) {
+ newRightButtonVerb = getVerbType(kVerbWalkTo);
+ }
}
if ((_currentVerb == getVerbType(kVerbTalkTo)) || ((_currentVerb == getVerbType(kVerbGive)) && _firstObjectSet)) {
diff --git a/engines/saga/script.h b/engines/saga/script.h
index 5e5e702132..37e35cf241 100644
--- a/engines/saga/script.h
+++ b/engines/saga/script.h
@@ -237,7 +237,6 @@ struct ModuleData {
voiceLUT.freeMem();
free(moduleBase);
free(entryPoints);
- memset(this, 0x0, sizeof(*this));
}
};
@@ -597,7 +596,7 @@ private:
void sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS);
void sfGetPoints(SCRIPTFUNC_PARAMS);
void sfSetGlobalFlag(SCRIPTFUNC_PARAMS);
- void sf92(SCRIPTFUNC_PARAMS);
+ void sfDemoSetInteractive(SCRIPTFUNC_PARAMS);
void sfClearGlobalFlag(SCRIPTFUNC_PARAMS);
void sfTestGlobalFlag(SCRIPTFUNC_PARAMS);
void sfSetPoints(SCRIPTFUNC_PARAMS);
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index c0e44584df..74f192c7f7 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -230,7 +230,7 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT
OPCODE(sfShowIHNMDemoHelpPage),
OPCODE(sfVstopFX),
OPCODE(sfVstopLoopedFX),
- OPCODE(sf92), // only used in the demo version of IHNM
+ OPCODE(sfDemoSetInteractive), // only used in the demo version of IHNM
OPCODE(sfDemoIsInteractive),
OPCODE(sfVsetTrack),
OPCODE(sfGetPoints),
@@ -253,8 +253,7 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT
// Script function #0 (0x00)
// Print a debugging message
void Script::sfPutString(SCRIPTFUNC_PARAMS) {
- const char *str;
- str = thread->_strings->getString(thread->pop());
+ const char *str = thread->_strings->getString(thread->pop());
_vm->_console->DebugPrintf("sfPutString: %s\n",str);
debug(0, "sfPutString: %s", str);
@@ -263,8 +262,7 @@ void Script::sfPutString(SCRIPTFUNC_PARAMS) {
// Script function #1 (0x01) blocking
// Param1: time in ticks
void Script::sfWait(SCRIPTFUNC_PARAMS) {
- int16 time;
- time = thread->pop();
+ int16 time = thread->pop();
if (!_skipSpeeches) {
thread->waitDelay(_vm->ticksToMSec(time)); // put thread to sleep
@@ -274,17 +272,17 @@ void Script::sfWait(SCRIPTFUNC_PARAMS) {
// Script function #2 (0x02)
void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {
uint16 objectId = thread->pop();
- ObjectData *obj;
- obj = _vm->_actor->getObj(objectId);
+ ObjectData *obj = _vm->_actor->getObj(objectId);
+
if (obj->_sceneNumber != ITE_SCENE_INV) {
obj->_sceneNumber = ITE_SCENE_INV;
// WORKAROUND for two incorrect object sprites in the IHNM demo
// (the mirror and the icon in Ted's part). Set them correctly here
if (_vm->getGameId() == GID_IHNM_DEMO) {
- if (obj->_spriteListResourceId == 4 && objectId == 16408)
+ if (objectId == 16408)
obj->_spriteListResourceId = 24;
- if (obj->_spriteListResourceId == 3 && objectId == 16409)
+ if (objectId == 16409)
obj->_spriteListResourceId = 25;
}
@@ -297,23 +295,20 @@ void Script::sfTakeObject(SCRIPTFUNC_PARAMS) {
void Script::sfIsCarried(SCRIPTFUNC_PARAMS) {
uint16 objectId = thread->pop();
CommonObjectData *object;
+
if (_vm->_actor->validObjId(objectId)) {
object = _vm->_actor->getObj(objectId);
thread->_returnValue = (object->_sceneNumber == ITE_SCENE_INV) ? 1 : 0;
} else {
thread->_returnValue = 0;
}
-
-
}
// Script function #4 (0x04) nonblocking
// Set the command display to the specified text string
// Param1: dialogue index of string
void Script::sfStatusBar(SCRIPTFUNC_PARAMS) {
- int16 stringIndex = thread->pop();
-
- _vm->_interface->setStatusText(thread->_strings->getString(stringIndex));
+ _vm->_interface->setStatusText(thread->_strings->getString(thread->pop()));
}
// Script function #5 (0x05)
@@ -323,9 +318,29 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) {
showVerb();
_vm->_interface->activate();
_vm->_interface->setMode(kPanelMain);
+ // Sometimes, the active cutaway is cleared after this opcode is called,
+ // resulting in an incorrect mode being set. An example is Ellen's chapter
+ // in IHNM, when using the computer with the chaos trebler CD. Make sure
+ // that the saved mode is kPanelMain, so that it won't get overwritten
+ // by an incorrect stored mode
+ _vm->_interface->rememberMode();
if (_vm->getGameType() == GType_ITE)
setPointerVerb();
+
+ // The early Windows and Mac demos of ITE were non-interactive. In those demos,
+ // the intro is shown and then when the first scene is shown, there's a dialog
+ // thanking the user for playing the demo and asking him to buy the full game,
+ // without allowing him to continue any further. The game data itself for these
+ // demos does not contain any scripts for the first scene (i.e. there's no text
+ // in the game data to look at Rif's silver medallion). Also, there are no more
+ // scenes apart from the Grand Tournament scene. This opcode is called in those
+ // demos, and I assume that its use there is to just show the popup window and
+ // exit the game. Therefore, once this opcode is called in the older ITE demos,
+ // exit the game. Known non-interactive demos are GID_ITE_MACDEMO1 and
+ // GID_ITE_WINDEMO1
+ if (_vm->getFeatures() & GF_NON_INTERACTIVE)
+ _vm->shutDown();
}
// Script function #6 (0x06) blocking
@@ -333,15 +348,11 @@ void Script::sfMainMode(SCRIPTFUNC_PARAMS) {
// Param2: actor x
// Param3: actor y
void Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) {
- uint16 actorId;
+ uint16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
Location actorLocation;
- ActorData *actor;
-
- actorId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
actor->_flags &= ~kFollower;
@@ -357,10 +368,10 @@ void Script::sfScriptWalkTo(SCRIPTFUNC_PARAMS) {
// Param3: theObject
// Param4: withObject
void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
- uint16 objectId;
- uint16 action;
- uint16 theObject;
- uint16 withObject;
+ uint16 objectId = thread->pop();
+ uint16 action = thread->pop();
+ uint16 theObject = thread->pop();
+ uint16 withObject = thread->pop();
int16 scriptEntryPointNumber;
int16 moduleNumber;
ActorData *actor;
@@ -368,11 +379,6 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
const HitZone *hitZone;
Event event;
- objectId = thread->pop();
- action = thread->pop();
- theObject = thread->pop();
- withObject = thread->pop();
-
switch (objectTypeId(objectId)) {
case kGameObjectObject:
obj = _vm->_actor->getObj(objectId);
@@ -381,6 +387,8 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
return;
}
moduleNumber = 0;
+ if (_vm->getGameType() == GType_IHNM)
+ moduleNumber = _vm->_scene->getScriptModuleNumber();
break;
case kGameObjectActor:
actor = _vm->_actor->getActor(objectId);
@@ -393,6 +401,8 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
} else {
moduleNumber = _vm->_scene->getScriptModuleNumber();
}
+ if (_vm->getGameType() == GType_IHNM)
+ moduleNumber = _vm->_scene->getScriptModuleNumber();
break;
case kGameObjectHitZone:
case kGameObjectStepZone:
@@ -421,7 +431,6 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
event.param4 = theObject; // Object
event.param5 = withObject; // With Object
event.param6 = objectId;
-
_vm->_events->queue(&event);
}
@@ -429,14 +438,9 @@ void Script::sfScriptDoAction(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: actor orientation
void Script::sfSetActorFacing(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int actorDirection;
- ActorData *actor;
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ int actorDirection = thread->pop();
- actorId = thread->pop();
- actorDirection = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actor->_facingDirection = actor->_actionDirection = actorDirection;
actor->_targetObject = ID_NOTHING;
}
@@ -448,7 +452,9 @@ void Script::sfStartBgdAnim(SCRIPTFUNC_PARAMS) {
_vm->_anim->setCycles(animId, cycles);
_vm->_anim->setFrameTime(animId, _vm->ticksToMSec(kRepeatSpeedTicks));
- _vm->_anim->play(animId, 0);
+
+ if (!_vm->_anim->isPlaying(animId))
+ _vm->_anim->play(animId, 0);
debug(1, "sfStartBgdAnim(%d, %d)", animId, cycles);
}
@@ -468,11 +474,7 @@ void Script::sfStopBgdAnim(SCRIPTFUNC_PARAMS) {
// reenabled.
// Param1: boolean
void Script::sfLockUser(SCRIPTFUNC_PARAMS) {
- int16 lock;
-
- lock = thread->pop();
-
- if (lock) {
+ if (thread->pop()) {
_vm->_interface->deactivate();
} else {
_vm->_interface->activate();
@@ -485,6 +487,7 @@ void Script::sfLockUser(SCRIPTFUNC_PARAMS) {
void Script::sfPreDialog(SCRIPTFUNC_PARAMS) {
_vm->_interface->deactivate();
_vm->_interface->converseClear();
+
if (_vm->_interface->isInMainMode())
_vm->_interface->setMode(kPanelConverse);
else
@@ -497,10 +500,7 @@ void Script::sfPreDialog(SCRIPTFUNC_PARAMS) {
void Script::sfKillActorThreads(SCRIPTFUNC_PARAMS) {
ScriptThread *anotherThread;
ScriptThreadList::iterator threadIterator;
- int16 actorId;
-
- actorId = thread->pop();
-
+ int16 actorId = thread->pop();
for (threadIterator = _threadList.begin(); threadIterator != _threadList.end(); ++threadIterator) {
anotherThread = threadIterator.operator->();
@@ -515,34 +515,21 @@ void Script::sfKillActorThreads(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: object id
void Script::sfFaceTowards(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 targetObject;
- ActorData *actor;
-
- actorId = thread->pop();
- targetObject = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
- actor->_targetObject = targetObject;
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ actor->_targetObject = thread->pop();
}
// Script function #15 (0x0F)
// Param1: actor id
// Param2: target object
void Script::sfSetFollower(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 targetObject;
-
- ActorData *actor;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
+ actor->_targetObject = thread->pop();
- actorId = thread->pop();
- targetObject = thread->pop();
+ debug(1, "sfSetFollower(%d, %d) [%d]", actorId, actor->_targetObject, _vm->_actor->actorIdToIndex(actorId));
- debug(1, "sfSetFollower(%d, %d) [%d]", actorId, targetObject, _vm->_actor->actorIdToIndex(actorId));
-
- actor = _vm->_actor->getActor(actorId);
- actor->_targetObject = targetObject;
- if (targetObject != ID_NOTHING) {
+ if (actor->_targetObject != ID_NOTHING) {
actor->_flags |= kFollower;
actor->_actorFlags &= ~kActorNoFollow;
} else {
@@ -552,53 +539,33 @@ void Script::sfSetFollower(SCRIPTFUNC_PARAMS) {
// Script function #16 (0x10)
void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
- int16 sceneNumber;
- int16 entrance;
- int16 transition = 0; // IHNM
+ int16 sceneNumber = thread->pop();
+ int16 entrance = thread->pop();
- sceneNumber = thread->pop();
- entrance = thread->pop();
if (_vm->getGameType() == GType_IHNM) {
- transition = thread->pop();
-
_vm->_gfx->setCursor(kCursorBusy);
}
- if ((_vm->getGameType() == GType_ITE && sceneNumber < 0) ||
- (_vm->getGameType() == GType_IHNM && sceneNumber == 0)) {
- // TODO: set creditsFlag to true for IHNM
+ if (_vm->getGameType() == GType_ITE && sceneNumber < 0) {
_vm->shutDown();
return;
}
- if (_vm->getGameType() == GType_IHNM) {
- // WORKAROUND for the briefly appearing actors at the beginning of each chapter
- // This will stop the actors being drawn in those specific scenes until the scene background has been drawn
- if ((_vm->_scene->currentChapterNumber() == 1 && _vm->_scene->currentSceneNumber() == 6) ||
- (_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 31) ||
- (_vm->_scene->currentChapterNumber() == 3 && _vm->_scene->currentSceneNumber() == 58) ||
- (_vm->_scene->currentChapterNumber() == 4 && _vm->_scene->currentSceneNumber() == 68) ||
- (_vm->_scene->currentChapterNumber() == 5 && _vm->_scene->currentSceneNumber() == 91) ||
- (_vm->_scene->currentChapterNumber() == 7 && _vm->_scene->currentSceneNumber() == 145))
- _vm->_actor->showActors(false); // Stop showing actors before the background is drawn
-
- // Since it doesn't look like the IHNM scripts remove the
- // cutaway after the intro, this is probably the best place to do it
- _vm->_anim->clearCutaway();
+ if (_vm->getGameType() == GType_IHNM && sceneNumber == 0) {
+ _vm->_scene->creditsScene();
+ return;
}
// It is possible to leave scene when converse panel is on,
// particulalrly it may happen at Moneychanger tent. This
- // prevent this from happening.
+ // prevents this from happening.
if (_vm->_interface->getMode() == kPanelConverse) {
_vm->_interface->setMode(kPanelMain);
}
// changeScene calls loadScene which calls setVerb. setVerb resets all pending objects and object flags
if (sceneNumber == -1 && _vm->getGameType() == GType_IHNM) {
- // TODO: This is used to return back to the character selection screen in IHNM.
- // However, it seems more than this is needed, AM's speech is wrong and no actors
- // are shown
+ // Return back to the character selection screen in IHNM
_vm->_scene->changeScene(154, entrance, kTransitionFade, 8);
} else {
_vm->_scene->changeScene(sceneNumber, entrance, (sceneNumber == ITE_SCENE_ENDCREDIT1) ? kTransitionFade : kTransitionNoFade);
@@ -615,23 +582,27 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
_currentObject[0] = _currentObject[1] = ID_NOTHING;
showVerb(); // calls setStatusText("")
- if (_vm->getGameType() == GType_IHNM)
+ if (_vm->getGameType() == GType_IHNM) {
+ // There are some cutaways which are not removed by game scripts, like the cutaway
+ // after the intro of IHNM or the cutaway at the end of Ellen's part in the IHNM demo.
+ // Clear any remaining cutaways here
+ _vm->_anim->clearCutaway();
_vm->_gfx->setCursor(kCursorNormal);
+ }
}
// Script function #17 (0x11)
// Param1: object id
// Param2: sprite index
void Script::sfSetObjImage(SCRIPTFUNC_PARAMS) {
- uint16 objectId;
- uint16 spriteId;
- ObjectData *obj;
-
- objectId = thread->pop();
- spriteId = thread->pop();
+ uint16 objectId = thread->pop();
+ uint16 spriteId = thread->pop();
+ ObjectData *obj = _vm->_actor->getObj(objectId);
- obj = _vm->_actor->getObj(objectId);
- obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId;
+ if (_vm->getGameType() == GType_IHNM)
+ obj->_spriteListResourceId = spriteId;
+ else
+ obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId;
_vm->_interface->refreshInventory();
}
@@ -639,26 +610,18 @@ void Script::sfSetObjImage(SCRIPTFUNC_PARAMS) {
// Param1: object id
// Param2: name index
void Script::sfSetObjName(SCRIPTFUNC_PARAMS) {
- uint16 objectId;
- uint16 nameIdx;
- ObjectData *obj;
-
- objectId = thread->pop();
- nameIdx = thread->pop();
+ uint16 objectId = thread->pop();
+ uint16 nameIdx = thread->pop();
+ ObjectData *obj = _vm->_actor->getObj(objectId);
- obj = _vm->_actor->getObj(objectId);
obj->_nameIndex = nameIdx;
}
// Script function #19 (0x13)
// Param1: object id
void Script::sfGetObjImage(SCRIPTFUNC_PARAMS) {
- uint16 objectId;
- ObjectData *obj;
-
- objectId = thread->pop();
-
- obj = _vm->_actor->getObj(objectId);
+ uint16 objectId = thread->pop();
+ ObjectData *obj = _vm->_actor->getObj(objectId);
if (_vm->getGameType() == GType_IHNM)
thread->_returnValue = obj->_spriteListResourceId;
@@ -686,8 +649,7 @@ void Script::sfGetNumber(SCRIPTFUNC_PARAMS) {
// Script function #21 (0x15)
// Param1: door #
void Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) {
- int16 doorNumber;
- doorNumber = thread->pop();
+ int16 doorNumber = thread->pop();
if (_vm->_scene->getFlags() & kSceneFlagISO) {
_vm->_isoMap->setTileDoorState(doorNumber, 1);
@@ -699,8 +661,7 @@ void Script::sfScriptOpenDoor(SCRIPTFUNC_PARAMS) {
// Script function #22 (0x16)
// Param1: door #
void Script::sfScriptCloseDoor(SCRIPTFUNC_PARAMS) {
- int16 doorNumber;
- doorNumber = thread->pop();
+ int16 doorNumber = thread->pop();
if (_vm->_scene->getFlags() & kSceneFlagISO) {
_vm->_isoMap->setTileDoorState(doorNumber, 0);
@@ -728,10 +689,7 @@ void Script::SF_cycleColors(SCRIPTFUNC_PARAMS) {
// Script function #25 (0x19)
// Param1: actor id
void Script::sfDoCenterActor(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- actorId = thread->pop();
-
- _vm->_actor->_centerActor = _vm->_actor->getActor(actorId);
+ _vm->_actor->_centerActor = _vm->_actor->getActor(thread->pop());
}
// Script function #26 (0x1A) nonblocking
@@ -743,7 +701,9 @@ void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
_vm->_anim->setCycles(animId, cycles);
_vm->_anim->setFrameTime(animId, _vm->ticksToMSec(speed));
- _vm->_anim->play(animId, 0);
+
+ if (!_vm->_anim->isPlaying(animId))
+ _vm->_anim->play(animId, 0);
debug(1, "sfStartBgdAnimSpeed(%d, %d, %d)", animId, cycles, speed);
}
@@ -753,19 +713,14 @@ void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
// Param2: actor x
// Param3: actor y
void Script::sfScriptWalkToAsync(SCRIPTFUNC_PARAMS) {
- int16 actorId;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
Location actorLocation;
- ActorData *actor;
-
- actorId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
actor->_flags &= ~kFollower;
-
_vm->_actor->actorWalkTo(actorId, actorLocation);
}
@@ -797,14 +752,8 @@ void Script::sfEnableZone(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: current action
void Script::sfSetActorState(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int currentAction;
- ActorData *actor;
-
- actorId = thread->pop();
- currentAction = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ int currentAction = thread->pop();
if ((currentAction >= kActionWalkToPoint) && (currentAction <= kActionWalkToPoint)) {
wakeUpActorThread(kWaitTypeWalk, actor);
@@ -818,14 +767,12 @@ void Script::sfSetActorState(SCRIPTFUNC_PARAMS) {
// Param2: actor pos x
// Param3: actor pos y
void Script::sfScriptMoveTo(SCRIPTFUNC_PARAMS) {
- int16 objectId;
+ int16 objectId = thread->pop();
Location location;
- ActorData *actor;
- ObjectData *obj;
-
- objectId = thread->pop();
location.x = thread->pop();
location.y = thread->pop();
+ ActorData *actor;
+ ObjectData *obj;
if (_vm->_actor->validActorId(objectId)) {
actor = _vm->_actor->getActor(objectId);
@@ -854,18 +801,11 @@ void Script::sfSceneEq(SCRIPTFUNC_PARAMS) {
// Script function #32 (0x20)
void Script::sfDropObject(SCRIPTFUNC_PARAMS) {
- uint16 objectId;
- uint16 spriteId;
- int16 x;
- int16 y;
- ObjectData *obj;
-
- objectId = thread->pop();
- spriteId = thread->pop();
- x = thread->pop();
- y = thread->pop();
-
- obj = _vm->_actor->getObj(objectId);
+ uint16 objectId = thread->pop();
+ ObjectData *obj = _vm->_actor->getObj(objectId);
+ uint16 spriteId = thread->pop();
+ obj->_location.x = thread->pop();
+ obj->_location.y = thread->pop();
if (obj->_sceneNumber == ITE_SCENE_INV) {
_vm->_interface->removeFromInventory(objectId);
@@ -873,10 +813,10 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) {
obj->_sceneNumber = _vm->_scene->currentSceneNumber();
- // WORKAROUND for the compact disk in Ellen's chapter
+ // HACK for the compact disk in Ellen's chapter
// Change the scene number of the compact disk so that it's not shown. It will be shown
// once Ellen says that there's something different (i.e. after speaking with AM)
- // See Actor::actorSpeech for the other part of this workaround
+ // See Actor::actorSpeech for the other part of this hack
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 3 &&
_vm->_scene->currentSceneNumber() == 59 && obj->_id == 16385)
obj->_sceneNumber = -1;
@@ -891,9 +831,6 @@ void Script::sfDropObject(SCRIPTFUNC_PARAMS) {
} else {
obj->_spriteListResourceId = OBJ_SPRITE_BASE + spriteId;
}
-
- obj->_location.x = x;
- obj->_location.y = y;
}
// Script function #33 (0x21)
@@ -909,16 +846,10 @@ void Script::sfFinishBgdAnim(SCRIPTFUNC_PARAMS) {
// Param1: actor id 1
// Param2: actor id 2
void Script::sfSwapActors(SCRIPTFUNC_PARAMS) {
- int16 actorId1;
- int16 actorId2;
- ActorData *actor1;
- ActorData *actor2;
-
- actorId1 = thread->pop();
- actorId2 = thread->pop();
-
- actor1 = _vm->_actor->getActor(actorId1);
- actor2 = _vm->_actor->getActor(actorId2);
+ int16 actorId1 = thread->pop();
+ int16 actorId2 = thread->pop();
+ ActorData *actor1 = _vm->_actor->getActor(actorId1);
+ ActorData *actor2 = _vm->_actor->getActor(actorId2);
SWAP(actor1->_location, actor2->_location);
@@ -944,24 +875,19 @@ void Script::sfSwapActors(SCRIPTFUNC_PARAMS) {
///....
// Param3: actor idN
void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) {
- int16 stringId;
- int16 actorsCount;
+ int16 stringId = thread->pop();
+ int16 actorsCount = thread->pop();
int i;
uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX];
- const char *string;
+ const char *string = thread->_strings->getString(stringId);
int16 sampleResourceId = -1;
- stringId = thread->pop();
- actorsCount = thread->pop();
-
if (actorsCount > ACTOR_SPEECH_ACTORS_MAX)
error("sfSimulSpeech actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount);
for (i = 0; i < actorsCount; i++)
actorsIds[i] = thread->pop();
- string = thread->_strings->getString(stringId);
-
if (thread->_voiceLUT->voices) {
if (_vm->getGameType() == GType_IHNM && stringId >= 338) {
sampleResourceId = -1;
@@ -982,22 +908,16 @@ void Script::sfSimulSpeech(SCRIPTFUNC_PARAMS) {
// Param3: actor y
// Param4: actor walk flag
void Script::sfScriptWalk(SCRIPTFUNC_PARAMS) {
- int16 actorId;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
Location actorLocation;
- ActorData *actor;
- uint16 walkFlags;
-
- actorId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
- walkFlags = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
-
- _vm->_actor->realLocation(actorLocation, ID_NOTHING, walkFlags);
+ uint16 walkFlags = thread->pop();
actor->_flags &= ~kFollower;
+ _vm->_actor->realLocation(actorLocation, ID_NOTHING, walkFlags);
if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) {
thread->waitWalk(actor);
@@ -1016,18 +936,10 @@ void Script::sfScriptWalk(SCRIPTFUNC_PARAMS) {
// Param3: cycle frame number
// Param4: cycle delay
void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 flags;
- int cycleFrameSequence;
- int cycleDelay;
- ActorData *actor;
-
- actorId = thread->pop();
- flags = thread->pop();
- cycleFrameSequence = thread->pop();
- cycleDelay = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ int16 flags = thread->pop();
+ int cycleFrameSequence = thread->pop();
+ int cycleDelay = thread->pop();
if (flags & kCyclePong) {
actor->_currentAction = kActionPongFrames;
@@ -1046,8 +958,8 @@ void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) {
if (flags & kCycleReverse) {
if (_vm->getGameType() == GType_IHNM &&
_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 41) {
- // Prevent Benny from walking backwards after talking to the child via the monitor. This occurs in the
- // original as well, and is fixed by not setting the kActorBackwards flag at this point
+ // WORKAROUND: Prevent Benny from walking backwards after talking to the child via the monitor. This
+ // occurs in the original as well, and is fixed by not setting the kActorBackwards flag at this point
} else {
actor->_actorFlags |= kActorBackwards;
}
@@ -1064,19 +976,11 @@ void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) {
// Param2: frame type
// Param3: frame offset
void Script::sfSetFrame(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int frameType;
- int frameOffset;
- ActorData *actor;
- ActorFrameRange *frameRange;
-
- actorId = thread->pop();
- frameType = thread->pop();
- frameOffset = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
-
- frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
+ int frameType = thread->pop();
+ int frameOffset = thread->pop();
+ ActorFrameRange *frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
actor->_frameNumber = frameRange->frameIndex + frameOffset;
@@ -1088,17 +992,13 @@ void Script::sfSetFrame(SCRIPTFUNC_PARAMS) {
// Script function #39 (0x27)
// Sets the right-hand portrait
void Script::sfSetPortrait(SCRIPTFUNC_PARAMS) {
- int16 param = thread->pop();
-
- _vm->_interface->setRightPortrait(param);
+ _vm->_interface->setRightPortrait(thread->pop());
}
// Script function #40 (0x28)
// Sets the left-hand portrait
void Script::sfSetProtagPortrait(SCRIPTFUNC_PARAMS) {
- int16 param = thread->pop();
-
- _vm->_interface->setLeftPortrait(param);
+ _vm->_interface->setLeftPortrait(thread->pop());
}
// Script function #41 (0x29) nonblocking
@@ -1130,21 +1030,15 @@ void Script::sfChainBgdAnim(SCRIPTFUNC_PARAMS) {
// Param3: actor y
// Param4: frame seq
void Script::sfScriptSpecialWalk(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 walkFrameSequence;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
Location actorLocation;
- ActorData *actor;
-
- actorId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
- walkFrameSequence = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
+ int16 walkFrameSequence = thread->pop();
_vm->_actor->actorWalkTo(actorId, actorLocation);
-
actor->_walkFrameSequence = walkFrameSequence;
}
@@ -1156,39 +1050,20 @@ void Script::sfScriptSpecialWalk(SCRIPTFUNC_PARAMS) {
// Param5: actor action
// Param6: actor frame number
void Script::sfPlaceActor(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- Location actorLocation;
- int actorDirection;
- int frameType;
- int frameOffset;
- ActorData *actor;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
+ actor->_location.x = thread->pop();
+ actor->_location.y = thread->pop();
+ actor->_facingDirection = actor->_actionDirection = thread->pop();
+ int frameType = thread->pop();
+ int frameOffset = thread->pop();
ActorFrameRange *frameRange;
- actorId = thread->pop();
- actorLocation.x = thread->pop();
- actorLocation.y = thread->pop();
- actorDirection = thread->pop();
- frameType = thread->pop();
- frameOffset = thread->pop();
-
- debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actorLocation.x,
- actorLocation.y, actorDirection, frameType, frameOffset);
-
- actor = _vm->_actor->getActor(actorId);
- actor->_location.x = actorLocation.x;
- actor->_location.y = actorLocation.y;
- actor->_facingDirection = actor->_actionDirection = actorDirection;
-
- if (!actor->_frames)
- _vm->_actor->loadActorResources(actor); //? is not it already loaded ?
+ debug(1, "sfPlaceActor(id = 0x%x, x=%d, y=%d, dir=%d, frameType=%d, frameOffset=%d)", actorId, actor->_location.x,
+ actor->_location.y, actor->_facingDirection, frameType, frameOffset);
if (frameType >= 0) {
frameRange = _vm->_actor->getActorFrameRange(actorId, frameType);
-
- if (frameRange->frameCount <= frameOffset) {
- warning("Wrong frameOffset 0x%X", frameOffset);
- }
-
actor->_frameNumber = frameRange->frameIndex + frameOffset;
actor->_currentAction = kActionFreeze;
} else {
@@ -1213,24 +1088,17 @@ void Script::sfCheckUserInterrupt(SCRIPTFUNC_PARAMS) {
// Param4: actor y
// Param5: actor walk flag
void Script::sfScriptWalkRelative(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 objectId;
- uint16 walkFlags;
+ int16 actorId = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(actorId);
+ int16 objectId = thread->pop();
Location actorLocation;
- ActorData *actor;
-
- actorId = thread->pop();
- objectId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
- walkFlags = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
-
- _vm->_actor->realLocation(actorLocation, objectId, walkFlags);
+ uint16 walkFlags = thread->pop();
actor->_flags &= ~kFollower;
+ _vm->_actor->realLocation(actorLocation, objectId, walkFlags);
if (_vm->_actor->actorWalkTo(actorId, actorLocation) && !(walkFlags & kWalkAsync)) {
thread->waitWalk(actor);
@@ -1250,50 +1118,36 @@ void Script::sfScriptWalkRelative(SCRIPTFUNC_PARAMS) {
// Param4: actor y
// Param5: actor walk flag
void Script::sfScriptMoveRelative(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 objectId;
- uint16 walkFlags;
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ int16 objectId = thread->pop();
Location actorLocation;
- ActorData *actor;
-
- actorId = thread->pop();
- objectId = thread->pop();
actorLocation.x = thread->pop();
actorLocation.y = thread->pop();
- walkFlags = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
actorLocation.z = actor->_location.z;
+ uint16 walkFlags = thread->pop();
_vm->_actor->realLocation(actorLocation, objectId, walkFlags);
-
actor->_location = actorLocation;
actor->_actorFlags = (actor->_actorFlags & ~kActorFacingMask) | (walkFlags & kActorFacingMask);
}
// Script function #47 (0x2F)
void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) {
- int16 stringId;
- int16 actorsCount;
- int16 speechFlags;
+ int16 stringId = thread->pop();
+ const char *string = thread->_strings->getString(stringId);
+ int16 actorsCount = thread->pop();
+ int16 speechFlags = thread->pop();
int i;
uint16 actorsIds[ACTOR_SPEECH_ACTORS_MAX];
- const char *string;
int16 sampleResourceId = -1;
- stringId = thread->pop();
- actorsCount = thread->pop();
- speechFlags = thread->pop();
-
if (actorsCount > ACTOR_SPEECH_ACTORS_MAX)
error("sfSimulSpeech2 actorsCount=0x%X exceed ACTOR_SPEECH_ACTORS_MAX", actorsCount);
for (i = 0; i < actorsCount; i++)
actorsIds[i] = thread->pop();
- string = thread->_strings->getString(stringId);
-
if (thread->_voiceLUT->voices) {
sampleResourceId = thread->_voiceLUT->voices[stringId];
if (sampleResourceId <= 0 || sampleResourceId > 4000)
@@ -1308,7 +1162,7 @@ void Script::sfSimulSpeech2(SCRIPTFUNC_PARAMS) {
// Script function #48 (0x30)
// Param1: string rid
void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
- int stringId;
+ int stringId = thread->pop();
Surface *backBuffer = _vm->_gfx->getBackBuffer();
static PalEntry cur_pal[PAL_ENTRIES];
PalEntry *pal;
@@ -1320,36 +1174,35 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
_vm->_interface->rememberMode();
_vm->_interface->setMode(kPanelPlacard);
- stringId = thread->pop();
-
event.type = kEvTOneshot;
event.code = kCursorEvent;
event.op = kEventHide;
-
q_event = _vm->_events->queue(&event);
- _vm->_gfx->getCurrentPal(cur_pal);
+ _vm->_interface->setFadeMode(kFadeOut);
+ // Fade to black out
+ _vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalToBlack;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
-
q_event = _vm->_events->chain(q_event, &event);
- event.type = kEvTOneshot;
+ // set fade mode
+ event.type = kEvTImmediate;
event.code = kInterfaceEvent;
- event.op = kEventClearStatus;
-
+ event.op = kEventSetFadeMode;
+ event.param = kNoFade;
+ event.time = 0;
+ event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
- event.code = kGraphicsEvent;
- event.op = kEventSetFlag;
- event.param = RF_PLACARD;
-
+ event.code = kInterfaceEvent;
+ event.op = kEventClearStatus;
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
@@ -1361,7 +1214,6 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.param3 = _vm->_scene->getHeight();
event.param4 = 0;
event.param5 = _vm->getDisplayWidth();
-
q_event = _vm->_events->chain(q_event, &event);
// Put the text in the center of the viewport, assuming it will fit on
@@ -1386,25 +1238,21 @@ void Script::sfPlacard(SCRIPTFUNC_PARAMS) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _placardTextEntry;
-
q_event = _vm->_events->chain(q_event, &event);
_vm->_scene->getBGPal(pal);
-
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventBlackToPal;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = pal;
-
q_event = _vm->_events->chain(q_event, &event);
event.type = kEvTOneshot;
event.code = kScriptEvent;
event.op = kEventThreadWake;
event.param = kWaitTypePlacard;
-
q_event = _vm->_events->chain(q_event, &event);
}
@@ -1419,8 +1267,7 @@ void Script::sfPlacardOff(SCRIPTFUNC_PARAMS) {
void Script::sfPsychicProfile(SCRIPTFUNC_PARAMS) {
thread->wait(kWaitTypePlacard);
- int stringId = thread->pop();
- _vm->_scene->showPsychicProfile(thread->_strings->getString(stringId));
+ _vm->_scene->showPsychicProfile(thread->_strings->getString(thread->pop()));
}
void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) {
@@ -1433,9 +1280,7 @@ void Script::sfPsychicProfileOff(SCRIPTFUNC_PARAMS) {
// Script function #50 (0x32)
void Script::sfSetProtagState(SCRIPTFUNC_PARAMS) {
- int protagState = thread->pop();
-
- _vm->_actor->setProtagState(protagState);
+ _vm->_actor->setProtagState(thread->pop());
}
// Script function #51 (0x33)
@@ -1456,28 +1301,20 @@ void Script::sfResumeBgdAnim(SCRIPTFUNC_PARAMS) {
// Param5: actionCycle
// Param6: flags
void Script::sfThrowActor(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- ActorData *actor;
- int16 flags;
- int32 actionCycle;
- Location location;
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ actor->_finalTarget.x = thread->pop();
+ actor->_finalTarget.y = thread->pop();
+ actor->_finalTarget.z = actor->_location.z;
+ thread->pop(); // not used
+ int32 actionCycle = thread->pop();
+ int16 flags = thread->pop();
- actorId = thread->pop();
- location.x = thread->pop();
- location.y = thread->pop();
- thread->pop();
- actionCycle = thread->pop();
- flags = thread->pop();
-
- actor = _vm->_actor->getActor(actorId);
- location.z = actor->_location.z;
actor->_currentAction = kActionFall;
actor->_actionCycle = actionCycle;
actor->_fallAcceleration = -20;
actor->_fallVelocity = - (actor->_fallAcceleration * actor->_actionCycle) / 2;
- actor->_fallPosition = actor->_location.z << 4;
+ actor->_fallPosition = actor->_location.z << 4;
- actor->_finalTarget = location;
actor->_actionCycle--;
if (!(flags & kWalkAsync)) {
thread->waitWalk(actor);
@@ -1488,11 +1325,7 @@ void Script::sfThrowActor(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: target object
void Script::sfWaitWalk(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- ActorData *actor;
-
- actorId = thread->pop();
- actor = _vm->_actor->getActor(actorId);
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
if ((actor->_currentAction == kActionWalkToPoint) ||
(actor->_currentAction == kActionWalkToLink) ||
@@ -1510,14 +1343,8 @@ void Script::sfScriptSceneID(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: scene number
void Script::sfChangeActorScene(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int32 sceneNumber;
- ActorData *actor;
-
- actorId = thread->pop();
- sceneNumber = thread->pop();
- actor = _vm->_actor->getActor(actorId);
- actor->_sceneNumber = sceneNumber;
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ actor->_sceneNumber = thread->pop();
}
// Script function #56 (0x38)
@@ -1526,19 +1353,11 @@ void Script::sfChangeActorScene(SCRIPTFUNC_PARAMS) {
// Param3: frame seq
// Param4: flags
void Script::sfScriptClimb(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- int16 z;
- ActorData *actor;
- uint16 flags;
- int cycleFrameSequence;
-
- actorId = thread->pop();
- z = thread->pop();
- cycleFrameSequence = thread->pop();
- flags = thread->pop();
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
+ actor->_finalTarget.z = thread->pop();
+ int cycleFrameSequence = thread->pop();
+ uint16 flags = thread->pop();
- actor = _vm->_actor->getActor(actorId);
- actor->_finalTarget.z = z;
actor->_flags &= ~kFollower;
actor->_actionCycle = 1;
actor->_cycleFrameSequence = cycleFrameSequence;
@@ -1552,10 +1371,8 @@ void Script::sfScriptClimb(SCRIPTFUNC_PARAMS) {
// Param1: door #
// Param2: door state
void Script::sfSetDoorState(SCRIPTFUNC_PARAMS) {
- int16 doorNumber;
- int16 doorState;
- doorNumber = thread->pop();
- doorState = thread->pop();
+ int16 doorNumber = thread->pop();
+ int16 doorState = thread->pop();
if (_vm->_scene->getFlags() & kSceneFlagISO) {
_vm->_isoMap->setTileDoorState(doorNumber, doorState);
@@ -1568,14 +1385,10 @@ void Script::sfSetDoorState(SCRIPTFUNC_PARAMS) {
// Param1: actor id
// Param2: z
void Script::sfSetActorZ(SCRIPTFUNC_PARAMS) {
- int16 objectId;
+ int16 objectId = thread->pop();
+ int16 z = thread->pop();
ActorData *actor;
ObjectData *obj;
- int16 z;
-
- objectId = thread->pop();
- z = thread->pop();
-
if (_vm->_actor->validActorId(objectId)) {
actor = _vm->_actor->getActor(objectId);
@@ -1595,22 +1408,15 @@ void Script::sfSetActorZ(SCRIPTFUNC_PARAMS) {
// Param4: x
// Param5: y
void Script::sfScriptText(SCRIPTFUNC_PARAMS) {
- int16 stringId;
- int16 flags;
- Rect rect;
- int color;
+ const char *text = thread->_strings->getString(thread->pop());
+ int16 flags = thread->pop();
+ int color = thread->pop();
Point point;
- int width;
- const char*text;
- stringId = thread->pop();
- flags = thread->pop();
- color = thread->pop();
point.x = thread->pop();
point.y = thread->pop();
+ Rect rect;
+ int width = _vm->_font->getStringWidth(kKnownFontScript, text, 0, kFontOutline);
- text = thread->_strings->getString(stringId);
-
- width = _vm->_font->getStringWidth(kKnownFontScript, text, 0, kFontOutline);
rect.top = point.y - 6;
rect.setHeight(12);
rect.left = point.x - width / 2;
@@ -1623,11 +1429,7 @@ void Script::sfScriptText(SCRIPTFUNC_PARAMS) {
// Script function #60 (0x3C)
// Param1: actor id
void Script::sfGetActorX(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- ActorData *actor;
-
- actorId = thread->pop();
- actor = _vm->_actor->getActor(actorId);
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
thread->_returnValue = actor->_location.x >> 2;
}
@@ -1635,23 +1437,17 @@ void Script::sfGetActorX(SCRIPTFUNC_PARAMS) {
// Script function #61 (0x3D)
// Param1: actor id
void Script::sfGetActorY(SCRIPTFUNC_PARAMS) {
- int16 actorId;
- ActorData *actor;
-
- actorId = thread->pop();
- actor = _vm->_actor->getActor(actorId);
+ ActorData *actor = _vm->_actor->getActor(thread->pop());
thread->_returnValue = actor->_location.y >> 2;
}
// Script function #62 (0x3E)
void Script::sfEraseDelta(SCRIPTFUNC_PARAMS) {
- Surface *backGroundSurface;
+ Surface *backGroundSurface = _vm->_render->getBackGroundSurface();
BGInfo backGroundInfo;
- backGroundSurface = _vm->_render->getBackGroundSurface();
_vm->_scene->getBGInfo(backGroundInfo);
-
backGroundSurface->blit(backGroundInfo.bounds, backGroundInfo.buffer);
}
@@ -1712,12 +1508,11 @@ void Script::sfPickClimbOutPos(SCRIPTFUNC_PARAMS) {
// Script function #65 (0x41)
void Script::sfTossRif(SCRIPTFUNC_PARAMS) {
- int16 uc , vc;
uint16 direction;
ActorData *protagonist = _vm->_actor->_protagonist;
+ int16 uc = protagonist->_location.u() >> 4;
+ int16 vc = protagonist->_location.v() >> 4;
- uc = protagonist->_location.u() >> 4;
- vc = protagonist->_location.v() >> 4;
if (_vm->_isoMap->findNearestChasm(uc, vc, direction)) {
uc <<= 4;
vc <<= 4;
@@ -1793,10 +1588,9 @@ void Script::sfPlayLoopedSound(SCRIPTFUNC_PARAMS) {
}
// Script function #72 (0x48)
+// Param1: animation id
void Script::sfGetDeltaFrame(SCRIPTFUNC_PARAMS) {
- uint16 animId = (uint16)thread->pop();
-
- thread->_returnValue = _vm->_anim->getCurrentFrame(animId);
+ thread->_returnValue = _vm->_anim->getCurrentFrame((uint16)thread->pop());
}
// Script function #73 (0x49)
@@ -1813,10 +1607,8 @@ void Script::sfProtectResult(SCRIPTFUNC_PARAMS) {
if (_vm->_copyProtection) {
thread->_returnValue = _vm->_interface->getProtectHash();
} else {
- int protectHash;
-
//cheating
- protectHash = thread->pop();
+ int protectHash = thread->pop();
thread->push(protectHash);
thread->_returnValue = protectHash;
}
@@ -1824,10 +1616,7 @@ void Script::sfProtectResult(SCRIPTFUNC_PARAMS) {
// Script function #75 (0x4b)
void Script::sfRand(SCRIPTFUNC_PARAMS) {
- int16 param;
-
- param = thread->pop();
- thread->_returnValue = _vm->_rnd.getRandomNumber(param - 1);
+ thread->_returnValue = _vm->_rnd.getRandomNumber(thread->pop() - 1);
}
// Script function #76 (0x4c)
@@ -1839,7 +1628,6 @@ void Script::sfFadeMusic(SCRIPTFUNC_PARAMS) {
void Script::sfPlayVoice(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop();
- warning("sfPlayVoice(%d)", param);
if (param > 0) {
_vm->_sndRes->playVoice(param + 3712);
} else {
@@ -1881,13 +1669,24 @@ void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) {
}
void Script::sfSetChapterPoints(SCRIPTFUNC_PARAMS) {
- int16 ethics = thread->pop();
- int16 barometer = thread->pop();
int chapter = _vm->_scene->currentChapterNumber();
+ _vm->_ethicsPoints[chapter] = thread->pop();
+ int16 barometer = thread->pop();
+ static PalEntry cur_pal[PAL_ENTRIES];
- _vm->_ethicsPoints[chapter] = ethics;
- _vm->_spiritualBarometer = ethics * 256 / barometer;
+ _vm->_spiritualBarometer = _vm->_ethicsPoints[chapter] * 256 / barometer;
_vm->_scene->setChapterPointsChanged(true); // don't save this music when saving in IHNM
+
+ if (_vm->_spiritualBarometer > 255)
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff);
+ else
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.red / 256,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.green / 256,
+ _vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.blue / 256);
+
+ _vm->_gfx->getCurrentPal(cur_pal);
+ _vm->_gfx->setPalette(cur_pal);
}
void Script::sfSetPortraitBgColor(SCRIPTFUNC_PARAMS) {
@@ -1899,12 +1698,9 @@ void Script::sfSetPortraitBgColor(SCRIPTFUNC_PARAMS) {
}
void Script::sfScriptStartCutAway(SCRIPTFUNC_PARAMS) {
- int16 cut;
- int16 fade;
-
- cut = thread->pop();
+ int16 cut = thread->pop();
thread->pop(); // Not used
- fade = thread->pop();
+ int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelCutaway);
_vm->_anim->playCutaway(cut, fade != 0);
@@ -1930,61 +1726,37 @@ void Script::sfResetMouseClicks(SCRIPTFUNC_PARAMS) {
// Used in IHNM only
// Param1: frames
void Script::sfWaitFrames(SCRIPTFUNC_PARAMS) {
- int16 frames;
- frames = thread->pop();
-
- // HACK for the nightfall scene in Benny's chapter
- // sfWaitFrames is supposed to wait for fadein and fadeout during that cutaway, but we
- // don't support it yet (function sfScriptFade). This is a temporary hack to avoid
- // having ScummVM wait for ever in that cutaway
- // FIXME: Remove this hack once the palette fading is properly handled
- if (_vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 41 && _vm->_anim->hasCutaway())
- return;
+ int16 frames = thread->pop();
if (!_skipSpeeches)
thread->waitFrames(_vm->_frameCount + frames);
}
void Script::sfScriptFade(SCRIPTFUNC_PARAMS) {
- thread->pop(); // first pal entry, ignored (already handled by Gfx::palToBlack)
- thread->pop(); // last pal entry, ignored (already handled by Gfx::palToBlack)
+ int16 firstPalEntry = thread->pop();
+ int16 lastPalEntry = thread->pop();
int16 startingBrightness = thread->pop();
int16 endingBrightness = thread->pop();
- // delay between pal changes is always 10 (not used)
- static PalEntry cur_pal[PAL_ENTRIES];
Event event;
- short delta = (startingBrightness < endingBrightness) ? +1 : -1;
+ static PalEntry cur_pal[PAL_ENTRIES];
_vm->_gfx->getCurrentPal(cur_pal);
-
- // TODO: This is still wrong, probably a new event type needs to be added (kEventPalFade)
- warning("TODO: sfScriptFade");
- return;
-
- if (startingBrightness > 255)
- startingBrightness = 255;
- if (startingBrightness < 0 )
- startingBrightness = 0;
- if (endingBrightness > 255)
- endingBrightness = 255;
- if (endingBrightness < 0)
- endingBrightness = 0;
-
event.type = kEvTImmediate;
event.code = kPalEvent;
- event.op = kEventPalToBlack;
+ event.op = kEventPalFade;
event.time = 0;
- event.duration = kNormalFadeDuration - ((endingBrightness - startingBrightness) * delta);
+ event.duration = kNormalFadeDuration;
event.data = cur_pal;
-
- _vm->_events->queue(&event);
+ event.param = startingBrightness;
+ event.param2 = endingBrightness;
+ event.param3 = firstPalEntry;
+ event.param4 = lastPalEntry - firstPalEntry + 1;
+ _vm->_events->queue(&event);
}
void Script::sfScriptStartVideo(SCRIPTFUNC_PARAMS) {
- int16 vid;
- int16 fade;
- vid = thread->pop();
- fade = thread->pop();
+ int16 vid = thread->pop();
+ int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelVideo);
_vm->_anim->startVideo(vid, fade != 0);
@@ -2006,14 +1778,10 @@ void Script::sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS) {
}
void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) {
- int stringId, textHeight;
+ int stringId = thread->pop();
TextListEntry textEntry;
Event event;
- stringId = thread->pop();
-
- textHeight = _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered);
-
textEntry.knownColor = kKnownColorBlack;
textEntry.useRect = true;
textEntry.rect.left = 245;
@@ -2030,10 +1798,9 @@ void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) {
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
-
_vm->_events->queue(&event);
- _ihnmDemoCurrentY += 10;
+ _ihnmDemoCurrentY += _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered);
}
void Script::sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS) {
@@ -2051,9 +1818,14 @@ void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) {
_vm->_sound->stopSound();
}
-void Script::sf92(SCRIPTFUNC_PARAMS) {
- SF_stub("sf92", thread, nArgs);
- // This opcode is empty in the full version of IHNM, but it's not empty in the demo
+void Script::sfDemoSetInteractive(SCRIPTFUNC_PARAMS) {
+ if (thread->pop() == 0) {
+ _vm->_interface->deactivate();
+ _vm->_interface->setMode(kPanelNull);
+ }
+
+ // Note: the original also sets an appropriate flag here, but we don't,
+ // as we don't use it
}
void Script::sfDemoIsInteractive(SCRIPTFUNC_PARAMS) {
@@ -2159,7 +1931,6 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
// change
// FIXME: If this is too short for other cases apart from chapter
// point change, set it back to 1000
-
_vm->_events->queue(&event);
if (!_vm->_scene->haveChapterPointsChanged()) {
@@ -2173,9 +1944,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
}
void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) {
- int value = thread->pop();
-
- _vm->_interface->disableAbortSpeeches(value != 0);
+ _vm->_interface->disableAbortSpeeches(thread->pop() != 0);
}
void Script::sfNull(SCRIPTFUNC_PARAMS) {
diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp
index edbdebabab..ac21656dfa 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -101,8 +101,7 @@ SndRes::~SndRes() {
}
}
-void SndRes::setVoiceBank(int serial)
-{
+void SndRes::setVoiceBank(int serial) {
if (_voiceSerial == serial) return;
_voiceSerial = serial;
@@ -183,9 +182,9 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
bool uncompressedSound = false;
- // If a patch file exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed
- if (_vm->getGameType() == GType_ITE && resourceId == 4 &&
- (Common::File::exists("sound/p2_a.iaf") || Common::File::exists("sound/p2_a.voc")))
+ // If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed
+ // Patch data for this resource is in file p2_a.iaf or p2_a.voc
+ if (_vm->getGameType() == GType_ITE && resourceId == 4 && context->table[resourceId].patchData != NULL)
uncompressedSound = true;
// FIXME: Currently, the SFX.RES file in IHNM cannot be compressed