aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorChristopher Page2008-07-14 00:10:09 +0000
committerChristopher Page2008-07-14 00:10:09 +0000
commitd2e8d4831e33f9e1c63d53c9dd615a15f67ab995 (patch)
tree308cc8bb9ab0bc80d006c84b8ff84267355cedcb /engines
parent3ac3e84ecffa967f02eeb497e260a0de08e3d2e7 (diff)
parentef95c6ff70c1b428ab1d086a9b0b551fc82c8451 (diff)
downloadscummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.tar.gz
scummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.tar.bz2
scummvm-rg350-d2e8d4831e33f9e1c63d53c9dd615a15f67ab995.zip
Merged revisions 32744-32745,32747,32750-32759,32762-32764,32769,32777,32783,32785-32786,32789-32791,32798-32799,32801-32807,32809-32812,32816-32817,32819-32821,32823-32830,32832-32836,32838-32844,32846-32850,32852-32854,32858-32859,32865-32868,32873-32874,32879,32883,32895,32899,32902-32904,32910-32912,32923-32924,32930-32931,32938,32940,32948-32949,32951,32960-32964,32966-32970,32972-32974,32976,32978,32983,32986-32990,32992,32994,33002-33004,33006-33007,33009-33010,33014,33017,33021-33023,33030,33033 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk svn-id: r33051
Diffstat (limited to 'engines')
-rw-r--r--engines/cine/bg_list.cpp2
-rw-r--r--engines/cine/gfx.cpp11
-rw-r--r--engines/cine/main_loop.cpp7
-rw-r--r--engines/cine/object.cpp75
-rw-r--r--engines/cine/object.h8
-rw-r--r--engines/cine/script.h10
-rw-r--r--engines/cine/script_fw.cpp20
-rw-r--r--engines/cine/script_os.cpp83
-rw-r--r--engines/cine/various.cpp244
-rw-r--r--engines/cine/various.h6
-rw-r--r--engines/cruise/cruise_main.h2
-rw-r--r--engines/drascula/animation.cpp6
-rw-r--r--engines/drascula/drascula.h2
-rw-r--r--engines/drascula/rooms.cpp16
-rw-r--r--engines/drascula/talk.cpp2
-rw-r--r--engines/gob/detection.cpp13
-rw-r--r--engines/gob/driver_vga.cpp2
-rw-r--r--engines/gob/goblin.cpp330
-rw-r--r--engines/gob/goblin.h103
-rw-r--r--engines/gob/goblin_v2.cpp2
-rw-r--r--engines/gob/inter.cpp20
-rw-r--r--engines/gob/inter.h2
-rw-r--r--engines/gob/inter_v1.cpp173
-rw-r--r--engines/gob/inter_v2.cpp12
-rw-r--r--engines/gob/mult.cpp26
-rw-r--r--engines/gob/mult.h9
-rw-r--r--engines/gob/mult_v1.cpp33
-rw-r--r--engines/gob/mult_v2.cpp26
-rw-r--r--engines/gob/sound/sound.h2
-rw-r--r--engines/gob/sound/soundmixer.h2
-rw-r--r--engines/gob/variables.cpp58
-rw-r--r--engines/gob/variables.h26
-rw-r--r--engines/igor/igor.cpp2
-rw-r--r--engines/kyra/animator_lok.cpp4
-rw-r--r--engines/kyra/detection.cpp172
-rw-r--r--engines/kyra/gui_hof.cpp22
-rw-r--r--engines/kyra/gui_lok.cpp10
-rw-r--r--engines/kyra/gui_lok.h2
-rw-r--r--engines/kyra/items_lok.cpp2
-rw-r--r--engines/kyra/kyra_hof.cpp8
-rw-r--r--engines/kyra/kyra_mr.cpp11
-rw-r--r--engines/kyra/kyra_mr.h5
-rw-r--r--engines/kyra/kyra_v1.cpp50
-rw-r--r--engines/kyra/kyra_v1.h6
-rw-r--r--engines/kyra/kyra_v2.cpp32
-rw-r--r--engines/kyra/kyra_v2.h3
-rw-r--r--engines/kyra/scene_hof.cpp4
-rw-r--r--engines/kyra/scene_lok.cpp4
-rw-r--r--engines/kyra/screen.cpp16
-rw-r--r--engines/kyra/script.cpp8
-rw-r--r--engines/kyra/script.h2
-rw-r--r--engines/kyra/script_hof.cpp10
-rw-r--r--engines/kyra/script_tim.cpp20
-rw-r--r--engines/kyra/script_tim.h10
-rw-r--r--engines/kyra/seqplayer.cpp4
-rw-r--r--engines/kyra/sequences_lok.cpp2
-rw-r--r--engines/kyra/sound.cpp19
-rw-r--r--engines/kyra/sound.h57
-rw-r--r--engines/kyra/sound_lok.cpp16
-rw-r--r--engines/kyra/sound_towns.cpp2101
-rw-r--r--engines/kyra/staticres.cpp54
-rw-r--r--engines/m4/assets.cpp1
-rw-r--r--engines/m4/converse.cpp4
-rw-r--r--engines/m4/globals.cpp10
-rw-r--r--engines/m4/globals.h2
-rw-r--r--engines/m4/resource.cpp2
-rw-r--r--engines/made/pmvplayer.cpp5
-rw-r--r--engines/made/screen.cpp4
-rw-r--r--engines/parallaction/balloons.cpp456
-rw-r--r--engines/parallaction/callables_ns.cpp9
-rw-r--r--engines/parallaction/debug.cpp14
-rw-r--r--engines/parallaction/dialogue.cpp36
-rw-r--r--engines/parallaction/disk.h36
-rw-r--r--engines/parallaction/disk_br.cpp31
-rw-r--r--engines/parallaction/disk_ns.cpp38
-rw-r--r--engines/parallaction/exec.h241
-rw-r--r--engines/parallaction/exec_br.cpp159
-rw-r--r--engines/parallaction/exec_ns.cpp277
-rw-r--r--engines/parallaction/gfxbase.cpp294
-rw-r--r--engines/parallaction/graphics.cpp576
-rw-r--r--engines/parallaction/graphics.h110
-rw-r--r--engines/parallaction/gui_br.cpp6
-rw-r--r--engines/parallaction/gui_ns.cpp2
-rw-r--r--engines/parallaction/input.cpp4
-rw-r--r--engines/parallaction/input.h2
-rw-r--r--engines/parallaction/module.mk1
-rw-r--r--engines/parallaction/objects.cpp14
-rw-r--r--engines/parallaction/objects.h7
-rw-r--r--engines/parallaction/parallaction.cpp104
-rw-r--r--engines/parallaction/parallaction.h171
-rw-r--r--engines/parallaction/parallaction_br.cpp25
-rw-r--r--engines/parallaction/parallaction_ns.cpp27
-rw-r--r--engines/parallaction/parser_br.cpp2
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/sound.cpp4
-rw-r--r--engines/parallaction/walk.cpp173
-rw-r--r--engines/queen/resource.cpp2
-rw-r--r--engines/scumm/detection.cpp2
-rw-r--r--engines/scumm/gfxARM.s2
-rw-r--r--engines/scumm/he/resource_he.cpp5
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.h4
-rw-r--r--engines/scumm/saveload.cpp6
-rw-r--r--engines/scumm/smush/codec47ARM.s8
-rw-r--r--engines/touche/midi.cpp9
-rw-r--r--engines/touche/midi.h2
-rw-r--r--engines/touche/saveload.cpp3
-rw-r--r--engines/touche/touche.cpp6
107 files changed, 4879 insertions, 2008 deletions
diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp
index cf25f1d355..b10211282f 100644
--- a/engines/cine/bg_list.cpp
+++ b/engines/cine/bg_list.cpp
@@ -63,6 +63,7 @@ void addSpriteFilledToBGList(int16 objIdx) {
void createBgIncrustListElement(int16 objIdx, int16 param) {
BGIncrust tmp;
+ tmp.unkPtr = 0;
tmp.objIdx = objIdx;
tmp.param = param;
tmp.x = objectTable[objIdx].x;
@@ -90,6 +91,7 @@ void loadBgIncrustFromSave(Common::InSaveFile &fHandle) {
fHandle.readUint32BE();
fHandle.readUint32BE();
+ tmp.unkPtr = 0;
tmp.objIdx = fHandle.readUint16BE();
tmp.param = fHandle.readUint16BE();
tmp.x = fHandle.readUint16BE();
diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp
index 47446f2410..2b7f3b8890 100644
--- a/engines/cine/gfx.cpp
+++ b/engines/cine/gfx.cpp
@@ -969,6 +969,7 @@ void OSRenderer::drawBackground() {
/*! \brief Draw one overlay
* \param it Overlay info
+ * \todo Add handling of type 22 overlays
*/
void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
int len;
@@ -979,6 +980,9 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
switch (it->type) {
// color sprite
case 0:
+ if (objectTable[it->objIdx].frame < 0) {
+ break;
+ }
sprite = animDataTable + objectTable[it->objIdx].frame;
len = sprite->_realWidth * sprite->_height;
mask = new byte[len];
@@ -988,6 +992,13 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
delete[] mask;
break;
+ // bitmap
+ case 4:
+ if (objectTable[it->objIdx].frame >= 0) {
+ FWRenderer::renderOverlay(it);
+ }
+ break;
+
// masked background
case 20:
assert(it->objIdx < NUM_MAX_OBJECT);
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index 7830f4d8f8..547379f02d 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -227,6 +227,13 @@ void CineEngine::mainLoop(int bootScriptIdx) {
do {
stopMusicAfterFadeOut();
di = executePlayerInput();
+
+ // Clear the zoneQuery table (Operation Stealth specific)
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ for (uint i = 0; i < NUM_MAX_ZONE; i++) {
+ zoneQuery[i] = 0;
+ }
+ }
processSeqList();
executeList1();
diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp
index 7666f05352..c02e01c8ce 100644
--- a/engines/cine/object.cpp
+++ b/engines/cine/object.cpp
@@ -99,21 +99,36 @@ int removeOverlay(uint16 objIdx, uint16 param) {
/*! \brief Add new overlay sprite to the list
* \param objIdx Associate the overlay with this object
- * \param param Type of new overlay
+ * \param type Type of new overlay
* \todo Why are x, y, width and color left uninitialized?
*/
-void addOverlay(uint16 objIdx, uint16 param) {
+void addOverlay(uint16 objIdx, uint16 type) {
Common::List<overlay>::iterator it;
overlay tmp;
for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+ // This is done for both Future Wars and Operation Stealth
if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) {
break;
}
+
+ // There are additional checks in Operation Stealth's implementation
+ if (g_cine->getGameType() == Cine::GType_OS && (it->type == 2 || it->type == 3)) {
+ break;
+ }
+ }
+
+ // In Operation Stealth's implementation we might bail out early
+ if (g_cine->getGameType() == Cine::GType_OS && it != overlayList.end() && it->objIdx == objIdx && it->type == type) {
+ return;
}
tmp.objIdx = objIdx;
- tmp.type = param;
+ tmp.type = type;
+ tmp.x = 0;
+ tmp.y = 0;
+ tmp.width = 0;
+ tmp.color = 0;
overlayList.insert(it, tmp);
}
@@ -122,24 +137,22 @@ void addOverlay(uint16 objIdx, uint16 param) {
* \param objIdx Associate the overlay with this object
* \param param source background index
*/
-void addGfxElementA0(int16 objIdx, int16 param) {
+void addGfxElement(int16 objIdx, int16 param, int16 type) {
Common::List<overlay>::iterator it;
overlay tmp;
for (it = overlayList.begin(); it != overlayList.end(); ++it) {
- // wtf?!
- if (objectTable[it->objIdx].mask == objectTable[objIdx].mask &&
- (it->type == 2 || it->type == 3)) {
+ if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask || it->type == 2 || it->type == 3) {
break;
}
}
- if (it != overlayList.end() && it->objIdx == objIdx && it->type == 20 && it->x == param) {
+ if (it != overlayList.end() && it->objIdx == objIdx && it->type == type && it->x == param) {
return;
}
tmp.objIdx = objIdx;
- tmp.type = 20;
+ tmp.type = type;
tmp.x = param;
tmp.y = 0;
tmp.width = 0;
@@ -153,11 +166,11 @@ void addGfxElementA0(int16 objIdx, int16 param) {
* \param param Remove overlay using this background
* \todo Check that it works
*/
-void removeGfxElementA0(int16 objIdx, int16 param) {
+void removeGfxElement(int16 objIdx, int16 param, int16 type) {
Common::List<overlay>::iterator it;
for (it = overlayList.begin(); it != overlayList.end(); ++it) {
- if (it->objIdx == objIdx && it->type == 20 && it->x == param) {
+ if (it->objIdx == objIdx && it->type == type && it->x == param) {
overlayList.erase(it);
return;
}
@@ -170,8 +183,12 @@ void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint1
objectTable[objIdx].mask = param3;
objectTable[objIdx].frame = param4;
- if (removeOverlay(objIdx, 0)) {
- addOverlay(objIdx, 0);
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ resetGfxEntityEntry(objIdx);
+ } else { // Future Wars
+ if (removeOverlay(objIdx, 0)) {
+ addOverlay(objIdx, 0);
+ }
}
}
@@ -199,9 +216,12 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) {
case 3:
objectTable[objIdx].mask = newValue;
- // TODO: Check this part against disassembly
- if (removeOverlay(objIdx, 0)) {
- addOverlay(objIdx, 0);
+ if (g_cine->getGameType() == Cine::GType_OS) { // Operation Stealth specific
+ resetGfxEntityEntry(objIdx);
+ } else { // Future Wars specific
+ if (removeOverlay(objIdx, 0)) {
+ addOverlay(objIdx, 0);
+ }
}
break;
case 4:
@@ -221,6 +241,29 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) {
}
}
+/**
+ * Check if at least one of the range B's endpoints is inside range A,
+ * not counting the starting and ending points of range A.
+ * Used at least by Operation Stealth's opcode 0x8D i.e. 141.
+ */
+bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd) {
+ return (bStart > aStart && bStart < aEnd) || (bEnd > aStart && bEnd < aEnd);
+}
+
+uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2) {
+ assert(objIdx1 < NUM_MAX_OBJECT && objIdx2 < NUM_MAX_OBJECT);
+ const objectStruct &obj1 = objectTable[objIdx1];
+ const objectStruct &obj2 = objectTable[objIdx2];
+
+ if (compareRanges(obj1.x, obj1.x + xAdd1, obj2.x, obj2.x + xAdd2) &&
+ compareRanges(obj1.y, obj1.y + yAdd1, obj2.y, obj2.y + yAdd2) &&
+ compareRanges(obj1.mask, obj1.mask + maskAdd1, obj2.mask, obj2.mask + maskAdd2)) {
+ return kCmpEQ;
+ } else {
+ return 0;
+ }
+}
+
uint16 compareObjectParam(byte objIdx, byte type, int16 value) {
uint16 compareResult = 0;
int16 objectParam = getObjectParam(objIdx, type);
diff --git a/engines/cine/object.h b/engines/cine/object.h
index e7de39649d..103b2f50ba 100644
--- a/engines/cine/object.h
+++ b/engines/cine/object.h
@@ -60,15 +60,17 @@ void loadObject(char *pObjectName);
void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4);
void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue);
-void addOverlay(uint16 objIdx, uint16 param);
+void addOverlay(uint16 objIdx, uint16 type);
int removeOverlay(uint16 objIdx, uint16 param);
-void addGfxElementA0(int16 objIdx, int16 param);
-void removeGfxElementA0(int16 objIdx, int16 param);
+void addGfxElement(int16 objIdx, int16 param, int16 type);
+void removeGfxElement(int16 objIdx, int16 param, int16 type);
int16 getObjectParam(uint16 objIdx, uint16 paramIdx);
void addObjectParam(byte objIdx, byte paramIdx, int16 newValue);
void subObjectParam(byte objIdx, byte paramIdx, int16 newValue);
+bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd);
+uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2);
uint16 compareObjectParam(byte objIdx, byte param1, int16 param2);
} // End of namespace Cine
diff --git a/engines/cine/script.h b/engines/cine/script.h
index eeac0e8809..fcd21990fa 100644
--- a/engines/cine/script.h
+++ b/engines/cine/script.h
@@ -237,7 +237,7 @@ protected:
int o2_playSample();
int o2_playSampleAlt();
int o2_op81();
- int o2_op82();
+ int o2_modifySeqListElement();
int o2_isSeqRunning();
int o2_gotoIfSupNearest();
int o2_gotoIfSupEquNearest();
@@ -258,10 +258,10 @@ protected:
int o2_useBgScroll();
int o2_setAdditionalBgVScroll();
int o2_op9F();
- int o2_addGfxElementA0();
- int o2_removeGfxElementA0();
- int o2_opA2();
- int o2_opA3();
+ int o2_addGfxElementType20();
+ int o2_removeGfxElementType20();
+ int o2_addGfxElementType21();
+ int o2_removeGfxElementType21();
int o2_loadMask22();
int o2_unloadMask22();
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 845120c99e..148e673095 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -1764,18 +1764,32 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI
int16 lx = objectTable[objIdx].x + x;
int16 ly = objectTable[objIdx].y + y;
int16 idx;
+ int16 result = 0;
for (int16 i = 0; i < numZones; i++) {
idx = getZoneFromPositionRaw(page3Raw, lx + i, ly, 320);
- assert(idx >= 0 && idx <= NUM_MAX_ZONE);
+ assert(idx >= 0 && idx < NUM_MAX_ZONE);
+
+ // The zoneQuery table is updated here only in Operation Stealth
+ if (g_cine->getGameType() == Cine::GType_OS) {
+ if (zoneData[idx] < NUM_MAX_ZONE) {
+ zoneQuery[zoneData[idx]]++;
+ }
+ }
if (zoneData[idx] == zoneIdx) {
- return 1;
+ result = 1;
+ // Future Wars breaks out early on the first match, but
+ // Operation Stealth doesn't because it needs to update
+ // the zoneQuery table for the whole loop's period.
+ if (g_cine->getGameType() == Cine::GType_FW) {
+ break;
+ }
}
}
- return 0;
+ return result;
}
uint16 compareVars(int16 a, int16 b) {
diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp
index 319fca5d3c..78b6c55564 100644
--- a/engines/cine/script_os.cpp
+++ b/engines/cine/script_os.cpp
@@ -202,7 +202,7 @@ const Opcode OSScript::_opcodeTable[] = {
/* 80 */
{ &FWScript::o2_removeSeq, "bb" },
{ &FWScript::o2_op81, "" }, /* TODO: Name this opcode properly. */
- { &FWScript::o2_op82, "bbwwb" }, /* TODO: Name this opcode properly. */
+ { &FWScript::o2_modifySeqListElement, "bbwwb" },
{ &FWScript::o2_isSeqRunning, "bb" },
/* 84 */
{ &FWScript::o2_gotoIfSupNearest, "b" },
@@ -240,10 +240,10 @@ const Opcode OSScript::_opcodeTable[] = {
{ &FWScript::o2_setAdditionalBgVScroll, "c" },
{ &FWScript::o2_op9F, "ww" }, /* TODO: Name this opcode properly. */
/* A0 */
- { &FWScript::o2_addGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */
- { &FWScript::o2_removeGfxElementA0, "ww" }, /* TODO: Name this opcode properly. */
- { &FWScript::o2_opA2, "ww" }, /* TODO: Name this opcode properly. */
- { &FWScript::o2_opA3, "ww" }, /* TODO: Name this opcode properly. */
+ { &FWScript::o2_addGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */
+ { &FWScript::o2_removeGfxElementType20, "ww" }, /* TODO: Name this opcode properly. */
+ { &FWScript::o2_addGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */
+ { &FWScript::o2_removeGfxElementType21, "ww" }, /* TODO: Name this opcode properly. */
/* A4 */
{ &FWScript::o2_loadMask22, "b" }, /* TODO: Name this opcode properly. */
{ &FWScript::o2_unloadMask22, "b" }, /* TODO: Name this opcode properly. */
@@ -442,6 +442,7 @@ int FWScript::o2_removeSeq() {
}
/*! \todo Implement this instruction
+ * \note According to the scripts' opcode usage comparison this opcode isn't used at all.
*/
int FWScript::o2_op81() {
warning("STUB: o2_op81()");
@@ -449,23 +450,25 @@ int FWScript::o2_op81() {
return 0;
}
-/*! \todo Implement this instruction
- */
-int FWScript::o2_op82() {
+int FWScript::o2_modifySeqListElement() {
byte a = getNextByte();
byte b = getNextByte();
uint16 c = getNextWord();
uint16 d = getNextWord();
byte e = getNextByte();
- warning("STUB: o2_op82(%x, %x, %x, %x, %x)", a, b, c, d, e);
+ debugC(5, kCineDebugScript, "Line: %d: o2_modifySeqListElement(%d,%d,%d,%d,%d)", _line, a, b, c, d, e);
+
+ modifySeqListElement(a, 0, b, c, d, e);
return 0;
}
+/*! \todo Check whether this opcode's name is backwards (i.e. should it be o2_isSeqNotRunning?)
+ */
int FWScript::o2_isSeqRunning() {
byte a = getNextByte();
byte b = getNextByte();
- debugC(5, kCineDebugScript, "Line: %d: OP83(%d,%d) -> TODO", _line, a, b);
+ debugC(5, kCineDebugScript, "Line: %d: o2_isSeqRunning(%d,%d)", _line, a, b);
if (isSeqRunning(a, 0, b)) {
_compare = 1;
@@ -593,19 +596,18 @@ int FWScript::o2_stopObjectScript() {
return 0;
}
-/*! \todo Implement this instruction
- */
int FWScript::o2_op8D() {
- uint16 a = getNextWord();
- uint16 b = getNextWord();
- uint16 c = getNextWord();
- uint16 d = getNextWord();
- uint16 e = getNextWord();
- uint16 f = getNextWord();
- uint16 g = getNextWord();
- uint16 h = getNextWord();
- warning("STUB: o2_op8D(%x, %x, %x, %x, %x, %x, %x, %x)", a, b, c, d, e, f, g, h);
- // _currentScriptElement->compareResult = ...
+ uint16 objIdx1 = getNextWord();
+ uint16 xAdd1 = getNextWord();
+ uint16 yAdd1 = getNextWord();
+ uint16 maskAdd1 = getNextWord();
+ uint16 objIdx2 = getNextWord();
+ uint16 xAdd2 = getNextWord();
+ uint16 yAdd2 = getNextWord();
+ uint16 maskAdd2 = getNextWord();
+ debugC(5, kCineDebugScript, "Line: %d: o2_op8D(%d, %d, %d, %d, %d, %d, %d, %d)", _line, objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2);
+
+ _compare = compareObjectParamRanges(objIdx1, xAdd1, yAdd1, maskAdd1, objIdx2, xAdd2, yAdd2, maskAdd2);
return 0;
}
@@ -649,16 +651,15 @@ int FWScript::o2_loadBg() {
return 0;
}
-/*! \todo Check the current implementation for correctness
- */
int FWScript::o2_wasZoneChecked() {
byte param = getNextByte();
- _compare = (param < 16 && zoneData[param]);
+ _compare = (param < NUM_MAX_ZONE && zoneQuery[param]) ? 1 : 0;
debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param);
return 0;
}
/*! \todo Implement this instruction
+ * \note According to the scripts' opcode usage comparison this opcode isn't used at all.
*/
int FWScript::o2_op9B() {
uint16 a = getNextWord();
@@ -674,6 +675,7 @@ int FWScript::o2_op9B() {
}
/*! \todo Implement this instruction
+ * \note According to the scripts' opcode usage comparison this opcode isn't used at all.
*/
int FWScript::o2_op9C() {
uint16 a = getNextWord();
@@ -713,6 +715,7 @@ int FWScript::o2_setAdditionalBgVScroll() {
}
/*! \todo Implement this instruction
+ * \note According to the scripts' opcode usage comparison this opcode isn't used at all.
*/
int FWScript::o2_op9F() {
warning("o2_op9F()");
@@ -721,42 +724,36 @@ int FWScript::o2_op9F() {
return 0;
}
-int FWScript::o2_addGfxElementA0() {
+int FWScript::o2_addGfxElementType20() {
uint16 param1 = getNextWord();
uint16 param2 = getNextWord();
- debugC(5, kCineDebugScript, "Line: %d: addGfxElementA0(%d,%d)", _line, param1, param2);
- addGfxElementA0(param1, param2);
+ debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType20(%d,%d)", _line, param1, param2);
+ addGfxElement(param1, param2, 20);
return 0;
}
-/*! \todo Implement this instruction
- */
-int FWScript::o2_removeGfxElementA0() {
+int FWScript::o2_removeGfxElementType20() {
uint16 idx = getNextWord();
uint16 param = getNextWord();
- warning("STUB? o2_removeGfxElementA0(%x, %x)", idx, param);
- removeGfxElementA0(idx, param);
+ debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType20(%d,%d)", _line, idx, param);
+ removeGfxElement(idx, param, 20);
return 0;
}
-/*! \todo Implement this instruction
- */
-int FWScript::o2_opA2() {
+int FWScript::o2_addGfxElementType21() {
uint16 a = getNextWord();
uint16 b = getNextWord();
- warning("STUB: o2_opA2(%x, %x)", a, b);
- // addGfxElementA2();
+ debugC(5, kCineDebugScript, "Line: %d: o2_addGfxElementType21(%d,%d)", _line, a, b);
+ addGfxElement(a, b, 21);
return 0;
}
-/*! \todo Implement this instruction
- */
-int FWScript::o2_opA3() {
+int FWScript::o2_removeGfxElementType21() {
uint16 a = getNextWord();
uint16 b = getNextWord();
- warning("STUB: o2_opA3(%x, %x)", a, b);
- // removeGfxElementA2();
+ debugC(5, kCineDebugScript, "Line: %d: o2_removeGfxElementType21(%d,%d)", _line, a, b);
+ removeGfxElement(a, b, 21);
return 0;
}
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp
index bdad805785..46168b306c 100644
--- a/engines/cine/various.cpp
+++ b/engines/cine/various.cpp
@@ -94,6 +94,9 @@ 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;
@@ -110,6 +113,7 @@ CommandeType objectListCommand[20];
int16 objListTab[20];
uint16 zoneData[NUM_MAX_ZONE];
+uint16 zoneQuery[NUM_MAX_ZONE]; //!< Only exists in Operation Stealth
void stopMusicAfterFadeOut(void) {
@@ -130,6 +134,7 @@ void runObjectScript(int16 entryIdx) {
*/
void addPlayerCommandMessage(int16 cmd) {
overlay tmp;
+ memset(&tmp, 0, sizeof(tmp));
tmp.objIdx = cmd;
tmp.type = 3;
@@ -389,6 +394,7 @@ bool brokenSave(Common::InSaveFile &fHandle) {
}
/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only
+ * \todo Add support for loading the zoneQuery table (Operation Stealth specific)
*/
bool CineEngine::makeLoad(char *saveName) {
int16 i;
@@ -586,6 +592,8 @@ bool CineEngine::makeLoad(char *saveName) {
return true;
}
+/*! \todo Add support for saving the zoneQuery table (Operation Stealth specific)
+ */
void makeSave(char *saveFileName) {
int16 i;
Common::OutSaveFile *fHandle;
@@ -1580,16 +1588,19 @@ void removeSeq(uint16 param1, uint16 param2, uint16 param3) {
}
}
-uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) {
+bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3) {
Common::List<SeqListElement>::iterator it;
for (it = seqList.begin(); it != seqList.end(); ++it) {
if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) {
- return 1;
+ // Just to be on the safe side there's a restriction of the
+ // addition's result to 16-bit arithmetic here like in the
+ // original. It's possible that it's not strictly needed.
+ return ((it->var14 + it->var16) & 0xFFFF) == 0;
}
}
- return 0;
+ return true;
}
void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) {
@@ -1616,6 +1627,19 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i
seqList.insert(it, tmp);
}
+void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4) {
+ // Find a suitable list element and modify it
+ for (Common::List<SeqListElement>::iterator it = seqList.begin(); it != seqList.end(); ++it) {
+ if (it->objIdx == objIdx && it->var4 == var4Test) {
+ it->varC = param1;
+ it->var18 = param2;
+ it->var1A = param3;
+ it->var10 = it->var12 = param4;
+ break;
+ }
+ }
+}
+
void computeMove1(SeqListElement &element, int16 x, int16 y, int16 param1,
int16 param2, int16 x2, int16 y2) {
element.var16 = 0;
@@ -1660,105 +1684,48 @@ uint16 computeMove2(SeqListElement &element) {
return returnVar;
}
-// sort all the gfx stuff...
-
-void resetGfxEntityEntry(uint16 objIdx) {
-#if 0
- overlayHeadElement* tempHead = &overlayHead;
- byte* var_16 = NULL;
- uint16 var_10 = 0;
- uint16 var_12 = 0;
- overlayHeadElement* currentHead = tempHead->next;
- byte* var_1A = NULL;
- overlayHeadElement* var1E = &overlayHead;
-
- while (currentHead) {
- tempHead2 = currentHead->next;
-
- if (currentHead->objIdx == objIdx && currentHead->type!=2 && currentHead->type!=3 && currentHead->type!=0x14) {
- tempHead->next = tempHead2;
-
- if (tempHead2) {
- tempHead2->previous = currentHead->previous;
- } else {
- seqVar0 = currentHead->previous;
- }
-
- var_22 = var_16;
-
- if (!var_22) {
- // todo: goto?
- }
-
- var_22->previous = currentHead;
- } else {
- }
-
- if (currentHead->type == 0x14) {
- } else {
- }
-
- if (currentHead->type == 0x2 || currentHead->type == 0x3) {
- si = 10000;
- } else {
- si = objectTable[currentHead->objIdx];
- }
-
- if (objectTable[objIdx]>si) {
- var1E = currentHead;
- }
-
- tempHead = tempHead->next;
-
- }
-
- if (var_1A) {
- currentHead = var_16;
- var_22 = var_1E->next;
- var_1E->next = currentHead;
- var_1A->next = var_22;
-
- if (var_1E != &gfxEntityHead) {
- currentHead->previous = var_1E;
- }
-
- if (!var_22) {
- seqVar0 = var_1A;
- } else {
- var_22->previous = var_1A;
- }
-
- }
-#endif
-}
-
-uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &element, uint16 param3, int16 *param4) {
- const byte *currentPtr = ptr;
- const byte *ptrData;
- const byte *ptr2;
+uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &element, uint16 param3, int16 *param4) {
+ const int8 *ptrData;
+ const int8 *ptr2;
int16 di;
+ // In the original an error string is set and 0 is returned if the following doesn't hold
assert(ptr);
- assert(param4);
-
- dummyU16 = READ_BE_UINT16((currentPtr + param1 * 2) + 8);
+ // We probably could just use a local variable here instead of the dummyU16 but
+ // haven't checked if this has any side-effects so keeping it this way still.
+ dummyU16 = READ_BE_UINT16(ptr + param1 * 2 + 8);
ptrData = ptr + dummyU16;
+ // In the original an error string is set and 0 is returned if the following doesn't hold
assert(*ptrData);
di = (objectTable[objIdx].costume + 1) % (*ptrData);
- ptr2 = (ptrData + (di * 8)) + 1;
-
+ ++ptrData; // Jump over the just read byte
+ // Here ptr2 seems to be indexing a table of structs (8 bytes per struct):
+ // struct {
+ // int8 x; // 0 (Used with checkCollision)
+ // int8 y; // 1 (Used with checkCollision)
+ // int8 numZones; // 2 (Used with checkCollision)
+ // int8 var3; // 3 (Not used in this function)
+ // int8 xAdd; // 4 (Used with an object)
+ // int8 yAdd; // 5 (Used with an object)
+ // int8 maskAdd; // 6 (Used with an object)
+ // int8 frameAdd; // 7 (Used with an object)
+ // };
+ ptr2 = ptrData + di * 8;
+
+ // We might probably safely discard the AND by 1 here because
+ // at least in the original checkCollision returns always 0 or 1.
if ((checkCollision(objIdx, ptr2[0], ptr2[1], ptr2[2], ptr[0]) & 1)) {
return 0;
}
- objectTable[objIdx].x += (int8)ptr2[4];
- objectTable[objIdx].y += (int8)ptr2[5];
- objectTable[objIdx].mask += (int8)ptr2[6];
+ objectTable[objIdx].x += ptr2[4];
+ objectTable[objIdx].y += ptr2[5];
+ objectTable[objIdx].mask += ptr2[6];
- if (objectTable[objIdx].frame) {
+ if (ptr2[6]) {
resetGfxEntityEntry(objIdx);
}
@@ -1767,16 +1734,63 @@ uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &ele
if (param3 || !element.var14) {
objectTable[objIdx].costume = di;
} else {
+ assert(param4);
*param4 = di;
}
return 1;
}
+/*!
+ * Permutates the overlay list into a different order according to some logic.
+ * \todo Check this function for correctness (Wasn't very easy to reverse engineer so there may be errors)
+ */
+void resetGfxEntityEntry(uint16 objIdx) {
+ Common::List<overlay>::iterator it, bObjsCutPoint;
+ Common::List<overlay> aReverseObjs, bObjs;
+ bool foundCutPoint = false;
+
+ // Go through the overlay list and partition the whole list into two categories (Type A and type B objects)
+ for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+ if (it->objIdx == objIdx && it->type != 2 && it->type != 3) { // Type A object
+ aReverseObjs.push_front(*it);
+ } else { // Type B object
+ bObjs.push_back(*it);
+ uint16 objectMask;
+ if (it->type == 2 || it->type == 3) {
+ objectMask = 10000;
+ } else {
+ objectMask = objectTable[it->objIdx].mask;
+ }
+
+ if (objectTable[objIdx].mask > objectMask) { // Check for B objects' cut point
+ bObjsCutPoint = bObjs.reverse_begin();
+ foundCutPoint = true;
+ }
+ }
+ }
+
+ // Recreate the overlay list in a different order.
+ overlayList.clear();
+ if (foundCutPoint) {
+ // If a cut point was found the order is:
+ // B objects before the cut point, the cut point, A objects in reverse order, B objects after cut point.
+ ++bObjsCutPoint; // Include the cut point in the first list insertion
+ overlayList.insert(overlayList.end(), bObjs.begin(), bObjsCutPoint);
+ overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end());
+ overlayList.insert(overlayList.end(), bObjsCutPoint, bObjs.end());
+ } else {
+ // If no cut point was found the order is:
+ // A objects in reverse order, B objects.
+ overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end());
+ overlayList.insert(overlayList.end(), bObjs.begin(), bObjs.end());
+ }
+}
+
void processSeqListElement(SeqListElement &element) {
int16 x = objectTable[element.objIdx].x;
int16 y = objectTable[element.objIdx].y;
- const byte *ptr1 = animDataTable[element.frame].data();
+ const int8 *ptr1 = (const int8 *) animDataTable[element.frame].data();
int16 var_10;
int16 var_4;
int16 var_2;
@@ -1789,22 +1803,44 @@ void processSeqListElement(SeqListElement &element) {
element.var12 = 0;
if (ptr1) {
- uint16 param1 = ptr1[1];
- uint16 param2 = ptr1[2];
+ int16 param1 = ptr1[1];
+ int16 param2 = ptr1[2];
if (element.varC != 255) {
- // FIXME: Why is this here? Fingolfin gets lots of these
- // in his copy of Operation Stealth (value 0 or 236) under
- // Mac OS X. Maybe it's a endian issue? At least the graphics
- // in the copy protection screen are partially messed up.
- warning("processSeqListElement: varC = %d", element.varC);
- }
-
- if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) {
- computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]);
+ int16 x2 = element.var18;
+ int16 y2 = element.var1A;
+ if (element.varC) {
+ x2 += objectTable[element.varC].x;
+ y2 += objectTable[element.varC].y;
+ }
+ computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2);
} else {
- element.var16 = 0;
- element.var14 = 0;
+ if (inputVar0 && allowPlayerInput) {
+ int16 adder = param1 + 1;
+ if (inputVar0 != 1) {
+ adder = -adder;
+ }
+ // FIXME: In Operation Stealth's disassembly global variable 251 is used here
+ // but it's named as VAR_MOUSE_Y_MODE in ScummVM. Is it correct or a
+ // left over from Future Wars's reverse engineering?
+ globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder;
+ }
+
+ if (inputVar1 && allowPlayerInput) {
+ int16 adder = param2 + 1;
+ if (inputVar1 != 1) {
+ adder = -adder;
+ }
+ // TODO: Name currently unnamed global variable 252
+ globalVars[VAR_MOUSE_Y_POS] = globalVars[252] = ptr1[5] + y + adder;
+ }
+
+ if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) {
+ computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]);
+ } else {
+ element.var16 = 0;
+ element.var14 = 0;
+ }
}
var_10 = computeMove2(element);
@@ -1845,14 +1881,14 @@ void processSeqListElement(SeqListElement &element) {
}
}
- if (element.var16 + element.var14) {
+ if (element.var16 + element.var14 == 0) {
if (element.var1C) {
if (element.var1E) {
objectTable[element.objIdx].costume = 0;
element.var1E = 0;
}
- addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, (int16 *) & var2);
+ addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, &var_2);
}
}
diff --git a/engines/cine/various.h b/engines/cine/various.h
index f4d1649aab..3befde7eb8 100644
--- a/engines/cine/various.h
+++ b/engines/cine/various.h
@@ -128,16 +128,20 @@ struct SelectedObjStruct {
#define NUM_MAX_ZONE 16
extern uint16 zoneData[NUM_MAX_ZONE];
+extern uint16 zoneQuery[NUM_MAX_ZONE];
void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5);
void removeMessages();
void removeSeq(uint16 param1, uint16 param2, uint16 param3);
-uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3);
+bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3);
void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8);
+void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4);
void processSeqList(void);
+void resetGfxEntityEntry(uint16 objIdx);
+
bool makeTextEntryMenu(const char *caption, char *string, int strLen, int y);
} // End of namespace Cine
diff --git a/engines/cruise/cruise_main.h b/engines/cruise/cruise_main.h
index 60afe5fa4c..c9c27ada49 100644
--- a/engines/cruise/cruise_main.h
+++ b/engines/cruise/cruise_main.h
@@ -28,7 +28,7 @@
#include <string.h>
#include <stdlib.h>
-#include <assert.h>
+#include <assert.h> // FIXME: WINCE: this is not needed/not portable (probably applies to all above includes)
#include "common/scummsys.h"
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index b0877a2e3e..06868494b5 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -372,7 +372,11 @@ void DrasculaEngine::animation_1_1() {
break;
clearRoom();
- playMusic(2);
+ if (_lang == kSpanish)
+ playMusic(31);
+ else
+ playMusic(2);
+
pause(5);
playFLI("intro.bin", 12);
term_int = 1;
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index 567d894b75..8bb73d8dd1 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -328,7 +328,7 @@ public:
int curHeight, curWidth, feetHeight;
int talkHeight, talkWidth;
int floorX1, floorY1, floorX2, floorY2;
- int near, far;
+ int lowerLimit, upperLimit;
int trackFinal, walkToObject;
int objExit;
int timeDiff, startTime;
diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp
index 6fe28bdbdc..37dddf4b7e 100644
--- a/engines/drascula/rooms.cpp
+++ b/engines/drascula/rooms.cpp
@@ -1672,8 +1672,8 @@ void DrasculaEngine::enterRoom(int roomIndex) {
getIntFromLine(buffer, size, &floorY2);
if (currentChapter != 2) {
- getIntFromLine(buffer, size, &far);
- getIntFromLine(buffer, size, &near);
+ getIntFromLine(buffer, size, &upperLimit);
+ getIntFromLine(buffer, size, &lowerLimit);
}
_arj.close();
@@ -1732,27 +1732,27 @@ void DrasculaEngine::enterRoom(int roomIndex) {
if (currentChapter != 2) {
for (l = 0; l <= floorY1; l++)
- factor_red[l] = far;
+ factor_red[l] = upperLimit;
for (l = floorY1; l <= 201; l++)
- factor_red[l] = near;
+ factor_red[l] = lowerLimit;
- chiquez = (float)(near - far) / (float)(floorY2 - floorY1);
+ chiquez = (float)(lowerLimit - upperLimit) / (float)(floorY2 - floorY1);
for (l = floorY1; l <= floorY2; l++) {
- factor_red[l] = (int)(far + pequegnez);
+ factor_red[l] = (int)(upperLimit + pequegnez);
pequegnez = pequegnez + chiquez;
}
}
if (roomNumber == 24) {
for (l = floorY1 - 1; l > 74; l--) {
- factor_red[l] = (int)(far - pequegnez);
+ factor_red[l] = (int)(upperLimit - pequegnez);
pequegnez = pequegnez + chiquez;
}
}
if (currentChapter == 5 && roomNumber == 54) {
for (l = floorY1 - 1; l > 84; l--) {
- factor_red[l] = (int)(far - pequegnez);
+ factor_red[l] = (int)(upperLimit - pequegnez);
pequegnez = pequegnez + chiquez;
}
}
diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp
index 4d3187a0fd..a89c5ff734 100644
--- a/engines/drascula/talk.cpp
+++ b/engines/drascula/talk.cpp
@@ -60,7 +60,7 @@ void DrasculaEngine::talk_igor(int index, int talkerType) {
int x_talk1[8] = { 56, 86, 116, 146, 176, 206, 236, 266 };
int x_talk3[4] = { 80, 102, 124, 146 };
int x_talk4[4] = { 119, 158, 197, 236 };
- int face;
+ int face = 0;
int length = strlen(said);
color_abc(kColorWhite);
diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp
index 8351f2ecfb..63a0f8f45b 100644
--- a/engines/gob/detection.cpp
+++ b/engines/gob/detection.cpp
@@ -277,6 +277,19 @@ static const GOBGameDescription gameDescriptions[] = {
kFeaturesNone,
"intro"
},
+ { // Supplied by raina in the forums
+ {
+ "gob1",
+ "",
+ AD_ENTRY1s("intro.stk", "6d837c6380d8f4d984c9f6cc0026df4f", 192712),
+ EN_ANY,
+ kPlatformMacintosh,
+ Common::ADGF_NO_FLAGS
+ },
+ kGameTypeGob1,
+ kFeaturesNone,
+ "intro"
+ },
{ // Supplied by paul66 in bug report #1652352
{
"gob1",
diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp
index f68ce47783..2d3a10b570 100644
--- a/engines/gob/driver_vga.cpp
+++ b/engines/gob/driver_vga.cpp
@@ -112,7 +112,7 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest,
if ((width < 1) || (height < 1))
return;
- byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left;
+ const byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left;
byte *destPos = dest->getVidMem() + (y * dest->getWidth()) + x;
uint32 size = width * height;
diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp
index e7aed0790e..5add0b9cea 100644
--- a/engines/gob/goblin.cpp
+++ b/engines/gob/goblin.cpp
@@ -78,58 +78,6 @@ Goblin::Goblin(GobEngine *vm) : _vm(vm) {
_pressedMapY = 0;
_pathExistence = 0;
- _some0ValPtr = 0;
-
- _gobRetVarPtr = 0;
- _curGobVarPtr = 0;
- _curGobXPosVarPtr = 0;
- _curGobYPosVarPtr = 0;
- _itemInPocketVarPtr = 0;
-
- _curGobStateVarPtr = 0;
- _curGobFrameVarPtr = 0;
- _curGobMultStateVarPtr = 0;
- _curGobNextStateVarPtr = 0;
- _curGobScrXVarPtr = 0;
- _curGobScrYVarPtr = 0;
- _curGobLeftVarPtr = 0;
- _curGobTopVarPtr = 0;
- _curGobRightVarPtr = 0;
- _curGobBottomVarPtr = 0;
- _curGobDoAnimVarPtr = 0;
- _curGobOrderVarPtr = 0;
- _curGobNoTickVarPtr = 0;
- _curGobTypeVarPtr = 0;
- _curGobMaxTickVarPtr = 0;
- _curGobTickVarPtr = 0;
- _curGobActStartStateVarPtr = 0;
- _curGobLookDirVarPtr = 0;
- _curGobPickableVarPtr = 0;
- _curGobRelaxVarPtr = 0;
- _curGobMaxFrameVarPtr = 0;
-
- _destItemStateVarPtr = 0;
- _destItemFrameVarPtr = 0;
- _destItemMultStateVarPtr = 0;
- _destItemNextStateVarPtr = 0;
- _destItemScrXVarPtr = 0;
- _destItemScrYVarPtr = 0;
- _destItemLeftVarPtr = 0;
- _destItemTopVarPtr = 0;
- _destItemRightVarPtr = 0;
- _destItemBottomVarPtr = 0;
- _destItemDoAnimVarPtr = 0;
- _destItemOrderVarPtr = 0;
- _destItemNoTickVarPtr = 0;
- _destItemTypeVarPtr = 0;
- _destItemMaxTickVarPtr = 0;
- _destItemTickVarPtr = 0;
- _destItemActStartStVarPtr = 0;
- _destItemLookDirVarPtr = 0;
- _destItemPickableVarPtr = 0;
- _destItemRelaxVarPtr = 0;
- _destItemMaxFrameVarPtr = 0;
-
_destItemType = 0;
_destItemState = 0;
for (int i = 0; i < 20; i++) {
@@ -690,7 +638,7 @@ void Goblin::switchGoblin(int16 index) {
_gobDestY = tmp;
_vm->_map->_curGoblinY = tmp;
- *_curGobVarPtr = _currentGoblin;
+ _curGobVarPtr = (uint32) _currentGoblin;
_pathExistence = 0;
_readyToAct = 0;
}
@@ -1250,172 +1198,172 @@ void Goblin::loadObjects(const char *source) {
void Goblin::saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) {
Gob_Object *obj;
- *_some0ValPtr = someVal;
- *_curGobXPosVarPtr = xPos;
- *_curGobYPosVarPtr = yPos;
- *_itemInPocketVarPtr = _itemIndInPocket;
+ _some0ValPtr = (uint32) someVal;
+ _curGobXPosVarPtr = (uint32) xPos;
+ _curGobYPosVarPtr = (uint32) yPos;
+ _itemInPocketVarPtr = (uint32) _itemIndInPocket;
obj = _goblins[_currentGoblin];
- *_curGobStateVarPtr = obj->state;
- *_curGobFrameVarPtr = obj->curFrame;
- *_curGobMultStateVarPtr = obj->multState;
- *_curGobNextStateVarPtr = obj->nextState;
- *_curGobScrXVarPtr = obj->xPos;
- *_curGobScrYVarPtr = obj->yPos;
- *_curGobLeftVarPtr = obj->left;
- *_curGobTopVarPtr = obj->top;
- *_curGobRightVarPtr = obj->right;
- *_curGobBottomVarPtr = obj->bottom;
- *_curGobDoAnimVarPtr = obj->doAnim;
- *_curGobOrderVarPtr = obj->order;
- *_curGobNoTickVarPtr = obj->noTick;
- *_curGobTypeVarPtr = obj->type;
- *_curGobMaxTickVarPtr = obj->maxTick;
- *_curGobTickVarPtr = obj->tick;
- *_curGobActStartStateVarPtr = obj->actionStartState;
- *_curGobLookDirVarPtr = obj->curLookDir;
- *_curGobPickableVarPtr = obj->pickable;
- *_curGobRelaxVarPtr = obj->relaxTime;
- *_curGobMaxFrameVarPtr = getObjMaxFrame(obj);
+ _curGobStateVarPtr = (uint32) obj->state;
+ _curGobFrameVarPtr = (uint32) obj->curFrame;
+ _curGobMultStateVarPtr = (uint32) obj->multState;
+ _curGobNextStateVarPtr = (uint32) obj->nextState;
+ _curGobScrXVarPtr = (uint32) obj->xPos;
+ _curGobScrYVarPtr = (uint32) obj->yPos;
+ _curGobLeftVarPtr = (uint32) obj->left;
+ _curGobTopVarPtr = (uint32) obj->top;
+ _curGobRightVarPtr = (uint32) obj->right;
+ _curGobBottomVarPtr = (uint32) obj->bottom;
+ _curGobDoAnimVarPtr = (uint32) obj->doAnim;
+ _curGobOrderVarPtr = (uint32) obj->order;
+ _curGobNoTickVarPtr = (uint32) obj->noTick;
+ _curGobTypeVarPtr = (uint32) obj->type;
+ _curGobMaxTickVarPtr = (uint32) obj->maxTick;
+ _curGobTickVarPtr = (uint32) obj->tick;
+ _curGobActStartStateVarPtr = (uint32) obj->actionStartState;
+ _curGobLookDirVarPtr = (uint32) obj->curLookDir;
+ _curGobPickableVarPtr = (uint32) obj->pickable;
+ _curGobRelaxVarPtr = (uint32) obj->relaxTime;
+ _curGobMaxFrameVarPtr = (uint32) getObjMaxFrame(obj);
if (_actDestItemDesc == 0)
return;
obj = _actDestItemDesc;
- *_destItemStateVarPtr = obj->state;
- *_destItemFrameVarPtr = obj->curFrame;
- *_destItemMultStateVarPtr = obj->multState;
- *_destItemNextStateVarPtr = obj->nextState;
- *_destItemScrXVarPtr = obj->xPos;
- *_destItemScrYVarPtr = obj->yPos;
- *_destItemLeftVarPtr = obj->left;
- *_destItemTopVarPtr = obj->top;
- *_destItemRightVarPtr = obj->right;
- *_destItemBottomVarPtr = obj->bottom;
- *_destItemDoAnimVarPtr = obj->doAnim;
- *_destItemOrderVarPtr = obj->order;
- *_destItemNoTickVarPtr = obj->noTick;
- *_destItemTypeVarPtr = obj->type;
- *_destItemMaxTickVarPtr = obj->maxTick;
- *_destItemTickVarPtr = obj->tick;
- *_destItemActStartStVarPtr = obj->actionStartState;
- *_destItemLookDirVarPtr = obj->curLookDir;
- *_destItemPickableVarPtr = obj->pickable;
- *_destItemRelaxVarPtr = obj->relaxTime;
- *_destItemMaxFrameVarPtr = getObjMaxFrame(obj);
+ _destItemStateVarPtr = (uint32) obj->state;
+ _destItemFrameVarPtr = (uint32) obj->curFrame;
+ _destItemMultStateVarPtr = (uint32) obj->multState;
+ _destItemNextStateVarPtr = (uint32) obj->nextState;
+ _destItemScrXVarPtr = (uint32) obj->xPos;
+ _destItemScrYVarPtr = (uint32) obj->yPos;
+ _destItemLeftVarPtr = (uint32) obj->left;
+ _destItemTopVarPtr = (uint32) obj->top;
+ _destItemRightVarPtr = (uint32) obj->right;
+ _destItemBottomVarPtr = (uint32) obj->bottom;
+ _destItemDoAnimVarPtr = (uint32) obj->doAnim;
+ _destItemOrderVarPtr = (uint32) obj->order;
+ _destItemNoTickVarPtr = (uint32) obj->noTick;
+ _destItemTypeVarPtr = (uint32) obj->type;
+ _destItemMaxTickVarPtr = (uint32) obj->maxTick;
+ _destItemTickVarPtr = (uint32) obj->tick;
+ _destItemActStartStVarPtr = (uint32) obj->actionStartState;
+ _destItemLookDirVarPtr = (uint32) obj->curLookDir;
+ _destItemPickableVarPtr = (uint32) obj->pickable;
+ _destItemRelaxVarPtr = (uint32) obj->relaxTime;
+ _destItemMaxFrameVarPtr = (uint32) getObjMaxFrame(obj);
_destItemState = obj->state;
_destItemType = obj->type;
}
void Goblin::initVarPointers(void) {
- _gobRetVarPtr = (int32 *)VAR_ADDRESS(59);
- _curGobStateVarPtr = (int32 *)VAR_ADDRESS(60);
- _curGobFrameVarPtr = (int32 *)VAR_ADDRESS(61);
- _curGobMultStateVarPtr = (int32 *)VAR_ADDRESS(62);
- _curGobNextStateVarPtr = (int32 *)VAR_ADDRESS(63);
- _curGobScrXVarPtr = (int32 *)VAR_ADDRESS(64);
- _curGobScrYVarPtr = (int32 *)VAR_ADDRESS(65);
- _curGobLeftVarPtr = (int32 *)VAR_ADDRESS(66);
- _curGobTopVarPtr = (int32 *)VAR_ADDRESS(67);
- _curGobRightVarPtr = (int32 *)VAR_ADDRESS(68);
- _curGobBottomVarPtr = (int32 *)VAR_ADDRESS(69);
- _curGobDoAnimVarPtr = (int32 *)VAR_ADDRESS(70);
- _curGobOrderVarPtr = (int32 *)VAR_ADDRESS(71);
- _curGobNoTickVarPtr = (int32 *)VAR_ADDRESS(72);
- _curGobTypeVarPtr = (int32 *)VAR_ADDRESS(73);
- _curGobMaxTickVarPtr = (int32 *)VAR_ADDRESS(74);
- _curGobTickVarPtr = (int32 *)VAR_ADDRESS(75);
- _curGobActStartStateVarPtr = (int32 *)VAR_ADDRESS(76);
- _curGobLookDirVarPtr = (int32 *)VAR_ADDRESS(77);
- _curGobPickableVarPtr = (int32 *)VAR_ADDRESS(80);
- _curGobRelaxVarPtr = (int32 *)VAR_ADDRESS(81);
- _destItemStateVarPtr = (int32 *)VAR_ADDRESS(82);
- _destItemFrameVarPtr = (int32 *)VAR_ADDRESS(83);
- _destItemMultStateVarPtr = (int32 *)VAR_ADDRESS(84);
- _destItemNextStateVarPtr = (int32 *)VAR_ADDRESS(85);
- _destItemScrXVarPtr = (int32 *)VAR_ADDRESS(86);
- _destItemScrYVarPtr = (int32 *)VAR_ADDRESS(87);
- _destItemLeftVarPtr = (int32 *)VAR_ADDRESS(88);
- _destItemTopVarPtr = (int32 *)VAR_ADDRESS(89);
- _destItemRightVarPtr = (int32 *)VAR_ADDRESS(90);
- _destItemBottomVarPtr = (int32 *)VAR_ADDRESS(91);
- _destItemDoAnimVarPtr = (int32 *)VAR_ADDRESS(92);
- _destItemOrderVarPtr = (int32 *)VAR_ADDRESS(93);
- _destItemNoTickVarPtr = (int32 *)VAR_ADDRESS(94);
- _destItemTypeVarPtr = (int32 *)VAR_ADDRESS(95);
- _destItemMaxTickVarPtr = (int32 *)VAR_ADDRESS(96);
- _destItemTickVarPtr = (int32 *)VAR_ADDRESS(97);
- _destItemActStartStVarPtr = (int32 *)VAR_ADDRESS(98);
- _destItemLookDirVarPtr = (int32 *)VAR_ADDRESS(99);
- _destItemPickableVarPtr = (int32 *)VAR_ADDRESS(102);
- _destItemRelaxVarPtr = (int32 *)VAR_ADDRESS(103);
- _destItemMaxFrameVarPtr = (int32 *)VAR_ADDRESS(105);
- _curGobVarPtr = (int32 *)VAR_ADDRESS(106);
- _some0ValPtr = (int32 *)VAR_ADDRESS(107);
- _curGobXPosVarPtr = (int32 *)VAR_ADDRESS(108);
- _curGobYPosVarPtr = (int32 *)VAR_ADDRESS(109);
- _curGobMaxFrameVarPtr = (int32 *)VAR_ADDRESS(110);
-
- _itemInPocketVarPtr = (int32 *)VAR_ADDRESS(114);
-
- *_itemInPocketVarPtr = -2;
+ _gobRetVarPtr.set(*_vm->_inter->_variables, 236);
+ _curGobStateVarPtr.set(*_vm->_inter->_variables, 240);
+ _curGobFrameVarPtr.set(*_vm->_inter->_variables, 244);
+ _curGobMultStateVarPtr.set(*_vm->_inter->_variables, 248);
+ _curGobNextStateVarPtr.set(*_vm->_inter->_variables, 252);
+ _curGobScrXVarPtr.set(*_vm->_inter->_variables, 256);
+ _curGobScrYVarPtr.set(*_vm->_inter->_variables, 260);
+ _curGobLeftVarPtr.set(*_vm->_inter->_variables, 264);
+ _curGobTopVarPtr.set(*_vm->_inter->_variables, 268);
+ _curGobRightVarPtr.set(*_vm->_inter->_variables, 272);
+ _curGobBottomVarPtr.set(*_vm->_inter->_variables, 276);
+ _curGobDoAnimVarPtr.set(*_vm->_inter->_variables, 280);
+ _curGobOrderVarPtr.set(*_vm->_inter->_variables, 284);
+ _curGobNoTickVarPtr.set(*_vm->_inter->_variables, 288);
+ _curGobTypeVarPtr.set(*_vm->_inter->_variables, 292);
+ _curGobMaxTickVarPtr.set(*_vm->_inter->_variables, 296);
+ _curGobTickVarPtr.set(*_vm->_inter->_variables, 300);
+ _curGobActStartStateVarPtr.set(*_vm->_inter->_variables, 304);
+ _curGobLookDirVarPtr.set(*_vm->_inter->_variables, 308);
+ _curGobPickableVarPtr.set(*_vm->_inter->_variables, 320);
+ _curGobRelaxVarPtr.set(*_vm->_inter->_variables, 324);
+ _destItemStateVarPtr.set(*_vm->_inter->_variables, 328);
+ _destItemFrameVarPtr.set(*_vm->_inter->_variables, 332);
+ _destItemMultStateVarPtr.set(*_vm->_inter->_variables, 336);
+ _destItemNextStateVarPtr.set(*_vm->_inter->_variables, 340);
+ _destItemScrXVarPtr.set(*_vm->_inter->_variables, 344);
+ _destItemScrYVarPtr.set(*_vm->_inter->_variables, 348);
+ _destItemLeftVarPtr.set(*_vm->_inter->_variables, 352);
+ _destItemTopVarPtr.set(*_vm->_inter->_variables, 356);
+ _destItemRightVarPtr.set(*_vm->_inter->_variables, 360);
+ _destItemBottomVarPtr.set(*_vm->_inter->_variables, 364);
+ _destItemDoAnimVarPtr.set(*_vm->_inter->_variables, 368);
+ _destItemOrderVarPtr.set(*_vm->_inter->_variables, 372);
+ _destItemNoTickVarPtr.set(*_vm->_inter->_variables, 376);
+ _destItemTypeVarPtr.set(*_vm->_inter->_variables, 380);
+ _destItemMaxTickVarPtr.set(*_vm->_inter->_variables, 384);
+ _destItemTickVarPtr.set(*_vm->_inter->_variables, 388);
+ _destItemActStartStVarPtr.set(*_vm->_inter->_variables, 392);
+ _destItemLookDirVarPtr.set(*_vm->_inter->_variables, 396);
+ _destItemPickableVarPtr.set(*_vm->_inter->_variables, 408);
+ _destItemRelaxVarPtr.set(*_vm->_inter->_variables, 412);
+ _destItemMaxFrameVarPtr.set(*_vm->_inter->_variables, 420);
+ _curGobVarPtr.set(*_vm->_inter->_variables, 424);
+ _some0ValPtr.set(*_vm->_inter->_variables, 428);
+ _curGobXPosVarPtr.set(*_vm->_inter->_variables, 432);
+ _curGobYPosVarPtr.set(*_vm->_inter->_variables, 436);
+ _curGobMaxFrameVarPtr.set(*_vm->_inter->_variables, 440);
+
+ _itemInPocketVarPtr.set(*_vm->_inter->_variables, 456);
+
+ _itemInPocketVarPtr = (uint32) -2;
}
void Goblin::loadGobDataFromVars(void) {
Gob_Object *obj;
- _itemIndInPocket = *_itemInPocketVarPtr;
+ _itemIndInPocket = (int32) _itemInPocketVarPtr;
obj = _goblins[_currentGoblin];
- obj->state = *_curGobStateVarPtr;
- obj->curFrame = *_curGobFrameVarPtr;
- obj->multState = *_curGobMultStateVarPtr;
- obj->nextState = *_curGobNextStateVarPtr;
- obj->xPos = *_curGobScrXVarPtr;
- obj->yPos = *_curGobScrYVarPtr;
- obj->left = *_curGobLeftVarPtr;
- obj->top = *_curGobTopVarPtr;
- obj->right = *_curGobRightVarPtr;
- obj->bottom = *_curGobBottomVarPtr;
- obj->doAnim = *_curGobDoAnimVarPtr;
- obj->order = *_curGobOrderVarPtr;
- obj->noTick = *_curGobNoTickVarPtr;
- obj->type = *_curGobTypeVarPtr;
- obj->maxTick = *_curGobMaxTickVarPtr;
- obj->tick = *_curGobTickVarPtr;
- obj->actionStartState = *_curGobActStartStateVarPtr;
- obj->curLookDir = *_curGobLookDirVarPtr;
- obj->pickable = *_curGobPickableVarPtr;
- obj->relaxTime = *_curGobRelaxVarPtr;
+ obj->state = (int32) _curGobStateVarPtr;
+ obj->curFrame = (int32) _curGobFrameVarPtr;
+ obj->multState = (int32) _curGobMultStateVarPtr;
+ obj->nextState = (int32) _curGobNextStateVarPtr;
+ obj->xPos = (int32) _curGobScrXVarPtr;
+ obj->yPos = (int32) _curGobScrYVarPtr;
+ obj->left = (int32) _curGobLeftVarPtr;
+ obj->top = (int32) _curGobTopVarPtr;
+ obj->right = (int32) _curGobRightVarPtr;
+ obj->bottom = (int32) _curGobBottomVarPtr;
+ obj->doAnim = (int32) _curGobDoAnimVarPtr;
+ obj->order = (int32) _curGobOrderVarPtr;
+ obj->noTick = (int32) _curGobNoTickVarPtr;
+ obj->type = (int32) _curGobTypeVarPtr;
+ obj->maxTick = (int32) _curGobMaxTickVarPtr;
+ obj->tick = (int32) _curGobTickVarPtr;
+ obj->actionStartState = (int32) _curGobActStartStateVarPtr;
+ obj->curLookDir = (int32) _curGobLookDirVarPtr;
+ obj->pickable = (int32) _curGobPickableVarPtr;
+ obj->relaxTime = (int32) _curGobRelaxVarPtr;
if (_actDestItemDesc == 0)
return;
obj = _actDestItemDesc;
- obj->state = *_destItemStateVarPtr;
- obj->curFrame = *_destItemFrameVarPtr;
- obj->multState = *_destItemMultStateVarPtr;
- obj->nextState = *_destItemNextStateVarPtr;
- obj->xPos = *_destItemScrXVarPtr;
- obj->yPos = *_destItemScrYVarPtr;
- obj->left = *_destItemLeftVarPtr;
- obj->top = *_destItemTopVarPtr;
- obj->right = *_destItemRightVarPtr;
- obj->bottom = *_destItemBottomVarPtr;
- obj->doAnim = *_destItemDoAnimVarPtr;
- obj->order = *_destItemOrderVarPtr;
- obj->noTick = *_destItemNoTickVarPtr;
- obj->type = *_destItemTypeVarPtr;
- obj->maxTick = *_destItemMaxTickVarPtr;
- obj->tick = *_destItemTickVarPtr;
- obj->actionStartState = *_destItemActStartStVarPtr;
- obj->curLookDir = *_destItemLookDirVarPtr;
- obj->pickable = *_destItemPickableVarPtr;
- obj->relaxTime = *_destItemRelaxVarPtr;
+ obj->state = (int32) _destItemStateVarPtr;
+ obj->curFrame = (int32) _destItemFrameVarPtr;
+ obj->multState = (int32) _destItemMultStateVarPtr;
+ obj->nextState = (int32) _destItemNextStateVarPtr;
+ obj->xPos = (int32) _destItemScrXVarPtr;
+ obj->yPos = (int32) _destItemScrYVarPtr;
+ obj->left = (int32) _destItemLeftVarPtr;
+ obj->top = (int32) _destItemTopVarPtr;
+ obj->right = (int32) _destItemRightVarPtr;
+ obj->bottom = (int32) _destItemBottomVarPtr;
+ obj->doAnim = (int32) _destItemDoAnimVarPtr;
+ obj->order = (int32) _destItemOrderVarPtr;
+ obj->noTick = (int32) _destItemNoTickVarPtr;
+ obj->type = (int32) _destItemTypeVarPtr;
+ obj->maxTick = (int32) _destItemMaxTickVarPtr;
+ obj->tick = (int32) _destItemTickVarPtr;
+ obj->actionStartState = (int32) _destItemActStartStVarPtr;
+ obj->curLookDir = (int32) _destItemLookDirVarPtr;
+ obj->pickable = (int32) _destItemPickableVarPtr;
+ obj->relaxTime = (int32) _destItemRelaxVarPtr;
if (obj->type != _destItemType)
obj->toRedraw = 1;
diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h
index 3fd8a9f93b..2100bcbdac 100644
--- a/engines/gob/goblin.h
+++ b/engines/gob/goblin.h
@@ -28,6 +28,7 @@
#include "gob/util.h"
#include "gob/mult.h"
+#include "gob/variables.h"
#include "gob/sound/sounddesc.h"
namespace Gob {
@@ -115,57 +116,57 @@ public:
char _pathExistence;
// Pointers to interpreter variables
- int32 *_some0ValPtr;
-
- int32 *_gobRetVarPtr;
- int32 *_curGobVarPtr;
- int32 *_curGobXPosVarPtr;
- int32 *_curGobYPosVarPtr;
- int32 *_itemInPocketVarPtr;
-
- int32 *_curGobStateVarPtr;
- int32 *_curGobFrameVarPtr;
- int32 *_curGobMultStateVarPtr;
- int32 *_curGobNextStateVarPtr;
- int32 *_curGobScrXVarPtr;
- int32 *_curGobScrYVarPtr;
- int32 *_curGobLeftVarPtr;
- int32 *_curGobTopVarPtr;
- int32 *_curGobRightVarPtr;
- int32 *_curGobBottomVarPtr;
- int32 *_curGobDoAnimVarPtr;
- int32 *_curGobOrderVarPtr;
- int32 *_curGobNoTickVarPtr;
- int32 *_curGobTypeVarPtr;
- int32 *_curGobMaxTickVarPtr;
- int32 *_curGobTickVarPtr;
- int32 *_curGobActStartStateVarPtr;
- int32 *_curGobLookDirVarPtr;
- int32 *_curGobPickableVarPtr;
- int32 *_curGobRelaxVarPtr;
- int32 *_curGobMaxFrameVarPtr;
-
- int32 *_destItemStateVarPtr;
- int32 *_destItemFrameVarPtr;
- int32 *_destItemMultStateVarPtr;
- int32 *_destItemNextStateVarPtr;
- int32 *_destItemScrXVarPtr;
- int32 *_destItemScrYVarPtr;
- int32 *_destItemLeftVarPtr;
- int32 *_destItemTopVarPtr;
- int32 *_destItemRightVarPtr;
- int32 *_destItemBottomVarPtr;
- int32 *_destItemDoAnimVarPtr;
- int32 *_destItemOrderVarPtr;
- int32 *_destItemNoTickVarPtr;
- int32 *_destItemTypeVarPtr;
- int32 *_destItemMaxTickVarPtr;
- int32 *_destItemTickVarPtr;
- int32 *_destItemActStartStVarPtr;
- int32 *_destItemLookDirVarPtr;
- int32 *_destItemPickableVarPtr;
- int32 *_destItemRelaxVarPtr;
- int32 *_destItemMaxFrameVarPtr;
+ VariableReference _some0ValPtr;
+
+ VariableReference _gobRetVarPtr;
+ VariableReference _curGobVarPtr;
+ VariableReference _curGobXPosVarPtr;
+ VariableReference _curGobYPosVarPtr;
+ VariableReference _itemInPocketVarPtr;
+
+ VariableReference _curGobStateVarPtr;
+ VariableReference _curGobFrameVarPtr;
+ VariableReference _curGobMultStateVarPtr;
+ VariableReference _curGobNextStateVarPtr;
+ VariableReference _curGobScrXVarPtr;
+ VariableReference _curGobScrYVarPtr;
+ VariableReference _curGobLeftVarPtr;
+ VariableReference _curGobTopVarPtr;
+ VariableReference _curGobRightVarPtr;
+ VariableReference _curGobBottomVarPtr;
+ VariableReference _curGobDoAnimVarPtr;
+ VariableReference _curGobOrderVarPtr;
+ VariableReference _curGobNoTickVarPtr;
+ VariableReference _curGobTypeVarPtr;
+ VariableReference _curGobMaxTickVarPtr;
+ VariableReference _curGobTickVarPtr;
+ VariableReference _curGobActStartStateVarPtr;
+ VariableReference _curGobLookDirVarPtr;
+ VariableReference _curGobPickableVarPtr;
+ VariableReference _curGobRelaxVarPtr;
+ VariableReference _curGobMaxFrameVarPtr;
+
+ VariableReference _destItemStateVarPtr;
+ VariableReference _destItemFrameVarPtr;
+ VariableReference _destItemMultStateVarPtr;
+ VariableReference _destItemNextStateVarPtr;
+ VariableReference _destItemScrXVarPtr;
+ VariableReference _destItemScrYVarPtr;
+ VariableReference _destItemLeftVarPtr;
+ VariableReference _destItemTopVarPtr;
+ VariableReference _destItemRightVarPtr;
+ VariableReference _destItemBottomVarPtr;
+ VariableReference _destItemDoAnimVarPtr;
+ VariableReference _destItemOrderVarPtr;
+ VariableReference _destItemNoTickVarPtr;
+ VariableReference _destItemTypeVarPtr;
+ VariableReference _destItemMaxTickVarPtr;
+ VariableReference _destItemTickVarPtr;
+ VariableReference _destItemActStartStVarPtr;
+ VariableReference _destItemLookDirVarPtr;
+ VariableReference _destItemPickableVarPtr;
+ VariableReference _destItemRelaxVarPtr;
+ VariableReference _destItemMaxFrameVarPtr;
int16 _destItemType;
int16 _destItemState;
diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp
index 9144e35070..d763aeb01c 100644
--- a/engines/gob/goblin_v2.cpp
+++ b/engines/gob/goblin_v2.cpp
@@ -88,7 +88,7 @@ void Goblin_v2::placeObject(Gob_Object *objDesc, char animated,
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) - (y + 1) / 2;
*obj->pPosX = x * _vm->_map->_tilesWidth;
} else {
- if (obj->goblinStates[state] != 0) {
+ if ((obj->goblinStates != 0) && (obj->goblinStates[state] != 0)) {
layer = obj->goblinStates[state][0].layer;
animation = obj->goblinStates[state][0].animation;
objAnim->state = state;
diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp
index ecba1c1a20..c0a1bfc21a 100644
--- a/engines/gob/inter.cpp
+++ b/engines/gob/inter.cpp
@@ -212,25 +212,35 @@ void Inter::funcBlock(int16 retFlag) {
break;
// WORKAROUND:
- // The EGA version of gob1 doesn't add a delay after showing
+ // The EGA and Mac versions of gob1 doesn't add a delay after showing
// images between levels. We manually add it here.
- if ((_vm->getGameType() == kGameTypeGob1) && _vm->isEGA()) {
+ if ((_vm->getGameType() == kGameTypeGob1) &&
+ (_vm->isEGA() || (_vm->getPlatform() == Common::kPlatformMacintosh))) {
+
int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData;
- if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie
+
+ if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie, EGA
+ !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) ||
+ (startaddr == 0x188D && addr == 0x1A58 && // Zombie, Mac
!strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) ||
(startaddr == 0x1299 && addr == 0x139A && // Dungeon
!strncmp(_vm->_game->_curTotFile, "avt006.tot", 10)) ||
- (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron
+ (startaddr == 0x11C0 && addr == 0x12C9 && // Cauldron, EGA
+ !strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) ||
+ (startaddr == 0x11C8 && addr == 0x1341 && // Cauldron, Mac
!strncmp(_vm->_game->_curTotFile, "avt012.tot", 10)) ||
(startaddr == 0x09F2 && addr == 0x0AF3 && // Statue
!strncmp(_vm->_game->_curTotFile, "avt016.tot", 10)) ||
(startaddr == 0x0B92 && addr == 0x0C93 && // Castle
!strncmp(_vm->_game->_curTotFile, "avt019.tot", 10)) ||
- (startaddr == 0x17D9 && addr == 0x18DA && // Finale
+ (startaddr == 0x17D9 && addr == 0x18DA && // Finale, EGA
+ !strncmp(_vm->_game->_curTotFile, "avt022.tot", 10)) ||
+ (startaddr == 0x17E9 && addr == 0x19A8 && // Finale, Mac
!strncmp(_vm->_game->_curTotFile, "avt022.tot", 10))) {
_vm->_util->longDelay(5000);
}
+
} // End of workaround
cmd = *_vm->_global->_inter_execPtr;
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index 60b3974d6d..b684be6c07 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -79,7 +79,7 @@ protected:
};
struct OpGobParams {
int16 extraData;
- int32 *retVarPtr;
+ VariableReference retVarPtr;
Goblin::Gob_Object *objDesc;
};
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
index 6a52770ad1..cc114f0afc 100644
--- a/engines/gob/inter_v1.cpp
+++ b/engines/gob/inter_v1.cpp
@@ -912,12 +912,21 @@ void Inter_v1::o1_initMult() {
animDataVar = _vm->_parse->parseVarIndex();
if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) {
+
warning("Initializing new objects without having "
"cleaned up the old ones at first");
+
+ for (int i = 0; i < _vm->_mult->_objCount; i++) {
+ delete _vm->_mult->_objects[i].pPosX;
+ delete _vm->_mult->_objects[i].pPosY;
+ }
+
delete[] _vm->_mult->_objects;
delete[] _vm->_mult->_renderData;
+
_vm->_mult->_objects = 0;
_vm->_mult->_renderObjs = 0;
+
}
if (_vm->_mult->_objects == 0) {
@@ -933,8 +942,8 @@ void Inter_v1::o1_initMult() {
uint32 offPosY = i * 4 + (posYVar / 4) * 4;
uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize;
- _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX);
- _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY);
+ _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX);
+ _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY);
_vm->_mult->_objects[i].pAnimData =
(Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim,
@@ -1774,7 +1783,7 @@ bool Inter_v1::o1_goblinFunc(OpFuncParams &params) {
gobParams.extraData = 0;
gobParams.objDesc = 0;
- gobParams.retVarPtr = (int32 *) VAR_ADDRESS(59);
+ gobParams.retVarPtr.set(*_vm->_inter->_variables, 236);
cmd = load16();
_vm->_global->_inter_execPtr += 2;
@@ -2268,49 +2277,49 @@ bool Inter_v1::o1_manageDataFile(OpFuncParams &params) {
void Inter_v1::o1_setState(OpGobParams &params) {
params.objDesc->state = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemStateVarPtr = params.extraData;
+ _vm->_goblin->_destItemStateVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setCurFrame(OpGobParams &params) {
params.objDesc->curFrame = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemFrameVarPtr = params.extraData;
+ _vm->_goblin->_destItemFrameVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setNextState(OpGobParams &params) {
params.objDesc->nextState = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemNextStateVarPtr = params.extraData;
+ _vm->_goblin->_destItemNextStateVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setMultState(OpGobParams &params) {
params.objDesc->multState = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemMultStateVarPtr = params.extraData;
+ _vm->_goblin->_destItemMultStateVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setOrder(OpGobParams &params) {
params.objDesc->order = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemOrderVarPtr = params.extraData;
+ _vm->_goblin->_destItemOrderVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setActionStartState(OpGobParams &params) {
params.objDesc->actionStartState = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemActStartStVarPtr = params.extraData;
+ _vm->_goblin->_destItemActStartStVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setCurLookDir(OpGobParams &params) {
params.objDesc->curLookDir = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemLookDirVarPtr = params.extraData;
+ _vm->_goblin->_destItemLookDirVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setType(OpGobParams &params) {
params.objDesc->type = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemTypeVarPtr = params.extraData;
+ _vm->_goblin->_destItemTypeVarPtr = (uint32) params.extraData;
if (params.extraData == 0)
params.objDesc->toRedraw = 1;
@@ -2319,107 +2328,107 @@ void Inter_v1::o1_setType(OpGobParams &params) {
void Inter_v1::o1_setNoTick(OpGobParams &params) {
params.objDesc->noTick = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemNoTickVarPtr = params.extraData;
+ _vm->_goblin->_destItemNoTickVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setPickable(OpGobParams &params) {
params.objDesc->pickable = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemPickableVarPtr = params.extraData;
+ _vm->_goblin->_destItemPickableVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setXPos(OpGobParams &params) {
params.objDesc->xPos = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemScrXVarPtr = params.extraData;
+ _vm->_goblin->_destItemScrXVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setYPos(OpGobParams &params) {
params.objDesc->yPos = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemScrYVarPtr = params.extraData;
+ _vm->_goblin->_destItemScrYVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setDoAnim(OpGobParams &params) {
params.objDesc->doAnim = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemDoAnimVarPtr = params.extraData;
+ _vm->_goblin->_destItemDoAnimVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setRelaxTime(OpGobParams &params) {
params.objDesc->relaxTime = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemRelaxVarPtr = params.extraData;
+ _vm->_goblin->_destItemRelaxVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_setMaxTick(OpGobParams &params) {
params.objDesc->maxTick = params.extraData;
if (params.objDesc == _vm->_goblin->_actDestItemDesc)
- *_vm->_goblin->_destItemMaxTickVarPtr = params.extraData;
+ _vm->_goblin->_destItemMaxTickVarPtr = (uint32) params.extraData;
}
void Inter_v1::o1_getState(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->state;
+ params.retVarPtr = (uint32) params.objDesc->state;
}
void Inter_v1::o1_getCurFrame(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->curFrame;
+ params.retVarPtr = (uint32) params.objDesc->curFrame;
}
void Inter_v1::o1_getNextState(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->nextState;
+ params.retVarPtr = (uint32) params.objDesc->nextState;
}
void Inter_v1::o1_getMultState(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->multState;
+ params.retVarPtr = (uint32) params.objDesc->multState;
}
void Inter_v1::o1_getOrder(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->order;
+ params.retVarPtr = (uint32) params.objDesc->order;
}
void Inter_v1::o1_getActionStartState(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->actionStartState;
+ params.retVarPtr = (uint32) params.objDesc->actionStartState;
}
void Inter_v1::o1_getCurLookDir(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->curLookDir;
+ params.retVarPtr = (uint32) params.objDesc->curLookDir;
}
void Inter_v1::o1_getType(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->type;
+ params.retVarPtr = (uint32) params.objDesc->type;
}
void Inter_v1::o1_getNoTick(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->noTick;
+ params.retVarPtr = (uint32) params.objDesc->noTick;
}
void Inter_v1::o1_getPickable(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->pickable;
+ params.retVarPtr = (uint32) params.objDesc->pickable;
}
void Inter_v1::o1_getObjMaxFrame(OpGobParams &params) {
- *params.retVarPtr = _vm->_goblin->getObjMaxFrame(params.objDesc);
+ params.retVarPtr = (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc);
}
void Inter_v1::o1_getXPos(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->xPos;
+ params.retVarPtr = (uint32) params.objDesc->xPos;
}
void Inter_v1::o1_getYPos(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->yPos;
+ params.retVarPtr = (uint32) params.objDesc->yPos;
}
void Inter_v1::o1_getDoAnim(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->doAnim;
+ params.retVarPtr = (uint32) params.objDesc->doAnim;
}
void Inter_v1::o1_getRelaxTime(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->relaxTime;
+ params.retVarPtr = (uint32) params.objDesc->relaxTime;
}
void Inter_v1::o1_getMaxTick(OpGobParams &params) {
- *params.retVarPtr = params.objDesc->maxTick;
+ params.retVarPtr = (uint32) params.objDesc->maxTick;
}
void Inter_v1::o1_manipulateMap(OpGobParams &params) {
@@ -2435,9 +2444,9 @@ void Inter_v1::o1_getItem(OpGobParams &params) {
int16 yPos = load16();
if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0)
- *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8;
+ params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8);
else
- *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos];
+ params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos];
}
void Inter_v1::o1_manipulateMapIndirect(OpGobParams &params) {
@@ -2460,9 +2469,9 @@ void Inter_v1::o1_getItemIndirect(OpGobParams &params) {
yPos = VAR(yPos);
if ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) != 0)
- *params.retVarPtr = (_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8;
+ params.retVarPtr = (uint32) ((_vm->_map->_itemsMap[yPos][xPos] & 0xFF00) >> 8);
else
- *params.retVarPtr = _vm->_map->_itemsMap[yPos][xPos];
+ params.retVarPtr = (uint32) _vm->_map->_itemsMap[yPos][xPos];
}
void Inter_v1::o1_setPassMap(OpGobParams &params) {
@@ -2500,11 +2509,11 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams &params) {
params.objDesc->curFrame = 0;
params.objDesc->state = 21;
if (_vm->_goblin->_currentGoblin == item) {
- *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos;
+ _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos;
- *_vm->_goblin->_curGobFrameVarPtr = 0;
- *_vm->_goblin->_curGobStateVarPtr = 18;
+ _vm->_goblin->_curGobFrameVarPtr = 0;
+ _vm->_goblin->_curGobStateVarPtr = 18;
_vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x;
_vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y;
}
@@ -2512,12 +2521,12 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams &params) {
void Inter_v1::o1_getGoblinPosXH(OpGobParams &params) {
int16 item = load16();
- *params.retVarPtr = _vm->_goblin->_gobPositions[item].x >> 1;
+ params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].x >> 1);
}
void Inter_v1::o1_getGoblinPosYH(OpGobParams &params) {
int16 item = load16();
- *params.retVarPtr = _vm->_goblin->_gobPositions[item].y >> 1;
+ params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].y >> 1);
}
void Inter_v1::o1_setGoblinMultState(OpGobParams &params) {
@@ -2539,14 +2548,14 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams &params) {
params.objDesc->xPos = animLayer->posX;
params.objDesc->yPos = animLayer->posY;
- *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos;
- *_vm->_goblin->_curGobFrameVarPtr = 0;
- *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state;
- *_vm->_goblin->_curGobNextStateVarPtr = params.objDesc->nextState;
- *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState;
- *_vm->_goblin->_curGobMaxFrameVarPtr =
- _vm->_goblin->getObjMaxFrame(params.objDesc);
+ _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos;
+ _vm->_goblin->_curGobFrameVarPtr = 0;
+ _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state;
+ _vm->_goblin->_curGobNextStateVarPtr = (uint32) params.objDesc->nextState;
+ _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState;
+ _vm->_goblin->_curGobMaxFrameVarPtr =
+ (uint32) _vm->_goblin->getObjMaxFrame(params.objDesc);
_vm->_goblin->_noPick = 1;
return;
}
@@ -2573,12 +2582,12 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams &params) {
_vm->_goblin->_pressedMapY = yPos;
_vm->_map->_curGoblinY = yPos;
- *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos;
- *_vm->_goblin->_curGobFrameVarPtr = 0;
- *_vm->_goblin->_curGobStateVarPtr = 21;
- *_vm->_goblin->_curGobNextStateVarPtr = 21;
- *_vm->_goblin->_curGobMultStateVarPtr = -1;
+ _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos;
+ _vm->_goblin->_curGobFrameVarPtr = 0;
+ _vm->_goblin->_curGobStateVarPtr = 21;
+ _vm->_goblin->_curGobNextStateVarPtr = 21;
+ _vm->_goblin->_curGobMultStateVarPtr = (uint32) -1;
_vm->_goblin->_noPick = 0;
}
@@ -2598,11 +2607,11 @@ void Inter_v1::o1_setItemIndInPocket(OpGobParams &params) {
}
void Inter_v1::o1_getItemIdInPocket(OpGobParams &params) {
- *params.retVarPtr = _vm->_goblin->_itemIdInPocket;
+ params.retVarPtr = (uint32) _vm->_goblin->_itemIdInPocket;
}
void Inter_v1::o1_getItemIndInPocket(OpGobParams &params) {
- *params.retVarPtr = _vm->_goblin->_itemIndInPocket;
+ params.retVarPtr = (uint32) _vm->_goblin->_itemIndInPocket;
}
void Inter_v1::o1_setGoblinPos(OpGobParams &params) {
@@ -2632,10 +2641,10 @@ void Inter_v1::o1_setGoblinPos(OpGobParams &params) {
params.objDesc->state = 21;
if (_vm->_goblin->_currentGoblin == item) {
- *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos;
- *_vm->_goblin->_curGobFrameVarPtr = 0;
- *_vm->_goblin->_curGobStateVarPtr = 18;
+ _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos;
+ _vm->_goblin->_curGobFrameVarPtr = 0;
+ _vm->_goblin->_curGobStateVarPtr = 18;
_vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[item].x;
_vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[item].y;
@@ -2659,11 +2668,11 @@ void Inter_v1::o1_setGoblinState(OpGobParams &params) {
params.objDesc->yPos = animLayer->posY;
if (item == _vm->_goblin->_currentGoblin) {
- *_vm->_goblin->_curGobScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_curGobScrYVarPtr = params.objDesc->yPos;
- *_vm->_goblin->_curGobFrameVarPtr = 0;
- *_vm->_goblin->_curGobStateVarPtr = params.objDesc->state;
- *_vm->_goblin->_curGobMultStateVarPtr = params.objDesc->multState;
+ _vm->_goblin->_curGobScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_curGobScrYVarPtr = (uint32) params.objDesc->yPos;
+ _vm->_goblin->_curGobFrameVarPtr = 0;
+ _vm->_goblin->_curGobStateVarPtr = (uint32) params.objDesc->state;
+ _vm->_goblin->_curGobMultStateVarPtr = (uint32) params.objDesc->multState;
}
}
@@ -2686,13 +2695,13 @@ void Inter_v1::o1_setGoblinStateRedraw(OpGobParams &params) {
params.objDesc->toRedraw = 1;
params.objDesc->type = 0;
if (params.objDesc == _vm->_goblin->_actDestItemDesc) {
- *_vm->_goblin->_destItemScrXVarPtr = params.objDesc->xPos;
- *_vm->_goblin->_destItemScrYVarPtr = params.objDesc->yPos;
+ _vm->_goblin->_destItemScrXVarPtr = (uint32) params.objDesc->xPos;
+ _vm->_goblin->_destItemScrYVarPtr = (uint32) params.objDesc->yPos;
- *_vm->_goblin->_destItemStateVarPtr = params.objDesc->state;
- *_vm->_goblin->_destItemNextStateVarPtr = -1;
- *_vm->_goblin->_destItemMultStateVarPtr = -1;
- *_vm->_goblin->_destItemFrameVarPtr = 0;
+ _vm->_goblin->_destItemStateVarPtr = (uint32) params.objDesc->state;
+ _vm->_goblin->_destItemNextStateVarPtr = (uint32) -1;
+ _vm->_goblin->_destItemMultStateVarPtr = (uint32) -1;
+ _vm->_goblin->_destItemFrameVarPtr = 0;
}
}
@@ -2712,12 +2721,12 @@ void Inter_v1::o1_decRelaxTime(OpGobParams &params) {
void Inter_v1::o1_getGoblinPosX(OpGobParams &params) {
int16 item = load16();
- *params.retVarPtr = _vm->_goblin->_gobPositions[item].x;
+ params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].x;
}
void Inter_v1::o1_getGoblinPosY(OpGobParams &params) {
int16 item = load16();
- *params.retVarPtr = _vm->_goblin->_gobPositions[item].y;
+ params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].y;
}
void Inter_v1::o1_clearPathExistence(OpGobParams &params) {
@@ -2741,9 +2750,9 @@ void Inter_v1::o1_getObjectIntersect(OpGobParams &params) {
params.objDesc = _vm->_goblin->_objects[params.extraData];
if (_vm->_goblin->objIntersected(params.objDesc,
_vm->_goblin->_goblins[item]))
- *params.retVarPtr = 1;
+ params.retVarPtr = 1;
else
- *params.retVarPtr = 0;
+ params.retVarPtr = 0;
}
void Inter_v1::o1_getGoblinIntersect(OpGobParams &params) {
@@ -2753,9 +2762,9 @@ void Inter_v1::o1_getGoblinIntersect(OpGobParams &params) {
params.objDesc = _vm->_goblin->_goblins[params.extraData];
if (_vm->_goblin->objIntersected(params.objDesc,
_vm->_goblin->_goblins[item]))
- *params.retVarPtr = 1;
+ params.retVarPtr = 1;
else
- *params.retVarPtr = 0;
+ params.retVarPtr = 0;
}
void Inter_v1::o1_setItemPos(OpGobParams &params) {
@@ -2886,7 +2895,7 @@ void Inter_v1::o1_initGoblin(OpGobParams &params) {
_vm->_map->_destY = _vm->_goblin->_gobPositions[0].y;
_vm->_goblin->_gobDestY = _vm->_goblin->_gobPositions[0].y;
- *_vm->_goblin->_curGobVarPtr = 0;
+ _vm->_goblin->_curGobVarPtr = 0;
_vm->_goblin->_pathExistence = 0;
_vm->_goblin->_readyToAct = 0;
}
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index ae7aaa662d..b245001653 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -881,9 +881,15 @@ void Inter_v2::o2_initMult() {
_vm->_mult->clearObjectVideos();
+ for (int i = 0; i < _vm->_mult->_objCount; i++) {
+ delete _vm->_mult->_objects[i].pPosX;
+ delete _vm->_mult->_objects[i].pPosY;
+ }
+
delete[] _vm->_mult->_objects;
delete[] _vm->_mult->_renderObjs;
delete[] _vm->_mult->_orderArray;
+
_vm->_mult->_objects = 0;
_vm->_mult->_renderObjs = 0;
_vm->_mult->_orderArray = 0;
@@ -908,8 +914,8 @@ void Inter_v2::o2_initMult() {
uint32 offPosY = i * 4 + (posYVar / 4) * 4;
uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize;
- _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX);
- _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY);
+ _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX);
+ _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY);
_vm->_mult->_objects[i].pAnimData =
(Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim,
@@ -1047,7 +1053,7 @@ void Inter_v2::o2_loadMultObject() {
} else if ((objAnim.animType != 100) && (objAnim.animType != 101)) {
- if ((*(obj.pPosX) == -1234) && (*(obj.pPosY) == -4321)) {
+ if ((((int32) *(obj.pPosX)) == -1234) && (((int32) *(obj.pPosY)) == -4321)) {
if (obj.videoSlot > 0)
_vm->_vidPlayer->slotClose(obj.videoSlot - 1);
diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp
index 46a903fd34..a502e92188 100644
--- a/engines/gob/mult.cpp
+++ b/engines/gob/mult.cpp
@@ -93,12 +93,18 @@ Mult::Mult(GobEngine *vm) : _vm(vm) {
}
Mult::~Mult() {
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
delete[] _objects;
delete[] _orderArray;
delete[] _renderData;
delete[] _renderObjs;
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
delete _multData;
}
@@ -123,6 +129,12 @@ void Mult::freeAll(void) {
void Mult::freeMult() {
clearObjectVideos();
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
delete[] _objects;
delete[] _renderData;
delete[] _renderObjs;
@@ -203,11 +215,17 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape,
if (_animDataAllocated) {
clearObjectVideos();
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
delete[] _objects;
delete[] _renderData;
delete[] _renderObjs;
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
delete[] _orderArray;
diff --git a/engines/gob/mult.h b/engines/gob/mult.h
index aaf2e2826c..3bb3af17b3 100644
--- a/engines/gob/mult.h
+++ b/engines/gob/mult.h
@@ -27,6 +27,7 @@
#define GOB_MULT_H
#include "gob/video.h"
+#include "gob/variables.h"
namespace Gob {
@@ -77,8 +78,8 @@ public:
} PACKED_STRUCT;
struct Mult_Object {
- int32 *pPosX;
- int32 *pPosY;
+ VariableReference *pPosX;
+ VariableReference *pPosY;
Mult_AnimData *pAnimData;
int16 tick;
int16 lastLeft;
@@ -267,8 +268,8 @@ protected:
bool _doPalSubst;
- int32 *_animArrayX;
- int32 *_animArrayY;
+ Variables *_animArrayX;
+ Variables *_animArrayY;
Mult_AnimData *_animArrayData;
int16 _palKeyIndex;
diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp
index 22683437e7..a369e7d297 100644
--- a/engines/gob/mult_v1.cpp
+++ b/engines/gob/mult_v1.cpp
@@ -216,10 +216,16 @@ void Mult_v1::freeMultKeys() {
if (_animDataAllocated) {
clearObjectVideos();
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
delete[] _objects;
delete[] _renderData;
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
_objects = 0;
@@ -263,6 +269,14 @@ void Mult_v1::playMultInit() {
_oldPalette = _vm->_global->_pPaletteDesc->vgaPal;
if (!_animSurf) {
+ if (_objects)
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
+ delete[] _objects;
+
_vm->_util->setFrameRate(_multData->frameRate);
_animTop = 0;
_animLeft = 0;
@@ -270,30 +284,27 @@ void Mult_v1::playMultInit() {
_animHeight = 200;
_objCount = 4;
- delete[] _objects;
delete[] _renderData;
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
_objects = new Mult_Object[_objCount];
_renderData = new int16[9 * _objCount];
- _animArrayX = new int32[_objCount];
- _animArrayY = new int32[_objCount];
+ _animArrayX = new VariablesLE(_objCount * 4);
+ _animArrayY = new VariablesLE(_objCount * 4);
_animArrayData = new Mult_AnimData[_objCount];
memset(_objects, 0, _objCount * sizeof(Mult_Object));
memset(_renderData, 0, _objCount * 9 * sizeof(int16));
- memset(_animArrayX, 0, _objCount * sizeof(int32));
- memset(_animArrayY, 0, _objCount * sizeof(int32));
memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData));
for (_counter = 0; _counter < _objCount; _counter++) {
Mult_Object &multObj = _objects[_counter];
Mult_AnimData &animData = _animArrayData[_counter];
- multObj.pPosX = (int32 *) &_animArrayX[_counter];
- multObj.pPosY = (int32 *) &_animArrayY[_counter];
+ multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4);
+ multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4);
multObj.pAnimData = &animData;
animData.isStatic = 1;
diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp
index 3a83ac1867..20a81174e5 100644
--- a/engines/gob/mult_v2.cpp
+++ b/engines/gob/mult_v2.cpp
@@ -329,8 +329,8 @@ void Mult_v2::freeMultKeys() {
if (_animDataAllocated) {
freeMult();
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
_animArrayX = 0;
@@ -510,6 +510,13 @@ void Mult_v2::playMultInit() {
if (!_animSurf) {
int16 width, height;
+ for (int i = 0; i < _objCount; i++) {
+ delete _objects[i].pPosX;
+ delete _objects[i].pPosY;
+ }
+
+ delete[] _objects;
+
_vm->_util->setFrameRate(_multData->frameRate);
_animTop = 0;
_animLeft = 0;
@@ -517,33 +524,30 @@ void Mult_v2::playMultInit() {
_animHeight = _vm->_video->_surfHeight;
_objCount = 4;
- delete[] _objects;
delete[] _orderArray;
delete[] _renderObjs;
- delete[] _animArrayX;
- delete[] _animArrayY;
+ delete _animArrayX;
+ delete _animArrayY;
delete[] _animArrayData;
_objects = new Mult_Object[_objCount];
_orderArray = new int8[_objCount];
_renderObjs = new Mult_Object*[_objCount];
- _animArrayX = new int32[_objCount];
- _animArrayY = new int32[_objCount];
+ _animArrayX = new VariablesLE(_objCount * 4);
+ _animArrayY = new VariablesLE(_objCount * 4);
_animArrayData = new Mult_AnimData[_objCount];
memset(_objects, 0, _objCount * sizeof(Mult_Object));
memset(_orderArray, 0, _objCount * sizeof(int8));
memset(_renderObjs, 0, _objCount * sizeof(Mult_Object *));
- memset(_animArrayX, 0, _objCount * sizeof(int32));
- memset(_animArrayY, 0, _objCount * sizeof(int32));
memset(_animArrayData, 0, _objCount * sizeof(Mult_AnimData));
for (_counter = 0; _counter < _objCount; _counter++) {
Mult_Object &multObj = _objects[_counter];
Mult_AnimData &animData = _animArrayData[_counter];
- multObj.pPosX = (int32 *) &_animArrayX[_counter];
- multObj.pPosY = (int32 *) &_animArrayY[_counter];
+ multObj.pPosX = new VariableReference(*_animArrayX, _counter * 4);
+ multObj.pPosY = new VariableReference(*_animArrayY, _counter * 4);
multObj.pAnimData = &animData;
animData.isStatic = 1;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index b59510e4bb..07b5a737db 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -144,4 +144,4 @@ private:
} // End of namespace Gob
-#endif // GOB_SOUND_H
+#endif // GOB_SOUND_SOUND_H
diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h
index 5789885a99..3e8e6b5c1b 100644
--- a/engines/gob/sound/soundmixer.h
+++ b/engines/gob/sound/soundmixer.h
@@ -37,7 +37,7 @@ namespace Gob {
class SoundMixer : public Audio::AudioStream {
public:
- SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType);
+ SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type);
~SoundMixer();
virtual void play(SoundDesc &sndDesc, int16 repCount,
diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp
index 0eea2f6547..805aaeb839 100644
--- a/engines/gob/variables.cpp
+++ b/engines/gob/variables.cpp
@@ -308,4 +308,62 @@ uint32 VariablesBE::read32(const byte *buf) const {
return READ_BE_UINT32(buf);
}
+VariableReference::VariableReference() {
+ _vars = 0;
+ _offset = 0;
+}
+
+VariableReference::VariableReference(Variables &vars, uint32 offset, Variables::Type type) {
+ set(vars, offset, type);
+}
+
+VariableReference::~VariableReference() {
+}
+
+void VariableReference::set(Variables &vars, uint32 offset, Variables::Type type) {
+ _vars = &vars;
+ _offset = offset;
+ _type = type;
+}
+
+VariableReference &VariableReference::operator=(uint32 value) {
+ if (_vars) {
+ switch (_type) {
+ case Variables::kVariableType8:
+ _vars->writeOff8(_offset, (uint8) value);
+ break;
+ case Variables::kVariableType16:
+ _vars->writeOff16(_offset, (uint16) value);
+ break;
+ case Variables::kVariableType32:
+ _vars->writeOff32(_offset, value);
+ break;
+ }
+ }
+ return *this;
+}
+
+VariableReference::operator uint32() {
+ if (_vars) {
+ switch (_type) {
+ case Variables::kVariableType8:
+ return (uint32) _vars->readOff8(_offset);
+ case Variables::kVariableType16:
+ return (uint32) _vars->readOff16(_offset);
+ case Variables::kVariableType32:
+ return _vars->readOff32(_offset);
+ }
+ }
+
+ return 0;
+}
+
+VariableReference &VariableReference::operator+=(uint32 value) {
+ return (*this = (*this + value));
+}
+
+VariableReference &VariableReference::operator*=(uint32 value) {
+ return (*this = (*this * value));
+}
+
} // End of namespace Gob
diff --git a/engines/gob/variables.h b/engines/gob/variables.h
index 5989ed38ee..32f160a6bd 100644
--- a/engines/gob/variables.h
+++ b/engines/gob/variables.h
@@ -30,6 +30,12 @@ namespace Gob {
class Variables {
public:
+ enum Type {
+ kVariableType8,
+ kVariableType16,
+ kVariableType32
+ };
+
Variables(uint32 size);
virtual ~Variables();
@@ -142,6 +148,26 @@ protected:
uint32 read32(const byte *buf) const;
};
+class VariableReference {
+ public:
+ VariableReference();
+ VariableReference(Variables &vars, uint32 offset,
+ Variables::Type type = Variables::kVariableType32);
+ ~VariableReference();
+
+ void set(Variables &vars, uint32 offset, Variables::Type type = Variables::kVariableType32);
+
+ VariableReference &operator=(uint32 value);
+ VariableReference &operator+=(uint32 value);
+ VariableReference &operator*=(uint32 value);
+ operator uint32();
+
+ private:
+ Variables *_vars;
+ uint32 _offset;
+ Variables::Type _type;
+};
+
} // End of namespace Gob
#endif // GOB_VARIABLES_H
diff --git a/engines/igor/igor.cpp b/engines/igor/igor.cpp
index 018709f34f..4d4fb97762 100644
--- a/engines/igor/igor.cpp
+++ b/engines/igor/igor.cpp
@@ -404,7 +404,7 @@ void IgorEngine::playSound(int num, int type) {
debugC(9, kDebugEngine, "playSound() %d", num);
--num;
int soundOffset = -1;
- Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType;
+ Audio::Mixer::SoundType soundType;
Audio::SoundHandle *soundHandle = 0;
if (type == 1) {
if (_mixer->isSoundHandleActive(_sfxHandle)) {
diff --git a/engines/kyra/animator_lok.cpp b/engines/kyra/animator_lok.cpp
index 1baa78b203..75d5537e4a 100644
--- a/engines/kyra/animator_lok.cpp
+++ b/engines/kyra/animator_lok.cpp
@@ -665,7 +665,7 @@ void Animator_LoK::animRefreshNPC(int character) {
void Animator_LoK::setCharacterDefaultFrame(int character) {
debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharacterDefaultFrame()");
- static uint16 initFrameTable[] = {
+ static const uint16 initFrameTable[] = {
7, 41, 77, 0, 0
};
assert(character < ARRAYSIZE(initFrameTable));
@@ -678,7 +678,7 @@ void Animator_LoK::setCharacterDefaultFrame(int character) {
void Animator_LoK::setCharactersHeight() {
debugC(9, kDebugLevelAnimator, "Animator_LoK::setCharactersHeight()");
- static int8 initHeightTable[] = {
+ static const int8 initHeightTable[] = {
48, 40, 48, 47, 56,
44, 42, 47, 38, 35,
40
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 344121b503..fce1e93bc2 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -41,9 +41,11 @@ struct KYRAGameDescription {
namespace {
-#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id }
+#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id }
+#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, id }
#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1)
+#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA1)
#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1)
#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1)
#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1)
@@ -59,13 +61,36 @@ namespace {
#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2)
#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3)
-#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3)
+#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3)
+#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3)
const KYRAGameDescription adGameDescs[] = {
{
{
"kyra1",
0,
+ AD_ENTRY1("DISK1.EXE", "c8641d0414d6c966d0a3dad79db07bf4"),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA1_FLOPPY_CMP_FLAGS
+ },
+ {
+ {
+ "kyra1",
+ 0,
+ AD_ENTRY1("DISK1.EXE", "5d5cee4c3d0b68d586788b74243d254a"),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA1_FLOPPY_CMP_FLAGS
+ },
+ {
+ {
+ "kyra1",
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"),
Common::EN_ANY,
Common::kPlatformPC,
@@ -76,7 +101,7 @@ const KYRAGameDescription adGameDescs[] = {
{
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "796e44863dd22fa635b042df1bf16673"),
Common::EN_ANY,
Common::kPlatformPC,
@@ -87,7 +112,7 @@ const KYRAGameDescription adGameDescs[] = {
{
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "abf8eb360e79a6c2a837751fbd4d3d24"),
Common::FR_FRA,
Common::kPlatformPC,
@@ -98,7 +123,7 @@ const KYRAGameDescription adGameDescs[] = {
{
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "6018e1dfeaca7fe83f8d0b00eb0dd049"),
Common::DE_DEU,
Common::kPlatformPC,
@@ -109,7 +134,7 @@ const KYRAGameDescription adGameDescs[] = {
{ // from Arne.F
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "f0b276781f47c130f423ec9679fe9ed9"),
Common::DE_DEU,
Common::kPlatformPC,
@@ -120,7 +145,7 @@ const KYRAGameDescription adGameDescs[] = {
{ // from VooD
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "8909b41596913b3f5deaf3c9f1017b01"),
Common::ES_ESP,
Common::kPlatformPC,
@@ -131,7 +156,7 @@ const KYRAGameDescription adGameDescs[] = {
{ // floppy 1.8 from clemmy
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "747861d2a9c643c59fdab570df5b9093"),
Common::ES_ESP,
Common::kPlatformPC,
@@ -142,7 +167,7 @@ const KYRAGameDescription adGameDescs[] = {
{ // from gourry
{
"kyra1",
- 0,
+ "Extracted",
AD_ENTRY1("GEMCUT.EMC", "ef08c8c237ee1473fd52578303fc36df"),
Common::IT_ITA,
Common::kPlatformPC,
@@ -323,7 +348,7 @@ const KYRAGameDescription adGameDescs[] = {
KYRA2_FLOPPY_CMP_FLAGS
},
- { // // Floppy version extracted
+ { // Floppy version extracted
{
"kyra2",
"Extracted",
@@ -463,6 +488,28 @@ const KYRAGameDescription adGameDescs[] = {
},
KYRA2_TOWNS_SJIS_FLAGS
},
+ { // PC-9821
+ {
+ "kyra2",
+ 0,
+ AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
+ Common::EN_ANY,
+ Common::kPlatformPC98,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_TOWNS_FLAGS
+ },
+ {
+ {
+ "kyra2",
+ 0,
+ AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
+ Common::JA_JPN,
+ Common::kPlatformPC98,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_TOWNS_SJIS_FLAGS
+ },
// Kyra3
@@ -480,7 +527,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_INS_FLAGS
+ KYRA3_CD_FLAGS
},
{
{
@@ -495,7 +542,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_INS_FLAGS
+ KYRA3_CD_FLAGS
},
{
{
@@ -510,7 +557,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_INS_FLAGS
+ KYRA3_CD_FLAGS
},
// installed version
@@ -527,7 +574,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
{
{
@@ -542,7 +589,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
{
{
@@ -557,9 +604,102 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
+ // Spanish fan translation, see fr#1994040 "KYRA3: Add support for Spanish fan translation"
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "9aaca21d2a205ca02ec53132f2911794", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
+ },
+
+ // Itlian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3"
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
+ },
+ {
+ {
+ "kyra3",
+ 0,
+ {
+ { "ONETIME.PAK", 0, "ee2d4d056a5de5333a3c6bda055b3cb4", -1 },
+ { "AUD.PAK", 0, 0, -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE
+ },
+ KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
+ },
{ AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) }
};
diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp
index 032c28d44d..cb3cef2fb3 100644
--- a/engines/kyra/gui_hof.cpp
+++ b/engines/kyra/gui_hof.cpp
@@ -454,14 +454,26 @@ void KyraEngine_HoF::loadBookBkgd() {
void KyraEngine_HoF::showBookPage() {
char filename[16];
- sprintf(filename, "PAGE%.01X.", _bookCurPage);
- strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
+ sprintf(filename, "PAGE%.01X.%s", _bookCurPage, _languageExtension[_lang]);
uint8 *leftPage = _res->fileData(filename, 0);
+ if (!leftPage) {
+ // some floppy version use a TXT extension
+ sprintf(filename, "PAGE%.01X.TXT", _bookCurPage);
+ leftPage = _res->fileData(filename, 0);
+ }
+
int leftPageY = _bookPageYOffset[_bookCurPage];
- sprintf(filename, "PAGE%.01X.", _bookCurPage+1);
- strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
- uint8 *rightPage = (_bookCurPage != _bookMaxPage) ? _res->fileData(filename, 0) : 0;
+ sprintf(filename, "PAGE%.01X.%s", _bookCurPage+1, _languageExtension[_lang]);
+ uint8 *rightPage = 0;
+ if (_bookCurPage != _bookMaxPage) {
+ rightPage = _res->fileData(filename, 0);
+ if (!rightPage) {
+ sprintf(filename, "PAGE%.01X.TXT", _bookCurPage);
+ rightPage = _res->fileData(filename, 0);
+ }
+ }
+
int rightPageY = _bookPageYOffset[_bookCurPage+1];
_screen->hideMouse();
diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp
index db9d61ce5e..092aaedb23 100644
--- a/engines/kyra/gui_lok.cpp
+++ b/engines/kyra/gui_lok.cpp
@@ -187,6 +187,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) {
#pragma mark -
GUI_LoK::GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen) : GUI(vm), _vm(vm), _screen(screen) {
+ _lastScreenUpdate = 0;
_menu = 0;
initStaticResource();
_scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::scrollUp);
@@ -478,7 +479,6 @@ int GUI_LoK::buttonMenuCallback(Button *caller) {
void GUI_LoK::getInput() {
Common::Event event;
- static uint32 lastScreenUpdate = 0;
uint32 now = _vm->_system->getMillis();
_mouseWheel = 0;
@@ -492,7 +492,7 @@ void GUI_LoK::getInput() {
break;
case Common::EVENT_MOUSEMOVE:
_vm->_system->updateScreen();
- lastScreenUpdate = now;
+ _lastScreenUpdate = now;
break;
case Common::EVENT_WHEELUP:
_mouseWheel = -1;
@@ -508,9 +508,9 @@ void GUI_LoK::getInput() {
}
}
- if (now - lastScreenUpdate > 50) {
+ if (now - _lastScreenUpdate > 50) {
_vm->_system->updateScreen();
- lastScreenUpdate = now;
+ _lastScreenUpdate = now;
}
_vm->_system->delayMillis(3);
@@ -1052,7 +1052,7 @@ void GUI_LoK::fadePalette() {
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
return;
- static int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1};
+ static const int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1};
int index = 0;
memcpy(_screen->getPalette(2), _screen->_currentPalette, 768);
diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h
index 607ef0b605..49081c7ae2 100644
--- a/engines/kyra/gui_lok.h
+++ b/engines/kyra/gui_lok.h
@@ -157,6 +157,8 @@ private:
KyraEngine_LoK *_vm;
Screen_LoK *_screen;
+ uint32 _lastScreenUpdate;
+
bool _menuRestoreScreen;
uint8 _toplevelMenu;
int _savegameOffset;
diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp
index 8eb62c20c2..2c2903d0b3 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
int KyraEngine_LoK::findDuplicateItemShape(int shape) {
- static uint8 dupTable[] = {
+ static const uint8 dupTable[] = {
0x48, 0x46, 0x49, 0x47, 0x4a, 0x46, 0x4b, 0x47,
0x4c, 0x46, 0x4d, 0x47, 0x5b, 0x5a, 0x5c, 0x5a,
0x5d, 0x5a, 0x5e, 0x5a, 0xFF, 0xFF
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 470e5f0343..ac69272ef4 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -296,6 +296,9 @@ int KyraEngine_HoF::go() {
_res->loadFileList("FILEDATA.FDT");
else
_res->loadFileList(_ingamePakList, _ingamePakListSize);
+
+ if (_flags.platform == Common::kPlatformPC98)
+ _res->loadPakFile("AUDIO.PAK");
}
_menuDirectlyToLoad = (_menuChoice == 3) ? true : false;
@@ -1560,7 +1563,7 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) {
int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]);
if (vocIndex != -1)
_sound->voicePlay(_ingameSoundList[vocIndex], true);
- else if (_flags.platform == Common::kPlatformPC)
+ else if (_flags.platform != Common::kPlatformFMTowns)
// TODO ?? Maybe there is a way to let users select whether they want
// voc, midi or adl sfx (even though it makes no sense to choose anything but voc).
KyraEngine_v1::snd_playSoundEffect(track);
@@ -2020,6 +2023,9 @@ void KyraEngine_HoF::writeSettings() {
break;
}
+ if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG)
+ _flags.lang = _flags.fanLang;
+
ConfMan.set("language", Common::getLanguageCode(_flags.lang));
KyraEngine_v1::writeSettings();
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index 700bec10b7..7097543750 100644
--- a/engines/kyra/kyra_mr.cpp
+++ b/engines/kyra/kyra_mr.cpp
@@ -343,6 +343,14 @@ void KyraEngine_MR::initMainMenu() {
0x80, 0xFF
};
+ if (_flags.lang == Common::ES_ESP) {
+ for (int i = 0; i < 4; ++i)
+ data.strings[i] = _mainMenuSpanishFan[i];
+ } else if (_flags.lang == Common::IT_ITA) {
+ for (int i = 0; i < 4; ++i)
+ data.strings[i] = _mainMenuItalianFan[i];
+ }
+
MainMenu::Animation anim;
anim.anim = _menuAnim;
anim.startFrame = 29;
@@ -1543,6 +1551,9 @@ void KyraEngine_MR::writeSettings() {
break;
}
+ if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG)
+ _flags.lang = _flags.fanLang;
+
ConfMan.set("language", Common::getLanguageCode(_flags.lang));
ConfMan.setBool("studio_audience", _configStudio);
diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h
index 5af138373c..5f9f6f91a3 100644
--- a/engines/kyra/kyra_mr.h
+++ b/engines/kyra/kyra_mr.h
@@ -184,9 +184,12 @@ private:
private:
// main menu
- const char *const *_mainMenuStrings;
+ const char * const *_mainMenuStrings;
int _mainMenuStringsSize;
+ static const char * const _mainMenuSpanishFan[];
+ static const char * const _mainMenuItalianFan[];
+
// animator
uint8 *_gamePlayBuffer;
void restorePage3();
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index accf5ab57e..cc97f43a05 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -105,14 +105,16 @@ int KyraEngine_v1::init() {
// "KYRA1: Crash on exceeded polyphony" for more information).
int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/);
- if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
- // TODO: currently we don't support the PC98 sound data,
- // but since it has the FM-Towns data files, we just use the
- // FM-Towns driver
+ if (_flags.platform == Common::kPlatformFMTowns) {
if (_flags.gameID == GI_KYRA1)
_sound = new SoundTowns(this, _mixer);
else
- _sound = new SoundTowns_v2(this, _mixer);
+ _sound = new SoundTownsPC98_v2(this, _mixer);
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ if (_flags.gameID == GI_KYRA1)
+ _sound = new SoundPC98(this, _mixer);
+ else
+ _sound = new SoundTownsPC98_v2(this, _mixer);
} else if (midiDriver == MD_ADLIB) {
_sound = new SoundAdlibPC(this, _mixer);
assert(_sound);
@@ -169,36 +171,6 @@ int KyraEngine_v1::init() {
_gameToLoad = -1;
}
- _lang = 0;
- Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
-
- if (_flags.gameID == GI_KYRA2 || _flags.gameID == GI_KYRA3) {
- switch (lang) {
- case Common::EN_ANY:
- case Common::EN_USA:
- case Common::EN_GRB:
- _lang = 0;
- break;
-
- case Common::FR_FRA:
- _lang = 1;
- break;
-
- case Common::DE_DEU:
- _lang = 2;
- break;
-
- case Common::JA_JPN:
- _lang = 3;
- break;
-
- default:
- warning("unsupported language, switching back to English");
- _lang = 0;
- break;
- }
- }
-
return 0;
}
@@ -276,6 +248,14 @@ void KyraEngine_v1::delayWithTicks(int ticks) {
void KyraEngine_v1::registerDefaultSettings() {
if (_flags.gameID != GI_KYRA3)
ConfMan.registerDefault("cdaudio", (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98));
+ if (_flags.fanLang != Common::UNK_LANG) {
+ // HACK/WORKAROUND: Since we can't use registerDefault here to overwrite
+ // the global subtitles settings, we're using this hack to enable subtitles
+ // for fan translations
+ const Common::ConfigManager::Domain *cur = ConfMan.getActiveDomain();
+ if (!cur || (cur && cur->get("subtitles").empty()))
+ ConfMan.setBool("subtitles", true);
+ }
}
void KyraEngine_v1::readSettings() {
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 921d5ba033..8dd95c79b9 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -44,6 +44,11 @@ namespace Kyra {
struct GameFlags {
Common::Language lang;
+
+ // language overwrites of fan translations (only needed for multilingual games)
+ Common::Language fanLang;
+ Common::Language replacedLang;
+
Common::Platform platform;
bool isDemo : 1;
@@ -207,7 +212,6 @@ protected:
// detection
GameFlags _flags;
- int _lang;
// opcode
virtual void setupOpcodeTable() = 0;
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index 20875202e5..08a4e9f4c5 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -23,6 +23,8 @@
*
*/
+#include "common/config-manager.h"
+
#include "kyra/kyra_v2.h"
#include "kyra/screen_v2.h"
#include "kyra/debugger.h"
@@ -70,6 +72,36 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
memset(&_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory));
_pauseStart = 0;
+
+ _lang = 0;
+ Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
+ if (lang == _flags.fanLang && _flags.replacedLang != Common::UNK_LANG)
+ lang = _flags.replacedLang;
+
+ switch (lang) {
+ case Common::EN_ANY:
+ case Common::EN_USA:
+ case Common::EN_GRB:
+ _lang = 0;
+ break;
+
+ case Common::FR_FRA:
+ _lang = 1;
+ break;
+
+ case Common::DE_DEU:
+ _lang = 2;
+ break;
+
+ case Common::JA_JPN:
+ _lang = 3;
+ break;
+
+ default:
+ warning("unsupported language, switching back to English");
+ _lang = 0;
+ break;
+ }
}
KyraEngine_v2::~KyraEngine_v2() {
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 24f7aad614..6fdf30fff8 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -94,6 +94,9 @@ protected:
virtual void update() = 0;
virtual void updateWithText() = 0;
+ // detection
+ int _lang;
+
// MainMenu
MainMenu *_menu;
diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp
index dbf54e1fcd..08df7b064e 100644
--- a/engines/kyra/scene_hof.cpp
+++ b/engines/kyra/scene_hof.cpp
@@ -723,7 +723,7 @@ void KyraEngine_HoF::fadeScenePal(int srcIndex, int delayTime) {
bool KyraEngine_HoF::lineIsPassable(int x, int y) {
debugC(9, kDebugLevelMain, "KyraEngine_HoF::lineIsPassable(%d, %d)", x, y);
- static int unkTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 };
+ static const int widthTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 };
if (_pathfinderFlag & 2) {
if (x >= 320)
@@ -743,7 +743,7 @@ bool KyraEngine_HoF::lineIsPassable(int x, int y) {
if (y > 143)
return false;
- int unk1 = unkTable[getScale(x, y) >> 5];
+ int unk1 = widthTable[getScale(x, y) >> 5];
if (y < 0)
y = 0;
diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp
index e4ae67f751..53c269a926 100644
--- a/engines/kyra/scene_lok.cpp
+++ b/engines/kyra/scene_lok.cpp
@@ -1144,11 +1144,11 @@ void KyraEngine_LoK::setCharactersInDefaultScene() {
}
void KyraEngine_LoK::setCharactersPositions(int character) {
- static uint16 initXPosTable[] = {
+ static const uint16 initXPosTable[] = {
0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B,
0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042
};
- static uint8 initYPosTable[] = {
+ static const uint8 initYPosTable[] = {
0x00, 0xA2, 0x00, 0x42, 0x00,
0x67, 0x67, 0x60, 0x5A, 0x71,
0x76
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index f00c47ceea..6e7a88b1a3 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -92,9 +92,19 @@ bool Screen::init() {
if (_useSJIS) {
if (!_sjisFontData) {
- _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0);
- if (!_sjisFontData)
- error("missing font rom ('FMT_FNT.ROM') required for this version");
+ // we use the FM-Towns font rom for PC-98, too, until we feel
+ // like adding support for the PC-98 font
+ //if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
+ // FM-Towns
+ _sjisFontData = _vm->resource()->fileData("FMT_FNT.ROM", 0);
+ if (!_sjisFontData)
+ error("missing font rom ('FMT_FNT.ROM') required for this version");
+ /*} else {
+ // PC-98
+ _sjisFontData = _vm->resource()->fileData("FONT.ROM", 0);
+ if (!_sjisFontData)
+ error("missing font rom ('FONT.ROM') required for this version");
+ }*/
}
if (!_sjisTempPage) {
diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp
index ef3e259cfa..b10a4b32bf 100644
--- a/engines/kyra/script.cpp
+++ b/engines/kyra/script.cpp
@@ -35,7 +35,7 @@
namespace Kyra {
EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm) {
#define COMMAND(x) { &EMCInterpreter::x, #x }
- static CommandEntry commandProcs[] = {
+ static const CommandEntry commandProcs[] = {
// 0x00
COMMAND(cmd_jmpTo),
COMMAND(cmd_setRetValue),
@@ -132,6 +132,8 @@ bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Commo
scriptData->opcodes = opcodes;
+ strncpy(scriptData->filename, filename, 13);
+
return true;
}
@@ -205,7 +207,7 @@ bool EMCInterpreter::run(EMCState *script) {
}
if (opcode > 18) {
- error("Script unknown command: %d", opcode);
+ error("Script unknown command: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset);
} else {
debugC(5, kDebugLevelScript, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _commands[opcode].desc, _parameter, (uint)_parameter);
(this->*(_commands[opcode].proc))(script);
@@ -388,7 +390,7 @@ void EMCInterpreter::cmd_execOpcode(EMCState* script) {
script->retValue = (*(*script->dataPtr->opcodes)[opcode])(script);
} else {
script->retValue = 0;
- warning("calling unimplemented opcode(0x%.02X/%d)", opcode, opcode);
+ warning("Calling unimplemented opcode(0x%.02X/%d) from file '%s'", opcode, opcode, script->dataPtr->filename);
}
}
diff --git a/engines/kyra/script.h b/engines/kyra/script.h
index de52093f66..2b97a83289 100644
--- a/engines/kyra/script.h
+++ b/engines/kyra/script.h
@@ -36,6 +36,8 @@ struct EMCState;
typedef Common::Functor1<EMCState*, int> Opcode;
struct EMCData {
+ char filename[13];
+
byte *text;
uint16 *data;
uint16 *ordr;
diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp
index 91fbfb3e49..94f160d11f 100644
--- a/engines/kyra/script_hof.cpp
+++ b/engines/kyra/script_hof.cpp
@@ -799,10 +799,14 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) {
_screen->fadeToBlack(0x14);
- sprintf(filename, "LETTER%.1d.", letter);
- strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
-
+ sprintf(filename, "LETTER%.1d.%s", letter, _languageExtension[_lang]);
uint8 *letterBuffer = _res->fileData(filename, 0);
+ if (!letterBuffer) {
+ // some floppy versions use a TXT extension
+ sprintf(filename, "LETTER%.1d.TXT", letter);
+ letterBuffer = _res->fileData(filename, 0);
+ }
+
if (letterBuffer) {
bookDecodeText(letterBuffer);
bookPrintText(2, letterBuffer, 0xC, 0xA, 0x20);
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index 4ad6464424..4b82232049 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -34,7 +34,8 @@ namespace Kyra {
TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) {
#define COMMAND(x) { &TIMInterpreter::x, #x }
#define COMMAND_UNIMPL() { 0, 0 }
- static CommandEntry commandProcs[] = {
+#define cmd_return(n) cmd_return_##n
+ static const CommandEntry commandProcs[] = {
// 0x00
COMMAND(cmd_initFunc0),
COMMAND(cmd_stopCurFunc),
@@ -66,15 +67,16 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s
COMMAND_UNIMPL(),
COMMAND(cmd_resetAllRuntimes),
// 0x18
- COMMAND(cmd_return<1>),
+ COMMAND(cmd_return(1)),
COMMAND(cmd_execOpcode),
COMMAND(cmd_initFuncNow),
COMMAND(cmd_stopFuncNow),
// 0x1C
- COMMAND(cmd_return<1>),
- COMMAND(cmd_return<1>),
- COMMAND(cmd_return<-1>)
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(n1))
};
+#undef cmd_return
_commands = commandProcs;
_commandsSize = ARRAYSIZE(commandProcs);
@@ -122,6 +124,8 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpc
for (int i = 0; i < num; ++i)
tim->func[i].avtl = tim->avtl + tim->avtl[i];
+ strncpy(tim->filename, filename, 13);
+
return tim;
}
@@ -199,12 +203,12 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) {
int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
if (cmd < 0 || cmd >= _commandsSize) {
- warning("Calling unimplemented TIM command %d", cmd);
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
return 0;
}
if (_commands[cmd].proc == 0) {
- warning("Calling unimplemented TIM command %d", cmd);
+ warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
return 0;
}
@@ -259,7 +263,7 @@ int TIMInterpreter::cmd_execOpcode(const uint16 *param) {
uint16 opcode = *param++;
if (opcode > _currentTim->opcodes->size()) {
- warning("Calling unimplemented TIM opcode(0x%.02X/%d)", opcode, opcode);
+ warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
return 0;
}
diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h
index cd715ff4ef..39a1d90a44 100644
--- a/engines/kyra/script_tim.h
+++ b/engines/kyra/script_tim.h
@@ -37,6 +37,8 @@ struct TIM;
typedef Common::Functor2<const TIM*, const uint16*, int> TIMOpcode;
struct TIM {
+ char filename[13];
+
int16 procFunc;
uint16 procParam;
@@ -102,8 +104,12 @@ private:
int cmd_execOpcode(const uint16 *param);
int cmd_initFuncNow(const uint16 *param);
int cmd_stopFuncNow(const uint16 *param);
- template<int T>
- int cmd_return(const uint16 *) { return T; }
+#define cmd_return(n, v) \
+ int cmd_return_##n(const uint16 *) { return v; }
+
+ cmd_return( 1, 1);
+ cmd_return(n1, -1);
+#undef cmd_return
};
} // end of namespace Kyra
diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp
index 73d69ef10c..dfda5bf859 100644
--- a/engines/kyra/seqplayer.cpp
+++ b/engines/kyra/seqplayer.cpp
@@ -500,7 +500,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) {
debugC(9, kDebugLevelSequence, "SeqPlayer::seq_playSequence(%p, %d)", (const void *)seqData, skipSeq);
assert(seqData);
- static SeqEntry floppySeqProcs[] = {
+ static const SeqEntry floppySeqProcs[] = {
// 0x00
SEQOP(3, s1_wsaOpen),
SEQOP(2, s1_wsaClose),
@@ -541,7 +541,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) {
SEQOP(1, s1_endOfScript)
};
- static SeqEntry cdromSeqProcs[] = {
+ static const SeqEntry cdromSeqProcs[] = {
// 0x00
SEQOP(3, s1_wsaOpen),
SEQOP(2, s1_wsaClose),
diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp
index 1940acbf7f..577dcd827b 100644
--- a/engines/kyra/sequences_lok.cpp
+++ b/engines/kyra/sequences_lok.cpp
@@ -1082,7 +1082,7 @@ void KyraEngine_LoK::seq_playCredits() {
_screen->_charWidth = -1;
// we only need this for the fm-towns version
- if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
+ if (_flags.platform == Common::kPlatformFMTowns && _configMusic == 1)
snd_playWanderScoreViaMap(53, 1);
uint8 *buffer = 0;
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index f56c43aabd..5068268d99 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -243,27 +243,14 @@ int SoundMidiPC::open() {
}
void SoundMidiPC::close() {
- if (_driver)
+ if (_driver) {
_driver->close();
+ delete _driver;
+ }
_driver = 0;
}
void SoundMidiPC::send(uint32 b) {
- // HACK: For Kyrandia, we make the simplifying assumption that a song
- // either loops in its entirety, or not at all. So if we see a FOR_LOOP
- // controller event, we turn on looping even if there isn't any
- // corresponding NEXT_BREAK event.
- //
- // This is a gross over-simplification of how XMIDI handles loops. If
- // anyone feels like doing a proper implementation, please refer to
- // the Exult project, and do it in midiparser_xmidi.cpp
-
- if ((b & 0xFFF0) == 0x74B0 && _eventFromMusic) {
- debugC(9, kDebugLevelMain | kDebugLevelSound, "SoundMidiPC: Looping song");
- _musicParser->property(MidiParser::mpAutoLoop, true);
- return;
- }
-
if (_passThrough) {
if ((b & 0xFFF0) == 0x007BB0)
return;
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 1baeb3064a..cebfdf491f 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -73,7 +73,8 @@ public:
kAdlib,
kMidiMT32,
kMidiGM,
- kTowns
+ kTowns,
+ kPC98
};
virtual kType getMusicType() const = 0;
@@ -382,7 +383,9 @@ private:
Common::Mutex _mutex;
};
-class SoundTowns_EuphonyDriver;
+class Towns_EuphonyDriver;
+class TownsPC98_OpnDriver;
+
class SoundTowns : public MidiDriver, public Sound {
public:
SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer);
@@ -417,6 +420,7 @@ public:
static float semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiToneRootkey,
uint32 sampleRate, uint32 outputRate, int32 pitchWheel);
+
private:
bool loadInstruments();
void playEuphonyTrack(uint32 offset, int loop);
@@ -430,7 +434,7 @@ private:
uint _sfxFileIndex;
uint8 *_sfxFileData;
- SoundTowns_EuphonyDriver * _driver;
+ Towns_EuphonyDriver * _driver;
MidiParser * _parser;
Common::Mutex _mutex;
@@ -439,13 +443,38 @@ private:
const uint8 *_sfxWDTable;
};
-//class SoundTowns_v2_TwnDriver;
-class SoundTowns_v2 : public Sound {
+class SoundPC98 : public Sound {
public:
- SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundTowns_v2();
+ SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundPC98();
- kType getMusicType() const { return kTowns; }
+ virtual kType getMusicType() const { return kPC98; }
+
+ bool init();
+
+ void process() {}
+ void loadSoundFile(uint file) {}
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ void beginFadeOut();
+
+ int32 voicePlay(const char *file, bool isSfx = false) { return -1; }
+ void playSoundEffect(uint8);
+
+protected:
+ int _lastTrack;
+ uint8 *_musicTrackData;
+ uint8 *_sfxTrackData;
+ TownsPC98_OpnDriver *_driver;
+};
+
+class SoundTownsPC98_v2 : public Sound {
+public:
+ SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundTownsPC98_v2();
+
+ kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
bool init();
void process();
@@ -457,15 +486,15 @@ public:
void beginFadeOut();
int32 voicePlay(const char *file, bool isSfx = false);
- void playSoundEffect(uint8) {}
-
-private:
- int _lastTrack;
+ void playSoundEffect(uint8 track);
+protected:
Audio::AudioStream *_currentSFX;
+ int _lastTrack;
+ bool _useFmSfx;
- //SoundTowns_v2_TwnDriver *_driver;
- uint8 *_twnTrackData;
+ uint8 *_musicTrackData;
+ TownsPC98_OpnDriver *_driver;
};
class MixedSoundDriver : public Sound {
diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp
index 8a1d16a6b1..b43d72ebce 100644
--- a/engines/kyra/sound_lok.cpp
+++ b/engines/kyra/sound_lok.cpp
@@ -43,19 +43,29 @@ void KyraEngine_LoK::snd_playWanderScoreViaMap(int command, int restart) {
if (restart)
_lastMusicCommand = -1;
- if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
+ if (_flags.platform == Common::kPlatformFMTowns) {
if (command == 1) {
_sound->beginFadeOut();
} else if (command >= 35 && command <= 38) {
snd_playSoundEffect(command-20);
} else if (command >= 2) {
- if (_lastMusicCommand != command) {
+ if (_lastMusicCommand != command)
// the original does -2 here we handle this inside _sound->playTrack()
_sound->playTrack(command);
- }
} else {
_sound->haltTrack();
}
+ _lastMusicCommand = command;
+ } else if (_flags.platform == Common::kPlatformPC98) {
+ if (command == 1) {
+ _sound->beginFadeOut();
+ } else if (command >= 2) {
+ if (_lastMusicCommand != command)
+ _sound->playTrack(command);
+ } else {
+ _sound->haltTrack();
+ }
+ _lastMusicCommand = command;
} else {
KyraEngine_v1::snd_playWanderScoreViaMap(command, restart);
}
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 4265533507..e96cef735c 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -34,18 +34,16 @@
#include "common/util.h"
-#include <math.h>
-
#define EUPHONY_FADEOUT_TICKS 600
namespace Kyra {
-enum ChannelState { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
+enum EnvelopeState { s_ready, s_attacking, s_decaying, s_sustaining, s_releasing };
-class MidiChannel_EuD : public MidiChannel {
+class Towns_EuphonyChannel : public MidiChannel {
public:
- MidiChannel_EuD() {}
- ~MidiChannel_EuD() {}
+ Towns_EuphonyChannel() {}
+ ~Towns_EuphonyChannel() {}
virtual void nextTick(int32 *outbuf, int buflen) = 0;
virtual void rate(uint16 r) = 0;
@@ -54,10 +52,10 @@ protected:
uint16 _rate;
};
-class MidiChannel_EuD_FM : public MidiChannel_EuD {
+class Towns_EuphonyFmChannel : public Towns_EuphonyChannel {
public:
- MidiChannel_EuD_FM();
- virtual ~MidiChannel_EuD_FM();
+ Towns_EuphonyFmChannel();
+ virtual ~Towns_EuphonyFmChannel();
void nextTick(int32 *outbuf, int buflen);
void rate(uint16 r);
@@ -79,13 +77,13 @@ protected:
Voice2612 *_voice;
};
-class MidiChannel_EuD_WAVE : public MidiChannel_EuD {
+class Towns_EuphonyPcmChannel : public Towns_EuphonyChannel {
public:
void nextTick(int32 *outbuf, int buflen);
void rate(uint16 r);
- MidiChannel_EuD_WAVE();
- virtual ~MidiChannel_EuD_WAVE();
+ Towns_EuphonyPcmChannel();
+ virtual ~Towns_EuphonyPcmChannel();
// MidiChannel interface
MidiDriver *device() { return 0; }
@@ -126,9 +124,9 @@ protected:
int32 keyOffset;
int32 keyNote;
const int8 *_samples;
- } * _snd[8];
+ } *_snd[8];
struct Env {
- ChannelState state;
+ EnvelopeState state;
int32 currentLevel;
int32 rate;
int32 tickCount;
@@ -141,40 +139,39 @@ protected:
int32 releaseRate;
int32 rootKeyOffset;
int32 size;
- } * _env[8];
- } * _voice;
+ } *_env[8];
+ } *_voice;
};
-class SoundTowns_EuphonyTrackQueue {
+class Towns_EuphonyTrackQueue {
public:
- SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver *driver, SoundTowns_EuphonyTrackQueue *last);
- ~SoundTowns_EuphonyTrackQueue() {}
+ Towns_EuphonyTrackQueue(Towns_EuphonyDriver *driver, Towns_EuphonyTrackQueue *last);
+ ~Towns_EuphonyTrackQueue() {}
- void release();
+ Towns_EuphonyTrackQueue *release();
void initDriver();
- void loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop = 0);
- void loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop = 0);
+ void loadDataToCurrentPosition(uint8 *trackdata, uint32 size, bool loop = 0);
+ void loadDataToEndOfQueue(uint8 *trackdata, uint32 size, bool loop = 0);
void setPlayBackStatus(bool playing);
- SoundTowns_EuphonyTrackQueue * reset();
bool isPlaying() {return _playing; }
- uint8 * trackData() {return _trackData; }
+ uint8 *trackData() {return _trackData; }
bool _loop;
- SoundTowns_EuphonyTrackQueue * _next;
+ Towns_EuphonyTrackQueue *_next;
private:
- uint8 * _trackData;
- uint8 * _used;
- uint8 * _fchan;
- uint8 * _wchan;
+ uint8 *_trackData;
+ uint8 *_used;
+ uint8 *_fchan;
+ uint8 *_wchan;
bool _playing;
- SoundTowns_EuphonyDriver * _driver;
- SoundTowns_EuphonyTrackQueue * _last;
+ Towns_EuphonyDriver *_driver;
+ Towns_EuphonyTrackQueue *_last;
};
-class MidiParser_EuD : public MidiParser {
+class Towns_EuphonyParser : public MidiParser {
public:
- MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue);
+ Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue);
bool loadMusic (byte *data, uint32 size);
int32 calculateTempo(int16 val);
@@ -183,11 +180,11 @@ protected:
void resetTracking();
void setup();
- byte * _enable;
- byte * _mode;
- byte * _channel;
- byte * _adjVelo;
- int8 * _adjNote;
+ byte *_enable;
+ byte *_mode;
+ byte *_channel;
+ byte *_adjVelo;
+ int8 *_adjNote;
uint8 _firstBaseTickStep;
uint8 _nextBaseTickStep;
@@ -195,13 +192,13 @@ protected:
uint32 _baseTick;
byte _tempo[3];
- SoundTowns_EuphonyTrackQueue * _queue;
+ Towns_EuphonyTrackQueue *_queue;
};
-class SoundTowns_EuphonyDriver : public MidiDriver_Emulated {
+class Towns_EuphonyDriver : public MidiDriver_Emulated {
public:
- SoundTowns_EuphonyDriver(Audio::Mixer *mixer);
- virtual ~SoundTowns_EuphonyDriver();
+ Towns_EuphonyDriver(Audio::Mixer *mixer);
+ virtual ~Towns_EuphonyDriver();
int open();
void close();
@@ -213,7 +210,7 @@ public:
void loadFmInstruments(const byte *instr);
void loadWaveInstruments(const byte *instr);
- SoundTowns_EuphonyTrackQueue * queue() { return _queue; }
+ Towns_EuphonyTrackQueue *queue() { return _queue; }
MidiChannel *allocateChannel() { return 0; }
MidiChannel *getPercussionChannel() { return 0; }
@@ -237,10 +234,10 @@ protected:
void generateSamples(int16 *buf, int len);
- MidiChannel_EuD_FM *_fChannel[6];
- MidiChannel_EuD_WAVE *_wChannel[8];
- MidiChannel_EuD * _channel[16];
- SoundTowns_EuphonyTrackQueue * _queue;
+ Towns_EuphonyFmChannel *_fChannel[6];
+ Towns_EuphonyPcmChannel *_wChannel[8];
+ Towns_EuphonyChannel *_channel[16];
+ Towns_EuphonyTrackQueue *_queue;
int _volume;
bool _fading;
@@ -251,23 +248,23 @@ protected:
int8 * _waveSounds[10];
};
-MidiChannel_EuD_FM::MidiChannel_EuD_FM() {
+Towns_EuphonyFmChannel::Towns_EuphonyFmChannel() {
_voice = new Voice2612;
}
-MidiChannel_EuD_FM::~MidiChannel_EuD_FM() {
+Towns_EuphonyFmChannel::~Towns_EuphonyFmChannel() {
delete _voice;
}
-void MidiChannel_EuD_FM::noteOn(byte note, byte onVelo) {
+void Towns_EuphonyFmChannel::noteOn(byte note, byte onVelo) {
_voice->noteOn(note, onVelo);
}
-void MidiChannel_EuD_FM::noteOff(byte note) {
+void Towns_EuphonyFmChannel::noteOff(byte note) {
_voice->noteOff(note);
}
-void MidiChannel_EuD_FM::controlChange(byte control, byte value) {
+void Towns_EuphonyFmChannel::controlChange(byte control, byte value) {
if (control == 121) {
// Reset controller
delete _voice;
@@ -279,25 +276,25 @@ void MidiChannel_EuD_FM::controlChange(byte control, byte value) {
}
}
-void MidiChannel_EuD_FM::sysEx_customInstrument(uint32, const byte *fmInst) {
+void Towns_EuphonyFmChannel::sysEx_customInstrument(uint32, const byte *fmInst) {
_voice->_rate = _rate;
_voice->setInstrument(fmInst);
}
-void MidiChannel_EuD_FM::pitchBend(int16 value) {
+void Towns_EuphonyFmChannel::pitchBend(int16 value) {
_voice->pitchBend(value);
}
-void MidiChannel_EuD_FM::nextTick(int32 *outbuf, int buflen) {
+void Towns_EuphonyFmChannel::nextTick(int32 *outbuf, int buflen) {
_voice->nextTick((int*) outbuf, buflen);
}
-void MidiChannel_EuD_FM::rate(uint16 r) {
+void Towns_EuphonyFmChannel::rate(uint16 r) {
_rate = r;
_voice->_rate = r;
}
-MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() {
+Towns_EuphonyPcmChannel::Towns_EuphonyPcmChannel() {
_voice = new Voice;
for (uint8 i = 0; i < 8; i++) {
_voice->_env[i] = new Voice::Env;
@@ -310,7 +307,7 @@ MidiChannel_EuD_WAVE::MidiChannel_EuD_WAVE() {
_current = -1;
}
-MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() {
+Towns_EuphonyPcmChannel::~Towns_EuphonyPcmChannel() {
for (uint8 i = 0; i < 8; i++) {
if (_voice->_snd[i])
delete _voice->_snd[i];
@@ -319,7 +316,7 @@ MidiChannel_EuD_WAVE::~MidiChannel_EuD_WAVE() {
delete _voice;
}
-void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) {
+void Towns_EuphonyPcmChannel::noteOn(byte note, byte onVelo) {
_note = note;
velocity(onVelo);
_phase = 0;
@@ -329,24 +326,24 @@ void MidiChannel_EuD_WAVE::noteOn(byte note, byte onVelo) {
break;
}
- _voice->_env[_current]->state = _s_attacking;
+ _voice->_env[_current]->state = s_attacking;
_voice->_env[_current]->currentLevel = 0;
_voice->_env[_current]->rate = _rate;
_voice->_env[_current]->tickCount = 0;
}
-void MidiChannel_EuD_WAVE::noteOff(byte note) {
+void Towns_EuphonyPcmChannel::noteOff(byte note) {
if (_current == -1)
return;
- if (_voice->_env[_current]->state == _s_ready)
+ if (_voice->_env[_current]->state == s_ready)
return;
- _voice->_env[_current]->state = _s_releasing;
+ _voice->_env[_current]->state = s_releasing;
_voice->_env[_current]->releaseLevel = _voice->_env[_current]->currentLevel;
_voice->_env[_current]->tickCount = 0;
}
-void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) {
+void Towns_EuphonyPcmChannel::controlChange(byte control, byte value) {
switch (control) {
case 0x07:
// volume
@@ -377,7 +374,7 @@ void MidiChannel_EuD_WAVE::controlChange(byte control, byte value) {
}
}
-void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmInst) {
+void Towns_EuphonyPcmChannel::sysEx_customInstrument(uint32 type, const byte *fmInst) {
if (type == 0x80) {
for (uint8 i = 0; i < 8; i++) {
const byte * const* pos = (const byte * const*) fmInst;
@@ -406,7 +403,7 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns
_voice->split[i] = READ_LE_UINT16(fmInst + 16 + 2 * i);
_voice->id[i] = READ_LE_UINT32(fmInst + 32 + 4 * i);
_voice->_snd[i] = 0;
- _voice->_env[i]->state = _s_ready;
+ _voice->_env[i]->state = s_ready;
_voice->_env[i]->currentLevel = 0;
_voice->_env[i]->totalLevel = *(fmInst + 64 + 8 * i);
_voice->_env[i]->attackRate = *(fmInst + 65 + 8 * i) * 10;
@@ -419,11 +416,11 @@ void MidiChannel_EuD_WAVE::sysEx_customInstrument(uint32 type, const byte *fmIns
}
}
-void MidiChannel_EuD_WAVE::pitchBend(int16 value) {
+void Towns_EuphonyPcmChannel::pitchBend(int16 value) {
_frequencyOffs = value;
}
-void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) {
+void Towns_EuphonyPcmChannel::nextTick(int32 *outbuf, int buflen) {
if (_current == -1 || !_voice->_snd[_current] || !_voice->_env[_current]->state || !_velocity) {
velocity(0);
_current = -1;
@@ -475,13 +472,13 @@ void MidiChannel_EuD_WAVE::nextTick(int32 *outbuf, int buflen) {
}
}
-void MidiChannel_EuD_WAVE::evpNextTick() {
+void Towns_EuphonyPcmChannel::evpNextTick() {
switch (_voice->_env[_current]->state) {
- case _s_ready:
+ case s_ready:
_voice->_env[_current]->currentLevel = 0;
return;
- case _s_attacking:
+ case s_attacking:
if (_voice->_env[_current]->attackRate == 0)
_voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
else if (_voice->_env[_current]->attackRate >= 1270)
@@ -493,12 +490,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() {
if (_voice->_env[_current]->currentLevel >= _voice->_env[_current]->totalLevel) {
_voice->_env[_current]->currentLevel = _voice->_env[_current]->totalLevel;
- _voice->_env[_current]->state = _s_decaying;
+ _voice->_env[_current]->state = s_decaying;
_voice->_env[_current]->tickCount = 0;
}
break;
- case _s_decaying:
+ case s_decaying:
if (_voice->_env[_current]->decayRate == 0)
_voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
else if (_voice->_env[_current]->decayRate >= 1270)
@@ -512,12 +509,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() {
if (_voice->_env[_current]->currentLevel <= _voice->_env[_current]->sustainLevel) {
_voice->_env[_current]->currentLevel = _voice->_env[_current]->sustainLevel;
- _voice->_env[_current]->state = _s_sustaining;
+ _voice->_env[_current]->state = s_sustaining;
_voice->_env[_current]->tickCount = 0;
}
break;
- case _s_sustaining:
+ case s_sustaining:
if (_voice->_env[_current]->sustainRate == 0)
_voice->_env[_current]->currentLevel = 0;
else if (_voice->_env[_current]->sustainRate >= 2540)
@@ -531,12 +528,12 @@ void MidiChannel_EuD_WAVE::evpNextTick() {
if (_voice->_env[_current]->currentLevel <= 0) {
_voice->_env[_current]->currentLevel = 0;
- _voice->_env[_current]->state = _s_ready;
+ _voice->_env[_current]->state = s_ready;
_voice->_env[_current]->tickCount = 0;
}
break;
- case _s_releasing:
+ case s_releasing:
if (_voice->_env[_current]->releaseRate == 0)
_voice->_env[_current]->currentLevel = 0;
else if (_voice->_env[_current]->releaseRate >= 1270)
@@ -550,7 +547,7 @@ void MidiChannel_EuD_WAVE::evpNextTick() {
if (_voice->_env[_current]->currentLevel <= 0) {
_voice->_env[_current]->currentLevel = 0;
- _voice->_env[_current]->state = _s_ready;
+ _voice->_env[_current]->state = s_ready;
}
break;
@@ -559,15 +556,15 @@ void MidiChannel_EuD_WAVE::evpNextTick() {
}
}
-void MidiChannel_EuD_WAVE::rate(uint16 r) {
+void Towns_EuphonyPcmChannel::rate(uint16 r) {
_rate = r;
}
-void MidiChannel_EuD_WAVE::velocity(int velo) {
+void Towns_EuphonyPcmChannel::velocity(int velo) {
_velocity = velo;
}
-SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer)
+Towns_EuphonyDriver::Towns_EuphonyDriver(Audio::Mixer *mixer)
: MidiDriver_Emulated(mixer) {
_volume = 255;
_fadestate = EUPHONY_FADEOUT_TICKS;
@@ -576,9 +573,9 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer)
MidiDriver_YM2612::createLookupTables();
for (uint8 i = 0; i < 6; i++)
- _channel[i] = _fChannel[i] = new MidiChannel_EuD_FM;
+ _channel[i] = _fChannel[i] = new Towns_EuphonyFmChannel;
for (uint8 i = 0; i < 8; i++)
- _channel[i + 6] = _wChannel[i] = new MidiChannel_EuD_WAVE;
+ _channel[i + 6] = _wChannel[i] = new Towns_EuphonyPcmChannel;
_channel[14] = _channel[15] = 0;
_fmInstruments = _waveInstruments = 0;
@@ -587,10 +584,10 @@ SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer)
rate(getRate());
fading(0);
- _queue = new SoundTowns_EuphonyTrackQueue(this, 0);
+ _queue = new Towns_EuphonyTrackQueue(this, 0);
}
-SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() {
+Towns_EuphonyDriver::~Towns_EuphonyDriver() {
for (int i = 0; i < 6; i++)
delete _fChannel[i];
for (int i = 0; i < 8; i++)
@@ -622,7 +619,7 @@ SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() {
}
}
-int SoundTowns_EuphonyDriver::open() {
+int Towns_EuphonyDriver::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
MidiDriver_Emulated::open();
@@ -633,18 +630,18 @@ int SoundTowns_EuphonyDriver::open() {
return 0;
}
-void SoundTowns_EuphonyDriver::close() {
+void Towns_EuphonyDriver::close() {
if (!_isOpen)
return;
_isOpen = false;
_mixer->stopHandle(_mixerSoundHandle);
}
-void SoundTowns_EuphonyDriver::send(uint32 b) {
+void Towns_EuphonyDriver::send(uint32 b) {
send(b & 0xF, b & 0xFFFFFFF0);
}
-void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) {
+void Towns_EuphonyDriver::send(byte chan, uint32 b) {
byte param2 = (byte) ((b >> 16) & 0xFF);
byte param1 = (byte) ((b >> 8) & 0xFF);
byte cmd = (byte) (b & 0xF0);
@@ -703,18 +700,18 @@ void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) {
_channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
break;
default:
- warning("SoundTowns_EuphonyDriver: Unknown send() command 0x%02X", cmd);
+ warning("Towns_EuphonyDriver: Unknown send() command 0x%02X", cmd);
}
}
-void SoundTowns_EuphonyDriver::loadFmInstruments(const byte *instr) {
+void Towns_EuphonyDriver::loadFmInstruments(const byte *instr) {
if (_fmInstruments)
delete[] _fmInstruments;
_fmInstruments = new uint8[0x1800];
memcpy(_fmInstruments, instr, 0x1800);
}
-void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) {
+void Towns_EuphonyDriver::loadWaveInstruments(const byte *instr) {
if (_waveInstruments)
delete[] _waveInstruments;
_waveInstruments = new uint8[0x1000];
@@ -739,24 +736,24 @@ void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) {
}
-void SoundTowns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) {
+void Towns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) {
_channel[midiChannelNumber] = _fChannel[fmChannelNumber];
}
-void SoundTowns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) {
+void Towns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) {
_channel[midiChannelNumber] = _wChannel[waveChannelNumber];
}
-void SoundTowns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) {
+void Towns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) {
_channel[midiChannelNumber] = 0;
}
-void SoundTowns_EuphonyDriver::generateSamples(int16 *data, int len) {
+void Towns_EuphonyDriver::generateSamples(int16 *data, int len) {
memset(data, 0, 2 * sizeof(int16) * len);
nextTick(data, len);
}
-void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
+void Towns_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
int32 *buf0 = (int32 *)buf1;
for (int i = 0; i < ARRAYSIZE(_channel); i++) {
@@ -779,26 +776,26 @@ void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
}
}
-void SoundTowns_EuphonyDriver::rate(uint16 r) {
+void Towns_EuphonyDriver::rate(uint16 r) {
for (uint8 i = 0; i < 16; i++) {
if (_channel[i])
_channel[i]->rate(r);
}
}
-void SoundTowns_EuphonyDriver::fading(bool status) {
+void Towns_EuphonyDriver::fading(bool status) {
_fading = status;
if (!_fading)
_fadestate = EUPHONY_FADEOUT_TICKS;
}
-MidiParser_EuD::MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue) : MidiParser(),
+Towns_EuphonyParser::Towns_EuphonyParser(Towns_EuphonyTrackQueue * queue) : MidiParser(),
_firstBaseTickStep(0x33), _nextBaseTickStep(0x33) {
_initialTempo = calculateTempo(0x5a);
_queue = queue;
}
-void MidiParser_EuD::parseNextEvent(EventInfo &info) {
+void Towns_EuphonyParser::parseNextEvent(EventInfo &info) {
byte *pos = _position._play_pos;
if (_queue->_next) {
@@ -878,7 +875,7 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) {
pos += 6;
}
} else if (cmd == 0xF2) {
- static uint16 tickTable [] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
+ static const uint16 tickTable[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
_baseTick += tickTable[_nextBaseTickStep >> 4] * ((_nextBaseTickStep & 0x0f) + 1);
_nextBaseTickStep = pos[1];
pos += 6;
@@ -920,15 +917,14 @@ void MidiParser_EuD::parseNextEvent(EventInfo &info) {
_position._play_pos = pos;
}
-bool MidiParser_EuD::loadMusic(byte *data, uint32 size) {
+bool Towns_EuphonyParser::loadMusic(byte *data, uint32 size) {
bool loop = _autoLoop;
if (_queue->isPlaying() && !_queue->_loop) {
_queue->loadDataToEndOfQueue(data, size, loop);
} else {
unloadMusic();
- _queue = _queue->reset();
- _queue->release();
+ _queue = _queue->release();
_queue->loadDataToCurrentPosition(data, size, loop);
setup();
setTrack(0);
@@ -937,7 +933,7 @@ bool MidiParser_EuD::loadMusic(byte *data, uint32 size) {
return true;
}
-int32 MidiParser_EuD::calculateTempo(int16 val) {
+int32 Towns_EuphonyParser::calculateTempo(int16 val) {
int32 tempo = val;
if (tempo < 0)
@@ -953,7 +949,7 @@ int32 MidiParser_EuD::calculateTempo(int16 val) {
return tempo;
}
-void MidiParser_EuD::resetTracking() {
+void Towns_EuphonyParser::resetTracking() {
MidiParser::resetTracking();
_nextBaseTickStep = _firstBaseTickStep;
@@ -962,7 +958,7 @@ void MidiParser_EuD::resetTracking() {
_queue->setPlayBackStatus(false);
}
-void MidiParser_EuD::setup() {
+void Towns_EuphonyParser::setup() {
uint8 *data = _queue->trackData();
if (!data)
return;
@@ -984,7 +980,7 @@ void MidiParser_EuD::setup() {
_tracks[0] = data + 0x806;
}
-SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver * driver, SoundTowns_EuphonyTrackQueue * last) {
+Towns_EuphonyTrackQueue::Towns_EuphonyTrackQueue(Towns_EuphonyDriver * driver, Towns_EuphonyTrackQueue * last) {
_trackData = 0;
_next = 0;
_driver = driver;
@@ -993,22 +989,15 @@ SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDri
_playing = false;
}
-void SoundTowns_EuphonyTrackQueue::setPlayBackStatus(bool playing) {
- SoundTowns_EuphonyTrackQueue * i = this;
+void Towns_EuphonyTrackQueue::setPlayBackStatus(bool playing) {
+ Towns_EuphonyTrackQueue * i = this;
do {
i->_playing = playing;
i = i->_next;
} while (i);
}
-SoundTowns_EuphonyTrackQueue * SoundTowns_EuphonyTrackQueue::reset() {
- SoundTowns_EuphonyTrackQueue * i = this;
- while (i->_last)
- i = i->_last;
- return i;
-}
-
-void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) {
+void Towns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) {
if (_trackData)
delete[] _trackData;
_trackData = new uint8[0xC58A];
@@ -1022,17 +1011,17 @@ void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata,
_playing = false;
}
-void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) {
+void Towns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) {
if (!_trackData) {
loadDataToCurrentPosition(trackdata, size, loop);
return;
}
- SoundTowns_EuphonyTrackQueue * i = this;
+ Towns_EuphonyTrackQueue * i = this;
while (i->_next)
i = i->_next;
- i = i->_next = new SoundTowns_EuphonyTrackQueue(_driver, i);
+ i = i->_next = new Towns_EuphonyTrackQueue(_driver, i);
i->_trackData = new uint8[0xC58A];
memset(i->_trackData, 0, 0xC58A);
Screen::decodeFrame4(trackdata, i->_trackData, size);
@@ -1044,29 +1033,39 @@ void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint3
i->_playing = _playing;
}
-void SoundTowns_EuphonyTrackQueue::release() {
- SoundTowns_EuphonyTrackQueue * i = _next;
- _next = 0;
- _playing = false;
- _used = _fchan = _wchan = 0;
+Towns_EuphonyTrackQueue *Towns_EuphonyTrackQueue::release() {
+ Towns_EuphonyTrackQueue *i = this;
+ while (i->_next)
+ i = i->_next;
- if (_trackData) {
- delete[] _trackData;
- _trackData = 0;
- }
+ Towns_EuphonyTrackQueue *res = i;
while (i) {
+ i->_playing = false;
+ i->_used = i->_fchan = i->_wchan = 0;
if (i->_trackData) {
delete[] i->_trackData;
i->_trackData = 0;
}
- i = i->_next;
- if (i)
- delete i->_last;
+ i = i->_last;
+ if (i) {
+ res = i;
+ if (i->_next) {
+ delete i->_next;
+ i->_next = 0;
+ }
+ }
}
+
+ if (res->_trackData) {
+ delete[] res->_trackData;
+ res->_trackData = 0;
+ }
+
+ return res;
}
-void SoundTowns_EuphonyTrackQueue::initDriver() {
+void Towns_EuphonyTrackQueue::initDriver() {
for (uint8 i = 0; i < 6; i++) {
if (_used[_fchan[i]])
_driver->assignFmChannel(_fchan[i], i);
@@ -1084,11 +1083,1685 @@ void SoundTowns_EuphonyTrackQueue::initDriver() {
_driver->send(0x79B0);
}
+class TownsPC98_OpnOperator {
+public:
+ TownsPC98_OpnOperator(double rate, const uint8 *rateTable,
+ const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
+ const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable);
+ ~TownsPC98_OpnOperator() {}
+
+ void keyOn();
+ void keyOff();
+ void frequency(int freq);
+ void updatePhaseIncrement();
+ void recalculateRates();
+ void generateOutput(int phasebuf, int *_feedbuf, int &out);
+
+ void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; }
+ void detune(int value) { _detn = &_detnTbl[value << 5]; }
+ void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; }
+ void attackRate(uint32 value) { _specifiedAttackRate = value; }
+ bool scaleRate(uint8 value);
+ void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); }
+ void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); }
+ void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; }
+ void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); }
+ void totalLevel(uint32 value) { _totalLevel = value << 3; }
+ void reset();
+
+protected:
+ EnvelopeState _state;
+ uint32 _feedbackLevel;
+ uint32 _multiple;
+ uint32 _totalLevel;
+ uint8 _keyScale1;
+ uint8 _keyScale2;
+ uint32 _specifiedAttackRate;
+ uint32 _specifiedDecayRate;
+ uint32 _specifiedSustainRate;
+ uint32 _specifiedReleaseRate;
+ uint32 _tickCount;
+ uint32 _sustainLevel;
+
+ uint32 _frequency;
+ uint8 _kcode;
+ uint32 _phase;
+ uint32 _phaseIncrement;
+ const int32 *_detn;
+
+ const uint8 *_rateTbl;
+ const uint8 *_rshiftTbl;
+ const uint8 *_adTbl;
+ const uint32 *_fTbl;
+ const uint32 *_sinTbl;
+ const int32 *_tLvlTbl;
+ const int32 *_detnTbl;
+
+ const double _tickLength;
+ double _tick;
+ int32 _currentLevel;
+
+ struct EvpState {
+ uint8 rate;
+ uint8 shift;
+ } fs_a, fs_d, fs_s, fs_r;
+};
+
+TownsPC98_OpnOperator::TownsPC98_OpnOperator(double rate, const uint8 *rateTable,
+ const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
+ const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :
+ _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
+ _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(rate * 65536.0),
+ _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
+ _phase(0), _state(s_ready) {
+
+ reset();
+}
+
+void TownsPC98_OpnOperator::keyOn() {
+ _state = s_attacking;
+ _phase = 0;
+}
+
+void TownsPC98_OpnOperator::keyOff() {
+ if (_state != s_ready)
+ _state = s_releasing;
+}
+
+void TownsPC98_OpnOperator::frequency(int freq) {
+ uint8 block = (freq >> 11);
+ uint16 pos = (freq & 0x7ff);
+ uint8 c = pos >> 7;
+ _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 ));
+ _frequency = _fTbl[pos << 1] >> (7 - block);
+}
+
+void TownsPC98_OpnOperator::updatePhaseIncrement() {
+ _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1;
+ uint8 keyscale = _kcode >> _keyScale1;
+ if (_keyScale2 != keyscale) {
+ _keyScale2 = keyscale;
+ recalculateRates();
+ }
+}
+
+void TownsPC98_OpnOperator::recalculateRates() {
+ int k = _keyScale2;
+ int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
+ fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
+ fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
+
+ r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0;
+ fs_d.rate = _rateTbl[r + k];
+ fs_d.shift = _rshiftTbl[r + k];
+
+ r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0;
+ fs_s.rate = _rateTbl[r + k];
+ fs_s.shift = _rshiftTbl[r + k];
+
+ r = (_specifiedReleaseRate << 2) + 0x22;
+ fs_r.rate = _rateTbl[r + k];
+ fs_r.shift = _rshiftTbl[r + k];
+}
+
+void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) {
+ if (_state == s_ready)
+ return;
+
+ _tick += _tickLength;
+ while (_tick > 0x30000) {
+ _tick -= 0x30000;
+ ++_tickCount;
+
+ int32 levelIncrement = 0;
+ uint32 targetTime = 0;
+ int32 targetLevel = 0;
+ EnvelopeState next_state = s_ready;
+
+ switch (_state) {
+ case s_ready:
+ return;
+ case s_attacking:
+ next_state = s_decaying;
+ targetTime = (1 << fs_a.shift) - 1;
+ targetLevel = 0;
+ levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
+ break;
+ case s_decaying:
+ targetTime = (1 << fs_d.shift) - 1;
+ next_state = s_sustaining;
+ targetLevel = _sustainLevel;
+ levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
+ break;
+ case s_sustaining:
+ targetTime = (1 << fs_s.shift) - 1;
+ next_state = s_ready;
+ targetLevel = 1023;
+ levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
+ break;
+ case s_releasing:
+ targetTime = (1 << fs_r.shift) - 1;
+ next_state = s_ready;
+ targetLevel = 1023;
+ levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
+ break;
+ }
+
+ if (!(_tickCount & targetTime)) {
+ _currentLevel += levelIncrement;
+ if ((!targetLevel && _currentLevel <= targetLevel) || (targetLevel && _currentLevel >= targetLevel)) {
+ if (_state != s_decaying)
+ _currentLevel = targetLevel;
+ if (_state != s_sustaining)
+ _state = next_state;
+ }
+ }
+ }
+
+ uint32 lvlout = _totalLevel + (uint32) _currentLevel;
+
+ int outp = 0;
+ int *i = &outp, *o = &outp;
+ int phaseShift = 0;
+
+ if (_feedbuf) {
+ o = &_feedbuf[0];
+ i = &_feedbuf[1];
+ phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0;
+ if (phasebuf == -1)
+ *i = 0;
+ *o = *i;
+ } else {
+ phaseShift = phasebuf << 15;
+ }
+
+ if (lvlout < 832) {
+ uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000)
+ + phaseShift)) >> 16) & 0x3ff];
+ *i = ((index < 6656) ? _tLvlTbl[index] : 0);
+ } else {
+ *i = 0;
+ }
+
+ _phase += _phaseIncrement;
+ out += *o;
+ if (out > 32767)
+ out = 32767;
+ if (out < -32767)
+ out = -32767;
+}
+
+void TownsPC98_OpnOperator::reset(){
+ keyOff();
+ _tick = 0;
+ _keyScale2 = 0;
+ _currentLevel = 1023;
+
+ frequency(0);
+ detune(0);
+ scaleRate(0);
+ multiple(0);
+ updatePhaseIncrement();
+ attackRate(0);
+ decayRate(0);
+ releaseRate(0);
+ sustainRate(0);
+ feedbackLevel(0);
+ totalLevel(127);
+}
+
+bool TownsPC98_OpnOperator::scaleRate(uint8 value) {
+ value = 3 - value;
+ if (_keyScale1 != value) {
+ _keyScale1 = value;
+ return true;
+ }
+
+ int k = _keyScale2;
+ int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
+ fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
+ fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
+ return false;
+}
+
+class TownsPC98_OpnDriver;
+class TownsPC98_OpnChannel {
+public:
+ TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
+ uint8 key, uint8 prt, uint8 id);
+ virtual ~TownsPC98_OpnChannel();
+ virtual void init();
+
+ typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para);
+
+ typedef enum channelState {
+ CHS_RECALCFREQ = 0x01,
+ CHS_KEYOFF = 0x02,
+ CHS_SSG = 0x04,
+ CHS_PITCHWHEELOFF = 0x08,
+ CHS_ALL_BUT_EOT = 0x0f,
+ CHS_EOT = 0x80
+ } ChannelState;
+
+ virtual void loadData(uint8 *data);
+ virtual void processEvents();
+ virtual void processFrequency();
+ bool processControlEvent(uint8 cmd);
+ void writeReg(uint8 regAdress, uint8 value);
+
+ virtual void keyOn();
+ virtual void keyOff();
+
+ void setOutputLevel();
+ void fadeStep();
+ void reset();
+
+ void updateEnv();
+ void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed);
+
+ bool _enableLeft;
+ bool _enableRight;
+ bool _updateEnvelopes;
+ const uint8 _idFlag;
+ int _feedbuf[3];
+
+protected:
+ bool control_dummy(uint8 para);
+ bool control_f0_setPatch(uint8 para);
+ bool control_f1_presetOutputLevel(uint8 para);
+ bool control_f2_setKeyOffTime(uint8 para);
+ bool control_f3_setFreqLSB(uint8 para);
+ bool control_f4_setOutputLevel(uint8 para);
+ bool control_f5_setTempo(uint8 para);
+ bool control_f6_repeatSection(uint8 para);
+ bool control_f7_setupPitchWheel(uint8 para);
+ bool control_f8_togglePitchWheel(uint8 para);
+ bool control_fa_writeReg(uint8 para);
+ bool control_fb_incOutLevel(uint8 para);
+ bool control_fc_decOutLevel(uint8 para);
+ bool control_fd_jump(uint8 para);
+ bool control_ff_endOfTrack(uint8 para);
+
+ bool control_f0_setPatchSSG(uint8 para);
+ bool control_f1_setTotalLevel(uint8 para);
+ bool control_f4_setAlgorithm(uint8 para);
+ bool control_f9_unkSSG(uint8 para);
+ bool control_fb_incOutLevelSSG(uint8 para);
+ bool control_fc_decOutLevelSSG(uint8 para);
+ bool control_ff_endOfTrackSSG(uint8 para);
+
+ uint8 _ticksLeft;
+ uint8 _algorithm;
+ uint8 _instrID;
+ uint8 _totalLevel;
+ uint8 _frqBlockMSB;
+ int8 _frqLSB;
+ uint8 _keyOffTime;
+ bool _protect;
+ uint8 *_dataPtr;
+ uint8 _ptchWhlInitDelayLo;
+ uint8 _ptchWhlInitDelayHi;
+ int16 _ptchWhlModInitVal;
+ uint8 _ptchWhlDuration;
+ uint8 _ptchWhlCurDelay;
+ int16 _ptchWhlModCurVal;
+ uint8 _ptchWhlDurLeft;
+ uint16 frequency;
+ uint8 _regOffset;
+ uint8 _flags;
+ uint8 _ssg1;
+ uint8 _ssg2;
+
+ const uint8 _chanNum;
+ const uint8 _keyNum;
+ const uint8 _part;
+
+ TownsPC98_OpnDriver *_drv;
+ TownsPC98_OpnOperator **_opr;
+ uint16 _frqTemp;
+
+ const ControlEventFunc *controlEvents;
+};
+
+class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel {
+public:
+ TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
+ uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
+ ~TownsPC98_OpnChannelSSG() {}
+ void init();
+
+ void processEvents();
+ void processFrequency();
+
+ void keyOn();
+ void keyOff();
+ void loadData(uint8 *data);
+
+private:
+ void opn_SSG_UNK(uint8 a);
+};
+
+
+class TownsPC98_OpnDriver : public Audio::AudioStream {
+friend class TownsPC98_OpnChannel;
+friend class TownsPC98_OpnChannelSSG;
+public:
+ enum OpnType {
+ OD_TOWNS,
+ OD_TYPE26,
+ OD_TYPE86
+ };
+
+ TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type);
+ ~TownsPC98_OpnDriver();
+
+ bool init();
+ void loadData(uint8 *data, bool loadPaused = false);
+ void reset();
+ void fadeOut();
+
+ void pause() { _playing = false; }
+ void cont() { _playing = true; }
+
+ void callback();
+ void nextTick(int16 *buffer, uint32 bufferSize);
+
+ bool looping() { return _looping == _updateChannelsFlag ? true : false; }
+
+ // AudioStream interface
+ int inline readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _mixer->getOutputRate(); }
+
+protected:
+ void generateTables();
+
+ TownsPC98_OpnChannel **_channels;
+ TownsPC98_OpnChannelSSG **_ssgChannels;
+ //TownsPC98_OpnChannel *_adpcmChannel;
+
+ void setTempo(uint8 tempo);
+
+ void lock() { _mutex.lock(); }
+ void unlock() { _mutex.unlock(); }
+
+ Audio::Mixer *_mixer;
+ Common::Mutex _mutex;
+ Audio::SoundHandle _soundHandle;
+
+ const uint8 *_opnCarrier;
+ const uint8 *_opnFreqTable;
+ const uint8 *_opnFxCmdLen;
+ const uint8 *_opnLvlPresets;
+
+ uint8 *_oprRates;
+ uint8 *_oprRateshift;
+ uint8 *_oprAttackDecay;
+ uint32 *_oprFrq;
+ uint32 *_oprSinTbl;
+ int32 *_oprLevelOut;
+ int32 *_oprDetune;
+
+ uint8 *_trackData;
+ uint8 *_patches;
+
+ uint8 _cbCounter;
+ uint8 _updateChannelsFlag;
+ uint8 _finishedChannelsFlag;
+ uint16 _tempo;
+ bool _playing;
+ bool _fading;
+ uint8 _looping;
+ uint32 _tickCounter;
+
+ bool _updateEnvelopes;
+ int _ssgFlag;
+
+ int32 _samplesTillCallback;
+ int32 _samplesTillCallbackRemainder;
+ int32 _samplesPerCallback;
+ int32 _samplesPerCallbackRemainder;
+
+ const int _numChan;
+ const int _numSSG;
+ const bool _hasADPCM;
+ const bool _hasStereo;
+
+ double _baserate;
+ static const uint8 _drvTables[];
+ static const uint32 _adtStat[];
+ bool _ready;
+};
+
+TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
+ uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
+ _part(prt), _idFlag(id) {
+
+ _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _ssg1 = _ssg2 = 0;
+ _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = 0;
+ _frqLSB = 0;
+ _protect = _updateEnvelopes = false;
+ _enableLeft = _enableRight = true;
+ _dataPtr = 0;
+ _ptchWhlModInitVal = _ptchWhlModCurVal = 0;
+ frequency = _frqTemp = 0;
+ memset(&_feedbuf, 0, sizeof(int) * 3);
+ _opr = 0;
+}
+
+TownsPC98_OpnChannel::~TownsPC98_OpnChannel() {
+ if (_opr) {
+ for (int i = 0; i < 4; i++)
+ delete _opr[i];
+ delete [] _opr;
+ }
+}
+
+void TownsPC98_OpnChannel::init() {
+
+ _opr = new TownsPC98_OpnOperator*[4];
+ for (int i = 0; i < 4; i++)
+ _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift,
+ _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);
+
+ #define Control(x) &TownsPC98_OpnChannel::control_##x
+ static const ControlEventFunc ctrlEvents[] = {
+ Control(f0_setPatch),
+ Control(f1_presetOutputLevel),
+ Control(f2_setKeyOffTime),
+ Control(f3_setFreqLSB),
+ Control(f4_setOutputLevel),
+ Control(f5_setTempo),
+ Control(f6_repeatSection),
+ Control(f7_setupPitchWheel),
+ Control(f8_togglePitchWheel),
+ Control(dummy),
+ Control(fa_writeReg),
+ Control(fb_incOutLevel),
+ Control(fc_decOutLevel),
+ Control(fd_jump),
+ Control(dummy),
+ Control(ff_endOfTrack)
+ };
+ #undef Control
+
+ controlEvents = ctrlEvents;
+}
+
+void TownsPC98_OpnChannel::keyOff() {
+ // all operators off
+ uint8 value = _keyNum & 0x0f;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+ _flags |= CHS_KEYOFF;
+}
+
+void TownsPC98_OpnChannel::keyOn() {
+ // all operators on
+ uint8 value = _keyNum | 0xf0;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+}
+
+void TownsPC98_OpnChannel::loadData(uint8 *data) {
+ _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT;
+ _ticksLeft = 1;
+ _dataPtr = data;
+ _totalLevel = 0x7F;
+
+ uint8 *src_b = _dataPtr;
+ int loop = 1;
+ uint8 cmd = 0;
+ while (loop) {
+ if (loop == 1) {
+ cmd = *src_b++;
+ if (cmd < 0xf0) {
+ src_b++;
+ loop = 1;
+ } else {
+ if (cmd == 0xff) {
+ loop = *src_b ? 2 : 0;
+ if (READ_LE_UINT16(src_b))
+ _drv->_looping |= _idFlag;
+ } else if (cmd == 0xf6) {
+ loop = 3;
+ } else {
+ loop = 2;
+ }
+ }
+ } else if (loop == 2) {
+ src_b += _drv->_opnFxCmdLen[cmd - 240];
+ loop = 1;
+ } else if (loop == 3) {
+ src_b[0] = src_b[1];
+ src_b += 4;
+ loop = 1;
+ }
+ }
+}
+
+void TownsPC98_OpnChannel::processEvents() {
+ if (_flags & CHS_EOT)
+ return;
+
+ if (_protect == false && _ticksLeft == _keyOffTime)
+ keyOff();
+
+ if (--_ticksLeft)
+ return;
+
+ if (_protect == false)
+ keyOff();
+
+ uint8 cmd = 0;
+ bool loop = true;
+
+ while (loop) {
+ cmd = *_dataPtr++;
+ if (cmd < 0xf0)
+ loop = false;
+ else if (!processControlEvent(cmd))
+ return;
+ }
+
+ uint8 para = *_dataPtr++;
+
+ if (cmd == 0x80) {
+ keyOff();
+ _protect = false;
+ } else {
+ keyOn();
+
+ if (_protect == false || cmd != _frqBlockMSB)
+ _flags |= CHS_RECALCFREQ;
+
+ _protect = (para & 0x80) ? true : false;
+ _frqBlockMSB = cmd;
+ }
+
+ _ticksLeft = para & 0x7f;
+}
+
+void TownsPC98_OpnChannel::processFrequency() {
+ if (_flags & CHS_RECALCFREQ) {
+ uint8 block = (_frqBlockMSB & 0x70) >> 1;
+ uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f];
+ frequency = (bfreq + _frqLSB) | (block << 8);
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ if (_flags & CHS_KEYOFF) {
+ _ptchWhlModCurVal = _ptchWhlModInitVal;
+ _ptchWhlCurDelay += _ptchWhlInitDelayLo;
+ }
+
+ _ptchWhlDurLeft = (_ptchWhlDuration >> 1);
+ _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
+ }
+
+ if (!(_flags & CHS_PITCHWHEELOFF)) {
+ if (--_ptchWhlCurDelay)
+ return;
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ frequency += _ptchWhlModCurVal;
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ if(!--_ptchWhlDurLeft) {
+ _ptchWhlDurLeft = _ptchWhlDuration;
+ _ptchWhlModCurVal = -_ptchWhlModCurVal;
+ }
+ }
+}
+
+bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) {
+ uint8 para = *_dataPtr++;
+ return (this->*controlEvents[cmd & 0x0f])(para);
+}
+
+void TownsPC98_OpnChannel::setOutputLevel() {
+ uint8 outopr = _drv->_opnCarrier[_algorithm];
+ uint8 reg = 0x40 + _regOffset;
+
+ for (int i = 0; i < 4; i++) {
+ if (outopr & 1)
+ writeReg(reg, _totalLevel);
+ outopr >>= 1;
+ reg += 4;
+ }
+}
+
+void TownsPC98_OpnChannel::fadeStep() {
+ _totalLevel += 3;
+ if (_totalLevel > 0x7f)
+ _totalLevel = 0x7f;
+ setOutputLevel();
+}
+
+void TownsPC98_OpnChannel::reset() {
+ for (int i = 0; i < 4; i++)
+ _opr[i]->reset();
+
+ _updateEnvelopes = false;
+ _enableLeft = _enableRight = true;
+ memset(&_feedbuf, 0, sizeof(int) * 3);
+}
+
+void TownsPC98_OpnChannel::updateEnv() {
+ for (int i = 0; i < 4 ; i++)
+ _opr[i]->updatePhaseIncrement();
+}
+
+void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) {
+ int phbuf1, phbuf2, output;
+ phbuf1 = phbuf2 = output = 0;
+
+ switch (_algorithm) {
+ case 0:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ *del = 0;
+ _opr[1]->generateOutput(phbuf1, 0, *del);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ break;
+ case 1:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ _opr[1]->generateOutput(0, 0, phbuf1);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = phbuf1;
+ break;
+ case 2:
+ _opr[0]->generateOutput(0, feed, phbuf2);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ _opr[1]->generateOutput(0, 0, phbuf1);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = phbuf1;
+ break;
+ case 3:
+ _opr[0]->generateOutput(0, feed, phbuf2);
+ _opr[2]->generateOutput(0, 0, *del);
+ _opr[1]->generateOutput(phbuf2, 0, phbuf1);
+ _opr[3]->generateOutput(*del, 0, output);
+ *del = phbuf1;
+ break;
+ case 4:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(0, 0, phbuf2);
+ _opr[1]->generateOutput(phbuf1, 0, output);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = 0;
+ break;
+ case 5:
+ *del = feed[1];
+ _opr[0]->generateOutput(-1, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, output);
+ _opr[1]->generateOutput(*del, 0, output);
+ _opr[3]->generateOutput(*del, 0, output);
+ break;
+ case 6:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(0, 0, output);
+ _opr[1]->generateOutput(phbuf1, 0, output);
+ _opr[3]->generateOutput(0, 0, output);
+ *del = 0;
+ break;
+ case 7:
+ _opr[0]->generateOutput(0, feed, output);
+ _opr[2]->generateOutput(0, 0, output);
+ _opr[1]->generateOutput(0, 0, output);
+ _opr[3]->generateOutput(0, 0, output);
+ *del = 0;
+ break;
+ };
+
+ if (_enableLeft) {
+ int l = output + leftSample;
+ if (l > 32767)
+ l = 32767;
+ if (l < -32767)
+ l = -32767;
+ leftSample = (int16) l;
+ }
+
+ if (_enableRight) {
+ int r = output + rightSample;
+ if (r > 32767)
+ r = 32767;
+ if (r < -32767)
+ r = -32767;
+ rightSample = (int16) r;
+ }
+}
+
+void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {
+ uint8 h = regAdress & 0xf0;
+ uint8 l = (regAdress & 0x0f);
+ static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
+ uint8 o = oprOrdr[(l - _regOffset) >> 2];
+
+ switch (h) {
+ case 0x00:
+ // ssg
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ case 0x10:
+ // adpcm
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ case 0x20:
+ if (l == 8) {
+ // Key on/off
+ for (int i = 0; i < 4; i++) {
+ if ((value >> (4 + i)) & 1)
+ _opr[i]->keyOn();
+ else
+ _opr[i]->keyOff();
+ }
+ } else if (l == 2) {
+ // LFO
+ warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)");
+ } else if (l == 7) {
+ // Timers; Ch 3/6 special mode
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)");
+ } else if (l == 4 || l == 5) {
+ // Timer A
+ warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)");
+ } else if (l == 6) {
+ // Timer B
+ warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)");
+ } else if (l == 10 || l == 11) {
+ // DAC
+ warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)");
+ }
+ break;
+
+ case 0x30:
+ // detune, multiple
+ _opr[o]->detune((value >> 4) & 7);
+ _opr[o]->multiple(value & 0x0f);
+ _updateEnvelopes = true;
+ break;
+
+ case 0x40:
+ // total level
+ _opr[o]->totalLevel(value & 0x7f);
+ break;
+
+ case 0x50:
+ // rate scaling, attack rate
+ _opr[o]->attackRate(value & 0x1f);
+ if (_opr[o]->scaleRate(value >> 6))
+ _updateEnvelopes = true;
+ break;
+
+ case 0x60:
+ // first decay rate, amplitude modulation
+ _opr[o]->decayRate(value & 0x1f);
+ if (value & 0x80)
+ warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)");
+
+ break;
+
+ case 0x70:
+ // secondary decay rate
+ _opr[o]->sustainRate(value & 0x1f);
+ break;
+
+ case 0x80:
+ // secondary amplitude, release rate;
+ _opr[o]->sustainLevel(value >> 4);
+ _opr[o]->releaseRate(value & 0x0f);
+ break;
+
+ case 0x90:
+ // ssg
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+
+ case 0xa0:
+ // frequency
+ l -= _regOffset;
+ if (l == 0) {
+ _frqTemp = (_frqTemp & 0xff00) | value;
+ _updateEnvelopes = true;
+ for (int i = 0; i < 4; i++)
+ _opr[i]->frequency(_frqTemp);
+ } else if (l == 4) {
+ _frqTemp = (_frqTemp & 0xff) | (value << 8);
+ } else if (l == 8) {
+ // Ch 3/6 special mode frq
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
+ } else if (l == 12) {
+ // Ch 3/6 special mode frq
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
+ }
+ break;
+
+ case 0xb0:
+ l -= _regOffset;
+ if (l == 0) {
+ // feedback, _algorithm
+ _opr[0]->feedbackLevel((value >> 3) & 7);
+ _opr[1]->feedbackLevel(0);
+ _opr[2]->feedbackLevel(0);
+ _opr[3]->feedbackLevel(0);
+ } else if (l == 4) {
+ // stereo, LFO sensitivity
+ _enableLeft = value & 0x80 ? true : false;
+ _enableRight = value & 0x40 ? true : false;
+ uint8 ams = (value & 0x3F) >> 3;
+ if (ams)
+ warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)");
+ uint8 fms = value & 3;
+ if (fms)
+ warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)");
+ }
+ break;
+
+ default:
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ }
+}
+
+bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) {
+ _instrID = para;
+ uint8 reg = _regOffset + 0x80;
+
+ for (int i = 0; i < 4; i++) {
+ // set release rate for each operator
+ writeReg(reg, 0x0f);
+ reg += 4;
+ }
+
+ const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5);
+ reg = _regOffset + 0x30;
+
+ // write registers 0x30 to 0x8f
+ for (int i = 0; i < 6; i++) {
+ writeReg(reg, tptr[0]);
+ reg += 4;
+ writeReg(reg, tptr[2]);
+ reg += 4;
+ writeReg(reg, tptr[1]);
+ reg += 4;
+ writeReg(reg, tptr[3]);
+ reg += 4;
+ tptr += 4;
+ }
+
+ reg = _regOffset + 0xB0;
+ _algorithm = tptr[0] & 7;
+ // set feedback and algorithm
+ writeReg(reg, tptr[0]);
+
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) {
+ if (_drv->_fading)
+ return true;
+
+ _totalLevel = _drv->_opnLvlPresets[para];
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) {
+ _keyOffTime = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) {
+ _frqLSB = (int8) para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) {
+ if (_drv->_fading)
+ return true;
+
+ _totalLevel = para;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) {
+ _drv->setTempo(para);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) {
+ _dataPtr--;
+ _dataPtr[0]--;
+
+ if (*_dataPtr) {
+ // repeat section until counter has reached zero
+ _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2);
+ } else {
+ // reset counter, advance to next section
+ _dataPtr[0] = _dataPtr[1];
+ _dataPtr += 4;
+ }
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) {
+ _ptchWhlInitDelayLo = _dataPtr[0];
+ _ptchWhlInitDelayHi = para;
+ _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1);
+ _ptchWhlDuration = _dataPtr[3];
+ _dataPtr += 4;
+ _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) {
+ if (para == 0x10) {
+ if (*_dataPtr++) {
+ _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF;
+ } else {
+ _flags |= CHS_PITCHWHEELOFF;
+ }
+ } else {
+ //uint8 skipChannels = para / 36;
+ //uint8 entry = para % 36;
+ //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels];
+ ////// NOT IMPLEMENTED
+ //t->unnamedEntries[entry] = *_dataPtr++;
+ }
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) {
+ writeReg(para, *_dataPtr++);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) {
+ _dataPtr--;
+ if (_drv->_fading)
+ return true;
+
+ uint8 val = (_totalLevel + 3);
+ if (val > 0x7f)
+ val = 0x7f;
+
+ _totalLevel = val;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) {
+ _dataPtr--;
+ if (_drv->_fading)
+ return true;
+
+ int8 val = (int8) (_totalLevel - 3);
+ if (val < 0)
+ val = 0;
+
+ _totalLevel = (uint8) val;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) {
+ uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1);
+ _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_dummy(uint8 para) {
+ _dataPtr--;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) {
+ uint16 val = READ_LE_UINT16(--_dataPtr);
+ if (val) {
+ // loop
+ _dataPtr = _drv->_trackData + val;
+ return true;
+ } else {
+ // quit parsing for active channel
+ --_dataPtr;
+ _flags |= CHS_EOT;
+ _drv->_finishedChannelsFlag |= _idFlag;
+ keyOff();
+ return false;
+ }
+}
+
+bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) {
+ _instrID = para << 4;
+ para = (para >> 3) & 0x1e;
+ if (para)
+ return control_f4_setAlgorithm(para | 0x40);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) {
+ if (!_drv->_fading)
+ _totalLevel = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) {
+ _algorithm = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) {
+ _dataPtr += 5;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) {
+ _dataPtr--;
+ if (_drv->_fading)
+ return true;
+
+ _totalLevel--;
+ if ((int8)_totalLevel < 0)
+ _totalLevel = 0;
+
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) {
+ _dataPtr--;
+ if (_drv->_fading)
+ return true;
+
+ if(_totalLevel + 1 < 0x10)
+ _totalLevel++;
+
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) {
+ uint16 val = READ_LE_UINT16(--_dataPtr);
+ if (val) {
+ // loop
+ _dataPtr = _drv->_trackData + val;
+ return true;
+ } else {
+ // quit parsing for active channel
+ --_dataPtr;
+ _flags |= CHS_EOT;
+ //_finishedChannelsFlag |= _idFlag;
+ keyOff();
+ return false;
+ }
+}
+
+TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
+ uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
+ TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) {
+}
+
+void TownsPC98_OpnChannelSSG::init() {
+ _algorithm = 0x80;
+
+ _opr = new TownsPC98_OpnOperator*[4];
+ for (int i = 0; i < 4; i++)
+ _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift,
+ _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);
+
+ #define Control(x) &TownsPC98_OpnChannelSSG::control_##x
+ static const ControlEventFunc ctrlEventsSSG[] = {
+ Control(f0_setPatchSSG),
+ Control(f1_setTotalLevel),
+ Control(f2_setKeyOffTime),
+ Control(f3_setFreqLSB),
+ Control(f4_setOutputLevel),
+ Control(f5_setTempo),
+ Control(f6_repeatSection),
+ Control(f7_setupPitchWheel),
+ Control(f8_togglePitchWheel),
+ Control(f9_unkSSG),
+ Control(fa_writeReg),
+ Control(fb_incOutLevelSSG),
+ Control(fc_decOutLevelSSG),
+ Control(fd_jump),
+ Control(dummy),
+ Control(ff_endOfTrackSSG)
+ };
+ #undef Control
+
+ controlEvents = ctrlEventsSSG;
+}
+
+void TownsPC98_OpnChannelSSG::processEvents() {
+ if (_flags & CHS_EOT)
+ return;
+
+ _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0;
+
+ if (_protect == false && _ticksLeft == _keyOffTime)
+ keyOff();
+
+ if (--_ticksLeft)
+ return;
+
+ if (_protect == false)
+ keyOff();
+
+ uint8 cmd = 0;
+ bool loop = true;
+
+ while (loop) {
+ cmd = *_dataPtr++;
+ if (cmd < 0xf0)
+ loop = false;
+ else if (!processControlEvent(cmd))
+ return;
+ }
+
+ uint8 para = *_dataPtr++;
+
+ if (cmd == 0x80) {
+ keyOff();
+ _protect = false;
+ } else {
+ keyOn();
+
+ if (_protect == false || cmd != _frqBlockMSB)
+ _flags |= CHS_RECALCFREQ;
+
+ _protect = (para & 0x80) ? true : false;
+ _frqBlockMSB = cmd;
+ }
+
+ _ticksLeft = para & 0x7f;
+
+ if (!(_flags & CHS_SSG)) {
+
+ }
+}
+
+void TownsPC98_OpnChannelSSG::processFrequency() {
+ if (_flags & CHS_RECALCFREQ) {
+ uint8 block = (_frqBlockMSB & 0x70) >> 1;
+ uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f];
+ frequency = (bfreq + _frqLSB) | (block << 8);
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ if (_flags & CHS_KEYOFF) {
+ _ptchWhlModCurVal = _ptchWhlModInitVal;
+ _ptchWhlCurDelay += _ptchWhlInitDelayLo;
+ }
+
+ _ptchWhlDurLeft = (_ptchWhlDuration >> 1);
+ _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
+ }
+
+ if (!(_flags & CHS_PITCHWHEELOFF)) {
+ if (--_ptchWhlCurDelay)
+ return;
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ frequency += _ptchWhlModCurVal;
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ if(!--_ptchWhlDurLeft) {
+ _ptchWhlDurLeft = _ptchWhlDuration;
+ _ptchWhlModCurVal = -_ptchWhlModCurVal;
+ }
+ }
+}
+
+void TownsPC98_OpnChannelSSG::keyOff() {
+ // all operators off
+ uint8 value = _keyNum & 0x0f;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+ _flags |= CHS_KEYOFF;
+}
+
+void TownsPC98_OpnChannelSSG::keyOn() {
+ // all operators on
+ uint8 value = _keyNum | 0xf0;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+}
+
+void TownsPC98_OpnChannelSSG::loadData(uint8 *data) {
+ _drv->_ssgFlag = (_flags & CHS_SSG) ? -1 : 0;
+ opn_SSG_UNK(0);
+ TownsPC98_OpnChannel::loadData(data);
+ _algorithm = 0x80;
+}
+
+void TownsPC98_OpnChannelSSG::opn_SSG_UNK(uint8 a) {
+ _ssg1 = a;
+ uint16 h = (_totalLevel + 1) * a;
+ if ((h >> 8) == _ssg2)
+ return;
+ _ssg2 = (h >> 8);
+ writeReg(8 + _regOffset, _ssg2);
+}
+
+TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) :
+ _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0), _ssgChannels(0),
+ _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84),
+ _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) ,
+ _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0),
+ _oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F),
+ _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false),
+ _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false),
+ _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) {
+ setTempo(84);
+ _baserate = (3579545.0 / (double)getRate()) / 144.0;
+}
+
+TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {
+ _mixer->stopHandle(_soundHandle);
+
+ if (_channels) {
+ for (int i = 0; i < _numChan; i++)
+ delete _channels[i];
+ delete [] _channels;
+ }
+
+ if (_ssgChannels) {
+ for (int i = 0; i < _numSSG; i++)
+ delete _ssgChannels[i];
+ delete [] _ssgChannels;
+ }
+
+ delete [] _oprRates;
+ delete [] _oprRateshift;
+ delete [] _oprFrq;
+ delete [] _oprAttackDecay;
+ delete [] _oprSinTbl;
+ delete [] _oprLevelOut;
+ delete [] _oprDetune;
+}
+
+bool TownsPC98_OpnDriver::init() {
+ if (_ready) {
+ reset();
+ return true;
+ }
+
+ generateTables();
+
+ if (_channels) {
+ for (int i = 0; i < _numChan; i++) {
+ if (_channels[i])
+ delete _channels[i];
+ }
+ delete [] _channels;
+ }
+ _channels = new TownsPC98_OpnChannel*[_numChan];
+ for (int i = 0; i < _numChan; i++) {
+ int ii = i * 6;
+ _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1],
+ _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
+ _channels[i]->init();
+ }
+
+ if (_ssgChannels) {
+ for (int i = 0; i < _numSSG; i++) {
+ if (_ssgChannels[i])
+ delete _ssgChannels[i];
+ }
+ delete [] _ssgChannels;
+ }
+ if (_numSSG) {
+ _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG];
+ for (int i = 0; i < _numSSG; i++) {
+ int ii = i * 6;
+ _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
+ _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
+ _ssgChannels[i]->init();
+ }
+ }
+
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType,
+ &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
+
+ _ready = true;
+ return true;
+}
+
+int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples) {
+ memset(buffer, 0, sizeof(int16) * numSamples);
+ int32 samplesLeft = numSamples >> 1;
+ while (samplesLeft) {
+ if (!_samplesTillCallback) {
+ callback();
+ _samplesTillCallback = _samplesPerCallback;
+ _samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
+ if (_samplesTillCallbackRemainder >= _tempo) {
+ _samplesTillCallback++;
+ _samplesTillCallbackRemainder -= _tempo;
+ }
+ }
+
+ int32 render = MIN(samplesLeft, _samplesTillCallback);
+ samplesLeft -= render;
+ _samplesTillCallback -= render;
+
+ nextTick(buffer, render);
+
+ for (int i = 0; i < render; ++i) {
+ buffer[i << 1] <<= 2;
+ buffer[(i << 1) + 1] <<= 2;
+ }
+
+ buffer += (render << 1);
+ }
+
+ return numSamples;
+}
+
+void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) {
+ if (!_ready) {
+ warning("TownsPC98_OpnDriver: Driver must be initialized before loading data");
+ return;
+ }
+
+ if (!data) {
+ warning("TownsPC98_OpnDriver: Invalid music file data");
+ return;
+ }
+
+ lock();
+ _trackData = data;
+
+ reset();
+
+ uint8 *src_a = data;
+
+ for (uint8 i = 0; i < 3; i++) {
+ _channels[i]->loadData(data + READ_LE_UINT16(src_a));
+ src_a += 2;
+ }
+
+ for (int i = 0; i < _numSSG; i++) {
+ _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a));
+ src_a += 2;
+ }
+
+ for (uint8 i = 3; i < _numChan; i++) {
+ _channels[i]->loadData(data + READ_LE_UINT16(src_a));
+ src_a += 2;
+ }
+
+ if (_hasADPCM) {
+ //_adpcmChannel->loadData(data + READ_LE_UINT16(src_a));
+ src_a += 2;
+ }
+
+ _ssgFlag = 0;
+
+ _patches = src_a + 4;
+ _cbCounter = 4;
+ _finishedChannelsFlag = 0;
+
+ // AH 0x17
+ unlock();
+ _playing = (loadPaused ? false : true);
+}
+
+void TownsPC98_OpnDriver::reset() {
+ for (int i = 0; i < (_numChan); i++)
+ _channels[i]->reset();
+ for (int i = 0; i < (_numSSG); i++)
+ _ssgChannels[i]->reset();
+
+ _playing = _fading = false;
+ _looping = 0;
+ _tickCounter = 0;
+}
+
+void TownsPC98_OpnDriver::fadeOut() {
+ if (!_playing)
+ return;
+
+ _fading = true;
+
+ for (int i = 0; i < 20; i++) {
+ lock();
+ uint32 dTime = _tickCounter + 2;
+ for (int j = 0; j < _numChan; j++) {
+ if (_updateChannelsFlag & _channels[j]->_idFlag)
+ _channels[j]->fadeStep();
+ }
+ for (int j = 0; j < _numSSG; j++)
+ _ssgChannels[j]->fadeStep();
+
+ unlock();
+
+ while (_playing) {
+ if (_tickCounter >= dTime)
+ break;
+ }
+ }
+
+ _fading = false;
+
+ reset();
+}
+
+void TownsPC98_OpnDriver::callback() {
+ if (!_playing || --_cbCounter)
+ return;
+
+ _cbCounter = 4;
+ _tickCounter++;
+
+ lock();
+
+ for (int i = 0; i < _numChan; i++) {
+ if (_updateChannelsFlag & _channels[i]->_idFlag) {
+ _channels[i]->processEvents();
+ _channels[i]->processFrequency();
+ }
+ }
+
+ if (_numSSG) {
+ for (int i = 0; i < _numSSG; i++) {
+ _ssgChannels[i]->processEvents();
+ _ssgChannels[i]->processFrequency();
+ }
+ }
+
+ _ssgFlag = 0;
+
+ unlock();
+
+ if (_finishedChannelsFlag == _updateChannelsFlag)
+ reset();
+}
+
+void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) {
+ if (!_playing)
+ return;
+
+ for (int i = 0; i < _numChan ; i++) {
+ if (_channels[i]->_updateEnvelopes) {
+ _channels[i]->_updateEnvelopes = false;
+ _channels[i]->updateEnv();
+ }
+
+ for (uint32 ii = 0; ii < bufferSize ; ii++)
+ _channels[i]->generateOutput(buffer[ii * 2],
+ buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf);
+ }
+
+ for (int i = 0; i < _numSSG ; i++) {
+ if (_ssgChannels[i]->_updateEnvelopes) {
+ _ssgChannels[i]->_updateEnvelopes = false;
+ _ssgChannels[i]->updateEnv();
+ }
+
+ for (uint32 ii = 0; ii < bufferSize ; ii++)
+ _ssgChannels[i]->generateOutput(buffer[ii * 2],
+ buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf);
+ }
+}
+
+void TownsPC98_OpnDriver::generateTables() {
+ delete [] _oprRates;
+ _oprRates = new uint8[128];
+ memset(_oprRates, 0x90, 32);
+ uint8 *dst = (uint8*) _oprRates + 32;
+ for (int i = 0; i < 48; i += 4)
+ WRITE_BE_UINT32(dst + i, 0x00081018);
+ dst += 48;
+ for (uint8 i = 0; i < 16; i ++) {
+ uint8 v = (i < 12) ? i : 12;
+ *dst++ = ((4 + v) << 3);
+ }
+ memset(dst, 0x80, 32);
+
+ delete [] _oprRateshift;
+ _oprRateshift = new uint8[128];
+ memset(_oprRateshift, 0, 128);
+ dst = (uint8*) _oprRateshift + 32;
+ for (int i = 11; i; i--) {
+ memset(dst, i, 4);
+ dst += 4;
+ }
+
+ delete [] _oprFrq;
+ _oprFrq = new uint32[0x1000];
+ for (uint32 i = 0; i < 0x1000; i++)
+ _oprFrq[i] = (uint32)(_baserate * (double)(i << 11));
+
+ delete [] _oprAttackDecay;
+ _oprAttackDecay = new uint8[152];
+ memset(_oprAttackDecay, 0, 152);
+ for (int i = 0; i < 36; i++)
+ WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]);
+
+ delete [] _oprSinTbl;
+ _oprSinTbl = new uint32[1024];
+ for (int i = 0; i < 1024; i++) {
+ double val = sin((double) (((i << 1) + 1) * PI / 1024.0));
+ double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0;
+ int32 i_dcb = (int32)(2.0 * d_dcb);
+ i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1);
+ _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1);
+ }
+
+ delete [] _oprLevelOut;
+ _oprLevelOut = new int32[0x1a00];
+ for (int i = 0; i < 256; i++) {
+ double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i)));
+ int32 val_int = ((int32) val) >> 4;
+ _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2;
+ _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1];
+ for (int ii = 1; ii < 13; ii++) {
+ _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii;
+ _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)];
+ }
+ }
+
+ uint8 *dtt = new uint8[128];
+ memset(dtt, 0, 36);
+ memset(dtt + 36, 1, 8);
+ memcpy(dtt + 44, _drvTables + 144, 84);
+
+ delete [] _oprDetune;
+ _oprDetune = new int32[256];
+ for (int i = 0; i < 128; i++) {
+ _oprDetune[i] = (int32) ((double)dtt[i] * _baserate * 64.0);
+ _oprDetune[i + 128] = -_oprDetune[i];
+ }
+
+ delete [] dtt;
+}
+
+void TownsPC98_OpnDriver::setTempo(uint8 tempo) {
+ _tempo = tempo;
+ _samplesPerCallback = getRate() / _tempo;
+ _samplesPerCallbackRemainder = getRate() % _tempo;
+}
+
+const uint8 TownsPC98_OpnDriver::_drvTables[] = {
+ // channel presets
+ 0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x80, 0x01, 0x01, 0x00, 0x02,
+ 0x02, 0x80, 0x02, 0x02, 0x00, 0x04,
+ 0x00, 0x80, 0x03, 0x04, 0x01, 0x08,
+ 0x01, 0x80, 0x04, 0x05, 0x01, 0x10,
+ 0x02, 0x80, 0x05, 0x06, 0x01, 0x20,
+
+ // control event size
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05,
+ 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02,
+
+ // fmt level presets
+ 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38,
+ 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18,
+ 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90,
+
+ // carriers
+ 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F,
+
+ // frequencies
+ 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02,
+ 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03,
+ 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04,
+ 0x00, 0x00, 0x00, 0x00,
+
+ // unused
+ 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+
+ // detune
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
+ 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+ 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
+ 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05,
+ 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14,
+ 0x16, 0x16, 0x16, 0x16,
+
+ // pc98 level presets
+ 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25,
+ 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10,
+ 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90
+};
+
+const uint32 TownsPC98_OpnDriver::_adtStat[] = {
+ 0x00010001, 0x00010001, 0x00010001, 0x01010001,
+ 0x00010101, 0x00010101, 0x00010101, 0x01010101,
+ 0x01010101, 0x01010101, 0x01010102, 0x01010102,
+ 0x01020102, 0x01020102, 0x01020202, 0x01020202,
+ 0x02020202, 0x02020202, 0x02020204, 0x02020204,
+ 0x02040204, 0x02040204, 0x02040404, 0x02040404,
+ 0x04040404, 0x04040404, 0x04040408, 0x04040408,
+ 0x04080408, 0x04080408, 0x04080808, 0x04080808,
+ 0x08080808, 0x08080808, 0x10101010, 0x10101010
+};
+
SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), _sfxFileData(0),
_sfxFileIndex((uint)-1), _sfxWDTable(0), _sfxBTTable(0), _parser(0) {
- _driver = new SoundTowns_EuphonyDriver(_mixer);
+ _driver = new Towns_EuphonyDriver(_mixer);
int ret = open();
if (ret != MERR_ALREADY_OPEN && ret != 0)
error("couldn't open midi driver");
@@ -1124,7 +2797,7 @@ void SoundTowns::playTrack(uint8 track) {
return;
track -= 2;
- const int32 * const tTable = (const int32 * const) cdaData();
+ const int32 *const tTable = (const int32 *const) cdaData();
int tTableIndex = 3 * track;
int trackNum = (int) READ_LE_UINT32(&tTable[tTableIndex + 2]);
@@ -1195,12 +2868,12 @@ void SoundTowns::playSoundEffect(uint8 track) {
}
}
- uint8 * fileBody = _sfxFileData + 0x01b8;
+ uint8 *fileBody = _sfxFileData + 0x01b8;
int32 offset = (int32)READ_LE_UINT32(_sfxFileData + (track - 0x0b) * 4);
if (offset == -1)
return;
- uint32 * sfxHeader = (uint32*)(fileBody + offset);
+ uint32 *sfxHeader = (uint32*)(fileBody + offset);
uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader);
uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]);
@@ -1220,7 +2893,7 @@ void SoundTowns::playSoundEffect(uint8 track) {
} else if (sfxHeaderID == 1) {
Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize);
} else if (_sfxWDTable) {
- uint8 * tgt = sfxPlaybackBuffer;
+ uint8 *tgt = sfxPlaybackBuffer;
uint32 sfx_BtTable_Offset = 0;
uint32 sfx_WdTable_Offset = 0;
uint32 sfx_WdTable_Number = 5;
@@ -1285,7 +2958,7 @@ uint32 SoundTowns::getBaseTempo(void) {
}
bool SoundTowns::loadInstruments() {
- uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
+ uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
if (!twm)
return false;
_driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0);
@@ -1300,11 +2973,11 @@ bool SoundTowns::loadInstruments() {
}
void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
- uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
+ uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
Common::StackLock lock(_mutex);
if (!_parser) {
- _parser = new MidiParser_EuD(_driver->queue());
+ _parser = new Towns_EuphonyParser(_driver->queue());
_parser->setMidiDriver(this);
_parser->setTimerRate(getBaseTempo());
}
@@ -1315,7 +2988,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
delete[] twm;
}
-void SoundTowns::onTimer(void * data) {
+void SoundTowns::onTimer(void *data) {
SoundTowns *music = (SoundTowns *)data;
Common::StackLock lock(music->_mutex);
if (music->_parser)
@@ -1356,22 +3029,75 @@ float SoundTowns::semitoneAndSampleRate_to_sampleStep(int8 semiTone, int8 semiTo
return (float) sampleRate * 10.0f * rateshift / outputRate;
}
+SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
+ Sound(vm, mixer), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0) {
+}
+
+SoundPC98::~SoundPC98() {
+ delete[] _musicTrackData;
+ delete[] _sfxTrackData;
+ delete _driver;
+}
+
+bool SoundPC98::init() {
+ _driver = new TownsPC98_OpnDriver(_mixer, TownsPC98_OpnDriver::OD_TYPE26);
+ _sfxTrackData = _vm->resource()->fileData("se.dat", 0);
+ if (!_sfxTrackData)
+ return false;
+ return _driver->init();
+}
+
+void SoundPC98::playTrack(uint8 track) {
+ if (--track >= 56)
+ track -= 55;
+
+ if (track == _lastTrack && _musicEnabled)
+ return;
+
+ haltTrack();
+
+ char musicfile[13];
+ sprintf(musicfile, fileListEntry(0), track);
+ delete[] _musicTrackData;
+ _musicTrackData = _vm->resource()->fileData(musicfile, 0);
+ if (_musicEnabled)
+ _driver->loadData(_musicTrackData);
+
+ _lastTrack = track;
+}
+
+void SoundPC98::haltTrack() {
+ _lastTrack = -1;
+ AudioCD.stop();
+ AudioCD.updateCD();
+ _driver->reset();
+}
+
+void SoundPC98::beginFadeOut() {
+ _driver->fadeOut();
+ haltTrack();
+}
+
+void SoundPC98::playSoundEffect(uint8) {
+ /// TODO ///
+}
+
+
// KYRA 2
-SoundTowns_v2::SoundTowns_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer)
- : Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), /*_driver(0),*/
- _twnTrackData(0) {
+SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
+ Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) {
}
-SoundTowns_v2::~SoundTowns_v2() {
- /*if (_driver)
- delete _driver;*/
- if (_twnTrackData)
- delete[] _twnTrackData;
+SoundTownsPC98_v2::~SoundTownsPC98_v2() {
+ delete[] _musicTrackData;
+ delete _driver;
}
-bool SoundTowns_v2::init() {
- //_driver = new SoundTowns_v2_TwnDriver(_mixer);
+bool SoundTownsPC98_v2::init() {
+ _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ?
+ TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS);
+ _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false;
_vm->checkCD();
// FIXME: While checking for 'track1.XXX(X)' looks like
// a good idea, we should definitely not be doing this
@@ -1384,55 +3110,61 @@ bool SoundTowns_v2::init() {
(Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") ||
Common::File::exists("track1.flac") || Common::File::exists("track1.fla")))
_musicEnabled = 2;
- return true;//_driver->init();
+ return _driver->init();
}
-void SoundTowns_v2::process() {
+void SoundTownsPC98_v2::process() {
AudioCD.updateCD();
}
-void SoundTowns_v2::playTrack(uint8 track) {
+void SoundTownsPC98_v2::playTrack(uint8 track) {
if (track == _lastTrack && _musicEnabled)
return;
- const uint16 * const cdaTracks = (const uint16 * const) cdaData();
+ const uint16 *const cdaTracks = (const uint16 *const) cdaData();
int trackNum = -1;
- for (int i = 0; i < cdaTrackNum(); i++) {
- if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) {
- trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1;
- break;
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
+ for (int i = 0; i < cdaTrackNum(); i++) {
+ if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) {
+ trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1;
+ break;
+ }
}
}
- haltTrack();
+ beginFadeOut();
- // TODO: figure out when to loop and when not for CD Audio
- bool loop = false;
+ char musicfile[13];
+ sprintf(musicfile, fileListEntry(0), track);
+ delete[] _musicTrackData;
+
+ _musicTrackData = _vm->resource()->fileData(musicfile, 0);
+ _driver->loadData(_musicTrackData, true);
if (_musicEnabled == 2 && trackNum != -1) {
- AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0);
+ AudioCD.play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0);
AudioCD.updateCD();
} else if (_musicEnabled) {
- char musicfile[13];
- sprintf(musicfile, fileListEntry(0), track);
- if (_twnTrackData)
- delete[] _twnTrackData;
- _twnTrackData = _vm->resource()->fileData(musicfile, 0);
- //_driver->loadData(_twnTrackData);
+ _driver->cont();
}
_lastTrack = track;
}
-void SoundTowns_v2::haltTrack() {
+void SoundTownsPC98_v2::haltTrack() {
_lastTrack = -1;
AudioCD.stop();
AudioCD.updateCD();
- //_driver->reset();
+ _driver->reset();
}
-int32 SoundTowns_v2::voicePlay(const char *file, bool) {
+void SoundTownsPC98_v2::beginFadeOut() {
+ _driver->fadeOut();
+ haltTrack();
+}
+
+int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) {
static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
int h = 0;
@@ -1443,11 +3175,11 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) {
return 0;
}
- char filename [13];
+ char filename[13];
sprintf(filename, "%s.PCM", file);
- uint8 * data = _vm->resource()->fileData(filename, 0);
- uint8 * src = data;
+ uint8 *data = _vm->resource()->fileData(filename, 0);
+ uint8 *src = data;
uint16 sfxRate = rates[READ_LE_UINT16(src)];
src += 2;
@@ -1500,9 +3232,16 @@ int32 SoundTowns_v2::voicePlay(const char *file, bool) {
return 1;
}
-void SoundTowns_v2::beginFadeOut() {
- //_driver->fadeOut();
- haltTrack();
+void SoundTownsPC98_v2::playSoundEffect(uint8 track) {
+ if (!_useFmSfx)
+ return;
+
+ uint8 *sd = _vm->resource()->fileData("sound.dat", 0);
+
+
+ //TODO
+
+ delete [] sd;
}
} // end of namespace Kyra
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index abdf115c1e..4f577c1d1e 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -1034,6 +1034,9 @@ void KyraEngine_LoK::initStaticResource() {
}
// audio data tables
+ static const char *tIntro98[] = { "intro%d.dat" };
+ static const char *tIngame98[] = { "kyram%d.dat" };
+
static const AudioDataStruct soundData_PC[] = {
{ _soundFilesIntro, _soundFilesIntroSize, 0, 0 },
{ _soundFiles, _soundFilesSize, 0, 0 },
@@ -1045,7 +1048,20 @@ void KyraEngine_LoK::initStaticResource() {
{ _soundFiles, _soundFilesSize, _cdaTrackTable, _cdaTrackTableSize },
{ 0, 0, 0, 0}
};
- _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS;
+
+ static const AudioDataStruct soundData_PC98[] = {
+ { tIntro98, 1, 0, 0 },
+ { tIngame98, 1, 0, 0 },
+ { 0, 0, 0, 0}
+ };
+
+ if (_flags.platform == Common::kPlatformPC)
+ _soundData = soundData_PC;
+ else if (_flags.platform == Common::kPlatformFMTowns)
+ _soundData = soundData_TOWNS;
+ else if (_flags.platform == Common::kPlatformPC98)
+ _soundData = soundData_PC98;
+
}
void KyraEngine_LoK::loadMouseShapes() {
@@ -1243,6 +1259,10 @@ void KyraEngine_HoF::initStaticResource() {
static const char *fmtMusicFileListFinale[] = { "finale%d.twn" };
static const char *fmtMusicFileListIngame[] = { "km%02d.twn" };
+ static const char *pc98MusicFileListIntro[] = { "intro%d.86" };
+ static const char *pc98MusicFileListFinale[] = { "finale%d.86" };
+ static const char *pc98MusicFileListIngame[] = { "km%02d.86" };
+
static const AudioDataStruct soundData_PC[] = {
{ _musicFileListIntro, _musicFileListIntroSize, 0, 0 },
{ _musicFileListIngame, _musicFileListIngameSize, 0, 0},
@@ -1254,7 +1274,19 @@ void KyraEngine_HoF::initStaticResource() {
{ fmtMusicFileListIngame, 1, _cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1 },
{ fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 }
};
- _soundData = (_flags.platform == Common::kPlatformPC) ? soundData_PC : soundData_TOWNS;
+
+ static const AudioDataStruct soundData_PC98[] = {
+ { pc98MusicFileListIntro, 1, 0, 0 },
+ { pc98MusicFileListIngame, 1, 0, 0 },
+ { pc98MusicFileListFinale, 1, 0, 0 }
+ };
+
+ if (_flags.platform == Common::kPlatformPC)
+ _soundData = soundData_PC;
+ else if (_flags.platform == Common::kPlatformFMTowns)
+ _soundData = soundData_TOWNS;
+ else if (_flags.platform == Common::kPlatformPC98)
+ _soundData = soundData_PC98;
// setup sequence data
_sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize);
@@ -1944,12 +1976,26 @@ const char *KyraEngine_MR::_languageExtension[] = {
"TRE",
"TRF",
"TRG"/*,
- "TRI", Italian and Spanish were never included
- "TRS"*/
+ "TRI", Italian and Spanish were never included, the supported fan translations are using
+ "TRS" English/French extensions thus overwriting these languages */
};
const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension);
+const char * const KyraEngine_MR::_mainMenuSpanishFan[] = {
+ "Nueva Partida",
+ "Ver Intro",
+ "Restaurar",
+ "Finalizar"
+};
+
+const char * const KyraEngine_MR::_mainMenuItalianFan[] = {
+ "Nuova Partita",
+ "Introduzione",
+ "Carica una partita",
+ "Esci dal gioco"
+};
+
const KyraEngine_MR::ShapeDesc KyraEngine_MR::_shapeDescs[] = {
{ 57, 91, -31, -82 },
{ 57, 91, -31, -82 },
diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp
index 80b21119ff..0488f17d8f 100644
--- a/engines/m4/assets.cpp
+++ b/engines/m4/assets.cpp
@@ -201,6 +201,7 @@ void SpriteAsset::loadMadsSpriteAsset(M4Engine *vm, Common::SeekableReadStream*
Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3);
SpriteAssetFrame frame;
for (curFrame = 0; curFrame < _frameCount; curFrame++) {
+ frame.stream = 0;
frame.comp = 0;
frameOffset = spriteStream->readUint32LE();
_frameOffsets.push_back(frameOffset);
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index a07a175066..5b8bdab9d6 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -379,8 +379,8 @@ void Converse::loadConversation(const char *convName) {
uint32 header = convS->readUint32LE();
uint32 size;
uint32 chunk;
- uint32 data;
- uint32 i;
+ uint32 data = 0;
+ uint32 i = 0;
ConvEntry* curEntry = NULL;
ConvEntry* replyEntry = NULL;
int32 currentWeightedEntry = -1;
diff --git a/engines/m4/globals.cpp b/engines/m4/globals.cpp
index 12d9a24d37..58c68979d1 100644
--- a/engines/m4/globals.cpp
+++ b/engines/m4/globals.cpp
@@ -75,7 +75,7 @@ bool Kernel::sendTrigger(int32 triggerNum) {
bool Kernel::handleTrigger(int32 triggerNum) {
- printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, triggerNum);
+ printf("betweenRooms = %d; triggerNum = %08X\n", betweenRooms, (uint)triggerNum);
if (betweenRooms)
return true;
@@ -271,11 +271,13 @@ Globals::Globals(M4Engine *vm): _vm(vm) {
}
Globals::~Globals() {
- for(uint32 i = 0; i < _madsVocab.size(); i++)
+ uint32 i;
+
+ for(i = 0; i < _madsVocab.size(); i++)
free(_madsVocab[i]);
_madsVocab.clear();
- for(uint32 i = 0; i < _madsQuotes.size(); i++)
+ for(i = 0; i < _madsQuotes.size(); i++)
free(_madsQuotes[i]);
_madsQuotes.clear();
@@ -351,7 +353,7 @@ void Globals::loadMadsMessagesInfo() {
_vm->res()->toss("messages.dat");
}
-char* Globals::loadMessage(uint32 index) {
+char* Globals::loadMessage(uint index) {
if (index > _madsMessages.size() - 1) {
warning("Invalid message index: %i", index);
return NULL;
diff --git a/engines/m4/globals.h b/engines/m4/globals.h
index a0133db2d6..a80e8bf710 100644
--- a/engines/m4/globals.h
+++ b/engines/m4/globals.h
@@ -177,7 +177,7 @@ public:
void loadMadsMessagesInfo();
uint32 getMessagesSize() { return _madsMessages.size(); }
- char* loadMessage(uint32 index);
+ char* loadMessage(uint index);
};
#define PLAYER_FIELD_LENGTH 40
diff --git a/engines/m4/resource.cpp b/engines/m4/resource.cpp
index 57816b6600..5070a2b79c 100644
--- a/engines/m4/resource.cpp
+++ b/engines/m4/resource.cpp
@@ -310,7 +310,7 @@ const char *MADSResourceManager::getResourceFilename(const char *resourceName) {
Common::SeekableReadStream *MADSResourceManager::loadResource(const char *resourceName, bool loadFlag) {
Common::File hagFile;
- uint32 offset, size;
+ uint32 offset = 0, size = 0;
// If the first character is a '@' then look for an external file
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 1a8ca9c50a..831f1fab8e 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -40,7 +40,10 @@ void PmvPlayer::play(const char *filename) {
_surface = NULL;
_fd = new Common::File();
- _fd->open(filename);
+ if (!_fd->open(filename)) {
+ delete _fd;
+ return;
+ }
uint32 chunkType, chunkSize;
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index cecd0c8968..0c22d40259 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -688,7 +688,7 @@ void Screen::printText(const char *text) {
for (int textPos = 0; textPos < textLen; textPos++) {
- uint c = text[textPos];
+ uint c = ((byte*)text)[textPos];
int charWidth = _font->getCharWidth(c);
if (c == 9) {
@@ -822,6 +822,8 @@ SpriteListItem Screen::getFromSpriteList(int16 index) {
if (((uint) index) > _spriteList.size()) {
SpriteListItem emptyItem;
emptyItem.index = 0;
+ emptyItem.xofs = 0;
+ emptyItem.yofs = 0;
return emptyItem;
} else {
return _spriteList[index - 1];
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
new file mode 100644
index 0000000000..fab92dada9
--- /dev/null
+++ b/engines/parallaction/balloons.cpp
@@ -0,0 +1,456 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "parallaction/graphics.h"
+#include "parallaction/parallaction.h"
+
+namespace Parallaction {
+
+
+#define BALLOON_TRANSPARENT_COLOR_NS 2
+#define BALLOON_TRANSPARENT_COLOR_BR 0
+
+#define BALLOON_TAIL_WIDTH 12
+#define BALLOON_TAIL_HEIGHT 10
+
+
+byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = {
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ },
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
+ }
+};
+
+class BalloonManager_ns : public BalloonManager {
+
+ static int16 _dialogueBalloonX[5];
+
+ struct Balloon {
+ Common::Rect outerBox;
+ Common::Rect innerBox;
+ Graphics::Surface *surface;
+ GfxObj *obj;
+ } _intBalloons[5];
+
+ uint _numBalloons;
+
+ void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
+ int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
+ Balloon *getBalloon(uint id);
+
+ Gfx *_gfx;
+
+public:
+ BalloonManager_ns(Gfx *gfx);
+ ~BalloonManager_ns();
+
+ void freeBalloons();
+ int setLocationBalloon(char *text, bool endGame);
+ int setDialogueBalloon(char *text, uint16 winding, byte textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
+ void setBalloonText(uint id, char *text, byte textColor);
+ int hitTestDialogueBalloon(int x, int y);
+};
+
+int16 BalloonManager_ns::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };
+
+BalloonManager_ns::BalloonManager_ns(Gfx *gfx) : _numBalloons(0), _gfx(gfx) {
+
+}
+
+BalloonManager_ns::~BalloonManager_ns() {
+
+}
+
+
+BalloonManager_ns::Balloon* BalloonManager_ns::getBalloon(uint id) {
+ assert(id < _numBalloons);
+ return &_intBalloons[id];
+}
+
+int BalloonManager_ns::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) {
+ assert(_numBalloons < 5);
+
+ int id = _numBalloons;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ int16 real_h = (winding == -1) ? h : h + 9;
+ balloon->surface = new Graphics::Surface;
+ balloon->surface->create(w, real_h, 1);
+ balloon->surface->fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR_NS);
+
+ Common::Rect r(w, h);
+ balloon->surface->fillRect(r, 0);
+ balloon->outerBox = r;
+
+ r.grow(-borderThickness);
+ balloon->surface->fillRect(r, 1);
+ balloon->innerBox = r;
+
+ if (winding != -1) {
+ // draws tail
+ // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill.
+ winding = (winding == 0 ? 1 : 0);
+ Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);
+ s.moveTo(r.width()/2 - 5, r.bottom - 1);
+ _gfx->blt(s, _resBalloonTail[winding], balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR_NS);
+ }
+
+ _numBalloons++;
+
+ return id;
+}
+
+
+int BalloonManager_ns::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+5, h, winding, 1);
+ Balloon *balloon = &_intBalloons[id];
+
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = x;
+ balloon->obj->y = y;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ return id;
+}
+
+int BalloonManager_ns::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+5, h, winding, 1);
+ Balloon *balloon = &_intBalloons[id];
+
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = _dialogueBalloonX[id];
+ balloon->obj->y = 10;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ if (id > 0) {
+ balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].outerBox.height();
+ }
+
+
+ return id;
+}
+
+void BalloonManager_ns::setBalloonText(uint id, char *text, byte textColor) {
+ Balloon *balloon = getBalloon(id);
+ balloon->surface->fillRect(balloon->innerBox, 1);
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+}
+
+
+int BalloonManager_ns::setLocationBalloon(char *text, bool endGame) {
+
+ int16 w, h;
+
+ _gfx->getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR_NS);
+ Balloon *balloon = &_intBalloons[id];
+ _gfx->drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 5;
+ balloon->obj->y = 5;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_NS;
+
+ return id;
+}
+
+int BalloonManager_ns::hitTestDialogueBalloon(int x, int y) {
+
+ Common::Point p;
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ p.x = x - _intBalloons[i].obj->x;
+ p.y = y - _intBalloons[i].obj->y;
+
+ if (_intBalloons[i].innerBox.contains(p))
+ return i;
+ }
+
+ return -1;
+}
+
+void BalloonManager_ns::freeBalloons() {
+ _gfx->destroyBalloons();
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ _intBalloons[i].obj = 0;
+ _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons
+ }
+
+ _numBalloons = 0;
+}
+
+
+
+
+
+
+
+
+class BalloonManager_br : public BalloonManager {
+
+ struct Balloon {
+ Common::Rect box;
+ Graphics::Surface *surface;
+ GfxObj *obj;
+ } _intBalloons[3];
+
+ uint _numBalloons;
+
+ Frames *_leftBalloon;
+ Frames *_rightBalloon;
+ Disk *_disk;
+ Gfx *_gfx;
+
+ void cacheAnims();
+ void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
+ int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
+ Balloon *getBalloon(uint id);
+ Graphics::Surface *expandBalloon(Frames *data, int frameNum);
+
+
+public:
+ BalloonManager_br(Disk *disk, Gfx *gfx);
+ ~BalloonManager_br();
+
+ void freeBalloons();
+ int setLocationBalloon(char *text, bool endGame);
+ int setDialogueBalloon(char *text, uint16 winding, byte textColor);
+ int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
+ void setBalloonText(uint id, char *text, byte textColor);
+ int hitTestDialogueBalloon(int x, int y);
+};
+
+
+
+BalloonManager_br::Balloon* BalloonManager_br::getBalloon(uint id) {
+ assert(id < _numBalloons);
+ return &_intBalloons[id];
+}
+
+Graphics::Surface *BalloonManager_br::expandBalloon(Frames *data, int frameNum) {
+
+ Common::Rect rect;
+ data->getRect(frameNum, rect);
+
+ rect.translate(-rect.left, -rect.top);
+
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf->create(rect.width(), rect.height(), 1);
+
+ _gfx->unpackBlt(rect, data->getData(frameNum), data->getRawSize(frameNum), surf, 0, BALLOON_TRANSPARENT_COLOR_BR);
+
+ return surf;
+}
+
+int BalloonManager_br::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
+ cacheAnims();
+
+ int id = _numBalloons;
+ Frames *src = 0;
+ int srcFrame = 0;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ if (winding == 0) {
+ src = _leftBalloon;
+ srcFrame = 0;
+ } else
+ if (winding == 1) {
+ src = _rightBalloon;
+ srcFrame = 0;
+ }
+
+ assert(src);
+
+ balloon->surface = expandBalloon(src, srcFrame);
+ src->getRect(srcFrame, balloon->box);
+
+// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = x;
+ balloon->obj->y = y;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
+
+ _numBalloons++;
+
+ return id;
+}
+
+int BalloonManager_br::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
+ cacheAnims();
+
+ int id = _numBalloons;
+ Frames *src = 0;
+ int srcFrame = 0;
+
+ Balloon *balloon = &_intBalloons[id];
+
+ if (winding == 0) {
+ src = _leftBalloon;
+ srcFrame = id;
+ } else
+ if (winding == 1) {
+ src = _rightBalloon;
+ srcFrame = 0;
+ }
+
+ assert(src);
+
+ balloon->surface = expandBalloon(src, srcFrame);
+ src->getRect(srcFrame, balloon->box);
+
+// drawWrappedText(_vm->_dialogueFont, balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 0;
+ balloon->obj->y = 10;
+ balloon->obj->transparentKey = BALLOON_TRANSPARENT_COLOR_BR;
+
+ if (id > 0) {
+ balloon->obj->y += _intBalloons[id - 1].obj->y + _intBalloons[id - 1].box.height();
+ }
+
+ _numBalloons++;
+
+ return id;
+}
+
+void BalloonManager_br::setBalloonText(uint id, char *text, byte textColor) { }
+
+int BalloonManager_br::setLocationBalloon(char *text, bool endGame) {
+/*
+ int16 w, h;
+
+ getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
+
+ int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR);
+ Balloon *balloon = &_intBalloons[id];
+ drawWrappedText(_vm->_dialogueFont, balloon->surface, text, 0, MAX_BALLOON_WIDTH);
+
+ // TODO: extract some text to make a name for obj
+ balloon->obj = _gfx->registerBalloon(new SurfaceToFrames(balloon->surface), 0);
+ balloon->obj->x = 5;
+ balloon->obj->y = 5;
+*/
+ return 0;
+}
+
+int BalloonManager_br::hitTestDialogueBalloon(int x, int y) {
+
+ Common::Point p;
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ p.x = x - _intBalloons[i].obj->x;
+ p.y = y - _intBalloons[i].obj->y;
+
+ if (_intBalloons[i].box.contains(p))
+ return i;
+ }
+
+ return -1;
+}
+
+void BalloonManager_br::freeBalloons() {
+ _gfx->destroyBalloons();
+
+ for (uint i = 0; i < _numBalloons; i++) {
+ _intBalloons[i].obj = 0;
+ _intBalloons[i].surface = 0; // no need to delete surface, since it is done by destroyBalloons
+ }
+
+ _numBalloons = 0;
+}
+
+void BalloonManager_br::cacheAnims() {
+ if (!_leftBalloon) {
+ _leftBalloon = _disk->loadFrames("fumetto.ani");
+ _rightBalloon = _disk->loadFrames("fumdx.ani");
+ }
+}
+
+BalloonManager_br::BalloonManager_br(Disk *disk, Gfx *gfx) : _numBalloons(0), _disk(disk), _gfx(gfx), _leftBalloon(0), _rightBalloon(0) {
+}
+
+BalloonManager_br::~BalloonManager_br() {
+ delete _leftBalloon;
+ delete _rightBalloon;
+}
+
+void Parallaction::setupBalloonManager() {
+ if (_vm->getGameType() == GType_Nippon) {
+ _balloonMan = new BalloonManager_ns(_vm->_gfx);
+ } else
+ if (_vm->getGameType() == GType_BRA) {
+ _balloonMan = new BalloonManager_br(_vm->_disk, _vm->_gfx);
+ } else {
+ error("Unknown game type");
+ }
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/callables_ns.cpp b/engines/parallaction/callables_ns.cpp
index 68e6a70ffb..7c053715f6 100644
--- a/engines/parallaction/callables_ns.cpp
+++ b/engines/parallaction/callables_ns.cpp
@@ -341,7 +341,7 @@ void Parallaction_ns::_c_endComment(void *param) {
}
_input->waitUntilLeftClick();
- _gfx->freeBalloons();
+ _balloonMan->freeBalloons();
return;
}
@@ -417,6 +417,13 @@ void Parallaction_ns::_c_ridux(void *parm) {
}
void Parallaction_ns::_c_testResult(void *parm) {
+ if (_inTestResult) { // NOTE: _inTestResult has been added because the scripts call _c_testResult multiple times to cope with
+ // the multiple buffering that was used in the original engine. _inTestResult now prevents the engine
+ // from crashing when the scripts are executed.
+ return;
+ }
+ _inTestResult = true;
+
_gfx->updateScreen();
_disk->selectArchive("disk1");
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index 3c90a76f61..f57976594e 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -188,17 +188,15 @@ bool Debugger::Cmd_GfxObjects(int argc, const char **argv) {
const char *objType[] = { "DOOR", "GET", "ANIM" };
DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n"
- "| name | x | y | z | f | type | flag |\n"
+ "| name | x | y | z | f | type | visi |\n"
"+--------------------+-----+-----+-----+-----+--------+--------+\n");
- for (uint i = 0; i < 3; i++) {
- GfxObjList::iterator b = _vm->_gfx->_gfxobjList[i].begin();
- GfxObjList::iterator e = _vm->_gfx->_gfxobjList[i].end();
+ GfxObjList::iterator b = _vm->_gfx->_gfxobjList.begin();
+ GfxObjList::iterator e = _vm->_gfx->_gfxobjList.end();
- for ( ; b != e; b++) {
- GfxObj *obj = *b;
- DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], 6 );
- }
+ for ( ; b != e; b++) {
+ GfxObj *obj = *b;
+ DebugPrintf("|%-20s|%5i|%5i|%5i|%5i|%8s|%8x|\n", obj->getName(), obj->x, obj->y, obj->z, obj->frame, objType[obj->type], obj->isVisible() );
}
DebugPrintf("+--------------------+-----+-----+-----+-----+--------+--------+\n");
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index eb2254cd80..a771f960a9 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -51,8 +51,8 @@ class DialogueManager {
bool _askPassword;
bool isNpc;
- Frames *_questioner;
- Frames *_answerer;
+ GfxObj *_questioner;
+ GfxObj *_answerer;
Question *_q;
@@ -93,7 +93,7 @@ uint16 DialogueManager::askPassword() {
uint16 passwordLen = 0;
_password[0] = '\0';
- _vm->_gfx->setDialogueBalloon(_q->_answers[0]->_text, 1, 3);
+ _vm->_balloonMan->setDialogueBalloon(_q->_answers[0]->_text, 1, 3);
int id = _vm->_gfx->setItem(_answerer, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y);
_vm->_gfx->setItemFrame(id, 0);
@@ -113,7 +113,7 @@ uint16 DialogueManager::askPassword() {
}
if (changed) {
- _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 3);
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 3);
_vm->_gfx->updateScreen();
changed = false;
}
@@ -138,7 +138,7 @@ uint16 DialogueManager::askPassword() {
}
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
return 0;
@@ -157,7 +157,7 @@ bool DialogueManager::displayAnswer(uint16 i) {
// display suitable answers
if (((a->_yesFlags & flags) == a->_yesFlags) && ((a->_noFlags & ~flags) == a->_noFlags)) {
- int id = _vm->_gfx->setDialogueBalloon(a->_text, 1, 3);
+ int id = _vm->_balloonMan->setDialogueBalloon(a->_text, 1, 3);
assert(id >= 0);
_visAnswers[id] = i;
@@ -185,13 +185,13 @@ void DialogueManager::displayQuestion() {
if (!scumm_stricmp(_q->_text, "NULL")) return;
- _vm->_gfx->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0);
+ _vm->_balloonMan->setSingleBalloon(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, _q->_mood & 0x10, 0);
int id = _vm->_gfx->setItem(_questioner, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y);
_vm->_gfx->setItemFrame(id, _q->_mood & 0xF);
_vm->_gfx->updateScreen();
_vm->_input->waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
return;
}
@@ -224,7 +224,7 @@ void DialogueManager::run() {
answer = 0;
displayQuestion();
-
+
if (_vm->quit())
return;
@@ -244,7 +244,7 @@ void DialogueManager::run() {
}
if (cmdlist)
- _vm->runCommands(*cmdlist);
+ _vm->_cmdExec->run(*cmdlist);
}
@@ -256,31 +256,31 @@ int16 DialogueManager::selectAnswer() {
_vm->_gfx->setItemFrame(id, _q->_answers[0]->_mood & 0xF);
if (numAvailableAnswers == 1) {
- _vm->_gfx->setBalloonText(0, _q->_answers[0]->_text, 0);
+ _vm->_balloonMan->setBalloonText(0, _q->_answers[0]->_text, 0);
_vm->_input->waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
return 0;
}
int oldSelection = -1;
- int selection;
+ int selection = 0;
uint32 event;
Common::Point p;
while (!_vm->quit()) {
-
+
_vm->_input->readInput();
_vm->_input->getCursorPos(p);
event = _vm->_input->getLastButtonEvent();
- selection = _vm->_gfx->hitTestDialogueBalloon(p.x, p.y);
+ selection = _vm->_balloonMan->hitTestDialogueBalloon(p.x, p.y);
if (selection != oldSelection) {
if (oldSelection != -1) {
- _vm->_gfx->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3);
+ _vm->_balloonMan->setBalloonText(oldSelection, _q->_answers[_visAnswers[oldSelection]]->_text, 3);
}
if (selection != -1) {
- _vm->_gfx->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0);
+ _vm->_balloonMan->setBalloonText(selection, _q->_answers[_visAnswers[selection]]->_text, 0);
_vm->_gfx->setItemFrame(0, _q->_answers[_visAnswers[selection]]->_mood & 0xF);
}
}
@@ -295,7 +295,7 @@ int16 DialogueManager::selectAnswer() {
oldSelection = selection;
}
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
return _visAnswers[selection];
}
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index b76c66aead..694d4efa6d 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -55,12 +55,12 @@ public:
virtual Script* loadLocation(const char *name) = 0;
virtual Script* loadScript(const char* name) = 0;
- virtual Frames* loadTalk(const char *name) = 0;
- virtual Frames* loadObjects(const char *name) = 0;
+ virtual GfxObj* loadTalk(const char *name) = 0;
+ virtual GfxObj* loadObjects(const char *name) = 0;
virtual Frames* loadPointer(const char *name) = 0;
- virtual Frames* loadHead(const char* name) = 0;
+ virtual GfxObj* loadHead(const char* name) = 0;
virtual Font* loadFont(const char* name) = 0;
- virtual Frames* loadStatic(const char* name) = 0;
+ virtual GfxObj* loadStatic(const char* name) = 0;
virtual Frames* loadFrames(const char* name) = 0;
virtual void loadSlide(BackgroundInfo& info, const char *filename) = 0;
virtual void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) = 0;
@@ -147,12 +147,12 @@ public:
Script* loadLocation(const char *name);
Script* loadScript(const char* name);
- Frames* loadTalk(const char *name);
- Frames* loadObjects(const char *name);
+ GfxObj* loadTalk(const char *name);
+ GfxObj* loadObjects(const char *name);
Frames* loadPointer(const char *name);
- Frames* loadHead(const char* name);
+ GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
- Frames* loadStatic(const char* name);
+ GfxObj* loadStatic(const char* name);
Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path);
@@ -181,12 +181,12 @@ public:
Script* loadLocation(const char *name);
Script* loadScript(const char* name);
- Frames* loadTalk(const char *name);
- Frames* loadObjects(const char *name);
+ GfxObj* loadTalk(const char *name);
+ GfxObj* loadObjects(const char *name);
Frames* loadPointer(const char *name);
- Frames* loadHead(const char* name);
+ GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
- Frames* loadStatic(const char* name);
+ GfxObj* loadStatic(const char* name);
Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path);
@@ -220,12 +220,12 @@ public:
void setLanguage(uint16 language);
Script* loadLocation(const char *name);
Script* loadScript(const char* name);
- Frames* loadTalk(const char *name);
- Frames* loadObjects(const char *name);
+ GfxObj* loadTalk(const char *name);
+ GfxObj* loadObjects(const char *name);
Frames* loadPointer(const char *name);
- Frames* loadHead(const char* name);
+ GfxObj* loadHead(const char* name);
Font* loadFont(const char* name);
- Frames* loadStatic(const char* name);
+ GfxObj* loadStatic(const char* name);
Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path);
@@ -248,9 +248,9 @@ public:
AmigaDisk_br(Parallaction *vm);
virtual ~AmigaDisk_br();
- Frames* loadTalk(const char *name);
+ GfxObj* loadTalk(const char *name);
Font* loadFont(const char* name);
- Frames* loadStatic(const char* name);
+ GfxObj* loadStatic(const char* name);
Frames* loadFrames(const char* name);
void loadSlide(BackgroundInfo& info, const char *filename);
void loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path);
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 5e88327879..ee1e111139 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -58,7 +58,7 @@ struct Sprites : public Frames {
}
~Sprites() {
- delete _sprites;
+ delete[] _sprites;
}
uint16 getNum() {
@@ -138,7 +138,7 @@ DosDisk_br::DosDisk_br(Parallaction* vm) : _vm(vm) {
DosDisk_br::~DosDisk_br() {
}
-Frames* DosDisk_br::loadTalk(const char *name) {
+GfxObj* DosDisk_br::loadTalk(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadTalk(%s)", name);
Common::File stream;
@@ -151,7 +151,7 @@ Frames* DosDisk_br::loadTalk(const char *name) {
errorFileNotFound(path);
}
- return createSprites(stream);
+ return new GfxObj(0, createSprites(stream), name);
}
Script* DosDisk_br::loadLocation(const char *name) {
@@ -184,7 +184,7 @@ Script* DosDisk_br::loadScript(const char* name) {
}
// there are no Head resources in Big Red Adventure
-Frames* DosDisk_br::loadHead(const char* name) {
+GfxObj* DosDisk_br::loadHead(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadHead");
return 0;
}
@@ -235,7 +235,7 @@ Font* DosDisk_br::loadFont(const char* name) {
}
-Frames* DosDisk_br::loadObjects(const char *name) {
+GfxObj* DosDisk_br::loadObjects(const char *name) {
debugC(5, kDebugDisk, "DosDisk_br::loadObjects");
return 0;
}
@@ -244,7 +244,7 @@ void genSlidePath(char *path, const char* name) {
sprintf(path, "%s.bmp", name);
}
-Frames* DosDisk_br::loadStatic(const char* name) {
+GfxObj* DosDisk_br::loadStatic(const char* name) {
debugC(5, kDebugDisk, "DosDisk_br::loadStatic");
char path[PATH_LEN];
@@ -256,7 +256,7 @@ Frames* DosDisk_br::loadStatic(const char* name) {
Graphics::Surface *surf = new Graphics::Surface;
loadBitmap(stream, *surf, 0);
- return new SurfaceToFrames(surf);
+ return new GfxObj(0, new SurfaceToFrames(surf), name);
}
Sprites* DosDisk_br::createSprites(Common::ReadStream &stream) {
@@ -287,9 +287,12 @@ Frames* DosDisk_br::loadFrames(const char* name) {
sprintf(path, "%s/ani/%s", _partPath, name);
Common::File stream;
- if (!stream.open(path))
- errorFileNotFound(path);
-
+ if (!stream.open(path)) {
+ sprintf(path, "%s/ani/%s.ani", _partPath, name);
+ if (!stream.open(path)) {
+ errorFileNotFound(path);
+ }
+ }
return createSprites(stream);
}
@@ -552,7 +555,7 @@ void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) {
return;
}
-Frames* AmigaDisk_br::loadStatic(const char* name) {
+GfxObj* AmigaDisk_br::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name);
char path[PATH_LEN];
@@ -570,7 +573,7 @@ Frames* AmigaDisk_br::loadStatic(const char* name) {
free(pal);
- return new SurfaceToFrames(surf);
+ return new GfxObj(0, new SurfaceToFrames(surf));
}
Sprites* AmigaDisk_br::createSprites(const char *path) {
@@ -609,13 +612,13 @@ Frames* AmigaDisk_br::loadFrames(const char* name) {
return createSprites(path);
}
-Frames* AmigaDisk_br::loadTalk(const char *name) {
+GfxObj* AmigaDisk_br::loadTalk(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_br::loadTalk '%s'", name);
char path[PATH_LEN];
sprintf(path, "%s/talks/%s.tal", _partPath, name);
- return createSprites(path);
+ return new GfxObj(0, createSprites(path));
}
Font* AmigaDisk_br::loadFont(const char* name) {
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index cdbe3458a7..55e6fc5e77 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -385,12 +385,12 @@ Cnv* DosDisk_ns::loadCnv(const char *filename) {
return new Cnv(numFrames, width, height, data);
}
-Frames* DosDisk_ns::loadTalk(const char *name) {
+GfxObj* DosDisk_ns::loadTalk(const char *name) {
const char *ext = strstr(name, ".talk");
if (ext != NULL) {
// npc talk
- return loadCnv(name);
+ return new GfxObj(0, loadCnv(name), name);
}
@@ -401,7 +401,7 @@ Frames* DosDisk_ns::loadTalk(const char *name) {
sprintf(v20, "%stal", name);
}
- return loadExternalCnv(v20);
+ return new GfxObj(0, loadExternalCnv(v20), name);
}
Script* DosDisk_ns::loadLocation(const char *name) {
@@ -434,14 +434,14 @@ Script* DosDisk_ns::loadScript(const char* name) {
return new Script(new DummyArchiveStream(_resArchive), true);
}
-Frames* DosDisk_ns::loadHead(const char* name) {
+GfxObj* DosDisk_ns::loadHead(const char* name) {
char path[PATH_LEN];
sprintf(path, "%shead", name);
path[8] = '\0';
- return loadExternalStaticCnv(path);
+ return new GfxObj(0, loadExternalStaticCnv(path));
}
@@ -457,15 +457,15 @@ Font* DosDisk_ns::loadFont(const char* name) {
}
-Frames* DosDisk_ns::loadObjects(const char *name) {
+GfxObj* DosDisk_ns::loadObjects(const char *name) {
char path[PATH_LEN];
sprintf(path, "%sobj", name);
- return loadExternalCnv(path);
+ return new GfxObj(0, loadExternalCnv(path), name);
}
-Frames* DosDisk_ns::loadStatic(const char* name) {
+GfxObj* DosDisk_ns::loadStatic(const char* name) {
char path[PATH_LEN];
@@ -487,7 +487,7 @@ Frames* DosDisk_ns::loadStatic(const char* name) {
Graphics::PackBitsReadStream decoder(_resArchive);
decoder.read(cnv->pixels, w*h);
- return new SurfaceToFrames(cnv);
+ return new GfxObj(0, new SurfaceToFrames(cnv), name);
}
Frames* DosDisk_ns::loadFrames(const char* name) {
@@ -1025,7 +1025,7 @@ Frames* AmigaDisk_ns::loadPointer(const char* name) {
return makeStaticCnv(stream);
}
-Frames* AmigaDisk_ns::loadStatic(const char* name) {
+GfxObj* AmigaDisk_ns::loadStatic(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_ns::loadStatic '%s'", name);
Common::SeekableReadStream *s = openArchivedFile(name, true);
@@ -1033,7 +1033,7 @@ Frames* AmigaDisk_ns::loadStatic(const char* name) {
delete s;
- return cnv;
+ return new GfxObj(0, cnv, name);
}
Common::SeekableReadStream *AmigaDisk_ns::openArchivedFile(const char* name, bool errorOnFileNotFound) {
@@ -1276,7 +1276,7 @@ Frames* AmigaDisk_ns::loadFrames(const char* name) {
return cnv;
}
-Frames* AmigaDisk_ns::loadHead(const char* name) {
+GfxObj* AmigaDisk_ns::loadHead(const char* name) {
debugC(1, kDebugDisk, "AmigaDisk_ns::loadHead '%s'", name);
char path[PATH_LEN];
@@ -1287,11 +1287,11 @@ Frames* AmigaDisk_ns::loadHead(const char* name) {
delete s;
- return cnv;
+ return new GfxObj(0, cnv, name);
}
-Frames* AmigaDisk_ns::loadObjects(const char *name) {
+GfxObj* AmigaDisk_ns::loadObjects(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_ns::loadObjects");
char path[PATH_LEN];
@@ -1305,11 +1305,11 @@ Frames* AmigaDisk_ns::loadObjects(const char *name) {
Cnv *cnv = makeCnv(*s);
delete s;
- return cnv;
+ return new GfxObj(0, cnv, name);
}
-Frames* AmigaDisk_ns::loadTalk(const char *name) {
+GfxObj* AmigaDisk_ns::loadTalk(const char *name) {
debugC(1, kDebugDisk, "AmigaDisk_ns::loadTalk '%s'", name);
Common::SeekableReadStream *s;
@@ -1328,7 +1328,7 @@ Frames* AmigaDisk_ns::loadTalk(const char *name) {
Cnv *cnv = makeCnv(*s);
delete s;
- return cnv;
+ return new GfxObj(0, cnv, name);
}
Table* AmigaDisk_ns::loadTable(const char* name) {
@@ -1395,9 +1395,7 @@ Common::ReadStream* AmigaDisk_ns::loadSound(const char* name) {
char path[PATH_LEN];
sprintf(path, "%s.snd", name);
- openArchivedFile(path);
-
- return new DummyArchiveStream(_resArchive);
+ return openArchivedFile(path);
}
} // namespace Parallaction
diff --git a/engines/parallaction/exec.h b/engines/parallaction/exec.h
new file mode 100644
index 0000000000..887d6be526
--- /dev/null
+++ b/engines/parallaction/exec.h
@@ -0,0 +1,241 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+
+#ifndef PARALLACTION_EXEC_H
+#define PARALLACTION_EXEC_H
+
+#include "common/util.h"
+#include "parallaction/objects.h"
+
+
+namespace Parallaction {
+
+typedef Common::Functor0<void> Opcode;
+typedef Common::Array<const Opcode*> OpcodeSet;
+
+#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op()
+#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op()
+
+class Parallaction_ns;
+class Parallaction_br;
+
+class CommandExec {
+protected:
+ struct ParallactionStruct1 {
+ CommandPtr cmd;
+ ZonePtr z;
+ } _ctxt;
+
+ OpcodeSet _opcodes;
+
+public:
+ virtual void init() = 0;
+ virtual void run(CommandList &list, ZonePtr z = nullZonePtr);
+ CommandExec() {
+ }
+ virtual ~CommandExec() {
+ for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ delete *i;
+ _opcodes.clear();
+ }
+};
+
+class CommandExec_ns : public CommandExec {
+
+ Parallaction_ns *_vm;
+
+protected:
+ void updateGetZone(ZonePtr z, bool visible);
+
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(set);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(get);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
+
+public:
+ void init();
+
+ CommandExec_ns(Parallaction_ns* vm);
+ ~CommandExec_ns();
+};
+
+class CommandExec_br : public CommandExec_ns {
+
+protected:
+ Parallaction_br *_vm;
+
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(character);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(add);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(let);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(music);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(give);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(text);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(part);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave);
+ DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave);
+
+public:
+ void init();
+
+ CommandExec_br(Parallaction_br* vm);
+ ~CommandExec_br();
+};
+
+
+
+
+
+class ProgramExec {
+protected:
+ struct ParallactionStruct2 {
+ AnimationPtr anim;
+ ProgramPtr program;
+ InstructionList::iterator inst;
+ uint16 modCounter;
+ bool suspend;
+ } _ctxt;
+
+ OpcodeSet _opcodes;
+
+ uint16 _modCounter;
+
+public:
+ virtual void init() = 0;
+ virtual void runScripts(ProgramList::iterator first, ProgramList::iterator last);
+ ProgramExec() : _modCounter(0) {
+ }
+ virtual ~ProgramExec() {
+ for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ delete *i;
+ _opcodes.clear();
+ }
+};
+
+class ProgramExec_ns : public ProgramExec {
+
+ Parallaction_ns *_vm;
+
+protected:
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
+
+public:
+ void init();
+
+ ProgramExec_ns(Parallaction_ns *vm);
+ ~ProgramExec_ns();
+};
+
+class ProgramExec_br : public ProgramExec_ns {
+
+ Parallaction_br *_vm;
+
+protected:
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop);
+ DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
+
+public:
+ void init();
+ ProgramExec_br(Parallaction_br *vm);
+ ~ProgramExec_br();
+};
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 3b67b4c370..edb832cffc 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
@@ -64,12 +65,13 @@ namespace Parallaction {
#define SetOpcodeTable(x) table = &x;
-typedef Common::Functor0Mem<void, Parallaction_br> OpcodeV2;
-#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::cmdOp_##op))
-#define DECLARE_COMMAND_OPCODE(op) void Parallaction_br::cmdOp_##op()
+typedef Common::Functor0Mem<void, CommandExec_br> OpcodeV1;
+#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_br::cmdOp_##op))
+#define DECLARE_COMMAND_OPCODE(op) void CommandExec_br::cmdOp_##op()
-#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_br::instOp_##op))
-#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_br::instOp_##op()
+typedef Common::Functor0Mem<void, ProgramExec_br> OpcodeV2;
+#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_br::instOp_##op))
+#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_br::instOp_##op()
void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
debugC(5, kDebugExec, "setupSubtitles(%s, %s, %i)", s, s2, y);
@@ -100,8 +102,13 @@ void Parallaction_br::setupSubtitles(char *s, char *s2, int y) {
}
void Parallaction_br::clearSubtitles() {
- _gfx->freeLabels();
- _subtitle[0] = _subtitle[1] = -1;
+ if (_subtitle[0] != -1) {
+ _gfx->hideLabel(_subtitle[0]);
+ }
+
+ if (_subtitle[1] != -1) {
+ _gfx->hideLabel(_subtitle[1]);
+ }
}
@@ -109,7 +116,7 @@ DECLARE_COMMAND_OPCODE(location) {
warning("Parallaction_br::cmdOp_location command not yet implemented");
// TODO: handle startPos and startPos2
- scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string);
+ _vm->scheduleLocationSwitch(_ctxt.cmd->u._string);
}
@@ -124,7 +131,7 @@ DECLARE_COMMAND_OPCODE(close) {
DECLARE_COMMAND_OPCODE(on) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
+ CommandData *data = &_ctxt.cmd->u;
ZonePtr z = data->_zone;
if (z) {
@@ -132,28 +139,28 @@ DECLARE_COMMAND_OPCODE(on) {
z->_flags &= ~kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
}
}
}
DECLARE_COMMAND_OPCODE(off) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
+ CommandData *data = &_ctxt.cmd->u;
ZonePtr z = data->_zone;
if (z) {
z->_flags |= kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, false);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
}
}
}
DECLARE_COMMAND_OPCODE(call) {
- callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z);
+ _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z);
}
@@ -167,17 +174,17 @@ DECLARE_COMMAND_OPCODE(move) {
}
DECLARE_COMMAND_OPCODE(start) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing;
+ _ctxt.cmd->u._zone->_flags |= kFlagsActing;
}
DECLARE_COMMAND_OPCODE(stop) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsActing;
}
DECLARE_COMMAND_OPCODE(character) {
- debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _cmdRunCtxt.cmd->u._string);
- changeCharacter(_cmdRunCtxt.cmd->u._string);
+ debugC(9, kDebugExec, "Parallaction_br::cmdOp_character(%s)", _ctxt.cmd->u._string);
+ _vm->changeCharacter(_ctxt.cmd->u._string);
}
@@ -187,12 +194,12 @@ DECLARE_COMMAND_OPCODE(followme) {
DECLARE_COMMAND_OPCODE(onmouse) {
- _input->showCursor(true);
+ _vm->_input->showCursor(true);
}
DECLARE_COMMAND_OPCODE(offmouse) {
- _input->showCursor(false);
+ _vm->_input->showCursor(false);
}
@@ -207,42 +214,42 @@ DECLARE_COMMAND_OPCODE(leave) {
DECLARE_COMMAND_OPCODE(inc) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] += _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] += _ctxt.cmd->u._rvalue;
}
DECLARE_COMMAND_OPCODE(dec) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] -= _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] -= _ctxt.cmd->u._rvalue;
}
DECLARE_COMMAND_OPCODE(ifeq) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] == _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] == _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(iflt) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] < _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] < _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(ifgt) {
- if (_counters[_cmdRunCtxt.cmd->u._lvalue] > _cmdRunCtxt.cmd->u._rvalue) {
- setLocationFlags(kFlagsTestTrue);
+ if (_vm->_counters[_ctxt.cmd->u._lvalue] > _ctxt.cmd->u._rvalue) {
+ _vm->setLocationFlags(kFlagsTestTrue);
} else {
- clearLocationFlags(kFlagsTestTrue);
+ _vm->clearLocationFlags(kFlagsTestTrue);
}
}
DECLARE_COMMAND_OPCODE(let) {
- _counters[_cmdRunCtxt.cmd->u._lvalue] = _cmdRunCtxt.cmd->u._rvalue;
+ _vm->_counters[_ctxt.cmd->u._lvalue] = _ctxt.cmd->u._rvalue;
}
@@ -252,25 +259,25 @@ DECLARE_COMMAND_OPCODE(music) {
DECLARE_COMMAND_OPCODE(fix) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsFixed;
+ _ctxt.cmd->u._zone->_flags |= kFlagsFixed;
}
DECLARE_COMMAND_OPCODE(unfix) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed;
}
DECLARE_COMMAND_OPCODE(zeta) {
- _location._zeta0 = _cmdRunCtxt.cmd->u._zeta0;
- _location._zeta1 = _cmdRunCtxt.cmd->u._zeta1;
- _location._zeta2 = _cmdRunCtxt.cmd->u._zeta2;
+ _vm->_location._zeta0 = _ctxt.cmd->u._zeta0;
+ _vm->_location._zeta1 = _ctxt.cmd->u._zeta1;
+ _vm->_location._zeta2 = _ctxt.cmd->u._zeta2;
}
DECLARE_COMMAND_OPCODE(scroll) {
warning("Parallaction_br::cmdOp_scroll not yet implemented");
- _gfx->setVar("scroll_x", _cmdRunCtxt.cmd->u._rvalue );
+ _vm->_gfx->setVar("scroll_x", _ctxt.cmd->u._rvalue );
}
@@ -285,8 +292,8 @@ DECLARE_COMMAND_OPCODE(give) {
DECLARE_COMMAND_OPCODE(text) {
- CommandData *data = &_cmdRunCtxt.cmd->u;
- setupSubtitles(data->_string, data->_string2, data->_zeta0);
+ CommandData *data = &_ctxt.cmd->u;
+ _vm->setupSubtitles(data->_string, data->_string2, data->_zeta0);
}
@@ -297,7 +304,7 @@ DECLARE_COMMAND_OPCODE(part) {
DECLARE_COMMAND_OPCODE(testsfx) {
warning("Parallaction_br::cmdOp_testsfx not completely implemented");
- clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled
+ _vm->clearLocationFlags(kFlagsTestTrue); // should test if sfx are enabled
}
@@ -319,7 +326,7 @@ DECLARE_COMMAND_OPCODE(offsave) {
DECLARE_INSTRUCTION_OPCODE(on) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
ZonePtr z = inst->_z;
if (z) {
@@ -327,28 +334,28 @@ DECLARE_INSTRUCTION_OPCODE(on) {
z->_flags &= ~kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, true);
}
}
}
DECLARE_INSTRUCTION_OPCODE(off) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
ZonePtr z = inst->_z;
if (z) {
z->_flags |= kFlagsRemove;
if ((z->_type & 0xFFFF) & kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, false);
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, false);
}
}
}
DECLARE_INSTRUCTION_OPCODE(set) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 rvalue = inst->_opB.getRValue();
int16* lvalue = inst->_opA.getLValue();
@@ -359,21 +366,21 @@ DECLARE_INSTRUCTION_OPCODE(set) {
DECLARE_INSTRUCTION_OPCODE(loop) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
- _instRunCtxt.program->_loopCounter = inst->_opB.getRValue();
- _instRunCtxt.program->_loopStart = _instRunCtxt.inst;
+ _ctxt.program->_loopCounter = inst->_opB.getRValue();
+ _ctxt.program->_loopStart = _ctxt.inst;
}
DECLARE_INSTRUCTION_OPCODE(inc) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 rvalue = inst->_opB.getRValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (rvalue > 0 ? rvalue : -rvalue);
- if (_instRunCtxt.modCounter % _bx != 0) return;
+ if (_ctxt.modCounter % _bx != 0) return;
rvalue = (rvalue > 0 ? 1 : -1);
}
@@ -420,12 +427,12 @@ DECLARE_INSTRUCTION_OPCODE(wait) {
DECLARE_INSTRUCTION_OPCODE(start) {
- (*_instRunCtxt.inst)->_z->_flags |= kFlagsActing;
+ (*_ctxt.inst)->_z->_flags |= kFlagsActing;
}
DECLARE_INSTRUCTION_OPCODE(process) {
- _activeZone2 = (*_instRunCtxt.inst)->_z;
+ _vm->_activeZone2 = (*_ctxt.inst)->_z;
}
@@ -435,18 +442,18 @@ DECLARE_INSTRUCTION_OPCODE(move) {
DECLARE_INSTRUCTION_OPCODE(color) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 entry = inst->_opB.getRValue();
- _gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]);
+ _vm->_gfx->_palette.setEntry(entry, inst->_colors[0], inst->_colors[1], inst->_colors[2]);
}
DECLARE_INSTRUCTION_OPCODE(mask) {
#if 0
- Instruction *inst = *_instRunCtxt.inst;
+ Instruction *inst = *_ctxt.inst;
_gfx->_bgLayers[0] = inst->_opA.getRValue();
_gfx->_bgLayers[1] = inst->_opB.getRValue();
_gfx->_bgLayers[2] = inst->_opC.getRValue();
@@ -459,8 +466,8 @@ DECLARE_INSTRUCTION_OPCODE(print) {
}
DECLARE_INSTRUCTION_OPCODE(text) {
- InstructionPtr inst = (*_instRunCtxt.inst);
- setupSubtitles(inst->_text, inst->_text2, inst->_y);
+ InstructionPtr inst = (*_ctxt.inst);
+ _vm->setupSubtitles(inst->_text, inst->_text2, inst->_y);
}
@@ -489,21 +496,20 @@ DECLARE_INSTRUCTION_OPCODE(stop) {
}
DECLARE_INSTRUCTION_OPCODE(endscript) {
- if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) {
- _instRunCtxt.anim->_flags &= ~kFlagsActing;
- runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim);
- _instRunCtxt.program->_status = kProgramDone;
+ if ((_ctxt.anim->_flags & kFlagsLooping) == 0) {
+ _ctxt.anim->_flags &= ~kFlagsActing;
+ _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
+ _ctxt.program->_status = kProgramDone;
}
- _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin();
+ _ctxt.program->_ip = _ctxt.program->_instructions.begin();
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
-void Parallaction_br::initOpcodes() {
-
+void CommandExec_br::init() {
Common::Array<const Opcode*> *table = 0;
- SetOpcodeTable(_commandOpcodes);
+ SetOpcodeTable(_opcodes);
COMMAND_OPCODE(invalid);
COMMAND_OPCODE(set);
COMMAND_OPCODE(clear);
@@ -546,8 +552,21 @@ void Parallaction_br::initOpcodes() {
COMMAND_OPCODE(ret);
COMMAND_OPCODE(onsave);
COMMAND_OPCODE(offsave);
+}
+
+CommandExec_br::CommandExec_br(Parallaction_br* vm) : CommandExec_ns(vm), _vm(vm) {
+
+}
+
+CommandExec_br::~CommandExec_br() {
- SetOpcodeTable(_instructionOpcodes);
+}
+
+void ProgramExec_br::init() {
+
+ Common::Array<const Opcode*> *table = 0;
+
+ SetOpcodeTable(_opcodes);
INSTRUCTION_OPCODE(invalid);
INSTRUCTION_OPCODE(on);
INSTRUCTION_OPCODE(off);
@@ -582,6 +601,12 @@ void Parallaction_br::initOpcodes() {
INSTRUCTION_OPCODE(endscript);
}
+ProgramExec_br::ProgramExec_br(Parallaction_br *vm) : ProgramExec_ns(vm), _vm(vm) {
+}
+
+ProgramExec_br::~ProgramExec_br() {
+}
+
#if 0
void Parallaction_br::jobWaitRemoveLabelJob(void *parm, Job *job) {
diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp
index 0c4addd9b7..b4578f80ad 100644
--- a/engines/parallaction/exec_ns.cpp
+++ b/engines/parallaction/exec_ns.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/parallaction.h"
#include "parallaction/sound.h"
@@ -52,18 +53,19 @@ namespace Parallaction {
#define SetOpcodeTable(x) table = &x;
-typedef Common::Functor0Mem<void, Parallaction_ns> OpcodeV2;
-#define COMMAND_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::cmdOp_##op))
-#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op()
+typedef Common::Functor0Mem<void, CommandExec_ns> OpcodeV1;
+#define COMMAND_OPCODE(op) table->push_back(new OpcodeV1(this, &CommandExec_ns::cmdOp_##op))
+#define DECLARE_COMMAND_OPCODE(op) void CommandExec_ns::cmdOp_##op()
-#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &Parallaction_ns::instOp_##op))
-#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op()
+typedef Common::Functor0Mem<void, ProgramExec_ns> OpcodeV2;
+#define INSTRUCTION_OPCODE(op) table->push_back(new OpcodeV2(this, &ProgramExec_ns::instOp_##op))
+#define DECLARE_INSTRUCTION_OPCODE(op) void ProgramExec_ns::instOp_##op()
DECLARE_INSTRUCTION_OPCODE(on) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
inst->_a->_flags |= kFlagsActive;
inst->_a->_flags &= ~kFlagsRemove;
@@ -71,31 +73,31 @@ DECLARE_INSTRUCTION_OPCODE(on) {
DECLARE_INSTRUCTION_OPCODE(off) {
- (*_instRunCtxt.inst)->_a->_flags |= kFlagsRemove;
+ (*_ctxt.inst)->_a->_flags |= kFlagsRemove;
}
DECLARE_INSTRUCTION_OPCODE(loop) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
- _instRunCtxt.program->_loopCounter = inst->_opB.getRValue();
- _instRunCtxt.program->_loopStart = _instRunCtxt.inst;
+ _ctxt.program->_loopCounter = inst->_opB.getRValue();
+ _ctxt.program->_loopStart = _ctxt.inst;
}
DECLARE_INSTRUCTION_OPCODE(endloop) {
- if (--_instRunCtxt.program->_loopCounter > 0) {
- _instRunCtxt.inst = _instRunCtxt.program->_loopStart;
+ if (--_ctxt.program->_loopCounter > 0) {
+ _ctxt.inst = _ctxt.program->_loopStart;
}
}
DECLARE_INSTRUCTION_OPCODE(inc) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 _si = inst->_opB.getRValue();
if (inst->_flags & kInstMod) { // mod
int16 _bx = (_si > 0 ? _si : -_si);
- if (_instRunCtxt.modCounter % _bx != 0) return;
+ if (_modCounter % _bx != 0) return;
_si = (_si > 0 ? 1 : -1);
}
@@ -116,7 +118,7 @@ DECLARE_INSTRUCTION_OPCODE(inc) {
DECLARE_INSTRUCTION_OPCODE(set) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
int16 _si = inst->_opB.getRValue();
int16 *lvalue = inst->_opA.getLValue();
@@ -127,7 +129,7 @@ DECLARE_INSTRUCTION_OPCODE(set) {
DECLARE_INSTRUCTION_OPCODE(put) {
- InstructionPtr inst = *_instRunCtxt.inst;
+ InstructionPtr inst = *_ctxt.inst;
Graphics::Surface v18;
v18.w = inst->_a->width();
v18.h = inst->_a->height();
@@ -137,7 +139,7 @@ DECLARE_INSTRUCTION_OPCODE(put) {
int16 y = inst->_opB.getRValue();
bool mask = (inst->_flags & kInstMaskedPut) == kInstMaskedPut;
- _gfx->patchBackground(v18, x, y, mask);
+ _vm->_gfx->patchBackground(v18, x, y, mask);
}
DECLARE_INSTRUCTION_OPCODE(null) {
@@ -145,170 +147,177 @@ DECLARE_INSTRUCTION_OPCODE(null) {
}
DECLARE_INSTRUCTION_OPCODE(invalid) {
- error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index);
+ error("Can't execute invalid opcode %i", (*_ctxt.inst)->_index);
}
DECLARE_INSTRUCTION_OPCODE(call) {
- callFunction((*_instRunCtxt.inst)->_immediate, 0);
+ _vm->callFunction((*_ctxt.inst)->_immediate, 0);
}
DECLARE_INSTRUCTION_OPCODE(wait) {
if (_engineFlags & kEngineWalking)
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
DECLARE_INSTRUCTION_OPCODE(start) {
- (*_instRunCtxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive);
+ (*_ctxt.inst)->_a->_flags |= (kFlagsActing | kFlagsActive);
}
DECLARE_INSTRUCTION_OPCODE(sound) {
- _activeZone = (*_instRunCtxt.inst)->_z;
+ _vm->_activeZone = (*_ctxt.inst)->_z;
}
DECLARE_INSTRUCTION_OPCODE(move) {
- InstructionPtr inst = (*_instRunCtxt.inst);
+ InstructionPtr inst = (*_ctxt.inst);
int16 x = inst->_opA.getRValue();
int16 y = inst->_opB.getRValue();
- _char.scheduleWalk(x, y);
+ _vm->_char.scheduleWalk(x, y);
}
DECLARE_INSTRUCTION_OPCODE(endscript) {
- if ((_instRunCtxt.anim->_flags & kFlagsLooping) == 0) {
- _instRunCtxt.anim->_flags &= ~kFlagsActing;
- runCommands(_instRunCtxt.anim->_commands, _instRunCtxt.anim);
- _instRunCtxt.program->_status = kProgramDone;
+ if ((_ctxt.anim->_flags & kFlagsLooping) == 0) {
+ _ctxt.anim->_flags &= ~kFlagsActing;
+ _vm->_cmdExec->run(_ctxt.anim->_commands, _ctxt.anim);
+ _ctxt.program->_status = kProgramDone;
}
- _instRunCtxt.program->_ip = _instRunCtxt.program->_instructions.begin();
+ _ctxt.program->_ip = _ctxt.program->_instructions.begin();
- _instRunCtxt.suspend = true;
+ _ctxt.suspend = true;
}
DECLARE_COMMAND_OPCODE(invalid) {
- error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id);
+ error("Can't execute invalid command '%i'", _ctxt.cmd->_id);
}
DECLARE_COMMAND_OPCODE(set) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags |= _cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags |= _ctxt.cmd->u._flags;
} else {
- setLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->setLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(clear) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags &= ~_cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags &= ~_ctxt.cmd->u._flags;
} else {
- clearLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->clearLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(start) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing;
+ _ctxt.cmd->u._zone->_flags |= kFlagsActing;
}
DECLARE_COMMAND_OPCODE(speak) {
- _activeZone = _cmdRunCtxt.cmd->u._zone;
+ _vm->_activeZone = _ctxt.cmd->u._zone;
}
DECLARE_COMMAND_OPCODE(get) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed;
- runZone(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsFixed;
+ _vm->runZone(_ctxt.cmd->u._zone);
}
DECLARE_COMMAND_OPCODE(location) {
- scheduleLocationSwitch(_cmdRunCtxt.cmd->u._string);
+ _vm->scheduleLocationSwitch(_ctxt.cmd->u._string);
}
DECLARE_COMMAND_OPCODE(open) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed;
- if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) {
- updateDoor(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
}
}
DECLARE_COMMAND_OPCODE(close) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed;
- if (_cmdRunCtxt.cmd->u._zone->u.door->gfxobj) {
- updateDoor(_cmdRunCtxt.cmd->u._zone);
+ _ctxt.cmd->u._zone->_flags |= kFlagsClosed;
+ if (_ctxt.cmd->u._zone->u.door->gfxobj) {
+ _vm->updateDoor(_ctxt.cmd->u._zone);
}
}
+void CommandExec_ns::updateGetZone(ZonePtr z, bool visible) {
+ if (!z) {
+ return;
+ }
+
+ if ((z->_type & 0xFFFF) == kZoneGet) {
+ _vm->_gfx->showGfxObj(z->u.get->gfxobj, visible);
+ }
+}
DECLARE_COMMAND_OPCODE(on) {
- ZonePtr z = _cmdRunCtxt.cmd->u._zone;
- // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing
- // the pointer to get structure members, thus leading to crashes in systems with memory
- // protection.
- // As a side note, the overwritten address is the 5th entry in the DOS interrupt table
- // (print screen handler): this suggests that a system would hang when the print screen
- // key is pressed after playing Nippon Safes, provided that this code path is taken.
+ ZonePtr z = _ctxt.cmd->u._zone;
+
if (z) {
z->_flags &= ~kFlagsRemove;
z->_flags |= kFlagsActive;
- if ((z->_type & 0xFFFF) == kZoneGet) {
- _gfx->showGfxObj(z->u.get->gfxobj, true);
- }
+ updateGetZone(z, true);
}
}
DECLARE_COMMAND_OPCODE(off) {
- _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove;
+ ZonePtr z = _ctxt.cmd->u._zone;
+
+ if (z) {
+ _ctxt.cmd->u._zone->_flags |= kFlagsRemove;
+ updateGetZone(z, false);
+ }
}
DECLARE_COMMAND_OPCODE(call) {
- callFunction(_cmdRunCtxt.cmd->u._callable, &_cmdRunCtxt.z);
+ _vm->callFunction(_ctxt.cmd->u._callable, &_ctxt.z);
}
DECLARE_COMMAND_OPCODE(toggle) {
- if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
- _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags ^= _cmdRunCtxt.cmd->u._flags;
+ if (_ctxt.cmd->u._flags & kFlagsGlobal) {
+ _ctxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags ^= _ctxt.cmd->u._flags;
} else {
- toggleLocationFlags(_cmdRunCtxt.cmd->u._flags);
+ _vm->toggleLocationFlags(_ctxt.cmd->u._flags);
}
}
DECLARE_COMMAND_OPCODE(drop){
- dropItem( _cmdRunCtxt.cmd->u._object );
+ _vm->dropItem( _ctxt.cmd->u._object );
}
DECLARE_COMMAND_OPCODE(quit) {
- _quit = true;
+ _vm->_quit = true;
_vm->quitGame();
}
DECLARE_COMMAND_OPCODE(move) {
- _char.scheduleWalk(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y);
+ _vm->_char.scheduleWalk(_ctxt.cmd->u._move.x, _ctxt.cmd->u._move.y);
}
DECLARE_COMMAND_OPCODE(stop) {
- _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing;
+ _ctxt.cmd->u._zone->_flags &= ~kFlagsActing;
}
@@ -357,16 +366,14 @@ void Parallaction_ns::drawAnimations() {
}
-void Parallaction_ns::runScripts() {
+void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator last) {
if (_engineFlags & kEnginePauseJobs) {
return;
}
debugC(9, kDebugExec, "runScripts");
- static uint16 modCounter = 0;
-
- for (ProgramList::iterator it = _location._programs.begin(); it != _location._programs.end(); it++) {
+ for (ProgramList::iterator it = first; it != last; it++) {
AnimationPtr a = (*it)->_anim;
@@ -383,17 +390,16 @@ void Parallaction_ns::runScripts() {
debugC(9, kDebugExec, "Animation: %s, instruction: %i", a->_name, (*inst)->_index); //_instructionNamesRes[(*inst)->_index - 1]);
- _instRunCtxt.inst = inst;
- _instRunCtxt.anim = AnimationPtr(a);
- _instRunCtxt.program = *it;
- _instRunCtxt.modCounter = modCounter;
- _instRunCtxt.suspend = false;
+ _ctxt.inst = inst;
+ _ctxt.anim = AnimationPtr(a);
+ _ctxt.program = *it;
+ _ctxt.suspend = false;
- (*_instructionOpcodes[(*inst)->_index])();
+ (*_opcodes[(*inst)->_index])();
- inst = _instRunCtxt.inst; // handles endloop correctly
+ inst = _ctxt.inst; // handles endloop correctly
- if (_instRunCtxt.suspend)
+ if (_ctxt.suspend)
goto label1;
inst++;
@@ -406,44 +412,54 @@ label1:
a->_z = a->_top + a->height();
}
- _char._ani->_z = _char._ani->height() + _char._ani->_top;
- if (_char._ani->gfxobj) {
- _char._ani->gfxobj->z = _char._ani->_z;
- }
- modCounter++;
+ _modCounter++;
return;
}
-void Parallaction::runCommands(CommandList& list, ZonePtr z) {
- if (list.size() == 0)
+void CommandExec::run(CommandList& list, ZonePtr z) {
+ if (list.size() == 0) {
+ debugC(3, kDebugExec, "runCommands: nothing to do");
return;
+ }
- debugC(3, kDebugExec, "runCommands");
+ debugC(3, kDebugExec, "runCommands starting");
+
+ uint32 useFlags = 0;
+ bool useLocalFlags;
CommandList::iterator it = list.begin();
for ( ; it != list.end(); it++) {
+ if (_vm->quit())
+ break;
+
CommandPtr cmd = *it;
- uint32 v8 = getLocationFlags();
if (_vm->quit())
break;
-
+
if (cmd->_flagsOn & kFlagsGlobal) {
- v8 = _commandFlags | kFlagsGlobal;
+ useFlags = _commandFlags | kFlagsGlobal;
+ useLocalFlags = false;
+ } else {
+ useFlags = _vm->getLocationFlags();
+ useLocalFlags = true;
}
- if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue;
- if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue;
+ bool onMatch = (cmd->_flagsOn & useFlags) == cmd->_flagsOn;
+ bool offMatch = (cmd->_flagsOff & ~useFlags) == cmd->_flagsOff;
+
+ debugC(3, kDebugExec, "runCommands[%i] (on: %x, off: %x), (%s = %x)", cmd->_id, cmd->_flagsOn, cmd->_flagsOff,
+ useLocalFlags ? "LOCALFLAGS" : "GLOBALFLAGS", useFlags);
-// debugC(3, kDebugExec, "runCommands[%i]: %s (on: %x, off: %x)", cmd->_id, _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff);
+ if (!onMatch || !offMatch) continue;
- _cmdRunCtxt.z = z;
- _cmdRunCtxt.cmd = cmd;
+ _ctxt.z = z;
+ _ctxt.cmd = cmd;
- (*_commandOpcodes[cmd->_id])();
+ (*_opcodes[cmd->_id])();
}
debugC(3, kDebugExec, "runCommands completed");
@@ -452,6 +468,13 @@ void Parallaction::runCommands(CommandList& list, ZonePtr z) {
}
+CommandExec_ns::CommandExec_ns(Parallaction_ns* vm) : _vm(vm) {
+
+}
+
+CommandExec_ns::~CommandExec_ns() {
+
+}
//
// ZONE TYPE: EXAMINE
@@ -470,7 +493,7 @@ void Parallaction::displayComment(ExamineData *data) {
}
_gfx->setHalfbriteMode(true);
- _gfx->setSingleBalloon(data->_description, 0, 90, 0, 0);
+ _balloonMan->setSingleBalloon(data->_description, 0, 90, 0, 0);
Common::Rect r;
data->_cnv->getRect(0, r);
id = _gfx->setItem(data->_cnv, 140, (_screenHeight - r.height())/2);
@@ -478,7 +501,7 @@ void Parallaction::displayComment(ExamineData *data) {
id = _gfx->setItem(_char._head, 100, 152);
_gfx->setItemFrame(id, 0);
} else {
- _gfx->setSingleBalloon(data->_description, 140, 10, 0, 0);
+ _balloonMan->setSingleBalloon(data->_description, 140, 10, 0, 0);
id = _gfx->setItem(_char._talk, 190, 80);
_gfx->setItemFrame(id, 0);
}
@@ -528,7 +551,7 @@ uint16 Parallaction::runZone(ZonePtr z) {
debugC(3, kDebugExec, "runZone completed");
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
return 0;
}
@@ -655,11 +678,34 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
}
-void Parallaction_ns::initOpcodes() {
+void CommandExec_ns::init() {
+ Common::Array<const Opcode*> *table = 0;
+
+ SetOpcodeTable(_opcodes);
+ COMMAND_OPCODE(invalid);
+ COMMAND_OPCODE(set);
+ COMMAND_OPCODE(clear);
+ COMMAND_OPCODE(start);
+ COMMAND_OPCODE(speak);
+ COMMAND_OPCODE(get);
+ COMMAND_OPCODE(location);
+ COMMAND_OPCODE(open);
+ COMMAND_OPCODE(close);
+ COMMAND_OPCODE(on);
+ COMMAND_OPCODE(off);
+ COMMAND_OPCODE(call);
+ COMMAND_OPCODE(toggle);
+ COMMAND_OPCODE(drop);
+ COMMAND_OPCODE(quit);
+ COMMAND_OPCODE(move);
+ COMMAND_OPCODE(stop);
+}
+
+void ProgramExec_ns::init() {
Common::Array<const Opcode*> *table = 0;
- SetOpcodeTable(_instructionOpcodes);
+ SetOpcodeTable(_opcodes);
INSTRUCTION_OPCODE(invalid);
INSTRUCTION_OPCODE(on);
INSTRUCTION_OPCODE(off);
@@ -681,25 +727,12 @@ void Parallaction_ns::initOpcodes() {
INSTRUCTION_OPCODE(move);
INSTRUCTION_OPCODE(endscript);
- SetOpcodeTable(_commandOpcodes);
- COMMAND_OPCODE(invalid);
- COMMAND_OPCODE(set);
- COMMAND_OPCODE(clear);
- COMMAND_OPCODE(start);
- COMMAND_OPCODE(speak);
- COMMAND_OPCODE(get);
- COMMAND_OPCODE(location);
- COMMAND_OPCODE(open);
- COMMAND_OPCODE(close);
- COMMAND_OPCODE(on);
- COMMAND_OPCODE(off);
- COMMAND_OPCODE(call);
- COMMAND_OPCODE(toggle);
- COMMAND_OPCODE(drop);
- COMMAND_OPCODE(quit);
- COMMAND_OPCODE(move);
- COMMAND_OPCODE(stop);
}
+ProgramExec_ns::ProgramExec_ns(Parallaction_ns *vm) : _vm(vm) {
+}
+
+ProgramExec_ns::~ProgramExec_ns() {
+}
} // namespace Parallaction
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index 6599a1f81c..9e7eb12ed8 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,7 @@
namespace Parallaction {
-GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(0), _keep(true) {
+GfxObj::GfxObj(uint objType, Frames *frames, const char* name) : type(objType), _frames(frames), x(0), y(0), z(0), frame(0), layer(3), _flags(kGfxObjNormal), _keep(true) {
if (name) {
_name = strdup(name);
} else {
@@ -86,93 +86,325 @@ void GfxObj::clearFlags(uint32 flags) {
}
GfxObj* Gfx::loadAnim(const char *name) {
- Frames *frames = _disk->loadFrames(name);
+ Frames* frames = _disk->loadFrames(name);
+ assert(frames);
+
GfxObj *obj = new GfxObj(kGfxObjTypeAnim, frames, name);
assert(obj);
+ // animation Z is not set here, but controlled by game scripts and user interaction.
+ // it is always >=0 and <screen height
+ obj->transparentKey = 0;
+ _gfxobjList.push_back(obj);
return obj;
}
GfxObj* Gfx::loadGet(const char *name) {
- Frames *frames = _disk->loadStatic(name);
- GfxObj *obj = new GfxObj(kGfxObjTypeGet, frames, name);
+ GfxObj *obj = _disk->loadStatic(name);
assert(obj);
+ obj->z = kGfxObjGetZ; // this preset Z value ensures that get zones are drawn after doors but before animations
+ obj->type = kGfxObjTypeGet;
+ obj->transparentKey = 0;
+ _gfxobjList.push_back(obj);
return obj;
}
GfxObj* Gfx::loadDoor(const char *name) {
Frames *frames = _disk->loadFrames(name);
+ assert(frames);
+
GfxObj *obj = new GfxObj(kGfxObjTypeDoor, frames, name);
assert(obj);
+ obj->z = kGfxObjDoorZ; // this preset Z value ensures that doors are drawn first
+ obj->transparentKey = 0;
+ _gfxobjList.push_back(obj);
return obj;
}
-void Gfx::clearGfxObjects() {
- _gfxobjList[0].clear();
- _gfxobjList[1].clear();
- _gfxobjList[2].clear();
+void Gfx::clearGfxObjects(uint filter) {
+
+ GfxObjList::iterator b = _gfxobjList.begin();
+ GfxObjList::iterator e = _gfxobjList.end();
+
+ for ( ; b != e; ) {
+ if (((*b)->_flags & filter) != 0) {
+ b = _gfxobjList.erase(b);
+ } else {
+ b++;
+ }
+ }
+
}
void Gfx::showGfxObj(GfxObj* obj, bool visible) {
- if (!obj || obj->isVisible() == visible) {
+ if (!obj) {
return;
}
if (visible) {
obj->setFlags(kGfxObjVisible);
- _gfxobjList[obj->type].push_back(obj);
} else {
obj->clearFlags(kGfxObjVisible);
- _gfxobjList[obj->type].remove(obj);
}
-
}
-bool compareAnimationZ(const GfxObj* a1, const GfxObj* a2) {
+bool compareZ(const GfxObj* a1, const GfxObj* a2) {
return a1->z < a2->z;
}
void Gfx::sortAnimations() {
- GfxObjList::iterator first = _gfxobjList[kGfxObjTypeAnim].begin();
- GfxObjList::iterator last = _gfxobjList[kGfxObjTypeAnim].end();
+ GfxObjList::iterator first = _gfxobjList.begin();
+ GfxObjList::iterator last = _gfxobjList.end();
- Common::sort(first, last, compareAnimationZ);
+ Common::sort(first, last, compareZ);
}
-void Gfx::drawGfxObjects(Graphics::Surface &surf) {
+
+void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) {
+ if (!obj->isVisible()) {
+ return;
+ }
Common::Rect rect;
byte *data;
+ uint scrollX = (scene) ? -_varScrollX : 0;
+
+ obj->getRect(obj->frame, rect);
+ rect.translate(obj->x + scrollX, obj->y);
+ data = obj->getData(obj->frame);
+
+ if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) {
+ blt(rect, data, &surf, obj->layer, obj->transparentKey);
+ } else {
+ unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, obj->transparentKey);
+ }
+
+}
+
+
+void Gfx::drawGfxObjects(Graphics::Surface &surf) {
+
sortAnimations();
// TODO: some zones don't appear because of wrong masking (3 or 0?)
- // TODO: Dr.Ki is not visible inside the club
+ GfxObjList::iterator b = _gfxobjList.begin();
+ GfxObjList::iterator e = _gfxobjList.end();
+
+ for (; b != e; b++) {
+ drawGfxObject(*b, surf, true);
+ }
+}
+
+
+
+void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) {
+ byte *dst = (byte*)surf->getBasePtr(x, y);
+ font->setColor(color);
+ font->drawString(dst, surf->w, text);
+}
+
+void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
+
+ uint16 lines = 0;
+ uint16 linewidth = 0;
+
+ uint16 rx = 10;
+ uint16 ry = 4;
+
+ uint16 blankWidth = font->getStringWidth(" ");
+ uint16 tokenWidth = 0;
+
+ char token[MAX_TOKEN_LEN];
+
+ if (wrapwidth == -1)
+ wrapwidth = _vm->_screenWidth;
+
+ while (strlen(text) > 0) {
+
+ text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
- for (uint i = 0; i < 3; i++) {
+ if (!scumm_stricmp(token, "%p")) {
+ lines++;
+ rx = 10;
+ ry = 4 + lines*10; // y
- GfxObjList::iterator b = _gfxobjList[i].begin();
- GfxObjList::iterator e = _gfxobjList[i].end();
+ strcpy(token, "> .......");
+ strncpy(token+2, _password, strlen(_password));
+ tokenWidth = font->getStringWidth(token);
+ } else {
+ tokenWidth = font->getStringWidth(token);
- for (; b != e; b++) {
- GfxObj *obj = *b;
- if (obj->isVisible()) {
- obj->getRect(obj->frame, rect);
- rect.translate(obj->x - _varScrollX, obj->y);
- data = obj->getData(obj->frame);
- if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) {
- blt(rect, data, &surf, obj->layer, 0);
- } else {
- unpackBlt(rect, data, obj->getRawSize(obj->frame), &surf, obj->layer, 0);
+ linewidth += tokenWidth;
+
+ if (linewidth > wrapwidth) {
+ // wrap line
+ lines++;
+ rx = 10; // x
+ ry = 4 + lines*10; // y
+ linewidth = tokenWidth;
+ }
+
+ if (!scumm_stricmp(token, "%s")) {
+ sprintf(token, "%d", _score);
+ }
+
+ }
+
+ drawText(font, surf, rx, ry, token, color);
+
+ rx += tokenWidth + blankWidth;
+ linewidth += blankWidth;
+
+ text = Common::ltrim(text);
+ }
+
+}
+
+
+// this is the maximum size of an unpacked frame in BRA
+byte _unpackedBitmap[640*401];
+
+#if 0
+void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+
+ byte *d = _unpackedBitmap;
+
+ while (size > 0) {
+
+ uint8 p = *data++;
+ size--;
+ uint8 color = p & 0xF;
+ uint8 repeat = (p & 0xF0) >> 4;
+ if (repeat == 0) {
+ repeat = *data++;
+ size--;
+ }
+
+ memset(d, color, repeat);
+ d += repeat;
+ }
+
+ blt(r, _unpackedBitmap, surf, z, transparentColor);
+}
+#endif
+void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+
+ byte *d = _unpackedBitmap;
+ uint pixelsLeftInLine = r.width();
+
+ while (size > 0) {
+ uint8 p = *data++;
+ size--;
+ uint8 color = p & 0xF;
+ uint8 repeat = (p & 0xF0) >> 4;
+ if (repeat == 0) {
+ repeat = *data++;
+ size--;
+ }
+ if (repeat == 0) {
+ // end of line
+ repeat = pixelsLeftInLine;
+ pixelsLeftInLine = r.width();
+ } else {
+ pixelsLeftInLine -= repeat;
+ }
+
+ memset(d, color, repeat);
+ d += repeat;
+ }
+
+ blt(r, _unpackedBitmap, surf, z, transparentColor);
+}
+
+
+void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) {
+
+ Common::Point dp;
+ Common::Rect q(r);
+
+ Common::Rect clipper(surf->w, surf->h);
+
+ q.clip(clipper);
+ if (!q.isValidRect()) return;
+
+ dp.x = q.left;
+ dp.y = q.top;
+
+ q.translate(-r.left, -r.top);
+
+ byte *s = data + q.left + q.top * r.width();
+ byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
+
+ uint sPitch = r.width() - q.width();
+ uint dPitch = surf->w - q.width();
+
+
+ if (_varRenderMode == 2) {
+
+ for (uint16 i = 0; i < q.height(); i++) {
+
+ for (uint16 j = 0; j < q.width(); j++) {
+ if (*s != transparentColor) {
+ if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
+ byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
+ if (z >= v) *d = 5;
+ } else {
+ *d = 5;
+ }
+ }
+
+ s++;
+ d++;
+ }
+
+ s += sPitch;
+ d += dPitch;
+ }
+
+ } else {
+ if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
+
+ for (uint16 i = 0; i < q.height(); i++) {
+
+ for (uint16 j = 0; j < q.width(); j++) {
+ if (*s != transparentColor) {
+ byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
+ if (z >= v) *d = *s;
+ }
+
+ s++;
+ d++;
+ }
+
+ s += sPitch;
+ d += dPitch;
+ }
+
+ } else {
+
+ for (uint16 i = q.top; i < q.bottom; i++) {
+ for (uint16 j = q.left; j < q.right; j++) {
+ if (*s != transparentColor)
+ *d = *s;
+
+ s++;
+ d++;
}
+
+ s += sPitch;
+ d += dPitch;
}
+
}
}
+
}
+
} // namespace Parallaction
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 58fb02a750..32d0e303eb 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -64,10 +64,6 @@ int32 Gfx::getVar(const Common::String &name) {
#define LABEL_TRANSPARENT_COLOR 0xFF
-#define BALLOON_TRANSPARENT_COLOR 2
-
-
-int16 Gfx::_dialogueBalloonX[5] = { 80, 120, 150, 150, 150 };
void halfbritePixel(int x, int y, int color, void *data) {
byte *buffer = (byte*)data;
@@ -238,37 +234,6 @@ void Palette::rotate(uint first, uint last, bool forward) {
}
-#define BALLOON_TAIL_WIDTH 12
-#define BALLOON_TAIL_HEIGHT 10
-
-
-byte _resBalloonTail[2][BALLOON_TAIL_WIDTH*BALLOON_TAIL_HEIGHT] = {
- {
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- },
- {
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
- }
-};
-
void Gfx::setPalette(Palette pal) {
byte sysPal[256*4];
@@ -356,21 +321,19 @@ void Gfx::drawItems() {
Graphics::Surface *surf = g_system->lockScreen();
for (uint i = 0; i < _numItems; i++) {
- blt(_items[i].rect, _items[i].data->getData(_items[i].frame), surf, LAYER_FOREGROUND, _items[i].transparentColor);
+ drawGfxObject(_items[i].data, *surf, false);
}
g_system->unlockScreen();
}
void Gfx::drawBalloons() {
- if (_numBalloons == 0) {
+ if (_balloons.size() == 0) {
return;
}
Graphics::Surface *surf = g_system->lockScreen();
- for (uint i = 0; i < _numBalloons; i++) {
- Common::Rect r(_balloons[i].surface.w, _balloons[i].surface.h);
- r.moveTo(_balloons[i].x, _balloons[i].y);
- blt(r, (byte*)_balloons[i].surface.getBasePtr(0, 0), surf, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR);
+ for (uint i = 0; i < _balloons.size(); i++) {
+ drawGfxObject(_balloons[i], *surf, false);
}
g_system->unlockScreen();
}
@@ -521,145 +484,6 @@ void Gfx::invertBackground(const Common::Rect& r) {
}
-// this is the maximum size of an unpacked frame in BRA
-byte _unpackedBitmap[640*401];
-
-#if 0
-void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
-
- byte *d = _unpackedBitmap;
-
- while (size > 0) {
-
- uint8 p = *data++;
- size--;
- uint8 color = p & 0xF;
- uint8 repeat = (p & 0xF0) >> 4;
- if (repeat == 0) {
- repeat = *data++;
- size--;
- }
-
- memset(d, color, repeat);
- d += repeat;
- }
-
- blt(r, _unpackedBitmap, surf, z, transparentColor);
-}
-#endif
-void Gfx::unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor) {
-
- byte *d = _unpackedBitmap;
- uint pixelsLeftInLine = r.width();
-
- while (size > 0) {
- uint8 p = *data++;
- size--;
- uint8 color = p & 0xF;
- uint8 repeat = (p & 0xF0) >> 4;
- if (repeat == 0) {
- repeat = *data++;
- size--;
- }
- if (repeat == 0) {
- // end of line
- repeat = pixelsLeftInLine;
- pixelsLeftInLine = r.width();
- } else {
- pixelsLeftInLine -= repeat;
- }
-
- memset(d, color, repeat);
- d += repeat;
- }
-
- blt(r, _unpackedBitmap, surf, z, transparentColor);
-}
-
-
-void Gfx::blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor) {
-
- Common::Point dp;
- Common::Rect q(r);
-
- Common::Rect clipper(surf->w, surf->h);
-
- q.clip(clipper);
- if (!q.isValidRect()) return;
-
- dp.x = q.left;
- dp.y = q.top;
-
- q.translate(-r.left, -r.top);
-
- byte *s = data + q.left + q.top * r.width();
- byte *d = (byte*)surf->getBasePtr(dp.x, dp.y);
-
- uint sPitch = r.width() - q.width();
- uint dPitch = surf->w - q.width();
-
-
- if (_varRenderMode == 2) {
-
- for (uint16 i = 0; i < q.height(); i++) {
-
- for (uint16 j = 0; j < q.width(); j++) {
- if (*s != transparentColor) {
- if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
- byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
- if (z >= v) *d = 5;
- } else {
- *d = 5;
- }
- }
-
- s++;
- d++;
- }
-
- s += sPitch;
- d += dPitch;
- }
-
- } else {
- if (_backgroundInfo.mask.data && (z < LAYER_FOREGROUND)) {
-
- for (uint16 i = 0; i < q.height(); i++) {
-
- for (uint16 j = 0; j < q.width(); j++) {
- if (*s != transparentColor) {
- byte v = _backgroundInfo.mask.getValue(dp.x + j, dp.y + i);
- if (z >= v) *d = *s;
- }
-
- s++;
- d++;
- }
-
- s += sPitch;
- d += dPitch;
- }
-
- } else {
-
- for (uint16 i = q.top; i < q.bottom; i++) {
- for (uint16 j = q.left; j < q.right; j++) {
- if (*s != transparentColor)
- *d = *s;
-
- s++;
- d++;
- }
-
- s += sPitch;
- d += dPitch;
- }
-
- }
- }
-
-}
-
@@ -669,10 +493,9 @@ void setupLabelSurface(Graphics::Surface &surf, uint w, uint h) {
surf.fillRect(Common::Rect(w,h), LABEL_TRANSPARENT_COLOR);
}
-Label *Gfx::renderFloatingLabel(Font *font, char *text) {
+uint Gfx::renderFloatingLabel(Font *font, char *text) {
- Label *label = new Label;
- Graphics::Surface *cnv = &label->_cnv;
+ Graphics::Surface *cnv = new Graphics::Surface;
uint w, h;
@@ -698,14 +521,74 @@ Label *Gfx::renderFloatingLabel(Font *font, char *text) {
drawText(font, cnv, 0, 0, text, 0);
}
- return label;
+ GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "floatingLabel");
+ obj->transparentKey = LABEL_TRANSPARENT_COLOR;
+ obj->layer = LAYER_FOREGROUND;
+
+ uint id = _labels.size();
+ _labels.insert_at(id, obj);
+
+ return id;
+}
+
+void Gfx::showFloatingLabel(uint label) {
+ assert(label < _labels.size());
+
+ hideFloatingLabel();
+
+ _labels[label]->x = -1000;
+ _labels[label]->y = -1000;
+ _labels[label]->setFlags(kGfxObjVisible);
+
+ _floatingLabel = label;
+}
+
+void Gfx::hideFloatingLabel() {
+ if (_floatingLabel != NO_FLOATING_LABEL) {
+ _labels[_floatingLabel]->clearFlags(kGfxObjVisible);
+ }
+ _floatingLabel = NO_FLOATING_LABEL;
+}
+
+
+void Gfx::updateFloatingLabel() {
+ if (_floatingLabel == NO_FLOATING_LABEL) {
+ return;
+ }
+
+ int16 _si, _di;
+
+ Common::Point cursor;
+ _vm->_input->getCursorPos(cursor);
+
+ Common::Rect r;
+ _labels[_floatingLabel]->getRect(0, r);
+
+ if (_vm->_input->_activeItem._id != 0) {
+ _si = cursor.x + 16 - r.width()/2;
+ _di = cursor.y + 34;
+ } else {
+ _si = cursor.x + 8 - r.width()/2;
+ _di = cursor.y + 21;
+ }
+
+ if (_si < 0) _si = 0;
+ if (_di > 190) _di = 190;
+
+ if (r.width() + _si > _vm->_screenWidth)
+ _si = _vm->_screenWidth - r.width();
+
+ _labels[_floatingLabel]->x = _si;
+ _labels[_floatingLabel]->y = _di;
}
+
+
+
uint Gfx::createLabel(Font *font, const char *text, byte color) {
- assert(_numLabels < MAX_NUM_LABELS);
+ assert(_labels.size() < MAX_NUM_LABELS);
- Label *label = new Label;
- Graphics::Surface *cnv = &label->_cnv;
+ Graphics::Surface *cnv = new Graphics::Surface;
uint w, h;
@@ -726,122 +609,65 @@ uint Gfx::createLabel(Font *font, const char *text, byte color) {
drawText(font, cnv, 0, 0, text, color);
}
- uint id = _numLabels;
- _labels[id] = label;
- _numLabels++;
+ GfxObj *obj = new GfxObj(kGfxObjTypeLabel, new SurfaceToFrames(cnv), "label");
+ obj->transparentKey = LABEL_TRANSPARENT_COLOR;
+ obj->layer = LAYER_FOREGROUND;
+
+ int id = _labels.size();
+
+ _labels.insert_at(id, obj);
return id;
}
void Gfx::showLabel(uint id, int16 x, int16 y) {
- assert(id < _numLabels);
- _labels[id]->_visible = true;
+ assert(id < _labels.size());
+ _labels[id]->setFlags(kGfxObjVisible);
+
+ Common::Rect r;
+ _labels[id]->getRect(0, r);
if (x == CENTER_LABEL_HORIZONTAL) {
- x = CLIP<int16>((_vm->_screenWidth - _labels[id]->_cnv.w) / 2, 0, _vm->_screenWidth/2);
+ x = CLIP<int16>((_vm->_screenWidth - r.width()) / 2, 0, _vm->_screenWidth/2);
}
if (y == CENTER_LABEL_VERTICAL) {
- y = CLIP<int16>((_vm->_screenHeight - _labels[id]->_cnv.h) / 2, 0, _vm->_screenHeight/2);
+ y = CLIP<int16>((_vm->_screenHeight - r.height()) / 2, 0, _vm->_screenHeight/2);
}
- _labels[id]->_pos.x = x;
- _labels[id]->_pos.y = y;
+ _labels[id]->x = x;
+ _labels[id]->y = y;
}
void Gfx::hideLabel(uint id) {
- assert(id < _numLabels);
- _labels[id]->_visible = false;
+ assert(id < _labels.size());
+ _labels[id]->clearFlags(kGfxObjVisible);
}
void Gfx::freeLabels() {
- for (uint i = 0; i < _numLabels; i++) {
+ for (uint i = 0; i < _labels.size(); i++) {
delete _labels[i];
}
- _numLabels = 0;
-}
-
-
-void Gfx::setFloatingLabel(Label *label) {
- _floatingLabel = label;
-
- if (_floatingLabel) {
- _floatingLabel->resetPosition();
- }
-}
-
-void Gfx::updateFloatingLabel() {
- if (!_floatingLabel) {
- return;
- }
-
- int16 _si, _di;
-
- Common::Point cursor;
- _vm->_input->getCursorPos(cursor);
-
- if (_vm->_input->_activeItem._id != 0) {
- _si = cursor.x + 16 - _floatingLabel->_cnv.w/2;
- _di = cursor.y + 34;
- } else {
- _si = cursor.x + 8 - _floatingLabel->_cnv.w/2;
- _di = cursor.y + 21;
- }
-
- if (_si < 0) _si = 0;
- if (_di > 190) _di = 190;
-
- if (_floatingLabel->_cnv.w + _si > _vm->_screenWidth)
- _si = _vm->_screenWidth - _floatingLabel->_cnv.w;
-
- _floatingLabel->_pos.x = _si;
- _floatingLabel->_pos.y = _di;
+ _labels.clear();
+ _floatingLabel = NO_FLOATING_LABEL;
}
void Gfx::drawLabels() {
- if ((!_floatingLabel) && (_numLabels == 0)) {
+ if (_labels.size() == 0) {
return;
}
+
updateFloatingLabel();
Graphics::Surface* surf = g_system->lockScreen();
- for (uint i = 0; i < _numLabels; i++) {
- if (_labels[i]->_visible) {
- Common::Rect r(_labels[i]->_cnv.w, _labels[i]->_cnv.h);
- r.moveTo(_labels[i]->_pos);
- blt(r, (byte*)_labels[i]->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR);
- }
- }
-
- if (_floatingLabel) {
- Common::Rect r(_floatingLabel->_cnv.w, _floatingLabel->_cnv.h);
- r.moveTo(_floatingLabel->_pos);
- blt(r, (byte*)_floatingLabel->_cnv.getBasePtr(0, 0), surf, LAYER_FOREGROUND, LABEL_TRANSPARENT_COLOR);
+ for (uint i = 0; i < _labels.size(); i++) {
+ drawGfxObject(_labels[i], *surf, false);
}
g_system->unlockScreen();
}
-Label::Label() {
- resetPosition();
- _visible = false;
-}
-
-Label::~Label() {
- free();
-}
-
-void Label::free() {
- _cnv.free();
- resetPosition();
-}
-
-void Label::resetPosition() {
- _pos.x = -1000;
- _pos.y = -1000;
-}
-
void Gfx::getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height) {
@@ -917,10 +743,8 @@ Gfx::Gfx(Parallaction* vm) :
setPalette(_palette);
- _numBalloons = 0;
_numItems = 0;
- _numLabels = 0;
- _floatingLabel = 0;
+ _floatingLabel = NO_FLOATING_LABEL;
_screenX = 0;
_screenY = 0;
@@ -943,20 +767,21 @@ Gfx::Gfx(Parallaction* vm) :
Gfx::~Gfx() {
freeBackground();
+ freeLabels();
return;
}
-int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) {
+int Gfx::setItem(GfxObj* frames, uint16 x, uint16 y, byte transparentColor) {
int id = _numItems;
_items[id].data = frames;
- _items[id].x = x;
- _items[id].y = y;
-
- _items[id].transparentColor = transparentColor;
+ _items[id].data->x = x;
+ _items[id].data->y = y;
+ _items[id].data->layer = LAYER_FOREGROUND;
+ _items[id].data->transparentKey = transparentColor;
_numItems++;
@@ -965,206 +790,35 @@ int Gfx::setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor) {
void Gfx::setItemFrame(uint item, uint16 f) {
assert(item < _numItems);
- _items[item].frame = f;
- _items[item].data->getRect(f, _items[item].rect);
- _items[item].rect.moveTo(_items[item].x, _items[item].y);
-}
-
-Gfx::Balloon* Gfx::getBalloon(uint id) {
- assert(id < _numBalloons);
- return &_balloons[id];
-}
-
-int Gfx::createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness) {
- assert(_numBalloons < 5);
-
- int id = _numBalloons;
-
- Gfx::Balloon *balloon = &_balloons[id];
-
- int16 real_h = (winding == -1) ? h : h + 9;
- balloon->surface.create(w, real_h, 1);
- balloon->surface.fillRect(Common::Rect(w, real_h), BALLOON_TRANSPARENT_COLOR);
-
- Common::Rect r(w, h);
- balloon->surface.fillRect(r, 0);
- balloon->outerBox = r;
-
- r.grow(-borderThickness);
- balloon->surface.fillRect(r, 1);
- balloon->innerBox = r;
-
- if (winding != -1) {
- // draws tail
- // TODO: this bitmap tail should only be used for Dos games. Amiga should use a polygon fill.
- winding = (winding == 0 ? 1 : 0);
- Common::Rect s(BALLOON_TAIL_WIDTH, BALLOON_TAIL_HEIGHT);
- s.moveTo(r.width()/2 - 5, r.bottom - 1);
- blt(s, _resBalloonTail[winding], &balloon->surface, LAYER_FOREGROUND, BALLOON_TRANSPARENT_COLOR);
- }
-
- _numBalloons++;
-
- return id;
-}
-
-int Gfx::setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+5, h, winding, 1);
- Gfx::Balloon *balloon = &_balloons[id];
-
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-
- balloon->x = x;
- balloon->y = y;
-
- return id;
-}
-
-int Gfx::setDialogueBalloon(char *text, uint16 winding, byte textColor) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+5, h, winding, 1);
- Gfx::Balloon *balloon = &_balloons[id];
-
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-
- balloon->x = _dialogueBalloonX[id];
- balloon->y = 10;
-
- if (id > 0) {
- balloon->y += _balloons[id - 1].y + _balloons[id - 1].outerBox.height();
- }
-
-
- return id;
+ _items[item].data->frame = f;
+ _items[item].data->setFlags(kGfxObjVisible);
}
-void Gfx::setBalloonText(uint id, char *text, byte textColor) {
- Gfx::Balloon *balloon = getBalloon(id);
- balloon->surface.fillRect(balloon->innerBox, 1);
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, textColor, MAX_BALLOON_WIDTH);
-}
-
-
-int Gfx::setLocationBalloon(char *text, bool endGame) {
-
- int16 w, h;
-
- getStringExtent(_vm->_dialogueFont, text, MAX_BALLOON_WIDTH, &w, &h);
-
- int id = createBalloon(w+(endGame ? 5 : 10), h+5, -1, BALLOON_TRANSPARENT_COLOR);
- Gfx::Balloon *balloon = &_balloons[id];
- drawWrappedText(_vm->_dialogueFont, &balloon->surface, text, 0, MAX_BALLOON_WIDTH);
-
- balloon->x = 5;
- balloon->y = 5;
- return id;
-}
+GfxObj* Gfx::registerBalloon(Frames *frames, const char *text) {
-int Gfx::hitTestDialogueBalloon(int x, int y) {
+ GfxObj *obj = new GfxObj(kGfxObjTypeBalloon, frames, text);
- Common::Point p;
+ obj->layer = LAYER_FOREGROUND;
+ obj->frame = 0;
+ obj->setFlags(kGfxObjVisible);
- for (uint i = 0; i < _numBalloons; i++) {
- p.x = x - _balloons[i].x;
- p.y = y - _balloons[i].y;
-
- if (_balloons[i].innerBox.contains(p))
- return i;
- }
+ _balloons.push_back(obj);
- return -1;
+ return obj;
}
-
-void Gfx::freeBalloons() {
- for (uint i = 0; i < _numBalloons; i++) {
- _balloons[i].surface.free();
+void Gfx::destroyBalloons() {
+ for (uint i = 0; i < _balloons.size(); i++) {
+ delete _balloons[i];
}
- _numBalloons = 0;
+ _balloons.clear();
}
void Gfx::freeItems() {
_numItems = 0;
}
-void Gfx::hideDialogueStuff() {
- freeItems();
- freeBalloons();
-}
-
-void Gfx::drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color) {
- byte *dst = (byte*)surf->getBasePtr(x, y);
- font->setColor(color);
- font->drawString(dst, surf->w, text);
-}
-
-void Gfx::drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth) {
-
- uint16 lines = 0;
- uint16 linewidth = 0;
-
- uint16 rx = 10;
- uint16 ry = 4;
-
- uint16 blankWidth = font->getStringWidth(" ");
- uint16 tokenWidth = 0;
-
- char token[MAX_TOKEN_LEN];
-
- if (wrapwidth == -1)
- wrapwidth = _vm->_screenWidth;
-
- while (strlen(text) > 0) {
-
- text = parseNextToken(text, token, MAX_TOKEN_LEN, " ", true);
-
- if (!scumm_stricmp(token, "%p")) {
- lines++;
- rx = 10;
- ry = 4 + lines*10; // y
-
- strcpy(token, "> .......");
- strncpy(token+2, _password, strlen(_password));
- tokenWidth = font->getStringWidth(token);
- } else {
- tokenWidth = font->getStringWidth(token);
-
- linewidth += tokenWidth;
-
- if (linewidth > wrapwidth) {
- // wrap line
- lines++;
- rx = 10; // x
- ry = 4 + lines*10; // y
- linewidth = tokenWidth;
- }
-
- if (!scumm_stricmp(token, "%s")) {
- sprintf(token, "%d", _score);
- }
-
- }
-
- drawText(font, surf, rx, ry, token, color);
-
- rx += tokenWidth + blankWidth;
- linewidth += blankWidth;
-
- text = Common::ltrim(text);
- }
-
-}
-
void Gfx::freeBackground() {
_backgroundInfo.free();
}
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index f03b8538b8..09f4b2f244 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -157,11 +157,11 @@ struct SurfaceToMultiFrames : public Frames {
r.setHeight(_height);
}
uint getRawSize(uint16 index) {
- assert(index == 0);
+ assert(index < _num);
return getSize(index);
}
uint getSize(uint16 index) {
- assert(index == 0);
+ assert(index < _num);
return _width * _height;
}
@@ -326,20 +326,6 @@ public:
#define CENTER_LABEL_HORIZONTAL -1
#define CENTER_LABEL_VERTICAL -1
-struct Label {
- Graphics::Surface _cnv;
-
- Common::Point _pos;
- bool _visible;
-
- Label();
- ~Label();
-
- void free();
- void resetPosition();
-};
-
-
#define MAX_BALLOON_WIDTH 130
@@ -354,25 +340,39 @@ class Disk;
enum {
kGfxObjVisible = 1,
+ kGfxObjNormal = 2,
+ kGfxObjCharacter = 4,
kGfxObjTypeDoor = 0,
kGfxObjTypeGet = 1,
- kGfxObjTypeAnim = 2
+ kGfxObjTypeAnim = 2,
+ kGfxObjTypeLabel = 3,
+ kGfxObjTypeBalloon = 4,
+ kGfxObjTypeCharacter = 8
+};
+
+enum {
+ kGfxObjDoorZ = -200,
+ kGfxObjGetZ = -100
};
class GfxObj {
char *_name;
Frames *_frames;
- uint32 _flags;
bool _keep;
public:
int16 x, y;
- uint16 z;
+
+ int32 z;
+
+ uint32 _flags;
+
uint type;
uint frame;
uint layer;
+ uint transparentKey;
GfxObj(uint type, Frames *frames, const char *name = NULL);
virtual ~GfxObj();
@@ -453,6 +453,20 @@ enum {
kBackgroundSlide = 2
};
+
+class BalloonManager {
+public:
+ virtual ~BalloonManager() { }
+
+ virtual void freeBalloons() = 0;
+ virtual int setLocationBalloon(char *text, bool endGame) = 0;
+ virtual int setDialogueBalloon(char *text, uint16 winding, byte textColor) = 0;
+ virtual int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor) = 0;
+ virtual void setBalloonText(uint id, char *text, byte textColor) = 0;
+ virtual int hitTestDialogueBalloon(int x, int y) = 0;
+};
+
+
typedef Common::HashMap<Common::String, int32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> VarMap;
class Gfx {
@@ -461,33 +475,33 @@ public:
Disk *_disk;
VarMap _vars;
- GfxObjList _gfxobjList[3];
+ GfxObjList _gfxobjList;
GfxObj* loadAnim(const char *name);
GfxObj* loadGet(const char *name);
GfxObj* loadDoor(const char *name);
void drawGfxObjects(Graphics::Surface &surf);
void showGfxObj(GfxObj* obj, bool visible);
- void clearGfxObjects();
+ void clearGfxObjects(uint filter);
void sortAnimations();
+
// labels
- void setFloatingLabel(Label *label);
- Label *renderFloatingLabel(Font *font, char *text);
+ void showFloatingLabel(uint label);
+ void hideFloatingLabel();
+
+ uint renderFloatingLabel(Font *font, char *text);
uint createLabel(Font *font, const char *text, byte color);
void showLabel(uint id, int16 x, int16 y);
void hideLabel(uint id);
void freeLabels();
// dialogue balloons
- int setLocationBalloon(char *text, bool endGame);
- int setDialogueBalloon(char *text, uint16 winding, byte textColor);
- int setSingleBalloon(char *text, uint16 x, uint16 y, uint16 winding, byte textColor);
- void setBalloonText(uint id, char *text, byte textColor);
- int hitTestDialogueBalloon(int x, int y);
void getStringExtent(Font *font, char *text, uint16 maxwidth, int16* width, int16* height);
+ GfxObj* registerBalloon(Frames *frames, const char *text);
+ void destroyBalloons();
// other items
- int setItem(Frames* frames, uint16 x, uint16 y, byte transparentColor = 0);
+ int setItem(GfxObj* obj, uint16 x, uint16 y, byte transparentColor = 0);
void setItemFrame(uint item, uint16 f);
void hideDialogueStuff();
void freeBalloons();
@@ -549,36 +563,22 @@ protected:
Graphics::Surface _bitmapMask;
int32 getRenderMode(const char *type);
-protected:
- static int16 _dialogueBalloonX[5];
-
- struct Balloon {
- uint16 x;
- uint16 y;
- Common::Rect outerBox;
- Common::Rect innerBox;
- uint16 winding;
- Graphics::Surface surface;
- } _balloons[5];
-
- uint _numBalloons;
+public:
struct Item {
- uint16 x;
- uint16 y;
- uint16 frame;
- Frames *data;
-
- byte transparentColor;
- Common::Rect rect;
+ GfxObj *data;
} _items[14];
uint _numItems;
- #define MAX_NUM_LABELS 5
- Label* _labels[MAX_NUM_LABELS];
- uint _numLabels;
- Label *_floatingLabel;
+ #define MAX_NUM_LABELS 20
+ #define NO_FLOATING_LABEL 1000
+
+ typedef Common::Array<GfxObj*> GfxObjArray;
+ GfxObjArray _labels;
+ GfxObjArray _balloons;
+
+ uint _floatingLabel;
void drawInventory();
void updateFloatingLabel();
@@ -588,13 +588,11 @@ protected:
void copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst);
- int createBalloon(int16 w, int16 h, int16 winding, uint16 borderThickness);
- Balloon *getBalloon(uint id);
-
// low level text and patches
void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color);
void drawWrappedText(Font *font, Graphics::Surface* surf, char *text, byte color, int16 wrapwidth);
+ void drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene);
void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, byte transparentColor);
void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, byte transparentColor);
};
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index e073a7c989..391459a12f 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -123,7 +123,7 @@ int Parallaction_br::guiShowMenu() {
// TODO: filter menu entries according to progress in game
#define NUM_MENULINES 7
- Frames *_lines[NUM_MENULINES];
+ GfxObj *_lines[NUM_MENULINES];
const char *menuStrings[NUM_MENULINES] = {
"SEE INTRO",
@@ -158,7 +158,7 @@ int Parallaction_br::guiShowMenu() {
int i;
for (i = 0; i < availItems; i++) {
- _lines[i] = guiRenderMenuItem(menuStrings[i]);
+ _lines[i] = new GfxObj(0, guiRenderMenuItem(menuStrings[i]), "MenuItem");
uint id = _gfx->setItem(_lines[i], MENUITEMS_X, MENUITEMS_Y + MENUITEM_HEIGHT * i, 0xFF);
_gfx->setItemFrame(id, 0);
}
@@ -196,7 +196,7 @@ int Parallaction_br::guiShowMenu() {
}
_system->showMouse(false);
- _gfx->hideDialogueStuff();
+ hideDialogueStuff();
for (i = 0; i < availItems; i++) {
delete _lines[i];
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 1d4d44fa46..9c48586dbc 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -166,6 +166,8 @@ void Parallaction_ns::guiStart() {
}
void Parallaction_ns::selectStartLocation() {
+ _inTestResult = false;
+
int character = guiSelectCharacter();
if (character == -1)
error("invalid character selected from menu screen");
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 0fc00ce03b..9d5ff4ef80 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -174,7 +174,7 @@ void Input::updateGameInput() {
void Input::updateCommentInput() {
waitUntilLeftClick();
- _vm->_gfx->hideDialogueStuff();
+ _vm->hideDialogueStuff();
_vm->_gfx->setHalfbriteMode(false);
_inputMode = kInputModeGame;
@@ -302,7 +302,7 @@ bool Input::translateInventoryInput() {
_vm->dropItem(z->u.merge->_obj1);
_vm->dropItem(z->u.merge->_obj2);
_vm->addInventoryItem(z->u.merge->_obj3);
- _vm->runCommands(z->_commands);
+ _vm->_cmdExec->run(z->_commands);
}
return true;
diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h
index 46dbb08c4e..e06fe96705 100644
--- a/engines/parallaction/input.h
+++ b/engines/parallaction/input.h
@@ -44,7 +44,7 @@ struct InputData {
Common::Point _mousePos;
int16 _inventoryIndex;
ZonePtr _zone;
- Label* _label;
+ uint _label;
};
class Input {
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
index 2478b4b2e1..fb867f5285 100644
--- a/engines/parallaction/module.mk
+++ b/engines/parallaction/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/parallaction
MODULE_OBJS := \
+ balloons.o \
callables_br.o \
callables_ns.o \
debug.o \
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index cac31911f4..66025cf0f7 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -54,6 +54,7 @@ Animation::Animation() {
Animation::~Animation() {
free(_scriptName);
+ gfxobj->release();
}
uint16 Animation::width() const {
@@ -182,7 +183,8 @@ Zone::~Zone() {
break;
}
- delete _label;
+
+ free(_linkedName);
}
void Zone::getRect(Common::Rect& r) const {
@@ -207,6 +209,16 @@ uint16 Zone::height() const {
return _bottom - _top;
}
+Dialogue::Dialogue() {
+ memset(_questions, 0, sizeof(_questions));
+}
+
+Dialogue::~Dialogue() {
+ for (int i = 0; i < NUM_QUESTIONS; i++) {
+ delete _questions[i];
+ }
+}
+
Answer::Answer() {
_text = NULL;
_mood = 0;
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index afa6cc5ed5..19835da9d0 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -181,6 +181,9 @@ struct Question {
struct Dialogue {
Question *_questions[NUM_QUESTIONS];
+
+ Dialogue();
+ ~Dialogue();
};
struct GetData { // size = 24
@@ -206,7 +209,7 @@ struct SpeakData { // size = 36
}
};
struct ExamineData { // size = 28
- Frames *_cnv;
+ GfxObj *_cnv;
uint16 _opBase; // unused
uint16 field_12; // unused
char* _description;
@@ -284,7 +287,7 @@ struct Zone {
int16 _bottom;
uint32 _type;
uint32 _flags;
- Label *_label;
+ uint _label;
uint16 field_2C; // unused
uint16 field_2E; // unused
TypeData u;
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index ee8e0cbcc8..2fc809977f 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -84,18 +84,20 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
Parallaction::~Parallaction() {
- clearSet(_commandOpcodes);
- clearSet(_instructionOpcodes);
-
delete _debugger;
delete _globalTable;
delete _callableNames;
+ delete _cmdExec;
+ delete _programExec;
+ _gfx->clearGfxObjects(kGfxObjCharacter | kGfxObjNormal);
+ hideDialogueStuff();
+ delete _balloonMan;
freeLocation();
freeCharacter();
destroyInventory();
-
+
delete _localFlagNames;
delete _gfx;
delete _soundMan;
@@ -136,6 +138,8 @@ int Parallaction::init() {
_debugger = new Debugger(this);
+ setupBalloonManager();
+
return 0;
}
@@ -166,6 +170,8 @@ void Parallaction::freeCharacter() {
delete _objectsNames;
_objectsNames = 0;
+ _gfx->clearGfxObjects(kGfxObjCharacter);
+
_char.free();
return;
@@ -195,6 +201,9 @@ AnimationPtr Parallaction::findAnimation(const char *name) {
}
void Parallaction::freeAnimations() {
+ for (AnimationList::iterator it = _location._animations.begin(); it != _location._animations.end(); it++) {
+ (*it)->_commands.clear(); // See comment for freeZones(), about circular references.
+ }
_location._animations.clear();
return;
}
@@ -245,7 +254,7 @@ void Parallaction::freeLocation() {
_location._walkNodes.clear();
- _gfx->clearGfxObjects();
+ _gfx->clearGfxObjects(kGfxObjNormal);
freeBackground();
_location._programs.clear();
@@ -280,7 +289,7 @@ void Parallaction::setBackground(const char* name, const char* mask, const char*
}
void Parallaction::showLocationComment(const char *text, bool end) {
- _gfx->setLocationBalloon(const_cast<char*>(text), end);
+ _balloonMan->setLocationBalloon(const_cast<char*>(text), end);
}
@@ -289,12 +298,12 @@ void Parallaction::processInput(InputData *data) {
switch (data->_event) {
case kEvEnterZone:
debugC(2, kDebugInput, "processInput: kEvEnterZone");
- _gfx->setFloatingLabel(data->_label);
+ _gfx->showFloatingLabel(data->_label);
break;
case kEvExitZone:
debugC(2, kDebugInput, "processInput: kEvExitZone");
- _gfx->setFloatingLabel(0);
+ _gfx->hideFloatingLabel();
break;
case kEvAction:
@@ -307,7 +316,7 @@ void Parallaction::processInput(InputData *data) {
case kEvOpenInventory:
_input->stopHovering();
- _gfx->setFloatingLabel(0);
+ _gfx->hideFloatingLabel();
if (hitZone(kZoneYou, data->_mousePos.x, data->_mousePos.y) == 0) {
setArrowCursor();
}
@@ -379,8 +388,12 @@ void Parallaction::runGame() {
_gfx->beginFrame();
if (_input->_inputMode == Input::kInputModeGame) {
- runScripts();
- walk();
+ _programExec->runScripts(_location._programs.begin(), _location._programs.end());
+ _char._ani->_z = _char._ani->height() + _char._ani->_top;
+ if (_char._ani->gfxobj) {
+ _char._ani->gfxobj->z = _char._ani->_z;
+ }
+ walk(_char);
drawAnimations();
}
@@ -415,14 +428,14 @@ void Parallaction::doLocationEnterTransition() {
pal.makeGrayscale();
_gfx->setPalette(pal);
- runScripts();
+ _programExec->runScripts(_location._programs.begin(), _location._programs.end());
drawAnimations();
_gfx->updateScreen();
showLocationComment(_location._comment, false);
_input->waitUntilLeftClick();
- _gfx->freeBalloons();
+ _balloonMan->freeBalloons();
// fades maximum intensity palette towards approximation of main palette
for (uint16 _si = 0; _si<6; _si++) {
@@ -482,6 +495,9 @@ void Parallaction::freeZones() {
debugC(2, kDebugExec, "freeZones preserving zone '%s'", z->_name);
it++;
} else {
+ (*it)->_commands.clear(); // Since commands may reference zones, and both commands and zones are kept stored into
+ // SharedPtr's, we need to kill commands explicitly to destroy any potential circular
+ // reference.
it = _location._zones.erase(it);
}
}
@@ -490,6 +506,34 @@ void Parallaction::freeZones() {
}
+enum {
+ WALK_LEFT = 0,
+ WALK_RIGHT = 1,
+ WALK_DOWN = 2,
+ WALK_UP = 3
+};
+
+struct WalkFrames {
+ int16 stillFrame[4];
+ int16 firstWalkFrame[4];
+ int16 numWalkFrames[4];
+ int16 frameRepeat[4];
+};
+
+WalkFrames _char20WalkFrames = {
+ { 0, 7, 14, 17 },
+ { 1, 8, 15, 18 },
+ { 6, 6, 2, 2 },
+ { 2, 2, 4, 4 }
+};
+
+WalkFrames _char24WalkFrames = {
+ { 0, 9, 18, 21 },
+ { 1, 10, 19, 22 },
+ { 8, 8, 2, 2 },
+ { 2, 2, 4, 4 }
+};
+
const char Character::_prefixMini[] = "mini";
const char Character::_suffixTras[] = "tras";
const char Character::_empty[] = "\0";
@@ -500,6 +544,9 @@ Character::Character(Parallaction *vm) : _vm(vm), _ani(new Animation), _builder(
_head = NULL;
_objs = NULL;
+ _direction = WALK_DOWN;
+ _step = 0;
+
_dummy = false;
_ani->_left = 150;
@@ -564,10 +611,14 @@ void Character::setName(const char *name) {
const char *end = begin + strlen(name);
_prefix = _empty;
+ _suffix = _empty;
_dummy = IS_DUMMY_CHARACTER(name);
if (!_dummy) {
+ if (!strstr(name, "donna")) {
+ _engineFlags &= ~kEngineTransformedDonna;
+ } else
if (_engineFlags & kEngineTransformedDonna) {
_suffix = _suffixTras;
} else {
@@ -576,8 +627,6 @@ void Character::setName(const char *name) {
_engineFlags |= kEngineTransformedDonna;
_suffix = _suffixTras;
end = s;
- } else {
- _suffix = _empty;
}
}
if (IS_MINI_CHARACTER(name)) {
@@ -618,4 +667,29 @@ void Parallaction::scheduleLocationSwitch(const char *location) {
}
+
+
+
+void Character::updateDirection(const Common::Point& pos, const Common::Point& to) {
+
+ Common::Point dist(to.x - pos.x, to.y - pos.y);
+ WalkFrames *frames = (_ani->getFrameNum() == 20) ? &_char20WalkFrames : &_char24WalkFrames;
+
+ _step++;
+
+ if (dist.x == 0 && dist.y == 0) {
+ _ani->_frame = frames->stillFrame[_direction];
+ return;
+ }
+
+ if (dist.x < 0)
+ dist.x = -dist.x;
+ if (dist.y < 0)
+ dist.y = -dist.y;
+
+ _direction = (dist.x > dist.y) ? ((to.x > pos.x) ? WALK_LEFT : WALK_RIGHT) : ((to.y > pos.y) ? WALK_DOWN : WALK_UP);
+ _ani->_frame = frames->firstWalkFrame[_direction] + (_step / frames->frameRepeat[_direction]) % frames->numWalkFrames[_direction];
+}
+
+
} // namespace Parallaction
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 9f8bbea1b0..461ddc674f 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -33,6 +33,7 @@
#include "engines/engine.h"
+#include "parallaction/exec.h"
#include "parallaction/input.h"
#include "parallaction/inventory.h"
#include "parallaction/parser.h"
@@ -201,9 +202,9 @@ struct Character {
AnimationPtr _ani;
- Frames *_head;
- Frames *_talk;
- Frames *_objs;
+ GfxObj *_head;
+ GfxObj *_talk;
+ GfxObj *_objs;
PathBuilder _builder;
WalkNodeList *_walkPath;
@@ -227,18 +228,19 @@ protected:
static const char _suffixTras[];
static const char _empty[];
+ int16 _direction, _step;
+
public:
void setName(const char *name);
const char *getName() const;
const char *getBaseName() const;
const char *getFullName() const;
bool dummy() const;
-};
+ void updateDirection(const Common::Point& pos, const Common::Point& to);
+};
-#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op()
-#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op()
#define NUM_LOCATIONS 120
@@ -263,31 +265,14 @@ public:
Input *_input;
- OpcodeSet _commandOpcodes;
-
- struct ParallactionStruct1 {
- CommandPtr cmd;
- ZonePtr z;
- } _cmdRunCtxt;
-
- OpcodeSet _instructionOpcodes;
-
- struct ParallactionStruct2 {
- AnimationPtr anim;
- ProgramPtr program;
- InstructionList::iterator inst;
- uint16 modCounter;
- bool suspend;
- } _instRunCtxt;
-
void processInput(InputData* data);
void pauseJobs();
void resumeJobs();
- void finalizeWalk(WalkNodeList *list);
- int16 selectWalkFrame(const Common::Point& pos, const WalkNodePtr from);
- void clipMove(Common::Point& pos, const WalkNodePtr from);
+ void finalizeWalk(Character &character);
+ int16 selectWalkFrame(Character &character, const Common::Point& pos, const WalkNodePtr to);
+ void clipMove(Common::Point& pos, const Common::Point& to);
ZonePtr findZone(const char *name);
ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
@@ -296,8 +281,6 @@ public:
void runDialogue(SpeakData*);
- void runCommands(CommandList& list, ZonePtr z = nullZonePtr);
-
AnimationPtr findAnimation(const char *name);
void freeAnimations();
@@ -331,6 +314,8 @@ public:
Gfx* _gfx;
Disk* _disk;
+ CommandExec* _cmdExec;
+ ProgramExec* _programExec;
Character _char;
void setLocationFlags(uint32 flags);
@@ -371,10 +356,8 @@ protected: // members
void runGame();
void updateView();
- void scheduleLocationSwitch(const char *location);
void doLocationEnterTransition();
virtual void changeLocation(char *location) = 0;
- virtual void changeCharacter(const char *name) = 0;
virtual void runPendingZones() = 0;
void allocateLocationSlot(const char *name);
void finalizeLocationParsing();
@@ -383,7 +366,7 @@ protected: // members
void displayComment(ExamineData *data);
- uint16 checkDoor();
+ void checkDoor(const Common::Point &foot);
void freeCharacter();
@@ -393,6 +376,9 @@ protected: // members
public:
+ void scheduleLocationSwitch(const char *location);
+ virtual void changeCharacter(const char *name) = 0;
+
virtual void callFunction(uint index, void* parm) { }
virtual void setArrowCursor() = 0;
@@ -402,12 +388,12 @@ public:
void updateDoor(ZonePtr z);
- virtual void runScripts() = 0;
- virtual void walk() = 0;
+ virtual void walk(Character &character) = 0;
virtual void drawAnimations() = 0;
void beep();
+ ZonePtr _zoneTrap;
public:
// const char **_zoneFlagNamesRes;
@@ -433,6 +419,15 @@ public:
Inventory *_inventory;
InventoryRenderer *_inventoryRenderer;
+ BalloonManager *_balloonMan;
+
+ void setupBalloonManager();
+
+ void hideDialogueStuff() {
+ _gfx->freeItems();
+ _balloonMan->freeBalloons();
+ }
+
};
@@ -528,7 +523,6 @@ private:
void initResources();
void initCursors();
- void initParsers();
static byte _resMouseArrow[256];
byte *_mouseArrow;
@@ -552,6 +546,9 @@ private:
ZonePtr _moveSarcExaZones[5];
AnimationPtr _rightHandAnim;
+ bool _inTestResult;
+
+
// common callables
void _c_play_boogie(void*);
void _c_startIntro(void*);
@@ -588,49 +585,12 @@ private:
const Callable *_callables;
protected:
- void runScripts();
- void walk();
+ void walk(Character &character);
void drawAnimations();
void parseLocation(const char *filename);
void loadProgram(AnimationPtr a, const char *filename);
- void initOpcodes();
-
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(set);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(get);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
-
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
-
void selectStartLocation();
void guiStart();
@@ -663,6 +623,9 @@ public:
typedef void (Parallaction_br::*Callable)(void*);
virtual void callFunction(uint index, void* parm);
void changeCharacter(const char *name);
+ void setupSubtitles(char *s, char *s2, int y);
+ void clearSubtitles();
+
public:
Table *_countersNames;
@@ -690,8 +653,6 @@ private:
void initResources();
void initFonts();
void freeFonts();
- void initOpcodes();
- void initParsers();
void setArrowCursor();
void setInventoryCursor(int pos);
@@ -733,68 +694,6 @@ private:
void parseLocation(const char* name);
void loadProgram(AnimationPtr a, const char *filename);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(location);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(open);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(close);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(on);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(off);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(call);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(move);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(start);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(character);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(add);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(let);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(music);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(give);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(text);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(part);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave);
- DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave);
-
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop);
- DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript);
-
- void setupSubtitles(char *s, char *s2, int y);
- void clearSubtitles();
#if 0
void jobWaitRemoveLabelJob(void *parm, Job *job);
void jobPauseSfx(void *parm, Job *job);
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 72a829d7cb..090184e9fe 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -72,14 +72,21 @@ int Parallaction_br::init() {
initResources();
initFonts();
initCursors();
- initOpcodes();
_locationParser = new LocationParser_br(this);
_locationParser->init();
_programParser = new ProgramParser_br(this);
_programParser->init();
+ _cmdExec = new CommandExec_br(this);
+ _cmdExec->init();
+ _programExec = new ProgramExec_br(this);
+ _programExec->init();
+
_part = -1;
+ _subtitle[0] = -1;
+ _subtitle[1] = -1;
+
Parallaction::init();
return 0;
@@ -221,10 +228,16 @@ void Parallaction_br::changeLocation(char *location) {
// free open location stuff
clearSubtitles();
freeBackground();
- _gfx->clearGfxObjects();
+ _gfx->clearGfxObjects(kGfxObjNormal | kGfxObjCharacter);
_location._programs.clear();
+
+ _location._animations.remove(_char._ani);
+
freeZones();
freeAnimations();
+
+ _location._animations.push_front(_char._ani);
+
// free(_location._comment);
// _location._comment = 0;
// _location._commands.clear();
@@ -233,9 +246,9 @@ void Parallaction_br::changeLocation(char *location) {
// load new location
parseLocation(location);
- runCommands(_location._commands);
+ _cmdExec->run(_location._commands);
// doLocationEnterTransition();
- runCommands(_location._aCommands);
+ _cmdExec->run(_location._aCommands);
_engineFlags &= ~kEngineChangeLocation;
}
@@ -284,12 +297,16 @@ void Parallaction_br::loadProgram(AnimationPtr a, const char *filename) {
void Parallaction_br::changeCharacter(const char *name) {
+ printf("changeCharacter(%s)\n", name);
+
const char *charName = _char.getName();
if (!scumm_stricmp(charName, name)) {
return;
}
_char.setName(name);
+ _char._ani->gfxobj = _gfx->loadAnim(name);
+ _char._ani->gfxobj->setFlags(kGfxObjCharacter);
_char._talk = _disk->loadTalk(name);
}
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 318443bb18..e5baf1864d 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -135,18 +135,24 @@ int Parallaction_ns::init() {
initResources();
initFonts();
initCursors();
- initOpcodes();
_locationParser = new LocationParser_ns(this);
_locationParser->init();
_programParser = new ProgramParser_ns(this);
_programParser->init();
+ _cmdExec = new CommandExec_ns(this);
+ _cmdExec->init();
+ _programExec = new ProgramExec_ns(this);
+ _programExec->init();
+
_introSarcData1 = 0;
_introSarcData2 = 1;
_introSarcData3 = 200;
num_foglie = 0;
+ _inTestResult = false;
+
_location._animations.push_front(_char._ani);
Parallaction::init();
@@ -156,7 +162,7 @@ int Parallaction_ns::init() {
Parallaction_ns::~Parallaction_ns() {
freeFonts();
-
+
delete _locationParser;
delete _programParser;
delete _mouseComposedArrow;
@@ -185,7 +191,7 @@ void Parallaction_ns::setArrowCursor() {
debugC(1, kDebugInput, "setting mouse cursor to arrow");
// this stuff is needed to avoid artifacts with labels and selected items when switching cursors
- _gfx->setFloatingLabel(0);
+ _gfx->hideFloatingLabel();
_input->_activeItem._id = 0;
_system->setMouseCursor(_mouseArrow, MOUSEARROW_WIDTH, MOUSEARROW_HEIGHT, 0, 0, 0);
@@ -235,10 +241,10 @@ int Parallaction_ns::go() {
_globalTable = _disk->loadTable("global");
guiStart();
-
+
if (quit())
return _eventMan->shouldRTL();
-
+
changeLocation(_location._name);
if (quit())
@@ -296,14 +302,17 @@ void Parallaction_ns::changeLocation(char *location) {
_soundMan->playLocationMusic(location);
- _gfx->setFloatingLabel(0);
+ _gfx->hideFloatingLabel();
_gfx->freeLabels();
+ _zoneTrap = nullZonePtr;
+
_input->stopHovering();
if (_engineFlags & kEngineBlockInput) {
setArrowCursor();
}
+ _gfx->showGfxObj(_char._ani->gfxobj, false);
_location._animations.remove(_char._ani);
freeLocation();
@@ -325,6 +334,7 @@ void Parallaction_ns::changeLocation(char *location) {
}
_location._animations.push_front(_char._ani);
+ _gfx->showGfxObj(_char._ani->gfxobj, true);
strcpy(_saveData1, locname.location());
parseLocation(_saveData1);
@@ -349,11 +359,11 @@ void Parallaction_ns::changeLocation(char *location) {
// and acommands are executed, so that it can be set again if needed.
_engineFlags &= ~kEngineChangeLocation;
- runCommands(_location._commands);
+ _cmdExec->run(_location._commands);
doLocationEnterTransition();
- runCommands(_location._aCommands);
+ _cmdExec->run(_location._aCommands);
if (_location._hasSound)
_soundMan->playSfx(_location._soundFile, 0, true);
@@ -409,6 +419,7 @@ void Parallaction_ns::changeCharacter(const char *name) {
Common::String oldArchive = _disk->selectArchive((getFeatures() & GF_DEMO) ? "disk0" : "disk1");
_char._ani->gfxobj = _gfx->loadAnim(_char.getFullName());
+ _char._ani->gfxobj->setFlags(kGfxObjCharacter);
if (!_char.dummy()) {
if (getPlatform() == Common::kPlatformAmiga) {
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index 51da7eb396..defc917a72 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -390,7 +390,7 @@ DECLARE_LOCATION_PARSER(flags) {
if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
// only for 1st visit
- _vm->clearLocationFlags(kFlagsAll);
+ _vm->clearLocationFlags((uint32)kFlagsAll);
int _si = 1;
do {
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index c654e3008e..2f4d2df776 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -1059,7 +1059,7 @@ DECLARE_LOCATION_PARSER(flags) {
if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
// only for 1st visit
- _vm->clearLocationFlags(kFlagsAll);
+ _vm->clearLocationFlags((uint32)kFlagsAll);
int _si = 1;
do {
diff --git a/engines/parallaction/sound.cpp b/engines/parallaction/sound.cpp
index dd74e8f7aa..df6867a90c 100644
--- a/engines/parallaction/sound.cpp
+++ b/engines/parallaction/sound.cpp
@@ -175,6 +175,7 @@ void MidiPlayer::close() {
_mutex.lock();
_driver->setTimerCallback(NULL, NULL);
_driver->close();
+ delete _driver;
_driver = 0;
_parser->setMidiDriver(NULL);
delete _parser;
@@ -249,6 +250,9 @@ void DosSoundMan::stopMusic() {
}
void DosSoundMan::playCharacterMusic(const char *character) {
+ if (character == NULL) {
+ return;
+ }
if (!scumm_stricmp(_vm->_location._name, "night") ||
!scumm_stricmp(_vm->_location._name, "intsushi")) {
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index 0a8ded9e29..40dfddb903 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -27,12 +27,6 @@
namespace Parallaction {
-static uint16 _doorData1 = 1000;
-static ZonePtr _zoneTrap;
-
-static uint16 walkData1 = 0;
-static uint16 walkData2 = 0; // next walk frame
-
inline byte PathBuffer::getValue(uint16 x, uint16 y) {
byte m = data[(x >> 3) + y * internalWidth];
@@ -259,172 +253,117 @@ uint16 PathBuilder::walkFunc1(int16 x, int16 y, WalkNodePtr Node) {
return 1;
}
-void Parallaction::clipMove(Common::Point& pos, const WalkNodePtr from) {
+void Parallaction::clipMove(Common::Point& pos, const Common::Point& to) {
- if ((pos.x < from->_x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) {
- pos.x = (pos.x + 2 < from->_x) ? pos.x + 2 : from->_x;
+ if ((pos.x < to.x) && (pos.x < _pathBuffer->w) && (_pathBuffer->getValue(pos.x + 2, pos.y) != 0)) {
+ pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x;
}
- if ((pos.x > from->_x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) {
- pos.x = (pos.x - 2 > from->_x) ? pos.x - 2 : from->_x;
+ if ((pos.x > to.x) && (pos.x > 0) && (_pathBuffer->getValue(pos.x - 2, pos.y) != 0)) {
+ pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x;
}
- if ((pos.y < from->_y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) {
- pos.y = (pos.y + 2 <= from->_y) ? pos.y + 2 : from->_y;
+ if ((pos.y < to.y) && (pos.y < _pathBuffer->h) && (_pathBuffer->getValue(pos.x, pos.y + 2) != 0)) {
+ pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y;
}
- if ((pos.y > from->_y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) {
- pos.y = (pos.y - 2 >= from->_y) ? pos.y - 2 :from->_y;
+ if ((pos.y > to.y) && (pos.y > 0) && (_pathBuffer->getValue(pos.x, pos.y - 2) != 0)) {
+ pos.y = (pos.y - 2 >= to.y) ? pos.y - 2 : to.y;
}
return;
}
-int16 Parallaction::selectWalkFrame(const Common::Point& pos, const WalkNodePtr from) {
-
- Common::Point dist(from->_x - pos.x, from->_y - pos.y);
-
- if (dist.x < 0)
- dist.x = -dist.x;
- if (dist.y < 0)
- dist.y = -dist.y;
- walkData1++;
-
- // walk frame selection
- int16 v16;
- if (_char._ani->getFrameNum() == 20) {
-
- if (dist.x > dist.y) {
- walkData2 = (from->_x > pos.x) ? 0 : 7;
- walkData1 %= 12;
- v16 = walkData1 / 2;
- } else {
- walkData2 = (from->_y > pos.y) ? 14 : 17;
- walkData1 %= 8;
- v16 = walkData1 / 4;
- }
-
- } else {
-
- if (dist.x > dist.y) {
- walkData2 = (from->_x > pos.x) ? 0 : 9;
- walkData1 %= 16;
- v16 = walkData1 / 2;
- } else {
- walkData2 = (from->_y > pos.y) ? 18 : 21;
- walkData1 %= 8;
- v16 = walkData1 / 4;
- }
-
- }
-
- return v16;
-}
-
-uint16 Parallaction::checkDoor() {
-// printf("checkDoor()...");
-
- if (_currentLocationIndex != _doorData1) {
- _doorData1 = _currentLocationIndex;
- _zoneTrap = nullZonePtr;
- }
-
- _engineFlags &= ~kEngineWalking;
-
- Common::Point foot;
+void Parallaction::checkDoor(const Common::Point &foot) {
- _char.getFoot(foot);
ZonePtr z = hitZone(kZoneDoor, foot.x, foot.y);
-
if (z) {
-
if ((z->_flags & kFlagsClosed) == 0) {
_location._startPosition = z->u.door->_startPos;
_location._startFrame = z->u.door->_startFrame;
-
scheduleLocationSwitch(z->u.door->_location);
_zoneTrap = nullZonePtr;
-
} else {
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
}
}
- _char.getFoot(foot);
z = hitZone(kZoneTrap, foot.x, foot.y);
-
if (z) {
setLocationFlags(kFlagsEnter);
- runCommands(z->_commands, z);
+ _cmdExec->run(z->_commands, z);
clearLocationFlags(kFlagsEnter);
_zoneTrap = z;
} else
if (_zoneTrap) {
setLocationFlags(kFlagsExit);
- runCommands(_zoneTrap->_commands, _zoneTrap);
+ _cmdExec->run(_zoneTrap->_commands, _zoneTrap);
clearLocationFlags(kFlagsExit);
_zoneTrap = nullZonePtr;
}
-// printf("done\n");
-
- _char._ani->_frame = walkData2;
- return _char._ani->_frame;
}
-void Parallaction::finalizeWalk(WalkNodeList *list) {
- checkDoor();
- delete list;
+void Parallaction::finalizeWalk(Character &character) {
+ _engineFlags &= ~kEngineWalking;
+
+ Common::Point foot;
+ character.getFoot(foot);
+ checkDoor(foot);
+
+ delete character._walkPath;
+ character._walkPath = 0;
}
-void Parallaction_ns::walk() {
+void Parallaction_ns::walk(Character &character) {
if ((_engineFlags & kEngineWalking) == 0) {
return;
}
- WalkNodeList *list = _char._walkPath;
-
- _char._ani->_oldPos.x = _char._ani->_left;
- _char._ani->_oldPos.y = _char._ani->_top;
-
- Common::Point pos;
- _char.getFoot(pos);
-
- WalkNodeList::iterator it = list->begin();
+ Common::Point curPos;
+ character.getFoot(curPos);
- if (it != list->end()) {
- if ((*it)->_x == pos.x && (*it)->_y == pos.y) {
+ // update target, if previous was reached
+ WalkNodeList::iterator it = character._walkPath->begin();
+ if (it != character._walkPath->end()) {
+ if ((*it)->_x == curPos.x && (*it)->_y == curPos.y) {
debugC(1, kDebugWalk, "walk reached node (%i, %i)", (*it)->_x, (*it)->_y);
- it = list->erase(it);
+ it = character._walkPath->erase(it);
}
}
- if (it == list->end()) {
- debugC(1, kDebugWalk, "walk reached last node");
-// j->_finished = 1;
- finalizeWalk(list);
- return;
- }
- _char._walkPath = list;
-
- // selectWalkFrame must be performed before position is changed by clipMove
- int16 v16 = selectWalkFrame(pos, *it);
- clipMove(pos, *it);
- _char.setFoot(pos);
+ // advance character towards the target
+ Common::Point targetPos;
+ if (it == character._walkPath->end()) {
+ debugC(1, kDebugWalk, "walk reached last node");
+ finalizeWalk(character);
+ targetPos = curPos;
+ } else {
+ if (*it) {
+ // targetPos is saved to help setting character direction
+ targetPos.x = (*it)->_x;
+ targetPos.y = (*it)->_y;
+ }
- Common::Point newpos(_char._ani->_left, _char._ani->_top);
+ Common::Point newPos(curPos);
+ clipMove(newPos, targetPos);
+ character.setFoot(newPos);
- if (newpos == _char._ani->_oldPos) {
- debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
-// j->_finished = 1;
- finalizeWalk(list);
- } else {
- _char._ani->_frame = v16 + walkData2 + 1;
+ if (newPos == curPos) {
+ debugC(1, kDebugWalk, "walk was blocked by an unforeseen obstacle");
+ finalizeWalk(character);
+ }
}
- return;
+ // targetPos is used to select the direction (and the walkFrame) of a character,
+ // since it doesn't cause the sudden changes in orientation that newPos would.
+ // Since newPos is 'adjusted' according to walkable areas, an imaginary line drawn
+ // from curPos to newPos is prone to abrutply change in direction, thus making the
+ // code select 'too different' frames when walking diagonally against obstacles,
+ // and yielding an annoying shaking effect in the character.
+ character.updateDirection(curPos, targetPos);
}
diff --git a/engines/queen/resource.cpp b/engines/queen/resource.cpp
index 5a8db74e3b..b3bd663baf 100644
--- a/engines/queen/resource.cpp
+++ b/engines/queen/resource.cpp
@@ -106,7 +106,7 @@ ResourceEntry *Resource::resourceEntry(const char *filename) const {
re = &_resourceTable[cur];
break;
}
- } while (cur++ < _resourceEntries);
+ } while (++cur < _resourceEntries);
#endif
return re;
}
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 9359c6610c..753ad45212 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -492,7 +492,7 @@ static bool testGame(const GameSettings *g, const DescMap &fileMD5Map, const Com
// Note that GF_OLD_BUNDLE is true if and only if GF_OLD256 is false.
// Candidates: maniac enhanced, zak enhanced, indy3ega, loom
- if (g->version != 2 && g->version != 3 || (g->features & GF_OLD256))
+ if ((g->version != 2 && g->version != 3) || (g->features & GF_OLD256))
return false;
/* We distinguish the games by the presence/absence of
diff --git a/engines/scumm/gfxARM.s b/engines/scumm/gfxARM.s
index cd3e5c7dad..83aaa78927 100644
--- a/engines/scumm/gfxARM.s
+++ b/engines/scumm/gfxARM.s
@@ -59,7 +59,7 @@ asmDrawStripToScreen:
CMP r1,#4 @ If width<4
BLT end @ return
- @ Width &= ~4 ? What's that about then? Width &= ~3 I could have
+ @ Width &= ~4 ? What''s that about then? Width &= ~3 I could have
@ understood...
BIC r1,r1,#4
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index 33e6748860..f8fb1efca2 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -522,12 +522,13 @@ int Win32ResExtractor::do_resources_recurs(WinLibrary *fi, WinResource *base,
/* get a list of all resources at this level */
wr = list_resources(fi, base, &rescnt);
- if (wr == NULL)
+ if (wr == NULL) {
if (size != 0)
return size;
else
return 0;
-
+ }
+
/* process each resource listed */
for (c = 0 ; c < rescnt ; c++) {
/* (over)write the corresponding WinResource holder with the current */
diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h
index 33147128cb..2d4c673cf6 100644
--- a/engines/scumm/imuse_digi/dimuse_track.h
+++ b/engines/scumm/imuse_digi/dimuse_track.h
@@ -85,13 +85,15 @@ struct Track {
int getPan() const { return (pan != 64) ? 2 * pan - 127 : 0; }
int getVol() const { return vol / 1000; }
Audio::Mixer::SoundType getType() const {
- Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType;
+ Audio::Mixer::SoundType type;
if (volGroupId == 1)
type = Audio::Mixer::kSpeechSoundType;
else if (volGroupId == 2)
type = Audio::Mixer::kSFXSoundType;
else if (volGroupId == 3)
type = Audio::Mixer::kMusicSoundType;
+ else
+ error("Track::getType(): invalid sound type");
return type;
}
};
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index f2b2a67835..5894e837aa 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -411,15 +411,15 @@ void ScummEngine::listSavegames(bool *marks, int num) {
char prefix[256];
char slot[3];
int slotNum;
- Common::StringList filenames;
+ Common::StringList files;
makeSavegameName(prefix, 99, false);
prefix[strlen(prefix)-2] = '*';
prefix[strlen(prefix)-1] = 0;
memset(marks, false, num * sizeof(bool)); //assume no savegames for this title
- filenames = _saveFileMan->listSavefiles(prefix);
+ files = _saveFileMan->listSavefiles(prefix);
- for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++){
+ for (Common::StringList::const_iterator file = files.begin(); file != files.end(); ++file) {
//Obtain the last 2 digits of the filename, since they correspond to the save slot
slot[0] = file->c_str()[file->size()-2];
slot[1] = file->c_str()[file->size()-1];
diff --git a/engines/scumm/smush/codec47ARM.s b/engines/scumm/smush/codec47ARM.s
index 81bfdb2d22..73341c117f 100644
--- a/engines/scumm/smush/codec47ARM.s
+++ b/engines/scumm/smush/codec47ARM.s
@@ -80,7 +80,7 @@ level1codeFD:
LDRB r9,[r8,#384] @ r9 = l = tmp_ptr[384]
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
ADD r12,r8,#384 @ r12= &tmp_ptr[384]
- @ I don't really believe the next 2 lines are necessary, but...
+ @ I don''t really believe the next 2 lines are necessary, but...
CMP r9,#0
BEQ level1codeFD_over1
level1codeFD_loop1:
@@ -94,7 +94,7 @@ level1codeFD_over1:
LDRB r9,[r12,#1] @ r9 = l = tmp_ptr[385]
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
SUB r12,r12,#256 @ r12= &tmp_ptr[128] (256 = 384-128)
- @ I don't really believe the next 2 lines are necessary, but...
+ @ I don''t really believe the next 2 lines are necessary, but...
CMP r9,#0
BEQ level1codeFD_over2
level1codeFD_loop2:
@@ -219,7 +219,7 @@ level2codeFD:
LDRB r9,[r8,#96] @ r9 = l = tmp_ptr[96]
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
ADD r12,r8,#32 @ r12 = tmp_ptr + 32
- @ I don't really believe the next 2 lines are necessary, but...
+ @ I don''t really believe the next 2 lines are necessary, but...
CMP r9,#0
BEQ level2codeFD_over1
level2codeFD_loop1:
@@ -232,7 +232,7 @@ level2codeFD_loop1:
level2codeFD_over1:
LDRB r9,[r12,#65] @ r9 = l = tmp_ptr[97] (65 = 97-32)
LDRB r6,[r1],#1 @ r6 = val = *_d_src++
- @ I don't really believe the next 2 lines are necessary, but...
+ @ I don''t really believe the next 2 lines are necessary, but...
CMP r9,#0
MOVEQ PC,R14
level2codeFD_loop2:
diff --git a/engines/touche/midi.cpp b/engines/touche/midi.cpp
index ce62849d2f..d77dbf5bfa 100644
--- a/engines/touche/midi.cpp
+++ b/engines/touche/midi.cpp
@@ -23,6 +23,7 @@
*
*/
+#include "common/config-manager.h"
#include "common/stream.h"
#include "sound/midiparser.h"
@@ -31,9 +32,8 @@
namespace Touche {
-MidiPlayer::MidiPlayer(MidiDriver *driver, bool nativeMT32)
- : _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0), _nativeMT32(nativeMT32) {
- assert(_driver);
+MidiPlayer::MidiPlayer()
+ : _driver(0), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0) {
memset(_channelsTable, 0, sizeof(_channelsTable));
memset(_channelsVolume, 0, sizeof(_channelsVolume));
open();
@@ -92,6 +92,9 @@ void MidiPlayer::setVolume(int volume) {
}
int MidiPlayer::open() {
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+ _nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+ _driver = MidiDriver::createMidi(midiDriver);
int ret = _driver->open();
if (ret == 0) {
_parser = MidiParser::createParser_SMF();
diff --git a/engines/touche/midi.h b/engines/touche/midi.h
index 3b128593db..a518a4bb29 100644
--- a/engines/touche/midi.h
+++ b/engines/touche/midi.h
@@ -46,7 +46,7 @@ public:
NUM_CHANNELS = 16
};
- MidiPlayer(MidiDriver *driver, bool nativeMT32);
+ MidiPlayer();
~MidiPlayer();
void play(Common::ReadStream &stream, int size, bool loop = false);
diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp
index 0fa09d5b7a..c96a28bc8e 100644
--- a/engines/touche/saveload.cpp
+++ b/engines/touche/saveload.cpp
@@ -200,9 +200,6 @@ static void saveOrLoad(S &s, ProgramPointData &data) {
saveOrLoad(s, data.order);
}
-template <class S, class A>
-static void saveOrLoadCommonArray(S &s, A &array);
-
template <class A>
static void saveOrLoadCommonArray(Common::WriteStream &stream, A &array) {
uint count = array.size();
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index cb8080effd..a4a9b7df92 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -91,11 +91,7 @@ int ToucheEngine::init() {
setupOpcodes();
- int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
- bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
- MidiDriver *driver = MidiDriver::createMidi(midiDriver);
- _midiPlayer = new MidiPlayer(driver, native_mt32);
-
+ _midiPlayer = new MidiPlayer;
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));