mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-29 05:03:29 +00:00
c8eeae8d4d
eos() now only returns true _after_ trying to read past the end of the stream. This has a large potential for regressions. Please test! svn-id: r34549
456 lines
11 KiB
C++
456 lines
11 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(M4Engine *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(M4Engine *vm): _vm(vm) {
|
|
}
|
|
|
|
Globals::~Globals() {
|
|
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();
|
|
}
|
|
|
|
bool Globals::isInterfaceVisible() {
|
|
return _vm->_interfaceView->isVisible();
|
|
}
|
|
|
|
void Globals::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 Globals::loadMadsQuotes() {
|
|
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 Globals::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 = new MessageItem();
|
|
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");
|
|
}
|
|
|
|
char* Globals::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");
|
|
|
|
return (char*)buffer;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
Player::Player(M4Engine *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);
|
|
//_vm->_interfaceView->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;
|
|
}
|
|
|
|
|
|
} // End of namespace M4
|