From 96f9910c79849c980a09ff733f4710ba9d414dc9 Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Sat, 18 Jun 2016 23:14:17 +0200 Subject: MACVENTURE: Add opcodes for script engine --- engines/macventure/macventure.cpp | 24 +- engines/macventure/macventure.h | 24 +- engines/macventure/script.cpp | 994 +++++++++++++++++++++++++++++++++++++- engines/macventure/script.h | 188 ++++++- engines/macventure/world.cpp | 54 +++ engines/macventure/world.h | 17 +- 6 files changed, 1281 insertions(+), 20 deletions(-) diff --git a/engines/macventure/macventure.cpp b/engines/macventure/macventure.cpp index 78884cf1bf..f2a2f43f51 100644 --- a/engines/macventure/macventure.cpp +++ b/engines/macventure/macventure.cpp @@ -92,7 +92,7 @@ Common::Error MacVentureEngine::run() { // Big class instantiation _gui = new Gui(this, _resourceManager); _world = new World(this, _resourceManager); - _scriptEngine = new ScriptEngine(_world); + _scriptEngine = new ScriptEngine(this, _world); _paused = false; _halted = true; @@ -193,6 +193,14 @@ void MacVentureEngine::gameChanged() { _gameChanged = true; } +void MacVentureEngine::winGame() { + _gameState = kGameStateWinnig; +} + +void MacVentureEngine::loseGame() { + _gameState = kGameStateLosing; +} + void MacVentureEngine::enqueueObject(ObjID id) { QueuedObject obj; obj.parent = _world->getObjAttr(id, kAttrParentObject); @@ -206,6 +214,13 @@ void MacVentureEngine::enqueueObject(ObjID id) { _objQueue.push_back(obj); } +void MacVentureEngine::enqueueText(TextQueueID type, ObjID target, ObjID source, ObjID text) { +} + +void MacVentureEngine::printTexts() { + debug("Printing texts.."); +} + const GlobalSettings& MacVentureEngine::getGlobalSettings() const { return _globalSettings; } @@ -284,6 +299,9 @@ bool MacVentureEngine::updateState() { return true; } +void MacVentureEngine::revert() { +} + void MacVentureEngine::runObjQueue() { } @@ -360,6 +378,10 @@ const HuffmanLists * MacVentureEngine::getDecodingHuffman() const { return _textHuffman; } +uint32 MacVentureEngine::randBetween(uint32 min, uint32 max) { + return _rnd->getRandomNumber(max - min) + min; +} + // Data loading bool MacVentureEngine::loadGlobalSettings() { diff --git a/engines/macventure/macventure.h b/engines/macventure/macventure.h index 457d685992..3ae195aef0 100644 --- a/engines/macventure/macventure.h +++ b/engines/macventure/macventure.h @@ -124,6 +124,12 @@ enum ObjectQueueID { kAnimateBack = 14 }; +enum TextQueueID { + kTextNumber = 1, + kTextNewLine = 2, + kTextPlain = 3 +}; + struct QueuedObject { ObjectQueueID id; ObjID object; @@ -152,8 +158,17 @@ public: void refreshReady(); void preparedToRun(); void gameChanged(); + void winGame(); + void loseGame(); + + bool updateState(); + void revert(); void enqueueObject(ObjID id); + void enqueueText(TextQueueID type, ObjID target, ObjID source, ObjID text); + + void runObjQueue(); + void printTexts(); // Data retrieval bool isPaused(); @@ -162,14 +177,13 @@ public: Common::String getFilePath(FilePathID id) const; bool isOldText() const; const HuffmanLists *getDecodingHuffman() const; + uint32 randBetween(uint32 min, uint32 max); private: void processEvents(); bool runScriptEngine(); void endGame(); - bool updateState(); - void runObjQueue(); void updateControls(); void resetVars(); @@ -181,6 +195,8 @@ private: ControlAction referenceToAction(ControlReference id); uint objectsToApplyCommand(); + const char* getGameFileName() const; + private: // Attributes const ADGameDescription *_gameDescription; @@ -217,10 +233,6 @@ private: // Attributes Common::List _currentSelection; Common::Point _deltaPoint; -private: // Methods - - const char* getGameFileName() const; - }; diff --git a/engines/macventure/script.cpp b/engines/macventure/script.cpp index 7e594f5a11..b0d5ef0011 100644 --- a/engines/macventure/script.cpp +++ b/engines/macventure/script.cpp @@ -20,6 +20,8 @@ * */ +#include "common/system.h" + #include "macventure/macventure.h" #include "macventure/script.h" #include "macventure/world.h" @@ -27,7 +29,8 @@ namespace MacVenture { -ScriptEngine::ScriptEngine(World * world) { +ScriptEngine::ScriptEngine(MacVentureEngine * engine, World * world) { + _engine = engine; _world = world; _scripts = new Container("Shadowgate II/Shadow Filter"); } @@ -133,7 +136,7 @@ bool ScriptEngine::loadScript(EngineFrame * frame, uint32 scriptID) { } bool ScriptEngine::resumeFunc(EngineFrame * frame) { - bool fail = runFunc(); + bool fail = runFunc(frame); if (fail) return fail; frame->scripts.remove_at(0); if (frame->scripts.size()) @@ -141,11 +144,986 @@ bool ScriptEngine::resumeFunc(EngineFrame * frame) { return false; } -bool ScriptEngine::runFunc() { +bool ScriptEngine::runFunc(EngineFrame *frame) { debug(7, "SCRIPT: I'm running the function"); + ScriptAsset &script = frame->scripts.front(); + EngineState *state = &frame->state; + byte op; + while (script.hasNext()) { + op = script.fetch(); + if (!(op & 0x80)) { + state->push(op); + } else { + switch (op) { + case 0x80: //get attribute + op80GATT(state, frame); + break; + case 0x81: //set attribute + op81SATT(state, frame); + break; + case 0x82: //sum children attribute + op82SUCH(state, frame); + break; + case 0x83: //push selected control + op83PUCT(state, frame); + break; + case 0x84: //push selected object + op84PUOB(state, frame); + break; + case 0x85: //push target + op85PUTA(state, frame); + break; + case 0x86: //push deltax + op86PUDX(state, frame); + break; + case 0x87: //push deltay + op87PUDY(state, frame); + break; + case 0x88: //push immediate.b + op88PUIB(state, frame, &script); + break; + case 0x89: //push immediate + op89PUI(state, frame, &script); + break; + case 0x8a: //get global + op8aGGLO(state, frame); + break; + case 0x8b: //set global + op8bSGLO(state, frame); + break; + case 0x8c: //random + op8cRAND(state, frame); + break; + case 0x8d: //copy + op8dCOPY(state, frame); + break; + case 0x8e: //copyn + op8eCOPYN(state, frame); + break; + case 0x8f: //swap + op8fSWAP(state, frame); + break; + case 0x90: //swapn + op90SWAPN(state, frame); + break; + case 0x91: //pop + op91POP(state, frame); + break; + case 0x92: //copy+1 + op92COPYP(state, frame); + break; + case 0x93: //copy+n + op93COPYPN(state, frame); + break; + case 0x94: //shuffle + op94SHUFF(state, frame); + break; + case 0x95: //sort + op95SORT(state, frame); + break; + case 0x96: //clear stack + op96CLEAR(state, frame); + break; + case 0x97: //get stack size + op97SIZE(state, frame); + break; + case 0x98: //add + op98ADD(state, frame); + break; + case 0x99: //subtract + op99SUB(state, frame); + break; + case 0x9a: //multiply + op9aMUL(state, frame); + break; + case 0x9b: //divide + op9bDIV(state, frame); + break; + case 0x9c: //mod + op9cMOD(state, frame); + break; + case 0x9d: //divmod + op9dDMOD(state, frame); + break; + case 0x9e: //abs + op9eABS(state, frame); + break; + case 0x9f: //neg + op9fNEG(state, frame); + break; + case 0xa0: //and + opa0AND(state, frame); + break; + case 0xa1: //or + opa1OR(state, frame); + break; + case 0xa2: //xor + opa2XOR(state, frame); + break; + case 0xa3: //not + opa3NOT(state, frame); + break; + case 0xa4: //logical and + opa4LAND(state, frame); + break; + case 0xa5: //logical or + opa5LOR(state, frame); + break; + case 0xa6: //logical xor + opa6LXOR(state, frame); + break; + case 0xa7: //logical not + opa7LNOT(state, frame); + break; + case 0xa8: //gt? unsigned + opa8GTU(state, frame); + break; + case 0xa9: //lt? unsigned + opa9LTU(state, frame); + break; + case 0xaa: //gt? signed + opaaGTS(state, frame); + break; + case 0xab: //lt? signed + opabLTS(state, frame); + break; + case 0xac: //eq? + opacEQ(state, frame); + break; + case 0xad: //eq string? + opadEQS(state, frame); + break; + case 0xae: //contains + opaeCONT(state, frame); + break; + case 0xaf: //contains word + opafCONTW(state, frame); + break; + case 0xb0: //bra + opb0BRA(state, frame, &script); + break; + case 0xb1: //bra.b + opb1BRAB(state, frame, &script); + break; + case 0xb2: //beq + opb2BEQ(state, frame, &script); + break; + case 0xb3: //beq.b + opb3BEQB(state, frame, &script); + break; + case 0xb4: //bne + opb4BNE(state, frame, &script); + break; + case 0xb5: //bne.b + opb5BNEB(state, frame, &script); + break; + case 0xb6: //call later + opb6CLAT(state, frame); + break; + case 0xb7: //cancel call + opb7CCA(state, frame); + break; + case 0xb8: //cancel low priority + opb8CLOW(state, frame); + break; + case 0xb9: //cancel high priority + opb9CHI(state, frame); + break; + case 0xba: //cancel priority range + opbaCRAN(state, frame); + break; + case 0xbb: //fork + opbbFORK(state, frame); + break; + case 0xbc: //call + opbcCALL(state, frame, &script); + break; + case 0xbd: //focus object + opbdFOOB(state, frame); + break; + case 0xbe: //swap objects + opbeSWOB(state, frame); + break; + case 0xbf: //snap object + opbfSNOB(state, frame); + break; + case 0xc0: //toggle exits + opc0TEXI(state, frame); + break; + case 0xc1: //print text + opc1PTXT(state, frame); + break; + case 0xc2: //print newline + opc2PNEW(state, frame); + break; + case 0xc3: //print text+nl + opc3PTNE(state, frame); + break; + case 0xc4: //print nl+text+nl + opc4PNTN(state, frame); + break; + case 0xc5: //print number + opc5PNUM(state, frame); + break; + case 0xc6: //push 2 + opc6P2(state, frame); + break; + case 0xc7: //play sound in background + opc7PLBG(state, frame); + break; + case 0xc8: //play sound and wait + opc8PLAW(state, frame); + break; + case 0xc9: //wait for sound to finish? + opc9WAIT(state, frame); + break; + case 0xca: //get current time + opcaTIME(state, frame); + break; + case 0xcb: //get current day + opcbDAY(state, frame); + break; + case 0xcc: //get children + opccCHLD(state, frame); + break; + case 0xcd: //get num children + opcdNCHLD(state, frame); + break; + case 0xce: //get engine version + opceVERS(state, frame); + break; + case 0xcf: //push scenario number + opcfPSCE(state, frame); + break; + case 0xd0: //push 1 + opd0P1(state, frame); + break; + case 0xd1: //get object dimensions + opd1GOBD(state, frame); + break; + case 0xd2: //get overlap percent + opd2GOVP(state, frame); + break; + case 0xd3: //capture children + opd3CAPC(state, frame); + break; + case 0xd4: //release children + opd4RELC(state, frame); + break; + case 0xd5: //show speech dialog + opd5DLOG(state, frame); + return true; + case 0xd6: //activate command + opd6ACMD(state, frame); + break; + case 0xd7: //lose game + opd7LOSE(state, frame); + break; + case 0xd8: //win game + opd8WIN(state, frame); + break; + case 0xd9: //sleep + opd9SLEEP(state, frame); + return true; + case 0xda: //click to continue + opdaCLICK(state, frame); + return true; + case 0xdb: //run queue + opdbROBQ(state, frame); + break; + case 0xdc: //run sound queue + opdcRSQ(state, frame); + break; + case 0xdd: //run text queue + opddRTQ(state, frame); + break; + case 0xde: //update screen + opdeUPSC(state, frame); + break; + case 0xdf: //flash main window + opdfFMAI(state, frame); + return true; + case 0xe0: //cache graphic and object + ope0CHGR(state, frame); + break; + case 0xe1: //cache sound + ope1CHSO(state, frame); + break; + case 0xe2: //muldiv + ope2MDIV(state, frame); + break; + case 0xe3: //update object + ope3UPOB(state, frame); + break; + case 0xe4: //currently playing event? + ope4PLEV(state, frame); + break; + case 0xe5: //wait for event to finish + ope5WEV(state, frame); + break; + case 0xe6: //get fibonacci (joke) + ope6GFIB(state, frame); + break; + case 0xe7: //calc fibonacci + ope7CFIB(state, frame); + break; + default: + op00NOOP(op); + } + } + } return false; } +word ScriptEngine::neg16(word val) { + if (val & 0x8000) + val = -((val ^ 0xFFFF) + 1); + return val; +} + +word ScriptEngine::neg8(word val) { + if (val & 0x80) + val = -((val ^ 0xff) + 1); + return val; +} + +word ScriptEngine::sumChildrenAttr(word obj, word attr, bool recursive) { + word sum = 0; + Common::Array children = _world->getChildren(obj, recursive); + for (Common::Array::const_iterator it = children.begin(); it != children.end(); it++) { + sum += _world->getObjAttr(*it, attr); + } + return sum; +} + +void MacVenture::ScriptEngine::op80GATT(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + word attr = state->pop(); + state->push(_world->getObjAttr(obj, attr)); +} + +void ScriptEngine::op81SATT(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + word attr = state->pop(); + word val = neg16(state->pop()); + _world->setObjAttr(obj, attr, val); +} + +void ScriptEngine::op82SUCH(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + word attr = state->pop(); + word recursive = neg16(state->pop()); + state->push(sumChildrenAttr(obj, attr, recursive)); +} + +void ScriptEngine::op83PUCT(EngineState * state, EngineFrame * frame) { + state->push(frame->action); +} + +void ScriptEngine::op84PUOB(EngineState * state, EngineFrame * frame) { + state->push(frame->src); +} + +void ScriptEngine::op85PUTA(EngineState * state, EngineFrame * frame) { + state->push(frame->dest); +} + +void ScriptEngine::op86PUDX(EngineState * state, EngineFrame * frame) { + state->push(frame->x); +} + +void ScriptEngine::op87PUDY(EngineState * state, EngineFrame * frame) { + state->push(frame->y); +} + +void ScriptEngine::op88PUIB(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + state->push(asset->fetch()); +} + +void ScriptEngine::op89PUI(EngineState * state, EngineFrame * frame, ScriptAsset * asset) { + word val = asset->fetch(); + val <<= 8; + val = val | asset->fetch(); + state->push(val); +} + +void ScriptEngine::op8aGGLO(EngineState * state, EngineFrame * frame) { + word idx = state->pop(); + state->push(_world->getGlobal(idx)); +} + +void ScriptEngine::op8bSGLO(EngineState * state, EngineFrame * frame) { + word idx = state->pop(); + word val = neg16(state->pop()); + _world->setGlobal(idx, val); + _engine->gameChanged(); +} + +void ScriptEngine::op8cRAND(EngineState * state, EngineFrame * frame) { + word max = state->pop(); + state->push(_engine->randBetween(0, max)); +} + +void ScriptEngine::op8dCOPY(EngineState * state, EngineFrame * frame) { + word val = state->pop(); + state->push(val); + state->push(val); +} + +void ScriptEngine::op8eCOPYN(EngineState * state, EngineFrame * frame) { + word n = state->pop(); + word offs = n - 1; + word val; + while (n) { + val = state->peek(offs); + state->push(val); + } +} + +void ScriptEngine::op8fSWAP(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(b); + state->push(a); +} + +void ScriptEngine::op90SWAPN(EngineState * state, EngineFrame * frame) { + word idx = state->pop(); + word a = state->peek(idx); + word b = state->peek(0); + state->poke(idx, b); + state->poke(0, a); +} + +void ScriptEngine::op91POP(EngineState * state, EngineFrame * frame) { + state->pop(); +} + +void ScriptEngine::op92COPYP(EngineState * state, EngineFrame * frame) { + word val = state->peek(1); + state->push(val); +} + +void ScriptEngine::op93COPYPN(EngineState * state, EngineFrame * frame) { + word idx = state->pop(); + word val = state->peek(idx); + state->push(val); +} + +void ScriptEngine::op94SHUFF(EngineState * state, EngineFrame * frame) { + word a = state->pop(); + word b = state->pop(); + word c = state->pop(); + state->push(a); + state->push(c); + state->push(b); +} + +void ScriptEngine::op95SORT(EngineState * state, EngineFrame * frame) { + word step = neg16(state->pop()); + word num = neg16(state->pop()); + step %= num; + if (step<0) step += num; + word end = 0; + word start = 0; + for (word i = 1;i= num) start -= num; + if (start == end) + { + end++; + start = end; + } + else + { + word a = state->peek(end); + word b = state->peek(start); + state->poke(end, b); + state->poke(start, a); + } + } +} + +void ScriptEngine::op96CLEAR(EngineState * state, EngineFrame * frame) { + state->clear(); +} + +void ScriptEngine::op97SIZE(EngineState * state, EngineFrame * frame) { + state->push(state->size()); +} + +void ScriptEngine::op98ADD(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a + b); +} + +void ScriptEngine::op99SUB(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a - b); +} + +void ScriptEngine::op9aMUL(EngineState * state, EngineFrame * frame) { + int16 b = state->pop(); + int16 a = state->pop(); + state->push(a * b); +} + +void ScriptEngine::op9bDIV(EngineState * state, EngineFrame * frame) { + int16 b = state->pop(); + int16 a = state->pop(); + state->push((a / b) | 0); +} + +void ScriptEngine::op9cMOD(EngineState * state, EngineFrame * frame) { + int16 b = state->pop(); + int16 a = state->pop(); + state->push(a % b); +} + +void ScriptEngine::op9dDMOD(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a % b); + state->push((a / b) | 0); +} + +void ScriptEngine::op9eABS(EngineState * state, EngineFrame * frame) { + word val = neg16(state->pop()); + if (val<0) val = -val; + state->push(val); +} + +void ScriptEngine::op9fNEG(EngineState * state, EngineFrame * frame) { + word val = -neg16(state->pop()); + state->push(val); +} + +void ScriptEngine::opa0AND(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a & b); +} + +void ScriptEngine::opa1OR(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a | b); +} + +void ScriptEngine::opa2XOR(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(a ^ b); +} + +void ScriptEngine::opa3NOT(EngineState * state, EngineFrame * frame) { + word a = state->pop(); + state->push(a ^ 0xFFFF); +} + +void ScriptEngine::opa4LAND(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push((a && b) ? 0xFFFF : 0); +} + +void ScriptEngine::opa5LOR(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push((a || b) ? 0xFFFF : 0); +} + +void ScriptEngine::opa6LXOR(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push((!a != !b) ? 0xFFFF : 0); +} + +void ScriptEngine::opa7LNOT(EngineState * state, EngineFrame * frame) { + word a = state->pop(); + state->push((a == 0) ? 0xFFFF : 0); +} + +void ScriptEngine::opa8GTU(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push((a > b) ? 0xFFFF : 0); +} + +void ScriptEngine::opa9LTU(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push((a < b) ? 0xFFFF : 0); +} + +void ScriptEngine::opaaGTS(EngineState * state, EngineFrame * frame) { + word b = neg16(state->pop()); + word a = neg16(state->pop()); + state->push((a > b) ? 0xFFFF : 0); +} + +void ScriptEngine::opabLTS(EngineState * state, EngineFrame * frame) { + word b = neg16(state->pop()); + word a = neg16(state->pop()); + state->push((a < b) ? 0xFFFF : 0); +} + +void ScriptEngine::opacEQ(EngineState * state, EngineFrame * frame) { + word b = neg16(state->pop()); + word a = neg16(state->pop()); + state->push((a == b) ? 0xFFFF : 0); +} + +void ScriptEngine::opadEQS(EngineState * state, EngineFrame * frame) { + Common::String b = _world->getText(state->pop()); + Common::String a = _world->getText(state->pop()); + state->push((a == b) ? 1 : 0); +} + +void ScriptEngine::opaeCONT(EngineState * state, EngineFrame * frame) { + Common::String needle = _world->getText(state->pop()); + Common::String haystack = _world->getText(state->pop()); + haystack.toLowercase(); + state->push(haystack.contains(needle) ? 1 : 0); +} + +void ScriptEngine::opafCONTW(EngineState * state, EngineFrame * frame) { + Common::String needle = _world->getText(state->pop()); + Common::String haystack = _world->getText(state->pop()); + haystack.toLowercase(); + state->push(haystack.contains(needle) ? 1 : 0); +} + +void ScriptEngine::opb0BRA(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val <<= 8; + val = val | asset->fetch(); + val = neg16(val); + asset->branch(val); +} + +void ScriptEngine::opb1BRAB(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val = neg8(val); + asset->branch(val); +} + +void ScriptEngine::opb2BEQ(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val <<= 8; + val = val | asset->fetch(); + val = neg16(val); + word b = state->pop(); + if (b != 0) asset->branch(val); +} + +void ScriptEngine::opb3BEQB(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val = neg8(val); + word b = state->pop(); + if (b != 0) asset->branch(val); +} + +void ScriptEngine::opb4BNE(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val <<= 8; + val = val | asset->fetch(); + val = neg16(val); + word b = state->pop(); + if (b == 0) asset->branch(val); +} + +void ScriptEngine::opb5BNEB(EngineState * state, EngineFrame * frame, ScriptAsset *asset) { + word val = asset->fetch(); + val = neg8(val); + word b = state->pop(); + if (b == 0) asset->branch(val); +} + +void ScriptEngine::opb6CLAT(EngineState * state, EngineFrame * frame) { + word rank = state->pop(); + word func = state->pop(); + frame->saves.push_back(FunCall(rank, func)); +} + +void ScriptEngine::opb7CCA(EngineState * state, EngineFrame * frame) { + word func = state->pop(); + for (int i = 0; i < frame->saves.size(); i++) { + if (frame->saves[i].func == func) + frame->saves[i].rank = 0; + } +} + +void ScriptEngine::opb8CLOW(EngineState * state, EngineFrame * frame) { + word hi = state->pop(); + for (int i = 0;isaves.size();i++) + if (frame->saves[i].rank <= hi) + frame->saves[i].rank = 0; +} + +void ScriptEngine::opb9CHI(EngineState * state, EngineFrame * frame) { + word lo = state->pop(); + for (int i = 0;isaves.size();i++) + if (frame->saves[i].rank >= lo) + frame->saves[i].rank = 0; +} + +void ScriptEngine::opbaCRAN(EngineState * state, EngineFrame * frame) { + word hi = state->pop(); + word lo = state->pop(); + for (int i = 0;isaves.size();i++) + if (frame->saves[i].rank >= lo && + frame->saves[i].rank <= hi) + frame->saves[i].rank = 0; +} + +void ScriptEngine::opbbFORK(EngineState * state, EngineFrame * frame) { + EngineFrame newframe; + newframe.action = (ControlAction)state->pop(); + newframe.src = state->pop(); + newframe.dest = state->pop(); + newframe.x = state->pop(); + newframe.y = state->pop(); + _frames.push_back(newframe); +} + +void ScriptEngine::opbcCALL(EngineState * state, EngineFrame * frame, ScriptAsset *script) { + word id = state->pop(); + ScriptAsset newfun = ScriptAsset(id, _scripts); + frame->scripts.remove_at(0); + frame->scripts.insert_at(0, newfun); + script = &frame->scripts.front(); +} + +void ScriptEngine::opbdFOOB(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + _engine->enqueueObject(obj); +} + +void ScriptEngine::opbeSWOB(EngineState * state, EngineFrame * frame) { + op00NOOP(0xbe); +} + +void ScriptEngine::opbfSNOB(EngineState * state, EngineFrame * frame) { + op00NOOP(0xbf); +} + +void ScriptEngine::opc0TEXI(EngineState * state, EngineFrame * frame) { + op00NOOP(0xc0); +} + +void ScriptEngine::opc1PTXT(EngineState * state, EngineFrame * frame) { + word tid = state->pop(); + _engine->enqueueText(kTextPlain, frame->dest, frame->src, tid); +} + +void ScriptEngine::opc2PNEW(EngineState * state, EngineFrame * frame) { + _engine->enqueueText(kTextNewLine, frame->dest, frame->src, 0); +} + +void ScriptEngine::opc3PTNE(EngineState * state, EngineFrame * frame) { + word tid = state->pop(); + _engine->enqueueText(kTextPlain, frame->dest, frame->src, tid); + _engine->enqueueText(kTextNewLine, frame->dest, frame->src, 0); +} + +void ScriptEngine::opc4PNTN(EngineState * state, EngineFrame * frame) { + word tid = state->pop(); + _engine->enqueueText(kTextNewLine, frame->dest, frame->src, 0); + _engine->enqueueText(kTextPlain, frame->dest, frame->src, tid); + _engine->enqueueText(kTextNewLine, frame->dest, frame->src, 0); +} + +void ScriptEngine::opc5PNUM(EngineState * state, EngineFrame * frame) { + word tid = state->pop(); + _engine->enqueueText(kTextNumber, frame->dest, frame->src, tid); +} + +void ScriptEngine::opc6P2(EngineState * state, EngineFrame * frame) { + state->push(2); +} + +void ScriptEngine::opc7PLBG(EngineState * state, EngineFrame * frame) { + state->pop(); + op00NOOP(0xc7); +} + +void ScriptEngine::opc8PLAW(EngineState * state, EngineFrame * frame) { + state->pop(); + op00NOOP(0xc8); +} + +void ScriptEngine::opc9WAIT(EngineState * state, EngineFrame * frame) { + op00NOOP(0xc9); +} + +void ScriptEngine::opcaTIME(EngineState * state, EngineFrame * frame) { + for (int i = 0; i < 6; i++) // Dummy + state->push(0x00); + op00NOOP(0xca); +} + +void ScriptEngine::opcbDAY(EngineState * state, EngineFrame * frame) { + state->push(9); +} + +void ScriptEngine::opccCHLD(EngineState * state, EngineFrame * frame) { + bool recursive = state->pop() != 0; + word obj = state->pop(); + Common::Array children = _world->getChildren(obj, recursive); + for (Common::Array::const_iterator it = children.begin(); it != children.end(); it++) { + state->push(*it); + } + state->push(children.size()); +} + +void ScriptEngine::opcdNCHLD(EngineState * state, EngineFrame * frame) { + bool recursive = state->pop() != 0; + word obj = state->pop(); + Common::Array children = _world->getChildren(obj, recursive); + state->push(children.size()); +} + +void ScriptEngine::opceVERS(EngineState * state, EngineFrame * frame) { + state->push(86); +} + +void ScriptEngine::opcfPSCE(EngineState * state, EngineFrame * frame) { + state->push(0); //Not release +} + +void ScriptEngine::opd0P1(EngineState * state, EngineFrame * frame) { + state->push(1); +} + +void ScriptEngine::opd1GOBD(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + Common::Rect bounds(0, 0, 1, 1); //= _world->getObjBounds(obj); + state->push(bounds.width()); + state->push(bounds.height()); +} + +void ScriptEngine::opd2GOVP(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + state->push(0);//_world->getOverlapPercent(b, a)); +} + +void ScriptEngine::opd3CAPC(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + _world->captureChildren(obj); +} + +void ScriptEngine::opd4RELC(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + _world->releaseChildren(obj); +} + +void ScriptEngine::opd5DLOG(EngineState * state, EngineFrame * frame) { + word txt = state->pop(); + op00NOOP(0xd5); +} + +void ScriptEngine::opd6ACMD(EngineState * state, EngineFrame * frame) { + _engine->activateCommand((ControlReference)state->pop()); +} + +void ScriptEngine::opd7LOSE(EngineState * state, EngineFrame * frame) { + _engine->loseGame(); +} + +void ScriptEngine::opd8WIN(EngineState * state, EngineFrame * frame) { + _engine->winGame(); +} + +void ScriptEngine::opd9SLEEP(EngineState * state, EngineFrame * frame) { + word ticks = state->pop(); + g_system->delayMillis((ticks / 60) * 1000); + _engine->preparedToRun(); +} + +void ScriptEngine::opdaCLICK(EngineState * state, EngineFrame * frame) { + //_engine->updateScreen(false); + //clickToContinue(); + op00NOOP(0xda); +} + +void ScriptEngine::opdbROBQ(EngineState * state, EngineFrame * frame) { + _engine->runObjQueue(); +} + +void ScriptEngine::opdcRSQ(EngineState * state, EngineFrame * frame) { + op00NOOP(0xdc); +} + +void ScriptEngine::opddRTQ(EngineState * state, EngineFrame * frame) { + _engine->printTexts(); +} + +void ScriptEngine::opdeUPSC(EngineState * state, EngineFrame * frame) { + //_engine->updateScreen(false); + op00NOOP(0xde); +} + +void ScriptEngine::opdfFMAI(EngineState * state, EngineFrame * frame) { + word ticks = state->pop(); + g_system->delayMillis((ticks / 60) * 1000); + _engine->revert(); +} + +void ScriptEngine::ope0CHGR(EngineState * state, EngineFrame * frame) { + word txt = state->pop(); + op00NOOP(0xe0); +} + +void ScriptEngine::ope1CHSO(EngineState * state, EngineFrame * frame) { + word txt = state->pop(); + op00NOOP(0xe1); +} + +void ScriptEngine::ope2MDIV(EngineState * state, EngineFrame * frame) { + word b = state->pop(); + word a = state->pop(); + a *= b; + word c = state->pop(); + a /= c; + state->push(a | 0); +} + +void ScriptEngine::ope3UPOB(EngineState * state, EngineFrame * frame) { + word obj = state->pop(); + _world->updateObj(obj); +} + +void ScriptEngine::ope4PLEV(EngineState * state, EngineFrame * frame) { + state->push(0); + op00NOOP(0xe4); +} + +void ScriptEngine::ope5WEV(EngineState * state, EngineFrame * frame) { + op00NOOP(0xe5); +} + +void ScriptEngine::ope6GFIB(EngineState * state, EngineFrame * frame) { + state->push(0); + op00NOOP(0xe6); +} + +void ScriptEngine::ope7CFIB(EngineState * state, EngineFrame * frame) { + state->pop(); + op00NOOP(0xe7); +} + +void ScriptEngine::op00NOOP(byte op) { + debug("SCRIPT: Opcode not implemented => %x", op); +} + + + + ScriptAsset::ScriptAsset(ObjID id, Container * container) { _id = id; _container = container; @@ -156,12 +1134,20 @@ void ScriptAsset::reset() { _ip = 0x0; } -uint8 ScriptAsset::fecth() { +uint8 ScriptAsset::fetch() { uint8 ins = _instructions[_ip]; _ip++; return ins; } +bool ScriptAsset::hasNext() { + return _ip < _instructions.size(); +} + +void ScriptAsset::branch(word amount) { + _ip += amount; +} + void ScriptAsset::loadInstructions() { uint32 amount = _container->getItemByteSize(_id); Common::SeekableReadStream *res = _container->getItem(_id); diff --git a/engines/macventure/script.h b/engines/macventure/script.h index d66a867eca..e56c6e7440 100644 --- a/engines/macventure/script.h +++ b/engines/macventure/script.h @@ -51,6 +51,7 @@ enum ControlAction { }; typedef uint32 ObjID; +typedef int16 word; class ScriptAsset { public: @@ -58,7 +59,9 @@ public: ~ScriptAsset() {} void reset(); - uint8 fecth(); + uint8 fetch(); + bool hasNext(); + void branch(word amount); private: @@ -72,13 +75,61 @@ private: uint32 _ip; // Instruction pointer }; -struct EngineState { - uint8 stack[0x80]; - uint8 sp; - +class EngineState { +public: EngineState() { + clear(); + } + + void push(word data) { + stack[sp] = unneg16(data); + sp--; + } + + word pop() { + byte v = stack[sp]; + sp++; + return v; + } + + word peek(word off) { + return stack[sp + off]; + } + + void poke(word off, word val) { + stack[sp + off] = unneg16(val); + } + + void clear() { sp = 0x80; } + + word size() { + return 0x80 - sp; + } + +private: + word unneg16(word data) { + if (data < 0) + data = ((-data) ^ 0xFFFF) + 1; + + return data; + } + +private: + + word stack[0x80]; + word sp; +}; + +struct FunCall { + word func; + word rank; + + FunCall(word f, word r) { + func = f; + rank = r; + } }; struct EngineFrame { @@ -89,6 +140,7 @@ struct EngineFrame { int y; EngineState state; Common::Array scripts; + Common::Array saves; uint32 familyIdx; bool haltedInFirst; @@ -98,7 +150,7 @@ struct EngineFrame { class ScriptEngine { public: - ScriptEngine(World *world); + ScriptEngine(MacVentureEngine *engine, World *world); ~ScriptEngine(); public: @@ -110,9 +162,131 @@ private: bool execFrame(bool execAll); bool loadScript(EngineFrame * frame, uint32 scriptID); bool resumeFunc(EngineFrame * frame); - bool runFunc(); + bool runFunc(EngineFrame * frame); + +private: + + // Aux + word neg16(word val); + word neg8(word val); + word sumChildrenAttr(word obj, word attr, bool recursive); + + // Opcodes + void op80GATT(EngineState *state, EngineFrame *frame); //get attribute + void op81SATT(EngineState *state, EngineFrame *frame); //set attribute + void op82SUCH(EngineState *state, EngineFrame *frame); //sum children attribute + void op83PUCT(EngineState *state, EngineFrame *frame); //push selected control + void op84PUOB(EngineState *state, EngineFrame *frame); //push selected object + void op85PUTA(EngineState *state, EngineFrame *frame); //push target + void op86PUDX(EngineState *state, EngineFrame *frame); //push deltax + void op87PUDY(EngineState *state, EngineFrame *frame); //push deltay + void op88PUIB(EngineState *state, EngineFrame *frame, ScriptAsset *asset);//push immediate.b + void op89PUI(EngineState *state, EngineFrame *frame, ScriptAsset *asset);//push immediate + void op8aGGLO(EngineState *state, EngineFrame *frame); //get global + void op8bSGLO(EngineState *state, EngineFrame *frame); //set global + void op8cRAND(EngineState *state, EngineFrame *frame); //random + void op8dCOPY(EngineState *state, EngineFrame *frame); //copy + void op8eCOPYN(EngineState *state, EngineFrame *frame); //copyn + void op8fSWAP(EngineState *state, EngineFrame *frame); //swap + + void op90SWAPN(EngineState *state, EngineFrame *frame); //swapn + void op91POP(EngineState *state, EngineFrame *frame); //pop + void op92COPYP(EngineState *state, EngineFrame *frame); //copy+1 + void op93COPYPN(EngineState *state, EngineFrame *frame);//copy+n + void op94SHUFF(EngineState *state, EngineFrame *frame); //shuffle + void op95SORT(EngineState *state, EngineFrame *frame); //sort + void op96CLEAR(EngineState *state, EngineFrame *frame); //clear stack + void op97SIZE(EngineState *state, EngineFrame *frame); //get stack size + void op98ADD(EngineState *state, EngineFrame *frame); //add + void op99SUB(EngineState *state, EngineFrame *frame); //subtract + void op9aMUL(EngineState *state, EngineFrame *frame); //multiply + void op9bDIV(EngineState *state, EngineFrame *frame); //divide + void op9cMOD(EngineState *state, EngineFrame *frame); //mod + void op9dDMOD(EngineState *state, EngineFrame *frame); //divmod + void op9eABS(EngineState *state, EngineFrame *frame); //abs + void op9fNEG(EngineState *state, EngineFrame *frame); //neg + + void opa0AND(EngineState *state, EngineFrame *frame); //and + void opa1OR(EngineState *state, EngineFrame *frame); //or + void opa2XOR(EngineState *state, EngineFrame *frame); //xor + void opa3NOT(EngineState *state, EngineFrame *frame); //not + void opa4LAND(EngineState *state, EngineFrame *frame); //logical and + void opa5LOR(EngineState *state, EngineFrame *frame); //logical or + void opa6LXOR(EngineState *state, EngineFrame *frame); //logical xor + void opa7LNOT(EngineState *state, EngineFrame *frame); //logical not + void opa8GTU(EngineState *state, EngineFrame *frame); //gt? unsigned + void opa9LTU(EngineState *state, EngineFrame *frame); //lt? unsigned + void opaaGTS(EngineState *state, EngineFrame *frame); //gt? signed + void opabLTS(EngineState *state, EngineFrame *frame); //lt? signed + void opacEQ(EngineState *state, EngineFrame *frame); //eq? + void opadEQS(EngineState *state, EngineFrame *frame); //eq string? + void opaeCONT(EngineState *state, EngineFrame *frame); //contains + void opafCONTW(EngineState *state, EngineFrame *frame); //contains word + + void opb0BRA(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //bra + void opb1BRAB(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //bra.b + void opb2BEQ(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //beq + void opb3BEQB(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //beq.b + void opb4BNE(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //bne + void opb5BNEB(EngineState *state, EngineFrame *frame, ScriptAsset *asset); //bne.b + void opb6CLAT(EngineState *state, EngineFrame *frame); //call later + void opb7CCA(EngineState *state, EngineFrame *frame); //cancel call + void opb8CLOW(EngineState *state, EngineFrame *frame); //cancel low priority + void opb9CHI(EngineState *state, EngineFrame *frame); //cancel high priority + void opbaCRAN(EngineState *state, EngineFrame *frame); //cancel priority range + void opbbFORK(EngineState *state, EngineFrame *frame); //fork + void opbcCALL(EngineState *state, EngineFrame *frame, ScriptAsset *script); //call + void opbdFOOB(EngineState *state, EngineFrame *frame); //focus object + void opbeSWOB(EngineState *state, EngineFrame *frame); //swap objects + void opbfSNOB(EngineState *state, EngineFrame *frame); //snap object + + void opc0TEXI(EngineState *state, EngineFrame *frame); //toggle exits + void opc1PTXT(EngineState *state, EngineFrame *frame); //print text + void opc2PNEW(EngineState *state, EngineFrame *frame); //print newline + void opc3PTNE(EngineState *state, EngineFrame *frame); //print text+nl + void opc4PNTN(EngineState *state, EngineFrame *frame); //print nl+text+nl + void opc5PNUM(EngineState *state, EngineFrame *frame); //print number + void opc6P2(EngineState *state, EngineFrame *frame); //push 2 + void opc7PLBG(EngineState *state, EngineFrame *frame); //play sound in background + void opc8PLAW(EngineState *state, EngineFrame *frame); //play sound and wait + void opc9WAIT(EngineState *state, EngineFrame *frame); //wait for sound to finish? + void opcaTIME(EngineState *state, EngineFrame *frame); //get current time + void opcbDAY(EngineState *state, EngineFrame *frame); //get current day + void opccCHLD(EngineState *state, EngineFrame *frame); //get children + void opcdNCHLD(EngineState *state, EngineFrame *frame); //get num children + void opceVERS(EngineState *state, EngineFrame *frame); //get engine version + void opcfPSCE(EngineState *state, EngineFrame *frame); //push scenario number + + void opd0P1(EngineState *state, EngineFrame *frame); //push 1 + void opd1GOBD(EngineState *state, EngineFrame *frame); //get object dimensions + void opd2GOVP(EngineState *state, EngineFrame *frame); //get overlap percent + void opd3CAPC(EngineState *state, EngineFrame *frame); //capture children + void opd4RELC(EngineState *state, EngineFrame *frame); //release children + void opd5DLOG(EngineState *state, EngineFrame *frame); //show speech dialog + void opd6ACMD(EngineState *state, EngineFrame *frame); //activate command + void opd7LOSE(EngineState *state, EngineFrame *frame); //lose game + void opd8WIN(EngineState *state, EngineFrame *frame); //win game + void opd9SLEEP(EngineState *state, EngineFrame *frame); //sleep + void opdaCLICK(EngineState *state, EngineFrame *frame); //click to continue + void opdbROBQ(EngineState *state, EngineFrame *frame); //run queue + void opdcRSQ(EngineState *state, EngineFrame *frame); //run sound queue + void opddRTQ(EngineState *state, EngineFrame *frame); //run text queue + void opdeUPSC(EngineState *state, EngineFrame *frame); //update screen + void opdfFMAI(EngineState *state, EngineFrame *frame); //flash main window + + void ope0CHGR(EngineState *state, EngineFrame *frame); //cache graphic and object + void ope1CHSO(EngineState *state, EngineFrame *frame); //cache sound + void ope2MDIV(EngineState *state, EngineFrame *frame); //muldiv + void ope3UPOB(EngineState *state, EngineFrame *frame); //update object + void ope4PLEV(EngineState *state, EngineFrame *frame); //currently playing event? + void ope5WEV(EngineState *state, EngineFrame *frame); //wait for event to finish + void ope6GFIB(EngineState *state, EngineFrame *frame); //get fibonacci (joke) + void ope7CFIB(EngineState *state, EngineFrame *frame); //calc fibonacci + + void op00NOOP(byte op); private: + MacVentureEngine *_engine; World *_world; Common::Array _frames; Container *_scripts; diff --git a/engines/macventure/world.cpp b/engines/macventure/world.cpp index 2cd50ff82a..2f603c5ddc 100644 --- a/engines/macventure/world.cpp +++ b/engines/macventure/world.cpp @@ -102,6 +102,56 @@ Common::Array World::getChildren(ObjID objID, bool recursive) { return Common::Array(); } +WindowReference World::getObjWindow(ObjID objID) { + switch (objID) { + case 0xfffc: return kExitsWindow; + case 0xfffd: return kSelfWindow; + case 0xfffe: return kOutConsoleWindow; + case 0xffff: return kCommandsWindow; + } + + return findObjWindow(objID); +} + +WindowReference World::findObjWindow(ObjID objID) { + return kMainGameWindow; +} + +Attribute World::getGlobal(uint32 attrID) { + return _saveGame->getGlobals()[attrID]; +} + +void World::setGlobal(uint32 attrID, Attribute value) { + _saveGame->setGlobal(attrID, value); +} + +void World::updateObj(ObjID objID) { + WindowReference win; + if (getObjAttr(1, kAttrParentObject) == objID) { + win = kMainGameWindow; + } else { + win = getObjWindow(objID); + } + if (win) { + //focusObjWin(objID); + _engine->runObjQueue(); + //_engine->updateWindow(win); + } +} + +void World::captureChildren(ObjID objID) { +} + +void World::releaseChildren(ObjID objID) { +} + +Common::String World::getText(ObjID objID) { + TextAsset text = TextAsset(objID, _gameText, _engine->isOldText(), _engine->getDecodingHuffman()); + + return *text.decode(); +} + + bool World::loadStartGameFileName() { Common::SeekableReadStream *res; @@ -186,6 +236,10 @@ const AttributeGroup * SaveGame::getGroup(uint32 groupID) { return &(_groups[groupID]); } +void SaveGame::setGlobal(uint32 attrID, Attribute value) { + _globals[attrID] = value; +} + const Common::Array& MacVenture::SaveGame::getGlobals() { return _globals; } diff --git a/engines/macventure/world.h b/engines/macventure/world.h index 3893aca445..370582665b 100644 --- a/engines/macventure/world.h +++ b/engines/macventure/world.h @@ -67,9 +67,11 @@ public: Attribute getAttr(ObjID objID, uint32 attrID); void setAttr(uint32 attrID, ObjID objID, Attribute value); + void setGlobal(uint32 attrID, Attribute value); + const Common::Array &getGlobals(); + const Common::Array &getGroups(); const AttributeGroup *getGroup(uint32 groupID); - const Common::Array &getGlobals(); const Common::String &getText(); private: @@ -88,11 +90,22 @@ public: World(MacVentureEngine *engine, Common::MacResManager *resMan); ~World(); - uint32 getObjAttr(ObjID objID, uint32 attrID); + void setObjAttr(ObjID objID, uint32 attrID, Attribute value); + void setGlobal(uint32 attrID, Attribute value); + void updateObj(ObjID objID); + void captureChildren(ObjID objID); + void releaseChildren(ObjID objID); + + uint32 getObjAttr(ObjID objID, uint32 attrID); + Attribute getGlobal(uint32 attrID); + Common::String getText(ObjID objID); + bool isObjActive(ObjID obj); Common::Array getFamily(ObjID objID, bool recursive); Common::Array getChildren(ObjID objID, bool recursive); + WindowReference getObjWindow(ObjID objID); + WindowReference findObjWindow(ObjID objID); private: bool loadStartGameFileName(); -- cgit v1.2.3