From 57a9ef3a8f42a7bb71d17f6150dce1e652ce33c0 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 21 Apr 2008 20:51:17 +0000 Subject: Patch #1941066: "CinE sprite overlay rewrite" courtsey of next_ghost svn-id: r31651 --- engines/cine/anim.cpp | 1 - engines/cine/anim.h | 1 + engines/cine/bg.cpp | 6 +- engines/cine/bg_list.cpp | 6 +- engines/cine/cine.cpp | 6 +- engines/cine/gfx.cpp | 135 +- engines/cine/gfx.h | 3 +- engines/cine/main_loop.cpp | 2 - engines/cine/module.mk | 3 +- engines/cine/msg.cpp | 39 +- engines/cine/msg.h | 6 + engines/cine/object.cpp | 160 +- engines/cine/object.h | 17 +- engines/cine/script.cpp | 3787 -------------------------------------------- engines/cine/script.h | 1 + engines/cine/script_fw.cpp | 2945 ++++++++++++++++++++++++++++++++++ engines/cine/script_os.cpp | 793 ++++++++++ engines/cine/various.cpp | 531 +++---- engines/cine/various.h | 11 +- engines/cine/xref.txt | 7 + 20 files changed, 4157 insertions(+), 4303 deletions(-) delete mode 100644 engines/cine/script.cpp create mode 100644 engines/cine/script_fw.cpp create mode 100644 engines/cine/script_os.cpp (limited to 'engines') diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 312de4a6db..f17c7a92fc 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -186,7 +186,6 @@ static const AnimDataEntry transparencyData[] = { }; void convertMask(byte *dest, const byte *source, int16 width, int16 height); -void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); void convert8BBP(byte *dest, const byte *source, int16 width, int16 height); void convert8BBP2(byte *dest, byte *source, int16 width, int16 height); diff --git a/engines/cine/anim.h b/engines/cine/anim.h index c15ab2eabd..0406f3159b 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -102,6 +102,7 @@ void freeAnimDataRange(byte startIdx, byte numIdx); void loadResource(const char *animName); void loadAbs(const char *resourceName, uint16 idx); void loadResourcesFromSave(Common::InSaveFile &fHandle, bool broken); +void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); } // End of namespace Cine diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index 351a633b5e..b6c07a05cb 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -50,7 +50,7 @@ byte loadCt(const char *ctName) { uint16 bpp = READ_BE_UINT16(ptr); ptr += 2; if (bpp == 8) { ctColorMode = 1; - memcpy(newPalette, ptr, 256*3); + memcpy(newPalette, ptr, 256 * 3); ptr += 3 * 256; memcpy(page3Raw, ptr, 320 * 200); } else { @@ -134,13 +134,11 @@ void addBackground(const char *bgName, uint16 bgIdx) { additionalBgTable[bgIdx] = (byte *) malloc(320 * 200); - debug("addBackground %d", bgIdx); - uint16 bpp = READ_BE_UINT16(ptr); ptr += 2; if (bpp == 8) { bgColorMode = 1; - memcpy(newPalette, ptr, 256*3); + memcpy(newPalette, ptr, 256 * 3); ptr += 3 * 256; memcpy(additionalBgTable[bgIdx], ptr, 320 * 200); } else { diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index 7d35f9981e..a70733dc68 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -77,7 +77,7 @@ void addToBGList(int16 objIdx, bool addList) { void addSpriteFilledToBGList(int16 objIdx, bool addList) { int16 x = objectTable[objIdx].x; int16 y = objectTable[objIdx].y; - int16 width = animDataTable[objectTable[objIdx].frame]._width; + int16 width = animDataTable[objectTable[objIdx].frame]._realWidth; int16 height = animDataTable[objectTable[objIdx].frame]._height; const byte *data = animDataTable[objectTable[objIdx].frame].data(); @@ -86,11 +86,11 @@ void addSpriteFilledToBGList(int16 objIdx, bool addList) { if (g_cine->getGameType() == GType_OS) { for (int i = 0; i < 8; i++) { if (additionalBgTable[i]) { - gfxFillSprite(data, width / 2, height, additionalBgTable[i], x, y); + gfxFillSprite(data, width, height, additionalBgTable[i], x, y); } } } else { - gfxFillSprite(data, width / 2, height, page2Raw, x, y); + gfxFillSprite(data, width, height, page2Raw, x, y); } } diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index ffcbfbaa82..41dd9be16f 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -129,14 +129,12 @@ void CineEngine::initialize() { globalScripts.clear(); bgIncrustList.clear(); freeAnimDataTable(); + overlayList.clear(); + messageTable.clear(); memset(objectTable, 0, sizeof(objectTable)); - memset(messageTable, 0, sizeof(messageTable)); - - overlayHead.next = overlayHead.previous = NULL; var8 = 0; -// bgIncrustList = NULL; var2 = var3 = var4 = var5 = 0; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 8db4456485..2730a92e62 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -25,6 +25,7 @@ #include "cine/cine.h" #include "cine/bg.h" +#include "cine/bg_list.h" #include "cine/various.h" #include "common/endian.h" @@ -168,7 +169,7 @@ void gfxFillSprite(const byte *spritePtr, uint16 width, uint16 height, byte *pag byte *destPtr = page + x + y * 320; destPtr += i * 320; - for (j = 0; j < width * 8; j++) { + for (j = 0; j < width; j++) { if (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) { if (!*(spritePtr++)) { @@ -191,7 +192,7 @@ void gfxDrawMaskedSprite(const byte *spritePtr, const byte *maskPtr, uint16 widt byte *destPtr = page + x + y * 320; destPtr += i * 320; - for (j = 0; j < width * 8; j++) { + for (j = 0; j < width; j++) { if (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200 && *maskPtr == 0) { *destPtr = *spritePtr; } @@ -202,61 +203,82 @@ void gfxDrawMaskedSprite(const byte *spritePtr, const byte *maskPtr, uint16 widt } } -void gfxUpdateSpriteMask(const byte *spritePtr, const byte *spriteMskPtr, int16 width, int16 height, const byte *maskPtr, - int16 maskWidth, int16 maskHeight, byte *bufferSprPtr, byte *bufferMskPtr, int16 xs, int16 ys, int16 xm, int16 ym, byte maskIdx) { +void gfxUpdateSpriteMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *srcMask, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight) { int16 i, j, d, spritePitch, maskPitch; - width *= 8; - maskWidth *= 8; - spritePitch = width; maskPitch = maskWidth; - if (maskIdx == 0) { - memcpy(bufferSprPtr, spritePtr, spritePitch * height); - memcpy(bufferMskPtr, spriteMskPtr, spritePitch * height); - } - - if (ys > ym) { - d = ys - ym; - maskPtr += d * maskPitch; + // crop update area to overlapping parts of masks + if (y > ym) { + d = y - ym; + srcMask += d * maskPitch; maskHeight -= d; + } else if (y < ym) { + d = ym - y; + destMask += d * spritePitch; + height -= d; } - if (maskHeight <= 0) { - return; - } - if (xs > xm) { - d = xs - xm; - maskPtr += d; + + if (x > xm) { + d = x - xm; + srcMask += d; maskWidth -= d; + } else if (x < xm) { + d = xm - x; + destMask += d; + width -= d; } - if (maskWidth <= 0) { - return; + + // update mask + for (j = 0; j < MIN(maskHeight, height); ++j) { + for (i = 0; i < MIN(maskWidth, width); ++i) { + destMask[i] |= srcMask[i] ^ 1; + } + destMask += spritePitch; + srcMask += maskPitch; } - if (ys < ym) { - d = ym - ys; - spriteMskPtr += d * spritePitch; - bufferMskPtr += d * spritePitch; +} + +void gfxUpdateIncrustMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *srcMask, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight) { + int16 i, j, d, spritePitch, maskPitch; + + spritePitch = width; + maskPitch = maskWidth; + + // crop update area to overlapping parts of masks + if (y > ym) { + d = y - ym; + srcMask += d * maskPitch; + maskHeight -= d; + } else if (y < ym) { + d = ym - y > height ? height : ym - y; + memset(destMask, 1, d * spritePitch); + destMask += d * spritePitch; height -= d; } - if (height <= 0) { - return; - } - if (xs < xm) { - d = xm - xs; - spriteMskPtr += d; - bufferMskPtr += d; - width -= d; - } - if (width <= 0) { - return; + + if (x > xm) { + d = x - xm; + xm = x; + srcMask += d; + maskWidth -= d; } + + d = xm - x; + maskWidth += d; + + // update mask for (j = 0; j < MIN(maskHeight, height); ++j) { - for (i = 0; i < MIN(maskWidth, width); ++i) { - bufferMskPtr[i] |= maskPtr[i] ^ 1; + for (i = 0; i < width; ++i) { + destMask[i] |= i < d || i >= maskWidth ? 1 : srcMask[i - d]; } - bufferMskPtr += spritePitch; - maskPtr += maskPitch; + destMask += spritePitch; + srcMask += maskPitch; + } + + if (j < height) { + memset(destMask, 1, (height - j) * spritePitch); } } @@ -431,15 +453,19 @@ void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 h void maskBgOverlay(const byte *bgPtr, const byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y) { - int16 i, j; + int16 i, j, tmpWidth, tmpHeight; + Common::List::iterator it; + byte *mask; + const byte *backup = maskPtr; + // background pass for (i = 0; i < height; i++) { byte *destPtr = page + x + y * 320; const byte *srcPtr = bgPtr + x + y * 320; destPtr += i * 320; srcPtr += i * 320; - for (j = 0; j < width * 8; j++) { + for (j = 0; j < width; j++) { if ((!maskPtr || !(*maskPtr)) && (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200)) { *destPtr = *srcPtr; @@ -450,6 +476,27 @@ void maskBgOverlay(const byte *bgPtr, const byte *maskPtr, int16 width, int16 he maskPtr++; } } + + maskPtr = backup; + + // incrust pass + for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { + tmpWidth = animDataTable[it->frame]._realWidth; + tmpHeight = animDataTable[it->frame]._height; + mask = (byte*)malloc(tmpWidth * tmpHeight); + + if (it->param == 0) { + generateMask(animDataTable[it->frame].data(), mask, tmpWidth * tmpHeight, it->part); + gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height); + gfxDrawMaskedSprite(animDataTable[it->frame].data(), mask, tmpWidth, tmpHeight, page, it->x, it->y); + } else { + memcpy(mask, animDataTable[it->frame].data(), tmpWidth * tmpHeight); + gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height); + gfxFillSprite(mask, tmpWidth, tmpHeight, page, it->x, it->y); + } + + free(mask); + } } /*! \todo Fix rendering to prevent fadein artifacts diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 9e03f351f9..3812b52113 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -53,8 +53,7 @@ void gfxFlipPage(void); void gfxDrawMaskedSprite(const byte *ptr, const byte *msk, uint16 width, uint16 height, byte *page, int16 x, int16 y); void gfxFillSprite(const byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy, uint8 fillColor = 0); -void gfxUpdateSpriteMask(const byte *spritePtr, const byte *spriteMskPtr, int16 width, int16 height, const byte *maskPtr, - int16 maskWidth, int16 maskHeight, byte *bufferSprPtr, byte *bufferMskPtr, int16 xs, int16 ys, int16 xm, int16 ym, byte maskIdx); +void gfxUpdateSpriteMask(byte *destMask, int16 x, int16 y, int16 width, int16 height, const byte *maskPtr, int16 xm, int16 ym, int16 maskWidth, int16 maskHeight); void gfxDrawLine(int16 x1, int16 y1, int16 x2, int16 y2, byte color, byte *page); void gfxDrawPlainBox(int16 x1, int16 y1, int16 x2, int16 y2, byte color); diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index c74dde0310..6042849f59 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -189,7 +189,6 @@ void CineEngine::mainLoop(int bootScriptIdx) { quitFlag = 0; if (_preLoad == false) { - resetMessageHead(); resetSeqList(); resetBgIncrustList(); @@ -315,7 +314,6 @@ void CineEngine::mainLoop(int bootScriptIdx) { hideMouse(); g_sound->stopMusic(); - unloadAllMasks(); // if (g_cine->getGameType() == Cine::GType_OS) { // freeUnkList(); // } diff --git a/engines/cine/module.mk b/engines/cine/module.mk index 23792a17b9..347af2dae1 100644 --- a/engines/cine/module.mk +++ b/engines/cine/module.mk @@ -14,7 +14,8 @@ MODULE_OBJS = \ part.o \ prc.o \ rel.o \ - script.o \ + script_fw.o \ + script_os.o \ sound.o \ texte.o \ unpack.o \ diff --git a/engines/cine/msg.cpp b/engines/cine/msg.cpp index 212b9ffd7c..55eb627309 100644 --- a/engines/cine/msg.cpp +++ b/engines/cine/msg.cpp @@ -31,45 +31,32 @@ namespace Cine { -uint16 messageCount; +Common::StringList messageTable; void loadMsg(char *pMsgName) { - uint16 i; + int i, count, len; byte *ptr, *dataPtr; + const char *messagePtr; checkDataDisk(-1); - messageCount = 0; - - for (i = 0; i < NUM_MAX_MESSAGE; i++) { - messageTable[i].len = 0; - if (messageTable[i].ptr) { - free(messageTable[i].ptr); - messageTable[i].ptr = NULL; - } - } + messageTable.clear(); ptr = dataPtr = readBundleFile(findFileInBundle(pMsgName)); setMouseCursor(MOUSE_CURSOR_DISK); - messageCount = READ_BE_UINT16(ptr); ptr += 2; - - assert(messageCount <= NUM_MAX_MESSAGE); - - for (i = 0; i < messageCount; i++) { - messageTable[i].len = READ_BE_UINT16(ptr); ptr += 2; - } - - for (i = 0; i < messageCount; i++) { - if (messageTable[i].len) { - messageTable[i].ptr = (byte *) malloc(messageTable[i].len); + count = READ_BE_UINT16(ptr); + ptr += 2; - assert(messageTable[i].ptr); + messagePtr = (const char*)(ptr + 2 * count); - memcpy(messageTable[i].ptr, ptr, messageTable[i].len); - ptr += messageTable[i].len; - } + for (i = 0; i < count; i++) { + len = READ_BE_UINT16(ptr); + ptr += 2; + + messageTable.push_back(messagePtr); + messagePtr += len; } free(dataPtr); diff --git a/engines/cine/msg.h b/engines/cine/msg.h index 9828da8bab..ddf8ade8c2 100644 --- a/engines/cine/msg.h +++ b/engines/cine/msg.h @@ -26,8 +26,14 @@ #ifndef CINE_MSG_H #define CINE_MSG_H +#include "common/str.h" + namespace Cine { +#define NUM_MAX_MESSAGE 255 + +extern Common::StringList messageTable; + void loadMsg(char *pMsgName); } // End of namespace Cine diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index bba1c094f1..36f7b17a69 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -36,27 +36,7 @@ namespace Cine { objectStruct objectTable[NUM_MAX_OBJECT]; -ScriptVars globalVars(NUM_MAX_VAR); -overlayHeadElement overlayHead; - -void unloadAllMasks(void) { - overlayHeadElement *current = overlayHead.next; - - while (current) { - overlayHeadElement *next = current->next; - - delete current; - - current = next; - } - - resetMessageHead(); -} - -void resetMessageHead(void) { - overlayHead.next = NULL; - overlayHead.previous = NULL; -} +Common::List overlayList; void loadObject(char *pObjectName) { uint16 numEntry; @@ -100,92 +80,88 @@ void loadObject(char *pObjectName) { free(dataPtr); } -int8 removeOverlayElement(uint16 objIdx, uint16 param) { - overlayHeadElement *currentHeadPtr = &overlayHead; - overlayHeadElement *tempHead = currentHeadPtr; - overlayHeadElement *tempPtr2; - - currentHeadPtr = tempHead->next; - - while (currentHeadPtr && (currentHeadPtr->objIdx != objIdx || currentHeadPtr->type != param)) { - tempHead = currentHeadPtr; - currentHeadPtr = tempHead->next; - } - - if (!currentHeadPtr || currentHeadPtr->objIdx != objIdx || currentHeadPtr->type != param) { - return -1; - } - - tempHead->next = tempPtr2 = currentHeadPtr->next; +/*! \brief Remove overlay sprite from the list + * \param objIdx Remove overlay associated with this object + * \param param Remove overlay of this type + */ +int removeOverlay(uint16 objIdx, uint16 param) { + Common::List::iterator it; - if (!tempPtr2) { - tempPtr2 = &overlayHead; + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + if (it->objIdx == objIdx && it->type == param) { + overlayList.erase(it); + return 1; + } } - tempPtr2->previous = currentHeadPtr->previous; - - delete currentHeadPtr; - return 0; } -int16 freeOverlay(uint16 objIdx, uint16 param) { - overlayHeadElement *currentHeadPtr = overlayHead.next; - overlayHeadElement *previousPtr = &overlayHead; - overlayHeadElement *tempPtr2; - - while (currentHeadPtr && ((currentHeadPtr->objIdx != objIdx) || (currentHeadPtr->type != param))) { - previousPtr = currentHeadPtr; - currentHeadPtr = previousPtr->next; - } - - if (!currentHeadPtr || !((currentHeadPtr->objIdx == objIdx) && (currentHeadPtr->type == param))) { - return -1; - } - - previousPtr->next = tempPtr2 = currentHeadPtr->next; +/*! \brief Add new overlay sprite to the list + * \param objIdx Associate the overlay with this object + * \param param Type of new overlay + * \todo Why are x, y, width and color left uninitialized? + */ +void addOverlay(uint16 objIdx, uint16 param) { + Common::List::iterator it; + overlay tmp; - if (!tempPtr2) { - tempPtr2 = &overlayHead; + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) { + break; + } } - tempPtr2->previous = currentHeadPtr->previous; + tmp.objIdx = objIdx; + tmp.type = param; - delete currentHeadPtr; - return 0; + overlayList.insert(it, tmp); } -void loadOverlayElement(uint16 objIdx, uint16 param) { - overlayHeadElement *currentHeadPtr = &overlayHead; - overlayHeadElement *pNewElement; - - uint16 si = objectTable[objIdx].mask; - - overlayHeadElement *tempHead = currentHeadPtr; - - currentHeadPtr = tempHead->next; - - while (currentHeadPtr && (objectTable[currentHeadPtr->objIdx].mask < si)) { - tempHead = currentHeadPtr; - currentHeadPtr = tempHead->next; +/*! \brief Add new background mask overlay + * \param objIdx Associate the overlay with this object + * \param param source background index + */ +void addGfxElementA0(int16 objIdx, int16 param) { + Common::List::iterator it; + overlay tmp; + + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + // wtf?! + if (objectTable[it->objIdx].mask == objectTable[objIdx].mask && + (it->type == 2 || it->type == 3)) { + break; + } } - pNewElement = new overlayHeadElement; + if (it != overlayList.end() && it->objIdx == objIdx && it->type == 20 && it->x == param) { + return; + } - assert(pNewElement); + tmp.objIdx = objIdx; + tmp.type = 20; + tmp.x = param; + tmp.y = 0; + tmp.width = 0; + tmp.color = 0; - pNewElement->next = tempHead->next; - tempHead->next = pNewElement; + overlayList.insert(it, tmp); +} - pNewElement->objIdx = objIdx; - pNewElement->type = param; +/*! \brief Remove background mask overlay + * \param objIdx Remove overlay associated with this object + * \param param Remove overlay using this background + * \todo Check that it works + */ +void removeGfxElementA0(int16 objIdx, int16 param) { + Common::List::iterator it; - if (!currentHeadPtr) { - currentHeadPtr = &overlayHead; + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + if (it->objIdx == objIdx && it->type == 20 && it->x == param) { + overlayList.erase(it); + return; + } } - - pNewElement->previous = currentHeadPtr->previous; - currentHeadPtr->previous = pNewElement; } void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4) { @@ -194,8 +170,8 @@ void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint1 objectTable[objIdx].mask = param3; objectTable[objIdx].frame = param4; - if (!removeOverlayElement(objIdx, 0)) { - loadOverlayElement(objIdx, 0); + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); } } @@ -223,8 +199,8 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { case 2: objectTable[objIdx].mask = newValue; - if (!removeOverlayElement(objIdx, 0)) { - loadOverlayElement(objIdx, 0); + if (removeOverlay(objIdx, 0)) { + addOverlay(objIdx, 0); } break; case 3: diff --git a/engines/cine/object.h b/engines/cine/object.h index e4ab1377ff..e7de39649d 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -40,9 +40,7 @@ struct objectStruct { uint16 part; }; -struct overlayHeadElement { - struct overlayHeadElement *next; - struct overlayHeadElement *previous; +struct overlay { uint16 objIdx; uint16 type; int16 x; @@ -55,22 +53,19 @@ struct overlayHeadElement { #define NUM_MAX_VAR 256 extern objectStruct objectTable[NUM_MAX_OBJECT]; -extern ScriptVars globalVars; -extern overlayHeadElement overlayHead; - -void unloadAllMasks(void); -void resetMessageHead(void); +extern Common::List overlayList; void loadObject(char *pObjectName); void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4); void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue); -void loadOverlayElement(uint16 objIdx, uint16 param); -int8 removeOverlayElement(uint16 objIdx, uint16 param); +void addOverlay(uint16 objIdx, uint16 param); +int removeOverlay(uint16 objIdx, uint16 param); +void addGfxElementA0(int16 objIdx, int16 param); +void removeGfxElementA0(int16 objIdx, int16 param); int16 getObjectParam(uint16 objIdx, uint16 paramIdx); -int16 freeOverlay(uint16 objIdx, uint16 param); void addObjectParam(byte objIdx, byte paramIdx, int16 newValue); void subObjectParam(byte objIdx, byte paramIdx, int16 newValue); diff --git a/engines/cine/script.cpp b/engines/cine/script.cpp deleted file mode 100644 index 8ccd0ce3a1..0000000000 --- a/engines/cine/script.cpp +++ /dev/null @@ -1,3787 +0,0 @@ -/* 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$ - * - */ - -/*! \file - * Script interpreter file - */ - -#include "common/endian.h" - -#include "cine/cine.h" -#include "cine/bg_list.h" -#include "cine/object.h" -#include "cine/sound.h" -#include "cine/various.h" -#include "cine/script.h" - -namespace Cine { - -uint16 compareVars(int16 a, int16 b); -void palRotate(byte a, byte b, byte c); -void removeSeq(uint16 param1, uint16 param2, uint16 param3); -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); -void addGfxElementA0(int16 param1, int16 param2); -void removeGfxElementA0(int16 idx, int16 param); - -const Opcode FWScript::_opcodeTable[] = { - /* 00 */ - { &FWScript::o1_modifyObjectParam, "bbw" }, - { &FWScript::o1_getObjectParam, "bbb" }, - { &FWScript::o1_addObjectParam, "bbw" }, - { &FWScript::o1_subObjectParam, "bbw" }, - /* 04 */ - { &FWScript::o1_add2ObjectParam, "bbw" }, - { &FWScript::o1_sub2ObjectParam, "bbw" }, - { &FWScript::o1_compareObjectParam, "bbw" }, - { &FWScript::o1_setupObject, "bwwww" }, - /* 08 */ - { &FWScript::o1_checkCollision, "bwwww" }, - { &FWScript::o1_loadVar, "bc" }, - { &FWScript::o1_addVar, "bc" }, - { &FWScript::o1_subVar, "bc" }, - /* 0C */ - { &FWScript::o1_mulVar, "bc" }, - { &FWScript::o1_divVar, "bc" }, - { &FWScript::o1_compareVar, "bc" }, - { &FWScript::o1_modifyObjectParam2, "bbb" }, - /* 10 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_loadMask0, "b" }, - /* 14 */ - { &FWScript::o1_unloadMask0, "b" }, - { &FWScript::o1_addToBgList, "b" }, - { &FWScript::o1_loadMask1, "b" }, - { &FWScript::o1_unloadMask1, "b" }, - /* 18 */ - { &FWScript::o1_loadMask4, "b" }, - { &FWScript::o1_unloadMask4, "b" }, - { &FWScript::o1_addSpriteFilledToBgList, "b" }, - { &FWScript::o1_op1B, "" }, - /* 1C */ - { 0, 0 }, - { &FWScript::o1_label, "l" }, - { &FWScript::o1_goto, "b" }, - { &FWScript::o1_gotoIfSup, "b" }, - /* 20 */ - { &FWScript::o1_gotoIfSupEqu, "b" }, - { &FWScript::o1_gotoIfInf, "b" }, - { &FWScript::o1_gotoIfInfEqu, "b" }, - { &FWScript::o1_gotoIfEqu, "b" }, - /* 24 */ - { &FWScript::o1_gotoIfDiff, "b" }, - { &FWScript::o1_removeLabel, "b" }, - { &FWScript::o1_loop, "bb" }, - { 0, 0 }, - /* 28 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 2C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 30 */ - { 0, 0 }, - { &FWScript::o1_startGlobalScript, "b" }, - { &FWScript::o1_endGlobalScript, "b" }, - { 0, 0 }, - /* 34 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 38 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_loadAnim, "s" }, - /* 3C */ - { &FWScript::o1_loadBg, "s" }, - { &FWScript::o1_loadCt, "s" }, - { 0, 0 }, - { &FWScript::o1_loadPart, "s" }, - /* 40 */ - { &FWScript::o1_closePart, "" }, - { &FWScript::o1_loadNewPrcName, "bs" }, - { &FWScript::o1_requestCheckPendingDataLoad, "" }, - { 0, 0 }, - /* 44 */ - { 0, 0 }, - { &FWScript::o1_blitAndFade, "" }, - { &FWScript::o1_fadeToBlack, "" }, - { &FWScript::o1_transformPaletteRange, "bbwww" }, - /* 48 */ - { 0, 0 }, - { &FWScript::o1_setDefaultMenuColor2, "b" }, - { &FWScript::o1_palRotate, "bbb" }, - { 0, 0 }, - /* 4C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_break, "" }, - /* 50 */ - { &FWScript::o1_endScript, "x" }, - { &FWScript::o1_message, "bwwww" }, - { &FWScript::o1_loadGlobalVar, "bc" }, - { &FWScript::o1_compareGlobalVar, "bc" }, - /* 54 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 58 */ - { 0, 0 }, - { &FWScript::o1_declareFunctionName, "s" }, - { &FWScript::o1_freePartRange, "bb" }, - { &FWScript::o1_unloadAllMasks, "" }, - // 5C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 60 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_setScreenDimensions, "wwww" }, - /* 64 */ - { &FWScript::o1_displayBackground, "" }, - { &FWScript::o1_initializeZoneData, "" }, - { &FWScript::o1_setZoneDataEntry, "bw" }, - { &FWScript::o1_getZoneDataEntry, "bb" }, - /* 68 */ - { &FWScript::o1_setDefaultMenuColor, "b" }, - { &FWScript::o1_allowPlayerInput, "" }, - { &FWScript::o1_disallowPlayerInput, "" }, - { &FWScript::o1_changeDataDisk, "b" }, - /* 6C */ - { 0, 0 }, - { &FWScript::o1_loadMusic, "s" }, - { &FWScript::o1_playMusic, "" }, - { &FWScript::o1_fadeOutMusic, "" }, - /* 70 */ - { &FWScript::o1_stopSample, "" }, - { &FWScript::o1_op71, "bw" }, - { &FWScript::o1_op72, "wbw" }, - { &FWScript::o1_op73, "wbw" }, - /* 74 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_playSample, "bbwbww" }, - /* 78 */ - { &FWScript::o1_playSample, "bbwbww" }, - { &FWScript::o1_disableSystemMenu, "b" }, - { &FWScript::o1_loadMask5, "b" }, - { &FWScript::o1_unloadMask5, "b" } -}; -const unsigned int FWScript::_numOpcodes = ARRAYSIZE(FWScript::_opcodeTable); - - -const Opcode OSScript::_opcodeTable[] = { - /* 00 */ - { &FWScript::o1_modifyObjectParam, "bbw" }, - { &FWScript::o1_getObjectParam, "bbb" }, - { &FWScript::o1_addObjectParam, "bbw" }, - { &FWScript::o1_subObjectParam, "bbw" }, - /* 04 */ - { &FWScript::o1_add2ObjectParam, "bbw" }, - { &FWScript::o1_sub2ObjectParam, "bbw" }, - { &FWScript::o1_compareObjectParam, "bbw" }, - { &FWScript::o1_setupObject, "bwwww" }, - /* 08 */ - { &FWScript::o1_checkCollision, "bwwww" }, - { &FWScript::o1_loadVar, "bc" }, - { &FWScript::o1_addVar, "bc" }, - { &FWScript::o1_subVar, "bc" }, - /* 0C */ - { &FWScript::o1_mulVar, "bc" }, - { &FWScript::o1_divVar, "bc" }, - { &FWScript::o1_compareVar, "bc" }, - { &FWScript::o1_modifyObjectParam2, "bbb" }, - /* 10 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_loadMask0, "b" }, - /* 14 */ - { &FWScript::o1_unloadMask0, "b" }, - { &FWScript::o1_addToBgList, "b" }, - { &FWScript::o1_loadMask1, "b" }, - { &FWScript::o1_unloadMask1, "b" }, - /* 18 */ - { &FWScript::o1_loadMask4, "b" }, - { &FWScript::o1_unloadMask4, "b" }, - { &FWScript::o1_addSpriteFilledToBgList, "b" }, - { &FWScript::o1_op1B, "" }, - /* 1C */ - { 0, 0 }, - { &FWScript::o1_label, "l" }, - { &FWScript::o1_goto, "b" }, - { &FWScript::o1_gotoIfSup, "b" }, - /* 20 */ - { &FWScript::o1_gotoIfSupEqu, "b" }, - { &FWScript::o1_gotoIfInf, "b" }, - { &FWScript::o1_gotoIfInfEqu, "b" }, - { &FWScript::o1_gotoIfEqu, "b" }, - /* 24 */ - { &FWScript::o1_gotoIfDiff, "b" }, - { &FWScript::o1_removeLabel, "b" }, - { &FWScript::o1_loop, "bb" }, - { 0, 0 }, - /* 28 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 2C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 30 */ - { 0, 0 }, - { &FWScript::o1_startGlobalScript, "b" }, - { &FWScript::o1_endGlobalScript, "b" }, - { 0, 0 }, - /* 34 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 38 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_loadAnim, "s" }, - /* 3C */ - { &FWScript::o1_loadBg, "s" }, - { &FWScript::o1_loadCt, "s" }, - { 0, 0 }, - { &FWScript::o2_loadPart, "s" }, - /* 40 */ - { 0, 0 }, /* o1_closePart, triggered by some scripts (STARTA.PRC 4 for ex.) */ - { &FWScript::o1_loadNewPrcName, "bs" }, - { &FWScript::o1_requestCheckPendingDataLoad, "" }, - { 0, 0 }, - /* 44 */ - { 0, 0 }, - { &FWScript::o1_blitAndFade, "" }, - { &FWScript::o1_fadeToBlack, "" }, - { &FWScript::o1_transformPaletteRange, "bbwww" }, - /* 48 */ - { 0, 0 }, - { &FWScript::o1_setDefaultMenuColor2, "b" }, - { &FWScript::o1_palRotate, "bbb" }, - { 0, 0 }, - /* 4C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_break, "" }, - /* 50 */ - { &FWScript::o1_endScript, "x" }, - { &FWScript::o1_message, "bwwww" }, - { &FWScript::o1_loadGlobalVar, "bc" }, - { &FWScript::o1_compareGlobalVar, "bc" }, - /* 54 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 58 */ - { 0, 0 }, - { &FWScript::o1_declareFunctionName, "s" }, - { &FWScript::o1_freePartRange, "bb" }, - { &FWScript::o1_unloadAllMasks, "" }, - // 5C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - /* 60 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o1_setScreenDimensions, "wwww" }, - /* 64 */ - { &FWScript::o1_displayBackground, "" }, - { &FWScript::o1_initializeZoneData, "" }, - { &FWScript::o1_setZoneDataEntry, "bw" }, - { &FWScript::o1_getZoneDataEntry, "bb" }, - /* 68 */ - { &FWScript::o1_setDefaultMenuColor, "b" }, - { &FWScript::o1_allowPlayerInput, "" }, - { &FWScript::o1_disallowPlayerInput, "" }, - { &FWScript::o1_changeDataDisk, "b" }, - /* 6C */ - { 0, 0 }, - { &FWScript::o1_loadMusic, "s" }, - { &FWScript::o1_playMusic, "" }, - { &FWScript::o1_fadeOutMusic, "" }, - /* 70 */ - { &FWScript::o1_stopSample, "" }, - { &FWScript::o1_op71, "bw" }, - { &FWScript::o1_op72, "wbw" }, - { &FWScript::o1_op72, "wbw" }, - /* 74 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o2_playSample, "bbwbww" }, - /* 78 */ - { &FWScript::o2_playSampleAlt, "bbwbww" }, - { &FWScript::o1_disableSystemMenu, "b" }, - { &FWScript::o1_loadMask5, "b" }, - { &FWScript::o1_unloadMask5, "b" }, - /* 7C */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { &FWScript::o2_addSeqListElement, "bbbbwww" }, - /* 80 */ - { &FWScript::o2_removeSeq, "bb" }, - { &FWScript::o2_op81, "" }, - { &FWScript::o2_op82, "bbw" }, - { &FWScript::o2_isSeqRunning, "bb" }, - /* 84 */ - { &FWScript::o2_gotoIfSupNearest, "b" }, - { &FWScript::o2_gotoIfSupEquNearest, "b" }, - { &FWScript::o2_gotoIfInfNearest, "b" }, - { &FWScript::o2_gotoIfInfEquNearest, "b" }, - /* 88 */ - { &FWScript::o2_gotoIfEquNearest, "b" }, - { &FWScript::o2_gotoIfDiffNearest, "b" }, - { 0, 0 }, - { &FWScript::o2_startObjectScript, "b" }, - /* 8C */ - { &FWScript::o2_stopObjectScript, "b" }, - { &FWScript::o2_op8D, "wwwwwwww" }, - { &FWScript::o2_addBackground, "bs" }, - { &FWScript::o2_removeBackground, "b" }, - /* 90 */ - { &FWScript::o2_loadAbs, "bs" }, - { &FWScript::o2_loadBg, "b" }, - { 0, 0 }, - { 0, 0 }, - /* 94 */ - { 0, 0 }, - { &FWScript::o1_changeDataDisk, "b" }, - { 0, 0 }, - { 0, 0 }, - /* 98 */ - { 0, 0 }, - { 0, 0 }, - { &FWScript::o2_wasZoneChecked, "" }, - { &FWScript::o2_op9B, "wwwwwwww" }, - /* 9C */ - { &FWScript::o2_op9C, "wwww" }, - { &FWScript::o2_useBgScroll, "b" }, - { &FWScript::o2_setAdditionalBgVScroll, "c" }, - { &FWScript::o2_op9F, "ww" }, - /* A0 */ - { &FWScript::o2_addGfxElementA0, "ww" }, - { &FWScript::o2_removeGfxElementA0, "ww" }, - { &FWScript::o2_opA2, "ww" }, - { &FWScript::o2_opA3, "ww" }, - /* A4 */ - { &FWScript::o2_loadMask22, "b" }, - { &FWScript::o2_unloadMask22, "b" }, - { 0, 0 }, - { 0, 0 }, - /* A8 */ - { 0, 0 }, - { &FWScript::o1_changeDataDisk, "b" } -}; -const unsigned int OSScript::_numOpcodes = ARRAYSIZE(OSScript::_opcodeTable); - -FWScriptInfo *scriptInfo; ///< Script factory -RawScriptArray scriptTable; ///< Table of script bytecode - -/*! \todo: replace with script subsystem - */ -void setupOpcodes() { - static FWScriptInfo fw; - static OSScriptInfo os; - if (g_cine->getGameType() == Cine::GType_FW) { - scriptInfo = &fw; - } else { - scriptInfo = &os; - } -} - -/*! \brief Allocate empty array - * \param len Size of array - * - * Explicit to prevent var=0 instead of var[i]=0 typos. - */ -ScriptVars::ScriptVars(unsigned int len) : _size(len), _vars(new int16[len]) { - assert(_vars); - reset(); -} - -/*! \brief Allocate array and read contents from savefile - * \param fHandle Savefile open for reading - * \param len Size of array - */ -ScriptVars::ScriptVars(Common::InSaveFile &fHandle, unsigned int len) - : _size(len), _vars(new int16[len]) { - - assert(_vars); - - load(fHandle); -} - -/*! \brief Copy constructor - */ -ScriptVars::ScriptVars(const ScriptVars &src) : _size(src._size), _vars(new int16[_size]) { - assert(_vars); - memcpy(_vars, src._vars, _size * sizeof(int16)); -} - -/*! \brief Destructor - */ -ScriptVars::~ScriptVars(void) { - delete[] _vars; -} - -/*! \brief Assignment operator - */ -ScriptVars &ScriptVars::operator=(const ScriptVars &src) { - ScriptVars tmp(src); - int16 *tmpvars = _vars; - - _vars = tmp._vars; - tmp._vars = tmpvars; - _size = src._size; - - return *this; -} - -/*! \brief Direct array item access - * \param idx Item index - * \return Reference to item - */ -int16 &ScriptVars::operator[](unsigned int idx) { - debug(6, "assert(%d < %d)", idx, _size); - assert(idx < _size); - return _vars[idx]; -} - -/*! \brief Direct read-only array item access - * \param idx Item index - * \return Copy of item - */ -int16 ScriptVars::operator[](unsigned int idx) const { - debug(6, "assert(%d < %d)", idx, _size); - assert(idx < _size); - return _vars[idx]; -} - -/*! \brief Savefile writer - * \param fHandle Savefile open for writing - */ -void ScriptVars::save(Common::OutSaveFile &fHandle) const { - save(fHandle, _size); -} - -/*! \brief Savefile writer with data length limit - * \param fHandle Savefile open for writing - * \param len Length of data to be written (len <= _size) - */ -void ScriptVars::save(Common::OutSaveFile &fHandle, unsigned int len) const { - debug(6, "assert(%d <= %d)", len, _size); - assert(len <= _size); - for (unsigned int i = 0; i < len; i++) { - fHandle.writeUint16BE(_vars[i]); - } -} - -/*! \brief Restore array from savefile - * \param fHandle Savefile open for reading - */ -void ScriptVars::load(Common::InSaveFile &fHandle) { - load(fHandle, _size); -} - -/*! \brief Restore part of array from savefile - * \param fHandle Savefile open for reading - * \param len Length of data to be read - */ -void ScriptVars::load(Common::InSaveFile &fHandle, unsigned int len) { - debug(6, "assert(%d <= %d)", len, _size); - assert(len <= _size); - for (unsigned int i = 0; i < len; i++) { - _vars[i] = fHandle.readUint16BE(); - } -} - -/*! \brief Reset all values to 0 - */ -void ScriptVars::reset(void) { - memset( _vars, 0, _size * sizeof(int16)); -} - -/*! \brief Constructor for partial loading - * \param s Size of bytecode which will be added later - * - * This constructor _MUST_ be followed by setdata() method call before the - * instance can be used. It leaves the instance in partially invalid state. - */ -RawScript::RawScript(uint16 s) : _size(s), _data(NULL), - _labels(SCRIPT_STACK_SIZE) { } - -/*! \brief Complete constructor - * \param data Script bytecode - * \param s Bytecode length - */ -RawScript::RawScript(const FWScriptInfo &info, const byte *data, uint16 s) : - _size(s), _data(NULL), _labels(SCRIPT_STACK_SIZE) { - - setData(info, data); -} - -/*! \brief Copy constructor - */ -RawScript::RawScript(const RawScript &src) : _size(src._size), - _data(new byte[_size+1]), _labels(src._labels) { - - assert(_data); - memcpy(_data, src._data, _size+1); -} - -/*! \brief Destructor - */ -RawScript::~RawScript(void) { - delete[] _data; -} - -/*! \brief Assignment operator - */ -RawScript &RawScript::operator=(const RawScript &src) { - assert(src._data); - byte *tmp = new byte[src._size+1]; - - assert(tmp); - _labels = src._labels; - _size = src._size; - - delete[] _data; - _data = tmp; - memcpy(_data, src._data, _size); - _data[_size] = 0; - - return *this; -} - -/*! \brief Get the next label in bytecode - * \param info Script info instance - * \param offset Starting offset - * \return Index of the next label in bytecode or _size on end of bytecode - * - * computeScriptStackSub replacement - */ -int RawScript::getNextLabel(const FWScriptInfo &info, int offset) const { - assert(_data); - int pos = offset; - - assert(pos >= 0); - - while (pos < _size) { - uint8 opcode = _data[pos++]; - const char *ptr = info.opcodeInfo(opcode); - - if (!ptr) { - continue; - } - - for (; *ptr; ++ptr) { - switch (*ptr) { - case 'b': // byte - pos++; - break; - case 'w': // word - pos += 2; - break; - case 'c': { // byte != 0 ? byte : word - uint8 test = _data[pos]; - pos++; - if (test) { - pos++; - } else { - pos += 2; - } - } - break; - case 'l': // label - return pos; - case 's': // string - while (_data[pos++] != 0); - break; - case 'x': // exit script - return -pos-1; - } - } - } - return _size; -} - -/*! \brief Calculate initial script labels - * \param info Script info instance - * - * computeScriptStack replacement - */ -void RawScript::computeLabels(const FWScriptInfo &info) { - assert(_data); - int pos = 0; - int i; - - // reset labels - for (i = 0; i < SCRIPT_STACK_SIZE; i++) { - _labels[i] = -1; - } - - // parse bytecode - while ((pos = getNextLabel(info, pos)) >= 0) { - i = _data[pos]; - _labels[i] = ++pos; - } -} - -/*! \brief find the next label from current position - * \param info Script info instance - * \param index Label index to look for - * \param offset Current position in script - * \return Position of next instruction following the label - * - * computeScriptStackFromScript replacement - */ -uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset) - const { - - assert(_data); - int pos = offset; - - while ((pos = getNextLabel(info, pos)) >= 0) { - if (_data[pos++] == index) { - return pos; - } - } - - return -pos - 1; -} - -/*! \brief Copy bytecode and calculate labels - * \param data Bytecode to copy, must be _size long - */ -void RawScript::setData(const FWScriptInfo &info, const byte *data) { - assert(!_data); // this function should be called only once per instance - _data = new byte[_size+1]; - - assert(data && _data); - memcpy(_data, data, _size * sizeof(byte)); - _data[_size] = 0; - - computeLabels(info); -} - -/*! \brief Initial script labels - * \return Precalculated script labels - */ -const ScriptVars &RawScript::labels(void) const { - assert(_data); - return _labels; -} - -/*! \brief One byte of bytecode - * \param pos Index in bytecode - * \return Byte from bytecode - */ -byte RawScript::getByte(unsigned int pos) const { - assert(_data && pos < _size); - - return _data[pos]; -} - -/*! \brief One word of bytecode - * \param pos Index of the first byte in bytecode - * \return Word of bytecode - */ -uint16 RawScript::getWord(unsigned int pos) const { - assert(_data && pos+1 < _size); - - return READ_BE_UINT16(_data + pos); -} - -/*! \brief String in bytecode - * \param pos Index of the first char in string - * \return Pointer to part of bytecode - */ -const char *RawScript::getString(unsigned int pos) const { - assert(_data && pos < _size); - - return (const char*)(_data+pos); -} - -/*! \brief Constructor for partial loading - * \param size Size of bytecode which will be added later - * \param p1 First object script parameter - * \param p2 Second object script parameter - * \param p3 Third object script parameter - * - * This constructor _MUST_ be followed by setdata() method call before the - * instance can be used. It leaves the instance in partially invalid state. - */ -RawObjectScript::RawObjectScript(uint16 s, uint16 p1, uint16 p2, uint16 p3) - : RawScript(s), _runCount(0), _param1(p1), _param2(p2), _param3(p3) -{ } - -/*! \brief Complete constructor - * \param data Script bytecode - * \param s Bytecode length - * \param p1 First object script parameter - * \param p2 Second object script parameter - * \param p3 Third object script parameter - */ -RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data, - uint16 s, uint16 p1, uint16 p2, uint16 p3) : RawScript(info, data, s), - _runCount(0), _param1(p1), _param2(p2), _param3(p3) { } - -/*! \brief Contructor for global scripts - * \param script Script bytecode reference - * \param idx Script bytecode index - */ -FWScript::FWScript(const RawScript &script, int16 idx) : _script(script), - _pos(0), _line(0), _compare(0), _index(idx), - _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(new FWScriptInfo) { } - -/*! \brief Copy constructor - */ -FWScript::FWScript(const FWScript &src) : _script(src._script), _pos(src._pos), - _line(src._line), _compare(src._compare), _index(src._index), - _labels(src._labels), _localVars(src._localVars), - _globalVars(src._globalVars), _info(new FWScriptInfo) { } - -/*! \brief Contructor for global scripts in derived classes - * \param script Script bytecode reference - * \param idx Script bytecode index - */ -FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) : - _script(script), _pos(0), _line(0), _compare(0), _index(idx), - _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(info) { } - -/*! \brief Constructor for object scripts in derived classes - * \param script Script bytecode reference - * \param idx Script bytecode index - */ -FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) : - _script(script), _pos(0), _line(0), _compare(0), _index(idx), - _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(info) { - - _localVars[0] = script.run(); -} - -/*! \brief Copy constructor for derived classes - */ -FWScript::FWScript(const FWScript &src, FWScriptInfo *info) : - _script(src._script), _pos(src._pos), _line(src._line), - _compare(src._compare), _index(src._index), _labels(src._labels), - _localVars(src._localVars), _globalVars(src._globalVars), _info(info) { } - -FWScript::~FWScript(void) { - delete _info; -} - -/*! \brief Read next byte from bytecode - * \return Byte from bytecode - */ -byte FWScript::getNextByte() { - byte val = _script.getByte(_pos); - _pos++; - return val; -} - -/*! \brief Read next word from bytecode - * \return Word from bytecode - */ -uint16 FWScript::getNextWord() { - uint16 val = _script.getWord(_pos); - _pos += 2; - return val; -} - -/*! \brief Read next string from bytecode - * \return Pointer to string - */ -const char *FWScript::getNextString() { - const char *val = _script.getString(_pos); - _pos += strlen(val) + 1; - return val; -} - -/*! \brief Restore script state from savefile - * \param labels Restored script labels - * \param local Restored local script variables - * \param compare Restored last comparison result - * \param pos Restored script position - */ -void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { - assert(pos < _script._size); - _labels = labels; - _localVars = local; - _compare = compare; - _pos = _line = pos; -} - -/*! \brief Execute script - * \return <0 on script termination, >0 on script pause - * - * executeScript replacement. - * Instruction handler must return 0 if the script should continue or - * nonzero with the same meaning as return value of this function - */ -int FWScript::execute() { - int ret = 0; - - while (!ret) { - _line = _pos; - byte opcode = getNextByte(); - opFunc handler = _info->opcodeHandler(opcode); - - if (handler) { - ret = (this->*handler)(); - } - } - - return ret; -} - -/*! \brief Save script to savefile - * \param fHandle Savefile handle - */ -void FWScript::save(Common::OutSaveFile &fHandle) const { - _labels.save(fHandle); - _localVars.save(fHandle); - fHandle.writeUint16BE(_compare); - fHandle.writeUint16BE(_pos); - // data order sucks... - fHandle.writeUint16BE(_index); -} - -/*! \brief Contructor for global scripts - * \param script Script bytecode reference - * \param idx Script bytecode index - */ -OSScript::OSScript(const RawScript &script, int16 idx) : - FWScript(script, idx, new OSScriptInfo) {} - -/*! \brief Constructor for object scripts - * \param script Script bytecode reference - * \param idx Script bytecode index - */ -OSScript::OSScript(RawObjectScript &script, int16 idx) : - FWScript(script, idx, new OSScriptInfo) {} - -/*! \brief Copy constructor - */ -OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {} - -/*! \brief Restore script state from savefile - * \param labels Restored script labels - * \param local Restored local script variables - * \param compare Restored last comparison result - * \param pos Restored script position - */ -void OSScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { - FWScript::load(labels, local, compare, pos); -} -/*! \brief Get opcode info string - * \param opcode Opcode to look for in opcode table - */ -const char *FWScriptInfo::opcodeInfo(byte opcode) const { - if (opcode == 0 || opcode > FWScript::_numOpcodes) { - return NULL; - } - - if (!FWScript::_opcodeTable[opcode - 1].args) { - warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeInfo", opcode - 1); - return NULL; - } - - return FWScript::_opcodeTable[opcode - 1].args; -} - -/*! \brief Get opcode handler pointer - * \param opcode Opcode to look for in opcode table - */ -opFunc FWScriptInfo::opcodeHandler(byte opcode) const { - if (opcode == 0 || opcode > FWScript::_numOpcodes) { - return NULL; - } - - if (!FWScript::_opcodeTable[opcode - 1].proc) { - warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeHandler", opcode - 1); - return NULL; - } - - return FWScript::_opcodeTable[opcode - 1].proc; -} - -/*! \brief Create new FWScript instance - * \param script Script bytecode - * \param index Bytecode index - */ -FWScript *FWScriptInfo::create(const RawScript &script, int16 index) const { - return new FWScript(script, index); -} - -/*! \brief Create new FWScript instance - * \param script Object script bytecode - * \param index Bytecode index - */ -FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index) const { - return new FWScript(script, index); -} - -/*! \brief Load saved FWScript instance - * \param script Script bytecode - * \param index Bytecode index - * \param local Local variables - * \param labels Script labels - * \param compare Last compare result - * \param pos Position in script - */ -FWScript *FWScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { - FWScript *tmp = new FWScript(script, index); - assert(tmp); - tmp->load(labels, local, compare, pos); - return tmp; -} - -/*! \brief Load saved FWScript instance - * \param script Object script bytecode - * \param index Bytecode index - * \param local Local variables - * \param labels Script labels - * \param compare Last compare result - * \param pos Position in script - */ -FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { - FWScript *tmp = new FWScript(script, index); - assert(tmp); - tmp->load(labels, local, compare, pos); - return tmp; -} - -/*! \brief Get opcode info string - * \param opcode Opcode to look for in opcode table - */ -const char *OSScriptInfo::opcodeInfo(byte opcode) const { - if (opcode == 0 || opcode > OSScript::_numOpcodes) { - return NULL; - } - - if (!OSScript::_opcodeTable[opcode - 1].args) { - warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeInfo", opcode - 1); - return NULL; - } - - return OSScript::_opcodeTable[opcode - 1].args; -} - -/*! \brief Get opcode handler pointer - * \param opcode Opcode to look for in opcode table - */ -opFunc OSScriptInfo::opcodeHandler(byte opcode) const { - if (opcode == 0 || opcode > OSScript::_numOpcodes) { - return NULL; - } - - if (!OSScript::_opcodeTable[opcode - 1].proc) { - warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeHandler", opcode - 1); - return NULL; - } - - return OSScript::_opcodeTable[opcode - 1].proc; -} - -/*! \brief Create new OSScript instance - * \param script Script bytecode - * \param index Bytecode index - */ -FWScript *OSScriptInfo::create(const RawScript &script, int16 index) const { - return new OSScript(script, index); -} - -/*! \brief Create new OSScript instance - * \param script Object script bytecode - * \param index Bytecode index - */ -FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index) const { - return new OSScript(script, index); -} - -/*! \brief Load saved OSScript instance - * \param script Script bytecode - * \param index Bytecode index - * \param local Local variables - * \param labels Script labels - * \param compare Last compare result - * \param pos Position in script - */ -FWScript *OSScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { - OSScript *tmp = new OSScript(script, index); - assert(tmp); - tmp->load(labels, local, compare, pos); - return tmp; -} - -/*! \brief Load saved OSScript instance - * \param script Object script bytecode - * \param index Bytecode index - * \param local Local variables - * \param labels Script labels - * \param compare Last compare result - * \param pos Position in script - */ -FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { - OSScript *tmp = new OSScript(script, index); - assert(tmp); - tmp->load(labels, local, compare, pos); - return tmp; -} - -// ------------------------------------------------------------------------ -// FUTURE WARS opcodes -// ------------------------------------------------------------------------ - -int FWScript::o1_modifyObjectParam() { - byte objIdx = getNextByte(); - byte paramIdx = getNextByte(); - int16 newValue = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); - - modifyObjectParam(objIdx, paramIdx, newValue); - return 0; -} - -int FWScript::o1_getObjectParam() { - byte objIdx = getNextByte(); - byte paramIdx = getNextByte(); - byte newValue = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: getObjectParam(objIdx:%d,paramIdx:%d,var:%d)", _line, objIdx, paramIdx, newValue); - - _localVars[newValue] = getObjectParam(objIdx, paramIdx); - return 0; -} - -int FWScript::o1_addObjectParam() { - byte objIdx = getNextByte(); - byte paramIdx = getNextByte(); - int16 newValue = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: addObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); - - addObjectParam(objIdx, paramIdx, newValue); - return 0; -} - -int FWScript::o1_subObjectParam() { - byte objIdx = getNextByte(); - byte paramIdx = getNextByte(); - int16 newValue = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: subObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); - - subObjectParam(objIdx, paramIdx, newValue); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_add2ObjectParam() { - uint16 a = getNextByte(); - uint16 b = getNextByte(); - uint16 c = getNextWord(); - warning("STUB: o1_add2ObjectParam(%x, %x, %x)", a, b, c); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_sub2ObjectParam() { - uint16 a = getNextByte(); - uint16 b = getNextByte(); - uint16 c = getNextWord(); - warning("STUB: o1_sub2ObjectParam(%x, %x, %x)", a, b, c); - return 0; -} - -int FWScript::o1_compareObjectParam() { - byte objIdx = getNextByte(); - byte param1 = getNextByte(); - int16 param2 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: compareObjectParam(objIdx:%d,type:%d,value:%d)", _line, objIdx, param1, param2); - - _compare = compareObjectParam(objIdx, param1, param2); - return 0; -} - -int FWScript::o1_setupObject() { - byte objIdx = getNextByte(); - int16 param1 = getNextWord(); - int16 param2 = getNextWord(); - int16 param3 = getNextWord(); - int16 param4 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: setupObject(objIdx:%d,%d,%d,%d,%d)", _line, objIdx, param1, param2, param3, param4); - - setupObject(objIdx, param1, param2, param3, param4); - return 0; -} - -int FWScript::o1_checkCollision() { - byte objIdx = getNextByte(); - int16 param1 = getNextWord(); - int16 param2 = getNextWord(); - int16 param3 = getNextWord(); - int16 param4 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: checkCollision(objIdx:%d,%d,%d,%d,%d)", _line, objIdx, param1, param2, param3, param4); - - _compare = checkCollision(objIdx, param1, param2, param3, param4); - return 0; -} - -int FWScript::o1_loadVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - int16 var; - - switch (varType) { - case 1: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = var[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] = _localVars[dataIdx]; - break; - case 2: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = globalVars[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] = _globalVars[dataIdx]; - break; - case 3: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = mouseX", _line, varIdx); - getMouseData(mouseUpdateStatus, &dummyU16, (uint16 *)&var, &dummyU16); - _localVars[varIdx] = var; - break; - case 4: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = mouseY", _line, varIdx); - getMouseData(mouseUpdateStatus, &dummyU16, &dummyU16, (uint16 *)&var); - _localVars[varIdx] = var; - break; - case 5: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = rand mod %d", _line, varIdx, dataIdx); - _localVars[varIdx] = g_cine->_rnd.getRandomNumber(dataIdx - 1); - break; - case 8: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].packedSize", _line, varIdx, dataIdx); - _localVars[varIdx] = partBuffer[dataIdx].packedSize; - break; - case 9: - debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].unpackedSize", _line, varIdx, dataIdx); - _localVars[varIdx] = partBuffer[dataIdx].unpackedSize; - break; - default: - error("executeScript: o1_loadVar: Unknown variable type %d", varType); - } - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: var[%d] = %d", _line, varIdx, value); - _localVars[varIdx] = value; - } - - return 0; -} - -int FWScript::o1_addVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] += var[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] += _localVars[dataIdx]; - } else if (varType == 2) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] += globalVar[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] += _globalVars[dataIdx]; - } - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: var[%d] += %d", _line, varIdx, value); - _localVars[varIdx] += value; - } - - return 0; -} - -int FWScript::o1_subVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] -= var[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] -= _localVars[dataIdx]; - } else if (varType == 2) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] -= globalVar[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] -= _globalVars[dataIdx]; - } - - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: var[%d] -= %d", _line, varIdx, value); - _localVars[varIdx] -= value; - } - - return 0; -} - -int FWScript::o1_mulVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] *= var[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] *= _localVars[dataIdx]; - } else if (varType == 2) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] *= globalVar[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] *= _globalVars[dataIdx]; - } - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: var[%d] *= %d", _line, varIdx, value); - _localVars[varIdx] *= value; - } - - return 0; -} - -int FWScript::o1_divVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] /= var[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] /= _localVars[dataIdx]; - } else if (varType == 2) { - debugC(5, kCineDebugScript, "Line: %d: var[%d] /= globalVar[%d]", _line, varIdx, dataIdx); - _localVars[varIdx] /= _globalVars[dataIdx]; - } - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: var[%d] /= %d", _line, varIdx, value); - _localVars[varIdx] /= value; - } - - return 0; -} - -int FWScript::o1_compareVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and var[%d]", _line, varIdx, dataIdx); - _compare = compareVars(_localVars[varIdx], _localVars[dataIdx]); - } else if (varType == 2) { - debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and globalVar[%d]", _line, varIdx, dataIdx); - _compare = compareVars(_localVars[varIdx], _globalVars[dataIdx]); - } - } else { - int16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and %d", _line, varIdx, value); - _compare = compareVars(_localVars[varIdx], value); - } - - return 0; -} - -int FWScript::o1_modifyObjectParam2() { - byte objIdx = getNextByte(); - byte paramIdx = getNextByte(); - byte newValue = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam2(objIdx:%d,paramIdx:%d,var[%d])", _line, objIdx, paramIdx, newValue); - - modifyObjectParam(objIdx, paramIdx, _localVars[newValue]); - return 0; -} - -int FWScript::o1_loadMask0() { - // OP_loadV7Element - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addSpriteOverlay(%d)", _line, param); - loadOverlayElement(param, 0); - return 0; -} - -int FWScript::o1_unloadMask0() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay(%d)", _line, param); - freeOverlay(param, 0); - return 0; -} - -int FWScript::o1_addToBgList() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addToBGList(%d)", _line, param); - addToBGList(param); - return 0; -} - -int FWScript::o1_loadMask1() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addOverlay1(%d)", _line, param); - loadOverlayElement(param, 1); - return 0; -} - -int FWScript::o1_unloadMask1() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeOverlay1(%d)", _line, param); - freeOverlay(param, 1); - return 0; -} - -int FWScript::o1_loadMask4() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addOverlayType4(%d)", _line, param); - loadOverlayElement(param, 4); - return 0; -} - -int FWScript::o1_unloadMask4() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay4(%d)", _line, param); - freeOverlay(param, 4); - return 0; -} - -int FWScript::o1_addSpriteFilledToBgList() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: op1A(%d) -> TODO !", _line, param); - addSpriteFilledToBGList(param); - return 0; -} - -int FWScript::o1_op1B() { - debugC(5, kCineDebugScript, "Line: %d: freeBgIncrustList", _line); - bgIncrustList.clear(); - return 0; -} - -int FWScript::o1_label() { - byte labelIdx = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: label(%d)", _line, labelIdx); - _labels[labelIdx] = _pos; - return 0; -} - -int FWScript::o1_goto() { - byte labelIdx = getNextByte(); - - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: goto label(%d)", _line, labelIdx); - _pos = _labels[labelIdx]; - return 0; -} - -int FWScript::o1_gotoIfSup() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpGT) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(>) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(>) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_gotoIfSupEqu() { - byte labelIdx = getNextByte(); - - if (_compare & (kCmpGT | kCmpEQ)) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(>=) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(>=) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_gotoIfInf() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpLT) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(<) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(<) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_gotoIfInfEqu() { - byte labelIdx = getNextByte(); - - if (_compare & (kCmpLT | kCmpEQ)) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(<=) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(<=) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_gotoIfEqu() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpEQ) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(==) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(==) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_gotoIfDiff() { - byte labelIdx = getNextByte(); - - if (_compare != kCmpEQ) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(!=) goto %d (true)", _line, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: if(!=) goto %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o1_removeLabel() { - byte labelIdx = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeLabel(%d)", _line, labelIdx); - _labels[labelIdx] = -1; - return 0; -} - -int FWScript::o1_loop() { - byte varIdx = getNextByte(); - byte labelIdx = getNextByte(); - - _localVars[varIdx]--; - - if (_localVars[varIdx] >= 0) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: loop(var[%d]) goto %d (continue)", _line, varIdx, labelIdx); - _pos = _labels[labelIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: loop(var[%d]) goto %d (stop)", _line, varIdx, labelIdx); - } - return 0; -} - -int FWScript::o1_startGlobalScript() { - // OP_startScript - byte param = getNextByte(); - - assert(param < NUM_MAX_SCRIPT); - - debugC(5, kCineDebugScript, "Line: %d: startScript(%d)", _line, param); - addScriptToList0(param); - return 0; -} - -int FWScript::o1_endGlobalScript() { - byte scriptIdx = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: stopGlobalScript(%d)", _line, scriptIdx); - - ScriptList::iterator it = globalScripts.begin(); - - for (; it != globalScripts.end(); ++it) { - if ((*it)->_index == scriptIdx) { - (*it)->_index = -1; - } - } - - return 0; -} - -int FWScript::o1_loadAnim() { - // OP_loadResource - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadResource(\"%s\")", _line, param); - loadResource(param); - return 0; -} - -int FWScript::o1_loadBg() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadBg(\"%s\")", _line, param); - - loadBg(param); - bgIncrustList.clear(); - bgVar0 = 0; - return 0; -} - -int FWScript::o1_loadCt() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadCt(\"%s\")", _line, param); - loadCt(param); - return 0; -} - -int FWScript::o1_loadPart() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param); - loadPart(param); - return 0; -} - -int FWScript::o1_closePart() { - debugC(5, kCineDebugScript, "Line: %d: closePart", _line); - closePart(); - return 0; -} - -int FWScript::o1_loadNewPrcName() { - // OP_loadData - byte param1 = getNextByte(); - const char *param2 = getNextString(); - - assert(param1 <= 3); - - switch (param1) { - case 0: - debugC(5, kCineDebugScript, "Line: %d: loadPrc(\"%s\")", _line, param2); - strcpy(newPrcName, param2); - break; - case 1: - debugC(5, kCineDebugScript, "Line: %d: loadRel(\"%s\")", _line, param2); - strcpy(newRelName, param2); - break; - case 2: - debugC(5, kCineDebugScript, "Line: %d: loadObject(\"%s\")", _line, param2); - strcpy(newObjectName, param2); - break; - case 3: - debugC(5, kCineDebugScript, "Line: %d: loadMsg(\"%s\")", _line, param2); - strcpy(newMsgName, param2); - break; - } - return 0; -} - -int FWScript::o1_requestCheckPendingDataLoad() { - debugC(5, kCineDebugScript, "Line: %d: request data load", _line); - checkForPendingDataLoadSwitch = 1; - return 0; -} - -int FWScript::o1_blitAndFade() { - debugC(5, kCineDebugScript, "Line: %d: request fadein", _line); - // TODO: use real code - - drawOverlays(); - fadeRequired = true; - flip(); - -// fadeFromBlack(); - return 0; -} - -int FWScript::o1_fadeToBlack() { - debugC(5, kCineDebugScript, "Line: %d: request fadeout", _line); - - fadeToBlack(); - return 0; -} - -int FWScript::o1_transformPaletteRange() { - byte startColor = getNextByte(); - byte numColor = getNextByte(); - uint16 r = getNextWord(); - uint16 g = getNextWord(); - uint16 b = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: transformPaletteRange(from:%d,numIdx:%d,r:%d,g:%d,b:%d)", _line, startColor, numColor, r, g, b); - - transformPaletteRange(startColor, numColor, r, g, b); - return 0; -} - -int FWScript::o1_setDefaultMenuColor2() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor2(%d)", _line, param); - defaultMenuBoxColor2 = param; - return 0; -} - -int FWScript::o1_palRotate() { - byte a = getNextByte(); - byte b = getNextByte(); - byte c = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: palRotate(%d,%d,%d)", _line, a, b, c); - palRotate(a, b, c); - return 0; -} - -/*!\brief Pause script - * \todo Make sure it works - */ -int FWScript::o1_break() { - debugC(5, kCineDebugScript, "Line: %d: break", _line); - - return 1; -} - -/*! \brief Terminate script - * \todo Make sure it works - */ -int FWScript::o1_endScript() { - debugC(5, kCineDebugScript, "Line: %d: endScript", _line); - - return -1; -} - -int FWScript::o1_message() { - byte param1 = getNextByte(); - uint16 param2 = getNextWord(); - uint16 param3 = getNextWord(); - uint16 param4 = getNextWord(); - uint16 param5 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: message(%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5); - - addMessage(param1, param2, param3, param4, param5); - return 0; -} - -int FWScript::o1_loadGlobalVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte dataIdx = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = var[%d]", _line, varIdx, dataIdx); - _globalVars[varIdx] = _localVars[dataIdx]; - } else { - debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = globalVars[%d]", _line, varIdx, dataIdx); - _globalVars[varIdx] = _globalVars[dataIdx]; - } - } else { - uint16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = %d", _line, varIdx, value); - _globalVars[varIdx] = value; - } - - return 0; -} - -int FWScript::o1_compareGlobalVar() { - byte varIdx = getNextByte(); - byte varType = getNextByte(); - - if (varType) { - byte value = getNextByte(); - - if (varType == 1) { - debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and var[%d]", _line, varIdx, value); - _compare = compareVars(_globalVars[varIdx], _localVars[value]); - } else { - debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and globalVars[%d]", _line, varIdx, value); - _compare = compareVars(_globalVars[varIdx], _globalVars[value]); - } - } else { - uint16 value = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value); - - if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) { // TODO: fix - _compare = 1; - } else { - _compare = compareVars(_globalVars[varIdx], value); - } - } - - return 0; -} - -int FWScript::o1_declareFunctionName() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: comment(%s)", _line, param); - return 0; -} - -int FWScript::o1_freePartRange() { - byte startIdx = getNextByte(); - byte numIdx = getNextByte(); - - assert(startIdx + numIdx <= NUM_MAX_ANIMDATA); - - debugC(5, kCineDebugScript, "Line: %d: freePartRange(%d,%d)", _line, startIdx, numIdx); - freeAnimDataRange(startIdx, numIdx); - return 0; -} - -int FWScript::o1_unloadAllMasks() { - debugC(5, kCineDebugScript, "Line: %d: unloadAllMasks()", _line); - unloadAllMasks(); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_setScreenDimensions() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - warning("STUB: o1_setScreenDimensions(%x, %x, %x, %x)", a, b, c, d); - // setupScreenParam - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_displayBackground() { - warning("STUB: o1_displayBackground()"); - return 0; -} - -int FWScript::o1_initializeZoneData() { - debugC(5, kCineDebugScript, "Line: %d: initializeZoneData()", _line); - - for (int i = 0; i < NUM_MAX_ZONE; i++) { - zoneData[i] = i; - } - return 0; -} - -int FWScript::o1_setZoneDataEntry() { - byte zoneIdx = getNextByte(); - uint16 var = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: setZone[%d] = %d", _line, zoneIdx, var); - zoneData[zoneIdx] = var; - return 0; -} - -int FWScript::o1_getZoneDataEntry() { - byte zoneIdx = getNextByte(); - byte var = getNextByte(); - - _localVars[var] = zoneData[zoneIdx]; - return 0; -} - -int FWScript::o1_setDefaultMenuColor() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor(%d)", _line, param); - defaultMenuBoxColor = param; - return 0; -} - -int FWScript::o1_allowPlayerInput() { - debugC(5, kCineDebugScript, "Line: %d: allowPlayerInput()", _line); - allowPlayerInput = 1; - return 0; -} - -int FWScript::o1_disallowPlayerInput() { - debugC(5, kCineDebugScript, "Line: %d: dissallowPlayerInput()", _line); - allowPlayerInput = 0; - return 0; -} - -int FWScript::o1_changeDataDisk() { - byte newDisk = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: changeDataDisk(%d)", _line, newDisk); - checkDataDisk(newDisk); - return 0; -} - -int FWScript::o1_loadMusic() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadMusic(%s)", _line, param); - g_sound->loadMusic(param); - return 0; -} - -int FWScript::o1_playMusic() { - debugC(5, kCineDebugScript, "Line: %d: playMusic()", _line); - g_sound->playMusic(); - return 0; -} - -int FWScript::o1_fadeOutMusic() { - debugC(5, kCineDebugScript, "Line: %d: fadeOutMusic()", _line); - g_sound->fadeOutMusic(); - return 0; -} - -int FWScript::o1_stopSample() { - debugC(5, kCineDebugScript, "Line: %d: stopSample()", _line); - g_sound->stopMusic(); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_op71() { - byte a = getNextByte(); - uint16 b = getNextWord(); - warning("STUB: o1_op71(%x, %x)", a, b); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_op72() { - uint16 a = getNextWord(); - byte b = getNextByte(); - uint16 c = getNextWord(); - warning("STUB: o1_op72(%x, %x, %x)", a, b, c); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o1_op73() { - // I believe this opcode is identical to o1_op72(). In fact, Operation - // Stealth doesn't even have it. It uses o1_op72() instead. - uint16 a = getNextWord(); - byte b = getNextByte(); - uint16 c = getNextWord(); - warning("STUB: o1_op72(%x, %x, %x)", a, b, c); - return 0; -} - -int FWScript::o1_playSample() { - debugC(5, kCineDebugScript, "Line: %d: playSample()", _line); - - byte anim = getNextByte(); - byte channel = getNextByte(); - - uint16 freq = getNextWord(); - byte repeat = getNextByte(); - - int16 volume = getNextWord(); - uint16 size = getNextWord(); - - const byte *data = animDataTable[anim].data(); - - if (!data) { - return 0; - } - - if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { - if (size == 0xFFFF) { - size = animDataTable[anim]._width * animDataTable[anim]._height; - } - if (channel < 10) { // || _currentOpcode == 0x78 - int channel1, channel2; - if (channel == 0) { - channel1 = 0; - channel2 = 1; - } else { - channel1 = 2; - channel2 = 3; - } - g_sound->playSound(channel1, freq, data, size, -1, volume, 63, repeat); - g_sound->playSound(channel2, freq, data, size, 1, volume, 0, repeat); - } else { - channel -= 10; - if (volume > 63) { - volume = 63; - } - g_sound->playSound(channel, freq, data, size, 0, 0, volume, repeat); - } - } else { - if (volume > 63 || volume < 0) { - volume = 63; - } - if (channel >= 10) { - channel -= 10; - } - if (volume < 50) { - volume = 50; - } - if (g_cine->getGameType() == Cine::GType_OS && size == 0) { - return 0; - } - g_sound->stopMusic(); - if (size == 0xFFFF) { - g_sound->playSound(channel, 0, data, 0, 0, 0, volume, 0); - } else { - g_sound->stopSound(channel); - } - } - return 0; -} - -int FWScript::o1_disableSystemMenu() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param); - disableSystemMenu = (param != 0); - return 0; -} - -int FWScript::o1_loadMask5() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addOverlay5(%d)", _line, param); - loadOverlayElement(param, 5); - return 0; -} - -int FWScript::o1_unloadMask5() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: freeOverlay5(%d)", _line, param); - freeOverlay(param, 5); - return 0; -} - -// ------------------------------------------------------------------------ -// OPERATION STEALTH opcodes -// ------------------------------------------------------------------------ - -int FWScript::o2_loadPart() { - const char *param = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param); - return 0; -} - -int FWScript::o2_playSample() { - if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { - // no-op in these versions - getNextByte(); - getNextByte(); - getNextWord(); - getNextByte(); - getNextWord(); - getNextWord(); - return 0; - } - return o1_playSample(); -} - -int FWScript::o2_playSampleAlt() { - byte num = getNextByte(); - byte channel = getNextByte(); - uint16 frequency = getNextWord(); - getNextByte(); - getNextWord(); - uint16 size = getNextWord(); - - if (size == 0xFFFF) { - size = animDataTable[num]._width * animDataTable[num]._height; - } - if (animDataTable[num].data()) { - if (g_cine->getPlatform() == Common::kPlatformPC) { - // if speaker output is available, play sound on it - // if it's another device, don't play anything - // TODO: implement this, it's used in the introduction for example - // on each letter displayed - } else { - g_sound->playSound(channel, frequency, animDataTable[num].data(), size, 0, 0, 63, 0); - } - } - return 0; -} - -int FWScript::o2_addSeqListElement() { - byte param1 = getNextByte(); - byte param2 = getNextByte(); - byte param3 = getNextByte(); - byte param4 = getNextByte(); - uint16 param5 = getNextWord(); - uint16 param6 = getNextWord(); - uint16 param7 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: addSeqListElement(%d,%d,%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5, param6, param7); - addSeqListElement(param1, 0, param2, param3, param4, param5, param6, 0, param7); - return 0; -} - -int FWScript::o2_removeSeq() { - byte a = getNextByte(); - byte b = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeSeq(%d,%d) -> TODO", _line, a, b); - removeSeq(a, 0, b); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op81() { - warning("STUB: o2_op81()"); - // freeUnkList(); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op82() { - byte a = getNextByte(); - byte b = getNextByte(); - uint16 c = getNextWord(); - warning("STUB: o2_op82(%x, %x, %x)", a, b, c); - return 0; -} - -int FWScript::o2_isSeqRunning() { - byte a = getNextByte(); - byte b = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b); - - if (isSeqRunning(a, 0, b)) { - _compare = 1; - } else { - _compare = 0; - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfSupNearest() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpGT) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfSupEquNearest() { - byte labelIdx = getNextByte(); - - if (_compare & (kCmpGT | kCmpEQ)) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfInfNearest() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpLT) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfInfEquNearest() { - byte labelIdx = getNextByte(); - - if (_compare & (kCmpLT | kCmpEQ)) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfEquNearest() { - byte labelIdx = getNextByte(); - - if (_compare == kCmpEQ) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -/*! \todo The assert may produce false positives and requires testing - */ -int FWScript::o2_gotoIfDiffNearest() { - byte labelIdx = getNextByte(); - - if (_compare != kCmpEQ) { - assert(_labels[labelIdx] != -1); - - debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (true)", _line, labelIdx); - _pos = _script.getLabel(*_info, labelIdx, _pos); - } else { - debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (false)", _line, labelIdx); - } - return 0; -} - -int FWScript::o2_startObjectScript() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: startObjectScript(%d)", _line, param); - runObjectScript(param); - return 0; -} - -int FWScript::o2_stopObjectScript() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: stopObjectScript(%d)", _line, param); - ScriptList::iterator it = objectScripts.begin(); - - for (; it != objectScripts.end(); ++it) { - if ((*it)->_index == param) { - (*it)->_index = -1; - } - } - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op8D() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - uint16 e = getNextWord(); - uint16 f = getNextWord(); - uint16 g = getNextWord(); - uint16 h = getNextWord(); - warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); - // _currentScriptElement->compareResult = ... - return 0; -} - -int FWScript::o2_addBackground() { - byte param1 = getNextByte(); - const char *param2 = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: addBackground(%s,%d)", _line, param2, param1); - addBackground(param2, param1); - return 0; -} - -int FWScript::o2_removeBackground() { - byte param = getNextByte(); - - assert(param); - - debugC(5, kCineDebugScript, "Line: %d: removeBackground(%d)", _line, param); - - if (additionalBgTable[param]) { - free(additionalBgTable[param]); - additionalBgTable[param] = NULL; - } - - if (currentAdditionalBgIdx == param) { - currentAdditionalBgIdx = 0; - } - - if (currentAdditionalBgIdx2 == param) { - currentAdditionalBgIdx2 = 0; - } - - strcpy(currentBgName[param], ""); - return 0; -} - -int FWScript::o2_loadAbs() { - byte param1 = getNextByte(); - const char *param2 = getNextString(); - - debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2); - loadAbs(param2, param1); - return 0; -} - -int FWScript::o2_loadBg() { - byte param = getNextByte(); - - assert(param <= 8); - - debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param); - - if (additionalBgTable[param]) { - currentAdditionalBgIdx = param; - if (param == 8) { - newColorMode = 3; - } else { - newColorMode = bgColorMode + 1; - } - //if (_screenNeedFadeOut == 0) { - // adBgVar1 = 1; - //} - fadeRequired = true; - } - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_wasZoneChecked() { - warning("STUB: o2_wasZoneChecked()"); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op9B() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - uint16 e = getNextWord(); - uint16 f = getNextWord(); - uint16 g = getNextWord(); - uint16 h = getNextWord(); - warning("STUB: o2_op9B(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op9C() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - uint16 c = getNextWord(); - uint16 d = getNextWord(); - warning("STUB: o2_op9C(%x, %x, %x, %x)", a, b, c, d); - return 0; -} - -int FWScript::o2_useBgScroll() { - byte param = getNextByte(); - - assert(param <= 8); - - debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param); - - if (additionalBgTable[param]) { - currentAdditionalBgIdx2 = param; - } - return 0; -} - -int FWScript::o2_setAdditionalBgVScroll() { - byte param1 = getNextByte(); - - if (param1) { - byte param2 = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = var[%d]", _line, param2); - additionalBgVScroll = _localVars[param2]; - } else { - uint16 param2 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2); - additionalBgVScroll = param2; - } - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_op9F() { - warning("o2_op9F()"); - getNextWord(); - getNextWord(); - return 0; -} - -int FWScript::o2_addGfxElementA0() { - uint16 param1 = getNextWord(); - uint16 param2 = getNextWord(); - - debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2); - addGfxElementA0(param1, param2); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_removeGfxElementA0() { - uint16 idx = getNextWord(); - uint16 param = getNextWord(); - warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param); - removeGfxElementA0(idx, param); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_opA2() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - warning("STUB: o2_opA2(%x, %x)", a, b); - // addGfxElementA2(); - return 0; -} - -/*! \todo Implement this instruction - */ -int FWScript::o2_opA3() { - uint16 a = getNextWord(); - uint16 b = getNextWord(); - warning("STUB: o2_opA3(%x, %x)", a, b); - // removeGfxElementA2(); - return 0; -} - -int FWScript::o2_loadMask22() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: addOverlay22(%d)", _line, param); - loadOverlayElement(param, 22); - return 0; -} - -int FWScript::o2_unloadMask22() { - byte param = getNextByte(); - - debugC(5, kCineDebugScript, "Line: %d: removeOverlay22(%d)", _line, param); - freeOverlay(param, 22); - return 0; -} - -//----------------------------------------------------------------------- - -void addGfxElementA0(int16 param1, int16 param2) { - overlayHeadElement *currentHead = &overlayHead; - overlayHeadElement *tempHead = currentHead; - overlayHeadElement *newElement; - - currentHead = tempHead->next; - - while (currentHead) { - if (objectTable[currentHead->objIdx].mask == objectTable[param1].mask) { - if (currentHead->type == 2 || currentHead->objIdx == 3) { - break; - } - } - - tempHead = currentHead; - currentHead = currentHead->next; - } - - if (currentHead && currentHead->objIdx == param1 && currentHead->type == 20 && currentHead->x == param2) - return; - - newElement = new overlayHeadElement; - - newElement->next = tempHead->next; - tempHead->next = newElement; - - newElement->objIdx = param1; - newElement->type = 20; - - newElement->x = param2; - newElement->y = 0; - newElement->width = 0; - newElement->color = 0; - - if (!currentHead) - currentHead = &overlayHead; - - newElement->previous = currentHead->previous; - - currentHead->previous = newElement; -} - -/*! \todo Check that it works - */ -void removeGfxElementA0(int16 idx, int16 param) { - overlayHeadElement *parent = &overlayHead; - overlayHeadElement *head = overlayHead.next; - overlayHeadElement *tmp; - - while (head) { - if (head->objIdx == idx && head->x == param) { - parent->next = head->next; - tmp = head->next ? head->next : &overlayHead; - tmp->previous = parent; - delete head; - return; - } - - parent = head; - head = head->next; - } -} - -void removeSeq(uint16 param1, uint16 param2, uint16 param3) { - SeqListElement *currentHead = &seqList; - SeqListElement *tempHead = currentHead; - - while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) { - tempHead = currentHead; - currentHead = tempHead->next; - } - - if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) { - currentHead->var4 = -1; - } -} - -uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { - SeqListElement *currentHead = &seqList; - SeqListElement *tempHead = currentHead; - - while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) { - tempHead = currentHead; - currentHead = tempHead->next; - } - - if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) { - return 1; - } - - return 0; -} - -void palRotate(byte a, byte b, byte c) { - if (c == 1) { - uint16 currentColor = c_palette[b]; - - for (int16 i = b; i > a; i--) { - c_palette[i] = c_palette[i - 1]; - } - - c_palette[a] = currentColor; - } -} - -void addScriptToList0(uint16 idx) { - ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx)); - assert(tmp); - globalScripts.push_back(tmp); -} - -int16 getZoneFromPosition(byte *page, int16 x, int16 y, int16 width) { - byte *ptr = page + (y * width) + x / 2; - byte zoneVar; - - if (!(x % 2)) { - zoneVar = (*(ptr) >> 4) & 0xF; - } else { - zoneVar = (*(ptr)) & 0xF; - } - - return zoneVar; -} - -int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) { - byte *ptr = page + (y * width) + x; - byte zoneVar; - - zoneVar = (*(ptr)) & 0xF; - - return zoneVar; -} - -int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) { - int16 lx = objectTable[objIdx].x + x; - int16 ly = objectTable[objIdx].y + y; - int16 idx; - - for (int16 i = 0; i < numZones; i++) { - idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320); - - assert(idx >= 0 && idx <= NUM_MAX_ZONE); - - if (zoneData[idx] == zoneIdx) { - return 1; - } - } - - return 0; -} - -uint16 compareVars(int16 a, int16 b) { - uint16 flag = 0; - - if (a == b) { - flag |= kCmpEQ; - } else if (a > b) { - flag |= kCmpGT; - } else if (a < b) { - flag |= kCmpLT; - } - - return flag; -} - -void executeList1(void) { - ScriptList::iterator it = objectScripts.begin(); - for (; it != objectScripts.end();) { - if ((*it)->_index < 0 || (*it)->execute() < 0) { - it = objectScripts.erase(it); - } else { - ++it; - } - } -} - -void executeList0(void) { - ScriptList::iterator it = globalScripts.begin(); - for (; it != globalScripts.end();) { - if ((*it)->_index < 0 || (*it)->execute() < 0) { - it = globalScripts.erase(it); - } else { - ++it; - } - } -} - -/*! \todo objectScripts.clear()? - */ -void purgeList1(void) { -} - -void purgeList0(void) { -} - -//////////////////////////////////// -// SCRIPT DECOMPILER - -#ifdef DUMP_SCRIPTS - -char decompileBuffer[10000][1000]; -uint16 decompileBufferPosition = 0; - -char bufferDec[256]; - -char compareString1[256]; -char compareString2[256]; - -const char *getObjPramName(byte paramIdx) { - switch (paramIdx) { - case 1: - return ".X"; - case 2: - return ".Y"; - case 3: - return ".mask"; - case 4: - return ".frame"; - case 5: - return ".status"; - case 6: - return ".costume"; - default: - sprintf(bufferDec, ".param%d", paramIdx); - return bufferDec; - } -} - -void decompileScript(byte *scriptPtr, int16 *stackPtr, uint16 scriptSize, uint16 scriptIdx) { - char lineBuffer[256]; - byte *localScriptPtr = scriptPtr; - uint16 exitScript; - uint32 position = 0; - - assert(scriptPtr); - // assert(stackPtr); - - exitScript = 0; - - sprintf(decompileBuffer[decompileBufferPosition++], "--------- SCRIPT %d ---------\n", scriptIdx); - - do { - uint16 opcode = *(localScriptPtr + position); - position++; - - if (position == scriptSize) { - opcode = 0; - } - - strcpy(lineBuffer, ""); - - switch (opcode - 1) { - case -1: - { - break; - } - case 0x0: - { - byte param1; - byte param2; - int16 param3; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "obj[%d]%s = %d\n", param1, getObjPramName(param2), param3); - - break; - } - case 0x1: - { - byte param1; - byte param2; - byte param3; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "var[%d]=obj[%d]%s\n", param3, param1, getObjPramName(param2)); - break; - } - case 0x2: - case 0x3: - case 0x4: - case 0x5: - case 0x6: - { - byte param1; - byte param2; - int16 param3; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - if (opcode - 1 == 0x2) { - sprintf(lineBuffer, "obj[%d]%s+=%d\n", param1, getObjPramName(param2), param3); - } else if (opcode - 1 == 0x3) { - sprintf(lineBuffer, "obj[%d]%s-=%d\n", param1, getObjPramName(param2), param3); - } else if (opcode - 1 == 0x4) { - sprintf(lineBuffer, "obj[%d]%s+=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2)); - } else if (opcode - 1 == 0x5) { - sprintf(lineBuffer, "obj[%d]%s-=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2)); - } else if (opcode - 1 == 0x6) { - sprintf(compareString1, "obj[%d]%s", param1, getObjPramName(param2)); - sprintf(compareString2, "%d", param3); - } - break; - } - case 0x7: - case 0x8: - { - byte param1; - int16 param2; - int16 param3; - int16 param4; - int16 param5; - - param1 = *(localScriptPtr + position); - position++; - - param2 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - if (opcode - 1 == 0x7) { - sprintf(lineBuffer, "setupObject(Idx:%d,X:%d,Y:%d,mask:%d,frame:%d)\n", param1, param2, param3, param4, param5); - } else if (opcode - 1 == 0x8) { - sprintf(lineBuffer, "checkCollision(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); - } - break; - } - case 0x9: - { - byte param1; - int16 param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - if (param2) { - byte param3; - - param3 = *(localScriptPtr + position); - position++; - - if (param2 == 1) { - sprintf(lineBuffer, "var[%d]=var[%d]\n", param1, param3); - } else if (param2 == 2) { - sprintf(lineBuffer, "var[%d]=globalVar[%d]\n", param1, param3); - } else if (param2 == 3) { - sprintf(lineBuffer, "var[%d]=mouse.X\n", param1); - } else if (param2 == 4) { - sprintf(lineBuffer, "var[%d]=mouse.Y\n", param1); - } else if (param2 == 5) { - sprintf(lineBuffer, "var[%d]=rand() mod %d\n", param1, param3); - } else if (param2 == 8) { - sprintf(lineBuffer, "var[%d]=file[%d].packedSize\n", param1, param3); - } else if (param2 == 9) { - sprintf(lineBuffer, "var[%d]=file[%d].unpackedSize\n", param1, param3); - } else { - error("decompileScript: 0x09: param2 = %d", param2); - } - } else { - int16 param3; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "var[%d]=%d\n", param1, param3); - } - - break; - } - case 0xA: - case 0xB: - case 0xC: - case 0xD: - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - if (param2) { - byte param3; - - param3 = *(localScriptPtr + position); - position++; - - if (opcode - 1 == 0xA) { - sprintf(lineBuffer, "var[%d]+=var[%d]\n", param1, param3); - } else if (opcode - 1 == 0xB) { - sprintf(lineBuffer, "var[%d]-=var[%d]\n", param1, param3); - } else if (opcode - 1 == 0xC) { - sprintf(lineBuffer, "var[%d]*=var[%d]\n", param1, param3); - } else if (opcode - 1 == 0xD) { - sprintf(lineBuffer, "var[%d]/=var[%d]\n", param1, param3); - } - } else { - int16 param3; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - if (opcode - 1 == 0xA) { - sprintf(lineBuffer, "var[%d]+=%d\n", param1, param3); - } else if (opcode - 1 == 0xB) { - sprintf(lineBuffer, "var[%d]-=%d\n", param1, param3); - } else if (opcode - 1 == 0xC) { - sprintf(lineBuffer, "var[%d]*=%d\n", param1, param3); - } else if (opcode - 1 == 0xD) { - sprintf(lineBuffer, "var[%d]/=%d\n", param1, param3); - } - } - break; - } - case 0xE: - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - if (param2) { - byte param3; - - param3 = *(localScriptPtr + position); - position++; - - if (param2 == 1) { - sprintf(compareString1, "var[%d]", param1); - sprintf(compareString2, "var[%d]", param3); - - } else if (param2 == 2) { - sprintf(compareString1, "var[%d]", param1); - sprintf(compareString2, "globalVar[%d]", param3); - } else { - error("decompileScript: 0x0E: param2 = %d", param2); - } - } else { - int16 param3; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(compareString1, "var[%d]", param1); - sprintf(compareString2, "%d", param3); - } - break; - } - case 0xF: - { - byte param1; - byte param2; - byte param3; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "obj[%d]%s=var[%d]\n", param1, getObjPramName(param2), param3); - - break; - } - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - if (opcode - 1 == 0x13) { - sprintf(lineBuffer, "loadMask0(%d)\n", param); - } else if (opcode - 1 == 0x14) { - sprintf(lineBuffer, "unloadMask0(%d)\n", param); - } else if (opcode - 1 == 0x15) { - sprintf(lineBuffer, "OP_15(%d)\n", param); - } else if (opcode - 1 == 0x16) { - sprintf(lineBuffer, "loadMask1(%d)\n", param); - } else if (opcode - 1 == 0x17) { - sprintf(lineBuffer, "unloadMask0(%d)\n", param); - } else if (opcode - 1 == 0x18) { - sprintf(lineBuffer, "loadMask4(%d)\n", param); - } else if (opcode - 1 == 0x19) { - sprintf(lineBuffer, "unloadMask4(%d)\n", param); - } - break; - } - case 0x1A: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_1A(%d)\n", param); - - break; - } - case 0x1B: - { - sprintf(lineBuffer, "bgIncrustList.clear()\n"); - break; - } - case 0x1D: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "label(%d)\n", param); - - break; - } - case 0x1E: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "goto(%d)\n", param); - - break; - } - // If cases - case 0x1F: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - if (opcode - 1 == 0x1F) { - sprintf(lineBuffer, "if(%s>%s) goto(%d)\n", compareString1, compareString2, param); - } else if (opcode - 1 == 0x20) { - sprintf(lineBuffer, "if(%s>=%s) goto(%d)\n", compareString1, compareString2, param); - } else if (opcode - 1 == 0x21) { - sprintf(lineBuffer, "if(%s<%s) goto(%d)\n", compareString1, compareString2, param); - } else if (opcode - 1 == 0x22) { - sprintf(lineBuffer, "if(%s<=%s) goto(%d)\n", compareString1, compareString2, param); - } else if (opcode - 1 == 0x23) { - sprintf(lineBuffer, "if(%s==%s) goto(%d)\n", compareString1, compareString2, param); - } else if (opcode - 1 == 0x24) { - sprintf(lineBuffer, "if(%s!=%s) goto(%d)\n", compareString1, compareString2, param); - } - break; - } - case 0x25: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "removeLabel(%d)\n", param); - - break; - } - case 0x26: - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "loop(--var[%d]) -> label(%d)\n", param1, param2); - - break; - } - case 0x31: - case 0x32: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - if (opcode - 1 == 0x31) { - sprintf(lineBuffer, "startGlobalScript(%d)\n", param); - } else if (opcode - 1 == 0x32) { - sprintf(lineBuffer, "endGlobalScript(%d)\n", param); - } - break; - } - case 0x3B: - case 0x3C: - case 0x3D: - case OP_loadPart: - { - if (opcode - 1 == 0x3B) { - sprintf(lineBuffer, "loadResource(%s)\n", localScriptPtr + position); - } else if (opcode - 1 == 0x3C) { - sprintf(lineBuffer, "loadBg(%s)\n", localScriptPtr + position); - } else if (opcode - 1 == 0x3D) { - sprintf(lineBuffer, "loadCt(%s)\n", localScriptPtr + position); - } else if (opcode - 1 == OP_loadPart) { - sprintf(lineBuffer, "loadPart(%s)\n", localScriptPtr + position); - } - - position += strlen((char *)localScriptPtr + position) + 1; - break; - } - case 0x40: - { - sprintf(lineBuffer, "closePart()\n"); - break; - } - case OP_loadNewPrcName: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "loadPrc(%d,%s)\n", param, localScriptPtr + position); - - position += strlen((char *)localScriptPtr + position) + 1; - break; - } - case OP_requestCheckPendingDataLoad: // nop - { - sprintf(lineBuffer, "requestCheckPendingDataLoad()\n"); - break; - } - case 0x45: - { - sprintf(lineBuffer, "blitAndFade()\n"); - break; - } - case 0x46: - { - sprintf(lineBuffer, "fadeToBlack()\n"); - break; - } - case 0x47: - { - byte param1; - byte param2; - int16 param3; - int16 param4; - int16 param5; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "transformPaletteRange(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); - - break; - } - case 0x49: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "setDefaultMenuColor2(%d)\n", param); - - break; - } - case 0x4F: - { - sprintf(lineBuffer, "break()\n"); - exitScript = 1; - break; - } - case 0x50: - { - sprintf(lineBuffer, "endScript()\n\n"); - break; - } - case 0x51: - { - byte param1; - int16 param2; - int16 param3; - int16 param4; - int16 param5; - - param1 = *(localScriptPtr + position); - position++; - - param2 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "message(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); - - break; - } - case 0x52: - case 0x53: - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - if (param2) { - byte param3; - - param3 = *(localScriptPtr + position); - position++; - - if (param2 == 1) { - if (opcode - 1 == 0x52) { - sprintf(lineBuffer, "globalVar[%d] = var[%d]\n", param1, param3); - } else if (opcode - 1 == 0x53) { - sprintf(compareString1, "globalVar[%d]", param1); - sprintf(compareString2, "var[%d]", param3); - } - } else if (param2 == 2) { - if (opcode - 1 == 0x52) { - sprintf(lineBuffer, "globalVar[%d] = globalVar[%d]\n", param1, param3); - } else if (opcode - 1 == 0x53) { - sprintf(compareString1, "globalVar[%d]", param1); - sprintf(compareString2, "globalVar[%d]", param3); - } - } else { - if (opcode - 1 == 0x52) { - error("decompileScript: 0x52: param2 = %d", param2); - } else if (opcode - 1 == 0x53) { - error("decompileScript: 0x53: param2 = %d", param2); - } - } - } else { - int16 param3; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - if (opcode - 1 == 0x52) { - sprintf(lineBuffer, "globalVar[%d] = %d\n", param1, param3); - } else if (opcode - 1 == 0x53) { - sprintf(compareString1, "globalVar[%d]", param1); - sprintf(compareString2, "%d", param3); - } - } - break; - } - case 0x59: - { - sprintf(lineBuffer, "comment: %s\n", localScriptPtr + position); - - position += strlen((char *)localScriptPtr + position); - break; - } - case 0x5A: - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "freePartRang(%d,%d)\n", param1, param2); - - break; - } - case 0x5B: - { - sprintf(lineBuffer, "unloadAllMasks()\n"); - break; - } - case 0x65: - { - sprintf(lineBuffer, "setupTableUnk1()\n"); - break; - } - case 0x66: - { - byte param1; - int16 param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "tableUnk1[%d] = %d\n", param1, param2); - - break; - } - case 0x68: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "setDefaultMenuBoxColor(%d)\n", param); - - break; - } - case 0x69: - { - sprintf(lineBuffer, "allowPlayerInput()\n"); - break; - } - case 0x6A: - { - sprintf(lineBuffer, "disallowPlayerInput()\n"); - break; - } - case 0x6B: - { - byte newDisk; - - newDisk = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "changeDataDisk(%d)\n", newDisk); - - break; - } - case 0x6D: - { - sprintf(lineBuffer, "loadDat(%s)\n", localScriptPtr + position); - - position += strlen((char *)localScriptPtr + position) + 1; - break; - } - case 0x6E: // nop - { - sprintf(lineBuffer, "updateDat()\n"); - break; - } - case 0x6F: - { - sprintf(lineBuffer, "OP_6F() -> dat related\n"); - break; - } - case 0x70: - { - sprintf(lineBuffer, "stopSample()\n"); - break; - } - case 0x79: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "disableSystemMenu(%d)\n", param); - - break; - } - case 0x77: - case 0x78: - { - byte param1; - byte param2; - int16 param3; - byte param4; - int16 param5; - int16 param6; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = *(localScriptPtr + position); - position++; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param6 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - if (opcode - 1 == 0x77) { - sprintf(lineBuffer, "playSample(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6); - } else if (opcode - 1 == 0x78) { - sprintf(lineBuffer, "OP_78(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6); - } - - break; - } - case 0x7A: - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_7A(%d)\n", param); - - break; - } - case 0x7B: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_7B(%d)\n", param); - - break; - } - case 0x7F: // OS only - { - byte param1; - byte param2; - byte param3; - byte param4; - int16 param5; - int16 param6; - int16 param7; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = *(localScriptPtr + position); - position++; - - param4 = *(localScriptPtr + position); - position++; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param6 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param7 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "OP_7F(%d,%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6, param7); - - break; - } - case 0x80: // OS only - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_80(%d,%d)\n", param1, param2); - - break; - } - case 0x82: // OS only - { - byte param1; - byte param2; - uint16 param3; - uint16 param4; - byte param5; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param5 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_82(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); - - break; - } - case 0x83: // OS only - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_83(%d,%d)\n", param1, param2); - - break; - } - case 0x89: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "if(%s!=%s) goto next label(%d)\n", compareString1, compareString2, param); - - break; - } - case 0x8B: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_8B(%d)\n", param); - - break; - } - case 0x8C: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_8C(%d)\n", param); - - break; - } - case 0x8D: // OS only - { - int16 param1; - int16 param2; - int16 param3; - int16 param4; - int16 param5; - int16 param6; - int16 param7; - int16 param8; - - param1 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param2 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param3 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param4 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param5 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param6 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param7 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - param8 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(compareString1, "obj[%d]", param1); - sprintf(compareString2, "{%d,%d,%d,%d,%d,%d,%d}", param2, param3, param4, param5, param6, param7, param8); - - break; - } - case 0x8E: // OS only - { - byte param1; - - param1 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "ADDBG(%d,%s)\n", param1, localScriptPtr + position); - - position += strlen((char *)localScriptPtr + position); - - break; - } - case 0x8F: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_8F(%d)\n", param); - - break; - } - case 0x90: // OS only - { - byte param1; - - param1 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "loadABS(%d,%s)\n", param1, localScriptPtr + position); - - position += strlen((char *)localScriptPtr + position); - - break; - } - case 0x91: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_91(%d)\n", param); - - break; - } - case 0x9D: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_9D(%d) -> flip img idx\n", param); - - break; - } - case 0x9E: // OS only - { - byte param; - - param = *(localScriptPtr + position); - position++; - - if (param) { - byte param2; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2); - } else { - int16 param2; - - param2 = READ_BE_UINT16(localScriptPtr + position); - position += 2; - - sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2); - } - - break; - } - case 0xA0: // OS only - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_A0(%d,%d)\n", param1, param2); - - break; - } - case 0xA1: // OS only - { - byte param1; - byte param2; - - param1 = *(localScriptPtr + position); - position++; - - param2 = *(localScriptPtr + position); - position++; - - sprintf(lineBuffer, "OP_A1(%d,%d)\n", param1, param2); - - break; - } - default: - { - sprintf(lineBuffer, "Unsupported opcode %X in decompileScript\n\n", opcode - 1); - position = scriptSize; - break; - } - } - - // printf(lineBuffer); - strcpy(decompileBuffer[decompileBufferPosition++], lineBuffer); - - exitScript = 0; - if (position >= scriptSize) { - exitScript = 1; - } - - } while (!exitScript); -} - -void dumpScript(char *dumpName) { - Common::File fHandle; - uint16 i; - - fHandle.open(dumpName, Common::File::kFileWriteMode); - - for (i = 0; i < decompileBufferPosition; i++) { - fHandle.writeString(Common::String(decompileBuffer[i])); - } - - fHandle.close(); - - decompileBufferPosition = 0; -} - -#endif - -} // End of namespace Cine diff --git a/engines/cine/script.h b/engines/cine/script.h index 4bcf4b6ccb..4a2e7072ee 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -358,6 +358,7 @@ typedef Common::Array RawObjectScriptArray; extern RawScriptArray scriptTable; extern FWScriptInfo *scriptInfo; +extern ScriptVars globalVars; void setupOpcodes(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp new file mode 100644 index 0000000000..f833d7c30b --- /dev/null +++ b/engines/cine/script_fw.cpp @@ -0,0 +1,2945 @@ +/* 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$ + * + */ + +/*! \file + * Future Wars script interpreter file + */ + +#include "common/endian.h" + +#include "cine/cine.h" +#include "cine/bg_list.h" +#include "cine/object.h" +#include "cine/sound.h" +#include "cine/various.h" +#include "cine/script.h" + +namespace Cine { + +ScriptVars globalVars(NUM_MAX_VAR); + +uint16 compareVars(int16 a, int16 b); +void palRotate(byte a, byte b, byte c); +void removeSeq(uint16 param1, uint16 param2, uint16 param3); +uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); +void addGfxElementA0(int16 param1, int16 param2); +void removeGfxElementA0(int16 idx, int16 param); + +const Opcode FWScript::_opcodeTable[] = { + /* 00 */ + { &FWScript::o1_modifyObjectParam, "bbw" }, + { &FWScript::o1_getObjectParam, "bbb" }, + { &FWScript::o1_addObjectParam, "bbw" }, + { &FWScript::o1_subObjectParam, "bbw" }, + /* 04 */ + { &FWScript::o1_add2ObjectParam, "bbw" }, + { &FWScript::o1_sub2ObjectParam, "bbw" }, + { &FWScript::o1_compareObjectParam, "bbw" }, + { &FWScript::o1_setupObject, "bwwww" }, + /* 08 */ + { &FWScript::o1_checkCollision, "bwwww" }, + { &FWScript::o1_loadVar, "bc" }, + { &FWScript::o1_addVar, "bc" }, + { &FWScript::o1_subVar, "bc" }, + /* 0C */ + { &FWScript::o1_mulVar, "bc" }, + { &FWScript::o1_divVar, "bc" }, + { &FWScript::o1_compareVar, "bc" }, + { &FWScript::o1_modifyObjectParam2, "bbb" }, + /* 10 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_loadMask0, "b" }, + /* 14 */ + { &FWScript::o1_unloadMask0, "b" }, + { &FWScript::o1_addToBgList, "b" }, + { &FWScript::o1_loadMask1, "b" }, + { &FWScript::o1_unloadMask1, "b" }, + /* 18 */ + { &FWScript::o1_loadMask4, "b" }, + { &FWScript::o1_unloadMask4, "b" }, + { &FWScript::o1_addSpriteFilledToBgList, "b" }, + { &FWScript::o1_op1B, "" }, + /* 1C */ + { 0, 0 }, + { &FWScript::o1_label, "l" }, + { &FWScript::o1_goto, "b" }, + { &FWScript::o1_gotoIfSup, "b" }, + /* 20 */ + { &FWScript::o1_gotoIfSupEqu, "b" }, + { &FWScript::o1_gotoIfInf, "b" }, + { &FWScript::o1_gotoIfInfEqu, "b" }, + { &FWScript::o1_gotoIfEqu, "b" }, + /* 24 */ + { &FWScript::o1_gotoIfDiff, "b" }, + { &FWScript::o1_removeLabel, "b" }, + { &FWScript::o1_loop, "bb" }, + { 0, 0 }, + /* 28 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 2C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 30 */ + { 0, 0 }, + { &FWScript::o1_startGlobalScript, "b" }, + { &FWScript::o1_endGlobalScript, "b" }, + { 0, 0 }, + /* 34 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 38 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_loadAnim, "s" }, + /* 3C */ + { &FWScript::o1_loadBg, "s" }, + { &FWScript::o1_loadCt, "s" }, + { 0, 0 }, + { &FWScript::o1_loadPart, "s" }, + /* 40 */ + { &FWScript::o1_closePart, "" }, + { &FWScript::o1_loadNewPrcName, "bs" }, + { &FWScript::o1_requestCheckPendingDataLoad, "" }, + { 0, 0 }, + /* 44 */ + { 0, 0 }, + { &FWScript::o1_blitAndFade, "" }, + { &FWScript::o1_fadeToBlack, "" }, + { &FWScript::o1_transformPaletteRange, "bbwww" }, + /* 48 */ + { 0, 0 }, + { &FWScript::o1_setDefaultMenuColor2, "b" }, + { &FWScript::o1_palRotate, "bbb" }, + { 0, 0 }, + /* 4C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_break, "" }, + /* 50 */ + { &FWScript::o1_endScript, "x" }, + { &FWScript::o1_message, "bwwww" }, + { &FWScript::o1_loadGlobalVar, "bc" }, + { &FWScript::o1_compareGlobalVar, "bc" }, + /* 54 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 58 */ + { 0, 0 }, + { &FWScript::o1_declareFunctionName, "s" }, + { &FWScript::o1_freePartRange, "bb" }, + { &FWScript::o1_unloadAllMasks, "" }, + /* 5C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 60 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_setScreenDimensions, "wwww" }, + /* 64 */ + { &FWScript::o1_displayBackground, "" }, + { &FWScript::o1_initializeZoneData, "" }, + { &FWScript::o1_setZoneDataEntry, "bw" }, + { &FWScript::o1_getZoneDataEntry, "bb" }, + /* 68 */ + { &FWScript::o1_setDefaultMenuColor, "b" }, + { &FWScript::o1_allowPlayerInput, "" }, + { &FWScript::o1_disallowPlayerInput, "" }, + { &FWScript::o1_changeDataDisk, "b" }, + /* 6C */ + { 0, 0 }, + { &FWScript::o1_loadMusic, "s" }, + { &FWScript::o1_playMusic, "" }, + { &FWScript::o1_fadeOutMusic, "" }, + /* 70 */ + { &FWScript::o1_stopSample, "" }, + { &FWScript::o1_op71, "bw" }, + { &FWScript::o1_op72, "wbw" }, + { &FWScript::o1_op73, "wbw" }, + /* 74 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_playSample, "bbwbww" }, + /* 78 */ + { &FWScript::o1_playSample, "bbwbww" }, + { &FWScript::o1_disableSystemMenu, "b" }, + { &FWScript::o1_loadMask5, "b" }, + { &FWScript::o1_unloadMask5, "b" } +}; +const unsigned int FWScript::_numOpcodes = ARRAYSIZE(FWScript::_opcodeTable); + +FWScriptInfo *scriptInfo; ///< Script factory +RawScriptArray scriptTable; ///< Table of script bytecode + +/*! \todo: replace with script subsystem + */ +void setupOpcodes() { + static FWScriptInfo fw; + static OSScriptInfo os; + if (g_cine->getGameType() == Cine::GType_FW) { + scriptInfo = &fw; + } else { + scriptInfo = &os; + } +} + +/*! \brief Allocate empty array + * \param len Size of array + * + * Explicit to prevent var=0 instead of var[i]=0 typos. + */ +ScriptVars::ScriptVars(unsigned int len) : _size(len), _vars(new int16[len]) { + assert(_vars); + reset(); +} + +/*! \brief Allocate array and read contents from savefile + * \param fHandle Savefile open for reading + * \param len Size of array + */ +ScriptVars::ScriptVars(Common::InSaveFile &fHandle, unsigned int len) + : _size(len), _vars(new int16[len]) { + + assert(_vars); + + load(fHandle); +} + +/*! \brief Copy constructor + */ +ScriptVars::ScriptVars(const ScriptVars &src) : _size(src._size), _vars(new int16[_size]) { + assert(_vars); + memcpy(_vars, src._vars, _size * sizeof(int16)); +} + +/*! \brief Destructor + */ +ScriptVars::~ScriptVars(void) { + delete[] _vars; +} + +/*! \brief Assignment operator + */ +ScriptVars &ScriptVars::operator=(const ScriptVars &src) { + ScriptVars tmp(src); + int16 *tmpvars = _vars; + + _vars = tmp._vars; + tmp._vars = tmpvars; + _size = src._size; + + return *this; +} + +/*! \brief Direct array item access + * \param idx Item index + * \return Reference to item + */ +int16 &ScriptVars::operator[](unsigned int idx) { + debug(6, "assert(%d < %d)", idx, _size); + assert(idx < _size); + return _vars[idx]; +} + +/*! \brief Direct read-only array item access + * \param idx Item index + * \return Copy of item + */ +int16 ScriptVars::operator[](unsigned int idx) const { + debug(6, "assert(%d < %d)", idx, _size); + assert(idx < _size); + return _vars[idx]; +} + +/*! \brief Savefile writer + * \param fHandle Savefile open for writing + */ +void ScriptVars::save(Common::OutSaveFile &fHandle) const { + save(fHandle, _size); +} + +/*! \brief Savefile writer with data length limit + * \param fHandle Savefile open for writing + * \param len Length of data to be written (len <= _size) + */ +void ScriptVars::save(Common::OutSaveFile &fHandle, unsigned int len) const { + debug(6, "assert(%d <= %d)", len, _size); + assert(len <= _size); + for (unsigned int i = 0; i < len; i++) { + fHandle.writeUint16BE(_vars[i]); + } +} + +/*! \brief Restore array from savefile + * \param fHandle Savefile open for reading + */ +void ScriptVars::load(Common::InSaveFile &fHandle) { + load(fHandle, _size); +} + +/*! \brief Restore part of array from savefile + * \param fHandle Savefile open for reading + * \param len Length of data to be read + */ +void ScriptVars::load(Common::InSaveFile &fHandle, unsigned int len) { + debug(6, "assert(%d <= %d)", len, _size); + assert(len <= _size); + for (unsigned int i = 0; i < len; i++) { + _vars[i] = fHandle.readUint16BE(); + } +} + +/*! \brief Reset all values to 0 + */ +void ScriptVars::reset(void) { + memset( _vars, 0, _size * sizeof(int16)); +} + +/*! \brief Constructor for partial loading + * \param s Size of bytecode which will be added later + * + * This constructor _MUST_ be followed by setdata() method call before the + * instance can be used. It leaves the instance in partially invalid state. + */ +RawScript::RawScript(uint16 s) : _size(s), _data(NULL), + _labels(SCRIPT_STACK_SIZE) { } + +/*! \brief Complete constructor + * \param data Script bytecode + * \param s Bytecode length + */ +RawScript::RawScript(const FWScriptInfo &info, const byte *data, uint16 s) : + _size(s), _data(NULL), _labels(SCRIPT_STACK_SIZE) { + + setData(info, data); +} + +/*! \brief Copy constructor + */ +RawScript::RawScript(const RawScript &src) : _size(src._size), + _data(new byte[_size+1]), _labels(src._labels) { + + assert(_data); + memcpy(_data, src._data, _size+1); +} + +/*! \brief Destructor + */ +RawScript::~RawScript(void) { + delete[] _data; +} + +/*! \brief Assignment operator + */ +RawScript &RawScript::operator=(const RawScript &src) { + assert(src._data); + byte *tmp = new byte[src._size+1]; + + assert(tmp); + _labels = src._labels; + _size = src._size; + + delete[] _data; + _data = tmp; + memcpy(_data, src._data, _size); + _data[_size] = 0; + + return *this; +} + +/*! \brief Get the next label in bytecode + * \param info Script info instance + * \param offset Starting offset + * \return Index of the next label in bytecode or _size on end of bytecode + * + * computeScriptStackSub replacement + */ +int RawScript::getNextLabel(const FWScriptInfo &info, int offset) const { + assert(_data); + int pos = offset; + + assert(pos >= 0); + + while (pos < _size) { + uint8 opcode = _data[pos++]; + const char *ptr = info.opcodeInfo(opcode); + + if (!ptr) { + continue; + } + + for (; *ptr; ++ptr) { + switch (*ptr) { + case 'b': // byte + pos++; + break; + case 'w': // word + pos += 2; + break; + case 'c': { // byte != 0 ? byte : word + uint8 test = _data[pos]; + pos++; + if (test) { + pos++; + } else { + pos += 2; + } + } + break; + case 'l': // label + return pos; + case 's': // string + while (_data[pos++] != 0); + break; + case 'x': // exit script + return -pos-1; + } + } + } + return _size; +} + +/*! \brief Calculate initial script labels + * \param info Script info instance + * + * computeScriptStack replacement + */ +void RawScript::computeLabels(const FWScriptInfo &info) { + assert(_data); + int pos = 0; + int i; + + // reset labels + for (i = 0; i < SCRIPT_STACK_SIZE; i++) { + _labels[i] = -1; + } + + // parse bytecode + while ((pos = getNextLabel(info, pos)) >= 0) { + i = _data[pos]; + _labels[i] = ++pos; + } +} + +/*! \brief find the next label from current position + * \param info Script info instance + * \param index Label index to look for + * \param offset Current position in script + * \return Position of next instruction following the label + * + * computeScriptStackFromScript replacement + */ +uint16 RawScript::getLabel(const FWScriptInfo &info, byte index, uint16 offset) + const { + + assert(_data); + int pos = offset; + + while ((pos = getNextLabel(info, pos)) >= 0) { + if (_data[pos++] == index) { + return pos; + } + } + + return -pos - 1; +} + +/*! \brief Copy bytecode and calculate labels + * \param data Bytecode to copy, must be _size long + */ +void RawScript::setData(const FWScriptInfo &info, const byte *data) { + assert(!_data); // this function should be called only once per instance + _data = new byte[_size+1]; + + assert(data && _data); + memcpy(_data, data, _size * sizeof(byte)); + _data[_size] = 0; + + computeLabels(info); +} + +/*! \brief Initial script labels + * \return Precalculated script labels + */ +const ScriptVars &RawScript::labels(void) const { + assert(_data); + return _labels; +} + +/*! \brief One byte of bytecode + * \param pos Index in bytecode + * \return Byte from bytecode + */ +byte RawScript::getByte(unsigned int pos) const { + assert(_data && pos < _size); + + return _data[pos]; +} + +/*! \brief One word of bytecode + * \param pos Index of the first byte in bytecode + * \return Word of bytecode + */ +uint16 RawScript::getWord(unsigned int pos) const { + assert(_data && pos+1 < _size); + + return READ_BE_UINT16(_data + pos); +} + +/*! \brief String in bytecode + * \param pos Index of the first char in string + * \return Pointer to part of bytecode + */ +const char *RawScript::getString(unsigned int pos) const { + assert(_data && pos < _size); + + return (const char*)(_data+pos); +} + +/*! \brief Constructor for partial loading + * \param size Size of bytecode which will be added later + * \param p1 First object script parameter + * \param p2 Second object script parameter + * \param p3 Third object script parameter + * + * This constructor _MUST_ be followed by setdata() method call before the + * instance can be used. It leaves the instance in partially invalid state. + */ +RawObjectScript::RawObjectScript(uint16 s, uint16 p1, uint16 p2, uint16 p3) + : RawScript(s), _runCount(0), _param1(p1), _param2(p2), _param3(p3) +{ } + +/*! \brief Complete constructor + * \param data Script bytecode + * \param s Bytecode length + * \param p1 First object script parameter + * \param p2 Second object script parameter + * \param p3 Third object script parameter + */ +RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data, + uint16 s, uint16 p1, uint16 p2, uint16 p3) : RawScript(info, data, s), + _runCount(0), _param1(p1), _param2(p2), _param3(p3) { } + +/*! \brief Contructor for global scripts + * \param script Script bytecode reference + * \param idx Script bytecode index + */ +FWScript::FWScript(const RawScript &script, int16 idx) : _script(script), + _pos(0), _line(0), _compare(0), _index(idx), + _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), + _globalVars(globalVars), _info(new FWScriptInfo) { } + +/*! \brief Copy constructor + */ +FWScript::FWScript(const FWScript &src) : _script(src._script), _pos(src._pos), + _line(src._line), _compare(src._compare), _index(src._index), + _labels(src._labels), _localVars(src._localVars), + _globalVars(src._globalVars), _info(new FWScriptInfo) { } + +/*! \brief Contructor for global scripts in derived classes + * \param script Script bytecode reference + * \param idx Script bytecode index + */ +FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) : + _script(script), _pos(0), _line(0), _compare(0), _index(idx), + _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), + _globalVars(globalVars), _info(info) { } + +/*! \brief Constructor for object scripts in derived classes + * \param script Script bytecode reference + * \param idx Script bytecode index + */ +FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) : + _script(script), _pos(0), _line(0), _compare(0), _index(idx), + _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), + _globalVars(globalVars), _info(info) { + + _localVars[0] = script.run(); +} + +/*! \brief Copy constructor for derived classes + */ +FWScript::FWScript(const FWScript &src, FWScriptInfo *info) : + _script(src._script), _pos(src._pos), _line(src._line), + _compare(src._compare), _index(src._index), _labels(src._labels), + _localVars(src._localVars), _globalVars(src._globalVars), _info(info) { } + +FWScript::~FWScript(void) { + delete _info; +} + +/*! \brief Read next byte from bytecode + * \return Byte from bytecode + */ +byte FWScript::getNextByte() { + byte val = _script.getByte(_pos); + _pos++; + return val; +} + +/*! \brief Read next word from bytecode + * \return Word from bytecode + */ +uint16 FWScript::getNextWord() { + uint16 val = _script.getWord(_pos); + _pos += 2; + return val; +} + +/*! \brief Read next string from bytecode + * \return Pointer to string + */ +const char *FWScript::getNextString() { + const char *val = _script.getString(_pos); + _pos += strlen(val) + 1; + return val; +} + +/*! \brief Restore script state from savefile + * \param labels Restored script labels + * \param local Restored local script variables + * \param compare Restored last comparison result + * \param pos Restored script position + */ +void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { + assert(pos < _script._size); + _labels = labels; + _localVars = local; + _compare = compare; + _pos = _line = pos; +} + +/*! \brief Execute script + * \return <0 on script termination, >0 on script pause + * + * executeScript replacement. + * Instruction handler must return 0 if the script should continue or + * nonzero with the same meaning as return value of this function + */ +int FWScript::execute() { + int ret = 0; + + while (!ret) { + _line = _pos; + byte opcode = getNextByte(); + opFunc handler = _info->opcodeHandler(opcode); + + if (handler) { + ret = (this->*handler)(); + } + } + + return ret; +} + +/*! \brief Save script to savefile + * \param fHandle Savefile handle + */ +void FWScript::save(Common::OutSaveFile &fHandle) const { + _labels.save(fHandle); + _localVars.save(fHandle); + fHandle.writeUint16BE(_compare); + fHandle.writeUint16BE(_pos); + // data order sucks... + fHandle.writeUint16BE(_index); +} + +/*! \brief Get opcode info string + * \param opcode Opcode to look for in opcode table + */ +const char *FWScriptInfo::opcodeInfo(byte opcode) const { + if (opcode == 0 || opcode > FWScript::_numOpcodes) { + return NULL; + } + + if (!FWScript::_opcodeTable[opcode - 1].args) { + warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeInfo", opcode - 1); + return NULL; + } + + return FWScript::_opcodeTable[opcode - 1].args; +} + +/*! \brief Get opcode handler pointer + * \param opcode Opcode to look for in opcode table + */ +opFunc FWScriptInfo::opcodeHandler(byte opcode) const { + if (opcode == 0 || opcode > FWScript::_numOpcodes) { + return NULL; + } + + if (!FWScript::_opcodeTable[opcode - 1].proc) { + warning("Undefined opcode 0x%02X in FWScriptInfo::opcodeHandler", opcode - 1); + return NULL; + } + + return FWScript::_opcodeTable[opcode - 1].proc; +} + +/*! \brief Create new FWScript instance + * \param script Script bytecode + * \param index Bytecode index + */ +FWScript *FWScriptInfo::create(const RawScript &script, int16 index) const { + return new FWScript(script, index); +} + +/*! \brief Create new FWScript instance + * \param script Object script bytecode + * \param index Bytecode index + */ +FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index) const { + return new FWScript(script, index); +} + +/*! \brief Load saved FWScript instance + * \param script Script bytecode + * \param index Bytecode index + * \param local Local variables + * \param labels Script labels + * \param compare Last compare result + * \param pos Position in script + */ +FWScript *FWScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { + FWScript *tmp = new FWScript(script, index); + assert(tmp); + tmp->load(labels, local, compare, pos); + return tmp; +} + +/*! \brief Load saved FWScript instance + * \param script Object script bytecode + * \param index Bytecode index + * \param local Local variables + * \param labels Script labels + * \param compare Last compare result + * \param pos Position in script + */ +FWScript *FWScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { + FWScript *tmp = new FWScript(script, index); + assert(tmp); + tmp->load(labels, local, compare, pos); + return tmp; +} + +// ------------------------------------------------------------------------ +// FUTURE WARS opcodes +// ------------------------------------------------------------------------ + +int FWScript::o1_modifyObjectParam() { + byte objIdx = getNextByte(); + byte paramIdx = getNextByte(); + int16 newValue = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); + + modifyObjectParam(objIdx, paramIdx, newValue); + return 0; +} + +int FWScript::o1_getObjectParam() { + byte objIdx = getNextByte(); + byte paramIdx = getNextByte(); + byte newValue = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: getObjectParam(objIdx:%d,paramIdx:%d,var:%d)", _line, objIdx, paramIdx, newValue); + + _localVars[newValue] = getObjectParam(objIdx, paramIdx); + return 0; +} + +int FWScript::o1_addObjectParam() { + byte objIdx = getNextByte(); + byte paramIdx = getNextByte(); + int16 newValue = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: addObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); + + addObjectParam(objIdx, paramIdx, newValue); + return 0; +} + +int FWScript::o1_subObjectParam() { + byte objIdx = getNextByte(); + byte paramIdx = getNextByte(); + int16 newValue = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: subObjectParam(objIdx:%d,paramIdx:%d,newValue:%d)", _line, objIdx, paramIdx, newValue); + + subObjectParam(objIdx, paramIdx, newValue); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_add2ObjectParam() { + uint16 a = getNextByte(); + uint16 b = getNextByte(); + uint16 c = getNextWord(); + warning("STUB: o1_add2ObjectParam(%x, %x, %x)", a, b, c); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_sub2ObjectParam() { + uint16 a = getNextByte(); + uint16 b = getNextByte(); + uint16 c = getNextWord(); + warning("STUB: o1_sub2ObjectParam(%x, %x, %x)", a, b, c); + return 0; +} + +int FWScript::o1_compareObjectParam() { + byte objIdx = getNextByte(); + byte param1 = getNextByte(); + int16 param2 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: compareObjectParam(objIdx:%d,type:%d,value:%d)", _line, objIdx, param1, param2); + + _compare = compareObjectParam(objIdx, param1, param2); + return 0; +} + +int FWScript::o1_setupObject() { + byte objIdx = getNextByte(); + int16 param1 = getNextWord(); + int16 param2 = getNextWord(); + int16 param3 = getNextWord(); + int16 param4 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: setupObject(objIdx:%d,%d,%d,%d,%d)", _line, objIdx, param1, param2, param3, param4); + + setupObject(objIdx, param1, param2, param3, param4); + return 0; +} + +int FWScript::o1_checkCollision() { + byte objIdx = getNextByte(); + int16 param1 = getNextWord(); + int16 param2 = getNextWord(); + int16 param3 = getNextWord(); + int16 param4 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: checkCollision(objIdx:%d,%d,%d,%d,%d)", _line, objIdx, param1, param2, param3, param4); + + _compare = checkCollision(objIdx, param1, param2, param3, param4); + return 0; +} + +int FWScript::o1_loadVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + int16 var; + + switch (varType) { + case 1: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = var[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] = _localVars[dataIdx]; + break; + case 2: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = globalVars[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] = _globalVars[dataIdx]; + break; + case 3: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = mouseX", _line, varIdx); + getMouseData(mouseUpdateStatus, &dummyU16, (uint16 *)&var, &dummyU16); + _localVars[varIdx] = var; + break; + case 4: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = mouseY", _line, varIdx); + getMouseData(mouseUpdateStatus, &dummyU16, &dummyU16, (uint16 *)&var); + _localVars[varIdx] = var; + break; + case 5: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = rand mod %d", _line, varIdx, dataIdx); + _localVars[varIdx] = g_cine->_rnd.getRandomNumber(dataIdx - 1); + break; + case 8: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].packedSize", _line, varIdx, dataIdx); + _localVars[varIdx] = partBuffer[dataIdx].packedSize; + break; + case 9: + debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].unpackedSize", _line, varIdx, dataIdx); + _localVars[varIdx] = partBuffer[dataIdx].unpackedSize; + break; + default: + error("executeScript: o1_loadVar: Unknown variable type %d", varType); + } + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: var[%d] = %d", _line, varIdx, value); + _localVars[varIdx] = value; + } + + return 0; +} + +int FWScript::o1_addVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] += var[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] += _localVars[dataIdx]; + } else if (varType == 2) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] += globalVar[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] += _globalVars[dataIdx]; + } + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: var[%d] += %d", _line, varIdx, value); + _localVars[varIdx] += value; + } + + return 0; +} + +int FWScript::o1_subVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] -= var[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] -= _localVars[dataIdx]; + } else if (varType == 2) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] -= globalVar[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] -= _globalVars[dataIdx]; + } + + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: var[%d] -= %d", _line, varIdx, value); + _localVars[varIdx] -= value; + } + + return 0; +} + +int FWScript::o1_mulVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] *= var[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] *= _localVars[dataIdx]; + } else if (varType == 2) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] *= globalVar[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] *= _globalVars[dataIdx]; + } + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: var[%d] *= %d", _line, varIdx, value); + _localVars[varIdx] *= value; + } + + return 0; +} + +int FWScript::o1_divVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] /= var[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] /= _localVars[dataIdx]; + } else if (varType == 2) { + debugC(5, kCineDebugScript, "Line: %d: var[%d] /= globalVar[%d]", _line, varIdx, dataIdx); + _localVars[varIdx] /= _globalVars[dataIdx]; + } + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: var[%d] /= %d", _line, varIdx, value); + _localVars[varIdx] /= value; + } + + return 0; +} + +int FWScript::o1_compareVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and var[%d]", _line, varIdx, dataIdx); + _compare = compareVars(_localVars[varIdx], _localVars[dataIdx]); + } else if (varType == 2) { + debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and globalVar[%d]", _line, varIdx, dataIdx); + _compare = compareVars(_localVars[varIdx], _globalVars[dataIdx]); + } + } else { + int16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: compare var[%d] and %d", _line, varIdx, value); + _compare = compareVars(_localVars[varIdx], value); + } + + return 0; +} + +int FWScript::o1_modifyObjectParam2() { + byte objIdx = getNextByte(); + byte paramIdx = getNextByte(); + byte newValue = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: modifyObjectParam2(objIdx:%d,paramIdx:%d,var[%d])", _line, objIdx, paramIdx, newValue); + + modifyObjectParam(objIdx, paramIdx, _localVars[newValue]); + return 0; +} + +int FWScript::o1_loadMask0() { + // OP_loadV7Element + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addSpriteOverlay(%d)", _line, param); + addOverlay(param, 0); + return 0; +} + +int FWScript::o1_unloadMask0() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay(%d)", _line, param); + removeOverlay(param, 0); + return 0; + return 0; +} + +int FWScript::o1_addToBgList() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addToBGList(%d)", _line, param); + addToBGList(param); + return 0; +} + +int FWScript::o1_loadMask1() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addOverlay1(%d)", _line, param); + addOverlay(param, 1); + return 0; +} + +int FWScript::o1_unloadMask1() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeOverlay1(%d)", _line, param); + removeOverlay(param, 1); + return 0; +} + +int FWScript::o1_loadMask4() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addOverlayType4(%d)", _line, param); + addOverlay(param, 4); + return 0; +} + +int FWScript::o1_unloadMask4() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeSpriteOverlay4(%d)", _line, param); + removeOverlay(param, 4); + return 0; +} + +int FWScript::o1_addSpriteFilledToBgList() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: op1A(%d) -> TODO !", _line, param); + addSpriteFilledToBGList(param); + return 0; +} + +int FWScript::o1_op1B() { + debugC(5, kCineDebugScript, "Line: %d: freeBgIncrustList", _line); + bgIncrustList.clear(); + return 0; +} + +int FWScript::o1_label() { + byte labelIdx = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: label(%d)", _line, labelIdx); + _labels[labelIdx] = _pos; + return 0; +} + +int FWScript::o1_goto() { + byte labelIdx = getNextByte(); + + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: goto label(%d)", _line, labelIdx); + _pos = _labels[labelIdx]; + return 0; +} + +int FWScript::o1_gotoIfSup() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpGT) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(>) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(>) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_gotoIfSupEqu() { + byte labelIdx = getNextByte(); + + if (_compare & (kCmpGT | kCmpEQ)) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(>=) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(>=) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_gotoIfInf() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpLT) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(<) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(<) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_gotoIfInfEqu() { + byte labelIdx = getNextByte(); + + if (_compare & (kCmpLT | kCmpEQ)) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(<=) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(<=) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_gotoIfEqu() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpEQ) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(==) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(==) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_gotoIfDiff() { + byte labelIdx = getNextByte(); + + if (_compare != kCmpEQ) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(!=) goto %d (true)", _line, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: if(!=) goto %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o1_removeLabel() { + byte labelIdx = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeLabel(%d)", _line, labelIdx); + _labels[labelIdx] = -1; + return 0; +} + +int FWScript::o1_loop() { + byte varIdx = getNextByte(); + byte labelIdx = getNextByte(); + + _localVars[varIdx]--; + + if (_localVars[varIdx] >= 0) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: loop(var[%d]) goto %d (continue)", _line, varIdx, labelIdx); + _pos = _labels[labelIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: loop(var[%d]) goto %d (stop)", _line, varIdx, labelIdx); + } + return 0; +} + +int FWScript::o1_startGlobalScript() { + // OP_startScript + byte param = getNextByte(); + + assert(param < NUM_MAX_SCRIPT); + + debugC(5, kCineDebugScript, "Line: %d: startScript(%d)", _line, param); + addScriptToList0(param); + return 0; +} + +int FWScript::o1_endGlobalScript() { + byte scriptIdx = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: stopGlobalScript(%d)", _line, scriptIdx); + + ScriptList::iterator it = globalScripts.begin(); + + for (; it != globalScripts.end(); ++it) { + if ((*it)->_index == scriptIdx) { + (*it)->_index = -1; + } + } + + return 0; +} + +int FWScript::o1_loadAnim() { + // OP_loadResource + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadResource(\"%s\")", _line, param); + loadResource(param); + return 0; +} + +int FWScript::o1_loadBg() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadBg(\"%s\")", _line, param); + + loadBg(param); + bgIncrustList.clear(); + bgVar0 = 0; + return 0; +} + +int FWScript::o1_loadCt() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadCt(\"%s\")", _line, param); + loadCt(param); + return 0; +} + +int FWScript::o1_loadPart() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param); + loadPart(param); + return 0; +} + +int FWScript::o1_closePart() { + debugC(5, kCineDebugScript, "Line: %d: closePart", _line); + closePart(); + return 0; +} + +int FWScript::o1_loadNewPrcName() { + // OP_loadData + byte param1 = getNextByte(); + const char *param2 = getNextString(); + + assert(param1 <= 3); + + switch (param1) { + case 0: + debugC(5, kCineDebugScript, "Line: %d: loadPrc(\"%s\")", _line, param2); + strcpy(newPrcName, param2); + break; + case 1: + debugC(5, kCineDebugScript, "Line: %d: loadRel(\"%s\")", _line, param2); + strcpy(newRelName, param2); + break; + case 2: + debugC(5, kCineDebugScript, "Line: %d: loadObject(\"%s\")", _line, param2); + strcpy(newObjectName, param2); + break; + case 3: + debugC(5, kCineDebugScript, "Line: %d: loadMsg(\"%s\")", _line, param2); + strcpy(newMsgName, param2); + break; + } + return 0; +} + +int FWScript::o1_requestCheckPendingDataLoad() { + debugC(5, kCineDebugScript, "Line: %d: request data load", _line); + checkForPendingDataLoadSwitch = 1; + return 0; +} + +int FWScript::o1_blitAndFade() { + debugC(5, kCineDebugScript, "Line: %d: request fadein", _line); + // TODO: use real code + + drawOverlays(); + fadeRequired = true; + flip(); + +// fadeFromBlack(); + return 0; +} + +int FWScript::o1_fadeToBlack() { + debugC(5, kCineDebugScript, "Line: %d: request fadeout", _line); + + fadeToBlack(); + return 0; +} + +int FWScript::o1_transformPaletteRange() { + byte startColor = getNextByte(); + byte numColor = getNextByte(); + uint16 r = getNextWord(); + uint16 g = getNextWord(); + uint16 b = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: transformPaletteRange(from:%d,numIdx:%d,r:%d,g:%d,b:%d)", _line, startColor, numColor, r, g, b); + + transformPaletteRange(startColor, numColor, r, g, b); + return 0; +} + +int FWScript::o1_setDefaultMenuColor2() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor2(%d)", _line, param); + defaultMenuBoxColor2 = param; + return 0; +} + +int FWScript::o1_palRotate() { + byte a = getNextByte(); + byte b = getNextByte(); + byte c = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: palRotate(%d,%d,%d)", _line, a, b, c); + palRotate(a, b, c); + return 0; +} + +/*!\brief Pause script + * \todo Make sure it works + */ +int FWScript::o1_break() { + debugC(5, kCineDebugScript, "Line: %d: break", _line); + + return 1; +} + +/*! \brief Terminate script + * \todo Make sure it works + */ +int FWScript::o1_endScript() { + debugC(5, kCineDebugScript, "Line: %d: endScript", _line); + + return -1; +} + +int FWScript::o1_message() { + byte param1 = getNextByte(); + uint16 param2 = getNextWord(); + uint16 param3 = getNextWord(); + uint16 param4 = getNextWord(); + uint16 param5 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: message(%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5); + + addMessage(param1, param2, param3, param4, param5); + return 0; +} + +int FWScript::o1_loadGlobalVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte dataIdx = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = var[%d]", _line, varIdx, dataIdx); + _globalVars[varIdx] = _localVars[dataIdx]; + } else { + debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = globalVars[%d]", _line, varIdx, dataIdx); + _globalVars[varIdx] = _globalVars[dataIdx]; + } + } else { + uint16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: globalVars[%d] = %d", _line, varIdx, value); + _globalVars[varIdx] = value; + } + + return 0; +} + +int FWScript::o1_compareGlobalVar() { + byte varIdx = getNextByte(); + byte varType = getNextByte(); + + if (varType) { + byte value = getNextByte(); + + if (varType == 1) { + debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and var[%d]", _line, varIdx, value); + _compare = compareVars(_globalVars[varIdx], _localVars[value]); + } else { + debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and globalVars[%d]", _line, varIdx, value); + _compare = compareVars(_globalVars[varIdx], _globalVars[value]); + } + } else { + uint16 value = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value); + + if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) { // TODO: fix + _compare = 1; + } else { + _compare = compareVars(_globalVars[varIdx], value); + } + } + + return 0; +} + +int FWScript::o1_declareFunctionName() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: comment(%s)", _line, param); + return 0; +} + +int FWScript::o1_freePartRange() { + byte startIdx = getNextByte(); + byte numIdx = getNextByte(); + + assert(startIdx + numIdx <= NUM_MAX_ANIMDATA); + + debugC(5, kCineDebugScript, "Line: %d: freePartRange(%d,%d)", _line, startIdx, numIdx); + freeAnimDataRange(startIdx, numIdx); + return 0; +} + +int FWScript::o1_unloadAllMasks() { + debugC(5, kCineDebugScript, "Line: %d: unloadAllMasks()", _line); + overlayList.clear(); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_setScreenDimensions() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + uint16 c = getNextWord(); + uint16 d = getNextWord(); + warning("STUB: o1_setScreenDimensions(%x, %x, %x, %x)", a, b, c, d); + // setupScreenParam + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_displayBackground() { + warning("STUB: o1_displayBackground()"); + return 0; +} + +int FWScript::o1_initializeZoneData() { + debugC(5, kCineDebugScript, "Line: %d: initializeZoneData()", _line); + + for (int i = 0; i < NUM_MAX_ZONE; i++) { + zoneData[i] = i; + } + return 0; +} + +int FWScript::o1_setZoneDataEntry() { + byte zoneIdx = getNextByte(); + uint16 var = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: setZone[%d] = %d", _line, zoneIdx, var); + zoneData[zoneIdx] = var; + return 0; +} + +int FWScript::o1_getZoneDataEntry() { + byte zoneIdx = getNextByte(); + byte var = getNextByte(); + + _localVars[var] = zoneData[zoneIdx]; + return 0; +} + +int FWScript::o1_setDefaultMenuColor() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor(%d)", _line, param); + defaultMenuBoxColor = param; + return 0; +} + +int FWScript::o1_allowPlayerInput() { + debugC(5, kCineDebugScript, "Line: %d: allowPlayerInput()", _line); + allowPlayerInput = 1; + return 0; +} + +int FWScript::o1_disallowPlayerInput() { + debugC(5, kCineDebugScript, "Line: %d: dissallowPlayerInput()", _line); + allowPlayerInput = 0; + return 0; +} + +int FWScript::o1_changeDataDisk() { + byte newDisk = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: changeDataDisk(%d)", _line, newDisk); + checkDataDisk(newDisk); + return 0; +} + +int FWScript::o1_loadMusic() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadMusic(%s)", _line, param); + g_sound->loadMusic(param); + return 0; +} + +int FWScript::o1_playMusic() { + debugC(5, kCineDebugScript, "Line: %d: playMusic()", _line); + g_sound->playMusic(); + return 0; +} + +int FWScript::o1_fadeOutMusic() { + debugC(5, kCineDebugScript, "Line: %d: fadeOutMusic()", _line); + g_sound->fadeOutMusic(); + return 0; +} + +int FWScript::o1_stopSample() { + debugC(5, kCineDebugScript, "Line: %d: stopSample()", _line); + g_sound->stopMusic(); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_op71() { + byte a = getNextByte(); + uint16 b = getNextWord(); + warning("STUB: o1_op71(%x, %x)", a, b); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_op72() { + uint16 a = getNextWord(); + byte b = getNextByte(); + uint16 c = getNextWord(); + warning("STUB: o1_op72(%x, %x, %x)", a, b, c); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o1_op73() { + // I believe this opcode is identical to o1_op72(). In fact, Operation + // Stealth doesn't even have it. It uses o1_op72() instead. + uint16 a = getNextWord(); + byte b = getNextByte(); + uint16 c = getNextWord(); + warning("STUB: o1_op72(%x, %x, %x)", a, b, c); + return 0; +} + +int FWScript::o1_playSample() { + debugC(5, kCineDebugScript, "Line: %d: playSample()", _line); + + byte anim = getNextByte(); + byte channel = getNextByte(); + + uint16 freq = getNextWord(); + byte repeat = getNextByte(); + + int16 volume = getNextWord(); + uint16 size = getNextWord(); + + const byte *data = animDataTable[anim].data(); + + if (!data) { + return 0; + } + + if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { + if (size == 0xFFFF) { + size = animDataTable[anim]._width * animDataTable[anim]._height; + } + if (channel < 10) { // || _currentOpcode == 0x78 + int channel1, channel2; + if (channel == 0) { + channel1 = 0; + channel2 = 1; + } else { + channel1 = 2; + channel2 = 3; + } + g_sound->playSound(channel1, freq, data, size, -1, volume, 63, repeat); + g_sound->playSound(channel2, freq, data, size, 1, volume, 0, repeat); + } else { + channel -= 10; + if (volume > 63) { + volume = 63; + } + g_sound->playSound(channel, freq, data, size, 0, 0, volume, repeat); + } + } else { + if (volume > 63 || volume < 0) { + volume = 63; + } + if (channel >= 10) { + channel -= 10; + } + if (volume < 50) { + volume = 50; + } + if (g_cine->getGameType() == Cine::GType_OS && size == 0) { + return 0; + } + g_sound->stopMusic(); + if (size == 0xFFFF) { + g_sound->playSound(channel, 0, data, 0, 0, 0, volume, 0); + } else { + g_sound->stopSound(channel); + } + } + return 0; +} + +int FWScript::o1_disableSystemMenu() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param); + disableSystemMenu = (param != 0); + return 0; +} + +int FWScript::o1_loadMask5() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addOverlay5(%d)", _line, param); + addOverlay(param, 5); + return 0; +} + +int FWScript::o1_unloadMask5() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: freeOverlay5(%d)", _line, param); + removeOverlay(param, 5); + return 0; +} + +//----------------------------------------------------------------------- + +void palRotate(byte a, byte b, byte c) { + if (c == 1) { + uint16 currentColor = c_palette[b]; + + for (int16 i = b; i > a; i--) { + c_palette[i] = c_palette[i - 1]; + } + + c_palette[a] = currentColor; + } +} + +void addScriptToList0(uint16 idx) { + ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx)); + assert(tmp); + globalScripts.push_back(tmp); +} + +int16 getZoneFromPosition(byte *page, int16 x, int16 y, int16 width) { + byte *ptr = page + (y * width) + x / 2; + byte zoneVar; + + if (!(x % 2)) { + zoneVar = (*(ptr) >> 4) & 0xF; + } else { + zoneVar = (*(ptr)) & 0xF; + } + + return zoneVar; +} + +int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) { + byte *ptr = page + (y * width) + x; + byte zoneVar; + + zoneVar = (*(ptr)) & 0xF; + + return zoneVar; +} + +int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) { + int16 lx = objectTable[objIdx].x + x; + int16 ly = objectTable[objIdx].y + y; + int16 idx; + + for (int16 i = 0; i < numZones; i++) { + idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320); + + assert(idx >= 0 && idx <= NUM_MAX_ZONE); + + if (zoneData[idx] == zoneIdx) { + return 1; + } + } + + return 0; +} + +uint16 compareVars(int16 a, int16 b) { + uint16 flag = 0; + + if (a == b) { + flag |= kCmpEQ; + } else if (a > b) { + flag |= kCmpGT; + } else if (a < b) { + flag |= kCmpLT; + } + + return flag; +} + +void executeList1(void) { + ScriptList::iterator it = objectScripts.begin(); + for (; it != objectScripts.end();) { + if ((*it)->_index < 0 || (*it)->execute() < 0) { + it = objectScripts.erase(it); + } else { + ++it; + } + } +} + +void executeList0(void) { + ScriptList::iterator it = globalScripts.begin(); + for (; it != globalScripts.end();) { + if ((*it)->_index < 0 || (*it)->execute() < 0) { + it = globalScripts.erase(it); + } else { + ++it; + } + } +} + +/*! \todo objectScripts.clear()? + */ +void purgeList1(void) { +} + +void purgeList0(void) { +} + +//////////////////////////////////// +// SCRIPT DECOMPILER + +#ifdef DUMP_SCRIPTS + +char decompileBuffer[10000][1000]; +uint16 decompileBufferPosition = 0; + +char bufferDec[256]; + +char compareString1[256]; +char compareString2[256]; + +const char *getObjPramName(byte paramIdx) { + switch (paramIdx) { + case 1: + return ".X"; + case 2: + return ".Y"; + case 3: + return ".mask"; + case 4: + return ".frame"; + case 5: + return ".status"; + case 6: + return ".costume"; + default: + sprintf(bufferDec, ".param%d", paramIdx); + return bufferDec; + } +} + +void decompileScript(byte *scriptPtr, int16 *stackPtr, uint16 scriptSize, uint16 scriptIdx) { + char lineBuffer[256]; + byte *localScriptPtr = scriptPtr; + uint16 exitScript; + uint32 position = 0; + + assert(scriptPtr); + // assert(stackPtr); + + exitScript = 0; + + sprintf(decompileBuffer[decompileBufferPosition++], "--------- SCRIPT %d ---------\n", scriptIdx); + + do { + uint16 opcode = *(localScriptPtr + position); + position++; + + if (position == scriptSize) { + opcode = 0; + } + + strcpy(lineBuffer, ""); + + switch (opcode - 1) { + case -1: + { + break; + } + case 0x0: + { + byte param1; + byte param2; + int16 param3; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "obj[%d]%s = %d\n", param1, getObjPramName(param2), param3); + + break; + } + case 0x1: + { + byte param1; + byte param2; + byte param3; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "var[%d]=obj[%d]%s\n", param3, param1, getObjPramName(param2)); + break; + } + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + { + byte param1; + byte param2; + int16 param3; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + if (opcode - 1 == 0x2) { + sprintf(lineBuffer, "obj[%d]%s+=%d\n", param1, getObjPramName(param2), param3); + } else if (opcode - 1 == 0x3) { + sprintf(lineBuffer, "obj[%d]%s-=%d\n", param1, getObjPramName(param2), param3); + } else if (opcode - 1 == 0x4) { + sprintf(lineBuffer, "obj[%d]%s+=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2)); + } else if (opcode - 1 == 0x5) { + sprintf(lineBuffer, "obj[%d]%s-=obj[%d]%s\n", param1, getObjPramName(param2), param3, getObjPramName(param2)); + } else if (opcode - 1 == 0x6) { + sprintf(compareString1, "obj[%d]%s", param1, getObjPramName(param2)); + sprintf(compareString2, "%d", param3); + } + break; + } + case 0x7: + case 0x8: + { + byte param1; + int16 param2; + int16 param3; + int16 param4; + int16 param5; + + param1 = *(localScriptPtr + position); + position++; + + param2 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + if (opcode - 1 == 0x7) { + sprintf(lineBuffer, "setupObject(Idx:%d,X:%d,Y:%d,mask:%d,frame:%d)\n", param1, param2, param3, param4, param5); + } else if (opcode - 1 == 0x8) { + sprintf(lineBuffer, "checkCollision(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); + } + break; + } + case 0x9: + { + byte param1; + int16 param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + if (param2) { + byte param3; + + param3 = *(localScriptPtr + position); + position++; + + if (param2 == 1) { + sprintf(lineBuffer, "var[%d]=var[%d]\n", param1, param3); + } else if (param2 == 2) { + sprintf(lineBuffer, "var[%d]=globalVar[%d]\n", param1, param3); + } else if (param2 == 3) { + sprintf(lineBuffer, "var[%d]=mouse.X\n", param1); + } else if (param2 == 4) { + sprintf(lineBuffer, "var[%d]=mouse.Y\n", param1); + } else if (param2 == 5) { + sprintf(lineBuffer, "var[%d]=rand() mod %d\n", param1, param3); + } else if (param2 == 8) { + sprintf(lineBuffer, "var[%d]=file[%d].packedSize\n", param1, param3); + } else if (param2 == 9) { + sprintf(lineBuffer, "var[%d]=file[%d].unpackedSize\n", param1, param3); + } else { + error("decompileScript: 0x09: param2 = %d", param2); + } + } else { + int16 param3; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "var[%d]=%d\n", param1, param3); + } + + break; + } + case 0xA: + case 0xB: + case 0xC: + case 0xD: + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + if (param2) { + byte param3; + + param3 = *(localScriptPtr + position); + position++; + + if (opcode - 1 == 0xA) { + sprintf(lineBuffer, "var[%d]+=var[%d]\n", param1, param3); + } else if (opcode - 1 == 0xB) { + sprintf(lineBuffer, "var[%d]-=var[%d]\n", param1, param3); + } else if (opcode - 1 == 0xC) { + sprintf(lineBuffer, "var[%d]*=var[%d]\n", param1, param3); + } else if (opcode - 1 == 0xD) { + sprintf(lineBuffer, "var[%d]/=var[%d]\n", param1, param3); + } + } else { + int16 param3; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + if (opcode - 1 == 0xA) { + sprintf(lineBuffer, "var[%d]+=%d\n", param1, param3); + } else if (opcode - 1 == 0xB) { + sprintf(lineBuffer, "var[%d]-=%d\n", param1, param3); + } else if (opcode - 1 == 0xC) { + sprintf(lineBuffer, "var[%d]*=%d\n", param1, param3); + } else if (opcode - 1 == 0xD) { + sprintf(lineBuffer, "var[%d]/=%d\n", param1, param3); + } + } + break; + } + case 0xE: + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + if (param2) { + byte param3; + + param3 = *(localScriptPtr + position); + position++; + + if (param2 == 1) { + sprintf(compareString1, "var[%d]", param1); + sprintf(compareString2, "var[%d]", param3); + + } else if (param2 == 2) { + sprintf(compareString1, "var[%d]", param1); + sprintf(compareString2, "globalVar[%d]", param3); + } else { + error("decompileScript: 0x0E: param2 = %d", param2); + } + } else { + int16 param3; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(compareString1, "var[%d]", param1); + sprintf(compareString2, "%d", param3); + } + break; + } + case 0xF: + { + byte param1; + byte param2; + byte param3; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "obj[%d]%s=var[%d]\n", param1, getObjPramName(param2), param3); + + break; + } + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + if (opcode - 1 == 0x13) { + sprintf(lineBuffer, "loadMask0(%d)\n", param); + } else if (opcode - 1 == 0x14) { + sprintf(lineBuffer, "unloadMask0(%d)\n", param); + } else if (opcode - 1 == 0x15) { + sprintf(lineBuffer, "OP_15(%d)\n", param); + } else if (opcode - 1 == 0x16) { + sprintf(lineBuffer, "loadMask1(%d)\n", param); + } else if (opcode - 1 == 0x17) { + sprintf(lineBuffer, "unloadMask0(%d)\n", param); + } else if (opcode - 1 == 0x18) { + sprintf(lineBuffer, "loadMask4(%d)\n", param); + } else if (opcode - 1 == 0x19) { + sprintf(lineBuffer, "unloadMask4(%d)\n", param); + } + break; + } + case 0x1A: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_1A(%d)\n", param); + + break; + } + case 0x1B: + { + sprintf(lineBuffer, "bgIncrustList.clear()\n"); + break; + } + case 0x1D: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "label(%d)\n", param); + + break; + } + case 0x1E: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "goto(%d)\n", param); + + break; + } + // If cases + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + if (opcode - 1 == 0x1F) { + sprintf(lineBuffer, "if(%s>%s) goto(%d)\n", compareString1, compareString2, param); + } else if (opcode - 1 == 0x20) { + sprintf(lineBuffer, "if(%s>=%s) goto(%d)\n", compareString1, compareString2, param); + } else if (opcode - 1 == 0x21) { + sprintf(lineBuffer, "if(%s<%s) goto(%d)\n", compareString1, compareString2, param); + } else if (opcode - 1 == 0x22) { + sprintf(lineBuffer, "if(%s<=%s) goto(%d)\n", compareString1, compareString2, param); + } else if (opcode - 1 == 0x23) { + sprintf(lineBuffer, "if(%s==%s) goto(%d)\n", compareString1, compareString2, param); + } else if (opcode - 1 == 0x24) { + sprintf(lineBuffer, "if(%s!=%s) goto(%d)\n", compareString1, compareString2, param); + } + break; + } + case 0x25: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "removeLabel(%d)\n", param); + + break; + } + case 0x26: + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "loop(--var[%d]) -> label(%d)\n", param1, param2); + + break; + } + case 0x31: + case 0x32: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + if (opcode - 1 == 0x31) { + sprintf(lineBuffer, "startGlobalScript(%d)\n", param); + } else if (opcode - 1 == 0x32) { + sprintf(lineBuffer, "endGlobalScript(%d)\n", param); + } + break; + } + case 0x3B: + case 0x3C: + case 0x3D: + case OP_loadPart: + { + if (opcode - 1 == 0x3B) { + sprintf(lineBuffer, "loadResource(%s)\n", localScriptPtr + position); + } else if (opcode - 1 == 0x3C) { + sprintf(lineBuffer, "loadBg(%s)\n", localScriptPtr + position); + } else if (opcode - 1 == 0x3D) { + sprintf(lineBuffer, "loadCt(%s)\n", localScriptPtr + position); + } else if (opcode - 1 == OP_loadPart) { + sprintf(lineBuffer, "loadPart(%s)\n", localScriptPtr + position); + } + + position += strlen((char *)localScriptPtr + position) + 1; + break; + } + case 0x40: + { + sprintf(lineBuffer, "closePart()\n"); + break; + } + case OP_loadNewPrcName: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "loadPrc(%d,%s)\n", param, localScriptPtr + position); + + position += strlen((char *)localScriptPtr + position) + 1; + break; + } + case OP_requestCheckPendingDataLoad: // nop + { + sprintf(lineBuffer, "requestCheckPendingDataLoad()\n"); + break; + } + case 0x45: + { + sprintf(lineBuffer, "blitAndFade()\n"); + break; + } + case 0x46: + { + sprintf(lineBuffer, "fadeToBlack()\n"); + break; + } + case 0x47: + { + byte param1; + byte param2; + int16 param3; + int16 param4; + int16 param5; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "transformPaletteRange(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); + + break; + } + case 0x49: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "setDefaultMenuColor2(%d)\n", param); + + break; + } + case 0x4F: + { + sprintf(lineBuffer, "break()\n"); + exitScript = 1; + break; + } + case 0x50: + { + sprintf(lineBuffer, "endScript()\n\n"); + break; + } + case 0x51: + { + byte param1; + int16 param2; + int16 param3; + int16 param4; + int16 param5; + + param1 = *(localScriptPtr + position); + position++; + + param2 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "message(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); + + break; + } + case 0x52: + case 0x53: + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + if (param2) { + byte param3; + + param3 = *(localScriptPtr + position); + position++; + + if (param2 == 1) { + if (opcode - 1 == 0x52) { + sprintf(lineBuffer, "globalVar[%d] = var[%d]\n", param1, param3); + } else if (opcode - 1 == 0x53) { + sprintf(compareString1, "globalVar[%d]", param1); + sprintf(compareString2, "var[%d]", param3); + } + } else if (param2 == 2) { + if (opcode - 1 == 0x52) { + sprintf(lineBuffer, "globalVar[%d] = globalVar[%d]\n", param1, param3); + } else if (opcode - 1 == 0x53) { + sprintf(compareString1, "globalVar[%d]", param1); + sprintf(compareString2, "globalVar[%d]", param3); + } + } else { + if (opcode - 1 == 0x52) { + error("decompileScript: 0x52: param2 = %d", param2); + } else if (opcode - 1 == 0x53) { + error("decompileScript: 0x53: param2 = %d", param2); + } + } + } else { + int16 param3; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + if (opcode - 1 == 0x52) { + sprintf(lineBuffer, "globalVar[%d] = %d\n", param1, param3); + } else if (opcode - 1 == 0x53) { + sprintf(compareString1, "globalVar[%d]", param1); + sprintf(compareString2, "%d", param3); + } + } + break; + } + case 0x59: + { + sprintf(lineBuffer, "comment: %s\n", localScriptPtr + position); + + position += strlen((char *)localScriptPtr + position); + break; + } + case 0x5A: + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "freePartRang(%d,%d)\n", param1, param2); + + break; + } + case 0x5B: + { + sprintf(lineBuffer, "unloadAllMasks()\n"); + break; + } + case 0x65: + { + sprintf(lineBuffer, "setupTableUnk1()\n"); + break; + } + case 0x66: + { + byte param1; + int16 param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "tableUnk1[%d] = %d\n", param1, param2); + + break; + } + case 0x68: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "setDefaultMenuBoxColor(%d)\n", param); + + break; + } + case 0x69: + { + sprintf(lineBuffer, "allowPlayerInput()\n"); + break; + } + case 0x6A: + { + sprintf(lineBuffer, "disallowPlayerInput()\n"); + break; + } + case 0x6B: + { + byte newDisk; + + newDisk = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "changeDataDisk(%d)\n", newDisk); + + break; + } + case 0x6D: + { + sprintf(lineBuffer, "loadDat(%s)\n", localScriptPtr + position); + + position += strlen((char *)localScriptPtr + position) + 1; + break; + } + case 0x6E: // nop + { + sprintf(lineBuffer, "updateDat()\n"); + break; + } + case 0x6F: + { + sprintf(lineBuffer, "OP_6F() -> dat related\n"); + break; + } + case 0x70: + { + sprintf(lineBuffer, "stopSample()\n"); + break; + } + case 0x79: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "disableSystemMenu(%d)\n", param); + + break; + } + case 0x77: + case 0x78: + { + byte param1; + byte param2; + int16 param3; + byte param4; + int16 param5; + int16 param6; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = *(localScriptPtr + position); + position++; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param6 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + if (opcode - 1 == 0x77) { + sprintf(lineBuffer, "playSample(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6); + } else if (opcode - 1 == 0x78) { + sprintf(lineBuffer, "OP_78(%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6); + } + + break; + } + case 0x7A: + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_7A(%d)\n", param); + + break; + } + case 0x7B: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_7B(%d)\n", param); + + break; + } + case 0x7F: // OS only + { + byte param1; + byte param2; + byte param3; + byte param4; + int16 param5; + int16 param6; + int16 param7; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = *(localScriptPtr + position); + position++; + + param4 = *(localScriptPtr + position); + position++; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param6 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param7 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "OP_7F(%d,%d,%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5, param6, param7); + + break; + } + case 0x80: // OS only + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_80(%d,%d)\n", param1, param2); + + break; + } + case 0x82: // OS only + { + byte param1; + byte param2; + uint16 param3; + uint16 param4; + byte param5; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param5 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_82(%d,%d,%d,%d,%d)\n", param1, param2, param3, param4, param5); + + break; + } + case 0x83: // OS only + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_83(%d,%d)\n", param1, param2); + + break; + } + case 0x89: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "if(%s!=%s) goto next label(%d)\n", compareString1, compareString2, param); + + break; + } + case 0x8B: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_8B(%d)\n", param); + + break; + } + case 0x8C: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_8C(%d)\n", param); + + break; + } + case 0x8D: // OS only + { + int16 param1; + int16 param2; + int16 param3; + int16 param4; + int16 param5; + int16 param6; + int16 param7; + int16 param8; + + param1 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param2 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param3 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param4 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param5 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param6 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param7 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + param8 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(compareString1, "obj[%d]", param1); + sprintf(compareString2, "{%d,%d,%d,%d,%d,%d,%d}", param2, param3, param4, param5, param6, param7, param8); + + break; + } + case 0x8E: // OS only + { + byte param1; + + param1 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "ADDBG(%d,%s)\n", param1, localScriptPtr + position); + + position += strlen((char *)localScriptPtr + position); + + break; + } + case 0x8F: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_8F(%d)\n", param); + + break; + } + case 0x90: // OS only + { + byte param1; + + param1 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "loadABS(%d,%s)\n", param1, localScriptPtr + position); + + position += strlen((char *)localScriptPtr + position); + + break; + } + case 0x91: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_91(%d)\n", param); + + break; + } + case 0x9D: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_9D(%d) -> flip img idx\n", param); + + break; + } + case 0x9E: // OS only + { + byte param; + + param = *(localScriptPtr + position); + position++; + + if (param) { + byte param2; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2); + } else { + int16 param2; + + param2 = READ_BE_UINT16(localScriptPtr + position); + position += 2; + + sprintf(lineBuffer, "OP_9E(%d,%d)\n", param, param2); + } + + break; + } + case 0xA0: // OS only + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_A0(%d,%d)\n", param1, param2); + + break; + } + case 0xA1: // OS only + { + byte param1; + byte param2; + + param1 = *(localScriptPtr + position); + position++; + + param2 = *(localScriptPtr + position); + position++; + + sprintf(lineBuffer, "OP_A1(%d,%d)\n", param1, param2); + + break; + } + default: + { + sprintf(lineBuffer, "Unsupported opcode %X in decompileScript\n\n", opcode - 1); + position = scriptSize; + break; + } + } + + // printf(lineBuffer); + strcpy(decompileBuffer[decompileBufferPosition++], lineBuffer); + + exitScript = 0; + if (position >= scriptSize) { + exitScript = 1; + } + + } while (!exitScript); +} + +void dumpScript(char *dumpName) { + Common::File fHandle; + uint16 i; + + fHandle.open(dumpName, Common::File::kFileWriteMode); + + for (i = 0; i < decompileBufferPosition; i++) { + fHandle.writeString(Common::String(decompileBuffer[i])); + } + + fHandle.close(); + + decompileBufferPosition = 0; +} + +#endif + +} // End of namespace Cine diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp new file mode 100644 index 0000000000..1f5ea2b838 --- /dev/null +++ b/engines/cine/script_os.cpp @@ -0,0 +1,793 @@ +/* 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$ + * + */ + +/*! \file + * Operation Stealth script interpreter file + */ + +#include "common/endian.h" + +#include "cine/cine.h" +#include "cine/bg_list.h" +#include "cine/object.h" +#include "cine/sound.h" +#include "cine/various.h" +#include "cine/script.h" + +namespace Cine { + +const Opcode OSScript::_opcodeTable[] = { + /* 00 */ + { &FWScript::o1_modifyObjectParam, "bbw" }, + { &FWScript::o1_getObjectParam, "bbb" }, + { &FWScript::o1_addObjectParam, "bbw" }, + { &FWScript::o1_subObjectParam, "bbw" }, + /* 04 */ + { &FWScript::o1_add2ObjectParam, "bbw" }, + { &FWScript::o1_sub2ObjectParam, "bbw" }, + { &FWScript::o1_compareObjectParam, "bbw" }, + { &FWScript::o1_setupObject, "bwwww" }, + /* 08 */ + { &FWScript::o1_checkCollision, "bwwww" }, + { &FWScript::o1_loadVar, "bc" }, + { &FWScript::o1_addVar, "bc" }, + { &FWScript::o1_subVar, "bc" }, + /* 0C */ + { &FWScript::o1_mulVar, "bc" }, + { &FWScript::o1_divVar, "bc" }, + { &FWScript::o1_compareVar, "bc" }, + { &FWScript::o1_modifyObjectParam2, "bbb" }, + /* 10 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_loadMask0, "b" }, + /* 14 */ + { &FWScript::o1_unloadMask0, "b" }, + { &FWScript::o1_addToBgList, "b" }, + { &FWScript::o1_loadMask1, "b" }, + { &FWScript::o1_unloadMask1, "b" }, + /* 18 */ + { &FWScript::o1_loadMask4, "b" }, + { &FWScript::o1_unloadMask4, "b" }, + { &FWScript::o1_addSpriteFilledToBgList, "b" }, + { &FWScript::o1_op1B, "" }, + /* 1C */ + { 0, 0 }, + { &FWScript::o1_label, "l" }, + { &FWScript::o1_goto, "b" }, + { &FWScript::o1_gotoIfSup, "b" }, + /* 20 */ + { &FWScript::o1_gotoIfSupEqu, "b" }, + { &FWScript::o1_gotoIfInf, "b" }, + { &FWScript::o1_gotoIfInfEqu, "b" }, + { &FWScript::o1_gotoIfEqu, "b" }, + /* 24 */ + { &FWScript::o1_gotoIfDiff, "b" }, + { &FWScript::o1_removeLabel, "b" }, + { &FWScript::o1_loop, "bb" }, + { 0, 0 }, + /* 28 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 2C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 30 */ + { 0, 0 }, + { &FWScript::o1_startGlobalScript, "b" }, + { &FWScript::o1_endGlobalScript, "b" }, + { 0, 0 }, + /* 34 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 38 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_loadAnim, "s" }, + /* 3C */ + { &FWScript::o1_loadBg, "s" }, + { &FWScript::o1_loadCt, "s" }, + { 0, 0 }, + { &FWScript::o2_loadPart, "s" }, + /* 40 */ + { 0, 0 }, /* o1_closePart, triggered by some scripts (STARTA.PRC 4 for ex.) */ + { &FWScript::o1_loadNewPrcName, "bs" }, + { &FWScript::o1_requestCheckPendingDataLoad, "" }, + { 0, 0 }, + /* 44 */ + { 0, 0 }, + { &FWScript::o1_blitAndFade, "" }, + { &FWScript::o1_fadeToBlack, "" }, + { &FWScript::o1_transformPaletteRange, "bbwww" }, + /* 48 */ + { 0, 0 }, + { &FWScript::o1_setDefaultMenuColor2, "b" }, + { &FWScript::o1_palRotate, "bbb" }, + { 0, 0 }, + /* 4C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_break, "" }, + /* 50 */ + { &FWScript::o1_endScript, "x" }, + { &FWScript::o1_message, "bwwww" }, + { &FWScript::o1_loadGlobalVar, "bc" }, + { &FWScript::o1_compareGlobalVar, "bc" }, + /* 54 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 58 */ + { 0, 0 }, + { &FWScript::o1_declareFunctionName, "s" }, + { &FWScript::o1_freePartRange, "bb" }, + { &FWScript::o1_unloadAllMasks, "" }, + /* 5C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + /* 60 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o1_setScreenDimensions, "wwww" }, + /* 64 */ + { &FWScript::o1_displayBackground, "" }, + { &FWScript::o1_initializeZoneData, "" }, + { &FWScript::o1_setZoneDataEntry, "bw" }, + { &FWScript::o1_getZoneDataEntry, "bb" }, + /* 68 */ + { &FWScript::o1_setDefaultMenuColor, "b" }, + { &FWScript::o1_allowPlayerInput, "" }, + { &FWScript::o1_disallowPlayerInput, "" }, + { &FWScript::o1_changeDataDisk, "b" }, + /* 6C */ + { 0, 0 }, + { &FWScript::o1_loadMusic, "s" }, + { &FWScript::o1_playMusic, "" }, + { &FWScript::o1_fadeOutMusic, "" }, + /* 70 */ + { &FWScript::o1_stopSample, "" }, + { &FWScript::o1_op71, "bw" }, + { &FWScript::o1_op72, "wbw" }, + { &FWScript::o1_op72, "wbw" }, + /* 74 */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o2_playSample, "bbwbww" }, + /* 78 */ + { &FWScript::o2_playSampleAlt, "bbwbww" }, + { &FWScript::o1_disableSystemMenu, "b" }, + { &FWScript::o1_loadMask5, "b" }, + { &FWScript::o1_unloadMask5, "b" }, + /* 7C */ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { &FWScript::o2_addSeqListElement, "bbbbwww" }, + /* 80 */ + { &FWScript::o2_removeSeq, "bb" }, + { &FWScript::o2_op81, "" }, + { &FWScript::o2_op82, "bbw" }, + { &FWScript::o2_isSeqRunning, "bb" }, + /* 84 */ + { &FWScript::o2_gotoIfSupNearest, "b" }, + { &FWScript::o2_gotoIfSupEquNearest, "b" }, + { &FWScript::o2_gotoIfInfNearest, "b" }, + { &FWScript::o2_gotoIfInfEquNearest, "b" }, + /* 88 */ + { &FWScript::o2_gotoIfEquNearest, "b" }, + { &FWScript::o2_gotoIfDiffNearest, "b" }, + { 0, 0 }, + { &FWScript::o2_startObjectScript, "b" }, + /* 8C */ + { &FWScript::o2_stopObjectScript, "b" }, + { &FWScript::o2_op8D, "wwwwwwww" }, + { &FWScript::o2_addBackground, "bs" }, + { &FWScript::o2_removeBackground, "b" }, + /* 90 */ + { &FWScript::o2_loadAbs, "bs" }, + { &FWScript::o2_loadBg, "b" }, + { 0, 0 }, + { 0, 0 }, + /* 94 */ + { 0, 0 }, + { &FWScript::o1_changeDataDisk, "b" }, + { 0, 0 }, + { 0, 0 }, + /* 98 */ + { 0, 0 }, + { 0, 0 }, + { &FWScript::o2_wasZoneChecked, "" }, + { &FWScript::o2_op9B, "wwwwwwww" }, + /* 9C */ + { &FWScript::o2_op9C, "wwww" }, + { &FWScript::o2_useBgScroll, "b" }, + { &FWScript::o2_setAdditionalBgVScroll, "c" }, + { &FWScript::o2_op9F, "ww" }, + /* A0 */ + { &FWScript::o2_addGfxElementA0, "ww" }, + { &FWScript::o2_removeGfxElementA0, "ww" }, + { &FWScript::o2_opA2, "ww" }, + { &FWScript::o2_opA3, "ww" }, + /* A4 */ + { &FWScript::o2_loadMask22, "b" }, + { &FWScript::o2_unloadMask22, "b" }, + { 0, 0 }, + { 0, 0 }, + /* A8 */ + { 0, 0 }, + { &FWScript::o1_changeDataDisk, "b" } +}; +const unsigned int OSScript::_numOpcodes = ARRAYSIZE(OSScript::_opcodeTable); + +/*! \brief Contructor for global scripts + * \param script Script bytecode reference + * \param idx Script bytecode index + */ +OSScript::OSScript(const RawScript &script, int16 idx) : + FWScript(script, idx, new OSScriptInfo) {} + +/*! \brief Constructor for object scripts + * \param script Script bytecode reference + * \param idx Script bytecode index + */ +OSScript::OSScript(RawObjectScript &script, int16 idx) : + FWScript(script, idx, new OSScriptInfo) {} + +/*! \brief Copy constructor + */ +OSScript::OSScript(const OSScript &src) : FWScript(src, new OSScriptInfo) {} + +/*! \brief Restore script state from savefile + * \param labels Restored script labels + * \param local Restored local script variables + * \param compare Restored last comparison result + * \param pos Restored script position + */ +void OSScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { + FWScript::load(labels, local, compare, pos); +} + +/*! \brief Get opcode info string + * \param opcode Opcode to look for in opcode table + */ +const char *OSScriptInfo::opcodeInfo(byte opcode) const { + if (opcode == 0 || opcode > OSScript::_numOpcodes) { + return NULL; + } + + if (!OSScript::_opcodeTable[opcode - 1].args) { + warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeInfo", opcode - 1); + return NULL; + } + + return OSScript::_opcodeTable[opcode - 1].args; +} + +/*! \brief Get opcode handler pointer + * \param opcode Opcode to look for in opcode table + */ +opFunc OSScriptInfo::opcodeHandler(byte opcode) const { + if (opcode == 0 || opcode > OSScript::_numOpcodes) { + return NULL; + } + + if (!OSScript::_opcodeTable[opcode - 1].proc) { + warning("Undefined opcode 0x%02X in OSScriptInfo::opcodeHandler", opcode - 1); + return NULL; + } + + return OSScript::_opcodeTable[opcode - 1].proc; +} + +/*! \brief Create new OSScript instance + * \param script Script bytecode + * \param index Bytecode index + */ +FWScript *OSScriptInfo::create(const RawScript &script, int16 index) const { + return new OSScript(script, index); +} + +/*! \brief Create new OSScript instance + * \param script Object script bytecode + * \param index Bytecode index + */ +FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index) const { + return new OSScript(script, index); +} + +/*! \brief Load saved OSScript instance + * \param script Script bytecode + * \param index Bytecode index + * \param local Local variables + * \param labels Script labels + * \param compare Last compare result + * \param pos Position in script + */ +FWScript *OSScriptInfo::create(const RawScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { + OSScript *tmp = new OSScript(script, index); + assert(tmp); + tmp->load(labels, local, compare, pos); + return tmp; +} + +/*! \brief Load saved OSScript instance + * \param script Object script bytecode + * \param index Bytecode index + * \param local Local variables + * \param labels Script labels + * \param compare Last compare result + * \param pos Position in script + */ +FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index, const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) const { + OSScript *tmp = new OSScript(script, index); + assert(tmp); + tmp->load(labels, local, compare, pos); + return tmp; +} + +// ------------------------------------------------------------------------ +// OPERATION STEALTH opcodes +// ------------------------------------------------------------------------ + +int FWScript::o2_loadPart() { + const char *param = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadPart(\"%s\")", _line, param); + return 0; +} + +int FWScript::o2_playSample() { + if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { + // no-op in these versions + getNextByte(); + getNextByte(); + getNextWord(); + getNextByte(); + getNextWord(); + getNextWord(); + return 0; + } + return o1_playSample(); +} + +int FWScript::o2_playSampleAlt() { + byte num = getNextByte(); + byte channel = getNextByte(); + uint16 frequency = getNextWord(); + getNextByte(); + getNextWord(); + uint16 size = getNextWord(); + + if (size == 0xFFFF) { + size = animDataTable[num]._width * animDataTable[num]._height; + } + if (animDataTable[num].data()) { + if (g_cine->getPlatform() == Common::kPlatformPC) { + // if speaker output is available, play sound on it + // if it's another device, don't play anything + // TODO: implement this, it's used in the introduction for example + // on each letter displayed + } else { + g_sound->playSound(channel, frequency, animDataTable[num].data(), size, 0, 0, 63, 0); + } + } + return 0; +} + +int FWScript::o2_addSeqListElement() { + byte param1 = getNextByte(); + byte param2 = getNextByte(); + byte param3 = getNextByte(); + byte param4 = getNextByte(); + uint16 param5 = getNextWord(); + uint16 param6 = getNextWord(); + uint16 param7 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: addSeqListElement(%d,%d,%d,%d,%d,%d,%d)", _line, param1, param2, param3, param4, param5, param6, param7); + addSeqListElement(param1, 0, param2, param3, param4, param5, param6, 0, param7); + return 0; +} + +int FWScript::o2_removeSeq() { + byte a = getNextByte(); + byte b = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeSeq(%d,%d) -> TODO", _line, a, b); + removeSeq(a, 0, b); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op81() { + warning("STUB: o2_op81()"); + // freeUnkList(); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op82() { + byte a = getNextByte(); + byte b = getNextByte(); + uint16 c = getNextWord(); + warning("STUB: o2_op82(%x, %x, %x)", a, b, c); + return 0; +} + +int FWScript::o2_isSeqRunning() { + byte a = getNextByte(); + byte b = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b); + + if (isSeqRunning(a, 0, b)) { + _compare = 1; + } else { + _compare = 0; + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfSupNearest() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpGT) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(>) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfSupEquNearest() { + byte labelIdx = getNextByte(); + + if (_compare & (kCmpGT | kCmpEQ)) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(>=) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfInfNearest() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpLT) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(<) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfInfEquNearest() { + byte labelIdx = getNextByte(); + + if (_compare & (kCmpLT | kCmpEQ)) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(<=) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfEquNearest() { + byte labelIdx = getNextByte(); + + if (_compare == kCmpEQ) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(==) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +/*! \todo The assert may produce false positives and requires testing + */ +int FWScript::o2_gotoIfDiffNearest() { + byte labelIdx = getNextByte(); + + if (_compare != kCmpEQ) { + assert(_labels[labelIdx] != -1); + + debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (true)", _line, labelIdx); + _pos = _script.getLabel(*_info, labelIdx, _pos); + } else { + debugC(5, kCineDebugScript, "Line: %d: if(!=) goto nearest %d (false)", _line, labelIdx); + } + return 0; +} + +int FWScript::o2_startObjectScript() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: startObjectScript(%d)", _line, param); + runObjectScript(param); + return 0; +} + +int FWScript::o2_stopObjectScript() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: stopObjectScript(%d)", _line, param); + ScriptList::iterator it = objectScripts.begin(); + + for (; it != objectScripts.end(); ++it) { + if ((*it)->_index == param) { + (*it)->_index = -1; + } + } + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op8D() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + uint16 c = getNextWord(); + uint16 d = getNextWord(); + uint16 e = getNextWord(); + uint16 f = getNextWord(); + uint16 g = getNextWord(); + uint16 h = getNextWord(); + warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); + // _currentScriptElement->compareResult = ... + return 0; +} + +int FWScript::o2_addBackground() { + byte param1 = getNextByte(); + const char *param2 = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: addBackground(%s,%d)", _line, param2, param1); + addBackground(param2, param1); + return 0; +} + +int FWScript::o2_removeBackground() { + byte param = getNextByte(); + + assert(param); + + debugC(5, kCineDebugScript, "Line: %d: removeBackground(%d)", _line, param); + + if (additionalBgTable[param]) { + free(additionalBgTable[param]); + additionalBgTable[param] = NULL; + } + + if (currentAdditionalBgIdx == param) { + currentAdditionalBgIdx = 0; + } + + if (currentAdditionalBgIdx2 == param) { + currentAdditionalBgIdx2 = 0; + } + + strcpy(currentBgName[param], ""); + return 0; +} + +int FWScript::o2_loadAbs() { + byte param1 = getNextByte(); + const char *param2 = getNextString(); + + debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2); + loadAbs(param2, param1); + return 0; +} + +int FWScript::o2_loadBg() { + byte param = getNextByte(); + + assert(param <= 8); + + debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param); + + if (additionalBgTable[param]) { + currentAdditionalBgIdx = param; + if (param == 8) { + newColorMode = 3; + } else { + newColorMode = bgColorMode + 1; + } + //if (_screenNeedFadeOut == 0) { + // adBgVar1 = 1; + //} + fadeRequired = true; + } + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_wasZoneChecked() { + warning("STUB: o2_wasZoneChecked()"); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op9B() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + uint16 c = getNextWord(); + uint16 d = getNextWord(); + uint16 e = getNextWord(); + uint16 f = getNextWord(); + uint16 g = getNextWord(); + uint16 h = getNextWord(); + warning("STUB: o2_op9B(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op9C() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + uint16 c = getNextWord(); + uint16 d = getNextWord(); + warning("STUB: o2_op9C(%x, %x, %x, %x)", a, b, c, d); + return 0; +} + +int FWScript::o2_useBgScroll() { + byte param = getNextByte(); + + assert(param <= 8); + + debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param); + + if (additionalBgTable[param]) { + currentAdditionalBgIdx2 = param; + } + return 0; +} + +int FWScript::o2_setAdditionalBgVScroll() { + byte param1 = getNextByte(); + + if (param1) { + byte param2 = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = var[%d]", _line, param2); + additionalBgVScroll = _localVars[param2]; + } else { + uint16 param2 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2); + additionalBgVScroll = param2; + } + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_op9F() { + warning("o2_op9F()"); + getNextWord(); + getNextWord(); + return 0; +} + +int FWScript::o2_addGfxElementA0() { + uint16 param1 = getNextWord(); + uint16 param2 = getNextWord(); + + debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2); + addGfxElementA0(param1, param2); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_removeGfxElementA0() { + uint16 idx = getNextWord(); + uint16 param = getNextWord(); + warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param); + removeGfxElementA0(idx, param); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_opA2() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + warning("STUB: o2_opA2(%x, %x)", a, b); + // addGfxElementA2(); + return 0; +} + +/*! \todo Implement this instruction + */ +int FWScript::o2_opA3() { + uint16 a = getNextWord(); + uint16 b = getNextWord(); + warning("STUB: o2_opA3(%x, %x)", a, b); + // removeGfxElementA2(); + return 0; +} + +int FWScript::o2_loadMask22() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: addOverlay22(%d)", _line, param); + addOverlay(param, 22); + return 0; +} + +int FWScript::o2_unloadMask22() { + byte param = getNextByte(); + + debugC(5, kCineDebugScript, "Line: %d: removeOverlay22(%d)", _line, param); + removeOverlay(param, 22); + return 0; +} + +} // End of namespace Cine diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 38c5677569..b288cd2a47 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -44,7 +44,7 @@ int16 commandVar3[4]; int16 commandVar1; int16 commandVar2; -Message messageTable[NUM_MAX_MESSAGE]; +//Message messageTable[NUM_MAX_MESSAGE]; uint16 var2; uint16 var3; @@ -130,32 +130,16 @@ void runObjectScript(int16 entryIdx) { objectScripts.push_back(tmp); } +/*! \brief Add action result message to overlay list + * \param cmd Message description + * \todo Why are x, y, width and color left uninitialized? + */ void addPlayerCommandMessage(int16 cmd) { - overlayHeadElement *currentHeadPtr = overlayHead.next; - overlayHeadElement *tempHead = &overlayHead; - overlayHeadElement *pNewElement; - - while (currentHeadPtr) { - tempHead = currentHeadPtr; - currentHeadPtr = tempHead->next; - } - - pNewElement = new overlayHeadElement; - - assert(pNewElement); - - pNewElement->next = tempHead->next; - tempHead->next = pNewElement; - - pNewElement->objIdx = cmd; - pNewElement->type = 3; - - if (!currentHeadPtr) { - currentHeadPtr = &overlayHead; - } + overlay tmp; + tmp.objIdx = cmd; + tmp.type = 3; - pNewElement->previous = currentHeadPtr->previous; - currentHeadPtr->previous = pNewElement; + overlayList.push_back(tmp); } int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) { @@ -180,55 +164,64 @@ int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSel return found; } +/*! \brief Find index of the object under cursor + * \param x Mouse cursor coordinate + * \param y Mouse cursor coordinate + * \todo Fix displaced type 1 objects + */ int16 getObjectUnderCursor(uint16 x, uint16 y) { - overlayHeadElement *currentHead = overlayHead.previous; + Common::List::iterator it; int16 objX, objY, frame, part, threshold, height, xdif, ydif; int width; - while (currentHead) { - if (currentHead->type < 2) { - if (objectTable[currentHead->objIdx].name[0]) { - objX = objectTable[currentHead->objIdx].x; - objY = objectTable[currentHead->objIdx].y; + // reverse_iterator would be nice + for (it = overlayList.reverse_begin(); it != overlayList.end(); --it) { + if (it->type >= 2 || !objectTable[it->objIdx].name[0]) { + continue; + } - frame = ABS((int16)(objectTable[currentHead->objIdx].frame)); + objX = objectTable[it->objIdx].x; + objY = objectTable[it->objIdx].y; - part = objectTable[currentHead->objIdx].part; + frame = ABS((int16)(objectTable[it->objIdx].frame)); + part = objectTable[it->objIdx].part; - if (currentHead->type == 0) { - threshold = animDataTable[frame]._var1; - } else { - threshold = animDataTable[frame]._width / 2; - } + if (it->type == 0) { + threshold = animDataTable[frame]._var1; + } else { + threshold = animDataTable[frame]._width / 2; + } - height = animDataTable[frame]._height; - width = animDataTable[frame]._realWidth; + height = animDataTable[frame]._height; + width = animDataTable[frame]._realWidth; - xdif = x - objX; - ydif = y - objY; + xdif = x - objX; + ydif = y - objY; - if ((xdif >= 0) && ((threshold << 4) > xdif) && (ydif > 0) && (ydif < height)) { - if (animDataTable[frame].data()) { - if (g_cine->getGameType() == Cine::GType_OS) { - if(xdif < width && (currentHead->type == 1 || animDataTable[frame].getColor(xdif, ydif) != objectTable[currentHead->objIdx].part)) { - return currentHead->objIdx; - } - } else if (currentHead->type == 0) { // use generated mask - if (gfxGetBit(x - objX, y - objY, animDataTable[frame].mask(), animDataTable[frame]._width)) { - return currentHead->objIdx; - } - } else if (currentHead->type == 1) { // is mask - if (gfxGetBit(x - objX, y - objY, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { - return currentHead->objIdx; - } - } - } - } - } + if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif < 0) || (ydif >= height) || !animDataTable[frame].data()) { + continue; } - currentHead = currentHead->previous; + if (g_cine->getGameType() == Cine::GType_OS) { + if (xdif >= width) { + continue; + } + + if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != part) { + return it->objIdx; + } else if (it->type == 1 && gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { + return it->objIdx; + } + } else if (it->type == 0) { // use generated mask + if (gfxGetBit(xdif, ydif, animDataTable[frame].mask(), animDataTable[frame]._width)) { + return it->objIdx; + } + } else if (it->type == 1) { // is mask + if (gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { + return it->objIdx; + } + } } return -1; @@ -285,38 +278,23 @@ void loadScriptFromSave(Common::InSaveFile *fHandle, bool isGlobal) { } } -void loadOverlayFromSave(Common::InSaveFile *fHandle) { - overlayHeadElement *newElement; - overlayHeadElement *currentHead = &overlayHead; - overlayHeadElement *tempHead = currentHead; - - currentHead = tempHead->next; - - while (currentHead) { - tempHead = currentHead; - currentHead = tempHead->next; - } - - newElement = new overlayHeadElement; - - fHandle->readUint32BE(); - fHandle->readUint32BE(); +/*! \brief Restore overlay sprites from savefile + * \param fHandle Savefile open for reading + */ +void loadOverlayFromSave(Common::InSaveFile &fHandle) { + overlay tmp; - newElement->objIdx = fHandle->readUint16BE(); - newElement->type = fHandle->readUint16BE(); - newElement->x = fHandle->readSint16BE(); - newElement->y = fHandle->readSint16BE(); - newElement->width = fHandle->readSint16BE(); - newElement->color = fHandle->readSint16BE(); + fHandle.readUint32BE(); + fHandle.readUint32BE(); - newElement->next = tempHead->next; - tempHead->next = newElement; + tmp.objIdx = fHandle.readUint16BE(); + tmp.type = fHandle.readUint16BE(); + tmp.x = fHandle.readSint16BE(); + tmp.y = fHandle.readSint16BE(); + tmp.width = fHandle.readSint16BE(); + tmp.color = fHandle.readSint16BE(); - if (!currentHead) - currentHead = &overlayHead; - - newElement->previous = currentHead->previous; - currentHead->previous = newElement; + overlayList.push_back(tmp); } /*! \brief Savefile format tester @@ -433,7 +411,7 @@ bool CineEngine::makeLoad(char *saveName) { g_sound->stopMusic(); freeAnimDataTable(); - unloadAllMasks(); + overlayList.clear(); // if (g_cine->getGameType() == Cine::GType_OS) { // freeUnkList(); // } @@ -444,15 +422,7 @@ bool CineEngine::makeLoad(char *saveName) { globalScripts.clear(); relTable.clear(); scriptTable.clear(); - - for (i = 0; i < NUM_MAX_MESSAGE; i++) { - messageTable[i].len = 0; - - if (messageTable[i].ptr) { - free(messageTable[i].ptr); - messageTable[i].ptr = NULL; - } - } + messageTable.clear(); for (i = 0; i < NUM_MAX_OBJECT; i++) { objectTable[i].part = 0; @@ -599,7 +569,7 @@ bool CineEngine::makeLoad(char *saveName) { size = fHandle->readSint16BE(); for (i = 0; i < size; i++) { - loadOverlayFromSave(fHandle); + loadOverlayFromSave(*fHandle); } loadBgIncrustFromSave(*fHandle); @@ -722,30 +692,19 @@ void makeSave(char *saveFileName) { } { - int16 numScript = 0; - overlayHeadElement *currentHead = overlayHead.next; - - while (currentHead) { - numScript++; - currentHead = currentHead->next; - } + Common::List::iterator it; - fHandle->writeUint16BE(numScript); + fHandle->writeUint16BE(overlayList.size()); - // actual save - currentHead = overlayHead.next; - - while (currentHead) { + for (it = overlayList.begin(); it != overlayList.end(); ++it) { fHandle->writeUint32BE(0); fHandle->writeUint32BE(0); - fHandle->writeUint16BE(currentHead->objIdx); - fHandle->writeUint16BE(currentHead->type); - fHandle->writeSint16BE(currentHead->x); - fHandle->writeSint16BE(currentHead->y); - fHandle->writeSint16BE(currentHead->width); - fHandle->writeSint16BE(currentHead->color); - - currentHead = currentHead->next; + fHandle->writeUint16BE(it->objIdx); + fHandle->writeUint16BE(it->type); + fHandle->writeSint16BE(it->x); + fHandle->writeSint16BE(it->y); + fHandle->writeSint16BE(it->width); + fHandle->writeSint16BE(it->color); } } @@ -762,30 +721,6 @@ void makeSave(char *saveFileName) { fHandle->writeUint16BE(it->frame); fHandle->writeUint16BE(it->part); } -/* - int numBgIncrustList = 0; - BGIncrustList *bgIncrustPtr = bgIncrustList; - - while (bgIncrustPtr) { - numBgIncrustList++; - bgIncrustPtr = bgIncrustPtr->next; - } - - fHandle->writeUint16BE(numBgIncrustList); - bgIncrustPtr = bgIncrustList; - while (bgIncrustPtr) { - fHandle->writeUint32BE(0); // next - fHandle->writeUint32BE(0); // unkPtr - fHandle->writeUint16BE(bgIncrustPtr->objIdx); - fHandle->writeUint16BE(bgIncrustPtr->param); - fHandle->writeUint16BE(bgIncrustPtr->x); - fHandle->writeUint16BE(bgIncrustPtr->y); - fHandle->writeUint16BE(bgIncrustPtr->frame); - fHandle->writeUint16BE(bgIncrustPtr->part); - - bgIncrustPtr = bgIncrustPtr->next; - } -*/ delete fHandle; @@ -1682,52 +1617,40 @@ uint16 executePlayerInput(void) { return var_5E; } -void drawSprite(overlayHeadElement *currentOverlay, const byte *spritePtr, - const byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) { - byte *ptr = NULL; +void drawSprite(Common::List::iterator it, const byte *spritePtr, const byte *maskPtr, uint16 width, uint16 height, byte *page, int16 x, int16 y) { byte *msk = NULL; - byte i = 0; - uint16 si = 0; - overlayHeadElement *pCurrentOverlay = currentOverlay; int16 maskX, maskY, maskWidth, maskHeight; uint16 maskSpriteIdx; + msk = (byte *)malloc(width * height); + if (g_cine->getGameType() == Cine::GType_OS) { - drawSpriteRaw2(spritePtr, objectTable[currentOverlay->objIdx].part, width, height, page, x, y); - return; + generateMask(spritePtr, msk, width * height, objectTable[it->objIdx].part); + } else { + memcpy(msk, maskPtr, width * height); } - while (pCurrentOverlay) { - if (pCurrentOverlay->type == 5) { - if (!si) { - ptr = (byte *)malloc(width * 8 * height); - msk = (byte *)malloc(width * 8 * height); - si = 1; - } + for (++it; it != overlayList.end(); ++it) { + if (it->type != 5) { + continue; + } - maskX = objectTable[pCurrentOverlay->objIdx].x; - maskY = objectTable[pCurrentOverlay->objIdx].y; + maskX = objectTable[it->objIdx].x; + maskY = objectTable[it->objIdx].y; - maskSpriteIdx = objectTable[pCurrentOverlay->objIdx].frame; + maskSpriteIdx = ABS((int16)(objectTable[it->objIdx].frame)); + + maskWidth = animDataTable[maskSpriteIdx]._realWidth; + maskHeight = animDataTable[maskSpriteIdx]._height; + gfxUpdateSpriteMask(msk, x, y, width, height, animDataTable[maskSpriteIdx].data(), maskX, maskY, maskWidth, maskHeight); - maskWidth = animDataTable[maskSpriteIdx]._width / 2; - maskHeight = animDataTable[maskSpriteIdx]._height; - gfxUpdateSpriteMask(spritePtr, maskPtr, width, height, animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, ptr, msk, x, y, maskX, maskY, i++); #ifdef DEBUG_SPRITE_MASK - gfxFillSprite(animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1); + gfxFillSprite(animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1); #endif - } - - pCurrentOverlay = pCurrentOverlay->next; } - if (si) { - gfxDrawMaskedSprite(ptr, msk, width, height, page, x, y); - free(ptr); - free(msk); - } else { - gfxDrawMaskedSprite(spritePtr, maskPtr, width, height, page, x, y); - } + gfxDrawMaskedSprite(spritePtr, msk, width, height, page, x, y); + free(msk); } int16 additionalBgVScroll = 0; @@ -1824,18 +1747,15 @@ void drawMessage(const char *messagePtr, int16 x, int16 y, int16 width, int16 co } void drawDialogueMessage(byte msgIdx, int16 x, int16 y, int16 width, int16 color) { - const char *messagePtr = (const char *)messageTable[msgIdx].ptr; - - if (!messagePtr) { - freeOverlay(msgIdx, 2); + if (msgIdx >= messageTable.size()) { + removeOverlay(msgIdx, 2); return; } - _messageLen += strlen(messagePtr); + _messageLen += messageTable[msgIdx].size(); + drawMessage(messageTable[msgIdx].c_str(), x, y, width, color); - drawMessage(messagePtr, x, y, width, color); - - freeOverlay(msgIdx, 2); + removeOverlay(msgIdx, 2); } void drawFailureMessage(byte cmd) { @@ -1857,161 +1777,129 @@ void drawFailureMessage(byte cmd) { drawMessage(messagePtr, x, y, width, color); - freeOverlay(cmd, 3); + removeOverlay(cmd, 3); } -/*! \todo Fix Operation Stealth logo in intro (the green text after the plane - * takes off). Each letter should slowly grow top-down, it has something to - * do with object 10 (some mask or something) - */ void drawOverlays(void) { - uint16 partVar1, partVar2; + uint16 width, height; AnimData *pPart; - overlayHeadElement *currentOverlay, *nextOverlay; int16 x, y; objectStruct *objPtr; byte messageIdx; - int16 part; + Common::List::iterator it; backupOverlayPage(); _messageLen = 0; - currentOverlay = (&overlayHead)->next; + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + switch (it->type) { + case 0: // sprite + assert(it->objIdx < NUM_MAX_OBJECT); - while (currentOverlay) { - nextOverlay = currentOverlay->next; + objPtr = &objectTable[it->objIdx]; + x = objPtr->x; + y = objPtr->y; - switch (currentOverlay->type) { - case 0: // sprite - { - assert(currentOverlay->objIdx <= NUM_MAX_OBJECT); - - objPtr = &objectTable[currentOverlay->objIdx]; - - x = objPtr->x; - y = objPtr->y; - - if (objPtr->frame >= 0) { - if (g_cine->getGameType() == Cine::GType_OS) { - pPart = &animDataTable[objPtr->frame]; - - partVar1 = pPart->_var1; - partVar2 = pPart->_height; - - if (pPart->data()) { - // NOTE: is the mask supposed to be in data()? Shouldn't that be mask(), like below? - // OS sprites don't use masks, see drawSprite() -- next_ghost - drawSprite(currentOverlay, pPart->data(), pPart->data(), partVar1, partVar2, page1Raw, x, y); - } - } else { - part = objPtr->part; + if (objPtr->frame < 0) { + continue; + } - assert(part >= 0 && part <= NUM_MAX_ANIMDATA); + pPart = &animDataTable[objPtr->frame]; + width = pPart->_realWidth; + height = pPart->_height; - pPart = &animDataTable[objPtr->frame]; + if (!pPart->data()) { + continue; + } - partVar1 = pPart->_var1; - partVar2 = pPart->_height; + // drawSprite ignores masks of Operation Stealth sprites + drawSprite(it, pPart->data(), pPart->mask(), width, height, page1Raw, x, y); + break; - if (pPart->data()) { - drawSprite(currentOverlay, pPart->data(), pPart->mask(), partVar1, partVar2, page1Raw, x, y); - } - } - } - break; - } case 2: // text - { - // gfxWaitVSync(); - // hideMouse(); + // gfxWaitVSync(); + // hideMouse(); - messageIdx = currentOverlay->objIdx; - x = currentOverlay->x; - y = currentOverlay->y; - partVar1 = currentOverlay->width; - partVar2 = currentOverlay->color; + messageIdx = it->objIdx; + x = it->x; + y = it->y; + width = it->width; + height = it->color; - blitRawScreen(page1Raw); + blitRawScreen(page1Raw); - drawDialogueMessage(messageIdx, x, y, partVar1, partVar2); + drawDialogueMessage(messageIdx, x, y, width, height); - // blitScreen(page0, NULL); - // gfxRedrawMouseCursor(); + // blitScreen(page0, NULL); + // gfxRedrawMouseCursor(); - waitForPlayerClick = 1; + waitForPlayerClick = 1; + + break; - break; - } case 3: - { - // gfxWaitSync() - // hideMouse(); + // gfxWaitSync() + // hideMouse(); - blitRawScreen(page1Raw); + blitRawScreen(page1Raw); - drawFailureMessage(currentOverlay->objIdx); + drawFailureMessage(it->objIdx); - // blitScreen(page0, NULL); - // gfxRedrawMouseCursor(); + // blitScreen(page0, NULL); + // gfxRedrawMouseCursor(); - waitForPlayerClick = 1; + waitForPlayerClick = 1; - break; - } - case 4: - { - assert(currentOverlay->objIdx <= NUM_MAX_OBJECT); - - objPtr = &objectTable[currentOverlay->objIdx]; + break; - x = objPtr->x; - y = objPtr->y; + case 4: + assert(it->objIdx < NUM_MAX_OBJECT); + objPtr = &objectTable[it->objIdx]; + x = objPtr->x; + y = objPtr->y; - if (objPtr->frame >= 0) { - part = objPtr->part; + if (objPtr->frame < 0) { + continue; + } - assert(part >= 0 && part <= NUM_MAX_ANIMDATA); + assert(objPtr->frame < NUM_MAX_ANIMDATA); - pPart = &animDataTable[objPtr->frame]; + pPart = &animDataTable[objPtr->frame]; - partVar1 = pPart->_width / 2; - partVar2 = pPart->_height; + width = pPart->_realWidth; + height = pPart->_height; - if (pPart->data()) { - gfxFillSprite(pPart->data(), partVar1, partVar2, page1Raw, x, y); - } - } - break; + if (!pPart->data()) { + continue; } - case 20: - { - assert(currentOverlay->objIdx <= NUM_MAX_OBJECT); - objPtr = &objectTable[currentOverlay->objIdx]; + gfxFillSprite(pPart->data(), width, height, page1Raw, x, y); + break; - x = objPtr->x; - y = objPtr->y; + case 20: + assert(it->objIdx < NUM_MAX_OBJECT); - var5 = currentOverlay->x; + objPtr = &objectTable[it->objIdx]; + x = objPtr->x; + y = objPtr->y; + var5 = it->x; - if (objPtr->frame >= 0 && var5 <= 8 && additionalBgTable[var5] && animDataTable[objPtr->frame]._bpp == 1) { - int16 x2; - int16 y2; + if (objPtr->frame < 0 || var5 > 8 || !additionalBgTable[var5] || animDataTable[objPtr->frame]._bpp != 1) { + continue; + } - x2 = animDataTable[objPtr->frame]._width / 2; - y2 = animDataTable[objPtr->frame]._height; + width = animDataTable[objPtr->frame]._realWidth; + height = animDataTable[objPtr->frame]._height; - if (animDataTable[objPtr->frame].data()) { - maskBgOverlay(additionalBgTable[var5], animDataTable[objPtr->frame].data(), x2, y2, page1Raw, x, y); - } - } - break; + if (!animDataTable[objPtr->frame].data()) { + continue; } - } - currentOverlay = nextOverlay; + maskBgOverlay(additionalBgTable[var5], animDataTable[objPtr->frame].data(), width, height, page1Raw, x, y); + break; + } } } @@ -2040,8 +1928,7 @@ void checkForPendingDataLoad(void) { } if (newObjectName[0] != 0) { - unloadAllMasks(); - resetMessageHead(); + overlayList.clear(); loadObject(newObjectName); @@ -2071,40 +1958,50 @@ void removeExtention(char *dest, const char *source) { } void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5) { - overlayHeadElement *currentHead = &overlayHead; - overlayHeadElement *tempHead = currentHead; - overlayHeadElement *newElement; + overlay tmp; - currentHead = tempHead->next; + tmp.objIdx = param1; + tmp.type = 2; + tmp.x = param2; + tmp.y = param3; + tmp.width = param4; + tmp.color = param5; - while (currentHead) { + overlayList.push_back(tmp); +} + +SeqListElement seqList; + +void removeSeq(uint16 param1, uint16 param2, uint16 param3) { + SeqListElement *currentHead = &seqList; + SeqListElement *tempHead = currentHead; + + while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) { tempHead = currentHead; currentHead = tempHead->next; } - newElement = new overlayHeadElement; - - newElement->next = tempHead->next; - tempHead->next = newElement; - - newElement->objIdx = param1; - newElement->type = 2; + if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) { + currentHead->var4 = -1; + } +} - newElement->x = param2; - newElement->y = param3; - newElement->width = param4; - newElement->color = param5; +uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { + SeqListElement *currentHead = &seqList; + SeqListElement *tempHead = currentHead; - if (!currentHead) - currentHead = &overlayHead; + while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) { + tempHead = currentHead; + currentHead = tempHead->next; + } - newElement->previous = currentHead->previous; + if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) { + return 1; + } - currentHead->previous = newElement; + return 0; } -SeqListElement seqList; - void addSeqListElement(int16 param0, int16 param1, int16 param2, int16 param3, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) { SeqListElement *currentHead = &seqList; SeqListElement *tempHead = currentHead; diff --git a/engines/cine/various.h b/engines/cine/various.h index 314a0bd24b..f906b2aa19 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -42,15 +42,6 @@ void makeActionMenu(void); extern bool disableSystemMenu; extern bool inMenu; -struct Message { - byte *ptr; - uint16 len; -}; - -#define NUM_MAX_MESSAGE 255 - -extern Message messageTable[NUM_MAX_MESSAGE]; - struct SeqListElement { struct SeqListElement *next; int16 var4; @@ -149,6 +140,8 @@ void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 par extern int16 additionalBgVScroll; +void removeSeq(uint16 param1, uint16 param2, uint16 param3); +uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3); void addSeqListElement(int16 param0, int16 param1, int16 param2, int16 param3, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8); void resetSeqList(); void processSeqList(void); diff --git a/engines/cine/xref.txt b/engines/cine/xref.txt index fd76f7eaaf..3640ef83d6 100644 --- a/engines/cine/xref.txt +++ b/engines/cine/xref.txt @@ -144,3 +144,10 @@ bg_list.cpp reincrustAllBg() - removed (obsoleted by new loadResourcesFromSave() and loadBgIncrustFromSave() implementation) freeBgIncrustList() - removed (obsoleted by Common::List::clear()) + +object.cpp +unloadAllMasks() - removed (obsoleted by Common::List::clear()) +resetMessageHead() - removed (obsoleted by Common::List) +freeOverlay() - removed (duplicate of removeOverlay) +removeOverlayElement() - renamed to removeOverlay +loadOverlayElement() - renamed to addOverlay -- cgit v1.2.3