aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorNeeraj Kumar2010-06-08 17:24:29 +0000
committerNeeraj Kumar2010-06-08 17:24:29 +0000
commit207a5e0779de9f0002b0b1984bde90ce6597e1f2 (patch)
tree98883ef89261afd4288f6dadbffe436d5d966dfc /engines/sci
parente00e94ae18aeb1ed460476f822e20b5bdfe171a4 (diff)
parent356728dab7f2c4cedf73684d7fe3b968be7396fd (diff)
downloadscummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.gz
scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.tar.bz2
scummvm-rg350-207a5e0779de9f0002b0b1984bde90ce6597e1f2.zip
updated my outdate copy of trunk, added couple of more tests in gfxtests
svn-id: r49510
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp171
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp223
-rw-r--r--engines/sci/engine/features.cpp88
-rw-r--r--engines/sci/engine/game.cpp173
-rw-r--r--engines/sci/engine/kernel.cpp8
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel32.cpp95
-rw-r--r--engines/sci/engine/kevent.cpp58
-rw-r--r--engines/sci/engine/kfile.cpp132
-rw-r--r--engines/sci/engine/kgraphics.cpp117
-rw-r--r--engines/sci/engine/klists.cpp52
-rw-r--r--engines/sci/engine/kmisc.cpp24
-rw-r--r--engines/sci/engine/kmovement.cpp141
-rw-r--r--engines/sci/engine/kparse.cpp40
-rw-r--r--engines/sci/engine/kpathing.cpp66
-rw-r--r--engines/sci/engine/kscripts.cpp36
-rw-r--r--engines/sci/engine/kstring.cpp36
-rw-r--r--engines/sci/engine/savegame.cpp206
-rw-r--r--engines/sci/engine/savegame.h2
-rw-r--r--engines/sci/engine/script.cpp277
-rw-r--r--engines/sci/engine/scriptdebug.cpp86
-rw-r--r--engines/sci/engine/seg_manager.cpp46
-rw-r--r--engines/sci/engine/seg_manager.h44
-rw-r--r--engines/sci/engine/segment.cpp425
-rw-r--r--engines/sci/engine/segment.h238
-rw-r--r--engines/sci/engine/selector.cpp44
-rw-r--r--engines/sci/engine/selector.h31
-rw-r--r--engines/sci/engine/state.cpp70
-rw-r--r--engines/sci/engine/state.h41
-rw-r--r--engines/sci/engine/vm.cpp425
-rw-r--r--engines/sci/engine/vm.h86
-rw-r--r--engines/sci/event.cpp3
-rw-r--r--engines/sci/graphics/animate.cpp87
-rw-r--r--engines/sci/graphics/animate.h3
-rw-r--r--engines/sci/graphics/compare.cpp68
-rw-r--r--engines/sci/graphics/controls.cpp18
-rw-r--r--engines/sci/graphics/coordadjuster.cpp16
-rw-r--r--engines/sci/graphics/frameout.cpp54
-rw-r--r--engines/sci/graphics/gui.cpp7
-rw-r--r--engines/sci/graphics/gui.h2
-rw-r--r--engines/sci/graphics/maciconbar.cpp91
-rw-r--r--engines/sci/graphics/maciconbar.h55
-rw-r--r--engines/sci/graphics/menu.cpp8
-rw-r--r--engines/sci/graphics/paint16.cpp5
-rw-r--r--engines/sci/graphics/paint16.h2
-rw-r--r--engines/sci/graphics/palette.cpp9
-rw-r--r--engines/sci/graphics/picture.cpp51
-rw-r--r--engines/sci/graphics/picture.h9
-rw-r--r--engines/sci/graphics/ports.cpp3
-rw-r--r--engines/sci/graphics/ports.h2
-rw-r--r--engines/sci/graphics/screen.cpp13
-rw-r--r--engines/sci/module.mk2
-rw-r--r--engines/sci/parser/grammar.cpp5
-rw-r--r--engines/sci/parser/said.cpp7
-rw-r--r--engines/sci/parser/said.y7
-rw-r--r--engines/sci/resource.cpp1065
-rw-r--r--engines/sci/resource.h64
-rw-r--r--engines/sci/resource_audio.cpp711
-rw-r--r--engines/sci/sci.cpp21
-rw-r--r--engines/sci/sci.h3
-rw-r--r--engines/sci/sound/audio.cpp12
-rw-r--r--engines/sci/sound/midiparser_sci.cpp26
-rw-r--r--engines/sci/sound/midiparser_sci.h13
-rw-r--r--engines/sci/sound/music.cpp95
-rw-r--r--engines/sci/sound/music.h11
-rw-r--r--engines/sci/sound/soundcmd.cpp231
67 files changed, 3386 insertions, 2876 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 540b7c84d8..2549be9403 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -47,6 +47,7 @@
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint.h"
+#include "sci/graphics/paint16.h"
#include "sci/graphics/palette.h"
#include "sci/parser/vocabulary.h"
@@ -74,10 +75,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger() {
// Variables
DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0);
- DVar_Register("gc_interval", &script_gc_interval, DVAR_INT, 0);
+ DVar_Register("gc_interval", &engine->_gamestate->script_gc_interval, DVAR_INT, 0);
DVar_Register("simulated_key", &g_debug_simulated_key, DVAR_INT, 0);
DVar_Register("track_mouse_clicks", &g_debug_track_mouse_clicks, DVAR_BOOL, 0);
- DVar_Register("script_abort_flag", &script_abort_flag, DVAR_INT, 0);
+ DVar_Register("script_abort_flag", &_engine->_gamestate->script_abort_flag, DVAR_INT, 0);
// General
DCmd_Register("help", WRAP_METHOD(Console, cmdHelp));
@@ -104,6 +105,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger() {
DCmd_Register("resource_types", WRAP_METHOD(Console, cmdResourceTypes));
DCmd_Register("list", WRAP_METHOD(Console, cmdList));
DCmd_Register("hexgrep", WRAP_METHOD(Console, cmdHexgrep));
+ DCmd_Register("verify_scripts", WRAP_METHOD(Console, cmdVerifyScripts));
// Game
DCmd_Register("save_game", WRAP_METHOD(Console, cmdSaveGame));
DCmd_Register("restore_game", WRAP_METHOD(Console, cmdRestoreGame));
@@ -276,8 +278,8 @@ void Console::postEnter() {
#if 0
// Unused
#define LOOKUP_SPECIES(species) (\
- (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \
- + s->_classtable[species].class_offset)
+ (species >= 1000) ? species : *(s->_classTable[species].scriptposp) \
+ + s->_classTable[species].class_offset)
#endif
bool Console::cmdHelp(int argc, const char **argv) {
@@ -323,6 +325,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
DebugPrintf(" resource_types - Shows the valid resource types\n");
DebugPrintf(" list - Lists all the resources of a given type\n");
DebugPrintf(" hexgrep - Searches some resources for a particular sequence of bytes, represented as hexadecimal numbers\n");
+ DebugPrintf(" verify_scripts - Performs sanity checks on SCI1.1-SCI2.1 game scripts (e.g. if they're up to 64KB in total)\n");
DebugPrintf("\n");
DebugPrintf("Game:\n");
DebugPrintf(" save_game - Saves the current game state to the hard disk\n");
@@ -421,10 +424,9 @@ const char *selector_name(EngineState *s, int selector) {
bool Console::cmdGetVersion(int argc, const char **argv) {
const char *viewTypeDesc[] = { "Unknown", "EGA", "VGA", "VGA SCI1.1", "Amiga" };
- EngineState *s = _engine->_gamestate;
bool hasVocab997 = g_sci->getResMan()->testResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SELECTORS)) ? true : false;
- DebugPrintf("Game ID: %s\n", s->_gameId.c_str());
+ DebugPrintf("Game ID: %s\n", _engine->getGameID());
DebugPrintf("Emulated interpreter version: %s\n", getSciVersionDesc(getSciVersion()));
DebugPrintf("\n");
DebugPrintf("Detected features:\n");
@@ -593,14 +595,14 @@ bool Console::cmdSetParseNodes(int argc, const char **argv) {
}
bool Console::cmdRegisters(int argc, const char **argv) {
+ EngineState *s = _engine->_gamestate;
DebugPrintf("Current register values:\n");
- DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(_engine->_gamestate->r_acc), PRINT_REG(_engine->_gamestate->r_prev), scriptState.restAdjust);
+ DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(s->r_acc), PRINT_REG(s->r_prev), s->restAdjust);
- if (!_engine->_gamestate->_executionStack.empty()) {
- EngineState *s = _engine->_gamestate; // for PRINT_STK
+ if (!s->_executionStack.empty()) {
DebugPrintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n",
- PRINT_REG(scriptState.xs->addr.pc), PRINT_REG(scriptState.xs->objp),
- (unsigned)(scriptState.xs->fp - s->stack_base), (unsigned)(scriptState.xs->sp - s->stack_base));
+ PRINT_REG(s->xs->addr.pc), PRINT_REG(s->xs->objp),
+ (unsigned)(s->xs->fp - s->stack_base), (unsigned)(s->xs->sp - s->stack_base));
} else
DebugPrintf("<no execution stack: pc,obj,fp omitted>\n");
@@ -811,6 +813,40 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
return true;
}
+bool Console::cmdVerifyScripts(int argc, const char **argv) {
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ DebugPrintf("This script check is only meant for SCI1.1-SCI2.1 games\n");
+ return true;
+ }
+
+ Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript);
+ sort(resources->begin(), resources->end(), ResourceIdLess());
+ Common::List<ResourceId>::iterator itr = resources->begin();
+
+ DebugPrintf("%d SCI1.1-SCI2.1 scripts found, performing sanity checks...\n", resources->size());
+
+ Resource *script, *heap;
+ while (itr != resources->end()) {
+ script = _engine->getResMan()->findResource(*itr, false);
+ if (!script)
+ DebugPrintf("Error: script %d couldn't be loaded\n", itr->number);
+
+ heap = _engine->getResMan()->findResource(*itr, false);
+ if (!heap)
+ DebugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->number);
+
+ if (script && heap && (script->size + heap->size > 65535))
+ DebugPrintf("Error: script and heap %d together are larger than 64KB (%d bytes)\n",
+ itr->number, script->size + heap->size);
+
+ ++itr;
+ }
+
+ DebugPrintf("SCI1.1-SCI2.1 script check finished\n");
+
+ return true;
+}
+
bool Console::cmdList(int argc, const char **argv) {
if (argc < 2) {
DebugPrintf("Lists all the resources of a given type\n");
@@ -921,35 +957,19 @@ bool Console::cmdRestoreGame(int argc, const char **argv) {
}
bool Console::cmdRestartGame(int argc, const char **argv) {
- if (argc != 2) {
- DebugPrintf("Restarts the game. There are two ways to restart a SCI game:\n");
- DebugPrintf("%s play - calls the game object's play() method\n", argv[0]);
- DebugPrintf("%s replay - calls the replay() methody\n", argv[0]);
- return true;
- }
-
- if (!scumm_stricmp(argv[1], "play")) {
- _engine->_gamestate->restarting_flags |= SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
- } else if (!scumm_stricmp(argv[1], "replay")) {
- _engine->_gamestate->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
- } else {
- DebugPrintf("Invalid usage of %s\n", argv[0]);
- return true;
- }
-
_engine->_gamestate->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
- script_abort_flag = 1;
+ _engine->_gamestate->script_abort_flag = 1;
return false;
}
bool Console::cmdClassTable(int argc, const char **argv) {
DebugPrintf("Available classes:\n");
- for (uint i = 0; i < _engine->_gamestate->_segMan->_classtable.size(); i++) {
- if (_engine->_gamestate->_segMan->_classtable[i].reg.segment) {
+ for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) {
+ if (_engine->_gamestate->_segMan->_classTable[i].reg.segment) {
DebugPrintf(" Class 0x%x at %04x:%04x (script 0x%x)\n", i,
- PRINT_REG(_engine->_gamestate->_segMan->_classtable[i].reg),
- _engine->_gamestate->_segMan->_classtable[i].script);
+ PRINT_REG(_engine->_gamestate->_segMan->_classTable[i].reg),
+ _engine->_gamestate->_segMan->_classTable[i].script);
}
}
@@ -1129,7 +1149,11 @@ bool Console::cmdUndither(int argc, const char **argv) {
bool flag = atoi(argv[1]) ? true : false;
_engine->_gfxScreen->debugUnditherSetState(flag);
- return false;
+ if (flag)
+ DebugPrintf("undithering ENABLED\n");
+ else
+ DebugPrintf("undithering DISABLED\n");
+ return true;
}
bool Console::cmdPicVisualize(int argc, const char **argv) {
@@ -1141,7 +1165,16 @@ bool Console::cmdPicVisualize(int argc, const char **argv) {
bool state = atoi(argv[1]) ? true : false;
- return _engine->_gui->debugEGAdrawingVisualize(state);
+ if (_engine->_resMan->getViewType() == kViewEga) {
+ _engine->_gfxPaint16->debugSetEGAdrawingVisualize(state);
+ if (state)
+ DebugPrintf("picture visualization ENABLED\n");
+ else
+ DebugPrintf("picture visualization DISABLED\n");
+ } else {
+ DebugPrintf("picture visualization only available for EGA games\n");
+ }
+ return true;
}
bool Console::cmdPlayVideo(int argc, const char **argv) {
@@ -1248,13 +1281,13 @@ bool Console::segmentInfo(int nr) {
case SEG_TYPE_SCRIPT: {
Script *scr = (Script *)mobj;
- DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->_bufSize, (uint)scr->_bufSize);
- if (scr->_exportTable)
- DebugPrintf(" Exports: %4d at %d\n", scr->_numExports, (int)(((byte *)scr->_exportTable) - ((byte *)scr->_buf)));
+ DebugPrintf("script.%03d locked by %d, bufsize=%d (%x)\n", scr->_nr, scr->getLockers(), (uint)scr->getBufSize(), (uint)scr->getBufSize());
+ if (scr->getExportTable())
+ DebugPrintf(" Exports: %4d at %d\n", scr->getExportsNr(), (int)(((const byte *)scr->getExportTable()) - ((const byte *)scr->_buf)));
else
DebugPrintf(" Exports: none\n");
- DebugPrintf(" Synonyms: %4d\n", scr->_numSynonyms);
+ DebugPrintf(" Synonyms: %4d\n", scr->getSynonymsNr());
if (scr->_localsBlock)
DebugPrintf(" Locals : %4d in segment 0x%x\n", scr->_localsBlock->_locals.size(), scr->_localsSegment);
@@ -1268,7 +1301,7 @@ bool Console::segmentInfo(int nr) {
for (it = scr->_objects.begin(); it != end; ++it) {
DebugPrintf(" ");
// Object header
- Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
+ const Object *obj = _engine->_gamestate->_segMan->getObject(it->_value.getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(it->_value.getPos()),
_engine->_gamestate->_segMan->getObjectName(it->_value.getPos()),
@@ -1315,7 +1348,7 @@ bool Console::segmentInfo(int nr) {
objpos.segment = nr;
DebugPrintf(" [%04x] %s; copy of ", i, _engine->_gamestate->_segMan->getObjectName(objpos));
// Object header
- Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
+ const Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct->_table[i].getPos()),
_engine->_gamestate->_segMan->getObjectName(ct->_table[i].getPos()),
@@ -1523,12 +1556,12 @@ bool Console::cmdToggleSound(int argc, const char **argv) {
int handle = id.segment << 16 | id.offset; // frobnicate handle
if (id.segment) {
- SegManager *segMan = _engine->_gamestate->_segMan; // for PUT_SEL32V
+ SegManager *segMan = _engine->_gamestate->_segMan; // for writeSelectorValue
_engine->_gamestate->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_engine->_gamestate->_sound.sfx_remove_song(handle);
- PUT_SEL32V(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
- PUT_SEL32V(segMan, id, SELECTOR(nodePtr), 0);
- PUT_SEL32V(segMan, id, SELECTOR(handle), 0);
+ writeSelectorValue(segMan, id, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, id, SELECTOR(nodePtr), 0);
+ writeSelectorValue(segMan, id, SELECTOR(handle), 0);
}
#else
@@ -1733,14 +1766,15 @@ bool Console::cmdGCNormalize(int argc, const char **argv) {
}
bool Console::cmdVMVarlist(int argc, const char **argv) {
+ EngineState *s = _engine->_gamestate;
const char *varnames[] = {"global", "local", "temp", "param"};
DebugPrintf("Addresses of variables in the VM:\n");
for (int i = 0; i < 4; i++) {
- DebugPrintf("%s vars at %04x:%04x ", varnames[i], PRINT_REG(make_reg(scriptState.variables_seg[i], scriptState.variables[i] - scriptState.variables_base[i])));
- if (scriptState.variables_max)
- DebugPrintf(" total %d", scriptState.variables_max[i]);
+ DebugPrintf("%s vars at %04x:%04x ", varnames[i], PRINT_REG(make_reg(s->variables_seg[i], s->variables[i] - s->variables_base[i])));
+ if (s->variables_max)
+ DebugPrintf(" total %d", s->variables_max[i]);
DebugPrintf("\n");
}
@@ -1758,6 +1792,7 @@ bool Console::cmdVMVars(int argc, const char **argv) {
return true;
}
+ EngineState *s = _engine->_gamestate;
const char *varnames[] = {"global", "local", "temp", "param"};
const char *varabbrev = "gltp";
const char *vartype_pre = strchr(varabbrev, *argv[1]);
@@ -1796,17 +1831,17 @@ bool Console::cmdVMVars(int argc, const char **argv) {
return true;
}
- if ((scriptState.variables_max) && (scriptState.variables_max[vartype] <= idx)) {
- DebugPrintf("Max. index is %d (0x%x)\n", scriptState.variables_max[vartype], scriptState.variables_max[vartype]);
+ if ((s->variables_max) && (s->variables_max[vartype] <= idx)) {
+ DebugPrintf("Max. index is %d (0x%x)\n", s->variables_max[vartype], s->variables_max[vartype]);
return true;
}
switch (argc) {
case 3:
- DebugPrintf("%s var %d == %04x:%04x\n", varnames[vartype], idx, PRINT_REG(scriptState.variables[vartype][idx]));
+ DebugPrintf("%s var %d == %04x:%04x\n", varnames[vartype], idx, PRINT_REG(s->variables[vartype][idx]));
break;
case 4:
- if (parse_reg_t(_engine->_gamestate, argv[3], &scriptState.variables[vartype][idx], true)) {
+ if (parse_reg_t(_engine->_gamestate, argv[3], &s->variables[vartype][idx], true)) {
DebugPrintf("Invalid value/address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
DebugPrintf("Or pass a decimal or hexadecimal value directly (e.g. 12, 1Ah)\n");
@@ -2039,7 +2074,7 @@ bool Console::cmdViewObject(int argc, const char **argv) {
bool Console::cmdViewActiveObject(int argc, const char **argv) {
DebugPrintf("Information on the currently active object or class:\n");
- printObject(scriptState.xs->objp);
+ printObject(_engine->_gamestate->xs->objp);
return true;
}
@@ -2052,7 +2087,7 @@ bool Console::cmdViewAccumulatorObject(int argc, const char **argv) {
}
bool Console::cmdScriptSteps(int argc, const char **argv) {
- DebugPrintf("Number of executed SCI operations: %d\n", script_step_counter);
+ DebugPrintf("Number of executed SCI operations: %d\n", _engine->_gamestate->script_step_counter);
return true;
}
@@ -2229,8 +2264,8 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
- int selector_id = _engine->getKernel()->findSelector(argv[2]);
+ const Object *obj = _engine->_gamestate->_segMan->getObject(objAddr);
+ int selectorId = _engine->getKernel()->findSelector(argv[2]);
reg_t addr;
if (!obj) {
@@ -2238,12 +2273,12 @@ bool Console::cmdDisassemble(int argc, const char **argv) {
return true;
}
- if (selector_id < 0) {
+ if (selectorId < 0) {
DebugPrintf("Not a valid selector name.");
return true;
}
- if (lookup_selector(_engine->_gamestate->_segMan, objAddr, selector_id, NULL, &addr) != kSelectorMethod) {
+ if (lookupSelector(_engine->_gamestate->_segMan, objAddr, selectorId, NULL, &addr) != kSelectorMethod) {
DebugPrintf("Not a method.");
return true;
}
@@ -2323,20 +2358,20 @@ bool Console::cmdSend(int argc, const char **argv) {
}
const char *selector_name = argv[2];
- int selector_id = _engine->getKernel()->findSelector(selector_name);
+ int selectorId = _engine->getKernel()->findSelector(selector_name);
- if (selector_id < 0) {
+ if (selectorId < 0) {
DebugPrintf("Unknown selector: \"%s\"\n", selector_name);
return true;
}
- Object *o = _engine->_gamestate->_segMan->getObject(object);
+ const Object *o = _engine->_gamestate->_segMan->getObject(object);
if (o == NULL) {
DebugPrintf("Address \"%04x:%04x\" is not an object\n", PRINT_REG(object));
return true;
}
- SelectorType selector_type = lookup_selector(_engine->_gamestate->_segMan, object, selector_id, 0, 0);
+ SelectorType selector_type = lookupSelector(_engine->_gamestate->_segMan, object, selectorId, 0, 0);
if (selector_type == kSelectorNone) {
DebugPrintf("Object does not support selector: \"%s\"\n", selector_name);
@@ -2349,7 +2384,7 @@ bool Console::cmdSend(int argc, const char **argv) {
// Create the data block for send_selecor() at the top of the stack:
// [selector_number][argument_counter][arguments...]
StackPtr stackframe = _engine->_gamestate->_executionStack.back().sp;
- stackframe[0] = make_reg(0, selector_id);
+ stackframe[0] = make_reg(0, selectorId);
stackframe[1] = make_reg(0, send_argc);
for (int i = 0; i < send_argc; i++) {
if (parse_reg_t(_engine->_gamestate, argv[3+i], &stackframe[2+i], false)) {
@@ -2696,7 +2731,7 @@ bool Console::cmdQuit(int argc, const char **argv) {
if (!scumm_stricmp(argv[1], "game")) {
// Quit gracefully
- script_abort_flag = 1; // Terminate VM
+ _engine->_gamestate->script_abort_flag = 1; // Terminate VM
g_debugState.seeking = kDebugSeekNothing;
g_debugState.runningStep = 0;
@@ -3021,8 +3056,8 @@ int Console::printNode(reg_t addr) {
int Console::printObject(reg_t pos) {
EngineState *s = _engine->_gamestate; // for the several defines in this function
- Object *obj = s->_segMan->getObject(pos);
- Object *var_container = obj;
+ const Object *obj = s->_segMan->getObject(pos);
+ const Object *var_container = obj;
uint i;
if (!obj) {
@@ -3034,7 +3069,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), s->_segMan->getObjectName(pos),
obj->getVarCount(), obj->getMethodCount());
- if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS))
+ if (!obj->isClass())
var_container = s->_segMan->getObject(obj->getSuperClassSelector());
DebugPrintf(" -- member variables:\n");
for (i = 0; (uint)i < obj->getVarCount(); i++) {
@@ -3051,7 +3086,7 @@ int Console::printObject(reg_t pos) {
if (!val.segment)
DebugPrintf(" (%d)", val.offset);
- Object *ref = s->_segMan->getObject(val);
+ const Object *ref = s->_segMan->getObject(val);
if (ref)
DebugPrintf(" (%s)", s->_segMan->getObjectName(val));
@@ -3063,7 +3098,7 @@ int Console::printObject(reg_t pos) {
DebugPrintf(" [%03x] %s = %04x:%04x\n", obj->getFuncSelector(i), selector_name(s, obj->getFuncSelector(i)), PRINT_REG(fptr));
}
if (s->_segMan->_heap[pos.segment]->getType() == SEG_TYPE_SCRIPT)
- DebugPrintf("\nOwner script:\t%d\n", s->_segMan->getScript(pos.segment)->_nr);
+ DebugPrintf("\nOwner script: %d\n", s->_segMan->getScript(pos.segment)->_nr);
return 0;
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index c88795ae26..2b13e03ef6 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -73,6 +73,7 @@ private:
bool cmdResourceTypes(int argc, const char **argv);
bool cmdList(int argc, const char **argv);
bool cmdHexgrep(int argc, const char **argv);
+ bool cmdVerifyScripts(int argc, const char **argv);
// Game
bool cmdSaveGame(int argc, const char **argv);
bool cmdRestoreGame(int argc, const char **argv);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index beea025aea..1ccfc6bf02 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -120,6 +120,154 @@ static const PlainGameDescriptor SciGameTitles[] = {
{0, 0}
};
+struct OldNewIdTableEntry {
+ const char *oldId;
+ const char *newId;
+ SciVersion version;
+};
+
+static const OldNewIdTableEntry s_oldNewTable[] = {
+ { "arthur", "camelot", SCI_VERSION_NONE },
+ { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
+ { "brain", "castlebrain", SCI_VERSION_1_LATE },
+ { "demo", "christmas1988", SCI_VERSION_NONE },
+ { "card", "christmas1990", SCI_VERSION_1_EARLY, },
+ { "card", "christmas1992", SCI_VERSION_1_1 },
+ { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
+ // iceman is the same
+ { "icedemo", "iceman", SCI_VERSION_NONE },
+ // longbow is the same
+ { "eco", "ecoquest", SCI_VERSION_NONE },
+ { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
+ { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
+ { "tales", "fairytales", SCI_VERSION_NONE },
+ { "fp", "freddypharkas", SCI_VERSION_NONE },
+ { "emc", "funseeker", SCI_VERSION_NONE },
+ { "gk", "gk1", SCI_VERSION_NONE },
+ // gk2 is the same
+ { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
+ { "cardgames", "hoyle1", SCI_VERSION_NONE },
+ { "solitare", "hoyle2", SCI_VERSION_NONE },
+ // hoyle3 is the same
+ // hoyle4 is the same
+ { "brain", "islandbrain", SCI_VERSION_1_1 },
+ { "demo000", "kq1sci", SCI_VERSION_NONE },
+ { "kq1", "kq1sci", SCI_VERSION_NONE },
+ { "kq4", "kq4sci", SCI_VERSION_NONE },
+ // kq5 is the same
+ // kq6 is the same
+ // kq7 is the same
+ { "mm1", "laurabow", SCI_VERSION_NONE },
+ { "cb1", "laurabow", SCI_VERSION_NONE },
+ { "lb2", "laurabow2", SCI_VERSION_NONE },
+ { "rh", "longbow", SCI_VERSION_NONE },
+ { "ll1", "lsl1sci", SCI_VERSION_NONE },
+ { "lsl1", "lsl1sci", SCI_VERSION_NONE },
+ // lsl2 is the same
+ { "lsl3", "lsl3", SCI_VERSION_NONE },
+ { "ll5", "lsl5", SCI_VERSION_NONE },
+ // lsl5 is the same
+ // lsl6 is the same
+ { "mg", "mothergoose", SCI_VERSION_NONE },
+ { "twisty", "pepper", SCI_VERSION_NONE },
+ { "scary", "phantasmagoria", SCI_VERSION_NONE },
+ // TODO: distinguish the full version of Phantasmagoria from the demo
+ { "pq1", "pq1sci", SCI_VERSION_NONE },
+ { "pq", "pq2", SCI_VERSION_NONE },
+ // pq3 is the same
+ // pq4 is the same
+ { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
+ { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
+ { "trial", "qfg2", SCI_VERSION_NONE },
+ { "hq2demo", "qfg2", SCI_VERSION_NONE },
+ // rama is the same
+ // TODO: distinguish the full version of rama from the demo
+ { "thegame", "slater", SCI_VERSION_NONE },
+ { "sq1demo", "sq1sci", SCI_VERSION_NONE },
+ { "sq1", "sq1sci", SCI_VERSION_NONE },
+ // sq3 is the same
+ // sq4 is the same
+ // sq5 is the same
+ // sq6 is the same
+ // TODO: distinguish the full version of SQ6 from the demo
+ // torin is the same
+
+
+ // TODO: SCI3 IDs
+
+ { "", "", SCI_VERSION_NONE }
+};
+
+Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager *resMan) {
+ // Convert the id to lower case, so that we match all upper/lower case variants.
+ sierraId.toLowercase();
+
+ // If the game has less than the expected scripts, it's a demo
+ uint32 demoThreshold = 100;
+ // ...but there are some exceptions
+ if (sierraId == "brain" || sierraId == "lsl1" ||
+ sierraId == "mg" || sierraId == "pq" ||
+ sierraId == "jones" ||
+ sierraId == "cardgames" || sierraId == "solitare" ||
+ sierraId == "hoyle3" || sierraId == "hoyle4")
+ demoThreshold = 40;
+ if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
+ demoThreshold = 150;
+
+ Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
+ if (resources->size() < demoThreshold) {
+ *gameFlags |= ADGF_DEMO;
+
+ // Crazy Nick's Picks
+ if (sierraId == "lsl1" && resources->size() == 34)
+ return "cnick-lsl";
+ if (sierraId == "sq4" && resources->size() == 34)
+ return "cnick-sq";
+
+ // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
+
+ // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
+ if (sierraId == "sq3" && resources->size() == 20)
+ return "astrochicken";
+ if (sierraId == "sq4")
+ return "msastrochicken";
+ }
+
+ if (sierraId == "torin" && resources->size() == 226) // Torin's Passage demo
+ *gameFlags |= ADGF_DEMO;
+
+ for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
+ if (sierraId == cur->oldId) {
+ // Distinguish same IDs from the SCI version
+ if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
+ continue;
+
+ return cur->newId;
+ }
+ }
+
+ if (sierraId == "glory") {
+ // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
+ // or qfg4 full (SCI2)
+ // qfg1 VGA doesn't have view 1
+ if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
+ return "qfg1";
+
+ // qfg4 full is SCI2
+ if (getSciVersion() == SCI_VERSION_2)
+ return "qfg4";
+
+ // qfg4 demo has less than 50 scripts
+ if (resources->size() < 50)
+ return "qfg4";
+
+ // Otherwise it's qfg3
+ return "qfg3";
+ }
+
+ return sierraId;
+}
+
#include "sci/detection_tables.h"
/**
@@ -205,42 +353,6 @@ Common::Language charToScummVMLanguage(const char c) {
}
}
-#define READ_UINT16(ptr) (!resMan->isSci11Mac() ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr))
-
-// Finds the internal ID of the current game from script 0
-Common::String getSierraGameId(ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, 0), false);
- // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
- Resource *heap = 0;
- byte *seeker = 0;
-
- // Seek to the name selector of the first export
- if (getSciVersion() < SCI_VERSION_1_1) {
- const int nameSelector = 3;
- int extraSci0EarlyBytes = (getSciVersion() == SCI_VERSION_0_EARLY) ? 2 : 0;
- byte *exportPtr = script->data + extraSci0EarlyBytes + 4 + 2;
- seeker = script->data + READ_UINT16(script->data + READ_UINT16(exportPtr) + nameSelector * 2);
- } else {
- const int nameSelector = 5 + 3;
- heap = resMan->findResource(ResourceId(kResourceTypeHeap, 0), false);
- byte *exportPtr = script->data + 4 + 2 + 2;
- seeker = heap->data + READ_UINT16(heap->data + READ_UINT16(exportPtr) + nameSelector * 2);
- }
-
- char sierraId[20];
- int i = 0;
- byte curChar = 0;
-
- do {
- curChar = *(seeker + i);
- sierraId[i++] = curChar;
- } while (curChar != 0);
-
- return sierraId;
-}
-
-#undef READ_UINT16
-
const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
bool foundResMap = false;
bool foundRes000 = false;
@@ -261,19 +373,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
filename.toLowercase();
if (filename.contains("resource.map") || filename.contains("resmap.00") || filename.contains("Data1")) {
- // HACK: resource.map is located in the same directory as the other resource files,
- // therefore add the directory here, so that the game files can be opened later on
- // We now add the parent directory temporary to our SearchMan so the engine code
- // used in the detection can access all files via Common::File without any problems.
- // In all branches returning from this function, we need to have a call to
- // SearchMan.remove to remove it from the default directory pool again.
- //
- // A proper solution to remove this hack would be to have the code, which is needed
- // for detection, to operate on Stream objects, so they can be easily called from
- // the detection code. This might be easily to achieve through refactoring the
- // code needed for detection.
- assert(!SearchMan.hasArchive("SCI_detection"));
- SearchMan.addDirectory("SCI_detection", file->getParent());
foundResMap = true;
}
@@ -317,7 +416,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// If these files aren't found, it can't be SCI
if (!foundResMap && !foundRes000) {
- SearchMan.remove("SCI_detection");
return 0;
}
@@ -325,11 +423,10 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
ViewType gameViews = resMan->getViewType();
// Have we identified the game views? If not, stop here
+ // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
+ // but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
if (gameViews == kViewUnknown) {
- SearchMan.remove("SCI_detection");
delete resMan;
- // Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
- // but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
return 0;
}
@@ -337,7 +434,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
// Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here
if (getSciVersion() >= SCI_VERSION_2) {
- SearchMan.remove("SCI_detection");
delete resMan;
return (const ADGameDescription *)&s_fallbackDesc;
}
@@ -352,7 +448,15 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
s_fallbackDesc.platform = Common::kPlatformAmiga;
// Determine the game id
- Common::String gameId = convertSierraGameId(getSierraGameId(resMan).c_str(), &s_fallbackDesc.flags, resMan);
+ Common::String sierraGameId = resMan->findSierraGameId();
+
+ // If we don't have a game id, the game is not SCI
+ if (sierraGameId.empty()) {
+ delete resMan;
+ return 0;
+ }
+
+ Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated
s_fallbackDesc.gameid = s_fallbackGameIdBuf;
@@ -386,7 +490,6 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
}
}
- delete resMan;
// Fill in extras field
if (!strcmp(s_fallbackDesc.gameid, "lsl1sci") ||
@@ -394,14 +497,14 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
!strcmp(s_fallbackDesc.gameid, "sq1sci"))
s_fallbackDesc.extra = "VGA Remake";
- if (!strcmp(s_fallbackDesc.gameid, "qfg1") && !Common::File::exists("resource.001"))
+ if (!strcmp(s_fallbackDesc.gameid, "qfg1") && getSciVersion() == SCI_VERSION_1_1)
s_fallbackDesc.extra = "VGA Remake";
// Add "demo" to the description for demos
if (s_fallbackDesc.flags & ADGF_DEMO)
s_fallbackDesc.extra = "demo";
- SearchMan.remove("SCI_detection");
+ delete resMan;
return (const ADGameDescription *)&s_fallbackDesc;
}
@@ -427,8 +530,8 @@ bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
bool SciEngine::hasFeature(EngineFeature f) const {
return
//(f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime);
- //(f == kSupportsSavingDuringRuntime);
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
}
SaveStateList SciMetaEngine::listSaves(const char *target) const {
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index e51867332a..48f7c2d64f 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -56,7 +56,7 @@ reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc
}
if (methodNum == -1) {
- if (lookup_selector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
+ if (lookupSelector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) {
warning("getDetectionAddr: target selector is not a method of object %s", objName.c_str());
return NULL_REG;
}
@@ -87,7 +87,7 @@ bool GameFeatures::autoDetectSoundType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
// The play method of the Sound object pushes the DoSound command
@@ -189,7 +189,7 @@ SciVersion GameFeatures::detectSetCursorType() {
}
// Now we check what the number variable holds in the handCursor object.
- uint16 number = GET_SEL32V(_segMan, objAddr, SELECTOR(number));
+ uint16 number = readSelectorValue(_segMan, objAddr, SELECTOR(number));
// If the number is 0, it uses views and therefore the SCI1.1 kSetCursor semantics,
// otherwise it uses the SCI0 early kSetCursor semantics.
@@ -223,7 +223,7 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_lofsa || opcode == op_lofss) {
@@ -231,13 +231,13 @@ bool GameFeatures::autoDetectLofsType(int methodNum) {
uint16 lofs = opparams[0];
// Check for going out of bounds when interpreting as abs/rel
- if (lofs >= script->_bufSize)
+ if (lofs >= script->getBufSize())
_lofsType = SCI_VERSION_0_EARLY;
if ((signed)offset + (int16)lofs < 0)
_lofsType = SCI_VERSION_1_MIDDLE;
- if ((signed)offset + (int16)lofs >= (signed)script->_bufSize)
+ if ((signed)offset + (int16)lofs >= (signed)script->getBufSize())
_lofsType = SCI_VERSION_1_MIDDLE;
if (_lofsType != SCI_VERSION_NONE)
@@ -266,7 +266,7 @@ SciVersion GameFeatures::detectLofsType() {
// Find a function of the game object which invokes lofsa/lofss
reg_t gameClass = _segMan->findObjectByName("Game");
- Object *obj = _segMan->getObject(gameClass);
+ const Object *obj = _segMan->getObject(gameClass);
bool found = false;
for (uint m = 0; m < obj->getMethodCount(); m++) {
@@ -309,7 +309,7 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
@@ -332,18 +332,47 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) {
SciVersion GameFeatures::detectGfxFunctionsType() {
if (_gfxFunctionsType == SCI_VERSION_NONE) {
- // This detection only works (and is only needed) for SCI0 games
- if (getSciVersion() >= SCI_VERSION_01) {
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ // Old SCI0 games always used old graphics functions
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ } else if (getSciVersion() >= SCI_VERSION_01) {
+ // SCI01 and newer games always used new graphics functions
_gfxFunctionsType = SCI_VERSION_0_LATE;
- } else if (getSciVersion() > SCI_VERSION_0_EARLY) {
+ } else { // SCI0 late
// Check if the game is using an overlay
- bool found = false;
+ bool searchRoomObj = false;
+ reg_t rmObjAddr = _segMan->findObjectByName("Rm");
+
+ if (_kernel->_selectorCache.overlay != -1) {
+ // The game has an overlay selector, check how it calls kDrawPicto determine
+ // the graphics functions type used
+ if (lookupSelector(_segMan, rmObjAddr, _kernel->_selectorCache.overlay, NULL, NULL) == kSelectorMethod) {
+ if (!autoDetectGfxFunctionsType()) {
+ warning("Graphics functions detection failed, taking an educated guess");
+
+ // Try detecting the graphics function types from the existence of the motionCue
+ // selector (which is a bit of a hack)
+ if (_kernel->findSelector("motionCue") != -1)
+ _gfxFunctionsType = SCI_VERSION_0_LATE;
+ else
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ }
+ } else {
+ // The game has an overlay selector, but it's not a method of the Rm object
+ // (like in Hoyle 1 and 2), so search for other methods
+ searchRoomObj = true;
+ }
+ } else {
+ // The game doesn't have an overlay selector, so search for it manually
+ searchRoomObj = true;
+ }
- if (_kernel->_selectorCache.overlay == -1) {
- // No overlay selector found, check if any method of the Rm object
- // is calling kDrawPic, as the overlay selector might be missing in demos
+ if (searchRoomObj) {
+ // If requested, check if any method of the Rm object is calling kDrawPic,
+ // as the overlay selector might be missing in demos
+ bool found = false;
- Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm"));
+ const Object *obj = _segMan->getObject(rmObjAddr);
for (uint m = 0; m < obj->getMethodCount(); m++) {
found = autoDetectGfxFunctionsType(m);
if (found)
@@ -351,30 +380,11 @@ SciVersion GameFeatures::detectGfxFunctionsType() {
}
if (!found) {
- // No overlay selector found, therefore the game is definitely
- // using old graphics functions
+ // No method of the Rm object is calling kDrawPic, thus the game
+ // doesn't have overlays and is using older graphics functions
_gfxFunctionsType = SCI_VERSION_0_EARLY;
}
- } else { // _kernel->_selectorCache.overlay != -1
- // An in-between case: The game does not have a shiftParser
- // selector, but it does have an overlay selector, so it uses an
- // overlay. Therefore, check it to see how it calls kDrawPic to
- // determine the graphics functions type used
-
- if (!autoDetectGfxFunctionsType()) {
- warning("Graphics functions detection failed, taking an educated guess");
-
- // Try detecting the graphics function types from the existence of the motionCue
- // selector (which is a bit of a hack)
- if (_kernel->findSelector("motionCue") != -1)
- _gfxFunctionsType = SCI_VERSION_0_LATE;
- else
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
- }
}
- } else { // (getSciVersion() == SCI_VERSION_0_EARLY)
- // Old SCI0 games always used old graphics functions
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
}
debugC(1, kDebugLevelVM, "Detected graphics functions type: %s", getSciVersionDesc(_gfxFunctionsType));
@@ -402,7 +412,7 @@ bool GameFeatures::autoDetectSci21KernelType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
@@ -455,7 +465,7 @@ bool GameFeatures::autoDetectMoveCountType() {
opcode = extOpcode >> 1;
// Check for end of script
- if (opcode == op_ret || offset >= script->_bufSize)
+ if (opcode == op_ret || offset >= script->getBufSize())
break;
if (opcode == op_callk) {
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index 4ac2a22531..bc10099e52 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -41,141 +41,6 @@
namespace Sci {
-struct OldNewIdTableEntry {
- const char *oldId;
- const char *newId;
- SciVersion version;
-};
-
-static const OldNewIdTableEntry s_oldNewTable[] = {
- { "arthur", "camelot", SCI_VERSION_NONE },
- { "brain", "castlebrain", SCI_VERSION_1_MIDDLE }, // Amiga
- { "brain", "castlebrain", SCI_VERSION_1_LATE },
- { "demo", "christmas1988", SCI_VERSION_NONE },
- { "card", "christmas1990", SCI_VERSION_1_EARLY, },
- { "card", "christmas1992", SCI_VERSION_1_1 },
- { "RH Budget", "cnick-longbow", SCI_VERSION_NONE },
- // iceman is the same
- { "icedemo", "iceman", SCI_VERSION_NONE },
- // longbow is the same
- { "eco", "ecoquest", SCI_VERSION_NONE },
- { "eco2", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 demo
- { "rain", "ecoquest2", SCI_VERSION_NONE }, // EcoQuest 2 full
- { "fp", "freddypharkas", SCI_VERSION_NONE },
- { "emc", "funseeker", SCI_VERSION_NONE },
- { "gk", "gk1", SCI_VERSION_NONE },
- { "hoyledemo", "hoyle1", SCI_VERSION_NONE },
- { "cardgames", "hoyle1", SCI_VERSION_NONE },
- { "solitare", "hoyle2", SCI_VERSION_NONE },
- // hoyle3 is the same
- // hoyle4 is the same
- { "brain", "islandbrain", SCI_VERSION_1_1 },
- { "demo000", "kq1sci", SCI_VERSION_NONE },
- { "kq1", "kq1sci", SCI_VERSION_NONE },
- { "kq4", "kq4sci", SCI_VERSION_NONE },
- { "mm1", "laurabow", SCI_VERSION_NONE },
- { "cb1", "laurabow", SCI_VERSION_NONE },
- { "lb2", "laurabow2", SCI_VERSION_NONE },
- { "rh", "longbow", SCI_VERSION_NONE },
- { "ll1", "lsl1sci", SCI_VERSION_NONE },
- { "lsl1", "lsl1sci", SCI_VERSION_NONE },
- // lsl2 is the same
- { "lsl3", "lsl3", SCI_VERSION_NONE },
- { "ll5", "lsl5", SCI_VERSION_NONE },
- // lsl5 is the same
- // lsl6 is the same
- { "mg", "mothergoose", SCI_VERSION_NONE },
- { "twisty", "pepper", SCI_VERSION_NONE },
- { "pq1", "pq1sci", SCI_VERSION_NONE },
- { "pq", "pq2", SCI_VERSION_NONE },
- // pq3 is the same
- // pq4 is the same
- { "tales", "fairytales", SCI_VERSION_NONE },
- { "hq", "qfg1", SCI_VERSION_NONE }, // QFG1 SCI0/EGA
- { "glory", "qfg1", SCI_VERSION_0_LATE }, // QFG1 SCI0/EGA
- { "trial", "qfg2", SCI_VERSION_NONE },
- { "hq2demo", "qfg2", SCI_VERSION_NONE },
- { "thegame", "slater", SCI_VERSION_NONE },
- { "sq1demo", "sq1sci", SCI_VERSION_NONE },
- { "sq1", "sq1sci", SCI_VERSION_NONE },
- // sq3 is the same
- // sq4 is the same
- // sq5 is the same
- // torin is the same
-
- // TODO: SCI2.1, SCI3 IDs
-
- { "", "", SCI_VERSION_NONE }
-};
-
-Common::String convertSierraGameId(const char *gameId, uint32 *gameFlags, ResourceManager *resMan) {
- // Convert the id to lower case, so that we match all upper/lower case variants.
- Common::String sierraId = gameId;
- sierraId.toLowercase();
-
- // If the game has less than the expected scripts, it's a demo
- uint32 demoThreshold = 100;
- // ...but there are some exceptions
- if (sierraId == "brain" || sierraId == "lsl1" ||
- sierraId == "mg" || sierraId == "pq" ||
- sierraId == "jones" ||
- sierraId == "cardgames" || sierraId == "solitare" ||
- sierraId == "hoyle3" || sierraId == "hoyle4")
- demoThreshold = 40;
- if (sierraId == "fp" || sierraId == "gk" || sierraId == "pq4")
- demoThreshold = 150;
-
- Common::List<ResourceId> *resources = resMan->listResources(kResourceTypeScript, -1);
- if (resources->size() < demoThreshold) {
- *gameFlags |= ADGF_DEMO;
-
- // Crazy Nick's Picks
- if (sierraId == "lsl1" && resources->size() == 34)
- return "cnick-lsl";
- if (sierraId == "sq4" && resources->size() == 34)
- return "cnick-sq";
-
- // TODO: cnick-kq, cnick-laurabow and cnick-longbow (their resources can't be read)
-
- // Handle Astrochicken 1 (SQ3) and 2 (SQ4)
- if (sierraId == "sq3" && resources->size() == 20)
- return "astrochicken";
- if (sierraId == "sq4")
- return "msastrochicken";
- }
-
- for (const OldNewIdTableEntry *cur = s_oldNewTable; cur->oldId[0]; ++cur) {
- if (sierraId == cur->oldId) {
- // Distinguish same IDs from the SCI version
- if (cur->version != SCI_VERSION_NONE && cur->version != getSciVersion())
- continue;
-
- return cur->newId;
- }
- }
-
- if (sierraId == "glory") {
- // This could either be qfg1 VGA, qfg3 or qfg4 demo (all SCI1.1),
- // or qfg4 full (SCI2)
- // qfg1 VGA doesn't have view 1
- if (!resMan->testResource(ResourceId(kResourceTypeView, 1)))
- return "qfg1";
-
- // qfg4 full is SCI2
- if (getSciVersion() == SCI_VERSION_2)
- return "qfg4";
-
- // qfg4 demo has less than 50 scripts
- if (resources->size() < 50)
- return "qfg4";
-
- // Otherwise it's qfg3
- return "qfg3";
- }
-
- return sierraId;
-}
-
#ifdef USE_OLD_MUSIC_FUNCTIONS
int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion) {
if (getSciVersion() > SCI_VERSION_0_LATE)
@@ -202,13 +67,7 @@ int script_init_engine(EngineState *s) {
s->script_000 = s->_segMan->getScript(script_000_segment);
- s->sys_strings = s->_segMan->allocateSysStrings(&s->sys_strings_segment);
-
- // Allocate static buffer for savegame and CWD directories
- SystemString *str = &s->sys_strings->_strings[SYS_STRING_SAVEDIR];
- str->_name = "savedir";
- str->_maxSize = MAX_SAVE_DIR_SIZE;
- str->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
+ s->_segMan->initSysStrings();
s->r_acc = s->r_prev = NULL_REG;
s->restAdjust = 0;
@@ -240,35 +99,26 @@ int game_init(EngineState *s) {
return 1;
}
- if (s->_voc) {
- s->_voc->parserIsValid = false; // Invalidate parser
- s->_voc->parser_event = NULL_REG; // Invalidate parser event
- s->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
+ // Reset parser
+ Vocabulary *voc = g_sci->getVocabulary();
+ if (voc) {
+ voc->parserIsValid = false; // Invalidate parser
+ voc->parser_event = NULL_REG; // Invalidate parser event
+ voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE);
}
// Initialize menu TODO: Actually this should be another init()
if (g_sci->_gfxMenu)
g_sci->_gfxMenu->reset();
- s->successor = NULL; // No successor
-
- SystemString *str = &s->sys_strings->_strings[SYS_STRING_PARSER_BASE];
- str->_name = "parser-base";
- str->_maxSize = MAX_PARSER_BASE;
- str->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
+ s->restoring = false;
s->game_start_time = g_system->getMillis();
s->last_wait_time = s->game_start_time;
srand(g_system->getMillis()); // Initialize random number generator
-// script_dissect(0, s->_selectorNames);
- // The first entry in the export table of script 0 points to the game object
- s->_gameObj = s->_segMan->lookupScriptExport(0, 0);
- uint32 gameFlags = 0; // unused
- s->_gameId = convertSierraGameId(s->_segMan->getObjectName(s->_gameObj), &gameFlags, g_sci->getResMan());
-
- debug(2, " \"%s\" at %04x:%04x", s->_gameId.c_str(), PRINT_REG(s->_gameObj));
+ s->_gameObj = g_sci->getResMan()->findGameObject();
#ifdef USE_OLD_MUSIC_FUNCTIONS
if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND)
@@ -284,9 +134,8 @@ int game_init(EngineState *s) {
}
int game_exit(EngineState *s) {
- s->_executionStack.clear();
-
- if (!s->successor) {
+ if (!s->restoring) {
+ s->_executionStack.clear();
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
// Reinit because some other code depends on having a valid state
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 49266f3a18..6ebee2dfbd 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -332,11 +332,12 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("DoSync", kDoSync, ".*"),
DEFUN("MemorySegment", kMemorySegment, "iri*"),
DEFUN("Intersections", kIntersections, "iiiiriiiri"),
+ DEFUN("MergePoly", kMergePoly, "rli"),
DEFUN("ResCheck", kResCheck, "iii*"),
DEFUN("SetQuitStr", kSetQuitStr, "r"),
DEFUN("ShowMovie", kShowMovie, ".*"),
DEFUN("SetVideoMode", kSetVideoMode, "i"),
- DEFUN("Platform", kPlatform, "i.*"),
+ DEFUN("Platform", kPlatform, ".*"),
DEFUN("TextColors", kTextColors, ".*"),
DEFUN("TextFonts", kTextFonts, ".*"),
DEFUN("Portrait", kPortrait, ".*"),
@@ -362,7 +363,7 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("ListIndexOf", kListIndexOf, "lZo"),
DEFUN("OnMe", kOnMe, "iio.*"),
DEFUN("InPolygon", kInPolygon, "iio"),
- DEFUN("CreateTextBitmap", kCreateTextBitmap, "iiio"),
+ DEFUN("CreateTextBitmap", kCreateTextBitmap, "i.*"),
// SCI2.1 Kernel Functions
DEFUN("Save", kSave, ".*"),
@@ -382,7 +383,6 @@ SciKernelFunction kfunct_mappers[] = {
DEFUN("ShiftScreen", kShiftScreen, ".*"),
DEFUN("ListOps", kListOps, ".*"),
DEFUN("ATan", kATan, ".*"),
- DEFUN("MergePoly", kMergePoly, ".*"),
DEFUN("Record", kRecord, ".*"),
DEFUN("PlayBack", kPlayBack, ".*"),
DEFUN("DbugStr", kDbugStr, ".*"),
@@ -628,7 +628,7 @@ int Kernel::findRegType(reg_t reg) {
switch (mobj->getType()) {
case SEG_TYPE_SCRIPT:
- if (reg.offset <= (*(Script *)mobj)._bufSize &&
+ if (reg.offset <= (*(Script *)mobj).getBufSize() &&
reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET &&
RAW_IS_OBJECT((*(Script *)mobj)._buf + reg.offset)) {
return ((Script *)mobj)->getObject(reg.offset) ? KSIG_OBJECT : KSIG_REF;
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 7717743e19..8f8f34f74e 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -414,6 +414,7 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv);
reg_t kDoSync(EngineState *s, int argc, reg_t *argv);
reg_t kMemorySegment(EngineState *s, int argc, reg_t *argv);
reg_t kIntersections(EngineState *s, int argc, reg_t *argv);
+reg_t kMergePoly(EngineState *s, int argc, reg_t *argv);
reg_t kResCheck(EngineState *s, int argc, reg_t *argv);
reg_t kSetQuitStr(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel32.cpp b/engines/sci/engine/kernel32.cpp
index 465e0e92df..0afdc3f2eb 100644
--- a/engines/sci/engine/kernel32.cpp
+++ b/engines/sci/engine/kernel32.cpp
@@ -501,7 +501,7 @@ reg_t kArray(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
+ return readSelector(s->_segMan, argv[1], SELECTOR(data));
default:
error("Unknown kArray subop %d", argv[0].toUint16());
}
@@ -524,8 +524,12 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
}
case 1: // Size
return make_reg(0, s->_segMan->getString(argv[1]).size());
- case 2: // At (return value at an index)
+ case 2: { // At (return value at an index)
+ if (argv[1].segment == s->_segMan->getStringSegmentId())
+ return make_reg(0, s->_segMan->lookupString(argv[1])->getRawData()[argv[2].toUint16()]);
+
return make_reg(0, s->_segMan->getString(argv[1])[argv[2].toUint16()]);
+ }
case 3: { // Atput (put value at an index)
SciString *string = s->_segMan->lookupString(argv[1]);
@@ -563,28 +567,40 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
return argv[1];
}
case 6: { // Cpy
- Common::String string2 = s->_segMan->getString(argv[3]);
+ const char *string2 = 0;
+ uint32 string2Size = 0;
+
+ if (argv[3].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[3]);
+ string2 = string->getRawData();
+ string2Size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[3]);
+ string2 = string.c_str();
+ string2Size = string.size() + 1;
+ }
+
uint32 index1 = argv[2].toUint16();
uint32 index2 = argv[4].toUint16();
// The original engine ignores bad copies too
- if (index2 > string2.size())
+ if (index2 > string2Size)
break;
// A count of -1 means fill the rest of the array
- uint32 count = argv[5].toSint16() == -1 ? string2.size() - index2 + 1 : argv[5].toUint16();
+ uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16();
// We have a special case here for argv[1] being a system string
- if (argv[1].segment == s->sys_strings_segment) {
+ if (argv[1].segment == s->_segMan->getSysStringsSegment()) {
// Resize if necessary
- if ((uint32)s->sys_strings->_strings[argv[1].toUint16()]._maxSize < index1 + count) {
- delete[] s->sys_strings->_strings[argv[1].toUint16()]._value;
- s->sys_strings->_strings[argv[1].toUint16()]._maxSize = index1 + count;
- s->sys_strings->_strings[argv[1].toUint16()]._value = new char[index1 + count];
- memset(s->sys_strings->_strings[argv[1].toUint16()]._value, 0, index1 + count);
+ const uint16 sysStringId = argv[1].toUint16();
+ if ((uint32)s->_segMan->sysStrings->_strings[sysStringId]._maxSize < index1 + count) {
+ free(s->_segMan->sysStrings->_strings[sysStringId]._value);
+ s->_segMan->sysStrings->_strings[sysStringId]._maxSize = index1 + count;
+ s->_segMan->sysStrings->_strings[sysStringId]._value = (char *)calloc(index1 + count, sizeof(char));
}
- strncpy(s->sys_strings->_strings[argv[1].toUint16()]._value + index1, string2.c_str() + index2, count);
+ strncpy(s->_segMan->sysStrings->_strings[sysStringId]._value + index1, string2 + index2, count);
} else {
SciString *string1 = s->_segMan->lookupString(argv[1]);
@@ -594,7 +610,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
// Note: We're accessing from c_str() here because the string's size ignores
// the trailing 0 and therefore triggers an assert when doing string2[i + index2].
for (uint16 i = 0; i < count; i++)
- string1->setValue(i + index1, string2.c_str()[i + index2]);
+ string1->setValue(i + index1, string2[i + index2]);
}
} return argv[1];
@@ -608,15 +624,25 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, strcmp(string1.c_str(), string2.c_str()));
}
case 8: { // Dup
- Common::String string = s->_segMan->getString(argv[1]);
+ const char *rawString = 0;
+ uint32 size = 0;
+
+ if (argv[1].segment == s->_segMan->getStringSegmentId()) {
+ SciString *string = s->_segMan->lookupString(argv[1]);
+ rawString = string->getRawData();
+ size = string->getSize();
+ } else {
+ Common::String string = s->_segMan->getString(argv[1]);
+ rawString = string.c_str();
+ size = string.size() + 1;
+ }
+
reg_t stringHandle;
SciString *dupString = s->_segMan->allocateString(&stringHandle);
- dupString->setSize(string.size() + 1);
+ dupString->setSize(size);
- for (uint32 i = 0; i < string.size(); i++)
- dupString->setValue(i, string.c_str()[i]);
-
- dupString->setValue(dupString->getSize() - 1, 0);
+ for (uint32 i = 0; i < size; i++)
+ dupString->setValue(i, rawString[i]);
return stringHandle;
}
@@ -624,7 +650,7 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) {
if (!s->_segMan->isHeapObject(argv[1]))
return argv[1];
- return GET_SEL32(s->_segMan, argv[1], SELECTOR(data));
+ return readSelector(s->_segMan, argv[1], SELECTOR(data));
case 10: // Stringlen
return make_reg(0, s->_segMan->strlen(argv[1]));
case 11: { // Printf
@@ -689,12 +715,12 @@ reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
/*
reg_t viewObj = argv[0];
- uint16 viewId = GET_SEL32V(s->_segMan, viewObj, SELECTOR(view));
- int16 loopNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(loop));
- int16 celNo = GET_SEL32V(s->_segMan, viewObj, SELECTOR(cel));
+ uint16 viewId = readSelectorValue(s->_segMan, viewObj, SELECTOR(view));
+ int16 loopNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(loop));
+ int16 celNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(cel));
//int16 leftPos = 0;
//int16 topPos = 0;
- int16 priority = GET_SEL32V(s->_segMan, viewObj, SELECTOR(priority));
+ int16 priority = readSelectorValue(s->_segMan, viewObj, SELECTOR(priority));
//int16 control = 0;
*/
@@ -761,10 +787,10 @@ reg_t kOnMe(EngineState *s, int argc, reg_t *argv) {
Common::Rect nsRect;
// Get the bounding rectangle of the object
- nsRect.left = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsLeft));
- nsRect.top = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsTop));
- nsRect.right = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsRight));
- nsRect.bottom = GET_SEL32V(s->_segMan, targetObject, SELECTOR(nsBottom));
+ nsRect.left = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsLeft));
+ nsRect.top = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsTop));
+ nsRect.right = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsRight));
+ nsRect.bottom = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsBottom));
//warning("kOnMe: (%d, %d) on object %04x:%04x, parameter %d", argv[0].toUint16(), argv[1].toUint16(), PRINT_REG(argv[2]), argv[3].toUint16());
@@ -778,9 +804,16 @@ reg_t kInPolygon(EngineState *s, int argc, reg_t *argv) {
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
// TODO: argument 0 is usually 0, and arguments 1 and 2 are usually 1
- reg_t object = argv[3];
- Common::String text = s->_segMan->getString(GET_SEL32(s->_segMan, object, SELECTOR(text)));
- debug("kCreateTextBitmap: %s", text.c_str());
+ switch (argv[0].toUint16()) {
+ case 0:
+ if (argc != 4) {
+ warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc);
+ return NULL_REG;
+ }
+ reg_t object = argv[3];
+ Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text)));
+ debug("kCreateTextBitmap: %s", text.c_str());
+ }
return NULL_REG;
}
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index 156035b30d..fd7711f196 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -49,16 +49,18 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
Common::Point mousePos;
+ // Limit the mouse cursor position, if necessary
+ g_sci->_gfxCursor->refreshPosition();
mousePos = g_sci->_gfxCursor->getPosition();
// If there's a simkey pending, and the game wants a keyboard event, use the
// simkey instead of a normal event
if (g_debug_simulated_key && (mask & SCI_EVENT_KEYBOARD)) {
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
- PUT_SEL32V(segMan, obj, SELECTOR(message), g_debug_simulated_key);
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
- PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ writeSelectorValue(segMan, obj, SELECTOR(message), g_debug_simulated_key);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), SCI_KEYMOD_NUMLOCK); // Numlock on
+ writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
g_debug_simulated_key = 0;
return make_reg(0, 1);
}
@@ -67,26 +69,26 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
oldy = mousePos.y;
curEvent = s->_event->get(mask);
- if (s->_voc)
- s->_voc->parser_event = NULL_REG; // Invalidate parser event
+ if (g_sci->getVocabulary())
+ g_sci->getVocabulary()->parser_event = NULL_REG; // Invalidate parser event
- PUT_SEL32V(segMan, obj, SELECTOR(x), mousePos.x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), mousePos.y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), mousePos.x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), mousePos.y);
//s->_gui->moveCursor(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y);
switch (curEvent.type) {
case SCI_EVENT_QUIT:
- quit_vm();
+ quit_vm(s);
break;
case SCI_EVENT_KEYBOARD:
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_KEYBOARD); // Keyboard event
s->r_acc = make_reg(0, 1);
- PUT_SEL32V(segMan, obj, SELECTOR(message), curEvent.character);
+ writeSelectorValue(segMan, obj, SELECTOR(message), curEvent.character);
// We only care about the translated character
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), curEvent.modifiers & modifier_mask);
break;
case SCI_EVENT_MOUSE_RELEASE:
@@ -111,9 +113,9 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
break;
}
- PUT_SEL32V(segMan, obj, SELECTOR(type), curEvent.type);
- PUT_SEL32V(segMan, obj, SELECTOR(message), 0);
- PUT_SEL32V(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
+ writeSelectorValue(segMan, obj, SELECTOR(type), curEvent.type);
+ writeSelectorValue(segMan, obj, SELECTOR(message), 0);
+ writeSelectorValue(segMan, obj, SELECTOR(modifiers), (curEvent.modifiers | extra_bits) & modifier_mask);
s->r_acc = make_reg(0, 1);
}
break;
@@ -165,9 +167,9 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
SegManager *segMan = s->_segMan;
- if (GET_SEL32V(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
+ if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard
int mover = -1;
- switch (GET_SEL32V(segMan, obj, SELECTOR(message))) {
+ switch (readSelectorValue(segMan, obj, SELECTOR(message))) {
case SCI_KEY_HOME:
mover = 8;
break;
@@ -201,8 +203,8 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) {
}
if (mover >= 0) {
- PUT_SEL32V(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
- PUT_SEL32V(segMan, obj, SELECTOR(message), mover);
+ writeSelectorValue(segMan, obj, SELECTOR(type), SCI_EVENT_JOYSTICK);
+ writeSelectorValue(segMan, obj, SELECTOR(message), mover);
return make_reg(0, 1);
} else
return NULL_REG;
@@ -217,13 +219,13 @@ reg_t kGlobalToLocal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
- int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
+ int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
+ int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelGlobalToLocal(x, y, planeObject);
- PUT_SEL32V(segMan, obj, SELECTOR(x), x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
@@ -236,13 +238,13 @@ reg_t kLocalToGlobal(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
if (obj.segment) {
- int16 x = GET_SEL32V(segMan, obj, SELECTOR(x));
- int16 y = GET_SEL32V(segMan, obj, SELECTOR(y));
+ int16 x = readSelectorValue(segMan, obj, SELECTOR(x));
+ int16 y = readSelectorValue(segMan, obj, SELECTOR(y));
g_sci->_gfxCoordAdjuster->kernelLocalToGlobal(x, y, planeObject);
- PUT_SEL32V(segMan, obj, SELECTOR(x), x);
- PUT_SEL32V(segMan, obj, SELECTOR(y), y);
+ writeSelectorValue(segMan, obj, SELECTOR(x), x);
+ writeSelectorValue(segMan, obj, SELECTOR(y), y);
}
return s->r_acc;
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index e6b9a5388c..3e0ecd1a28 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -44,6 +44,8 @@ struct SavegameDesc {
int id;
int date;
int time;
+ int version;
+ char name[SCI_MAX_SAVENAME_LENGTH];
};
/*
@@ -245,13 +247,10 @@ static void fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle) {
debugC(2, kDebugLevelFile, "FGets'ed \"%s\"", dest);
}
-static int _savegame_index_struct_compare(const void *a, const void *b) {
- const SavegameDesc *A = (const SavegameDesc *)a;
- const SavegameDesc *B = (const SavegameDesc *)b;
-
- if (B->date != A->date)
- return B->date - A->date;
- return B->time - A->time;
+static bool _savegame_index_struct_compare(const SavegameDesc &l, const SavegameDesc &r) {
+ if (l.date != r.date)
+ return (l.date > r.date);
+ return (l.time > r.time);
}
void listSavegames(Common::Array<SavegameDesc> &saves) {
@@ -265,7 +264,7 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
Common::SeekableReadStream *in;
if ((in = saveFileMan->openForLoading(filename))) {
SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
+ if (!get_savegame_metadata(in, &meta) || meta.savegame_name.empty()) {
// invalid
delete in;
continue;
@@ -278,6 +277,13 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
// We need to fix date in here, because we save DDMMYYYY instead of YYYYMMDD, so sorting wouldnt work
desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24);
desc.time = meta.savegame_time;
+ desc.version = meta.savegame_version;
+
+ if (meta.savegame_name.lastChar() == '\n')
+ meta.savegame_name.deleteLastChar();
+
+ Common::strlcpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH);
+
debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id);
saves.push_back(desc);
@@ -285,35 +291,18 @@ void listSavegames(Common::Array<SavegameDesc> &saves) {
}
// Sort the list by creation date of the saves
- qsort(saves.begin(), saves.size(), sizeof(SavegameDesc), _savegame_index_struct_compare);
+ Common::sort(saves.begin(), saves.end(), _savegame_index_struct_compare);
}
bool Console::cmdListSaves(int argc, const char **argv) {
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
-
for (uint i = 0; i < saves.size(); i++) {
Common::String filename = g_sci->getSavegameName(saves[i].id);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- delete in;
- continue;
- }
-
- if (!meta.savegame_name.empty()) {
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
-
- DebugPrintf("%s: '%s'\n", filename.c_str(), meta.savegame_name.c_str());
- }
- delete in;
- }
+ DebugPrintf("%s: '%s'\n", filename.c_str(), saves[i].name);
}
+
return true;
}
@@ -428,7 +417,7 @@ reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) {
warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0]));
#endif
- return make_reg(s->sys_strings_segment, SYS_STRING_SAVEDIR);
+ return make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_SAVEDIR);
}
reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
@@ -449,90 +438,59 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
- int savedir_nr = argv[1].toUint16();
+ uint16 savedir_nr = argv[1].toUint16();
debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), savedir_nr);
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- savedir_nr = saves[savedir_nr].id;
-
- if (savedir_nr > MAX_SAVEGAME_NR - 1) {
+ // Check for savegame slot being out of range
+ if (savedir_nr >= saves.size())
return NULL_REG;
- }
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
- Common::String filename = g_sci->getSavegameName(savedir_nr);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- // found a savegame file
-
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- s->r_acc = make_reg(0, 0);
- } else {
- s->r_acc = make_reg(0, 1);
- }
- delete in;
- } else {
- s->r_acc = make_reg(0, 1);
- }
+ // Check for compatible savegame version
+ int ver = saves[savedir_nr].version;
+ if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION)
+ return NULL_REG;
- return s->r_acc;
+ // Otherwise we assume the savegame is OK
+ return make_reg(0, 1);
}
reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
Common::String game_id = s->_segMan->getString(argv[0]);
- reg_t nametarget = argv[1];
- reg_t *nameoffsets = s->_segMan->derefRegPtr(argv[2], 0);
debug(3, "kGetSaveFiles(%s)", game_id.c_str());
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- s->r_acc = NULL_REG;
- Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+ uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR);
- for (uint i = 0; i < saves.size(); i++) {
- Common::String filename = g_sci->getSavegameName(saves[i].id);
- Common::SeekableReadStream *in;
- if ((in = saveFileMan->openForLoading(filename))) {
- // found a savegame file
+ reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves);
- SavegameMetadata meta;
- if (!get_savegame_metadata(in, &meta)) {
- // invalid
- delete in;
- continue;
- }
-
- if (!meta.savegame_name.empty()) {
- if (meta.savegame_name.lastChar() == '\n')
- meta.savegame_name.deleteLastChar();
-
- *nameoffsets = s->r_acc; // Store savegame ID
- ++s->r_acc.offset; // Increase number of files found
+ if (!slot) {
+ warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2]));
+ totalSaves = 0;
+ }
- nameoffsets++; // Make sure the next ID string address is written to the next pointer
- Common::String name = meta.savegame_name;
- if (name.size() > SCI_MAX_SAVENAME_LENGTH-1)
- name = Common::String(meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH-1);
- s->_segMan->strcpy(nametarget, name.c_str());
+ const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1;
+ char *saveNames = new char[bufSize];
+ char *saveNamePtr = saveNames;
- // Increase name offset pointer accordingly
- nametarget.offset += SCI_MAX_SAVENAME_LENGTH;
- }
- delete in;
- }
+ for (uint i = 0; i < totalSaves; i++) {
+ *slot++ = make_reg(0, i); // Store slot
+ strcpy(saveNamePtr, saves[i].name);
+ saveNamePtr += SCI_MAX_SAVENAME_LENGTH;
}
- //free(gfname);
- s->_segMan->strcpy(nametarget, ""); // Terminate list
+ *saveNamePtr = 0; // Terminate list
- return s->r_acc;
+ s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize);
+ delete[] saveNames;
+
+ return make_reg(0, totalSaves);
}
reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index d587790b6c..abe55455de 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -23,8 +23,10 @@
*
*/
+#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/video/avi_decoder.h"
+#include "graphics/video/qt_decoder.h"
#include "graphics/surface.h"
#include "sci/sci.h"
@@ -51,8 +53,8 @@
namespace Sci {
void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *argv) {
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
- uint16 signal = GET_SEL32V(s->_segMan, object, SELECTOR(signal));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+ uint16 signal = readSelectorValue(s->_segMan, object, SELECTOR(signal));
int16 loopNo;
int16 maxLoops;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
@@ -91,7 +93,7 @@ void _k_dirloop(reg_t object, uint16 angle, EngineState *s, int argc, reg_t *arg
if ((loopNo > 1) && (maxLoops < 4))
return;
- PUT_SEL32V(s->_segMan, object, SELECTOR(loop), loopNo);
+ writeSelectorValue(s->_segMan, object, SELECTOR(loop), loopNo);
}
static reg_t kSetCursorSci0(EngineState *s, int argc, reg_t *argv) {
@@ -146,6 +148,10 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) {
int16 bottom = argv[2].toSint16();
int16 right = argv[3].toSint16();
+ // In SCI32, the right parameter seems to be divided by 2
+ if (getSciVersion() >= SCI_VERSION_2)
+ right *= 2;
+
if ((right >= left) && (bottom >= top)) {
Common::Rect rect = Common::Rect(left, top, right, bottom);
g_sci->_gfxCursor->kernelSetMoveZone(rect);
@@ -437,7 +443,7 @@ reg_t kCelWide(EngineState *s, int argc, reg_t *argv) {
reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
int16 loopCount;
loopCount = g_sci->_gfxCache->kernelViewGetLoopCount(viewId);
@@ -449,8 +455,8 @@ reg_t kNumLoops(EngineState *s, int argc, reg_t *argv) {
reg_t kNumCels(EngineState *s, int argc, reg_t *argv) {
reg_t object = argv[0];
- GuiResourceId viewId = GET_SEL32V(s->_segMan, object, SELECTOR(view));
- int16 loopNo = GET_SEL32V(s->_segMan, object, SELECTOR(loop));
+ GuiResourceId viewId = readSelectorValue(s->_segMan, object, SELECTOR(view));
+ int16 loopNo = readSelectorValue(s->_segMan, object, SELECTOR(loop));
int16 celCount;
celCount = g_sci->_gfxCache->kernelViewGetCelCount(viewId, loopNo);
@@ -525,9 +531,9 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) {
// WORKAROUND for a problem in LSL1VGA. This allows the casino door to be opened,
// till the actual problem is found
- if (s->_gameId == "lsl1sci" && s->currentRoomNumber() == 300) {
- int top = GET_SEL32V(s->_segMan, object, SELECTOR(brTop));
- PUT_SEL32V(s->_segMan, object, SELECTOR(brTop), top + 2);
+ if (!strcmp(g_sci->getGameID(), "lsl1sci") && s->currentRoomNumber() == 300) {
+ int top = readSelectorValue(s->_segMan, object, SELECTOR(brTop));
+ writeSelectorValue(s->_segMan, object, SELECTOR(brTop), top + 2);
}
return s->r_acc;
@@ -741,12 +747,12 @@ Common::Rect kControlCreateRect(int16 x, int16 y, int16 x1, int16 y1) {
}
void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
- int16 type = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
- int16 style = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
- int16 x = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsLeft));
- int16 y = GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsTop));
- GuiResourceId fontId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(font));
- reg_t textReference = GET_SEL32(s->_segMan, controlObject, SELECTOR(text));
+ int16 type = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
+ int16 style = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
+ int16 x = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsLeft));
+ int16 y = readSelectorValue(s->_segMan, controlObject, SELECTOR(nsTop));
+ GuiResourceId fontId = readSelectorValue(s->_segMan, controlObject, SELECTOR(font));
+ reg_t textReference = readSelector(s->_segMan, controlObject, SELECTOR(text));
Common::String text;
Common::Rect rect;
TextAlignment alignment;
@@ -762,8 +768,8 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
bool isAlias = false;
rect = kControlCreateRect(x, y,
- GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsRight)),
- GET_SEL32V(s->_segMan, controlObject, SELECTOR(nsBottom)));
+ readSelectorValue(s->_segMan, controlObject, SELECTOR(nsRight)),
+ readSelectorValue(s->_segMan, controlObject, SELECTOR(nsBottom)));
if (!textReference.isNull())
text = s->_segMan->getString(textReference);
@@ -775,32 +781,32 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
return;
case SCI_CONTROLS_TYPE_TEXT:
- alignment = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
+ alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment);
g_sci->_gfxControls->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite);
return;
case SCI_CONTROLS_TYPE_TEXTEDIT:
- mode = GET_SEL32V(s->_segMan, controlObject, SELECTOR(mode));
- maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(max));
- cursorPos = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
+ mode = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode));
+ maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(max));
+ cursorPos = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
debugC(2, kDebugLevelGraphics, "drawing edit control %04x:%04x (text %04x:%04x, '%s') to %d,%d", PRINT_REG(controlObject), PRINT_REG(textReference), text.c_str(), x, y);
g_sci->_gfxControls->kernelDrawTextEdit(rect, controlObject, g_sci->strSplit(text.c_str(), NULL).c_str(), fontId, mode, style, cursorPos, maxChars, hilite);
return;
case SCI_CONTROLS_TYPE_ICON:
- viewId = GET_SEL32V(s->_segMan, controlObject, SELECTOR(view));
+ viewId = readSelectorValue(s->_segMan, controlObject, SELECTOR(view));
{
- int l = GET_SEL32V(s->_segMan, controlObject, SELECTOR(loop));
+ int l = readSelectorValue(s->_segMan, controlObject, SELECTOR(loop));
loopNo = (l & 0x80) ? l - 256 : l;
- int c = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cel));
+ int c = readSelectorValue(s->_segMan, controlObject, SELECTOR(cel));
celNo = (c & 0x80) ? c - 256 : c;
// Game-specific: *ONLY* the jones EGA/VGA sierra interpreter contain code using priority selector
// ALL other games use a hardcoded -1 (madness!)
// We are detecting jones/talkie as "jones" as well, but the sierra interpreter of talkie doesnt have this
// "hack". Hopefully it wont cause regressions (the code causes regressions if used against kq5/floppy)
- if (s->_gameId == "jones")
- priority = GET_SEL32V(s->_segMan, controlObject, SELECTOR(priority));
+ if (!strcmp(g_sci->getGameID(), "jones"))
+ priority = readSelectorValue(s->_segMan, controlObject, SELECTOR(priority));
else
priority = -1;
}
@@ -813,17 +819,17 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) {
if (type == SCI_CONTROLS_TYPE_LIST_ALIAS)
isAlias = true;
- maxChars = GET_SEL32V(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
- cursorOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(cursor));
+ maxChars = readSelectorValue(s->_segMan, controlObject, SELECTOR(x)); // max chars per entry
+ cursorOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(cursor));
if (g_sci->getKernel()->_selectorCache.topString != -1) {
// Games from early SCI1 onwards use topString
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(topString));
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(topString));
} else {
// Earlier games use lsTop or brTop
- if (lookup_selector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(brTop));
+ if (lookupSelector(s->_segMan, controlObject, g_sci->getKernel()->_selectorCache.brTop, NULL, NULL) == kSelectorVariable)
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(brTop));
else
- upperOffset = GET_SEL32V(s->_segMan, controlObject, SELECTOR(lsTop));
+ upperOffset = readSelectorValue(s->_segMan, controlObject, SELECTOR(lsTop));
}
// Count string entries in NULL terminated string list
@@ -874,8 +880,8 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
// Disable the "Change Directory" button, as we don't allow the game engine to
// change the directory where saved games are placed
if (objName == "changeDirI") {
- int state = GET_SEL32V(s->_segMan, controlObject, SELECTOR(state));
- PUT_SEL32V(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
+ int state = readSelectorValue(s->_segMan, controlObject, SELECTOR(state));
+ writeSelectorValue(s->_segMan, controlObject, SELECTOR(state), (state | SCI_CONTROLS_STYLE_DISABLED) & ~SCI_CONTROLS_STYLE_ENABLED);
}
_k_GenericDrawControl(s, controlObject, false);
@@ -894,7 +900,7 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) {
reg_t eventObject = argv[1];
if (!controlObject.isNull()) {
- int16 controlType = GET_SEL32V(s->_segMan, controlObject, SELECTOR(type));
+ int16 controlType = readSelectorValue(s->_segMan, controlObject, SELECTOR(type));
switch (controlType) {
case SCI_CONTROLS_TYPE_TEXTEDIT:
@@ -983,7 +989,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
bool hiresMode = (argc > 7) ? true : false;
reg_t upscaledHiresHandle = (argc > 7) ? argv[7] : NULL_REG;
- if ((s->_gameId == "freddypharkas") || (s->_gameId == "freddypharkas-demo")) {
+ if (!strcmp(g_sci->getGameID(), "freddypharkas") || !strcmp(g_sci->getGameID(), "freddypharkas-demo")) {
// WORKAROUND
// Script 24 contains code that draws the game menu on screen. It uses a temp variable for setting priority that
// is not set. in Sierra sci this happens to be 8250h. In our sci temporary variables are initialized thus we would
@@ -994,7 +1000,7 @@ reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {
priority = 15;
}
- if (s->_gameId == "laurabow2") {
+ if (!strcmp(g_sci->getGameID(), "laurabow2")) {
// WORKAROUND
// see the one above
if ((viewId == 995) && (priority == 0))
@@ -1080,11 +1086,12 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) {
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
// Hide the cursor if it's showing and then show it again if it was
// previously visible.
- bool reshowCursor;
-
- reshowCursor = g_sci->_gfxCursor->isVisible();
+ bool reshowCursor = g_sci->_gfxCursor->isVisible();
if (reshowCursor)
g_sci->_gfxCursor->kernelHide();
+
+ uint16 screenWidth = g_system->getWidth();
+ uint16 screenHeight = g_system->getHeight();
Graphics::VideoDecoder *videoDecoder = 0;
@@ -1094,8 +1101,18 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
// Mac QuickTime
// The only argument is the string for the video
- warning("TODO: Play QuickTime movie '%s'", filename.c_str());
- return s->r_acc;
+
+ // HACK: Switch to 16bpp graphics for Cinepak.
+ initGraphics(screenWidth, screenHeight, screenWidth > 320, NULL);
+
+ if (g_system->getScreenFormat().bytesPerPixel == 1) {
+ warning("This video requires >8bpp color to be displayed, but could not switch to RGB color mode.");
+ return NULL_REG;
+ }
+
+ videoDecoder = new Graphics::QuickTimeDecoder();
+ if (!videoDecoder->loadFile(filename))
+ error("Could not open '%s'", filename.c_str());
} else {
// DOS SEQ
// SEQ's are called with no subops, just the string and delay
@@ -1110,7 +1127,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
}
} else {
- // Windows AVI (Macintosh QuickTime? Need to check KQ6 Macintosh)
+ // Windows AVI
// TODO: This appears to be some sort of subop. case 0 contains the string
// for the video, so we'll just play it from there for now.
@@ -1142,10 +1159,10 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
if (videoDecoder) {
- uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
- uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
+ uint16 x = (screenWidth - videoDecoder->getWidth()) / 2;
+ uint16 y = (screenHeight - videoDecoder->getHeight()) / 2;
- while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
if (videoDecoder->needsUpdate()) {
Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
@@ -1164,9 +1181,15 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
g_system->delayMillis(10);
}
+
+ // HACK: Switch back to 8bpp if we played a QuickTime video.
+ // We also won't be copying the screen to the SCI screen...
+ if (g_system->getScreenFormat().bytesPerPixel != 1)
+ initGraphics(screenWidth, screenHeight, screenWidth > 320);
+ else
+ g_sci->_gfxScreen->kernelSyncWithFramebuffer();
delete videoDecoder;
- g_sci->_gfxScreen->kernelSyncWithFramebuffer();
}
if (reshowCursor)
diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp
index c04454ca3d..f06f3eec77 100644
--- a/engines/sci/engine/klists.cpp
+++ b/engines/sci/engine/klists.cpp
@@ -155,28 +155,10 @@ reg_t kDisposeList(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-static reg_t _k_new_node(EngineState *s, reg_t value, reg_t key) {
- reg_t nodebase;
- Node *n = s->_segMan->allocateNode(&nodebase);
-
- if (!n) {
- error("[Kernel] Out of memory while creating a node");
- return NULL_REG;
- }
-
- n->pred = n->succ = NULL_REG;
- n->key = key;
- n->value = value;
-
- return nodebase;
-}
-
reg_t kNewNode(EngineState *s, int argc, reg_t *argv) {
-
- if (argc == 1)
- s->r_acc = _k_new_node(s, argv[0], argv[0]);
- else
- s->r_acc = _k_new_node(s, argv[0], argv[1]);
+ reg_t nodeValue = argv[0];
+ reg_t nodeKey = (argc == 2) ? argv[1] : NULL_REG;
+ s->r_acc = s->_segMan->newNode(nodeValue, nodeKey);
debugC(2, kDebugLevelNodes, "New nodebase at %04x:%04x", PRINT_REG(s->r_acc));
@@ -415,11 +397,11 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
reg_t dest = argv[1];
reg_t order_func = argv[2];
- int input_size = (int16)GET_SEL32V(segMan, source, SELECTOR(size));
+ int input_size = (int16)readSelectorValue(segMan, source, SELECTOR(size));
int i;
- reg_t input_data = GET_SEL32(segMan, source, SELECTOR(elements));
- reg_t output_data = GET_SEL32(segMan, dest, SELECTOR(elements));
+ reg_t input_data = readSelector(segMan, source, SELECTOR(elements));
+ reg_t output_data = readSelector(segMan, dest, SELECTOR(elements));
List *list;
Node *node;
@@ -430,10 +412,10 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
if (output_data.isNull()) {
list = s->_segMan->allocateList(&output_data);
list->first = list->last = NULL_REG;
- PUT_SEL32(segMan, dest, SELECTOR(elements), output_data);
+ writeSelector(segMan, dest, SELECTOR(elements), output_data);
}
- PUT_SEL32V(segMan, dest, SELECTOR(size), input_size);
+ writeSelectorValue(segMan, dest, SELECTOR(size), input_size);
list = s->_segMan->lookupList(input_data);
node = s->_segMan->lookupNode(list->first);
@@ -442,7 +424,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
i = 0;
while (node) {
- invoke_selector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
+ invokeSelector(INV_SEL(s, order_func, doit, kStopOnInvalidSelector), 1, node->value);
temp_array[i].key = node->key;
temp_array[i].value = node->value;
temp_array[i].order = s->r_acc;
@@ -453,7 +435,7 @@ reg_t kSort(EngineState *s, int argc, reg_t *argv) {
qsort(temp_array, input_size, sizeof(sort_temp_t), sort_temp_cmp);
for (i = 0;i < input_size;i++) {
- reg_t lNode = _k_new_node(s, temp_array[i].key, temp_array[i].value);
+ reg_t lNode = s->_segMan->newNode(temp_array[i].value, temp_array[i].key);
_k_add_to_end(s, output_data, lNode);
}
@@ -533,15 +515,15 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// This can only happen with 3 params (list, target selector, variable)
if (argc != 3) {
warning("kListEachElementDo: Attempted to modify a variable selector with %d params", argc);
} else {
- write_selector(s->_segMan, curObject, slc, argv[2]);
+ writeSelector(s->_segMan, curObject, slc, argv[2]);
}
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
}
curNode = s->_segMan->lookupNode(nextNode);
@@ -566,11 +548,11 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListFirstTrue: Attempted to access a variable selector");
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result is true
if (!s->r_acc.isNull())
@@ -600,11 +582,11 @@ reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv) {
curObject = curNode->value;
// First, check if the target selector is a variable
- if (lookup_selector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
+ if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
// Can this happen with variable selectors?
warning("kListAllTrue: Attempted to access a variable selector");
} else {
- invoke_selector_argv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
+ invokeSelectorArgv(s, curObject, slc, kContinueOnInvalidSelector, argc, argv, argc - 2, argv + 2);
// Check if the result isn't true
if (s->r_acc.isNull())
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 450dca3770..f91ba0fd82 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -32,16 +32,16 @@
#include "sci/engine/kernel.h"
#include "sci/engine/gc.h"
#include "sci/graphics/gui.h"
+#include "sci/graphics/maciconbar.h"
namespace Sci {
reg_t kRestartGame(EngineState *s, int argc, reg_t *argv) {
s->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW;
- s->restarting_flags &= ~SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE; // This appears to help
- shrink_execution_stack(s, s->execution_stack_base + 1);
+ s->shrinkStackToBase();
- script_abort_flag = 1; // Force vm to abort ASAP
+ s->script_abort_flag = 1; // Force vm to abort ASAP
return NULL_REG;
}
@@ -62,9 +62,9 @@ reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
// LSL3 calculates a machinespeed variable during game startup (right after the filthy questions)
// This one would go through w/o throttling resulting in having to do 1000 pushups or something
// Another way of handling this would be delaying incrementing of "machineSpeed" selector
- if (s->_gameId == "lsl3" && s->currentRoomNumber() == 290)
+ if (!strcmp(g_sci->getGameID(), "lsl3") && s->currentRoomNumber() == 290)
s->_throttleTrigger = true;
- if (s->_gameId == "iceman" && s->currentRoomNumber() == 27) {
+ if (!strcmp(g_sci->getGameID(), "iceman") && s->currentRoomNumber() == 27) {
s->_throttleTrigger = true;
neededSleep = 60;
}
@@ -252,10 +252,15 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
break;
}
case K_MEMORY_PEEK : {
+ if (!argv[1].segment) {
+ // This occurs in KQ5CD when interacting with certain objects
+ warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
+ return s->r_acc;
+ }
+
SegmentRef ref = s->_segMan->dereference(argv[1]);
if (!ref.isValid() || ref.maxSize < 2) {
- // This occurs in KQ5CD when interacting with certain objects
warning("Attempt to peek invalid memory at %04x:%04x", PRINT_REG(argv[1]));
return s->r_acc;
}
@@ -298,9 +303,12 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) {
reg_t kIconBar(EngineState *s, int argc, reg_t *argv) {
// TODO...
- if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0)
+ if (argv[0].toUint16() == 4 && argv[1].toUint16() == 0) {
for (int i = 0; i < argv[2].toUint16(); i++)
- warning("kIconBar: Icon Object %d = %04x:%04x", i, PRINT_REG(argv[i + 3]));
+ g_sci->_gfxMacIconBar->addIcon(argv[i + 3]);
+
+ g_sci->_gfxMacIconBar->drawIcons();
+ }
// Other calls seem to handle selecting/deselecting them
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index fcaf0d7ea0..499aeabcc6 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -158,8 +158,8 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "SetJump for object at %04x:%04x", PRINT_REG(object));
debugC(2, kDebugLevelBresen, "xStep: %d, yStep: %d", vx, vy);
- PUT_SEL32V(segMan, object, SELECTOR(xStep), vx);
- PUT_SEL32V(segMan, object, SELECTOR(yStep), vy);
+ writeSelectorValue(segMan, object, SELECTOR(xStep), vx);
+ writeSelectorValue(segMan, object, SELECTOR(yStep), vy);
return s->r_acc;
}
@@ -168,9 +168,9 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) {
#define _K_BRESEN_AXIS_Y 1
static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t mover, int step_factor, int deltax, int deltay) {
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
- int stepx = (int16)GET_SEL32V(segMan, client, SELECTOR(xStep)) * step_factor;
- int stepy = (int16)GET_SEL32V(segMan, client, SELECTOR(yStep)) * step_factor;
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
+ int stepx = (int16)readSelectorValue(segMan, client, SELECTOR(xStep)) * step_factor;
+ int stepy = (int16)readSelectorValue(segMan, client, SELECTOR(yStep)) * step_factor;
int numsteps_x = stepx ? (abs(deltax) + stepx - 1) / stepx : 0;
int numsteps_y = stepy ? (abs(deltay) + stepy - 1) / stepy : 0;
int bdi, i1;
@@ -191,15 +191,15 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
/* if (abs(deltax) > abs(deltay)) {*/ // Bresenham on y
if (numsteps_y < numsteps_x) {
- PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
- PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y);
+ writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1);
//i1 = 2 * (abs(deltay) - abs(deltay_step * numsteps)) * abs(deltax_step);
//bdi = -abs(deltax);
i1 = 2 * (abs(deltay) - abs(deltay_step * (numsteps - 1))) * abs(deltax_step);
bdi = -abs(deltax);
} else { // Bresenham on x
- PUT_SEL32V(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
- PUT_SEL32V(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X);
+ writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1);
//i1= 2 * (abs(deltax) - abs(deltax_step * numsteps)) * abs(deltay_step);
//bdi = -abs(deltay);
i1 = 2 * (abs(deltax) - abs(deltax_step * (numsteps - 1))) * abs(deltay_step);
@@ -207,26 +207,26 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m
}
- PUT_SEL32V(segMan, mover, SELECTOR(dx), deltax_step);
- PUT_SEL32V(segMan, mover, SELECTOR(dy), deltay_step);
+ writeSelectorValue(segMan, mover, SELECTOR(dx), deltax_step);
+ writeSelectorValue(segMan, mover, SELECTOR(dy), deltay_step);
debugC(2, kDebugLevelBresen, "Init bresen for mover %04x:%04x: d=(%d,%d)", PRINT_REG(mover), deltax, deltay);
debugC(2, kDebugLevelBresen, " steps=%d, mv=(%d, %d), i1= %d, i2=%d",
numsteps, deltax_step, deltay_step, i1, bdi*2);
- //PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
- PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
- PUT_SEL32V(segMan, mover, SELECTOR(b_i1), i1);
- PUT_SEL32V(segMan, mover, SELECTOR(b_i2), bdi * 2);
+ //writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), numsteps); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
+ writeSelectorValue(segMan, mover, SELECTOR(b_i1), i1);
+ writeSelectorValue(segMan, mover, SELECTOR(b_i2), bdi * 2);
}
reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
- int deltax = (int16)GET_SEL32V(segMan, mover, SELECTOR(x)) - (int16)GET_SEL32V(segMan, client, SELECTOR(x));
- int deltay = (int16)GET_SEL32V(segMan, mover, SELECTOR(y)) - (int16)GET_SEL32V(segMan, client, SELECTOR(y));
+ int deltax = (int16)readSelectorValue(segMan, mover, SELECTOR(x)) - (int16)readSelectorValue(segMan, client, SELECTOR(x));
+ int deltay = (int16)readSelectorValue(segMan, mover, SELECTOR(y)) - (int16)readSelectorValue(segMan, client, SELECTOR(y));
int step_factor = (argc < 1) ? argv[1].toUint16() : 1;
initialize_bresen(s->_segMan, argc, argv, mover, step_factor, deltax, deltay);
@@ -240,42 +240,42 @@ reg_t kInitBresen(EngineState *s, int argc, reg_t *argv) {
reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
SegManager *segMan = s->_segMan;
reg_t mover = argv[0];
- reg_t client = GET_SEL32(segMan, mover, SELECTOR(client));
+ reg_t client = readSelector(segMan, mover, SELECTOR(client));
- int x = (int16)GET_SEL32V(segMan, client, SELECTOR(x));
- int y = (int16)GET_SEL32V(segMan, client, SELECTOR(y));
+ int x = (int16)readSelectorValue(segMan, client, SELECTOR(x));
+ int y = (int16)readSelectorValue(segMan, client, SELECTOR(y));
int oldx, oldy, destx, desty, dx, dy, bdi, bi1, bi2, movcnt, bdelta, axis;
- uint16 signal = GET_SEL32V(segMan, client, SELECTOR(signal));
+ uint16 signal = readSelectorValue(segMan, client, SELECTOR(signal));
int completed = 0;
- int max_movcnt = GET_SEL32V(segMan, client, SELECTOR(moveSpeed));
+ int max_movcnt = readSelectorValue(segMan, client, SELECTOR(moveSpeed));
if (getSciVersion() > SCI_VERSION_01)
signal &= ~kSignalHitObstacle;
- PUT_SEL32(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
+ writeSelector(segMan, client, SELECTOR(signal), make_reg(0, signal)); // This is a NOP for SCI0
oldx = x;
oldy = y;
- destx = (int16)GET_SEL32V(segMan, mover, SELECTOR(x));
- desty = (int16)GET_SEL32V(segMan, mover, SELECTOR(y));
- dx = (int16)GET_SEL32V(segMan, mover, SELECTOR(dx));
- dy = (int16)GET_SEL32V(segMan, mover, SELECTOR(dy));
- bdi = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_di));
- bi1 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i1));
- bi2 = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_i2));
- movcnt = GET_SEL32V(segMan, mover, SELECTOR(b_movCnt));
- bdelta = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_incr));
- axis = (int16)GET_SEL32V(segMan, mover, SELECTOR(b_xAxis));
+ destx = (int16)readSelectorValue(segMan, mover, SELECTOR(x));
+ desty = (int16)readSelectorValue(segMan, mover, SELECTOR(y));
+ dx = (int16)readSelectorValue(segMan, mover, SELECTOR(dx));
+ dy = (int16)readSelectorValue(segMan, mover, SELECTOR(dy));
+ bdi = (int16)readSelectorValue(segMan, mover, SELECTOR(b_di));
+ bi1 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i1));
+ bi2 = (int16)readSelectorValue(segMan, mover, SELECTOR(b_i2));
+ movcnt = readSelectorValue(segMan, mover, SELECTOR(b_movCnt));
+ bdelta = (int16)readSelectorValue(segMan, mover, SELECTOR(b_incr));
+ axis = (int16)readSelectorValue(segMan, mover, SELECTOR(b_xAxis));
//printf("movecnt %d, move speed %d\n", movcnt, max_movcnt);
if (g_sci->_features->handleMoveCount()) {
if (max_movcnt > movcnt) {
++movcnt;
- PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
return NULL_REG;
} else {
movcnt = 0;
- PUT_SEL32V(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
+ writeSelectorValue(segMan, mover, SELECTOR(b_movCnt), movcnt); // Needed for HQ1/Ogre?
}
}
@@ -288,7 +288,7 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
dy += bdelta;
}
- PUT_SEL32V(segMan, mover, SELECTOR(b_di), bdi);
+ writeSelectorValue(segMan, mover, SELECTOR(b_di), bdi);
x += dx;
y += dy;
@@ -310,33 +310,32 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) {
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x", PRINT_REG(mover));
}
- PUT_SEL32V(segMan, client, SELECTOR(x), x);
- PUT_SEL32V(segMan, client, SELECTOR(y), y);
+ writeSelectorValue(segMan, client, SELECTOR(x), x);
+ writeSelectorValue(segMan, client, SELECTOR(y), y);
debugC(2, kDebugLevelBresen, "New data: (x,y)=(%d,%d), di=%d", x, y, bdi);
if (g_sci->getKernel()->_selectorCache.cantBeHere != -1) {
- invoke_selector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, client, cantBeHere, kStopOnInvalidSelector), 0);
s->r_acc = make_reg(0, !s->r_acc.offset);
} else {
- invoke_selector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, client, canBeHere, kStopOnInvalidSelector), 0);
}
if (!s->r_acc.offset) { // Contains the return value
- signal = GET_SEL32V(segMan, client, SELECTOR(signal));
+ signal = readSelectorValue(segMan, client, SELECTOR(signal));
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
- PUT_SEL32V(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy);
+ writeSelectorValue(segMan, client, SELECTOR(signal), (signal | kSignalHitObstacle));
debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x by collision", PRINT_REG(mover));
completed = 1;
}
- // FIXME: find out why iceman needs this and we ask for version > SCI01
- if ((getSciVersion() > SCI_VERSION_01) || (s->_gameId == "iceman"))
+ if ((getSciVersion() >= SCI_VERSION_1_EGA))
if (completed)
- invoke_selector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
+ invokeSelector(INV_SEL(s, mover, moveDone, kStopOnInvalidSelector), 0);
return make_reg(0, completed);
}
@@ -378,15 +377,15 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
- client = GET_SEL32(segMan, avoider, SELECTOR(client));
+ client = readSelector(segMan, avoider, SELECTOR(client));
if (!s->_segMan->isHeapObject(client)) {
warning("DoAvoider() where client %04x:%04x is not an object", PRINT_REG(client));
return NULL_REG;
}
- looper = GET_SEL32(segMan, client, SELECTOR(looper));
- mover = GET_SEL32(segMan, client, SELECTOR(mover));
+ looper = readSelector(segMan, client, SELECTOR(looper));
+ mover = readSelector(segMan, client, SELECTOR(mover));
if (!s->_segMan->isHeapObject(mover)) {
if (mover.segment) {
@@ -395,38 +394,38 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- destx = GET_SEL32V(segMan, mover, SELECTOR(x));
- desty = GET_SEL32V(segMan, mover, SELECTOR(y));
+ destx = readSelectorValue(segMan, mover, SELECTOR(x));
+ desty = readSelectorValue(segMan, mover, SELECTOR(y));
debugC(2, kDebugLevelBresen, "Doing avoider %04x:%04x (dest=%d,%d)", PRINT_REG(avoider), destx, desty);
- if (invoke_selector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, mover, doit, kContinueOnInvalidSelector) , 0)) {
error("Mover %04x:%04x of avoider %04x:%04x doesn't have a doit() funcselector", PRINT_REG(mover), PRINT_REG(avoider));
return NULL_REG;
}
- mover = GET_SEL32(segMan, client, SELECTOR(mover));
+ mover = readSelector(segMan, client, SELECTOR(mover));
if (!mover.segment) // Mover has been disposed?
return s->r_acc; // Return gracefully.
- if (invoke_selector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, client, isBlocked, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have an isBlocked() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- dx = destx - GET_SEL32V(segMan, client, SELECTOR(x));
- dy = desty - GET_SEL32V(segMan, client, SELECTOR(y));
+ dx = destx - readSelectorValue(segMan, client, SELECTOR(x));
+ dy = desty - readSelectorValue(segMan, client, SELECTOR(y));
angle = getAngle(dx, dy);
debugC(2, kDebugLevelBresen, "Movement (%d,%d), angle %d is %sblocked", dx, dy, angle, (s->r_acc.offset) ? " " : "not ");
if (s->r_acc.offset) { // isBlocked() returned non-zero
int rotation = (rand() & 1) ? 45 : (360 - 45); // Clockwise/counterclockwise
- int oldx = GET_SEL32V(segMan, client, SELECTOR(x));
- int oldy = GET_SEL32V(segMan, client, SELECTOR(y));
- int xstep = GET_SEL32V(segMan, client, SELECTOR(xStep));
- int ystep = GET_SEL32V(segMan, client, SELECTOR(yStep));
+ int oldx = readSelectorValue(segMan, client, SELECTOR(x));
+ int oldy = readSelectorValue(segMan, client, SELECTOR(y));
+ int xstep = readSelectorValue(segMan, client, SELECTOR(xStep));
+ int ystep = readSelectorValue(segMan, client, SELECTOR(yStep));
int moves;
debugC(2, kDebugLevelBresen, " avoider %04x:%04x", PRINT_REG(avoider));
@@ -435,23 +434,23 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
int move_x = (int)(sin(angle * PI / 180.0) * (xstep));
int move_y = (int)(-cos(angle * PI / 180.0) * (ystep));
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx + move_x);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy + move_y);
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx + move_x);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy + move_y);
debugC(2, kDebugLevelBresen, "Pos (%d,%d): Trying angle %d; delta=(%d,%d)", oldx, oldy, angle, move_x, move_y);
- if (invoke_selector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
+ if (invokeSelector(INV_SEL(s, client, canBeHere, kContinueOnInvalidSelector) , 0)) {
error("Client %04x:%04x of avoider %04x:%04x doesn't"
" have a canBeHere() funcselector", PRINT_REG(client), PRINT_REG(avoider));
return NULL_REG;
}
- PUT_SEL32V(segMan, client, SELECTOR(x), oldx);
- PUT_SEL32V(segMan, client, SELECTOR(y), oldy);
+ writeSelectorValue(segMan, client, SELECTOR(x), oldx);
+ writeSelectorValue(segMan, client, SELECTOR(y), oldy);
if (s->r_acc.offset) { // We can be here
debugC(2, kDebugLevelBresen, "Success");
- PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
+ writeSelectorValue(segMan, client, SELECTOR(heading), angle);
return make_reg(0, angle);
}
@@ -464,17 +463,17 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) {
warning("DoAvoider failed for avoider %04x:%04x", PRINT_REG(avoider));
} else {
- int heading = GET_SEL32V(segMan, client, SELECTOR(heading));
+ int heading = readSelectorValue(segMan, client, SELECTOR(heading));
if (heading == -1)
return s->r_acc; // No change
- PUT_SEL32V(segMan, client, SELECTOR(heading), angle);
+ writeSelectorValue(segMan, client, SELECTOR(heading), angle);
s->r_acc = make_reg(0, angle);
if (looper.segment) {
- if (invoke_selector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
+ if (invokeSelector(INV_SEL(s, looper, doit, kContinueOnInvalidSelector), 2, angle, client)) {
error("Looper %04x:%04x of avoider %04x:%04x doesn't"
" have a doit() funcselector", PRINT_REG(looper), PRINT_REG(avoider));
} else
diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp
index 0254d21642..785ff39d22 100644
--- a/engines/sci/engine/kparse.cpp
+++ b/engines/sci/engine/kparse.cpp
@@ -42,6 +42,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
reg_t heap_said_block = argv[0];
byte *said_block;
int new_lastmatch;
+ Vocabulary *voc = g_sci->getVocabulary();
#ifdef DEBUG_PARSER
const int debug_parser = 1;
#else
@@ -63,7 +64,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->_voc->decipherSaidBlock(said_block);
#endif
- if (s->_voc->parser_event.isNull() || (GET_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed)))) {
+ if (voc->parser_event.isNull() || (readSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed)))) {
return NULL_REG;
}
@@ -77,7 +78,7 @@ reg_t kSaid(EngineState *s, int argc, reg_t *argv) {
s->r_acc = make_reg(0, 1);
if (new_lastmatch != SAID_PARTIAL_MATCH)
- PUT_SEL32V(s->_segMan, s->_voc->parser_event, SELECTOR(claimed), 1);
+ writeSelectorValue(s->_segMan, voc->parser_event, SELECTOR(claimed), 1);
} else {
return NULL_REG;
@@ -92,15 +93,15 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
char *error;
ResultWordList words;
reg_t event = argv[1];
- Vocabulary *voc = s->_voc;
+ Vocabulary *voc = g_sci->getVocabulary();
- s->_voc->parser_event = event;
+ voc->parser_event = event;
bool res = voc->tokenizeString(words, string.c_str(), &error);
- s->_voc->parserIsValid = false; /* not valid */
+ voc->parserIsValid = false; /* not valid */
if (res && !words.empty()) {
- s->_voc->synonymizeTokens(words);
+ voc->synonymizeTokens(words);
s->r_acc = make_reg(0, 1);
@@ -115,32 +116,32 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) {
if (syntax_fail) {
s->r_acc = make_reg(0, 1);
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
- invoke_selector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
+ invokeSelector(INV_SEL(s, s->_gameObj, syntaxFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
/* Issue warning */
debugC(2, kDebugLevelParser, "Tree building failed");
} else {
- s->_voc->parserIsValid = true;
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 0);
+ voc->parserIsValid = true;
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 0);
#ifdef DEBUG_PARSER
- s->_voc->dumpParseTree();
+ voc->dumpParseTree();
#endif
}
} else {
s->r_acc = make_reg(0, 0);
- PUT_SEL32V(segMan, event, SELECTOR(claimed), 1);
+ writeSelectorValue(segMan, event, SELECTOR(claimed), 1);
if (error) {
- s->_segMan->strcpy(s->_voc->parser_base, error);
+ s->_segMan->strcpy(voc->parser_base, error);
debugC(2, kDebugLevelParser, "Word unknown: %s", error);
/* Issue warning: */
- invoke_selector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, s->_voc->parser_base, stringpos);
+ invokeSelector(INV_SEL(s, s->_gameObj, wordFail, kStopOnInvalidSelector), 2, voc->parser_base, stringpos);
free(error);
return make_reg(0, 1); /* Tell them that it didn't work */
}
@@ -156,28 +157,29 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
Node *node;
int script;
int numSynonyms = 0;
+ Vocabulary *voc = g_sci->getVocabulary();
// Only SCI0-SCI1 EGA games had a parser. In newer versions, this is a stub
if (getSciVersion() > SCI_VERSION_1_EGA)
return s->r_acc;
- s->_voc->clearSynonyms();
+ voc->clearSynonyms();
- list = s->_segMan->lookupList(GET_SEL32(segMan, object, SELECTOR(elements)));
+ list = s->_segMan->lookupList(readSelector(segMan, object, SELECTOR(elements)));
node = s->_segMan->lookupNode(list->first);
while (node) {
reg_t objpos = node->value;
int seg;
- script = GET_SEL32V(segMan, objpos, SELECTOR(number));
+ script = readSelectorValue(segMan, objpos, SELECTOR(number));
seg = s->_segMan->getScriptSegment(script);
if (seg > 0)
numSynonyms = s->_segMan->getScript(seg)->getSynonymsNr();
if (numSynonyms) {
- byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
+ const byte *synonyms = s->_segMan->getScript(seg)->getSynonyms();
if (synonyms) {
debugC(2, kDebugLevelParser, "Setting %d synonyms for script.%d",
@@ -193,7 +195,7 @@ reg_t kSetSynonyms(EngineState *s, int argc, reg_t *argv) {
synonym_t tmp;
tmp.replaceant = (int16)READ_LE_UINT16(synonyms + i * 4);
tmp.replacement = (int16)READ_LE_UINT16(synonyms + i * 4 + 2);
- s->_voc->addSynonym(tmp);
+ voc->addSynonym(tmp);
}
} else
warning("Synonyms of script.%03d were requested, but script is not available", script);
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 25d967c247..857ccc2a08 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -337,15 +337,15 @@ static void draw_point(EngineState *s, Common::Point p, int start, int width, in
static void draw_polygon(EngineState *s, reg_t polygon, int width, int height) {
SegManager *segMan = s->_segMan;
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
- int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
+ int type = readSelectorValue(segMan, polygon, SELECTOR(type));
Common::Point first, prev;
int i;
@@ -386,15 +386,15 @@ static void draw_input(EngineState *s, reg_t poly_list, Common::Point start, Com
}
static void print_polygon(SegManager *segMan, reg_t polygon) {
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
#ifdef ENABLE_SCI32
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
- int type = GET_SEL32V(segMan, polygon, SELECTOR(type));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
+ int type = readSelectorValue(segMan, polygon, SELECTOR(type));
int i;
Common::Point point;
@@ -1036,13 +1036,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
// Returns : (Polygon *) The converted polygon, or NULL on error
SegManager *segMan = s->_segMan;
int i;
- reg_t points = GET_SEL32(segMan, polygon, SELECTOR(points));
- int size = GET_SEL32V(segMan, polygon, SELECTOR(size));
+ reg_t points = readSelector(segMan, polygon, SELECTOR(points));
+ int size = readSelectorValue(segMan, polygon, SELECTOR(size));
#ifdef ENABLE_SCI32
// SCI32 stores the actual points in the data property of points (in a new array)
if (segMan->isHeapObject(points))
- points = GET_SEL32(segMan, points, SELECTOR(data));
+ points = readSelector(segMan, points, SELECTOR(data));
#endif
if (size == 0) {
@@ -1050,13 +1050,13 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
return NULL;
}
- Polygon *poly = new Polygon(GET_SEL32V(segMan, polygon, SELECTOR(type)));
+ Polygon *poly = new Polygon(readSelectorValue(segMan, polygon, SELECTOR(type)));
int skip = 0;
// WORKAROUND: broken polygon in lsl1sci, room 350, after opening elevator
// Polygon has 17 points but size is set to 19
- if ((size == 19) && (s->_gameId == "lsl1sci")) {
+ if ((size == 19) && !strcmp(g_sci->getGameID(), "lsl1sci")) {
if ((s->currentRoomNumber() == 350)
&& (read_point(segMan, points, 18) == Common::Point(108, 137))) {
debug(1, "Applying fix for broken polygon in lsl1sci, room 350");
@@ -1121,7 +1121,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
if (polygon) {
pf_s->polygons.push_back(polygon);
- count += GET_SEL32V(segMan, node->value, SELECTOR(size));
+ count += readSelectorValue(segMan, node->value, SELECTOR(size));
}
node = s->_segMan->lookupNode(node->succ);
@@ -1174,7 +1174,7 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
// WORKAROUND LSL5 room 660. Priority glitch due to us choosing a different path
// than SSCI. Happens when Patti walks to the control room.
- if ((s->_gameId == "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
+ if (!strcmp(g_sci->getGameID(), "lsl5") && (s->currentRoomNumber() == 660) && (Common::Point(67, 131) == *new_start) && (Common::Point(229, 101) == *new_end)) {
debug(1, "[avoidpath] Applying fix for priority problem in LSL5, room 660");
pf_s->_prependPoint = new_start;
new_start = new Common::Point(77, 107);
@@ -1394,7 +1394,7 @@ reg_t kAvoidPath(EngineState *s, int argc, reg_t *argv) {
if (argc < 7)
error("[avoidpath] Not enough arguments");
- poly_list = (!argv[4].isNull() ? GET_SEL32(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
+ poly_list = (!argv[4].isNull() ? readSelector(s->_segMan, argv[4], SELECTOR(elements)) : NULL_REG);
width = argv[5].toUint16();
height = argv[6].toUint16();
if (argc > 7)
@@ -1694,4 +1694,38 @@ reg_t kIntersections(EngineState *s, int argc, reg_t *argv) {
}
}
+// This is a quite rare kernel function. An example of when it's called
+// is in QFG1VGA, after killing any monster.
+reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) {
+ // 3 parameters: raw polygon data, polygon list, list size
+ reg_t polygonData = argv[0];
+
+ // TODO: actually merge the polygon
+ // In QFG1VGA, there are no immediately visible side-effects
+ // of this being a stub.
+
+#if 0
+ List *list = s->_segMan->lookupList(argv[1]);
+ Node *node = s->_segMan->lookupNode(list->first);
+ // List size is not needed
+
+ Polygon *polygon;
+ int count = 0;
+
+ while (node) {
+ polygon = convert_polygon(s, node->value);
+
+ if (polygon) {
+ count += readSelectorValue(s->_segMan, node->value, SELECTOR(size));
+ }
+
+ node = s->_segMan->lookupNode(node->succ);
+ }
+#endif
+
+ warning("Stub: kMergePoly");
+
+ return polygonData;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index ba29f64966..722d0175d1 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -111,7 +111,7 @@ reg_t kResCheck(EngineState *s, int argc, reg_t *argv) {
reg_t kClone(EngineState *s, int argc, reg_t *argv) {
reg_t parent_addr = argv[0];
- Object *parent_obj = s->_segMan->getObject(parent_addr);
+ const Object *parent_obj = s->_segMan->getObject(parent_addr);
reg_t clone_addr;
Clone *clone_obj; // same as Object*
@@ -132,7 +132,7 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) {
*clone_obj = *parent_obj;
// Mark as clone
- clone_obj->setInfoSelector(make_reg(0, SCRIPT_INFO_CLONE));
+ clone_obj->markAsClone();
clone_obj->setSpeciesSelector(clone_obj->getPos());
if (parent_obj->isClass())
clone_obj->setSuperClassSelector(parent_obj->getPos());
@@ -154,14 +154,14 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- if (victim_obj->getInfoSelector().offset != SCRIPT_INFO_CLONE) {
+ if (!victim_obj->isClone()) {
//warning("Attempt to dispose something other than a clone at %04x", offset);
// SCI silently ignores this behaviour; some games actually depend on it
return s->r_acc;
}
// QFG3 clears clones with underbits set
- //if (GET_SEL32V(victim_addr, underBits))
+ //if (readSelectorValue(victim_addr, underBits))
// warning("Clone %04x:%04x was cleared with underBits set", PRINT_REG(victim_addr));
#if 0
@@ -181,7 +181,7 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
// Returns script dispatch address index in the supplied script
reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
int script = argv[0].toUint16();
- int index = (argc > 1) ? argv[1].toUint16() : 0;
+ uint16 index = (argc > 1) ? argv[1].toUint16() : 0;
if (argv[0].segment)
return argv[0];
@@ -193,18 +193,30 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
Script *scr = s->_segMan->getScript(scriptSeg);
- if (!scr->_numExports) {
- // FIXME: Is this fatal? This occurs in SQ4CD
- warning("Script 0x%x does not have a dispatch table", script);
+ if (!scr->getExportsNr()) {
+ // This is normal. Some scripts don't have a dispatch (exports) table,
+ // and this call is probably used to load them in memory, ignoring
+ // the return value. If only one argument is passed, this call is done
+ // only to load the script in memory. Thus, don't show any warning,
+ // as no return value is expected
+ if (argc == 2)
+ warning("Script 0x%x does not have a dispatch table and export %d "
+ "was requested from it", script, index);
return NULL_REG;
}
- if (index > scr->_numExports) {
- error("Dispatch index too big: %d > %d", index, scr->_numExports);
+ if (index > scr->getExportsNr()) {
+ error("Dispatch index too big: %d > %d", index, scr->getExportsNr());
return NULL_REG;
}
- return make_reg(scriptSeg, scr->validateExportFunc(index));
+ uint16 address = scr->validateExportFunc(index);
+
+ // Point to the heap for SCI1.1+ games
+ if (getSciVersion() >= SCI_VERSION_1_1)
+ address += scr->getScriptSize();
+
+ return make_reg(scriptSeg, address);
}
reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
@@ -244,7 +256,7 @@ reg_t kRespondsTo(EngineState *s, int argc, reg_t *argv) {
reg_t obj = argv[0];
int selector = argv[1].toUint16();
- return make_reg(0, s->_segMan->isHeapObject(obj) && lookup_selector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
+ return make_reg(0, s->_segMan->isHeapObject(obj) && lookupSelector(s->_segMan, obj, selector, NULL, NULL) != kSelectorNone);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 426c682e11..2681b612e9 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -138,10 +138,36 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
while (isspace((unsigned char)*source))
source++; /* Skip whitespace */
- if (*source == '$') /* SCI uses this for hex numbers */
- return make_reg(0, (int16)strtol(source + 1, NULL, 16)); /* Hex */
- else
- return make_reg(0, (int16)strtol(source, NULL, 10)); /* Force decimal */
+ int16 result = 0;
+
+ if (*source == '$') {
+ // hexadecimal input
+ result = (int16)strtol(source + 1, NULL, 16);
+ } else {
+ // decimal input, we can not use strtol/atoi in here, because sierra used atoi BUT it was a non standard compliant
+ // atoi, that didnt do clipping. In SQ4 we get the door code in here and that's even larger than uint32!
+ if (*source == '-') {
+ result = -1;
+ source++;
+ }
+ while (*source) {
+ if ((*source < '0') || (*source > '9')) {
+ // Sierras atoi stopped processing at anything different than number
+ // Sometimes the input has a trailing space, that's fine (example: lsl3)
+ if (*source != ' ') {
+ // TODO: this happens in lsl5 right in the intro -> we get '1' '3' 0xCD 0xCD 0xCD 0xCD 0xCD
+ // find out why this happens and fix it
+ warning("Invalid character in kReadNumber input");
+ }
+ break;
+ }
+ result *= 10;
+ result += *source - 0x30;
+ source++;
+ }
+ }
+
+ return make_reg(0, result);
}
@@ -241,7 +267,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) {
#ifdef ENABLE_SCI32
// If the string is a string object, get to the actual string in the data selector
if (s->_segMan->isObject(reg))
- reg = GET_SEL32(s->_segMan, reg, SELECTOR(data));
+ reg = readSelector(s->_segMan, reg, SELECTOR(data));
#endif
Common::String tempsource = (reg == NULL_REG) ? "" : g_sci->getKernel()->lookupText(reg,
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index fef2b9a19e..9bf23dedf5 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -383,7 +383,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
sync_SegManagerPtr(s, _segMan);
- syncArray<Class>(s, _segMan->_classtable);
+ syncArray<Class>(s, _segMan->_classTable);
#ifdef USE_OLD_MUSIC_FUNCTIONS
sync_songlib(s, _sound._songlib);
@@ -541,8 +541,8 @@ void Script::saveLoadWithSerializer(Common::Serializer &s) {
}
}
- s.syncAsSint32LE(_numExports);
- s.syncAsSint32LE(_numSynonyms);
+ s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numExports
+ s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numSynonyms
s.syncAsSint32LE(_lockers);
// Sync _objects. This is a hashmap, and we use the following on disk format:
@@ -615,7 +615,7 @@ void DynMem::saveLoadWithSerializer(Common::Serializer &s) {
void DataStack::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint32LE(_capacity);
if (s.isLoading()) {
- //free(entries);
+ free(_entries);
_entries = (reg_t *)calloc(_capacity, sizeof(reg_t));
}
}
@@ -731,15 +731,6 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 1;
}
-/*
- if (s->sound_server) {
- if ((s->sound_server->save)(s, dirname)) {
- warning("Saving failed for the sound subsystem");
- //chdir("..");
- return 1;
- }
- }
-*/
Common::Serializer ser(0, fh);
sync_SavegameMetadata(ser, meta);
Graphics::saveThumbnail(*fh);
@@ -748,26 +739,6 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
return 0;
}
-static byte *find_unique_script_block(EngineState *s, byte *buf, int type) {
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-
- if (oldScriptHeader)
- buf += 2;
-
- do {
- int seeker_type = READ_LE_UINT16(buf);
-
- if (seeker_type == 0) break;
- if (seeker_type == type) return buf;
-
- int seeker_size = READ_LE_UINT16(buf + 2);
- assert(seeker_size > 0);
- buf += seeker_size;
- } while (1);
-
- return NULL;
-}
-
// TODO: This should probably be turned into an EngineState or DataStack method.
static void reconstruct_stack(EngineState *retval) {
SegmentId stack_seg = retval->_segMan->findSegmentByType(SEG_TYPE_STACK);
@@ -777,99 +748,37 @@ static void reconstruct_stack(EngineState *retval) {
retval->stack_top = stack->_entries + stack->_capacity;
}
-static void load_script(EngineState *s, Script *scr) {
- scr->_buf = (byte *)malloc(scr->_bufSize);
- assert(scr->_buf);
-
- Resource *script = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, scr->_nr), 0);
- assert(script != 0);
-
- assert(scr->_bufSize >= script->size);
- memcpy(scr->_buf, script->data, script->size);
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- Resource *heap = g_sci->getResMan()->findResource(ResourceId(kResourceTypeHeap, scr->_nr), 0);
- assert(heap != 0);
-
- scr->_heapStart = scr->_buf + scr->_scriptSize;
-
- assert(scr->_bufSize - scr->_scriptSize <= heap->size);
- memcpy(scr->_heapStart, heap->data, heap->size);
- }
-}
-
// TODO: Move thie function to a more appropriate place, such as vm.cpp or script.cpp
void SegManager::reconstructScripts(EngineState *s) {
uint i;
- SegmentObj *mobj;
for (i = 0; i < _heap.size(); i++) {
- mobj = _heap[i];
- if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
+ if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)mobj;
-
- // FIXME: Unify this code with script_instantiate_* ?
- load_script(s, scr);
+ Script *scr = (Script *)_heap[i];
+ scr->load(g_sci->getResMan());
scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
- if (getSciVersion() >= SCI_VERSION_1_1) {
- scr->_exportTable = 0;
- scr->_synonyms = 0;
- if (READ_LE_UINT16(scr->_buf + 6) > 0) {
- scr->setExportTableOffset(6);
- s->_segMan->scriptRelocateExportsSci11(i);
- }
- } else {
- scr->_exportTable = (uint16 *) find_unique_script_block(s, scr->_buf, SCI_OBJ_EXPORTS);
- scr->_synonyms = find_unique_script_block(s, scr->_buf, SCI_OBJ_SYNONYMS);
- scr->_exportTable += 3;
- }
- scr->_codeBlocks.clear();
- ObjMap::iterator it;
- const ObjMap::iterator end = scr->_objects.end();
- for (it = scr->_objects.begin(); it != end; ++it) {
- byte *data = scr->_buf + it->_value.getPos().offset;
- it->_value._baseObj = data;
- }
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
+ it->_value._baseObj = scr->_buf + it->_value.getPos().offset;
}
for (i = 0; i < _heap.size(); i++) {
- mobj = _heap[i];
- if (!mobj || mobj->getType() != SEG_TYPE_SCRIPT)
+ if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
continue;
- Script *scr = (Script *)mobj;
+ Script *scr = (Script *)_heap[i];
- // FIXME: Unify this code with Script::scriptObjInit ?
- ObjMap::iterator it;
- const ObjMap::iterator end = scr->_objects.end();
- for (it = scr->_objects.begin(); it != end; ++it) {
- byte *data = scr->_buf + it->_value.getPos().offset;
-
- if (getSciVersion() >= SCI_VERSION_1_1) {
- uint16 *funct_area = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 6 ));
- uint16 *prop_area = (uint16 *)(scr->_buf + READ_LE_UINT16( data + 4 ));
-
- it->_value._baseMethod = funct_area;
- it->_value._baseVars = prop_area;
- } else {
- int funct_area = READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET);
- Object *_baseObj;
-
- _baseObj = s->_segMan->getObject(it->_value.getSpeciesSelector());
-
- if (!_baseObj) {
- warning("Object without a base class: Script %d, index %d (reg address %04x:%04x",
- scr->_nr, i, PRINT_REG(it->_value.getSpeciesSelector()));
- continue;
- }
- it->_value.setVarCount(_baseObj->getVarCount());
- it->_value._baseObj = _baseObj->_baseObj;
+ for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
+ reg_t addr = it->_value.getPos();
+ Object *obj = scr->scriptObjInit(addr, false);
- it->_value._baseMethod = (uint16 *)(data + funct_area);
- it->_value._baseVars = (uint16 *)(data + it->_value.getVarCount() * 2 + SCRIPT_SELECTOR_OFFSET);
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ if (!obj->initBaseObject(this, addr, false)) {
+ warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
+ scr->scriptObjRemove(addr);
+ }
}
}
}
@@ -912,7 +821,6 @@ static void reconstruct_sounds(EngineState *s) {
#endif
void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
- EngineState *retval;
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongLibrary temp;
#endif
@@ -947,86 +855,68 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
thumbnail = 0;
}
- // Create a new EngineState object
- retval = new EngineState(s->_voc, s->_segMan);
- retval->_event = s->_event;
-
- // Copy some old data
- retval->_soundCmd = s->_soundCmd;
-
- // Copy memory segment
- retval->_memorySegmentSize = s->_memorySegmentSize;
- memcpy(retval->_memorySegment, s->_memorySegment, s->_memorySegmentSize);
-
- retval->saveLoadWithSerializer(ser); // FIXME: Error handling?
+ s->reset(true);
+ s->saveLoadWithSerializer(ser); // FIXME: Error handling?
#ifdef USE_OLD_MUSIC_FUNCTIONS
s->_sound.sfx_exit();
#endif
// Set exec stack base to zero
- retval->execution_stack_base = 0;
+ s->execution_stack_base = 0;
// Now copy all current state information
#ifdef USE_OLD_MUSIC_FUNCTIONS
- temp = retval->_sound._songlib;
- retval->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
- retval->sfx_init_flags = s->sfx_init_flags;
- retval->_sound._songlib.freeSounds();
- retval->_sound._songlib = temp;
- retval->_soundCmd->updateSfxState(&retval->_sound);
+ temp = s->_sound._songlib;
+ s->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
+ s->sfx_init_flags = s->sfx_init_flags;
+ s->_sound._songlib.freeSounds();
+ s->_sound._songlib = temp;
+ s->_soundCmd->updateSfxState(&retval->_sound);
#endif
- reconstruct_stack(retval);
- retval->_segMan->reconstructScripts(retval);
- retval->_segMan->reconstructClones();
- retval->_gameObj = s->_gameObj;
- retval->script_000 = retval->_segMan->getScript(retval->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
- retval->gc_countdown = GC_INTERVAL - 1;
- retval->sys_strings_segment = retval->_segMan->findSegmentByType(SEG_TYPE_SYS_STRINGS);
- retval->sys_strings = (SystemStrings *)(retval->_segMan->_heap[retval->sys_strings_segment]);
+ reconstruct_stack(s);
+ s->_segMan->reconstructScripts(s);
+ s->_segMan->reconstructClones();
+ s->_gameObj = s->_gameObj;
+ s->script_000 = s->_segMan->getScript(s->_segMan->getScriptSegment(0, SCRIPT_GET_DONT_LOAD));
+ s->gc_countdown = GC_INTERVAL - 1;
// Time state:
- retval->last_wait_time = g_system->getMillis();
- retval->game_start_time = g_system->getMillis();
-
- // static parser information:
-
- if (retval->_voc)
- retval->_voc->parser_base = make_reg(s->sys_strings_segment, SYS_STRING_PARSER_BASE);
+ s->last_wait_time = g_system->getMillis();
+ s->game_start_time = g_system->getMillis();
- retval->successor = NULL;
- retval->_gameId = s->_gameId;
+ s->restoring = false;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- retval->_sound._it = NULL;
- retval->_sound._flags = s->_sound._flags;
- retval->_sound._song = NULL;
- retval->_sound._suspended = s->_sound._suspended;
- reconstruct_sounds(retval);
+ s->_sound._it = NULL;
+ s->_sound._flags = s->_sound._flags;
+ s->_sound._song = NULL;
+ s->_sound._suspended = s->_sound._suspended;
+ reconstruct_sounds(s);
#else
- retval->_soundCmd->reconstructPlayList(meta.savegame_version);
+ s->_soundCmd->reconstructPlayList(meta.savegame_version);
#endif
// Message state:
- retval->_msgState = new MessageState(retval->_segMan);
+ s->_msgState = new MessageState(s->_segMan);
#ifdef ENABLE_SCI32
if (g_sci->_gui32) {
g_sci->_gui32->init();
} else {
#endif
- g_sci->_gui->resetEngineState(retval);
+ g_sci->_gui->resetEngineState(s);
g_sci->_gui->init(g_sci->_features->usesOldGfxFunctions());
#ifdef ENABLE_SCI32
}
#endif
- s->successor = retval; // Set successor
- script_abort_flag = 2; // Abort current game with replay
- shrink_execution_stack(s, s->execution_stack_base + 1);
+ s->restoring = true;
+ s->script_abort_flag = 2; // Abort current game with replay
+ s->shrinkStackToBase();
}
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index bad79fca27..7be05381da 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -36,7 +36,7 @@ namespace Sci {
struct EngineState;
enum {
- CURRENT_SAVEGAME_VERSION = 19,
+ CURRENT_SAVEGAME_VERSION = 20,
MINIMUM_SAVEGAME_VERSION = 9
};
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index e9b1ce3f28..1f32e50b67 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -123,13 +123,13 @@ void SegManager::createClassTable() {
error("SegManager: failed to open vocab 996");
int totalClasses = vocab996->size >> 2;
- _classtable.resize(totalClasses);
+ _classTable.resize(totalClasses);
for (uint16 classNr = 0; classNr < totalClasses; classNr++) {
uint16 scriptNr = READ_SCI11ENDIAN_UINT16(vocab996->data + classNr * 4 + 2);
- _classtable[classNr].reg = NULL_REG;
- _classtable[classNr].script = scriptNr;
+ _classTable[classNr].reg = NULL_REG;
+ _classTable[classNr].script = scriptNr;
}
_resMan->unlockResource(vocab996);
@@ -139,11 +139,11 @@ reg_t SegManager::getClassAddress(int classnr, ScriptLoadType lock, reg_t caller
if (classnr == 0xffff)
return NULL_REG;
- if (classnr < 0 || (int)_classtable.size() <= classnr || _classtable[classnr].script < 0) {
- error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classtable.size());
+ if (classnr < 0 || (int)_classTable.size() <= classnr || _classTable[classnr].script < 0) {
+ error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classTable.size());
return NULL_REG;
} else {
- Class *the_class = &_classtable[classnr];
+ Class *the_class = &_classTable[classnr];
if (!the_class->reg.segment) {
getScriptSegment(the_class->script, lock);
@@ -175,7 +175,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
Script *scr = getScript(location.segment);
unsigned int count;
- VERIFY(location.offset + 1 < (uint16)scr->_bufSize, "Locals beyond end of script\n");
+ VERIFY(location.offset + 1 < (uint16)scr->getBufSize(), "Locals beyond end of script\n");
if (getSciVersion() >= SCI_VERSION_1_1)
count = READ_SCI11ENDIAN_UINT16(scr->_buf + location.offset - 2);
@@ -185,55 +185,38 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
scr->_localsOffset = location.offset;
- if (!(location.offset + count * 2 + 1 < scr->_bufSize)) {
- warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->_bufSize);
- count = (scr->_bufSize - location.offset) >> 1;
+ if (!(location.offset + count * 2 + 1 < scr->getBufSize())) {
+ warning("Locals extend beyond end of script: offset %04x, count %x vs size %x", location.offset, count, (uint)scr->getBufSize());
+ count = (scr->getBufSize() - location.offset) >> 1;
}
LocalVariables *locals = allocLocalsSegment(scr, count);
if (locals) {
uint i;
- byte *base = (byte *)(scr->_buf + location.offset);
+ const byte *base = (const byte *)(scr->_buf + location.offset);
for (i = 0; i < count; i++)
locals->_locals[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(base + i * 2));
}
}
-void SegManager::scriptRelocateExportsSci11(SegmentId seg) {
- Script *scr = getScript(seg);
- for (int i = 0; i < scr->_numExports; i++) {
- /* We are forced to use an ugly heuristic here to distinguish function
- exports from object/class exports. The former kind points into the
- script resource, the latter into the heap resource. */
- uint16 location = READ_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i));
-
- if ((location < scr->_heapSize - 1) && (READ_SCI11ENDIAN_UINT16(scr->_heapStart + location) == SCRIPT_OBJECT_MAGIC_NUMBER)) {
- WRITE_SCI11ENDIAN_UINT16((byte *)(scr->_exportTable + i), location + scr->_heapStart - scr->_buf);
- } else {
- // Otherwise it's probably a function export,
- // and we don't need to do anything.
- }
- }
-}
-
void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
Script *scr = getScript(seg);
- byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
+ const byte *seeker = scr->_heapStart + 4 + READ_SCI11ENDIAN_UINT16(scr->_heapStart + 2) * 2;
while (READ_SCI11ENDIAN_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- if (READ_SCI11ENDIAN_UINT16(seeker + 14) & SCRIPT_INFO_CLASS) {
+ if (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass) { // -info- selector
int classpos = seeker - scr->_buf;
int species = READ_SCI11ENDIAN_UINT16(seeker + 10);
- if (species < 0 || species >= (int)_classtable.size()) {
+ if (species < 0 || species >= (int)_classTable.size()) {
error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d",
- species, species, _classtable.size(), scr->_nr);
+ species, species, _classTable.size(), scr->_nr);
return;
}
- _classtable[species].reg.segment = seg;
- _classtable[species].reg.offset = classpos;
+ _classTable[species].reg.segment = seg;
+ _classTable[species].reg.offset = classpos;
}
seeker += READ_SCI11ENDIAN_UINT16(seeker + 2) * 2;
}
@@ -243,19 +226,20 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
reg_t reg = make_reg(seg, seeker - scr->_buf);
Object *obj = scr->scriptObjInit(reg);
-#if 0
- if (obj->_variables[5].offset != 0xffff) {
- obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset);
- baseObj = getObject(obj->_variables[5]);
- obj->variable_names_nr = baseObj->variables_nr;
- obj->_baseObj = baseObj->_baseObj;
- }
-#endif
-
// Copy base from species class, as we need its selector IDs
obj->setSuperClassSelector(
getClassAddress(obj->getSuperClassSelector().offset, SCRIPT_GET_LOCK, NULL_REG));
+ // If object is instance, get -propDict- from class and set it for this object
+ // This is needed for ::isMemberOf() to work.
+ // Example testcase - room 381 of sq4cd - if isMemberOf() doesn't work, talk-clicks on the robot will act like
+ // clicking on ego
+ if (!obj->isClass()) {
+ reg_t classObject = obj->getSuperClassSelector();
+ Object *classObj = getObject(classObject);
+ obj->setPropDictSelector(classObj->getPropDictSelector());
+ }
+
// Set the -classScript- selector to the script number.
// FIXME: As this selector is filled in at run-time, it is likely
// that it is supposed to hold a pointer. The Obj::isKindOf method
@@ -268,86 +252,24 @@ void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
}
}
-
-
-int script_instantiate_common(ResourceManager *resMan, SegManager *segMan, int script_nr, Resource **script, Resource **heap, int *was_new) {
- *was_new = 1;
-
- *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- if (getSciVersion() >= SCI_VERSION_1_1)
- *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
-
- if (!*script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
- warning("Script 0x%x requested but not found", script_nr);
- if (getSciVersion() >= SCI_VERSION_1_1) {
- if (*heap)
- warning("Inconsistency: heap resource WAS found");
- else if (*script)
- warning("Inconsistency: script resource WAS found");
- }
- return 0;
- }
-
- SegmentId seg_id = segMan->getScriptSegment(script_nr);
- Script *scr = segMan->getScriptIfLoaded(seg_id);
- if (scr) {
- if (!scr->isMarkedAsDeleted()) {
- scr->incrementLockers();
- return seg_id;
- } else {
- scr->freeScript();
- }
- } else {
- scr = segMan->allocateScript(script_nr, &seg_id);
- if (!scr) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
- error("Not enough heap space for script size 0x%x of script 0x%x (Should this happen?)", (*script)->size, script_nr);
- return 0;
- }
- }
-
- scr->init(script_nr, resMan);
-
- // Set heap position (beyond the size word)
- scr->setLockers(1);
- scr->setExportTableOffset(0);
- scr->setSynonymsOffset(0);
- scr->setSynonymsNr(0);
-
- *was_new = 0;
-
- return seg_id;
-}
-
-#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segMan->getClassAddress(id, SCRIPT_GET_LOCK, addr))
-
-int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int script_nr) {
+void script_instantiate_sci0(Script *scr, int segmentId, SegManager *segMan) {
int objType;
uint32 objLength = 0;
- int relocation = -1;
- Resource *script;
- int was_new;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
- const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, NULL, &was_new);
uint16 curOffset = oldScriptHeader ? 2 : 0;
- if (was_new)
- return seg_id;
-
- Script *scr = segMan->getScript(seg_id);
- scr->mcpyInOut(0, script->data, script->size);
-
if (oldScriptHeader) {
// Old script block
// There won't be a localvar block in this case
// Instead, the script starts with a 16 bit int specifying the
// number of locals we need; these are then allocated and zeroed.
- int locals_nr = READ_LE_UINT16(script->data);
- if (locals_nr)
- segMan->scriptInitialiseLocalsZero(seg_id, locals_nr);
+ int localsCount = READ_LE_UINT16(scr->_buf);
+ if (localsCount)
+ segMan->scriptInitialiseLocalsZero(segmentId, localsCount);
}
// Now do a first pass through the script objects to find the
- // export table and local variable block
+ // local variable blocks
do {
objType = scr->getHeap(curOffset);
@@ -355,48 +277,30 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
break;
objLength = scr->getHeap(curOffset + 2);
-
- // This happens in some demos (e.g. the EcoQuest 1 demo). Not sure what is the
- // actual cause of it, but the scripts of these demos can't be loaded properly
- // and we're stuck forever in this loop, as objLength never changes
- if (!objLength) {
- warning("script_instantiate_sci0: objLength is 0, unable to parse script");
- return 0;
- }
-
curOffset += 4; // skip header
switch (objType) {
- case SCI_OBJ_EXPORTS:
- scr->setExportTableOffset(curOffset);
- break;
- case SCI_OBJ_SYNONYMS:
- scr->setSynonymsOffset(curOffset);
- scr->setSynonymsNr((objLength) / 4);
- break;
case SCI_OBJ_LOCALVARS:
- segMan->scriptInitialiseLocals(make_reg(seg_id, curOffset));
+ segMan->scriptInitialiseLocals(make_reg(segmentId, curOffset));
break;
-
case SCI_OBJ_CLASS: {
int classpos = curOffset - SCRIPT_OBJECT_MAGIC_OFFSET;
int species = scr->getHeap(curOffset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET);
- if (species < 0 || species >= (int)segMan->_classtable.size()) {
- if (species == (int)segMan->_classtable.size()) {
+ if (species < 0 || species >= (int)segMan->classTableSize()) {
+ if (species == (int)segMan->classTableSize()) {
// Happens in the LSL2 demo
warning("Applying workaround for an off-by-one invalid species access");
- segMan->_classtable.resize(segMan->_classtable.size() + 1);
+ segMan->resizeClassTable(segMan->classTableSize() + 1);
} else {
- warning("Invalid species %d(0x%x) not in interval "
- "[0,%d) while instantiating script %d\n",
- species, species, segMan->_classtable.size(),
- script_nr);
- return 0;
+ error("Invalid species %d(0x%x) not in interval "
+ "[0,%d) while instantiating script at segment %d\n",
+ species, species, segMan->classTableSize(),
+ segmentId);
+ return;
}
}
- segMan->_classtable[species].reg.segment = seg_id;
- segMan->_classtable[species].reg.offset = classpos;
+ segMan->setClassOffset(species, make_reg(segmentId, classpos));
// Set technical class position-- into the block allocated for it
}
break;
@@ -406,7 +310,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < script->size - 2);
+ } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
// And now a second pass to adjust objects and class pointers, and the general pointers
objLength = 0;
@@ -420,7 +324,7 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
objLength = scr->getHeap(curOffset + 2);
curOffset += 4; // skip header
- reg_t addr = make_reg(seg_id, curOffset);
+ reg_t addr = make_reg(segmentId, curOffset);
switch (objType) {
case SCI_OBJ_CODE:
@@ -429,77 +333,52 @@ int script_instantiate_sci0(ResourceManager *resMan, SegManager *segMan, int scr
case SCI_OBJ_OBJECT:
case SCI_OBJ_CLASS: { // object or class?
Object *obj = scr->scriptObjInit(addr);
+ obj->initSpecies(segMan, addr);
- // Instantiate the superclass, if neccessary
- obj->setSpeciesSelector(INST_LOOKUP_CLASS(obj->getSpeciesSelector().offset));
-
- Object *baseObj = segMan->getObject(obj->getSpeciesSelector());
-
- if (baseObj) {
- obj->setVarCount(baseObj->getVarCount());
- // Copy base from species class, as we need its selector IDs
- obj->_baseObj = baseObj->_baseObj;
-
- obj->setSuperClassSelector(INST_LOOKUP_CLASS(obj->getSuperClassSelector().offset));
- } else {
+ if (!obj->initBaseObject(segMan, addr)) {
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
-
scr->scriptObjRemove(addr);
}
} // if object or class
break;
- case SCI_OBJ_POINTERS: // A relocation table
- relocation = addr.offset;
- break;
-
default:
break;
}
curOffset += objLength - 4;
- } while (objType != 0 && curOffset < script->size - 2);
-
- if (relocation >= 0)
- scr->scriptRelocate(make_reg(seg_id, relocation));
-
- return seg_id; // instantiation successful
+ } while (objType != 0 && curOffset < scr->getScriptSize() - 2);
}
-int script_instantiate_sci11(ResourceManager *resMan, SegManager *segMan, int script_nr) {
- Resource *script, *heap;
- int was_new;
- const int seg_id = script_instantiate_common(resMan, segMan, script_nr, &script, &heap, &was_new);
-
- if (was_new)
- return seg_id;
-
- Script *scr = segMan->getScript(seg_id);
- int _heapStart = script->size;
-
- if (script->size & 2)
- _heapStart++;
-
- scr->mcpyInOut(0, script->data, script->size);
- scr->mcpyInOut(_heapStart, heap->data, heap->size);
-
- if (READ_SCI11ENDIAN_UINT16(script->data + 6) > 0)
- scr->setExportTableOffset(6);
-
- segMan->scriptInitialiseLocals(make_reg(seg_id, _heapStart + 4));
-
- segMan->scriptRelocateExportsSci11(seg_id);
- segMan->scriptInitialiseObjectsSci11(seg_id);
+int script_instantiate(ResourceManager *resMan, SegManager *segMan, int scriptNum) {
+ SegmentId segmentId = segMan->getScriptSegment(scriptNum);
+ Script *scr = segMan->getScriptIfLoaded(segmentId);
+ if (scr) {
+ if (!scr->isMarkedAsDeleted()) {
+ scr->incrementLockers();
+ return segmentId;
+ } else {
+ scr->freeScript();
+ }
+ } else {
+ scr = segMan->allocateScript(scriptNum, &segmentId);
+ }
- scr->heapRelocate(make_reg(seg_id, READ_SCI11ENDIAN_UINT16(heap->data)));
+ scr->init(scriptNum, resMan);
+ scr->load(resMan);
- return seg_id;
-}
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ int heapStart = scr->getScriptSize();
+ segMan->scriptInitialiseLocals(make_reg(segmentId, heapStart + 4));
+ segMan->scriptInitialiseObjectsSci11(segmentId);
+ scr->relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(scr->_heapStart)));
+ } else {
+ script_instantiate_sci0(scr, segmentId, segMan);
+ byte *relocationBlock = scr->findBlock(SCI_OBJ_POINTERS);
+ if (relocationBlock)
+ scr->relocate(make_reg(segmentId, relocationBlock - scr->_buf + 4));
+ }
-int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_nr) {
- if (getSciVersion() >= SCI_VERSION_1_1)
- return script_instantiate_sci11(resMan, segMan, script_nr);
- else
- return script_instantiate_sci0(resMan, segMan, script_nr);
+ return segmentId;
}
void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg) {
@@ -528,7 +407,7 @@ void script_uninstantiate_sci0(SegManager *segMan, int script_nr, SegmentId seg)
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
if (superclass >= 0) {
- int superclass_script = segMan->_classtable[superclass].script;
+ int superclass_script = segMan->getClass(superclass).script;
if (superclass_script == script_nr) {
if (scr->getLockers())
@@ -562,9 +441,9 @@ void script_uninstantiate(SegManager *segMan, int script_nr) {
return;
// Free all classtable references to this script
- for (uint i = 0; i < segMan->_classtable.size(); i++)
- if (segMan->_classtable[i].reg.segment == segment)
- segMan->_classtable[i].reg = NULL_REG;
+ for (uint i = 0; i < segMan->classTableSize(); i++)
+ if (segMan->getClass(i).reg.segment == segment)
+ segMan->setClassOffset(i, NULL_REG);
if (getSciVersion() < SCI_VERSION_1_1)
script_uninstantiate_sci0(segMan, script_nr, segment);
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 4b60626b2e..159c278e8c 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -67,37 +67,6 @@ extern const char *selector_name(EngineState *s, int selector);
DebugState g_debugState;
-int propertyOffsetToId(SegManager *segMan, int prop_ofs, reg_t objp) {
- Object *obj = segMan->getObject(objp);
- byte *selectoroffset;
- int selectors;
-
- if (!obj) {
- warning("Applied propertyOffsetToId on non-object at %04x:%04x", PRINT_REG(objp));
- return -1;
- }
-
- selectors = obj->getVarCount();
-
- if (getSciVersion() < SCI_VERSION_1_1)
- selectoroffset = ((byte *)(obj->_baseObj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2;
- else {
- if (!(obj->getInfoSelector().offset & SCRIPT_INFO_CLASS)) {
- obj = segMan->getObject(obj->getSuperClassSelector());
- selectoroffset = (byte *)obj->_baseVars;
- } else
- selectoroffset = (byte *)obj->_baseVars;
- }
-
- if (prop_ofs < 0 || (prop_ofs >> 1) >= selectors) {
- warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d]) on object at %04x:%04x",
- prop_ofs, prop_ofs >> 1, selectors - 1, PRINT_REG(objp));
- return -1;
- }
-
- return READ_SCI11ENDIAN_UINT16(selectoroffset + prop_ofs);
-}
-
// Disassembles one command from the heap, returns address of next command or 0 if a ret was encountered.
reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecode) {
SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT);
@@ -116,7 +85,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
script_entity = (Script *)mobj;
scr = script_entity->_buf;
- scr_size = script_entity->_bufSize;
+ scr_size = script_entity->getBufSize();
if (pos.offset >= scr_size) {
warning("Trying to disassemble beyond end of script");
@@ -221,51 +190,52 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
}
}
- if (pos == scriptState.xs->addr.pc) { // Extra information if debugging the current opcode
+ if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
if ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) ||
(opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) {
- int prop_ofs = scr[pos.offset + 1];
- int prop_id = propertyOffsetToId(s->_segMan, prop_ofs, scriptState.xs->objp);
-
- printf(" (%s)", selector_name(s, prop_id));
+ const Object *obj = s->_segMan->getObject(s->xs->objp);
+ if (!obj)
+ warning("Attempted to reference on non-object at %04x:%04x", PRINT_REG(s->xs->objp));
+ else
+ printf(" (%s)", selector_name(s, obj->propertyOffsetToId(s->_segMan, scr[pos.offset + 1])));
}
}
printf("\n");
- if (pos == scriptState.xs->addr.pc) { // Extra information if debugging the current opcode
+ if (pos == s->xs->addr.pc) { // Extra information if debugging the current opcode
if (opcode == op_callk) {
- int stackframe = (scr[pos.offset + 2] >> 1) + (scriptState.restAdjust);
- int argc = ((scriptState.xs->sp)[- stackframe - 1]).offset;
+ int stackframe = (scr[pos.offset + 2] >> 1) + (s->restAdjust);
+ int argc = ((s->xs->sp)[- stackframe - 1]).offset;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (!oldScriptHeader)
- argc += (scriptState.restAdjust);
+ argc += (s->restAdjust);
printf(" Kernel params: (");
for (int j = 0; j < argc; j++) {
- printf("%04x:%04x", PRINT_REG((scriptState.xs->sp)[j - stackframe]));
+ printf("%04x:%04x", PRINT_REG((s->xs->sp)[j - stackframe]));
if (j + 1 < argc)
printf(", ");
}
printf(")\n");
} else if ((opcode == op_send) || (opcode == op_self)) {
- int restmod = scriptState.restAdjust;
+ int restmod = s->restAdjust;
int stackframe = (scr[pos.offset + 1] >> 1) + restmod;
- reg_t *sb = scriptState.xs->sp;
+ reg_t *sb = s->xs->sp;
uint16 selector;
reg_t fun_ref;
while (stackframe > 0) {
int argc = sb[- stackframe + 1].offset;
const char *name = NULL;
- reg_t called_obj_addr = scriptState.xs->objp;
+ reg_t called_obj_addr = s->xs->objp;
if (opcode == op_send)
called_obj_addr = s->r_acc;
else if (opcode == op_self)
- called_obj_addr = scriptState.xs->objp;
+ called_obj_addr = s->xs->objp;
selector = sb[- stackframe].offset;
@@ -276,7 +246,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
printf(" %s::%s[", name, (selector > kernel->getSelectorNamesSize()) ? "<invalid>" : selector_name(s, selector));
- switch (lookup_selector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
+ switch (lookupSelector(s->_segMan, called_obj_addr, selector, 0, &fun_ref)) {
case kSelectorMethod:
printf("FUNCT");
argc += restmod;
@@ -315,10 +285,10 @@ void script_debug(EngineState *s) {
#if 0
if (sci_debug_flags & _DEBUG_FLAG_LOGGING) {
printf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc));
- disassemble(s, scriptState.xs->addr.pc, 0, 1);
- if (scriptState.seeking == kDebugSeekGlobal)
- printf("Global %d (0x%x) = %04x:%04x\n", scriptState.seekSpecial,
- scriptState.seekSpecial, PRINT_REG(s->script_000->_localsBlock->_locals[scriptState.seekSpecial]));
+ disassemble(s, s->xs->addr.pc, 0, 1);
+ if (s->seeking == kDebugSeekGlobal)
+ printf("Global %d (0x%x) = %04x:%04x\n", s->seekSpecial,
+ s->seekSpecial, PRINT_REG(s->script_000->_localsBlock->_locals[s->seekSpecial]));
}
#endif
@@ -328,16 +298,16 @@ void script_debug(EngineState *s) {
#endif
if (g_debugState.seeking && !g_debugState.breakpointWasHit) { // Are we looking for something special?
- SegmentObj *mobj = s->_segMan->getSegment(scriptState.xs->addr.pc.segment, SEG_TYPE_SCRIPT);
+ SegmentObj *mobj = s->_segMan->getSegment(s->xs->addr.pc.segment, SEG_TYPE_SCRIPT);
if (mobj) {
Script *scr = (Script *)mobj;
byte *code_buf = scr->_buf;
- int code_buf_size = scr->_bufSize;
- int opcode = scriptState.xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset];
+ int code_buf_size = scr->getBufSize();
+ int opcode = s->xs->addr.pc.offset >= code_buf_size ? 0 : code_buf[s->xs->addr.pc.offset];
int op = opcode >> 1;
- int paramb1 = scriptState.xs->addr.pc.offset + 1 >= code_buf_size ? 0 : code_buf[scriptState.xs->addr.pc.offset + 1];
- int paramf1 = (opcode & 1) ? paramb1 : (scriptState.xs->addr.pc.offset + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + scriptState.xs->addr.pc.offset + 1));
+ int paramb1 = s->xs->addr.pc.offset + 1 >= code_buf_size ? 0 : code_buf[s->xs->addr.pc.offset + 1];
+ int paramf1 = (opcode & 1) ? paramb1 : (s->xs->addr.pc.offset + 2 >= code_buf_size ? 0 : (int16)READ_SCI11ENDIAN_UINT16(code_buf + s->xs->addr.pc.offset + 1));
switch (g_debugState.seeking) {
case kDebugSeekSpecialCallk:
@@ -381,8 +351,8 @@ void script_debug(EngineState *s) {
}
}
- printf("Step #%d\n", script_step_counter);
- disassemble(s, scriptState.xs->addr.pc, 0, 1);
+ printf("Step #%d\n", s->script_step_counter);
+ disassemble(s, s->xs->addr.pc, 0, 1);
if (g_debugState.runningStep) {
g_debugState.runningStep--;
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index b18d76e1a7..4d3e6f754e 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -54,7 +54,6 @@ SegManager::SegManager(ResourceManager *resMan) {
createClassTable();
}
-// Destroy the object, free the memorys if allocated before
SegManager::~SegManager() {
resetSegMan();
}
@@ -77,10 +76,29 @@ void SegManager::resetSegMan() {
Hunks_seg_id = 0;
// Reinitialize class table
- _classtable.clear();
+ _classTable.clear();
createClassTable();
}
+void SegManager::initSysStrings() {
+ sysStrings = (SystemStrings *)allocSegment(new SystemStrings(), &sysStringsSegment);
+
+ // Allocate static buffer for savegame and CWD directories
+ SystemString *strSaveDir = &sysStrings->_strings[SYS_STRING_SAVEDIR];
+ strSaveDir->_name = "savedir";
+ strSaveDir->_maxSize = MAX_SAVE_DIR_SIZE;
+ strSaveDir->_value = (char *)calloc(MAX_SAVE_DIR_SIZE, sizeof(char));
+ // Set the savegame dir (actually, we set it to a fake value,
+ // since we cannot let the game control where saves are stored)
+ ::strcpy(strSaveDir->_value, "");
+
+ // Allocate static buffer for the parser base
+ SystemString *strParserBase = &sysStrings->_strings[SYS_STRING_PARSER_BASE];
+ strParserBase->_name = "parser-base";
+ strParserBase->_maxSize = MAX_PARSER_BASE;
+ strParserBase->_value = (char *)calloc(MAX_PARSER_BASE, sizeof(char));
+}
+
SegmentId SegManager::findFreeSegment() const {
// FIXME: This is a very crude approach: We find a free segment id by scanning
// from the start. This can be slow if the number of segments becomes large.
@@ -156,7 +174,7 @@ int SegManager::deallocate(SegmentId seg, bool recursive) {
}
bool SegManager::isHeapObject(reg_t pos) {
- Object *obj = getObject(pos);
+ const Object *obj = getObject(pos);
if (obj == NULL || (obj && obj->isFreed()))
return false;
Script *scr = getScriptIfLoaded(pos.segment);
@@ -223,7 +241,7 @@ Object *SegManager::getObject(reg_t pos) {
warning("getObject(): Trying to get an invalid object");
} else if (mobj->getType() == SEG_TYPE_SCRIPT) {
Script *scr = (Script *)mobj;
- if (pos.offset <= scr->_bufSize && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
+ if (pos.offset <= scr->getBufSize() && pos.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
&& RAW_IS_OBJECT(scr->_buf + pos.offset)) {
obj = scr->getObject(pos.offset);
}
@@ -234,7 +252,7 @@ Object *SegManager::getObject(reg_t pos) {
}
const char *SegManager::getObjectName(reg_t pos) {
- Object *obj = getObject(pos);
+ const Object *obj = getObject(pos);
if (!obj)
return "<no such object>";
@@ -275,7 +293,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
// It's a script or a clone table, scan all objects in it
for (; idx < max_index; ++idx) {
- Object *obj = NULL;
+ const Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
@@ -393,10 +411,6 @@ DataStack *SegManager::allocateStack(int size, SegmentId *segid) {
return retval;
}
-SystemStrings *SegManager::allocateSysStrings(SegmentId *segid) {
- return (SystemStrings *)allocSegment(new SystemStrings(), segid);
-}
-
void SegManager::freeHunkEntry(reg_t addr) {
if (addr.isNull()) {
warning("Attempt to free a Hunk from a null address");
@@ -485,7 +499,7 @@ void SegManager::reconstructClones() {
continue;
CloneTable::Entry &seeker = ct->_table[j];
- Object *baseObj = getObject(seeker.getSpeciesSelector());
+ const Object *baseObj = getObject(seeker.getSpeciesSelector());
seeker.cloneFromObject(baseObj);
if (!baseObj)
warning("Clone entry without a base class: %d", j);
@@ -523,6 +537,16 @@ Node *SegManager::allocateNode(reg_t *addr) {
return &(table->_table[offset]);
}
+reg_t SegManager::newNode(reg_t value, reg_t key) {
+ reg_t nodebase;
+ Node *n = allocateNode(&nodebase);
+ n->pred = n->succ = NULL_REG;
+ n->key = key;
+ n->value = value;
+
+ return nodebase;
+}
+
List *SegManager::lookupList(reg_t addr) {
if (getSegmentType(addr.segment) != SEG_TYPE_LISTS) {
warning("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr));
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index e8bbdbdb3f..9312f51f9d 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -112,12 +112,6 @@ public:
SegmentId getScriptSegment(int script_nr, ScriptLoadType load);
// TODO: document this
- reg_t lookupScriptExport(int script_nr, int export_index) {
- SegmentId seg = getScriptSegment(script_nr, SCRIPT_GET_DONT_LOAD);
- return make_reg(seg, getScript(seg)->validateExportFunc(export_index));
- }
-
- // TODO: document this
reg_t getClassAddress(int classnr, ScriptLoadType lock, reg_t caller);
/**
@@ -188,15 +182,10 @@ public:
// 5. System Strings
/**
- * Allocates a system string table
- * See also sys_string_acquire();
- * @param[in] segid Segment ID of the stack
- * @returns The physical stack
+ * Initializes the system string table.
*/
- SystemStrings *allocateSysStrings(SegmentId *segid);
-
+ void initSysStrings();
- // 5. System Strings
// 6, 7. Lists and Nodes
@@ -215,6 +204,14 @@ public:
Node *allocateNode(reg_t *addr);
/**
+ * Allocate and initialize a new list node.
+ * @param[in] value The value to set the node to
+ * @param[in] key The key to set
+ * @return Pointer to the newly initialized list node
+ */
+ reg_t newNode(reg_t value, reg_t key);
+
+ /**
* Resolves a list pointer to a list.
* @param addr The address to resolve
* @return The list referenced, or NULL on error
@@ -432,12 +429,22 @@ public:
*/
reg_t findObjectByName(const Common::String &name, int index = -1);
- void scriptRelocateExportsSci11(SegmentId seg);
void scriptInitialiseObjectsSci11(SegmentId seg);
+ uint32 classTableSize() { return _classTable.size(); }
+ Class getClass(int index) { return _classTable[index]; }
+ void setClassOffset(int index, reg_t offset) { _classTable[index].reg = offset; }
+ void resizeClassTable(uint32 size) { _classTable.resize(size); }
+
+ /**
+ * Obtains the system strings segment ID
+ */
+ SegmentId getSysStringsSegment() { return sysStringsSegment; }
+
public: // TODO: make private
Common::Array<SegmentObj *> _heap;
- Common::Array<Class> _classtable; /**< Table of all classes */
+ // Only accessible from saveLoadWithSerializer()
+ Common::Array<Class> _classTable; /**< Table of all classes */
#ifdef ENABLE_SCI32
SciArray<reg_t> *allocateArray(reg_t *addr);
@@ -460,6 +467,13 @@ private:
SegmentId Nodes_seg_id; ///< ID of the (a) node segment
SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment
+ /* System strings */
+ SegmentId sysStringsSegment;
+public: // TODO: make private. Only kString() needs direct access
+ SystemStrings *sysStrings;
+
+private:
+
#ifdef ENABLE_SCI32
SegmentId Arrays_seg_id;
SegmentId String_seg_id;
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index ab1a68d165..0e0a759d4b 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -27,6 +27,7 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
+#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
#include "sci/engine/segment.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
@@ -100,8 +101,7 @@ Script::Script() : SegmentObj(SEG_TYPE_SCRIPT) {
_localsSegment = 0;
_localsBlock = NULL;
- _relocated = false;
- _markedAsDeleted = 0;
+ _markedAsDeleted = false;
}
Script::~Script() {
@@ -117,54 +117,39 @@ void Script::freeScript() {
_codeBlocks.clear();
}
-bool Script::init(int script_nr, ResourceManager *resMan) {
- setScriptSize(script_nr, resMan);
-
- _buf = (byte *)malloc(_bufSize);
-
- if (!_buf) {
- freeScript();
- warning("Not enough memory space for script size");
- _bufSize = 0;
- return false;
- }
+void Script::init(int script_nr, ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
_localsOffset = 0;
_localsBlock = NULL;
_codeBlocks.clear();
- _relocated = false;
_markedAsDeleted = false;
_nr = script_nr;
-
- if (getSciVersion() >= SCI_VERSION_1_1)
- _heapStart = _buf + _scriptSize;
- else
- _heapStart = _buf;
-
- return true;
-}
-
-void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
- Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
+ _buf = 0;
+ _heapStart = 0;
_scriptSize = script->size;
- _heapSize = 0; // Set later
+ _bufSize = script->size;
+ _heapSize = 0;
- if (!script || (getSciVersion() >= SCI_VERSION_1_1 && !heap)) {
- error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");
- }
- if (oldScriptHeader) {
- _bufSize = script->size + READ_LE_UINT16(script->data) * 2;
- //locals_size = READ_LE_UINT16(script->data) * 2;
- } else if (getSciVersion() < SCI_VERSION_1_1) {
- _bufSize = script->size;
- } else {
- _bufSize = script->size + heap->size;
+ _lockers = 1;
+
+ if (getSciVersion() == SCI_VERSION_0_EARLY) {
+ _bufSize += READ_LE_UINT16(script->data) * 2;
+ } else if (getSciVersion() >= SCI_VERSION_1_1) {
+ /**
+ * In SCI11, the heap was in a separate space from the script.
+ * We append it to the end of the script, and adjust addressing accordingly.
+ * However, since we address the heap with a 16-bit pointer, the combined
+ * size of the stack and the heap must be 64KB. So far this has worked
+ * for SCI11, SCI2 and SCI21 games. SCI3 games use a different script format,
+ * and theoretically they can exceed the 64KB boundary using relocation.
+ */
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+ _bufSize += heap->size;
_heapSize = heap->size;
// Ensure that the start of the heap resource can be word-aligned.
@@ -173,12 +158,56 @@ void Script::setScriptSize(int script_nr, ResourceManager *resMan) {
_scriptSize++;
}
- if (_bufSize > 65535) {
- error("Script and heap sizes combined exceed 64K."
- "This means a fundamental design bug was made in SCI\n"
- "regarding SCI1.1 games.\nPlease report this so it can be"
- "fixed in the next major version");
- return;
+ // As mentioned above, the script and the heap together should not exceed 64KB
+ if (_bufSize > 65535)
+ error("Script and heap sizes combined exceed 64K. This means a fundamental "
+ "design bug was made regarding SCI1.1 and newer games.\nPlease "
+ "report this error to the ScummVM team");
+ }
+}
+
+void Script::load(ResourceManager *resMan) {
+ Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
+ assert(script != 0);
+
+ _buf = (byte *)malloc(_bufSize);
+ assert(_buf);
+
+ assert(_bufSize >= script->size);
+ memcpy(_buf, script->data, script->size);
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0);
+ assert(heap != 0);
+
+ _heapStart = _buf + _scriptSize;
+
+ assert(_bufSize - _scriptSize <= heap->size);
+ memcpy(_heapStart, heap->data, heap->size);
+ }
+
+ _codeBlocks.clear();
+
+ _exportTable = 0;
+ _numExports = 0;
+ _synonyms = 0;
+ _numSynonyms = 0;
+
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ if (READ_LE_UINT16(_buf + 1 + 5) > 0) {
+ _exportTable = (const uint16 *)(_buf + 1 + 5 + 2);
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1);
+ }
+ } else {
+ _exportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS);
+ if (_exportTable) {
+ _numExports = READ_SCI11ENDIAN_UINT16(_exportTable + 1);
+ _exportTable += 3; // skip header plus 2 bytes (_exportTable is a uint16 pointer)
+ }
+ _synonyms = findBlock(SCI_OBJ_SYNONYMS);
+ if (_synonyms) {
+ _numSynonyms = READ_SCI11ENDIAN_UINT16(_synonyms + 2) / 4;
+ _synonyms += 4; // skip header
}
}
}
@@ -194,19 +223,26 @@ Object *Script::getObject(uint16 offset) {
return 0;
}
-Object *Script::scriptObjInit(reg_t obj_pos) {
+const Object *Script::getObject(uint16 offset) const {
+ if (_objects.contains(offset))
+ return &_objects[offset];
+ else
+ return 0;
+}
+
+Object *Script::scriptObjInit(reg_t obj_pos, bool fullObjectInit) {
Object *obj;
- if (getSciVersion() < SCI_VERSION_1_1)
+ if (getSciVersion() < SCI_VERSION_1_1 && fullObjectInit)
obj_pos.offset += 8; // magic offset (SCRIPT_OBJECT_MAGIC_OFFSET)
VERIFY(obj_pos.offset < _bufSize, "Attempt to initialize object beyond end of script\n");
obj = allocateObject(obj_pos.offset);
- VERIFY(obj_pos.offset + SCRIPT_FUNCTAREAPTR_OFFSET < (int)_bufSize, "Function area pointer stored beyond end of script\n");
+ VERIFY(obj_pos.offset + kOffsetFunctionArea < (int)_bufSize, "Function area pointer stored beyond end of script\n");
- obj->init(_buf, obj_pos);
+ obj->init(_buf, obj_pos, fullObjectInit);
return obj;
}
@@ -218,37 +254,34 @@ void Script::scriptObjRemove(reg_t obj_pos) {
_objects.erase(obj_pos.toUint16());
}
-int Script::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) {
+// This helper function is used by Script::relocateLocal and Object::relocate
+static bool relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location, size_t scriptSize) {
int rel = location - block_location;
if (rel < 0)
- return 0;
+ return false;
uint idx = rel >> 1;
if (idx >= block.size())
- return 0;
+ return false;
if (rel & 1) {
warning("Attempt to relocate odd variable #%d.5e (relative to %04x)\n", idx, block_location);
- return 0;
+ return false;
}
block[idx].segment = segment; // Perform relocation
if (getSciVersion() >= SCI_VERSION_1_1)
- block[idx].offset += _scriptSize;
+ block[idx].offset += scriptSize;
- return 1;
+ return true;
}
-int Script::relocateLocal(SegmentId segment, int location) {
+bool Script::relocateLocal(SegmentId segment, int location) {
if (_localsBlock)
- return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location);
+ return relocateBlock(_localsBlock->_locals, _localsOffset, segment, location, _scriptSize);
else
- return 0; // No hands, no cookies
-}
-
-int Script::relocateObject(Object &obj, SegmentId segment, int location) {
- return relocateBlock(obj._variables, obj.getPos().offset, segment, location);
+ return false;
}
void Script::scriptAddCodeBlock(reg_t location) {
@@ -258,61 +291,35 @@ void Script::scriptAddCodeBlock(reg_t location) {
_codeBlocks.push_back(cb);
}
-void Script::scriptRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_bufSize && READ_SCI11ENDIAN_UINT16(_buf + block.offset) * 2 + block.offset < (uint16)_bufSize,
- "Relocation block outside of script\n");
-
- int count = READ_SCI11ENDIAN_UINT16(_buf + block.offset);
-
- for (int i = 0; i <= count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_buf + block.offset + 2 + (i * 2));
- if (!pos)
- continue; // FIXME: A hack pending investigation
-
- if (!relocateLocal(block.segment, pos)) {
- bool done = false;
- uint k;
-
- ObjMap::iterator it;
- const ObjMap::iterator end = _objects.end();
- for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
- done = true;
- }
-
- for (k = 0; !done && k < _codeBlocks.size(); k++) {
- if (pos >= _codeBlocks[k].pos.offset &&
- pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
- done = true;
- }
+void Script::relocate(reg_t block) {
+ byte *heap = _buf;
+ uint16 heapSize = (uint16)_bufSize;
+ uint16 heapOffset = 0;
- if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
- if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
- else
- printf("- No locals\n");
- for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- // SQ3 script 71 has broken relocation entries.
- printf("Trying to continue anyway...\n");
- }
- }
+ if (getSciVersion() >= SCI_VERSION_1_1) {
+ heap = _heapStart;
+ heapSize = (uint16)_heapSize;
+ heapOffset = _scriptSize;
}
-}
-void Script::heapRelocate(reg_t block) {
- VERIFY(block.offset < (uint16)_heapSize && READ_SCI11ENDIAN_UINT16(_heapStart + block.offset) * 2 + block.offset < (uint16)_bufSize,
+ VERIFY(block.offset < (uint16)heapSize && READ_SCI11ENDIAN_UINT16(heap + block.offset) * 2 + block.offset < (uint16)heapSize,
"Relocation block outside of script\n");
- if (_relocated)
- return;
- _relocated = true;
- int count = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset);
+ int count = READ_SCI11ENDIAN_UINT16(heap + block.offset);
+ int exportIndex = 0;
for (int i = 0; i < count; i++) {
- int pos = READ_SCI11ENDIAN_UINT16(_heapStart + block.offset + 2 + (i * 2)) + _scriptSize;
+ int pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ // This occurs in SCI01/SCI1 games where every usually one export
+ // value is zero. It seems that in this situation, we should skip
+ // the export and move to the next one, though the total count
+ // of valid exports remains the same
+ if (!pos) {
+ exportIndex++;
+ pos = READ_SCI11ENDIAN_UINT16(heap + block.offset + 2 + (exportIndex * 2)) + heapOffset;
+ if (!pos)
+ error("Script::relocate(): Consecutive zero exports found");
+ }
if (!relocateLocal(block.segment, pos)) {
bool done = false;
@@ -321,22 +328,33 @@ void Script::heapRelocate(reg_t block) {
ObjMap::iterator it;
const ObjMap::iterator end = _objects.end();
for (it = _objects.begin(); !done && it != end; ++it) {
- if (relocateObject(it->_value, block.segment, pos))
+ if (it->_value.relocate(block.segment, pos, _scriptSize))
done = true;
}
+ // Sanity check for SCI0-SCI1
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ for (k = 0; !done && k < _codeBlocks.size(); k++) {
+ if (pos >= _codeBlocks[k].pos.offset &&
+ pos < _codeBlocks[k].pos.offset + _codeBlocks[k].size)
+ done = true;
+ }
+ }
+
if (!done) {
- printf("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
- printf("Relocation failed for index %04x (%d/%d)\n", pos, i + 1, count);
+ debug("While processing relocation block %04x:%04x:\n", PRINT_REG(block));
+ debug("Relocation failed for index %04x (%d/%d)\n", pos, exportIndex + 1, count);
if (_localsBlock)
- printf("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
+ debug("- locals: %d at %04x\n", _localsBlock->_locals.size(), _localsOffset);
else
- printf("- No locals\n");
+ debug("- No locals\n");
for (it = _objects.begin(), k = 0; it != end; ++it, ++k)
- printf("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
- error("Breakpoint in %s, line %d", __FILE__, __LINE__);
+ debug("- obj#%d at %04x w/ %d vars\n", k, it->_value.getPos().offset, it->_value.getVarCount());
+ debug("Trying to continue anyway...\n");
}
}
+
+ exportIndex++;
}
}
@@ -357,16 +375,6 @@ void Script::setLockers(int lockers) {
_lockers = lockers;
}
-void Script::setExportTableOffset(int offset) {
- if (offset) {
- _exportTable = (uint16 *)(_buf + offset + 2);
- _numExports = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable - 1));
- } else {
- _exportTable = NULL;
- _numExports = 0;
- }
-}
-
uint16 Script::validateExportFunc(int pubfunct) {
bool exportsAreWide = (g_sci->_features->detectLofsType() == SCI_VERSION_1_MIDDLE);
@@ -377,28 +385,36 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (exportsAreWide)
pubfunct *= 2;
- uint16 offset = READ_SCI11ENDIAN_UINT16((byte *)(_exportTable + pubfunct));
+ uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct);
VERIFY(offset < _bufSize, "invalid export function pointer");
return offset;
}
-void Script::setSynonymsOffset(int offset) {
- _synonyms = _buf + offset;
-}
+byte *Script::findBlock(int type) {
+ byte *buf = _buf;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
-byte *Script::getSynonyms() const {
- return _synonyms;
-}
+ if (oldScriptHeader)
+ buf += 2;
-void Script::setSynonymsNr(int n) {
- _numSynonyms = n;
-}
+ do {
+ int seekerType = READ_LE_UINT16(buf);
+
+ if (seekerType == 0)
+ break;
+ if (seekerType == type)
+ return buf;
-int Script::getSynonymsNr() const {
- return _numSynonyms;
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
+
+ return NULL;
}
+
// memory operations
void Script::mcpyInOut(int dst, const void *src, size_t n) {
@@ -511,7 +527,7 @@ SegmentRef SystemStrings::dereference(reg_t pointer) {
//-------------------- script --------------------
-reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
@@ -527,13 +543,13 @@ void Script::freeAtAddress(SegManager *segMan, reg_t addr) {
segMan->deallocateScript(_nr);
}
-void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
-void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (addr.offset <= _bufSize && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(_buf + addr.offset)) {
- Object *obj = getObject(addr.offset);
+ const Object *obj = getObject(addr.offset);
if (obj) {
// Note all local variables, if we have a local variable environment
if (_localsSegment)
@@ -553,16 +569,14 @@ void Script::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback not
//-------------------- clones --------------------
-void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
- Clone *clone;
-
+void CloneTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
if (!isValidEntry(addr.offset)) {
error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
}
- clone = &(_table[addr.offset]);
+ const Clone *clone = &(_table[addr.offset]);
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
@@ -597,7 +611,7 @@ void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
//-------------------- locals --------------------
-reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) const {
// Reference the owning script
SegmentId owner_seg = segMan->getScriptSegment(script_id);
@@ -606,7 +620,7 @@ reg_t LocalVariables::findCanonicAddress(SegManager *segMan, reg_t addr) {
return make_reg(owner_seg, 0);
}
-void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
// assert(addr.segment == _segId);
for (uint i = 0; i < _locals.size(); i++)
@@ -615,12 +629,12 @@ void LocalVariables::listAllOutgoingReferences(reg_t addr, void *param, NoteCall
//-------------------- stack --------------------
-reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DataStack::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void DataStack::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
fprintf(stderr, "Emitting %d stack entries\n", _capacity);
for (int i = 0; i < _capacity; i++)
(*note)(param, _entries[i]);
@@ -633,13 +647,13 @@ void ListTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ListTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- List *list = &(_table[addr.offset]);
+ const List *list = &(_table[addr.offset]);
note(param, list->first);
note(param, list->last);
@@ -653,12 +667,12 @@ void NodeTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- Node *node = &(_table[addr.offset]);
+ const Node *node = &(_table[addr.offset]);
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
@@ -673,20 +687,43 @@ void NodeTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
//-------------------- object ----------------------------
-Object *Object::getClass(SegManager *segMan) {
+void Object::init(byte *buf, reg_t obj_pos, bool initVariables) {
+ byte *data = buf + obj_pos.offset;
+ _baseObj = data;
+ _pos = obj_pos;
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ _variables.resize(READ_LE_UINT16(data + kOffsetSelectorCounter));
+ _baseVars = (const uint16 *)(_baseObj + _variables.size() * 2);
+ _baseMethod = (const uint16 *)(data + READ_LE_UINT16(data + kOffsetFunctionArea));
+ _methodCount = READ_LE_UINT16(_baseMethod - 1);
+ } else {
+ _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
+ _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
+ _baseMethod = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
+ _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
+ }
+
+ if (initVariables) {
+ for (uint i = 0; i < _variables.size(); i++)
+ _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
+ }
+}
+
+const Object *Object::getClass(SegManager *segMan) const {
return isClass() ? this : segMan->getObject(getSuperClassSelector());
}
-int Object::locateVarSelector(SegManager *segMan, Selector slc) {
- byte *buf;
+int Object::locateVarSelector(SegManager *segMan, Selector slc) const {
+ const byte *buf;
uint varnum;
if (getSciVersion() < SCI_VERSION_1_1) {
varnum = getVarCount();
- int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET;
+ int selector_name_offset = varnum * 2 + kOffsetSelectorSegment;
buf = _baseObj + selector_name_offset;
} else {
- Object *obj = getClass(segMan);
+ const Object *obj = getClass(segMan);
varnum = obj->getVariable(1).toUint16();
buf = (byte *)obj->_baseVars;
}
@@ -698,14 +735,72 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) {
return -1; // Failed
}
+bool Object::relocate(SegmentId segment, int location, size_t scriptSize) {
+ return relocateBlock(_variables, getPos().offset, segment, location, scriptSize);
+}
+
+int Object::propertyOffsetToId(SegManager *segMan, int propertyOffset) const {
+ int selectors = getVarCount();
+
+ if (propertyOffset < 0 || (propertyOffset >> 1) >= selectors) {
+ warning("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d])",
+ propertyOffset, propertyOffset >> 1, selectors - 1);
+ return -1;
+ }
+
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ const byte *selectoroffset = ((const byte *)(_baseObj)) + kOffsetSelectorSegment + selectors * 2;
+ return READ_SCI11ENDIAN_UINT16(selectoroffset + propertyOffset);
+ } else {
+ const Object *obj = this;
+ if (!isClass())
+ obj = segMan->getObject(getSuperClassSelector());
+
+ return READ_SCI11ENDIAN_UINT16((const byte *)obj->_baseVars + propertyOffset);
+ }
+}
+
+void Object::initSpecies(SegManager *segMan, reg_t addr) {
+ uint16 speciesOffset = getSpeciesSelector().offset;
+
+ if (speciesOffset == 0xffff) // -1
+ setSpeciesSelector(NULL_REG); // no species
+ else
+ setSpeciesSelector(segMan->getClassAddress(speciesOffset, SCRIPT_GET_LOCK, addr));
+}
+
+void Object::initSuperClass(SegManager *segMan, reg_t addr) {
+ uint16 superClassOffset = getSuperClassSelector().offset;
+
+ if (superClassOffset == 0xffff) // -1
+ setSuperClassSelector(NULL_REG); // no superclass
+ else
+ setSuperClassSelector(segMan->getClassAddress(superClassOffset, SCRIPT_GET_LOCK, addr));
+}
+
+bool Object::initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass) {
+ const Object *baseObj = segMan->getObject(getSpeciesSelector());
+
+ if (baseObj) {
+ _variables.resize(baseObj->getVarCount());
+ // Copy base from species class, as we need its selector IDs
+ _baseObj = baseObj->_baseObj;
+ if (doInitSuperClass)
+ initSuperClass(segMan, addr);
+ return true;
+ }
+
+ return false;
+}
+
//-------------------- dynamic memory --------------------
-reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) {
+reg_t DynMem::findCanonicAddress(SegManager *segMan, reg_t addr) const {
addr.offset = 0;
return addr;
}
-void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
(*note)(param, make_reg(segId, 0));
}
@@ -724,13 +819,13 @@ void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
freeEntry(sub_addr.offset);
}
-void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) {
+void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback note) const {
if (!isValidEntry(addr.offset)) {
warning("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
return;
}
- SciArray<reg_t> *array = &(_table[addr.offset]);
+ const SciArray<reg_t> *array = &(_table[addr.offset]);
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
@@ -739,7 +834,7 @@ void ArrayTable::listAllOutgoingReferences(reg_t addr, void *param, NoteCallback
}
}
-Common::String SciString::toString() {
+Common::String SciString::toString() const {
if (_type != 3)
error("SciString::toString(): Array is not a string");
@@ -750,7 +845,7 @@ Common::String SciString::toString() {
return string;
}
-void SciString::fromString(Common::String string) {
+void SciString::fromString(const Common::String &string) {
if (_type != 3)
error("SciString::fromString(): Array is not a string");
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 1089ada475..f1b6dccaa2 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -112,7 +112,7 @@ public:
*
* @param sub_addr base address whose canonic address is to be found
*/
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) { return sub_addr; }
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const { return sub_addr; }
/**
* Deallocates all memory associated with the specified address.
@@ -125,7 +125,7 @@ public:
* @param note Invoked for each address on which free_at_address() makes sense
* @param param parameter passed to 'note'
*/
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {}
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {}
/**
* Iterates over all references reachable from the specified object.
@@ -134,7 +134,7 @@ public:
* @param note Invoked for each outgoing reference within the object
* Note: This function may also choose to report numbers (segment 0) as adresses
*/
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) {}
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const {}
};
@@ -194,8 +194,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -205,6 +205,22 @@ enum {
OBJECT_FLAG_FREED = (1 << 0)
};
+enum infoSelectorFlags {
+ kInfoFlagClone = 0x0001,
+ kInfoFlagClass = 0x8000
+};
+
+enum ObjectOffsets {
+ kOffsetLocalVariables = -6,
+ kOffsetFunctionArea = -4,
+ kOffsetSelectorCounter = -2,
+ kOffsetSelectorSegment = 0,
+ kOffsetInfoSelectorSci0 = 4,
+ kOffsetNamePointerSci0 = 6,
+ kOffsetInfoSelectorSci11 = 14,
+ kOffsetNamePointerSci11 = 16
+};
+
class Object {
public:
Object() {
@@ -214,31 +230,34 @@ public:
~Object() { }
- reg_t getSpeciesSelector() { return _variables[_offset]; }
+ reg_t getSpeciesSelector() const { return _variables[_offset]; }
void setSpeciesSelector(reg_t value) { _variables[_offset] = value; }
- reg_t getSuperClassSelector() { return _variables[_offset + 1]; }
+ reg_t getSuperClassSelector() const { return _variables[_offset + 1]; }
void setSuperClassSelector(reg_t value) { _variables[_offset + 1] = value; }
- reg_t getInfoSelector() { return _variables[_offset + 2]; }
- void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
+ reg_t getInfoSelector() const { return _variables[_offset + 2]; }
+ void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; }
- reg_t getNameSelector() { return _variables[_offset + 3]; }
- void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
+ reg_t getNameSelector() const { return _variables[_offset + 3]; }
+ void setNameSelector(reg_t value) { _variables[_offset + 3] = value; }
- reg_t getClassScriptSelector() { return _variables[4]; }
+ reg_t getPropDictSelector() const { return _variables[2]; }
+ void setPropDictSelector(reg_t value) { _variables[2] = value; }
+
+ reg_t getClassScriptSelector() const { return _variables[4]; }
void setClassScriptSelector(reg_t value) { _variables[4] = value; }
- Selector getVarSelector(uint16 i) { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
+ Selector getVarSelector(uint16 i) const { return READ_SCI11ENDIAN_UINT16(_baseVars + i); }
- reg_t getFunction(uint16 i) {
+ reg_t getFunction(uint16 i) const {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? _methodCount + 1 + i : i * 2 + 2;
- return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset)));
+ return make_reg(_pos.segment, READ_SCI11ENDIAN_UINT16(_baseMethod + offset));
}
- Selector getFuncSelector(uint16 i) {
+ Selector getFuncSelector(uint16 i) const {
uint16 offset = (getSciVersion() < SCI_VERSION_1_1) ? i : i * 2 + 1;
- return READ_SCI11ENDIAN_UINT16((byte *) (_baseMethod + offset));
+ return READ_SCI11ENDIAN_UINT16(_baseMethod + offset);
}
/**
@@ -247,7 +266,7 @@ public:
* superclasses, i.e. failure may be returned even if one of the
* superclasses defines the funcselector
*/
- int funcSelectorPosition(Selector sel) {
+ int funcSelectorPosition(Selector sel) const {
for (uint i = 0; i < _methodCount; i++)
if (getFuncSelector(i) == sel)
return i;
@@ -256,61 +275,56 @@ public:
}
/**
- * Determines if the object explicitly defines slc as a varselector
- * Returns -1 if not found
+ * Determines if the object explicitly defines slc as a varselector.
+ * Returns -1 if not found.
*/
- int locateVarSelector(SegManager *segMan, Selector slc);
-
- bool isClass() { return (getInfoSelector().offset & SCRIPT_INFO_CLASS); }
- Object *getClass(SegManager *segMan);
+ int locateVarSelector(SegManager *segMan, Selector slc) const;
- void markAsFreed() { _flags |= OBJECT_FLAG_FREED; }
- bool isFreed() { return _flags & OBJECT_FLAG_FREED; }
+ bool isClass() const { return (getInfoSelector().offset & kInfoFlagClass); }
+ const Object *getClass(SegManager *segMan) const;
- void setVarCount(uint size) { _variables.resize(size); }
- uint getVarCount() { return _variables.size(); }
+ void markAsClone() { setInfoSelector(make_reg(0, kInfoFlagClone)); }
+ bool isClone() const { return (getInfoSelector().offset & kInfoFlagClone); }
- void init(byte *buf, reg_t obj_pos) {
- byte *data = (byte *)(buf + obj_pos.offset);
- _baseObj = data;
- _pos = obj_pos;
+ void markAsFreed() { _flags |= OBJECT_FLAG_FREED; }
+ bool isFreed() const { return _flags & OBJECT_FLAG_FREED; }
- if (getSciVersion() < SCI_VERSION_1_1) {
- _variables.resize(READ_LE_UINT16(data + SCRIPT_SELECTORCTR_OFFSET));
- _baseVars = (uint16 *)(_baseObj + _variables.size() * 2);
- _baseMethod = (uint16 *)(data + READ_LE_UINT16(data + SCRIPT_FUNCTAREAPTR_OFFSET));
- _methodCount = READ_LE_UINT16(_baseMethod - 1);
- } else {
- _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2));
- _baseVars = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4));
- _baseMethod = (uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 6));
- _methodCount = READ_SCI11ENDIAN_UINT16(_baseMethod);
- }
+ uint getVarCount() const { return _variables.size(); }
- for (uint i = 0; i < _variables.size(); i++)
- _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2)));
- }
+ void init(byte *buf, reg_t obj_pos, bool initVariables = true);
- reg_t getVariable(uint var) { return _variables[var]; }
+ reg_t getVariable(uint var) const { return _variables[var]; }
+ reg_t &getVariableRef(uint var) { return _variables[var]; }
- uint16 getMethodCount() { return _methodCount; }
- reg_t getPos() { return _pos; }
+ uint16 getMethodCount() const { return _methodCount; }
+ reg_t getPos() const { return _pos; }
void saveLoadWithSerializer(Common::Serializer &ser);
- void cloneFromObject(Object *obj) {
+ void cloneFromObject(const Object *obj) {
_baseObj = obj ? obj->_baseObj : NULL;
_baseMethod = obj ? obj->_baseMethod : NULL;
_baseVars = obj ? obj->_baseVars : NULL;
}
+ bool relocate(SegmentId segment, int location, size_t scriptSize);
+
+ int propertyOffsetToId(SegManager *segMan, int propertyOffset) const;
+
+ void initSpecies(SegManager *segMan, reg_t addr);
+ void initSuperClass(SegManager *segMan, reg_t addr);
+ bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
+
// TODO: make private
- Common::Array<reg_t> _variables;
- byte *_baseObj; /**< base + object offset within base */
- uint16 *_baseVars; /**< Pointer to the varselector area for this object */
- uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
+ // Only SegManager::reconstructScripts() is left needing direct access to these
+public:
+ const byte *_baseObj; /**< base + object offset within base */
private:
+ const uint16 *_baseVars; /**< Pointer to the varselector area for this object */
+ const uint16 *_baseMethod; /**< Pointer to the method selector area for this object */
+
+ Common::Array<reg_t> _variables;
uint16 _methodCount;
int _flags;
uint16 _offset;
@@ -328,21 +342,28 @@ class Script : public SegmentObj {
public:
int _nr; /**< Script number */
byte *_buf; /**< Static data buffer, or NULL if not used */
- size_t _bufSize;
- size_t _scriptSize;
- size_t _heapSize;
-
byte *_heapStart; /**< Start of heap if SCI1.1, NULL otherwise */
- uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
- int _numExports; /**< Number of entries in the exports table */
-
- byte *_synonyms; /**< Synonyms block or 0 if not present*/
- int _numSynonyms; /**< Number of entries in the synonyms block */
+ uint32 getScriptSize() { return _scriptSize; }
+ uint32 getHeapSize() { return _heapSize; }
+ uint32 getBufSize() { return _bufSize; }
protected:
int _lockers; /**< Number of classes and objects that require this script */
+private:
+ size_t _scriptSize;
+ size_t _heapSize;
+ size_t _bufSize;
+
+ const uint16 *_exportTable; /**< Abs. offset of the export table or 0 if not present */
+ uint16 _numExports; /**< Number of entries in the exports table */
+
+ const byte *_synonyms; /**< Synonyms block or 0 if not present*/
+ uint16 _numSynonyms; /**< Number of entries in the synonyms block */
+
+ Common::Array<CodeBlock> _codeBlocks;
+
public:
/**
* Table for objects, contains property variables.
@@ -354,8 +375,6 @@ public:
SegmentId _localsSegment; /**< The local variable segment */
LocalVariables *_localsBlock;
- Common::Array<CodeBlock> _codeBlocks;
- bool _relocated;
bool _markedAsDeleted;
public:
@@ -363,19 +382,21 @@ public:
~Script();
void freeScript();
- bool init(int script_nr, ResourceManager *resMan);
+ void init(int script_nr, ResourceManager *resMan);
+ void load(ResourceManager *resMan);
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
Object *allocateObject(uint16 offset);
Object *getObject(uint16 offset);
+ const Object *getObject(uint16 offset) const;
/**
* Informs the segment manager that a code block must be relocated
@@ -392,7 +413,7 @@ public:
* @returns A newly created Object describing the object,
* stored within the relevant script
*/
- Object *scriptObjInit(reg_t obj_pos);
+ Object *scriptObjInit(reg_t obj_pos, bool fullObjectInit = true);
/**
* Removes a script object
@@ -407,14 +428,10 @@ public:
* @param obj_pos Location (segment, offset) of the block
* @return Location of the relocation block
*/
- void scriptRelocate(reg_t block);
-
- void heapRelocate(reg_t block);
+ void relocate(reg_t block);
private:
- int relocateLocal(SegmentId segment, int location);
- int relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location);
- int relocateObject(Object &obj, SegmentId segment, int location);
+ bool relocateLocal(SegmentId segment, int location);
public:
// script lock operations
@@ -435,22 +452,28 @@ public:
void setLockers(int lockers);
/**
+ * Retrieves a pointer to the exports of this script
+ * @return pointer to the exports.
+ */
+ const uint16 *getExportTable() const { return _exportTable; }
+
+ /**
+ * Retrieves the number of exports of script.
+ * @return the number of exports of this script
+ */
+ uint16 getExportsNr() const { return _numExports; }
+
+ /**
* Retrieves a pointer to the synonyms associated with this script
* @return pointer to the synonyms, in non-parsed format.
*/
- byte *getSynonyms() const;
+ const byte *getSynonyms() const { return _synonyms; }
/**
* Retrieves the number of synonyms associated with this script.
* @return the number of synonyms associated with this script
*/
- int getSynonymsNr() const;
-
- /**
- * Sets the script-relative offset of the exports table.
- * @param offset script-relative exports table offset
- */
- void setExportTableOffset(int offset);
+ uint16 getSynonymsNr() const { return _numSynonyms; }
/**
* Validate whether the specified public function is exported by
@@ -462,19 +485,6 @@ public:
uint16 validateExportFunc(int pubfunct);
/**
- * Sets the script-relative offset of the synonyms associated with this script.
- * @param offset script-relative offset of the synonyms block
- */
- void setSynonymsOffset(int offset);
-
- /**
- * Sets the number of synonyms associated with this script,
- * @param nr number of synonyms, as to be stored within the script
- */
- void setSynonymsNr(int nr);
-
-
- /**
* Marks the script as deleted.
* This will not actually delete the script. If references remain present on the
* heap or the stack, the script will stay in memory in a quasi-deleted state until
@@ -508,8 +518,10 @@ public:
*/
int16 getHeap(uint16 offset) const;
-private:
- void setScriptSize(int script_nr, ResourceManager *resMan);
+ /**
+ * Finds the pointer where a block of a specific type starts from
+ */
+ byte *findBlock(int type);
};
/** Data stack */
@@ -529,8 +541,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -618,7 +630,7 @@ public:
entries_used--;
}
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) {
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const {
for (uint i = 0; i < _table.size(); i++)
if (isValidEntry(i))
(*note)(param, make_reg(segId, i));
@@ -631,7 +643,7 @@ struct CloneTable : public Table<Clone> {
CloneTable() : Table<Clone>(SEG_TYPE_CLONES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -642,7 +654,7 @@ struct NodeTable : public Table<Node> {
NodeTable() : Table<Node>(SEG_TYPE_NODES) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -653,7 +665,7 @@ struct ListTable : public Table<List> {
ListTable() : Table<List>(SEG_TYPE_LISTS) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -688,8 +700,8 @@ public:
virtual bool isValidOffset(uint16 offset) const;
virtual SegmentRef dereference(reg_t pointer);
- virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note);
+ virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const;
+ virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) const;
virtual void saveLoadWithSerializer(Common::Serializer &ser);
};
@@ -782,7 +794,7 @@ public:
_size = _actualSize = size;
}
- T getValue(uint16 index) {
+ T getValue(uint16 index) const {
if (index >= _size)
error("SciArray::getValue(): %d is out of bounds (%d)", index, _size);
@@ -796,8 +808,8 @@ public:
_data[index] = value;
}
- byte getType() { return _type; }
- uint32 getSize() { return _size; }
+ byte getType() const { return _type; }
+ uint32 getSize() const { return _size; }
T *getRawData() { return _data; }
protected:
@@ -814,15 +826,15 @@ public:
// We overload destroy to ensure the string type is 3 after destroying
void destroy() { SciArray<char>::destroy(); _type = 3; }
- Common::String toString();
- void fromString(Common::String string);
+ Common::String toString() const;
+ void fromString(const Common::String &string);
};
struct ArrayTable : public Table<SciArray<reg_t> > {
ArrayTable() : Table<SciArray<reg_t> >(SEG_TYPE_ARRAY) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr);
- virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note);
+ virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note) const;
void saveLoadWithSerializer(Common::Serializer &ser);
SegmentRef dereference(reg_t pointer);
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index e226c4b574..04a1b8fbba 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -153,11 +153,11 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(subtitleLang);
FIND_SELECTOR(parseLang);
FIND_SELECTOR(overlay);
- FIND_SELECTOR(setCursor);
FIND_SELECTOR(topString);
FIND_SELECTOR(scaleSignal);
FIND_SELECTOR(scaleX);
FIND_SELECTOR(scaleY);
+ FIND_SELECTOR(iconIndex);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
@@ -175,32 +175,32 @@ void Kernel::mapSelectors() {
#endif
}
-reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id) {
+reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
ObjVarRef address;
- if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
+ if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
return NULL_REG;
else
return *address.getPointer(segMan);
}
-void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value) {
+void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value) {
ObjVarRef address;
- if ((selector_id < 0) || (selector_id > (int)g_sci->getKernel()->getSelectorNamesSize())) {
+ if ((selectorId < 0) || (selectorId > (int)g_sci->getKernel()->getSelectorNamesSize())) {
warning("Attempt to write to invalid selector %d of"
- " object at %04x:%04x.", selector_id, PRINT_REG(object));
+ " object at %04x:%04x.", selectorId, PRINT_REG(object));
return;
}
- if (lookup_selector(segMan, object, selector_id, &address, NULL) != kSelectorVariable)
+ if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
warning("Selector '%s' of object at %04x:%04x could not be"
- " written to", g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ " written to", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
else
*address.getPointer(segMan) = value;
}
-int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, const reg_t *argv) {
int i;
int framesize = 2 + 1 * argc;
@@ -208,21 +208,21 @@ int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, Selector
int slc_type;
StackPtr stackframe = k_argp + k_argc;
- stackframe[0] = make_reg(0, selector_id); // The selector we want to call
+ stackframe[0] = make_reg(0, selectorId); // The selector we want to call
stackframe[1] = make_reg(0, argc); // Argument count
- slc_type = lookup_selector(s->_segMan, object, selector_id, NULL, &address);
+ slc_type = lookupSelector(s->_segMan, object, selectorId, NULL, &address);
if (slc_type == kSelectorNone) {
warning("Selector '%s' of object at %04x:%04x could not be invoked",
- g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
if (noinvalid == kStopOnInvalidSelector)
error("[Kernel] Not recoverable: VM was halted");
return 1;
}
if (slc_type == kSelectorVariable) {
warning("Attempting to invoke variable selector %s of object %04x:%04x",
- g_sci->getKernel()->getSelectorName(selector_id).c_str(), PRINT_REG(object));
+ g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object));
return 0;
}
@@ -242,7 +242,7 @@ int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, Selector
return 0;
}
-int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
+int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
int k_argc, StackPtr k_argp, int argc, ...) {
va_list argp;
reg_t *args = new reg_t[argc];
@@ -252,28 +252,28 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc
args[i] = va_arg(argp, reg_t);
va_end(argp);
- int retval = invoke_selector_argv(s, object, selector_id, noinvalid, k_argc, k_argp, argc, args);
+ int retval = invokeSelectorArgv(s, object, selectorId, noinvalid, k_argc, k_argp, argc, args);
delete[] args;
return retval;
}
-SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) {
- Object *obj = segMan->getObject(obj_location);
+SelectorType lookupSelector(SegManager *segMan, reg_t obj_location, Selector selectorId, ObjVarRef *varp, reg_t *fptr) {
+ const Object *obj = segMan->getObject(obj_location);
int index;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle, meaning that we must remove it for selector lookup.
if (oldScriptHeader)
- selector_id &= ~1;
+ selectorId &= ~1;
if (!obj) {
- error("lookup_selector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
+ error("lookupSelector(): Attempt to send to non-object or invalid script. Address was %04x:%04x",
PRINT_REG(obj_location));
}
- index = obj->locateVarSelector(segMan, selector_id);
+ index = obj->locateVarSelector(segMan, selectorId);
if (index >= 0) {
// Found it as a variable
@@ -285,7 +285,7 @@ SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector se
} else {
// Check if it's a method, with recursive lookup in superclasses
while (obj) {
- index = obj->funcSelectorPosition(selector_id);
+ index = obj->funcSelectorPosition(selectorId);
if (index >= 0) {
if (fptr)
*fptr = obj->getFunction(index);
@@ -300,7 +300,7 @@ SelectorType lookup_selector(SegManager *segMan, reg_t obj_location, Selector se
}
-// return _lookup_selector_function(segMan, obj, selector_id, fptr);
+// return _lookupSelector_function(segMan, obj, selectorId, fptr);
}
} // End of namespace Sci
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 70eeb34d93..f50b9ab1b3 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -34,20 +34,15 @@
namespace Sci {
-
-/******************** Selector functionality ********************/
-
enum SelectorInvocation {
kStopOnInvalidSelector = 0,
kContinueOnInvalidSelector = 1
};
-
/**
* Map a selector name to a selector id. Shortcut for accessing the selector cache.
*/
#define SELECTOR(_slc_) (g_sci->getKernel()->_selectorCache._slc_)
-//#define SELECTOR(_slc_) _slc_
/**
* Retrieves a selector from an object.
@@ -58,8 +53,8 @@ enum SelectorInvocation {
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-#define GET_SEL32(segMan, _obj_, _slc_) read_selector(segMan, _obj_, _slc_)
-#define GET_SEL32V(segMan, _obj_, _slc_) (GET_SEL32(segMan, _obj_, _slc_).offset)
+reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId);
+#define readSelectorValue(segMan, _obj_, _slc_) (readSelector(segMan, _obj_, _slc_).offset)
/**
* Writes a selector value to an object.
@@ -70,27 +65,25 @@ enum SelectorInvocation {
* This macro halts on error. 'selector' must be a selector name registered in vm.h's
* SelectorCache and mapped in script.cpp.
*/
-#define PUT_SEL32(segMan, _obj_, _slc_, _val_) write_selector(segMan, _obj_, _slc_, _val_)
-#define PUT_SEL32V(segMan, _obj_, _slc_, _val_) PUT_SEL32(segMan, _obj_, _slc_, make_reg(0, _val_))
+void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t value);
+#define writeSelectorValue(segMan, _obj_, _slc_, _val_) writeSelector(segMan, _obj_, _slc_, make_reg(0, _val_))
+/**
+ * Invokes a selector from an object.
+ */
+int invokeSelector(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, ...);
+int invokeSelectorArgv(EngineState *s, reg_t object, int selectorId, SelectorInvocation noinvalid,
+ int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
/**
- * Kludge for use with invoke_selector(). Used for compatibility with compilers
+ * Kludge for use with invokeSelector(). Used for compatibility with compilers
* that cannot handle vararg macros.
*/
#define INV_SEL(s, _object_, _selector_, _noinvalid_) \
s, _object_, g_sci->getKernel()->_selectorCache._selector_, _noinvalid_, argc, argv
-reg_t read_selector(SegManager *segMan, reg_t object, Selector selector_id);
-void write_selector(SegManager *segMan, reg_t object, Selector selector_id, reg_t value);
-int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, ...);
-int invoke_selector_argv(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid,
- int k_argc, StackPtr k_argp, int argc, const reg_t *argv);
-
-
-
} // End of namespace Sci
#endif // SCI_ENGINE_KERNEL_H
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index bd78639c77..b4a04f8826 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -69,51 +69,56 @@ static const uint16 s_halfWidthSJISMap[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-EngineState::EngineState(Vocabulary *voc, SegManager *segMan)
-: _voc(voc), _segMan(segMan), _dirseeker() {
+EngineState::EngineState(SegManager *segMan)
+: _segMan(segMan), _dirseeker() {
+ reset(false);
+}
+
+EngineState::~EngineState() {
+ delete _msgState;
+}
+
+void EngineState::reset(bool isRestoring) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
sfx_init_flags = 0;
#endif
- restarting_flags = 0;
-
- last_wait_time = 0;
+ if (!isRestoring) {
+ script_000 = 0;
+ _gameObj = NULL_REG;
- _fileHandles.resize(5);
+ _memorySegmentSize = 0;
+ _soundCmd = 0;
- execution_stack_base = 0;
- _executionStackPosChanged = false;
+ restarting_flags = 0;
- r_acc = NULL_REG;
- restAdjust = 0;
- r_prev = NULL_REG;
+ execution_stack_base = 0;
+ _executionStackPosChanged = false;
- stack_base = 0;
- stack_top = 0;
+ _fileHandles.resize(5);
- script_000 = 0;
+ r_acc = NULL_REG;
+ restAdjust = 0;
+ r_prev = NULL_REG;
- sys_strings_segment = 0;
- sys_strings = 0;
+ stack_base = 0;
+ stack_top = 0;
+ }
- _gameObj = NULL_REG;
+ last_wait_time = 0;
gc_countdown = 0;
- successor = 0;
-
_throttleCounter = 0;
_throttleLastTime = 0;
_throttleTrigger = false;
- _memorySegmentSize = 0;
-
- _soundCmd = 0;
-}
+ script_abort_flag = 0;
+ script_step_counter = 0;
+ script_gc_interval = GC_INTERVAL;
-EngineState::~EngineState() {
- delete _msgState;
+ restoring = false;
}
void EngineState::wait(int16 ticks) {
@@ -135,6 +140,15 @@ void EngineState::setRoomNumber(uint16 roomNumber) {
script_000->_localsBlock->_locals[13] = make_reg(0, roomNumber);
}
+void EngineState::shrinkStackToBase() {
+ uint size = execution_stack_base + 1;
+ assert(_executionStack.size() >= size);
+ Common::List<ExecStack>::iterator iter = _executionStack.begin();
+ for (uint i = 0; i < size; ++i)
+ ++iter;
+ _executionStack.erase(iter, _executionStack.end());
+}
+
static kLanguage charToLanguage(const char c) {
switch (c) {
case 'F':
@@ -218,7 +232,7 @@ kLanguage SciEngine::getSciLanguage() {
lang = K_LANG_ENGLISH;
if (_kernel->_selectorCache.printLang != -1) {
- lang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
+ lang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));
if ((getSciVersion() >= SCI_VERSION_1_1) || (lang == K_LANG_NONE)) {
// If language is set to none, we use the language from the game detector.
@@ -253,7 +267,7 @@ kLanguage SciEngine::getSciLanguage() {
}
// Store language in printLang selector
- PUT_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
+ writeSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
}
}
@@ -265,7 +279,7 @@ Common::String SciEngine::strSplit(const char *str, const char *sep) {
kLanguage subLang = K_LANG_NONE;
if (_kernel->_selectorCache.subtitleLang != -1) {
- subLang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
+ subLang = (kLanguage)readSelectorValue(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
}
kLanguage secondLang;
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index c4b995806f..68e6a5516a 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -76,8 +76,7 @@ enum {
enum {
SCI_GAME_IS_NOT_RESTARTING = 0,
SCI_GAME_WAS_RESTARTED = 1,
- SCI_GAME_IS_RESTARTING_NOW = 2,
- SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE = 4
+ SCI_GAME_IS_RESTARTING_NOW = 2
};
class FileHandle {
@@ -96,16 +95,13 @@ public:
struct EngineState : public Common::Serializable {
public:
- EngineState(Vocabulary *voc, SegManager *segMan);
+ EngineState(SegManager *segMan);
virtual ~EngineState();
virtual void saveLoadWithSerializer(Common::Serializer &ser);
public:
SegManager *_segMan; /**< The segment manager */
- Vocabulary *_voc;
-
- Common::String _gameId; /**< Designation of the primary object (which inherits from Game) */
/* Non-VM information */
@@ -152,14 +148,34 @@ public:
StackPtr stack_base; /**< Pointer to the least stack element */
StackPtr stack_top; /**< First invalid stack element */
+ // Script state
+ ExecStack *xs;
+ reg_t *variables[4]; ///< global, local, temp, param, as immediate pointers
+ reg_t *variables_base[4]; ///< Used for referencing VM ops
+ SegmentId variables_seg[4]; ///< Same as above, contains segment IDs
+ int variables_max[4]; ///< Max. values for all variables
+
Script *script_000; /**< script 000, e.g. for globals */
+ int loadFromLauncher;
+
+ /**
+ * Set this to 1 to abort script execution immediately. Aborting will
+ * leave the debug exec stack intact.
+ * Set it to 2 to force a replay afterwards.
+ */
+ int script_abort_flag; // Set to 1 to abort execution. Set to 2 to force a replay afterwards
+ int script_step_counter; // Counts the number of steps executed
+ int script_gc_interval; // Number of steps in between gcs
+
uint16 currentRoomNumber() const;
void setRoomNumber(uint16 roomNumber);
- /* System strings */
- SegmentId sys_strings_segment;
- SystemStrings *sys_strings;
+ /**
+ * Shrink execution stack to size.
+ * Contains an assert it is not already smaller.
+ */
+ void shrinkStackToBase();
reg_t _gameObj; /**< Pointer to the game object */
@@ -176,7 +192,12 @@ public:
uint _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
- EngineState *successor; /**< Successor of this state: Used for restoring */
+ /**
+ * Resets the engine state.
+ */
+ void reset(bool isRestoring);
+
+ bool restoring; /**< A flag to indicate if a game is being restored */
};
} // End of namespace Sci
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index e2ee2e1971..b04cc473b5 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -46,13 +46,6 @@ const reg_t SIGNAL_REG = {0, SIGNAL_OFFSET};
//#define VM_DEBUG_SEND
-ScriptState scriptState; // FIXME: Avoid non-const global vars
-int g_loadFromLauncher; // FIXME: Avoid non-const global vars
-
-int script_abort_flag = 0; // Set to 1 to abort execution. Set to 2 to force a replay afterwards // FIXME: Avoid non-const global vars
-int script_step_counter = 0; // Counts the number of steps executed // FIXME: Avoid non-const global vars
-int script_gc_interval = GC_INTERVAL; // Number of steps in between gcs // FIXME: Avoid non-const global vars
-
#define SCI_XS_CALLEE_LOCALS ((SegmentId)-1)
/**
@@ -120,7 +113,7 @@ static reg_t &validate_property(Object *obj, int index) {
return dummyReg;
}
- return obj->_variables[index];
+ return obj->getVariableRef(index);
}
static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) {
@@ -212,7 +205,7 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
if (!stopGroopPos.isNull()) { // does the game have a stopGroop object?
// Find the "client" member variable of the stopGroop object, and update it
ObjVarRef varp;
- if (lookup_selector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
+ if (lookupSelector(segMan, stopGroopPos, kernel->_selectorCache.client, &varp, NULL) == kSelectorVariable) {
reg_t *clientVar = varp.getPointer(segMan);
*clientVar = value;
}
@@ -236,8 +229,8 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#endif
-#define READ_VAR(type, index, def) validate_read_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, def)
-#define WRITE_VAR(type, index, value) validate_write_var(scriptState.variables[type], s->stack_base, type, scriptState.variables_max[type], index, __LINE__, value, s->_segMan, g_sci->getKernel())
+#define READ_VAR(type, index, def) validate_read_var(s->variables[type], s->stack_base, type, s->variables_max[type], index, __LINE__, def)
+#define WRITE_VAR(type, index, value) validate_write_var(s->variables[type], s->stack_base, type, s->variables_max[type], index, __LINE__, value, s->_segMan, g_sci->getKernel())
#define WRITE_VAR16(type, index, value) WRITE_VAR(type, index, make_reg(0, value));
#define ACC_ARITHMETIC_L(op) make_reg(0, (op validate_arithmetic(s->r_acc)))
@@ -251,8 +244,8 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#define PUSH(v) PUSH32(make_reg(0, v))
#define POP() (validate_arithmetic(POP32()))
// 32 bit:
-#define PUSH32(a) (*(validate_stack_addr(s, (scriptState.xs->sp)++)) = (a))
-#define POP32() (*(validate_stack_addr(s, --(scriptState.xs->sp))))
+#define PUSH32(a) (*(validate_stack_addr(s, (s->xs->sp)++)) = (a))
+#define POP32() (*(validate_stack_addr(s, --(s->xs->sp))))
ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp) {
int seg = s->_segMan->getScriptSegment(script);
@@ -341,7 +334,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
int selector;
int argc;
int origin = s->_executionStack.size()-1; // Origin: Used for debugging
- int print_send_action = 0;
+ bool printSendActions = false;
// We return a pointer to the new active ExecStack
// The selector calls we catch are stored below:
@@ -370,7 +363,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
if (bp->type == BREAK_SELECTOR && !strncmp(bp->name.c_str(), method_name, cmplen)) {
Console *con = g_sci->getSciDebugger();
con->DebugPrintf("Break on %s (in [%04x:%04x])\n", method_name, PRINT_REG(send_obj));
- print_send_action = 1;
+ printSendActions = true;
g_debugState.debugging = true;
g_debugState.breakpointWasHit = true;
break;
@@ -383,7 +376,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
ObjVarRef varp;
- switch (lookup_selector(s->_segMan, send_obj, selector, &varp, &funcp)) {
+ switch (lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp)) {
case kSelectorNone:
error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj));
break;
@@ -398,22 +391,34 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
#endif // VM_DEBUG_SEND
// argc == 0: read selector
- // argc == 1: write selector
- // argc > 1: write selector?
- if (print_send_action && argc == 0) { // read selector
- printf("[read selector]\n");
- print_send_action = 0;
+ // argc != 0: write selector
+ if (printSendActions && !argc) { // read selector
+ debug("[read selector]\n");
+ printSendActions = false;
}
- if (print_send_action && argc > 0) {
+ if (printSendActions && argc) {
reg_t oldReg = *varp.getPointer(s->_segMan);
reg_t newReg = argp[1];
- printf("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
- print_send_action = 0;
+ debug("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg));
+ printSendActions = false;
}
- if (argc > 1)
- warning("send_selector(): more than 1 parameter (%d) while modifying a variable selector", argc);
+ if (argc > 1) {
+ // argc can indeed be bigger than 1 in some cases, and it seems correct
+ // (i.e. we should skip that many bytes later on)... question is, why
+ // does this occur? Could such calls be used to point to data after X
+ // bytes in the heap? What are the skipped bytes in this case?
+ // In SQ4CD, this occurs with the returnVal selector of object
+ // Sq4GlobalNarrator when the game starts, and right after the narrator
+ // is heard (e.g. after he talks when examining something)
+ reg_t oldReg = *varp.getPointer(s->_segMan);
+ reg_t newReg = argp[1];
+ warning("send_selector(): argc = %d while modifying variable selector "
+ "%x (%s) of object %04x:%04x (%s) from %04x:%04x to %04x:%04x",
+ argc, selector, g_sci->getKernel()->getSelectorName(selector).c_str(), PRINT_REG(send_obj),
+ s->_segMan->getObjectName(send_obj), PRINT_REG(oldReg), PRINT_REG(newReg));
+ }
{
CallsStruct call;
@@ -438,9 +443,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
printf(") at %04x:%04x\n", PRINT_REG(funcp));
#endif // VM_DEBUG_SEND
- if (print_send_action) {
- printf("[invoke selector]\n");
- print_send_action = 0;
+ if (printSendActions) {
+ debug("[invoke selector]\n");
+ printSendActions = false;
}
{
@@ -456,7 +461,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
}
break;
- } // switch (lookup_selector())
+ } // switch (lookupSelector())
framesize -= (2 + argc);
argp += argc + 1;
@@ -477,9 +482,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
_exec_varselectors(s);
- if (s->_executionStack.empty())
- return NULL;
- return &(s->_executionStack.back());
+ return s->_executionStack.empty() ? NULL : &(s->_executionStack.back());
}
static ExecStack *add_exec_stack_varselector(Common::List<ExecStack> &execStack, reg_t objp, int argc, StackPtr argp, Selector selector, const ObjVarRef& address, int origin) {
@@ -565,11 +568,11 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
const KernelFuncWithSignature &kernelFunc = g_sci->getKernel()->_kernelFuncs[kernelFuncNum];
if (kernelFunc.signature
- && !g_sci->getKernel()->signatureMatch(kernelFunc.signature, argc, scriptState.xs->sp + 1)) {
+ && !g_sci->getKernel()->signatureMatch(kernelFunc.signature, argc, s->xs->sp + 1)) {
error("[VM] Invalid arguments to kernel call %x", kernelFuncNum);
}
- reg_t *argv = scriptState.xs->sp + 1;
+ reg_t *argv = s->xs->sp + 1;
if (!kernelFunc.isDummy) {
// Add stack frame to indicate we're executing a callk.
@@ -583,19 +586,26 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
//warning("callk %s", kernelFunc.orig_name.c_str());
- // TODO: SCI2/SCI2.1+ equivalent, once saving/loading works in SCI2/SCI2.1+
- if (g_loadFromLauncher >= 0 && kernelFuncNum == 0x8) {
- // A game is being loaded from the launcher, and kDisplay is called, all initialization has taken
- // place (i.e. menus have been constructed etc). Therefore, inject a kRestoreGame call
- // here, instead of the requested function.
- int saveSlot = g_loadFromLauncher;
- g_loadFromLauncher = -1; // invalidate slot, so that we don't load again
-
- if (saveSlot < 0)
- error("Requested to load invalid save slot"); // should never happen, really
-
- reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
- kRestoreGame(s, 2, restoreArgv);
+ // TODO: SCI2.1 equivalent
+ if (s->loadFromLauncher >= 0 && (
+ (kernelFuncNum == 0x8 && getSciVersion() <= SCI_VERSION_1_1) || // DrawPic
+ (kernelFuncNum == 0x3d && getSciVersion() == SCI_VERSION_2) // GetSaveDir
+ //(kernelFuncNum == 0x28 && getSciVersion() == SCI_VERSION_2_1) // AddPlane
+ )) {
+
+ // A game is being loaded from the launcher, and the game is about to draw something on
+ // screen, hence all initialization has taken place (i.e. menus have been constructed etc).
+ // Therefore, inject a kRestoreGame call here, instead of the requested function.
+ // The restore call is injected here mainly for games which have a menu, as the menu is
+ // constructed when the game starts and is not reconstructed when a saved game is loaded.
+ int saveSlot = s->loadFromLauncher;
+ s->loadFromLauncher = -1; // invalidate slot, so that we don't load again
+
+ if (saveSlot < 0)
+ error("Requested to load invalid save slot"); // should never happen, really
+
+ reg_t restoreArgv[2] = { NULL_REG, make_reg(0, saveSlot) }; // special call (argv[0] is NULL)
+ kRestoreGame(s, 2, restoreArgv);
} else {
// Call kernel function
s->r_acc = kernelFunc.fun(s, argc, argv);
@@ -620,7 +630,7 @@ static void callKernelFunc(EngineState *s, int kernelFuncNum, int argc) {
static void gc_countdown(EngineState *s) {
if (s->gc_countdown-- <= 0) {
- s->gc_countdown = script_gc_interval;
+ s->gc_countdown = s->script_gc_interval;
run_gc(s);
}
}
@@ -708,13 +718,13 @@ void run_vm(EngineState *s, bool restoring) {
StackPtr s_temp; // Temporary stack pointer
int16 opparams[4]; // opcode parameters
- scriptState.restAdjust = s->restAdjust;
+ s->restAdjust = s->restAdjust;
// &rest adjusts the parameter count by this value
// Current execution data:
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
ExecStack *xs_new = NULL;
- Object *obj = s->_segMan->getObject(scriptState.xs->objp);
- Script *local_script = s->_segMan->getScriptIfLoaded(scriptState.xs->local_segment);
+ Object *obj = s->_segMan->getObject(s->xs->objp);
+ Script *local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
int old_execution_stack_base = s->execution_stack_base;
// Used to detect the stack bottom, for "physical" returns
const byte *code_buf = NULL; // (Avoid spurious warning)
@@ -724,25 +734,25 @@ void run_vm(EngineState *s, bool restoring) {
}
if (!restoring)
- s->execution_stack_base = s->_executionStack.size()-1;
+ s->execution_stack_base = s->_executionStack.size() - 1;
#ifndef DISABLE_VALIDATIONS
// Initialize maximum variable count
if (s->script_000->_localsBlock)
- scriptState.variables_max[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.size();
+ s->variables_max[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.size();
else
- scriptState.variables_max[VAR_GLOBAL] = 0;
+ s->variables_max[VAR_GLOBAL] = 0;
#endif
- scriptState.variables_seg[VAR_GLOBAL] = s->script_000->_localsSegment;
- scriptState.variables_seg[VAR_TEMP] = scriptState.variables_seg[VAR_PARAM] = s->_segMan->findSegmentByType(SEG_TYPE_STACK);
- scriptState.variables_base[VAR_TEMP] = scriptState.variables_base[VAR_PARAM] = s->stack_base;
+ s->variables_seg[VAR_GLOBAL] = s->script_000->_localsSegment;
+ s->variables_seg[VAR_TEMP] = s->variables_seg[VAR_PARAM] = s->_segMan->findSegmentByType(SEG_TYPE_STACK);
+ s->variables_base[VAR_TEMP] = s->variables_base[VAR_PARAM] = s->stack_base;
// SCI code reads the zeroth argument to determine argc
if (s->script_000->_localsBlock)
- scriptState.variables_base[VAR_GLOBAL] = scriptState.variables[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.begin();
+ s->variables_base[VAR_GLOBAL] = s->variables[VAR_GLOBAL] = s->script_000->_localsBlock->_locals.begin();
else
- scriptState.variables_base[VAR_GLOBAL] = scriptState.variables[VAR_GLOBAL] = NULL;
+ s->variables_base[VAR_GLOBAL] = s->variables[VAR_GLOBAL] = NULL;
s->_executionStackPosChanged = true; // Force initialization
@@ -750,63 +760,63 @@ void run_vm(EngineState *s, bool restoring) {
int var_type; // See description below
int var_number;
- g_debugState.old_pc_offset = scriptState.xs->addr.pc.offset;
- g_debugState.old_sp = scriptState.xs->sp;
+ g_debugState.old_pc_offset = s->xs->addr.pc.offset;
+ g_debugState.old_sp = s->xs->sp;
if (s->_executionStackPosChanged) {
Script *scr;
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
s->_executionStackPosChanged = false;
- scr = s->_segMan->getScriptIfLoaded(scriptState.xs->addr.pc.segment);
+ scr = s->_segMan->getScriptIfLoaded(s->xs->addr.pc.segment);
if (!scr) {
// No script? Implicit return via fake instruction buffer
- warning("Running on non-existant script in segment %x", scriptState.xs->addr.pc.segment);
+ warning("Running on non-existant script in segment %x", s->xs->addr.pc.segment);
code_buf = _fake_return_buffer;
#ifndef DISABLE_VALIDATIONS
code_buf_size = 2;
#endif
- scriptState.xs->addr.pc.offset = 1;
+ s->xs->addr.pc.offset = 1;
scr = NULL;
obj = NULL;
} else {
- obj = s->_segMan->getObject(scriptState.xs->objp);
+ obj = s->_segMan->getObject(s->xs->objp);
code_buf = scr->_buf;
#ifndef DISABLE_VALIDATIONS
- code_buf_size = scr->_bufSize;
+ code_buf_size = scr->getBufSize();
#endif
- local_script = s->_segMan->getScriptIfLoaded(scriptState.xs->local_segment);
+ local_script = s->_segMan->getScriptIfLoaded(s->xs->local_segment);
if (!local_script) {
- warning("Could not find local script from segment %x", scriptState.xs->local_segment);
+ warning("Could not find local script from segment %x", s->xs->local_segment);
local_script = NULL;
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = NULL;
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL;
#ifndef DISABLE_VALIDATIONS
- scriptState.variables_max[VAR_LOCAL] = 0;
+ s->variables_max[VAR_LOCAL] = 0;
#endif
} else {
- scriptState.variables_seg[VAR_LOCAL] = local_script->_localsSegment;
+ s->variables_seg[VAR_LOCAL] = local_script->_localsSegment;
if (local_script->_localsBlock)
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = local_script->_localsBlock->_locals.begin();
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = local_script->_localsBlock->_locals.begin();
else
- scriptState.variables_base[VAR_LOCAL] = scriptState.variables[VAR_LOCAL] = NULL;
+ s->variables_base[VAR_LOCAL] = s->variables[VAR_LOCAL] = NULL;
#ifndef DISABLE_VALIDATIONS
if (local_script->_localsBlock)
- scriptState.variables_max[VAR_LOCAL] = local_script->_localsBlock->_locals.size();
+ s->variables_max[VAR_LOCAL] = local_script->_localsBlock->_locals.size();
else
- scriptState.variables_max[VAR_LOCAL] = 0;
- scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp;
- scriptState.variables_max[VAR_PARAM] = scriptState.xs->argc + 1;
+ s->variables_max[VAR_LOCAL] = 0;
+ s->variables_max[VAR_TEMP] = s->xs->sp - s->xs->fp;
+ s->variables_max[VAR_PARAM] = s->xs->argc + 1;
#endif
}
- scriptState.variables[VAR_TEMP] = scriptState.xs->fp;
- scriptState.variables[VAR_PARAM] = scriptState.xs->variables_argp;
+ s->variables[VAR_TEMP] = s->xs->fp;
+ s->variables[VAR_PARAM] = s->xs->variables_argp;
}
}
- if (script_abort_flag || g_engine->shouldQuit())
+ if (s->script_abort_flag || g_engine->shouldQuit())
return; // Emergency
// Debug if this has been requested:
@@ -821,18 +831,20 @@ void run_vm(EngineState *s, bool restoring) {
}
#ifndef DISABLE_VALIDATIONS
- if (scriptState.xs->sp < scriptState.xs->fp)
- error("run_vm(): stack underflow");
+ if (s->xs->sp < s->xs->fp)
+ error("run_vm(): stack underflow, sp: %04x:%04x, fp: %04x:%04x",
+ PRINT_REG(*s->xs->sp), PRINT_REG(*s->xs->fp));
- scriptState.variables_max[VAR_TEMP] = scriptState.xs->sp - scriptState.xs->fp;
+ s->variables_max[VAR_TEMP] = s->xs->sp - s->xs->fp;
- if (scriptState.xs->addr.pc.offset >= code_buf_size)
- error("run_vm(): program counter gone astray");
+ if (s->xs->addr.pc.offset >= code_buf_size)
+ error("run_vm(): program counter gone astray, addr: %d, code buffer size: %d",
+ s->xs->addr.pc.offset, code_buf_size);
#endif
// Get opcode
byte extOpcode;
- scriptState.xs->addr.pc.offset += readPMachineInstruction(code_buf + scriptState.xs->addr.pc.offset, extOpcode, opparams);
+ s->xs->addr.pc.offset += readPMachineInstruction(code_buf + s->xs->addr.pc.offset, extOpcode, opparams);
const byte opcode = extOpcode >> 1;
switch (opcode) {
@@ -1063,16 +1075,16 @@ void run_vm(EngineState *s, bool restoring) {
case op_bt: // 0x17 (23)
if (s->r_acc.offset || s->r_acc.segment)
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_bnt: // 0x18 (24)
if (!(s->r_acc.offset || s->r_acc.segment))
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_jmp: // 0x19 (25)
- scriptState.xs->addr.pc.offset += opparams[0];
+ s->xs->addr.pc.offset += opparams[0];
break;
case op_ldi: // 0x1a (26)
@@ -1088,34 +1100,34 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_toss: // 0x1d (29)
- scriptState.xs->sp--;
+ s->xs->sp--;
break;
case op_dup: // 0x1e (30)
- r_temp = scriptState.xs->sp[-1];
+ r_temp = s->xs->sp[-1];
PUSH32(r_temp);
break;
case op_link: // 0x1f (31)
for (int i = 0; i < opparams[0]; i++)
- scriptState.xs->sp[i] = NULL_REG;
- scriptState.xs->sp += opparams[0];
+ s->xs->sp[i] = NULL_REG;
+ s->xs->sp += opparams[0];
break;
case op_call: { // 0x20 (32)
int argc = (opparams[1] >> 1) // Given as offset, but we need count
- + 1 + scriptState.restAdjust;
- StackPtr call_base = scriptState.xs->sp - argc;
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
-
- xs_new = add_exec_stack_entry(s->_executionStack, make_reg(scriptState.xs->addr.pc.segment,
- scriptState.xs->addr.pc.offset + opparams[0]),
- scriptState.xs->sp, scriptState.xs->objp,
- (validate_arithmetic(*call_base)) + scriptState.restAdjust,
- call_base, NULL_SELECTOR, scriptState.xs->objp,
- s->_executionStack.size()-1, scriptState.xs->local_segment);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
- scriptState.xs->sp = call_base;
+ + 1 + s->restAdjust;
+ StackPtr call_base = s->xs->sp - argc;
+ s->xs->sp[1].offset += s->restAdjust;
+
+ xs_new = add_exec_stack_entry(s->_executionStack, make_reg(s->xs->addr.pc.segment,
+ s->xs->addr.pc.offset + opparams[0]),
+ s->xs->sp, s->xs->objp,
+ (validate_arithmetic(*call_base)) + s->restAdjust,
+ call_base, NULL_SELECTOR, s->xs->objp,
+ s->_executionStack.size()-1, s->xs->local_segment);
+ s->restAdjust = 0; // Used up the &rest adjustment
+ s->xs->sp = call_base;
s->_executionStackPosChanged = true;
break;
@@ -1124,23 +1136,23 @@ void run_vm(EngineState *s, bool restoring) {
case op_callk: { // 0x21 (33)
gc_countdown(s);
- scriptState.xs->sp -= (opparams[1] >> 1) + 1;
+ s->xs->sp -= (opparams[1] >> 1) + 1;
bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
if (!oldScriptHeader) {
- scriptState.xs->sp -= scriptState.restAdjust;
- s->restAdjust = 0; // We just used up the scriptState.restAdjust, remember?
+ s->xs->sp -= s->restAdjust;
+ s->restAdjust = 0; // We just used up the s->restAdjust, remember?
}
- int argc = validate_arithmetic(scriptState.xs->sp[0]);
+ int argc = validate_arithmetic(s->xs->sp[0]);
if (!oldScriptHeader)
- argc += scriptState.restAdjust;
+ argc += s->restAdjust;
callKernelFunc(s, opparams[0], argc);
if (!oldScriptHeader)
- scriptState.restAdjust = s->restAdjust;
+ s->restAdjust = s->restAdjust;
// Calculate xs again: The kernel function might
// have spawned a new VM
@@ -1151,27 +1163,27 @@ void run_vm(EngineState *s, bool restoring) {
}
case op_callb: // 0x22 (34)
- temp = ((opparams[1] >> 1) + scriptState.restAdjust + 1);
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= temp;
-
- scriptState.xs->sp[0].offset += scriptState.restAdjust;
- xs_new = execute_method(s, 0, opparams[0], s_temp, scriptState.xs->objp,
- scriptState.xs->sp[0].offset, scriptState.xs->sp);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
+ temp = ((opparams[1] >> 1) + s->restAdjust + 1);
+ s_temp = s->xs->sp;
+ s->xs->sp -= temp;
+
+ s->xs->sp[0].offset += s->restAdjust;
+ xs_new = execute_method(s, 0, opparams[0], s_temp, s->xs->objp,
+ s->xs->sp[0].offset, s->xs->sp);
+ s->restAdjust = 0; // Used up the &rest adjustment
if (xs_new) // in case of error, keep old stack
s->_executionStackPosChanged = true;
break;
case op_calle: // 0x23 (35)
- temp = ((opparams[2] >> 1) + scriptState.restAdjust + 1);
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= temp;
+ temp = ((opparams[2] >> 1) + s->restAdjust + 1);
+ s_temp = s->xs->sp;
+ s->xs->sp -= temp;
- scriptState.xs->sp[0].offset += scriptState.restAdjust;
- xs_new = execute_method(s, opparams[0], opparams[1], s_temp, scriptState.xs->objp,
- scriptState.xs->sp[0].offset, scriptState.xs->sp);
- scriptState.restAdjust = 0; // Used up the &rest adjustment
+ s->xs->sp[0].offset += s->restAdjust;
+ xs_new = execute_method(s, opparams[0], opparams[1], s_temp, s->xs->objp,
+ s->xs->sp[0].offset, s->xs->sp);
+ s->restAdjust = 0; // Used up the &rest adjustment
if (xs_new) // in case of error, keep old stack
s->_executionStackPosChanged = true;
@@ -1179,17 +1191,17 @@ void run_vm(EngineState *s, bool restoring) {
case op_ret: // 0x24 (36)
do {
- StackPtr old_sp2 = scriptState.xs->sp;
- StackPtr old_fp = scriptState.xs->fp;
+ StackPtr old_sp2 = s->xs->sp;
+ StackPtr old_fp = s->xs->fp;
ExecStack *old_xs = &(s->_executionStack.back());
- if ((int)s->_executionStack.size()-1 == s->execution_stack_base) { // Have we reached the base?
+ if ((int)s->_executionStack.size() - 1 == s->execution_stack_base) { // Have we reached the base?
s->execution_stack_base = old_execution_stack_base; // Restore stack base
s->_executionStack.pop_back();
s->_executionStackPosChanged = true;
- s->restAdjust = scriptState.restAdjust; // Update &rest
+ s->restAdjust = s->restAdjust; // Update &rest
return; // "Hard" return
}
@@ -1205,33 +1217,33 @@ void run_vm(EngineState *s, bool restoring) {
// Not reached the base, so let's do a soft return
s->_executionStack.pop_back();
s->_executionStackPosChanged = true;
- scriptState.xs = &(s->_executionStack.back());
+ s->xs = &(s->_executionStack.back());
- if (scriptState.xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
- || scriptState.xs->type != EXEC_STACK_TYPE_CALL) {
- scriptState.xs->sp = old_sp2;
- scriptState.xs->fp = old_fp;
+ if (s->xs->sp == CALL_SP_CARRY // Used in sends to 'carry' the stack pointer
+ || s->xs->type != EXEC_STACK_TYPE_CALL) {
+ s->xs->sp = old_sp2;
+ s->xs->fp = old_fp;
}
- } while (scriptState.xs->type == EXEC_STACK_TYPE_VARSELECTOR);
+ } while (s->xs->type == EXEC_STACK_TYPE_VARSELECTOR);
// Iterate over all varselector accesses
s->_executionStackPosChanged = true;
- xs_new = scriptState.xs;
+ xs_new = s->xs;
break;
case op_send: // 0x25 (37)
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[0] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[0] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
+ s->xs->sp[1].offset += s->restAdjust;
xs_new = send_selector(s, s->r_acc, s->r_acc, s_temp,
- (int)(opparams[0] >> 1) + (uint16)scriptState.restAdjust, scriptState.xs->sp);
+ (int)(opparams[0] >> 1) + (uint16)s->restAdjust, s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
break;
@@ -1242,7 +1254,7 @@ void run_vm(EngineState *s, bool restoring) {
case op_class: // 0x28 (40)
s->r_acc = s->_segMan->getClassAddress((unsigned)opparams[0], SCRIPT_GET_LOCK,
- scriptState.xs->addr.pc);
+ s->xs->addr.pc);
break;
case 0x29: // (41)
@@ -1250,48 +1262,48 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_self: // 0x2a (42)
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[0] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[0] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
- xs_new = send_selector(s, scriptState.xs->objp, scriptState.xs->objp,
- s_temp, (int)(opparams[0] >> 1) + (uint16)scriptState.restAdjust,
- scriptState.xs->sp);
+ s->xs->sp[1].offset += s->restAdjust;
+ xs_new = send_selector(s, s->xs->objp, s->xs->objp,
+ s_temp, (int)(opparams[0] >> 1) + (uint16)s->restAdjust,
+ s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
break;
case op_super: // 0x2b (43)
- r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, scriptState.xs->addr.pc);
+ r_temp = s->_segMan->getClassAddress(opparams[0], SCRIPT_GET_LOAD, s->xs->addr.pc);
if (!r_temp.segment)
error("[VM]: Invalid superclass in object");
else {
- s_temp = scriptState.xs->sp;
- scriptState.xs->sp -= ((opparams[1] >> 1) + scriptState.restAdjust); // Adjust stack
+ s_temp = s->xs->sp;
+ s->xs->sp -= ((opparams[1] >> 1) + s->restAdjust); // Adjust stack
- scriptState.xs->sp[1].offset += scriptState.restAdjust;
- xs_new = send_selector(s, r_temp, scriptState.xs->objp, s_temp,
- (int)(opparams[1] >> 1) + (uint16)scriptState.restAdjust,
- scriptState.xs->sp);
+ s->xs->sp[1].offset += s->restAdjust;
+ xs_new = send_selector(s, r_temp, s->xs->objp, s_temp,
+ (int)(opparams[1] >> 1) + (uint16)s->restAdjust,
+ s->xs->sp);
- if (xs_new && xs_new != scriptState.xs)
+ if (xs_new && xs_new != s->xs)
s->_executionStackPosChanged = true;
- scriptState.restAdjust = 0;
+ s->restAdjust = 0;
}
break;
case op_rest: // 0x2c (44)
temp = (uint16) opparams[0]; // First argument
- scriptState.restAdjust = MAX<int16>(scriptState.xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
+ s->restAdjust = MAX<int16>(s->xs->argc - temp + 1, 0); // +1 because temp counts the paramcount while argc doesn't
- for (; temp <= scriptState.xs->argc; temp++)
- PUSH32(scriptState.xs->variables_argp[temp]);
+ for (; temp <= s->xs->argc; temp++)
+ PUSH32(s->xs->variables_argp[temp]);
break;
@@ -1300,8 +1312,8 @@ void run_vm(EngineState *s, bool restoring) {
var_number = temp & 0x03; // Get variable type
// Get variable block offset
- r_temp.segment = scriptState.variables_seg[var_number];
- r_temp.offset = scriptState.variables[var_number] - scriptState.variables_base[var_number];
+ r_temp.segment = s->variables_seg[var_number];
+ r_temp.offset = s->variables[var_number] - s->variables_base[var_number];
if (temp & 0x08) // Add accumulator offset if requested
r_temp.offset += signed_validate_arithmetic(s->r_acc);
@@ -1314,7 +1326,7 @@ void run_vm(EngineState *s, bool restoring) {
case op_selfID: // 0x2e (46)
- s->r_acc = scriptState.xs->objp;
+ s->r_acc = s->xs->objp;
break;
case 0x2f: // (47)
@@ -1382,17 +1394,17 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_lofsa: // 0x39 (57)
- s->r_acc.segment = scriptState.xs->addr.pc.segment;
+ s->r_acc.segment = s->xs->addr.pc.segment;
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- s->r_acc.offset = opparams[0] + local_script->_scriptSize;
+ s->r_acc.offset = opparams[0] + local_script->getScriptSize();
break;
case SCI_VERSION_1_MIDDLE:
s->r_acc.offset = opparams[0];
break;
default:
- s->r_acc.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ s->r_acc.offset = s->xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
@@ -1404,17 +1416,17 @@ void run_vm(EngineState *s, bool restoring) {
break;
case op_lofss: // 0x3a (58)
- r_temp.segment = scriptState.xs->addr.pc.segment;
+ r_temp.segment = s->xs->addr.pc.segment;
switch (g_sci->_features->detectLofsType()) {
case SCI_VERSION_1_1:
- r_temp.offset = opparams[0] + local_script->_scriptSize;
+ r_temp.offset = opparams[0] + local_script->getScriptSize();
break;
case SCI_VERSION_1_MIDDLE:
r_temp.offset = opparams[0];
break;
default:
- r_temp.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ r_temp.offset = s->xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
@@ -1440,10 +1452,10 @@ void run_vm(EngineState *s, bool restoring) {
case op_pushSelf: // 0x3e (62)
if (!(extOpcode & 1)) {
- PUSH32(scriptState.xs->objp);
+ PUSH32(s->xs->objp);
} else {
// Debug opcode op_file, skip null-terminated string (file name)
- while (code_buf[scriptState.xs->addr.pc.offset++]) ;
+ while (code_buf[s->xs->addr.pc.offset++]) ;
}
break;
@@ -1657,16 +1669,16 @@ void run_vm(EngineState *s, bool restoring) {
} // switch (opcode)
if (s->_executionStackPosChanged) // Force initialization
- scriptState.xs = xs_new;
+ s->xs = xs_new;
//#ifndef DISABLE_VALIDATIONS
- if (scriptState.xs != &(s->_executionStack.back())) {
+ if (s->xs != &(s->_executionStack.back())) {
warning("xs is stale (%p vs %p); last command was %02x",
- (void *)scriptState.xs, (void *)&(s->_executionStack.back()),
+ (void *)s->xs, (void *)&(s->_executionStack.back()),
opcode);
}
//#endif
- ++script_step_counter;
+ ++s->script_step_counter;
}
}
@@ -1676,17 +1688,16 @@ static void _init_stack_base_with_selector(EngineState *s, Selector selector) {
}
static EngineState *_game_run(EngineState *&s) {
- EngineState *successor = NULL;
- int game_is_finished = 0;
+ bool restoring = false;
if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup))
g_sci->getSciDebugger()->attach();
do {
s->_executionStackPosChanged = false;
- run_vm(s, successor ? true : false);
+ run_vm(s, restoring);
if (s->restarting_flags & SCI_GAME_IS_RESTARTING_NOW) { // Restart was requested?
- successor = NULL;
+ restoring = false;
s->_executionStack.clear();
s->_executionStackPosChanged = false;
@@ -1700,17 +1711,15 @@ static EngineState *_game_run(EngineState *&s) {
send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base);
- script_abort_flag = 0;
- s->restarting_flags = SCI_GAME_WAS_RESTARTED | SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE;
+ s->script_abort_flag = 0;
+ s->restarting_flags = SCI_GAME_WAS_RESTARTED;
} else {
- successor = s->successor;
- if (successor) {
+ restoring = s->restoring;
+ if (restoring) {
game_exit(s);
- delete s;
- s = successor;
-
- if (script_abort_flag == 2) {
+ s->restoring = false;
+ if (s->script_abort_flag == 2) {
debugC(2, kDebugLevelVM, "Restarting with replay()");
s->_executionStack.clear(); // Restart with replay
@@ -1719,12 +1728,12 @@ static EngineState *_game_run(EngineState *&s) {
send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base);
}
- script_abort_flag = 0;
+ s->script_abort_flag = 0;
} else
- game_is_finished = 1;
+ break; // exit loop
}
- } while (!game_is_finished);
+ } while (true);
return s;
}
@@ -1732,7 +1741,7 @@ static EngineState *_game_run(EngineState *&s) {
int game_run(EngineState **_s) {
EngineState *s = *_s;
- debugC(2, kDebugLevelVM, "Calling %s::play()", s->_gameId.c_str());
+ debugC(2, kDebugLevelVM, "Calling %s::play()", g_sci->getGameID());
_init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.play); // Call the play selector
// Now: Register the first element on the execution stack-
@@ -1750,28 +1759,18 @@ int game_run(EngineState **_s) {
return 0;
}
-void quit_vm() {
- script_abort_flag = 1; // Terminate VM
+void quit_vm(EngineState *s) {
+ s->script_abort_flag = 1; // Terminate VM
g_debugState.seeking = kDebugSeekNothing;
g_debugState.runningStep = 0;
}
-void shrink_execution_stack(EngineState *s, uint size) {
- assert(s->_executionStack.size() >= size);
- Common::List<ExecStack>::iterator iter;
- iter = s->_executionStack.begin();
- for (uint i = 0; i < size; ++i)
- ++iter;
- s->_executionStack.erase(iter, s->_executionStack.end());
-}
-
-reg_t* ObjVarRef::getPointer(SegManager *segMan) const {
+reg_t *ObjVarRef::getPointer(SegManager *segMan) const {
Object *o = segMan->getObject(obj);
- if (!o) return 0;
- return &(o->_variables[varindex]);
+ return o ? &o->getVariableRef(varindex) : 0;
}
-reg_t* ExecStack::getVarPointer(SegManager *segMan) const {
+reg_t *ExecStack::getVarPointer(SegManager *segMan) const {
assert(type == EXEC_STACK_TYPE_VARSELECTOR);
return addr.varp.getPointer(segMan);
}
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 8e40fed818..67a6bd0dc3 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -43,44 +43,9 @@ class ResourceManager;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
-/** Maximum number of calls residing on the stack */
-#define SCRIPT_MAX_EXEC_STACK 256
-/** Maximum number of entries in the class table */
-#define SCRIPT_MAX_CLASSTABLE_SIZE 256
-/** Maximum number of cloned objects on the heap */
-#define SCRIPT_MAX_CLONES 256
-
-
-/** Object-relative offset of the selector area inside a script */
-#define SCRIPT_SELECTOR_OFFSET 8 -8
-
-/** Object-relative offset of the pointer to the underlying script's local variables */
-#define SCRIPT_LOCALVARPTR_OFFSET 2 -8
-
-/** Object-relative offset of the selector counter */
-#define SCRIPT_SELECTORCTR_OFFSET 6 -8
-
-/** Object-relative offset of the offset of the function area */
-#define SCRIPT_FUNCTAREAPTR_OFFSET 4 -8
-
-/** Offset that has to be added to the function area pointer */
-#define SCRIPT_FUNCTAREAPTR_MAGIC 8 -8
-
-/** Offset of the name pointer */
-#define SCRIPT_NAME_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 14 -8 : 16)
-
-/** Object-relative offset of the -info- selector */
-#define SCRIPT_INFO_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 12 -8 : 14)
-
-/** Flag fo the -info- selector */
-#define SCRIPT_INFO_CLONE 0x0001
-
-/** Flag for the -info- selector */
-#define SCRIPT_INFO_CLASS 0x8000
-
-
/** Magical object identifier */
#define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234
+
/** Offset of this identifier */
#define SCRIPT_OBJECT_MAGIC_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? -8 : 0)
@@ -89,13 +54,10 @@ class ResourceManager;
#define SCRIPT_SUPERCLASS_OFFSET (getSciVersion() < SCI_VERSION_1_1 ? 10 -8 : 12)
-/** Magic adjustment value for lofsa and lofss */
-#define SCRIPT_LOFS_MAGIC 3
-
/** Stack pointer value: Use predecessor's value */
#define CALL_SP_CARRY NULL
-/** Types of selectors as returned by lookup_selector() below. */
+/** Types of selectors as returned by lookupSelector() below. */
enum SelectorType {
kSelectorNone = 0,
kSelectorVariable,
@@ -195,7 +157,9 @@ struct SelectorCache {
// Used for auto detection purposes
Selector overlay; ///< Used to determine if a game is using old gfx functions or not
- Selector setCursor; ///< For cursor semantics autodetection
+
+ // SCI1.1 Mac icon bar selectors
+ Selector iconIndex; ///< Used to index icon bar objects
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
@@ -260,41 +224,11 @@ enum {
VAR_PARAM = 3
};
-/**
- * Structure for storing the current internal state of the VM.
- */
-struct ScriptState {
- ExecStack *xs;
- int16 restAdjust;
- reg_t *variables[4]; ///< global, local, temp, param, as immediate pointers
- reg_t *variables_base[4]; ///< Used for referencing VM ops
- SegmentId variables_seg[4]; ///< Same as above, contains segment IDs
- int variables_max[4]; ///< Max. values for all variables
-};
-
-/**
- * The current internal state of the VM.
- */
-extern ScriptState scriptState;
-
-/**
- * Set this to 1 to abort script execution immediately. Aborting will
- * leave the debug exec stack intact.
- * Set it to 2 to force a replay afterwards.
- */
-extern int script_abort_flag;
-
/** Number of kernel calls in between gcs; should be < 50000 */
enum {
GC_INTERVAL = 32768
};
-/** Initially GC_DELAY, can be set at runtime */
-extern int script_gc_interval;
-
-/** Number of steps executed */
-extern int script_step_counter;
-
/**
* Executes function pubfunct of the specified script.
@@ -376,7 +310,7 @@ int script_init_engine(EngineState *);
* kSelectorMethod if the selector represents a
* method
*/
-SelectorType lookup_selector(SegManager *segMan, reg_t obj, Selector selectorid,
+SelectorType lookupSelector(SegManager *segMan, reg_t obj, Selector selectorid,
ObjVarRef *varp, reg_t *fptr);
/**
@@ -466,13 +400,7 @@ int game_exit(EngineState *s);
/**
* Instructs the virtual machine to abort
*/
-void quit_vm();
-
-/**
- * Shrink execution stack to size.
- * Contains an assert it is not already smaller.
- */
-void shrink_execution_stack(EngineState *s, uint size);
+void quit_vm(EngineState *s);
/**
* Read a PMachine instruction from a memory buffer and return its length.
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 53f4675f56..c3be22b143 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -319,8 +319,6 @@ sciEvent SciEvent::get(unsigned int mask) {
//sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 };
sciEvent event = { 0, 0, 0, 0 };
- // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
-
// Update the screen here, since it's called very often
g_system->updateScreen();
@@ -389,7 +387,6 @@ void SciEvent::sleep(uint32 msecs) {
while (true) {
// let backend process events and update the screen
get(SCI_EVENT_PEEK);
- // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position
time = g_system->getMillis();
if (time + 10 < wakeup_time) {
g_system->delayMillis(10);
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index 71c7b7dd7f..c201b2cfb7 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -92,10 +92,10 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
}
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (!(signal & kSignalFrozen)) {
// Call .doit method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
+ invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.doit, kContinueOnInvalidSelector, argc, argv, 0);
// Lookup node again, since the nodetable it was in may have been reallocated
curNode = _s->_segMan->lookupNode(curAddress);
}
@@ -109,7 +109,15 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
}
bool sortHelper(const AnimateEntry* entry1, const AnimateEntry* entry2) {
- return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y);
+ if (entry1->y == entry2->y) {
+ // if both y and z are the same, use the order we were given originally
+ // this is needed for special cases like iceman room 35
+ if (entry1->z == entry2->z)
+ return entry1->givenOrderNo < entry2->givenOrderNo;
+ else
+ return entry1->z < entry2->z;
+ }
+ return entry1->y < entry2->y;
}
void GfxAnimate::makeSortedList(List *list) {
@@ -156,21 +164,22 @@ void GfxAnimate::makeSortedList(List *list) {
listEntry->object = curObject;
// Get data from current object
- listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, SELECTOR(view));
- listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(loop));
- listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(cel));
- listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, SELECTOR(palette));
- listEntry->x = GET_SEL32V(_s->_segMan, curObject, SELECTOR(x));
- listEntry->y = GET_SEL32V(_s->_segMan, curObject, SELECTOR(y));
- listEntry->z = GET_SEL32V(_s->_segMan, curObject, SELECTOR(z));
- listEntry->priority = GET_SEL32V(_s->_segMan, curObject, SELECTOR(priority));
- listEntry->signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ listEntry->givenOrderNo = listNr;
+ listEntry->viewId = readSelectorValue(_s->_segMan, curObject, SELECTOR(view));
+ listEntry->loopNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(loop));
+ listEntry->celNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(cel));
+ listEntry->paletteNo = readSelectorValue(_s->_segMan, curObject, SELECTOR(palette));
+ listEntry->x = readSelectorValue(_s->_segMan, curObject, SELECTOR(x));
+ listEntry->y = readSelectorValue(_s->_segMan, curObject, SELECTOR(y));
+ listEntry->z = readSelectorValue(_s->_segMan, curObject, SELECTOR(z));
+ listEntry->priority = readSelectorValue(_s->_segMan, curObject, SELECTOR(priority));
+ listEntry->signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if (getSciVersion() >= SCI_VERSION_1_1) {
// Cel scaling
- listEntry->scaleSignal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleSignal));
+ listEntry->scaleSignal = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleSignal));
if (listEntry->scaleSignal & kScaleSignalDoScaling) {
- listEntry->scaleX = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleX));
- listEntry->scaleY = GET_SEL32V(_s->_segMan, curObject, SELECTOR(scaleY));
+ listEntry->scaleX = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleX));
+ listEntry->scaleY = readSelectorValue(_s->_segMan, curObject, SELECTOR(scaleY));
} else {
listEntry->scaleX = 128;
listEntry->scaleY = 128;
@@ -219,11 +228,11 @@ void GfxAnimate::fill(byte &old_picNotValid) {
// adjust loop and cel, if any of those is invalid
if (listEntry->loopNo >= view->getLoopCount()) {
listEntry->loopNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), listEntry->loopNo);
}
if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) {
listEntry->celNo = 0;
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), listEntry->celNo);
}
// Create rect according to coordinates and given cel
@@ -232,17 +241,17 @@ void GfxAnimate::fill(byte &old_picNotValid) {
} else {
view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsLeft), listEntry->celRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsTop), listEntry->celRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsRight), listEntry->celRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(nsBottom), listEntry->celRect.bottom);
signal = listEntry->signal;
// Calculate current priority according to y-coordinate
if (!(signal & kSignalFixedPriority)) {
listEntry->priority = _ports->kernelCoordinateToPriority(listEntry->y);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(priority), listEntry->priority);
}
if (signal & kSignalNoUpdate) {
@@ -282,14 +291,14 @@ void GfxAnimate::update() {
if (signal & kSignalNoUpdate) {
if (!(signal & kSignalRemoveView)) {
- bitsHandle = GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits));
+ bitsHandle = readSelector(_s->_segMan, curObject, SELECTOR(underBits));
if (_screen->_picNotValid != 1) {
_paint16->bitsRestore(bitsHandle);
listEntry->showBitsFlag = true;
} else {
_paint16->bitsFree(bitsHandle);
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
signal &= 0xFFFF ^ kSignalForceUpdate;
signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF;
@@ -339,7 +348,7 @@ void GfxAnimate::update() {
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
else
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
}
listEntry->signal = signal;
}
@@ -387,7 +396,7 @@ void GfxAnimate::drawCels() {
if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) {
// Save background
bitsHandle = _paint16->bitsSave(listEntry->celRect, GFX_SCREEN_MASK_ALL);
- PUT_SEL32(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
+ writeSelector(_s->_segMan, curObject, SELECTOR(underBits), bitsHandle);
// draw corresponding cel
_paint16->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo, listEntry->scaleX, listEntry->scaleY);
@@ -423,10 +432,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) ||
(!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) {
- lsRect.left = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft));
- lsRect.top = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop));
- lsRect.right = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight));
- lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom));
+ lsRect.left = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft));
+ lsRect.top = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop));
+ lsRect.right = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight));
+ lsRect.bottom = readSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom));
workerRect = lsRect;
workerRect.clip(listEntry->celRect);
@@ -438,10 +447,10 @@ void GfxAnimate::updateScreen(byte oldPicNotValid) {
_paint16->bitsShow(lsRect);
workerRect = listEntry->celRect;
}
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsLeft), workerRect.left);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsTop), workerRect.top);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsRight), workerRect.right);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(lsBottom), workerRect.bottom);
_paint16->bitsShow(workerRect);
if (signal & kSignalHidden) {
@@ -472,7 +481,7 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
signal = listEntry->signal;
// Finally update signal
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(signal), signal);
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(signal), signal);
listIterator++;
}
@@ -481,16 +490,16 @@ void GfxAnimate::restoreAndDelete(int argc, reg_t *argv) {
listEntry = *listIterator;
curObject = listEntry->object;
// We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal
- signal = GET_SEL32V(_s->_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_s->_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) {
- _paint16->bitsRestore(GET_SEL32(_s->_segMan, curObject, SELECTOR(underBits)));
- PUT_SEL32V(_s->_segMan, curObject, SELECTOR(underBits), 0);
+ _paint16->bitsRestore(readSelector(_s->_segMan, curObject, SELECTOR(underBits)));
+ writeSelectorValue(_s->_segMan, curObject, SELECTOR(underBits), 0);
}
if (signal & kSignalDisposeMe) {
// Call .delete_ method of that object
- invoke_selector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
+ invokeSelector(_s, curObject, g_sci->getKernel()->_selectorCache.delete_, kContinueOnInvalidSelector, argc, argv, 0);
}
listIterator--;
}
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 2cc59b1767..706b7182cf 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -40,7 +40,7 @@ enum ViewSignals {
kSignalAlwaysUpdate = 0x0020,
kSignalForceUpdate = 0x0040,
kSignalRemoveView = 0x0080,
- kSignalFrozen = 0x0100,
+ kSignalFrozen = 0x0100, // I got frozen today!!
kSignalExtraActor = 0x0200, // unused by us, defines all actors that may be included into the background if speed is too slow
kSignalHitObstacle = 0x0400, // used in the actor movement code by kDoBresen()
kSignalDoesntTurn = 0x0800, // used by _k_dirloop() to determine if an actor can turn or not
@@ -57,6 +57,7 @@ enum ViewScaleSignals {
};
struct AnimateEntry {
+ int16 givenOrderNo;
reg_t object;
GuiResourceId viewId;
int16 loopNo;
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 36dd2d4aed..3102edc2fa 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -79,12 +79,12 @@ bool GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &c
while (curNode) {
curObject = curNode->value;
if (curObject != checkObject) {
- signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
+ signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
if ((signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate)) == 0) {
- curRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
- curRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
- curRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
- curRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
+ curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ curRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
// Check if curRect is within checkRect
// TODO: This check is slightly odd, because it means that a rect is not contained
// in itself. It may very well be that the original SCI engine did it just
@@ -115,29 +115,29 @@ uint16 GfxCompare::kernelOnControl(byte screenMask, const Common::Rect &rect) {
void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
GfxView *view = NULL;
Common::Rect celRect(0, 0);
- GuiResourceId viewId = (GuiResourceId)GET_SEL32V(_segMan, objectReference, SELECTOR(view));
+ GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
return;
- int16 loopNo = GET_SEL32V(_segMan, objectReference, SELECTOR(loop));
- int16 celNo = GET_SEL32V(_segMan, objectReference, SELECTOR(cel));
- int16 x = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(x));
- int16 y = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(y));
+ int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop));
+ int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel));
+ int16 x = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(x));
+ int16 y = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(y));
int16 z = 0;
if (_kernel->_selectorCache.z > -1)
- z = (int16)GET_SEL32V(_segMan, objectReference, SELECTOR(z));
+ z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z));
// now get cel rectangle
view = _cache->getView(viewId);
view->getCelRect(loopNo, celNo, x, y, z, &celRect);
- if (lookup_selector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
- PUT_SEL32V(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
+ if (lookupSelector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) {
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsLeft), celRect.left);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsRight), celRect.right);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsTop), celRect.top);
+ writeSelectorValue(_segMan, objectReference, SELECTOR(nsBottom), celRect.bottom);
}
}
@@ -147,10 +147,10 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
uint16 signal, controlMask;
bool result;
- checkRect.left = GET_SEL32V(_segMan, curObject, SELECTOR(brLeft));
- checkRect.top = GET_SEL32V(_segMan, curObject, SELECTOR(brTop));
- checkRect.right = GET_SEL32V(_segMan, curObject, SELECTOR(brRight));
- checkRect.bottom = GET_SEL32V(_segMan, curObject, SELECTOR(brBottom));
+ checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
if (!checkRect.isValidRect()) { // can occur in Iceman - HACK? TODO: is this really occuring in sierra sci? check this
warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom);
@@ -159,8 +159,8 @@ bool GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
adjustedRect = _coordAdjuster->onControl(checkRect);
- signal = GET_SEL32V(_segMan, curObject, SELECTOR(signal));
- controlMask = GET_SEL32V(_segMan, curObject, SELECTOR(illegalBits));
+ signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
+ controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits));
result = (isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask) ? false : true;
if ((result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) {
List *list = _segMan->lookupList(listReference);
@@ -183,14 +183,14 @@ bool GfxCompare::kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo,
}
void GfxCompare::kernelBaseSetter(reg_t object) {
- if (lookup_selector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
- int16 x = GET_SEL32V(_segMan, object, SELECTOR(x));
- int16 y = GET_SEL32V(_segMan, object, SELECTOR(y));
- int16 z = (_kernel->_selectorCache.z > -1) ? GET_SEL32V(_segMan, object, SELECTOR(z)) : 0;
- int16 yStep = GET_SEL32V(_segMan, object, SELECTOR(yStep));
- GuiResourceId viewId = GET_SEL32V(_segMan, object, SELECTOR(view));
- int16 loopNo = GET_SEL32V(_segMan, object, SELECTOR(loop));
- int16 celNo = GET_SEL32V(_segMan, object, SELECTOR(cel));
+ if (lookupSelector(_segMan, object, _kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
+ int16 x = readSelectorValue(_segMan, object, SELECTOR(x));
+ int16 y = readSelectorValue(_segMan, object, SELECTOR(y));
+ int16 z = (_kernel->_selectorCache.z > -1) ? readSelectorValue(_segMan, object, SELECTOR(z)) : 0;
+ int16 yStep = readSelectorValue(_segMan, object, SELECTOR(yStep));
+ GuiResourceId viewId = readSelectorValue(_segMan, object, SELECTOR(view));
+ int16 loopNo = readSelectorValue(_segMan, object, SELECTOR(loop));
+ int16 celNo = readSelectorValue(_segMan, object, SELECTOR(cel));
// HACK: Ignore invalid views for now (perhaps unimplemented text views?)
if (viewId == 0xFFFF) // invalid view
@@ -203,10 +203,10 @@ void GfxCompare::kernelBaseSetter(reg_t object) {
celRect.bottom = y + 1;
celRect.top = celRect.bottom - yStep;
- PUT_SEL32V(_segMan, object, SELECTOR(brLeft), celRect.left);
- PUT_SEL32V(_segMan, object, SELECTOR(brRight), celRect.right);
- PUT_SEL32V(_segMan, object, SELECTOR(brTop), celRect.top);
- PUT_SEL32V(_segMan, object, SELECTOR(brBottom), celRect.bottom);
+ writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left);
+ writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right);
+ writeSelectorValue(_segMan, object, SELECTOR(brTop), celRect.top);
+ writeSelectorValue(_segMan, object, SELECTOR(brBottom), celRect.bottom);
}
}
diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp
index f744d6e7f1..26af9741c2 100644
--- a/engines/sci/graphics/controls.cpp
+++ b/engines/sci/graphics/controls.cpp
@@ -143,9 +143,9 @@ void GfxControls::texteditSetBlinkTime() {
}
void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
- uint16 cursorPos = GET_SEL32V(_segMan, controlObject, SELECTOR(cursor));
- uint16 maxChars = GET_SEL32V(_segMan, controlObject, SELECTOR(max));
- reg_t textReference = GET_SEL32(_segMan, controlObject, SELECTOR(text));
+ uint16 cursorPos = readSelectorValue(_segMan, controlObject, SELECTOR(cursor));
+ uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
+ reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
Common::String text;
uint16 textSize, eventType, eventKey = 0;
bool textChanged = false;
@@ -158,14 +158,14 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (!eventObject.isNull()) {
textSize = text.size();
- eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
+ eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
switch (eventType) {
case SCI_EVENT_MOUSE_PRESS:
// TODO: Implement mouse support for cursor change
break;
case SCI_EVENT_KEYBOARD:
- eventKey = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
+ eventKey = readSelectorValue(_segMan, eventObject, SELECTOR(message));
switch (eventKey) {
case SCI_KEY_BACKSPACE:
if (cursorPos > 0) {
@@ -207,9 +207,9 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
if (textChanged) {
GuiResourceId oldFontId = _text16->GetFontId();
- GuiResourceId fontId = GET_SEL32V(_segMan, controlObject, SELECTOR(font));
- rect = Common::Rect(GET_SEL32V(_segMan, controlObject, SELECTOR(nsLeft)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsTop)),
- GET_SEL32V(_segMan, controlObject, SELECTOR(nsRight)), GET_SEL32V(_segMan, controlObject, SELECTOR(nsBottom)));
+ GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
+ rect = Common::Rect(readSelectorValue(_segMan, controlObject, SELECTOR(nsLeft)), readSelectorValue(_segMan, controlObject, SELECTOR(nsTop)),
+ readSelectorValue(_segMan, controlObject, SELECTOR(nsRight)), readSelectorValue(_segMan, controlObject, SELECTOR(nsBottom)));
_text16->SetFont(fontId);
if (textAddChar) {
// We check, if we are really able to add the new char
@@ -241,7 +241,7 @@ void GfxControls::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
}
}
- PUT_SEL32V(_segMan, controlObject, SELECTOR(cursor), cursorPos);
+ writeSelectorValue(_segMan, controlObject, SELECTOR(cursor), cursorPos);
}
int GfxControls::getPicNotValid() {
diff --git a/engines/sci/graphics/coordadjuster.cpp b/engines/sci/graphics/coordadjuster.cpp
index 40ef655be7..422df52f27 100644
--- a/engines/sci/graphics/coordadjuster.cpp
+++ b/engines/sci/graphics/coordadjuster.cpp
@@ -93,18 +93,18 @@ GfxCoordAdjuster32::~GfxCoordAdjuster32() {
}
void GfxCoordAdjuster32::kernelGlobalToLocal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
+ //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
//*x = ( *x * _screen->getWidth()) / resX;
//*y = ( *y * _screen->getHeight()) / resY;
- x -= GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- y -= GET_SEL32V(_segMan, planeObject, SELECTOR(top));
+ x -= readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ y -= readSelectorValue(_segMan, planeObject, SELECTOR(top));
}
void GfxCoordAdjuster32::kernelLocalToGlobal(int16 &x, int16 &y, reg_t planeObject) {
- //int16 resY = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resY));
- //int16 resX = GET_SEL32V(_s->_segMan, planeObj, SELECTOR(resX));
- x += GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- y += GET_SEL32V(_segMan, planeObject, SELECTOR(top));
+ //int16 resY = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resY));
+ //int16 resX = readSelectorValue(_s->_segMan, planeObj, SELECTOR(resX));
+ x += readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ y += readSelectorValue(_segMan, planeObject, SELECTOR(top));
//*x = ( *x * resX) / _screen->getWidth();
//*y = ( *y * resY) / _screen->getHeight();
}
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 78253bd913..3cc5ca5447 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -54,7 +54,7 @@ GfxFrameout::~GfxFrameout() {
void GfxFrameout::kernelAddPlane(reg_t object) {
_planes.push_back(object);
- int16 planePri = GET_SEL32V(_segMan, object, SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = readSelectorValue(_segMan, object, SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -74,7 +74,7 @@ void GfxFrameout::kernelDeletePlane(reg_t object) {
_highPlanePri = 0;
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
- int16 planePri = GET_SEL32V(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
+ int16 planePri = readSelectorValue(_segMan, _planes[planeNr], SELECTOR(priority)) & 0xFFFF;
if (planePri > _highPlanePri)
_highPlanePri = planePri;
}
@@ -126,29 +126,29 @@ void GfxFrameout::kernelFrameout() {
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
planeObject = _planes[planeNr];
- planePriority = GET_SEL32V(_segMan, planeObject, SELECTOR(priority));
+ planePriority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));
if (planePriority == -1) // Plane currently not meant to be shown
continue;
- planeRect.top = GET_SEL32V(_segMan, planeObject, SELECTOR(top));
- planeRect.left = GET_SEL32V(_segMan, planeObject, SELECTOR(left));
- planeRect.bottom = GET_SEL32V(_segMan, planeObject, SELECTOR(bottom));
- planeRect.right = GET_SEL32V(_segMan, planeObject, SELECTOR(right));
- planeResY = GET_SEL32V(_segMan, planeObject, SELECTOR(resY));
- planeResX = GET_SEL32V(_segMan, planeObject, SELECTOR(resX));
+ planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top));
+ planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left));
+ planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom));
+ planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right));
+ planeResY = readSelectorValue(_segMan, planeObject, SELECTOR(resY));
+ planeResX = readSelectorValue(_segMan, planeObject, SELECTOR(resX));
planeRect.top = (planeRect.top * _screen->getHeight()) / planeResY;
planeRect.left = (planeRect.left * _screen->getWidth()) / planeResX;
planeRect.bottom = (planeRect.bottom * _screen->getHeight()) / planeResY;
planeRect.right = (planeRect.right * _screen->getWidth()) / planeResX;
- planeBack = GET_SEL32V(_segMan, planeObject, SELECTOR(back));
+ planeBack = readSelectorValue(_segMan, planeObject, SELECTOR(back));
if (planeBack) {
_paint32->fillRect(planeRect, planeBack);
}
- planePictureNr = GET_SEL32V(_segMan, planeObject, SELECTOR(picture));
+ planePictureNr = readSelectorValue(_segMan, planeObject, SELECTOR(picture));
if ((planePictureNr != 0xFFFF) && (planePictureNr != 0xFFFE)) {
planePicture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, planePictureNr, false);
planePictureCels = planePicture->getSci32celCount();
@@ -161,19 +161,19 @@ void GfxFrameout::kernelFrameout() {
itemEntry = itemData;
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
itemObject = _screenItems[itemNr];
- itemPlane = GET_SEL32(_segMan, itemObject, SELECTOR(plane));
+ itemPlane = readSelector(_segMan, itemObject, SELECTOR(plane));
if (planeObject == itemPlane) {
// Found an item on current plane
- itemEntry->viewId = GET_SEL32V(_segMan, itemObject, SELECTOR(view));
- itemEntry->loopNo = GET_SEL32V(_segMan, itemObject, SELECTOR(loop));
- itemEntry->celNo = GET_SEL32V(_segMan, itemObject, SELECTOR(cel));
- itemEntry->x = GET_SEL32V(_segMan, itemObject, SELECTOR(x));
- itemEntry->y = GET_SEL32V(_segMan, itemObject, SELECTOR(y));
- itemEntry->z = GET_SEL32V(_segMan, itemObject, SELECTOR(z));
- itemEntry->priority = GET_SEL32V(_segMan, itemObject, SELECTOR(priority));
- itemEntry->signal = GET_SEL32V(_segMan, itemObject, SELECTOR(signal));
- itemEntry->scaleX = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleX));
- itemEntry->scaleY = GET_SEL32V(_segMan, itemObject, SELECTOR(scaleY));
+ itemEntry->viewId = readSelectorValue(_segMan, itemObject, SELECTOR(view));
+ itemEntry->loopNo = readSelectorValue(_segMan, itemObject, SELECTOR(loop));
+ itemEntry->celNo = readSelectorValue(_segMan, itemObject, SELECTOR(cel));
+ itemEntry->x = readSelectorValue(_segMan, itemObject, SELECTOR(x));
+ itemEntry->y = readSelectorValue(_segMan, itemObject, SELECTOR(y));
+ itemEntry->z = readSelectorValue(_segMan, itemObject, SELECTOR(z));
+ itemEntry->priority = readSelectorValue(_segMan, itemObject, SELECTOR(priority));
+ itemEntry->signal = readSelectorValue(_segMan, itemObject, SELECTOR(signal));
+ itemEntry->scaleX = readSelectorValue(_segMan, itemObject, SELECTOR(scaleX));
+ itemEntry->scaleY = readSelectorValue(_segMan, itemObject, SELECTOR(scaleY));
itemEntry->object = itemObject;
itemEntry->y = ((itemEntry->y * _screen->getHeight()) / planeResY);
@@ -240,12 +240,12 @@ void GfxFrameout::kernelFrameout() {
// This doesn't work for SCI2.1 games...
if (getSciVersion() == SCI_VERSION_2) {
Kernel *kernel = g_sci->getKernel();
- if (lookup_selector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
- Common::String text = _segMan->getString(GET_SEL32(_segMan, itemEntry->object, SELECTOR(text)));
- int16 fontRes = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(font));
+ if (lookupSelector(_segMan, itemEntry->object, kernel->_selectorCache.text, NULL, NULL) == kSelectorVariable) {
+ Common::String text = _segMan->getString(readSelector(_segMan, itemEntry->object, SELECTOR(text)));
+ int16 fontRes = readSelectorValue(_segMan, itemEntry->object, SELECTOR(font));
GfxFont *font = new GfxFontFromResource(_resMan, _screen, fontRes);
- bool dimmed = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(dimmed));
- uint16 foreColor = GET_SEL32V(_segMan, itemEntry->object, SELECTOR(fore));
+ bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed));
+ uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore));
uint16 curX = itemEntry->x;
uint16 curY = itemEntry->y;
for (uint32 i = 0; i < text.size(); i++) {
diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp
index 46f7fcd689..e427edd732 100644
--- a/engines/sci/graphics/gui.cpp
+++ b/engines/sci/graphics/gui.cpp
@@ -92,7 +92,7 @@ void SciGui::resetEngineState(EngineState *s) {
}
void SciGui::init(bool usesOldGfxFunctions) {
- _ports->init(usesOldGfxFunctions, this, _paint16, _text16, _s->_gameId);
+ _ports->init(usesOldGfxFunctions, this, _paint16, _text16);
_paint16->init(_animate, _text16);
}
@@ -136,9 +136,4 @@ void SciGui::portraitShow(Common::String resourceName, Common::Point position, u
void SciGui::portraitUnload(uint16 portraitId) {
}
-bool SciGui::debugEGAdrawingVisualize(bool state) {
- _paint16->setEGAdrawingVisualize(state);
- return false;
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/gui.h b/engines/sci/graphics/gui.h
index 732e195026..7663036117 100644
--- a/engines/sci/graphics/gui.h
+++ b/engines/sci/graphics/gui.h
@@ -61,8 +61,6 @@ public:
virtual void portraitShow(Common::String resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq);
virtual void portraitUnload(uint16 portraitId);
- virtual bool debugEGAdrawingVisualize(bool state);
-
// FIXME: Don't store EngineState
virtual void resetEngineState(EngineState *s);
diff --git a/engines/sci/graphics/maciconbar.cpp b/engines/sci/graphics/maciconbar.cpp
new file mode 100644
index 0000000000..a06e98ccbf
--- /dev/null
+++ b/engines/sci/graphics/maciconbar.cpp
@@ -0,0 +1,91 @@
+/* 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 "sci/sci.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/state.h"
+#include "sci/graphics/maciconbar.h"
+#include "sci/graphics/palette.h"
+
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/pict.h"
+#include "graphics/surface.h"
+
+namespace Sci {
+
+void GfxMacIconBar::addIcon(reg_t obj) {
+ _iconBarObjects.push_back(obj);
+}
+
+void GfxMacIconBar::drawIcons() {
+ // Draw the icons to the bottom of the screen
+
+ byte *pal = new byte[256 * 4];
+ Graphics::PictDecoder *pict = new Graphics::PictDecoder(Graphics::PixelFormat::createFormatCLUT8());
+ uint32 lastX = 0;
+
+ for (uint32 i = 0; i < _iconBarObjects.size(); i++) {
+ uint32 iconIndex = readSelectorValue(g_sci->getEngineState()->_segMan, _iconBarObjects[i], SELECTOR(iconIndex));
+ Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMacIconBarPictN, iconIndex + 1), false);
+ if (!res)
+ continue;
+
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(res->data, res->size);
+ Graphics::Surface *surf = pict->decodeImage(stream, pal);
+ remapColors(surf, pal);
+
+ g_system->copyRectToScreen((byte *)surf->pixels, surf->pitch, lastX, 200, MIN<uint32>(surf->w, 320 - lastX), surf->h);
+
+ lastX += surf->w;
+ surf->free();
+ delete surf;
+ delete stream;
+ }
+
+ delete pict;
+ delete[] pal;
+}
+
+void GfxMacIconBar::remapColors(Graphics::Surface *surf, byte *palette) {
+ byte *pixels = (byte *)surf->pixels;
+
+ // Remap to the screen palette
+ for (uint16 i = 0; i < surf->w * surf->h; i++) {
+ byte color = *pixels;
+
+ byte r = palette[color * 4];
+ byte g = palette[color * 4 + 1];
+ byte b = palette[color * 4 + 2];
+
+ // For black, make sure the index is 0
+ if (r == 0 && g == 0 && b == 0)
+ *pixels++ = 0;
+ else
+ *pixels++ = g_sci->_gfxPalette->kernelFindColor(r, g, b);
+ }
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/maciconbar.h b/engines/sci/graphics/maciconbar.h
new file mode 100644
index 0000000000..71e65fcb40
--- /dev/null
+++ b/engines/sci/graphics/maciconbar.h
@@ -0,0 +1,55 @@
+/* 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 SCI_GRAPHICS_MACICONBAR_H
+#define SCI_GRAPHICS_MACICONBAR_H
+
+#include "common/array.h"
+
+#include "sci/engine/vm.h"
+
+namespace Graphics {
+ struct Surface;
+}
+
+namespace Sci {
+
+class GfxMacIconBar {
+public:
+ GfxMacIconBar() {}
+ ~GfxMacIconBar() {}
+
+ void addIcon(reg_t obj);
+ void drawIcons();
+
+private:
+ Common::Array<reg_t> _iconBarObjects;
+
+ void remapColors(Graphics::Surface *surf, byte *palette);
+};
+
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp
index 5e3b419fe3..880e1aba12 100644
--- a/engines/sci/graphics/menu.cpp
+++ b/engines/sci/graphics/menu.cpp
@@ -378,7 +378,7 @@ void GfxMenu::calculateMenuAndItemWidth() {
}
reg_t GfxMenu::kernelSelect(reg_t eventObject) {
- int16 eventType = GET_SEL32V(_segMan, eventObject, SELECTOR(type));
+ int16 eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));
int16 keyPress, keyModifier;
Common::Point mousePosition;
GuiMenuItemList::iterator itemIterator = _itemList.begin();
@@ -390,8 +390,8 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
switch (eventType) {
case SCI_EVENT_KEYBOARD:
- keyPress = GET_SEL32V(_segMan, eventObject, SELECTOR(message));
- keyModifier = GET_SEL32V(_segMan, eventObject, SELECTOR(modifiers));
+ keyPress = readSelectorValue(_segMan, eventObject, SELECTOR(message));
+ keyModifier = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
// If tab got pressed, handle it here as if it was Ctrl-I - at least sci0 also did it that way
if (keyPress == SCI_KEY_TAB) {
keyModifier = SCI_KEYMOD_CTRL;
@@ -465,7 +465,7 @@ reg_t GfxMenu::kernelSelect(reg_t eventObject) {
_ports->setPort(_oldPort);
if ((itemEntry) || (forceClaimed))
- PUT_SEL32(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
+ writeSelector(_segMan, eventObject, SELECTOR(claimed), make_reg(0, 1));
if (itemEntry)
return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id));
return NULL_REG;
diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp
index d0975f3d3d..ff4f3bec52 100644
--- a/engines/sci/graphics/paint16.cpp
+++ b/engines/sci/graphics/paint16.cpp
@@ -61,7 +61,7 @@ void GfxPaint16::init(GfxAnimate *animate, GfxText16 *text16) {
_EGAdrawingVisualize = false;
}
-void GfxPaint16::setEGAdrawingVisualize(bool state) {
+void GfxPaint16::debugSetEGAdrawingVisualize(bool state) {
_EGAdrawingVisualize = state;
}
@@ -354,7 +354,8 @@ void GfxPaint16::bitsRestore(reg_t memoryHandle) {
}
void GfxPaint16::bitsFree(reg_t memoryHandle) {
- _segMan->freeHunkEntry(memoryHandle);
+ if (!memoryHandle.isNull()) // happens in KQ5CD
+ _segMan->freeHunkEntry(memoryHandle);
}
void GfxPaint16::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index b18c879387..65f9dd0d9c 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -50,7 +50,7 @@ public:
void init(GfxAnimate *animate, GfxText16 *text16);
- void setEGAdrawingVisualize(bool state);
+ void debugSetEGAdrawingVisualize(bool state);
void drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId);
void drawCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, uint16 scaleX = 128, uint16 scaleY = 128);
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 96bdb42007..3c4cf7e964 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -30,8 +30,9 @@
#include "sci/sci.h"
#include "sci/engine/state.h"
-#include "sci/graphics/screen.h"
+#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/screen.h"
namespace Sci {
@@ -55,6 +56,7 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool autoSetP
_sysPalette.colors[255].g = 255;
_sysPalette.colors[255].b = 255;
+ _sysPaletteChanged = false;
if (autoSetPalette) {
if (_resMan->getViewType() == kViewEga)
setEGA();
@@ -63,7 +65,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen, bool autoSetP
else
kernelSetFromResource(999, true);
}
- _sysPaletteChanged = false;
}
GfxPalette::~GfxPalette() {
@@ -311,6 +312,10 @@ void GfxPalette::setOnScreen() {
if (_resMan->isAmiga32color())
return;
_screen->setPalette(&_sysPalette);
+
+ // Redraw the Mac SCI1.1 Icon bar every palette change
+ if (g_sci->_gfxMacIconBar)
+ g_sci->_gfxMacIconBar->drawIcons();
}
bool GfxPalette::kernelSetFromResource(GuiResourceId resourceId, bool force) {
diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp
index 74f651a88a..a59153f116 100644
--- a/engines/sci/graphics/picture.cpp
+++ b/engines/sci/graphics/picture.cpp
@@ -69,15 +69,20 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1
headerSize = READ_LE_UINT16(_resource->data);
switch (headerSize) {
case 0x26: // SCI 1.1 VGA picture
+ _resourceType = SCI_PICTURE_TYPE_SCI11;
+ if (_addToFlag)
+ _priority = 15;
drawSci11Vga();
break;
#ifdef ENABLE_SCI32
case 0x0e: // SCI32 VGA picture
+ _resourceType = SCI_PICTURE_TYPE_SCI32;
drawSci32Vga();
break;
#endif
default:
// VGA, EGA or Amiga vector data
+ _resourceType = SCI_PICTURE_TYPE_REGULAR;
drawVectorData(_resource->data, _resource->size);
}
}
@@ -108,9 +113,8 @@ void GfxPicture::drawSci11Vga() {
_palette->set(&palette, true);
// display Cel-data
- if (has_cel) {
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false);
- }
+ if (has_cel)
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0);
// process vector data
drawVectorData(inbuffer + vector_dataPos, vector_size);
@@ -139,6 +143,7 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
// HACK
_mirroredFlag = false;
_addToFlag = false;
+ _resourceType = SCI_PICTURE_TYPE_SCI32;
if ((celNo == -1) || (celNo == 0)) {
// Create palette and set it
@@ -155,14 +160,14 @@ void GfxPicture::drawSci32Vga(int16 celNo) {
cel_LiteralPos = READ_LE_UINT32(inbuffer + cel_headerPos + 28);
cel_relXpos = READ_LE_UINT16(inbuffer + cel_headerPos + 38);
cel_relYpos = READ_LE_UINT16(inbuffer + cel_headerPos + 40);
- drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos, true);
+ drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, cel_relXpos, cel_relYpos);
cel_headerPos += 42;
celCount--;
}
}
#endif
-void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header) {
+void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY) {
byte *celBitmap = NULL;
byte *ptr = NULL;
byte *headerPtr = inbuffer + headerPos;
@@ -179,11 +184,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos
int pixelNr, pixelCount;
#ifdef ENABLE_SCI32
- if (!hasSci32Header) {
+ if (_resourceType != SCI_PICTURE_TYPE_SCI32) {
#endif
displaceX = (signed char)headerPtr[4];
displaceY = (unsigned char)headerPtr[5];
- clearColor = headerPtr[6];
+ if (_resourceType == SCI_PICTURE_TYPE_SCI11) {
+ // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise
+ clearColor = _screen->getColorWhite();
+ } else {
+ clearColor = headerPtr[6];
+ }
#ifdef ENABLE_SCI32
} else {
displaceX = READ_LE_UINT16(headerPtr + 4); // probably signed?!?
@@ -518,10 +528,29 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
+ // Pattern opcodes are handled in sierra sci1.1+ as actual NOPs and normally they definitely should not occur
+ // inside picture data for such games
case PIC_OP_SET_PATTERN:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11) {
+ if (strcmp(g_sci->getGameID(), "sq4") == 0) {
+ // WORKAROUND: For SQ4 / for some pictures handle this like a terminator
+ // This picture includes garbage data, first a set pattern w/o parameter and then short pattern
+ // I guess that garbage is a left over from the sq4-floppy (sci1) to sq4-cd (sci1.1) conversion
+ switch (_resourceId) {
+ case 381:
+ case 376:
+ return;
+ default:
+ break;
+ }
+ }
+ error("pic-operation set pattern inside sci1.1+ vector data");
+ }
pattern_Code = data[curPos++];
break;
case PIC_OP_SHORT_PATTERNS:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation short pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -532,6 +561,8 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_MEDIUM_PATTERNS:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation medium pattern inside sci1.1+ vector data");
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture);
@@ -542,6 +573,8 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
}
break;
case PIC_OP_ABSOLUTE_PATTERN:
+ if (_resourceType >= SCI_PICTURE_TYPE_SCI11)
+ error("pic-operation absolute pattern inside sci1.1+ vector data");
while (vectorIsNonOpcode(data[curPos])) {
vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture);
vectorGetAbsCoords(data, curPos, x, y);
@@ -585,7 +618,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
vectorGetAbsCoordsNoMirror(data, curPos, x, y);
size = READ_LE_UINT16(data + curPos); curPos += 2;
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
curPos += size;
break;
case PIC_OPX_EGA_SET_PRIORITY_TABLE:
@@ -627,7 +660,7 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) {
_priority = pic_priority; // set global priority so the cel gets drawn using current priority as well
if (pic_priority == 255)
_priority = 0; // if priority not set, use priority 0
- drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false);
+ drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y);
curPos += size;
break;
case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST:
diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h
index 3374c33b52..5a86539b37 100644
--- a/engines/sci/graphics/picture.h
+++ b/engines/sci/graphics/picture.h
@@ -32,6 +32,12 @@ namespace Sci {
#define SCI_PATTERN_CODE_USE_TEXTURE 0x20
#define SCI_PATTERN_CODE_PENSIZE 0x07
+enum {
+ SCI_PICTURE_TYPE_REGULAR = 0,
+ SCI_PICTURE_TYPE_SCI11 = 1,
+ SCI_PICTURE_TYPE_SCI32 = 2
+};
+
class GfxPorts;
class GfxScreen;
class GfxPalette;
@@ -57,7 +63,7 @@ private:
void initData(GuiResourceId resourceId);
void reset();
void drawSci11Vga();
- void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header);
+ void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY);
void drawVectorData(byte *data, int size);
bool vectorIsNonOpcode(byte pixel);
void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y);
@@ -80,6 +86,7 @@ private:
int16 _resourceId;
Resource *_resource;
+ int _resourceType;
int16 _animationNr;
bool _mirroredFlag;
diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp
index ab3291dd79..cdb6fe4ae1 100644
--- a/engines/sci/graphics/ports.cpp
+++ b/engines/sci/graphics/ports.cpp
@@ -54,7 +54,7 @@ GfxPorts::~GfxPorts() {
delete _menuPort;
}
-void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId) {
+void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16) {
int16 offTop = 10;
_usesOldGfxFunctions = usesOldGfxFunctions;
@@ -88,6 +88,7 @@ void GfxPorts::init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16,
// Jones, Slater and Hoyle 3 were called with parameter -Nw 0 0 200 320.
// Mother Goose (SCI1) uses -Nw 0 0 159 262. The game will later use SetPort so we don't need to set the other fields.
// This actually meant not skipping the first 10 pixellines in windowMgrPort
+ Common::String gameId = g_sci->getGameID();
if (gameId == "jones" || gameId == "slater" || gameId == "hoyle3" || (gameId == "mothergoose" && getSciVersion() == SCI_VERSION_1_EARLY))
offTop = 0;
diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h
index 0876d9e442..c8ce6b3470 100644
--- a/engines/sci/graphics/ports.h
+++ b/engines/sci/graphics/ports.h
@@ -45,7 +45,7 @@ public:
GfxPorts(SegManager *segMan, GfxScreen *screen);
~GfxPorts();
- void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16, Common::String gameId);
+ void init(bool usesOldGfxFunctions, SciGui *gui, GfxPaint16 *paint16, GfxText16 *text16);
void kernelSetActive(uint16 portId);
Common::Rect kernelGetPicWindow(int16 &picTop, int16 &picLeft);
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 7ca9e33509..0e054d5a76 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -93,7 +93,18 @@ GfxScreen::GfxScreen(ResourceManager *resMan, int16 width, int16 height, int ups
}
// Initialize the actual screen
- initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
+
+ if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1) {
+ // For SCI1.1 Mac, we need to expand the screen to accommodate for
+ // the icon bar. Of course, both KQ6 and QFG1 VGA differ in size.
+ if (!scumm_stricmp(g_sci->getGameID(), "kq6"))
+ initGraphics(_displayWidth, _displayHeight + 26, _displayWidth > 320);
+ else if (!scumm_stricmp(g_sci->getGameID(), "qfg1"))
+ initGraphics(_displayWidth, _displayHeight + 20, _displayWidth > 320);
+ else
+ error("Unknown SCI1.1 Mac game");
+ } else
+ initGraphics(_displayWidth, _displayHeight, _displayWidth > 320);
}
GfxScreen::~GfxScreen() {
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 8c4d666ba7..a2cfd38f95 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
detection.o \
event.o \
resource.o \
+ resource_audio.o \
sci.o \
util.o \
engine/features.o \
@@ -44,6 +45,7 @@ MODULE_OBJS := \
graphics/font.o \
graphics/fontsjis.o \
graphics/gui.o \
+ graphics/maciconbar.o \
graphics/menu.o \
graphics/paint.o \
graphics/paint16.o \
diff --git a/engines/sci/parser/grammar.cpp b/engines/sci/parser/grammar.cpp
index 1cfe84076f..070e6767cf 100644
--- a/engines/sci/parser/grammar.cpp
+++ b/engines/sci/parser/grammar.cpp
@@ -258,6 +258,11 @@ void Vocabulary::freeRuleList(ParseRuleList *list) {
static ParseRuleList *_vocab_add_rule(ParseRuleList *list, ParseRule *rule) {
if (!rule)
return list;
+ if (!rule->_data.size()) {
+ // Special case for qfg2 demo
+ warning("no rule contents on _vocab_add_rule()");
+ return list;
+ }
ParseRuleList *new_elem = new ParseRuleList(rule);
diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp
index 5cd1310ad3..f49704372a 100644
--- a/engines/sci/parser/said.cpp
+++ b/engines/sci/parser/said.cpp
@@ -2443,13 +2443,14 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
+ Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
- if (s->_voc->parserIsValid) {
+ if (voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- s->_voc->decipherSaidBlock(spec);
+ voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/parser/said.y b/engines/sci/parser/said.y
index 27486c5794..cbb2ff3e62 100644
--- a/engines/sci/parser/said.y
+++ b/engines/sci/parser/said.y
@@ -799,13 +799,14 @@ static int augment_parse_nodes(parse_tree_node_t *parset, parse_tree_node_t *sai
int said(EngineState *s, byte *spec, bool verbose) {
int retval;
+ Vocabulary *voc = g_sci->getVocabulary();
- parse_tree_node_t *parse_tree_ptr = s->_voc->_parserNodes;
+ parse_tree_node_t *parse_tree_ptr = voc->_parserNodes;
- if (s->_voc->parserIsValid) {
+ if (voc->parserIsValid) {
if (said_parse_spec(spec)) {
printf("Offending spec was: ");
- s->_voc->decipherSaidBlock(spec);
+ voc->decipherSaidBlock(spec);
return SAID_NO_MATCH;
}
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 4888dbd4cb..4818428663 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -26,7 +26,6 @@
// Resource library
#include "common/file.h"
-#include "common/macresman.h"
#include "sci/resource.h"
#include "sci/util.h"
@@ -45,18 +44,6 @@ struct resource_index_t {
uint16 wSize;
};
-struct ResourceSource {
- ResSourceType source_type;
- bool scanned;
- Common::String location_name; // FIXME: Replace by FSNode ?
- const Common::FSNode *resourceFile;
- int volume_number;
- ResourceSource *associated_map;
- uint32 audioCompressionType;
- int32 *audioCompressionOffsetMapping;
- Common::MacResManager macResMan;
-};
-
//////////////////////////////////////////////////////////////////////
static SciVersion s_sciVersion = SCI_VERSION_NONE; // FIXME: Move this inside a suitable class, e.g. SciEngine
@@ -196,7 +183,7 @@ ResourceSource *ResourceManager::addExternalMap(const char *file_name, int volum
return newsrc;
}
-ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
+ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile, int volume_nr) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceExtMap;
@@ -204,7 +191,7 @@ ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
newsrc->resourceFile = mapFile;
newsrc->scanned = false;
newsrc->associated_map = NULL;
- newsrc->volume_number = 0;
+ newsrc->volume_number = volume_nr;
_sources.push_back(newsrc);
return newsrc;
@@ -250,6 +237,7 @@ ResourceSource *ResourceManager::addPatchDir(const char *dirname) {
ResourceSource *newsrc = new ResourceSource();
newsrc->source_type = kSourceDirectory;
+ newsrc->resourceFile = 0;
newsrc->scanned = false;
newsrc->location_name = dirname;
@@ -270,37 +258,7 @@ ResourceSource *ResourceManager::getVolume(ResourceSource *map, int volume_nr) {
// Resource manager constructors and operations
-void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
- Common::File *file = getVolumeFile(source->location_name.c_str());
- if (!file) {
- warning("Failed to open %s", source->location_name.c_str());
- return;
- }
- file->seek(0, SEEK_SET);
- uint32 compressionType = file->readUint32BE();
- switch (compressionType) {
- case MKID_BE('MP3 '):
- case MKID_BE('OGG '):
- case MKID_BE('FLAC'):
- // Detected a compressed audio volume
- source->audioCompressionType = compressionType;
- // Now read the whole offset mapping table for later usage
- int32 recordCount = file->readUint32LE();
- if (!recordCount)
- error("compressed audio volume doesn't contain any entries!");
- int32 *offsetMapping = new int32[(recordCount + 1) * 2];
- source->audioCompressionOffsetMapping = offsetMapping;
- for (int recordNo = 0; recordNo < recordCount; recordNo++) {
- *offsetMapping++ = file->readUint32LE();
- *offsetMapping++ = file->readUint32LE();
- }
- // Put ending zero
- *offsetMapping++ = 0;
- *offsetMapping++ = file->size();
- }
-}
-
-bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
+bool ResourceManager::loadPatch(Resource *res, Common::SeekableReadStream *file) {
// We assume that the resource type matches res->type
// We also assume that the current file position is right at the actual data (behind resourceid/headersize byte)
@@ -315,12 +273,12 @@ bool ResourceManager::loadPatch(Resource *res, Common::File &file) {
unsigned int really_read;
if (res->_headerSize > 0) {
- really_read = file.read(res->_header, res->_headerSize);
+ really_read = file->read(res->_header, res->_headerSize);
if (really_read != res->_headerSize)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->_headerSize);
}
- really_read = file.read(res->data, res->size);
+ really_read = file->read(res->data, res->size);
if (really_read != res->size)
error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
@@ -338,77 +296,18 @@ bool ResourceManager::loadFromPatchFile(Resource *res) {
}
// Skip resourceid and header size byte
file.seek(2, SEEK_SET);
- return loadPatch(res, file);
-}
-
-bool ResourceManager::loadFromWaveFile(Resource *res, Common::File &file) {
- res->data = new byte[res->size];
-
- uint32 really_read = file.read(res->data, res->size);
- if (really_read != res->size)
- error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) {
- // Check for WAVE files here
- uint32 riffTag = file.readUint32BE();
- if (riffTag == MKID_BE('RIFF')) {
- res->_headerSize = 0;
- res->size = file.readUint32LE();
- file.seek(-8, SEEK_CUR);
- return loadFromWaveFile(res, file);
- }
- file.seek(-4, SEEK_CUR);
-
- ResourceType type = (ResourceType)(file.readByte() & 0x7f);
- if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
- || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
- warning("Resource type mismatch loading %s from %s", res->_id.toString().c_str(), file.getName());
- res->unalloc();
- return false;
- }
-
- res->_headerSize = file.readByte();
-
- if (type == kResourceTypeAudio) {
- if (res->_headerSize != 11 && res->_headerSize != 12) {
- warning("Unsupported audio header");
- res->unalloc();
- return false;
- }
-
- // Load sample size
- file.seek(7, SEEK_CUR);
- res->size = file.readUint32LE();
- // Adjust offset to point at the header data again
- file.seek(-11, SEEK_CUR);
- }
-
- return loadPatch(res, file);
-}
-
-bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) {
- res->data = new byte[res->size];
-
- if (res->data == NULL) {
- error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
- }
-
- unsigned int really_read = file.read(res->data, res->size);
- if (really_read != res->size)
- warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
-
- res->_status = kResStatusAllocated;
- return true;
+ return loadPatch(res, &file);
}
-Common::File *ResourceManager::getVolumeFile(const char *filename) {
+Common::SeekableReadStream *ResourceManager::getVolumeFile(ResourceSource *source) {
Common::List<Common::File *>::iterator it = _volumeFiles.begin();
Common::File *file;
+ if (source->resourceFile)
+ return source->resourceFile->createReadStream();
+
+ const char *filename = source->location_name.c_str();
+
// check if file is already opened
while (it != _volumeFiles.end()) {
file = *it;
@@ -445,11 +344,10 @@ void ResourceManager::loadResource(Resource *res) {
return;
if (res->_source->source_type == kSourceMacResourceFork) {
- //error("ResourceManager::loadResource(): TODO: Mac resource fork ;)");
Common::SeekableReadStream *stream = res->_source->macResMan.getResource(resTypeToMacTag(res->_id.type), res->_id.number);
if (!stream)
- error("Could not get Mac resource fork resource");
+ error("Could not get Mac resource fork resource: %d %d", res->_id.type, res->_id.number);
int error = decompress(res, stream);
if (error) {
@@ -460,10 +358,9 @@ void ResourceManager::loadResource(Resource *res) {
return;
}
- Common::File *file;
- // Either loading from volume or patch loading failed
- file = getVolumeFile(res->_source->location_name.c_str());
- if (!file) {
+ Common::SeekableReadStream *fileStream = getVolumeFile(res->_source);
+
+ if (!fileStream) {
warning("Failed to open %s", res->_source->location_name.c_str());
res->unalloc();
return;
@@ -471,8 +368,10 @@ void ResourceManager::loadResource(Resource *res) {
switch(res->_source->source_type) {
case kSourceWave:
- file->seek(res->_fileOffset, SEEK_SET);
- loadFromWaveFile(res, *file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ loadFromWaveFile(res, fileStream);
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
case kSourceAudioVolume:
@@ -503,30 +402,39 @@ void ResourceManager::loadResource(Resource *res) {
if (!compressedOffset)
error("could not translate offset to compressed offset in audio volume");
- file->seek(compressedOffset, SEEK_SET);
+ fileStream->seek(compressedOffset, SEEK_SET);
switch (res->_id.type) {
case kResourceTypeAudio:
case kResourceTypeAudio36:
// Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
default:
break;
}
} else {
// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
- file->seek(res->_fileOffset, SEEK_SET);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
}
if (getSciVersion() < SCI_VERSION_1_1)
- loadFromAudioVolumeSCI1(res, *file);
+ loadFromAudioVolumeSCI1(res, fileStream);
else
- loadFromAudioVolumeSCI11(res, *file);
+ loadFromAudioVolumeSCI11(res, fileStream);
+
+ if (res->_source->resourceFile)
+ delete fileStream;
return;
default:
- file->seek(res->_fileOffset, SEEK_SET);
- int error = decompress(res, file);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+ int error = decompress(res, fileStream);
+
+ if (res->_source->resourceFile)
+ delete fileStream;
+
if (error) {
warning("Error %d occured while reading %s from resource file: %s",
error, res->_id.toString().c_str(), sci_error_types[error]);
@@ -539,27 +447,14 @@ Resource *ResourceManager::testResource(ResourceId id) {
return _resMap.getVal(id, NULL);
}
-int sci0_get_compression_method(Common::ReadStream &stream) {
- uint16 compressionMethod;
-
- stream.readUint16LE();
- stream.readUint16LE();
- stream.readUint16LE();
- compressionMethod = stream.readUint16LE();
- if (stream.err())
- return SCI_ERROR_IO_ERROR;
-
- return compressionMethod;
-}
-
int ResourceManager::addAppropriateSources() {
Common::ArchiveMemberList files;
- if (Common::File::exists("RESOURCE.MAP")) {
+ if (Common::File::exists("resource.map")) {
// SCI0-SCI2 file naming scheme
- ResourceSource *map = addExternalMap("RESOURCE.MAP");
+ ResourceSource *map = addExternalMap("resource.map");
- SearchMan.listMatchingMembers(files, "RESOURCE.0??");
+ SearchMan.listMatchingMembers(files, "resource.0??");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
const Common::String name = (*x)->getName();
@@ -570,12 +465,12 @@ int ResourceManager::addAppropriateSources() {
}
#ifdef ENABLE_SCI32
// GK1CD hires content
- if (Common::File::exists("ALT.MAP") && Common::File::exists("RESOURCE.ALT"))
- addSource(addExternalMap("ALT.MAP", 10), kSourceVolume, "RESOURCE.ALT", 10);
+ if (Common::File::exists("alt.map") && Common::File::exists("resource.alt"))
+ addSource(addExternalMap("alt.map", 10), kSourceVolume, "resource.alt", 10);
#endif
} else if (Common::File::exists("Data1")) {
// Mac SCI1.1+ file naming scheme
- SearchMan.listMatchingMembers(files, "Data?");
+ SearchMan.listMatchingMembers(files, "Data?*");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
Common::String filename = (*x)->getName();
@@ -594,8 +489,8 @@ int ResourceManager::addAppropriateSources() {
} else {
// SCI2.1-SCI3 file naming scheme
Common::ArchiveMemberList mapFiles;
- SearchMan.listMatchingMembers(mapFiles, "RESMAP.0??");
- SearchMan.listMatchingMembers(files, "RESSCI.0??");
+ SearchMan.listMatchingMembers(mapFiles, "resmap.0??");
+ SearchMan.listMatchingMembers(files, "ressci.0??");
// We need to have the same number of maps as resource archives
if (mapFiles.empty() || files.empty() || mapFiles.size() != files.size())
@@ -617,9 +512,9 @@ int ResourceManager::addAppropriateSources() {
}
// SCI2.1 resource patches
- if (Common::File::exists("RESMAP.PAT") && Common::File::exists("RESSCI.PAT")) {
+ if (Common::File::exists("resmap.pat") && Common::File::exists("ressci.pat")) {
// We add this resource with a map which surely won't exist
- addSource(addExternalMap("RESMAP.PAT", 100), kSourceVolume, "RESSCI.PAT", 100);
+ addSource(addExternalMap("resmap.pat", 100), kSourceVolume, "ressci.pat", 100);
}
}
#else
@@ -628,14 +523,18 @@ int ResourceManager::addAppropriateSources() {
#endif
addPatchDir(".");
- if (Common::File::exists("MESSAGE.MAP"))
- addSource(addExternalMap("MESSAGE.MAP"), kSourceVolume, "RESOURCE.MSG", 0);
+ if (Common::File::exists("message.map"))
+ addSource(addExternalMap("message.map"), kSourceVolume, "resource.msg", 0);
return 1;
}
int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
ResourceSource *map = 0;
+#ifdef ENABLE_SCI32
+ ResourceSource *sci21PatchMap = 0;
+ const Common::FSNode *sci21PatchRes = 0;
+#endif
// First, find resource.map
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
@@ -645,17 +544,33 @@ int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
Common::String filename = file->getName();
filename.toLowercase();
- // TODO: Load the SCI2.1+ maps (resmap.*) in concurrence with the volumes to
- // get the proper volume numbers from the maps.
- if (filename.contains("resource.map") || filename.contains("resmap.000")) {
+ if (filename.contains("resource.map"))
map = addExternalMap(file);
- break;
+
+ if (filename.contains("resmap.0")) {
+ const char *dot = strrchr(file->getName().c_str(), '.');
+ int number = atoi(dot + 1);
+ map = addExternalMap(file, number);
}
+
+#ifdef ENABLE_SCI32
+ // SCI2.1 resource patches
+ if (filename.contains("resmap.pat"))
+ sci21PatchMap = addExternalMap(file, 100);
+
+ if (filename.contains("ressci.pat"))
+ sci21PatchRes = file;
+#endif
}
if (!map)
return 0;
+#ifdef ENABLE_SCI32
+ if (sci21PatchMap && sci21PatchRes)
+ addSource(sci21PatchMap, kSourceVolume, sci21PatchRes, 100);
+#endif
+
// Now find all the resource.0?? files
for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory())
@@ -696,36 +611,6 @@ int ResourceManager::addInternalSources() {
return 1;
}
-void ResourceManager::addNewGMPatch(const Common::String &gameId) {
- Common::String gmPatchFile;
-
- if (gameId == "ecoquest")
- gmPatchFile = "ECO1GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "hoyle3")
- gmPatchFile = "HOY3GM.PAT";
- else if (gameId == "lsl1sci")
- gmPatchFile = "LL1_GM.PAT";
- else if (gameId == "lsl5")
- gmPatchFile = "LL5_GM.PAT";
- else if (gameId == "longbow")
- gmPatchFile = "ROBNGM.PAT";
- else if (gameId == "sq1sci")
- gmPatchFile = "SQ1_GM.PAT";
- else if (gameId == "sq4")
- gmPatchFile = "SQ4_GM.PAT";
- else if (gameId == "fairytales")
- gmPatchFile = "TALEGM.PAT";
-
- if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourcePatch;
- psrcPatch->location_name = gmPatchFile;
- processPatch(psrcPatch, kResourceTypePatch, 4);
- }
-}
-
void ResourceManager::scanNewSources() {
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
ResourceSource *source = *it;
@@ -735,6 +620,9 @@ void ResourceManager::scanNewSources() {
switch (source->source_type) {
case kSourceDirectory:
readResourcePatches(source);
+#ifdef ENABLE_SCI32
+ readResourcePatchesBase36(source);
+#endif
readWaveAudioPatches();
break;
case kSourceExtMap:
@@ -990,7 +878,6 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -1001,7 +888,7 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1081,7 +968,6 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
Common::SeekableReadStream *fileStream = 0;
- Common::File *file = 0;
ResourceSource *rsrc;
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
@@ -1091,7 +977,7 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
if (rsrc->resourceFile) {
fileStream = rsrc->resourceFile->createReadStream();
} else {
- file = new Common::File();
+ Common::File *file = new Common::File();
file->open(rsrc->location_name);
if (file->isOpen())
fileStream = file;
@@ -1180,27 +1066,36 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
}
// version-agnostic patch application
-void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, int resnumber) {
- Common::File file;
+void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, uint16 resnumber, uint32 tuple) {
+ Common::SeekableReadStream *fileStream = 0;
Resource *newrsc;
- ResourceId resId = ResourceId(restype, resnumber);
+ ResourceId resId = ResourceId(restype, resnumber, tuple);
byte patchtype, patch_data_offset;
int fsize;
- if (resnumber == -1)
- return;
- if (!file.open(source->location_name)) {
- warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ if (resnumber == 0xFFFF)
return;
+
+ if (source->resourceFile) {
+ fileStream = source->resourceFile->createReadStream();
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(source->location_name)) {
+ warning("ResourceManager::processPatch(): failed to open %s", source->location_name.c_str());
+ return;
+ }
+ fileStream = file;
}
- fsize = file.size();
+ fsize = fileStream->size();
if (fsize < 3) {
debug("Patching %s failed - file too small", source->location_name.c_str());
return;
}
- patchtype = file.readByte() & 0x7F;
- patch_data_offset = file.readByte();
+ patchtype = fileStream->readByte() & 0x7F;
+ patch_data_offset = fileStream->readByte();
+
+ delete fileStream;
if (patchtype != restype) {
debug("Patching %s failed - resource type mismatch", source->location_name.c_str());
@@ -1215,8 +1110,12 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
case 1:
patch_data_offset = 2;
break;
+ case 4:
+ patch_data_offset = 8;
+ break;
default:
- warning("Resource patch unsupported special case %X", patch_data_offset);
+ warning("Resource patch unsupported special case %X", patch_data_offset & 0x7F);
+ return;
}
}
@@ -1241,11 +1140,70 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype,
debugC(1, kDebugLevelResMan, "Patching %s - OK", source->location_name.c_str());
}
+#ifdef ENABLE_SCI32
+
+void ResourceManager::readResourcePatchesBase36(ResourceSource *source) {
+ // The base36 encoded audio36 and sync36 resources use a different naming scheme, because they
+ // cannot be described with a single resource number, but are a result of a
+ // <number, noun, verb, cond, seq> tuple. Please don't be confused with the normal audio patches
+ // (*.aud) and normal sync patches (*.syn). audio36 patches can be seen for example in the AUD
+ // folder of GK1CD, and are like this file: @0CS0M00.0X1. GK1CD is the first game where these
+ // have been observed. The actual audio36 and sync36 resources exist in SCI1.1 as well, but the
+ // first game where external patch files for them have been found is GK1CD. The names of these
+ // files are base36 encoded, and we handle their decoding here. audio36 files start with a '@',
+ // whereas sync36 start with a '#'. Mac versions begin with 'A' (probably meaning AIFF). Torin
+ // has several that begin with 'B'.
+
+ Common::String name, inputName;
+ Common::ArchiveMemberList files;
+ //ResourceSource *psrcPatch;
+
+ for (int i = kResourceTypeAudio36; i <= kResourceTypeSync36; ++i) {
+ // audio36 resources start with a @, A, or B
+ // sync36 resources start with a #
+ if (i == kResourceTypeAudio36) {
+ SearchMan.listMatchingMembers(files, "@???????.???");
+ SearchMan.listMatchingMembers(files, "A???????.???");
+ SearchMan.listMatchingMembers(files, "B???????.???");
+ } else
+ SearchMan.listMatchingMembers(files, "#???????.???");
+
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ name = (*x)->getName();
+ inputName = (*x)->getName();
+ inputName.toUppercase();
+ inputName.deleteChar(0); // delete the first character (type)
+ inputName.deleteChar(7); // delete the dot
+
+ // The base36 encoded resource contains the following:
+ // uint16 number, byte noun, byte verb, byte cond, byte seq
+ // TODO: this is still not right (especially the tuple part, seems to be overflowing?)
+ uint16 number = strtol(Common::String(inputName.c_str(), 2).c_str(), 0, 36);
+ uint32 tuple = strtol(inputName.c_str() + 2, 0, 36);
+ ResourceId resource36((ResourceType)i, number, tuple);
+
+ if (i == kResourceTypeAudio36)
+ debug("audio36 patch: %s => %s. tuple:%d, %s\n", name.c_str(), inputName.c_str(), tuple, resource36.toString().c_str());
+ else
+ debug("sync36 patch: %s => %s. tuple:%d, %s\n", name.c_str(), inputName.c_str(), tuple, resource36.toString().c_str());
+
+ /*
+ psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourcePatch;
+ psrcPatch->location_name = name;
+ psrcPatch->resourceFile = 0;
+ processPatch(psrcPatch, (ResourceType)i, number, tuple);
+ */
+ }
+ }
+}
+
+#endif
void ResourceManager::readResourcePatches(ResourceSource *source) {
-// Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
-// this function tries to read patch file with any supported naming scheme,
-// regardless of s_sciVersion value
+ // Note: since some SCI1 games(KQ5 floppy, SQ4) might use SCI0 naming scheme for patch files
+ // this function tries to read patch file with any supported naming scheme,
+ // regardless of s_sciVersion value
Common::String mask, name;
Common::ArchiveMemberList files;
@@ -1253,11 +1211,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
const char *szResType;
ResourceSource *psrcPatch;
- for (int i = kResourceTypeView; i <= kResourceTypeRobot; ++i) {
- // TODO: add support for audio36 and sync36 files
- if (i == kResourceTypeAudio36 || i == kResourceTypeSync36)
- continue;
-
+ for (int i = kResourceTypeView; i <= kResourceTypeHeap; ++i) {
files.clear();
szResType = getResourceTypeName((ResourceType)i);
// SCI0 naming - type.nnn
@@ -1268,6 +1222,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
mask = "*.";
mask += resourceTypeSuffixes[i];
SearchMan.listMatchingMembers(files, mask);
+
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
bool bAdd = false;
name = (*x)->getName();
@@ -1289,75 +1244,42 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
psrcPatch = new ResourceSource;
psrcPatch->source_type = kSourcePatch;
psrcPatch->location_name = name;
+ psrcPatch->resourceFile = 0;
processPatch(psrcPatch, (ResourceType)i, number);
}
}
}
}
-void ResourceManager::readWaveAudioPatches() {
- // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, "*.wav");
-
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- Common::String name = (*x)->getName();
-
- if (isdigit(name[0])) {
- int number = atoi(name.c_str());
- ResourceSource *psrcPatch = new ResourceSource;
- psrcPatch->source_type = kSourceWave;
- psrcPatch->location_name = name;
- psrcPatch->volume_number = 0;
- psrcPatch->audioCompressionType = 0;
-
- ResourceId resId = ResourceId(kResourceTypeAudio, number);
-
- Resource *newrsc = NULL;
-
- // Prepare destination, if neccessary
- if (_resMap.contains(resId) == false) {
- newrsc = new Resource;
- _resMap.setVal(resId, newrsc);
- } else
- newrsc = _resMap.getVal(resId);
-
- // Get the size of the file
- Common::SeekableReadStream *stream = (*x)->createReadStream();
- uint32 fileSize = stream->size();
- delete stream;
-
- // Overwrite everything, because we're patching
- newrsc->_id = resId;
- newrsc->_status = kResStatusNoMalloc;
- newrsc->_source = psrcPatch;
- newrsc->size = fileSize;
- newrsc->_headerSize = 0;
- debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
- }
- }
-}
-
int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res;
ResourceType type;
uint16 number, id;
uint32 offset;
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
+ if (map->resourceFile) {
+ fileStream = map->resourceFile->createReadStream();
+ if (!fileStream)
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ fileStream = file;
+ }
- file.seek(0, SEEK_SET);
+ fileStream->seek(0, SEEK_SET);
byte bMask = (_mapVersion == kResVersionSci1Middle) ? 0xF0 : 0xFC;
byte bShift = (_mapVersion == kResVersionSci1Middle) ? 28 : 26;
do {
- id = file.readUint16LE();
- offset = file.readUint32LE();
+ id = fileStream->readUint16LE();
+ offset = fileStream->readUint32LE();
- if (file.eos() || file.err()) {
+ if (fileStream->eos() || fileStream->err()) {
+ delete fileStream;
warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND;
}
@@ -1386,15 +1308,26 @@ int ResourceManager::readResourceMapSCI0(ResourceSource *map) {
res->_id = resId;
_resMap.setVal(resId, res);
}
- } while (!file.eos());
+ } while (!fileStream->eos());
+
+ delete fileStream;
return 0;
}
int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res;
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ if (map->resourceFile) {
+ fileStream = map->resourceFile->createReadStream();
+ if (!fileStream)
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ } else {
+ Common::File *file = new Common::File();
+ if (!file->open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ fileStream = file;
+ }
resource_index_t resMap[32];
memset(resMap, 0, sizeof(resource_index_t) * 32);
@@ -1405,8 +1338,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// Read resource type and offsets to resource offsets block from .MAP file
// The last entry has type=0xFF (0x1F) and offset equals to map file length
do {
- type = file.readByte() & 0x1F;
- resMap[type].wOffset = file.readUint16LE();
+ type = fileStream->readByte() & 0x1F;
+ resMap[type].wOffset = fileStream->readUint16LE();
resMap[prevtype].wSize = (resMap[type].wOffset
- resMap[prevtype].wOffset) / nEntrySize;
prevtype = type;
@@ -1417,18 +1350,18 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
for (type = 0; type < 32; type++) {
if (resMap[type].wOffset == 0) // this resource does not exist in map
continue;
- file.seek(resMap[type].wOffset);
+ fileStream->seek(resMap[type].wOffset);
for (int i = 0; i < resMap[type].wSize; i++) {
- uint16 number = file.readUint16LE();
+ uint16 number = fileStream->readUint16LE();
int volume_nr = 0;
if (_mapVersion == kResVersionSci11) {
// offset stored in 3 bytes
- off = file.readUint16LE();
- off |= file.readByte() << 16;
+ off = fileStream->readUint16LE();
+ off |= fileStream->readByte() << 16;
off <<= 1;
} else {
// offset/volume stored in 4 bytes
- off = file.readUint32LE();
+ off = fileStream->readUint32LE();
if (_mapVersion < kResVersionSci11) {
volume_nr = off >> 28; // most significant 4 bits
off &= 0x0FFFFFFF; // least significant 28 bits
@@ -1436,7 +1369,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
// in SCI32 it's a plain offset
}
}
- if (file.eos() || file.err()) {
+ if (fileStream->eos() || fileStream->err()) {
+ delete fileStream;
warning("Error while reading %s", map->location_name.c_str());
return SCI_ERROR_RESMAP_NOT_FOUND;
}
@@ -1448,7 +1382,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
res->_id = resId;
// NOTE: We add the map's volume number here to the specified volume number
- // for SCI2.1 and SCI3 maps that are not RESMAP.000. The RESMAP.* files' numbers
+ // for SCI2.1 and SCI3 maps that are not resmap.000. The resmap.* files' numbers
// need to be used in concurrence with the volume specified in the map to get
// the actual resource file.
res->_source = getVolume(map, volume_nr + map->volume_number);
@@ -1456,6 +1390,8 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) {
}
}
}
+
+ delete fileStream;
return 0;
}
@@ -1476,7 +1412,11 @@ struct {
{ MKID_BE('PAL '), kResourceTypePalette },
{ MKID_BE('snd '), kResourceTypeAudio },
{ MKID_BE('MSG '), kResourceTypeMessage },
- { MKID_BE('HEP '), kResourceTypeHeap }
+ { MKID_BE('HEP '), kResourceTypeHeap },
+ { MKID_BE('IBIN'), kResourceTypeMacIconBarPictN },
+ { MKID_BE('IBIS'), kResourceTypeMacIconBarPictS },
+ { MKID_BE('PICT'), kResourceTypeMacPict },
+ { MKID_BE('SYN '), kResourceTypeSync }
};
static uint32 resTypeToMacTag(ResourceType type) {
@@ -1509,6 +1449,16 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
Common::MacResIDArray idArray = source->macResMan.getResIDArray(tagArray[i]);
for (uint32 j = 0; j < idArray.size(); j++) {
+ // Get the size of the file
+ Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
+
+ // Some IBIS resources have a size of 0, so we skip them
+ if (!stream)
+ continue;
+
+ uint32 fileSize = stream->size();
+ delete stream;
+
ResourceId resId = ResourceId(type, idArray[j]);
Resource *newrsc = NULL;
@@ -1520,11 +1470,6 @@ int ResourceManager::readMacResourceFork(ResourceSource *source) {
} else
newrsc = _resMap.getVal(resId);
- // Get the size of the file
- Common::SeekableReadStream *stream = source->macResMan.getResource(tagArray[i], idArray[j]);
- uint32 fileSize = stream->size();
- delete stream;
-
// Overwrite everything
newrsc->_id = resId;
newrsc->_status = kResStatusNoMalloc;
@@ -1549,261 +1494,6 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32
}
}
-void ResourceManager::removeAudioResource(ResourceId resId) {
- // Remove resource, unless it was loaded from a patch
- if (_resMap.contains(resId)) {
- Resource *res = _resMap.getVal(resId);
-
- if (res->_source->source_type == kSourceAudioVolume) {
- if (res->_status == kResStatusLocked) {
- warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
- } else {
- if (res->_status == kResStatusEnqueued)
- removeFromLRU(res);
-
- _resMap.erase(resId);
- delete res;
- }
- }
- }
-}
-
-// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
-// =========
-// 6-byte entries:
-// w nEntry
-// dw offset
-
-// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
-// =========
-// 5-byte entries:
-// w nEntry
-// tb offset (cumulative)
-
-// Early SCI1.1 MAP structure:
-// ===============
-// 10-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// dw offset
-// w syncSize + syncAscSize
-
-// Late SCI1.1 MAP structure:
-// ===============
-// Header:
-// dw baseOffset
-// Followed by 7 or 11-byte entries:
-// b noun
-// b verb
-// b cond
-// b seq
-// tb cOffset (cumulative offset)
-// w syncSize (iff seq has bit 7 set)
-// w syncAscSize (iff seq has bit 6 set)
-
-int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
- bool isEarly = true;
- uint32 offset = 0;
- Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
-
- if (!mapRes) {
- warning("Failed to open %i.MAP", map->volume_number);
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- ResourceSource *src = getVolume(map, 0);
-
- if (!src)
- return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
-
- byte *ptr = mapRes->data;
-
- if (map->volume_number == 65535) {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
- isEarly = false;
-
- while (ptr < mapRes->data + mapRes->size) {
- uint16 n = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (n == 0xffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- addResource(ResourceId(kResourceTypeAudio, n), src, offset);
- }
- } else {
- // Heuristic to detect late SCI1.1 map format
- if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
- isEarly = false;
-
- if (!isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- }
-
- while (ptr < mapRes->data + mapRes->size) {
- uint32 n = READ_BE_UINT32(ptr);
- int syncSize = 0;
- ptr += 4;
-
- if (n == 0xffffffff)
- break;
-
- if (isEarly) {
- offset = READ_LE_UINT32(ptr);
- ptr += 4;
- } else {
- offset += READ_LE_UINT24(ptr);
- ptr += 3;
- }
-
- if (isEarly || (n & 0x80)) {
- syncSize = READ_LE_UINT16(ptr);
- ptr += 2;
-
- if (syncSize > 0)
- addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
- }
-
- if (n & 0x40) {
- syncSize += READ_LE_UINT16(ptr);
- ptr += 2;
- }
-
- addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
- }
- }
-
- return 0;
-}
-
-// AUDIOnnn.MAP contains 10-byte entries:
-// Early format:
-// w 5 bits resource type and 11 bits resource number
-// dw 7 bits volume number and 25 bits offset
-// dw size
-// Later format:
-// w nEntry
-// dw offset+volume (as in resource.map)
-// dw size
-// ending with 10 0xFFs
-int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
- Common::File file;
-
- if (!file.open(map->location_name))
- return SCI_ERROR_RESMAP_NOT_FOUND;
-
- bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
- file.seek(0);
-
- while (1) {
- uint16 n = file.readUint16LE();
- uint32 offset = file.readUint32LE();
- uint32 size = file.readUint32LE();
-
- if (file.eos() || file.err()) {
- warning("Error while reading %s", map->location_name.c_str());
- return SCI_ERROR_RESMAP_NOT_FOUND;
- }
-
- if (n == 0xffff)
- break;
-
- byte volume_nr;
-
- if (oldFormat) {
- n &= 0x07ff; // Mask out resource type
- volume_nr = offset >> 25; // most significant 7 bits
- offset &= 0x01ffffff; // least significant 25 bits
- } else {
- volume_nr = offset >> 28; // most significant 4 bits
- offset &= 0x0fffffff; // least significant 28 bits
- }
-
- ResourceSource *src = getVolume(map, volume_nr);
-
- if (src) {
- if (unload)
- removeAudioResource(ResourceId(kResourceTypeAudio, n));
- else
- addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
- } else {
- warning("Failed to find audio volume %i", volume_nr);
- }
- }
-
- return 0;
-}
-
-void ResourceManager::setAudioLanguage(int language) {
- if (_audioMapSCI1) {
- if (_audioMapSCI1->volume_number == language) {
- // This language is already loaded
- return;
- }
-
- // We already have a map loaded, so we unload it first
- readAudioMapSCI1(_audioMapSCI1, true);
-
- // Remove all volumes that use this map from the source list
- Common::List<ResourceSource *>::iterator it = _sources.begin();
- while (it != _sources.end()) {
- ResourceSource *src = *it;
- if (src->associated_map == _audioMapSCI1) {
- it = _sources.erase(it);
- delete src;
- } else {
- ++it;
- }
- }
-
- // Remove the map itself from the source list
- _sources.remove(_audioMapSCI1);
- delete _audioMapSCI1;
-
- _audioMapSCI1 = NULL;
- }
-
- char filename[9];
- snprintf(filename, 9, "AUDIO%03d", language);
-
- Common::String fullname = Common::String(filename) + ".MAP";
- if (!Common::File::exists(fullname)) {
- warning("No audio map found for language %i", language);
- return;
- }
-
- _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
-
- // Search for audio volumes for this language and add them to the source list
- Common::ArchiveMemberList files;
- SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- const Common::String name = (*x)->getName();
- const char *dot = strrchr(name.c_str(), '.');
- int number = atoi(dot + 1);
-
- addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
- }
-
- scanNewSources();
-}
-
-int ResourceManager::getAudioLanguage() const {
- return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
-}
-
int ResourceManager::readResourceInfo(Resource *res, Common::SeekableReadStream *file,
uint32&szPacked, ResourceCompression &compression) {
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
@@ -1954,7 +1644,7 @@ ResourceCompression ResourceManager::getViewCompression() {
// Test 10 views to see if any are compressed
for (int i = 0; i < 1000; i++) {
- Common::File *file;
+ Common::SeekableReadStream *fileStream = 0;
Resource *res = testResource(ResourceId(kResourceTypeView, i));
if (!res)
@@ -1963,16 +1653,23 @@ ResourceCompression ResourceManager::getViewCompression() {
if (res->_source->source_type != kSourceVolume)
continue;
- file = getVolumeFile(res->_source->location_name.c_str());
- if (!file)
+ fileStream = getVolumeFile(res->_source);
+
+ if (!fileStream)
continue;
- file->seek(res->_fileOffset, SEEK_SET);
+ fileStream->seek(res->_fileOffset, SEEK_SET);
uint32 szPacked;
ResourceCompression compression;
- if (readResourceInfo(res, file, szPacked, compression))
+ if (readResourceInfo(res, fileStream, szPacked, compression)) {
+ if (res->_source->resourceFile)
+ delete fileStream;
continue;
+ }
+
+ if (res->_source->resourceFile)
+ delete fileStream;
if (compression != kCompNone)
return compression;
@@ -2329,248 +2026,98 @@ bool ResourceManager::hasSci1Voc900() {
return offset == res->size;
}
-SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
- Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
- int trackNr, channelNr;
- if (!resource)
- return;
-
- _innerResource = resource;
-
- byte *data, *data2;
- byte *dataEnd;
- Channel *channel, *sampleChannel;
-
- switch (_soundVersion) {
- case SCI_VERSION_0_EARLY:
- case SCI_VERSION_0_LATE:
- // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
- _trackCount = 1;
- _tracks = new Track[_trackCount];
- _tracks->digitalChannelNr = -1;
- _tracks->type = 0; // Not used for SCI0
- _tracks->channelCount = 1;
- // Digital sample data included? -> Add an additional channel
- if (resource->data[0] == 2)
- _tracks->channelCount++;
- _tracks->channels = new Channel[_tracks->channelCount];
- memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
- channel = &_tracks->channels[0];
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- channel->data = resource->data + 0x11;
- channel->size = resource->size - 0x11;
- } else {
- channel->data = resource->data + 0x21;
- channel->size = resource->size - 0x21;
- }
- if (_tracks->channelCount == 2) {
- // Digital sample data included
- _tracks->digitalChannelNr = 1;
- sampleChannel = &_tracks->channels[1];
- // we need to find 0xFC (channel terminator) within the data
- data = channel->data;
- dataEnd = channel->data + channel->size;
- while ((data < dataEnd) && (*data != 0xfc))
- data++;
- // Skip any following 0xFCs as well
- while ((data < dataEnd) && (*data == 0xfc))
- data++;
- // Now adjust channels accordingly
- sampleChannel->data = data;
- sampleChannel->size = channel->size - (data - channel->data);
- channel->size = data - channel->data;
- // Read sample header information
- //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
- _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
- _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
- _tracks->digitalSampleStart = 0;
- _tracks->digitalSampleEnd = 0;
- sampleChannel->data += 44; // Skip over header
- sampleChannel->size -= 44;
- }
- break;
-
- case SCI_VERSION_1_EARLY:
- case SCI_VERSION_1_LATE:
- data = resource->data;
- // Count # of tracks
- _trackCount = 0;
- while ((*data++) != 0xFF) {
- _trackCount++;
- while (*data != 0xFF)
- data += 6;
- data++;
- }
- _tracks = new Track[_trackCount];
- data = resource->data;
- for (trackNr = 0; trackNr < _trackCount; trackNr++) {
- // Track info starts with track type:BYTE
- // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
- // 0xFF:BYTE as terminator to end that track and begin with another track type
- // Track type 0xFF is the marker signifying the end of the tracks
-
- _tracks[trackNr].type = *data++;
- // Counting # of channels used
- data2 = data;
- _tracks[trackNr].channelCount = 0;
- while (*data2 != 0xFF) {
- data2 += 6;
- _tracks[trackNr].channelCount++;
- }
- _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
- _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
- _tracks[trackNr].digitalSampleRate = 0;
- _tracks[trackNr].digitalSampleSize = 0;
- _tracks[trackNr].digitalSampleStart = 0;
- _tracks[trackNr].digitalSampleEnd = 0;
- if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
- for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
- channel = &_tracks[trackNr].channels[channelNr];
- channel->prio = READ_LE_UINT16(data);
- channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
- channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
- channel->number = *(channel->data - 2);
- channel->poly = *(channel->data - 1);
- channel->time = channel->prev = 0;
- if (channel->number == 0xFE) { // Digital channel
- _tracks[trackNr].digitalChannelNr = channelNr;
- _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
- _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
- _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
- _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
- channel->data += 8; // Skip over header
- channel->size -= 8;
- }
- data += 6;
- }
- } else {
- // Skip over digital track
- data += 6;
- }
- data++; // Skipping 0xFF that closes channels list
- }
- break;
-
- default:
- error("SoundResource: SCI version %d is unsupported", _soundVersion);
- }
-}
-
-SoundResource::~SoundResource() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++)
- delete[] _tracks[trackNr].channels;
- delete[] _tracks;
+// Same function as Script::findBlock(). Slight code
+// duplication here, but this has been done to keep the resource
+// manager independent from the rest of the engine
+static byte *findSci0ExportsBlock(byte *buffer) {
+ byte *buf = buffer;
+ bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY);
- _resMan->unlockResource(_innerResource);
-}
+ if (oldScriptHeader)
+ buf += 2;
-#if 0
-SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
-
- if (/*number >= 0 &&*/number < _trackCount)
- return &_tracks[number];
- return NULL;
-}
-#endif
+ do {
+ int seekerType = READ_LE_UINT16(buf);
-SoundResource::Track *SoundResource::getTrackByType(byte type) {
- if (_soundVersion <= SCI_VERSION_0_LATE)
- return &_tracks[0];
+ if (seekerType == 0)
+ break;
+ if (seekerType == 7) // exports
+ return buf;
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].type == type)
- return &_tracks[trackNr];
- }
- return NULL;
-}
+ int seekerSize = READ_LE_UINT16(buf + 2);
+ assert(seekerSize > 0);
+ buf += seekerSize;
+ } while (1);
-SoundResource::Track *SoundResource::getDigitalTrack() {
- for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
- if (_tracks[trackNr].digitalChannelNr != -1)
- return &_tracks[trackNr];
- }
return NULL;
}
-// Gets the filter mask for SCI0 sound resources
-int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
- byte *data = _innerResource->data;
- int channelMask = 0;
-
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0;
+reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) {
+ Resource *script = findResource(ResourceId(kResourceTypeScript, 0), false);
- data++; // Skip over digital sample flag
+ if (!script)
+ return NULL_REG;
- for (int channelNr = 0; channelNr < 16; channelNr++) {
- channelMask = channelMask >> 1;
+ byte *offsetPtr = 0;
- byte flags;
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ byte *buf = (getSciVersion() == SCI_VERSION_0_EARLY) ? script->data + 2 : script->data;
- if (_soundVersion == SCI_VERSION_0_EARLY) {
- // Each channel is specified by a single byte
- // Upper 4 bits of the byte is a voices count
- // Lower 4 bits -> bit 0 set: use for AdLib
- // bit 1 set: use for PCjr
- // bit 2 set: use for PC speaker
- // bit 3 set and bit 0 clear: control channel (15)
- // bit 3 set and bit 0 set: rhythm channel (9)
- // Note: control channel is dynamically assigned inside the drivers,
- // but seems to be fixed at 15 in the song data.
- flags = *data++;
-
- // Get device bits
- flags &= 0x7;
+ // Check if the first block is the exports block (in most cases, it is)
+ bool exportsIsFirst = (READ_LE_UINT16(buf + 4) == 7);
+ if (exportsIsFirst) {
+ offsetPtr = buf + 4 + 2;
} else {
- // Each channel is specified by 2 bytes
- // 1st byte is voices count
- // 2nd byte is play mask, which specifies if the channel is supposed to be played
- // by the corresponding hardware
-
- // Skip voice count
- data++;
-
- flags = *data++;
+ offsetPtr = findSci0ExportsBlock(script->data);
+ if (!offsetPtr)
+ error("Unable to find exports block from script 0");
+ offsetPtr += 4 + 2;
}
+ } else {
+ offsetPtr = script->data + 4 + 2 + 2;
+ }
+
+ int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr);
- bool play;
- switch (channelNr) {
- case 15:
- // Always play control channel
- play = true;
- break;
- case 9:
- // Play rhythm channel when requested
- play = wantsRhythm;
- break;
- default:
- // Otherwise check for flag
- play = flags & hardwareMask;
- }
+ // In SCI1.1 and newer, the heap is appended at the end of the script,
+ // so adjust the offset accordingly
+ if (getSciVersion() >= SCI_VERSION_1_1 && addSci11ScriptOffset) {
+ offset += script->size;
- if (play) {
- // This Channel is supposed to be played by the hardware
- channelMask |= 0x8000;
- }
+ // Ensure that the start of the heap is word-aligned - same as in Script::init()
+ if (script->size & 2)
+ offset++;
}
- return channelMask;
+ return make_reg(1, offset);
}
-byte SoundResource::getInitialVoiceCount(byte channel) {
- byte *data = _innerResource->data;
+Common::String ResourceManager::findSierraGameId() {
+ // In SCI0-SCI1, the heap is embedded in the script. In SCI1.1+, it's separated
+ Resource *heap = 0;
+ int nameSelector = 3;
- if (_soundVersion > SCI_VERSION_0_LATE)
- return 0; // TODO
+ if (getSciVersion() < SCI_VERSION_1_1) {
+ heap = findResource(ResourceId(kResourceTypeScript, 0), false);
+ } else {
+ heap = findResource(ResourceId(kResourceTypeHeap, 0), false);
+ nameSelector += 5;
+ }
- data++; // Skip over digital sample flag
+ if (!heap)
+ return "";
- if (_soundVersion == SCI_VERSION_0_EARLY)
- return data[channel] >> 4;
- else
- return data[channel * 2];
+ int16 gameObjectOffset = findGameObject(false).offset;
+
+ if (!gameObjectOffset)
+ return "";
+
+ // Seek to the name selector of the first export
+ byte *seeker = heap->data + READ_UINT16(heap->data + gameObjectOffset + nameSelector * 2);
+ Common::String sierraId;
+ sierraId += (const char *)seeker;
+
+ return sierraId;
}
} // End of namespace Sci
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 48b5f095b1..43e61eaadb 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -26,8 +26,9 @@
#ifndef SCI_SCICORE_RESOURCE_H
#define SCI_SCICORE_RESOURCE_H
-#include "common/str.h"
#include "common/fs.h"
+#include "common/macresman.h"
+#include "common/str.h"
#include "sci/graphics/helpers.h" // for ViewType
#include "sci/decompressor.h"
@@ -108,14 +109,31 @@ enum ResourceType {
kResourceTypeUnknown1, // Translation, currently unsupported
kResourceTypeUnknown2,
kResourceTypeRobot,
- kResourceTypeInvalid
+ kResourceTypeInvalid,
+
+ // Mac-only resources, these resource types are self-defined
+ // Numbers subject to change
+ kResourceTypeMacIconBarPictN = -1, // IBIN resources (icon bar, not selected)
+ kResourceTypeMacIconBarPictS = -2, // IBIS resources (icon bar, selected)
+ kResourceTypeMacPict = -3 // PICT resources (inventory)
};
const char *getResourceTypeName(ResourceType restype);
class ResourceManager;
-struct ResourceSource;
+
+struct ResourceSource {
+ ResSourceType source_type;
+ bool scanned;
+ Common::String location_name; // FIXME: Replace by FSNode ?
+ const Common::FSNode *resourceFile;
+ int volume_number;
+ ResourceSource *associated_map;
+ uint32 audioCompressionType;
+ int32 *audioCompressionOffsetMapping;
+ Common::MacResManager macResMan;
+};
class ResourceId {
public:
@@ -127,7 +145,7 @@ public:
ResourceId(ResourceType type_, uint16 number_, uint32 tuple_ = 0)
: type(type_), number(number_), tuple(tuple_) {
- if ((type < kResourceTypeView) || (type > kResourceTypeInvalid))
+ if (type < kResourceTypeMacPict || type > kResourceTypeInvalid)
type = kResourceTypeInvalid;
}
@@ -273,6 +291,19 @@ public:
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
+ /**
+ * Finds the internal Sierra ID of the current game from script 0
+ */
+ Common::String findSierraGameId();
+
+ /**
+ * Finds the location of the game object from script 0
+ * @param addSci11ScriptOffset: Adjust the return value for SCI1.1 and newer
+ * games. Needs to be false when the heap is accessed directly inside
+ * findSierraGameId().
+ */
+ reg_t findGameObject(bool addSci11ScriptOffset = true);
+
protected:
// Maximum number of bytes to allow being allocated for resources
// Note: maxMemory will not be interpreted as a hard limit, only as a restriction
@@ -290,8 +321,8 @@ protected:
ResourceMap _resMap;
Common::List<Common::File *> _volumeFiles; ///< list of opened volume files
ResourceSource *_audioMapSCI1; ///< Currently loaded audio map for SCI1
- ResVersion _volVersion; ///< RESOURCE.0xx version
- ResVersion _mapVersion; ///< RESOURCE.MAP version
+ ResVersion _volVersion; ///< resource.0xx version
+ ResVersion _mapVersion; ///< resource.map version
/**
* Initializes the resource manager
@@ -327,7 +358,7 @@ protected:
*/
ResourceSource *addExternalMap(const char *file_name, int volume_nr = 0);
- ResourceSource *addExternalMap(const Common::FSNode *mapFile);
+ ResourceSource *addExternalMap(const Common::FSNode *mapFile, int volume_nr = 0);
/**
* Add an internal (i.e., resource) map to the resource manager's list of sources.
@@ -362,13 +393,13 @@ protected:
*/
const char *versionDescription(ResVersion version) const;
- Common::File *getVolumeFile(const char *filename);
+ Common::SeekableReadStream *getVolumeFile(ResourceSource *source);
void loadResource(Resource *res);
- bool loadPatch(Resource *res, Common::File &file);
+ bool loadPatch(Resource *res, Common::SeekableReadStream *file);
bool loadFromPatchFile(Resource *res);
- bool loadFromWaveFile(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file);
- bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file);
+ bool loadFromWaveFile(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file);
+ bool loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file);
void freeOldResources();
int decompress(Resource *res, Common::SeekableReadStream *file);
int readResourceInfo(Resource *res, Common::SeekableReadStream *file, uint32&szPacked, ResourceCompression &compression);
@@ -421,7 +452,10 @@ protected:
* Reads patch files from a local directory.
*/
void readResourcePatches(ResourceSource *source);
- void processPatch(ResourceSource *source, ResourceType restype, int resnumber);
+#ifdef ENABLE_SCI32
+ void readResourcePatchesBase36(ResourceSource *source);
+#endif
+ void processPatch(ResourceSource *source, ResourceType restype, uint16 resnumber, uint32 tuple = 0);
/**
* Process wave files as patches for Audio resources
@@ -481,6 +515,7 @@ public:
Track *getDigitalTrack();
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
byte getInitialVoiceCount(byte channel);
+ bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
private:
SciVersion _soundVersion;
@@ -488,6 +523,9 @@ private:
Track *_tracks;
Resource *_innerResource;
ResourceManager *_resMan;
+ uint16 _channelsUsed;
+
+ void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
};
} // End of namespace Sci
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
new file mode 100644
index 0000000000..57efbdcb38
--- /dev/null
+++ b/engines/sci/resource_audio.cpp
@@ -0,0 +1,711 @@
+/* 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$
+ *
+ */
+
+// Resource library
+
+#include "common/file.h"
+
+#include "sci/resource.h"
+#include "sci/util.h"
+
+namespace Sci {
+
+void ResourceManager::checkIfAudioVolumeIsCompressed(ResourceSource *source) {
+ Common::SeekableReadStream *fileStream = getVolumeFile(source);
+
+ if (!fileStream) {
+ warning("Failed to open %s", source->location_name.c_str());
+ return;
+ }
+
+ fileStream->seek(0, SEEK_SET);
+ uint32 compressionType = fileStream->readUint32BE();
+ switch (compressionType) {
+ case MKID_BE('MP3 '):
+ case MKID_BE('OGG '):
+ case MKID_BE('FLAC'):
+ // Detected a compressed audio volume
+ source->audioCompressionType = compressionType;
+ // Now read the whole offset mapping table for later usage
+ int32 recordCount = fileStream->readUint32LE();
+ if (!recordCount)
+ error("compressed audio volume doesn't contain any entries!");
+ int32 *offsetMapping = new int32[(recordCount + 1) * 2];
+ source->audioCompressionOffsetMapping = offsetMapping;
+ for (int recordNo = 0; recordNo < recordCount; recordNo++) {
+ *offsetMapping++ = fileStream->readUint32LE();
+ *offsetMapping++ = fileStream->readUint32LE();
+ }
+ // Put ending zero
+ *offsetMapping++ = 0;
+ *offsetMapping++ = fileStream->size();
+ }
+
+ if (source->resourceFile)
+ delete fileStream;
+}
+
+bool ResourceManager::loadFromWaveFile(Resource *res, Common::SeekableReadStream *file) {
+ res->data = new byte[res->size];
+
+ uint32 really_read = file->read(res->data, res->size);
+ if (really_read != res->size)
+ error("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::SeekableReadStream *file) {
+ // Check for WAVE files here
+ uint32 riffTag = file->readUint32BE();
+ if (riffTag == MKID_BE('RIFF')) {
+ res->_headerSize = 0;
+ res->size = file->readUint32LE();
+ file->seek(-8, SEEK_CUR);
+ return loadFromWaveFile(res, file);
+ }
+ file->seek(-4, SEEK_CUR);
+
+ ResourceType type = (ResourceType)(file->readByte() & 0x7f);
+ if (((res->_id.type == kResourceTypeAudio || res->_id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio))
+ || ((res->_id.type == kResourceTypeSync || res->_id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) {
+ warning("Resource type mismatch loading %s", res->_id.toString().c_str());
+ res->unalloc();
+ return false;
+ }
+
+ res->_headerSize = file->readByte();
+
+ if (type == kResourceTypeAudio) {
+ if (res->_headerSize != 11 && res->_headerSize != 12) {
+ warning("Unsupported audio header");
+ res->unalloc();
+ return false;
+ }
+
+ // Load sample size
+ file->seek(7, SEEK_CUR);
+ res->size = file->readUint32LE();
+ // Adjust offset to point at the header data again
+ file->seek(-11, SEEK_CUR);
+ }
+
+ return loadPatch(res, file);
+}
+
+bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::SeekableReadStream *file) {
+ res->data = new byte[res->size];
+
+ if (res->data == NULL) {
+ error("Can't allocate %d bytes needed for loading %s", res->size, res->_id.toString().c_str());
+ }
+
+ unsigned int really_read = file->read(res->data, res->size);
+ if (really_read != res->size)
+ warning("Read %d bytes from %s but expected %d", really_read, res->_id.toString().c_str(), res->size);
+
+ res->_status = kResStatusAllocated;
+ return true;
+}
+
+void ResourceManager::addNewGMPatch(const Common::String &gameId) {
+ Common::String gmPatchFile;
+
+ if (gameId == "ecoquest")
+ gmPatchFile = "ECO1GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "hoyle3")
+ gmPatchFile = "HOY3GM.PAT";
+ else if (gameId == "lsl1sci")
+ gmPatchFile = "LL1_GM.PAT";
+ else if (gameId == "lsl5")
+ gmPatchFile = "LL5_GM.PAT";
+ else if (gameId == "longbow")
+ gmPatchFile = "ROBNGM.PAT";
+ else if (gameId == "sq1sci")
+ gmPatchFile = "SQ1_GM.PAT";
+ else if (gameId == "sq4")
+ gmPatchFile = "SQ4_GM.PAT";
+ else if (gameId == "fairytales")
+ gmPatchFile = "TALEGM.PAT";
+
+ if (!gmPatchFile.empty() && Common::File::exists(gmPatchFile)) {
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourcePatch;
+ psrcPatch->resourceFile = 0;
+ psrcPatch->location_name = gmPatchFile;
+ processPatch(psrcPatch, kResourceTypePatch, 4);
+ }
+}
+
+void ResourceManager::readWaveAudioPatches() {
+ // Here we do check for SCI1.1+ so we can patch wav files in as audio resources
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, "*.wav");
+
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ Common::String name = (*x)->getName();
+
+ if (isdigit(name[0])) {
+ int number = atoi(name.c_str());
+ ResourceSource *psrcPatch = new ResourceSource;
+ psrcPatch->source_type = kSourceWave;
+ psrcPatch->resourceFile = 0;
+ psrcPatch->location_name = name;
+ psrcPatch->volume_number = 0;
+ psrcPatch->audioCompressionType = 0;
+
+ ResourceId resId = ResourceId(kResourceTypeAudio, number);
+
+ Resource *newrsc = NULL;
+
+ // Prepare destination, if neccessary
+ if (_resMap.contains(resId) == false) {
+ newrsc = new Resource;
+ _resMap.setVal(resId, newrsc);
+ } else
+ newrsc = _resMap.getVal(resId);
+
+ // Get the size of the file
+ Common::SeekableReadStream *stream = (*x)->createReadStream();
+ uint32 fileSize = stream->size();
+ delete stream;
+
+ // Overwrite everything, because we're patching
+ newrsc->_id = resId;
+ newrsc->_status = kResStatusNoMalloc;
+ newrsc->_source = psrcPatch;
+ newrsc->size = fileSize;
+ newrsc->_headerSize = 0;
+ debugC(1, kDebugLevelResMan, "Patching %s - OK", psrcPatch->location_name.c_str());
+ }
+ }
+}
+
+void ResourceManager::removeAudioResource(ResourceId resId) {
+ // Remove resource, unless it was loaded from a patch
+ if (_resMap.contains(resId)) {
+ Resource *res = _resMap.getVal(resId);
+
+ if (res->_source->source_type == kSourceAudioVolume) {
+ if (res->_status == kResStatusLocked) {
+ warning("Failed to remove resource %s (still in use)", resId.toString().c_str());
+ } else {
+ if (res->_status == kResStatusEnqueued)
+ removeFromLRU(res);
+
+ _resMap.erase(resId);
+ delete res;
+ }
+ }
+ }
+}
+
+// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
+// =========
+// 6-byte entries:
+// w nEntry
+// dw offset
+
+// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
+// =========
+// 5-byte entries:
+// w nEntry
+// tb offset (cumulative)
+
+// Early SCI1.1 MAP structure:
+// ===============
+// 10-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// dw offset
+// w syncSize + syncAscSize
+
+// Late SCI1.1 MAP structure:
+// ===============
+// Header:
+// dw baseOffset
+// Followed by 7 or 11-byte entries:
+// b noun
+// b verb
+// b cond
+// b seq
+// tb cOffset (cumulative offset)
+// w syncSize (iff seq has bit 7 set)
+// w syncAscSize (iff seq has bit 6 set)
+
+int ResourceManager::readAudioMapSCI11(ResourceSource *map) {
+ bool isEarly = true;
+ uint32 offset = 0;
+ Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false);
+
+ if (!mapRes) {
+ warning("Failed to open %i.MAP", map->volume_number);
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ ResourceSource *src = getVolume(map, 0);
+
+ if (!src)
+ return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
+
+ byte *ptr = mapRes->data;
+
+ if (map->volume_number == 65535) {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 6) && (ptr[mapRes->size - 6] != 0xff))
+ isEarly = false;
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint16 n = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (n == 0xffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset);
+ }
+ } else {
+ // Heuristic to detect late SCI1.1 map format
+ if ((mapRes->size >= 11) && (ptr[mapRes->size - 11] == 0xff))
+ isEarly = false;
+
+ if (!isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ }
+
+ while (ptr < mapRes->data + mapRes->size) {
+ uint32 n = READ_BE_UINT32(ptr);
+ int syncSize = 0;
+ ptr += 4;
+
+ if (n == 0xffffffff)
+ break;
+
+ if (isEarly) {
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+ } else {
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+ }
+
+ if (isEarly || (n & 0x80)) {
+ syncSize = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (syncSize > 0)
+ addResource(ResourceId(kResourceTypeSync36, map->volume_number, n & 0xffffff3f), src, offset, syncSize);
+ }
+
+ if (n & 0x40) {
+ syncSize += READ_LE_UINT16(ptr);
+ ptr += 2;
+ }
+
+ addResource(ResourceId(kResourceTypeAudio36, map->volume_number, n & 0xffffff3f), src, offset + syncSize);
+ }
+ }
+
+ return 0;
+}
+
+// AUDIOnnn.MAP contains 10-byte entries:
+// Early format:
+// w 5 bits resource type and 11 bits resource number
+// dw 7 bits volume number and 25 bits offset
+// dw size
+// Later format:
+// w nEntry
+// dw offset+volume (as in resource.map)
+// dw size
+// ending with 10 0xFFs
+int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) {
+ Common::File file;
+
+ if (!file.open(map->location_name))
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+
+ bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio;
+ file.seek(0);
+
+ while (1) {
+ uint16 n = file.readUint16LE();
+ uint32 offset = file.readUint32LE();
+ uint32 size = file.readUint32LE();
+
+ if (file.eos() || file.err()) {
+ warning("Error while reading %s", map->location_name.c_str());
+ return SCI_ERROR_RESMAP_NOT_FOUND;
+ }
+
+ if (n == 0xffff)
+ break;
+
+ byte volume_nr;
+
+ if (oldFormat) {
+ n &= 0x07ff; // Mask out resource type
+ volume_nr = offset >> 25; // most significant 7 bits
+ offset &= 0x01ffffff; // least significant 25 bits
+ } else {
+ volume_nr = offset >> 28; // most significant 4 bits
+ offset &= 0x0fffffff; // least significant 28 bits
+ }
+
+ ResourceSource *src = getVolume(map, volume_nr);
+
+ if (src) {
+ if (unload)
+ removeAudioResource(ResourceId(kResourceTypeAudio, n));
+ else
+ addResource(ResourceId(kResourceTypeAudio, n), src, offset, size);
+ } else {
+ warning("Failed to find audio volume %i", volume_nr);
+ }
+ }
+
+ return 0;
+}
+
+void ResourceManager::setAudioLanguage(int language) {
+ if (_audioMapSCI1) {
+ if (_audioMapSCI1->volume_number == language) {
+ // This language is already loaded
+ return;
+ }
+
+ // We already have a map loaded, so we unload it first
+ readAudioMapSCI1(_audioMapSCI1, true);
+
+ // Remove all volumes that use this map from the source list
+ Common::List<ResourceSource *>::iterator it = _sources.begin();
+ while (it != _sources.end()) {
+ ResourceSource *src = *it;
+ if (src->associated_map == _audioMapSCI1) {
+ it = _sources.erase(it);
+ delete src;
+ } else {
+ ++it;
+ }
+ }
+
+ // Remove the map itself from the source list
+ _sources.remove(_audioMapSCI1);
+ delete _audioMapSCI1;
+
+ _audioMapSCI1 = NULL;
+ }
+
+ char filename[9];
+ snprintf(filename, 9, "AUDIO%03d", language);
+
+ Common::String fullname = Common::String(filename) + ".MAP";
+ if (!Common::File::exists(fullname)) {
+ warning("No audio map found for language %i", language);
+ return;
+ }
+
+ _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language);
+
+ // Search for audio volumes for this language and add them to the source list
+ Common::ArchiveMemberList files;
+ SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??");
+ for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
+ const Common::String name = (*x)->getName();
+ const char *dot = strrchr(name.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number);
+ }
+
+ scanNewSources();
+}
+
+int ResourceManager::getAudioLanguage() const {
+ return (_audioMapSCI1 ? _audioMapSCI1->volume_number : 0);
+}
+
+SoundResource::SoundResource(uint32 resNumber, ResourceManager *resMan, SciVersion soundVersion) : _resMan(resMan), _soundVersion(soundVersion) {
+ Resource *resource = _resMan->findResource(ResourceId(kResourceTypeSound, resNumber), true);
+ int trackNr, channelNr;
+ if (!resource)
+ return;
+
+ _innerResource = resource;
+
+ byte *data, *data2;
+ byte *dataEnd;
+ Channel *channel, *sampleChannel;
+
+ _channelsUsed = 0;
+
+ switch (_soundVersion) {
+ case SCI_VERSION_0_EARLY:
+ case SCI_VERSION_0_LATE:
+ // SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
+ _trackCount = 1;
+ _tracks = new Track[_trackCount];
+ _tracks->digitalChannelNr = -1;
+ _tracks->type = 0; // Not used for SCI0
+ _tracks->channelCount = 1;
+ // Digital sample data included? -> Add an additional channel
+ if (resource->data[0] == 2)
+ _tracks->channelCount++;
+ _tracks->channels = new Channel[_tracks->channelCount];
+ memset(_tracks->channels, 0, sizeof(Channel) * _tracks->channelCount);
+ channel = &_tracks->channels[0];
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ channel->data = resource->data + 0x11;
+ channel->size = resource->size - 0x11;
+ } else {
+ channel->data = resource->data + 0x21;
+ channel->size = resource->size - 0x21;
+ }
+ if (_tracks->channelCount == 2) {
+ // Digital sample data included
+ _tracks->digitalChannelNr = 1;
+ sampleChannel = &_tracks->channels[1];
+ // we need to find 0xFC (channel terminator) within the data
+ data = channel->data;
+ dataEnd = channel->data + channel->size;
+ while ((data < dataEnd) && (*data != 0xfc))
+ data++;
+ // Skip any following 0xFCs as well
+ while ((data < dataEnd) && (*data == 0xfc))
+ data++;
+ // Now adjust channels accordingly
+ sampleChannel->data = data;
+ sampleChannel->size = channel->size - (data - channel->data);
+ channel->size = data - channel->data;
+ // Read sample header information
+ //Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
+ _tracks->digitalSampleRate = READ_LE_UINT16(sampleChannel->data + 14);
+ _tracks->digitalSampleSize = READ_LE_UINT16(sampleChannel->data + 32);
+ _tracks->digitalSampleStart = 0;
+ _tracks->digitalSampleEnd = 0;
+ sampleChannel->data += 44; // Skip over header
+ sampleChannel->size -= 44;
+ }
+ break;
+
+ case SCI_VERSION_1_EARLY:
+ case SCI_VERSION_1_LATE:
+ data = resource->data;
+ // Count # of tracks
+ _trackCount = 0;
+ while ((*data++) != 0xFF) {
+ _trackCount++;
+ while (*data != 0xFF)
+ data += 6;
+ data++;
+ }
+ _tracks = new Track[_trackCount];
+ data = resource->data;
+ for (trackNr = 0; trackNr < _trackCount; trackNr++) {
+ // Track info starts with track type:BYTE
+ // Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
+ // 0xFF:BYTE as terminator to end that track and begin with another track type
+ // Track type 0xFF is the marker signifying the end of the tracks
+
+ _tracks[trackNr].type = *data++;
+ // Counting # of channels used
+ data2 = data;
+ _tracks[trackNr].channelCount = 0;
+ while (*data2 != 0xFF) {
+ data2 += 6;
+ _tracks[trackNr].channelCount++;
+ }
+ _tracks[trackNr].channels = new Channel[_tracks[trackNr].channelCount];
+ _tracks[trackNr].digitalChannelNr = -1; // No digital sound associated
+ _tracks[trackNr].digitalSampleRate = 0;
+ _tracks[trackNr].digitalSampleSize = 0;
+ _tracks[trackNr].digitalSampleStart = 0;
+ _tracks[trackNr].digitalSampleEnd = 0;
+ if (_tracks[trackNr].type != 0xF0) { // Digital track marker - not supported currently
+ for (channelNr = 0; channelNr < _tracks[trackNr].channelCount; channelNr++) {
+ channel = &_tracks[trackNr].channels[channelNr];
+ channel->prio = READ_LE_UINT16(data);
+ channel->data = resource->data + READ_LE_UINT16(data + 2) + 2;
+ channel->size = READ_LE_UINT16(data + 4) - 2; // Not counting channel header
+ channel->number = *(channel->data - 2);
+ setChannelUsed(channel->number);
+ channel->poly = *(channel->data - 1);
+ channel->time = channel->prev = 0;
+ if (channel->number == 0xFE) { // Digital channel
+ _tracks[trackNr].digitalChannelNr = channelNr;
+ _tracks[trackNr].digitalSampleRate = READ_LE_UINT16(channel->data);
+ _tracks[trackNr].digitalSampleSize = READ_LE_UINT16(channel->data + 2);
+ _tracks[trackNr].digitalSampleStart = READ_LE_UINT16(channel->data + 4);
+ _tracks[trackNr].digitalSampleEnd = READ_LE_UINT16(channel->data + 6);
+ channel->data += 8; // Skip over header
+ channel->size -= 8;
+ }
+ data += 6;
+ }
+ } else {
+ // Skip over digital track
+ data += 6;
+ }
+ data++; // Skipping 0xFF that closes channels list
+ }
+ break;
+
+ default:
+ error("SoundResource: SCI version %d is unsupported", _soundVersion);
+ }
+}
+
+SoundResource::~SoundResource() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++)
+ delete[] _tracks[trackNr].channels;
+ delete[] _tracks;
+
+ _resMan->unlockResource(_innerResource);
+}
+
+#if 0
+SoundResource::Track* SoundResource::getTrackByNumber(uint16 number) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
+
+ if (/*number >= 0 &&*/number < _trackCount)
+ return &_tracks[number];
+ return NULL;
+}
+#endif
+
+SoundResource::Track *SoundResource::getTrackByType(byte type) {
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ return &_tracks[0];
+
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].type == type)
+ return &_tracks[trackNr];
+ }
+ return NULL;
+}
+
+SoundResource::Track *SoundResource::getDigitalTrack() {
+ for (int trackNr = 0; trackNr < _trackCount; trackNr++) {
+ if (_tracks[trackNr].digitalChannelNr != -1)
+ return &_tracks[trackNr];
+ }
+ return NULL;
+}
+
+// Gets the filter mask for SCI0 sound resources
+int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
+ byte *data = _innerResource->data;
+ int channelMask = 0;
+
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0;
+
+ data++; // Skip over digital sample flag
+
+ for (int channelNr = 0; channelNr < 16; channelNr++) {
+ channelMask = channelMask >> 1;
+
+ byte flags;
+
+ if (_soundVersion == SCI_VERSION_0_EARLY) {
+ // Each channel is specified by a single byte
+ // Upper 4 bits of the byte is a voices count
+ // Lower 4 bits -> bit 0 set: use for AdLib
+ // bit 1 set: use for PCjr
+ // bit 2 set: use for PC speaker
+ // bit 3 set and bit 0 clear: control channel (15)
+ // bit 3 set and bit 0 set: rhythm channel (9)
+ // Note: control channel is dynamically assigned inside the drivers,
+ // but seems to be fixed at 15 in the song data.
+ flags = *data++;
+
+ // Get device bits
+ flags &= 0x7;
+ } else {
+ // Each channel is specified by 2 bytes
+ // 1st byte is voices count
+ // 2nd byte is play mask, which specifies if the channel is supposed to be played
+ // by the corresponding hardware
+
+ // Skip voice count
+ data++;
+
+ flags = *data++;
+ }
+
+ bool play;
+ switch (channelNr) {
+ case 15:
+ // Always play control channel
+ play = true;
+ break;
+ case 9:
+ // Play rhythm channel when requested
+ play = wantsRhythm;
+ break;
+ default:
+ // Otherwise check for flag
+ play = flags & hardwareMask;
+ }
+
+ if (play) {
+ // This Channel is supposed to be played by the hardware
+ channelMask |= 0x8000;
+ }
+ }
+
+ return channelMask;
+}
+
+byte SoundResource::getInitialVoiceCount(byte channel) {
+ byte *data = _innerResource->data;
+
+ if (_soundVersion > SCI_VERSION_0_LATE)
+ return 0; // TODO
+
+ data++; // Skip over digital sample flag
+
+ if (_soundVersion == SCI_VERSION_0_EARLY)
+ return data[channel] >> 4;
+ else
+ return data[channel * 2];
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 4862d0579a..929bdf3307 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -43,6 +43,7 @@
#include "sci/sound/audio.h"
#include "sci/sound/soundcmd.h"
#include "sci/graphics/gui.h"
+#include "sci/graphics/maciconbar.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/cursor.h"
@@ -55,8 +56,6 @@
namespace Sci {
-extern int g_loadFromLauncher;
-
SciEngine *g_sci = 0;
@@ -97,6 +96,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc)
DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game");
_gamestate = 0;
+ _gfxMacIconBar = 0;
const Common::FSNode gameDataDir(ConfMan.get("path"));
@@ -124,6 +124,7 @@ SciEngine::~SciEngine() {
delete _console;
delete _resMan;
delete _features;
+ delete _gfxMacIconBar;
g_sci = 0;
}
@@ -170,6 +171,9 @@ Common::Error SciEngine::run() {
else
screen = new GfxScreen(_resMan, 320, 200, upscaledHires);
+ if (_resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1)
+ _gfxMacIconBar = new GfxMacIconBar();
+
GfxPalette *palette = new GfxPalette(_resMan, screen);
GfxCache *cache = new GfxCache(_resMan, screen, palette);
GfxCursor *cursor = new GfxCursor(_resMan, palette, screen);
@@ -184,7 +188,7 @@ Common::Error SciEngine::run() {
_features = new GameFeatures(segMan, _kernel);
- _gamestate = new EngineState(_vocabulary, segMan);
+ _gamestate = new EngineState(segMan);
_gamestate->_event = new SciEvent(_resMan);
@@ -222,16 +226,11 @@ Common::Error SciEngine::run() {
}
// Add the after market GM patches for the specified game, if they exist
- _resMan->addNewGMPatch(_gamestate->_gameId);
+ _resMan->addNewGMPatch(getGameID());
script_adjust_opcode_formats(_gamestate);
_kernel->loadKernelNames(getGameID());
- // Set the savegame dir (actually, we set it to a fake value,
- // since we cannot let the game control where saves are stored)
- assert(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value != 0);
- strcpy(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value, "");
-
SciVersion soundVersion = _features->detectDoSoundType();
_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
@@ -258,9 +257,9 @@ Common::Error SciEngine::run() {
// Check whether loading a savestate was requested
if (ConfMan.hasKey("save_slot")) {
- g_loadFromLauncher = ConfMan.getInt("save_slot");
+ _gamestate->loadFromLauncher = ConfMan.getInt("save_slot");
} else {
- g_loadFromLauncher = -1;
+ _gamestate->loadFromLauncher = -1;
}
game_run(&_gamestate); // Run the game
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index fdd10bcd04..685f05e685 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -65,7 +65,7 @@ class GfxPalette;
class GfxPorts;
class GfxScreen;
class SciGui;
-
+class GfxMacIconBar;
#ifdef ENABLE_SCI32
class SciGui32;
@@ -206,6 +206,7 @@ public:
GfxPorts *_gfxPorts; // Port managment for 16-bit gfx
GfxScreen *_gfxScreen;
SciGui *_gui; /* Currently active Gui */
+ GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager
#ifdef ENABLE_SCI32
SciGui32 *_gui32; // GUI for SCI32 games
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 331561eea4..7748c0505b 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -235,6 +235,7 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
uint32 audioCompressionType = audioRes->getAudioCompressionType();
if (audioCompressionType) {
+#if (defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC))
// Compressed audio made by our tool
byte *compressedData = (byte *)malloc(audioRes->size);
assert(compressedData);
@@ -261,6 +262,9 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
#endif
break;
}
+#else
+ error("Compressed audio file encountered, but no appropriate decoder is compiled in");
+#endif
} else {
// Original source file
if (audioRes->_headerSize > 0) {
@@ -332,11 +336,11 @@ void AudioPlayer::setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *seg
_syncOffset = 0;
if (_syncResource) {
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), 0);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), 0);
} else {
warning("setSoundSync: failed to find resource %s", id.toString().c_str());
// Notify the scripts to stop sound sync
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
}
}
@@ -352,8 +356,8 @@ void AudioPlayer::doSoundSync(reg_t syncObjAddr, SegManager *segMan) {
_syncOffset += 2;
}
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
- PUT_SEL32V(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
+ writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
}
}
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 2068ea9a33..3ee8a3a83d 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -60,6 +60,9 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion) :
_dataincToAdd = 0;
_resetOnPause = false;
_channelsUsed = 0;
+
+ for (int i = 0; i < 16; i++)
+ _channelRemap[i] = i;
}
MidiParser_SCI::~MidiParser_SCI() {
@@ -85,7 +88,6 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
_tracks[0] = _mixedData;
setTrack(0);
_loopTick = 0;
- _channelsUsed = 0;
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Set initial voice count
@@ -120,17 +122,20 @@ void MidiParser_SCI::unloadMusic() {
// Center the pitch wheels and hold pedal in preparation for the next piece of music
if (_driver) {
for (int i = 0; i < 16; ++i) {
- if (_channelsUsed & (1 << i)) {
+ if (isChannelUsed(i)) {
_driver->send(0xE0 | i, 0, 0x40); // Reset pitch wheel
_driver->send(0xB0 | i, 0x40, 0); // Reset hold pedal
}
}
}
+
+ for (int i = 0; i < 16; i++)
+ _channelRemap[i] = i;
}
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// Monitor which channels are used by this song
- _channelsUsed |= (1 << info.channel());
+ setChannelUsed(info.channel());
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
if (_dataincAdd) {
@@ -322,7 +327,7 @@ byte MidiParser_SCI::midiGetNextChannel(long ticker) {
for (int i = 0; i < _track->channelCount; i++) {
if (_track->channels[i].time == -1) // channel ended
continue;
- next = *_track->channels[i].data; // when the next event shoudl occur
+ next = *_track->channels[i].data; // when the next event should occur
if (next == 0xF8) // 0xF8 means 240 ticks delay
next = 240;
next += _track->channels[i].time;
@@ -389,9 +394,18 @@ byte *MidiParser_SCI::midiMixChannels() {
channel->time = -1; // FIXME
break;
default: // MIDI command
- if (command & 0x80)
+ if (command & 0x80) {
par1 = *channel->data++;
- else {// running status
+
+ // TODO: Fix remapping
+
+#if 0
+ // Remap channel. Keep the upper 4 bits (command code) and change
+ // the lower 4 bits (channel)
+ byte remappedChannel = _channelRemap[par1 & 0xF];
+ par1 = (par1 & 0xF0) | (remappedChannel & 0xF);
+#endif
+ } else {// running status
par1 = command;
command = channel->prev;
}
diff --git a/engines/sci/sound/midiparser_sci.h b/engines/sci/sound/midiparser_sci.h
index f95c71ce2f..9d4b5a39da 100644
--- a/engines/sci/sound/midiparser_sci.h
+++ b/engines/sci/sound/midiparser_sci.h
@@ -71,7 +71,18 @@ public:
jumpToTick(0);
}
+ void remapChannel(byte channel, byte newChannel) {
+ assert(channel < 0xF); // don't touch special SCI channel 15
+ assert(newChannel < 0xF); // don't touch special SCI channel 15
+ _channelRemap[channel] = newChannel;
+ }
+
+ void clearUsedChannels() { _channelsUsed = 0; }
+
protected:
+ bool isChannelUsed(byte channel) const { return _channelsUsed & (1 << channel); }
+ void setChannelUsed(byte channel) { _channelsUsed |= (1 << channel); }
+
void parseNextEvent(EventInfo &info);
byte *midiMixChannels();
byte *midiFilterChannels(int channelMask);
@@ -93,6 +104,8 @@ protected:
// A 16-bit mask, containing the channels used
// by the currently parsed song
uint16 _channelsUsed;
+
+ byte _channelRemap[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 66f5ce9710..fa5716e7cc 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -37,9 +37,6 @@
namespace Sci {
-// When defined, volume fading immediately sets the final sound volume
-#define DISABLE_VOLUME_FADING
-
SciMusic::SciMusic(SciVersion soundVersion)
: _soundVersion(soundVersion), _soundOn(true), _masterVolume(0) {
@@ -115,8 +112,6 @@ void SciMusic::clearPlayList() {
}
void SciMusic::pauseAll(bool pause) {
- Common::StackLock lock(_mutex);
-
const MusicList::iterator end = _playList.end();
for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
soundToggle(*i, pause);
@@ -170,14 +165,29 @@ void SciMusic::setReverb(byte reverb) {
_pMidiDrv->setReverb(reverb);
}
-static int f_compare(const void *arg1, const void *arg2) {
- return ((const MusicEntry *)arg2)->priority - ((const MusicEntry *)arg1)->priority;
+static bool musicEntryCompare(const MusicEntry *l, const MusicEntry *r) {
+ return (l->priority > r->priority);
}
void SciMusic::sortPlayList() {
- MusicEntry ** pData = _playList.begin();
- qsort(pData, _playList.size(), sizeof(MusicEntry *), &f_compare);
+ // Sort the play list in descending priority order
+ Common::sort(_playList.begin(), _playList.end(), musicEntryCompare);
}
+
+void SciMusic::findUsedChannels() {
+ // Reset list
+ for (int k = 0; k < 16; k++)
+ _usedChannels[k] = false;
+
+ const MusicList::const_iterator end = _playList.end();
+ for (MusicList::const_iterator i = _playList.begin(); i != end; ++i) {
+ for (int channel = 0; channel < 16; channel++) {
+ if ((*i)->soundRes && (*i)->soundRes->isChannelUsed(channel))
+ _usedChannels[channel] = true;
+ }
+ }
+}
+
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
int channelFilterMask = 0;
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
@@ -221,6 +231,27 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
pSnd->pauseCounter = 0;
+ // TODO: Fix channel remapping. This doesn't quite work... (e.g. no difference in LSL1VGA)
+#if 0
+ // Remap channels
+ findUsedChannels();
+
+ pSnd->pMidiParser->clearUsedChannels();
+
+ for (int i = 0; i < 16; i++) {
+ if (_usedChannels[i] && pSnd->soundRes->isChannelUsed(i)) {
+ int16 newChannel = getNextUnusedChannel();
+ if (newChannel >= 0) {
+ _usedChannels[newChannel] = true;
+ debug("Remapping channel %d to %d\n", i, newChannel);
+ pSnd->pMidiParser->remapChannel(i, newChannel);
+ } else {
+ warning("Attempt to remap channel %d, but no unused channels exist", i);
+ }
+ }
+ }
+#endif
+
// Find out what channels to filter for SCI0
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
@@ -243,14 +274,14 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
uint playListCount = _playList.size();
uint playListNo = playListCount;
- bool alreadyPlaying = false;
+ MusicEntry *alreadyPlaying = NULL;
// searching if sound is already in _playList
for (uint i = 0; i < playListCount; i++) {
if (_playList[i] == pSnd)
playListNo = i;
if ((_playList[i]->status == kSoundPlaying) && (_playList[i]->pMidiParser))
- alreadyPlaying = true;
+ alreadyPlaying = _playList[i];
}
if (playListNo == playListCount) { // not found
_playList.push_back(pSnd);
@@ -261,13 +292,20 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
if (pSnd->pMidiParser) {
if ((_soundVersion <= SCI_VERSION_0_LATE) && (alreadyPlaying)) {
- // if any music is already playing, SCI0 queues music and plays it after the current music has finished
- // done by SoundCommandParser::updateSci0Cues()
- // Example of such case: iceman room 14
- // FIXME: this code is supposed to also take a look at priority and pause currently playing sound accordingly
- pSnd->isQueued = true;
- pSnd->status = kSoundPaused;
- return;
+ // Music already playing in SCI0?
+ if (pSnd->priority > alreadyPlaying->priority) {
+ // And new priority higher? pause previous music and play new one immediately
+ // Example of such case: lsl3, when getting points (jingle is played then)
+ soundPause(alreadyPlaying);
+ alreadyPlaying->isQueued = true;
+ } else {
+ // And new priority equal or lower? queue up music and play it afterwards done by
+ // SoundCommandParser::updateSci0Cues()
+ // Example of such case: iceman room 14
+ pSnd->isQueued = true;
+ pSnd->status = kSoundPaused;
+ return;
+ }
}
}
@@ -298,6 +336,8 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->status = kSoundStopped;
+ if (_soundVersion <= SCI_VERSION_0_LATE)
+ pSnd->isQueued = false;
if (pSnd->pStreamAud)
_pMixer->stopHandle(pSnd->hCurrentAud);
@@ -380,7 +420,12 @@ void SciMusic::soundResume(MusicEntry *pSnd) {
return;
if (pSnd->status != kSoundPaused)
return;
- soundPlay(pSnd);
+ if (pSnd->pStreamAud) {
+ _pMixer->pauseHandle(pSnd->hCurrentAud, false);
+ pSnd->status = kSoundPlaying;
+ } else {
+ soundPlay(pSnd);
+ }
}
void SciMusic::soundToggle(MusicEntry *pSnd, bool pause) {
@@ -522,15 +567,17 @@ void MusicEntry::doFade() {
fadeStep = 0;
fadeCompleted = true;
}
-
- // Only process MIDI streams in this thread, not digital sound effects
- if (pMidiParser) {
-#ifdef DISABLE_VOLUME_FADING
- // Signal fading to stop...
+#ifdef ENABLE_SCI32
+ // Disable fading for SCI32 - sound drivers have issues when fading in (gabriel knight 1 sierra title)
+ if (getSciVersion() >= SCI_VERSION_2) {
volume = fadeTo;
fadeStep = 0;
fadeCompleted = true;
+ }
#endif
+
+ // Only process MIDI streams in this thread, not digital sound effects
+ if (pMidiParser) {
pMidiParser->setVolume(volume);
}
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index 8f08065b99..83cd59e89b 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -197,7 +197,6 @@ public:
Common::Mutex _mutex;
protected:
- byte findAudEntry(uint16 nAud, byte&oVolume, uint32& oOffset, uint32&oSize);
void sortPlayList();
SciVersion _soundVersion;
@@ -211,10 +210,20 @@ protected:
bool _bMultiMidi;
private:
static void miditimerCallback(void *p);
+ void findUsedChannels();
+ int16 getNextUnusedChannel() const {
+ for (int i = 0; i < 16; i++) {
+ if (!_usedChannels[i])
+ return i;
+ }
+
+ return -1;
+ }
MusicList _playList;
bool _soundOn;
byte _masterVolume;
+ bool _usedChannels[16];
};
} // End of namespace Sci
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 925f3b2e1a..ece4c1430c 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -50,9 +50,9 @@ namespace Sci {
#ifdef USE_OLD_MUSIC_FUNCTIONS
static void script_set_priority(ResourceManager *resMan, SegManager *segMan, SfxState *state, reg_t obj, int priority) {
- int song_nr = GET_SEL32V(segMan, obj, SELECTOR(number));
+ int song_nr = readSelectorValue(segMan, obj, SELECTOR(number));
Resource *song = resMan->findResource(ResourceId(kResourceTypeSound, song_nr), 0);
- int flags = GET_SEL32V(segMan, obj, SELECTOR(flags));
+ int flags = readSelectorValue(segMan, obj, SELECTOR(flags));
if (priority == -1) {
if (song->data[0] == 0xf0)
@@ -64,7 +64,7 @@ static void script_set_priority(ResourceManager *resMan, SegManager *segMan, Sfx
} else flags |= SCI1_SOUND_FLAG_SCRIPTED_PRI;
state->sfx_song_renice(FROBNICATE_HANDLE(obj), priority);
- PUT_SEL32V(segMan, obj, SELECTOR(flags), flags);
+ writeSelectorValue(segMan, obj, SELECTOR(flags), flags);
}
SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id) {
@@ -98,27 +98,27 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
case SI_LOOP:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x looped (to %d)",
PRINT_REG(obj), cue);
- /* PUT_SEL32V(segMan, obj, SELECTOR(loops), GET_SEL32V(segMan, obj, SELECTOR(loop));; - 1);*/
- PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ /* writeSelectorValue(segMan, obj, SELECTOR(loops), readSelectorValue(segMan, obj, SELECTOR(loop));; - 1);*/
+ writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_RELATIVE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received relative cue %d",
PRINT_REG(obj), cue);
- PUT_SEL32V(segMan, obj, SELECTOR(signal), cue + 0x7f);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), cue + 0x7f);
break;
case SI_ABSOLUTE_CUE:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x received absolute cue %d",
PRINT_REG(obj), cue);
- PUT_SEL32V(segMan, obj, SELECTOR(signal), cue);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), cue);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "[process-sound] Song %04x:%04x finished",
PRINT_REG(obj));
- PUT_SEL32V(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
- PUT_SEL32V(segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(segMan, obj, SELECTOR(state), kSoundStopped);
break;
default:
@@ -253,7 +253,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (!obj.segment)
return;
- int resourceId = GET_SEL32V(_segMan, obj, SELECTOR(number));
+ int resourceId = readSelectorValue(_segMan, obj, SELECTOR(number));
#ifdef USE_OLD_MUSIC_FUNCTIONS
@@ -267,7 +267,7 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
SongIteratorType type = (_soundVersion <= SCI_VERSION_0_LATE) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1;
if (_soundVersion <= SCI_VERSION_0_LATE) {
- if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr))) {
+ if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr))) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
}
@@ -281,11 +281,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
#else
@@ -302,10 +302,10 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
newSound->soundRes = 0;
newSound->soundObj = obj;
- newSound->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- newSound->priority = GET_SEL32V(_segMan, obj, SELECTOR(pri)) & 0xFF;
- if (_soundVersion >= SCI_VERSION_1_LATE)
- newSound->volume = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
+ newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF;
+ if (_soundVersion >= SCI_VERSION_1_EARLY)
+ newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
@@ -327,11 +327,11 @@ void SoundCommandParser::cmdInitSound(reg_t obj, int16 value) {
if (newSound->soundRes || newSound->pStreamAud) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundInitialized);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
#endif
@@ -346,30 +346,30 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
} else if (_soundVersion == SCI_VERSION_1_EARLY) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- _state->sfx_song_renice(handle, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ _state->sfx_song_renice(handle, readSelectorValue(_segMan, obj, SELECTOR(pri)));
RESTORE_BEHAVIOR rb = (RESTORE_BEHAVIOR) value; /* Too lazy to look up a default value for this */
_state->_songlib.setSongRestoreBehavior(handle, rb);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
} else if (_soundVersion == SCI_VERSION_1_LATE) {
- int looping = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- //int vol = GET_SEL32V(_segMan, obj, SELECTOR(vol));
- int pri = GET_SEL32V(_segMan, obj, SELECTOR(pri));
+ int looping = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ //int vol = readSelectorValue(_segMan, obj, SELECTOR(vol));
+ int pri = readSelectorValue(_segMan, obj, SELECTOR(pri));
int sampleLen = 0;
Song *song = _state->_songlib.findSong(handle);
- int songNumber = GET_SEL32V(_segMan, obj, SELECTOR(number));
+ int songNumber = readSelectorValue(_segMan, obj, SELECTOR(number));
- if (GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
+ if (readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && (song && songNumber != song->_resourceNum)) {
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
_state->sfx_remove_song(handle);
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
}
- if (!GET_SEL32V(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
+ if (!readSelectorValue(_segMan, obj, SELECTOR(nodePtr)) && obj.segment) {
// In SCI1.1 games, sound effects are started from here. If we can find
// a relevant audio resource, play it, otherwise switch to synthesized
// effects. If the resource exists, play it using map 65535 (sound
@@ -387,7 +387,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
warning("Could not open song number %d", songNumber);
// Send a "stop handle" event so that the engine won't wait forever here
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
return;
}
debugC(2, kDebugLevelSound, "Initializing song number %d", songNumber);
@@ -395,15 +395,15 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
handle), 0, handle, songNumber);
}
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
if (obj.segment) {
_state->sfx_song_set_status(handle, SOUND_STATUS_PLAYING);
_state->sfx_song_set_loops(handle, looping);
_state->sfx_song_renice(handle, pri);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
}
}
@@ -415,7 +415,7 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
return;
}
- int resourceId = obj.segment ? GET_SEL32V(_segMan, obj, SELECTOR(number)) : -1;
+ int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
if (musicSlot->resourceId != resourceId) { // another sound loaded into struct
cmdDisposeSound(obj, value);
@@ -423,25 +423,25 @@ void SoundCommandParser::cmdPlaySound(reg_t obj, int16 value) {
// Find slot again :)
musicSlot = _music->getSlot(obj);
}
- int16 loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
+ int16 loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
debugC(2, kDebugLevelSound, "cmdPlaySound: resource number %d, loop %d", resourceId, loop);
- PUT_SEL32(_segMan, obj, SELECTOR(handle), obj);
+ writeSelector(_segMan, obj, SELECTOR(handle), obj);
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), obj);
- PUT_SEL32V(_segMan, obj, SELECTOR(min), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), 0);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), 0);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), 0);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundPlaying);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundPlaying);
}
- musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- musicSlot->priority = GET_SEL32V(_segMan, obj, SELECTOR(priority));
- if (_soundVersion >= SCI_VERSION_1_LATE)
- musicSlot->volume = GET_SEL32V(_segMan, obj, SELECTOR(vol));
+ musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
+ if (_soundVersion >= SCI_VERSION_1_EARLY)
+ musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
_music->soundPlay(musicSlot);
#endif
@@ -458,7 +458,7 @@ void SoundCommandParser::changeSoundStatus(reg_t obj, int newStatus) {
if (obj.segment) {
_state->sfx_song_set_status(handle, newStatus);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), newStatus);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), newStatus);
}
}
#endif
@@ -475,7 +475,7 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
_state->sfx_remove_song(handle);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0x0000);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0x0000);
}
#else
@@ -489,11 +489,11 @@ void SoundCommandParser::cmdDisposeSound(reg_t obj, int16 value) {
cmdStopSound(obj, value);
_music->soundKill(musicSlot);
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- PUT_SEL32(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
+ writeSelector(_segMan, obj, SELECTOR(nodePtr), NULL_REG);
else
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
#endif
}
@@ -509,7 +509,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
changeSoundStatus(obj, SOUND_STATUS_STOPPED);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
#else
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
@@ -518,9 +518,9 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
}
if (_soundVersion <= SCI_VERSION_0_LATE) {
- PUT_SEL32V(_segMan, obj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundStopped);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
}
// Set signal selector in sound SCI0 games only, when the sample has finished playing
@@ -530,7 +530,7 @@ void SoundCommandParser::processStopSound(reg_t obj, int16 value, bool sampleFin
// sfx drivers included
// We need to set signal in sound SCI1+ games all the time
if ((_soundVersion > SCI_VERSION_0_LATE) || sampleFinishedPlaying)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
musicSlot->dataInc = 0;
musicSlot->signal = 0;
@@ -565,7 +565,7 @@ void SoundCommandParser::cmdPauseSound(reg_t obj, int16 value) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
// Always pause the sound in SCI0 games. It's resumed in cmdResumeSound()
- PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPaused);
_music->soundPause(musicSlot);
} else {
_music->soundToggle(musicSlot, value);
@@ -590,7 +590,7 @@ void SoundCommandParser::cmdResumeSound(reg_t obj, int16 value) {
return;
}
- PUT_SEL32V(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
+ writeSelectorValue(_segMan, musicSlot->soundObj, SELECTOR(state), kSoundPlaying);
_music->soundResume(musicSlot);
#endif
}
@@ -630,13 +630,12 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion != SCI_VERSION_1_LATE) {
- /*s->sound_server->command(s, SOUND_COMMAND_FADE_HANDLE, obj, 120);*/ /* Fade out in 2 secs */
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(state), SOUND_STATUS_STOPPED);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
} else {
fade_params_t fade;
fade.final_volume = _argv[2].toUint16();
@@ -651,11 +650,11 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
/* FIXME: The next couple of lines actually STOP the handle, rather
** than fading it! */
if (_argv[5].toUint16()) {
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
} else {
// FIXME: Support fade-and-continue. For now, send signal right away.
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
}
#else
@@ -692,7 +691,7 @@ void SoundCommandParser::cmdFadeSound(reg_t obj, int16 value) {
// If sound is not playing currently, set signal directly
if (musicSlot->status != kSoundPlaying) {
warning("cmdFadeSound: fading requested, but sound is currently not playing");
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
}
debugC(2, kDebugLevelSound, "cmdFadeSound: to %d, step %d, ticker %d", musicSlot->fadeTo, musicSlot->fadeStep, musicSlot->fadeTickerStep);
@@ -714,8 +713,8 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
#ifdef USE_OLD_MUSIC_FUNCTIONS
SongHandle handle = FROBNICATE_HANDLE(obj);
if (_soundVersion <= SCI_VERSION_0_LATE && obj.segment) {
- _state->sfx_song_set_loops(handle, GET_SEL32V(_segMan, obj, SELECTOR(loop)));
- script_set_priority(_resMan, _segMan, _state, obj, GET_SEL32V(_segMan, obj, SELECTOR(pri)));
+ _state->sfx_song_set_loops(handle, readSelectorValue(_segMan, obj, SELECTOR(loop)));
+ script_set_priority(_resMan, _segMan, _state, obj, readSelectorValue(_segMan, obj, SELECTOR(pri)));
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -724,11 +723,11 @@ void SoundCommandParser::cmdUpdateSound(reg_t obj, int16 value) {
return;
}
- musicSlot->loop = GET_SEL32V(_segMan, obj, SELECTOR(loop));
- int16 objVol = CLIP<int>(GET_SEL32V(_segMan, obj, SELECTOR(vol)), 0, 255);
+ musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255);
if (objVol != musicSlot->volume)
_music->soundSetVolume(musicSlot, objVol);
- uint32 objPrio = GET_SEL32V(_segMan, obj, SELECTOR(pri));
+ uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(pri));
if (objPrio != musicSlot->priority)
_music->soundSetPriority(musicSlot, objPrio);
@@ -755,7 +754,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
debugC(2, kDebugLevelSound, "--- [CUE] %04x:%04x Absolute Cue: %d",
PRINT_REG(obj), signal);
debugC(2, kDebugLevelSound, "abs-signal %04X", signal);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
break;
case SI_RELATIVE_CUE:
@@ -765,17 +764,17 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
/* FIXME to match commented-out semantics
* below, with proper storage of dataInc and
* signal in the iterator code. */
- PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(dataInc), signal);
debugC(2, kDebugLevelSound, "rel-signal %04X", signal);
if (_soundVersion == SCI_VERSION_1_EARLY)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal);
else
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), signal + 127);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), signal + 127);
break;
case SI_FINISHED:
debugC(2, kDebugLevelSound, "--- [FINISHED] %04x:%04x", PRINT_REG(obj));
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
break;
case SI_LOOP:
@@ -784,30 +783,30 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
//switch (signal) {
//case 0x00:
- // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
- // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc+0x7f);
+ // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
+ // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc+0x7f);
// } else {
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//case 0xFF: // May be unnecessary
// s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
// break;
//default :
- // if (dataInc != GET_SEL32V(segMan, obj, SELECTOR(dataInc))) {
- // PUT_SEL32V(segMan, obj, SELECTOR(dataInc), dataInc);
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
+ // if (dataInc != readSelectorValue(segMan, obj, SELECTOR(dataInc))) {
+ // writeSelectorValue(segMan, obj, SELECTOR(dataInc), dataInc);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), dataInc + 0x7f);
// } else {
- // PUT_SEL32V(segMan, obj, SELECTOR(signal), signal);
+ // writeSelectorValue(segMan, obj, SELECTOR(signal), signal);
// }
// break;
//}
if (_soundVersion == SCI_VERSION_1_EARLY) {
- PUT_SEL32V(_segMan, obj, SELECTOR(min), min);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), sec);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), frame);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), min);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), sec);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), frame);
}
#else
MusicEntry *musicSlot = _music->getSlot(obj);
@@ -828,7 +827,7 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
musicSlot->loop -= currentLoopCounter - musicSlot->sampleLoopCounter;
musicSlot->sampleLoopCounter = currentLoopCounter;
}
- if (!_music->soundIsActive(musicSlot)) {
+ if ((!_music->soundIsActive(musicSlot)) && (musicSlot->status != kSoundPaused)) {
processStopSound(obj, 0, true);
} else {
_music->updateAudioStreamTicker(musicSlot);
@@ -841,14 +840,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else if (musicSlot->pMidiParser) {
// Update MIDI slots
if (musicSlot->signal == 0) {
- if (musicSlot->dataInc != GET_SEL32V(_segMan, obj, SELECTOR(dataInc))) {
+ if (musicSlot->dataInc != readSelectorValue(_segMan, obj, SELECTOR(dataInc))) {
if (_kernel->_selectorCache.dataInc > -1)
- PUT_SEL32V(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
+ writeSelectorValue(_segMan, obj, SELECTOR(dataInc), musicSlot->dataInc);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->dataInc + 127);
}
} else {
// Sync the signal of the sound object
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), musicSlot->signal);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), musicSlot->signal);
// We need to do this especially because state selector needs to get updated
if (musicSlot->signal == SIGNAL_OFFSET)
cmdStopSound(obj, 0);
@@ -856,14 +855,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
} else {
// Slot actually has no data (which would mean that a sound-resource w/ unsupported data is used
// (example lsl5 - sound resource 744 - it's roland exclusive
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
// If we don't set signal here, at least the switch to the mud wrestling room in lsl5 will not work
}
if (musicSlot->fadeCompleted) {
musicSlot->fadeCompleted = false;
// We need signal for sci0 at least in iceman as well (room 14, fireworks)
- PUT_SEL32V(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);
if (_soundVersion <= SCI_VERSION_0_LATE) {
cmdStopSound(obj, 0);
} else {
@@ -874,14 +873,14 @@ void SoundCommandParser::cmdUpdateCues(reg_t obj, int16 value) {
// Sync loop selector for SCI0
if (_soundVersion <= SCI_VERSION_0_LATE)
- PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
musicSlot->signal = 0;
if (_soundVersion >= SCI_VERSION_1_EARLY) {
- PUT_SEL32V(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
- PUT_SEL32V(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
- PUT_SEL32V(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
+ writeSelectorValue(_segMan, obj, SELECTOR(min), musicSlot->ticker / 3600);
+ writeSelectorValue(_segMan, obj, SELECTOR(sec), musicSlot->ticker % 3600 / 60);
+ writeSelectorValue(_segMan, obj, SELECTOR(frame), musicSlot->ticker);
}
#endif
@@ -927,18 +926,13 @@ void SoundCommandParser::cmdStopAllSounds(reg_t obj, int16 value) {
#ifndef USE_OLD_MUSIC_FUNCTIONS
Common::StackLock(_music->_mutex);
- // FIXME: this can't be right, it's called in iceman (room 14) when the door sound has done playing
- // stopping sounds can't be right, because music is starting afterwards in ssci. can't be resume queued
- // song(s), because music is playing even when this call is nuked inside ssci.
- return;
-
const MusicList::iterator end = _music->getPlayListEnd();
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
if (_soundVersion <= SCI_VERSION_0_LATE) {
- PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
+ writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(state), kSoundStopped);
} else {
- PUT_SEL32V(_segMan, obj, SELECTOR(handle), 0);
- PUT_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
+ writeSelectorValue(_segMan, obj, SELECTOR(handle), 0);
+ writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal), SIGNAL_OFFSET);
}
(*i)->dataInc = 0;
@@ -969,7 +963,7 @@ void SoundCommandParser::cmdSetSoundVolume(reg_t obj, int16 value) {
if (musicSlot->volume != value) {
musicSlot->volume = value;
_music->soundSetVolume(musicSlot, value);
- PUT_SEL32V(_segMan, obj, SELECTOR(vol), value);
+ writeSelectorValue(_segMan, obj, SELECTOR(vol), value);
}
#endif
}
@@ -996,12 +990,12 @@ void SoundCommandParser::cmdSetSoundPriority(reg_t obj, int16 value) {
warning("cmdSetSoundPriority: Attempt to unset song priority when there is no built-in value");
//pSnd->prio=0;field_15B=0
- PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) & 0xFD);
+ writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) & 0xFD);
} else {
// Scripted priority
//pSnd->field_15B=1;
- PUT_SEL32V(_segMan, obj, SELECTOR(flags), GET_SEL32V(_segMan, obj, SELECTOR(flags)) | 2);
+ writeSelectorValue(_segMan, obj, SELECTOR(flags), readSelectorValue(_segMan, obj, SELECTOR(flags)) | 2);
//DoSOund(0xF,hobj,w)
}
#endif
@@ -1012,7 +1006,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
return;
#ifdef USE_OLD_MUSIC_FUNCTIONS
- if (!GET_SEL32(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
+ if (!readSelector(_segMan, obj, SELECTOR(nodePtr)).isNull()) {
SongHandle handle = FROBNICATE_HANDLE(obj);
_state->sfx_song_set_loops(handle, value);
}
@@ -1037,7 +1031,7 @@ void SoundCommandParser::cmdSetSoundLoop(reg_t obj, int16 value) {
musicSlot->loop = 1; // actually plays the music once
}
- PUT_SEL32V(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+ writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
#endif
}
@@ -1058,8 +1052,11 @@ void SoundCommandParser::updateSci0Cues() {
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
// Is the sound stopped, and the sound object updated too? If yes, skip
// this sound, as SCI0 only allows one active song
- if (((*i)->isQueued) && (!pWaitingForPlay)) {
+ if ((*i)->isQueued) {
pWaitingForPlay = (*i);
+ // FIXME (?) - in iceman 2 songs are queued when playing the door sound - if we use the first song for resuming
+ // then it's the wrong one. Both songs have same priority. Maybe the new sound function in sci0
+ // is somehow responsible
continue;
}
if ((*i)->signal == 0 && (*i)->status != kSoundPlaying)
@@ -1105,11 +1102,11 @@ void SoundCommandParser::reconstructPlayList(int savegame_version) {
}
if ((*i)->status == kSoundPlaying) {
if (savegame_version < 14) {
- (*i)->dataInc = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(dataInc));
- (*i)->signal = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(signal));
+ (*i)->dataInc = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(dataInc));
+ (*i)->signal = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal));
if (_soundVersion >= SCI_VERSION_1_LATE)
- (*i)->volume = GET_SEL32V(_segMan, (*i)->soundObj, SELECTOR(vol));
+ (*i)->volume = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol));
}
cmdPlaySound((*i)->soundObj, 0);
@@ -1145,7 +1142,7 @@ void SoundCommandParser::startNewSound(int number) {
MusicEntry *song = *_music->getPlayListStart();
reg_t soundObj = song->soundObj;
cmdDisposeSound(soundObj, 0);
- PUT_SEL32V(_segMan, soundObj, SELECTOR(number), number);
+ writeSelectorValue(_segMan, soundObj, SELECTOR(number), number);
cmdInitSound(soundObj, 0);
cmdPlaySound(soundObj, 0);
#endif