aboutsummaryrefslogtreecommitdiff
path: root/engines/saga/scene.cpp
diff options
context:
space:
mode:
authorMax Horn2006-02-11 22:45:04 +0000
committerMax Horn2006-02-11 22:45:04 +0000
commit26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch)
tree26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/saga/scene.cpp
parent2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff)
downloadscummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2
scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/saga/scene.cpp')
-rw-r--r--engines/saga/scene.cpp1283
1 files changed, 1283 insertions, 0 deletions
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
new file mode 100644
index 0000000000..708800dc41
--- /dev/null
+++ b/engines/saga/scene.cpp
@@ -0,0 +1,1283 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * 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$
+ *
+ */
+
+// Scene management module
+#include "saga/saga.h"
+
+#include "saga/gfx.h"
+#include "saga/animation.h"
+#include "saga/console.h"
+#include "saga/interface.h"
+#include "saga/events.h"
+#include "saga/isomap.h"
+#include "saga/objectmap.h"
+#include "saga/palanim.h"
+#include "saga/puzzle.h"
+#include "saga/render.h"
+#include "saga/script.h"
+#include "saga/sound.h"
+#include "saga/music.h"
+
+#include "saga/scene.h"
+#include "saga/stream.h"
+#include "saga/actor.h"
+#include "saga/rscfile.h"
+#include "saga/resnames.h"
+
+#include "graphics/ilbm.h"
+#include "common/util.h"
+
+namespace Saga {
+
+static int initSceneDoors[SCENE_DOORS_MAX] = {
+ 0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static SAGAResourceTypes ITESceneResourceTypes[26] = {
+ SAGA_ACTOR,
+ SAGA_OBJECT,
+ SAGA_BG_IMAGE,
+ SAGA_BG_MASK,
+SAGA_UNKNOWN,
+ SAGA_STRINGS,
+ SAGA_OBJECT_MAP,
+ SAGA_ACTION_MAP,
+ SAGA_ISO_IMAGES,
+ SAGA_ISO_MAP,
+ SAGA_ISO_PLATFORMS,
+ SAGA_ISO_METATILES,
+ SAGA_ENTRY,
+SAGA_UNKNOWN,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ISO_MULTI,
+ SAGA_PAL_ANIM,
+ SAGA_FACES,
+ SAGA_PALETTE
+};
+
+static SAGAResourceTypes IHNMSceneResourceTypes[28] = {
+ SAGA_ACTOR,
+SAGA_UNKNOWN,
+ SAGA_BG_IMAGE,
+ SAGA_BG_MASK,
+SAGA_UNKNOWN,
+ SAGA_STRINGS,
+ SAGA_OBJECT_MAP,
+ SAGA_ACTION_MAP,
+ SAGA_ISO_IMAGES,
+ SAGA_ISO_MAP,
+ SAGA_ISO_PLATFORMS,
+ SAGA_ISO_METATILES,
+ SAGA_ENTRY,
+SAGA_UNKNOWN,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ANIM,
+ SAGA_ISO_MULTI,
+ SAGA_PAL_ANIM,
+ SAGA_FACES,
+ SAGA_PALETTE
+};
+
+const char *SAGAResourceTypesString[] = {
+ "SAGA_UNKNOWN",
+ "SAGA_ACTOR",
+ "SAGA_OBJECT",
+ "SAGA_BG_IMAGE",
+ "SAGA_BG_MASK",
+ "SAGA_STRINGS",
+ "SAGA_OBJECT_MAP",
+ "SAGA_ACTION_MAP",
+ "SAGA_ISO_IMAGES",
+ "SAGA_ISO_MAP",
+ "SAGA_ISO_PLATFORMS",
+ "SAGA_ISO_METATILES",
+ "SAGA_ENTRY",
+ "SAGA_ANIM",
+ "SAGA_ISO_MULTI",
+ "SAGA_PAL_ANIM",
+ "SAGA_FACES",
+ "SAGA_PALETTE"
+};
+
+Scene::Scene(SagaEngine *vm) : _vm(vm) {
+ byte *sceneLUTPointer;
+ size_t sceneLUTLength;
+ uint32 resourceId;
+ int i;
+
+ // Load scene module resource context
+ _sceneContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
+ if (_sceneContext == NULL) {
+ error("Scene::Scene() scene context not found");
+ }
+
+ // Load scene lookup table
+ resourceId = _vm->_resource->convertResourceId(_vm->getResourceDescription()->sceneLUTResourceId);
+ debug(3, "Loading scene LUT from resource %i", resourceId);
+ _vm->_resource->loadResource(_sceneContext, resourceId, sceneLUTPointer, sceneLUTLength);
+ if (sceneLUTLength == 0) {
+ error("Scene::Scene() sceneLUTLength == 0");
+ }
+ _sceneCount = sceneLUTLength / 2;
+ _sceneLUT = (int *)malloc(_sceneCount * sizeof(*_sceneLUT));
+ if (_sceneLUT == NULL) {
+ memoryError("Scene::Scene()");
+ }
+
+ MemoryReadStreamEndian readS(sceneLUTPointer, sceneLUTLength, _sceneContext->isBigEndian);
+
+ for (i = 0; i < _sceneCount; i++) {
+ _sceneLUT[i] = readS.readUint16();
+ debug(8, "sceneNumber %i has resourceId %i", i, _sceneLUT[i]);
+ }
+
+ free(sceneLUTPointer);
+
+#define DUMP_SCENES_LEVEL 10
+
+ if (DUMP_SCENES_LEVEL <= gDebugLevel) {
+ uint j;
+ int backUpDebugLevel = gDebugLevel;
+ SAGAResourceTypes *types;
+ int typesCount;
+ SAGAResourceTypes resType;
+
+ getResourceTypes(types, typesCount);
+
+ for (i = 0; i < _sceneCount; i++) {
+ gDebugLevel = -1;
+ loadSceneDescriptor(_sceneLUT[i]);
+ loadSceneResourceList(_sceneDescription.resourceListResourceId);
+ gDebugLevel = backUpDebugLevel;
+ debug(DUMP_SCENES_LEVEL, "Dump Scene: number %i, descriptor resourceId %i, resourceList resourceId %i", i, _sceneLUT[i], _sceneDescription.resourceListResourceId);
+ debug(DUMP_SCENES_LEVEL, "\tresourceListCount %i", _resourceListCount);
+ for (j = 0; j < _resourceListCount; j++) {
+ if (_resourceList[j].resourceType >= typesCount) {
+ error("wrong resource type %i", _resourceList[j].resourceType);
+ }
+ resType = types[_resourceList[j].resourceType];
+
+ debug(DUMP_SCENES_LEVEL, "\t%s resourceId %i", SAGAResourceTypesString[resType], _resourceList[j].resourceId);
+ }
+ free(_resourceList);
+ }
+ }
+
+
+ debug(3, "LUT has %d entries.", _sceneCount);
+
+ _sceneLoaded = false;
+ _sceneNumber = 0;
+ _sceneResourceId = 0;
+ _inGame = false;
+ _loadDescription = false;
+ memset(&_sceneDescription, 0, sizeof(_sceneDescription));
+ _resourceListCount = 0;
+ _resourceList = NULL;
+ _sceneProc = NULL;
+ _objectMap = new ObjectMap(_vm);
+ _actionMap = new ObjectMap(_vm);
+ memset(&_bg, 0, sizeof(_bg));
+ memset(&_bgMask, 0, sizeof(_bgMask));
+}
+
+Scene::~Scene() {
+ delete _actionMap;
+ delete _objectMap;
+ free(_sceneLUT);
+}
+
+void Scene::getResourceTypes(SAGAResourceTypes *&types, int &typesCount) {
+ if (_vm->getGameType() == GType_IHNM) {
+ typesCount = ARRAYSIZE(IHNMSceneResourceTypes);
+ types = IHNMSceneResourceTypes;
+ } else {
+ typesCount = ARRAYSIZE(ITESceneResourceTypes);
+ types = ITESceneResourceTypes;
+ }
+}
+
+void Scene::drawTextList(Surface *ds) {
+ TextListEntry *entry;
+
+ for (TextList::iterator textIterator = _textList.begin(); textIterator != _textList.end(); ++textIterator) {
+ entry = (TextListEntry *)textIterator.operator->();
+ if (entry->display) {
+
+ if (entry->useRect) {
+ _vm->_font->textDrawRect(entry->font, ds, entry->text, entry->rect, _vm->KnownColor2ColorId(entry->knownColor), _vm->KnownColor2ColorId(entry->effectKnownColor), entry->flags);
+ } else {
+ _vm->_font->textDraw(entry->font, ds, entry->text, entry->point, _vm->KnownColor2ColorId(entry->knownColor), _vm->KnownColor2ColorId(entry->effectKnownColor), entry->flags);
+ }
+ }
+ }
+}
+
+void Scene::startScene() {
+ SceneQueueList::iterator queueIterator;
+ LoadSceneParams *sceneQueue;
+ Event event;
+
+ if (_sceneLoaded) {
+ error("Scene::start(): Error: Can't start game...scene already loaded");
+ }
+
+ if (_inGame) {
+ error("Scene::start(): Error: Can't start game...game already started");
+ }
+
+ // Hide cursor during intro
+ event.type = kEvTOneshot;
+ event.code = kCursorEvent;
+ event.op = kEventHide;
+ _vm->_events->queue(&event);
+
+ switch (_vm->getGameType()) {
+ case GType_ITE:
+ ITEStartProc();
+ break;
+ case GType_IHNM:
+ IHNMStartProc();
+ break;
+ default:
+ error("Scene::start(): Error: Can't start game... gametype not supported");
+ break;
+ }
+
+ // Load the head in scene queue
+ queueIterator = _sceneQueue.begin();
+ if (queueIterator == _sceneQueue.end()) {
+ return;
+ }
+
+ sceneQueue = queueIterator.operator->();
+
+ loadScene(sceneQueue);
+}
+
+void Scene::nextScene() {
+ SceneQueueList::iterator queueIterator;
+ LoadSceneParams *sceneQueue;
+
+ if (!_sceneLoaded) {
+ error("Scene::next(): Error: Can't advance scene...no scene loaded");
+ }
+
+ if (_inGame) {
+ error("Scene::next(): Error: Can't advance scene...game already started");
+ }
+
+ endScene();
+
+ // Delete the current head in scene queue
+ queueIterator = _sceneQueue.begin();
+ if (queueIterator == _sceneQueue.end()) {
+ return;
+ }
+
+ queueIterator = _sceneQueue.erase(queueIterator);
+
+ if (queueIterator == _sceneQueue.end()) {
+ return;
+ }
+
+ // Load the head in scene queue
+ sceneQueue = queueIterator.operator->();
+
+ loadScene(sceneQueue);
+}
+
+void Scene::skipScene() {
+ SceneQueueList::iterator queueIterator;
+
+ LoadSceneParams *sceneQueue = NULL;
+ LoadSceneParams *skipQueue = NULL;
+
+ if (!_sceneLoaded) {
+ error("Scene::skip(): Error: Can't skip scene...no scene loaded");
+ }
+
+ if (_inGame) {
+ error("Scene::skip(): Error: Can't skip scene...game already started");
+ }
+
+ // Walk down scene queue and try to find a skip target
+ queueIterator = _sceneQueue.begin();
+ if (queueIterator == _sceneQueue.end()) {
+ error("Scene::skip(): Error: Can't skip scene...no scenes in queue");
+ }
+
+ ++queueIterator;
+ while (queueIterator != _sceneQueue.end()) {
+ sceneQueue = queueIterator.operator->();
+ assert(sceneQueue != NULL);
+
+ if (sceneQueue->sceneSkipTarget) {
+ skipQueue = sceneQueue;
+ break;
+ }
+ ++queueIterator;
+ }
+
+ // If skip target found, remove preceding scenes and load
+ if (skipQueue != NULL) {
+ _sceneQueue.erase(_sceneQueue.begin(), queueIterator);
+
+ endScene();
+ loadScene(skipQueue);
+ }
+}
+
+static struct SceneSubstitutes {
+ int sceneId;
+ const char *message;
+ const char *title;
+ const char *image;
+} sceneSubstitutes[] = {
+ {
+ 7,
+ "Tycho says he knows much about the northern lands. Can Rif convince "
+ "the Dog to share this knowledge?",
+ "The Home of Tycho Northpaw",
+ "tycho.bbm"
+ },
+
+ {
+ 27,
+ "The scene of the crime may hold many clues, but will the servants of "
+ "the Sanctuary trust Rif?",
+ "The Sanctuary of the Orb",
+ "sanctuar.bbm"
+ },
+
+ {
+ 5,
+ "The Rats hold many secrets that could guide Rif on his quest -- assuming "
+ "he can get past the doorkeeper.",
+ "The Rat Complex",
+ "ratdoor.bbm"
+ },
+
+ {
+ 2,
+ "The Ferrets enjoy making things and have the materials to do so. How can "
+ "that help Rif?",
+ "The Ferret Village",
+ "ferrets.bbm"
+ },
+
+ {
+ 67,
+ "What aid can the noble King of the Elks provide to Rif and his companions?",
+ "The Realm of the Forest King",
+ "elkenter.bbm"
+ },
+
+ {
+ 3,
+ "The King holds Rif's sweetheart hostage. Will the Boar provide any "
+ "assistance to Rif?",
+ "The Great Hall of the Boar King",
+ "boarhall.bbm"
+ }
+};
+
+void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionType transitionType, int chapter) {
+
+ debug(5, "Scene::changeScene(%d, %d, %d, %d)", sceneNumber, actorsEntrance, transitionType, chapter);
+
+ // This is used for latter ITE demos where all places on world map except
+ // Tent Faire are substituted with LBM picture and short description
+ if (_vm->getFeatures() & GF_SCENE_SUBSTITUTES) {
+ for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) {
+ if (sceneSubstitutes[i].sceneId == sceneNumber) {
+ Surface *backBuffer = _vm->_gfx->getBackBuffer();
+ Surface bbmBuffer;
+ byte *pal, *colors;
+ Common::File file;
+ Rect rect;
+ PalEntry cPal[PAL_ENTRIES];
+
+ _vm->_interface->setMode(kPanelSceneSubstitute);
+
+ if (file.open(sceneSubstitutes[i].image)) {
+ Graphics::decodeILBM(file, bbmBuffer, pal);
+ colors = pal;
+ rect.setWidth(bbmBuffer.w);
+ rect.setHeight(bbmBuffer.h);
+ backBuffer->blit(rect, (const byte*)bbmBuffer.pixels);
+ for (int j = 0; j < PAL_ENTRIES; j++) {
+ cPal[j].red = *pal++;
+ cPal[j].green = *pal++;
+ cPal[j].blue = *pal++;
+ }
+ free(colors);
+ _vm->_gfx->setPalette(cPal);
+
+ }
+
+ _vm->_interface->setStatusText("Click or Press Return to continue. Press Q to quit.", 96);
+ _vm->_font->textDrawRect(kKnownFontMedium, backBuffer, sceneSubstitutes[i].title,
+ Common::Rect(0, 7, _vm->getDisplayWidth(), 27), _vm->KnownColor2ColorId(kKnownColorBrightWhite), _vm->KnownColor2ColorId(kKnownColorBlack), kFontOutline);
+ _vm->_font->textDrawRect(kKnownFontMedium, backBuffer, sceneSubstitutes[i].message,
+ Common::Rect(24, getHeight() - 33, _vm->getDisplayWidth() - 11,
+ getHeight()), _vm->KnownColor2ColorId(kKnownColorBrightWhite), _vm->KnownColor2ColorId(kKnownColorBlack), kFontOutline);
+ return;
+ }
+ }
+ }
+
+ LoadSceneParams sceneParams;
+
+ sceneParams.actorsEntrance = actorsEntrance;
+ sceneParams.loadFlag = kLoadBySceneNumber;
+ sceneParams.sceneDescriptor = sceneNumber;
+ sceneParams.transitionType = transitionType;
+ sceneParams.sceneProc = NULL;
+ sceneParams.sceneSkipTarget = false;
+ sceneParams.chapter = chapter;
+
+ if (sceneNumber != -2) {
+ endScene();
+ }
+ loadScene(&sceneParams);
+}
+
+void Scene::getSlopes(int &beginSlope, int &endSlope) {
+ beginSlope = getHeight() - _sceneDescription.beginSlope;
+ endSlope = getHeight() - _sceneDescription.endSlope;
+}
+
+void Scene::getBGInfo(BGInfo &bgInfo) {
+ bgInfo.buffer = _bg.buf;
+ bgInfo.bufferLength = _bg.buf_len;
+ bgInfo.bounds.left = 0;
+ bgInfo.bounds.top = 0;
+
+ if (_bg.w < _vm->getDisplayWidth()) {
+ bgInfo.bounds.left = (_vm->getDisplayWidth() - _bg.w) / 2;
+ }
+
+ if (_bg.h < getHeight()) {
+ bgInfo.bounds.top = (getHeight() - _bg.h) / 2;
+ }
+
+ bgInfo.bounds.setWidth(_bg.w);
+ bgInfo.bounds.setHeight(_bg.h);
+}
+
+int Scene::getBGMaskType(const Point &testPoint) {
+ uint offset;
+ if (!_bgMask.loaded) {
+ return 0;
+ }
+ offset = testPoint.x + testPoint.y * _bgMask.w;
+ if (offset >= _bgMask.buf_len) {
+ error("Scene::getBGMaskType offset 0x%X exceed bufferLength 0x%X", offset, _bgMask.buf_len);
+ }
+
+ return (_bgMask.buf[offset] >> 4) & 0x0f;
+}
+
+bool Scene::validBGMaskPoint(const Point &testPoint) {
+ if (!_bgMask.loaded) {
+ error("Scene::validBGMaskPoint _bgMask not loaded");
+ }
+
+ return !((testPoint.x < 0) || (testPoint.x >= _bgMask.w) ||
+ (testPoint.y < 0) || (testPoint.y >= _bgMask.h));
+}
+
+bool Scene::canWalk(const Point &testPoint) {
+ int maskType;
+
+ if (!_bgMask.loaded) {
+ return true;
+ }
+ if (!validBGMaskPoint(testPoint)) {
+ return true;
+ }
+
+ maskType = getBGMaskType(testPoint);
+ return getDoorState(maskType) == 0;
+}
+
+bool Scene::offscreenPath(Point &testPoint) {
+ Point point;
+
+ if (!_bgMask.loaded) {
+ return false;
+ }
+
+ point.x = clamp( 0, testPoint.x, _bgMask.w - 1 );
+ point.y = clamp( 0, testPoint.y, _bgMask.h - 1 );
+ if (point == testPoint) {
+ return false;
+ }
+
+ if (point.y >= _bgMask.h - 1) {
+ point.y = _bgMask.h - 2;
+ }
+ testPoint = point;
+
+ return true;
+}
+
+
+void Scene::getBGMaskInfo(int &width, int &height, byte *&buffer, size_t &bufferLength) {
+ if (!_bgMask.loaded) {
+ error("Scene::getBGMaskInfo _bgMask not loaded");
+ }
+
+ width = _bgMask.w;
+ height = _bgMask.h;
+ buffer = _bgMask.buf;
+ bufferLength = _bgMask.buf_len;
+}
+
+void Scene::setDoorState(int doorNumber, int doorState) {
+ if ((doorNumber < 0) || (doorNumber >= SCENE_DOORS_MAX))
+ error("Scene::setDoorState wrong doorNumber");
+
+ _sceneDoors[doorNumber] = doorState;
+}
+
+int Scene::getDoorState(int doorNumber) {
+ if ((doorNumber < 0) || (doorNumber >= SCENE_DOORS_MAX))
+ error("Scene::getDoorState wrong doorNumber");
+
+ return _sceneDoors[doorNumber];
+}
+
+void Scene::initDoorsState() {
+ memcpy(_sceneDoors, initSceneDoors, sizeof (_sceneDoors) );
+}
+
+void Scene::loadScene(LoadSceneParams *loadSceneParams) {
+ size_t i;
+ Event event;
+ Event *q_event;
+ static PalEntry current_pal[PAL_ENTRIES];
+
+ if ((_vm->getGameType() == GType_IHNM) && (loadSceneParams->chapter != NO_CHAPTER_CHANGE)) {
+ if (loadSceneParams->loadFlag != kLoadBySceneNumber) {
+ error("loadScene wrong usage");
+ }
+
+ if (loadSceneParams->chapter == 6)
+ _vm->_interface->setLeftPortrait(0);
+
+ _vm->_anim->freeCutawayList();
+ _vm->_script->freeModules();
+ // deleteAllScenes();
+
+ // installSomeAlarm()
+
+ _vm->_interface->clearInventory();
+ _vm->_resource->loadGlobalResources(loadSceneParams->chapter, loadSceneParams->actorsEntrance);
+ _vm->_interface->addToInventory(IHNM_OBJ_PROFILE);
+ _vm->_interface->activate();
+
+ if (loadSceneParams->chapter == 8 || loadSceneParams->chapter == -1)
+ _vm->_interface->setMode(kPanelChapterSelection);
+ else
+ _vm->_interface->setMode(kPanelMain);
+
+ _inGame = true;
+
+ _vm->_script->setVerb(_vm->_script->getVerbType(kVerbWalkTo));
+
+ if (loadSceneParams->sceneDescriptor == -2) {
+ return;
+ }
+ }
+
+ if (_sceneLoaded) {
+ error("Scene::loadScene(): Error, a scene is already loaded");
+ }
+
+ _loadDescription = true;
+
+ if (_vm->getGameType() == GType_IHNM) {
+ if (loadSceneParams->loadFlag == kLoadBySceneNumber) // When will we get rid of it?
+ if (loadSceneParams->sceneDescriptor <= 0)
+ loadSceneParams->sceneDescriptor = _vm->_resource->_metaResource.sceneIndex;
+ }
+
+ switch (loadSceneParams->loadFlag) {
+ case kLoadByResourceId:
+ _sceneNumber = 0; // original assign zero for loaded by resource id
+ _sceneResourceId = loadSceneParams->sceneDescriptor;
+ break;
+ case kLoadBySceneNumber:
+ _sceneNumber = loadSceneParams->sceneDescriptor;
+ _sceneResourceId = getSceneResourceId(_sceneNumber);
+ break;
+ case kLoadByDescription:
+ _sceneNumber = -1;
+ _sceneResourceId = -1;
+ assert(loadSceneParams->sceneDescription != NULL);
+ assert(loadSceneParams->sceneDescription->resourceList != NULL);
+ _loadDescription = false;
+ _sceneDescription = *loadSceneParams->sceneDescription;
+ _resourceList = loadSceneParams->sceneDescription->resourceList;
+ _resourceListCount = loadSceneParams->sceneDescription->resourceListCount;
+ break;
+ }
+
+ debug(3, "Loading scene number %d:", _sceneNumber);
+
+ // Load scene descriptor and resource list resources
+ if (_loadDescription) {
+ debug(3, "Loading scene resource %i", _sceneResourceId);
+
+ loadSceneDescriptor(_sceneResourceId);
+
+ loadSceneResourceList(_sceneDescription.resourceListResourceId);
+ } else {
+ debug(3, "Loading memory scene resource");
+ }
+
+ // Load resources from scene resource list
+ for (i = 0; i < _resourceListCount; i++) {
+ if (!_resourceList[i].invalid) {
+ _vm->_resource->loadResource(_sceneContext, _resourceList[i].resourceId,
+ _resourceList[i].buffer, _resourceList[i].size);
+
+
+ if (_resourceList[i].size >= 6) {
+ if (!memcmp(_resourceList[i].buffer, "DUMMY!", 6)) {
+ _resourceList[i].invalid = true;
+ warning("DUMMY resource %i", _resourceList[i].resourceId);
+ }
+ }
+ }
+ }
+
+ // Process resources from scene resource list
+ processSceneResources();
+
+ if (_sceneDescription.flags & kSceneFlagISO) {
+ _outsetSceneNumber = _sceneNumber;
+
+ _sceneClip.left = 0;
+ _sceneClip.top = 0;
+ _sceneClip.right = _vm->getDisplayWidth();
+ _sceneClip.bottom = getHeight();
+ } else {
+ BGInfo backGroundInfo;
+ getBGInfo(backGroundInfo);
+ _sceneClip = backGroundInfo.bounds;
+ if (!(_bg.w < _vm->getDisplayWidth() || _bg.h < getHeight()))
+ _outsetSceneNumber = _sceneNumber;
+ }
+
+ _sceneLoaded = true;
+
+ 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);
+
+ // Fade to black out
+ _vm->_gfx->getCurrentPal(current_pal);
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventPalToBlack;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = current_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);
+
+ // Display scene background, but stay with black palette
+ event.type = kEvTImmediate;
+ event.code = kBgEvent;
+ event.op = kEventDisplay;
+ event.param = kEvPNoSetPalette;
+ event.time = 0;
+ event.duration = 0;
+ q_event = _vm->_events->chain(q_event, &event);
+
+ }
+
+ // Start the scene pre script, but stay with black palette
+ if (_sceneDescription.startScriptEntrypointNumber > 0) {
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventExecBlocking;
+ event.time = 0;
+ event.param = _sceneDescription.scriptModuleNumber;
+ event.param2 = _sceneDescription.startScriptEntrypointNumber;
+ event.param3 = 0; // Action
+ event.param4 = _sceneNumber; // Object
+ event.param5 = loadSceneParams->actorsEntrance; // With Object
+ event.param6 = 0; // Actor
+
+ q_event = _vm->_events->chain(q_event, &event);
+ }
+
+ if (loadSceneParams->transitionType == kTransitionFade) {
+
+ // set fade mode
+ event.type = kEvTImmediate;
+ event.code = kInterfaceEvent;
+ event.op = kEventSetFadeMode;
+ event.param = kFadeIn;
+ event.time = 0;
+ event.duration = 0;
+ q_event = _vm->_events->chain(q_event, &event);
+
+ // Fade in from black to the scene background palette
+ event.type = kEvTImmediate;
+ event.code = kPalEvent;
+ event.op = kEventBlackToPal;
+ event.time = 0;
+ event.duration = kNormalFadeDuration;
+ event.data = _bg.pal;
+
+ q_event = _vm->_events->chain(q_event, &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);
+ }
+
+ if (loadSceneParams->sceneProc == NULL) {
+ if (!_inGame && _vm->getGameType() == GType_ITE) {
+ _inGame = true;
+ _vm->_interface->setMode(kPanelMain);
+ }
+
+ _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;
+ event.code = kMusicEvent;
+ event.param = _sceneDescription.musicResourceId;
+ 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);
+ }
+ }
+
+ // Set scene background
+ event.type = kEvTOneshot;
+ event.code = kBgEvent;
+ event.op = kEventDisplay;
+ event.param = kEvPSetPalette;
+ event.time = 0;
+
+ _vm->_events->queue(&event);
+
+ // Begin palette cycle animation if present
+ event.type = kEvTOneshot;
+ event.code = kPalAnimEvent;
+ event.op = kEventCycleStart;
+ event.time = 0;
+
+ q_event = _vm->_events->queue(&event);
+
+ // Start the scene main script
+ if (_sceneDescription.sceneScriptEntrypointNumber > 0) {
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventExecNonBlocking;
+ event.time = 0;
+ event.param = _sceneDescription.scriptModuleNumber;
+ event.param2 = _sceneDescription.sceneScriptEntrypointNumber;
+ event.param3 = _vm->_script->getVerbType(kVerbEnter); // Action
+ event.param4 = _sceneNumber; // Object
+ event.param5 = loadSceneParams->actorsEntrance; // With Object
+ event.param6 = 0; // Actor
+
+ _vm->_events->queue(&event);
+ }
+
+ debug(3, "Scene started");
+
+ } else {
+ loadSceneParams->sceneProc(SCENE_BEGIN, this);
+ }
+
+
+
+ // We probably don't want "followers" to go into scene -1 , 0. At the very
+ // least we don't want garbage to be drawn that early in the ITE intro.
+ if (_sceneNumber > 0 && _sceneNumber != ITE_SCENE_PUZZLE)
+ _vm->_actor->updateActorsScene(loadSceneParams->actorsEntrance);
+
+ if (_sceneNumber == ITE_SCENE_PUZZLE)
+ _vm->_puzzle->execute();
+
+ if (getFlags() & kSceneFlagShowCursor) {
+ // Activate user interface
+ event.type = kEvTOneshot;
+ event.code = kInterfaceEvent;
+ event.op = kEventActivate;
+ event.time = 0;
+ _vm->_events->queue(&event);
+ }
+}
+
+void Scene::loadSceneDescriptor(uint32 resourceId) {
+ byte *sceneDescriptorData;
+ size_t sceneDescriptorDataLength;
+
+ memset(&_sceneDescription, 0, sizeof(_sceneDescription));
+
+ if (resourceId == 0) {
+ return;
+ }
+
+ _vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData, sceneDescriptorDataLength);
+
+ if (sceneDescriptorDataLength == 16) {
+ MemoryReadStreamEndian readS(sceneDescriptorData, sceneDescriptorDataLength, _sceneContext->isBigEndian);
+
+ _sceneDescription.flags = readS.readSint16();
+ _sceneDescription.resourceListResourceId = readS.readSint16();
+ _sceneDescription.endSlope = readS.readSint16();
+ _sceneDescription.beginSlope = readS.readSint16();
+ _sceneDescription.scriptModuleNumber = readS.readUint16();
+ _sceneDescription.sceneScriptEntrypointNumber = readS.readUint16();
+ _sceneDescription.startScriptEntrypointNumber = readS.readUint16();
+ _sceneDescription.musicResourceId = readS.readSint16();
+ }
+
+ free(sceneDescriptorData);
+}
+
+void Scene::loadSceneResourceList(uint32 resourceId) {
+ byte *resourceListData;
+ size_t resourceListDataLength;
+ size_t i;
+
+ _resourceListCount = 0;
+ _resourceList = NULL;
+
+ if (resourceId == 0) {
+ return;
+ }
+
+ // Load the scene resource table
+ _vm->_resource->loadResource(_sceneContext, resourceId, resourceListData, resourceListDataLength);
+
+ if ((resourceListDataLength % SAGA_RESLIST_ENTRY_LEN) == 0) {
+ MemoryReadStreamEndian readS(resourceListData, resourceListDataLength, _sceneContext->isBigEndian);
+
+ // Allocate memory for scene resource list
+ _resourceListCount = resourceListDataLength / SAGA_RESLIST_ENTRY_LEN;
+ debug(3, "Scene resource list contains %i entries", _resourceListCount);
+ _resourceList = (SceneResourceData *)calloc(_resourceListCount, sizeof(*_resourceList));
+
+ // Load scene resource list from raw scene
+ // resource table
+ debug(3, "Loading scene resource list");
+
+ for (i = 0; i < _resourceListCount; i++) {
+ _resourceList[i].resourceId = readS.readUint16();
+ _resourceList[i].resourceType = readS.readUint16();
+ // demo version may contain invalid resourceId
+ _resourceList[i].invalid = !_vm->_resource->validResourceId(_sceneContext, _resourceList[i].resourceId);
+ }
+
+ }
+ free(resourceListData);
+}
+
+void Scene::processSceneResources() {
+ byte *resourceData;
+ size_t resourceDataLength;
+ const byte *palPointer;
+ size_t i;
+ SAGAResourceTypes *types;
+ int typesCount;
+ SAGAResourceTypes resType;
+
+ getResourceTypes(types, typesCount);
+
+ // Process the scene resource list
+ for (i = 0; i < _resourceListCount; i++) {
+ if (_resourceList[i].invalid) {
+ continue;
+ }
+ resourceData = _resourceList[i].buffer;
+ resourceDataLength = _resourceList[i].size;
+
+ if (_resourceList[i].resourceType >= typesCount) {
+ error("Scene::processSceneResources() wrong resource type %i", _resourceList[i].resourceType);
+ }
+
+ resType = types[_resourceList[i].resourceType];
+
+ switch (resType) {
+ case SAGA_UNKNOWN:
+ warning("UNKNOWN resourceType %i", _resourceList[i].resourceType);
+ break;
+ case SAGA_ACTOR:
+ //for (a = actorsInScene; a; a = a->nextInScene)
+ // if (a->obj.figID == glist->file_id)
+ // if (_vm->getGameType() == GType_ITE ||
+ // ((a->obj.flags & ACTORF_FINAL_FACE) & 0xff))
+ // a->sprites = (xSpriteSet *)glist->offset;
+ warning("STUB: unimplemeted handler of SAGA_ACTOR resource");
+ break;
+ case SAGA_OBJECT:
+ break;
+ case SAGA_BG_IMAGE: // Scene background resource
+ if (_bg.loaded) {
+ error("Scene::processSceneResources() Multiple background resources encountered");
+ }
+
+ debug(3, "Loading background resource.");
+ _bg.res_buf = resourceData;
+ _bg.res_len = resourceDataLength;
+ _bg.loaded = 1;
+
+ if (_vm->decodeBGImage(_bg.res_buf,
+ _bg.res_len,
+ &_bg.buf,
+ &_bg.buf_len,
+ &_bg.w,
+ &_bg.h) != SUCCESS) {
+ error("Scene::processSceneResources() Error loading background resource %i", _resourceList[i].resourceId);
+ }
+
+ palPointer = _vm->getImagePal(_bg.res_buf, _bg.res_len);
+ memcpy(_bg.pal, palPointer, sizeof(_bg.pal));
+ break;
+ case SAGA_BG_MASK: // Scene background mask resource
+ if (_bgMask.loaded) {
+ error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
+ }
+ debug(3, "Loading BACKGROUND MASK resource.");
+ _bgMask.res_buf = resourceData;
+ _bgMask.res_len = resourceDataLength;
+ _bgMask.loaded = 1;
+ _vm->decodeBGImage(_bgMask.res_buf, _bgMask.res_len, &_bgMask.buf,
+ &_bgMask.buf_len, &_bgMask.w, &_bgMask.h, true);
+
+ // At least in ITE the mask needs to be clipped.
+
+ _bgMask.w = MIN(_bgMask.w, _vm->getDisplayWidth());
+ _bgMask.h = MIN(_bgMask.h, getHeight());
+
+ debug(4, "BACKGROUND MASK width=%d height=%d length=%d", _bgMask.w, _bgMask.h, _bgMask.buf_len);
+ break;
+ case SAGA_STRINGS:
+ debug(3, "Loading scene strings resource...");
+ _vm->loadStrings(_sceneStrings, resourceData, resourceDataLength);
+ break;
+ case SAGA_OBJECT_MAP:
+ debug(3, "Loading object map resource...");
+ _objectMap->load(resourceData, resourceDataLength);
+ break;
+ case SAGA_ACTION_MAP:
+ debug(3, "Loading action map resource...");
+ _actionMap->load(resourceData, resourceDataLength);
+ break;
+ case SAGA_ISO_IMAGES:
+ if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ error("Scene::ProcessSceneResources(): not Iso mode");
+ }
+
+ debug(3, "Loading isometric images resource.");
+
+ _vm->_isoMap->loadImages(resourceData, resourceDataLength);
+ break;
+ case SAGA_ISO_MAP:
+ if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ error("Scene::ProcessSceneResources(): not Iso mode");
+ }
+
+ debug(3, "Loading isometric map resource.");
+
+ _vm->_isoMap->loadMap(resourceData, resourceDataLength);
+ break;
+ case SAGA_ISO_PLATFORMS:
+ if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ error("Scene::ProcessSceneResources(): not Iso mode");
+ }
+
+ debug(3, "Loading isometric platforms resource.");
+
+ _vm->_isoMap->loadPlatforms(resourceData, resourceDataLength);
+ break;
+ case SAGA_ISO_METATILES:
+ if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ error("Scene::ProcessSceneResources(): not Iso mode");
+ }
+
+ debug(3, "Loading isometric metatiles resource.");
+
+ _vm->_isoMap->loadMetaTiles(resourceData, resourceDataLength);
+ break;
+ case SAGA_ANIM:
+ {
+ uint16 animId = _resourceList[i].resourceType - 14;
+
+ debug(3, "Loading animation resource animId=%i", animId);
+
+ _vm->_anim->load(animId, resourceData, resourceDataLength);
+ }
+ break;
+ case SAGA_ENTRY:
+ debug(3, "Loading entry list resource...");
+ loadSceneEntryList(resourceData, resourceDataLength);
+ break;
+ case SAGA_ISO_MULTI:
+ if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ error("Scene::ProcessSceneResources(): not Iso mode");
+ }
+
+ debug(3, "Loading isometric multi resource.");
+
+ _vm->_isoMap->loadMulti(resourceData, resourceDataLength);
+ break;
+ case SAGA_PAL_ANIM:
+ debug(3, "Loading palette animation resource.");
+ _vm->_palanim->loadPalAnim(resourceData, resourceDataLength);
+ break;
+ case SAGA_FACES:
+ if (_vm->getGameType() == GType_ITE)
+ _vm->_interface->loadScenePortraits(_resourceList[i].resourceId);
+ break;
+ case SAGA_PALETTE:
+ {
+ PalEntry pal[PAL_ENTRIES];
+ byte *palPtr = resourceData;
+
+ if (resourceDataLength < 3 * PAL_ENTRIES)
+ error("Too small scene palette %i", resourceDataLength);
+
+ for (uint16 c = 0; c < PAL_ENTRIES; c++) {
+ pal[c].red = *palPtr++;
+ pal[c].green = *palPtr++;
+ pal[c].blue = *palPtr++;
+ }
+ _vm->_gfx->setPalette(pal);
+ }
+ break;
+ default:
+ error("Scene::ProcessSceneResources() Encountered unknown resource type %i", _resourceList[i].resourceType);
+ break;
+ }
+ }
+}
+
+void Scene::draw() {
+ Surface *backBuffer;
+ Surface *backGroundSurface;
+ Rect rect;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ backGroundSurface = _vm->_render->getBackGroundSurface();
+
+ if (_sceneDescription.flags & kSceneFlagISO) {
+ _vm->_isoMap->adjustScroll(false);
+ _vm->_isoMap->draw(backBuffer);
+ } else {
+ backGroundSurface->getRect(rect);
+ if (_sceneClip.bottom < rect.bottom) {
+ rect.bottom = getHeight();
+ }
+ backBuffer->blit(rect, (const byte *)backGroundSurface->pixels);
+ }
+}
+
+void Scene::endScene() {
+ Surface *backBuffer;
+ Surface *backGroundSurface;
+ Rect rect;
+ size_t i;
+
+ if (!_sceneLoaded)
+ return;
+
+ debug(3, "Ending scene...");
+
+ if (_sceneProc != NULL) {
+ _sceneProc(SCENE_END, this);
+ }
+
+ //
+ _vm->_script->abortAllThreads();
+ _vm->_script->_skipSpeeches = false;
+
+ // Copy current screen to render buffer so inset rooms will get proper background
+ backGroundSurface = _vm->_render->getBackGroundSurface();
+ if (!(_sceneDescription.flags & kSceneFlagISO) && !_vm->_scene->isInIntro()) {
+ BGInfo bgInfo;
+
+ _vm->_scene->getBGInfo(bgInfo);
+ backGroundSurface->blit(bgInfo.bounds, bgInfo.buffer);
+ } else {
+ backBuffer = _vm->_gfx->getBackBuffer();
+ backBuffer->getRect(rect);
+ backGroundSurface->blit(rect, (const byte *)backBuffer->pixels);
+ }
+
+ // Free scene background
+ if (_bg.loaded) {
+ free(_bg.buf);
+ _bg.loaded = 0;
+ }
+
+ // Free scene background mask
+ if (_bgMask.loaded) {
+ free(_bgMask.buf);
+ _bgMask.loaded = 0;
+ }
+
+ // Free scene resource list
+ for (i = 0; i < _resourceListCount; i++) {
+ free(_resourceList[i].buffer);
+ }
+
+ if (_loadDescription) {
+ free(_resourceList);
+ }
+
+ // Free animation info list
+ _vm->_anim->reset();
+
+ _vm->_palanim->freePalAnim();
+
+ _objectMap->freeMem();
+ _actionMap->freeMem();
+ _entryList.freeMem();
+ _sceneStrings.freeMem();
+ _vm->_isoMap->freeMem();
+
+ _vm->_events->clearList();
+ _textList.clear();
+
+ _sceneLoaded = false;
+
+}
+
+void Scene::cmdSceneChange(int argc, const char **argv) {
+ int scene_num = 0;
+
+ scene_num = atoi(argv[1]);
+
+ if ((scene_num < 1) || (scene_num >= _sceneCount)) {
+ _vm->_console->DebugPrintf("Invalid scene number.\n");
+ return;
+ }
+
+ clearSceneQueue();
+
+ changeScene(scene_num, 0, kTransitionNoFade);
+}
+
+void Scene::cmdActionMapInfo() {
+ _actionMap->cmdInfo();
+}
+
+void Scene::cmdObjectMapInfo() {
+ _objectMap->cmdInfo();
+}
+
+
+void Scene::loadSceneEntryList(const byte* resourcePointer, size_t resourceLength) {
+ int i;
+
+ _entryList.entryListCount = resourceLength / 8;
+
+ MemoryReadStreamEndian readS(resourcePointer, resourceLength, _sceneContext->isBigEndian);
+
+
+ if (_entryList.entryList)
+ error("Scene::loadSceneEntryList entryList != NULL");
+
+ _entryList.entryList = (SceneEntry *) malloc(_entryList.entryListCount * sizeof(*_entryList.entryList));
+ if (_entryList.entryList == NULL) {
+ memoryError("Scene::loadSceneEntryList");
+ }
+
+ for (i = 0; i < _entryList.entryListCount; i++) {
+ _entryList.entryList[i].location.x = readS.readSint16();
+ _entryList.entryList[i].location.y = readS.readSint16();
+ _entryList.entryList[i].location.z = readS.readSint16();
+ _entryList.entryList[i].facing = readS.readUint16();
+ }
+}
+
+} // End of namespace Saga