2006-04-29 13:38:07 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2001-2006 The ScummVM project
|
|
|
|
*
|
|
|
|
* 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 "common/stdafx.h"
|
|
|
|
|
|
|
|
#include "simon/simon.h"
|
|
|
|
#include "simon/intern.h"
|
|
|
|
|
|
|
|
using Common::File;
|
|
|
|
|
|
|
|
namespace Simon {
|
|
|
|
|
|
|
|
Subroutine *SimonEngine::getSubroutineByID(uint subroutine_id) {
|
|
|
|
Subroutine *cur;
|
|
|
|
|
|
|
|
_subroutine = subroutine_id;
|
|
|
|
|
|
|
|
for (cur = _subroutineList; cur; cur = cur->next) {
|
|
|
|
if (cur->id == subroutine_id)
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
loadTablesIntoMem(subroutine_id);
|
|
|
|
|
|
|
|
for (cur = _subroutineList; cur; cur = cur->next) {
|
|
|
|
if (cur->id == subroutine_id)
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subroutine_id != 160)
|
|
|
|
debug(0,"getSubroutineByID: subroutine %d not found", subroutine_id);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::alignTableMem() {
|
|
|
|
if ((unsigned long)_tablesHeapPtr & 3) {
|
|
|
|
_tablesHeapPtr += 2;
|
|
|
|
_tablesHeapCurPos += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
byte *SimonEngine::allocateTable(uint size) {
|
|
|
|
byte *org = _tablesHeapPtr;
|
|
|
|
|
|
|
|
size = (size + 1) & ~1;
|
|
|
|
|
|
|
|
_tablesHeapPtr += size;
|
|
|
|
_tablesHeapCurPos += size;
|
|
|
|
|
|
|
|
if (_tablesHeapCurPos > _tablesHeapSize)
|
|
|
|
error("Tablesheap overflow");
|
|
|
|
|
|
|
|
return org;
|
|
|
|
}
|
|
|
|
|
|
|
|
File *SimonEngine::openTablesFile(const char *filename) {
|
|
|
|
if (getFeatures() & GF_OLD_BUNDLE)
|
|
|
|
return openTablesFile_simon1(filename);
|
|
|
|
else
|
|
|
|
return openTablesFile_gme(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
File *SimonEngine::openTablesFile_simon1(const char *filename) {
|
|
|
|
File *fo = new File();
|
|
|
|
fo->open(filename);
|
|
|
|
if (fo->isOpen() == false)
|
|
|
|
error("openTablesFile: Can't open '%s'", filename);
|
|
|
|
return fo;
|
|
|
|
}
|
|
|
|
|
|
|
|
File *SimonEngine::openTablesFile_gme(const char *filename) {
|
|
|
|
uint res;
|
|
|
|
uint32 offs;
|
|
|
|
|
|
|
|
res = atoi(filename + 6) + TABLE_INDEX_BASE - 1;
|
|
|
|
offs = _gameOffsetsPtr[res];
|
|
|
|
|
|
|
|
_gameFile->seek(offs, SEEK_SET);
|
|
|
|
return _gameFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::loadTablesIntoMem(uint subr_id) {
|
|
|
|
byte *p;
|
|
|
|
int i;
|
|
|
|
uint min_num, max_num;
|
|
|
|
char filename[30];
|
|
|
|
File *in;
|
|
|
|
|
|
|
|
p = _tblList;
|
|
|
|
if (p == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
for (i = 0; *p; p++, i++)
|
|
|
|
filename[i] = *p;
|
|
|
|
filename[i] = 0;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
min_num = (p[0] * 256) | p[1];
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
if (min_num == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
max_num = (p[0] * 256) | p[1];
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
if (subr_id >= min_num && subr_id <= max_num) {
|
|
|
|
_subroutineList = _subroutineListOrg;
|
|
|
|
_tablesHeapPtr = _tablesHeapPtrOrg;
|
|
|
|
_tablesHeapCurPos = _tablesHeapCurPosOrg;
|
|
|
|
_stringIdLocalMin = 1;
|
|
|
|
_stringIdLocalMax = 0;
|
|
|
|
|
|
|
|
in = openTablesFile(filename);
|
|
|
|
readSubroutineBlock(in);
|
|
|
|
closeTablesFile(in);
|
|
|
|
if (getGameType() == GType_FF) {
|
|
|
|
// TODO
|
|
|
|
} else if (getGameType() == GType_SIMON2) {
|
|
|
|
_sound->loadSfxTable(_gameFile, _gameOffsetsPtr[atoi(filename + 6) - 1 + SOUND_INDEX_BASE]);
|
|
|
|
} else if (getPlatform() == Common::kPlatformWindows) {
|
|
|
|
memcpy(filename, "SFXXXX", 6);
|
|
|
|
_sound->readSfxFile(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
alignTableMem();
|
|
|
|
|
|
|
|
_tablesheapPtrNew = _tablesHeapPtr;
|
|
|
|
_tablesHeapCurPosNew = _tablesHeapCurPos;
|
|
|
|
|
|
|
|
if (_tablesHeapCurPos > _tablesHeapSize)
|
|
|
|
error("loadTablesIntoMem: Out of table memory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
debug(1,"loadTablesIntoMem: didn't find %d", subr_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::closeTablesFile(File *in) {
|
|
|
|
if (getFeatures() & GF_OLD_BUNDLE) {
|
|
|
|
in->close();
|
|
|
|
delete in;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Subroutine *SimonEngine::createSubroutine(uint id) {
|
|
|
|
Subroutine *sub;
|
|
|
|
|
|
|
|
alignTableMem();
|
|
|
|
|
|
|
|
sub = (Subroutine *)allocateTable(sizeof(Subroutine));
|
|
|
|
sub->id = id;
|
|
|
|
sub->first = 0;
|
|
|
|
sub->next = _subroutineList;
|
|
|
|
_subroutineList = sub;
|
|
|
|
return sub;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubroutineLine *SimonEngine::createSubroutineLine(Subroutine *sub, int where) {
|
|
|
|
SubroutineLine *sl, *cur_sl = NULL, *last_sl = NULL;
|
|
|
|
|
|
|
|
if (sub->id == 0)
|
|
|
|
sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_BIG_SIZE);
|
|
|
|
else
|
|
|
|
sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_SMALL_SIZE);
|
|
|
|
|
|
|
|
// where is what offset to insert the line at, locate the proper beginning line
|
|
|
|
if (sub->first != 0) {
|
|
|
|
cur_sl = (SubroutineLine *)((byte *)sub + sub->first);
|
|
|
|
while (where) {
|
|
|
|
last_sl = cur_sl;
|
|
|
|
cur_sl = (SubroutineLine *)((byte *)sub + cur_sl->next);
|
|
|
|
if ((byte *)cur_sl == (byte *)sub)
|
|
|
|
break;
|
|
|
|
where--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last_sl != NULL) {
|
|
|
|
// Insert the subroutine line in the middle of the link
|
|
|
|
last_sl->next = (byte *)sl - (byte *)sub;
|
|
|
|
sl->next = (byte *)cur_sl - (byte *)sub;
|
|
|
|
} else {
|
|
|
|
// Insert the subroutine line at the head of the link
|
|
|
|
sl->next = sub->first;
|
|
|
|
sub->first = (byte *)sl - (byte *)sub;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
2006-04-29 14:11:29 +00:00
|
|
|
void SimonEngine::runSubroutine101() {
|
|
|
|
Subroutine *sub;
|
|
|
|
|
|
|
|
sub = getSubroutineByID(101);
|
|
|
|
if (sub != NULL)
|
|
|
|
startSubroutineEx(sub);
|
|
|
|
|
|
|
|
permitInput();
|
|
|
|
}
|
|
|
|
|
2006-04-29 13:38:07 +00:00
|
|
|
int SimonEngine::startSubroutine(Subroutine *sub) {
|
|
|
|
int result = -1;
|
|
|
|
SubroutineLine *sl;
|
|
|
|
const byte *old_code_ptr;
|
|
|
|
|
|
|
|
if (_startMainScript)
|
|
|
|
dumpSubroutine(sub);
|
|
|
|
|
|
|
|
old_code_ptr = _codePtr;
|
|
|
|
|
|
|
|
if (++_recursionDepth > 40)
|
|
|
|
error("Recursion error");
|
|
|
|
|
2006-05-03 12:54:37 +00:00
|
|
|
// WORKAROUND: Bit Flag 171 isn't set when Simon rides the lion to the
|
|
|
|
// goblin camp in non-English versions. Bit Flag 171 is required to display
|
|
|
|
// the red trail between locations on the map, during the ride.
|
|
|
|
if (getGameType() == GType_SIMON2) {
|
|
|
|
if (sub->id == 13020)
|
|
|
|
setBitFlag(171, true);
|
|
|
|
if (sub->id == 13021)
|
|
|
|
setBitFlag(171, false);
|
|
|
|
}
|
|
|
|
|
2006-04-29 13:38:07 +00:00
|
|
|
sl = (SubroutineLine *)((byte *)sub + sub->first);
|
|
|
|
|
|
|
|
while ((byte *)sl != (byte *)sub) {
|
|
|
|
if (checkIfToRunSubroutineLine(sl, sub)) {
|
|
|
|
result = 0;
|
|
|
|
_codePtr = (byte *)sl;
|
|
|
|
if (sub->id)
|
|
|
|
_codePtr += 2;
|
|
|
|
else
|
|
|
|
_codePtr += 8;
|
|
|
|
|
|
|
|
if (_continousMainScript)
|
|
|
|
fprintf(_dumpFile, "; %d\n", sub->id);
|
|
|
|
result = runScript();
|
|
|
|
if (result != 0) {
|
|
|
|
/* result -10 means restart subroutine */
|
|
|
|
if (result == -10) {
|
|
|
|
delay(0); /* maybe leave control to the VGA */
|
|
|
|
sl = (SubroutineLine *)((byte *)sub + sub->first);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sl = (SubroutineLine *)((byte *)sub + sl->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
_codePtr = old_code_ptr;
|
|
|
|
|
|
|
|
_recursionDepth--;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SimonEngine::startSubroutineEx(Subroutine *sub) {
|
|
|
|
return startSubroutine(sub);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SimonEngine::checkIfToRunSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
|
|
|
|
if (sub->id)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (sl->verb != -1 && sl->verb != _scriptVerb &&
|
|
|
|
(sl->verb != -2 || _scriptVerb != -1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sl->noun1 != -1 && sl->noun1 != _scriptNoun1 &&
|
|
|
|
(sl->noun1 != -2 || _scriptNoun1 != -1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sl->noun2 != -1 && sl->noun2 != _scriptNoun2 &&
|
|
|
|
(sl->noun2 != -2 || _scriptNoun2 != -1))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::readSubroutine(File *in, Subroutine *sub) {
|
|
|
|
while (in->readUint16BE() == 0) {
|
|
|
|
readSubroutineLine(in, createSubroutineLine(sub, 0xFFFF), sub);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::readSubroutineLine(File *in, SubroutineLine *sl, Subroutine *sub) {
|
|
|
|
byte line_buffer[1024], *q = line_buffer;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
if (sub->id == 0) {
|
|
|
|
sl->verb = in->readUint16BE();
|
|
|
|
sl->noun1 = in->readUint16BE();
|
|
|
|
sl->noun2 = in->readUint16BE();
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((*q = in->readByte()) != 0xFF) {
|
|
|
|
if (*q == 87) {
|
|
|
|
in->readUint16BE();
|
|
|
|
} else {
|
|
|
|
q = readSingleOpcode(in, q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
size = q - line_buffer + 1;
|
|
|
|
|
|
|
|
memcpy(allocateTable(size), line_buffer, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SimonEngine::readSubroutineBlock(File *in) {
|
|
|
|
while (in->readUint16BE() == 0) {
|
|
|
|
readSubroutine(in, createSubroutine(in->readUint16BE()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // End of namespace Simon
|