diff options
Diffstat (limited to 'engines')
87 files changed, 1191 insertions, 1853 deletions
diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index cf01d9bdbc..2147419886 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -169,6 +169,9 @@ bool CruiseEngine::loadLanguageStrings() { case Common::DE_DEU: p = germanLanguageStrings; break; + case Common::IT_ITA: + p = italianLanguageStrings; + break; default: return false; } diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index eb7c1c524f..b2e267ca49 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -171,6 +171,19 @@ static const CRUISEGameDescription gameDescriptions[] = { GType_CRUISE, 0, }, + { // Amiga Italian US GOLD edition. + { + "cruise", + 0, + AD_ENTRY1("D1", "a0011075413b7335e003e8e3c9cf51b9"), + Common::IT_ITA, + Common::kPlatformAmiga, + ADGF_NO_FLAGS, + GUIO0() + }, + GType_CRUISE, + 0, + }, { // AtariST English KixxXL edition. { "cruise", diff --git a/engines/cruise/staticres.cpp b/engines/cruise/staticres.cpp index 1565f254d0..a3fc4f884b 100644 --- a/engines/cruise/staticres.cpp +++ b/engines/cruise/staticres.cpp @@ -320,5 +320,9 @@ const char *germanLanguageStrings[13] = { " ", NULL, NULL, NULL, NULL, "Inventar", "Sprechen ""\xFC""ber", "Speilermen\xFC", "Speicherlaufwerk", "Speichern", "Laden", "Neu beginnen", "Ende" }; +const char *italianLanguageStrings[13] = { + "Pausa", NULL, NULL, NULL, NULL, "Inventario", "Parla di...", "Menu giocatore", NULL, + "Salva", "Carica", "Ricomincia", "Esci" +}; } // End of namespace Cruise diff --git a/engines/cruise/staticres.h b/engines/cruise/staticres.h index a3cf13e41c..acf0b640be 100644 --- a/engines/cruise/staticres.h +++ b/engines/cruise/staticres.h @@ -57,6 +57,7 @@ extern const byte mouseCursorMagnifyingGlass[]; extern const char *englishLanguageStrings[13]; extern const char *frenchLanguageStrings[13]; extern const char *germanLanguageStrings[13]; +extern const char *italianLanguageStrings[13]; } // End of namespace Cruise diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h index d54b2402c8..063aabbd89 100644 --- a/engines/dreamweb/detection_tables.h +++ b/engines/dreamweb/detection_tables.h @@ -41,6 +41,7 @@ static const DreamWebGameDescription gameDescriptions[] = { { {"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918}, {"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466}, + {"dreamweb.exe", 0, "56b1d73aa56e964b45872ff552402341", 64985}, AD_LISTEND }, Common::EN_ANY, @@ -67,6 +68,27 @@ static const DreamWebGameDescription gameDescriptions[] = { }, }, + // UK-V (Early UK) CD Release - From bug #3526483 + // Note: r00 and r02 files are identical to international floppy release + // so was misidentified as floppy, resulting in disabled CD speech. + // Added executable to detection to avoid this. + { + { + "dreamweb", + "CD", + { + {"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918}, + {"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466}, + {"dreamweb.exe", 0, "dd1c7793b151489e67b83cd1ecab51cd", -1}, + AD_LISTEND + }, + Common::EN_GRB, + Common::kPlatformPC, + ADGF_CD | ADGF_TESTING, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + // US CD release { { @@ -79,7 +101,7 @@ static const DreamWebGameDescription gameDescriptions[] = { }, Common::EN_USA, Common::kPlatformPC, - ADGF_CD, + ADGF_CD | ADGF_TESTING, GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) }, }, @@ -101,6 +123,24 @@ static const DreamWebGameDescription gameDescriptions[] = { }, }, + // French CD release + // From bug #3524362 + { + { + "dreamweb", + "CD", + { + {"dreamwfr.r00", 0, "e354582a8564faf5c515df92f207e8d1", 154657}, + {"dreamwfr.r02", 0, "cb99f08d5aefd04184eac76927eced80", 200575}, + AD_LISTEND + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_CD | ADGF_TESTING, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + // German floppy release { { @@ -169,6 +209,24 @@ static const DreamWebGameDescription gameDescriptions[] = { }, }, + // Spanish CD release + // From bug #3524362 + { + { + "dreamweb", + "CD", + { + {"dreamwsp.r00", 0, "2df07174321de39c4f17c9ff654b268a", 153608}, + {"dreamwsp.r02", 0, "f97d435ad5da08fb1bcf6ea3dd6e0b9e", 199499}, + AD_LISTEND + }, + Common::ES_ESP, + Common::kPlatformPC, + ADGF_CD | ADGF_TESTING, + GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE) + }, + }, + // Italian floppy release { { diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp index 299dd74b53..11e8e3f8cc 100644 --- a/engines/dreamweb/dreamweb.cpp +++ b/engines/dreamweb/dreamweb.cpp @@ -63,14 +63,18 @@ DreamWebEngine::DreamWebEngine(OSystem *syst, const DreamWebGameDescription *gam _channel1 = 0; _datafilePrefix = "DREAMWEB."; + _speechDirName = "SPEECH"; // ES and FR CD release use a different data file prefix + // and speech directory naming. if (isCD()) { switch(getLanguage()) { case Common::ES_ESP: _datafilePrefix = "DREAMWSP."; + _speechDirName = "SPANISH"; break; case Common::FR_FRA: _datafilePrefix = "DREAMWFR."; + _speechDirName = "FRENCH"; break; default: // Nothing to do @@ -381,7 +385,7 @@ Common::Error DreamWebEngine::run() { ConfMan.registerDefault("originalsaveload", "false"); ConfMan.registerDefault("bright_palette", true); - _hasSpeech = Common::File::exists("speech/r01c0000.raw") && !ConfMan.getBool("speech_mute"); + _hasSpeech = Common::File::exists(_speechDirName + "/r01c0000.raw") && !ConfMan.getBool("speech_mute"); _brightPalette = ConfMan.getBool("bright_palette"); _timer->installTimerProc(vSyncInterrupt, 1000000 / 70, this, "dreamwebVSync"); diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h index 4065e5a860..6744b53ebc 100644 --- a/engines/dreamweb/dreamweb.h +++ b/engines/dreamweb/dreamweb.h @@ -164,6 +164,7 @@ private: const DreamWebGameDescription *_gameDescription; Common::RandomSource _rnd; Common::String _datafilePrefix; + Common::String _speechDirName; uint _speed; bool _turbo; diff --git a/engines/dreamweb/monitor.cpp b/engines/dreamweb/monitor.cpp index 95aa400c3a..25435ae0e9 100644 --- a/engines/dreamweb/monitor.cpp +++ b/engines/dreamweb/monitor.cpp @@ -626,15 +626,12 @@ void DreamWebEngine::signOn() { _monAdX = prevX; _monAdY = prevY; - inputLine = (const char *)_inputLine; - inputLine.toUppercase(); - // The entered line has zeroes in-between each character uint32 len = strlen(monitorKeyEntries[foundIndex].password); bool found = true; for (uint32 i = 0; i < len; i++) { - if (monitorKeyEntries[foundIndex].password[i] != inputLine[i * 2]) { + if (monitorKeyEntries[foundIndex].password[i] != _inputLine[i * 2]) { found = false; break; } diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp index 5d7f02c5cf..d30bf754de 100644 --- a/engines/dreamweb/saveload.cpp +++ b/engines/dreamweb/saveload.cpp @@ -839,8 +839,9 @@ void DreamWebEngine::showOpBox() { // This call displays half of the ops dialog in the CD version. It's not // in the floppy version, and if it's called, a stray red dot is shown in - // the game dialogs. - if (isCD()) + // the game dialogs. It is included in the early UK CD release, which had + // similar data files as the floppy release (bug #3528160). + if (isCD() && getLanguage() != Common::EN_GRB) showFrame(_saveGraphics, kOpsx, kOpsy + 55, 4, 0); } diff --git a/engines/dreamweb/sound.cpp b/engines/dreamweb/sound.cpp index b51527a8cd..b3d5db9e0d 100644 --- a/engines/dreamweb/sound.cpp +++ b/engines/dreamweb/sound.cpp @@ -55,6 +55,7 @@ void DreamWebEngine::volumeAdjust() { } void DreamWebEngine::playChannel0(uint8 index, uint8 repeat) { + debug(1, "playChannel0(index:%d, repeat:%d)", index, repeat); _channel0Playing = index; if (index >= 12) index -= 12; @@ -72,6 +73,7 @@ void DreamWebEngine::playChannel1(uint8 index) { } void DreamWebEngine::cancelCh0() { + debug(1, "cancelCh0()"); _channel0Repeat = 0; _channel0Playing = 255; stopSound(0); @@ -83,6 +85,7 @@ void DreamWebEngine::cancelCh1() { } void DreamWebEngine::loadRoomsSample() { + debug(1, "loadRoomsSample() _roomsSample:%d", _roomsSample); uint8 sample = _roomsSample; if (sample == 255 || _currentSample == sample) @@ -177,7 +180,7 @@ bool DreamWebEngine::loadSpeech(const Common::String &filename) { return false; Common::File file; - if (!file.open("speech/" + filename)) + if (!file.open(_speechDirName + "/" + filename)) return false; debug(1, "loadSpeech(%s)", filename.c_str()); @@ -190,6 +193,11 @@ bool DreamWebEngine::loadSpeech(const Common::String &filename) { } void DreamWebEngine::soundHandler() { + static uint8 volumeOld = 0, channel0Old = 0, channel0PlayingOld = 0; + if (_volume != volumeOld || _channel0 != channel0Old || _channel0Playing != channel0PlayingOld) + debug(1, "soundHandler() _volume: %d _channel0: %d _channel0Playing: %d", _volume, _channel0, _channel0Playing); + volumeOld = _volume, channel0Old = _channel0, channel0PlayingOld = _channel0Playing; + _subtitles = ConfMan.getBool("subtitles"); volumeAdjust(); @@ -230,6 +238,8 @@ void DreamWebEngine::soundHandler() { } } if (!_mixer->isSoundHandleActive(_channelHandle[0])) { + if (_channel0Playing != 255 && _channel0 != 0) + debug(1, "!_mixer->isSoundHandleActive _channelHandle[0] _channel0Playing:%d _channel0:%d", _channel0Playing, _channel0); _channel0Playing = 255; _channel0 = 0; } @@ -237,7 +247,6 @@ void DreamWebEngine::soundHandler() { _channel1Playing = 255; _channel1 = 0; } - } void DreamWebEngine::loadSounds(uint bank, const Common::String &suffix) { diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index ea2acaf64d..409b53f6f0 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -441,20 +441,20 @@ bool LoLEngine::launchObject(int objectType, Item item, int startX, int startY, return true; } -void LoLEngine::endObjectFlight(FlyingObject *t, int x, int y, int collisionObject) { +void LoLEngine::endObjectFlight(FlyingObject *t, int x, int y, int collisionType) { int cx = x; int cy = y; uint16 block = calcBlockIndex(t->x, t->y); removeAssignedObjectFromBlock(&_levelBlockProperties[block], t->item); removeDrawObjectFromBlock(&_levelBlockProperties[block], t->item); - if (collisionObject == 1) { + if (collisionType == 1) { cx = t->x; cy = t->y; } if (t->objectType == 0 || t->objectType == 1) { - objectFlightProcessHits(t, cx, cy, collisionObject); + objectFlightProcessHits(t, cx, cy, collisionType); t->x = (cx & 0xffc0) | 0x40; t->y = (cy & 0xffc0) | 0x40; t->flyingHeight = 0; @@ -488,27 +488,23 @@ void LoLEngine::updateObjectFlightPosition(FlyingObject *t) { } } -void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objectOnNextBlock) { - uint16 r = 0; - - if (objectOnNextBlock == 1) { +void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int collisionType) { + if (collisionType == 1) { runLevelScriptCustom(calcNewBlockPosition(_itemsInPlay[t->item].block, t->direction >> 1), 0x8000, -1, t->item, 0, 0); - } else if (objectOnNextBlock == 2) { + } else if (collisionType == 2) { if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { - int o = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects; - while (o & 0x8000) { - LoLObject *i = findObject(o); - o = i->nextAssignedObject; - runItemScript(t->attackerId, t->item, 0x8000, o, 0); + uint16 obj = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects; + while (obj & 0x8000) { + runItemScript(t->attackerId, t->item, 0x8000, obj, 0); + obj = findObject(obj)->nextAssignedObject; } } else { - r = getNearestMonsterFromPos(x, y); - runItemScript(t->attackerId, t->item, 0x8000, r, 0); + runItemScript(t->attackerId, t->item, 0x8000, getNearestMonsterFromPos(x, y), 0); } - } else if (objectOnNextBlock == 4) { + } else if (collisionType == 4) { _partyAwake = true; if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { for (int i = 0; i < 4; i++) { @@ -516,8 +512,7 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec runItemScript(t->attackerId, t->item, 0x8000, i, 0); } } else { - r = getNearestPartyMemberFromPos(x, y); - runItemScript(t->attackerId, t->item, 0x8000, r, 0); + runItemScript(t->attackerId, t->item, 0x8000, getNearestPartyMemberFromPos(x, y), 0); } } } @@ -543,9 +538,9 @@ void LoLEngine::updateFlyingObject(FlyingObject *t) { middle of a block (or making the monsters align to the middle before casting them) wouldn't help here (and wouldn't be faithful to the original either). */ - int objectOnNextBlock = checkBlockBeforeObjectPlacement(x, y, /*_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000 ? 256 :*/ 63, t->flags, t->wallFlags); - if (objectOnNextBlock) { - endObjectFlight(t, x, y, objectOnNextBlock); + int collisionType = checkBlockBeforeObjectPlacement(x, y, /*_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000 ? 256 :*/ 63, t->flags, t->wallFlags); + if (collisionType) { + endObjectFlight(t, x, y, collisionType); } else { if (--t->distance) { processObjectFlight(t, x, y); @@ -567,16 +562,16 @@ void LoLEngine::assignItemToBlock(uint16 *assignedBlockObjects, int id) { *assignedBlockObjects = id; } -int LoLEngine::checkDrawObjectSpace(int itemX, int itemY, int partyX, int partyY) { - int a = itemX - partyX; - if (a < 0) - a = -a; +int LoLEngine::checkDrawObjectSpace(int x1, int y1, int x2, int y2) { + int dx = x1 - x2; + if (dx < 0) + dx = -dx; - int b = itemY - partyY; - if (b < 0) - b = -b; + int dy = y1 - y2; + if (dy < 0) + dy = -dy; - return a + b; + return dx + dy; } int LoLEngine::checkSceneForItems(uint16 *blockDrawObjects, int color) { diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 38e9d33259..d3028c5e2d 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -1436,7 +1436,7 @@ void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) { bool loop = true; while (loop) { - if (_characters[charNum].experiencePts[skill] <= _expRequirements[_characters[charNum].skillLevels[skill]]) + if (_characters[charNum].experiencePts[skill] < _expRequirements[_characters[charNum].skillLevels[skill]]) break; _characters[charNum].skillLevels[skill]++; @@ -2894,11 +2894,11 @@ int LoLEngine::processMagicVaelansCube() { uint8 s = _levelBlockProperties[bl].walls[_currentDirection ^ 2]; uint8 flg = _wllWallFlags[s]; - int v = (s == 47 && (_currentLevel == 17 || _currentLevel == 24)) ? 1 : 0; - if ((_wllVmpMap[s] == 1 || _wllVmpMap[s] == 2) && (flg & 1) && (_currentLevel == 22)) { + int res = (s == 47 && (_currentLevel == 17 || _currentLevel == 24)) ? 1 : 0; + if ((_wllVmpMap[s] == 1 || _wllVmpMap[s] == 2) && (!(flg & 1)) && (_currentLevel != 22)) { memset(_levelBlockProperties[bl].walls, 0, 4); gui_drawScene(0); - v = 1; + res = 1; } uint16 o = _levelBlockProperties[bl].assignedObjects; @@ -2906,7 +2906,7 @@ int LoLEngine::processMagicVaelansCube() { LoLMonster *m = &_monsters[o & 0x7fff]; if (m->properties->flags & 0x1000) { inflictDamage(o, 100, 0xffff, 0, 0x80); - v = 1; + res = 1; } o = m->nextAssignedObject; } @@ -2922,7 +2922,7 @@ int LoLEngine::processMagicVaelansCube() { delete[] tmpPal1; delete[] tmpPal2; - return v; + return res; } int LoLEngine::processMagicGuardian(int charNum) { diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index dbd461267f..dcd13804b3 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -1047,14 +1047,14 @@ private: void setItemPosition(Item item, uint16 x, uint16 y, int flyingHeight, int moveable); void removeLevelItem(Item item, int block); bool launchObject(int objectType, Item item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c); - void endObjectFlight(FlyingObject *t, int x, int y, int collisionObject); + void endObjectFlight(FlyingObject *t, int x, int y, int collisionType); void processObjectFlight(FlyingObject *t, int x, int y); void updateObjectFlightPosition(FlyingObject *t); - void objectFlightProcessHits(FlyingObject *t, int x, int y, int objectOnNextBlock); + void objectFlightProcessHits(FlyingObject *t, int x, int y, int collisionType); void updateFlyingObject(FlyingObject *t); void assignItemToBlock(uint16 *assignedBlockObjects, int id); - int checkDrawObjectSpace(int itemX, int itemY, int partyX, int partyY); + int checkDrawObjectSpace(int x1, int y1, int x2, int y2); int checkSceneForItems(uint16 *blockDrawObjects, int color); uint8 _moneyColumnHeight[5]; @@ -1095,7 +1095,7 @@ private: void monsterDropItems(LoLMonster *monster); void giveItemToMonster(LoLMonster *monster, Item item); int checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 objectWidth, uint16 testFlag, uint16 wallFlag); - int checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag); + int testBlockPassability(int block, int x, int y, int objectWidth, int testFlag, int wallFlag); int calcMonsterSkillLevel(int id, int a); int checkBlockOccupiedByParty(int x, int y, int testFlag); const uint16 *getCharacterOrMonsterStats(int id); @@ -1122,7 +1122,7 @@ private: int checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock); int walkMonsterCheckDest(int x, int y, LoLMonster *monster, int unk); void getNextStepCoords(int16 monsterX, int16 monsterY, int &newX, int &newY, uint16 direction); - void rearrangeAttackingMonster(LoLMonster *monster); + void alignMonsterToParty(LoLMonster *monster); void moveStrayingMonster(LoLMonster *monster); void killMonster(LoLMonster *monster); diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index c5d1d49030..9c0fe21ad4 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -958,10 +958,9 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) { l->hitPoints = stackPos(26); l->speedTotalWaitTicks = 1; l->flags = stackPos(27); - l->unk5 = stackPos(28); - // FIXME??? + // This is what the original does here (setting the value first to stackPos(28) and then to stackPos(29): + //l->unk5 = stackPos(28); l->unk5 = stackPos(29); - // l->numDistAttacks = stackPos(30); l->numDistWeapons = stackPos(31); diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index a07abd4580..f4bae113c5 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -355,7 +355,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object int yOffs = 0; int flag = 0; - int r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y), x, y, objectWidth, testFlag, wallFlag); + int r = testBlockPassability(calcBlockIndex(x, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -369,7 +369,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 2; x2 = x + objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -385,7 +385,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 6; x2 = x - objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -403,7 +403,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 4; y2 = y + objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -420,7 +420,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object _objectLastDirection = 0; y2 = y - objectWidth; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -436,7 +436,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object if (!flag) return 0; - r = checkBlockForWallsAndSufficientSpace(calcBlockIndex(x2, y2), x, y, objectWidth, testFlag, wallFlag); + r = testBlockPassability(calcBlockIndex(x2, y2), x, y, objectWidth, testFlag, wallFlag); if (r) return r; @@ -447,7 +447,7 @@ int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 object return 0; } -int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag) { +int LoLEngine::testBlockPassability(int block, int x, int y, int objectWidth, int testFlag, int wallFlag) { if (block == _currentBlock) testFlag &= 0xfffe; @@ -461,9 +461,9 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int if (!(testFlag & 2)) return 0; - uint16 b = _levelBlockProperties[block].assignedObjects; - while (b & 0x8000) { - LoLMonster *monster = &_monsters[b & 0x7fff]; + uint16 obj = _levelBlockProperties[block].assignedObjects; + while (obj & 0x8000) { + LoLMonster *monster = &_monsters[obj & 0x7fff]; if (monster->mode < 13) { int r = checkDrawObjectSpace(x, y, monster->x, monster->y); @@ -471,7 +471,7 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int return 2; } - b = findObject(b)->nextAssignedObject; + obj = findObject(obj)->nextAssignedObject; } return 0; @@ -1105,7 +1105,7 @@ void LoLEngine::updateMonster(LoLMonster *monster) { if ((monster->fightCurTick <= 0) || (checkDrawObjectSpace(_partyPosX, _partyPosY, monster->x, monster->y) > 256) || (monster->flags & 8)) setMonsterMode(monster, 7); else - rearrangeAttackingMonster(monster); + alignMonsterToParty(monster); break; case 6: @@ -1428,26 +1428,26 @@ int LoLEngine::walkMonsterCheckDest(int x, int y, LoLMonster *monster, int unk) uint8 m = monster->mode; monster->mode = 15; - int res = checkBlockBeforeObjectPlacement(x, y, monster->properties->maxWidth, 7, monster->properties->flags & 0x1000 ? 32 : unk); + int objType = checkBlockBeforeObjectPlacement(x, y, monster->properties->maxWidth, 7, monster->properties->flags & 0x1000 ? 32 : unk); monster->mode = m; - return res; + return objType; } void LoLEngine::getNextStepCoords(int16 srcX, int16 srcY, int &newX, int &newY, uint16 direction) { - static const int8 shiftTableX[] = { 0, 32, 32, 32, 0, -32, -32, -32 }; - static const int8 shiftTableY[] = { -32, -32, 0, 32, 32, 32, 0, -32 }; + static const int8 stepAdjustX[] = { 0, 32, 32, 32, 0, -32, -32, -32 }; + static const int8 stepAdjustY[] = { -32, -32, 0, 32, 32, 32, 0, -32 }; - newX = (srcX + shiftTableX[direction]) & 0x1fff; - newY = (srcY + shiftTableY[direction]) & 0x1fff; + newX = (srcX + stepAdjustX[direction]) & 0x1fff; + newY = (srcY + stepAdjustY[direction]) & 0x1fff; } -void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { - int t = (monster->direction >> 1); +void LoLEngine::alignMonsterToParty(LoLMonster *monster) { + uint8 mdir = monster->direction >> 1; uint16 mx = monster->x; uint16 my = monster->y; - uint16 *c = (t & 1) ? &my : &mx; - bool centered = (*c & 0x7f) == 0; + uint16 *pos = (mdir & 1) ? &my : &mx; + bool centered = (*pos & 0x7f) == 0; bool posFlag = true; if (monster->properties->maxWidth <= 63) { @@ -1464,11 +1464,13 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { r = true; } else { for (int i = 0; i < 3; i++) { - t = (t + 1) & 3; - id = _levelBlockProperties[calcNewBlockPosition(monster->block, t)].assignedObjects; + mdir = (mdir + 1) & 3; + id = _levelBlockProperties[calcNewBlockPosition(monster->block, mdir)].assignedObjects; id = (id & 0x8000) ? (id & 0x7fff) : 0xffff; - if (id != 0xffff) + if (id != 0xffff) { r = true; + break; + } } } } @@ -1484,15 +1486,15 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { return; if (posFlag) { - if (*c & 0x80) - *c -= 32; + if (*pos & 0x80) + *pos -= 32; else - *c += 32; + *pos += 32; } else { - if (*c & 0x80) - *c += 32; + if (*pos & 0x80) + *pos += 32; else - *c -= 32; + *pos -= 32; } if (walkMonsterCheckDest(mx, my, monster, 4)) @@ -1502,8 +1504,10 @@ void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) { int fy = _partyPosY; calcSpriteRelPosition(mx, my, fx, fy, monster->direction >> 1); - t = (fx < 0) ? -fx : fx; - if (fy > 160 || t > 80) + if (fx < 0) + fx = -fx; + + if (fy > 160 || fx > 80) return; placeMonster(monster, mx, my); diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 8c72c9875e..3cf5ac740e 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -157,7 +157,7 @@ void NECursorManager::setCursor(uint16 id) { Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id); if (cursorGroup) { - Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor; + Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor; CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor()); CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256); return; @@ -257,7 +257,7 @@ void PECursorManager::setCursor(uint16 id) { Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id); if (cursorGroup) { - Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor; + Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor; CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor()); CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256); delete cursorGroup; diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp index 2ced265f02..cae165ccf0 100644 --- a/engines/mohawk/myst_stacks/dni.cpp +++ b/engines/mohawk/myst_stacks/dni.cpp @@ -103,7 +103,7 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) { VideoHandle atrus = _vm->_video->findVideoHandle(_video); // Good ending and Atrus asked to give page - if (_globals.ending == 1 && _vm->_video->getElapsedTime(atrus) > (uint)Audio::Timestamp(0, 6801, 600).msecs()) { + if (_globals.ending == 1 && _vm->_video->getTime(atrus) > (uint)Audio::Timestamp(0, 6801, 600).msecs()) { _globals.ending = 2; _globals.heldPage = 0; _vm->setMainCursor(kDefaultMystCursor); diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 95a8313536..07b1b59929 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -979,7 +979,7 @@ void MohawkEngine_Riven::doVideoTimer(VideoHandle handle, bool force) { return; // Run the opcode if we can at this point - if (force || _video->getElapsedTime(handle) >= _scriptMan->getStoredMovieOpcodeTime()) + if (force || _video->getTime(handle) >= _scriptMan->getStoredMovieOpcodeTime()) _scriptMan->runStoredMovieOpcode(); } diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 8dfc74ebf0..337a57e3e1 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -2059,7 +2059,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) { debug(0, "\tHotspot = %d -> %d", argv[3], hotspotMap[argv[3] - 1]); // Just let the video play while we wait until Gehn opens the trap book for us - while (_vm->_video->getElapsedTime(video) < startTime && !_vm->shouldQuit()) { + while (_vm->_video->getTime(video) < startTime && !_vm->shouldQuit()) { if (_vm->_video->updateMovies()) _vm->_system->updateScreen(); @@ -2084,7 +2084,7 @@ void RivenExternal::xbookclick(uint16 argc, uint16 *argv) { // OK, Gehn has opened the trap book and has asked us to go in. Let's watch // and see what the player will do... - while (_vm->_video->getElapsedTime(video) < endTime && !_vm->shouldQuit()) { + while (_vm->_video->getTime(video) < endTime && !_vm->shouldQuit()) { bool updateScreen = _vm->_video->updateMovies(); Common::Event event; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 80fa4bf9a0..83fca9ac35 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -49,7 +49,7 @@ void VideoEntry::clear() { } bool VideoEntry::endOfVideo() { - return !video || video->endOfVideo() || video->getElapsedTime() >= (uint)end.msecs(); + return !video || video->endOfVideo() || video->getTime() >= (uint)end.msecs(); } VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { @@ -481,9 +481,9 @@ uint32 VideoManager::getFrameCount(VideoHandle handle) { return _videoStreams[handle]->getFrameCount(); } -uint32 VideoManager::getElapsedTime(VideoHandle handle) { +uint32 VideoManager::getTime(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); - return _videoStreams[handle]->getElapsedTime(); + return _videoStreams[handle]->getTime(); } uint32 VideoManager::getDuration(VideoHandle handle) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 34c287497f..8736782d7a 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -100,7 +100,7 @@ public: VideoHandle findVideoHandle(const Common::String &filename); int32 getCurFrame(VideoHandle handle); uint32 getFrameCount(VideoHandle handle); - uint32 getElapsedTime(VideoHandle handle); + uint32 getTime(VideoHandle handle); uint32 getDuration(VideoHandle videoHandle); bool endOfVideo(VideoHandle handle); void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end); diff --git a/engines/pegasus/movie.cpp b/engines/pegasus/movie.cpp index 9a13864cab..f4aa9eecee 100644 --- a/engines/pegasus/movie.cpp +++ b/engines/pegasus/movie.cpp @@ -198,7 +198,7 @@ void Movie::updateTime() { uint32 startTime = _startTime * getScale() / _startScale; uint32 stopTime = _stopTime * getScale() / _stopScale; - uint32 actualTime = CLIP<int>(_video->getElapsedTime() * getScale() / 1000, startTime, stopTime); + uint32 actualTime = CLIP<int>(_video->getTime() * getScale() / 1000, startTime, stopTime); _time = Common::Rational(actualTime, getScale()); } } diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp index 701c4161bb..1665b474ee 100644 --- a/engines/pegasus/pegasus.cpp +++ b/engines/pegasus/pegasus.cpp @@ -2093,7 +2093,7 @@ void PegasusEngine::doSubChase() { if (!video->loadFile("Images/Norad Alpha/Sub Chase Movie")) error("Failed to load sub chase"); - while (!shouldQuit() && !video->endOfVideo() && video->getElapsedTime() < endTime) { + while (!shouldQuit() && !video->endOfVideo() && video->getTime() < endTime) { if (video->needsUpdate()) { const Graphics::Surface *frame = video->decodeNextFrame(); diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 9248f2b530..484ebe1779 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -126,21 +126,25 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue textEntry.text = dialogue[i].i_str; entry = _vm->_scene->_textList.addEntry(textEntry); - // Display text - event.type = kEvTOneshot; - event.code = kTextEvent; - event.op = kEventDisplay; - event.data = entry; - event.time = (i == 0) ? 0 : VOICE_PAD; - eventColumns = _vm->_events->chain(eventColumns, event); + if (_vm->_subtitlesEnabled) { + // Display text + event.type = kEvTOneshot; + event.code = kTextEvent; + event.op = kEventDisplay; + event.data = entry; + event.time = (i == 0) ? 0 : VOICE_PAD; + eventColumns = _vm->_events->chain(eventColumns, event); + } - // Play voice - event.type = kEvTOneshot; - event.code = kVoiceEvent; - event.op = kEventPlay; - event.param = dialogue[i].i_voice_rn; - event.time = 0; - _vm->_events->chain(eventColumns, event); + if (_vm->_voicesEnabled) { + // Play voice + event.type = kEvTOneshot; + event.code = kVoiceEvent; + event.op = kEventPlay; + event.param = dialogue[i].i_voice_rn; + event.time = 0; + _vm->_events->chain(eventColumns, event); + } voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn); if (voice_len < 0) { diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 9607a8e66d..5b5301b468 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -53,6 +53,7 @@ #include "video/avi_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/frameout.h" #include "video/coktel_decoder.h" #include "sci/video/robot_decoder.h" #endif @@ -131,6 +132,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), DCmd_Register("al", WRAP_METHOD(Console, cmdAnimateList)); // alias DCmd_Register("window_list", WRAP_METHOD(Console, cmdWindowList)); DCmd_Register("wl", WRAP_METHOD(Console, cmdWindowList)); // alias + DCmd_Register("plane_list", WRAP_METHOD(Console, cmdPlaneList)); + DCmd_Register("pl", WRAP_METHOD(Console, cmdPlaneList)); // alias + DCmd_Register("plane_items", WRAP_METHOD(Console, cmdPlaneItemList)); + DCmd_Register("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias DCmd_Register("saved_bits", WRAP_METHOD(Console, cmdSavedBits)); DCmd_Register("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits)); // Segments @@ -365,7 +370,9 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" pic_visualize - Enables visualization of the drawing process of EGA pictures\n"); DebugPrintf(" undither - Enable/disable undithering\n"); DebugPrintf(" play_video - Plays a SEQ, AVI, VMD, RBT or DUK video\n"); - DebugPrintf(" animate_object_list / al - Shows the current list of objects in kAnimate's draw list\n"); + DebugPrintf(" animate_list / al - Shows the current list of objects in kAnimate's draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" window_list / wl - Shows a list of all the windows (ports) in the draw list (SCI0 - SCI1.1)\n"); + DebugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n"); DebugPrintf(" saved_bits - List saved bits on the hunk\n"); DebugPrintf(" show_saved_bits - Display saved bits\n"); DebugPrintf("\n"); @@ -1589,6 +1596,8 @@ bool Console::cmdAnimateList(int argc, const char **argv) { if (_engine->_gfxAnimate) { DebugPrintf("Animate list:\n"); _engine->_gfxAnimate->printAnimateList(this); + } else { + DebugPrintf("This SCI version does not have an animate list\n"); } return true; } @@ -1597,9 +1606,52 @@ bool Console::cmdWindowList(int argc, const char **argv) { if (_engine->_gfxPorts) { DebugPrintf("Window list:\n"); _engine->_gfxPorts->printWindowList(this); + } else { + DebugPrintf("This SCI version does not have a list of ports\n"); } return true; +} +bool Console::cmdPlaneList(int argc, const char **argv) { +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane list:\n"); + _engine->_gfxFrameout->printPlaneList(this); + } else { + DebugPrintf("This SCI version does not have a list of planes\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; +} + +bool Console::cmdPlaneItemList(int argc, const char **argv) { + if (argc != 2) { + DebugPrintf("Shows the list of items for a plane\n"); + DebugPrintf("Usage: %s <plane address>\n", argv[0]); + return true; + } + + reg_t planeObject = NULL_REG; + + if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) { + DebugPrintf("Invalid address passed.\n"); + DebugPrintf("Check the \"addresses\" command on how to use addresses\n"); + return true; + } + +#ifdef ENABLE_SCI32 + if (_engine->_gfxFrameout) { + DebugPrintf("Plane item list:\n"); + _engine->_gfxFrameout->printPlaneItemList(this, planeObject); + } else { + DebugPrintf("This SCI version does not have a list of plane items\n"); + } +#else + DebugPrintf("SCI32 isn't included in this compiled executable\n"); +#endif + return true; } bool Console::cmdSavedBits(int argc, const char **argv) { diff --git a/engines/sci/console.h b/engines/sci/console.h index d943923ba1..be17fdb728 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -94,6 +94,8 @@ private: bool cmdPlayVideo(int argc, const char **argv); bool cmdAnimateList(int argc, const char **argv); bool cmdWindowList(int argc, const char **argv); + bool cmdPlaneList(int argc, const char **argv); + bool cmdPlaneItemList(int argc, const char **argv); bool cmdSavedBits(int argc, const char **argv); bool cmdShowSavedBits(int argc, const char **argv); // Segments diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index e549c1f8ae..42651ec4a5 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -458,6 +458,8 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv); reg_t kInPolygon(EngineState *s, int argc, reg_t *argv); reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv); reg_t kEditText(EngineState *s, int argc, reg_t *argv); +reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv); +reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv); // SCI2.1 Kernel Functions reg_t kText(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 622511c906..1fa12b01fd 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -500,29 +500,26 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL }, { MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL }, + { MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL }, // SCI2 unmapped functions - TODO! // SetScroll - called by script 64909, Styler::doit() // PalCycle - called by Game::newRoom. Related to RemapColors. - // VibrateMouse - used in QFG4 // SCI2 Empty functions // Debug function used to track resources { MAP_EMPTY(ResourceTrack), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - - // SCI2 functions that are used in the original save/load menus. Marked as dummy, so - // that the engine errors out on purpose. TODO: Implement once the original save/load - // menus are implemented. - - // Creates the name of the save catalogue/directory to save into. - // TODO: Implement once the original save/load menus are implemented. - { MAP_DUMMY(MakeSaveCatName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - - // Creates the name of the save file to save into - // TODO: Implement once the original save/load menus are implemented. - { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // Future TODO: This call is used in the floppy version of QFG4 to add + // vibration to exotic mice with force feedback, such as the Logitech + // Cyberman and Wingman mice. Since this is only used for very exotic + // hardware and we have no direct and cross-platform way of communicating + // with them via SDL, plus we would probably need to make changes to common + // code, this call is mapped to an empty function for now as it's a rare + // feature not worth the effort. + { MAP_EMPTY(VibrateMouse), SIG_EVERYWHERE, "(.*)", NULL, NULL }, // Unused / debug SCI2 unused functions, always mapped to kDummy diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 312497720a..af438bdaff 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -331,7 +331,7 @@ reg_t kDeviceInfo(EngineState *s, int argc, reg_t *argv) { s->_segMan->strcpy(argv[1], "__throwaway"); debug(3, "K_DEVICE_INFO_GET_SAVEFILE_NAME(%s,%d) -> %s", game_prefix.c_str(), virtualId, "__throwaway"); if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) - error("kDeviceInfo(deleteSave): invalid savegame-id specified"); + error("kDeviceInfo(deleteSave): invalid savegame ID specified"); uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; Common::Array<SavegameDesc> saves; listSavegames(saves); @@ -526,7 +526,7 @@ reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) { char *saveNamePtr = saveNames; for (uint i = 0; i < totalSaves; i++) { - *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame-id ffs. see above + *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame ID ffs. see above strcpy(saveNamePtr, saves[i].name); saveNamePtr += SCI_MAX_SAVENAME_LENGTH; } @@ -863,6 +863,10 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) { int savedir_nr = saves[slotNum].id; name = g_sci->getSavegameName(savedir_nr); result = saveFileMan->removeSavefile(name); + } else if (getSciVersion() >= SCI_VERSION_2) { + // We don't need to wrap the filename in SCI32 games, as it's already + // constructed here + result = saveFileMan->removeSavefile(name); } else { const Common::String wrappedName = g_sci->wrapFilename(name); result = saveFileMan->removeSavefile(wrappedName); @@ -1168,6 +1172,35 @@ reg_t kCD(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } +reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv) { + // Normally, this creates the name of the save catalogue/directory to save into. + // First parameter is the string to save the result into. Second is a string + // with game parameters. We don't have a use for this at all, as we have our own + // savegame directory management, thus we always return an empty string. + return argv[0]; +} + +reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) { + // Creates a savegame name from a slot number. Used when deleting saved games. + // Param 0: the output buffer (same as in kMakeSaveCatName) + // Param 1: a string with game parameters, ignored + // Param 2: the selected slot + + SciString *resultString = s->_segMan->lookupString(argv[0]); + uint16 virtualId = argv[2].toUint16(); + if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) + error("kMakeSaveFileName: invalid savegame ID specified"); + uint saveSlot = virtualId - SAVEGAMEID_OFFICIALRANGE_START; + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + + Common::String filename = g_sci->getSavegameName(saveSlot); + resultString->fromString(filename); + + return argv[0]; +} + reg_t kSave(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 0: @@ -1181,12 +1214,9 @@ reg_t kSave(EngineState *s, int argc, reg_t *argv) { case 5: return kGetSaveFiles(s, argc - 1, argv + 1); case 6: - // This is used in Shivers to delete saved games, however it - // always passes the same file name (SHIVER), so it doesn't - // actually delete anything... - // TODO: Check why this happens - // argv[1] is a string (most likely the save game directory) - return kFileIOUnlink(s, argc - 2, argv + 2); + return kMakeSaveCatName(s, argc - 1, argv + 1); + case 7: + return kMakeSaveFileName(s, argc - 1, argv + 1); case 8: // TODO // This is a timer callback, with 1 parameter: the timer object diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index caae562d67..8bf7be4ca3 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -25,12 +25,10 @@ #include "engines/util.h" #include "graphics/cursorman.h" #include "graphics/surface.h" -#include "graphics/palette.h" // temporary, for the fadeIn()/fadeOut() functions below #include "gui/message.h" #include "sci/sci.h" -#include "sci/debug.h" // for g_debug_sleeptime_factor #include "sci/event.h" #include "sci/resource.h" #include "sci/engine/features.h" @@ -50,10 +48,7 @@ #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 -#include "sci/graphics/controls32.h" -#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class #include "sci/graphics/text32.h" -#include "sci/graphics/frameout.h" #endif namespace Sci { @@ -1275,622 +1270,4 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -#ifdef ENABLE_SCI32 - -reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { - // Returns 0 if the screen width or height is less than 640 or 400, - // respectively. - if (g_system->getWidth() < 640 || g_system->getHeight() < 400) - return make_reg(0, 0); - - return make_reg(0, 1); -} - -// SCI32 variant, can't work like sci16 variants -reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { - // TODO -// reg_t curObject = argv[0]; -// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; - - return NULL_REG; -} - -reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { - if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) - g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); - else - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); - return s->r_acc; -} - -reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelAddPlane(argv[0]); - return s->r_acc; -} - -reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); - return s->r_acc; -} - -reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); - return s->r_acc; -} - -reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { - reg_t planeObj = argv[0]; - GuiResourceId pictureId = argv[1].toUint16(); - int16 pictureX = argv[2].toSint16(); - int16 pictureY = argv[3].toSint16(); - - g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); - return s->r_acc; -} - -reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, g_sci->_gfxFrameout->kernelGetHighPlanePri()); -} - -reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxFrameout->kernelFrameout(); - return NULL_REG; -} - -reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { - Common::Rect objRect1 = g_sci->_gfxCompare->getNSRect(argv[0]); - Common::Rect objRect2 = g_sci->_gfxCompare->getNSRect(argv[1]); - return make_reg(0, objRect1.intersects(objRect2)); -} - -// Tests if the coordinate is on the passed object -reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - uint16 illegalBits = argv[3].offset; - Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject, true); - - // we assume that x, y are local coordinates - - bool contained = nsRect.contains(x, y); - if (contained && illegalBits) { - // If illegalbits are set, we check the color of the pixel that got clicked on - // for now, we return false if the pixel is transparent - // although illegalBits may get differently set, don't know yet how this really works out - uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); - int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); - int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); - if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) - contained = false; - } - return make_reg(0, contained); -} - -reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: { - if (argc != 4) { - warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[3]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", - PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - uint16 maxWidth = argv[1].toUint16(); // nsRight - nsLeft + 1 - uint16 maxHeight = argv[2].toUint16(); // nsBottom - nsTop + 1 - return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); - } - case 1: { - if (argc != 2) { - warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[1]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - return g_sci->_gfxText32->createTextBitmap(object); - } - default: - warning("CreateTextBitmap(%d)", argv[0].toUint16()); - return NULL_REG; - } -} - -reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { - g_sci->_gfxText32->disposeTextBitmap(argv[0]); - return s->r_acc; -} - -reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) { - uint16 windowsOption = argv[0].toUint16(); - switch (windowsOption) { - case 0: - // Title bar on/off in Phantasmagoria, we return 0 (off) - return NULL_REG; - default: - warning("GetWindowsOption: Unknown option %d", windowsOption); - return NULL_REG; - } -} - -reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 1: - // Load a help file - // Maybe in the future we can implement this, but for now this message should suffice - showScummVMDialog("Please use an external viewer to open the game's help file: " + s->_segMan->getString(argv[1])); - break; - case 2: - // Looks like some init function - break; - default: - warning("Unknown kWinHelp subop %d", argv[0].toUint16()); - } - - return s->r_acc; -} - -// Taken from the SCI16 GfxTransitions class -static void fadeOut() { - byte oldPalette[3 * 256], workPalette[3 * 256]; - int16 stepNr, colorNr; - // Sierra did not fade in/out color 255 for sci1.1, but they used it in - // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; - - g_system->getPaletteManager()->grabPalette(oldPalette, 0, 256); - - for (stepNr = 100; stepNr >= 0; stepNr -= 10) { - for (colorNr = 1; colorNr <= tillColorNr; colorNr++) { - if (g_sci->_gfxPalette->colorIsFromMacClut(colorNr)) { - workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3]; - workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1]; - workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2]; - } else { - workPalette[colorNr * 3 + 0] = oldPalette[colorNr * 3] * stepNr / 100; - workPalette[colorNr * 3 + 1] = oldPalette[colorNr * 3 + 1] * stepNr / 100; - workPalette[colorNr * 3 + 2] = oldPalette[colorNr * 3 + 2] * stepNr / 100; - } - } - g_system->getPaletteManager()->setPalette(workPalette + 3, 1, tillColorNr); - g_sci->getEngineState()->wait(2); - } -} - -// Taken from the SCI16 GfxTransitions class -static void fadeIn() { - int16 stepNr; - // Sierra did not fade in/out color 255 for sci1.1, but they used it in - // several pictures (e.g. qfg3 demo/intro), so the fading looked weird - int16 tillColorNr = getSciVersion() >= SCI_VERSION_1_1 ? 255 : 254; - - for (stepNr = 0; stepNr <= 100; stepNr += 10) { - g_sci->_gfxPalette->kernelSetIntensity(1, tillColorNr + 1, stepNr, true); - g_sci->getEngineState()->wait(2); - } -} - -/** - * Used for scene transitions, replacing (but reusing parts of) the old - * transition code. - */ -reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { - // Can be called with 7 or 8 parameters - // The style defines which transition to perform. Related to the transition - // tables inside graphics/transitions.cpp - uint16 showStyle = argv[0].toUint16(); // 0 - 15 - reg_t planeObj = argv[1]; // the affected plane - uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts - uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff - int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out - uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts - uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out - int16 divisions; - - // If the game has the pFadeArray selector, another parameter is used here, - // before the optional last parameter - bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; - if (hasFadeArray) { - // argv[7] - divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) - } else { - divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) - } - - if (showStyle > 15) { - warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); - return s->r_acc; - } - - // TODO: Proper implementation. This is a very basic version. I'm not even - // sure if the rest of the styles will work with this mechanism. - - // Check if the passed parameters are the ones we expect - if (showStyle == 13 || showStyle == 14) { // fade out / fade in - if (seconds != 1) - warning("kSetShowStyle(fade): seconds isn't 1, it's %d", seconds); - if (backColor != 0 && backColor != 0xFFFF) - warning("kSetShowStyle(fade): backColor isn't 0 or 0xFFFF, it's %d", backColor); - if (priority != 200) - warning("kSetShowStyle(fade): priority isn't 200, it's %d", priority); - if (animate != 0) - warning("kSetShowStyle(fade): animate isn't 0, it's %d", animate); - if (refFrame != 0) - warning("kSetShowStyle(fade): refFrame isn't 0, it's %d", refFrame); - if (divisions >= 0 && divisions != 20) - warning("kSetShowStyle(fade): divisions isn't 20, it's %d", divisions); - } - - // TODO: Check if the plane is in the list of planes to draw - - switch (showStyle) { - //case 0: // no transition, perhaps? (like in the previous SCI versions) - case 13: // fade out - // TODO: Temporary implementation, which ignores all additional parameters - fadeOut(); - break; - case 14: // fade in - // TODO: Temporary implementation, which ignores all additional parameters - g_sci->_gfxFrameout->kernelFrameout(); // draw new scene before fading in - fadeIn(); - break; - default: - // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now - kStub(s, argc, argv); - break; - } - - return s->r_acc; -} - -reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) { - // Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board - // are occupied by pieces already - - switch (argv[0].toUint16()) { // subops 0 - 4 - // 0 - return the view - // 1 - return the loop - // 2, 3 - nop - case 4: { - GuiResourceId viewId = argv[1].toSint16(); - int16 loopNo = argv[2].toSint16(); - int16 celNo = argv[3].toSint16(); - int16 x = argv[4].toUint16(); - int16 y = argv[5].toUint16(); - byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y); - return make_reg(0, color); - } - default: { - kStub(s, argc, argv); - return s->r_acc; - } - } -} - -reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { - // Used by Phantasmagoria 1 and SQ6. In SQ6, it is used for the messages - // shown in the scroll window at the bottom of the screen. - - // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now - kStub(s, argc, argv); - - switch (argv[0].toUint16()) { - case 0: // Init - // 2 parameters - // argv[1] points to the scroll object (e.g. textScroller in SQ6) - // argv[2] is an integer (e.g. 0x32) - break; - case 1: // Show message - // 5 or 6 parameters - // Seems to be called with 5 parameters when the narrator speaks, and - // with 6 when Roger speaks - // argv[1] unknown (usually 0) - // argv[2] the text to show - // argv[3] a small integer (e.g. 0x32) - // argv[4] a small integer (e.g. 0x54) - // argv[5] optional, unknown (usually 0) - warning("kScrollWindow: '%s'", s->_segMan->getString(argv[2]).c_str()); - break; - case 2: // Clear - // 2 parameters - // TODO - break; - case 3: // Page up - // 2 parameters - // TODO - break; - case 4: // Page down - // 2 parameters - // TODO - break; - case 5: // Up arrow - // 2 parameters - // TODO - break; - case 6: // Down arrow - // 2 parameters - // TODO - break; - case 7: // Home - // 2 parameters - // TODO - break; - case 8: // End - // 2 parameters - // TODO - break; - case 9: // Resize - // 3 parameters - // TODO - break; - case 10: // Where - // 3 parameters - // TODO - break; - case 11: // Go - // 4 parameters - // TODO - break; - case 12: // Insert - // 7 parameters - // TODO - break; - case 13: // Delete - // 3 parameters - // TODO - break; - case 14: // Modify - // 7 or 8 parameters - // TODO - break; - case 15: // Hide - // 2 parameters - // TODO - break; - case 16: // Show - // 2 parameters - // TODO - break; - case 17: // Destroy - // 2 parameters - // TODO - break; - case 18: // Text - // 2 parameters - // TODO - break; - case 19: // Reconstruct - // 3 parameters - // TODO - break; - default: - error("kScrollWindow: unknown subop %d", argv[0].toUint16()); - break; - } - - return s->r_acc; -} - -reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { - // TODO: This defines the resolution that the fonts are supposed to be displayed - // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but - // should be extended to handle other font resolutions such as those - - int xResolution = argv[0].toUint16(); - //int yResolution = argv[1].toUint16(); - - g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && - g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); - - return s->r_acc; -} - -reg_t kFont(EngineState *s, int argc, reg_t *argv) { - // Handle font settings for SCI2.1 - - switch (argv[0].toUint16()) { - case 1: - // Set font resolution - return kSetFontRes(s, argc - 1, argv + 1); - default: - warning("kFont: unknown subop %d", argv[0].toUint16()); - } - - return s->r_acc; -} - -// TODO: Eventually, all of the kBitmap operations should be put -// in a separate class - -#define BITMAP_HEADER_SIZE 46 - -reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { - // Used for bitmap operations in SCI2.1 and SCI3. - // This is the SCI2.1 version, the functionality seems to have changed in SCI3. - - switch (argv[0].toUint16()) { - case 0: // init bitmap surface - { - // 6 params, called e.g. from TextView::init() in Torin's Passage, - // script 64890 and TransView::init() in script 64884 - uint16 width = argv[1].toUint16(); - uint16 height = argv[2].toUint16(); - //uint16 skip = argv[3].toUint16(); - uint16 back = argv[4].toUint16(); // usually equals skip - //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; - //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; - //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; - - // TODO: skip, width2, height2, transparentFlag - // (used for transparent bitmaps) - int entrySize = width * height + BITMAP_HEADER_SIZE; - reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); - byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); - memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header - memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); - // Save totalWidth, totalHeight - // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); - return memoryId; - } - break; - case 1: // dispose text bitmap surface - return kDisposeTextBitmap(s, argc - 1, argv + 1); - case 2: // dispose bitmap surface, with extra param - // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, - // script 64893 - warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); - break; - case 3: // tiled surface - { - // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, - // script 64869 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - // The tiled view seems to always have 2 loops. - // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. - uint16 viewNum = argv[2].toUint16(); // vTiles selector - uint16 loop = argv[3].toUint16(); - uint16 cel = argv[4].toUint16(); - uint16 x = argv[5].toUint16(); - uint16 y = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxView *view = g_sci->_gfxCache->getView(viewNum); - uint16 tileWidth = view->getWidth(loop, cel); - uint16 tileHeight = view->getHeight(loop, cel); - const byte *tileBitmap = view->getBitmap(loop, cel); - uint16 width = MIN<uint16>(totalWidth - x, tileWidth); - uint16 height = MIN<uint16>(totalHeight - y, tileHeight); - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; - } - } - - } - break; - case 4: // add text to bitmap - { - // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, - // script 64894 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - Common::String text = s->_segMan->getString(argv[2]); - uint16 textX = argv[3].toUint16(); - uint16 textY = argv[4].toUint16(); - //reg_t unk5 = argv[5]; - //reg_t unk6 = argv[6]; - //reg_t unk7 = argv[7]; // skip? - //reg_t unk8 = argv[8]; // back? - //reg_t unk9 = argv[9]; - uint16 fontId = argv[10].toUint16(); - //uint16 mode = argv[11].toUint16(); - uint16 dimmed = argv[12].toUint16(); - //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", - // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); - uint16 foreColor = 255; // TODO - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - GfxFont *font = g_sci->_gfxCache->getFont(fontId); - - int16 charCount = 0; - uint16 curX = textX, curY = textY; - const char *txt = text.c_str(); - - while (*txt) { - charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); - if (charCount == 0) - break; - - for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); - curX += font->getCharWidth(curChar); - } - - curX = textX; - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces - } - - } - break; - case 5: // fill with color - { - // 6 params, called e.g. from TextView::init() and TextView::draw() - // in Torin's Passage, script 64890 - reg_t hunkId = argv[1]; // obtained from kBitmap(0) - uint16 x = argv[2].toUint16(); - uint16 y = argv[3].toUint16(); - uint16 fillWidth = argv[4].toUint16(); // width - 1 - uint16 fillHeight = argv[5].toUint16(); // height - 1 - uint16 back = argv[6].toUint16(); - - byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); - // Get totalWidth, totalHeight - uint16 totalWidth = READ_LE_UINT16(memoryPtr); - uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); - uint16 width = MIN<uint16>(totalWidth - x, fillWidth); - uint16 height = MIN<uint16>(totalHeight - y, fillHeight); - byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - - for (uint16 curY = 0; curY < height; curY++) { - for (uint16 curX = 0; curX < width; curX++) { - bitmap[(curY + y) * totalWidth + (curX + x)] = back; - } - } - - } - break; - default: - kStub(s, argc, argv); - break; - } - - return s->r_acc; -} - -// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, -// but it handles events on its own, using an internal loop, instead of using SCI -// scripts for event management like kEditControl does. Called by script 64914, -// DEdit::hilite(). -reg_t kEditText(EngineState *s, int argc, reg_t *argv) { - reg_t controlObject = argv[0]; - - if (!controlObject.isNull()) { - g_sci->_gfxControls32->kernelTexteditChange(controlObject); - } - - return s->r_acc; -} - -#endif - } // End of namespace Sci diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp new file mode 100644 index 0000000000..2bb8288cb7 --- /dev/null +++ b/engines/sci/engine/kgraphics32.cpp @@ -0,0 +1,622 @@ +/* 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/system.h" + +#include "engines/util.h" +#include "graphics/cursorman.h" +#include "graphics/surface.h" + +#include "gui/message.h" + +#include "sci/sci.h" +#include "sci/event.h" +#include "sci/resource.h" +#include "sci/engine/features.h" +#include "sci/engine/state.h" +#include "sci/engine/selector.h" +#include "sci/engine/kernel.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/cache.h" +#include "sci/graphics/compare.h" +#include "sci/graphics/controls16.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/paint16.h" +#include "sci/graphics/picture.h" +#include "sci/graphics/ports.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/text16.h" +#include "sci/graphics/view.h" +#ifdef ENABLE_SCI32 +#include "sci/graphics/controls32.h" +#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class +#include "sci/graphics/text32.h" +#include "sci/graphics/frameout.h" +#endif + +namespace Sci { +#ifdef ENABLE_SCI32 + +extern void showScummVMDialog(const Common::String &message); + +reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { + // Returns 0 if the screen width or height is less than 640 or 400, + // respectively. + if (g_system->getWidth() < 640 || g_system->getHeight() < 400) + return make_reg(0, 0); + + return make_reg(0, 1); +} + +// SCI32 variant, can't work like sci16 variants +reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { + // TODO +// reg_t curObject = argv[0]; +// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG; + + return NULL_REG; +} + +reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { + if (g_sci->_gfxFrameout->findScreenItem(argv[0]) == NULL) + g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); + else + g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); + return s->r_acc; +} + +reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelAddPlane(argv[0]); + return s->r_acc; +} + +reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); + return s->r_acc; +} + +reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); + return s->r_acc; +} + +reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { + reg_t planeObj = argv[0]; + GuiResourceId pictureId = argv[1].toUint16(); + int16 pictureX = argv[2].toSint16(); + int16 pictureY = argv[3].toSint16(); + + g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, pictureX, pictureY); + return s->r_acc; +} + +reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_gfxFrameout->kernelGetHighPlanePri()); +} + +reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxFrameout->kernelFrameout(); + return NULL_REG; +} + +reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) { + Common::Rect objRect1 = g_sci->_gfxCompare->getNSRect(argv[0]); + Common::Rect objRect2 = g_sci->_gfxCompare->getNSRect(argv[1]); + return make_reg(0, objRect1.intersects(objRect2)); +} + +// Tests if the coordinate is on the passed object +reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { + uint16 x = argv[0].toUint16(); + uint16 y = argv[1].toUint16(); + reg_t targetObject = argv[2]; + uint16 illegalBits = argv[3].offset; + Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(targetObject, true); + + // we assume that x, y are local coordinates + + bool contained = nsRect.contains(x, y); + if (contained && illegalBits) { + // If illegalbits are set, we check the color of the pixel that got clicked on + // for now, we return false if the pixel is transparent + // although illegalBits may get differently set, don't know yet how this really works out + uint16 viewId = readSelectorValue(s->_segMan, targetObject, SELECTOR(view)); + int16 loopNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(loop)); + int16 celNo = readSelectorValue(s->_segMan, targetObject, SELECTOR(cel)); + if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) + contained = false; + } + return make_reg(0, contained); +} + +reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { + switch (argv[0].toUint16()) { + case 0: { + if (argc != 4) { + warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); + return NULL_REG; + } + reg_t object = argv[3]; + Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); + debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", + PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); + debugC(kDebugLevelStrings, "%s", text.c_str()); + uint16 maxWidth = argv[1].toUint16(); // nsRight - nsLeft + 1 + uint16 maxHeight = argv[2].toUint16(); // nsBottom - nsTop + 1 + return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); + } + case 1: { + if (argc != 2) { + warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); + return NULL_REG; + } + reg_t object = argv[1]; + Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); + debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); + debugC(kDebugLevelStrings, "%s", text.c_str()); + return g_sci->_gfxText32->createTextBitmap(object); + } + default: + warning("CreateTextBitmap(%d)", argv[0].toUint16()); + return NULL_REG; + } +} + +reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { + g_sci->_gfxText32->disposeTextBitmap(argv[0]); + return s->r_acc; +} + +reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) { + uint16 windowsOption = argv[0].toUint16(); + switch (windowsOption) { + case 0: + // Title bar on/off in Phantasmagoria, we return 0 (off) + return NULL_REG; + default: + warning("GetWindowsOption: Unknown option %d", windowsOption); + return NULL_REG; + } +} + +reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { + switch (argv[0].toUint16()) { + case 1: + // Load a help file + // Maybe in the future we can implement this, but for now this message should suffice + showScummVMDialog("Please use an external viewer to open the game's help file: " + s->_segMan->getString(argv[1])); + break; + case 2: + // Looks like some init function + break; + default: + warning("Unknown kWinHelp subop %d", argv[0].toUint16()); + } + + return s->r_acc; +} + +/** + * Used for scene transitions, replacing (but reusing parts of) the old + * transition code. + */ +reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { + // Can be called with 7 or 8 parameters + // The style defines which transition to perform. Related to the transition + // tables inside graphics/transitions.cpp + uint16 showStyle = argv[0].toUint16(); // 0 - 15 + reg_t planeObj = argv[1]; // the affected plane + //uint16 seconds = argv[2].toUint16(); // seconds that the transition lasts + //uint16 backColor = argv[3].toUint16(); // target back color(?). When fading out, it's 0x0000. When fading in, it's 0xffff + //int16 priority = argv[4].toSint16(); // always 0xc8 (200) when fading in/out + //uint16 animate = argv[5].toUint16(); // boolean, animate or not while the transition lasts + //uint16 refFrame = argv[6].toUint16(); // refFrame, always 0 when fading in/out + int16 divisions; + + // If the game has the pFadeArray selector, another parameter is used here, + // before the optional last parameter + bool hasFadeArray = g_sci->getKernel()->findSelector("pFadeArray") > 0; + if (hasFadeArray) { + // argv[7] + divisions = (argc >= 9) ? argv[8].toSint16() : -1; // divisions (transition steps?) + } else { + divisions = (argc >= 8) ? argv[7].toSint16() : -1; // divisions (transition steps?) + } + + if (showStyle > 15) { + warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); + return s->r_acc; + } + + // GK1 calls fadeout (13) / fadein (14) with the following parameters: + // seconds: 1 + // backColor: 0 / -1 + // fade: 200 + // animate: 0 + // refFrame: 0 + // divisions: 0 / 20 + + // TODO: Check if the plane is in the list of planes to draw + + switch (showStyle) { + //case 0: // no transition, perhaps? (like in the previous SCI versions) + case 13: // fade out + // TODO + case 14: // fade in + // TODO + default: + // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now + kStub(s, argc, argv); + break; + } + + return s->r_acc; +} + +reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) { + // Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board + // are occupied by pieces already + + switch (argv[0].toUint16()) { // subops 0 - 4 + // 0 - return the view + // 1 - return the loop + // 2, 3 - nop + case 4: { + GuiResourceId viewId = argv[1].toSint16(); + int16 loopNo = argv[2].toSint16(); + int16 celNo = argv[3].toSint16(); + int16 x = argv[4].toUint16(); + int16 y = argv[5].toUint16(); + byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y); + return make_reg(0, color); + } + default: { + kStub(s, argc, argv); + return s->r_acc; + } + } +} + +reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { + // Used by Phantasmagoria 1 and SQ6. In SQ6, it is used for the messages + // shown in the scroll window at the bottom of the screen. + + // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now + kStub(s, argc, argv); + + switch (argv[0].toUint16()) { + case 0: // Init + // 2 parameters + // argv[1] points to the scroll object (e.g. textScroller in SQ6) + // argv[2] is an integer (e.g. 0x32) + break; + case 1: // Show message + // 5 or 6 parameters + // Seems to be called with 5 parameters when the narrator speaks, and + // with 6 when Roger speaks + // argv[1] unknown (usually 0) + // argv[2] the text to show + // argv[3] a small integer (e.g. 0x32) + // argv[4] a small integer (e.g. 0x54) + // argv[5] optional, unknown (usually 0) + warning("kScrollWindow: '%s'", s->_segMan->getString(argv[2]).c_str()); + break; + case 2: // Clear + // 2 parameters + // TODO + break; + case 3: // Page up + // 2 parameters + // TODO + break; + case 4: // Page down + // 2 parameters + // TODO + break; + case 5: // Up arrow + // 2 parameters + // TODO + break; + case 6: // Down arrow + // 2 parameters + // TODO + break; + case 7: // Home + // 2 parameters + // TODO + break; + case 8: // End + // 2 parameters + // TODO + break; + case 9: // Resize + // 3 parameters + // TODO + break; + case 10: // Where + // 3 parameters + // TODO + break; + case 11: // Go + // 4 parameters + // TODO + break; + case 12: // Insert + // 7 parameters + // TODO + break; + case 13: // Delete + // 3 parameters + // TODO + break; + case 14: // Modify + // 7 or 8 parameters + // TODO + break; + case 15: // Hide + // 2 parameters + // TODO + break; + case 16: // Show + // 2 parameters + // TODO + break; + case 17: // Destroy + // 2 parameters + // TODO + break; + case 18: // Text + // 2 parameters + // TODO + break; + case 19: // Reconstruct + // 3 parameters + // TODO + break; + default: + error("kScrollWindow: unknown subop %d", argv[0].toUint16()); + break; + } + + return s->r_acc; +} + +reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { + // TODO: This defines the resolution that the fonts are supposed to be displayed + // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but + // should be extended to handle other font resolutions such as those + + int xResolution = argv[0].toUint16(); + //int yResolution = argv[1].toUint16(); + + g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && + g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); + + return s->r_acc; +} + +reg_t kFont(EngineState *s, int argc, reg_t *argv) { + // Handle font settings for SCI2.1 + + switch (argv[0].toUint16()) { + case 1: + // Set font resolution + return kSetFontRes(s, argc - 1, argv + 1); + default: + warning("kFont: unknown subop %d", argv[0].toUint16()); + } + + return s->r_acc; +} + +// TODO: Eventually, all of the kBitmap operations should be put +// in a separate class + +#define BITMAP_HEADER_SIZE 46 + +reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { + // Used for bitmap operations in SCI2.1 and SCI3. + // This is the SCI2.1 version, the functionality seems to have changed in SCI3. + + switch (argv[0].toUint16()) { + case 0: // init bitmap surface + { + // 6 params, called e.g. from TextView::init() in Torin's Passage, + // script 64890 and TransView::init() in script 64884 + uint16 width = argv[1].toUint16(); + uint16 height = argv[2].toUint16(); + //uint16 skip = argv[3].toUint16(); + uint16 back = argv[4].toUint16(); // usually equals skip + //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0; + //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0; + //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0; + + // TODO: skip, width2, height2, transparentFlag + // (used for transparent bitmaps) + int entrySize = width * height + BITMAP_HEADER_SIZE; + reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize); + byte *memoryPtr = s->_segMan->getHunkPointer(memoryId); + memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header + memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); + // Save totalWidth, totalHeight + // TODO: Save the whole bitmap header, like SSCI does + WRITE_LE_UINT16(memoryPtr, width); + WRITE_LE_UINT16(memoryPtr + 2, height); + return memoryId; + } + break; + case 1: // dispose text bitmap surface + return kDisposeTextBitmap(s, argc - 1, argv + 1); + case 2: // dispose bitmap surface, with extra param + // 2 params, called e.g. from MenuItem::dispose in Torin's Passage, + // script 64893 + warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2])); + break; + case 3: // tiled surface + { + // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage, + // script 64869 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + // The tiled view seems to always have 2 loops. + // These loops need to have 1 cel in loop 0 and 8 cels in loop 1. + uint16 viewNum = argv[2].toUint16(); // vTiles selector + uint16 loop = argv[3].toUint16(); + uint16 cel = argv[4].toUint16(); + uint16 x = argv[5].toUint16(); + uint16 y = argv[6].toUint16(); + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + GfxView *view = g_sci->_gfxCache->getView(viewNum); + uint16 tileWidth = view->getWidth(loop, cel); + uint16 tileHeight = view->getHeight(loop, cel); + const byte *tileBitmap = view->getBitmap(loop, cel); + uint16 width = MIN<uint16>(totalWidth - x, tileWidth); + uint16 height = MIN<uint16>(totalHeight - y, tileHeight); + + for (uint16 curY = 0; curY < height; curY++) { + for (uint16 curX = 0; curX < width; curX++) { + bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX]; + } + } + + } + break; + case 4: // add text to bitmap + { + // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage, + // script 64894 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + Common::String text = s->_segMan->getString(argv[2]); + uint16 textX = argv[3].toUint16(); + uint16 textY = argv[4].toUint16(); + //reg_t unk5 = argv[5]; + //reg_t unk6 = argv[6]; + //reg_t unk7 = argv[7]; // skip? + //reg_t unk8 = argv[8]; // back? + //reg_t unk9 = argv[9]; + uint16 fontId = argv[10].toUint16(); + //uint16 mode = argv[11].toUint16(); + uint16 dimmed = argv[12].toUint16(); + //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"", + // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str()); + uint16 foreColor = 255; // TODO + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + GfxFont *font = g_sci->_gfxCache->getFont(fontId); + + int16 charCount = 0; + uint16 curX = textX, curY = textY; + const char *txt = text.c_str(); + + while (*txt) { + charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font); + if (charCount == 0) + break; + + for (int i = 0; i < charCount; i++) { + unsigned char curChar = txt[i]; + font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight); + curX += font->getCharWidth(curChar); + } + + curX = textX; + curY += font->getHeight(); + txt += charCount; + while (*txt == ' ') + txt++; // skip over breaking spaces + } + + } + break; + case 5: // fill with color + { + // 6 params, called e.g. from TextView::init() and TextView::draw() + // in Torin's Passage, script 64890 + reg_t hunkId = argv[1]; // obtained from kBitmap(0) + uint16 x = argv[2].toUint16(); + uint16 y = argv[3].toUint16(); + uint16 fillWidth = argv[4].toUint16(); // width - 1 + uint16 fillHeight = argv[5].toUint16(); // height - 1 + uint16 back = argv[6].toUint16(); + + byte *memoryPtr = s->_segMan->getHunkPointer(hunkId); + // Get totalWidth, totalHeight + uint16 totalWidth = READ_LE_UINT16(memoryPtr); + uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2); + uint16 width = MIN<uint16>(totalWidth - x, fillWidth); + uint16 height = MIN<uint16>(totalHeight - y, fillHeight); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; + + for (uint16 curY = 0; curY < height; curY++) { + for (uint16 curX = 0; curX < width; curX++) { + bitmap[(curY + y) * totalWidth + (curX + x)] = back; + } + } + + } + break; + default: + kStub(s, argc, argv); + break; + } + + return s->r_acc; +} + +// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl, +// but it handles events on its own, using an internal loop, instead of using SCI +// scripts for event management like kEditControl does. Called by script 64914, +// DEdit::hilite(). +reg_t kEditText(EngineState *s, int argc, reg_t *argv) { + reg_t controlObject = argv[0]; + + if (!controlObject.isNull()) { + g_sci->_gfxControls32->kernelTexteditChange(controlObject); + } + + return s->r_acc; +} + +#endif + +} // End of namespace Sci diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 187f1ce021..69eb377684 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -775,7 +775,7 @@ const uint16 mothergoose256PatchReplay[] = { PATCH_END }; -// when saving, it also checks if the savegame-id is below 13. +// when saving, it also checks if the savegame ID is below 13. // we change this to check if below 113 instead const byte mothergoose256SignatureSaveLimit[] = { 5, diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index a8b1cf7ec2..2f6b4d58dd 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -181,6 +181,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(skip); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); + FIND_SELECTOR(visible); FIND_SELECTOR(useInsetRect); FIND_SELECTOR(inTop); FIND_SELECTOR(inLeft); diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index 4b913a866a..2308a6c387 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -149,6 +149,7 @@ struct SelectorCache { Selector fixPriority; Selector mirrored; + Selector visible; Selector useInsetRect; Selector inTop, inLeft, inBottom, inRight; diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 334d224baf..cdd9b9a06e 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -139,7 +139,7 @@ enum { GC_INTERVAL = 0x8000 }; -enum sci_opcodes { +enum SciOpcodes { op_bnot = 0x00, // 000 op_add = 0x01, // 001 op_sub = 0x02, // 002 diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 4a0aea81ff..c1d4a3d9f9 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -176,6 +176,7 @@ const SciWorkaroundEntry kAbs_workarounds[] = { { GID_HOYLE1, 2, 2, 0, "room2", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // old maid - called with objects instead of integers { GID_HOYLE1, 3, 3, 0, "room3", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // hearts - called with objects instead of integers { GID_QFG1VGA, -1, -1, 0, NULL, "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // when the game is patched with the NRS patch + { GID_QFG3 , -1, -1, 0, NULL, "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // when the game is patched with the NRS patch (bugs #3528416, #3528542) SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -321,8 +322,9 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = { { GID_ECOQUEST2, 100, 333, 0, "showEcorder", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // necessary workaround for our ecorder script patch, because there isn't enough space to patch the function - { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 { GID_PQ3, 202, 202, 0, "MapEdit", "addPt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 + { GID_PQ3, 202, 202, 0, "MapEdit", "movePt", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters - bug #3038077 + { GID_PQ3, 202, 202, 0, "MapEdit", "dispose", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when plotting crimes, gets called with 2 extra parameters SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index b12413ab69..709a708d8b 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -31,6 +31,7 @@ #include "graphics/surface.h" #include "sci/sci.h" +#include "sci/console.h" #include "sci/engine/kernel.h" #include "sci/engine/state.h" #include "sci/engine/selector.h" @@ -237,6 +238,7 @@ void GfxFrameout::kernelAddScreenItem(reg_t object) { memset(itemEntry, 0, sizeof(FrameoutEntry)); itemEntry->object = object; itemEntry->givenOrderNr = _screenItems.size(); + itemEntry->visible = true; _screenItems.push_back(itemEntry); kernelUpdateScreenItem(object); @@ -266,6 +268,11 @@ void GfxFrameout::kernelUpdateScreenItem(reg_t object) { itemEntry->signal = readSelectorValue(_segMan, object, SELECTOR(signal)); itemEntry->scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); itemEntry->scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); + itemEntry->visible = true; + + // Check if the entry can be hidden + if (lookupSelector(_segMan, object, SELECTOR(visible), NULL, NULL) != kSelectorNone) + itemEntry->visible = readSelectorValue(_segMan, object, SELECTOR(visible)); } void GfxFrameout::kernelDeleteScreenItem(reg_t object) { @@ -433,6 +440,7 @@ void GfxFrameout::createPlaneItemList(reg_t planeObject, FrameoutList &itemList) picEntry->x = planePicture->getSci32celX(pictureCelNr); picEntry->picStartX = pictureIt->startX; picEntry->picStartY = pictureIt->startY; + picEntry->visible = true; picEntry->priority = planePicture->getSci32celPriority(pictureCelNr); @@ -541,6 +549,9 @@ void GfxFrameout::kernelFrameout() { for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) { FrameoutEntry *itemEntry = *listIterator; + if (!itemEntry->visible) + continue; + if (itemEntry->object.isNull()) { // Picture cel data itemEntry->x = upscaleHorizontalCoordinate(itemEntry->x); @@ -667,4 +678,54 @@ void GfxFrameout::kernelFrameout() { g_sci->getEngineState()->_throttleTrigger = true; } +void GfxFrameout::printPlaneList(Console *con) { + for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) { + PlaneEntry p = *it; + Common::String curPlaneName = _segMan->getObjectName(p.object); + Common::Rect r = p.upscaledPlaneRect; + Common::Rect cr = p.upscaledPlaneClipRect; + + con->DebugPrintf("%04x:%04x (%s): prio %d, lastprio %d, offsetX %d, offsetY %d, pic %d, mirror %d, back %d\n", + PRINT_REG(p.object), curPlaneName.c_str(), + (int16)p.priority, (int16)p.lastPriority, + p.planeOffsetX, p.planeOffsetY, p.pictureId, + p.planePictureMirrored, p.planeBack); + con->DebugPrintf(" rect: (%d, %d, %d, %d), clip rect: (%d, %d, %d, %d)\n", + r.left, r.top, r.right, r.bottom, + cr.left, cr.top, cr.right, cr.bottom); + + if (p.pictureId != 0xffff && p.pictureId != 0xfffe) { + con->DebugPrintf("Pictures:\n"); + + for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) { + if (pictureIt->object == p.object) { + con->DebugPrintf(" Picture %d: x %d, y %d\n", pictureIt->pictureId, pictureIt->startX, pictureIt->startY); + } + } + } + } +} + +void GfxFrameout::printPlaneItemList(Console *con, reg_t planeObject) { + for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) { + FrameoutEntry *e = *listIterator; + reg_t itemPlane = readSelector(_segMan, e->object, SELECTOR(plane)); + + if (planeObject == itemPlane) { + Common::String curItemName = _segMan->getObjectName(e->object); + Common::Rect icr = e->celRect; + GuiResourceId picId = e->picture ? e->picture->getResourceId() : 0; + + con->DebugPrintf("%d: %04x:%04x (%s), view %d, loop %d, cel %d, x %d, y %d, z %d, " + "signal %d, scale signal %d, scaleX %d, scaleY %d, rect (%d, %d, %d, %d), " + "pic %d, picX %d, picY %d, visible %d\n", + e->givenOrderNr, PRINT_REG(e->object), curItemName.c_str(), + e->viewId, e->loopNo, e->celNo, e->x, e->y, e->z, + e->signal, e->scaleSignal, e->scaleX, e->scaleY, + icr.left, icr.top, icr.right, icr.bottom, + picId, e->picStartX, e->picStartY, e->visible); + } + } +} + } // End of namespace Sci diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 8c3cc261d5..ec4de62c0a 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -60,6 +60,7 @@ struct FrameoutEntry { GfxPicture *picture; int16 picStartX; int16 picStartY; + bool visible; }; typedef Common::List<FrameoutEntry *> FrameoutList; @@ -103,6 +104,8 @@ public: void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0); void deletePlanePictures(reg_t object); void clear(); + void printPlaneList(Console *con); + void printPlaneItemList(Console *con, reg_t planeObject); private: void showVideo(); diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 7894c7109c..cd24ca5a99 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -187,8 +187,11 @@ void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t t byte *memoryPtr = _segMan->getHunkPointer(hunkId); - if (!memoryPtr) - error("Attempt to draw an invalid text bitmap"); + if (!memoryPtr) { + // Happens when restoring in some SCI32 games + warning("Attempt to draw an invalid text bitmap"); + return; + } byte *surface = memoryPtr + BITMAP_HEADER_SIZE; diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index a77bcccc52..4e5c4da8b2 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -720,6 +720,19 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); + // WORKAROUND: EcoQuest French and German draw the fish and anemone sprites + // with priority 15 in scene 440. Afterwards, a dialog is shown on top of + // these sprites with priority 15 as well. This is undefined behavior + // actually, as the sprites and dialog share the same priority, so in our + // implementation the sprites get drawn incorrectly on top of the dialog. + // Perhaps this worked by mistake in SSCI because of subtle differences in + // how sprites are drawn. We compensate for this by resetting the priority + // of all sprites that have a priority of 15 in scene 440 to priority 14, + // so that the speech bubble can be drawn correctly on top of them. Fixes + // bug #3040625. + if (g_sci->getGameId() == GID_ECOQUEST && g_sci->getEngineState()->currentRoomNumber() == 440 && priority == 15) + priority = 14; + if (!_EGAmapping) { for (y = 0; y < height; y++, bitmap += celWidth) { for (x = 0; x < width; x++) { diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 90a0f33f06..b6d5837b31 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -79,6 +79,7 @@ MODULE_OBJS := \ ifdef ENABLE_SCI32 MODULE_OBJS += \ + engine/kgraphics32.o \ graphics/controls32.o \ graphics/frameout.o \ graphics/paint32.o \ diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 77a6a40a92..f8ddf64551 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -93,7 +93,7 @@ const char *getSciVersionDesc(SciVersion version) { //#define SCI_VERBOSE_RESMAN 1 -static const char *const sci_error_types[] = { +static const char *const s_errorDescriptions[] = { "No error", "I/O error", "Resource is empty (size 0)", @@ -101,10 +101,8 @@ static const char *const sci_error_types[] = { "resource.map file not found", "No resource files found", "Unknown compression method", - "Decompression failed: Decompression buffer overflow", "Decompression failed: Sanity check failed", - "Decompression failed: Resource too big", - "SCI version is unsupported" + "Decompression failed: Resource too big" }; static const char *const s_resourceTypeNames[] = { @@ -576,7 +574,7 @@ void ResourceSource::loadResource(ResourceManager *resMan, Resource *res) { if (error) { warning("Error %d occurred while reading %s from resource file %s: %s", error, res->_id.toString().c_str(), res->getResourceLocation().c_str(), - sci_error_types[error]); + s_errorDescriptions[error]); res->unalloc(); } @@ -1876,6 +1874,9 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream uint32 wCompression, szUnpacked; ResourceType type; + if (file->size() == 0) + return SCI_ERROR_EMPTY_RESOURCE; + switch (volVersion) { case kResVersionSci0Sci1Early: case kResVersionSci1Middle: @@ -1920,7 +1921,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream break; #endif default: - return SCI_ERROR_INVALID_RESMAP_ENTRY; + return SCI_ERROR_RESMAP_INVALID_ENTRY; } // check if there were errors while reading @@ -1961,7 +1962,7 @@ int Resource::readResourceInfo(ResVersion volVersion, Common::SeekableReadStream compression = kCompUnknown; } - return compression == kCompUnknown ? SCI_ERROR_UNKNOWN_COMPRESSION : 0; + return (compression == kCompUnknown) ? SCI_ERROR_UNKNOWN_COMPRESSION : SCI_ERROR_NONE; } int Resource::decompress(ResVersion volVersion, Common::SeekableReadStream *file) { diff --git a/engines/sci/resource.h b/engines/sci/resource.h index 294a4672e2..4baf39c67f 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -54,17 +54,17 @@ enum ResourceStatus { kResStatusLocked /**< Allocated and in use */ }; -/** Initialization result types */ -enum { +/** Resource error codes. Should be in sync with s_errorDescriptions */ +enum ResourceErrorCodes { + SCI_ERROR_NONE = 0, SCI_ERROR_IO_ERROR = 1, - SCI_ERROR_INVALID_RESMAP_ENTRY = 2, /**< Invalid resource.map entry */ - SCI_ERROR_RESMAP_NOT_FOUND = 3, - SCI_ERROR_NO_RESOURCE_FILES_FOUND = 4, /**< No resource at all was found */ - SCI_ERROR_UNKNOWN_COMPRESSION = 5, - SCI_ERROR_DECOMPRESSION_ERROR = 6, /**< sanity checks failed during decompression */ + SCI_ERROR_EMPTY_RESOURCE = 2, + SCI_ERROR_RESMAP_INVALID_ENTRY = 3, /**< Invalid resource.map entry */ + SCI_ERROR_RESMAP_NOT_FOUND = 4, + SCI_ERROR_NO_RESOURCE_FILES_FOUND = 5, /**< No resource at all was found */ + SCI_ERROR_UNKNOWN_COMPRESSION = 6, + SCI_ERROR_DECOMPRESSION_ERROR = 7, /**< sanity checks failed during decompression */ SCI_ERROR_RESOURCE_TOO_BIG = 8 /**< Resource size exceeds SCI_MAX_RESOURCE_SIZE */ - - /* the first critical error number */ }; enum { diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 9b0ee6924b..960016764a 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -385,7 +385,7 @@ bool SciEngine::gameHasFanMadePatch() { { GID_PQ3, 994, 4686, 1291, 0x78 }, // English { GID_PQ3, 994, 4734, 1283, 0x78 }, // German { GID_QFG1VGA, 994, 4388, 0, 0x00 }, - { GID_QFG3, 994, 4714, 0, 0x00 }, + { GID_QFG3, 33, 260, 0, 0x00 }, // TODO: Disabled, as it fixes a whole lot of bugs which can't be tested till SCI2.1 support is finished //{ GID_QFG4, 710, 11477, 0, 0x00 }, { GID_SQ1, 994, 4740, 0, 0x00 }, diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 42748d08ed..ce4b2239d2 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -129,7 +129,7 @@ bool Win32ResExtractor::extractResource(int id, CachedCursor *cc) { if (!group) return false; - Graphics::WinCursor *cursor = group->cursors[0].cursor; + Graphics::Cursor *cursor = group->cursors[0].cursor; cc->bitmap = new byte[cursor->getWidth() * cursor->getHeight()]; cc->width = cursor->getWidth(); diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 1e2964054a..a70ca960ba 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -510,11 +510,11 @@ DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { } -uint32 DXADecoderWithSound::getElapsedTime() const { +uint32 DXADecoderWithSound::getTime() const { if (_mixer->isSoundHandleActive(*_bgSoundHandle)) return _mixer->getSoundElapsedTime(*_bgSoundHandle); - return DXADecoder::getElapsedTime(); + return DXADecoder::getTime(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index f64b03dd1b..c2ed86a1a3 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -60,7 +60,7 @@ public: DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); ~DXADecoderWithSound() {} - uint32 getElapsedTime() const; + uint32 getTime() const; private: Audio::Mixer *_mixer; diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index e77ae98163..90ee7375ab 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -410,11 +410,11 @@ DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { } -uint32 DXADecoderWithSound::getElapsedTime() const { +uint32 DXADecoderWithSound::getTime() const { if (_mixer->isSoundHandleActive(*_bgSoundHandle)) return _mixer->getSoundElapsedTime(*_bgSoundHandle); - return DXADecoder::getElapsedTime(); + return DXADecoder::getTime(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 3ef8dac754..3d5c42b7f7 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -60,7 +60,7 @@ public: DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); ~DXADecoderWithSound() {} - uint32 getElapsedTime() const; + uint32 getTime() const; private: Audio::Mixer *_mixer; Audio::SoundHandle *_bgSoundHandle; diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index 1acb366b3a..4609565223 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -167,7 +167,7 @@ void MoviePlayer::setScaleFactor(float scaleFactor) { } double MoviePlayer::getTime() { - return _decoder.getElapsedTime() / 1000.0; + return _decoder.getTime() / 1000.0; } #else // USE_THEORADEC diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp index a7ebb5df8c..082c569fda 100644 --- a/engines/sword25/fmv/theora_decoder.cpp +++ b/engines/sword25/fmv/theora_decoder.cpp @@ -507,7 +507,7 @@ uint32 TheoraDecoder::getTimeToNextFrame() const { if (endOfVideo() || _curFrame < 0) return 0; - uint32 elapsedTime = getElapsedTime(); + uint32 elapsedTime = getTime(); uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); if (nextFrameStartTime <= elapsedTime) @@ -516,11 +516,11 @@ uint32 TheoraDecoder::getTimeToNextFrame() const { return nextFrameStartTime - elapsedTime; } -uint32 TheoraDecoder::getElapsedTime() const { +uint32 TheoraDecoder::getTime() const { if (_audStream) return g_system->getMixer()->getSoundElapsedTime(*_audHandle); - return VideoDecoder::getElapsedTime(); + return VideoDecoder::getTime(); } void TheoraDecoder::pauseVideoIntern(bool pause) { diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h index e8cc5ab8b9..4fd7cc0f03 100644 --- a/engines/sword25/fmv/theora_decoder.h +++ b/engines/sword25/fmv/theora_decoder.h @@ -81,7 +81,7 @@ public: } Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } - uint32 getElapsedTime() const; + uint32 getTime() const; uint32 getTimeToNextFrame() const; bool endOfVideo() const; diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp index acacd89667..a784ff5788 100644 --- a/engines/tinsel/actors.cpp +++ b/engines/tinsel/actors.cpp @@ -340,7 +340,7 @@ void RestoreActorProcess(int id, INT_CONTEXT *pic, bool savegameFlag) { if (savegameFlag) pic->resumeState = RES_SAVEGAME; - g_scheduler->createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); + CoroScheduler.createProcess(PID_TCODE, ActorRestoredProcess, &r, sizeof(r)); } /** @@ -358,7 +358,7 @@ void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be) { atp.event = event; atp.bev = be; atp.pic = NULL; - g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); + CoroScheduler.createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); } } @@ -369,7 +369,7 @@ void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEsca ATP_INIT atp; int index; CORO_BEGIN_CONTEXT; - PPROCESS pProc; + Common::PPROCESS pProc; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); @@ -389,7 +389,7 @@ void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEsca myEscape); if (atp.pic != NULL) { - _ctx->pProc = g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); + _ctx->pProc = CoroScheduler.createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp)); AttachInterpret(atp.pic, _ctx->pProc); if (bWait) @@ -474,8 +474,8 @@ void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript) { // Run actor's script for this scene if (bRunScript) { // Send in reverse order - they get swapped round in the scheduler - ActorEvent(nullContext, taggedActors[i].id, SHOWEVENT, false, 0); - ActorEvent(nullContext, taggedActors[i].id, STARTUP, false, 0); + ActorEvent(Common::nullContext, taggedActors[i].id, SHOWEVENT, false, 0); + ActorEvent(Common::nullContext, taggedActors[i].id, STARTUP, false, 0); } } } diff --git a/engines/tinsel/background.h b/engines/tinsel/background.h index 34f1bd6dd2..cfa3998eda 100644 --- a/engines/tinsel/background.h +++ b/engines/tinsel/background.h @@ -24,9 +24,9 @@ #ifndef TINSEL_BACKGND_H // prevent multiple includes #define TINSEL_BACKGND_H +#include "common/coroutines.h" #include "common/frac.h" #include "common/rect.h" -#include "tinsel/coroutine.h" #include "tinsel/dw.h" // for SCNHANDLE #include "tinsel/palette.h" // palette definitions diff --git a/engines/tinsel/bg.cpp b/engines/tinsel/bg.cpp index 72ba05f0b9..a3e21a8227 100644 --- a/engines/tinsel/bg.cpp +++ b/engines/tinsel/bg.cpp @@ -255,17 +255,17 @@ void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) { g_BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate); // Start display process for each reel in the film - g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); + CoroScheduler.createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL)); if (TinselV0) { for (uint i = 1; i < FROM_LE_32(pfilm->numreels); ++i) - g_scheduler->createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL)); + CoroScheduler.createProcess(PID_REEL, BGotherProcess, &pfilm->reels[i], sizeof(FREEL)); } if (g_pBG[0] == NULL) ControlStartOff(); - if (TinselV2 && (coroParam != nullContext)) + if (TinselV2 && (coroParam != Common::nullContext)) CORO_GIVE_WAY; CORO_END_CODE; diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp index 24d47b920f..438fd52a81 100644 --- a/engines/tinsel/bmv.cpp +++ b/engines/tinsel/bmv.cpp @@ -529,7 +529,7 @@ int BMVPlayer::MovieCommand(char cmd, int commandOffset) { if (cmd & CD_PRINT) { PRINT_CMD *pCmd = (PRINT_CMD *)(bigBuffer + commandOffset); - MovieText(nullContext, (int16)READ_LE_UINT16(&pCmd->stringId), + MovieText(Common::nullContext, (int16)READ_LE_UINT16(&pCmd->stringId), (int16)READ_LE_UINT16(&pCmd->x), (int16)READ_LE_UINT16(&pCmd->y), pCmd->fontId, @@ -542,7 +542,7 @@ int BMVPlayer::MovieCommand(char cmd, int commandOffset) { TALK_CMD *pCmd = (TALK_CMD *)(bigBuffer + commandOffset); talkColor = TINSEL_RGB(pCmd->r, pCmd->g, pCmd->b); - MovieText(nullContext, (int16)READ_LE_UINT16(&pCmd->stringId), + MovieText(Common::nullContext, (int16)READ_LE_UINT16(&pCmd->stringId), (int16)READ_LE_UINT16(&pCmd->x), (int16)READ_LE_UINT16(&pCmd->y), 0, diff --git a/engines/tinsel/bmv.h b/engines/tinsel/bmv.h index eadf65c3aa..fa254ed26d 100644 --- a/engines/tinsel/bmv.h +++ b/engines/tinsel/bmv.h @@ -24,12 +24,12 @@ #ifndef TINSEL_BMV_H #define TINSEL_BMV_H +#include "common/coroutines.h" #include "common/file.h" #include "audio/audiostream.h" #include "audio/mixer.h" -#include "tinsel/coroutine.h" #include "tinsel/object.h" #include "tinsel/palette.h" diff --git a/engines/tinsel/coroutine.cpp b/engines/tinsel/coroutine.cpp deleted file mode 100644 index ef0097f043..0000000000 --- a/engines/tinsel/coroutine.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "tinsel/coroutine.h" -#include "common/hashmap.h" -#include "common/hash-str.h" - -namespace Tinsel { - - -CoroContext nullContext = NULL; // FIXME: Avoid non-const global vars - - -#if COROUTINE_DEBUG -namespace { -static int s_coroCount = 0; - -typedef Common::HashMap<Common::String, int> CoroHashMap; -static CoroHashMap *s_coroFuncs = 0; - -static void changeCoroStats(const char *func, int change) { - if (!s_coroFuncs) - s_coroFuncs = new CoroHashMap(); - - (*s_coroFuncs)[func] += change; -} - -static void displayCoroStats() { - debug("%d active coros", s_coroCount); - - // Loop over s_coroFuncs and print info about active coros - if (!s_coroFuncs) - return; - for (CoroHashMap::const_iterator it = s_coroFuncs->begin(); - it != s_coroFuncs->end(); ++it) { - if (it->_value != 0) - debug(" %3d x %s", it->_value, it->_key.c_str()); - } -} - -} -#endif - -CoroBaseContext::CoroBaseContext(const char *func) - : _line(0), _sleep(0), _subctx(0) { -#if COROUTINE_DEBUG - _funcName = func; - changeCoroStats(_funcName, +1); - s_coroCount++; -#endif -} - -CoroBaseContext::~CoroBaseContext() { -#if COROUTINE_DEBUG - s_coroCount--; - changeCoroStats(_funcName, -1); - debug("Deleting coro in %s at %p (subctx %p)", - _funcName, (void *)this, (void *)_subctx); - displayCoroStats(); -#endif - delete _subctx; -} - -} // End of namespace Tinsel diff --git a/engines/tinsel/coroutine.h b/engines/tinsel/coroutine.h deleted file mode 100644 index 5bcf1149d9..0000000000 --- a/engines/tinsel/coroutine.h +++ /dev/null @@ -1,282 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef TINSEL_COROUTINE_H -#define TINSEL_COROUTINE_H - -#include "common/scummsys.h" -#include "common/util.h" // for SCUMMVM_CURRENT_FUNCTION - -namespace Tinsel { - -/** - * @defgroup TinselCoroutines Coroutine support for Tinsel - * - * The following is loosely based on an article by Simon Tatham: - * <http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html>. - * However, many improvements and tweaks have been made, in particular - * by taking advantage of C++ features not available in C. - * - * Why is this code here? Well, the Tinsel engine apparently used - * setjmp/longjmp based coroutines as a core tool from the start, and - * so they are deeply ingrained into the whole code base. When we - * started to get Tinsel ready for ScummVM, we had to deal with that. - * It soon got clear that we could not simply rewrite the code to work - * without some form of coroutines. While possible in principle, it - * would have meant a major restructuring of the entire code base, a - * rather daunting task. Also, it would have very likely introduced - * tons of regressons. - * - * So instead of getting rid of the coroutines, we chose to implement - * them in an alternate way, using Simon Tatham's trick as described - * above. While the trick is dirty, the result seems to be clear enough, - * we hope; plus, it allowed us to stay relatively close to the - * original structure of the code, which made it easier to avoid - * regressions, and will be helpful in the future when comparing things - * against the original code base. - */ -//@{ - - -// Enable this macro to enable some debugging support in the coroutine code. -//#define COROUTINE_DEBUG 1 - -/** - * The core of any coroutine context which captures the 'state' of a coroutine. - * Private use only. - */ -struct CoroBaseContext { - int _line; - int _sleep; - CoroBaseContext *_subctx; -#if COROUTINE_DEBUG - const char *_funcName; -#endif - CoroBaseContext(const char *func); - ~CoroBaseContext(); -}; - -typedef CoroBaseContext *CoroContext; - - -// FIXME: Document this! -extern CoroContext nullContext; - -/** - * Wrapper class which holds a pointer to a pointer to a CoroBaseContext. - * The interesting part is the destructor, which kills the context being held, - * but ONLY if the _sleep val of that context is zero. This way, a coroutine - * can just 'return' w/o having to worry about freeing the allocated context - * (in Simon Tatham's original code, one had to use a special macro to - * return from a coroutine). - */ -class CoroContextHolder { - CoroContext &_ctx; -public: - CoroContextHolder(CoroContext &ctx) : _ctx(ctx) { - assert(ctx); - assert(ctx->_sleep >= 0); - ctx->_sleep = 0; - } - ~CoroContextHolder() { - if (_ctx && _ctx->_sleep == 0) { - delete _ctx; - _ctx = 0; - } - } -}; - - -#define CORO_PARAM CoroContext &coroParam - - -/** - * Begin the declaration of a coroutine context. - * This allows declaring variables which are 'persistent' during the - * lifetime of the coroutine. An example use would be: - * - * CORO_BEGIN_CONTEXT; - * int var; - * char *foo; - * CORO_END_CONTEXT(_ctx); - * - * It is not possible to initialize variables here, due to the way this - * macro is implemented. Furthermore, to use the variables declared in - * the coroutine context, you have to access them via the context variable - * name that was specified as parameter to CORO_END_CONTEXT, e.g. - * _ctx->var = 0; - * - * @see CORO_END_CONTEXT - * - * @note We declare a variable 'DUMMY' to allow the user to specify an 'empty' - * context, and so compilers won't complain about ";" following the macro. - */ -#define CORO_BEGIN_CONTEXT \ - struct CoroContextTag : CoroBaseContext { \ - CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) {} \ - int DUMMY - -/** - * End the declaration of a coroutine context. - * @param x name of the coroutine context - * @see CORO_BEGIN_CONTEXT - */ -#define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam - -/** - * Begin the code section of a coroutine. - * @param x name of the coroutine context - * @see CORO_BEGIN_CODE - */ -#define CORO_BEGIN_CODE(x) \ - if (&coroParam == &nullContext) assert(!nullContext);\ - if (!x) {coroParam = x = new CoroContextTag();}\ - CoroContextHolder tmpHolder(coroParam);\ - switch (coroParam->_line) { case 0:; - -/** - * End the code section of a coroutine. - * @see CORO_END_CODE - */ -#define CORO_END_CODE \ - if (&coroParam == &nullContext) { \ - delete nullContext; \ - nullContext = NULL; \ - } \ - } - -/** - * Sleep for the specified number of scheduler cycles. - */ -#define CORO_SLEEP(delay) do {\ - coroParam->_line = __LINE__;\ - coroParam->_sleep = delay;\ - assert(&coroParam != &nullContext);\ - return; case __LINE__:;\ - } while (0) - -#define CORO_GIVE_WAY do { g_scheduler->giveWay(); CORO_SLEEP(1); } while (0) -#define CORO_RESCHEDULE do { g_scheduler->reschedule(); CORO_SLEEP(1); } while (0) - -/** - * Stop the currently running coroutine and all calling coroutines. - * - * This sets _sleep to -1 rather than 0 so that the context doesn't get - * deleted by CoroContextHolder, since we want CORO_INVOKE_ARGS to - * propogate the _sleep value and return immediately (the scheduler will - * then delete the entire coroutine's state, including all subcontexts). - */ -#define CORO_KILL_SELF() \ - do { if (&coroParam != &nullContext) { coroParam->_sleep = -1; } return; } while (0) - - -/** - * This macro is to be used in conjunction with CORO_INVOKE_ARGS and - * similar macros for calling coroutines-enabled subroutines. - */ -#define CORO_SUBCTX coroParam->_subctx - -/** - * Invoke another coroutine. - * - * If the subcontext still exists after the coroutine is invoked, it has - * either yielded/slept or killed itself, and so we copy the _sleep value - * to our own context and return (execution will continue at the case - * statement below, where we loop and call the coroutine again). - * If the subcontext is null, the coroutine ended normally, and we can - * simply break out of the loop and continue execution. - * - * @param subCoro name of the coroutine-enabled function to invoke - * @param ARGS list of arguments to pass to subCoro - * - * @note ARGS must be surrounded by parentheses, and the first argument - * in this list must always be CORO_SUBCTX. For example, the - * regular function call - * myFunc(a, b); - * becomes the following: - * CORO_INVOKE_ARGS(myFunc, (CORO_SUBCTX, a, b)); - */ -#define CORO_INVOKE_ARGS(subCoro, ARGS) \ - do {\ - coroParam->_line = __LINE__;\ - coroParam->_subctx = 0;\ - do {\ - subCoro ARGS;\ - if (!coroParam->_subctx) break;\ - coroParam->_sleep = coroParam->_subctx->_sleep;\ - assert(&coroParam != &nullContext);\ - return; case __LINE__:;\ - } while (1);\ - } while (0) - -/** - * Invoke another coroutine. Similar to CORO_INVOKE_ARGS, - * but allows specifying a return value which is returned - * if invoked coroutine yields (thus causing the current - * coroutine to yield, too). - */ -#define CORO_INVOKE_ARGS_V(subCoro, RESULT, ARGS) \ - do {\ - coroParam->_line = __LINE__;\ - coroParam->_subctx = 0;\ - do {\ - subCoro ARGS;\ - if (!coroParam->_subctx) break;\ - coroParam->_sleep = coroParam->_subctx->_sleep;\ - assert(&coroParam != &nullContext);\ - return RESULT; case __LINE__:;\ - } while (1);\ - } while (0) - -/** - * Convenience wrapper for CORO_INVOKE_ARGS for invoking a coroutine - * with no parameters. - */ -#define CORO_INVOKE_0(subCoroutine) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX)) - -/** - * Convenience wrapper for CORO_INVOKE_ARGS for invoking a coroutine - * with one parameter. - */ -#define CORO_INVOKE_1(subCoroutine, a0) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0)) - -/** - * Convenience wrapper for CORO_INVOKE_ARGS for invoking a coroutine - * with two parameters. - */ -#define CORO_INVOKE_2(subCoroutine, a0,a1) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1)) - -/** - * Convenience wrapper for CORO_INVOKE_ARGS for invoking a coroutine - * with three parameters. - */ -#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \ - CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2)) - -//@} - -} // End of namespace Tinsel - -#endif // TINSEL_COROUTINE_H diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp index 5396e47566..fbe9e8d1f6 100644 --- a/engines/tinsel/dialogs.cpp +++ b/engines/tinsel/dialogs.cpp @@ -1075,7 +1075,7 @@ static void PrimeSceneHopper() { uint32 vSize; // Open the file (it's on the CD) - CdCD(nullContext); + CdCD(Common::nullContext); if (!f.open(HOPPER_FILENAME)) error(CANNOT_FIND_FILE, HOPPER_FILENAME); @@ -1191,13 +1191,13 @@ static void HopAction() { debugC(DEBUG_BASIC, kTinselDebugAnimations, "Scene hopper chose scene %xh,%d\n", hScene, eNumber); if (FROM_LE_32(pEntry->flags) & fCall) { - SaveScene(nullContext); - NewScene(nullContext, g_pChosenScene->hScene, pEntry->eNumber, TRANS_FADE); + SaveScene(Common::nullContext); + NewScene(Common::nullContext, g_pChosenScene->hScene, pEntry->eNumber, TRANS_FADE); } else if (FROM_LE_32(pEntry->flags) & fHook) HookScene(hScene, eNumber, TRANS_FADE); else - NewScene(nullContext, hScene, eNumber, TRANS_CUT); + NewScene(Common::nullContext, hScene, eNumber, TRANS_CUT); } /**************************************************************************/ @@ -1406,13 +1406,13 @@ static void InvTinselEvent(INV_OBJECT *pinvo, TINSEL_EVENT event, PLR_EVENT be, return; g_GlitterIndex = index; - g_scheduler->createProcess(PID_TCODE, ObjectProcess, &to, sizeof(to)); + CoroScheduler.createProcess(PID_TCODE, ObjectProcess, &to, sizeof(to)); } extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, int myEscape, bool *result) { // COROUTINE CORO_BEGIN_CONTEXT; - PROCESS *pProc; + Common::PROCESS *pProc; INV_OBJECT *pInvo; OP_INIT op; CORO_END_CONTEXT(_ctx); @@ -1428,7 +1428,7 @@ extern void ObjectEvent(CORO_PARAM, int objId, TINSEL_EVENT event, bool bWait, i _ctx->op.event = event; _ctx->op.myEscape = myEscape; - g_scheduler->createProcess(PID_TCODE, ObjectProcess, &_ctx->op, sizeof(_ctx->op)); + CoroScheduler.createProcess(PID_TCODE, ObjectProcess, &_ctx->op, sizeof(_ctx->op)); if (bWait) CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result); @@ -3540,9 +3540,9 @@ extern void ConvAction(int index) { } if (g_thisConvPoly != NOPOLY) - PolygonEvent(nullContext, g_thisConvPoly, CONVERSE, 0, false, 0); + PolygonEvent(Common::nullContext, g_thisConvPoly, CONVERSE, 0, false, 0); else - ActorEvent(nullContext, g_thisConvActor, CONVERSE, false, 0); + ActorEvent(Common::nullContext, g_thisConvActor, CONVERSE, false, 0); } } @@ -5128,7 +5128,7 @@ static void InvPickup(int index) { if (TinselV2) InvPutDown(index); else - g_scheduler->createProcess(PID_TCODE, InvPdProcess, &index, sizeof(index)); + CoroScheduler.createProcess(PID_TCODE, InvPdProcess, &index, sizeof(index)); } } } diff --git a/engines/tinsel/drives.cpp b/engines/tinsel/drives.cpp index d815fd165d..5c4b939e4e 100644 --- a/engines/tinsel/drives.cpp +++ b/engines/tinsel/drives.cpp @@ -48,13 +48,13 @@ void CdCD(CORO_PARAM) { CORO_BEGIN_CODE(_ctx); while (g_bChangingCD) { - if (g_scheduler->getCurrentProcess()) { - // FIXME: CdCD gets passed a nullContext in RegisterGlobals() and + if (CoroScheduler.getCurrentProcess()) { + // FIXME: CdCD gets passed a Common::nullContext in RegisterGlobals() and // PrimeSceneHopper(), because I didn't know how to get a proper // context without converting the whole calling stack to CORO'd // functions. If these functions really get called while a CD // change is requested, this needs to be resolved. - if (coroParam == nullContext) + if (coroParam == Common::nullContext) error("CdCD needs context"); CORO_SLEEP(1); } else diff --git a/engines/tinsel/drives.h b/engines/tinsel/drives.h index 907071d2f8..9e97b92fa5 100644 --- a/engines/tinsel/drives.h +++ b/engines/tinsel/drives.h @@ -24,9 +24,9 @@ #ifndef TINSEL_DRIVES_H #define TINSEL_DRIVES_H +#include "common/coroutines.h" #include "common/stream.h" #include "tinsel/dw.h" -#include "tinsel/coroutine.h" namespace Tinsel { diff --git a/engines/tinsel/effect.cpp b/engines/tinsel/effect.cpp index 22027b0f02..f5adb63c2b 100644 --- a/engines/tinsel/effect.cpp +++ b/engines/tinsel/effect.cpp @@ -108,7 +108,7 @@ static void FettleEffectPolys(int x, int y, int index, PMOVER pActor) { epi.hEpoly = hPoly; epi.pMover = pActor; epi.index = index; - g_scheduler->createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi)); + CoroScheduler.createProcess(PID_TCODE, EffectProcess, &epi, sizeof(epi)); } } } diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp index 74454c5f2a..1aa4d34227 100644 --- a/engines/tinsel/events.cpp +++ b/engines/tinsel/events.cpp @@ -22,10 +22,10 @@ * Also provides a couple of utility functions. */ +#include "common/coroutines.h" #include "tinsel/actors.h" #include "tinsel/background.h" #include "tinsel/config.h" -#include "tinsel/coroutine.h" #include "tinsel/cursor.h" #include "tinsel/dw.h" #include "tinsel/events.h" @@ -276,7 +276,7 @@ static void WalkProcess(CORO_PARAM, const void *param) { void WalkTo(int x, int y) { WP_INIT to = { x, y }; - g_scheduler->createProcess(PID_TCODE, WalkProcess, &to, sizeof(to)); + CoroScheduler.createProcess(PID_TCODE, WalkProcess, &to, sizeof(to)); } /** @@ -295,7 +295,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P if ((actor = GetTaggedActor()) != 0) { // Event for a tagged actor if (TinselV2) - ActorEvent(nullContext, actor, uEvent, false, 0); + ActorEvent(Common::nullContext, actor, uEvent, false, 0); else ActorEvent(actor, uEvent, be); } else if ((hPoly = GetTaggedPoly()) != NOPOLY) { @@ -303,7 +303,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P if (!TinselV2) RunPolyTinselCode(hPoly, uEvent, be, false); else if (uEvent != PROV_WALKTO) - PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0); + PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0); } else { GetCursorXY(&aniX, &aniY, true); @@ -312,7 +312,7 @@ static void ProcessUserEvent(TINSEL_EVENT uEvent, const Common::Point &coOrds, P if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY || (!TinselV2 && ((hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY))) { if (TinselV2 && (uEvent != PROV_WALKTO)) - PolygonEvent(nullContext, hPoly, uEvent, 0, false, 0); + PolygonEvent(Common::nullContext, hPoly, uEvent, 0, false, 0); else if (!TinselV2) RunPolyTinselCode(hPoly, uEvent, be, false); } else if ((uEvent == PROV_WALKTO) || (uEvent == WALKTO)) { @@ -604,7 +604,7 @@ void PolyTinselProcess(CORO_PARAM, const void *param) { void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bool bWait, int myEscape, bool *result) { CORO_BEGIN_CONTEXT; - PPROCESS pProc; + Common::PPROCESS pProc; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); @@ -623,7 +623,7 @@ void PolygonEvent(CORO_PARAM, HPOLYGON hPoly, TINSEL_EVENT tEvent, int actor, bo NULL, // No Object myEscape); if (to.pic != NULL) { - _ctx->pProc = g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + _ctx->pProc = CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); AttachInterpret(to.pic, _ctx->pProc); if (bWait) @@ -640,14 +640,14 @@ void RunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, PLR_EVENT be, bool tc PTP_INIT to = { hPoly, event, be, tc, 0, NULL }; assert(!TinselV2); - g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } void effRunPolyTinselCode(HPOLYGON hPoly, TINSEL_EVENT event, int actor) { PTP_INIT to = { hPoly, event, PLR_NOEVENT, false, actor, NULL }; assert(!TinselV2); - g_scheduler->createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); + CoroScheduler.createProcess(PID_TCODE, PolyTinselProcess, &to, sizeof(to)); } /** diff --git a/engines/tinsel/events.h b/engines/tinsel/events.h index f2b4d7f663..cdf5ae2ae4 100644 --- a/engines/tinsel/events.h +++ b/engines/tinsel/events.h @@ -24,9 +24,9 @@ #ifndef TINSEL_EVENTS_H #define TINSEL_EVENTS_H -#include "tinsel/dw.h" -#include "tinsel/coroutine.h" +#include "common/coroutines.h" #include "common/rect.h" +#include "tinsel/dw.h" namespace Tinsel { diff --git a/engines/tinsel/faders.cpp b/engines/tinsel/faders.cpp index 86d117af81..c1574ff963 100644 --- a/engines/tinsel/faders.cpp +++ b/engines/tinsel/faders.cpp @@ -145,7 +145,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { if (TinselV2) { // The is only ever one cuncurrent fade // But this could be a fade out and the fade in is still going! - g_scheduler->killMatchingProcess(PID_FADER); + CoroScheduler.killMatchingProcess(PID_FADER); NoFadingPalettes(); } @@ -176,7 +176,7 @@ static void Fader(const long multTable[], SCNHANDLE noFadeTable[]) { fade.pPalQ = pPal; // create a fader process for this palette - g_scheduler->createProcess(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); + CoroScheduler.createProcess(PID_FADER, FadeProcess, (void *)&fade, sizeof(FADE)); } } } diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index e31b2141f5..c3089db990 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -361,7 +361,7 @@ byte *LockMem(SCNHANDLE offset) { if (TinselV2) { SetCD(pH->flags2 & fAllCds); - CdCD(nullContext); + CdCD(Common::nullContext); } LoadFile(pH); } diff --git a/engines/tinsel/module.mk b/engines/tinsel/module.mk index 2ab94b830a..3485bac74b 100644 --- a/engines/tinsel/module.mk +++ b/engines/tinsel/module.mk @@ -9,7 +9,6 @@ MODULE_OBJS := \ bmv.o \ cliprect.o \ config.o \ - coroutine.o \ cursor.o \ debugger.o \ detection.o \ diff --git a/engines/tinsel/move.cpp b/engines/tinsel/move.cpp index bb49e59fe7..275b6006f5 100644 --- a/engines/tinsel/move.cpp +++ b/engines/tinsel/move.cpp @@ -1299,14 +1299,14 @@ static void SetOffWithinNodePath(PMOVER pMover, HPOLYGON StartPath, HPOLYGON Des */ void SSetActorDest(PMOVER pActor) { if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { - Stand(nullContext, pActor->actorID, pActor->objX, pActor->objY, 0); + Stand(Common::nullContext, pActor->actorID, pActor->objX, pActor->objY, 0); if (pActor->UtargetX != -1 && pActor->UtargetY != -1) { SetActorDest(pActor, pActor->UtargetX, pActor->UtargetY, pActor->bIgPath, 0); } } else { - Stand(nullContext, pActor->actorID, pActor->objX, pActor->objY, 0); + Stand(Common::nullContext, pActor->actorID, pActor->objX, pActor->objY, 0); } } diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index 145a6a8e5d..60f04b47fd 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -243,13 +243,13 @@ static INT_CONTEXT *AllocateInterpretContext(GSORT gsort) { for (i = 0, pic = g_icList; i < NUM_INTERPRET; i++, pic++) { if (pic->GSort == GS_NONE) { - pic->pProc = g_scheduler->getCurrentProcess(); + pic->pProc = CoroScheduler.getCurrentProcess(); pic->GSort = gsort; return pic; } #ifdef DEBUG else { - if (pic->pProc == g_scheduler->getCurrentProcess()) + if (pic->pProc == CoroScheduler.getCurrentProcess()) error("Found unreleased interpret context"); } #endif @@ -277,7 +277,7 @@ static void FreeWaitCheck(PINT_CONTEXT pic, bool bVoluntary) { if ((g_icList + i)->waitNumber1 == pic->waitNumber2) { (g_icList + i)->waitNumber1 = 0; (g_icList + i)->resumeCode = bVoluntary ? RES_FINISHED : RES_CUTSHORT; - g_scheduler->reschedule((g_icList + i)->pProc); + CoroScheduler.reschedule((g_icList + i)->pProc); break; } } @@ -301,7 +301,7 @@ static void FreeInterpretContextPi(INT_CONTEXT *pic) { * Ensures that interpret contexts don't get lost when an Interpret() * call doesn't complete. */ -void FreeInterpretContextPr(PROCESS *pProc) { +void FreeInterpretContextPr(Common::PROCESS *pProc) { INT_CONTEXT *pic; int i; @@ -393,7 +393,7 @@ INT_CONTEXT *RestoreInterpretContext(INT_CONTEXT *ric) { ic = AllocateInterpretContext(GS_NONE); // Sort will soon be overridden memcpy(ic, ric, sizeof(INT_CONTEXT)); - ic->pProc = g_scheduler->getCurrentProcess(); + ic->pProc = CoroScheduler.getCurrentProcess(); ic->resumeState = RES_1; LockCode(ic); @@ -422,7 +422,7 @@ void RegisterGlobals(int num) { if (g_icList == NULL) { error("Cannot allocate memory for interpret contexts"); } - g_scheduler->setResourceCallback(FreeInterpretContextPr); + CoroScheduler.setResourceCallback(FreeInterpretContextPr); } else { // Check size is still the same assert(g_numGlobals == num); @@ -433,7 +433,7 @@ void RegisterGlobals(int num) { if (TinselV2) { // read initial values - CdCD(nullContext); + CdCD(Common::nullContext); Common::File f; if (!f.open(GLOBALS_FILENAME)) @@ -839,7 +839,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { * Associates an interpret context with the * process that will run it. */ -void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc) { +void AttachInterpret(INT_CONTEXT *pic, Common::PROCESS *pProc) { // Attach the process which is using this context pic->pProc = pProc; } @@ -869,9 +869,9 @@ static uint32 UniqueWaitNumber() { /** * WaitInterpret */ -void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result) { +void WaitInterpret(CORO_PARAM, Common::PPROCESS pWaitProc, bool *result) { int i; - PPROCESS currentProcess = g_scheduler->getCurrentProcess(); + Common::PPROCESS currentProcess = CoroScheduler.getCurrentProcess(); assert(currentProcess); assert(currentProcess != pWaitProc); if (result) *result = false; diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h index 5d16dae432..4980fc6ed9 100644 --- a/engines/tinsel/pcode.h +++ b/engines/tinsel/pcode.h @@ -25,7 +25,7 @@ #define TINSEL_PCODE_H #include "tinsel/events.h" // for TINSEL_EVENT -#include "tinsel/sched.h" // for PROCESS +#include "tinsel/sched.h" // for Common::PROCESS namespace Common { class Serializer; @@ -56,7 +56,7 @@ struct WorkaroundEntry; struct INT_CONTEXT { // Elements for interpret context management - PROCESS *pProc; ///< processes owning this context + Common::PROCESS *pProc; ///< processes owning this context GSORT GSort; ///< sort of this context // Previously parameters to Interpret() @@ -114,12 +114,12 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo); void RegisterGlobals(int num); void FreeGlobals(); -void AttachInterpret(INT_CONTEXT *pic, PROCESS *pProc); +void AttachInterpret(INT_CONTEXT *pic, Common::PROCESS *pProc); -void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result); +void WaitInterpret(CORO_PARAM, Common::PPROCESS pWaitProc, bool *result); -#define NUM_INTERPRET (NUM_PROCESS - 20) -#define MAX_INTERPRET (MAX_PROCESSES - 20) +#define NUM_INTERPRET (CORO_NUM_PROCESS - 20) +#define MAX_INTERPRET (CORO_MAX_PROCESSES - 20) /*----------------------------------------------------------------------*\ |* Library Procedure and Function codes parameter enums *| diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp index 9a9e6ab00f..b821c5dee2 100644 --- a/engines/tinsel/pdisplay.cpp +++ b/engines/tinsel/pdisplay.cpp @@ -23,9 +23,9 @@ * PointProcess() */ +#include "common/coroutines.h" #include "tinsel/actors.h" #include "tinsel/background.h" -#include "tinsel/coroutine.h" #include "tinsel/cursor.h" #include "tinsel/dw.h" #include "tinsel/events.h" @@ -265,7 +265,7 @@ void DisablePointing() { if (hPoly != NOPOLY && PolyType(hPoly) == TAG && PolyIsPointedTo(hPoly)) { SetPolyPointedTo(hPoly, false); SetPolyTagWanted(hPoly, false, false, 0); - PolygonEvent(nullContext, hPoly, UNPOINT, 0, false, 0); + PolygonEvent(Common::nullContext, hPoly, UNPOINT, 0, false, 0); } } @@ -275,7 +275,7 @@ void DisablePointing() { SetActorPointedTo(i, false); SetActorTagWanted(i, false, false, 0); - ActorEvent(nullContext, i, UNPOINT, false, 0); + ActorEvent(Common::nullContext, i, UNPOINT, false, 0); } } } diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp index 40729d9f3a..9e0baa749e 100644 --- a/engines/tinsel/play.cpp +++ b/engines/tinsel/play.cpp @@ -21,9 +21,9 @@ * Plays films within a scene, takes into account the actor in each 'column'. | */ +#include "common/coroutines.h" #include "tinsel/actors.h" #include "tinsel/background.h" -#include "tinsel/coroutine.h" #include "tinsel/dw.h" #include "tinsel/film.h" #include "tinsel/handle.h" @@ -395,7 +395,7 @@ static void SoundReelWaitCheck() { if (--g_soundReelWait == 0) { for (int i = 0; i < MAX_SOUNDREELS; i++) { if (g_soundReels[i].hFilm) { - g_scheduler->createProcess(PID_REEL, ResSoundReel, &i, sizeof(i)); + CoroScheduler.createProcess(PID_REEL, ResSoundReel, &i, sizeof(i)); } } } @@ -1001,7 +1001,7 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay NewestFilm(hFilm, &pFilm->reels[i]); ppi.column = i; - g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(PPINIT)); + CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(PPINIT)); } if (TinselV2) { @@ -1011,7 +1011,7 @@ void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay CORO_GIVE_WAY; if (myescEvent && myescEvent != GetEscEvents()) - g_scheduler->rescheduleAll(); + CoroScheduler.rescheduleAll(); } CORO_END_CODE; @@ -1063,7 +1063,7 @@ void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool spla NewestFilm(hFilm, &pFilm->reels[i]); _ctx->ppi.column = i; - g_scheduler->createProcess(PID_REEL, PlayProcess, &_ctx->ppi, sizeof(PPINIT)); + CoroScheduler.createProcess(PID_REEL, PlayProcess, &_ctx->ppi, sizeof(PPINIT)); } if (TinselV2) { @@ -1078,7 +1078,7 @@ void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool spla // Wait until film changes or loop count increases while (GetActorPresFilm(_ctx->i) == hFilm && GetLoopCount(_ctx->i) == _ctx->loopCount) { if (myescEvent && myescEvent != GetEscEvents()) { - g_scheduler->rescheduleAll(); + CoroScheduler.rescheduleAll(); break; } @@ -1126,7 +1126,7 @@ void RestoreActorReels(SCNHANDLE hFilm, short reelnum, short z, int x, int y) { NewestFilm(hFilm, &pfilm->reels[reelnum]); // Start display process for the reel - g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi)); + CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi)); } /** @@ -1160,7 +1160,7 @@ void RestoreActorReels(SCNHANDLE hFilm, int actor, int x, int y) { NewestFilm(hFilm, &pFilm->reels[i]); // Start display process for the reel - g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi)); + CoroScheduler.createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi)); g_soundReelWait++; } diff --git a/engines/tinsel/play.h b/engines/tinsel/play.h index 041b7096a8..fffa8a9329 100644 --- a/engines/tinsel/play.h +++ b/engines/tinsel/play.h @@ -24,7 +24,7 @@ #ifndef TINSEL_PLAY_H // prevent multiple includes #define TINSEL_PLAY_H -#include "tinsel/coroutine.h" +#include "common/coroutines.h" #include "tinsel/dw.h" #include "tinsel/multiobj.h" diff --git a/engines/tinsel/polygons.cpp b/engines/tinsel/polygons.cpp index 6fc1c65ec5..d8c1cef0b6 100644 --- a/engines/tinsel/polygons.cpp +++ b/engines/tinsel/polygons.cpp @@ -1469,7 +1469,7 @@ static void SetExTags(SCNHANDLE ph) { pts = &TagStates[SceneTags[i].offset]; for (j = 0; j < SceneTags[i].nooftags; j++, pts++) { if (!pts->enabled) - DisableTag(nullContext, pts->tid); + DisableTag(Common::nullContext, pts->tid); } return; } @@ -1873,7 +1873,7 @@ void InitPolygons(SCNHANDLE ph, int numPoly, bool bRestart) { } else { for (int i = numPoly - 1; i >= 0; i--) { if (Polys[i]->polyType == TAG) { - PolygonEvent(nullContext, i, STARTUP, 0, false, 0); + PolygonEvent(Common::nullContext, i, STARTUP, 0, false, 0); } } } diff --git a/engines/tinsel/rince.cpp b/engines/tinsel/rince.cpp index bb0aeabd2f..ba8f47f9cf 100644 --- a/engines/tinsel/rince.cpp +++ b/engines/tinsel/rince.cpp @@ -202,8 +202,8 @@ void KillMover(PMOVER pMover) { pMover->bActive = false; MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), pMover->actorObj); pMover->actorObj = NULL; - assert(g_scheduler->getCurrentProcess() != pMover->pProc); - g_scheduler->killProcess(pMover->pProc); + assert(CoroScheduler.getCurrentProcess() != pMover->pProc); + CoroScheduler.killProcess(pMover->pProc); } } @@ -856,10 +856,10 @@ void MoverProcessCreate(int X, int Y, int id, PMOVER pMover) { iStruct.Y = Y; iStruct.pMover = pMover; - g_scheduler->createProcess(PID_MOVER, T2MoverProcess, &iStruct, sizeof(MAINIT)); + CoroScheduler.createProcess(PID_MOVER, T2MoverProcess, &iStruct, sizeof(MAINIT)); } else { MoverProcessHelper(X, Y, id, pMover); - pMover->pProc = g_scheduler->createProcess(PID_MOVER, T1MoverProcess, &pMover, sizeof(PMOVER)); + pMover->pProc = CoroScheduler.createProcess(PID_MOVER, T1MoverProcess, &pMover, sizeof(PMOVER)); } } diff --git a/engines/tinsel/rince.h b/engines/tinsel/rince.h index 93fd191172..623f3ee137 100644 --- a/engines/tinsel/rince.h +++ b/engines/tinsel/rince.h @@ -31,7 +31,6 @@ namespace Tinsel { struct OBJECT; -struct PROCESS; enum NPS {NOT_IN, GOING_UP, GOING_DOWN, LEAVING, ENTERING}; @@ -110,7 +109,7 @@ struct MOVER { /* NOTE: If effect polys can overlap, this needs improving */ bool bInEffect; - PROCESS *pProc; + Common::PROCESS *pProc; // Discworld 2 specific fields int32 zOverride; diff --git a/engines/tinsel/savescn.cpp b/engines/tinsel/savescn.cpp index 1b06e3929c..0c0cc5c81e 100644 --- a/engines/tinsel/savescn.cpp +++ b/engines/tinsel/savescn.cpp @@ -190,7 +190,7 @@ void sortActors(SAVED_DATA *sd) { RestoreAuxScales(sd->SavedMoverInfo); for (int i = 0; i < MAX_MOVERS; i++) { if (sd->SavedMoverInfo[i].bActive) - Stand(nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX, + Stand(Common::nullContext, sd->SavedMoverInfo[i].actorID, sd->SavedMoverInfo[i].objX, sd->SavedMoverInfo[i].objY, sd->SavedMoverInfo[i].hLastfilm); } } @@ -245,7 +245,7 @@ static void SortMAProcess(CORO_PARAM, const void *) { void ResumeInterprets() { // Master script only affected on restore game, not restore scene if (!TinselV2 && (g_rsd == &g_sgData)) { - g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1); + CoroScheduler.killMatchingProcess(PID_MASTER_SCR, -1); FreeMasterInterpretContext(); } @@ -314,7 +314,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) { // Master script only affected on restore game, not restore scene if (sd == &g_sgData) { - g_scheduler->killMatchingProcess(PID_MASTER_SCR); + CoroScheduler.killMatchingProcess(PID_MASTER_SCR); KillGlobalProcesses(); FreeMasterInterpretContext(); } @@ -340,7 +340,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) { SetDoFadeIn(!g_bNoFade); g_bNoFade = false; - StartupBackground(nullContext, sd->SavedBgroundHandle); + StartupBackground(Common::nullContext, sd->SavedBgroundHandle); if (TinselV2) { Offset(EX_USEXY, sd->SavedLoffset, sd->SavedToffset); @@ -354,7 +354,7 @@ static int DoRestoreSceneFrame(SAVED_DATA *sd, int n) { if (TinselV2) { // create process to sort out the moving actors - g_scheduler->createProcess(PID_MOVER, SortMAProcess, NULL, 0); + CoroScheduler.createProcess(PID_MOVER, SortMAProcess, NULL, 0); g_bNotDoneYet = true; RestoreActorZ(sd->savedActorZ); diff --git a/engines/tinsel/scene.cpp b/engines/tinsel/scene.cpp index f635ce13a3..79bb30f7a3 100644 --- a/engines/tinsel/scene.cpp +++ b/engines/tinsel/scene.cpp @@ -193,7 +193,7 @@ void SendSceneTinselProcess(TINSEL_EVENT event) { init.event = event; init.hTinselCode = ss->hSceneScript; - g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); + CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } } } @@ -271,7 +271,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { init.event = STARTUP; init.hTinselCode = es->hScript; - g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); + CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } break; } @@ -291,7 +291,7 @@ static void LoadScene(SCNHANDLE scene, int entry) { init.event = STARTUP; init.hTinselCode = ss->hSceneScript; - g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); + CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } } @@ -344,7 +344,7 @@ void EndScene() { KillAllObjects(); // kill all destructable process - g_scheduler->killMatchingProcess(PID_DESTROY, PID_DESTROY); + CoroScheduler.killMatchingProcess(PID_DESTROY, PID_DESTROY); } /** @@ -405,16 +405,16 @@ void PrimeScene() { if (!TinselV2) EnableTags(); // Next scene with tags enabled - g_scheduler->createProcess(PID_SCROLL, ScrollProcess, NULL, 0); - g_scheduler->createProcess(PID_SCROLL, EffectPolyProcess, NULL, 0); + CoroScheduler.createProcess(PID_SCROLL, ScrollProcess, NULL, 0); + CoroScheduler.createProcess(PID_SCROLL, EffectPolyProcess, NULL, 0); #ifdef DEBUG if (g_ShowPosition) - g_scheduler->createProcess(PID_POSITION, CursorPositionProcess, NULL, 0); + CoroScheduler.createProcess(PID_POSITION, CursorPositionProcess, NULL, 0); #endif - g_scheduler->createProcess(PID_TAG, TagProcess, NULL, 0); - g_scheduler->createProcess(PID_TAG, PointProcess, NULL, 0); + CoroScheduler.createProcess(PID_TAG, TagProcess, NULL, 0); + CoroScheduler.createProcess(PID_TAG, PointProcess, NULL, 0); // init the current background PrimeBackground(); @@ -471,7 +471,7 @@ void DoHailScene(SCNHANDLE scene) { init.event = NOEVENT; init.hTinselCode = ss->hSceneScript; - g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); + CoroScheduler.createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } } diff --git a/engines/tinsel/sched.cpp b/engines/tinsel/sched.cpp index 343758d924..4bf356ba36 100644 --- a/engines/tinsel/sched.cpp +++ b/engines/tinsel/sched.cpp @@ -32,8 +32,6 @@ namespace Tinsel { -Scheduler *g_scheduler = 0; - #include "common/pack-start.h" // START STRUCT PACKING struct PROCESS_STRUC { @@ -53,471 +51,6 @@ static SCNHANDLE g_hSceneProcess; static uint32 g_numGlobalProcess; static PROCESS_STRUC *g_pGlobalProcess; -//--------------------- FUNCTIONS ------------------------ - -Scheduler::Scheduler() { - processList = 0; - pFreeProcesses = 0; - pCurrent = 0; - -#ifdef DEBUG - // diagnostic process counters - numProcs = 0; - maxProcs = 0; -#endif - - pRCfunction = 0; - - active = new PROCESS; - active->pPrevious = NULL; - active->pNext = NULL; - - g_scheduler = this; // FIXME HACK -} - -Scheduler::~Scheduler() { - // Kill all running processes (i.e. free memory allocated for their state). - PROCESS *pProc = active->pNext; - while (pProc != NULL) { - delete pProc->state; - pProc->state = 0; - pProc = pProc->pNext; - } - - free(processList); - processList = NULL; - - delete active; - active = 0; -} - -/** - * Kills all processes and places them on the free list. - */ -void Scheduler::reset() { - -#ifdef DEBUG - // clear number of process in use - numProcs = 0; -#endif - - if (processList == NULL) { - // first time - allocate memory for process list - processList = (PROCESS *)calloc(MAX_PROCESSES, sizeof(PROCESS)); - - // make sure memory allocated - if (processList == NULL) { - error("Cannot allocate memory for process data"); - } - - // fill with garbage - memset(processList, 'S', MAX_PROCESSES * sizeof(PROCESS)); - } - - // Kill all running processes (i.e. free memory allocated for their state). - PROCESS *pProc = active->pNext; - while (pProc != NULL) { - delete pProc->state; - pProc->state = 0; - pProc = pProc->pNext; - } - - // no active processes - pCurrent = active->pNext = NULL; - - // place first process on free list - pFreeProcesses = processList; - - // link all other processes after first - for (int i = 1; i <= NUM_PROCESS; i++) { - processList[i - 1].pNext = (i == NUM_PROCESS) ? NULL : processList + i; - processList[i - 1].pPrevious = (i == 1) ? active : processList + (i - 2); - } -} - - -#ifdef DEBUG -/** - * Shows the maximum number of process used at once. - */ -void Scheduler::printStats() { - debug("%i process of %i used", maxProcs, NUM_PROCESS); -} -#endif - -#ifdef DEBUG -/** - * Checks both the active and free process list to insure all the links are valid, - * and that no processes have been lost - */ -void Scheduler::CheckStack() { - Common::List<PROCESS *> pList; - - // Check both the active and free process lists - for (int i = 0; i < 2; ++i) { - PROCESS *p = (i == 0) ? active : pFreeProcesses; - - if (p != NULL) { - // Make sure the linkages are correct - while (p->pNext != NULL) { - assert(p->pNext->pPrevious == p); - pList.push_back(p); - p = p->pNext; - } - pList.push_back(p); - } - } - - // Make sure all processes are accounted for - for (int idx = 0; idx < NUM_PROCESS; idx++) { - bool found = false; - for (Common::List<PROCESS *>::iterator i = pList.begin(); i != pList.end(); ++i) { - PROCESS *pTemp = *i; - if (*i == &processList[idx]) { - found = true; - break; - } - } - - assert(found); - } -} -#endif - -/** - * Give all active processes a chance to run - */ -void Scheduler::schedule() { - // start dispatching active process list - PROCESS *pNext; - PROCESS *pProc = active->pNext; - while (pProc != NULL) { - pNext = pProc->pNext; - - if (--pProc->sleepTime <= 0) { - // process is ready for dispatch, activate it - pCurrent = pProc; - pProc->coroAddr(pProc->state, pProc->param); - - if (!pProc->state || pProc->state->_sleep <= 0) { - // Coroutine finished - pCurrent = pCurrent->pPrevious; - killProcess(pProc); - } else { - pProc->sleepTime = pProc->state->_sleep; - } - - // pCurrent may have been changed - pNext = pCurrent->pNext; - pCurrent = NULL; - } - - pProc = pNext; - } -} - -/** - * Reschedules all the processes to run again this query - */ -void Scheduler::rescheduleAll() { - assert(pCurrent); - - // Unlink current process - pCurrent->pPrevious->pNext = pCurrent->pNext; - if (pCurrent->pNext) - pCurrent->pNext->pPrevious = pCurrent->pPrevious; - - // Add process to the start of the active list - pCurrent->pNext = active->pNext; - active->pNext->pPrevious = pCurrent; - active->pNext = pCurrent; - pCurrent->pPrevious = active; -} - -/** - * If the specified process has already run on this tick, make it run - * again on the current tick. - */ -void Scheduler::reschedule(PPROCESS pReSchedProc) { - // If not currently processing the schedule list, then no action is needed - if (!pCurrent) - return; - - if (!pReSchedProc) - pReSchedProc = pCurrent; - - PPROCESS pEnd; - - // Find the last process in the list. - // But if the target process is down the list from here, do nothing - for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext) { - if (pEnd->pNext == pReSchedProc) - return; - } - - assert(pEnd->pNext == NULL); - - // Could be in the middle of a KillProc()! - // Dying process was last and this process was penultimate - if (pReSchedProc->pNext == NULL) - return; - - // If we're moving the current process, move it back by one, so that the next - // schedule() iteration moves to the now next one - if (pCurrent == pReSchedProc) - pCurrent = pCurrent->pPrevious; - - // Unlink the process, and add it at the end - pReSchedProc->pPrevious->pNext = pReSchedProc->pNext; - pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious; - pEnd->pNext = pReSchedProc; - pReSchedProc->pPrevious = pEnd; - pReSchedProc->pNext = NULL; -} - -/** - * Moves the specified process to the end of the dispatch queue - * allowing it to run again within the current game cycle. - * @param pGiveProc Which process - */ -void Scheduler::giveWay(PPROCESS pReSchedProc) { - // If not currently processing the schedule list, then no action is needed - if (!pCurrent) - return; - - if (!pReSchedProc) - pReSchedProc = pCurrent; - - // If the process is already at the end of the queue, nothing has to be done - if (!pReSchedProc->pNext) - return; - - PPROCESS pEnd; - - // Find the last process in the list. - for (pEnd = pCurrent; pEnd->pNext != NULL; pEnd = pEnd->pNext) - ; - assert(pEnd->pNext == NULL); - - - // If we're moving the current process, move it back by one, so that the next - // schedule() iteration moves to the now next one - if (pCurrent == pReSchedProc) - pCurrent = pCurrent->pPrevious; - - // Unlink the process, and add it at the end - pReSchedProc->pPrevious->pNext = pReSchedProc->pNext; - pReSchedProc->pNext->pPrevious = pReSchedProc->pPrevious; - pEnd->pNext = pReSchedProc; - pReSchedProc->pPrevious = pEnd; - pReSchedProc->pNext = NULL; -} - -/** - * Creates a new process. - * - * @param pid process identifier - * @param CORO_ADDR coroutine start address - * @param pParam process specific info - * @param sizeParam size of process specific info - */ -PROCESS *Scheduler::createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam) { - PROCESS *pProc; - - // get a free process - pProc = pFreeProcesses; - - // trap no free process - assert(pProc != NULL); // Out of processes - -#ifdef DEBUG - // one more process in use - if (++numProcs > maxProcs) - maxProcs = numProcs; -#endif - - // get link to next free process - pFreeProcesses = pProc->pNext; - if (pFreeProcesses) - pFreeProcesses->pPrevious = NULL; - - if (pCurrent != NULL) { - // place new process before the next active process - pProc->pNext = pCurrent->pNext; - if (pProc->pNext) - pProc->pNext->pPrevious = pProc; - - // make this new process the next active process - pCurrent->pNext = pProc; - pProc->pPrevious = pCurrent; - - } else { // no active processes, place process at head of list - pProc->pNext = active->pNext; - pProc->pPrevious = active; - - if (pProc->pNext) - pProc->pNext->pPrevious = pProc; - active->pNext = pProc; - - } - - // set coroutine entry point - pProc->coroAddr = coroAddr; - - // clear coroutine state - pProc->state = 0; - - // wake process up as soon as possible - pProc->sleepTime = 1; - - // set new process id - pProc->pid = pid; - - // set new process specific info - if (sizeParam) { - assert(sizeParam > 0 && sizeParam <= PARAM_SIZE); - - // set new process specific info - memcpy(pProc->param, pParam, sizeParam); - } - - // return created process - return pProc; -} - -/** - * Kills the specified process. - * - * @param pKillProc which process to kill - */ -void Scheduler::killProcess(PROCESS *pKillProc) { - // make sure a valid process pointer - assert(pKillProc >= processList && pKillProc <= processList + NUM_PROCESS - 1); - - // can not kill the current process using killProcess ! - assert(pCurrent != pKillProc); - -#ifdef DEBUG - // one less process in use - --numProcs; - assert(numProcs >= 0); -#endif - - // Free process' resources - if (pRCfunction != NULL) - (pRCfunction)(pKillProc); - - delete pKillProc->state; - pKillProc->state = 0; - - // Take the process out of the active chain list - pKillProc->pPrevious->pNext = pKillProc->pNext; - if (pKillProc->pNext) - pKillProc->pNext->pPrevious = pKillProc->pPrevious; - - // link first free process after pProc - pKillProc->pNext = pFreeProcesses; - if (pFreeProcesses) - pKillProc->pNext->pPrevious = pKillProc; - pKillProc->pPrevious = NULL; - - // make pKillProc the first free process - pFreeProcesses = pKillProc; -} - - - -/** - * Returns a pointer to the currently running process. - */ -PROCESS *Scheduler::getCurrentProcess() { - return pCurrent; -} - -/** - * Returns the process identifier of the specified process. - * - * @param pProc which process - */ -int Scheduler::getCurrentPID() const { - PROCESS *pProc = pCurrent; - - // make sure a valid process pointer - assert(pProc >= processList && pProc <= processList + NUM_PROCESS - 1); - - // return processes PID - return pProc->pid; -} - -/** - * Kills any process matching the specified PID. The current - * process cannot be killed. - * - * @param pidKill process identifier of process to kill - * @param pidMask mask to apply to process identifiers before comparison - * @return The number of processes killed is returned. - */ -int Scheduler::killMatchingProcess(int pidKill, int pidMask) { - int numKilled = 0; - PROCESS *pProc, *pPrev; // process list pointers - - for (pProc = active->pNext, pPrev = active; pProc != NULL; pPrev = pProc, pProc = pProc->pNext) { - if ((pProc->pid & pidMask) == pidKill) { - // found a matching process - - // dont kill the current process - if (pProc != pCurrent) { - // kill this process - numKilled++; - - // Free the process' resources - if (pRCfunction != NULL) - (pRCfunction)(pProc); - - delete pProc->state; - pProc->state = 0; - - // make prev point to next to unlink pProc - pPrev->pNext = pProc->pNext; - if (pProc->pNext) - pPrev->pNext->pPrevious = pPrev; - - // link first free process after pProc - pProc->pNext = pFreeProcesses; - pProc->pPrevious = NULL; - pFreeProcesses->pPrevious = pProc; - - // make pProc the first free process - pFreeProcesses = pProc; - - // set to a process on the active list - pProc = pPrev; - } - } - } - -#ifdef DEBUG - // adjust process in use - numProcs -= numKilled; - assert(numProcs >= 0); -#endif - - // return number of processes killed - return numKilled; -} - -/** - * Set pointer to a function to be called by killProcess(). - * - * May be called by a resource allocator, the function supplied is - * called by killProcess() to allow the resource allocator to free - * resources allocated to the dying process. - * - * @param pFunc Function to be called by killProcess() - */ -void Scheduler::setResourceCallback(VFPTRPP pFunc) { - pRCfunction = pFunc; -} /**************************************************************************\ |*********** Stuff to do with scene and global processes ************| @@ -537,7 +70,7 @@ static void RestoredProcessProcess(CORO_PARAM, const void *param) { _ctx->pic = *(const PINT_CONTEXT *)param; _ctx->pic = RestoreInterpretContext(_ctx->pic); - AttachInterpret(_ctx->pic, g_scheduler->getCurrentProcess()); + AttachInterpret(_ctx->pic, CoroScheduler.getCurrentProcess()); CORO_INVOKE_1(Interpret, _ctx->pic); @@ -577,7 +110,7 @@ void RestoreSceneProcess(INT_CONTEXT *pic) { pStruc = (PROCESS_STRUC *)LockMem(g_hSceneProcess); for (i = 0; i < g_numSceneProcess; i++) { if (FROM_LE_32(pStruc[i].hProcessCode) == pic->hCode) { - g_scheduler->createProcess(PID_PROCESS + i, RestoredProcessProcess, + CoroScheduler.createProcess(PID_PROCESS + i, RestoredProcessProcess, &pic, sizeof(pic)); break; } @@ -596,7 +129,7 @@ void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait CORO_BEGIN_CONTEXT; PROCESS_STRUC *pStruc; - PPROCESS pProc; + Common::PPROCESS pProc; PINT_CONTEXT pic; CORO_END_CONTEXT(_ctx); @@ -617,7 +150,7 @@ void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait if (_ctx->pic == NULL) return; - _ctx->pProc = g_scheduler->createProcess(PID_PROCESS + i, ProcessTinselProcess, + _ctx->pProc = CoroScheduler.createProcess(PID_PROCESS + i, ProcessTinselProcess, &_ctx->pic, sizeof(_ctx->pic)); AttachInterpret(_ctx->pic, _ctx->pProc); break; @@ -644,7 +177,7 @@ void KillSceneProcess(uint32 procID) { pStruc = (PROCESS_STRUC *) LockMem(g_hSceneProcess); for (i = 0; i < g_numSceneProcess; i++) { if (FROM_LE_32(pStruc[i].processId) == procID) { - g_scheduler->killMatchingProcess(PID_PROCESS + i, -1); + CoroScheduler.killMatchingProcess(PID_PROCESS + i, -1); break; } } @@ -671,7 +204,7 @@ void RestoreGlobalProcess(INT_CONTEXT *pic) { for (i = 0; i < g_numGlobalProcess; i++) { if (g_pGlobalProcess[i].hProcessCode == pic->hCode) { - g_scheduler->createProcess(PID_GPROCESS + i, RestoredProcessProcess, + CoroScheduler.createProcess(PID_GPROCESS + i, RestoredProcessProcess, &pic, sizeof(pic)); break; } @@ -686,7 +219,7 @@ void RestoreGlobalProcess(INT_CONTEXT *pic) { void KillGlobalProcesses() { for (uint32 i = 0; i < g_numGlobalProcess; ++i) { - g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1); + CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1); } } @@ -696,7 +229,7 @@ void KillGlobalProcesses() { bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape) { CORO_BEGIN_CONTEXT; PINT_CONTEXT pic; - PPROCESS pProc; + Common::PPROCESS pProc; CORO_END_CONTEXT(_ctx); bool result = false; @@ -720,7 +253,7 @@ bool GlobalProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWai if (_ctx->pic != NULL) { - _ctx->pProc = g_scheduler->createProcess(PID_GPROCESS + i, ProcessTinselProcess, + _ctx->pProc = CoroScheduler.createProcess(PID_GPROCESS + i, ProcessTinselProcess, &_ctx->pic, sizeof(_ctx->pic)); AttachInterpret(_ctx->pic, _ctx->pProc); } @@ -745,7 +278,7 @@ void xKillGlobalProcess(uint32 procID) { for (i = 0; i < g_numGlobalProcess; ++i) { if (g_pGlobalProcess[i].processId == procID) { - g_scheduler->killMatchingProcess(PID_GPROCESS + i, -1); + CoroScheduler.killMatchingProcess(PID_GPROCESS + i, -1); break; } } diff --git a/engines/tinsel/sched.h b/engines/tinsel/sched.h index a1eafcdc47..3e791cecd8 100644 --- a/engines/tinsel/sched.h +++ b/engines/tinsel/sched.h @@ -24,105 +24,16 @@ #ifndef TINSEL_SCHED_H // prevent multiple includes #define TINSEL_SCHED_H +#include "common/coroutines.h" #include "tinsel/dw.h" // new data types -#include "tinsel/coroutine.h" #include "tinsel/events.h" +#include "tinsel/pcode.h" #include "tinsel/tinsel.h" namespace Tinsel { -// the size of process specific info -#define PARAM_SIZE 32 - -// the maximum number of processes -#define NUM_PROCESS (TinselV2 ? 70 : 64) -#define MAX_PROCESSES 70 - -typedef void (*CORO_ADDR)(CoroContext &, const void *); - -/** process structure */ -struct PROCESS { - PROCESS *pNext; ///< pointer to next process in active or free list - PROCESS *pPrevious; ///< pointer to previous process in active or free list - - CoroContext state; ///< the state of the coroutine - CORO_ADDR coroAddr; ///< the entry point of the coroutine - - int sleepTime; ///< number of scheduler cycles to sleep - int pid; ///< process ID - char param[PARAM_SIZE]; ///< process specific info -}; -typedef PROCESS *PPROCESS; - struct INT_CONTEXT; -/** - * Create and manage "processes" (really coroutines). - */ -class Scheduler { -public: - /** Pointer to a function of the form "void function(PPROCESS)" */ - typedef void (*VFPTRPP)(PROCESS *); - -private: - - /** list of all processes */ - PROCESS *processList; - - /** active process list - also saves scheduler state */ - PROCESS *active; - - /** pointer to free process list */ - PROCESS *pFreeProcesses; - - /** the currently active process */ - PROCESS *pCurrent; - -#ifdef DEBUG - // diagnostic process counters - int numProcs; - int maxProcs; - - void CheckStack(); -#endif - - /** - * Called from killProcess() to enable other resources - * a process may be allocated to be released. - */ - VFPTRPP pRCfunction; - - -public: - - Scheduler(); - ~Scheduler(); - - void reset(); - - #ifdef DEBUG - void printStats(); - #endif - - void schedule(); - void rescheduleAll(); - void reschedule(PPROCESS pReSchedProc = NULL); - void giveWay(PPROCESS pReSchedProc = NULL); - - PROCESS *createProcess(int pid, CORO_ADDR coroAddr, const void *pParam, int sizeParam); - void killProcess(PROCESS *pKillProc); - - PROCESS *getCurrentProcess(); - int getCurrentPID() const; - int killMatchingProcess(int pidKill, int pidMask = -1); - - - void setResourceCallback(VFPTRPP pFunc); - -}; - -extern Scheduler *g_scheduler; // FIXME: Temporary global var, to be used until everything has been OOifyied - //----------------- FUNCTION PROTOTYPES -------------------- void SceneProcesses(uint32 numProcess, SCNHANDLE hProcess); diff --git a/engines/tinsel/text.h b/engines/tinsel/text.h index 4c80300c46..97e82c7a93 100644 --- a/engines/tinsel/text.h +++ b/engines/tinsel/text.h @@ -24,7 +24,7 @@ #ifndef TINSEL_TEXT_H // prevent multiple includes #define TINSEL_TEXT_H -#include "tinsel/coroutine.h" +#include "common/coroutines.h" #include "tinsel/object.h" // object manager defines namespace Tinsel { diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index cd65a4ec32..5dda836144 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -28,11 +28,11 @@ #define BODGE +#include "common/coroutines.h" #include "tinsel/actors.h" #include "tinsel/background.h" #include "tinsel/bmv.h" #include "tinsel/config.h" -#include "tinsel/coroutine.h" #include "tinsel/cursor.h" #include "tinsel/drives.h" #include "tinsel/dw.h" @@ -1468,7 +1468,7 @@ void NewScene(CORO_PARAM, SCNHANDLE scene, int entrance, int transition) { ++g_sceneCtr; // Prevent code subsequent to this call running before scene changes - if (g_scheduler->getCurrentPID() != PID_MASTER_SCR) + if (CoroScheduler.getCurrentPID() != PID_MASTER_SCR) CORO_KILL_SELF(); CORO_END_CODE; } @@ -2594,7 +2594,7 @@ static void Scroll(CORO_PARAM, EXTREME extreme, int xp, int yp, int xIter, int y sm.y = _ctx->y; sm.thisScroll = g_scrollNumber; sm.myEscape = myEscape; - g_scheduler->createProcess(PID_TCODE, ScrollMonitorProcess, &sm, sizeof(sm)); + CoroScheduler.createProcess(PID_TCODE, ScrollMonitorProcess, &sm, sizeof(sm)); } } CORO_END_CODE; @@ -2975,12 +2975,12 @@ static void StandTag(int actor, HPOLYGON hp) { && hFilm != TF_LEFT && hFilm != TF_RIGHT) hFilm = 0; - Stand(nullContext, actor, pnodex, pnodey, hFilm); + Stand(Common::nullContext, actor, pnodex, pnodey, hFilm); } else if (hFilm && (actor == LEAD_ACTOR || actor == GetLeadId())) - Stand(nullContext, actor, pnodex, pnodey, hFilm); + Stand(Common::nullContext, actor, pnodex, pnodey, hFilm); else - Stand(nullContext, actor, pnodex, pnodey, 0); + Stand(Common::nullContext, actor, pnodex, pnodey, 0); } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 65900cc7f3..e09e2c1dcf 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -109,8 +109,8 @@ static Scene g_NextScene = { 0, 0, 0 }; static Scene g_HookScene = { 0, 0, 0 }; static Scene g_DelayedScene = { 0, 0, 0 }; -static PROCESS *g_pMouseProcess = 0; -static PROCESS *g_pKeyboardProcess = 0; +static Common::PROCESS *g_pMouseProcess = 0; +static Common::PROCESS *g_pKeyboardProcess = 0; static SCNHANDLE g_hCdChangeScene; @@ -324,7 +324,7 @@ static void MouseProcess(CORO_PARAM, const void *) { if (TinselV2) { // Kill off the button process and fire off the action command - g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1); + CoroScheduler.killMatchingProcess(PID_BTN_CLICK, -1); PlayerEvent(PLR_ACTION, _ctx->clickPos); } else { // signal left drag start @@ -368,7 +368,7 @@ static void MouseProcess(CORO_PARAM, const void *) { // will activate a single button click if (TinselV2 && ControlIsOn()) { _ctx->clickPos = mousePos; - g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, &_ctx->clickPos, sizeof(Common::Point)); + CoroScheduler.createProcess(PID_BTN_CLICK, SingleLeftProcess, &_ctx->clickPos, sizeof(Common::Point)); } } else _ctx->lastLeftClick -= _vm->_config->_dclickSpeed; @@ -616,11 +616,11 @@ static void RestoredProcess(CORO_PARAM, const void *param) { } void RestoreProcess(INT_CONTEXT *pic) { - g_scheduler->createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); + CoroScheduler.createProcess(PID_TCODE, RestoredProcess, &pic, sizeof(pic)); } void RestoreMasterProcess(INT_CONTEXT *pic) { - g_scheduler->createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); + CoroScheduler.createProcess(PID_MASTER_SCR, RestoredProcess, &pic, sizeof(pic)); } // FIXME: CountOut is used by ChangeScene @@ -878,7 +878,6 @@ TinselEngine::~TinselEngine() { FreeObjectList(); FreeGlobalProcesses(); FreeGlobals(); - delete _scheduler; delete _config; @@ -905,7 +904,7 @@ Common::Error TinselEngine::run() { _console = new Console(); - _scheduler = new Scheduler(); + CoroScheduler.reset(); InitSysVars(); @@ -1022,7 +1021,7 @@ void TinselEngine::NextGameCycle() { ResetEcount(); // schedule process - _scheduler->schedule(); + CoroScheduler.schedule(); if (_bmv->MoviePlaying()) _bmv->CopyMovieToScreen(); @@ -1078,11 +1077,11 @@ bool TinselEngine::pollEvent() { */ void TinselEngine::CreateConstProcesses() { // Process to run the master script - _scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); + CoroScheduler.createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); // Processes to run the cursor and inventory, - _scheduler->createProcess(PID_CURSOR, CursorProcess, NULL, 0); - _scheduler->createProcess(PID_INVENTORY, InventoryProcess, NULL, 0); + CoroScheduler.createProcess(PID_CURSOR, CursorProcess, NULL, 0); + CoroScheduler.createProcess(PID_INVENTORY, InventoryProcess, NULL, 0); } /** @@ -1132,11 +1131,11 @@ void TinselEngine::RestartDrivers() { KillAllObjects(); // init the process scheduler - _scheduler->reset(); + CoroScheduler.reset(); // init the event handlers - g_pMouseProcess = _scheduler->createProcess(PID_MOUSE, MouseProcess, NULL, 0); - g_pKeyboardProcess = _scheduler->createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0); + g_pMouseProcess = CoroScheduler.createProcess(PID_MOUSE, MouseProcess, NULL, 0); + g_pKeyboardProcess = CoroScheduler.createProcess(PID_KEYBOARD, KeyboardProcess, NULL, 0); // open MIDI files OpenMidiFiles(); @@ -1164,8 +1163,8 @@ void TinselEngine::ChopDrivers() { DeleteMidiBuffer(); // remove event drivers - _scheduler->killProcess(g_pMouseProcess); - _scheduler->killProcess(g_pKeyboardProcess); + CoroScheduler.killProcess(g_pMouseProcess); + CoroScheduler.killProcess(g_pKeyboardProcess); } /** diff --git a/engines/tinsel/token.cpp b/engines/tinsel/token.cpp index c26fa40466..080c005c3c 100644 --- a/engines/tinsel/token.cpp +++ b/engines/tinsel/token.cpp @@ -31,7 +31,7 @@ namespace Tinsel { //----------------- LOCAL GLOBAL DATA -------------------- struct Token { - PROCESS *proc; + Common::PROCESS *proc; }; static Token g_tokens[NUMTOKENS]; // FIXME: Avoid non-const global vars @@ -40,7 +40,7 @@ static Token g_tokens[NUMTOKENS]; // FIXME: Avoid non-const global vars /** * Release all tokens held by this process, and kill the process. */ -static void TerminateProcess(PROCESS *tProc) { +static void TerminateProcess(Common::PROCESS *tProc) { // Release tokens held by the process for (int i = 0; i < NUMTOKENS; i++) { @@ -50,7 +50,7 @@ static void TerminateProcess(PROCESS *tProc) { } // Kill the process - g_scheduler->killProcess(tProc); + CoroScheduler.killProcess(tProc); } /** @@ -60,7 +60,7 @@ void GetControlToken() { const int which = TOKEN_CONTROL; if (g_tokens[which].proc == NULL) { - g_tokens[which].proc = g_scheduler->getCurrentProcess(); + g_tokens[which].proc = CoroScheduler.getCurrentProcess(); } } @@ -85,11 +85,11 @@ void GetToken(int which) { assert(TOKEN_LEAD <= which && which < NUMTOKENS); if (g_tokens[which].proc != NULL) { - assert(g_tokens[which].proc != g_scheduler->getCurrentProcess()); + assert(g_tokens[which].proc != CoroScheduler.getCurrentProcess()); TerminateProcess(g_tokens[which].proc); } - g_tokens[which].proc = g_scheduler->getCurrentProcess(); + g_tokens[which].proc = CoroScheduler.getCurrentProcess(); } /** @@ -99,7 +99,7 @@ void GetToken(int which) { void FreeToken(int which) { assert(TOKEN_LEAD <= which && which < NUMTOKENS); - assert(g_tokens[which].proc == g_scheduler->getCurrentProcess()); // we'd have been killed if some other proc had taken this token + assert(g_tokens[which].proc == CoroScheduler.getCurrentProcess()); // we'd have been killed if some other proc had taken this token g_tokens[which].proc = NULL; } diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 304d3a4298..216444e722 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -5571,7 +5571,7 @@ void Scene1337::subCF979() { tmpVal = subC26CB(0, i); if (tmpVal != -1) { - bool flag = false;; + bool flag = false; for (int j = 0; j <= 7; j++) { if (_arrunkObj1337[0]._arr2[j]._field34 == _arrunkObj1337[0]._arr1[tmpVal]._field34) { flag = true; @@ -11068,7 +11068,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { case R2_REBREATHER_TANK: if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { if (R2_GLOBALS.getFlag(30)) - return SceneActor::startAction(action, event);; + return SceneActor::startAction(action, event); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1878; diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 3dd566c900..61711d0a4f 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -3294,7 +3294,7 @@ void Scene3500::Action1::signal() { NpcMover *mover = new NpcMover(); scene->_actor8.addMover(mover, &pt, this); - scene->_actor9.setPosition(Common::Point(160 + ((_field1E * 2) * 160), 73));; + scene->_actor9.setPosition(Common::Point(160 + ((_field1E * 2) * 160), 73)); scene->_actor9._moveDiff.x = 160 - scene->_field126E; scene->_fieldB9E = 160; Common::Point pt2(scene->_fieldB9E, 73); |