diff options
Diffstat (limited to 'engines/kyra/script/script.h')
-rw-r--r-- | engines/kyra/script/script.h | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/engines/kyra/script/script.h b/engines/kyra/script/script.h new file mode 100644 index 0000000000..12a44b0a03 --- /dev/null +++ b/engines/kyra/script/script.h @@ -0,0 +1,159 @@ +/* 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. + * + */ + +#ifndef KYRA_SCRIPT_H +#define KYRA_SCRIPT_H + +#include "common/stream.h" +#include "common/array.h" +#include "common/func.h" +#include "common/iff_container.h" + +namespace Kyra { + +struct EMCState; +typedef Common::Functor1<EMCState *, int> Opcode; + +struct EMCData { + char filename[13]; + + byte *text; + uint16 *data; + uint16 *ordr; + uint16 dataSize; + + const Common::Array<const Opcode *> *sysFuncs; +}; + +struct EMCState { + enum { + kStackSize = 100, + kStackLastEntry = kStackSize - 1 + }; + + const uint16 *ip; + const EMCData *dataPtr; + int16 retValue; + uint16 bp; + uint16 sp; + int16 regs[30]; // VM registers + int16 stack[kStackSize]; // VM stack +}; + +#define stackPos(x) (script->stack[script->sp+x]) +#define stackPosString(x) ((const char *)&script->dataPtr->text[READ_BE_UINT16(&script->dataPtr->text[stackPos(x)<<1])]) + +class Resource; +class KyraEngine_v1; + +class IFFParser : public Common::IFFParser { +public: + IFFParser(Common::ReadStream &input) : Common::IFFParser(&input) { + // It seems Westwood missunderstood the 'size' field of the FORM chunk. + // + // For EMC scripts (type EMC2) it's filesize instead of filesize - 8, + // means accidently including the 8 bytes used by the chunk header for the FORM + // chunk. + // + // For TIM scripts (type AVFS) it's filesize - 12 instead of filesize - 8, + // means it will not include the size of the 'type' field in the FORM chunk, + // instead of only not including the chunk header size. + // + // Both lead to some problems in our IFF parser, either reading after the end + // of file or producing a "Chunk overread" error message. To work around this + // we need to adjust the size field properly. + + // Fix for certain Russian fan translations: + // Westwood's original code completely ignores the FORM chunk and its size + // setting. After opening a TIM or EMC file they just check whether the FORM + // chunk exists (as a kind of file type verification) and then immediately seek + // behind the FORM chunk. + // This means that their parser is immune to weird fan translation scripts + // where the file size doesn't match the form chunk size. In our implemetation + // this would produce "Chunk overread" errors. + // Westwood also always pads all chunk sizes to 2 byte alignment after reading + // them from the file (not with FORM though, since they completely ignore it). + // This seems to do the trick for our FORM chunk size issue with the Russian + // fan translations. Another method which I have tried and which seems to work + // well would be simply setting _formChunk.size to the file size (-12 for TIM). + + _formChunk.size = (_formChunk.size + 1) & ~1; + + if (_formType == MKTAG('E','M','C','2')) + _formChunk.size -= 8; + else if (_formType == MKTAG('A','V','F','S')) + _formChunk.size += 4; + } +}; + +class EMCInterpreter { +public: + EMCInterpreter(KyraEngine_v1 *vm); + + bool load(const char *filename, EMCData *data, const Common::Array<const Opcode *> *opcodes); + void unload(EMCData *data); + + void init(EMCState *scriptState, const EMCData *data); + bool start(EMCState *script, int function); + + bool isValid(EMCState *script); + + bool run(EMCState *script); +protected: + KyraEngine_v1 *_vm; + int16 _parameter; + + const char *_filename; + EMCData *_scriptData; + + bool callback(Common::IFFChunk &chunk); + + typedef void (EMCInterpreter::*OpcodeProc)(EMCState *); + struct OpcodeEntry { + OpcodeProc proc; + const char *desc; + }; + + const OpcodeEntry *_opcodes; +private: + void op_jmp(EMCState *); + void op_setRetValue(EMCState *); + void op_pushRetOrPos(EMCState *); + void op_push(EMCState *); + void op_pushReg(EMCState *); + void op_pushBPNeg(EMCState *); + void op_pushBPAdd(EMCState *); + void op_popRetOrPos(EMCState *); + void op_popReg(EMCState *); + void op_popBPNeg(EMCState *); + void op_popBPAdd(EMCState *); + void op_addSP(EMCState *); + void op_subSP(EMCState *); + void op_sysCall(EMCState *); + void op_ifNotJmp(EMCState *); + void op_negate(EMCState *); + void op_eval(EMCState *); + void op_setRetAndJmp(EMCState *); +}; +} // End of namespace Kyra + +#endif |