/* 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. * */ #include "common/config-manager.h" #include "common/endian.h" #include "common/events.h" #include "common/system.h" // for g_system->getEventManager() #include "common/textconsole.h" #include "cruise/cruise.h" #include "cruise/cruise_main.h" #include "cruise/cell.h" #include "cruise/staticres.h" namespace Cruise { enum RelationType {RT_REL = 30, RT_MSG = 50}; static bool _playerDontAskQuit; unsigned int timer = 0; gfxEntryStruct *linkedMsgList = nullptr; typedef CruiseEngine::MemInfo MemInfo; void MemoryList() { if (!_vm->_memList.empty()) { debug("Current list of un-freed memory blocks:"); Common::List::iterator i; for (i = _vm->_memList.begin(); i != _vm->_memList.end(); ++i) { MemInfo const *const v = *i; debug("%s - %d", v->fname, v->lineNum); } } } void *MemoryAlloc(uint32 size, bool clearFlag, int32 lineNum, const char *fname) { void *result; if (gDebugLevel > 0) { // Find the point after the final slash const char *fnameP = fname + strlen(fname); while ((fnameP > fname) && (*(fnameP - 1) != '/') && (*(fnameP - 1) != '\\')) --fnameP; // Create the new memory block and add it to the memory list MemInfo *const v = (MemInfo *)malloc(sizeof(MemInfo) + size); v->lineNum = lineNum; strncpy(v->fname, fnameP, sizeof(v->fname)); v->fname[ARRAYSIZE(v->fname) - 1] = '\0'; v->magic = MemInfo::cookie; // Add the block to the memory list _vm->_memList.push_back(v); result = v + 1; } else result = malloc(size); if (clearFlag) memset(result, 0, size); return result; } void MemoryFree(void *v) { if (!v) return; if (gDebugLevel > 0) { MemInfo *const p = (MemInfo *)v - 1; assert(p->magic == MemInfo::cookie); _vm->_memList.remove(p); free(p); } else free(v); } void drawBlackSolidBoxSmall() { // gfxModuleData.drawSolidBox(64,100,256,117,0); drawSolidBox(64, 100, 256, 117, 0); } void loadPackedFileToMem(int fileIdx, uint8 *buffer) { changeCursor(CURSOR_DISK); _vm->_currentVolumeFile.seek(volumePtrToFileDescriptor[fileIdx].offset, SEEK_SET); _vm->_currentVolumeFile.read(buffer, volumePtrToFileDescriptor[fileIdx].size); } int getNumObjectsByClass(int scriptIdx, int param) { objDataStruct *ptr2; int counter; if (!overlayTable[scriptIdx].ovlData) return (0); ptr2 = overlayTable[scriptIdx].ovlData->arrayObject; if (!ptr2) return (0); if (overlayTable[scriptIdx].ovlData->numObj == 0) return (0); counter = 0; for (int i = 0; i < overlayTable[scriptIdx].ovlData->numObj; i++) { if (ptr2[i]._class == param) { counter++; } } return (counter); } void resetFileEntryRange(int start, int count) { for (int i = 0; i < count; ++i) resetFileEntry(start + i); } int getProcParam(int overlayIdx, int param2, const char *name) { int numSymbGlob; exportEntryStruct *arraySymbGlob; char *exportNamePtr; char exportName[80]; if (!overlayTable[overlayIdx].alreadyLoaded) return 0; if (!overlayTable[overlayIdx].ovlData) return 0; numSymbGlob = overlayTable[overlayIdx].ovlData->numSymbGlob; arraySymbGlob = overlayTable[overlayIdx].ovlData->arraySymbGlob; exportNamePtr = overlayTable[overlayIdx].ovlData->arrayNameSymbGlob; if (!exportNamePtr) return 0; for (int i = 0; i < numSymbGlob; i++) { if (arraySymbGlob[i].var4 == param2) { Common::strlcpy(exportName, arraySymbGlob[i].offsetToName + exportNamePtr, sizeof(exportName)); if (!strcmp(exportName, name)) { return (arraySymbGlob[i].idx); } } } return 0; } void changeScriptParamInList(int param1, int param2, scriptInstanceStruct *pScriptInstance, int oldFreeze, int newValue) { pScriptInstance = pScriptInstance->nextScriptPtr; while (pScriptInstance) { if ((pScriptInstance->overlayNumber == param1) || (param1 == -1)) if ((pScriptInstance->scriptNumber == param2) || (param2 == -1)) if ((pScriptInstance->freeze == oldFreeze) || (oldFreeze == -1)) { pScriptInstance->freeze = newValue; } pScriptInstance = pScriptInstance->nextScriptPtr; } } void initBigVar3() { for (int i = 0; i < NUM_FILE_ENTRIES; i++) { if (filesDatabase[i].subData.ptr) { MemFree(filesDatabase[i].subData.ptr); } filesDatabase[i].subData.ptr = NULL; filesDatabase[i].subData.ptrMask = NULL; filesDatabase[i].subData.index = -1; filesDatabase[i].subData.resourceType = 0; } } void resetPtr2(scriptInstanceStruct *ptr) { ptr->nextScriptPtr = NULL; ptr->scriptNumber = -1; } void resetActorPtr(actorStruct *ptr) { actorStruct *p = ptr; if (p->next) { p = p->next; do { actorStruct *pNext = p->next; MemFree(p); p = pNext; } while (p); } ptr->next = NULL; ptr->prev = NULL; } ovlData3Struct *getOvlData3Entry(int32 scriptNumber, int32 param) { ovlDataStruct *ovlData = overlayTable[scriptNumber].ovlData; if (!ovlData) { return NULL; } if (param < 0) { return NULL; } if (ovlData->numProc <= param) { return NULL; } if (!ovlData->arrayProc) { return NULL; } return (&ovlData->arrayProc[param]); } ovlData3Struct *scriptFunc1Sub2(int32 scriptNumber, int32 param) { ovlDataStruct *ovlData = overlayTable[scriptNumber].ovlData; if (!ovlData) { return NULL; } if (param < 0) { return NULL; } if (ovlData->numRel <= param) { return NULL; } if (!ovlData->ptr1) { return NULL; } return &ovlData->ptr1[param]; } void scriptFunc2(int scriptNumber, scriptInstanceStruct * scriptHandle, int param, int param2) { if (scriptHandle->nextScriptPtr) { if (scriptNumber == scriptHandle->nextScriptPtr->overlayNumber || scriptNumber != -1) { if (param2 == scriptHandle->nextScriptPtr->scriptNumber || param2 != -1) { scriptHandle->nextScriptPtr->sysKey = param; } } } } uint8 *getDataFromData3(ovlData3Struct *ptr, int param) { uint8 *dataPtr; if (!ptr) return (NULL); dataPtr = ptr->dataPtr; if (!dataPtr) return (NULL); switch (param) { case 0: return (dataPtr); case 1: return (dataPtr + ptr->offsetToSubData3); // strings case 2: return (dataPtr + ptr->offsetToSubData2); case 3: return (dataPtr + ptr->offsetToImportData); // import data case 4: return (dataPtr + ptr->offsetToImportName); // import names case 5: return (dataPtr + ptr->offsetToSubData5); default: return NULL; } } void printInfoBlackBox(const char *string) { } void waitForPlayerInput() { } void getFileExtention(const char *name, char *buffer) { while (*name != '.' && *name) { name++; } strcpy(buffer, name); } void removeExtention(const char *name, char *buffer) { // not like in original char *ptr; strcpy(buffer, name); ptr = strchr(buffer, '.'); if (ptr) *ptr = 0; } int lastFileSize; int loadFileSub1(uint8 **ptr, const char *name, uint8 *ptr2) { char buffer[256]; int fileIdx; int unpackedSize; uint8 *unpackedBuffer; for (int i = 0; i < 64; i++) { if (preloadData[i].ptr) { if (!strcmp(preloadData[i].name, name)) { error("Unsupported code in loadFIleSub1"); } } } getFileExtention(name, buffer); if (!strcmp(buffer, ".SPL")) { removeExtention(name, buffer); /* if (useH32) *{ * strcat(buffer, ".H32"); *} * else * if (useAdLib) * { */ strcat(buffer,".ADL"); /* } * else * { * strcatuint8(buffer,".HP"); * } */ } else { Common::strlcpy(buffer, name, sizeof(buffer)); } fileIdx = findFileInDisks(buffer); if (fileIdx < 0) return (-18); unpackedSize = loadFileVar1 = volumePtrToFileDescriptor[fileIdx].extSize + 2; unpackedBuffer = (uint8 *)mallocAndZero(unpackedSize); if (!unpackedBuffer) { return (-2); } lastFileSize = unpackedSize; if (volumePtrToFileDescriptor[fileIdx].size + 2 != unpackedSize) { uint8 *pakedBuffer = (uint8 *) mallocAndZero(volumePtrToFileDescriptor[fileIdx].size + 2); loadPackedFileToMem(fileIdx, pakedBuffer); uint32 realUnpackedSize = READ_BE_UINT32(pakedBuffer + volumePtrToFileDescriptor[fileIdx].size - 4); lastFileSize = realUnpackedSize; delphineUnpack(unpackedBuffer, pakedBuffer, volumePtrToFileDescriptor[fileIdx].size); MemFree(pakedBuffer); } else { loadPackedFileToMem(fileIdx, unpackedBuffer); } *ptr = unpackedBuffer; return (1); } void resetFileEntry(int32 entryNumber) { if (entryNumber >= NUM_FILE_ENTRIES) return; if (!filesDatabase[entryNumber].subData.ptr) return; MemFree(filesDatabase[entryNumber].subData.ptr); if (filesDatabase[entryNumber].subData.ptrMask) MemFree(filesDatabase[entryNumber].subData.ptrMask); filesDatabase[entryNumber].subData.ptr = NULL; filesDatabase[entryNumber].subData.ptrMask = NULL; filesDatabase[entryNumber].widthInColumn = 0; filesDatabase[entryNumber].width = 0; filesDatabase[entryNumber].resType = OBJ_TYPE_LINE; filesDatabase[entryNumber].height = 0; filesDatabase[entryNumber].subData.index = -1; filesDatabase[entryNumber].subData.resourceType = 0; filesDatabase[entryNumber].subData.compression = 0; filesDatabase[entryNumber].subData.name[0] = 0; } uint8 *mainProc14(uint16 overlay, uint16 idx) { assert(0); return NULL; } void CruiseEngine::initAllData() { setupFuncArray(); initOverlayTable(); stateID = 0; masterScreen = 0; freeDisk(); soundList[0].frameNum = -1; soundList[1].frameNum = -1; soundList[2].frameNum = -1; soundList[3].frameNum = -1; menuTable[0] = NULL; for (int i = 0; i < 2000; i++) globalVars[i] = 0; for (int i = 0; i < 8; i++) backgroundTable[i].name[0] = 0; for (int i = 0; i < NUM_FILE_ENTRIES; i++) { filesDatabase[i].subData.ptr = NULL; filesDatabase[i].subData.ptrMask = NULL; } initBigVar3(); resetPtr2(&procHead); resetPtr2(&relHead); resetPtr(&cellHead); resetActorPtr(&actorHead); resetBackgroundIncrustList(&backgroundIncrustHead); bootOverlayNumber = loadOverlay("AUTO00"); #ifdef DUMP_SCRIPT loadOverlay("TITRE"); loadOverlay("TOM"); loadOverlay("XX2"); loadOverlay("SUPER"); loadOverlay("BEBE1"); loadOverlay("BIBLIO"); loadOverlay("BRACAGE"); loadOverlay("CONVERS"); loadOverlay("DAF"); loadOverlay("DAPHNEE"); loadOverlay("DESIRE"); loadOverlay("FAB"); loadOverlay("FABIANI"); loadOverlay("FIN"); loadOverlay("FIN01"); loadOverlay("FINBRAC"); loadOverlay("GEN"); loadOverlay("GENDEB"); loadOverlay("GIFLE"); loadOverlay("HECTOR"); loadOverlay("HECTOR2"); loadOverlay("I00"); loadOverlay("I01"); loadOverlay("I04"); loadOverlay("I06"); loadOverlay("I07"); loadOverlay("INVENT"); loadOverlay("JULIO"); loadOverlay("LOGO"); loadOverlay("MANOIR"); loadOverlay("MISSEL"); loadOverlay("POKER"); loadOverlay("PROJ"); loadOverlay("REB"); loadOverlay("REBECCA"); loadOverlay("ROS"); loadOverlay("ROSE"); loadOverlay("S01"); loadOverlay("S02"); loadOverlay("S03"); loadOverlay("S04"); loadOverlay("S06"); loadOverlay("S07"); loadOverlay("S08"); loadOverlay("S09"); loadOverlay("S10"); loadOverlay("S103"); loadOverlay("S11"); loadOverlay("S113"); loadOverlay("S12"); loadOverlay("S129"); loadOverlay("S131"); loadOverlay("S132"); loadOverlay("S133"); loadOverlay("int16"); loadOverlay("S17"); loadOverlay("S18"); loadOverlay("S19"); loadOverlay("S20"); loadOverlay("S21"); loadOverlay("S22"); loadOverlay("S23"); loadOverlay("S24"); loadOverlay("S25"); loadOverlay("S26"); loadOverlay("S27"); loadOverlay("S29"); loadOverlay("S30"); loadOverlay("S31"); loadOverlay("int32"); loadOverlay("S33"); loadOverlay("S33B"); loadOverlay("S34"); loadOverlay("S35"); loadOverlay("S36"); loadOverlay("S37"); loadOverlay("SHIP"); loadOverlay("SUPER"); loadOverlay("SUZAN"); loadOverlay("SUZAN2"); loadOverlay("TESTA1"); loadOverlay("TESTA2"); //exit(1); #endif if (bootOverlayNumber) { positionInStack = 0; attacheNewScriptToTail(&procHead, bootOverlayNumber, 0, 20, 0, 0, scriptType_PROC); scriptFunc2(bootOverlayNumber, &procHead, 1, 0); } strcpy(lastOverlay, "AUTO00"); _gameSpeed = GAME_FRAME_DELAY_1; _speedFlag = false; return; } int removeFinishedScripts(scriptInstanceStruct *ptrHandle) { scriptInstanceStruct *ptr = ptrHandle->nextScriptPtr; // can't destruct the head scriptInstanceStruct *oldPtr = ptrHandle; if (!ptr) return (0); do { if (ptr->scriptNumber == -1) { oldPtr->nextScriptPtr = ptr->nextScriptPtr; if (ptr->data) MemFree(ptr->data); MemFree(ptr); ptr = oldPtr->nextScriptPtr; } else { oldPtr = ptr; ptr = ptr->nextScriptPtr; } } while (ptr); return (0); } void removeAllScripts(scriptInstanceStruct *ptrHandle) { scriptInstanceStruct *ptr = ptrHandle->nextScriptPtr; // can't destruct the head scriptInstanceStruct *oldPtr = ptrHandle; if (!ptr) return; do { oldPtr->nextScriptPtr = ptr->nextScriptPtr; if (ptr->data) MemFree(ptr->data); MemFree(ptr); ptr = oldPtr->nextScriptPtr; } while (ptr); } bool testMask(int x, int y, unsigned char* pData, int stride) { unsigned char* ptr = y * stride + x / 8 + pData; unsigned char bitToTest = 0x80 >> (x & 7); if ((*ptr) & bitToTest) return true; return false; } int buttonDown; int selectDown = 0; int menuDown = 0; int findObject(int mouseX, int mouseY, int *outObjOvl, int *outObjIdx) { char objectName[80]; cellStruct *currentObject = cellHead.prev; while (currentObject) { if (currentObject->overlay > 0 && overlayTable[currentObject->overlay].alreadyLoaded && (currentObject->type == OBJ_TYPE_SPRITE || currentObject->type == OBJ_TYPE_MASK || currentObject->type == OBJ_TYPE_EXIT || currentObject->type == OBJ_TYPE_VIRTUAL)) { const char* pObjectName = getObjectName(currentObject->idx, overlayTable[currentObject->overlay].ovlData->arrayNameObj); Common::strlcpy(objectName, pObjectName, sizeof(objectName)); if (strlen(objectName) && (currentObject->freeze == 0)) { int objIdx = currentObject->idx; int objOvl = currentObject->overlay; int linkedObjIdx = currentObject->followObjectIdx; int linkedObjOvl = currentObject->followObjectOverlayIdx; objectParamsQuery params; getMultipleObjectParam(objOvl, objIdx, ¶ms); int x2 = 0; int y2 = 0; int j2 = 0; if ((objOvl != linkedObjOvl) || (objIdx != linkedObjIdx)) { objectParamsQuery params2; getMultipleObjectParam(linkedObjOvl, linkedObjIdx, ¶ms2); x2 = params2.X; y2 = params2.Y; j2 = params2.fileIdx; } if (params.state >= 0 && params.fileIdx >= 0) { if (currentObject->type == OBJ_TYPE_SPRITE || currentObject->type == OBJ_TYPE_MASK || currentObject->type == OBJ_TYPE_EXIT) { int x = params.X + x2; int y = params.Y + y2; int j = params.fileIdx; if (j >= 0) { j += j2; } if ((filesDatabase[j].subData.resourceType == OBJ_TYPE_POLY) && (filesDatabase[j].subData.ptr)) { int zoom = params.scale; int16* dataPtr = (int16 *)filesDatabase[j].subData.ptr; if (*dataPtr == 0) { int16 offset; int16 newX; int16 newY; dataPtr ++; offset = (int16)READ_BE_UINT16(dataPtr); dataPtr++; newX = (int16)READ_BE_UINT16(dataPtr); dataPtr++; newY = (int16)READ_BE_UINT16(dataPtr); dataPtr++; offset += j; if (offset >= 0) { if (filesDatabase[offset].resType == OBJ_TYPE_LINE && filesDatabase[offset].subData.ptr) { dataPtr = (int16 *)filesDatabase[offset].subData.ptr; } } zoom = -zoom; x -= newX; y -= newY; } if (dataPtr && findPoly((char *)dataPtr, x, y, zoom, mouseX, mouseY)) { *outObjOvl = linkedObjOvl; *outObjIdx = linkedObjIdx; return (currentObject->type); } } else { // int numBitPlanes = filesDatabase[j].resType; int nWidth; int nHeight; nWidth = filesDatabase[j].width; nHeight = filesDatabase[j].height; int offsetX = mouseX - x; int offsetY = mouseY - y; if ((offsetX >= 0) && (offsetX < nWidth) && (offsetY >= 0) && (offsetY <= nHeight) && filesDatabase[j].subData.ptr) { if (testMask(offsetX, offsetY, filesDatabase[j].subData.ptrMask, filesDatabase[j].width / 8)) { *outObjOvl = linkedObjOvl; *outObjIdx = linkedObjIdx; return currentObject->type; } } } } else if (currentObject->type == OBJ_TYPE_VIRTUAL) { int x = params.X + x2; int y = params.Y + y2; int width = params.fileIdx; int height = params.scale; if ((mouseX >= x) && (mouseX <= x + width) && (mouseY >= y) && (mouseY <= y + height)) { *outObjOvl = linkedObjOvl; *outObjIdx = linkedObjIdx; return (currentObject->type); } } } } } currentObject = currentObject->prev; } *outObjOvl = 0; *outObjIdx = 0; return -1; } Common::KeyCode keyboardCode = Common::KEYCODE_INVALID; void freeStuff2() { warning("implement freeStuff2"); } void *allocAndZero(int size) { void *ptr; ptr = MemAlloc(size); memset(ptr, 0, size); return ptr; } void buildInventory(int X, int Y) { menuStruct *pMenu; pMenu = createMenu(X, Y, _vm->langString(ID_INVENTORY)); menuTable[1] = pMenu; if (pMenu == NULL) return; int numObjectInInventory = 0; for (int i = 1; i < numOfLoadedOverlay; i++) { ovlDataStruct *pOvlData = overlayTable[i].ovlData; if (overlayTable[i].alreadyLoaded) { if (overlayTable[i].ovlData->arrayObject) { for (int j = 0; j < pOvlData->numObj; j++) { if (getObjectClass(i, j) != 3) { int16 returnVar; getSingleObjectParam(i, j, 5, &returnVar); if (returnVar < -1) { addSelectableMenuEntry(i, j, pMenu, 1, -1, getObjectName(j, pOvlData->arrayNameObj)); numObjectInInventory++; } } } } } } if (numObjectInInventory == 0) { freeMenu(menuTable[1]); menuTable[1] = NULL; } } int currentMenuElementX; int currentMenuElementY; menuElementStruct *currentMenuElement; menuElementSubStruct *getSelectedEntryInMenu(menuStruct *pMenu) { menuElementStruct *pMenuElement; if (pMenu == NULL) { return NULL; } if (pMenu->numElements == 0) { return NULL; } pMenuElement = pMenu->ptrNextElement; while (pMenuElement) { if (pMenuElement->selected) { currentMenuElementX = pMenuElement->x; currentMenuElementY = pMenuElement->y; currentMenuElement = pMenuElement; return pMenuElement->ptrSub; } pMenuElement = pMenuElement->next; } return NULL; } bool createDialog(int objOvl, int objIdx, int x, int y) { bool found = false; int testState1 = -1; int testState2 = -1; int16 objectState; int16 objectState2; getSingleObjectParam(objOvl, objIdx, 5, &objectState); menuTable[0] = createMenu(x, y, _vm->langString(ID_SPEAK_ABOUT)); for (int j = 1; j < numOfLoadedOverlay; j++) { if (overlayTable[j].alreadyLoaded) { int idHeader = overlayTable[j].ovlData->numMsgRelHeader; for (int i = 0; i < idHeader; i++) { linkDataStruct* ptrHead = &overlayTable[j].ovlData->arrayMsgRelHeader[i]; int thisOvl = ptrHead->obj1Overlay; if (!thisOvl) { thisOvl = j; } objDataStruct* pObject = getObjectDataFromOverlay(thisOvl, ptrHead->obj1Number); getSingleObjectParam(thisOvl, ptrHead->obj1Number, 5, &objectState2); if (pObject && (pObject->_class == THEME) && (objectState2 < -1)) { thisOvl = ptrHead->obj2Overlay; if (!thisOvl) { thisOvl = j; } if ((thisOvl == objOvl) && (ptrHead->obj2Number == objIdx)) { int verbOvl = ptrHead->verbOverlay; int obj1Ovl = ptrHead->obj1Overlay; int obj2Ovl = ptrHead->obj2Overlay; if (!verbOvl) verbOvl = j; if (!obj1Ovl) obj1Ovl = j; if (!obj2Ovl) obj2Ovl = j; char verbName[80]; verbName[0] = 0; ovlDataStruct *ovl2 = NULL; ovlDataStruct *ovl3 = NULL; ovlDataStruct *ovl4 = NULL; if (verbOvl > 0) ovl2 = overlayTable[verbOvl].ovlData; if (obj1Ovl > 0) ovl3 = overlayTable[obj1Ovl].ovlData; if (obj2Ovl > 0) ovl4 = overlayTable[obj2Ovl].ovlData; if (ovl3 && (ptrHead->obj1Number >= 0)) { testState1 = ptrHead->obj1OldState; } if (ovl4 && (ptrHead->obj2Number >= 0)) { testState2 = ptrHead->obj2OldState; } if (ovl4 && ovl2 && (ptrHead->verbNumber >= 0) && ((testState1 == -1) || (testState1 == objectState2)) && ((testState2 == -1) || (testState2 == objectState))) { if (ovl2->nameVerbGlob) { const char *ptr = getObjectName(ptrHead->verbNumber, ovl2->nameVerbGlob); Common::strlcpy(verbName, ptr, sizeof(verbName)); if (!strlen(verbName)) attacheNewScriptToTail(&relHead, j, ptrHead->id, 30, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_REL); else if (ovl2->nameVerbGlob) { found = true; int color; if (objectState2 == -2) color = subColor; else color = -1; if (ovl3) { ptr = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj); addSelectableMenuEntry(j, i, menuTable[0], 1, color, ptr); } else error("Unexpected null pointer in createDialog()"); } } } } } } } } return found; } bool findRelation(int objOvl, int objIdx, int x, int y) { bool found = false; bool first = true; int testState = -1; int16 objectState; getSingleObjectParam(objOvl, objIdx, 5, &objectState); for (int j = 1; j < numOfLoadedOverlay; j++) { if (overlayTable[j].alreadyLoaded) { int idHeader = overlayTable[j].ovlData->numMsgRelHeader; for (int i = 0; i < idHeader; i++) { linkDataStruct* ptrHead = &overlayTable[j].ovlData->arrayMsgRelHeader[i]; int thisOvl = ptrHead->obj1Overlay; if (!thisOvl) { thisOvl = j; } //const char* pName = getObjectName(ptrHead->obj1Number, overlayTable[thisOvl].ovlData->arrayNameObj); objDataStruct* pObject = getObjectDataFromOverlay(thisOvl, ptrHead->obj1Number); if ((thisOvl == objOvl) && (objIdx == ptrHead->obj1Number) && pObject && (pObject->_class != THEME)) { int verbOvl = ptrHead->verbOverlay; int obj1Ovl = ptrHead->obj1Overlay; // Unused variable // int obj2Ovl = ptrHead->obj2Overlay; if (!verbOvl) verbOvl = j; if (!obj1Ovl) obj1Ovl = j; // Unused variable // if (!obj2Ovl) // obj2Ovl = j; char verbName[80]; verbName[0] = 0; ovlDataStruct *ovl2 = NULL; ovlDataStruct *ovl3 = NULL; if (verbOvl > 0) ovl2 = overlayTable[verbOvl].ovlData; if (obj1Ovl > 0) ovl3 = overlayTable[obj1Ovl].ovlData; //if (obj2Ovl > 0) // ovl4 = overlayTable[obj2Ovl].ovlData; if ((ovl3) && (ptrHead->obj1Number >= 0)) { testState = ptrHead->obj1OldState; if ((first) && (ovl3->arrayNameObj) && ((testState == -1) || (testState == objectState))) { const char *ptrName = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj); menuTable[0] = createMenu(x, y, ptrName); first = false; } } if ((ovl2) && (ptrHead->verbNumber >= 0)) { if (ovl2->nameVerbGlob) { const char *ptr = getObjectName(ptrHead->verbNumber, ovl2->nameVerbGlob); Common::strlcpy(verbName, ptr, sizeof(verbName)); if ((!first) && ((testState == -1) || (testState == objectState))) { if (!strlen(verbName)) { if (currentScriptPtr) { attacheNewScriptToTail(&relHead, j, ptrHead->id, 30, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_REL); } else { attacheNewScriptToTail(&relHead, j, ptrHead->id, 30, 0, 0, scriptType_REL); } } else if (ovl2->nameVerbGlob) { found = true; ptr = getObjectName(ptrHead->verbNumber, ovl2->nameVerbGlob); addSelectableMenuEntry(j, i, menuTable[0], 1, -1, ptr); } } } } } } } } return found; } int processInventory() { if (menuTable[1]) { menuElementSubStruct *pMenuElementSub = getSelectedEntryInMenu(menuTable[1]); if (pMenuElementSub) { int var2 = pMenuElementSub->ovlIdx; int var4 = pMenuElementSub->header; freeMenu(menuTable[1]); menuTable[1] = NULL; findRelation(var2, var4, currentMenuElementX + 80, currentMenuElementY); return 1; } else { freeMenu(menuTable[1]); menuTable[1] = NULL; } } return 0; } void callSubRelation(menuElementSubStruct *pMenuElement, int nOvl, int nObj) { if (pMenuElement == NULL) return; menuElementSubStruct* pCurrent = pMenuElement; while (pCurrent != NULL) { int ovlIdx = pCurrent->ovlIdx; int header = pCurrent->header; linkDataStruct* pHeader = &overlayTable[ovlIdx].ovlData->arrayMsgRelHeader[header]; int obj2Ovl = pHeader->obj2Overlay; if (obj2Ovl == 0) { obj2Ovl = ovlIdx; } if ((obj2Ovl == nOvl) && (pHeader->obj2Number != -1) && (pHeader->obj2Number == nObj)) { objectParamsQuery params; memset(¶ms, 0, sizeof(objectParamsQuery)); // to remove warning if (pHeader->obj2Number >= 0) { getMultipleObjectParam(obj2Ovl, pHeader->obj2Number, ¶ms); } if ((pHeader->obj2OldState == -1) || (params.state == pHeader->obj2OldState)) { if (pHeader->type == RT_REL) { // REL if (currentScriptPtr) { attacheNewScriptToTail(&relHead, ovlIdx, pHeader->id, 30, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_REL); } else { attacheNewScriptToTail(&relHead, ovlIdx, pHeader->id, 30, 0, 0, scriptType_REL); } if ((narratorOvl > 0) && (pHeader->trackX != -1) && (pHeader->trackY != -1)) { actorStruct* pTrack = findActor(&actorHead, narratorOvl, narratorIdx, 0); if (pTrack) { animationStart = false; if (pHeader->trackDirection == 9999) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = direction(naratorParams.X, naratorParams.Y, pTrack->x_dest, pTrack->y_dest, 0, 0); } else if ((pHeader->trackX == 9999) && (pHeader->trackY == 9999)) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = pHeader->trackDirection; } else { pTrack->x_dest = pHeader->trackX; pTrack->y_dest = pHeader->trackY; pTrack->endDirection = pHeader->trackDirection; } pTrack->flag = 1; autoTrack = true; userEnabled = 0; changeScriptParamInList(ovlIdx, pHeader->id, &relHead, 0, 9998); } } } else if (pHeader->type == RT_MSG) { int x = 60; int y = 60; if (pHeader->obj2Number >= 0) { if ((pHeader->trackX !=-1) && (pHeader->trackY !=-1) && (pHeader->trackX != 9999) && (pHeader->trackY != 9999)) { x = pHeader->trackX - 100; y = pHeader->trackY - 150; } else if (params.scale >= 0) { x = params.X - 100; y = params.Y - 40; } if (pHeader->obj2NewState != -1) { objInit(obj2Ovl, pHeader->obj2Number, pHeader->obj2NewState); } } if ((pHeader->obj1Number >= 0) && (pHeader->obj1NewState != -1)) { int obj1Ovl = pHeader->obj1Overlay; if (!obj1Ovl) obj1Ovl = ovlIdx; objInit(obj1Ovl, pHeader->obj1Number, pHeader->obj1NewState); } if (currentScriptPtr) { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber); } else { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0); } userWait = true; autoOvl = ovlIdx; autoMsg = pHeader->id; if ((narratorOvl > 0) && (pHeader->trackX != -1) && (pHeader->trackY != -1)) { actorStruct *pTrack = findActor(&actorHead, narratorOvl, narratorIdx, 0); if (pTrack) { objectParamsQuery naratorParams; animationStart = false; if (pHeader->trackDirection == 9999) { getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = direction(naratorParams.X, naratorParams.Y, pHeader->trackX,pHeader->trackY, 0, 0); } else if ((pHeader->trackX == 9999) && (pHeader->trackY == 9999)) { getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = pHeader->trackDirection; } else { pTrack->x_dest = pHeader->trackX; pTrack->y_dest = pHeader->trackY; pTrack->endDirection = pHeader->trackDirection; } pTrack->flag = 1; autoTrack = true; userWait = false; userEnabled = 0; freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998); } } } } } pCurrent = pCurrent->pNext; } } int findHighColor() { int bestColorResult = -1; int bestColorIdx = -1; for (unsigned long int i = 0; i < 256; i++) { int colorResult = (workpal[i*3+0] + workpal[i*3+1] + workpal[i*3+2]) / 256; if (colorResult > bestColorResult) { bestColorIdx = i; bestColorResult = colorResult; } } return bestColorIdx; } void callRelation(menuElementSubStruct *pMenuElement, int nObj2) { if (pMenuElement == NULL) return; menuElementSubStruct* pCurrent = pMenuElement; while (pCurrent != NULL) { int ovlIdx = pCurrent->ovlIdx; int header = pCurrent->header; linkDataStruct* pHeader = &overlayTable[ovlIdx].ovlData->arrayMsgRelHeader[header]; if (pHeader->obj2Number == nObj2) { // REL if (pHeader->type == RT_REL) { if (currentScriptPtr) { attacheNewScriptToTail(&relHead, ovlIdx, pHeader->id, 30, currentScriptPtr->scriptNumber, currentScriptPtr->overlayNumber, scriptType_REL); } else { attacheNewScriptToTail(&relHead, ovlIdx, pHeader->id, 30, 0, 0, scriptType_REL); } if ((narratorOvl > 0) && (pHeader->trackX != -1) && (pHeader->trackY != -1)) { actorStruct* pTrack = findActor(&actorHead, narratorOvl, narratorIdx, 0); if (pTrack) { animationStart = false; if (pHeader->trackDirection == 9999) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = direction(naratorParams.X, naratorParams.Y, pTrack->x_dest, pTrack->y_dest, 0, 0); } else if ((pHeader->trackX == 9999) && (pHeader->trackY == 9999)) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = pHeader->trackDirection; } else { pTrack->x_dest = pHeader->trackX; pTrack->y_dest = pHeader->trackY; pTrack->endDirection = pHeader->trackDirection; } pTrack->flag = 1; autoTrack = true; userEnabled = 0; changeScriptParamInList(ovlIdx, pHeader->id, &relHead, 0, 9998); } } } else if (pHeader->type == RT_MSG) { // MSG int obj1Ovl = pHeader->obj1Overlay; if (!obj1Ovl) obj1Ovl = ovlIdx; int x = 60; int y = 40; if (pHeader->obj1Number >= 0) { objectParamsQuery params; getMultipleObjectParam(obj1Ovl, pHeader->obj1Number, ¶ms); if (narratorOvl > 0) { if ((pHeader->trackX != -1) && (pHeader->trackY != -1) && (pHeader->trackX != 9999) && (pHeader->trackY != 9999)) { x = pHeader->trackX - 100; y = pHeader->trackY - 150; } else { getMultipleObjectParam(narratorOvl, narratorIdx, ¶ms); x = params.X - 100; y = params.Y - 150; } } else if (params.scale >= 0) { x = params.X - 100; y = params.Y - 40; } if (pHeader->obj1NewState != -1) { objInit(obj1Ovl, pHeader->obj1Number, pHeader->obj1NewState); } } if (currentScriptPtr) { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber); } else { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0); } userWait = true; autoOvl = ovlIdx; autoMsg = pHeader->id; if ((narratorOvl > 0) && (pHeader->trackX != -1) && (pHeader->trackY != -1)) { actorStruct* pTrack = findActor(&actorHead, narratorOvl, narratorIdx, 0); if (pTrack) { animationStart = false; if (pHeader->trackDirection == 9999) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = direction(naratorParams.X, naratorParams.Y, pTrack->x_dest, pTrack->y_dest, 0, 0); } else if ((pHeader->trackX == 9999) && (pHeader->trackY == 9999)) { objectParamsQuery naratorParams; getMultipleObjectParam(narratorOvl, narratorIdx, &naratorParams); pTrack->x_dest = naratorParams.X; pTrack->y_dest = naratorParams.Y; pTrack->endDirection = pHeader->trackDirection; } else { pTrack->x_dest = pHeader->trackX; pTrack->y_dest = pHeader->trackY; pTrack->endDirection = pHeader->trackDirection; } pTrack->flag = 1; autoTrack = true; userWait = false; userEnabled = 0; freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998); } } } } else { linkedRelation = pMenuElement; } pCurrent = pCurrent->pNext; } } void closeAllMenu() { if (menuTable[0]) { freeMenu(menuTable[0]); menuTable[0] = NULL; } if (menuTable[1]) { freeMenu(menuTable[1]); menuTable[1] = NULL; } if (linkedMsgList) { assert(0); // freeMsgList(linkedMsgList); } linkedMsgList = NULL; linkedRelation = NULL; } bool checkInput(int16 *buttonPtr) { int16 handle, button; Common::Point pt; getMouseStatus(&handle, &pt.x, &button, &pt.y); if (!button) buttonDown = 0; else if (!buttonDown && button) { *buttonPtr = button; buttonDown = 1; } return false; } extern bool manageEvents(); int CruiseEngine::processInput() { int16 mouseX = 0; int16 mouseY = 0; int16 button = 0; /*if (inputSub1keyboad()) * { * return 1; * } */ button = 0; if (sysKey != -1) { button = sysKey; mouseX = sysX; mouseY = sysY; sysKey = -1; } else if (automaticMode == 0) { getMouseStatus(&main10, &mouseX, &button, &mouseY); } if (!button) { buttonDown = 0; } // Check for Exit 'X' key if (keyboardCode == Common::KEYCODE_x) return 1; // Check for Pause 'P' key if (keyboardCode == Common::KEYCODE_p) { keyboardCode = Common::KEYCODE_INVALID; _vm->pauseEngine(true); mouseOff(); bool pausedButtonDown = false; while (!_vm->shouldQuit()) { manageEvents(); getMouseStatus(&main10, &mouseX, &button, &mouseY); if (button) pausedButtonDown = true; else if (pausedButtonDown) // Button released, so exit pause break; else if (keyboardCode != Common::KEYCODE_INVALID) break; g_system->delayMillis(10); } if (keyboardCode == Common::KEYCODE_x) // Exit the game return 1; keyboardCode = Common::KEYCODE_INVALID; _vm->pauseEngine(false); mouseOn(); return 0; } // Player Menu - test for both buttons or the F10 key if (((button & CRS_MB_BOTH) == CRS_MB_BOTH) || (keyboardCode == Common::KEYCODE_F10)) { changeCursor(CURSOR_NORMAL); keyboardCode = Common::KEYCODE_INVALID; return (playerMenu(mouseX, mouseY)); } if (userWait) { // Check for left mouse button click or Space to end user waiting if ((keyboardCode == Common::KEYCODE_SPACE) || (button == CRS_MB_LEFT)) userWait = false; keyboardCode = Common::KEYCODE_INVALID; return 0; } // Handle any changes in game speed if (_speedFlag) { if ((keyboardCode == Common::KEYCODE_KP_PLUS) && (_gameSpeed >= 30)) { _gameSpeed -= 10; keyboardCode = Common::KEYCODE_INVALID; } if ((keyboardCode == Common::KEYCODE_KP_MINUS) && (_gameSpeed <= 200)) { _gameSpeed += 10; keyboardCode = Common::KEYCODE_INVALID; } } if (!userEnabled) { return 0; } if ((currentActiveMenu != -1) && menuTable[currentActiveMenu]) { updateMenuMouse(mouseX, mouseY, menuTable[currentActiveMenu]); } if (dialogueEnabled) { if (menuDown || selectDown || linkedRelation) { closeAllMenu(); menuDown = 0; selectDown = 0; currentActiveMenu = -1; changeCursor(CURSOR_NORMAL); } if ((menuTable[0] == NULL) && (!buttonDown)) { int dialogFound = createDialog(dialogueOvl, dialogueObj, xdial, 0); if (menuTable[0]) { if (dialogFound) { currentActiveMenu = 0; } else { freeMenu(menuTable[0]); menuTable[0] = NULL; currentActiveMenu = -1; } } else { menuDown = 0; } } else { if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { if (menuTable[0]) { callRelation(getSelectedEntryInMenu(menuTable[0]), dialogueObj); freeMenu(menuTable[0]); menuTable[0] = NULL; if (linkedMsgList) { assert(0); // freeMsgList(linkedMsgList); } linkedMsgList = NULL; linkedRelation = NULL; changeCursor(CURSOR_NORMAL); currentActiveMenu = -1; } buttonDown = 1; } } } else if ((button & CRS_MB_LEFT) && (buttonDown == 0)) { // left click buttonDown = 1; // is there a relation if (linkedRelation) { // call sub relation when clicking on an object if (menuDown == 0) { if (menuTable[0]) { int objOvl; int objIdx; int objType; objType = findObject(mouseX, mouseY, &objOvl, &objIdx); if (objType != -1) { callSubRelation(linkedRelation, objOvl, objIdx); } freeMenu(menuTable[0]); menuTable[0] = NULL; } if (linkedMsgList) { // freeMsgList(linkedMsgList); } linkedMsgList = NULL; linkedRelation = NULL; changeCursor(CURSOR_NORMAL); } else { // call sub relation when clicking in inventory if (menuTable[0] && menuTable[1]) { menuElementSubStruct * p0 = getSelectedEntryInMenu(menuTable[1]); if (p0) callSubRelation(linkedRelation, p0->ovlIdx, p0->header); closeAllMenu(); changeCursor(CURSOR_NORMAL); } } selectDown = 0; menuDown = 0; } else { // manage click on object menu if (menuDown == 0) { // Handle left click on an object if (menuTable[0] == 0) { int objOvl; int objIdx; int objType; objType = findObject(mouseX, mouseY, &objOvl, &objIdx); if (objType != -1) { int relation = findRelation(objOvl, objIdx, mouseX, mouseY); if (menuTable[0]) { if (relation) { currentActiveMenu = 0; selectDown = 1; } else { // object has a name but no relation, just move the character freeMenu(menuTable[0]); menuTable[0] = NULL; aniX = mouseX; aniY = mouseY; animationStart = true; } } else { aniX = mouseX; aniY = mouseY; animationStart = true; } } else { // No object found, we move the character to the cursor aniX = mouseX; aniY = mouseY; animationStart = true; } } else { // handle click in menu if (menuTable[0]) { menuElementSubStruct *pMenuElementSub = getSelectedEntryInMenu(menuTable[0]); callRelation(pMenuElementSub, -1); // if there is a linked relation, close menu if (!linkedRelation) { freeMenu(menuTable[0]); menuTable[0] = NULL; changeCursor(CURSOR_NORMAL); } else { // else create the message for the linked relation char text[80]; strcpy(text, menuTable[0]->stringPtr); strcat(text, ":"); strcat(text, currentMenuElement->string); linkedMsgList = renderText(320, (const char *)text); changeCursor(CURSOR_CROSS); } } currentActiveMenu = -1; selectDown = 0; } } else { // Handle left click in inventory if (processInventory()) { currentActiveMenu = 0; selectDown = 1; menuDown = 0; } else { currentActiveMenu = -1; menuDown = 0; } } } } else if ((button & CRS_MB_RIGHT) || (keyboardCode == Common::KEYCODE_F9)) { if (buttonDown == 0) { keyboardCode = Common::KEYCODE_INVALID; // close object menu if there is no linked relation if ((linkedRelation == 0) && (menuTable[0])) { freeMenu(menuTable[0]); menuTable[0] = NULL; selectDown = 0; menuDown = 0; currentActiveMenu = -1; } if ((!selectDown) && (!menuDown) && (menuTable[1] == NULL)) { buildInventory(mouseX, mouseY); if (menuTable[1]) { currentActiveMenu = 1; menuDown = 1; } else { menuDown = 1; } } buttonDown = 1; } } return 0; } int currentMouseX = 0; int currentMouseY = 0; int currentMouseButton = 0; bool bFastMode = false; bool manageEvents() { Common::Event event; Common::EventManager * eventMan = g_system->getEventManager(); while (eventMan->pollEvent(event)) { bool abortFlag = true; switch (event.type) { case Common::EVENT_LBUTTONDOWN: currentMouseButton |= CRS_MB_LEFT; break; case Common::EVENT_LBUTTONUP: currentMouseButton &= ~CRS_MB_LEFT; break; case Common::EVENT_RBUTTONDOWN: currentMouseButton |= CRS_MB_RIGHT; break; case Common::EVENT_RBUTTONUP: currentMouseButton &= ~CRS_MB_RIGHT; break; case Common::EVENT_MOUSEMOVE: currentMouseX = event.mouse.x; currentMouseY = event.mouse.y; abortFlag = false; break; case Common::EVENT_QUIT: case Common::EVENT_RTL: _playerDontAskQuit = true; break; case Common::EVENT_KEYUP: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: currentMouseButton &= ~CRS_MB_MIDDLE; break; default: break; } break; case Common::EVENT_KEYDOWN: switch (event.kbd.keycode) { case Common::KEYCODE_ESCAPE: currentMouseButton |= CRS_MB_MIDDLE; break; default: keyboardCode = event.kbd.keycode; break; } if (event.kbd.hasFlags(Common::KBD_CTRL)) { if (event.kbd.keycode == Common::KEYCODE_d) { // Start the debugger _vm->getDebugger()->attach(); keyboardCode = Common::KEYCODE_INVALID; } else if (event.kbd.keycode == Common::KEYCODE_f) { bFastMode = !bFastMode; keyboardCode = Common::KEYCODE_INVALID; } } default: break; } if (abortFlag) return true; } return false; } void getMouseStatus(int16 *pMouseVar, int16 *pMouseX, int16 *pMouseButton, int16 *pMouseY) { *pMouseX = currentMouseX; *pMouseY = currentMouseY; *pMouseButton = currentMouseButton; } void CruiseEngine::mainLoop() { //int32 t_start,t_left; //uint32 t_end; //int32 q=0; /* Dummy */ int16 mouseX, mouseY; int16 mouseButton; int enableUser = 0; strcpy(nextOverlay, ""); strcpy(lastOverlay, ""); strcpy(cmdLine, ""); currentActiveMenu = -1; autoMsg = -1; linkedRelation = 0; userWait = false; autoTrack = false; initAllData(); _playerDontAskQuit = false; if (ConfMan.hasKey("save_slot")) loadGameState(ConfMan.getInt("save_slot")); do { // Handle frame delay uint32 currentTick = g_system->getMillis(); // Delay for the specified amount of time, but still respond to events bool skipEvents = false; do { if (userEnabled && !userWait && !autoTrack) { if (currentActiveMenu == -1) { static int16 oldMouseX = -1; static int16 oldMouseY = -1; getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY); if (mouseX != oldMouseX || mouseY != oldMouseY) { int objectType; int newCursor1; int newCursor2; oldMouseX = mouseX; oldMouseY = mouseY; objectType = findObject(mouseX, mouseY, &newCursor1, &newCursor2); if (objectType == 9) { changeCursor(CURSOR_EXIT); } else if (objectType != -1) { changeCursor(CURSOR_MAGNIFYING_GLASS); } else { changeCursor(CURSOR_WALK); } } } else { changeCursor(CURSOR_NORMAL); } } else { changeCursor(CURSOR_NORMAL); } g_system->updateScreen(); if (!skipEvents || bFastMode) skipEvents = manageEvents(); if (!bFastMode) { g_system->delayMillis(10); currentTick = g_system->getMillis(); } if (_playerDontAskQuit) break; _vm->getDebugger()->onFrame(); } while (currentTick < _lastTick + _gameSpeed && !bFastMode); if (_playerDontAskQuit) break; _lastTick = g_system->getMillis(); // Handle switchover in game speed after intro if (!_speedFlag && canLoadGameStateCurrently()) { _speedFlag = true; _gameSpeed = GAME_FRAME_DELAY_2; } // Handle the next frame // frames++; // t_start=Osystem_GetTicks(); // readKeyboard(); bool isUserWait = userWait; // WORKAROUND: This prevents hotspots responding during // delays i.e. Menu opening if you click fast on another // hotspot after trying to open a locked door, which // occurred with the original interpreter. if (userDelay) { currentMouseButton = 0; } _playerDontAskQuit = processInput(); if (_playerDontAskQuit) break; if (enableUser) { userEnabled = 1; enableUser = 0; } if (userDelay && !userWait) { userDelay--; } if (isUserWait & !userWait) { // User waiting has ended changeScriptParamInList(-1, -1, &procHead, 9999, 0); changeScriptParamInList(-1, -1, &relHead, 9999, 0); // Disable any mouse click used to end the user wait currentMouseButton = 0; } // FIXME: I suspect that the original game does multiple script executions between game frames; the bug with // Raoul appearing when looking at the book is being there are 3 script iterations separation between the // scene being changed to the book, and the Raoul actor being frozen/disabled. This loop is a hack to ensure // that does a few extra script executions for that scene int numIterations = 1; while (numIterations-- > 0) { bool bgChanged = backgroundChanged[masterScreen]; manageScripts(&relHead); manageScripts(&procHead); removeFinishedScripts(&relHead); removeFinishedScripts(&procHead); if (!bgChanged && backgroundChanged[masterScreen] && !strcmp(backgroundTable[0].name, "S06B.PI1")) { bgChanged = true; numIterations += 2; } } processAnimation(); if (remdo) { // assert(0); /* main3 = 0; * var24 = 0; * var23 = 0; * * freeStuff2(); */ } if (cmdLine[0]) { assert(0); /* redrawStrings(0,&cmdLine,8); waitForPlayerInput(); cmdLine = 0; */ } if (displayOn) { if (doFade) PCFadeFlag = false; /*if (!PCFadeFlag)*/ mainDraw(userWait); flipScreen(); if (userWait) { // Waiting for press - original wait loop has been integrated into the // main event loop continue; } // wait for character to finish auto track if (autoTrack) { if (isAnimFinished(narratorOvl, narratorIdx, &actorHead, ATP_MOUSE)) { if (autoMsg != -1) { freezeCell(&cellHead, autoOvl, autoMsg, 5, -1, 9998, 0); char* pText = getText(autoMsg, autoOvl); if (strlen(pText)) userWait = true; } changeScriptParamInList(-1, -1, &relHead, 9998, 0); autoTrack = false; enableUser = 1; } else { userEnabled = false; } } else if (autoMsg != -1) { removeCell(&cellHead, autoOvl, autoMsg, 5, masterScreen); autoMsg = -1; } } else { // Keep ScummVM being responsive even when displayOn is false g_system->updateScreen(); } } while (!_playerDontAskQuit); // Free data removeAllScripts(&relHead); removeAllScripts(&procHead); resetActorPtr(&actorHead); freeOverlayTable(); closeCnf(); closeBase(); resetFileEntryRange(0, NUM_FILE_ENTRIES); freeObjectList(&cellHead); freeBackgroundIncrustList(&backgroundIncrustHead); } } // End of namespace Cruise