scummvm/engines/m4/globals.cpp

541 lines
13 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$
*
*/
#include "m4/m4.h"
#include "m4/globals.h"
#include "m4/graphics.h"
#include "m4/gui.h"
#include "m4/viewmgr.h"
#include "m4/script.h"
#include "m4/m4_views.h"
#include "m4/compression.h"
namespace M4 {
Kernel::Kernel(MadsM4Engine *vm) : _vm(vm) {
daemonTriggerAvailable = true;
firstFadeColorIndex = 0;
paused = false;
betweenRooms = false;
currentSection = 0;
newSection = 0;
previousSection = 0;
currentRoom = 0;
newRoom = 0;
previousRoom = 0;
trigger = 0;
triggerMode = KT_DAEMON;
_globalDaemonFn = NULL;
_globalParserFn = NULL;
_sectionInitFn = NULL;
_sectionDaemonFn = NULL;
_sectionParserFn = NULL;
_roomInitFn = NULL;
_roomDaemonFn = NULL;
_roomPreParserFn = NULL;
_roomParserFn = NULL;
}
int32 Kernel::createTrigger(int32 triggerNum) {
if (triggerNum < 0)
return triggerNum;
else
return triggerNum | (currentRoom << 16) | (triggerMode << 28);
}
bool Kernel::sendTrigger(int32 triggerNum) {
return handleTrigger(createTrigger(triggerNum));
}
bool Kernel::handleTrigger(int32 triggerNum) {
printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum);
if (betweenRooms)
return true;
if (triggerNum < 0)
return false;
KernelTriggerType saveTriggerMode = triggerMode;
int32 saveTrigger = trigger;
bool result = false;
int room = (triggerNum >> 16) & 0xFFF;
printf("room = %d; currentRoom = %d\n", room, currentRoom); fflush(stdout);
if (room != currentRoom) {
printf("Kernel::handleTrigger() Trigger from another room\n");
return false;
}
trigger = triggerNum & 0xFFFF;
KernelTriggerType mode = (KernelTriggerType)(triggerNum >> 28);
switch (mode) {
case KT_PREPARSE:
if (trigger < 32000) {
triggerMode = KT_PREPARSE;
roomPreParser();
result = true;
}
break;
case KT_PARSE:
if (trigger < 32000) {
triggerMode = KT_PARSE;
// TODO player.commandReady = TRUE;
roomParser();
/* TODO
if (player.commandReady)
globalParser();
*/
result = true;
}
break;
case KT_DAEMON:
printf("KT_DAEMON\n");
fflush(stdout);
triggerMode = KT_DAEMON;
daemonTriggerAvailable = false;
roomDaemon();
if (daemonTriggerAvailable) {
daemonTriggerAvailable = false;
sectionDaemon();
}
if (daemonTriggerAvailable) {
daemonTriggerAvailable = false;
globalDaemon();
}
break;
default:
printf("Kernel::handleTrigger() Unknown trigger mode %d\n", mode);
}
triggerMode = saveTriggerMode;
trigger = saveTrigger;
return result;
}
void Kernel::loadGlobalScriptFunctions() {
_globalDaemonFn = _vm->_script->loadFunction("global_daemon");
_globalParserFn = _vm->_script->loadFunction("global_parser");
}
void Kernel::loadSectionScriptFunctions() {
char tempFnName[128];
snprintf(tempFnName, 128, "section_init_%d", currentSection);
_sectionInitFn = _vm->_script->loadFunction(tempFnName);
snprintf(tempFnName, 128, "section_daemon_%d", currentSection);
_sectionDaemonFn = _vm->_script->loadFunction(tempFnName);
snprintf(tempFnName, 128, "section_parser_%d", currentSection);
_sectionParserFn = _vm->_script->loadFunction(tempFnName);
}
void Kernel::loadRoomScriptFunctions() {
char tempFnName[128];
snprintf(tempFnName, 128, "room_init_%d", currentRoom);
_roomInitFn = _vm->_script->loadFunction(tempFnName);
snprintf(tempFnName, 128, "room_daemon_%d", currentRoom);
_roomDaemonFn = _vm->_script->loadFunction(tempFnName);
snprintf(tempFnName, 128, "room_pre_parser_%d", currentRoom);
_roomPreParserFn = _vm->_script->loadFunction(tempFnName);
snprintf(tempFnName, 128, "room_parser_%d", currentRoom);
_roomParserFn = _vm->_script->loadFunction(tempFnName);
}
void Kernel::globalDaemon() {
if (_globalDaemonFn)
_vm->_script->runFunction(_globalDaemonFn);
else {
printf("Kernel::globalDaemon() _globalDaemonFn is NULL\n");
}
}
void Kernel::globalParser() {
if (_globalParserFn)
_vm->_script->runFunction(_globalParserFn);
else {
printf("Kernel::globalParser() _globalParserFn is NULL\n");
}
}
void Kernel::sectionInit() {
if (_sectionInitFn)
_vm->_script->runFunction(_sectionInitFn);
else {
printf("Kernel::sectionInit() _sectionInitFn is NULL\n");
}
}
void Kernel::sectionDaemon() {
if (_sectionDaemonFn)
_vm->_script->runFunction(_sectionDaemonFn);
else {
printf("Kernel::sectionDaemon() _sectionDaemonFn is NULL\n");
}
}
void Kernel::sectionParser() {
if (_sectionParserFn)
_vm->_script->runFunction(_sectionParserFn);
else {
printf("Kernel::sectionParser() _sectionParserFn is NULL\n");
}
}
void Kernel::roomInit() {
if (_roomInitFn)
_vm->_script->runFunction(_roomInitFn);
else {
printf("Kernel::roomInit() _roomInitFn is NULL\n");
}
}
void Kernel::roomDaemon() {
if (_roomDaemonFn)
_vm->_script->runFunction(_roomDaemonFn);
else {
printf("Kernel::roomDaemon() _roomDaemonFn is NULL\n");
}
}
void Kernel::roomPreParser() {
if (_roomPreParserFn)
_vm->_script->runFunction(_roomPreParserFn);
else {
printf("Kernel::roomPreParser() _roomPreParserFn is NULL\n");
}
}
void Kernel::roomParser() {
if (_roomParserFn)
_vm->_script->runFunction(_roomParserFn);
else {
printf("Kernel::roomParser() _roomParserFn is NULL\n");
}
}
void Kernel::pauseGame(bool value) {
paused = value;
if (paused) pauseEngines();
else unpauseEngines();
}
void Kernel::pauseEngines() {
// TODO: A proper implementation of game pausing. At the moment I'm using a hard-coded
// check in events.cpp on Kernel::paused to prevent any events going to the scene
}
void Kernel::unpauseEngines() {
// TODO: A proper implementation of game unpausing
}
/*--------------------------------------------------------------------------*/
Globals::Globals(MadsM4Engine *vm): _vm(vm) {
}
bool Globals::isInterfaceVisible() {
return _m4Vm->scene()->getInterface()->isVisible();
}
/*--------------------------------------------------------------------------*/
MadsGlobals::MadsGlobals(MadsEngine *vm): Globals(vm) {
_vm = vm;
playerSpriteChanged = false;
dialogType = DIALOG_NONE;
sceneNumber = -1;
for (int i = 0; i < 3; ++i)
actionNouns[i] = 0;
}
MadsGlobals::~MadsGlobals() {
uint32 i;
for (i = 0; i < _madsVocab.size(); i++)
free(_madsVocab[i]);
_madsVocab.clear();
for (i = 0; i < _madsQuotes.size(); i++)
free(_madsQuotes[i]);
_madsQuotes.clear();
_madsMessages.clear();
}
void MadsGlobals::loadMadsVocab() {
Common::SeekableReadStream *vocabS = _vm->res()->get("vocab.dat");
int curPos = 0;
char buffer[30];
strcpy(buffer, "");
while (true) {
uint8 b = vocabS->readByte();
if (vocabS->eos()) break;
buffer[curPos++] = b;
if (buffer[curPos - 1] == '\0') {
// end of string, add it to the strings list
_madsVocab.push_back(strdup(buffer));
curPos = 0;
strcpy(buffer, "");
}
}
_vm->res()->toss("vocab.dat");
}
void MadsGlobals::loadQuotes() {
Common::SeekableReadStream *quoteS = _vm->res()->get("quotes.dat");
int curPos = 0;
char buffer[128];
strcpy(buffer, "");
while (true) {
uint8 b = quoteS->readByte();
if (quoteS->eos()) break;
buffer[curPos++] = b;
if (buffer[curPos - 1] == '\0') {
// end of string, add it to the strings list
_madsQuotes.push_back(strdup(buffer));
curPos = 0;
strcpy(buffer, "");
}
}
_vm->res()->toss("quotes.dat");
}
void MadsGlobals::loadMadsMessagesInfo() {
Common::SeekableReadStream *messageS = _vm->res()->get("messages.dat");
int16 count = messageS->readUint16LE();
//printf("%i messages\n", count);
for (int i = 0; i < count; i++) {
MessageItem curMessage;
curMessage.id = messageS->readUint32LE();
curMessage.offset = messageS->readUint32LE();
curMessage.uncompSize = messageS->readUint16LE();
if (i > 0)
_madsMessages[i - 1].compSize = curMessage.offset - _madsMessages[i - 1].offset;
if (i == count - 1)
curMessage.compSize = messageS->size() - curMessage.offset;
//printf("id: %i, offset: %i, uncomp size: %i\n", curMessage->id, curMessage->offset, curMessage->uncompSize);
_madsMessages.push_back(curMessage);
}
_vm->res()->toss("messages.dat");
}
void MadsGlobals::loadMadsObjects() {
Common::SeekableReadStream *objList = _vm->res()->get("objects.dat");
int numObjects = objList->readUint16LE();
for (int i = 0; i < numObjects; ++i)
_madsObjects.push_back(MadsObjectArray::value_type(new MadsObject(objList)));
_vm->res()->toss("objects.dat");
}
int MadsGlobals::messageIndexOf(uint32 messageId) {
for (uint i = 0; i < _madsMessages.size(); ++i)
{
if (_madsMessages[i].id == messageId)
return i;
}
return -1;
}
const char *MadsGlobals::loadMessage(uint index) {
if (index > _madsMessages.size() - 1) {
warning("Invalid message index: %i", index);
return NULL;
}
FabDecompressor fab;
byte *compData = new byte[_madsMessages[index].compSize];
byte *buffer = new byte[_madsMessages[index].uncompSize];
Common::SeekableReadStream *messageS = _vm->res()->get("messages.dat");
messageS->seek(_madsMessages[index].offset, SEEK_SET);
messageS->read(compData, _madsMessages[index].compSize);
fab.decompress(compData, _madsMessages[index].compSize, buffer, _madsMessages[index].uncompSize);
for (int i = 0; i < _madsMessages[index].uncompSize - 1; i++)
if (buffer[i] == '\0') buffer[i] = '\n';
_vm->res()->toss("messages.dat");
delete[] compData;
return (char*)buffer;
}
/**
* Adds the specified scene number to list of scenes previously visited
*/
void MadsGlobals::addVisitedScene(int newSceneNumber) {
if (!isSceneVisited(newSceneNumber))
_visitedScenes.push_back(newSceneNumber);
}
/**
* Returns true if the specified scene has been previously visited
*/
bool MadsGlobals::isSceneVisited(int checkSceneNumber) {
Common::List<int>::iterator i;
for (i = _visitedScenes.begin(); i != _visitedScenes.end(); ++i)
if (*i == checkSceneNumber)
return true;
return false;
}
void MadsGlobals::removeVisitedScene(int oldSceneNumber) {
_visitedScenes.remove(oldSceneNumber);
}
/*--------------------------------------------------------------------------*/
M4Globals::M4Globals(M4Engine *vm): Globals(vm) {
_vm = vm;
}
/*--------------------------------------------------------------------------*/
Player::Player(MadsM4Engine *vm) : _vm(vm) {
commandsAllowed = true;
needToWalk = false;
readyToWalk = false;
waitingForWalk = false;
commandReady = false;
strcpy(verb, "");
strcpy(noun, "");
strcpy(prep, "");
strcpy(object, "");
}
void Player::setCommandsAllowed(bool value) {
setCommandsAllowedFlag = true;
commandsAllowed = value;
if (value) {
// Player commands are enabled again
_vm->_mouse->lockCursor(CURSOR_ARROW);
//_m4Vm->scene()->getInterface()->cancelSentence();
} else {
// Player commands are disabled, so show hourglass cursor
_vm->_mouse->lockCursor(CURSOR_HOURGLASS);
}
}
bool Player::said(const char *word1, const char *word2, const char *word3) {
const char *words[3];
words[0] = word1;
words[1] = word2;
words[2] = word2;
for (int i = 0; i < 3; i++) {
if (words[i])
if ((scumm_stricmp(noun, words[i])) &&
(scumm_stricmp(object, words[i])) &&
(scumm_stricmp(verb, words[i])))
return false;
}
return true;
}
bool Player::saidAny(const char *word1, const char *word2, const char *word3,
const char *word4, const char *word5, const char *word6, const char *word7,
const char *word8, const char *word9, const char *word10) {
const char *words[10];
words[0] = word1;
words[1] = word2;
words[2] = word3;
words[3] = word4;
words[4] = word5;
words[5] = word6;
words[6] = word7;
words[7] = word8;
words[8] = word9;
words[9] = word10;
for (int i = 0; i < 10; i++) {
if (words[i]) {
if (!scumm_stricmp(noun, words[i]))
return true;
if (!scumm_stricmp(object, words[i]))
return true;
if (!scumm_stricmp(verb, words[i]))
return true;
}
}
return false;
}
/*--------------------------------------------------------------------------*/
MadsObject::MadsObject(Common::SeekableReadStream *stream) {
load(stream);
}
void MadsObject::load(Common::SeekableReadStream *stream) {
// Get the next data block
uint8 obj[0x30];
stream->read(obj, 0x30);
// Extract object data fields
descId = READ_LE_UINT16(&obj[0]);
roomNumber = READ_LE_UINT16(&obj[2]);
article = (MADSArticles)obj[4];
vocabCount = obj[5] & 0x7f;
assert(vocabCount <= 3);
for (int i = 0; i < vocabCount; ++i) {
vocabList[i].flags1 = obj[6 + i * 4];
vocabList[i].flags2 = obj[7 + i * 4];
vocabList[i].vocabId = READ_LE_UINT16(&obj[8 + i * 4]);
}
}
} // End of namespace M4