mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-28 20:55:19 +00:00
1990 lines
48 KiB
C++
1990 lines
48 KiB
C++
/* 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<MemInfo *>::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
|