aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README29
-rw-r--r--backends/fs/windows/windows-fs.cpp5
-rw-r--r--backends/midi/alsa.cpp42
-rw-r--r--backends/platform/wince/CEActionsPocket.cpp2
-rw-r--r--backends/platform/wince/CEActionsSmartphone.cpp2
-rw-r--r--backends/platform/wince/missing/missing.cpp11
-rw-r--r--base/commandLine.cpp3
-rw-r--r--common/unarj.cpp7
-rw-r--r--engines/agos/animation.cpp4
-rw-r--r--engines/agos/input.cpp4
-rw-r--r--engines/agos/oracle.cpp2
-rw-r--r--engines/agos/saveload.cpp20
-rw-r--r--engines/agos/script.cpp2
-rw-r--r--engines/agos/script_e1.cpp8
-rw-r--r--engines/agos/script_e2.cpp4
-rw-r--r--engines/agos/script_s1.cpp12
-rw-r--r--engines/agos/script_ww.cpp4
-rw-r--r--engines/agos/verb.cpp3
-rw-r--r--engines/agos/window.cpp2
-rw-r--r--engines/cine/anim.cpp24
-rw-r--r--engines/cine/bg.cpp6
-rw-r--r--engines/cine/cine.cpp22
-rw-r--r--engines/cine/cine.h6
-rw-r--r--engines/cine/detection.cpp34
-rw-r--r--engines/cine/gfx.cpp81
-rw-r--r--engines/cine/gfx.h4
-rw-r--r--engines/cine/main_loop.cpp98
-rw-r--r--engines/cine/main_loop.h5
-rw-r--r--engines/cine/part.cpp18
-rw-r--r--engines/cine/part.h2
-rw-r--r--engines/cine/prc.cpp2
-rw-r--r--engines/cine/script_fw.cpp10
-rw-r--r--engines/cine/script_os.cpp24
-rw-r--r--engines/cine/various.cpp90
-rw-r--r--engines/cine/various.h1
-rw-r--r--engines/kyra/kyra_hof.cpp8
-rw-r--r--engines/kyra/lol.cpp3
-rw-r--r--engines/kyra/resource.cpp9
-rw-r--r--engines/kyra/saveload.cpp12
-rw-r--r--engines/kyra/scene_mr.cpp3
-rw-r--r--engines/scumm/dialogs.cpp43
-rw-r--r--engines/scumm/script.cpp8
-rw-r--r--engines/scumm/script_v6.cpp9
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/touche/graphics.cpp5
-rw-r--r--engines/touche/graphics.h2
-rw-r--r--engines/touche/staticres.cpp5
-rw-r--r--engines/touche/touche.cpp9
-rw-r--r--engines/touche/touche.h7
-rw-r--r--graphics/scaler/hq2x_i386.asm5
-rw-r--r--graphics/scaler/hq3x_i386.asm5
51 files changed, 550 insertions, 178 deletions
diff --git a/README b/README
index ac44f53cab..6f59e172bc 100644
--- a/README
+++ b/README
@@ -1322,34 +1322,39 @@ sequencer support does not work, you can always fall back on Adlib emulation.
7.6.1) Playing sound with ALSA sequencer: [UNIX ONLY]
------ ----------------------------------
-If you have installed the ALSA driver with the sequencer support, then
-set the environment variable SCUMMVM_PORT or the config file parameter
-alsa_port to your sequencer port. The default is "65:0".
+If you have installed the ALSA driver with the sequencer support, then set the
+environment variable SCUMMVM_PORT or the config file parameter alsa_port to
+your sequencer port. The default is to try both "65:0" and "17:0".
Here is a little howto on how to use the ALSA sequencer with your soundcard.
In all cases, to have a list of all the sequencer ports you have, try the
command "aconnect -o -l". This should give output similar to:
-client 64: 'External MIDI 0' [type=kernel]
- 0 'MIDI 0-0 '
-client 65: 'Emu10k1 WaveTable' [type=kernel]
+
+client 14: 'Midi Through' [type=kernel]
+ 0 'Midi Through Port-0'
+client 16: 'SBLive! Value [CT4832]' [type=kernel]
+ 0 'EMU10K1 MPU-401 (UART)'
+client 17: 'Emu10k1 WaveTable' [type=kernel]
0 'Emu10k1 Port 0 '
1 'Emu10k1 Port 1 '
2 'Emu10k1 Port 2 '
3 'Emu10k1 Port 3 '
-client 128: 'Client-128' [type=user]
+client 128: 'TiMidity' [type=user]
0 'TiMidity port 0 '
1 'TiMidity port 1 '
+ 2 'TiMidity port 2 '
+ 3 'TiMidity port 3 '
-This means the external MIDI output of the sound card is located on the
-port 64:0, four WaveTable MIDI outputs in 65:0, 65:1, 65:2
-and 65:3, and two TiMidity ports, located at 128:0 and 128:1.
+The most important bit here is that there are four WaveTable MIDI outputs
+located at 17:0, 17:1, 17:2 and 17:3, and four TiMidity ports located at 128:0,
+128:1, 128:2 and 128:3.
If you have a FM-chip on your card, like the SB16, then you have to load
the SoundFonts using the sbiload software. Example:
- sbiload -p 65:0 /etc/std.o3 /etc/drums.o3
+ sbiload -p 17:0 /etc/std.o3 /etc/drums.o3
If you have a WaveTable capable sound card, you have to load a sbk or sf2
-SoundFont using the sfxload software. Example:
+SoundFont using the sfxload or asfxload software. Example:
sfxload /path/to/8mbgmsfx.sf2
If you don't have a MIDI capable soundcard, there are two options: FluidSynth
diff --git a/backends/fs/windows/windows-fs.cpp b/backends/fs/windows/windows-fs.cpp
index ac2f521e21..77530c6073 100644
--- a/backends/fs/windows/windows-fs.cpp
+++ b/backends/fs/windows/windows-fs.cpp
@@ -260,11 +260,6 @@ AbstractFilesystemNode *WindowsFilesystemNode::getChild(const String &n) const {
newPath += '\\';
newPath += n;
- // Check whether the directory actually exists
- DWORD fileAttribs = GetFileAttributes(toUnicode(newPath.c_str()));
- if (fileAttribs == INVALID_FILE_ATTRIBUTES)
- return 0;
-
return new WindowsFilesystemNode(newPath, false);
}
diff --git a/backends/midi/alsa.cpp b/backends/midi/alsa.cpp
index 2a252b9323..5a978a0fd2 100644
--- a/backends/midi/alsa.cpp
+++ b/backends/midi/alsa.cpp
@@ -79,20 +79,18 @@ MidiDriver_ALSA::MidiDriver_ALSA()
}
int MidiDriver_ALSA::open() {
- const char *var;
+ const char *var = NULL;
if (_isOpen)
return MERR_ALREADY_OPEN;
_isOpen = true;
- if (!(var = getenv("SCUMMVM_PORT"))) {
- // use config option if no var specified
+ var = getenv("SCUMMVM_PORT");
+ if (!var && ConfMan.hasKey("alsa_port")) {
var = ConfMan.get("alsa_port").c_str();
- if (parse_addr(var, &seq_client, &seq_port) < 0) {
- error("Invalid port %s", var);
- return -1;
- }
- } else {
+ }
+
+ if (var) {
if (parse_addr(var, &seq_client, &seq_port) < 0) {
error("Invalid port %s", var);
return -1;
@@ -120,14 +118,32 @@ int MidiDriver_ALSA::open() {
return -1;
}
- if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
- /* subscribe to MIDI port */
- if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
- error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
+ if (var) {
+ if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
+ // subscribe to MIDI port
+ if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
+ error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
+ }
}
- else printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port);
+ } else {
+ int defaultPorts[] = {
+ 65, 0,
+ 17, 0
+ };
+ int i;
+
+ for (i = 0; i < ARRAYSIZE(defaultPorts); i += 2) {
+ seq_client = defaultPorts[i];
+ seq_port = defaultPorts[i + 1];
+ if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) >= 0)
+ break;
+ }
+
+ if (i >= ARRAYSIZE(defaultPorts))
+ error("Can't subscribe to MIDI port (65:0) or (17:0)");
}
+ printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port);
printf("ALSA client initialised [%d:0]\n", my_client);
return 0;
diff --git a/backends/platform/wince/CEActionsPocket.cpp b/backends/platform/wince/CEActionsPocket.cpp
index 45310dba88..932599004d 100644
--- a/backends/platform/wince/CEActionsPocket.cpp
+++ b/backends/platform/wince/CEActionsPocket.cpp
@@ -121,7 +121,7 @@ void CEActionsPocket::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (gameid == "kyra1");
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
diff --git a/backends/platform/wince/CEActionsSmartphone.cpp b/backends/platform/wince/CEActionsSmartphone.cpp
index 97d780d534..6877c343e3 100644
--- a/backends/platform/wince/CEActionsSmartphone.cpp
+++ b/backends/platform/wince/CEActionsSmartphone.cpp
@@ -111,7 +111,7 @@ void CEActionsSmartphone::initInstanceGame() {
bool is_comi = (strncmp(gameid.c_str(), "comi", 4) == 0);
bool is_gob = (strncmp(gameid.c_str(), "gob", 3) == 0);
bool is_saga = (gameid == "saga");
- bool is_kyra = (gameid == "kyra1");
+ bool is_kyra = (strncmp(gameid.c_str(), "kyra",4) == 0);
bool is_samnmax = (gameid == "samnmax");
bool is_cine = (gameid == "cine");
bool is_touche = (gameid == "touche");
diff --git a/backends/platform/wince/missing/missing.cpp b/backends/platform/wince/missing/missing.cpp
index c760b1f7df..f03f00bb9a 100644
--- a/backends/platform/wince/missing/missing.cpp
+++ b/backends/platform/wince/missing/missing.cpp
@@ -171,7 +171,7 @@ int _access(const char *path, int mode) {
MultiByteToWideChar(CP_ACP, 0, path, -1, fname, sizeof(fname)/sizeof(TCHAR));
WIN32_FIND_DATA ffd;
- HANDLE h=FindFirstFile(fname, &ffd);
+ HANDLE h = FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
@@ -179,9 +179,14 @@ int _access(const char *path, int mode) {
if (ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) {
// WORKAROUND: WinCE (or the emulator) sometimes returns bogus direcotry
- // hits for files that don't exist. Checking for the same fname twice
+ // hits for files that don't exist. TRIPLE checking for the same fname
// seems to weed out those false positives.
- HANDLE h=FindFirstFile(fname, &ffd);
+ // Exhibited in kyra engine.
+ HANDLE h = FindFirstFile(fname, &ffd);
+ FindClose(h);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1; //Can't find file
+ h = FindFirstFile(fname, &ffd);
FindClose(h);
if (h == INVALID_HANDLE_VALUE)
return -1; //Can't find file
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 84f2013ae9..f8ca8a90cd 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -193,9 +193,6 @@ void registerDefaults() {
ConfMan.registerDefault("joystick_num", -1);
ConfMan.registerDefault("confirm_exit", false);
ConfMan.registerDefault("disable_sdl_parachute", false);
-#ifdef USE_ALSA
- ConfMan.registerDefault("alsa_port", "65:0");
-#endif
ConfMan.registerDefault("record_mode", "none");
ConfMan.registerDefault("record_file_name", "record.bin");
diff --git a/common/unarj.cpp b/common/unarj.cpp
index da88c11fc9..9a7766a41f 100644
--- a/common/unarj.cpp
+++ b/common/unarj.cpp
@@ -75,7 +75,7 @@ static uint32 GetCRC(byte *data, int len) {
return CRC ^ 0xFFFFFFFF;
}
-ArjFile::ArjFile() {
+ArjFile::ArjFile() : _uncompressedData(NULL) {
InitCRC();
_isOpen = false;
_fallBack = false;
@@ -256,6 +256,11 @@ bool ArjFile::open(const Common::String &filename) {
_compsize = hdr->compSize;
_origsize = hdr->origSize;
+ // FIXME: This hotfix prevents Drascula from leaking memory.
+ // As far as sanity checks go this is not bad, but the engine should be fixed.
+ if (_uncompressedData)
+ free(_uncompressedData);
+
_uncompressedData = (byte *)malloc(_origsize);
_outstream = new MemoryWriteStream(_uncompressedData, _origsize);
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index 1b6626fa89..f29baefde1 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -150,7 +150,7 @@ void MoviePlayer::play() {
startSound();
- while (_frameNum < _framesCount)
+ while (_frameNum < _framesCount && !_vm->_quit)
handleNextFrame();
closeFile();
@@ -166,7 +166,7 @@ void MoviePlayer::play() {
_vm->_system->setPalette(palette, 0, 256);
}
- _vm->fillBackGroundFromBack();
+ _vm->fillBackGroundFromBack();
_vm->_fastFadeOutFlag = true;
}
diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp
index 3ee81e1375..ca6b67fa61 100644
--- a/engines/agos/input.cpp
+++ b/engines/agos/input.cpp
@@ -123,7 +123,7 @@ void AGOSEngine::setup_cond_c_helper() {
clearName();
_lastNameOn = last;
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = 0;
_leftButtonDown = 0;
@@ -145,7 +145,7 @@ void AGOSEngine::setup_cond_c_helper() {
}
delay(100);
- } while (_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0);
+ } while ((_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0) && !_quit);
if (_lastHitArea == NULL) {
} else if (_lastHitArea->id == 0x7FFB) {
diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp
index a113c8e2ea..2d2feb7b9e 100644
--- a/engines/agos/oracle.cpp
+++ b/engines/agos/oracle.cpp
@@ -459,7 +459,7 @@ void AGOSEngine_Feeble::saveUserGame(int slot) {
}
windowPutChar(window, 0x7f);
- for (;;) {
+ while (!_quit) {
_keyPressed.reset();
delay(1);
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index 4a5c43e706..9779630d47 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -279,11 +279,11 @@ restart:
name = buf;
_saveGameNameLen = 0;
- for (;;) {
+ while (!_quit) {
windowPutChar(window, 128);
_keyPressed.reset();
- for (;;) {
+ while (!_quit) {
delay(10);
if (_keyPressed.ascii && _keyPressed.ascii < 128) {
i = _keyPressed.ascii;
@@ -443,7 +443,7 @@ void AGOSEngine_Elvira2::userGame(bool load) {
name = buf + 192;
- for (;;) {
+ while (!_quit) {
windowPutChar(window, 128);
_saveLoadEdit = true;
@@ -516,7 +516,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
_keyPressed.reset();
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
@@ -526,7 +526,7 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
return _keyPressed.ascii;
}
delay(10);
- } while (_lastHitArea3 == 0);
+ } while (_lastHitArea3 == 0 && !_quit);
ha = _lastHitArea;
if (ha == NULL || ha->id < 200) {
@@ -543,6 +543,8 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
return ha->id - 200;
}
}
+
+ return 225;
}
void AGOSEngine_Simon1::listSaveGames(char *dst) {
@@ -706,7 +708,7 @@ restart:;
_saveGameNameLen++;
}
- for (;;) {
+ while (!_quit) {
windowPutChar(window, 127);
_saveLoadEdit = true;
@@ -785,7 +787,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
_keyPressed.reset();
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
@@ -795,7 +797,7 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
return _keyPressed.ascii;
}
delay(10);
- } while (_lastHitArea3 == 0);
+ } while (_lastHitArea3 == 0 && !_quit);
ha = _lastHitArea;
if (ha == NULL || ha->id < 205) {
@@ -824,6 +826,8 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
return ha->id - 208;
}
}
+
+ return 205;
}
void AGOSEngine::disableFileBoxes() {
diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp
index a0151d7713..2a2ddeeb86 100644
--- a/engines/agos/script.cpp
+++ b/engines/agos/script.cpp
@@ -1012,7 +1012,7 @@ int AGOSEngine::runScript() {
executeOpcode(_opcode);
} while (getScriptCondition() != flag && !getScriptReturn() && !quit());
- return getScriptReturn();
+ return (_quit) ? 1 : getScriptReturn();
}
Child *nextSub(Child *sub, int16 key) {
diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp
index 9ac308b114..d3ee4297c0 100644
--- a/engines/agos/script_e1.cpp
+++ b/engines/agos/script_e1.cpp
@@ -1052,11 +1052,11 @@ uint AGOSEngine::confirmYesOrNo(uint16 x, uint16 y) {
ha->priority = 999;
ha->window = 0;
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!_quit) {
if (_lastHitArea3 != 0)
break;
delay(1);
@@ -1101,11 +1101,11 @@ uint AGOSEngine::continueOrQuit() {
ha->priority = 999;
ha->window = 0;
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!_quit) {
if (_lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp
index da9afc5a7d..6f6db8efb4 100644
--- a/engines/agos/script_e2.cpp
+++ b/engines/agos/script_e2.cpp
@@ -370,11 +370,11 @@ void AGOSEngine_Elvira2::oe2_pauseGame() {
uint32 pauseTime = getTime();
haltAnimation();
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!_quit) {
if (processSpecialKeys() != 0 || _lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp
index 8bd9159ad8..86088a4385 100644
--- a/engines/agos/script_s1.cpp
+++ b/engines/agos/script_s1.cpp
@@ -338,18 +338,8 @@ void AGOSEngine_Simon1::os1_pauseGame() {
break;
}
- for (;;) {
+ while (!_quit) {
delay(1);
-#ifdef _WIN32_WCE
- if (isSmartphone()) {
- if (_keyPressed.keycode) {
- if (_keyPressed.keycode == Common::KEYCODE_RETURN)
- quitGame();
- else
- break;
- }
- }
-#endif
if (_keyPressed.keycode == keyYes)
quitGame();
else if (_keyPressed.keycode == keyNo)
diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp
index 5fd83312c3..8dc915f6e8 100644
--- a/engines/agos/script_ww.cpp
+++ b/engines/agos/script_ww.cpp
@@ -368,11 +368,11 @@ void AGOSEngine_Waxworks::oww_pauseGame() {
uint32 pauseTime = getTime();
haltAnimation();
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
- for (;;) {
+ while (!_quit) {
if (_lastHitArea3 != 0)
break;
delay(1);
diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp
index 963bd6bd86..c8f6d40f1f 100644
--- a/engines/agos/verb.cpp
+++ b/engines/agos/verb.cpp
@@ -343,6 +343,9 @@ void AGOSEngine::handleVerbClicked(uint verb) {
Subroutine *sub;
int result;
+ if (_quit)
+ return;
+
_objectItem = _hitAreaObjectItem;
if (_objectItem == _dummyItem2) {
_objectItem = me();
diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp
index e25bd6b438..e1f986b92e 100644
--- a/engines/agos/window.cpp
+++ b/engines/agos/window.cpp
@@ -298,7 +298,7 @@ void AGOSEngine::waitWindow(WindowBlock *window) {
ha->id = 0x7FFF;
ha->priority = 999;
- for (;;) {
+ while (!_quit) {
_lastHitArea = NULL;
_lastHitArea3 = NULL;
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp
index eb820804a6..c19435c59a 100644
--- a/engines/cine/anim.cpp
+++ b/engines/cine/anim.cpp
@@ -535,10 +535,14 @@ int loadSpl(const char *resourceName, int16 idx) {
/*! \brief Load 1bpp mask
* \param resourceName Mask filename
* \param idx Target index in animDataTable (-1 if any empty space will do)
- * \return The number of the animDataTable entry after the loaded mask
+ * \return The number of the animDataTable entry after the loaded mask (-1 if error)
*/
int loadMsk(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
int entry = 0;
byte *dataPtr = readBundleFile(foundFileIdx);
byte *ptr;
@@ -562,10 +566,14 @@ int loadMsk(const char *resourceName, int16 idx) {
/*! \brief Load animation
* \param resourceName Animation filename
* \param idx Target index in animDataTable (-1 if any empty space will do)
- * \return The number of the animDataTable entry after the loaded animation
+ * \return The number of the animDataTable entry after the loaded animation (-1 if error)
*/
int loadAni(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
int entry = 0;
byte *dataPtr = readBundleFile(foundFileIdx);
byte *ptr;
@@ -651,7 +659,7 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) {
/*! \brief Load image set
* \param resourceName Image set filename
* \param idx Target index in animDataTable (-1 if any empty space will do)
- * \return The number of the animDataTable entry after the loaded image set
+ * \return The number of the animDataTable entry after the loaded image set (-1 if error)
*/
int loadSet(const char *resourceName, int16 idx) {
AnimHeader2Struct header2;
@@ -661,6 +669,10 @@ int loadSet(const char *resourceName, int16 idx) {
byte *ptr, *startOfDataPtr, *dataPtr, *origDataPtr;
int type;
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
origDataPtr = dataPtr = readBundleFile(foundFileIdx);
assert(!memcmp(dataPtr, "SET", 3));
ptr = dataPtr + 4;
@@ -708,10 +720,14 @@ int loadSet(const char *resourceName, int16 idx) {
/*! \brief Load SEQ data into animDataTable
* \param resourceName SEQ data filename
* \param idx Target index in animDataTable (-1 if any empty space will do)
- * \return The number of the animDataTable entry after the loaded SEQ data
+ * \return The number of the animDataTable entry after the loaded SEQ data (-1 if error)
*/
int loadSeq(const char *resourceName, int16 idx) {
int16 foundFileIdx = findFileInBundle(resourceName);
+ if (foundFileIdx < 0) {
+ return -1;
+ }
+
byte *dataPtr = readBundleFile(foundFileIdx);
int entry = idx < 0 ? emptyAnimSpace() : idx;
diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp
index 2a4e7f0ab1..45bfae7925 100644
--- a/engines/cine/bg.cpp
+++ b/engines/cine/bg.cpp
@@ -56,7 +56,7 @@ byte loadCtFW(const char *ctName) {
header[i] = readS.readUint16BE();
}
- gfxConvertSpriteToRaw(page3Raw, ptr + 0x80, 160, 200);
+ gfxConvertSpriteToRaw(collisionPage, ptr + 0x80, 160, 200);
free(dataPtr);
return 0;
@@ -74,10 +74,10 @@ byte loadCtOS(const char *ctName) {
ptr += 2;
if (bpp == 8) {
- memcpy(page3Raw, ptr + 256 * 3, 320 * 200);
+ memcpy(collisionPage, ptr + 256 * 3, 320 * 200);
renderer->loadCt256(ptr, ctName);
} else {
- gfxConvertSpriteToRaw(page3Raw, ptr + 32, 160, 200);
+ gfxConvertSpriteToRaw(collisionPage, ptr + 32, 160, 200);
renderer->loadCt16(ptr, ctName);
}
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp
index 50aefe5ff9..127d390f66 100644
--- a/engines/cine/cine.cpp
+++ b/engines/cine/cine.cpp
@@ -56,6 +56,10 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng
// Setup mixer
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ // Use music volume for plain sound types (At least the Adlib player uses a plain sound type
+ // so previously the music and sfx volume controls didn't affect it at all).
+ // FIXME: Make Adlib player differentiate between playing sound effects and music and remove this.
+ _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("music_volume"));
g_cine = this;
@@ -99,14 +103,28 @@ int CineEngine::go() {
mainLoop(1);
delete renderer;
- delete[] page3Raw;
+ delete[] collisionPage;
delete g_sound;
return _eventMan->shouldRTL();
}
+int CineEngine::getTimerDelay() const {
+ return (10923000 * _timerDelayMultiplier) / 1193180;
+}
+
+/*! \brief Modify game speed
+ * \param speedChange Negative values slow game down, positive values speed it up, zero does nothing
+ * \return Timer delay multiplier's value after the game speed change
+ */
+int CineEngine::modifyGameSpeed(int speedChange) {
+ // If we want more speed we decrement the timer delay multiplier and vice versa.
+ _timerDelayMultiplier = CLIP(_timerDelayMultiplier - speedChange, 1, 50);
+ return _timerDelayMultiplier;
+}
void CineEngine::initialize() {
+ _timerDelayMultiplier = 12; // Set default speed
setupOpcodes();
initLanguage(g_cine->getLanguage());
@@ -117,7 +135,7 @@ void CineEngine::initialize() {
renderer = new FWRenderer;
}
- page3Raw = new byte[320 * 200];
+ collisionPage = new byte[320 * 200];
textDataPtr = (byte *)malloc(8000);
partBuffer = (PartBuffer *)malloc(NUM_MAX_PARTDATA * sizeof(PartBuffer));
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index eaae555812..6011036eb1 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -59,7 +59,8 @@ enum CineGameType {
enum CineGameFeatures {
GF_CD = 1 << 0,
GF_DEMO = 1 << 1,
- GF_ALT_FONT = 1 << 2
+ GF_ALT_FONT = 1 << 2,
+ GF_CRYPTED_BOOT_PRC = 1 << 3
};
struct CINEGameDescription;
@@ -86,6 +87,8 @@ public:
bool loadSaveDirectory(void);
void makeSystemMenu(void);
+ int modifyGameSpeed(int speedChange);
+ int getTimerDelay() const;
const CINEGameDescription *_gameDescription;
Common::File _partFileHandle;
@@ -109,6 +112,7 @@ private:
void readVolCnf();
bool _preLoad;
+ int _timerDelayMultiplier;
};
extern CineEngine *g_cine;
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 899e4c4754..1dc6f89c49 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -76,6 +76,25 @@ static const CINEGameDescription gameDescriptions[] = {
0,
},
+ // This is a CD version of Future Wars published by Sony.
+ // This version has a crypted AUTO00.PRC.
+ {
+ {
+ "fw",
+ "Sony CD version",
+ {
+ { "AUTO00.PRC", 0, "4fe1e7930b38e3c63f0f2474d471bf8f", -1},
+ { "PART01", 0, "61d003202d301c29dd399acfb1354310", -1},
+ { NULL, 0, NULL, 0}
+ },
+ Common::EN_USA,
+ Common::kPlatformPC,
+ Common::ADGF_CD
+ },
+ GType_FW,
+ GF_CD | GF_CRYPTED_BOOT_PRC,
+ },
+
{
// This is the version included in the UK "Classic Collection"
{
@@ -251,6 +270,21 @@ static const CINEGameDescription gameDescriptions[] = {
},
{
+ // This is a 16 color PC version (It came on three 720kB 3.5" disks).
+ // The protagonist is named John Glames in this version.
+ {
+ "os",
+ "",
+ AD_ENTRY1("procs1", "9629129b86979fa592c1787385bf3695"),
+ Common::EN_GRB,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ GType_OS,
+ 0,
+ },
+
+ {
{
"os",
"",
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index cbddf0fc59..b882c9760e 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -36,7 +36,7 @@
namespace Cine {
-byte *page3Raw;
+byte *collisionPage;
FWRenderer *renderer = NULL;
static const byte mouseCursorNormal[] = {
@@ -282,20 +282,43 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo
*/
void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) {
int i;
- byte *dest = _backBuffer + y * 320 + x;
+ // Handle horizontally flipped boxes
if (width < 0) {
x += width;
- width = -width;
+ width = ABS(width);
}
+ // Handle vertically flipped boxes
if (height < 0) {
y += height;
- height = -height;
+ height = ABS(height);
}
- for (i = 0; i < height; i++) {
- memset(dest + i * 320, color, width);
+ // Handle horizontal boundaries
+ if (x < 0) {
+ width += x; // Remove invisible columns
+ x = 0; // Start drawing at the screen's left border
+ } else if (x > 319) {
+ // Nothing left to draw as we're over the screen's right border
+ width = 0;
+ }
+
+ // Handle vertical boundaries
+ if (y < 0) {
+ height += y; // Remove invisible rows
+ y = 0; // Start drawing at the screen's top border
+ } else if (y > 199) {
+ // Nothing left to draw as we're below the screen's bottom border
+ height = 0;
+ }
+
+ // Draw the box if it's not empty
+ if (width > 0 && height > 0) {
+ byte *dest = _backBuffer + y * 320 + x;
+ for (i = 0; i < height; i++) {
+ memset(dest + i * 320, color, width);
+ }
}
}
@@ -422,6 +445,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
_messageLen += messageTable[it->objIdx].size();
drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color);
+ waitForPlayerClick = 1;
break;
// action failure message
@@ -433,6 +457,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
width = width > 300 ? 300 : width;
drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, 4);
+ waitForPlayerClick = 1;
break;
// bitmap
@@ -617,6 +642,11 @@ void FWRenderer::saveBgNames(Common::OutSaveFile &fHandle) {
fHandle.write(_bgName, 13);
}
+const char *FWRenderer::getBgName(uint idx) const {
+ assert(idx == 0);
+ return _bgName;
+}
+
/*! \brief Restore active and backup palette from save
* \param fHandle Savefile open for reading
*/
@@ -1011,8 +1041,12 @@ void OSRenderer::drawBackground() {
assert(scroll);
- memcpy(_backBuffer, main + mainShift, mainSize);
- memcpy(_backBuffer + mainSize, scroll, mainShift);
+ if (mainSize > 0) { // Just a precaution
+ memcpy(_backBuffer, main + mainShift, mainSize);
+ }
+ if (mainShift > 0) { // Just a precaution
+ memcpy(_backBuffer + mainSize, scroll, mainShift);
+ }
}
}
@@ -1041,6 +1075,19 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
delete[] mask;
break;
+ // game message
+ case 2:
+ if (it->objIdx >= messageTable.size()) {
+ return;
+ }
+
+ _messageLen += messageTable[it->objIdx].size();
+ drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color);
+ if (it->color >= 0) { // This test isn't in Future Wars's implementation
+ waitForPlayerClick = 1;
+ }
+ break;
+
// bitmap
case 4:
if (objectTable[it->objIdx].frame >= 0) {
@@ -1051,16 +1098,27 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
// masked background
case 20:
assert(it->objIdx < NUM_MAX_OBJECT);
+ var5 = it->x; // A global variable updated here!
obj = objectTable + it->objIdx;
sprite = animDataTable + obj->frame;
- if (obj->frame < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) {
+ if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) {
break;
}
maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y);
break;
+ // TODO: Figure out what this overlay type is and name it
+ // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing)
+ case 22: {
+ assert(it->objIdx < NUM_MAX_OBJECT);
+ obj = objectTable + it->objIdx;
+ byte transCol = obj->part & 0x0F;
+ drawPlainBox(obj->x, obj->y, obj->frame, obj->costume, transCol);
+ break;
+ }
+
// something else
default:
FWRenderer::renderOverlay(it);
@@ -1332,6 +1390,11 @@ void OSRenderer::saveBgNames(Common::OutSaveFile &fHandle) {
}
}
+const char *OSRenderer::getBgName(uint idx) const {
+ assert(idx < 9);
+ return _bgTable[idx].name;
+}
+
/*! \brief Fade to black
* \bug Operation Stealth sometimes seems to fade to black using
* transformPalette resulting in double fadeout
diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h
index 6a3aa1ef89..078954e3b9 100644
--- a/engines/cine/gfx.h
+++ b/engines/cine/gfx.h
@@ -111,6 +111,7 @@ public:
virtual uint getScroll() const;
virtual void removeBg(unsigned int idx);
virtual void saveBgNames(Common::OutSaveFile &fHandle);
+ virtual const char *getBgName(uint idx = 0) const;
virtual void refreshPalette();
virtual void reloadPalette();
@@ -168,6 +169,7 @@ public:
uint getScroll() const;
void removeBg(unsigned int idx);
void saveBgNames(Common::OutSaveFile &fHandle);
+ const char *getBgName(uint idx = 0) const;
void refreshPalette();
void reloadPalette();
@@ -181,7 +183,7 @@ public:
void gfxDrawSprite(byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy);
-extern byte *page3Raw;
+extern byte *collisionPage;
extern FWRenderer *renderer;
void setMouseCursor(int cursor);
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index deac4fd57f..9361eb3822 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -121,11 +121,68 @@ static void processEvent(Common::Event &event) {
g_cine->makeSystemMenu();
}
break;
+ case Common::KEYCODE_MINUS:
+ case Common::KEYCODE_KP_MINUS:
+ g_cine->modifyGameSpeed(-1); // Slower
+ break;
+ case Common::KEYCODE_PLUS:
+ case Common::KEYCODE_KP_PLUS:
+ g_cine->modifyGameSpeed(+1); // Faster
+ break;
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_KP4:
+ moveUsingKeyboard(-1, 0); // Left
+ break;
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_KP6:
+ moveUsingKeyboard(+1, 0); // Right
+ break;
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_KP8:
+ moveUsingKeyboard(0, +1); // Up
+ break;
+ case Common::KEYCODE_DOWN:
+ case Common::KEYCODE_KP2:
+ moveUsingKeyboard(0, -1); // Down
+ break;
+ case Common::KEYCODE_KP9:
+ moveUsingKeyboard(+1, +1); // Up & Right
+ break;
+ case Common::KEYCODE_KP7:
+ moveUsingKeyboard(-1, +1); // Up & Left
+ break;
+ case Common::KEYCODE_KP1:
+ moveUsingKeyboard(-1, -1); // Down & Left
+ break;
+ case Common::KEYCODE_KP3:
+ moveUsingKeyboard(+1, -1); // Down & Right
+ break;
default:
lastKeyStroke = event.kbd.keycode;
break;
}
break;
+ case Common::EVENT_KEYUP:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_KP5: // Emulated left mouse button click
+ case Common::KEYCODE_LEFT: // Left
+ case Common::KEYCODE_KP4: // Left
+ case Common::KEYCODE_RIGHT: // Right
+ case Common::KEYCODE_KP6: // Right
+ case Common::KEYCODE_UP: // Up
+ case Common::KEYCODE_KP8: // Up
+ case Common::KEYCODE_DOWN: // Down
+ case Common::KEYCODE_KP2: // Down
+ case Common::KEYCODE_KP9: // Up & Right
+ case Common::KEYCODE_KP7: // Up & Left
+ case Common::KEYCODE_KP1: // Down & Left
+ case Common::KEYCODE_KP3: // Down & Right
+ // Stop ego movement made with keyboard when releasing a known key
+ moveUsingKeyboard(0, 0);
+ break;
+ default:
+ break;
+ }
default:
break;
}
@@ -134,7 +191,7 @@ static void processEvent(Common::Event &event) {
void manageEvents() {
Common::EventManager *eventMan = g_system->getEventManager();
- uint32 nextFrame = g_system->getMillis() + kGameTimerDelay * kGameSpeed;
+ uint32 nextFrame = g_system->getMillis() + g_cine->getTimerDelay();
do {
Common::Event event;
while (eventMan->pollEvent(event)) {
@@ -239,6 +296,38 @@ void CineEngine::mainLoop(int bootScriptIdx) {
}
do {
+ // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence.
+ // This makes it possible to pass the arcade sequence for now.
+ // FIXME: Remove the hack and make the first arcade sequence normally playable.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ Common::String bgName(renderer->getBgName());
+ // Check if the background is one of the three backgrounds
+ // that are only used during the first arcade sequence.
+ if (bgName == "28.PI1" || bgName == "29.PI1" || bgName == "30.PI1") {
+ static const uint oxygenObjNum = 202, maxOxygen = 264;
+ // Force the amount of oxygen left to the maximum.
+ objectTable[oxygenObjNum].x = maxOxygen;
+ }
+ }
+
+ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck.
+ // After the first arcade sequence the player comes up stairs from
+ // the water in Santa Paragua's downtown in front of the flower shop.
+ // Previously he was completely stuck after getting up the stairs.
+ // If the background is the one used in the flower shop scene ("21.PI1")
+ // and the player is at the exact location after getting up the stairs
+ // then we just nudge him a tiny bit away from the stairs and voila, he's free!
+ // Maybe the real problem behind all this is collision data related as it looks
+ // like there's some boundary right there near position (204, 110) which we can
+ // jump over by moving the character to (204, 109). The script handling the
+ // flower shop scene is AIRPORT.PRC's 13th script.
+ // FIXME: Remove the hack and solve what's really causing the problem in the first place.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ if (scumm_stricmp(renderer->getBgName(), "21.PI1") == 0 && objectTable[1].x == 204 && objectTable[1].y == 110) {
+ objectTable[1].y--; // Move the player character upward on-screen by one pixel
+ }
+ }
+
stopMusicAfterFadeOut();
di = executePlayerInput();
@@ -271,6 +360,11 @@ void CineEngine::mainLoop(int bootScriptIdx) {
renderer->drawFrame();
}
+ // NOTE: In the original Future Wars and Operation Stealth messages
+ // were removed when running the drawOverlays function which is
+ // currently called from the renderer's drawFrame function.
+ removeMessages();
+
if (waitForPlayerClick) {
playerAction = false;
@@ -300,8 +394,6 @@ void CineEngine::mainLoop(int bootScriptIdx) {
} while (mouseButton != 0);
waitForPlayerClick = 0;
-
- removeMessages();
}
if (checkForPendingDataLoadSwitch) {
diff --git a/engines/cine/main_loop.h b/engines/cine/main_loop.h
index a2f828fd34..c729b324ca 100644
--- a/engines/cine/main_loop.h
+++ b/engines/cine/main_loop.h
@@ -28,11 +28,6 @@
namespace Cine {
-enum {
- kGameTimerDelay = 1000 / (1193180 / 10923),
- kGameSpeed = 12
-};
-
void mainLoop(int bootScriptIdx);
void manageEvents();
diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp
index 88f2dcef52..d605bdd623 100644
--- a/engines/cine/part.cpp
+++ b/engines/cine/part.cpp
@@ -259,7 +259,13 @@ byte *readBundleSoundFile(const char *entryName, uint32 *size) {
return data;
}
-byte *readFile(const char *filename) {
+/*! \brief Rotate byte value to the left by n bits */
+byte rolByte(byte value, uint n) {
+ n %= 8;
+ return (byte) ((value << n) | (value >> (8 - n)));
+}
+
+byte *readFile(const char *filename, bool crypted) {
Common::File in;
in.open(filename);
@@ -272,6 +278,16 @@ byte *readFile(const char *filename) {
byte *dataPtr = (byte *)malloc(size);
in.read(dataPtr, size);
+ // The Sony published CD version of Future Wars has its
+ // AUTO00.PRC file's bytes rotated to the right by one.
+ // So we decode the so called crypting by rotating all
+ // the bytes to the left by one.
+ if (crypted) {
+ for (uint index = 0; index < size; index++) {
+ dataPtr[index] = rolByte(dataPtr[index], 1);
+ }
+ }
+
return dataPtr;
}
diff --git a/engines/cine/part.h b/engines/cine/part.h
index 2a979e4879..72dc944db3 100644
--- a/engines/cine/part.h
+++ b/engines/cine/part.h
@@ -48,7 +48,7 @@ void readFromPart(int16 idx, byte *dataPtr);
byte *readBundleFile(int16 foundFileIdx);
byte *readBundleSoundFile(const char *entryName, uint32 *size = 0);
-byte *readFile(const char *filename);
+byte *readFile(const char *filename, bool crypted = false);
void checkDataDisk(int16 param);
diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp
index 657edf96af..797a354c4f 100644
--- a/engines/cine/prc.cpp
+++ b/engines/cine/prc.cpp
@@ -64,7 +64,7 @@ bool loadPrc(const char *pPrcName) {
checkDataDisk(-1);
if ((g_cine->getGameType() == Cine::GType_FW) &&
(!scumm_stricmp(pPrcName, BOOT_PRC_NAME) || !scumm_stricmp(pPrcName, "demo.prc"))) {
- scriptPtr = dataPtr = readFile(pPrcName);
+ scriptPtr = dataPtr = readFile(pPrcName, (g_cine->getFeatures() & GF_CRYPTED_BOOT_PRC) != 0);
} else {
scriptPtr = dataPtr = readBundleFile(findFileInBundle(pPrcName));
}
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index e761a0c8e4..97f45488f2 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -1319,6 +1319,7 @@ int FWScript::o1_loadBg() {
return 0;
}
+/*! \brief Load collision table data */
int FWScript::o1_loadCt() {
const char *param = getNextString();
@@ -1789,7 +1790,14 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI
int16 result = 0;
for (int16 i = 0; i < numZones; i++) {
- idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320);
+ // Don't try to read data in Operation Stealth if position isn't in 320x200 screen bounds.
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ if ((lx + i) < 0 || (lx + i) > 319 || ly < 0 || ly > 199) {
+ continue;
+ }
+ }
+
+ idx = getZoneFromPositionRaw(collisionPage, lx + i, ly, 320);
assert(idx >= 0 && idx < NUM_MAX_ZONE);
diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp
index 0289a2a0bc..e8f16ebfcc 100644
--- a/engines/cine/script_os.cpp
+++ b/engines/cine/script_os.cpp
@@ -365,6 +365,7 @@ FWScript *OSScriptInfo::create(const RawObjectScript &script, int16 index, const
// OPERATION STEALTH opcodes
// ------------------------------------------------------------------------
+/*! \brief Load collision table data */
int FWScript::o2_loadCt() {
const char *param = getNextString();
@@ -636,7 +637,28 @@ int FWScript::o2_loadAbs() {
const char *param2 = getNextString();
debugC(5, kCineDebugScript, "Line: %d: loadABS(%d,%s)", _line, param1, param2);
- loadResource(param2, param1);
+ // Load the resource to an absolute position
+ if (loadResource(param2, param1) == -1) { // Check if the loading failed
+ // WORKAROUND: In the 256 color PC version of Operation Stealth when
+ // walking out of the airport in Santa Paragua to the street the
+ // player character should be seen as a grey silhuette while walking
+ // behind the glass. But actually the player character is completely
+ // invisible when walking behind the glass because the animation files
+ // used are wrongly loaded. In AIRPORT.PRC's 6th script there are
+ // calls loadAbs("JOHN01.ANI", 73) and loadAbs("JOHN02.ANI", 37) to
+ // load the animations involved but no such files are found with the
+ // game. Corresponding SET-files are found though. As it worked and
+ // looked fine when I tried loading them instead of the missing ANI
+ // files I'm doing so here. NOTE: At least the German Amiga version
+ // of Operation Stealth seems to have all the files involved
+ // (JOHN01.ANI, JOHN02.ANI, JOHN01.SET and JOHN02.SET).
+ if (scumm_stricmp(param2, "JOHN01.ANI") == 0 && param1 == 73) {
+ loadResource("JOHN01.SET", param1);
+ } else if (scumm_stricmp(param2, "JOHN02.ANI") == 0 && param1 == 37) {
+ loadResource("JOHN02.SET", param1);
+ }
+ }
+
return 0;
}
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index c490756403..0ead13e3ab 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -94,11 +94,23 @@ int16 saveVar2;
byte isInPause = 0;
-// TODO: Implement inputVar0's changes in the program
-// Currently inputVar0 isn't updated anywhere even though it's used at least in processSeqListElement.
-uint16 inputVar0 = 0;
-byte inputVar1 = 0;
-uint16 inputVar2 = 0, inputVar3 = 0;
+/*! \brief Values used by the xMoveKeyb variable */
+enum xMoveKeybEnums {
+ kKeybMoveCenterX = 0,
+ kKeybMoveRight = 1,
+ kKeybMoveLeft = 2
+};
+
+/*! \brief Values used by the yMoveKeyb variable */
+enum yMoveKeybEnums {
+ kKeybMoveCenterY = 0,
+ kKeybMoveDown = 1,
+ kKeybMoveUp = 2
+};
+
+uint16 xMoveKeyb = kKeybMoveCenterX;
+bool egoMovedWithKeyboard = false;
+uint16 yMoveKeyb = kKeybMoveCenterY;
SelectedObjStruct currentSelectedObject;
@@ -115,6 +127,31 @@ int16 objListTab[20];
uint16 zoneData[NUM_MAX_ZONE];
uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth
+/*! \brief Move the player character using the keyboard
+ * \param x Negative values move left, positive right, zero not at all
+ * \param y Negative values move down, positive up, zero not at all
+ * NOTE: If both x and y are zero then the character stops
+ * FIXME: This seems to only work in Operation Stealth. May need code changes somewhere else...
+ */
+void moveUsingKeyboard(int x, int y) {
+ if (x > 0) {
+ xMoveKeyb = kKeybMoveRight;
+ } else if (x < 0) {
+ xMoveKeyb = kKeybMoveLeft;
+ } else {
+ xMoveKeyb = kKeybMoveCenterX;
+ }
+
+ if (y > 0) {
+ yMoveKeyb = kKeybMoveUp;
+ } else if (y < 0) {
+ yMoveKeyb = kKeybMoveDown;
+ } else {
+ yMoveKeyb = kKeybMoveCenterY;
+ }
+
+ egoMovedWithKeyboard = x || y;
+}
void stopMusicAfterFadeOut(void) {
// if (g_sfxPlayer->_fadeOutCounter != 0 && g_sfxPlayer->_fadeOutCounter < 100) {
@@ -139,7 +176,6 @@ void addPlayerCommandMessage(int16 cmd) {
tmp.type = 3;
overlayList.push_back(tmp);
- waitForPlayerClick = 1;
}
int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) {
@@ -1516,6 +1552,7 @@ void makeCommandLine(void) {
}
if (!disableSystemMenu) {
+ isDrawCommandEnabled = 1;
renderer->setCommand(commandBuffer);
}
}
@@ -1688,6 +1725,11 @@ uint16 executePlayerInput(void) {
}
if (allowPlayerInput) {
+ if (isDrawCommandEnabled) {
+ renderer->setCommand(commandBuffer);
+ isDrawCommandEnabled = 0;
+ }
+
getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
while (mouseButton && currentEntry < 200) {
@@ -1868,8 +1910,8 @@ uint16 executePlayerInput(void) {
var_2 = 0;
}
- if (inputVar1 && allowPlayerInput) { // use keyboard
- inputVar1 = 0;
+ if (egoMovedWithKeyboard && allowPlayerInput) { // use keyboard
+ egoMovedWithKeyboard = false;
switch (globalVars[VAR_MOUSE_X_MODE]) {
case 1:
@@ -1901,8 +1943,8 @@ uint16 executePlayerInput(void) {
globalVars[VAR_MOUSE_X_POS] = mouseX;
globalVars[VAR_MOUSE_Y_POS] = mouseY;
} else {
- if (inputVar2) {
- if (inputVar2 == 2) {
+ if (xMoveKeyb) {
+ if (xMoveKeyb == kKeybMoveLeft) {
globalVars[VAR_MOUSE_X_POS] = 1;
} else {
globalVars[VAR_MOUSE_X_POS] = 320;
@@ -1911,8 +1953,8 @@ uint16 executePlayerInput(void) {
globalVars[VAR_MOUSE_X_POS] = mouseX;
}
- if (inputVar3) {
- if (inputVar3 == 2) {
+ if (yMoveKeyb) {
+ if (yMoveKeyb == kKeybMoveUp) {
globalVars[VAR_MOUSE_Y_POS] = 1;
} else {
globalVars[VAR_MOUSE_Y_POS] = 200;
@@ -1994,9 +2036,22 @@ void drawSprite(Common::List<overlay>::iterator it, const byte *spritePtr, const
void removeMessages() {
Common::List<overlay>::iterator it;
+ bool remove;
for (it = overlayList.begin(); it != overlayList.end(); ) {
- if (it->type == 2 || it->type == 3) {
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ // NOTE: These are really removeOverlay calls that have been deferred.
+ // In Operation Stealth's disassembly elements are removed from the
+ // overlay list right in the drawOverlays function (And actually in
+ // some other places too) and that's where incrementing a the overlay's
+ // last parameter by one if it's negative and testing it for positivity
+ // comes from too.
+ remove = it->type == 3 || (it->type == 2 && (it->color >= 0 || ++it->color >= 0));
+ } else { // Future Wars
+ remove = it->type == 2 || it->type == 3;
+ }
+
+ if (remove) {
it = overlayList.erase(it);
} else {
++it;
@@ -2079,7 +2134,6 @@ void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 par
tmp.color = param5;
overlayList.push_back(tmp);
- waitForPlayerClick = 1;
}
Common::List<SeqListElement> seqList;
@@ -2338,9 +2392,9 @@ void processSeqListElement(SeqListElement &element) {
}
computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2);
} else {
- if (inputVar0 && allowPlayerInput) {
+ if (xMoveKeyb && allowPlayerInput) {
int16 adder = param1 + 1;
- if (inputVar0 != 1) {
+ if (xMoveKeyb != kKeybMoveRight) {
adder = -adder;
}
// FIXME: In Operation Stealth's disassembly global variable 251 is used here
@@ -2349,9 +2403,9 @@ void processSeqListElement(SeqListElement &element) {
globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder;
}
- if (inputVar1 && allowPlayerInput) {
+ if (yMoveKeyb && allowPlayerInput) {
int16 adder = param2 + 1;
- if (inputVar1 != 1) {
+ if (yMoveKeyb != kKeybMoveDown) {
adder = -adder;
}
// TODO: Name currently unnamed global variable 252
diff --git a/engines/cine/various.h b/engines/cine/various.h
index 5f24d502be..acab15e235 100644
--- a/engines/cine/various.h
+++ b/engines/cine/various.h
@@ -143,6 +143,7 @@ void processSeqList(void);
void resetGfxEntityEntry(uint16 objIdx);
bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y);
+void moveUsingKeyboard(int x, int y);
} // End of namespace Cine
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index fd14e8c909..0c9b117866 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -295,10 +295,12 @@ int KyraEngine_HoF::go() {
if (_menuChoice != 4) {
// load just the pak files needed for ingame
_res->loadPakFile(StaticResource::staticDataFilename());
- if (_flags.platform == Common::kPlatformPC && _flags.isTalkie)
- _res->loadFileList("FILEDATA.FDT");
- else
+ if (_flags.platform == Common::kPlatformPC && _flags.isTalkie) {
+ if (!_res->loadFileList("FILEDATA.FDT"))
+ error("couldn't load 'FILEDATA.FDT'");
+ } else {
_res->loadFileList(_ingamePakList, _ingamePakListSize);
+ }
if (_flags.platform == Common::kPlatformPC98)
_res->loadPakFile("AUDIO.PAK");
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 148b7daf4d..2011f65b3e 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -87,6 +87,9 @@ int LoLEngine::init() {
_screen->setAnimBlockPtr(10000);
_screen->setScreenDim(0);
+ if (!_sound->init())
+ error("Couldn't init sound");
+
return 0;
}
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index 5d3c5ff715..91150ad354 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -89,14 +89,17 @@ bool Resource::reset() {
return true;
} else if (_vm->game() == GI_KYRA3) {
- if (_vm->gameFlags().useInstallerPackage)
- loadPakFile("WESTWOOD.001");
+ if (_vm->gameFlags().useInstallerPackage) {
+ if (!loadPakFile("WESTWOOD.001"))
+ error("couldn't load file: 'WESTWOOD.001'");
+ }
// Add default file directories
Common::File::addDefaultDirectory(ConfMan.get("path") + "malcolm");
Common::File::addDefaultDirectory(ConfMan.get("path") + "MALCOLM");
- loadFileList("FILEDATA.FDT");
+ if (!loadFileList("FILEDATA.FDT"))
+ error("couldn't load file: 'FILEDATA.FDT'");
return true;
} else if (_vm->game() == GI_LOL) {
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index 0dc7cf2c02..cffd0c7800 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -37,7 +37,7 @@
namespace Kyra {
-KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::InSaveFile *in, SaveHeader &header) {
+KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header) {
uint32 type = in->readUint32BE();
header.originalSave = false;
header.oldHeader = false;
@@ -111,10 +111,10 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::InSave
return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
}
-Common::InSaveFile *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
+Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForReading('%s', -)", filename);
- Common::InSaveFile *in = 0;
+ Common::SeekableReadStream *in = 0;
if (!(in = _saveFileMan->openForLoading(filename)))
return 0;
@@ -162,12 +162,12 @@ Common::InSaveFile *KyraEngine_v1::openSaveForReading(const char *filename, Save
return in;
}
-Common::OutSaveFile *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const {
+Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName) const {
debugC(9, kDebugLevelMain, "KyraEngine_v1::openSaveForWriting('%s', '%s')", filename, saveName);
if (quit())
return 0;
- Common::OutSaveFile *out = 0;
+ Common::WriteStream *out = 0;
if (!(out = _saveFileMan->openForSaving(filename))) {
warning("Can't create file '%s', game not saved", filename);
return 0;
@@ -212,7 +212,7 @@ bool KyraEngine_v1::saveFileLoadable(int slot) {
return false;
SaveHeader header;
- Common::InSaveFile *in = openSaveForReading(getSavegameFilename(slot), header);
+ Common::SeekableReadStream *in = openSaveForReading(getSavegameFilename(slot), header);
if (in) {
delete in;
diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp
index 716c139129..ad4ce63b6c 100644
--- a/engines/kyra/scene_mr.cpp
+++ b/engines/kyra/scene_mr.cpp
@@ -378,10 +378,11 @@ void KyraEngine_MR::loadSceneMsc() {
_screen->loadBitmap(filename, 5, 5, 0, true);
// HACK
- uint8 data[320*200];
+ uint8 *data = new uint8[320*200];
_screen->copyRegionToBuffer(5, 0, 0, 320, 200, data);
_screen->clearPage(5);
_screen->copyBlockToPage(5, 0, _maskPageMinY, 320, height, data);
+ delete[] data;
musicUpdate(0);
}
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index cb9113fe65..b590bba65e 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -364,37 +364,32 @@ void SaveLoadChooser::reflowLayout() {
void SaveLoadChooser::updateInfos(bool redraw) {
int selItem = _list->getSelected();
- Graphics::Surface *thumb;
- thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
+ Graphics::Surface *thumb = 0;
+ if (selItem >= 0 && !_list->getSelectedString().empty())
+ thumb = _vm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
if (thumb) {
_gfxWidget->setGfx(thumb);
_gfxWidget->useAlpha(256);
thumb->free();
+ delete thumb;
} else {
_gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
}
- delete thumb;
- if (redraw)
- _gfxWidget->draw();
-
InfoStuff infos;
memset(&infos, 0, sizeof(InfoStuff));
- char buffer[32];
- if (_vm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
+ if (selItem >= 0 && !_list->getSelectedString().empty()
+ && _vm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
+ char buffer[32];
snprintf(buffer, 32, "Date: %.2d.%.2d.%.4d",
(infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF,
infos.date & 0xFFFF);
_date->setLabel(buffer);
- if (redraw)
- _date->draw();
snprintf(buffer, 32, "Time: %.2d:%.2d",
(infos.time >> 8) & 0xFF, infos.time & 0xFF);
_time->setLabel(buffer);
- if (redraw)
- _time->draw();
int minutes = infos.playtime / 60;
int hours = minutes / 60;
@@ -403,23 +398,17 @@ void SaveLoadChooser::updateInfos(bool redraw) {
snprintf(buffer, 32, "Playtime: %.2d:%.2d",
hours & 0xFF, minutes & 0xFF);
_playtime->setLabel(buffer);
- if (redraw)
- _playtime->draw();
} else {
- snprintf(buffer, 32, "No date saved");
- _date->setLabel(buffer);
- if (redraw)
- _date->draw();
-
- snprintf(buffer, 32, "No time saved");
- _time->setLabel(buffer);
- if (redraw)
- _time->draw();
+ _date->setLabel("No date saved");
+ _time->setLabel("No time saved");
+ _playtime->setLabel("No playtime saved");
+ }
- snprintf(buffer, 32, "No playtime saved");
- _playtime->setLabel(buffer);
- if (redraw)
- _playtime->draw();
+ if (redraw) {
+ _gfxWidget->draw();
+ _date->draw();
+ _time->draw();
+ _playtime->draw();
}
}
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 9268768f2e..c727b59c64 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -769,14 +769,14 @@ void ScummEngine::runInventoryScript(int i) {
args[0] = i;
if (VAR(VAR_INVENTORY_SCRIPT)) {
if (_game.id == GID_INDY3 && _game.platform == Common::kPlatformMacintosh) {
- inventoryScript();
+ inventoryScriptIndy3Mac();
} else {
runScript(VAR(VAR_INVENTORY_SCRIPT), 0, 0, args);
}
}
}
-void ScummEngine::inventoryScript() {
+void ScummEngine::inventoryScriptIndy3Mac() {
VerbSlot *vs;
int args[24];
int j, slot;
@@ -1201,11 +1201,11 @@ void ScummEngine::runInputScript(int clickArea, int val, int mode) {
if (clickArea == kVerbClickArea && (val >= 101 && val <= 108)) {
if (val == 107) {
VAR(67) -= 2;
- inventoryScript();
+ inventoryScriptIndy3Mac();
return;
} else if (val == 108) {
VAR(67) += 2;
- inventoryScript();
+ inventoryScriptIndy3Mac();
return;
} else {
args[0] = 3;
diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
index f8502cbbe7..245dca883a 100644
--- a/engines/scumm/script_v6.cpp
+++ b/engines/scumm/script_v6.cpp
@@ -2390,6 +2390,15 @@ void ScummEngine_v6::o6_talkActor() {
_actorToPrintStrFor = pop();
+ // WORKAROUND for bug #2016521: "DOTT: Bernard impersonating LaVerne"
+ // Original script did not check for VAR_EGO == 2 before executing
+ // a talkActor opcode.
+ if (_game.id == GID_TENTACLE && vm.slot[_currentScript].number == 307
+ && VAR(VAR_EGO) != 2 && _actorToPrintStrFor == 2) {
+ _scriptPointer += resStrLen(_scriptPointer) + 1;
+ return;
+ }
+
_string[0].loadDefault();
actorTalk(_scriptPointer);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index b839d37b08..054a1f59b9 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -669,7 +669,7 @@ protected:
void executeScript();
void updateScriptPtr();
virtual void runInventoryScript(int i);
- void inventoryScript();
+ void inventoryScriptIndy3Mac();
void checkAndRunSentenceScript();
void runExitScript();
void runEntryScript();
diff --git a/engines/touche/graphics.cpp b/engines/touche/graphics.cpp
index 999aa8005c..ab711beba0 100644
--- a/engines/touche/graphics.cpp
+++ b/engines/touche/graphics.cpp
@@ -76,10 +76,13 @@ int Graphics::getCharWidth16(uint8 chr) {
return chrData[2];
}
-void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str) {
+void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax) {
while (*str) {
uint8 chr = (uint8)*str++;
x += drawChar16(dst, dstPitch, chr, x, y, color);
+ if (xmax != 0 && x > xmax) {
+ break;
+ }
}
}
diff --git a/engines/touche/graphics.h b/engines/touche/graphics.h
index 6b4072d896..9c928f983c 100644
--- a/engines/touche/graphics.h
+++ b/engines/touche/graphics.h
@@ -40,7 +40,7 @@ public:
static void setupFont(Common::Language language);
static int getStringWidth16(const char *str);
static int getCharWidth16(uint8 chr);
- static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str);
+ static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax = 0);
static int drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color);
static void fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color);
static void drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2);
diff --git a/engines/touche/staticres.cpp b/engines/touche/staticres.cpp
index ec9a0ea903..a377a6e45f 100644
--- a/engines/touche/staticres.cpp
+++ b/engines/touche/staticres.cpp
@@ -889,6 +889,7 @@ const uint8 Graphics::_freGerFontData[] = {
0xC0, 0x00, 0x00,
};
+// spanish charset differs from original executable, see tracker item #2040311.
const uint16 Graphics::_spaFontOffs[] = {
0x0000, 0x0007, 0x0024, 0x0043, 0x0072, 0x00AD, 0x00E0, 0x0113, 0x0124, 0x0141,
0x015E, 0x0191, 0x01C4, 0x01E3, 0x01F8, 0x0215, 0x0232, 0x0269, 0x0286, 0x02BD,
@@ -904,11 +905,11 @@ const uint16 Graphics::_spaFontOffs[] = {
0x1462, 0x1499, 0x14A4, 0x14DB, 0x1512, 0x1549, 0x1580, 0x15B7, 0x15EE, 0x1625,
0x165C, 0x1667, 0x169E, 0x16D5, 0x16E0, 0x16EB, 0x1722, 0x172D, 0x1738, 0x176F,
0x178C, 0x17C3, 0x17FA, 0x1831, 0x1868, 0x1873, 0x187E, 0x18B5, 0x18C0, 0x18CB,
- 0x18D6, 0x18E1, 0x18FE, 0x1929, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x18D6, 0x18E1, 0x18FE, 0x1929, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x054B,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0703, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x1954
};
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index a7a362f2b1..d1d7528517 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -1256,10 +1256,11 @@ int ToucheEngine::getStringWidth(int num) const {
return Graphics::getStringWidth16(str);
}
-void ToucheEngine::drawString(uint16 color, int x, int y, int16 num) {
+void ToucheEngine::drawString(uint16 color, int x, int y, int16 num, StringType strType) {
+ const int xmax = (_language == Common::ES_ESP && strType == kStringTypeConversation) ? kScreenWidth - 20 : 0;
if (num) {
const char *str = getString(num);
- Graphics::drawString16(_offscreenBuffer, kScreenWidth, color, x, y, str);
+ Graphics::drawString16(_offscreenBuffer, kScreenWidth, color, x, y, str, xmax);
}
}
@@ -2422,7 +2423,7 @@ void ToucheEngine::drawCharacterConversation() {
}
drawConversationPanel();
for (int i = 0; i < 4; ++i) {
- drawString(214, 42, 328 + i * kTextHeight, _conversationChoicesTable[_scrollConversationChoiceOffset + i].msg);
+ drawString(214, 42, 328 + i * kTextHeight, _conversationChoicesTable[_scrollConversationChoiceOffset + i].msg, kStringTypeConversation);
}
updateScreenArea(0, 320, kScreenWidth, kScreenHeight - 320);
_conversationAreaCleared = false;
@@ -2430,7 +2431,7 @@ void ToucheEngine::drawCharacterConversation() {
void ToucheEngine::drawConversationString(int num, uint16 color) {
const int y = 328 + num * kTextHeight;
- drawString(color, 42, y, _conversationChoicesTable[num + _scrollConversationChoiceOffset].msg);
+ drawString(color, 42, y, _conversationChoicesTable[num + _scrollConversationChoiceOffset].msg, kStringTypeConversation);
updateScreenArea(0, y, kScreenWidth, kTextHeight);
}
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index 90ab9933bd..f341769422 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -333,6 +333,11 @@ enum {
kCurrentGameStateVersion = 6 // for --list-saves support
};
+enum StringType {
+ kStringTypeDefault,
+ kStringTypeConversation
+};
+
class MidiPlayer;
class ToucheEngine: public Engine {
@@ -402,7 +407,7 @@ protected:
void setKeyCharMoney();
const char *getString(int num) const;
int getStringWidth(int num) const;
- void drawString(uint16 color, int x, int y, int16 num);
+ void drawString(uint16 color, int x, int y, int16 num, StringType strType = kStringTypeDefault);
void drawGameString(uint16 color, int x1, int y, const char *str);
int restartKeyCharScriptOnAction(int action, int obj1, int obj2);
void buildSpriteScalingTable(int z1, int z2);
diff --git a/graphics/scaler/hq2x_i386.asm b/graphics/scaler/hq2x_i386.asm
index ed194441ed..f176c340c1 100644
--- a/graphics/scaler/hq2x_i386.asm
+++ b/graphics/scaler/hq2x_i386.asm
@@ -1840,3 +1840,8 @@ FuncTable2:
dd ..@cross8, ..@flag0, ..@flag0, ..@flag0,
dd ..@flag0, ..@flag0, ..@flag0, ..@flag0
+
+%ifidn __OUTPUT_FORMAT__,elf
+section .note.GNU-stack noalloc noexec nowrite progbits
+%endif
+
diff --git a/graphics/scaler/hq3x_i386.asm b/graphics/scaler/hq3x_i386.asm
index e713fdd51a..8ffb2d5aba 100644
--- a/graphics/scaler/hq3x_i386.asm
+++ b/graphics/scaler/hq3x_i386.asm
@@ -2432,3 +2432,8 @@ FuncTable2:
dd ..@cross8, ..@flag0, ..@flag0, ..@flag0,
dd ..@flag0, ..@flag0, ..@flag0, ..@flag0
+
+%ifidn __OUTPUT_FORMAT__,elf
+section .note.GNU-stack noalloc noexec nowrite progbits
+%endif
+