aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/agi/graphics.cpp2
-rw-r--r--engines/agi/op_cmd.cpp2
-rw-r--r--engines/agi/sound.cpp8
-rw-r--r--engines/agi/wagparser.cpp2
-rw-r--r--engines/agos/agos.h29
-rw-r--r--engines/agos/draw.cpp2
-rw-r--r--engines/agos/event.cpp2
-rw-r--r--engines/agos/pn.cpp10
-rw-r--r--engines/agos/res_snd.cpp2
-rw-r--r--engines/agos/script_pn.cpp248
-rw-r--r--engines/agos/string.cpp14
-rw-r--r--engines/agos/vga.cpp3
-rw-r--r--engines/agos/vga_e2.cpp22
-rw-r--r--engines/agos/vga_pn.cpp1
-rw-r--r--engines/cine/saveload.cpp24
-rw-r--r--engines/cruise/actor.cpp2
-rw-r--r--engines/cruise/cruise_main.cpp93
-rw-r--r--engines/cruise/ctp.cpp4
-rw-r--r--engines/cruise/menu.cpp2
-rw-r--r--engines/gob/detection.cpp38
-rw-r--r--engines/gob/resources.cpp58
-rw-r--r--engines/gob/resources.h2
-rw-r--r--engines/gob/videoplayer.cpp30
-rw-r--r--engines/gob/videoplayer.h6
-rw-r--r--engines/groovie/resource.cpp2
-rw-r--r--engines/kyra/kyra_lok.cpp2
-rw-r--r--engines/kyra/kyra_v1.cpp5
-rw-r--r--engines/kyra/saveload.cpp2
-rw-r--r--engines/kyra/scene_v2.cpp2
-rw-r--r--engines/kyra/script_lol.cpp4
-rw-r--r--engines/kyra/script_tim.cpp10
-rw-r--r--engines/kyra/sequences_lol.cpp2
-rw-r--r--engines/kyra/sound.h20
-rw-r--r--engines/kyra/sound_adlib.h113
-rw-r--r--engines/kyra/sound_intern.h65
-rw-r--r--engines/kyra/sound_pcspk.cpp31
-rw-r--r--engines/sci/detection.cpp30
-rw-r--r--engines/sci/gfx/gfx_resmgr.cpp2
-rw-r--r--engines/sci/gfx/gfx_resmgr.h8
-rw-r--r--engines/sci/gfx/gfx_system.h2
-rw-r--r--engines/sci/gfx/operations.cpp5
-rw-r--r--engines/sci/gfx/res_pal.cpp5
-rw-r--r--engines/scumm/dialogs.cpp15
-rw-r--r--engines/scumm/dialogs.h1
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.cpp6
-rw-r--r--engines/scumm/input.cpp17
-rw-r--r--engines/scumm/player_v2.h4
-rw-r--r--engines/scumm/script.cpp11
-rw-r--r--engines/scumm/script_v6.cpp5
-rw-r--r--engines/scumm/scumm.cpp1
-rw-r--r--engines/scumm/scumm_v6.h1
-rw-r--r--engines/scumm/scumm_v7.h1
-rw-r--r--engines/scumm/string.cpp3
-rw-r--r--engines/sky/grid.cpp6
-rw-r--r--engines/sky/logic.cpp9
-rw-r--r--engines/sky/sky.cpp7
-rw-r--r--engines/sword1/sound.cpp16
-rw-r--r--engines/tinsel/handle.cpp4
-rw-r--r--engines/tinsel/pcode.cpp147
-rw-r--r--engines/tinsel/pcode.h14
-rw-r--r--engines/touche/saveload.cpp6
-rw-r--r--engines/tucker/saveload.cpp2
62 files changed, 724 insertions, 468 deletions
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index ad2c264184..3461bb473e 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -846,7 +846,7 @@ void GfxMgr::setAGIPal(int p0) {
//Chunks4-7 are duplicates of chunks0-3
- if (agipal.ioFailed()) {
+ if (agipal.eos() || agipal.err()) {
warning("Couldn't read AGIPAL palette from '%s'. Not changing palette", filename);
return;
}
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 97255097bc..7012174c20 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1256,7 +1256,7 @@ cmd(restart_game) {
int sel;
g_sound->stopSound();
- sel = g_agi->getflag(fAutoRestart) ? 1 :
+ sel = g_agi->getflag(fAutoRestart) ? 0 :
g_agi->selectionBox(" Restart game, or continue? \n\n\n", buttons);
if (sel == 0) {
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index fb73c6b71f..5a39b663a5 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -133,7 +133,7 @@ bool IIgsEnvelope::read(Common::SeekableReadStream &stream) {
seg[segNum].inc = stream.readUint16LE();
}
- return !stream.ioFailed();
+ return !(stream.eos() || stream.err());
}
/** Reads an Apple IIGS wave information structure from the given stream. */
@@ -154,7 +154,7 @@ bool IIgsWaveInfo::read(Common::SeekableReadStream &stream, bool ignoreAddr) {
if (ignoreAddr)
addr = 0;
- return !stream.ioFailed();
+ return !(stream.eos() || stream.err());
}
bool IIgsWaveInfo::finalize(Common::SeekableReadStream &uint8Wave) {
@@ -219,7 +219,7 @@ bool IIgsInstrumentHeader::read(Common::SeekableReadStream &stream, bool ignoreA
byte wac = stream.readByte(); // Read A wave count
byte wbc = stream.readByte(); // Read B wave count
oscList.read(stream, wac, ignoreAddr); // Read the oscillators
- return (wac == wbc) && !stream.ioFailed(); // A and B wave counts must match
+ return (wac == wbc) && !(stream.eos() || stream.err()); // A and B wave counts must match
}
bool IIgsInstrumentHeader::finalize(Common::SeekableReadStream &uint8Wave) {
@@ -1158,7 +1158,7 @@ bool SoundMgr::convertWave(Common::SeekableReadStream &source, int8 *dest, uint
// Convert the wave from 8-bit unsigned to 8-bit signed format
for (uint i = 0; i < length; i++)
dest[i] = (int8) ((int) source.readByte() - 128);
- return !source.ioFailed();
+ return !(source.eos() || source.err());
}
bool IIgsSoundMgr::loadWaveFile(const Common::FSNode &wavePath, const IIgsExeInfo &exeInfo) {
diff --git a/engines/agi/wagparser.cpp b/engines/agi/wagparser.cpp
index e6ed5345e0..d243439dff 100644
--- a/engines/agi/wagparser.cpp
+++ b/engines/agi/wagparser.cpp
@@ -70,7 +70,7 @@ bool WagProperty::read(Common::SeekableReadStream &stream) {
_propNum = stream.readByte();
_propSize = stream.readUint16LE();
- if (stream.ioFailed()) { // Check that we got the whole header
+ if (stream.eos() || stream.err()) { // Check that we got the whole header
_readOk = false;
return _readOk;
}
diff --git a/engines/agos/agos.h b/engines/agos/agos.h
index 093f7bb039..263811b78a 100644
--- a/engines/agos/agos.h
+++ b/engines/agos/agos.h
@@ -1265,8 +1265,8 @@ protected:
#ifdef ENABLE_PN
class AGOSEngine_PN : public AGOSEngine {
- struct stackframe {
- struct stackframe *nextframe;
+ struct StackFrame {
+ StackFrame *nextframe;
int16 flag[6];
int16 param[8];
int16 classnum;
@@ -1276,7 +1276,7 @@ class AGOSEngine_PN : public AGOSEngine {
int16 linenum;
int16 process;
jmp_buf *savearea;
- stackframe() { memset(this, 0, sizeof(*this)); }
+ StackFrame() { memset(this, 0, sizeof(*this)); }
};
@@ -1284,6 +1284,7 @@ class AGOSEngine_PN : public AGOSEngine {
void demoSeq();
void introSeq();
void setupBoxes();
+ int readfromline();
public:
AGOSEngine_PN(OSystem *system);
~AGOSEngine_PN();
@@ -1297,10 +1298,10 @@ public:
int actCallD(int n);
void opn_opcode00();
- void opn_opcode01();
- void opn_opcode02();
- void opn_opcode03();
- void opn_opcode04();
+ void opn_add();
+ void opn_sub();
+ void opn_mul();
+ void opn_div();
void opn_opcode05();
void opn_opcode06();
void opn_opcode07();
@@ -1313,10 +1314,10 @@ public:
void opn_opcode14();
void opn_opcode15();
void opn_opcode16();
- void opn_opcode17();
- void opn_opcode18();
- void opn_opcode19();
- void opn_opcode20();
+ void opn_lt();
+ void opn_gt();
+ void opn_eq();
+ void opn_neq();
void opn_opcode21();
void opn_opcode22();
void opn_opcode23();
@@ -1357,14 +1358,14 @@ public:
void opn_opcode62();
void opn_opcode63();
- stackframe *_stackbase;
+ StackFrame *_stackbase;
byte *_dataBase, *_textBase;
uint32 _dataBaseSize, _textBaseSize;
HitArea _invHitAreas[45];
- char _buffer[80];
+ char _buffer[80];
char _inputline[61];
char _saveFile[20];
char _sb[80];
@@ -1390,7 +1391,7 @@ public:
uint16 _objects;
int16 _objectCountS;
- int16 _bp;
+ int16 _bp;
int16 _xofs;
int16 _havinit;
uint16 _seed;
diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp
index d09f02c76d..45443aa335 100644
--- a/engines/agos/draw.cpp
+++ b/engines/agos/draw.cpp
@@ -503,7 +503,7 @@ void AGOSEngine::saveBackGround(VgaSprite *vsp) {
animTable->y = y;
animTable->width = READ_BE_UINT16(ptr + 6) / 16;
- if (vsp->flags & 40) {
+ if (vsp->flags & 0x40) {
animTable->width++;
}
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
index b9c16d3d86..cbb09e1ec7 100644
--- a/engines/agos/event.cpp
+++ b/engines/agos/event.cpp
@@ -484,7 +484,7 @@ void AGOSEngine::delay(uint amount) {
_fastMode ^= 1;
} else if (event.kbd.keycode == Common::KEYCODE_d) {
_debugger->attach();
- } else if (event.kbd.keycode == Common::KEYCODE_u) {
+ } else if (event.kbd.keycode == Common::KEYCODE_s) {
dumpAllSubroutines();
} else if (event.kbd.keycode == Common::KEYCODE_i) {
dumpAllVgaImageFiles();
diff --git a/engines/agos/pn.cpp b/engines/agos/pn.cpp
index fd88d63ec3..d92efa9077 100644
--- a/engines/agos/pn.cpp
+++ b/engines/agos/pn.cpp
@@ -269,16 +269,16 @@ void AGOSEngine_PN::processor() {
_variableArray[16] = _quickshort[6];
_variableArray[17] = _quickshort[7];
_variableArray[19] = getptr(55L);
+
+ // q indicates the process to run and is 0 the first time,
+ // but 1 later on (i.e., when we are "called" from badload()).
setposition(q, 0);
doline(0);
}
void AGOSEngine_PN::setqptrs() {
- int a = 0;
-
- while (a < 11) {
- _quickptr[a] = getlong(3L * a);
- a++;
+ for (int i = 0; i < 11; ++i) {
+ _quickptr[i] = getlong(3 * i);
}
_quickptr[11] = getlong(58L);
_quickptr[12] = getlong(61L);
diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp
index 810f953bd7..e85440d8e1 100644
--- a/engines/agos/res_snd.cpp
+++ b/engines/agos/res_snd.cpp
@@ -332,7 +332,7 @@ void AGOSEngine::playSting(uint16 soundId) {
mus_file.seek(soundId * 2, SEEK_SET);
mus_offset = mus_file.readUint16LE();
- if (mus_file.ioFailed())
+ if (mus_file.err())
error("playSting: Can't read sting %d offset", soundId);
mus_file.seek(mus_offset, SEEK_SET);
diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp
index 62ca94e387..4f9aab2965 100644
--- a/engines/agos/script_pn.cpp
+++ b/engines/agos/script_pn.cpp
@@ -30,17 +30,21 @@
namespace AGOS {
+enum {
+ kJmpClassNum = -1
+};
+
#define OPCODE(x) _OPCODE(AGOSEngine_PN, x)
void AGOSEngine_PN::setupOpcodes() {
static const OpcodeEntryPN opcodes[] = {
/* 00 */
OPCODE(opn_opcode00),
- OPCODE(opn_opcode01),
- OPCODE(opn_opcode02),
- OPCODE(opn_opcode03),
+ OPCODE(opn_add),
+ OPCODE(opn_sub),
+ OPCODE(opn_mul),
/* 04 */
- OPCODE(opn_opcode04),
+ OPCODE(opn_div),
OPCODE(opn_opcode05),
OPCODE(opn_opcode06),
OPCODE(opn_opcode07),
@@ -56,11 +60,11 @@ void AGOSEngine_PN::setupOpcodes() {
OPCODE(opn_opcode15),
/* 16 */
OPCODE(opn_opcode16),
- OPCODE(opn_opcode17),
- OPCODE(opn_opcode18),
- OPCODE(opn_opcode19),
+ OPCODE(opn_lt),
+ OPCODE(opn_gt),
+ OPCODE(opn_eq),
/* 20 */
- OPCODE(opn_opcode20),
+ OPCODE(opn_neq),
OPCODE(opn_opcode21),
OPCODE(opn_opcode22),
OPCODE(opn_opcode23),
@@ -122,13 +126,14 @@ void AGOSEngine_PN::setupOpcodes() {
void AGOSEngine_PN::executeOpcode(int opcode) {
OpcodeProcPN op = _opcodesPN[opcode].proc;
- (this->*op) ();
+ (this->*op)();
}
-#define readfromline() (_linct-- ? (int)*_workptr++ : readoverr())
-
-int readoverr() {
- error("readfromline: Internal Error - Line Over-run");
+int AGOSEngine_PN::readfromline() {
+ if (!_linct)
+ error("readfromline: Internal Error - Line Over-run");
+ _linct--;
+ return *_workptr++;
}
// -----------------------------------------------------------------------
@@ -142,30 +147,30 @@ void AGOSEngine_PN::opn_opcode00() {
setScriptReturn(true);
}
-void AGOSEngine_PN::opn_opcode01() {
+void AGOSEngine_PN::opn_add() {
uint8 *str = _workptr;
int32 sp = varval() + varval();
_variableArray[12] = sp % 65536;
_variableArray[13] = sp / 65536;
if (sp > 65535)
- sp=65535;
+ sp = 65535;
writeval(str, (int)sp);
setScriptReturn(true);
}
-void AGOSEngine_PN::opn_opcode02() {
+void AGOSEngine_PN::opn_sub() {
uint8 *str = _workptr;
int32 sp = varval();
sp -= varval();
_variableArray[12] = sp % 65536;
_variableArray[13] = sp / 65536;
- if(sp < 0)
+ if (sp < 0)
sp = 0;
writeval(str, (int)sp);
setScriptReturn(true);
}
-void AGOSEngine_PN::opn_opcode03() {
+void AGOSEngine_PN::opn_mul() {
uint8 *str = _workptr;
int32 sp = varval() * varval();
_variableArray[12] = sp % 65536;
@@ -176,12 +181,12 @@ void AGOSEngine_PN::opn_opcode03() {
setScriptReturn(true);
}
-void AGOSEngine_PN::opn_opcode04() {
+void AGOSEngine_PN::opn_div() {
uint8 *str = _workptr;
int32 sp = varval();
int32 sp2 = varval();
if (sp2 == 0)
- error("Division by 0");
+ error("opn_div: Division by 0");
sp = sp / sp2;
_variableArray[12] = sp % 65536;
_variableArray[13] = sp / 65536;
@@ -234,7 +239,7 @@ void AGOSEngine_PN::opn_opcode12() {
char bf[8];
int a = 0;
sprintf(bf,"%d", varval());
- while(bf[a])
+ while (bf[a])
pcf(bf[a++]);
setScriptReturn(true);
}
@@ -243,7 +248,7 @@ void AGOSEngine_PN::opn_opcode13() {
char bf[8];
int a = 0;
sprintf(bf,"%d", varval());
- while(bf[a])
+ while (bf[a])
pcf(bf[a++]);
pcf((uint8)'\n');
setScriptReturn(true);
@@ -271,25 +276,25 @@ void AGOSEngine_PN::opn_opcode16() {
setScriptReturn((sp >= 0 && sp <= 4));
}
-void AGOSEngine_PN::opn_opcode17() {
+void AGOSEngine_PN::opn_lt() {
int16 v1 = varval();
int16 v2 = varval();
setScriptReturn(v1 < v2);
}
-void AGOSEngine_PN::opn_opcode18() {
+void AGOSEngine_PN::opn_gt() {
int16 v1 = varval();
int16 v2 = varval();
setScriptReturn(v1 > v2);
}
-void AGOSEngine_PN::opn_opcode19() {
+void AGOSEngine_PN::opn_eq() {
int16 v1 = varval();
int16 v2 = varval();
setScriptReturn(v1 == v2);
}
-void AGOSEngine_PN::opn_opcode20() {
+void AGOSEngine_PN::opn_neq() {
int16 v1 = varval();
int16 v2 = varval();
setScriptReturn(v1 != v2);
@@ -302,11 +307,10 @@ void AGOSEngine_PN::opn_opcode21() {
void AGOSEngine_PN::opn_opcode22() {
int pf[8];
- int a;
- a = varval();
- funcentry(pf, a);
+ int n = varval();
+ funcentry(pf, n);
funccpy(pf);
- setposition(a, 0);
+ setposition(n, 0);
setScriptReturn(true);
}
@@ -315,19 +319,27 @@ void AGOSEngine_PN::opn_opcode23() {
}
void AGOSEngine_PN::opn_opcode24() {
- popstack(-1);
+ popstack(kJmpClassNum);
+ // Jump back to the last doline, which will return 2-1=1.
+ // That value then is returned to actCallD, which once again
+ // returns it. In the end, this amounts to a setScriptReturn(true)
+ // (but possibly in a different level than the current one).
longjmp(*(_stackbase->savearea), 2);
setScriptReturn(false);
}
void AGOSEngine_PN::opn_opcode25() {
- popstack(-1);
+ popstack(kJmpClassNum);
+ // Jump back to the last doline, which will return 1-1=0.
+ // That value then is returned to actCallD, which once again
+ // returns it. In the end, this amounts to a setScriptReturn(false)
+ // (but possibly in a different level than the current one).
longjmp(*(_stackbase->savearea), 1);
setScriptReturn(false);
}
void AGOSEngine_PN::opn_opcode26() {
- while ((_stackbase->classnum != -1) && (_stackbase != NULL))
+ while ((_stackbase != NULL) && (_stackbase->classnum != kJmpClassNum))
junkstack();
dumpstack();
setScriptReturn(true);
@@ -347,6 +359,8 @@ void AGOSEngine_PN::opn_opcode28() {
void AGOSEngine_PN::opn_opcode29() {
popstack(varval());
+ // Jump back to the last doline indicated by the top stackfram.
+ // The -1 tells it to simply go on with its business.
longjmp(*(_stackbase->savearea), -1);
setScriptReturn(false);
}
@@ -395,7 +409,8 @@ void AGOSEngine_PN::opn_opcode32() {
char bf[60];
int a, slot;
- if ((a = varval()) > 2) {
+ a = varval();
+ if (a > 2) {
setScriptReturn(true);
return;
}
@@ -451,10 +466,8 @@ void AGOSEngine_PN::opn_opcode35() {
}
void AGOSEngine_PN::opn_opcode36() {
- int ct = 0;
- while (ct < _dataBase[57] + 1)
- _wordcp[ct++] = 0;
- ct = 1;
+ for (int i = 0; i < _dataBase[57] + 1; ++i)
+ _wordcp[i] = 0;
if (isspace(*_inpp))
while ((*_inpp) && (isspace(*_inpp)))
_inpp++;
@@ -468,6 +481,8 @@ void AGOSEngine_PN::opn_opcode36() {
setScriptReturn(true);
return;
}
+
+ int ct = 1;
while ((*_inpp != '.') && (*_inpp != ',') && (!isspace(*_inpp)) && (*_inpp != '\0') &&
(*_inpp!='"')) {
if (ct < _dataBase[57])
@@ -734,37 +749,38 @@ int AGOSEngine_PN::varval() {
int a;
int b;
- if ((a = readfromline()) < 247) {
+ a = readfromline();
+ if (a < 247) {
return a;
}
switch (a) {
case 249:
b = readfromline();
- return((int)(b + 256 * readfromline()));
+ return (int)(b + 256 * readfromline());
break;
case 250:
- return(readfromline());
+ return readfromline();
case 251:
- return((int)_variableArray[varval()]);
+ return (int)_variableArray[varval()];
case 252:
b = varval();
- return((int)_dataBase[_quickptr[0] + b * _quickshort[0] + varval()]);
+ return (int)_dataBase[_quickptr[0] + b * _quickshort[0] + varval()];
case 254:
b = varval();
- return((int)_dataBase[_quickptr[3] + b * _quickshort[2] + varval()]);
+ return (int)_dataBase[_quickptr[3] + b * _quickshort[2] + varval()];
case 247:
b = varval();
- return((int)getptr(_quickptr[11] + (b * _quickshort[4]) + (2 * varval())));
+ return (int)getptr(_quickptr[11] + (b * _quickshort[4]) + (2 * varval()));
case 248:
b = varval();
- return((int)getptr(_quickptr[12] + (b * _quickshort[5]) + (2 * varval())));
+ return (int)getptr(_quickptr[12] + (b * _quickshort[5]) + (2 * varval()));
case 253:
b = varval();
- return(bitextract((int32)_quickptr[1] + b * _quickshort[1], varval()));
+ return bitextract((int32)_quickptr[1] + b * _quickshort[1], varval());
case 255:
b = varval();
- return(bitextract((int32)_quickptr[4] + b * _quickshort[3], varval()));
+ return bitextract((int32)_quickptr[4] + b * _quickshort[3], varval());
default:
error("VARVAL : Illegal code %d encountered", a);
}
@@ -834,10 +850,10 @@ void AGOSEngine_PN::setbitf(uint32 ptr, int offs, int val) {
int AGOSEngine_PN::actCallD(int n) {
int pf[8];
funcentry(pf, n);
- addstack(-1);
+ addstack(kJmpClassNum);
funccpy(pf);
setposition(n, 0);
- return(doline(1));
+ return doline(1);
}
int AGOSEngine_PN::doaction() {
@@ -859,47 +875,59 @@ int AGOSEngine_PN::doaction() {
int AGOSEngine_PN::doline(int needsave) {
int x;
- jmp_buf *ljmpbuff = NULL;
+ jmp_buf *old_jmpbuf = NULL;
jmp_buf *mybuf;
mybuf = (jmp_buf *)malloc(sizeof(jmp_buf));
if (mybuf == NULL)
error("doline: Out of memory - stack overflow");
- if ((x = setjmp(*mybuf)) > 0) {
+ x = setjmp(*mybuf);
+ // Looking at the longjmp calls below, x can be -1, 1 or 2
+ // (and of course 0 when it returns directly, as always).
+ if (x > 0) {
dumpstack();
- _cjmpbuff = ljmpbuff;
+ // Restore the active jmpbuf to its previous value,
+ // then return the longjmp value (will be 2-1=1 or 1-1=0).
+ _cjmpbuff = old_jmpbuf;
free((char *)mybuf);
return (x - 1);
}
if (x == -1) {
+ // Make this doline instance the active one (again).
+ // This is used to "return" over possibly multiple
+ // layers of nested script invocations.
+ // Kind of like throwing an exception.
_cjmpbuff = mybuf;
goto carryon;
}
- ljmpbuff = _cjmpbuff;
+
+ // Remember the previous active jmpbuf (gets restored
+ // above when a longjmp with a positive param occurs).
+ old_jmpbuf = _cjmpbuff;
_cjmpbuff = mybuf;
if (needsave)
_stackbase->savearea = mybuf;
-nln: _linct = ((*_linebase) & 127) - 1;
- _workptr = _linebase + 1;
- if (*_linebase > 127) {
- x = varval();
- if (x != (int)_variableArray[1])
- goto skipln;
- }
-
-carryon:
do {
- x = doaction();
- } while (x && !shouldQuit());
+ _linct = ((*_linebase) & 127) - 1;
+ _workptr = _linebase + 1;
+ if (*_linebase > 127) {
+ x = varval();
+ if (x != (int)_variableArray[1])
+ goto skipln;
+ }
-skipln: _linebase += 127 & *_linebase;
- _linembr++;
+carryon:
+ do {
+ x = doaction();
+ } while (x && !shouldQuit());
- if (!shouldQuit())
- goto nln;
+skipln:
+ _linebase += 127 & *_linebase;
+ _linembr++;
+ } while (!shouldQuit());
return 0;
}
@@ -951,23 +979,15 @@ int AGOSEngine_PN::findset() {
}
void AGOSEngine_PN::funccpy(int *store) {
- int a = 0;
- int b = 24;
-
- while (a < 8) {
- _variableArray[b++] = *store++;
- a++;
+ for (int i = 24; i < 32; ++i) {
+ _variableArray[i] = *store++;
}
}
void AGOSEngine_PN::funcentry(int *store, int procn) {
- int ct = 0;
- int nprm;
-
- nprm = _dataBase[getlong(_quickptr[6] + 3L * procn)];
- while (ct < nprm) {
+ int numParams = _dataBase[getlong(_quickptr[6] + 3 * procn)];
+ for (int i = 0; i < numParams; ++i) {
*store++ = varval();
- ct++;
}
}
@@ -990,23 +1010,28 @@ int AGOSEngine_PN::gvwrd(uint8 *wptr, int mask) {
int AGOSEngine_PN::setposition(int process, int line) {
uint8 *ourptr;
int np;
- int ct = 0;
- ourptr = _dataBase + getlong(_quickptr[6] + 3L * process);
+ int ct;
+
+ ourptr = _dataBase + getlong(_quickptr[6] + 3 * process);
np = *ourptr++;
- while (ct < line) {
+ for (ct = 0; ct < line; ++ct) {
ourptr += (127 & *ourptr);
- ct++;
}
-x1: _linebase = ourptr;
- _linct = (127 & (*ourptr)) - 1;
- if (*ourptr++ > 127) {
+
+ while (true) {
+ _linebase = ourptr;
+ _linct = (127 & *ourptr) - 1;
+ if (*ourptr++ <= 127)
+ break;
+
ct = varval();
- if (ct != (int)_variableArray[1]) {
- ourptr += _linct - 1;
- line++;
- goto x1;
- }
+ if (ct == (int)_variableArray[1])
+ break;
+
+ ourptr += _linct - 1;
+ line++;
}
+
_linembr = line;
_procnum = process;
_variableArray[0] = process;
@@ -1035,22 +1060,20 @@ int AGOSEngine_PN::wrdmatch(uint8 *word1, int mask1, uint8 *word2, int mask2) {
// -----------------------------------------------------------------------
void AGOSEngine_PN::addstack(int type) {
- struct stackframe *a;
- int pt, ct = 0;
+ StackFrame *a;
+ int i;
- a = (struct stackframe *)malloc(sizeof(struct stackframe));
+ a = (StackFrame *)malloc(sizeof(StackFrame));
if (a == NULL)
error("addstack: Out of memory - stack overflow");
a->nextframe = _stackbase;
_stackbase = a;
- pt = 0;
- while (ct < 6)
- a->flag[ct++] = _variableArray[pt++];
- ct = 0;
- pt = 24;
- while (ct < 8)
- a->param[ct++] = _variableArray[pt++];
+
+ for (i = 0; i < 6; ++i)
+ a->flag[i] = _variableArray[i];
+ for (i = 0; i < 8; ++i)
+ a->param[i] = _variableArray[24 + i];
a->classnum = type;
a->ll = _linct;
a->linenum = _linembr;
@@ -1060,7 +1083,7 @@ void AGOSEngine_PN::addstack(int type) {
}
void AGOSEngine_PN::dumpstack() {
- struct stackframe *a;
+ StackFrame *a;
if (_stackbase == NULL)
error("dumpstack: Stack underflow or unknown longjmp");
@@ -1071,20 +1094,20 @@ void AGOSEngine_PN::dumpstack() {
}
void AGOSEngine_PN::junkstack() {
- struct stackframe *a;
+ StackFrame *a;
if (_stackbase == NULL)
error("junkstack: Stack underflow or unknown longjmp");
a = _stackbase->nextframe;
- if (_stackbase->classnum == -1)
+ if (_stackbase->classnum == kJmpClassNum)
free((char *)_stackbase->savearea);
free((char *)_stackbase);
_stackbase = a;
}
void AGOSEngine_PN::popstack(int type) {
- int a = 0, b;
+ int i;
while ((_stackbase != NULL) && (_stackbase->classnum != type))
junkstack();
@@ -1097,13 +1120,10 @@ void AGOSEngine_PN::popstack(int type) {
_workptr = _stackbase->linpos;
_procnum = _stackbase->process;
_linembr = _stackbase->linenum;
- b = 0;
- while (a < 6)
- _variableArray[b++] = _stackbase->flag[a++];
- b = 24;
- a = 0;
- while (a < 8)
- _variableArray[b++] = _stackbase->param[a++];
+ for (i = 0; i < 6; ++i)
+ _variableArray[i] = _stackbase->flag[i];
+ for (i = 0; i < 8; ++i)
+ _variableArray[24 + i] = _stackbase->param[i];
}
} // End of namespace AGOS
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index a466be796f..3773b1fa10 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -136,6 +136,20 @@ const byte *AGOSEngine::getStringPtrByID(uint16 stringId, bool upperCase) {
strcpy((char *)dst, (const char *)stringPtr);
}
+ // WORKAROUND bug #1538873: The French version of Simon 1 and the
+ // Polish version of Simon 2 used excess spaces, at the end of many
+ // messages, so we strip off those excess spaces.
+ if ((getGameType() == GType_SIMON1 && _language == Common::FR_FRA) ||
+ (getGameType() == GType_SIMON2 && _language == Common::PL_POL)) {
+ uint16 len = strlen((const char *)dst) - 1;
+
+ while (len && dst[len] == 32) {
+ dst[len] = 0;
+ len--;
+ }
+
+ }
+
if (upperCase && *dst) {
if (islower(*dst))
*dst = toupper(*dst);
diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp
index d2e620d86e..d37681508e 100644
--- a/engines/agos/vga.cpp
+++ b/engines/agos/vga.cpp
@@ -1186,7 +1186,8 @@ void AGOSEngine::vc32_saveScreen() {
byte *src = (byte *)screen->pixels;
for (int i = 0; i < _screenHeight; i++) {
memcpy(dst, src, _screenWidth);
- dst += screen->pitch;
+ dst += _backGroundBuf->pitch;
+ src += screen->pitch;
}
_system->unlockScreen();
} else {
diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp
index 7f02398e13..f6e6630d43 100644
--- a/engines/agos/vga_e2.cpp
+++ b/engines/agos/vga_e2.cpp
@@ -207,6 +207,7 @@ void AGOSEngine::vc53_dissolveIn() {
uint16 speed = vcReadNextWord() + 1;
byte *src, *dst, *srcOffs, *srcOffs2, *dstOffs, *dstOffs2;
+ int16 xoffs, yoffs;
uint8 color = 0;
// Only uses Video Window 4
@@ -218,15 +219,13 @@ void AGOSEngine::vc53_dissolveIn() {
uint16 dissolveDelay = dissolveCheck * 2 / speed;
uint16 dissolveCount = dissolveCheck * 2 / speed;
- Graphics::Surface *screen = _system->lockScreen();
-
- int16 xoffs = _videoWindows[num * 4 + 0] * 16;
- int16 yoffs = _videoWindows[num * 4 + 1];
- int16 offs = xoffs + yoffs * screen->pitch;
+ int16 x = _videoWindows[num * 4 + 0] * 16;
+ int16 y = _videoWindows[num * 4 + 1];
uint16 count = dissolveCheck * 2;
while (count--) {
- byte *dstPtr = (byte *)screen->pixels + offs;
+ Graphics::Surface *screen = _system->lockScreen();
+ byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch;
yoffs = _rnd.getRandomNumber(dissolveY);
dst = dstPtr + yoffs * screen->pitch;
@@ -285,6 +284,7 @@ void AGOSEngine::vc54_dissolveOut() {
uint16 speed = vcReadNextWord() + 1;
byte *dst, *dstOffs;
+ int16 xoffs, yoffs;
uint16 dissolveX = _videoWindows[num * 4 + 2] * 8;
uint16 dissolveY = (_videoWindows[num * 4 + 3] + 1) / 2;
@@ -292,15 +292,13 @@ void AGOSEngine::vc54_dissolveOut() {
uint16 dissolveDelay = dissolveCheck * 2 / speed;
uint16 dissolveCount = dissolveCheck * 2 / speed;
- Graphics::Surface *screen = _system->lockScreen();
-
- int16 xoffs = _videoWindows[num * 4 + 0] * 16;
- int16 yoffs = _videoWindows[num * 4 + 1];
- int16 offs = xoffs + yoffs * screen->pitch;
+ int16 x = _videoWindows[num * 4 + 0] * 16;
+ int16 y = _videoWindows[num * 4 + 1];
uint16 count = dissolveCheck * 2;
while (count--) {
- byte *dstPtr = (byte *)screen->pixels + offs;
+ Graphics::Surface *screen = _system->lockScreen();
+ byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch;
color |= dstPtr[0] & 0xF0;
yoffs = _rnd.getRandomNumber(dissolveY);
diff --git a/engines/agos/vga_pn.cpp b/engines/agos/vga_pn.cpp
index 32c6e15f00..12846b08f1 100644
--- a/engines/agos/vga_pn.cpp
+++ b/engines/agos/vga_pn.cpp
@@ -129,7 +129,6 @@ void AGOSEngine::vc36_pause() {
_keyPressed.reset();
windowPutChar(_windowArray[2], 13);
- windowPutChar(_windowArray[2], 128);
_wiped = oldWiped;
_videoLockOut &= ~8;
diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp
index ea0ff0079b..be1e19b229 100644
--- a/engines/cine/saveload.cpp
+++ b/engines/cine/saveload.cpp
@@ -49,7 +49,7 @@ bool loadChunkHeader(Common::SeekableReadStream &in, ChunkHeader &header) {
header.id = in.readUint32BE();
header.version = in.readUint32BE();
header.size = in.readUint32BE();
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
/*! \brief Savegame format detector
@@ -240,21 +240,21 @@ bool loadObjectTable(Common::SeekableReadStream &in) {
in.read(objectTable[i].name, 20);
objectTable[i].part = in.readUint16BE();
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadZoneData(Common::SeekableReadStream &in) {
for (int i = 0; i < 16; i++) {
zoneData[i] = in.readUint16BE();
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadCommandVariables(Common::SeekableReadStream &in) {
for (int i = 0; i < 4; i++) {
commandVar3[i] = in.readUint16BE();
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadScreenParams(Common::SeekableReadStream &in) {
@@ -265,7 +265,7 @@ bool loadScreenParams(Common::SeekableReadStream &in) {
in.readUint16BE();
in.readUint16BE();
in.readUint16BE();
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadGlobalScripts(Common::SeekableReadStream &in) {
@@ -273,7 +273,7 @@ bool loadGlobalScripts(Common::SeekableReadStream &in) {
for (int i = 0; i < size; i++) {
loadScriptFromSave(in, true);
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadObjectScripts(Common::SeekableReadStream &in) {
@@ -281,7 +281,7 @@ bool loadObjectScripts(Common::SeekableReadStream &in) {
for (int i = 0; i < size; i++) {
loadScriptFromSave(in, false);
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadOverlayList(Common::SeekableReadStream &in) {
@@ -289,7 +289,7 @@ bool loadOverlayList(Common::SeekableReadStream &in) {
for (int i = 0; i < size; i++) {
loadOverlayFromSave(in);
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadSeqList(Common::SeekableReadStream &in) {
@@ -312,14 +312,14 @@ bool loadSeqList(Common::SeekableReadStream &in) {
tmp.var1E = in.readSint16BE();
seqList.push_back(tmp);
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool loadZoneQuery(Common::SeekableReadStream &in) {
for (int i = 0; i < 16; i++) {
zoneQuery[i] = in.readUint16BE();
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
void saveObjectTable(Common::OutSaveFile &out) {
@@ -632,7 +632,7 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) {
warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over");
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) {
@@ -755,7 +755,7 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor
}
}
- return !in.ioFailed();
+ return !(in.eos() || in.err());
}
bool CineEngine::makeLoad(char *saveName) {
diff --git a/engines/cruise/actor.cpp b/engines/cruise/actor.cpp
index 969be96573..845867409e 100644
--- a/engines/cruise/actor.cpp
+++ b/engines/cruise/actor.cpp
@@ -528,7 +528,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2
return;
}
- /****** COUPE LE CHEMIN ******/
+ /****** Trim down any un-necessary walk points ******/
i++;
d = 0;
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index 711f7bdf94..e5864ebb31 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -1626,11 +1626,14 @@ int currentMouseButton = 0;
bool bFastMode = false;
-void manageEvents() {
+bool manageEvents() {
Common::Event event;
+ bool result = false;
Common::EventManager * eventMan = g_system->getEventManager();
- while (eventMan->pollEvent(event)) {
+ while (eventMan->pollEvent(event) && !result) {
+ result = true;
+
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
currentMouseButton |= MB_LEFT;
@@ -1647,11 +1650,12 @@ void manageEvents() {
case Common::EVENT_MOUSEMOVE:
currentMouseX = event.mouse.x;
currentMouseY = event.mouse.y;
+ result = false;
break;
case Common::EVENT_QUIT:
case Common::EVENT_RTL:
playerDontAskQuit = 1;
- return;
+ break;
case Common::EVENT_KEYUP:
switch (event.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
@@ -1671,72 +1675,6 @@ void manageEvents() {
break;
}
- /*
- * switch (event.kbd.keycode) {
- * case '\n':
- * case '\r':
- * case 261: // Keypad 5
- * if (allowPlayerInput) {
- * mouseLeft = 1;
- * }
- * break;
- * case 27: // ESC
- * if (allowPlayerInput) {
- * mouseRight = 1;
- * }
- * break;
- * case 282: // F1
- * if (allowPlayerInput) {
- * playerCommand = 0; // EXAMINE
- * makeCommandLine();
- * }
- * break;
- * case 283: // F2
- * if (allowPlayerInput) {
- * playerCommand = 1; // TAKE
- * makeCommandLine();
- * }
- * break;
- * case 284: // F3
- * if (allowPlayerInput) {
- * playerCommand = 2; // INVENTORY
- * makeCommandLine();
- * }
- * break;
- * case 285: // F4
- * if (allowPlayerInput) {
- * playerCommand = 3; // USE
- * makeCommandLine();
- * }
- * break;
- * case 286: // F5
- * if (allowPlayerInput) {
- * playerCommand = 4; // ACTIVATE
- * makeCommandLine();
- * }
- * break;
- * case 287: // F6
- * if (allowPlayerInput) {
- * playerCommand = 5; // SPEAK
- * makeCommandLine();
- * }
- * break;
- * case 290: // F9
- * if (allowPlayerInput && !inMenu) {
- * makeActionMenu();
- * makeCommandLine();
- * }
- * break;
- * case 291: // F10
- * if (!disableSystemMenu && !inMenu) {
- * g_cine->makeSystemMenu();
- * }
- * break;
- * default:
- * //lastKeyStroke = event.kbd.keycode;
- * break;
- * }
- * break; */
if (event.kbd.flags == Common::KBD_CTRL) {
if (event.kbd.keycode == Common::KEYCODE_d) {
// Start the debugger
@@ -1753,17 +1691,10 @@ void manageEvents() {
}
}
- /*if (count) {
- * mouseData.left = mouseLeft;
- * mouseData.right = mouseRight;
- * mouseLeft = 0;
- * mouseRight = 0;
- * }
- */
+ return result;
}
void getMouseStatus(int16 *pMouseVar, int16 *pMouseX, int16 *pMouseButton, int16 *pMouseY) {
- manageEvents();
*pMouseX = currentMouseX;
*pMouseY = currentMouseY;
*pMouseButton = currentMouseButton;
@@ -1806,11 +1737,15 @@ void CruiseEngine::mainLoop(void) {
if (!bFastMode) {
// Delay for the specified amount of time, but still respond to events
+ bool skipEvents = false;
+
while (currentTick < lastTick + _gameSpeed) {
g_system->delayMillis(10);
currentTick = g_system->getMillis();
- manageEvents();
+ if (!skipEvents)
+ skipEvents = manageEvents();
+
if (playerDontAskQuit) break;
if (_vm->getDebugger()->isAttached())
@@ -1906,7 +1841,7 @@ void CruiseEngine::mainLoop(void) {
getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY);
- if (mouseX != oldMouseX && mouseY != oldMouseY) {
+ if (mouseX != oldMouseX || mouseY != oldMouseY) {
int objectType;
int newCursor1;
int newCursor2;
diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp
index 11d5f582ed..aa2a6c7772 100644
--- a/engines/cruise/ctp.cpp
+++ b/engines/cruise/ctp.cpp
@@ -106,7 +106,7 @@ void renderCTPWalkBox(int16 *walkboxData, int hotPointX, int hotPointY, int X, i
int16 *destination;
int startX = X - ((upscaleValue(hotPointX, scale) + 0x8000) >> 16);
-// int startY = Y - ((upscaleValue(hotPointY, scale) + 0x8000) >> 16);
+ int startY = Y - ((upscaleValue(hotPointY, scale) + 0x8000) >> 16);
numPoints = *(walkboxData++);
@@ -117,7 +117,7 @@ void renderCTPWalkBox(int16 *walkboxData, int hotPointX, int hotPointY, int X, i
int pointY = *(walkboxData++);
int scaledX = ((upscaleValue(pointX, scale) + 0x8000) >> 16) + startX;
- int scaledY = ((upscaleValue(pointY, scale) + 0x8000) >> 16) + startX;
+ int scaledY = ((upscaleValue(pointY, scale) + 0x8000) >> 16) + startY;
*(destination++) = scaledX;
*(destination++) = scaledY;
diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp
index 0e9ab55c82..54f686f32a 100644
--- a/engines/cruise/menu.cpp
+++ b/engines/cruise/menu.cpp
@@ -146,7 +146,7 @@ void updateMenuMouse(int mouseX, int mouseY, menuStruct *pMenu) {
}
}
-void manageEvents();
+bool manageEvents();
int processMenu(menuStruct *pMenu) {
int16 mouseX;
diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp
index 3827c3635c..61c17b16f8 100644
--- a/engines/gob/detection.cpp
+++ b/engines/gob/detection.cpp
@@ -68,6 +68,7 @@ static const PlainGameDescriptor gobGames[] = {
{"playtoons5", "Playtoons 5 - The Stone of Wakan"},
{"playtnck1", "Playtoons Construction Kit 1 - Monsters"},
{"playtnck2", "Playtoons Construction Kit 2 - Knights"},
+ {"playtnck3", "Playtoons Construction Kit 3 - Far West"},
{"bambou", "Playtoons Limited Edition - Bambou le sauveur de la jungle"},
{"fascination", "Fascination"},
{"geisha", "Geisha"},
@@ -3560,7 +3561,6 @@ static const GOBGameDescription gameDescriptions[] = {
kFeatures640,
"intro2.stk", 0, 0
},
-
{
{
"playtoons4",
@@ -3579,6 +3579,24 @@ static const GOBGameDescription gameDescriptions[] = {
kFeatures640,
"intro2.stk", 0, 0
},
+ { //Supplied by goodoldgeorg in bug report #2820006
+ {
+ "playtoons4",
+ "",
+ {
+ {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506},
+ {"manda.stk", 0, "69a79c9f61b2618e482726f2ff68078d", 6499208},
+ {0, 0, 0, 0}
+ },
+ EN_ANY,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO_NOSUBTITLES | GUIO_NOSPEECH
+ },
+ kGameTypePlaytoon,
+ kFeatures640,
+ "intro2.stk", 0, 0
+ },
{
{
"playtoons5",
@@ -3653,6 +3671,24 @@ static const GOBGameDescription gameDescriptions[] = {
},
{
{
+ "playtnck3",
+ "",
+ {
+ {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024},
+ {"dan.itk", 0, "9a8f62809eca5a52f429b5b6a8e70f8f", 2861056},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO_NOSUBTITLES | GUIO_NOSPEECH
+ },
+ kGameTypePlaytnCk,
+ kFeatures640,
+ "intro2.stk", 0, 0
+ },
+ {
+ {
"magicstones",
"",
{
diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp
index 20427e547b..c52b65f0d7 100644
--- a/engines/gob/resources.cpp
+++ b/engines/gob/resources.cpp
@@ -158,29 +158,29 @@ bool Resources::load(const Common::String &fileName) {
_extFile = fileBase + ".ext";
- if (!loadTOTResourceTable()) {
- unload();
- return false;
- }
+ bool hasTOTRes = loadTOTResourceTable();
+ bool hasEXTRes = loadEXTResourceTable();
- if (!loadEXTResourceTable()) {
- unload();
+ if (!hasTOTRes && !hasEXTRes)
return false;
- }
- if (!loadTOTTextTable(fileBase)) {
- unload();
- return false;
- }
+ if (hasTOTRes) {
+ if (!loadTOTTextTable(fileBase)) {
+ unload();
+ return false;
+ }
- if (!loadIMFile()) {
- unload();
- return false;
+ if (!loadIMFile()) {
+ unload();
+ return false;
+ }
}
- if (!loadEXFile()) {
- unload();
- return false;
+ if (hasEXTRes) {
+ if (!loadEXFile()) {
+ unload();
+ return false;
+ }
}
return true;
@@ -255,7 +255,7 @@ bool Resources::loadTOTResourceTable() {
TOTResourceItem &item = _totResourceTable->items[i];
item.offset = stream->readSint32LE();
- item.size = stream->readSint16LE();
+ item.size = stream->readUint16LE();
item.width = stream->readSint16LE();
item.height = stream->readSint16LE();
@@ -286,7 +286,7 @@ bool Resources::loadEXTResourceTable() {
DataStream *stream = _vm->_dataIO->getDataStream(_extFile.c_str());
if (!stream)
- return true;
+ return false;
_extResourceTable->itemsCount = stream->readSint16LE();
_extResourceTable->unknown = stream->readByte();
@@ -588,15 +588,22 @@ Resource *Resources::getTOTResource(uint16 id) const {
if (totItem.type == kResourceTOT)
data = getTOTData(totItem);
- if (!data)
+ if (!data) {
+ warning("Failed to load TOT resource (%s, %d/%d, %d)",
+ _totFile.c_str(), id, _totResourceTable->itemsCount - 1, totItem.type);
return 0;
+ }
return new Resource(data, totItem.size, false, totItem.width, totItem.height);
}
Resource *Resources::getEXTResource(uint16 id) const {
- if (!_extResourceTable || (id > _extResourceTable->itemsCount))
+ if (!_extResourceTable || (id > _extResourceTable->itemsCount)) {
+ warning("Trying to load non-existent EXT resource (%s, %d/%d)",
+ _totFile.c_str(), id,
+ _extResourceTable ? (_extResourceTable->itemsCount - 1) : -1);
return 0;
+ }
EXTResourceItem &extItem = _extResourceTable->items[id];
@@ -617,8 +624,11 @@ Resource *Resources::getEXTResource(uint16 id) const {
if (extItem.type == kResourceEX)
data = getEXData(extItem, size);
- if (!data)
+ if (!data) {
+ warning("Failed to load EXT resource (%s, %d/%d, %d)",
+ _totFile.c_str(), id, _extResourceTable->itemsCount - 1, extItem.type);
return 0;
+ }
if (extItem.packed) {
byte *packedData = data;
@@ -635,7 +645,7 @@ Resource *Resources::getEXTResource(uint16 id) const {
}
byte *Resources::getTOTData(TOTResourceItem &totItem) const {
- if (totItem.size < 0)
+ if (totItem.size == 0)
return 0;
int32 offset = _totResourceTable->dataOffset + totItem.offset - _totResStart;
@@ -647,7 +657,7 @@ byte *Resources::getTOTData(TOTResourceItem &totItem) const {
}
byte *Resources::getIMData(TOTResourceItem &totItem) const {
- if (totItem.size < 0)
+ if (totItem.size == 0)
return 0;
int32 indexOffset = totItem.index * 4;
diff --git a/engines/gob/resources.h b/engines/gob/resources.h
index 80acef645c..d316be83e5 100644
--- a/engines/gob/resources.h
+++ b/engines/gob/resources.h
@@ -109,7 +109,7 @@ private:
struct TOTResourceItem {
ResourceType type;
- int16 size;
+ uint16 size;
int16 width;
int16 height;
union {
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index da552d7202..f708729fd8 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -156,6 +156,7 @@ VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) {
_backSurf = false;
_needBlit = false;
_noCursorSwitch = false;
+ _woodruffCohCottWorkaround = false;
}
VideoPlayer::~VideoPlayer() {
@@ -248,6 +249,14 @@ bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y,
_noCursorSwitch = true;
}
+ // WORKAROUND: In Woodruff, Coh Cott vanished in one video on her party.
+ // This is a bug in video, so we work around it.
+ _woodruffCohCottWorkaround = false;
+ if (_vm->getGameType() == kGameTypeWoodruff) {
+ if (!scumm_stricmp(fileName, "SQ32-03.VMD"))
+ _woodruffCohCottWorkaround = true;
+ }
+
_ownSurf = false;
if (!(flags & kFlagNoVideo)) {
@@ -316,6 +325,7 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey,
endFrame = lastFrame;
palCmd &= 0x3F;
+ int16 realStartFrame = startFrame;
if (video.getCurrentFrame() != startFrame) {
if (!forceSeek && (video.getFeatures() & Graphics::CoktelVideo::kFeaturesSound))
startFrame = video.getCurrentFrame();
@@ -331,7 +341,9 @@ bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey,
bool canceled = false;
while (startFrame <= lastFrame) {
- if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) {
+ if (doPlay(startFrame, breakKey,
+ palCmd, palStart, palEnd, palFrame, endFrame, startFrame < realStartFrame)) {
+
canceled = true;
break;
}
@@ -621,7 +633,7 @@ Common::MemoryReadStream *VideoPlayer::getExtraData(const char *fileName, int sl
void VideoPlayer::playFrame(int16 frame, int16 breakKey,
uint16 palCmd, int16 palStart, int16 palEnd,
- int16 palFrame, int16 endFrame) {
+ int16 palFrame, int16 endFrame, bool noRetrace) {
if (!_primaryVideo)
return;
@@ -657,6 +669,12 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey,
Graphics::CoktelVideo::State state = video.nextFrame();
WRITE_VAR(11, frame);
+ if (_woodruffCohCottWorkaround && (frame == 32)) {
+ // WORKAROUND: This frame mistakenly masks Coh Cott, making her vanish
+ // To prevent that, we'll never draw that part
+ state.left += 50;
+ }
+
if (_needBlit)
_vm->_draw->forceBlit(true);
@@ -688,7 +706,9 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey,
_vm->_draw->blitInvalidated();
} else
_vm->_video->dirtyRectsAdd(state.left, state.top, state.right, state.bottom);
- _vm->_video->retrace();
+
+ if (!noRetrace)
+ _vm->_video->retrace();
}
@@ -698,9 +718,9 @@ void VideoPlayer::playFrame(int16 frame, int16 breakKey,
bool VideoPlayer::doPlay(int16 frame, int16 breakKey,
uint16 palCmd, int16 palStart, int16 palEnd,
- int16 palFrame, int16 endFrame) {
+ int16 palFrame, int16 endFrame, bool noRetrace) {
- playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame);
+ playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame, noRetrace);
_vm->_util->processInput();
diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h
index ead752d446..532d216d7e 100644
--- a/engines/gob/videoplayer.h
+++ b/engines/gob/videoplayer.h
@@ -70,7 +70,7 @@ public:
void playFrame(int16 frame, int16 breakKey = kShortKeyEscape,
uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255,
- int16 palFrame = -1 , int16 endFrame = -1);
+ int16 palFrame = -1 , int16 endFrame = -1, bool noRetrace = false);
int slotOpen(const char *videoFile, Type which = kVideoTypeTry);
void slotPlay(int slot, int16 frame = -1);
@@ -152,6 +152,8 @@ private:
bool _needBlit;
bool _noCursorSwitch;
+ bool _woodruffCohCottWorkaround;
+
bool findFile(char *fileName, Type &which);
const Video *getVideoBySlot(int slot = -1) const;
@@ -162,7 +164,7 @@ private:
void copyPalette(Graphics::CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1);
bool doPlay(int16 frame, int16 breakKey,
uint16 palCmd, int16 palStart, int16 palEnd,
- int16 palFrame, int16 endFrame);
+ int16 palFrame, int16 endFrame, bool noRetrace = false);
void evalBgShading(Graphics::CoktelVideo &video);
};
diff --git a/engines/groovie/resource.cpp b/engines/groovie/resource.cpp
index eda3f0bec0..148fa9c451 100644
--- a/engines/groovie/resource.cpp
+++ b/engines/groovie/resource.cpp
@@ -98,7 +98,7 @@ uint16 ResMan_t7g::getRef(Common::String name, Common::String scriptname) {
uint16 resNum;
bool found = false;
- for (resNum = 0; !found && !rlFile.ioFailed(); resNum++) {
+ for (resNum = 0; !found && !rlFile.err() && !rlFile.eos(); resNum++) {
// Read the resource name
char readname[12];
rlFile.read(readname, 12);
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index e5ca52abcc..a3a249de18 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -434,7 +434,7 @@ void KyraEngine_LoK::mainLoop() {
// FIXME: Why is this here?
_screen->showMouse();
- int inputFlag = checkInput(_buttonList, true);
+ int inputFlag = checkInput(_buttonList, _currentCharacter->sceneId != 210);
removeInputTop();
updateMousePointer();
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index 80872877d5..258d0c402f 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -115,7 +115,6 @@ Common::Error KyraEngine_v1::init() {
_sound = new SoundTownsPC98_v2(this, _mixer);
} else if (midiDriver == MD_ADLIB) {
_sound = new SoundAdlibPC(this, _mixer);
- assert(_sound);
} else {
Sound::kType type;
@@ -126,7 +125,6 @@ Common::Error KyraEngine_v1::init() {
else
type = Sound::kMidiGM;
-
MidiDriver *driver = 0;
if (midiDriver == MD_PCSPK) {
@@ -151,9 +149,10 @@ Common::Error KyraEngine_v1::init() {
assert(adlib);
_sound = new MixedSoundDriver(this, _mixer, soundMidiPc, adlib);
- assert(_sound);
}
}
+
+ assert(_sound);
}
if (_sound)
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index a1aaf77d51..83230d6e3b 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -126,7 +126,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
}
}
- return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
+ return ((in->err() || in->eos()) ? kRSHEIoError : kRSHENoError);
}
Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp
index 9ffaf5515d..3def71a076 100644
--- a/engines/kyra/scene_v2.cpp
+++ b/engines/kyra/scene_v2.cpp
@@ -73,7 +73,7 @@ void KyraEngine_v2::runSceneScript6() {
_sceneScriptState.regs[0] = _mainCharacter.sceneId;
_sceneScriptState.regs[1] = _mouseX;
_sceneScriptState.regs[2] = _mouseY;
- _sceneScriptState.regs[3] = _itemInHand;
+ _sceneScriptState.regs[4] = _itemInHand;
_emc->start(&_sceneScriptState, 6);
while (_emc->isValid(&_sceneScriptState))
diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp
index 611ad8f9ef..e4b77f6a07 100644
--- a/engines/kyra/script_lol.cpp
+++ b/engines/kyra/script_lol.cpp
@@ -2345,8 +2345,8 @@ int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) {
int h2 = (h1 * factor) / 100;
anim->wsa->displayFrame(frame, 2, x1, y1, anim->wsaCopyParams & 0xF0FF, 0, 0);
- _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, _flags.isDemo ? 0 : 8, 0);
- if (!_flags.isDemo)
+ _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, _flags.isDemo && _flags.platform != Common::kPlatformPC98 ? 0 : 8, 0);
+ if (!_flags.isDemo && _flags.platform != Common::kPlatformPC98)
_screen->checkedPageUpdate(8, 4);
_screen->updateScreen();
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index bc62e5bd6a..731b8d206f 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -98,7 +98,10 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSys
_textDisplayed = false;
_textAreaBuffer = new uint8[320*40];
assert(_textAreaBuffer);
- _drawPage2 = (_vm->gameFlags().isDemo && _vm->gameFlags().gameID == GI_LOL) ? 0 : 8;
+ if ((_vm->gameFlags().platform == Common::kPlatformPC98 || _vm->gameFlags().isDemo) && _vm->gameFlags().gameID == GI_LOL)
+ _drawPage2 = 0;
+ else
+ _drawPage2 = 8;
_palDelayInc = _palDiff = _palDelayAcc = 0;
_abortFlag = 0;
@@ -461,7 +464,10 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char
anim->wsaCopyParams = wsaFlags;
const bool isLoLDemo = _vm->gameFlags().isDemo && _vm->gameFlags().gameID == GI_LOL;
- _drawPage2 = (isLoLDemo || _currentTim->isLoLOutro) ? 0 : 8;
+ if (isLoLDemo || _vm->gameFlags().platform == Common::kPlatformPC98 || _currentTim->isLoLOutro)
+ _drawPage2 = 0;
+ else
+ _drawPage2 = 8;
uint16 wsaOpenFlags = 0;
if (isLoLDemo) {
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index beea129f66..5826b2b09e 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -224,7 +224,7 @@ void LoLEngine::showIntro() {
while (!_tim->finished() && !shouldQuit() && !skipFlag()) {
updateInput();
_tim->exec(intro, false);
- if (!_flags.isDemo)
+ if (!_flags.isDemo && _flags.platform != Common::kPlatformPC98)
_screen->checkedPageUpdate(8, 4);
if (_tim->_palDiff) {
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index f393ae15ba..263cd586f7 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -8,32 +8,16 @@
* 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.
*
- * LGPL License
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library 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
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
* $URL$
* $Id$
*
diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h
new file mode 100644
index 0000000000..f384113af7
--- /dev/null
+++ b/engines/kyra/sound_adlib.h
@@ -0,0 +1,113 @@
+/* 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.
+ *
+ * LGPL License
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef KYRA_SOUND_ADLIB_H
+#define KYRA_SOUND_ADLIB_H
+
+#include "kyra/sound.h"
+
+#include "common/mutex.h"
+
+namespace Kyra {
+class AdlibDriver;
+
+/**
+ * AdLib implementation of the sound output device.
+ *
+ * It uses a special sound file format special to
+ * Dune II, Kyrandia 1 and 2. While Dune II and
+ * Kyrandia 1 are using exact the same format, the
+ * one of Kyrandia 2 slightly differs.
+ *
+ * See AdlibDriver for more information.
+ * @see AdlibDriver
+ */
+class SoundAdlibPC : public Sound {
+public:
+ SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundAdlibPC();
+
+ kType getMusicType() const { return kAdlib; }
+
+ bool init();
+ void process();
+
+ void loadSoundFile(uint file);
+ void loadSoundFile(Common::String file);
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ bool isPlaying();
+
+ void playSoundEffect(uint8 track);
+
+ void beginFadeOut();
+private:
+ void internalLoadFile(Common::String file);
+
+ void play(uint8 track);
+
+ void unk1();
+ void unk2();
+
+ AdlibDriver *_driver;
+
+ bool _v2;
+ uint8 _trackEntries[500];
+ uint8 *_soundDataPtr;
+ int _sfxPlayingSound;
+
+ Common::String _soundFileLoaded;
+
+ uint8 _sfxPriority;
+ uint8 _sfxFourthByteOfSong;
+
+ int _numSoundTriggers;
+ const int *_soundTriggers;
+
+ static const int _kyra1NumSoundTriggers;
+ static const int _kyra1SoundTriggers[];
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index 8792c14815..975672b76a 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -8,12 +8,12 @@
* 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.
@@ -27,6 +27,7 @@
#define KYRA_SOUND_INTERN_H
#include "kyra/sound.h"
+#include "kyra/sound_adlib.h"
#include "common/mutex.h"
@@ -39,66 +40,6 @@ class PCSpeaker;
} // end of namespace Audio
namespace Kyra {
-class AdlibDriver;
-
-/**
- * AdLib implementation of the sound output device.
- *
- * It uses a special sound file format special to
- * Dune II, Kyrandia 1 and 2. While Dune II and
- * Kyrandia 1 are using exact the same format, the
- * one of Kyrandia 2 slightly differs.
- *
- * See AdlibDriver for more information.
- * @see AdlibDriver
- */
-class SoundAdlibPC : public Sound {
-public:
- SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundAdlibPC();
-
- kType getMusicType() const { return kAdlib; }
-
- bool init();
- void process();
-
- void loadSoundFile(uint file);
- void loadSoundFile(Common::String file);
-
- void playTrack(uint8 track);
- void haltTrack();
- bool isPlaying();
-
- void playSoundEffect(uint8 track);
-
- void beginFadeOut();
-private:
- void internalLoadFile(Common::String file);
-
- void play(uint8 track);
-
- void unk1();
- void unk2();
-
- AdlibDriver *_driver;
-
- bool _v2;
- uint8 _trackEntries[500];
- uint8 *_soundDataPtr;
- int _sfxPlayingSound;
-
- Common::String _soundFileLoaded;
-
- uint8 _sfxPriority;
- uint8 _sfxFourthByteOfSong;
-
- int _numSoundTriggers;
- const int *_soundTriggers;
-
- static const int _kyra1NumSoundTriggers;
- static const int _kyra1SoundTriggers[];
-};
-
class MidiOutput;
/**
diff --git a/engines/kyra/sound_pcspk.cpp b/engines/kyra/sound_pcspk.cpp
index 22c24bf56c..2afed22a80 100644
--- a/engines/kyra/sound_pcspk.cpp
+++ b/engines/kyra/sound_pcspk.cpp
@@ -1,25 +1,22 @@
-/*
- * 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.
+/* ScummVM - Graphic Adventure Engine
*
- * LGPL License
+ * 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 library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * 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 library is distributed in the hope that it will be useful,
+ * 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
- * Lesser General Public License for more details.
+ * 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 Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * 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.
*
* $URL$
* $Id$
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 566d82405a..7118eb682d 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -1149,6 +1149,25 @@ static const struct SciGameDescription SciGameDescriptions[] = {
SCI_VERSION_1
},
+ // King's Quest 5 - French DOS Floppy (from the King's Quest Collector's Edition 1994)
+ // Supplied by aroenai in bug report #2812611
+ // VERSION file reports "1.000", SCI interpreter version 1.000.784
+ {{"kq5", "", {
+ {"resource.map", 0, "eb7853832f3bb10900b13b421a0bbe7f", 8283},
+ {"resource.000", 0, "f063775b279208c14a83eda47073be90", 332806},
+ {"resource.001", 0, "3e6add38564250fd1a5bb10593007530", 1136827},
+ {"resource.002", 0, "d9a97a9cf6c79bbe8f19378f6dea45d5", 1343738},
+ {"resource.003", 0, "bef90d755076c110e67ee3e635503f82", 1324811},
+ {"resource.004", 0, "c14dbafcfbe00855ac6b2f2701058047", 1332216},
+ {"resource.005", 0, "f4b31cafc5defac75125c5f7b7f9a31a", 1268334},
+ {"resource.006", 0, "f7dc85307632ef657ceb1651204f6f51", 1210081},
+ {"resource.007", 0, "7db4d0a1d8d547c0019cb7d2a6acbdd4", 1338473},
+ {NULL, 0, NULL, 0}}, Common::FR_FRA, Common::kPlatformPC, 0, GUIO_NOSPEECH},
+ 0,
+ SCI_VERSION_AUTODETECT,
+ SCI_VERSION_1
+ },
+
// King's Quest 5 - Italian DOS Floppy (from glorifindel)
// SCI interpreter version 1.000.060
{{"kq5", "", {
@@ -2203,6 +2222,17 @@ static const struct SciGameDescription SciGameDescriptions[] = {
},
#endif // ENABLE_SCI32
+ // Pepper's Adventure In Time 1.000 English
+ // Executable scanning reports "1.001.072", VERSION file reports "1.000"
+ {{"pepper", "", {
+ {"resource.map", 0, "72726dc81c1b4c1110c486be77369bc8", 5179},
+ {"resource.000", 0, "670d0c53622429f4b11275caf7f8d292", 5459574},
+ {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH},
+ 0,
+ SCI_VERSION_AUTODETECT,
+ SCI_VERSION_1_1
+ },
+
// Pepper - English DOS Non-Interactive Demo
// Executable scanning reports "1.001.060", VERSION file reports "1.000"
{{"pepper", "Demo", {
diff --git a/engines/sci/gfx/gfx_resmgr.cpp b/engines/sci/gfx/gfx_resmgr.cpp
index b8c005b620..cd5b1be431 100644
--- a/engines/sci/gfx/gfx_resmgr.cpp
+++ b/engines/sci/gfx/gfx_resmgr.cpp
@@ -341,7 +341,7 @@ gfxr_pic_t *GfxResManager::getPic(int num, int maps, int flags, int default_pale
res = resMap.contains(num) ? resMap[num] : NULL;
if (!res || res->mode != hash) {
- gfxr_pic_t *pic;
+ gfxr_pic_t *pic = NULL;
gfxr_pic_t *unscaled_pic = NULL;
#ifdef CUSTOM_GRAPHICS_OPTIONS
diff --git a/engines/sci/gfx/gfx_resmgr.h b/engines/sci/gfx/gfx_resmgr.h
index fc4e0b3d6f..5cd5d018cc 100644
--- a/engines/sci/gfx/gfx_resmgr.h
+++ b/engines/sci/gfx/gfx_resmgr.h
@@ -270,8 +270,7 @@ public:
/**
* Retrieves a color from the static palette
*/
- const PaletteEntry &getColor(int color)
- {
+ const PaletteEntry &getColor(int color) {
return _staticPalette->getColor(color);
}
@@ -313,6 +312,11 @@ public:
return _staticPalette ? _staticPalette->size() : 0;
}
+ /**
+ * Returns the resource version that the resource manager is using
+ */
+ int getVersion() { return _version; }
+
private:
int _version;
gfx_options_t *_options;
diff --git a/engines/sci/gfx/gfx_system.h b/engines/sci/gfx/gfx_system.h
index fe93922e21..0f5292aedf 100644
--- a/engines/sci/gfx/gfx_system.h
+++ b/engines/sci/gfx/gfx_system.h
@@ -192,7 +192,7 @@ struct gfx_pixmap_t {
* As a special exception, 256 colors are allowed for background pictures
* (which do not use transparency)
*/
- int colors_nr() const { return palette ? palette->size() : 0; }
+ int colors_nr() const { return palette ? MIN<int>(palette->size(), 256) : 0; }
uint32 flags;
/* @} */
diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp
index 77b887778b..5604166794 100644
--- a/engines/sci/gfx/operations.cpp
+++ b/engines/sci/gfx/operations.cpp
@@ -1715,9 +1715,10 @@ static int _gfxop_set_pic(GfxState *state) {
// FIXME: The _gfxop_install_pixmap call below updates the OSystem palette.
// This is too soon, since it causes brief palette corruption until the
// screen is updated too. (Possibly related: EngineState::pic_not_valid .)
- if (state->driver->getMode()->palette)
+ if (state->pic->visual_map->palette && state->driver->getMode()->palette) {
state->pic->visual_map->palette->forceInto(state->driver->getMode()->palette);
- _gfxop_install_pixmap(state->driver, state->pic->visual_map);
+ _gfxop_install_pixmap(state->driver, state->pic->visual_map);
+ }
#ifdef CUSTOM_GRAPHICS_OPTIONS
if (state->options->pic0_unscaled)
diff --git a/engines/sci/gfx/res_pal.cpp b/engines/sci/gfx/res_pal.cpp
index 97e7297d43..d686220453 100644
--- a/engines/sci/gfx/res_pal.cpp
+++ b/engines/sci/gfx/res_pal.cpp
@@ -44,6 +44,11 @@ Palette *gfxr_read_pal11(int id, byte *resource, int size) {
int entry_size = (format == SCI_PAL_FORMAT_VARIABLE_FLAGS) ? 4 : 3;
byte *pal_data = resource + 37;
int _colors_nr = READ_LE_UINT16(resource + 29);
+
+ // Happens at the beginning of Pepper
+ if (_colors_nr > 256)
+ return NULL;
+
Palette *retval = new Palette(_colors_nr + start_color);
int i;
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 9fb107f9fc..880fab04a5 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -641,6 +641,8 @@ HelpDialog::HelpDialog(const GameSettings &game)
new GUI::ButtonWidget(this, "ScummHelp.Close", "Close", kCloseCmd, 'C');
_prevButton->clearFlags(WIDGET_ENABLED);
+ _numLines = HELP_NUM_LINES;
+
// Dummy entries
for (int i = 0; i < HELP_NUM_LINES; i++) {
_key[i] = new StaticTextWidget(this, 0, 0, 10, 10, "", Graphics::kTextAlignRight);
@@ -658,22 +660,25 @@ void HelpDialog::reflowLayout() {
g_gui.xmlEval()->getWidgetData("ScummHelp.HelpText", x, y, w, h);
+ // Make sure than we don't have more lines than what we can fit
+ // on the space that the layout reserves for text
+ _numLines = MIN(HELP_NUM_LINES, (int)(h / lineHeight));
+
int keyW = w * 20 / 100;
int dscX = x + keyW + 32;
int dscW = w * 80 / 100;
int xoff = (_w >> 1) - (w >> 1);
- for (int i = 0; i < HELP_NUM_LINES; i++) {
- _key[i]->resize(xoff + x, y + lineHeight * i, keyW, lineHeight + 2);
- _dsc[i]->resize(xoff + dscX, y + lineHeight * i, dscW, lineHeight + 2);
+ for (int i = 0; i < _numLines; i++) {
+ _key[i]->resize(xoff + x, y + lineHeight * i, keyW, lineHeight);
+ _dsc[i]->resize(xoff + dscX, y + lineHeight * i, dscW, lineHeight);
}
displayKeyBindings();
}
void HelpDialog::displayKeyBindings() {
-
String titleStr, *keyStr, *dscStr;
#ifndef __DS__
@@ -684,7 +689,7 @@ void HelpDialog::displayKeyBindings() {
#endif
_title->setLabel(titleStr);
- for (int i = 0; i < HELP_NUM_LINES; i++) {
+ for (int i = 0; i < _numLines; i++) {
_key[i]->setLabel(keyStr[i]);
_dsc[i]->setLabel(dscStr[i]);
}
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 290b3450dc..af844272fa 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -124,6 +124,7 @@ protected:
int _page;
int _numPages;
+ int _numLines;
const GameSettings _game;
diff --git a/engines/scumm/imuse_digi/dimuse_track.cpp b/engines/scumm/imuse_digi/dimuse_track.cpp
index 6ded6d23b2..a389c0e7e7 100644
--- a/engines/scumm/imuse_digi/dimuse_track.cpp
+++ b/engines/scumm/imuse_digi/dimuse_track.cpp
@@ -22,6 +22,7 @@
* $Id$
*/
+#include "common/config-manager.h"
#include "common/timer.h"
#include "scumm/actor.h"
@@ -136,6 +137,11 @@ void IMuseDigital::startSound(int soundId, const char *soundName, int soundType,
track->pan = a->_talkPan;
track->vol = a->_talkVolume * 1000;
}
+
+ // The volume is set to zero, when using subtitles only setting in COMI
+ if (ConfMan.getBool("speech_mute") || _vm->VAR(_vm->VAR_VOICE_MODE) == 2) {
+ track->vol = 0;
+ }
}
assert(bits == 8 || bits == 12 || bits == 16);
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 42b48a3f3d..61b714a3e2 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -258,6 +258,18 @@ void ScummEngine_v0::processInput() {
ScummEngine::processInput();
}
+#ifdef ENABLE_SCUMM_7_8
+void ScummEngine_v7::processInput() {
+ ScummEngine::processInput();
+
+ if (_skipVideo && !_smushActive) {
+ abortCutscene();
+ _mouseAndKeyboardStat = Common::ASCII_ESCAPE;
+ _skipVideo = false;
+ }
+}
+#endif
+
void ScummEngine::processInput() {
Common::KeyState lastKeyHit = _keyPressed;
_keyPressed.reset();
@@ -392,9 +404,10 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
_insane->escapeKeyHandler();
else
_smushVideoShouldFinish = true;
- }
- if (!_smushActive || _smushVideoShouldFinish)
+ _skipVideo = true;
+ } else {
abortCutscene();
+ }
_mouseAndKeyboardStat = Common::ASCII_ESCAPE;
diff --git a/engines/scumm/player_v2.h b/engines/scumm/player_v2.h
index f0e14cdde3..5b375fb1e5 100644
--- a/engines/scumm/player_v2.h
+++ b/engines/scumm/player_v2.h
@@ -242,8 +242,8 @@ protected:
Voice2 _cmsVoices[8];
MusicChip _cmsChips[2];
- char _tempo;
- char _tempoSum;
+ int8 _tempo;
+ int8 _tempoSum;
byte _looping;
byte _octaveMask;
int16 _midiDelay;
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index 78f7fb0453..4d9447bee5 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -1367,17 +1367,6 @@ void ScummEngine::abortCutscene() {
VAR(VAR_OVERRIDE) = 1;
vm.cutScenePtr[idx] = 0;
-
- // HACK to fix issues with SMUSH and the way it does keyboard handling.
- // In particular, normally abortCutscene() is being called while no
- // scripts are active. But SMUSH runs from *inside* the script engine.
- // And it calls abortCutscene() if ESC is pressed... not good.
- // Proper fix might be to let SMUSH/INSANE run from outside the script
- // engine but that would require lots of changes and may actually have
- // negative effects, too. So we cheat here, to fix bug #751670.
- if (_game.version == 7)
- getScriptEntryPoint();
-
}
}
diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
index c23a64be5b..dcd60352c7 100644
--- a/engines/scumm/script_v6.cpp
+++ b/engines/scumm/script_v6.cpp
@@ -1396,6 +1396,7 @@ void ScummEngine_v6::o6_getVerbFromXY() {
void ScummEngine_v6::o6_beginOverride() {
beginOverride();
+ _skipVideo = 0;
}
void ScummEngine_v6::o6_endOverride() {
@@ -2457,7 +2458,7 @@ void ScummEngine_v7::o6_kernelSetFunctions() {
break;
case 6: {
// SMUSH movie playback
- if (args[1] == 0) {
+ if (args[1] == 0 && !_skipVideo) {
const char *videoname = (const char *)getStringAddressVar(VAR_VIDEONAME);
assert(videoname);
@@ -2474,7 +2475,7 @@ void ScummEngine_v7::o6_kernelSetFunctions() {
if (_game.id == GID_DIG) {
_disableFadeInEffect = true;
}
- } else if (_game.id == GID_FT) {
+ } else if (_game.id == GID_FT && !_skipVideo) {
const int insaneVarNum = ((_game.features & GF_DEMO) && (_game.platform == Common::kPlatformPC))
? 232 : 233;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index a00ace1f49..70b2d7285e 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -687,6 +687,7 @@ ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr)
_curVerbSlot = 0;
_forcedWaitForMessage = false;
+ _skipVideo = false;
VAR_VIDEONAME = 0xFF;
VAR_RANDOM_NR = 0xFF;
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index d4768a7e92..eb55b83596 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -93,6 +93,7 @@ protected:
int _curVerbSlot;
bool _forcedWaitForMessage;
+ bool _skipVideo;
public:
ScummEngine_v6(OSystem *syst, const DetectorResult &dr);
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index fdc1d6de9c..fcadadb04d 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -103,6 +103,7 @@ protected:
virtual void scummLoop_handleSound();
virtual void scummLoop_handleDrawing();
+ virtual void processInput();
virtual void processKeyboard(Common::KeyState lastKeyHit);
virtual void setupScumm();
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index d40bbb9aaa..f00f4ff33b 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -1415,6 +1415,9 @@ void ScummEngine_v7::loadLanguageBundle() {
}
void ScummEngine_v7::playSpeech(const byte *ptr) {
+ if (_game.id == GID_DIG && (ConfMan.getBool("speech_mute") || VAR(VAR_VOICE_MODE) == 2))
+ return;
+
if ((_game.id == GID_DIG || _game.id == GID_CMI) && ptr[0]) {
char pointer[20];
strcpy(pointer, (const char *)ptr);
diff --git a/engines/sky/grid.cpp b/engines/sky/grid.cpp
index d9b7a17351..7b473c7934 100644
--- a/engines/sky/grid.cpp
+++ b/engines/sky/grid.cpp
@@ -255,8 +255,10 @@ void Grid::removeGrid(uint32 x, uint32 y, uint32 width, Compact *cpt) {
}
uint8 *Grid::giveGrid(uint32 pScreen) {
- assert((_gridConvertTable[pScreen] >= 0) && (_gridConvertTable[pScreen] < TOT_NO_GRIDS));
- return _gameGrids[_gridConvertTable[pScreen]];
+ if ((_gridConvertTable[pScreen] >= 0) && (_gridConvertTable[pScreen] < TOT_NO_GRIDS)) {
+ return _gameGrids[_gridConvertTable[pScreen]];
+ }
+ return 0;
}
} // End of namespace Sky
diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp
index ccfbfbbd62..991fbe19d0 100644
--- a/engines/sky/logic.cpp
+++ b/engines/sky/logic.cpp
@@ -1702,6 +1702,15 @@ bool Logic::fnQuit(uint32 a, uint32 b, uint32 c) {
}
bool Logic::fnSpeakMe(uint32 targetId, uint32 mesgNum, uint32 animNum) {
+ /* WORKAROUND for #2687172: When Mrs. Piermont is talking
+ on the phone in her apartment, ignore her fnSpeakMe calls
+ on other screens, as the lack of speech files for these lines
+ will cause Foster's speech to be aborted if the timing is bad.
+ */
+ if (targetId == 0x4039 && animNum == 0x9B && Logic::_scriptVariables[SCREEN] != 38) {
+ return false;
+ }
+
stdSpeak(_skyCompact->fetchCpt(targetId), mesgNum, animNum, 0);
return false; //drop out of script
}
diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp
index 47cc65e96d..e85da6297a 100644
--- a/engines/sky/sky.cpp
+++ b/engines/sky/sky.cpp
@@ -208,8 +208,11 @@ Common::Error SkyEngine::go() {
_skyScreen->recreate();
_skyScreen->spriteEngine();
if (_debugger->showGrid()) {
- _skyScreen->showGrid(_skyLogic->_skyGrid->giveGrid(Logic::_scriptVariables[SCREEN]));
- _skyScreen->forceRefresh();
+ uint8 *grid = _skyLogic->_skyGrid->giveGrid(Logic::_scriptVariables[SCREEN]);
+ if (grid) {
+ _skyScreen->showGrid(grid);
+ _skyScreen->forceRefresh();
+ }
}
_skyScreen->flip();
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index b3fa1aa0fd..b23bf71445 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -77,11 +77,11 @@ void Sound::checkSpeechFileEndianness() {
// little endian assumption. The one with the smallest sum should be the
// correct one (the sound wave is supposed to be relatively smooth).
// It needs at least 1000 samples to get stable result (the code below is
- // using the first 2000 samples of the wav sound.
+ // using the first 2000 samples of the wav sound).
- // Init speach file if not already done.
+ // Init speech file if not already done.
if (!_currentCowFile) {
- // Open one of the speech file. It uses SwordEngine::_systemVars.currentCD
+ // Open one of the speech files. It uses SwordEngine::_systemVars.currentCD
// to decide which file to open, therefore if it is currently set to zero
// we have to set it to either 1 or 2 (I decided to set it to 1 as this is
// more likely to be the first file that will be needed).
@@ -92,22 +92,22 @@ void Sound::checkSpeechFileEndianness() {
}
initCowSystem();
if (no_current_cd) {
- // In case it fails with CD1 retyr with CD2
+ // In case it fails with CD1 retry with CD2
if (!_currentCowFile) {
SwordEngine::_systemVars.currentCD = 2;
initCowSystem();
}
- // Reset curentCD flag
+ // Reset currentCD flag
SwordEngine::_systemVars.currentCD = 0;
}
}
- // Testing for endianness makes sense only if using the nom compressed files.
+ // Testing for endianness makes sense only if using the uncompressed files.
if (_cowHeader == NULL || (_cowMode != CowWave && _cowMode != CowDemo))
return;
// I picked the sample to use randomly (I just made sure it is long enough so that there is
- // a fair change of the heuristic to have a stable result and work for every languages).
+ // a fair change of the heuristic to have a stable result and work for every language).
int roomNo = _currentCowFile == 1 ? 1 : 129;
int localNo = _currentCowFile == 1 ? 2 : 933;
// Get the speech data and apply the heuristic
@@ -119,7 +119,7 @@ void Sound::checkSpeechFileEndianness() {
double be_diff_sum = 0., le_diff_sum = 0.;
_bigEndianSpeech = false;
int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
- // Compute average of differecen between two consecutive samples for both BE and LE
+ // Compute average of difference between two consecutive samples for both BE and LE
if (data) {
if (size > 4000)
size = 2000;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 9a0e1f37f8..5ef5bea702 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -207,9 +207,7 @@ void OpenCDGraphFile(void) {
// As the theory goes, the right CD will be in there!
- cdGraphStream.clearIOFailed();
- cdGraphStream.open(szCdPlayFile);
- if (cdGraphStream.ioFailed())
+ if (!cdGraphStream.open(szCdPlayFile))
error(CANNOT_FIND_FILE, szCdPlayFile);
}
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index a9c6f43d85..1d73411e13 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -112,6 +112,43 @@ static INT_CONTEXT *icList = 0;
static uint32 hMasterScript;
+//----------------- SCRIPT BUGS WORKAROUNDS --------------
+
+const byte fragment1[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 206, 0};
+const int fragment1_size = 4;
+const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110};
+const int fragment2_size = 2;
+const byte fragment3[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 490 % 256, 490 / 256};
+const int fragment3_size = 4;
+
+const WorkaroundEntry workaroundList[] = {
+ // DW1-SCN: Global 206 is whether Rincewind is trying to take the book back to the present.
+ // In the GRA version, it was global 373, and was reset when he is returned to the past, but
+ // was forgotten in the SCN version, so this ensures the flag is properly reset
+ {TINSEL_V1, true, 427942095, 1, fragment1_size, fragment1},
+
+ // DW1-GRA: Rincewind exiting the Inn is blocked by the luggage. Whilst you can then move
+ // into walkable areas, saving and restoring the game, it will error if you try to move.
+ // This fragment turns off NPC blocking for the Outside Inn rooms so that the luggage won't block
+ // Past Outside Inn
+ {TINSEL_V1, false, 444622076, 0, fragment2_size, fragment2},
+ // Present Outside Inn
+ {TINSEL_V1, false, 352600876, 0, fragment2_size, fragment2},
+
+ // DW2: In the garden, global #490 is set when the bees begin their 'out of hive' animation, and reset when done.
+ // But if the game is saved/restored during it, the animation sequence is reset without the global being cleared.
+ // This causes bugs in several actions which try to disable the bees animation, since they wait indefinitely for
+ // the global to be cleared, incorrectly believing the animation is currently playing. This includes
+ // * Giving the brochure to the beekeeper
+ // * Stealing the mallets from the wizards
+ // This fix ensures that the global is reset when the Garden scene is loaded (both entering and restoring a game)
+ {TINSEL_V2, true, 2888147476U, 0, fragment3_size, fragment3},
+
+ {TINSEL_V0, false, 0, 0, 0, NULL}
+};
+
+//----------------- LOCAL GLOBAL DATA --------------------
+
/**
* Keeps the code array pointer up to date.
*/
@@ -398,38 +435,93 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo) {
}
/**
- * Fetch (and sign extend, if necessary) a 8/16/32 bit value from the code
- * stream and advance the instruction pointer accordingly.
+ * Fetches up to 4 bytes from the code script
*/
-static int32 Fetch(byte opcode, byte *code, int &ip) {
- int32 tmp;
- if (TinselV0) {
- // Fetch a 32 bit value.
- tmp = (int32)READ_LE_UINT32(code + ip++ * 4);
- } else if (opcode & OPSIZE8) {
+static int32 GetBytes(const byte *scriptCode, const WorkaroundEntry* &wkEntry, int &ip, uint numBytes) {
+ assert(numBytes <= 4 && numBytes != 3);
+ const byte *code = scriptCode;
+
+ if (wkEntry != NULL) {
+ if (ip >= wkEntry->numBytes) {
+ // Finished the workaround
+ ip = wkEntry->ip;
+ wkEntry = NULL;
+ } else {
+ code = wkEntry->script;
+ }
+ }
+
+ uint32 tmp;
+ switch (numBytes) {
+ case 0:
+ // Instruction byte
+ tmp = code[ip++ * (TinselV0 ? 4 : 1)];
+ break;
+ case 1:
// Fetch and sign extend a 8 bit value to 32 bits.
- tmp = *(int8 *)(code + ip);
- ip += 1;
- } else if (opcode & OPSIZE16) {
+ tmp = (int8)code[ip++];
+ break;
+ case 2:
// Fetch and sign extend a 16 bit value to 32 bits.
tmp = (int16)READ_LE_UINT16(code + ip);
ip += 2;
- } else {
- // Fetch a 32 bit value.
- tmp = (int32)READ_LE_UINT32(code + ip);
- ip += 4;
+ break;
+ default:
+ if (TinselV0)
+ tmp = (int32)READ_LE_UINT32(code + ip++ * 4);
+ else {
+ tmp = (int32)READ_LE_UINT32(code + ip);
+ ip += 4;
+ }
+ break;
}
+
return tmp;
}
/**
+ * Fetch (and sign extend, if necessary) a 8/16/32 bit value from the code
+ * stream and advance the instruction pointer accordingly.
+ */
+static int32 Fetch(byte opcode, const byte *code, const WorkaroundEntry* &wkEntry, int &ip) {
+ if (TinselV0)
+ // Fetch a 32 bit value.
+ return GetBytes(code, wkEntry, ip, 4);
+ else if (opcode & OPSIZE8)
+ // Fetch and sign extend a 8 bit value to 32 bits.
+ return GetBytes(code, wkEntry, ip, 1);
+ else if (opcode & OPSIZE16)
+ return GetBytes(code, wkEntry, ip, 2);
+
+ return GetBytes(code, wkEntry, ip, 4);
+}
+
+/**
* Interprets the PCODE instructions in the code array.
*/
void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
do {
int tmp, tmp2;
int ip = ic->ip;
- byte opcode = ic->code[ip++ * (TinselV0 ? 4 : 1)];
+ const WorkaroundEntry *wkEntry = ic->fragmentPtr;
+
+ if (wkEntry == NULL) {
+ // Check to see if a workaround fragment needs to be executed
+ for (wkEntry = workaroundList; wkEntry->script != NULL; ++wkEntry) {
+ if ((wkEntry->version == TinselVersion) &&
+ (wkEntry->hCode == ic->hCode) &&
+ (wkEntry->ip == ip) &&
+ (!TinselV1 || (wkEntry->scnFlag == ((_vm->getFeatures() & GF_SCNFILES) != 0)))) {
+ // Point to start of workaround fragment
+ ip = 0;
+ break;
+ }
+ }
+ if (wkEntry->script == NULL)
+ wkEntry = NULL;
+ }
+
+ byte opcode = (byte)GetBytes(ic->code, wkEntry, ip, 0);
if (TinselV0 && ((opcode & OPMASK) > OP_IMM))
opcode += 3;
@@ -447,7 +539,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
case OP_FONT: // loads font handle onto stack
case OP_PAL: // loads palette handle onto stack
- ic->stack[++ic->sp] = Fetch(opcode, ic->code, ip);
+ ic->stack[++ic->sp] = Fetch(opcode, ic->code, wkEntry, ip);
break;
case OP_ZERO: // loads zero onto stack
@@ -464,31 +556,31 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
case OP_LOAD: // loads local variable onto stack
- ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, ip)];
+ ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)];
break;
case OP_GLOAD: // loads global variable onto stack
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
assert(0 <= tmp && tmp < numGlobals);
ic->stack[++ic->sp] = pGlobals[tmp];
break;
case OP_STORE: // pops stack and stores in local variable
- ic->stack[ic->bp + Fetch(opcode, ic->code, ip)] = ic->stack[ic->sp--];
+ ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)] = ic->stack[ic->sp--];
break;
case OP_GSTORE: // pops stack and stores in global variable
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
assert(0 <= tmp && tmp < numGlobals);
pGlobals[tmp] = ic->stack[ic->sp--];
break;
case OP_CALL: // procedure call
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
//assert(0 <= tmp && tmp < codeSize); // TODO: Verify jumps are not out of bounds
ic->stack[ic->sp + 1] = 0; // static link
ic->stack[ic->sp + 2] = ic->bp; // dynamic link
@@ -499,7 +591,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
case OP_LIBCALL: // library procedure or function call
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
// NOTE: Interpret() itself is not using the coroutine facilities,
// but still accepts a CORO_PARAM, so from the outside it looks
// like a coroutine. In fact it may still acts as a kind of "proxy"
@@ -538,17 +630,17 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
case OP_ALLOC: // allocate storage on stack
- ic->sp += (int32)Fetch(opcode, ic->code, ip);
+ ic->sp += (int32)Fetch(opcode, ic->code, wkEntry, ip);
break;
case OP_JUMP: // unconditional jump
- ip = Fetch(opcode, ic->code, ip);
+ ip = Fetch(opcode, ic->code, wkEntry, ip);
break;
case OP_JMPFALSE: // conditional jump
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
if (ic->stack[ic->sp--] == 0) {
// condition satisfied - do the jump
ip = tmp;
@@ -557,7 +649,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
case OP_JMPTRUE: // conditional jump
- tmp = Fetch(opcode, ic->code, ip);
+ tmp = Fetch(opcode, ic->code, wkEntry, ip);
if (ic->stack[ic->sp--] != 0) {
// condition satisfied - do the jump
ip = tmp;
@@ -660,6 +752,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
// check for stack under-overflow
assert(ic->sp >= 0 && ic->sp < PCODE_STACK_SIZE);
ic->ip = ip;
+ ic->fragmentPtr = wkEntry;
} while (!ic->bHalt);
// make sure stack is unwound
diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h
index 4bdfcf5626..fad50cdb9d 100644
--- a/engines/tinsel/pcode.h
+++ b/engines/tinsel/pcode.h
@@ -54,6 +54,17 @@ enum GSORT {
enum RESCODE {RES_WAITING, RES_FINISHED, RES_CUTSHORT};
+// The following structure is used to introduce bug fixes into the scripts used by the games
+
+struct WorkaroundEntry {
+ TinselEngineVersion version;
+ bool scnFlag; // Only applicable for Tinsel 1 (DW 1)
+ SCNHANDLE hCode; // Script to apply fragment to
+ int ip; // Script offset to run this fragment before
+ int numBytes; // Number of bytes in the script
+ const byte *script; // Instruction(s) to execute
+};
+
struct INT_CONTEXT {
// Elements for interpret context management
@@ -82,6 +93,9 @@ struct INT_CONTEXT {
RESCODE resumeCode;
RESUME_STATE resumeState;
+ // Used to store execution state within a script workaround fragment
+ const WorkaroundEntry *fragmentPtr;
+
void syncWithSerializer(Common::Serializer &s);
};
typedef INT_CONTEXT *PINT_CONTEXT;
diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp
index 69b8f9ba43..73817a5a1a 100644
--- a/engines/touche/saveload.cpp
+++ b/engines/touche/saveload.cpp
@@ -355,10 +355,10 @@ Common::Error ToucheEngine::loadGameState(int num) {
} else {
f->skip(2 + kGameStateDescriptionLen);
loadGameStateData(f);
- if (!f->ioFailed()) {
- loadOk = true;
- } else {
+ if (f->err() || f->eos()) {
warning("Can't read file '%s'", gameStateFileName.c_str());
+ } else {
+ loadOk = true;
}
}
delete f;
diff --git a/engines/tucker/saveload.cpp b/engines/tucker/saveload.cpp
index cf7f985416..83533a90c3 100644
--- a/engines/tucker/saveload.cpp
+++ b/engines/tucker/saveload.cpp
@@ -88,7 +88,7 @@ Common::Error TuckerEngine::loadGameState(int num) {
} else {
f->skip(2);
saveOrLoadGameStateData(*f);
- if (f->ioFailed()) {
+ if (f->err() || f->eos()) {
warning("Can't read file '%s'", gameStateFileName.c_str());
ret = Common::kReadingFailed;
} else {