- Split the IHNM script functions into a different file

- Added two new defines, ENABLE_IHNM and ENABLE_SAGA2 (enabled by default), which can be used to remove the parts of the SAGA engine which are specific to IHNM and SAGA 2 games. Hopefully, this will reduce the size of the engine even more for platforms with little memory (e.g. the Nintendo DS)

svn-id: r35672
This commit is contained in:
Filippos Karapetis 2009-01-02 16:52:38 +00:00
parent a09a7678f4
commit d5b6996c45
29 changed files with 656 additions and 430 deletions

View file

@ -22,7 +22,7 @@
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
BasicRuntimeChecks="3"
@ -71,7 +71,7 @@
FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
RuntimeLibrary="0"
@ -262,6 +262,9 @@
<File
RelativePath="..\..\engines\saga\sfuncs.cpp">
</File>
<File
RelativePath="..\..\engines\saga\sfuncs_ihnm.cpp">
</File>
<File
RelativePath="..\..\engines\saga\sndres.cpp">
</File>

View file

@ -22,7 +22,7 @@
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="TRUE"
ExceptionHandling="TRUE"
BasicRuntimeChecks="3"
@ -77,7 +77,7 @@
FavorSizeOrSpeed="2"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="TRUE"
ExceptionHandling="TRUE"
RuntimeLibrary="0"
@ -276,6 +276,9 @@
<File
RelativePath="..\..\engines\saga\sfuncs.cpp">
</File>
<File
RelativePath="..\..\engines\saga\sfuncs_ihnm.cpp">
</File>
<File
RelativePath="..\..\engines\saga\sndres.cpp">
</File>

View file

@ -43,7 +43,7 @@
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
BasicRuntimeChecks="3"
@ -120,7 +120,7 @@
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -378,6 +378,10 @@
RelativePath="..\..\engines\saga\sfuncs.cpp"
>
</File>
<File
RelativePath="..\..\engines\saga\sfuncs_ihnm.cpp"
>
</File>
<File
RelativePath="..\..\engines\saga\sndres.cpp"
>

View file

@ -44,7 +44,7 @@
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;_DEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;_DEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
MinimalRebuild="true"
ExceptionHandling="1"
BasicRuntimeChecks="3"
@ -121,7 +121,7 @@
FavorSizeOrSpeed="2"
OmitFramePointers="true"
AdditionalIncludeDirectories="../../;../../engines"
PreprocessorDefinitions="WIN32;NDEBUG;USE_ZLIB;USE_MAD;USE_VORBIS"
PreprocessorDefinitions="WIN32;NDEBUG;ENABLE_IHNM;ENABLE_SAGA2;USE_ZLIB;USE_MAD;USE_VORBIS"
StringPooling="true"
ExceptionHandling="1"
RuntimeLibrary="0"
@ -379,6 +379,10 @@
RelativePath="..\..\engines\saga\sfuncs.cpp"
>
</File>
<File
RelativePath="..\..\engines\saga\sfuncs_ihnm.cpp"
>
</File>
<File
RelativePath="..\..\engines\saga\sndres.cpp"
>

View file

@ -51,6 +51,7 @@ static int commonObjectCompare(const CommonObjectDataPointer& obj1, const Common
return 1;
}
#ifdef ENABLE_IHNM
static int commonObjectCompareIHNM(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
int p1 = obj1->_location.y;
int p2 = obj2->_location.y;
@ -60,6 +61,7 @@ static int commonObjectCompareIHNM(const CommonObjectDataPointer& obj1, const Co
return -1;
return 1;
}
#endif
static int tileCommonObjectCompare(const CommonObjectDataPointer& obj1, const CommonObjectDataPointer& obj2) {
int p1 = -obj1->_location.u() - obj1->_location.v() - obj1->_location.z;
@ -182,6 +184,7 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
obj->_location.z = ITE_ObjectTable[i].z;
}
} else {
#ifdef ENABLE_IHNM
// TODO. This is causing problems for SYMBIAN os as it doesn't like a static class here
ActorData dummyActor;
@ -189,6 +192,7 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) {
dummyActor._walkStepsPoints = NULL;
_protagonist = &dummyActor;
#endif
}
_dragonHunt = true;
@ -612,6 +616,7 @@ ActorData *Actor::getActor(uint16 actorId) {
void Actor::setProtagState(int state) {
_protagState = state;
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
if (!_protagonist->_shareFrames)
free(_protagonist->_frames);
@ -620,6 +625,8 @@ void Actor::setProtagState(int state) {
_protagonist->_framesCount = _protagStates[state]._framesCount;
_protagonist->_shareFrames = true;
}
#endif
}
int Actor::getFrameType(ActorFrameTypes frameType) {
@ -643,8 +650,8 @@ int Actor::getFrameType(ActorFrameTypes frameType) {
case kFrameLook:
return kFrameITELook;
}
}
else {
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM) {
switch (frameType) {
case kFrameStand:
return kFrameIHNMStand;
@ -662,6 +669,7 @@ int Actor::getFrameType(ActorFrameTypes frameType) {
error("Actor::getFrameType() unknown frame type %d", frameType);
return kFrameIHNMStand;
}
#endif
}
error("Actor::getFrameType() unknown frame type %d", frameType);
}
@ -689,6 +697,7 @@ ActorFrameRange *Actor::getActorFrameRange(uint16 actorId, int frameType) {
return &actor->_frames[frameType].directions[fourDirection];
}
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
// It is normal for some actors to have no frames for a given frameType
// These are mainly actors with no frames at all (e.g. narrators or immovable actors)
@ -703,6 +712,8 @@ ActorFrameRange *Actor::getActorFrameRange(uint16 actorId, int frameType) {
fourDirection = actorDirectionsLUT[actor->_facingDirection];
return &actor->_frames[frameType].directions[fourDirection];
}
#endif
return NULL;
}
@ -875,10 +886,12 @@ bool Actor::calcScreenPosition(CommonObjectData *commonObjectData) {
if (middle <= beginSlope) {
commonObjectData->_screenScale = 256;
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM && (objectTypeId(commonObjectData->_id) & kGameObjectObject)) {
commonObjectData->_screenScale = 256;
} else if (_vm->getGameId() == GID_IHNM && (commonObjectData->_flags & kNoScale)) {
commonObjectData->_screenScale = 256;
#endif
} else if (middle >= endSlope) {
commonObjectData->_screenScale = 1;
} else {
@ -951,15 +964,17 @@ void Actor::createDrawOrderList() {
int i;
ActorData *actor;
ObjectData *obj;
CommonObjectOrderList::CompareFunction compareFunction;
CommonObjectOrderList::CompareFunction compareFunction = 0;
if (_vm->_scene->getFlags() & kSceneFlagISO) {
compareFunction = &tileCommonObjectCompare;
} else {
if (_vm->getGameId() == GID_ITE)
compareFunction = &commonObjectCompare;
else
#ifdef ENABLE_IHNM
else if (_vm->getGameId() == GID_IHNM)
compareFunction = &commonObjectCompareIHNM;
#endif
}
_drawOrderList.clear();

View file

@ -55,9 +55,13 @@ Anim::Anim(SagaEngine *vm) : _vm(vm) {
Anim::~Anim(void) {
reset();
#ifdef ENABLE_IHNM
freeCutawayList();
#endif
}
#ifdef ENABLE_IHNM
void Anim::loadCutawayList(const byte *resourcePointer, size_t resourceLength) {
free(_cutawayList);
_cutawayListLength = resourceLength / 8;
@ -391,6 +395,8 @@ void Anim::returnFromVideo(void) {
returnFromCutaway();
}
#endif
void Anim::load(uint16 animId, const byte *animResourceData, size_t animResourceLength) {
AnimationData *anim;
uint16 temp;
@ -935,6 +941,7 @@ void Anim::animInfo() {
}
}
#ifdef ENABLE_IHNM
void Anim::cutawayInfo() {
uint16 i;
@ -946,6 +953,7 @@ void Anim::cutawayInfo() {
_cutawayList[i].cycles, _cutawayList[i].frameRate);
}
}
#endif
void Anim::resumeAll() {
// Restore the animations

View file

@ -104,15 +104,19 @@ bool Console::cmdAnimInfo(int argc, const char **argv) {
}
bool Console::cmdCutawayInfo(int argc, const char **argv) {
#ifdef ENABLE_IHNM
_vm->_anim->cutawayInfo();
#endif
return true;
}
bool Console::cmdPlayCutaway(int argc, const char **argv) {
#ifdef ENABLE_IHNM
if (argc != 2)
DebugPrintf("Usage: %s <Cutaway number>\n", argv[0]);
else
_vm->_anim->playCutaway(atoi(argv[1]), false);
#endif
return true;
}

View file

@ -321,15 +321,17 @@ const GameDisplayInfo &SagaEngine::getDisplayInfo() {
switch (_gameDescription->gameId) {
case GID_ITE:
return ITE_DisplayInfo;
#ifdef ENABLE_IHNM
case GID_IHNM:
return IHNM_DisplayInfo;
#endif
case GID_DINO:
return IHNM_DisplayInfo; // TODO
return FTA2_DisplayInfo; // TODO
case GID_FTA2:
return FTA2_DisplayInfo;
default:
error("getDisplayInfo: Unknown game ID");
return IHNM_DisplayInfo; // unreachable
return ITE_DisplayInfo; // unreachable
}
}

View file

@ -626,7 +626,7 @@ static const SAGAGameDescription gameDescriptions[] = {
// TODO: Add the Amiga versions here (not supported yet)
#ifdef ENABLE_IHNM
// IHNM Section ///////////////////////////////////////////////////////////////////////////////////////////
// I Have No Mouth And I Must Scream - Demo version
@ -833,6 +833,7 @@ static const SAGAGameDescription gameDescriptions[] = {
NULL,
NULL,
},
#endif
// Dinotopia Section //////////////////////////////////////////////////////////////////////////////////////

View file

@ -361,7 +361,7 @@ static PanelButton IHNM_SavePanelButtons[] = {
{kPanelButtonSaveText, -1,30, 0,0, kTextEnterSaveGameName,'-',0, 0,0,0},
};
#ifdef ENABLE_IHNM
static const GameDisplayInfo IHNM_DisplayInfo = {
640, 480, // logical width&height
@ -427,7 +427,7 @@ static const GameDisplayInfo IHNM_DisplayInfo = {
ARRAYSIZE(IHNM_SavePanelButtons),
IHNM_SavePanelButtons
};
#endif
// TODO: Fill in missing bits, currently contains IHNM_DisplayInfo
static const GameDisplayInfo FTA2_DisplayInfo = {

View file

@ -155,9 +155,11 @@ int Events::handleContinuous(Event *event) {
case kEventPalToBlack:
_vm->_gfx->palToBlack((PalEntry *)event->data, event_pc);
break;
#ifdef ENABLE_IHNM
case kEventPalFade:
_vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc);
break;
#endif
default:
break;
}
@ -240,9 +242,11 @@ int Events::handleImmediate(Event *event) {
case kEventPalToBlack:
_vm->_gfx->palToBlack((PalEntry *)event->data, event_pc);
break;
#ifdef ENABLE_IHNM
case kEventPalFade:
_vm->_gfx->palFade((PalEntry *)event->data, event->param, event->param2, event->param3, event->param4, event_pc);
break;
#endif
default:
break;
}
@ -338,6 +342,7 @@ int Events::handleOneShot(Event *event) {
if (event->param == kEvPSetPalette) {
PalEntry *palPointer;
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
if (_vm->_spiritualBarometer > 255)
_vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff);
@ -347,6 +352,7 @@ int Events::handleOneShot(Event *event) {
_vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.green / 256,
_vm->_spiritualBarometer * _vm->_interface->_portraitBgColor.blue / 256);
}
#endif
_vm->_scene->getBGPal(palPointer);
_vm->_gfx->setPalette(palPointer);
@ -539,6 +545,7 @@ int Events::handleOneShot(Event *event) {
default:
break;
}
#ifdef ENABLE_IHNM
case kCutawayEvent:
switch (event->op) {
case kEventClear:
@ -550,6 +557,7 @@ int Events::handleOneShot(Event *event) {
default:
break;
}
#endif
case kActorEvent:
switch (event->op) {
case kEventMove:

View file

@ -681,6 +681,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) {
fontId = _vm->_font->valid(kBigFont) ? kBigFont : kMediumFont;
break;
}
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM && !(_vm->getFeatures() & GF_IHNM_DEMO)) {
switch (font) {
case (kKnownFontSmall):
@ -703,6 +704,7 @@ Font::FontId Font::knownFont2FontIdx(KnownFont font) {
fontId = kMediumFont; // unchecked
break;
}
#endif
}
return fontId;
}

View file

@ -398,6 +398,8 @@ void Gfx::blackToPal(PalEntry *srcPal, double percent) {
_system->setPalette(_currentPal, 0, PAL_ENTRIES);
}
#ifdef ENABLE_IHNM
// Used in IHNM only
void Gfx::palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 numColors, double percent) {
int i;
@ -464,6 +466,8 @@ void Gfx::palFade(PalEntry *srcPal, int16 from, int16 to, int16 start, int16 num
_system->setPalette(_currentPal, 0, PAL_ENTRIES);
}
#endif
void Gfx::showCursor(bool state) {
// Don't show the mouse cursor in the non-interactive part of the IHNM demo
if (_vm->_scene->isNonInteractiveIHNMDemoPart())

View file

@ -180,6 +180,7 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
_optionPanel.sprites.spriteCount = 0;
}
#ifdef ENABLE_IHNM
// Quit panel
if (_vm->getGameId() == GID_IHNM) {
_quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
@ -212,6 +213,7 @@ Interface::Interface(SagaEngine *vm) : _vm(vm) {
&_loadPanel.imageLength, &_loadPanel.imageWidth, &_loadPanel.imageHeight);
free(resource);
}
#endif
// Main panel sprites
_vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites);
@ -703,6 +705,7 @@ bool Interface::processAscii(Common::KeyState keystate) {
}
break;
case kPanelPlacard:
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
// Any keypress here returns the user back to the game
if (!(_vm->getFeatures() & GF_IHNM_DEMO)) {
@ -713,6 +716,7 @@ bool Interface::processAscii(Common::KeyState keystate) {
_vm->_script->wakeUpThreads(kWaitTypeDelay);
}
}
#endif
break;
}
return false;
@ -1055,9 +1059,11 @@ void Interface::setQuit(PanelButton *panelButton) {
setMode(kPanelOption);
break;
case kTextQuit:
#ifdef ENABLE_IHNM
if (_vm->getFeatures() & GF_IHNM_DEMO)
_vm->_scene->creditsScene(); // display sales info for IHNM demo
else
#endif
_vm->quitGame();
break;
}
@ -1822,6 +1828,7 @@ void Interface::update(const Point& mousePoint, int updateFlag) {
break;
case kPanelPlacard:
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
// Any mouse click here returns the user back to the game
if (updateFlag & UPDATE_MOUSECLICK) {
@ -1834,6 +1841,7 @@ void Interface::update(const Point& mousePoint, int updateFlag) {
}
}
}
#endif
break;
case kPanelNull:

View file

@ -23,6 +23,8 @@
*
*/
#ifdef ENABLE_SAGA2
// "Faery Tale Adventure II: Halls of the Dead" Intro sequence scene procedures
#include "saga/saga.h"
@ -209,3 +211,5 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) {
}
} // End of namespace Saga
#endif

View file

@ -23,6 +23,8 @@
*
*/
#ifdef ENABLE_IHNM
// "I Have No Mouth" Intro sequence scene procedures
#include "saga/saga.h"
@ -290,3 +292,5 @@ bool Scene::playLoopingTitle(int title, int seconds) {
}
} // End of namespace Saga
#endif

View file

@ -14,9 +14,7 @@ MODULE_OBJS := \
image.o \
input.o \
interface.o \
introproc_ihnm.o \
introproc_ite.o \
introproc_fta2.o \
isomap.o \
itedata.o \
music.o \
@ -25,8 +23,6 @@ MODULE_OBJS := \
puzzle.o \
render.o \
resource.o \
resource_hrs.o \
resource_res.o \
resource_rsc.o \
saga.o \
saveload.o \
@ -38,6 +34,19 @@ MODULE_OBJS := \
sprite.o \
sthread.o
ifdef ENABLE_IHNM
MODULE_OBJS += \
introproc_ihnm.o \
resource_res.o \
sfuncs_ihnm.o
endif
ifdef ENABLE_SAGA2
MODULE_OBJS += \
introproc_fta2.o \
resource_hrs.o
endif
# This module can be built as a plugin
ifeq ($(ENABLE_SAGA), DYNAMIC_PLUGIN)
PLUGIN := 1

View file

@ -183,6 +183,7 @@ private:
}
};
#ifdef ENABLE_IHNM
// IHNM
class Resource_RES : public Resource {
public:
@ -197,7 +198,9 @@ private:
}
MetaResource _metaResource;
};
#endif
#ifdef ENABLE_SAGA2
// DINO, FTA2
class Resource_HRS : public Resource {
public:
@ -215,6 +218,7 @@ private:
}
bool loadResContext_v2(ResourceContext *context, uint32 contextSize);
};
#endif
} // End of namespace Saga

View file

@ -23,6 +23,8 @@
*
*/
#ifdef ENABLE_SAGA2
// HRS Resource file management module (SAGA 2, used in DINO and FTA2)
#include "saga/saga.h"
@ -102,3 +104,5 @@ bool Resource_HRS::loadResContext_v2(ResourceContext *context, uint32 contextSiz
}
} // End of namespace Saga
#endif

View file

@ -39,6 +39,8 @@
namespace Saga {
#ifdef ENABLE_IHNM
static int metaResourceTable[] = { 0, 326, 517, 677, 805, 968, 1165, 0, 1271 };
static int metaResourceTableDemo[] = { 0, 0, 0, 0, 0, 0, 0, 285, 0 };
@ -213,5 +215,6 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
_vm->_spiritualBarometer = 0;
_vm->_scene->setChapterNumber(chapter);
}
#endif
} // End of namespace Saga

View file

@ -167,13 +167,17 @@ Common::Error SagaEngine::init() {
case GID_ITE:
_resource = new Resource_RSC(this);
break;
#ifdef ENABLE_IHNM
case GID_IHNM:
_resource = new Resource_RES(this);
break;
#endif
#ifdef ENABLE_SAGA2
case GID_DINO:
case GID_FTA2:
_resource = new Resource_HRS(this);
break;
#endif
}
// Detect game and open resource files
@ -513,6 +517,7 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
default:
error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor);
}
#ifdef ENABLE_IHNM
} else if (getGameId() == GID_IHNM) {
// The default colors in the Spanish version of IHNM are shifted by one
// Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
@ -544,6 +549,7 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
default:
error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor);
}
#endif
}
return colorId;
}

View file

@ -199,6 +199,7 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
// Surrounding scene
out->writeSint32LE(_scene->getOutsetSceneNumber());
#ifdef ENABLE_IHNM
if (getGameId() == GID_IHNM) {
out->writeSint32LE(_scene->currentChapterNumber());
// Protagonist
@ -206,15 +207,17 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
out->writeSint32LE(_scene->getCurrentMusicTrack());
out->writeSint32LE(_scene->getCurrentMusicRepeat());
}
#endif
// Inset scene
out->writeSint32LE(_scene->currentSceneNumber());
#ifdef ENABLE_IHNM
if (getGameId() == GID_IHNM) {
out->writeUint32LE(_globalFlags);
for (int i = 0; i < ARRAYSIZE(_ethicsPoints); i++)
out->writeSint16LE(_ethicsPoints[i]);
}
#endif
_interface->saveState(out);
@ -288,6 +291,7 @@ void SagaEngine::load(const char *fileName) {
// Surrounding scene
sceneNumber = in->readSint32LE();
#ifdef ENABLE_IHNM
if (getGameId() == GID_IHNM) {
int currentChapter = _scene->currentChapterNumber();
_scene->setChapterNumber(in->readSint32LE());
@ -305,15 +309,18 @@ void SagaEngine::load(const char *fileName) {
_music->play(3, MUSIC_LOOP);
}
}
#endif
// Inset scene
insetSceneNumber = in->readSint32LE();
#ifdef ENABLE_IHNM
if (getGameId() == GID_IHNM) {
_globalFlags = in->readUint32LE();
for (int i = 0; i < ARRAYSIZE(_ethicsPoints); i++)
_ethicsPoints[i] = in->readSint16LE();
}
#endif
_interface->loadState(in);
@ -334,6 +341,7 @@ void SagaEngine::load(const char *fileName) {
if (getGameId() == GID_ITE)
_isoMap->setMapPosition(mapx, mapy);
#ifdef ENABLE_IHNM
// Protagonist swapping
if (getGameId() == GID_IHNM) {
if (_scene->currentProtag() != 0 && _scene->currentChapterNumber() != 6) {
@ -355,6 +363,7 @@ void SagaEngine::load(const char *fileName) {
_scene->setProtag(actor1->_id);
}
}
#endif
_scene->clearSceneQueue();
_scene->changeScene(sceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade);

View file

@ -82,6 +82,7 @@ SAGA_UNKNOWN,
SAGA_PALETTE
};
#ifdef ENABLE_IHNM
static SAGAResourceTypes IHNMSceneResourceTypes[28] = {
SAGA_ACTOR,
SAGA_UNKNOWN,
@ -112,6 +113,7 @@ SAGA_UNKNOWN,
SAGA_FACES,
SAGA_PALETTE
};
#endif
const char *SAGAResourceTypesString[] = {
"SAGA_UNKNOWN",
@ -238,12 +240,14 @@ Scene::~Scene() {
}
void Scene::getResourceTypes(SAGAResourceTypes *&types, int &typesCount) {
if (_vm->getGameId() == GID_IHNM) {
typesCount = ARRAYSIZE(IHNMSceneResourceTypes);
types = IHNMSceneResourceTypes;
} else {
if (_vm->getGameId() == GID_ITE) {
typesCount = ARRAYSIZE(ITESceneResourceTypes);
types = ITESceneResourceTypes;
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM) {
typesCount = ARRAYSIZE(IHNMSceneResourceTypes);
types = IHNMSceneResourceTypes;
#endif
}
}
@ -286,15 +290,19 @@ void Scene::startScene() {
case GID_ITE:
ITEStartProc();
break;
#ifdef ENABLE_IHNM
case GID_IHNM:
IHNMStartProc();
break;
#endif
#ifdef ENABLE_SAGA2
case GID_DINO:
// TODO
break;
case GID_FTA2:
FTA2StartProc();
break;
#endif
default:
error("Scene::start(): Error: Can't start game... gametype not supported");
break;
@ -314,6 +322,8 @@ void Scene::startScene() {
loadScene(sceneQueue);
}
#ifdef ENABLE_IHNM
void Scene::creditsScene() {
// End the last game ending scene
_vm->_scene->endScene();
@ -339,6 +349,8 @@ void Scene::creditsScene() {
return;
}
#endif
void Scene::nextScene() {
SceneQueueList::iterator queueIterator;
LoadSceneParams *sceneQueue;
@ -619,6 +631,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
_chapterPointsChanged = false;
#ifdef ENABLE_IHNM
if ((_vm->getGameId() == GID_IHNM) && (loadSceneParams->chapter != NO_CHAPTER_CHANGE)) {
if (loadSceneParams->loadFlag != kLoadBySceneNumber) {
error("loadScene wrong usage");
@ -657,6 +670,7 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
return;
}
}
#endif
if (_sceneLoaded) {
error("Scene::loadScene(): Error, a scene is already loaded");
@ -664,11 +678,13 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) {
_loadDescription = true;
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
if (loadSceneParams->loadFlag == kLoadBySceneNumber) // When will we get rid of it?
if (loadSceneParams->sceneDescriptor <= 0)
loadSceneParams->sceneDescriptor = _vm->_resource->getMetaResource()->sceneIndex;
}
#endif
switch (loadSceneParams->loadFlag) {
case kLoadByResourceId:
@ -1365,6 +1381,7 @@ void Scene::clearPlacard() {
event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
// set mode to main
event.type = kEvTImmediate;
@ -1375,6 +1392,7 @@ void Scene::clearPlacard() {
event.duration = 0;
q_event = _vm->_events->chain(q_event, &event);
}
#endif
// Display scene background, but stay with black palette
event.type = kEvTImmediate;

View file

@ -163,7 +163,19 @@ Script::Script(SagaEngine *vm) : _vm(vm) {
free(stringsPointer);
setupScriptOpcodeList();
setupScriptFuncList();
// Setup script functions
switch (_vm->getGameId()) {
case GID_ITE:
setupITEScriptFuncList();
break;
#ifdef ENABLE_IHNM
case GID_IHNM:
setupIHNMScriptFuncList();
break;
#endif
// TODO: FTA2 and DINO
}
}
// Shut down script module gracefully; free all allocated module resources
@ -566,12 +578,18 @@ void Script::opCcall(SCRIPTOP_PARAMS) {
if (stopParsing)
return;
if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
scriptFunction == &Saga::Script::sfVsetTrack) {
if (scriptFunction == &Saga::Script::sfScriptGotoScene) {
stopParsing = true; // cause abortAllThreads called and _this_ thread destroyed
return;
}
#ifdef ENABLE_IHNM
if (scriptFunction == &Saga::Script::sfVsetTrack) {
stopParsing = true;
return; // cause abortAllThreads called and _this_ thread destroyed
}
#endif
thread->_stackTopIndex = checkStackTopIndex;
thread->push(thread->_returnValue); // return value
@ -607,12 +625,18 @@ void Script::opCcallV(SCRIPTOP_PARAMS) {
if (stopParsing)
return;
if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
scriptFunction == &Saga::Script::sfVsetTrack) {
if (scriptFunction == &Saga::Script::sfScriptGotoScene) {
stopParsing = true;
return; // cause abortAllThreads called and _this_ thread destroyed
}
#ifdef ENABLE_IHNM
if (scriptFunction == &Saga::Script::sfVsetTrack) {
stopParsing = true;
return; // cause abortAllThreads called and _this_ thread destroyed
}
#endif
thread->_stackTopIndex = checkStackTopIndex;
if (thread->_flags & kTFlagAsleep)
@ -1556,6 +1580,7 @@ void Script::playfieldClick(const Point& mousePoint, bool leftButton) {
}
}
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
if ((_pendingVerb == getVerbType(kVerbWalkTo)) ||
@ -1607,6 +1632,7 @@ void Script::playfieldClick(const Point& mousePoint, bool leftButton) {
}
}
}
#endif
}

View file

@ -275,6 +275,7 @@ typedef SortedList<ScriptThread> ScriptThreadList;
#define SCRIPTOP_PARAMS ScriptThread *thread, MemoryReadStream *scriptS, bool &stopParsing, bool &breakOut
#define SCRIPTFUNC_PARAMS ScriptThread *thread, int nArgs, bool &disContinue
#define OPCODE(x) {&Script::x, #x}
class Script {
public:
@ -498,7 +499,8 @@ private:
};
const ScriptFunctionDescription *_scriptFunctionsList;
void setupScriptFuncList();
void setupITEScriptFuncList();
void setupIHNMScriptFuncList();
void sfPutString(SCRIPTFUNC_PARAMS);
void sfWait(SCRIPTFUNC_PARAMS);
@ -613,7 +615,7 @@ private:
void sfQueueMusic(SCRIPTFUNC_PARAMS);
void sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS);
void SF_stub(const char *name, ScriptThread *thread, int nArgs);
void sfStub(const char *name, ScriptThread *thread, int nArgs);
};
} // End of namespace Saga

View file

@ -52,9 +52,7 @@
namespace Saga {
#define OPCODE(x) {&Script::x, #x}
void Script::setupScriptFuncList() {
void Script::setupITEScriptFuncList() {
static const ScriptFunctionDescription ITEScriptFunctionsList[ITE_SCRIPT_FUNCTION_MAX] = {
OPCODE(sfPutString),
OPCODE(sfWait),
@ -136,116 +134,6 @@ void Script::setupScriptFuncList() {
OPCODE(sfPlayVoice)
};
static const ScriptFunctionDescription IHNMScriptFunctionsList[IHNM_SCRIPT_FUNCTION_MAX] = {
OPCODE(sfNull),
OPCODE(sfWait),
OPCODE(sfTakeObject),
OPCODE(sfIsCarried),
OPCODE(sfStatusBar),
OPCODE(sfMainMode),
OPCODE(sfScriptWalkTo),
OPCODE(sfScriptDoAction),
OPCODE(sfSetActorFacing),
OPCODE(sfStartBgdAnim),
OPCODE(sfStopBgdAnim),
OPCODE(sfLockUser),
OPCODE(sfPreDialog),
OPCODE(sfKillActorThreads),
OPCODE(sfFaceTowards),
OPCODE(sfSetFollower),
OPCODE(sfScriptGotoScene),
OPCODE(sfSetObjImage),
OPCODE(sfSetObjName),
OPCODE(sfGetObjImage),
OPCODE(sfGetNumber),
OPCODE(sfScriptOpenDoor),
OPCODE(sfScriptCloseDoor),
OPCODE(sfSetBgdAnimSpeed),
OPCODE(sfCycleColors),
OPCODE(sfDoCenterActor),
OPCODE(sfStartBgdAnimSpeed),
OPCODE(sfScriptWalkToAsync),
OPCODE(sfEnableZone),
OPCODE(sfSetActorState),
OPCODE(sfScriptMoveTo),
OPCODE(sfSceneEq),
OPCODE(sfDropObject),
OPCODE(sfFinishBgdAnim),
OPCODE(sfSwapActors),
OPCODE(sfSimulSpeech),
OPCODE(sfScriptWalk),
OPCODE(sfCycleFrames),
OPCODE(sfSetFrame),
OPCODE(sfSetPortrait),
OPCODE(sfSetProtagPortrait),
OPCODE(sfChainBgdAnim),
OPCODE(sfScriptSpecialWalk),
OPCODE(sfPlaceActor),
OPCODE(sfCheckUserInterrupt),
OPCODE(sfScriptWalkRelative),
OPCODE(sfScriptMoveRelative),
OPCODE(sfSimulSpeech2),
OPCODE(sfPsychicProfile),
OPCODE(sfPsychicProfileOff),
OPCODE(sfSetProtagState),
OPCODE(sfResumeBgdAnim),
OPCODE(sfThrowActor),
OPCODE(sfWaitWalk),
OPCODE(sfScriptSceneID),
OPCODE(sfChangeActorScene),
OPCODE(sfScriptClimb),
OPCODE(sfSetDoorState),
OPCODE(sfSetActorZ),
OPCODE(sfScriptText),
OPCODE(sfGetActorX),
OPCODE(sfGetActorY),
OPCODE(sfEraseDelta),
OPCODE(sfPlayMusic),
OPCODE(sfNull),
OPCODE(sfEnableEscape),
OPCODE(sfPlaySound),
OPCODE(sfPlayLoopedSound),
OPCODE(sfGetDeltaFrame),
OPCODE(sfNull),
OPCODE(sfNull),
OPCODE(sfRand),
OPCODE(sfFadeMusic),
OPCODE(sfNull),
OPCODE(sfSetChapterPoints),
OPCODE(sfSetPortraitBgColor),
OPCODE(sfScriptStartCutAway),
OPCODE(sfReturnFromCutAway),
OPCODE(sfEndCutAway),
OPCODE(sfGetMouseClicks),
OPCODE(sfResetMouseClicks),
OPCODE(sfWaitFrames),
OPCODE(sfScriptFade),
OPCODE(sfScriptStartVideo),
OPCODE(sfScriptReturnFromVideo),
OPCODE(sfScriptEndVideo),
OPCODE(sfSetActorZ),
OPCODE(sfShowIHNMDemoHelpBg),
OPCODE(sfAddIHNMDemoHelpTextLine),
OPCODE(sfShowIHNMDemoHelpPage),
OPCODE(sfVstopFX),
OPCODE(sfVstopLoopedFX),
OPCODE(sfDemoSetInteractive), // only used in the demo version of IHNM
OPCODE(sfDemoIsInteractive),
OPCODE(sfVsetTrack),
OPCODE(sfGetPoints),
OPCODE(sfSetGlobalFlag),
OPCODE(sfClearGlobalFlag),
OPCODE(sfTestGlobalFlag),
OPCODE(sfSetPoints),
OPCODE(sfSetSpeechBox),
OPCODE(sfDebugShowData),
OPCODE(sfWaitFramesEsc),
OPCODE(sfQueueMusic),
OPCODE(sfDisableAbortSpeeches)
};
if (_vm->getGameId() == GID_IHNM)
_scriptFunctionsList = IHNMScriptFunctionsList;
else
_scriptFunctionsList = ITEScriptFunctionsList;
}
@ -550,19 +438,23 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
int16 sceneNumber = thread->pop();
int16 entrance = thread->pop();
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
_vm->_gfx->setCursor(kCursorBusy);
}
#endif
if (_vm->getGameId() == GID_ITE && sceneNumber < 0) {
_vm->quitGame();
return;
}
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM && sceneNumber == 0) {
_vm->_scene->creditsScene();
return;
}
#endif
// It is possible to leave scene when converse panel is on,
// particulalrly it may happen at Moneychanger tent. This
@ -590,6 +482,7 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
_currentObject[0] = _currentObject[1] = ID_NOTHING;
showVerb(); // calls setStatusText("")
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_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.
@ -597,6 +490,8 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) {
_vm->_anim->clearCutaway();
_vm->_gfx->setCursor(kCursorNormal);
}
#endif
}
// Script function #17 (0x11)
@ -689,7 +584,7 @@ void Script::sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS) {
// Script function #24 (0x18)
void Script::sfCycleColors(SCRIPTFUNC_PARAMS) {
SF_stub("sfCycleColors", thread, nArgs);
sfStub("sfCycleColors", thread, nArgs);
error("Please, report this to sev");
}
@ -1640,13 +1535,13 @@ void Script::sfPlayVoice(SCRIPTFUNC_PARAMS) {
void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) {
byte *addr;
const char *str;
if (_conversingThread) {
_vm->_interface->setMode(kPanelNull);
#ifdef ENABLE_IHNM
if (_vm->getGameId() == GID_IHNM) {
str = _conversingThread->_strings->getString(strID);
const char *str = _conversingThread->_strings->getString(strID);
if (*str != '[') {
int sampleResourceId = -1;
sampleResourceId = _conversingThread->_voiceLUT->voices[strID];
@ -1656,6 +1551,7 @@ void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) {
_vm->_actor->actorSpeech(_vm->_actor->_protagonist->_id, &str, 1, sampleResourceId, 0);
}
}
#endif
_conversingThread->_flags &= ~kTFlagWaiting;
@ -1671,291 +1567,12 @@ void Script::finishDialog(int strID, int replyID, int flags, int bitOffset) {
wakeUpThreads(kWaitTypeDialogBegin);
}
void Script::sfSetChapterPoints(SCRIPTFUNC_PARAMS) {
int chapter = _vm->_scene->currentChapterNumber();
_vm->_ethicsPoints[chapter] = thread->pop();
int16 barometer = thread->pop();
static PalEntry cur_pal[PAL_ENTRIES];
_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) {
int16 red = thread->pop();
int16 green = thread->pop();
int16 blue = thread->pop();
_vm->_interface->setPortraitBgColor(red, green, blue);
}
void Script::sfScriptStartCutAway(SCRIPTFUNC_PARAMS) {
int16 cut = thread->pop();
thread->pop(); // Not used
int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelCutaway);
_vm->_anim->playCutaway(cut, fade != 0);
}
void Script::sfReturnFromCutAway(SCRIPTFUNC_PARAMS) {
_vm->_anim->returnFromCutaway();
thread->wait(kWaitTypeWakeUp);
}
void Script::sfEndCutAway(SCRIPTFUNC_PARAMS) {
_vm->_anim->endCutaway();
}
void Script::sfGetMouseClicks(SCRIPTFUNC_PARAMS) {
thread->_returnValue = _vm->getMouseClickCount();
}
void Script::sfResetMouseClicks(SCRIPTFUNC_PARAMS) {
_vm->resetMouseClickCount();
}
// Used in IHNM only
// Param1: frames
void Script::sfWaitFrames(SCRIPTFUNC_PARAMS) {
int16 frames = thread->pop();
if (!_skipSpeeches)
thread->waitFrames(_vm->_frameCount + frames);
}
void Script::sfScriptFade(SCRIPTFUNC_PARAMS) {
int16 firstPalEntry = thread->pop();
int16 lastPalEntry = thread->pop();
int16 startingBrightness = thread->pop();
int16 endingBrightness = thread->pop();
Event event;
static PalEntry cur_pal[PAL_ENTRIES];
_vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalFade;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
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 = thread->pop();
int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelVideo);
_vm->_anim->startVideo(vid, fade != 0);
}
void Script::sfScriptReturnFromVideo(SCRIPTFUNC_PARAMS) {
_vm->_anim->returnFromVideo();
}
void Script::sfScriptEndVideo(SCRIPTFUNC_PARAMS) {
_vm->_anim->endVideo();
}
void Script::sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS) {
_ihnmDemoCurrentY = 0;
_vm->_scene->_textList.clear();
_vm->_interface->setMode(kPanelConverse);
_vm->_scene->showPsychicProfile(NULL);
}
void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) {
int stringId = thread->pop();
TextListEntry textEntry;
Event event;
textEntry.knownColor = kKnownColorBlack;
textEntry.useRect = true;
textEntry.rect.left = 245;
textEntry.rect.setHeight(210 + 76);
textEntry.rect.setWidth(226);
textEntry.rect.top = 76 + _ihnmDemoCurrentY;
textEntry.font = kKnownFontVerb;
textEntry.flags = (FontEffectFlags)(kFontCentered);
textEntry.text = thread->_strings->getString(stringId);
TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry);
event.type = kEvTOneshot;
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
_vm->_events->queue(&event);
_ihnmDemoCurrentY += _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered);
}
void Script::sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS) {
// Note: The IHNM demo changes panel mode to 8 (kPanelProtect in ITE)
// when changing pages
_vm->_interface->setMode(kPanelPlacard);
_ihnmDemoCurrentY = 0;
}
void Script::sfVstopFX(SCRIPTFUNC_PARAMS) {
_vm->_sound->stopSound();
}
void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) {
_vm->_sound->stopSound();
}
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) {
thread->_returnValue = 0;
}
void Script::sfVsetTrack(SCRIPTFUNC_PARAMS) {
int16 chapter = thread->pop();
int16 sceneNumber = thread->pop();
int16 actorsEntrance = thread->pop();
debug(2, "sfVsetTrrack(%d, %d, %d)", chapter, sceneNumber, actorsEntrance);
_vm->_scene->changeScene(sceneNumber, actorsEntrance, kTransitionFade, chapter);
}
void Script::sfGetPoints(SCRIPTFUNC_PARAMS) {
int16 index = thread->pop();
if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
thread->_returnValue = _vm->_ethicsPoints[index];
else
thread->_returnValue = 0;
}
void Script::sfSetGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32)
_vm->_globalFlags |= (1 << flag);
}
void Script::sfClearGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32)
_vm->_globalFlags &= ~(1 << flag);
}
void Script::sfTestGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32 && _vm->_globalFlags & (1 << flag))
thread->_returnValue = 1;
else
thread->_returnValue = 0;
}
void Script::sfSetPoints(SCRIPTFUNC_PARAMS) {
int16 index = thread->pop();
int16 points = thread->pop();
if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
_vm->_ethicsPoints[index] = points;
}
void Script::sfSetSpeechBox(SCRIPTFUNC_PARAMS) {
int16 param1 = thread->pop();
int16 param2 = thread->pop();
int16 param3 = thread->pop();
int16 param4 = thread->pop();
_vm->_actor->_speechBoxScript.left = param1;
_vm->_actor->_speechBoxScript.top = param2;
_vm->_actor->_speechBoxScript.setWidth(param3 - param1);
_vm->_actor->_speechBoxScript.setHeight(param4 - param2);
}
void Script::sfDebugShowData(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop();
char buf[50];
snprintf(buf, 50, "Reached breakpoint %d", param);
_vm->_interface->setStatusText(buf);
}
void Script::sfWaitFramesEsc(SCRIPTFUNC_PARAMS) {
thread->_returnValue = _vm->_framesEsc;
}
void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
int16 param1 = thread->pop();
int16 param2 = thread->pop();
Event event;
if (param1 < 0) {
_vm->_music->stop();
return;
}
if (param1 >= _vm->_music->_songTableLen) {
warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
} else {
_vm->_music->setVolume(_vm->_musicVolume, 1);
event.type = kEvTOneshot;
event.code = kMusicEvent;
event.param = _vm->_music->_songTable[param1];
event.param2 = param2 ? MUSIC_LOOP : MUSIC_NORMAL;
event.op = kEventPlay;
event.time = _vm->ticksToMSec(500); // I find the delay in the original to be too long, so I've set it to
// wait for half the time, which sounds better when chapter points
// 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()) {
_vm->_scene->setCurrentMusicTrack(param1);
_vm->_scene->setCurrentMusicRepeat(param2);
} else {
// Don't save this music track when saving in IHNM
_vm->_scene->setChapterPointsChanged(false);
}
}
}
void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) {
_vm->_interface->disableAbortSpeeches(thread->pop() != 0);
}
void Script::sfNull(SCRIPTFUNC_PARAMS) {
for (int i = 0; i < nArgs; i++)
thread->pop();
}
void Script::SF_stub(const char *name, ScriptThread *thread, int nArgs) {
void Script::sfStub(const char *name, ScriptThread *thread, int nArgs) {
char buf[256], buf1[100];
snprintf(buf, 256, "STUB: %s(", name);

View file

@ -0,0 +1,448 @@
/* 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$
*
*/
#ifdef ENABLE_IHNM
// Scripting module script function component
#include "saga/saga.h"
#include "saga/gfx.h"
#include "saga/actor.h"
#include "saga/animation.h"
#include "saga/console.h"
#include "saga/events.h"
#include "saga/font.h"
#include "saga/interface.h"
#include "saga/music.h"
#include "saga/itedata.h"
#include "saga/puzzle.h"
#include "saga/render.h"
#include "saga/sound.h"
#include "saga/sndres.h"
#include "saga/resource.h"
#include "saga/script.h"
#include "saga/objectmap.h"
#include "saga/scene.h"
#include "saga/isomap.h"
#include "common/config-manager.h"
namespace Saga {
void Script::setupIHNMScriptFuncList() {
static const ScriptFunctionDescription IHNMScriptFunctionsList[IHNM_SCRIPT_FUNCTION_MAX] = {
OPCODE(sfNull),
OPCODE(sfWait),
OPCODE(sfTakeObject),
OPCODE(sfIsCarried),
OPCODE(sfStatusBar),
OPCODE(sfMainMode),
OPCODE(sfScriptWalkTo),
OPCODE(sfScriptDoAction),
OPCODE(sfSetActorFacing),
OPCODE(sfStartBgdAnim),
OPCODE(sfStopBgdAnim),
OPCODE(sfLockUser),
OPCODE(sfPreDialog),
OPCODE(sfKillActorThreads),
OPCODE(sfFaceTowards),
OPCODE(sfSetFollower),
OPCODE(sfScriptGotoScene),
OPCODE(sfSetObjImage),
OPCODE(sfSetObjName),
OPCODE(sfGetObjImage),
OPCODE(sfGetNumber),
OPCODE(sfScriptOpenDoor),
OPCODE(sfScriptCloseDoor),
OPCODE(sfSetBgdAnimSpeed),
OPCODE(sfCycleColors),
OPCODE(sfDoCenterActor),
OPCODE(sfStartBgdAnimSpeed),
OPCODE(sfScriptWalkToAsync),
OPCODE(sfEnableZone),
OPCODE(sfSetActorState),
OPCODE(sfScriptMoveTo),
OPCODE(sfSceneEq),
OPCODE(sfDropObject),
OPCODE(sfFinishBgdAnim),
OPCODE(sfSwapActors),
OPCODE(sfSimulSpeech),
OPCODE(sfScriptWalk),
OPCODE(sfCycleFrames),
OPCODE(sfSetFrame),
OPCODE(sfSetPortrait),
OPCODE(sfSetProtagPortrait),
OPCODE(sfChainBgdAnim),
OPCODE(sfScriptSpecialWalk),
OPCODE(sfPlaceActor),
OPCODE(sfCheckUserInterrupt),
OPCODE(sfScriptWalkRelative),
OPCODE(sfScriptMoveRelative),
OPCODE(sfSimulSpeech2),
OPCODE(sfPsychicProfile),
OPCODE(sfPsychicProfileOff),
OPCODE(sfSetProtagState),
OPCODE(sfResumeBgdAnim),
OPCODE(sfThrowActor),
OPCODE(sfWaitWalk),
OPCODE(sfScriptSceneID),
OPCODE(sfChangeActorScene),
OPCODE(sfScriptClimb),
OPCODE(sfSetDoorState),
OPCODE(sfSetActorZ),
OPCODE(sfScriptText),
OPCODE(sfGetActorX),
OPCODE(sfGetActorY),
OPCODE(sfEraseDelta),
OPCODE(sfPlayMusic),
OPCODE(sfNull),
OPCODE(sfEnableEscape),
OPCODE(sfPlaySound),
OPCODE(sfPlayLoopedSound),
OPCODE(sfGetDeltaFrame),
OPCODE(sfNull),
OPCODE(sfNull),
OPCODE(sfRand),
OPCODE(sfFadeMusic),
OPCODE(sfNull),
OPCODE(sfSetChapterPoints),
OPCODE(sfSetPortraitBgColor),
OPCODE(sfScriptStartCutAway),
OPCODE(sfReturnFromCutAway),
OPCODE(sfEndCutAway),
OPCODE(sfGetMouseClicks),
OPCODE(sfResetMouseClicks),
OPCODE(sfWaitFrames),
OPCODE(sfScriptFade),
OPCODE(sfScriptStartVideo),
OPCODE(sfScriptReturnFromVideo),
OPCODE(sfScriptEndVideo),
OPCODE(sfSetActorZ),
OPCODE(sfShowIHNMDemoHelpBg),
OPCODE(sfAddIHNMDemoHelpTextLine),
OPCODE(sfShowIHNMDemoHelpPage),
OPCODE(sfVstopFX),
OPCODE(sfVstopLoopedFX),
OPCODE(sfDemoSetInteractive), // only used in the demo version of IHNM
OPCODE(sfDemoIsInteractive),
OPCODE(sfVsetTrack),
OPCODE(sfGetPoints),
OPCODE(sfSetGlobalFlag),
OPCODE(sfClearGlobalFlag),
OPCODE(sfTestGlobalFlag),
OPCODE(sfSetPoints),
OPCODE(sfSetSpeechBox),
OPCODE(sfDebugShowData),
OPCODE(sfWaitFramesEsc),
OPCODE(sfQueueMusic),
OPCODE(sfDisableAbortSpeeches)
};
_scriptFunctionsList = IHNMScriptFunctionsList;
}
void Script::sfSetChapterPoints(SCRIPTFUNC_PARAMS) {
int chapter = _vm->_scene->currentChapterNumber();
_vm->_ethicsPoints[chapter] = thread->pop();
int16 barometer = thread->pop();
static PalEntry cur_pal[PAL_ENTRIES];
_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) {
int16 red = thread->pop();
int16 green = thread->pop();
int16 blue = thread->pop();
_vm->_interface->setPortraitBgColor(red, green, blue);
}
void Script::sfScriptStartCutAway(SCRIPTFUNC_PARAMS) {
int16 cut = thread->pop();
thread->pop(); // Not used
int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelCutaway);
_vm->_anim->playCutaway(cut, fade != 0);
}
void Script::sfReturnFromCutAway(SCRIPTFUNC_PARAMS) {
_vm->_anim->returnFromCutaway();
thread->wait(kWaitTypeWakeUp);
}
void Script::sfEndCutAway(SCRIPTFUNC_PARAMS) {
_vm->_anim->endCutaway();
}
void Script::sfGetMouseClicks(SCRIPTFUNC_PARAMS) {
thread->_returnValue = _vm->getMouseClickCount();
}
void Script::sfResetMouseClicks(SCRIPTFUNC_PARAMS) {
_vm->resetMouseClickCount();
}
void Script::sfWaitFrames(SCRIPTFUNC_PARAMS) {
int16 frames = thread->pop();
if (!_skipSpeeches)
thread->waitFrames(_vm->_frameCount + frames);
}
void Script::sfScriptFade(SCRIPTFUNC_PARAMS) {
int16 firstPalEntry = thread->pop();
int16 lastPalEntry = thread->pop();
int16 startingBrightness = thread->pop();
int16 endingBrightness = thread->pop();
Event event;
static PalEntry cur_pal[PAL_ENTRIES];
_vm->_gfx->getCurrentPal(cur_pal);
event.type = kEvTImmediate;
event.code = kPalEvent;
event.op = kEventPalFade;
event.time = 0;
event.duration = kNormalFadeDuration;
event.data = cur_pal;
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 = thread->pop();
int16 fade = thread->pop();
_vm->_anim->setCutAwayMode(kPanelVideo);
_vm->_anim->startVideo(vid, fade != 0);
}
void Script::sfScriptReturnFromVideo(SCRIPTFUNC_PARAMS) {
_vm->_anim->returnFromVideo();
}
void Script::sfScriptEndVideo(SCRIPTFUNC_PARAMS) {
_vm->_anim->endVideo();
}
void Script::sfShowIHNMDemoHelpBg(SCRIPTFUNC_PARAMS) {
_ihnmDemoCurrentY = 0;
_vm->_scene->_textList.clear();
_vm->_interface->setMode(kPanelConverse);
_vm->_scene->showPsychicProfile(NULL);
}
void Script::sfAddIHNMDemoHelpTextLine(SCRIPTFUNC_PARAMS) {
int stringId = thread->pop();
TextListEntry textEntry;
Event event;
textEntry.knownColor = kKnownColorBlack;
textEntry.useRect = true;
textEntry.rect.left = 245;
textEntry.rect.setHeight(210 + 76);
textEntry.rect.setWidth(226);
textEntry.rect.top = 76 + _ihnmDemoCurrentY;
textEntry.font = kKnownFontVerb;
textEntry.flags = (FontEffectFlags)(kFontCentered);
textEntry.text = thread->_strings->getString(stringId);
TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry);
event.type = kEvTOneshot;
event.code = kTextEvent;
event.op = kEventDisplay;
event.data = _psychicProfileTextEntry;
_vm->_events->queue(&event);
_ihnmDemoCurrentY += _vm->_font->getHeight(kKnownFontVerb, thread->_strings->getString(stringId), 226, kFontCentered);
}
void Script::sfShowIHNMDemoHelpPage(SCRIPTFUNC_PARAMS) {
// Note: The IHNM demo changes panel mode to 8 (kPanelProtect in ITE)
// when changing pages
_vm->_interface->setMode(kPanelPlacard);
_ihnmDemoCurrentY = 0;
}
void Script::sfVstopFX(SCRIPTFUNC_PARAMS) {
_vm->_sound->stopSound();
}
void Script::sfVstopLoopedFX(SCRIPTFUNC_PARAMS) {
_vm->_sound->stopSound();
}
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) {
thread->_returnValue = 0;
}
void Script::sfVsetTrack(SCRIPTFUNC_PARAMS) {
int16 chapter = thread->pop();
int16 sceneNumber = thread->pop();
int16 actorsEntrance = thread->pop();
debug(2, "sfVsetTrrack(%d, %d, %d)", chapter, sceneNumber, actorsEntrance);
_vm->_scene->changeScene(sceneNumber, actorsEntrance, kTransitionFade, chapter);
}
void Script::sfGetPoints(SCRIPTFUNC_PARAMS) {
int16 index = thread->pop();
if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
thread->_returnValue = _vm->_ethicsPoints[index];
else
thread->_returnValue = 0;
}
void Script::sfSetGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32)
_vm->_globalFlags |= (1 << flag);
}
void Script::sfClearGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32)
_vm->_globalFlags &= ~(1 << flag);
}
void Script::sfTestGlobalFlag(SCRIPTFUNC_PARAMS) {
int16 flag = thread->pop();
if (flag >= 0 && flag < 32 && _vm->_globalFlags & (1 << flag))
thread->_returnValue = 1;
else
thread->_returnValue = 0;
}
void Script::sfSetPoints(SCRIPTFUNC_PARAMS) {
int16 index = thread->pop();
int16 points = thread->pop();
if (index >= 0 && index < ARRAYSIZE(_vm->_ethicsPoints))
_vm->_ethicsPoints[index] = points;
}
void Script::sfSetSpeechBox(SCRIPTFUNC_PARAMS) {
int16 param1 = thread->pop();
int16 param2 = thread->pop();
int16 param3 = thread->pop();
int16 param4 = thread->pop();
_vm->_actor->_speechBoxScript.left = param1;
_vm->_actor->_speechBoxScript.top = param2;
_vm->_actor->_speechBoxScript.setWidth(param3 - param1);
_vm->_actor->_speechBoxScript.setHeight(param4 - param2);
}
void Script::sfDebugShowData(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop();
char buf[50];
snprintf(buf, 50, "Reached breakpoint %d", param);
_vm->_interface->setStatusText(buf);
}
void Script::sfWaitFramesEsc(SCRIPTFUNC_PARAMS) {
thread->_returnValue = _vm->_framesEsc;
}
void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
int16 param1 = thread->pop();
int16 param2 = thread->pop();
Event event;
if (param1 < 0) {
_vm->_music->stop();
return;
}
if (param1 >= _vm->_music->_songTableLen) {
warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1);
} else {
_vm->_music->setVolume(_vm->_musicVolume, 1);
event.type = kEvTOneshot;
event.code = kMusicEvent;
event.param = _vm->_music->_songTable[param1];
event.param2 = param2 ? MUSIC_LOOP : MUSIC_NORMAL;
event.op = kEventPlay;
event.time = _vm->ticksToMSec(500); // I find the delay in the original to be too long, so I've set it to
// wait for half the time, which sounds better when chapter points
// 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()) {
_vm->_scene->setCurrentMusicTrack(param1);
_vm->_scene->setCurrentMusicRepeat(param2);
} else {
// Don't save this music track when saving in IHNM
_vm->_scene->setChapterPointsChanged(false);
}
}
}
void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) {
_vm->_interface->disableAbortSpeeches(thread->pop() != 0);
}
} // End of namespace Saga
#endif

View file

@ -60,6 +60,7 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm) {
if (_vm->getGameId() == GID_ITE) {
_fxTable = ITE_SfxTable;
_fxTableLen = ITE_SFXCOUNT;
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM) {
ResourceContext *resourceContext;
@ -94,6 +95,7 @@ SndRes::SndRes(SagaEngine *vm) : _vm(vm) {
_fxTable = 0;
_fxTableLen = 0;
#endif
} else if (_vm->getGameId() == GID_DINO) {
// TODO
} else if (_vm->getGameId() == GID_FTA2) {

View file

@ -61,6 +61,7 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
if (_vm->getGameId() == GID_ITE) {
loadList(_vm->getResourceDescription()->mainSpritesResourceId, _mainSprites);
_arrowSprites = _saveReminderSprites = _inventorySprites = _mainSprites;
#ifdef ENABLE_IHNM
} else if (_vm->getGameId() == GID_IHNM) {
if (_vm->getFeatures() & GF_IHNM_DEMO) {
loadList(RID_IHNMDEMO_ARROW_SPRITES, _arrowSprites);
@ -69,6 +70,7 @@ Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
loadList(RID_IHNM_ARROW_SPRITES, _arrowSprites);
loadList(RID_IHNM_SAVEREMINDER_SPRITES, _saveReminderSprites);
}
#endif
} else {
error("Sprite: unknown game type");
}
@ -167,6 +169,7 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) {
memoryError("Sprite::loadList");
}
#ifdef ENABLE_IHNM
// IHNM sprites are upside-down, for reasons which i can only
// assume are perverse. To simplify things, flip them now. Not
// at drawing time.
@ -181,6 +184,7 @@ void Sprite::loadList(int resourceId, SpriteList &spriteList) {
dst += spriteInfo->width;
}
} else
#endif
memcpy(spriteInfo->decodedBuffer, _decodeBuf, outputLength);
}