mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-23 18:24:59 +00:00
769dd1d7a2
- The spiritual barometer display in IHNM is now updated only when necessary, to speed drawing up. This also corrects an issue where the spiritual barometer display was updated only after changing a scene - sf92 is sfDemoSetInteractive - It's now possible to use dashes and underscores in savegames - Screen fading when changing scenes is now done correctly: the interface will no longer be incorrectly briefly shown while the screen is fading to black - The interface mode is now correctly set in the non-interactive part of the IHNM demo - sfScriptGotoScene does not have a transition parameter, therefore that parameter has been removed svn-id: r28643
1480 lines
39 KiB
C++
1480 lines
39 KiB
C++
/* 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$
|
|
*
|
|
*/
|
|
|
|
// 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/sagaresnames.h"
|
|
|
|
#include "graphics/iff.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", (int)_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::decodePBM(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);
|
|
}
|
|
|
|
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::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 (loadSceneParams->transitionType == kTransitionFade)
|
|
_vm->_interface->setFadeMode(kFadeOut);
|
|
|
|
// Change the cursor to an hourglass in IHNM
|
|
event.type = kEvTOneshot;
|
|
event.code = kCursorEvent;
|
|
event.op = kEventSetBusyCursor;
|
|
event.time = 0;
|
|
_vm->_events->queue(&event);
|
|
|
|
_chapterPointsChanged = false;
|
|
|
|
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();
|
|
// 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();
|
|
|
|
// 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) {
|
|
if (_vm->getGameId() != GID_IHNM_DEMO)
|
|
_vm->_interface->setMode(kPanelChapterSelection);
|
|
else
|
|
_vm->_interface->setMode(kPanelNull);
|
|
} else {
|
|
_vm->_interface->setMode(kPanelMain);
|
|
}
|
|
|
|
_inGame = true;
|
|
|
|
_vm->_script->setVerb(_vm->_script->getVerbType(kVerbWalkTo));
|
|
|
|
if (loadSceneParams->sceneDescriptor == -2) {
|
|
_vm->_interface->setFadeMode(kNoFade);
|
|
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);
|
|
|
|
if (_vm->getGameId() == GID_IHNM_DEMO && (_sceneNumber >= 144 && _sceneNumber <= 149)) {
|
|
// WORKAROUND for the non-interactive part of the IHNM demo: When restarting the
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Change the cursor back to a crosshair in IHNM
|
|
event.type = kEvTOneshot;
|
|
event.code = kCursorEvent;
|
|
event.op = kEventSetNormalCursor;
|
|
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", (int)_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, (int)_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", (int)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::restoreScene() {
|
|
// There is no implementation for tiled scenes, since this function is only used
|
|
// in IHNM, which has no tiled scenes
|
|
|
|
Event event;
|
|
|
|
_vm->_gfx->showCursor(false);
|
|
_vm->_gfx->restorePalette();
|
|
|
|
event.type = kEvTImmediate;
|
|
event.code = kBgEvent;
|
|
event.op = kEventDisplay;
|
|
event.param = kEvPNoSetPalette;
|
|
event.time = 0;
|
|
event.duration = 0;
|
|
_vm->_events->queue(&event);
|
|
|
|
_vm->_gfx->showCursor(true);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
void Scene::clearPlacard() {
|
|
static PalEntry cur_pal[PAL_ENTRIES];
|
|
PalEntry *pal;
|
|
Event event;
|
|
Event *q_event;
|
|
|
|
_vm->_interface->restoreMode();
|
|
|
|
_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;
|
|
|
|
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);
|
|
|
|
_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 = 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);
|
|
}
|
|
|
|
void Scene::showPsychicProfile(const char *text) {
|
|
int textHeight;
|
|
static PalEntry cur_pal[PAL_ENTRIES];
|
|
PalEntry *pal;
|
|
TextListEntry textEntry;
|
|
Event event;
|
|
Event *q_event;
|
|
|
|
if (_vm->_interface->getMode() == kPanelPlacard)
|
|
return;
|
|
|
|
_vm->_interface->rememberMode();
|
|
_vm->_interface->setMode(kPanelPlacard);
|
|
_vm->_gfx->savePalette();
|
|
|
|
event.type = kEvTOneshot;
|
|
event.code = kCursorEvent;
|
|
event.op = kEventHide;
|
|
|
|
q_event = _vm->_events->queue(&event);
|
|
|
|
_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;
|
|
event.code = kInterfaceEvent;
|
|
event.op = kEventClearStatus;
|
|
|
|
q_event = _vm->_events->chain(q_event, &event);
|
|
|
|
event.type = kEvTOneshot;
|
|
event.code = kGraphicsEvent;
|
|
event.op = kEventSetFlag;
|
|
event.param = RF_PLACARD;
|
|
|
|
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();
|
|
|
|
if (text != NULL) {
|
|
textHeight = _vm->_font->getHeight(kKnownFontVerb, text, 226, kFontCentered);
|
|
|
|
textEntry.knownColor = kKnownColorBlack;
|
|
textEntry.useRect = true;
|
|
textEntry.rect.left = 245;
|
|
textEntry.rect.setHeight(210 + 76);
|
|
textEntry.rect.setWidth(226);
|
|
textEntry.rect.top = 210 - textHeight;
|
|
textEntry.font = kKnownFontVerb;
|
|
textEntry.flags = (FontEffectFlags)(kFontCentered);
|
|
textEntry.text = text;
|
|
|
|
TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry);
|
|
|
|
event.type = kEvTOneshot;
|
|
event.code = kTextEvent;
|
|
event.op = kEventDisplay;
|
|
event.data = _psychicProfileTextEntry;
|
|
|
|
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);
|
|
}
|
|
|
|
void Scene::clearPsychicProfile() {
|
|
if (_vm->_interface->getMode() == kPanelPlacard || _vm->getGameId() == GID_IHNM_DEMO) {
|
|
_vm->_scene->clearPlacard();
|
|
_vm->_scene->_textList.clear();
|
|
_vm->_actor->showActors(false);
|
|
_vm->_gfx->restorePalette();
|
|
_vm->_scene->restoreScene();
|
|
_vm->_interface->activate();
|
|
}
|
|
}
|
|
|
|
void Scene::showIHNMDemoSpecialScreen() {
|
|
_vm->_gfx->showCursor(true);
|
|
_vm->_interface->clearInventory();
|
|
_vm->_scene->changeScene(150, 0, kTransitionFade);
|
|
}
|
|
|
|
} // End of namespace Saga
|