aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/cruise/cruise.cpp3
-rw-r--r--engines/cruise/detection.cpp13
-rw-r--r--engines/cruise/staticres.cpp4
-rw-r--r--engines/cruise/staticres.h1
-rw-r--r--engines/dreamweb/detection_tables.h60
-rw-r--r--engines/dreamweb/dreamweb.cpp6
-rw-r--r--engines/dreamweb/dreamweb.h1
-rw-r--r--engines/dreamweb/monitor.cpp5
-rw-r--r--engines/dreamweb/saveload.cpp5
-rw-r--r--engines/dreamweb/sound.cpp13
-rw-r--r--engines/kyra/items_lol.cpp53
-rw-r--r--engines/kyra/lol.cpp12
-rw-r--r--engines/kyra/lol.h10
-rw-r--r--engines/kyra/script_lol.cpp5
-rw-r--r--engines/kyra/sprites_lol.cpp70
-rw-r--r--engines/mohawk/cursors.cpp4
-rw-r--r--engines/mohawk/myst_stacks/dni.cpp2
-rw-r--r--engines/mohawk/riven.cpp2
-rw-r--r--engines/mohawk/riven_external.cpp4
-rw-r--r--engines/mohawk/video.cpp6
-rw-r--r--engines/mohawk/video.h2
-rw-r--r--engines/pegasus/movie.cpp2
-rw-r--r--engines/pegasus/pegasus.cpp2
-rw-r--r--engines/saga/introproc_ite.cpp32
-rw-r--r--engines/sci/console.cpp54
-rw-r--r--engines/sci/console.h2
-rw-r--r--engines/sci/engine/kernel.h2
-rw-r--r--engines/sci/engine/kernel_tables.h23
-rw-r--r--engines/sci/engine/kfile.cpp46
-rw-r--r--engines/sci/engine/kgraphics.cpp623
-rw-r--r--engines/sci/engine/kgraphics32.cpp622
-rw-r--r--engines/sci/engine/script_patches.cpp2
-rw-r--r--engines/sci/engine/selector.cpp1
-rw-r--r--engines/sci/engine/selector.h1
-rw-r--r--engines/sci/engine/vm.h2
-rw-r--r--engines/sci/engine/workarounds.cpp4
-rw-r--r--engines/sci/graphics/frameout.cpp61
-rw-r--r--engines/sci/graphics/frameout.h3
-rw-r--r--engines/sci/graphics/text32.cpp7
-rw-r--r--engines/sci/graphics/view.cpp13
-rw-r--r--engines/sci/module.mk1
-rw-r--r--engines/sci/resource.cpp15
-rw-r--r--engines/sci/resource.h18
-rw-r--r--engines/sci/sci.cpp2
-rw-r--r--engines/scumm/he/resource_he.cpp2
-rw-r--r--engines/sword1/animation.cpp4
-rw-r--r--engines/sword1/animation.h2
-rw-r--r--engines/sword2/animation.cpp4
-rw-r--r--engines/sword2/animation.h2
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/sword25/fmv/theora_decoder.cpp6
-rw-r--r--engines/sword25/fmv/theora_decoder.h2
-rw-r--r--engines/tinsel/actors.cpp12
-rw-r--r--engines/tinsel/background.h2
-rw-r--r--engines/tinsel/bg.cpp6
-rw-r--r--engines/tinsel/bmv.cpp4
-rw-r--r--engines/tinsel/bmv.h2
-rw-r--r--engines/tinsel/coroutine.cpp82
-rw-r--r--engines/tinsel/coroutine.h282
-rw-r--r--engines/tinsel/dialogs.cpp20
-rw-r--r--engines/tinsel/drives.cpp6
-rw-r--r--engines/tinsel/drives.h2
-rw-r--r--engines/tinsel/effect.cpp2
-rw-r--r--engines/tinsel/events.cpp18
-rw-r--r--engines/tinsel/events.h4
-rw-r--r--engines/tinsel/faders.cpp4
-rw-r--r--engines/tinsel/handle.cpp2
-rw-r--r--engines/tinsel/module.mk1
-rw-r--r--engines/tinsel/move.cpp4
-rw-r--r--engines/tinsel/pcode.cpp20
-rw-r--r--engines/tinsel/pcode.h12
-rw-r--r--engines/tinsel/pdisplay.cpp6
-rw-r--r--engines/tinsel/play.cpp16
-rw-r--r--engines/tinsel/play.h2
-rw-r--r--engines/tinsel/polygons.cpp4
-rw-r--r--engines/tinsel/rince.cpp8
-rw-r--r--engines/tinsel/rince.h3
-rw-r--r--engines/tinsel/savescn.cpp10
-rw-r--r--engines/tinsel/scene.cpp20
-rw-r--r--engines/tinsel/sched.cpp487
-rw-r--r--engines/tinsel/sched.h93
-rw-r--r--engines/tinsel/text.h2
-rw-r--r--engines/tinsel/tinlib.cpp12
-rw-r--r--engines/tinsel/tinsel.cpp33
-rw-r--r--engines/tinsel/token.cpp14
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.cpp4
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes3.cpp2
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);