From 7ca439f410ac1c46a387567b30271ae4e4a2ed30 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Sun, 20 Apr 2008 14:47:37 +0000 Subject: Initial import of the work in progress M4 engine svn-id: r31600 --- engines/m4/ws_machine.cpp | 422 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 engines/m4/ws_machine.cpp (limited to 'engines/m4/ws_machine.cpp') diff --git a/engines/m4/ws_machine.cpp b/engines/m4/ws_machine.cpp new file mode 100644 index 0000000000..ece76fe5ab --- /dev/null +++ b/engines/m4/ws_machine.cpp @@ -0,0 +1,422 @@ +/* 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/woodscript.h" + +namespace M4 { + +bool (Machine::*machineCommandsTable[])(Instruction &instruction) = { + NULL, + NULL,//TODO: nop + &Machine::m1_gotoState, + &Machine::m1_jump, + &Machine::m1_terminate, + &Machine::m1_startSequence, + &Machine::m1_pauseSequence, + &Machine::m1_resumeSequence, + &Machine::m1_storeValue, + &Machine::m1_sendMessage, + &Machine::m1_broadcastMessage, + &Machine::m1_replyMessage, + &Machine::m1_sendSystemMessage, + &Machine::m1_createMachine, + &Machine::m1_createMachineEx, + &Machine::m1_clearVars +}; + +void (Machine::*machineConditionalsTable[])(Instruction &instruction) = { + NULL,//TODO: after + &Machine::m1_onEndSequence, + &Machine::m1_onMessage, + NULL,//TODO: on_p_msg + &Machine::m1_switchLt, + &Machine::m1_switchLe, + &Machine::m1_switchEq, + &Machine::m1_switchNe, + &Machine::m1_switchGe, + &Machine::m1_switchGt, +}; + +Machine::Machine(WoodScript *ws, int32 machineHash, Sequence *parentSeq, int32 dataHash, + int32 dataRowIndex, int callbackHandler, Common::String machineName, int32 id) { + + _ws = ws; + + _machHash = machineHash; + _name = machineName; + _id = id; + + // initialize the machine's bytecode + MachineAsset *machineAsset = _ws->assets()->getMachine(_machHash); + byte *code; + uint32 codeSize; + machineAsset->getCode(code, codeSize); + _code = new Bytecode(_ws, code, codeSize, NULL); + + // initialize the machine's data + if (dataHash >= 0) { + DataAsset *dataAsset = _ws->assets()->getData(dataHash); + _dataRow = dataAsset->getRow(dataRowIndex); + } else { + _dataRow = NULL; + } + + _recursionLevel = 0; + _currentState = 0; + _sequence = NULL; + _parentSequence = parentSeq; + _targetCount = 0; + +} + +Machine::~Machine() { + delete _code; +} + +void Machine::clearMessages() { +} + +void Machine::clearPersistentMessages() { +} + +void Machine::restorePersistentMessages() { +} + +void Machine::sendMessage(uint32 messageHash, long messageValue, Machine *sender) { +} + +void Machine::resetSwitchTime() { +} + +bool Machine::changeSequenceProgram(int32 sequenceHash) { + return _sequence->changeProgram(sequenceHash); +} + +bool Machine::searchMessages(uint32 messageHash, uint32 messageValue, Machine *sender) { + return false; +} + +bool Machine::searchPersistentMessages(uint32 messageHash, uint32 messageValue, Machine *sender) { + return false; +} + +void Machine::enterState() { + + MachineAsset *machineAsset = _ws->assets()->getMachine(_machHash); + + _code->jumpAbsolute(machineAsset->getStateOffset(_currentState)); + + int32 instruction = -1; + + _recursionLevel++; + + int32 oldId = _id; + int32 oldRecursionLevel = _recursionLevel; + + while (instruction && instruction != 4 && _id == oldId && _recursionLevel == oldRecursionLevel) { + instruction = execInstruction(); + } + + if (instruction != 4 && _id == oldId && _recursionLevel == oldRecursionLevel) { + _recursionLevel--; + } + +} + +int32 Machine::execInstruction() { + + //printf("Machine::execInstruction()\n"); fflush(stdout); + + bool done = false; + Instruction instruction; + //Sequence *sequence; + int32 machID = _id; + + _code->loadInstruction(instruction); + + if (instruction.instr >= 64) { + if (machineConditionalsTable[instruction.instr - 64] != NULL) + (this->*machineConditionalsTable[instruction.instr - 64])(instruction); + /* The next line is to yield on unimplemented opcodes */ + else { fflush(stdout); g_system->delayMillis(5000); } + } else if (instruction.instr > 0) { + if (machineCommandsTable[instruction.instr] != NULL) + done = !(this->*machineCommandsTable[instruction.instr])(instruction); + /* The next line is to yield on unimplemented opcodes */ + else { fflush(stdout); g_system->delayMillis(5000); } + if (done) { + if (_id == machID) { + //TODO: Cancel all requests + if (_currentState == -1) { + // TODO: Set terminated flag and delete machine in WoodScript update + } + else { + // initialize new state + enterState(); + } + } + } + } + + return instruction.instr; + +} + +void Machine::execBlock(int32 offset, int32 count) { + + // MachineAsset *machineAsset = _ws->assets()->getMachine(_machHash); + + int32 startOffset = offset, endOffset = offset + count; + + _recursionLevel++; + + int32 oldId = _id; + int32 oldRecursionLevel = _recursionLevel; + + _code->jumpAbsolute(offset); + + int32 instruction = -1; + + //printf("---------------------------------------\n"); fflush(stdout); + + while (instruction && instruction != 4 && _id == oldId && _recursionLevel == oldRecursionLevel && + _code->pos() >= (uint32)startOffset && _code->pos() < (uint32)endOffset) { + + instruction = execInstruction(); + //g_system->delayMillis(500); + } + + //printf("---------------------------------------\n"); fflush(stdout); + + if (instruction == 3) { + execInstruction(); + } + + if (instruction != 4 && _id == oldId && _recursionLevel == oldRecursionLevel) { + _recursionLevel--; + } + +} + +bool Machine::m1_gotoState(Instruction &instruction) { + //printf("Machine::m1_gotoState() state = %d\n", (int32)instruction.argv[0] >> 16); + + _currentState = (int32)instruction.argv[0] >> 16; + _recursionLevel = 0; + return false; +} + +bool Machine::m1_jump(Instruction &instruction) { + //printf("Machine::m1_jump() ofs = %08X\n", (int32)instruction.argv[0] >> 16); + + _code->jumpRelative((int32)instruction.argv[0] >> 16); + return true; +} + +bool Machine::m1_terminate(Instruction &instruction) { + //printf("Machine::m1_terminate()\n"); fflush(stdout); + + _currentState = -1; + _recursionLevel = 0; + return false; +} + +bool Machine::m1_startSequence(Instruction &instruction) { + //printf("Machine::m1_startSequence() sequence hash = %d\n", (uint32)instruction.argv[0] >> 16); fflush(stdout); + + int32 sequenceHash = instruction.argv[0] >> 16; + if (_sequence == NULL) { + //printf("Machine::m1_startSequence() creating new sequence\n"); + _sequence = _ws->createSequence(this, sequenceHash); + _code->setSequence(_sequence); + } else { + //printf("Machine::m1_startSequence() using existing sequence\n"); + _sequence->changeProgram(sequenceHash); + //_code->setSequence(_sequence); + } + return true; +} + +bool Machine::m1_pauseSequence(Instruction &instruction) { + //printf("Machine::m1_pauseSequence()\n"); fflush(stdout); + + _sequence->pause(); + return true; +} + +bool Machine::m1_resumeSequence(Instruction &instruction) { + //printf("Machine::m1_resumeSequence()\n"); fflush(stdout); + + _sequence->resume(); + return true; +} + +bool Machine::m1_storeValue(Instruction &instruction) { + //printf("Machine::m1_storeValue() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]); + + *instruction.argp[0] = instruction.getValue(); + return true; +} + +bool Machine::m1_sendMessage(Instruction &instruction) { + //printf("Machine::m1_sendMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]); + +#if 0 +//TODO + long messageValue; + + if (instruction.argc == 3) { + messageValue = instruction.argv[2]; + } else { + messageValue = 0; + } + //_ws->sendMessage((uint32)instruction.argv[1], messageValue, (uint32)instruction.argv[0] >> 16); + //void SendWSMessage(uint32 msgHash, long msgValue, machine *recvM, uint32 machHash, machine *sendM, int32 msgCount) { +#endif + return true; + +} + +bool Machine::m1_broadcastMessage(Instruction &instruction) { + //printf("Machine::m1_broadcastMessage() %p = %d (%08X)\n", (void*)instruction.argp[0], (uint32)instruction.argv[1], (uint32)instruction.argv[1]); + +#if 0 +//TODO + long messageValue; + + if (instruction.argc == 3) { + messageValue = instruction.argv[2]; + } else { + messageValue = 0; + } + //_ws->sendMessage((uint32)instruction.argv[1], messageValue, (uint32)instruction.argv[0] >> 16); +#endif + return true; +} + +bool Machine::m1_replyMessage(Instruction &instruction) { + //printf("Machine::m1_replyMessage() messageHash = %d; messageValue = %d\n", (uint32)instruction.argv[0], (uint32)instruction.argv[1]); +#if 0 + if (myArg2) { + msgValue = *myArg2; + } + else { + msgValue = 0; + } + SendWSMessage(*myArg1, msgValue, m->msgReplyXM, 0, m, 1); +#endif + return true; +} + +bool Machine::m1_sendSystemMessage(Instruction &instruction) { + //printf("Machine::m1_sendSystemMessage() messageValue = %d\n", (uint32)instruction.argv[0]); +#if 0 +#endif + return true; +} + +bool Machine::m1_createMachine(Instruction &instruction) { + //printf("Machine::m1_createMachine()\n"); +#if 0 +#endif + return true; +} + +bool Machine::m1_createMachineEx(Instruction &instruction) { + //printf("Machine::m1_createMachineEx()\n"); +#if 0 +#endif + return true; +} + +bool Machine::m1_clearVars(Instruction &instruction) { + //printf("Machine::m1_clearVars()\n"); fflush(stdout); + + _sequence->clearVars(); + return true; +} + + +void Machine::m1_onEndSequence(Instruction &instruction) { + //printf("Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16); fflush(stdout); + + int32 count = instruction.argv[0] >> 16; + _sequence->issueEndOfSequenceRequest(_code->pos(), count); + _code->jumpRelative(count); +} + +void Machine::m1_onMessage(Instruction &instruction) { + //printf("Machine::m1_onEndSequence() count = %08X\n", (uint32)instruction.argv[0] >> 16); fflush(stdout); + + // TODO: Add message to list + + int32 count = instruction.argv[0] >> 16; + _code->jumpRelative(count); + +} + +void Machine::m1_switchLt(Instruction &instruction) { + //printf("Machine::m1_switchLt() %d < %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] >= instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +void Machine::m1_switchLe(Instruction &instruction) { + //printf("Machine::m1_switchLe() %d <= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] > instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +void Machine::m1_switchEq(Instruction &instruction) { + //printf("Machine::m1_switchEq() %d == %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] != instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +void Machine::m1_switchNe(Instruction &instruction) { + //printf("Machine::m1_switchNe() %d != %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] == instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +void Machine::m1_switchGe(Instruction &instruction) { + //printf("Machine::m1_switchGe() %d >= %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] < instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +void Machine::m1_switchGt(Instruction &instruction) { + //printf("Machine::m1_switchGt() %d > %d -> %08X\n", (uint32)instruction.argv[1], (uint32)instruction.argv[2], (uint32)instruction.argv[0] >> 16); fflush(stdout); + + if (instruction.argv[1] <= instruction.argv[2]) + _code->jumpRelative(instruction.argv[0] >> 16); +} + +} -- cgit v1.2.3