Introduce the RivenScriptManager to keep track of scripts and free them when required. The old way of using SharedPtr was quite hacky and didn't work properly when talking to Gehn in ospit.

svn-id: r50761
This commit is contained in:
Matthew Hoops 2010-07-09 16:53:20 +00:00
parent eddd6d0dba
commit 541daf918a
5 changed files with 92 additions and 38 deletions

View File

@ -558,9 +558,11 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) {
printf ("==================================\n\n");
Common::SeekableReadStream *cardStream = _vm->getRawData(MKID_BE('CARD'), (uint16)atoi(argv[3]));
cardStream->seek(4);
RivenScriptList scriptList = RivenScript::readScripts(_vm, cardStream);
for (uint32 i = 0; i < scriptList.size(); i++)
RivenScriptList scriptList = _vm->_scriptMan->readScripts(cardStream, false);
for (uint32 i = 0; i < scriptList.size(); i++) {
scriptList[i]->dumpScript(varNames, xNames, 0);
delete scriptList[i];
}
delete cardStream;
} else if (!scumm_stricmp(argv[2], "HSPT")) {
printf ("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3]));
@ -573,9 +575,11 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) {
for (uint16 i = 0; i < hotspotCount; i++) {
printf ("Hotspot %d:\n", i);
hsptStream->seek(22, SEEK_CUR); // Skip non-script related stuff
RivenScriptList scriptList = RivenScript::readScripts(_vm, hsptStream);
for (uint32 j = 0; j < scriptList.size(); j++)
RivenScriptList scriptList = _vm->_scriptMan->readScripts(hsptStream, false);
for (uint32 j = 0; j < scriptList.size(); j++) {
scriptList[j]->dumpScript(varNames, xNames, 1);
delete scriptList[j];
}
}
delete hsptStream;

View File

@ -53,6 +53,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_ignoreNextMouseUp = false;
_extrasFile = NULL;
_curStack = aspit;
_hotspots = NULL;
// NOTE: We can never really support CD swapping. All of the music files
// (*_Sounds.mhk) are stored on disc 1. They are copied to the hard drive
@ -80,16 +81,17 @@ MohawkEngine_Riven::~MohawkEngine_Riven() {
delete _externalScriptHandler;
delete _extrasFile;
delete _saveLoad;
delete _scriptMan;
delete[] _vars;
delete _optionsDialog;
delete _rnd;
delete[] _hotspots;
delete g_atrusJournalRect1;
delete g_atrusJournalRect2;
delete g_cathJournalRect2;
delete g_atrusJournalRect3;
delete g_cathJournalRect3;
delete g_trapBookRect3;
_cardData.scripts.clear();
}
GUI::Debugger *MohawkEngine_Riven::getDebugger() {
@ -105,6 +107,7 @@ Common::Error MohawkEngine_Riven::run() {
_saveLoad = new RivenSaveLoad(this, _saveFileMan);
_externalScriptHandler = new RivenExternal(this);
_optionsDialog = new RivenOptionsDialog(this);
_scriptMan = new RivenScriptManager(this);
_rnd = new Common::RandomSource();
g_eventRec.registerRandomSource(*_rnd, "riven");
@ -347,13 +350,13 @@ void MohawkEngine_Riven::refreshCard() {
}
void MohawkEngine_Riven::loadCard(uint16 id) {
// NOTE: Do not clear the card scripts because it may delete a currently running script!
// NOTE: The card scripts are cleared by the RivenScriptManager automatically.
Common::SeekableReadStream* inStream = getRawData(ID_CARD, id);
_cardData.name = inStream->readSint16BE();
_cardData.zipModePlace = inStream->readUint16BE();
_cardData.scripts = RivenScript::readScripts(this, inStream);
_cardData.scripts = _scriptMan->readScripts(inStream);
_cardData.hasData = true;
delete inStream;
@ -371,7 +374,10 @@ void MohawkEngine_Riven::loadCard(uint16 id) {
}
void MohawkEngine_Riven::loadHotspots(uint16 id) {
// NOTE: Do not clear the hotspots because it may delete a currently running script!
// Clear old hotspots
delete[] _hotspots;
// NOTE: The hotspot scripts are cleared by the RivenScriptManager automatically.
Common::SeekableReadStream* inStream = getRawData(ID_HSPT, id);
@ -413,7 +419,7 @@ void MohawkEngine_Riven::loadHotspots(uint16 id) {
_hotspots[i].zipModeHotspot = inStream->readUint16BE();
// Read in the scripts now
_hotspots[i].scripts = RivenScript::readScripts(this, inStream);
_hotspots[i].scripts = _scriptMan->readScripts(inStream);
}
delete inStream;
@ -649,4 +655,4 @@ bool ZipMode::operator== (const ZipMode &z) const {
return z.name == name && z.id == id;
}
}
} // End of namespace Mohawk

View File

@ -113,6 +113,7 @@ public:
RivenGraphics *_gfx;
RivenExternal *_externalScriptHandler;
Common::RandomSource *_rnd;
RivenScriptManager *_scriptMan;
Card _cardData;

View File

@ -35,28 +35,16 @@
namespace Mohawk {
RivenScript::RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType)
: _vm(vm), _stream(stream), _scriptType(scriptType) {
RivenScript::RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType, uint16 parentStack, uint16 parentCard)
: _vm(vm), _stream(stream), _scriptType(scriptType), _parentStack(parentStack), _parentCard(parentCard) {
setupOpcodes();
_isRunning = false;
}
RivenScript::~RivenScript() {
delete _stream;
}
RivenScriptList RivenScript::readScripts(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream) {
RivenScriptList scriptList;
uint16 scriptCount = stream->readUint16BE();
for (uint16 i = 0; i < scriptCount; i++) {
uint16 scriptType = stream->readUint16BE();
uint32 scriptSize = calculateScriptSize(stream);
scriptList.push_back(Common::SharedPtr<RivenScript>(new RivenScript(vm, stream->readStream(scriptSize), scriptType)));
}
return scriptList;
}
uint32 RivenScript::calculateCommandSize(Common::SeekableReadStream* script) {
uint16 command = script->readUint16BE();
uint32 commandSize = 2;
@ -161,7 +149,7 @@ void RivenScript::setupOpcodes() {
OPCODE(activateFLST),
OPCODE(zipMode),
OPCODE(activateMLST),
OPCODE(activateSLSTWithVolume)
OPCODE(empty) // Activate an SLST with a volume parameter (not used)
};
_opcodes = riven_opcodes;
@ -239,10 +227,13 @@ void RivenScript::dumpCommands(Common::StringArray varNames, Common::StringArray
}
void RivenScript::runScript() {
_isRunning = true;
if (_stream->pos() != 0)
_stream->seek(0);
processCommands(true);
_isRunning = false;
}
void RivenScript::processCommands(bool runCommands) {
@ -610,9 +601,46 @@ void RivenScript::activateMLST(uint16 op, uint16 argc, uint16 *argv) {
_vm->_video->activateMLST(argv[0], _vm->getCurCard());
}
// Command 47: activate SLST record with a volume argument
void RivenScript::activateSLSTWithVolume(uint16 op, uint16 argc, uint16 *argv) {
warning("STUB: activateSLSTWithVolume()");
RivenScriptManager::RivenScriptManager(MohawkEngine_Riven *vm) {
_vm = vm;
}
RivenScriptManager::~RivenScriptManager() {
for (uint32 i = 0; i < _currentScripts.size(); i++)
delete _currentScripts[i];
}
RivenScriptList RivenScriptManager::readScripts(Common::SeekableReadStream *stream, bool garbageCollect) {
if (garbageCollect)
unloadUnusedScripts(); // Garbage collect!
RivenScriptList scriptList;
uint16 scriptCount = stream->readUint16BE();
for (uint16 i = 0; i < scriptCount; i++) {
uint16 scriptType = stream->readUint16BE();
uint32 scriptSize = RivenScript::calculateScriptSize(stream);
RivenScript *script = new RivenScript(_vm, stream->readStream(scriptSize), scriptType, _vm->getCurStack(), _vm->getCurCard());
scriptList.push_back(script);
// Only add it to the scripts that we will free later if it is requested.
// (ie. we don't want to store scripts from the dumpScript console command)
if (garbageCollect)
_currentScripts.push_back(script);
}
return scriptList;
}
void RivenScriptManager::unloadUnusedScripts() {
// Free any scripts that aren't part of the current card and aren't running
for (uint32 i = 0; i < _currentScripts.size(); i++) {
if ((_vm->getCurStack() != _currentScripts[i]->getParentStack() || _vm->getCurCard() != _currentScripts[i]->getParentCard()) && !_currentScripts[i]->isRunning()) {
delete _currentScripts[i];
_currentScripts.remove_at(i);
i--;
}
}
}
} // End of namespace Mohawk

View File

@ -50,19 +50,20 @@ enum {
};
class RivenScript;
typedef Common::Array<Common::SharedPtr<RivenScript> > RivenScriptList;
class RivenScript {
public:
RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType);
RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType, uint16 parentStack, uint16 parentCard);
~RivenScript();
void runScript();
void dumpScript(Common::StringArray varNames, Common::StringArray xNames, byte tabs);
uint16 getScriptType() { return _scriptType; }
uint16 getParentStack() { return _parentStack; }
uint16 getParentCard() { return _parentCard; }
bool isRunning() { return _isRunning; }
// Read in an array of script objects from a stream
static RivenScriptList readScripts(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream);
static uint32 calculateScriptSize(Common::SeekableReadStream *script);
private:
typedef void (RivenScript::*OpcodeProcRiven)(uint16 op, uint16 argc, uint16 *argv);
@ -70,18 +71,18 @@ private:
OpcodeProcRiven proc;
const char *desc;
};
const RivenOpcode* _opcodes;
const RivenOpcode *_opcodes;
void setupOpcodes();
MohawkEngine_Riven *_vm;
Common::SeekableReadStream *_stream;
uint16 _scriptType;
uint16 _scriptType, _parentStack, _parentCard, _parentHotspot;
bool _isRunning;
void dumpCommands(Common::StringArray varNames, Common::StringArray xNames, byte tabs);
void processCommands(bool runCommands);
static uint32 calculateCommandSize(Common::SeekableReadStream* script);
static uint32 calculateScriptSize(Common::SeekableReadStream* script);
static uint32 calculateCommandSize(Common::SeekableReadStream *script);
DECLARE_OPCODE(empty) { warning ("Unknown Opcode %04x", op); }
@ -120,7 +121,21 @@ private:
DECLARE_OPCODE(activateFLST);
DECLARE_OPCODE(zipMode);
DECLARE_OPCODE(activateMLST);
DECLARE_OPCODE(activateSLSTWithVolume);
};
typedef Common::Array<RivenScript*> RivenScriptList;
class RivenScriptManager {
public:
RivenScriptManager(MohawkEngine_Riven *vm);
~RivenScriptManager();
RivenScriptList readScripts(Common::SeekableReadStream *stream, bool garbageCollect = true);
private:
void unloadUnusedScripts();
RivenScriptList _currentScripts;
MohawkEngine_Riven *_vm;
};
} // End of namespace Mohawk