diff options
author | Travis Howell | 2009-06-06 00:10:40 +0000 |
---|---|---|
committer | Travis Howell | 2009-06-06 00:10:40 +0000 |
commit | 8ff3a568fa8fe564749080a9af5e20b897933d93 (patch) | |
tree | 3136763937adc1fb6bcd30993b00d1476f490b6f /engines | |
parent | d65bbe1d7a5efbcf04831dbb68a45ca833db1ae1 (diff) | |
parent | da36901b0751b9d4faaae30dce230b67d75e04e6 (diff) | |
download | scummvm-rg350-8ff3a568fa8fe564749080a9af5e20b897933d93.tar.gz scummvm-rg350-8ff3a568fa8fe564749080a9af5e20b897933d93.tar.bz2 scummvm-rg350-8ff3a568fa8fe564749080a9af5e20b897933d93.zip |
Merged revisions 41154-41156,41160,41163-41181,41185-41186,41188-41189,41196-41202 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
........
r41154 | thebluegr | 2009-06-04 18:25:48 +1000 (Thu, 04 Jun 2009) | 1 line
Turned debug_weak_validations on by default again, as apparently some games like SQ3 fail in some validations (e.g. when loading). Also, fixed a potential out of bounds access when copying the value of __FILE__ into a buffer (as its value can be quite long in some cases).
........
r41155 | thebluegr | 2009-06-04 18:28:20 +1000 (Thu, 04 Jun 2009) | 1 line
Reordered the numpad keys so that they make more sense, and simplified the code which returns the values of shifted function keys
........
r41156 | djwillis | 2009-06-04 18:30:31 +1000 (Thu, 04 Jun 2009) | 1 line
Initial import of the GP2XWiz backend (based on the GP2X and SDL backends). Includes configure changes and one #ifdef to SDL backend. Also updates NEWS.
........
r41160 | strangerke | 2009-06-04 19:48:56 +1000 (Thu, 04 Jun 2009) | 1 line
gob : _spriteBottom incorrectly saved and restored in Draw_v2::spriteOperation
........
r41163 | fingolfin | 2009-06-04 21:28:05 +1000 (Thu, 04 Jun 2009) | 1 line
SCI: Renamed various debug related global variables to have a g_ prefix; and moved any 'extern' decls of them into a new header file
........
r41164 | waltervn | 2009-06-04 21:35:17 +1000 (Thu, 04 Jun 2009) | 2 lines
SCI: Support for 16-bit DPCM.
........
r41165 | fingolfin | 2009-06-04 21:44:55 +1000 (Thu, 04 Jun 2009) | 1 line
SCI: cleanup
........
r41166 | fingolfin | 2009-06-04 21:45:17 +1000 (Thu, 04 Jun 2009) | 1 line
SCI: Moved MemObject code into a separate source file
........
r41167 | fingolfin | 2009-06-04 21:45:34 +1000 (Thu, 04 Jun 2009) | 1 line
Code formatting in the gp2xwiz backend
........
r41168 | thebluegr | 2009-06-04 22:47:11 +1000 (Thu, 04 Jun 2009) | 1 line
Updated the MSVC project files of the SCI engine
........
r41169 | waltervn | 2009-06-05 00:29:20 +1000 (Fri, 05 Jun 2009) | 2 lines
SCI: Message: Added support for escape sequences.
........
r41170 | waltervn | 2009-06-05 01:56:11 +1000 (Fri, 05 Jun 2009) | 2 lines
SCI: Added support for early SCI1.1 audio maps.
........
r41171 | waltervn | 2009-06-05 02:18:35 +1000 (Fri, 05 Jun 2009) | 2 lines
SCI: Audio: Fixed bug in reading of SOL header.
........
r41172 | fingolfin | 2009-06-05 06:50:51 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Added FIXME comment to not_register()
........
r41173 | fingolfin | 2009-06-05 06:51:09 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: cleanup
........
r41174 | fingolfin | 2009-06-05 06:51:24 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Slightly modified kAddAfter so that it does not modify its arguments needlessly
........
r41175 | fingolfin | 2009-06-05 06:51:40 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Added MemObject::isValidOffset method; use it to simplify determine_reg_type
........
r41176 | fingolfin | 2009-06-05 07:42:24 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Renamed _kfuncTable -> _kernelFuncs; and simplified/streamlined the kernel func map in kernel.cpp a bit
........
r41177 | fingolfin | 2009-06-05 07:44:39 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Renamed EngineState::flags and version to _flags and _version (following our conventions); also slightly changed the EngineState constructor to init _version & _flags, and used this to make them constant
........
r41178 | fingolfin | 2009-06-05 07:53:45 +1000 (Fri, 05 Jun 2009) | 1 line
oops
........
r41179 | athrxx | 2009-06-05 08:12:13 +1000 (Fri, 05 Jun 2009) | 1 line
LOL: implemented Vaelan's cube
........
r41180 | fingolfin | 2009-06-05 08:16:31 +1000 (Fri, 05 Jun 2009) | 1 line
SCI: Made some members of class Resource protected; some cleanup
........
r41181 | waltervn | 2009-06-05 09:55:08 +1000 (Fri, 05 Jun 2009) | 3 lines
SCI: Fixed some endian bugs related to speech handling. READ_UINT* are not LE,
but use native endianness. Thanks to clone2727 for pointing this out.
........
r41185 | Kirben | 2009-06-05 10:57:58 +1000 (Fri, 05 Jun 2009) | 1 line
Update sound code in HE80+ games, for sound rate differences.
........
r41186 | waltervn | 2009-06-05 11:12:52 +1000 (Fri, 05 Jun 2009) | 2 lines
SCI: Audio: Fixed bug in sample length computation.
........
r41188 | Kirben | 2009-06-05 12:35:38 +1000 (Fri, 05 Jun 2009) | 1 line
Fix issues selecting some items in arttime and football.
........
r41189 | Kirben | 2009-06-05 14:16:32 +1000 (Fri, 05 Jun 2009) | 1 line
Minor cleanup.
........
r41196 | dreammaster | 2009-06-05 22:20:42 +1000 (Fri, 05 Jun 2009) | 1 line
Tweaks to the code that pauses for a mouse press when displaying many text messages
........
r41197 | thebluegr | 2009-06-06 04:05:45 +1000 (Sat, 06 Jun 2009) | 1 line
Removed some unused code and performed some cleanup
........
r41198 | thebluegr | 2009-06-06 05:04:14 +1000 (Sat, 06 Jun 2009) | 1 line
Moved some more debug commands to ScummVM's coneole and removed some unused code
........
r41199 | athrxx | 2009-06-06 07:34:18 +1000 (Sat, 06 Jun 2009) | 1 line
LOL: implemented another opcode
........
r41200 | mthreepwood | 2009-06-06 08:35:13 +1000 (Sat, 06 Jun 2009) | 1 line
Make the PlayStation's abbreviation to all lower-case for consistency and change the description from Playstation to Sony PlayStation
........
r41201 | athrxx | 2009-06-06 08:53:36 +1000 (Sat, 06 Jun 2009) | 1 line
LOL: minor bug fix
........
r41202 | thebluegr | 2009-06-06 09:08:35 +1000 (Sat, 06 Jun 2009) | 1 line
Cleanup
........
svn-id: r41206
Diffstat (limited to 'engines')
57 files changed, 2101 insertions, 1835 deletions
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index bdbf257b32..649cc72cb8 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -40,6 +40,8 @@ unsigned int timer = 0; gfxEntryStruct* linkedMsgList = NULL; +extern bool isBlack; + void drawBlackSolidBoxSmall() { // gfxModuleData.drawSolidBox(64,100,256,117,0); drawSolidBox(64, 100, 256, 117, 0); @@ -1712,6 +1714,8 @@ void CruiseEngine::mainLoop(void) { //int32 t_start,t_left; //uint32 t_end; //int32 q=0; /* Dummy */ + int16 mouseX, mouseY; + int16 mouseButton; int enableUser = 0; @@ -1793,13 +1797,15 @@ void CruiseEngine::mainLoop(void) { enableUser = 0; } - manageScripts(&relHead); - manageScripts(&procHead); + if (userWait < 1) { + manageScripts(&relHead); + manageScripts(&procHead); - removeFinishedScripts(&relHead); - removeFinishedScripts(&procHead); + removeFinishedScripts(&relHead); + removeFinishedScripts(&procHead); - processAnimation(); + processAnimation(); + } if (remdo) { // ASSERT(0); @@ -1824,17 +1830,13 @@ void CruiseEngine::mainLoop(void) { PCFadeFlag = 0; /*if (!PCFadeFlag)*/ - if (userWait != 2) { + if (!isUserWait) { mainDraw(0); flipScreen(); } if (userEnabled && !userWait && !autoTrack) { if (currentActiveMenu == -1) { - int16 mouseX; - int16 mouseY; - int16 mouseButton; - static int16 oldMouseX = -1; static int16 oldMouseY = -1; @@ -1869,9 +1871,14 @@ void CruiseEngine::mainLoop(void) { // User Wait handling if (userWait == 1) { // Initial step + do { + // Make sure any previous mouse press is released + getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY); + } while (mouseButton != 0); + ++userWait; - mainDraw(0); - flipScreen(); +// mainDraw(0); +// flipScreen(); } else { // Standard handling @@ -1881,9 +1888,16 @@ void CruiseEngine::mainLoop(void) { removeFinishedScripts(&relHead); removeFinishedScripts(&procHead); - // Draw the next screen - processAnimation(); - gfxModuleData_flipScreen(); + if (isBlack) { + // This is a bit of a hack to ensure that user waits directly after a palette fade + // have time to restore the palette before waiting starts + mainDraw(0); + flipScreen(); + } else { + // Draw the next screen + processAnimation(); + gfxModuleData_flipScreen(); + } } continue; } diff --git a/engines/cruise/gfxModule.cpp b/engines/cruise/gfxModule.cpp index 47d3f49204..50e6587d90 100644 --- a/engines/cruise/gfxModule.cpp +++ b/engines/cruise/gfxModule.cpp @@ -40,6 +40,7 @@ palEntry lpalette[256]; int palDirtyMin = 256; int palDirtyMax = -1; +bool isBlack = false; gfxModuleDataStruct gfxModuleData = { 0, // use Tandy @@ -237,6 +238,12 @@ void flip() { g_system->setPalette(paletteRGBA + palDirtyMin*4, palDirtyMin, palDirtyMax - palDirtyMin + 1); palDirtyMin = 256; palDirtyMax = -1; + + isBlack = true; + for (i = 0; i < 256; ++i) { + isBlack = (lpalette[i].R == 0) && (lpalette[i].G == 0) && (lpalette[i].B == 0); + if (!isBlack) break; + } } g_system->copyRectToScreen(globalScreen, 320, 0, 0, 320, 200); diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 5e307d760e..852e0b51fb 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -649,7 +649,7 @@ void Draw_v2::spriteOperation(int16 operation) { int16 spriteLeft = _spriteLeft; int16 spriteTop = _spriteTop; int16 spriteRight = _spriteRight; - int16 spriteBottom = _spriteLeft; + int16 spriteBottom = _spriteBottom; int16 destSpriteX = _destSpriteX; int16 destSpriteY = _destSpriteY; int16 destSurface = _destSurface; @@ -913,7 +913,7 @@ void Draw_v2::spriteOperation(int16 operation) { _spriteLeft = spriteLeft; _spriteTop = spriteTop; _spriteRight = spriteRight; - _spriteLeft = spriteBottom; + _spriteBottom = spriteBottom; _destSpriteX = destSpriteX; _destSpriteY = destSpriteY; _destSurface = destSurface; diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 564e64c8d7..5c494b5180 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -536,7 +536,7 @@ Common::Error LoLEngine::init() { _spellProcs.push_back(new SpellProc(this, &LoLEngine::castSwarm)); _spellProcs.push_back(new SpellProc(this, 0)); _spellProcs.push_back(new SpellProc(this, 0)); - _spellProcs.push_back(new SpellProc(this, &LoLEngine::castUnk)); + _spellProcs.push_back(new SpellProc(this, &LoLEngine::castVaelansCube)); _spellProcs.push_back(new SpellProc(this, 0)); _spellProcs.push_back(new SpellProc(this, 0)); _spellProcs.push_back(new SpellProc(this, 0)); @@ -1910,13 +1910,12 @@ int LoLEngine::castSwarm(ActiveSpell *a) { return 1; } -int LoLEngine::castUnk(ActiveSpell *a) { - return 1; +int LoLEngine::castVaelansCube(ActiveSpell *a) { + return processMagicVaelansCube(); } int LoLEngine::castGuardian(ActiveSpell *a) { - processMagicGuardian(a->charNum); - return 1; + return processMagicGuardian(a->charNum); } int LoLEngine::castHealOnSingleCharacter(ActiveSpell *a) { @@ -1924,7 +1923,7 @@ int LoLEngine::castHealOnSingleCharacter(ActiveSpell *a) { return 1; } -void LoLEngine::processMagicSpark(int charNum, int spellLevel) { +int LoLEngine::processMagicSpark(int charNum, int spellLevel) { WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); _screen->copyPage(0, 12); @@ -1994,16 +1993,18 @@ void LoLEngine::processMagicSpark(int charNum, int spellLevel) { _sceneUpdateRequired = true; delete mov; + return 1; } -void LoLEngine::processMagicHealSelectTarget() { +int LoLEngine::processMagicHealSelectTarget() { _txt->printMessage(0, getLangString(0x4040)); gui_resetButtonList(); gui_setFaceFramesControlButtons(81, 0); gui_initButtonsFromList(_buttonList8); + return 1; } -void LoLEngine::processMagicHeal(int charNum, int spellLevel) { +int LoLEngine::processMagicHeal(int charNum, int spellLevel) { if (!_healOverlay) { _healOverlay = new uint8[256]; _screen->generateGrayOverlay(_screen->getPalette(1), _healOverlay, 52, 22, 20, 0, 256, true); @@ -2113,9 +2114,10 @@ void LoLEngine::processMagicHeal(int charNum, int spellLevel) { _screen->setCurPage(cp); updateDrawPage2(); + return 1; } -void LoLEngine::processMagicIce(int charNum, int spellLevel) { +int LoLEngine::processMagicIce(int charNum, int spellLevel) { int cp = _screen->setCurPage(2); disableSysTimer(2); @@ -2261,9 +2263,10 @@ void LoLEngine::processMagicIce(int charNum, int spellLevel) { delete[] swampCol; delete[] tpal; _screen->setCurPage(cp); + return 1; } -void LoLEngine::processMagicFireball(int charNum, int spellLevel) { +int LoLEngine::processMagicFireball(int charNum, int spellLevel) { int fbCnt = 0; int d = 1; @@ -2412,9 +2415,10 @@ void LoLEngine::processMagicFireball(int charNum, int spellLevel) { updateDrawPage2(); snd_playQueuedEffects(); runLevelScriptCustom(bl, 0x20, charNum, 3, 0, 0); + return 1; } -void LoLEngine::processMagicHandOfFate(int spellLevel) { +int LoLEngine::processMagicHandOfFate(int spellLevel) { int cp = _screen->setCurPage(2); _screen->copyPage(0, 12); @@ -2491,9 +2495,10 @@ void LoLEngine::processMagicHandOfFate(int spellLevel) { gui_drawScene(2); updateDrawPage2(); + return 1; } -void LoLEngine::processMagicMistOfDoom(int charNum, int spellLevel) { +int LoLEngine::processMagicMistOfDoom(int charNum, int spellLevel) { static const uint8 mistDamage[] = { 30, 70, 110, 200 }; _envSfxUseQueue = true; @@ -2525,10 +2530,11 @@ void LoLEngine::processMagicMistOfDoom(int charNum, int spellLevel) { _screen->copyPage(12, 0); updateDrawPage2(); - this->snd_playQueuedEffects(); + this->snd_playQueuedEffects(); + return 1; } -void LoLEngine::processMagicLightning(int charNum, int spellLevel) { +int LoLEngine::processMagicLightning(int charNum, int spellLevel) { _screen->hideMouse(); _screen->copyPage(0, 2); gui_drawScene(2); @@ -2562,9 +2568,10 @@ void LoLEngine::processMagicLightning(int charNum, int spellLevel) { _sceneUpdateRequired = true; gui_drawScene(0); _screen->showMouse(); + return 1; } -void LoLEngine::processMagicFog() { +int LoLEngine::processMagicFog() { int cp = _screen->setCurPage(2); _screen->copyPage(0, 12); @@ -2598,9 +2605,10 @@ void LoLEngine::processMagicFog() { } gui_drawScene(0); + return 1; } -void LoLEngine::processMagicSwarm(int charNum, int damage) { +int LoLEngine::processMagicSwarm(int charNum, int damage) { int cp = _screen->setCurPage(2); _screen->copyPage(0, 12); snd_playSoundEffect(74, -1); @@ -2662,12 +2670,71 @@ void LoLEngine::processMagicSwarm(int charNum, int damage) { _screen->setCurPage(cp); delete mov; + return 1; } -void LoLEngine::processMagicGuardian(int charNum) { - //uint16 targetBlock = 0; - //int dist = getSpellTargetBlock(_currentBlock, _currentDirection, 3, targetBlock); +int LoLEngine::processMagicVaelansCube() { + uint8 *tmpPal1 = new uint8[768]; + uint8 *tmpPal2 = new uint8[768]; + uint8 *sp1 = _screen->getPalette(1); + + memcpy(tmpPal1, sp1, 768); + memcpy(tmpPal2, sp1, 768); + + for (int i = 0; i < 128; i++) { + uint16 a = sp1[i * 3] + 16; + tmpPal2[i * 3] = (a > 60) ? 60 : a; + tmpPal2[i * 3 + 1] = sp1[i * 3 + 1]; + a = sp1[i * 3 + 2] + 19; + tmpPal2[i * 3 + 2] = (a > 60) ? 60 : a; + } + + snd_playSoundEffect(146, -1); + + uint32 ctime = _system->getMillis(); + uint32 endTime = _system->getMillis() + 70 * _tickLength; + + while (_system->getMillis() < endTime) { + _screen->fadePaletteStep(tmpPal1, tmpPal2, _system->getMillis() - ctime, 70 * _tickLength); + updateInput(); + } + uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection); + uint8 s = _levelBlockProperties[bl].walls[_currentDirection ^ 2]; + uint8 flg = _wllWallFlags[s]; + + int v = (s == 47 && (_currentLevel == 17 || _currentLevel == 24)) ? 1 : 0; + if ((_wllVmpMap[s] == 1 || _wllVmpMap[s] == 2) && (flg & 1) && (_currentLevel == 22)) { + memset(_levelBlockProperties[bl].walls, 0, 4); + gui_drawScene(0); + v = 1; + } + + uint16 o = _levelBlockProperties[bl].assignedObjects; + while (o & 0x8000) { + MonsterInPlay *m = &_monsters[o & 0x7fff]; + o = m->nextAssignedObject; + if (m->properties->flags & 0x1000) { + inflictDamage(o, 100, 0xffff, 0, 0x80); + v = 1; + } + } + + ctime = _system->getMillis(); + endTime = _system->getMillis() + 70 * _tickLength; + + while (_system->getMillis() < endTime) { + _screen->fadePaletteStep(tmpPal2, tmpPal1, _system->getMillis() - ctime, 70 * _tickLength); + updateInput(); + } + + delete[] tmpPal1; + delete[] tmpPal2; + + return v; +} + +int LoLEngine::processMagicGuardian(int charNum) { int cp = _screen->setCurPage(2); _screen->copyPage(0, 2); _screen->copyPage(2, 12); @@ -2682,7 +2749,7 @@ void LoLEngine::processMagicGuardian(int charNum) { _screen->copyPage(2, 12); uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection); - //bool a = (_levelBlockProperties[bl].assignedObjects & 0x8000) ? true : false; + int res = (_levelBlockProperties[bl].assignedObjects & 0x8000) ? 1 : 0; inflictMagicalDamageForBlock(bl, charNum, 200, 0x80); _screen->copyPage(12, 2); @@ -2699,6 +2766,7 @@ void LoLEngine::processMagicGuardian(int charNum) { _screen->setCurPage(cp); gui_drawPlayField(); updateDrawPage2(); + return res; } void LoLEngine::callbackProcessMagicSwarm(WSAMovie_v2 *mov, int x, int y) { diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index 4e9b39b88d..be734d083c 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -69,7 +69,7 @@ struct LoLCharacter { int16 nextAnimUpdateCountdown; uint16 items[11]; uint8 skillLevels[3]; - uint8 skillModifiers[3]; + int8 skillModifiers[3]; int32 experiencePts[3]; uint8 characterUpdateEvents[5]; uint8 characterUpdateDelay[5]; @@ -771,6 +771,7 @@ private: int olol_getNextActiveCharacter(EMCState *script); int olol_paralyzePoisonCharacter(EMCState *script); int olol_drawCharPortrait(EMCState *script); + int olol_removeInventoryItem(EMCState *script); int olol_getAnimationLastPart(EMCState *script); int olol_assignSpecialGuiShape(EMCState *script); int olol_findInventoryItem(EMCState *script); @@ -1326,21 +1327,22 @@ private: int castLightning(ActiveSpell *a); int castFog(ActiveSpell *a); int castSwarm(ActiveSpell *a); - int castUnk(ActiveSpell *a); + int castVaelansCube(ActiveSpell *a); int castGuardian(ActiveSpell *a); int castHealOnSingleCharacter(ActiveSpell *a); - void processMagicSpark(int charNum, int spellLevel); - void processMagicHealSelectTarget(); - void processMagicHeal(int charNum, int spellLevel); - void processMagicIce(int charNum, int spellLevel); - void processMagicFireball(int charNum, int spellLevel); - void processMagicHandOfFate(int spellLevel); - void processMagicMistOfDoom(int charNum, int spellLevel); - void processMagicLightning(int charNum, int spellLevel); - void processMagicFog(); - void processMagicSwarm(int charNum, int damage); - void processMagicGuardian(int charNum); + int processMagicSpark(int charNum, int spellLevel); + int processMagicHealSelectTarget(); + int processMagicHeal(int charNum, int spellLevel); + int processMagicIce(int charNum, int spellLevel); + int processMagicFireball(int charNum, int spellLevel); + int processMagicHandOfFate(int spellLevel); + int processMagicMistOfDoom(int charNum, int spellLevel); + int processMagicLightning(int charNum, int spellLevel); + int processMagicFog(); + int processMagicSwarm(int charNum, int damage); + int processMagicVaelansCube(); + int processMagicGuardian(int charNum); void callbackProcessMagicSwarm(WSAMovie_v2 *mov, int x, int y); void callbackProcessMagicLightning(WSAMovie_v2 *mov, int x, int y); diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp index 4998795f73..248c46c2a3 100644 --- a/engines/kyra/saveload_lol.cpp +++ b/engines/kyra/saveload_lol.cpp @@ -85,7 +85,7 @@ Common::Error LoLEngine::loadGameState(int slot) { for (int ii = 0; ii < 3; ii++) c->skillLevels[ii] = in.readByte(); for (int ii = 0; ii < 3; ii++) - c->skillModifiers[ii] = in.readByte(); + c->skillModifiers[ii] = in.readSByte(); for (int ii = 0; ii < 3; ii++) c->experiencePts[ii] = in.readUint32BE(); for (int ii = 0; ii < 5; ii++) @@ -294,7 +294,7 @@ Common::Error LoLEngine::saveGameState(int slot, const char *saveName, const Gra for (int ii = 0; ii < 3; ii++) out->writeByte(c->skillLevels[ii]); for (int ii = 0; ii < 3; ii++) - out->writeByte(c->skillModifiers[ii]); + out->writeSByte(c->skillModifiers[ii]); for (int ii = 0; ii < 3; ii++) out->writeUint32BE(c->experiencePts[ii]); for (int ii = 0; ii < 5; ii++) diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index b834123d2f..5f64a1cddd 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -589,6 +589,16 @@ void Screen_LoL::copyRegionSpecial(int page1, int w1, int h1, int x1, int y1, in va_end(args); } + // _internDimH: h0 +// _internDimW: w0 +// _internDimDstX: x1 +// _internDimDstY: y1 +// _internBlockWidth: w1 +// _internBlockHeight: h1 +// _internDimU5: x2 +// _internDimU6: y2 +// _internBlockWidth2: w2 + _internDimX = _internDimY = 0; _internDimW = w1; _internDimH = h1; diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index 75651a2a9a..33edfa0e24 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -1896,6 +1896,31 @@ int LoLEngine::olol_drawCharPortrait(EMCState *script) { return 1; } +int LoLEngine::olol_removeInventoryItem(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_removeInventoryItem(%p) (%d)", (const void *)script, stackPos(0)); + int itemType = stackPos(0); + for (int i = 0; i < 48; i++) { + if (!_inventory[i] || _itemsInPlay[_inventory[i]].itemPropertyIndex != itemType) + continue; + _inventory[i] = 0; + gui_drawInventory(); + return 1; + } + + for (int i = 0; i < 4; i++) { + if (!(_characters[i].flags & 1)) + continue; + + for (int ii = 0; ii < 11; ii++) { + if (!_characters[i].items[ii] || _itemsInPlay[_characters[i].items[ii]].itemPropertyIndex != itemType) + continue; + _characters[i].items[ii] = 0; + return 1; + } + } + return 0; +} + int LoLEngine::olol_getAnimationLastPart(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getAnimationLastPart(%p) (%d)", (const void *)script, stackPos(0)); return _tim->resetAnimationLastPart(stackPos(0)); @@ -2730,7 +2755,7 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_drawCharPortrait); // 0xA0 - OpcodeUnImpl(); + Opcode(olol_removeInventoryItem); OpcodeUnImpl(); OpcodeUnImpl(); Opcode(olol_getAnimationLastPart); diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 67e324f078..26ff08d065 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -27,6 +27,7 @@ #include "sci/sci.h" #include "sci/console.h" +#include "sci/debug.h" #include "sci/resource.h" #include "sci/vocabulary.h" #include "sci/engine/savegame.h" @@ -47,21 +48,22 @@ namespace Sci { extern EngineState *g_EngineState; -int debug_sleeptime_factor = 1; -int debug_simulated_key = 0; -bool debug_track_mouse_clicks = false; -bool debug_weak_validations = false; +int g_debug_sleeptime_factor = 1; +int g_debug_simulated_key = 0; +bool g_debug_track_mouse_clicks = false; +bool g_debug_weak_validations = true; Console::Console(SciEngine *vm) : GUI::Debugger() { _vm = vm; // Variables - DVar_Register("sleeptime_factor", &debug_sleeptime_factor, DVAR_INT, 0); + DVar_Register("sleeptime_factor", &g_debug_sleeptime_factor, DVAR_INT, 0); DVar_Register("gc_interval", &script_gc_interval, DVAR_INT, 0); - DVar_Register("simulated_key", &debug_simulated_key, DVAR_INT, 0); - DVar_Register("track_mouse_clicks", &debug_track_mouse_clicks, DVAR_BOOL, 0); - DVar_Register("weak_validations", &debug_weak_validations, DVAR_BOOL, 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("weak_validations", &g_debug_weak_validations, DVAR_BOOL, 0); + DVar_Register("script_abort_flag", &script_abort_flag, DVAR_INT, 0); // General DCmd_Register("help", WRAP_METHOD(Console, cmdHelp)); @@ -114,6 +116,9 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { DCmd_Register("dynamic_views", WRAP_METHOD(Console, cmdDynamicViews)); DCmd_Register("dropped_views", WRAP_METHOD(Console, cmdDroppedViews)); DCmd_Register("status_bar", WRAP_METHOD(Console, cmdStatusBarColors)); +#ifdef GFXW_DEBUG_WIDGETS + DCmd_Register("print_widget", WRAP_METHOD(Console, cmdPrintWidget)); +#endif // Segments DCmd_Register("segment_table", WRAP_METHOD(Console, cmdPrintSegmentTable)); DCmd_Register("segment_info", WRAP_METHOD(Console, cmdSegmentInfo)); @@ -181,6 +186,14 @@ void Console::postEnter() { _vm->_mixer->pauseAll(false); } + +#if 0 +// Unused +#define LOOKUP_SPECIES(species) (\ + (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \ + + s->_classtable[species].class_offset) +#endif + bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf("\n"); DebugPrintf("Variables\n"); @@ -190,6 +203,7 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf("simulated_key: Add a key with the specified scan code to the event list\n"); DebugPrintf("track_mouse_clicks: Toggles mouse click tracking to the console\n"); DebugPrintf("weak_validations: Turns some validation errors into warnings\n"); + DebugPrintf("script_abort_flag: Set to 1 to abort script execution. Set to 2 to force a replay afterwards\n"); DebugPrintf("\n"); DebugPrintf("Commands\n"); DebugPrintf("--------\n"); @@ -247,6 +261,9 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" dynamic_views - Lists active dynamic views\n"); DebugPrintf(" dropped_views - Lists dropped dynamic views\n"); DebugPrintf(" status_bar - Sets the colors of the status bar\n"); +#ifdef GFXW_DEBUG_WIDGETS + DebugPrintf(" print_widget - Shows active widgets (no params) or information on the specified widget indices\n"); +#endif DebugPrintf("\n"); DebugPrintf("Segments:\n"); DebugPrintf(" segment_table - Lists all segments\n"); @@ -666,8 +683,8 @@ bool Console::cmdRestoreGame(int argc, const char **argv) { if (newstate) { g_EngineState->successor = newstate; // Set successor - script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game - _debugstate_valid = 0; + script_abort_flag = 2; // Abort current game with replay + g_debugstate_valid = 0; shrink_execution_stack(g_EngineState, g_EngineState->execution_stack_base + 1); return 0; @@ -698,7 +715,7 @@ bool Console::cmdRestartGame(int argc, const char **argv) { g_EngineState->restarting_flags |= SCI_GAME_IS_RESTARTING_NOW; script_abort_flag = 1; - _debugstate_valid = 0; + g_debugstate_valid = 0; return false; } @@ -1645,7 +1662,7 @@ bool Console::cmdValueType(int argc, const char **argv) { return true; } - int t = determine_reg_type(g_EngineState, val, 1); + int t = determine_reg_type(g_EngineState, val, true); int invalid = t & KSIG_INVALID; switch (t & ~KSIG_INVALID) { @@ -2347,9 +2364,9 @@ bool Console::cmdExit(int argc, const char **argv) { if (!scumm_stricmp(argv[1], "game")) { // Quit gracefully script_abort_flag = 1; // Terminate VM - _debugstate_valid = 0; - _debug_seeking = 0; - _debug_step_running = 0; + g_debugstate_valid = 0; + g_debug_seeking = 0; + g_debug_step_running = 0; } else if (!scumm_stricmp(argv[1], "now")) { // Quit ungracefully @@ -2677,4 +2694,225 @@ int printObject(EngineState *s, reg_t pos) { return 0; } +#define GETRECT(ll, rr, tt, bb) \ + ll = GET_SELECTOR(pos, ll); \ + rr = GET_SELECTOR(pos, rr); \ + tt = GET_SELECTOR(pos, tt); \ + bb = GET_SELECTOR(pos, bb); + +#if 0 +// TODO Re-implement this +static void viewobjinfo(EngineState *s, HeapPtr pos) { + char *signals[16] = { + "stop_update", + "updated", + "no_update", + "hidden", + "fixed_priority", + "always_update", + "force_update", + "remove", + "frozen", + "is_extra", + "hit_obstacle", + "doesnt_turn", + "no_cycler", + "ignore_horizon", + "ignore_actor", + "dispose!" + }; + + int x, y, z, priority; + int cel, loop, view, signal; + int nsLeft, nsRight, nsBottom, nsTop; + int lsLeft, lsRight, lsBottom, lsTop; + int brLeft, brRight, brBottom, brTop; + int i; + int have_rects = 0; + Common::Rect nsrect, nsrect_clipped, brrect; + + if (lookup_selector(s, pos, s->_kernel->_selectorMap.nsBottom, NULL) == kSelectorVariable) { + GETRECT(nsLeft, nsRight, nsBottom, nsTop); + GETRECT(lsLeft, lsRight, lsBottom, lsTop); + GETRECT(brLeft, brRight, brBottom, brTop); + have_rects = 1; + } + + GETRECT(view, loop, signal, cel); + + sciprintf("\n-- View information:\ncel %d/%d/%d at ", view, loop, cel); + + x = GET_SELECTOR(pos, x); + y = GET_SELECTOR(pos, y); + priority = GET_SELECTOR(pos, priority); + if (s->_kernel->_selectorMap.z > 0) { + z = GET_SELECTOR(pos, z); + sciprintf("(%d,%d,%d)\n", x, y, z); + } else + sciprintf("(%d,%d)\n", x, y); + + if (priority == -1) + sciprintf("No priority.\n\n"); + else + sciprintf("Priority = %d (band starts at %d)\n\n", priority, PRIORITY_BAND_FIRST(priority)); + + if (have_rects) { + sciprintf("nsRect: [%d..%d]x[%d..%d]\n", nsLeft, nsRight, nsTop, nsBottom); + sciprintf("lsRect: [%d..%d]x[%d..%d]\n", lsLeft, lsRight, lsTop, lsBottom); + sciprintf("brRect: [%d..%d]x[%d..%d]\n", brLeft, brRight, brTop, brBottom); + } + + nsrect = get_nsrect(s, pos, 0); + nsrect_clipped = get_nsrect(s, pos, 1); + brrect = set_base(s, pos); + sciprintf("new nsRect: [%d..%d]x[%d..%d]\n", nsrect.x, nsrect.xend, nsrect.y, nsrect.yend); + sciprintf("new clipped nsRect: [%d..%d]x[%d..%d]\n", nsrect_clipped.x, nsrect_clipped.xend, nsrect_clipped.y, nsrect_clipped.yend); + sciprintf("new brRect: [%d..%d]x[%d..%d]\n", brrect.x, brrect.xend, brrect.y, brrect.yend); + sciprintf("\n signals = %04x:\n", signal); + + for (i = 0; i < 16; i++) + if (signal & (1 << i)) + sciprintf(" %04x: %s\n", 1 << i, signals[i]); +} +#endif +#undef GETRECT + +#define GETRECT(ll, rr, tt, bb) \ + ll = GET_SELECTOR(pos, ll); \ + rr = GET_SELECTOR(pos, rr); \ + tt = GET_SELECTOR(pos, tt); \ + bb = GET_SELECTOR(pos, bb); + +#if 0 +// Draws the nsRect and brRect of a dynview object. nsRect is green, brRect is blue. +// TODO: Re-implement this +static int c_gfx_draw_viewobj(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { + HeapPtr pos = (HeapPtr)(cmdParams[0].val); + int is_view; + int x, y, priority; + int nsLeft, nsRight, nsBottom, nsTop; + int brLeft, brRight, brBottom, brTop; + + if (!s) { + sciprintf("Not in debug state!\n"); + return 1; + } + + if ((pos < 4) || (pos > 0xfff0)) { + sciprintf("Invalid address.\n"); + return 1; + } + + if (((int16)READ_LE_UINT16(s->heap + pos + SCRIPT_OBJECT_MAGIC_OFFSET)) != SCRIPT_OBJECT_MAGIC_NUMBER) { + sciprintf("Not an object.\n"); + return 0; + } + + + is_view = (lookup_selector(s, pos, s->_kernel->_selectorMap.x, NULL) == kSelectorVariable) && + (lookup_selector(s, pos, s->_kernel->_selectorMap.brLeft, NULL) == kSelectorVariable) && + (lookup_selector(s, pos, s->_kernel->_selectorMap.signal, NULL) == kSelectorVariable) && + (lookup_selector(s, pos, s->_kernel->_selectorMap.nsTop, NULL) == kSelectorVariable); + + if (!is_view) { + sciprintf("Not a dynamic View object.\n"); + return 0; + } + + x = GET_SELECTOR(pos, x); + y = GET_SELECTOR(pos, y); + priority = GET_SELECTOR(pos, priority); + GETRECT(brLeft, brRight, brBottom, brTop); + GETRECT(nsLeft, nsRight, nsBottom, nsTop); + gfxop_set_clip_zone(s->gfx_state, gfx_rect_fullscreen); + + brTop += 10; + brBottom += 10; + nsTop += 10; + nsBottom += 10; + + gfxop_fill_box(s->gfx_state, gfx_rect(nsLeft, nsTop, nsRight - nsLeft + 1, nsBottom - nsTop + 1), s->ega_colors[2]); + gfxop_fill_box(s->gfx_state, gfx_rect(brLeft, brTop, brRight - brLeft + 1, brBottom - brTop + 1), s->ega_colors[1]); + gfxop_fill_box(s->gfx_state, gfx_rect(x - 1, y - 1, 3, 3), s->ega_colors[0]); + gfxop_fill_box(s->gfx_state, gfx_rect(x - 1, y, 3, 1), s->ega_colors[priority]); + gfxop_fill_box(s->gfx_state, gfx_rect(x, y - 1, 1, 3), s->ega_colors[priority]); + gfxop_update(s->gfx_state); + + return 0; +} +#endif +#undef GETRECT + +#if 0 +// Executes one operation skipping over sends +// TODO Re-implement this +int c_stepover(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { + int opcode, opnumber; + + if (!g_debugstate_valid) { + sciprintf("Not in debug state\n"); + return 1; + } + + g_debugstate_valid = 0; + opcode = s->_heap[*p_pc]; + opnumber = opcode >> 1; + if (opnumber == 0x22 /* callb */ || opnumber == 0x23 /* calle */ || + opnumber == 0x25 /* send */ || opnumber == 0x2a /* self */ || opnumber == 0x2b /* super */) { + g_debug_seeking = _DEBUG_SEEK_SO; + s_debug_seek_level = s->_executionStack.size()-1; + // Store in s_debug_seek_special the offset of the next command after send + switch (opcode) { + case 0x46: // calle W + s_debug_seek_special = *p_pc + 5; + break; + + case 0x44: // callb W + case 0x47: // calle B + case 0x56: // super W + s_debug_seek_special = *p_pc + 4; + break; + + case 0x45: // callb B + case 0x57: // super B + case 0x4A: // send W + case 0x54: // self W + s_debug_seek_special = *p_pc + 3; + break; + + default: + s_debug_seek_special = *p_pc + 2; + } + } + + return 0; +} +#endif + +#ifdef GFXW_DEBUG_WIDGETS +extern GfxWidget *debug_widgets[]; +extern int debug_widget_pos; + +// If called with no parameters, it shows which widgets are active +// With parameters, it lists the widget corresponding to the numerical index specified (for each parameter). +bool Console::cmdPrintWidget(int argc, const char **argv) { + if (argc > 1) { + for (int i = 0; i < argc; i++) { + int widget_nr = atoi(argv[1]); + + DebugPrintf("===== Widget #%d:\n", widget_nr); + debug_widgets[widget_nr]->print(0); + } + } else if (debug_widget_pos > 1) { + DebugPrintf("Widgets 0-%d are active\n", debug_widget_pos - 1); + } else if (debug_widget_pos == 1) { + DebugPrintf("Widget 0 is active\n"); + } else { + DebugPrintf("No widgets are active\n"); + } + + return true; +} +#endif + } // End of namespace Sci diff --git a/engines/sci/console.h b/engines/sci/console.h index f0975837df..b2e66daa0f 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -33,6 +33,7 @@ namespace Sci { class SciEngine; +struct List; // Refer to the "addresses" command on how to pass address parameters int parse_reg_t(EngineState *s, const char *str, reg_t *dest); @@ -97,6 +98,7 @@ private: bool cmdDynamicViews(int argc, const char **argv); bool cmdDroppedViews(int argc, const char **argv); bool cmdStatusBarColors(int argc, const char **argv); + bool cmdPrintWidget(int argc, const char **argv); // Segments bool cmdPrintSegmentTable(int argc, const char **argv); bool cmdSegmentInfo(int argc, const char **argv); diff --git a/engines/sci/debug.h b/engines/sci/debug.h new file mode 100644 index 0000000000..ec44838826 --- /dev/null +++ b/engines/sci/debug.h @@ -0,0 +1,47 @@ +/* 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_DEBUG_H +#define SCI_DEBUG_H + +namespace Sci { + +// Various global variables used for debugging are declared here + +extern int g_stop_on_event; + +extern int g_debugstate_valid; +extern int g_debug_seeking; +extern int g_debug_step_running; + +extern int g_debug_sleeptime_factor; +extern int g_debug_simulated_key; +extern bool g_debug_track_mouse_clicks; +extern bool g_debug_weak_validations; + + +} // End of namespace Sci + +#endif diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp index 6aba9b3f10..bfd38f2c1b 100644 --- a/engines/sci/engine/game.cpp +++ b/engines/sci/engine/game.cpp @@ -43,7 +43,7 @@ int _reset_graphics_input(EngineState *s) { gfx_color_t transparent = { PaletteEntry(), 0, -1, -1, 0 }; debug(2, "Initializing graphics"); - if (s->resmgr->_sciVersion <= SCI_VERSION_01 || (s->flags & GF_SCI1_EGA)) { + if (s->resmgr->_sciVersion <= SCI_VERSION_01 || (s->_flags & GF_SCI1_EGA)) { int i; for (i = 0; i < 16; i++) { @@ -66,7 +66,7 @@ int _reset_graphics_input(EngineState *s) { } else { resource = s->resmgr->findResource(kResourceTypePalette, 999, 1); if (resource) { - if (s->version < SCI_VERSION_1_1) + if (s->_version < SCI_VERSION_1_1) s->gfx_state->gfxResMan->setStaticPalette(gfxr_read_pal1(999, resource->data, resource->size)); else s->gfx_state->gfxResMan->setStaticPalette(gfxr_read_pal11(999, resource->data, resource->size)); @@ -89,7 +89,7 @@ int _reset_graphics_input(EngineState *s) { s->priority_first = 42; // Priority zone 0 ends here - if (s->flags & GF_SCI0_OLDGFXFUNCS) + if (s->_flags & GF_SCI0_OLDGFXFUNCS) s->priority_last = 200; else s->priority_last = 190; @@ -259,7 +259,7 @@ static int create_class_table_sci0(EngineState *s) { Resource *script = s->resmgr->findResource(kResourceTypeScript, scriptnr, 0); if (script) { - if (s->flags & GF_SCI0_OLD) + if (s->_flags & GF_SCI0_OLD) magic_offset = seeker = 2; else magic_offset = seeker = 0; @@ -324,13 +324,12 @@ static int create_class_table_sci0(EngineState *s) { } // Architectural stuff: Init/Unintialize engine -int script_init_engine(EngineState *s, sci_version_t version) { +int script_init_engine(EngineState *s) { int result; s->kernel_opt_flags = 0; - s->version = version; - if (s->version >= SCI_VERSION_1_1) + if (s->_version >= SCI_VERSION_1_1) result = create_class_table_sci11(s); else result = create_class_table_sci0(s); @@ -340,7 +339,7 @@ int script_init_engine(EngineState *s, sci_version_t version) { return 1; } - s->seg_manager = new SegManager(s->version >= SCI_VERSION_1_1); + s->seg_manager = new SegManager(s->_version >= SCI_VERSION_1_1); s->gc_countdown = GC_INTERVAL - 1; SegmentId script_000_segment = script_get_segment(s, 0, SCRIPT_GET_LOCK); @@ -370,7 +369,7 @@ int script_init_engine(EngineState *s, sci_version_t version) { s->_executionStack.clear(); // Start without any execution stack s->execution_stack_base = -1; // No vm is running yet - s->_kernel = new Kernel(s->resmgr, (s->flags & GF_SCI0_OLD)); + s->_kernel = new Kernel(s->resmgr, (s->_flags & GF_SCI0_OLD)); s->_vocabulary = new Vocabulary(s->resmgr); s->restarting_flags = SCI_GAME_IS_NOT_RESTARTING; @@ -378,7 +377,7 @@ int script_init_engine(EngineState *s, sci_version_t version) { s->bp_list = NULL; // No breakpoints defined s->have_bp = 0; - if ((s->flags & GF_SCI1_LOFSABSOLUTE) && s->version < SCI_VERSION_1_1) + if ((s->_flags & GF_SCI1_LOFSABSOLUTE) && s->_version < SCI_VERSION_1_1) s->seg_manager->setExportWidth(1); else s->seg_manager->setExportWidth(0); diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 719ff16334..3b998c7092 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -298,21 +298,14 @@ static const char *sci1_default_knames[SCI1_KNAMES_DEFAULT_ENTRIES_NR] = { /*0x88*/ "DbugStr" }; -enum KernelFunctionType { - KF_NEW = 1, - KF_NONE = -1, /**< No mapping, but name is known */ - KF_TERMINATOR = -42 /**< terminates kfunct_mappers */ -}; - struct SciKernelFunction { - KernelFunctionType type; const char *name; - kfunct *fun; /* The actual function */ + KernelFunc *fun; /* The actual function */ const char *signature; /* kfunct signature */ }; -#define DEFUN(nm, cname, sig) {KF_NEW, nm, cname, sig} -#define NOFUN(nm) {KF_NONE, nm, NULL, NULL} +#define DEFUN(name, fun, sig) {name, fun, sig} +#define NOFUN(name) {name, NULL, NULL} SciKernelFunction kfunct_mappers[] = { /*00*/ DEFUN("Load", kLoad, "iii*"), @@ -434,8 +427,8 @@ SciKernelFunction kfunct_mappers[] = { /*6f*/ DEFUN("6f", kTimesCos, "ii"), /*70*/ DEFUN("Graph", kGraph, ".*"), /*71*/ DEFUN("Joystick", kJoystick, ".*"), - /*72*/ NOFUN(NULL), - /*73*/ NOFUN(NULL), + /*72*/ NOFUN("unknown72"), + /*73*/ NOFUN("unknown73"), // Experimental functions /*74*/ DEFUN("FileIO", kFileIO, "i.*"), @@ -464,12 +457,19 @@ SciKernelFunction kfunct_mappers[] = { DEFUN("SetVideoMode", kSetVideoMode, "i"), // Special and NOP stuff - {KF_NEW, NULL, k_Unknown, NULL}, + {NULL, k_Unknown, NULL}, - {KF_TERMINATOR, NULL, NULL, NULL} // Terminator + {NULL, NULL, NULL} // Terminator }; -static const char *argtype_description[] = { "Undetermined", "List", "Node", "Object", "Reference", "Arithmetic" }; +static const char *argtype_description[] = { + "Undetermined", + "List", + "Node", + "Object", + "Reference", + "Arithmetic" +}; Kernel::Kernel(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr) { memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t @@ -490,10 +490,6 @@ Kernel::Kernel(ResourceManager *resmgr, bool isOldSci0) : _resmgr(resmgr) { } Kernel::~Kernel() { - _selectorNames.clear(); - _opcodes.clear(); - _kernelNames.clear(); - _kfuncTable.clear(); } bool Kernel::loadSelectorNames(bool isOldSci0) { @@ -577,7 +573,7 @@ int kfree(EngineState *s, reg_t handle) { return 0; } -void kernel_compile_signature(const char **s) { +static void kernel_compile_signature(const char **s) { const char *src = *s; char *result; int ellipsis = 0; @@ -670,50 +666,49 @@ void Kernel::mapFunctions() { functions_nr = max_functions_nr; } - _kfuncTable.resize(functions_nr); + _kernelFuncs.resize(functions_nr); for (uint functnr = 0; functnr < functions_nr; functnr++) { - int seeker, found = -1; - Common::String sought_name; + int found = -1; + // First, get the name, if known, of the kernel function with number functnr + Common::String sought_name; if (functnr < getKernelNamesSize()) sought_name = getKernelName(functnr); - if (!sought_name.empty()) - for (seeker = 0; (found == -1) && kfunct_mappers[seeker].type != KF_TERMINATOR; seeker++) - if (kfunct_mappers[seeker].name && sought_name == kfunct_mappers[seeker].name) - found = seeker; // Found a kernel function with the same name! + // If the name is known, look it up in kfunct_mappers. This table + // maps kernel func names to actual function (pointers). + if (!sought_name.empty()) { + for (uint seeker = 0; (found == -1) && kfunct_mappers[seeker].name; seeker++) + if (sought_name == kfunct_mappers[seeker].name) + found = seeker; // Found a kernel function with the correct name! + } + + // Reset the table entry + _kernelFuncs[functnr].fun = NULL; + _kernelFuncs[functnr].signature = NULL; + _kernelFuncs[functnr].orig_name = sought_name; if (found == -1) { if (!sought_name.empty()) { - warning("Kernel function %s[%x] unmapped", getKernelName(functnr).c_str(), functnr); - _kfuncTable[functnr].fun = kNOP; + // No match but a name was given -> NOP + warning("Kernel function %s[%x] unmapped", sought_name.c_str(), functnr); + _kernelFuncs[functnr].fun = kNOP; } else { + // No match and no name was given -> must be an unknown opcode warning("Flagging kernel function %x as unknown", functnr); - _kfuncTable[functnr].fun = k_Unknown; + _kernelFuncs[functnr].fun = k_Unknown; } - - _kfuncTable[functnr].signature = NULL; - _kfuncTable[functnr].orig_name = sought_name; - } else - switch (kfunct_mappers[found].type) { - case KF_NONE: - _kfuncTable[functnr].signature = NULL; - ++ignored; - break; - - case KF_NEW: - _kfuncTable[functnr].fun = kfunct_mappers[found].fun; - _kfuncTable[functnr].signature = kfunct_mappers[found].signature; - _kfuncTable[functnr].orig_name.clear(); - kernel_compile_signature(&(_kfuncTable[functnr].signature)); + } else { + // A match in kfunct_mappers was found + if (kfunct_mappers[found].fun) { + _kernelFuncs[functnr].fun = kfunct_mappers[found].fun; + _kernelFuncs[functnr].signature = kfunct_mappers[found].signature; + kernel_compile_signature(&(_kernelFuncs[functnr].signature)); ++mapped; - break; - case KF_TERMINATOR: - error("Unexpectedly encountered KF_TERMINATOR"); - break; - } - + } else + ++ignored; + } } // for all functions requesting to be mapped sciprintf("Handled %d/%d kernel functions, mapping %d", mapped + ignored, getKernelNamesSize(), mapped); @@ -724,14 +719,16 @@ void Kernel::mapFunctions() { return; } -int determine_reg_type(EngineState *s, reg_t reg, int allow_invalid) { +int determine_reg_type(EngineState *s, reg_t reg, bool allow_invalid) { MemObject *mobj; + int type = 0; if (!reg.segment) { + type = KSIG_ARITHMETIC; if (!reg.offset) - return KSIG_ARITHMETIC | KSIG_NULL; + type |= KSIG_NULL; - return KSIG_ARITHMETIC; + return type; } if ((reg.segment >= s->seg_manager->_heap.size()) || !s->seg_manager->_heap[reg.segment]) @@ -752,52 +749,31 @@ int determine_reg_type(EngineState *s, reg_t reg, int allow_invalid) { return KSIG_REF; case MEM_OBJ_CLONES: - if (allow_invalid || ((CloneTable *)mobj)->isValidEntry(reg.offset)) - return KSIG_OBJECT; - else - return KSIG_OBJECT | KSIG_INVALID; + type = KSIG_OBJECT; + break; case MEM_OBJ_LOCALS: - if (allow_invalid || reg.offset < (*(LocalVariables *)mobj)._locals.size() * sizeof(reg_t)) - return KSIG_REF; - else - return KSIG_REF | KSIG_INVALID; - case MEM_OBJ_STACK: - if (allow_invalid || reg.offset < (*(DataStack *)mobj).nr * sizeof(reg_t)) - return KSIG_REF; - else - return KSIG_REF | KSIG_INVALID; - case MEM_OBJ_SYS_STRINGS: - if (allow_invalid || (reg.offset < SYS_STRINGS_MAX - && (*(SystemStrings *)mobj).strings[reg.offset].name)) - return KSIG_REF; - else - return KSIG_REF | KSIG_INVALID; + case MEM_OBJ_DYNMEM: + type = KSIG_REF; + break; case MEM_OBJ_LISTS: - if (allow_invalid || ((ListTable *)mobj)->isValidEntry(reg.offset)) - return KSIG_LIST; - else - return KSIG_LIST | KSIG_INVALID; + type = KSIG_LIST; + break; case MEM_OBJ_NODES: - if (allow_invalid || ((NodeTable *)mobj)->isValidEntry(reg.offset)) - return KSIG_NODE; - else - return KSIG_NODE | KSIG_INVALID; - - case MEM_OBJ_DYNMEM: - if (allow_invalid || reg.offset < (*(DynMem *)mobj)._size) - return KSIG_REF; - else - return KSIG_REF | KSIG_INVALID; + type = KSIG_NODE; + break; default: return 0; - } + + if (!allow_invalid && !mobj->isValidOffset(reg.offset)) + type |= KSIG_INVALID; + return type; } const char *kernel_argtype_description(int type) { @@ -806,9 +782,10 @@ const char *kernel_argtype_description(int type) { return argtype_description[sci_ffs(type)]; } -int kernel_matches_signature(EngineState *s, const char *sig, int argc, reg_t *argv) { +bool kernel_matches_signature(EngineState *s, const char *sig, int argc, const reg_t *argv) { + // Always "match" if no signature is given if (!sig) - return 1; + return true; while (*sig && argc) { if ((*sig & KSIG_ANY) != KSIG_ANY) { @@ -816,17 +793,17 @@ int kernel_matches_signature(EngineState *s, const char *sig, int argc, reg_t *a if (!type) { sciprintf("[KERN] Could not determine type of ref %04x:%04x; failing signature check\n", PRINT_REG(*argv)); - return 0; + return false; } if (type & KSIG_INVALID) { sciprintf("[KERN] ref %04x:%04x was determined to be a %s, but the reference itself is invalid\n", PRINT_REG(*argv), kernel_argtype_description(type)); - return 0; + return false; } if (!(type & *sig)) - return 0; + return false; } if (!(*sig & KSIG_ELLIPSIS)) @@ -836,7 +813,7 @@ int kernel_matches_signature(EngineState *s, const char *sig, int argc, reg_t *a } if (argc) - return 0; // Too many arguments + return false; // Too many arguments else return (*sig == 0 || (*sig & KSIG_ELLIPSIS)); } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 862ca2514e..ddc3f93cb7 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -38,11 +38,6 @@ namespace Sci { struct Node; // from vm.h struct List; // from vm.h -extern int stop_on_event; - -extern int _debug_seeking; -extern int _debug_step_running; - #define AVOIDPATH_DYNMEM_STRING "AvoidPath polyline" //#define DEBUG_PARSER // enable for parser debugging @@ -52,12 +47,12 @@ struct opcode { }; /* Generic description: */ -typedef reg_t kfunct(EngineState *s, int funct_nr, int argc, reg_t *argv); +typedef reg_t KernelFunc(EngineState *s, int funct_nr, int argc, reg_t *argv); -struct kfunct_sig_pair_t { - kfunct *fun; /* The actual function */ - const char *signature; /* kfunct signature */ - Common::String orig_name; /* Original name, in case we couldn't map it */ +struct KernelFuncWithSignature { + KernelFunc *fun; /**< The actual function */ + const char *signature; /**< KernelFunc signature */ + Common::String orig_name; /**< Original name, in case we couldn't map it */ }; class Kernel { @@ -93,7 +88,7 @@ public: void dumpScriptClass(char *data, int seeker, int objsize); selector_map_t _selectorMap; /**< Shortcut list for important selectors */ - Common::Array<kfunct_sig_pair_t> _kfuncTable; /**< Table of kernel functions */ + Common::Array<KernelFuncWithSignature> _kernelFuncs; /**< Table of kernel functions */ private: /** diff --git a/engines/sci/engine/kernel_types.h b/engines/sci/engine/kernel_types.h index 24478c9119..8927586a8e 100644 --- a/engines/sci/engine/kernel_types.h +++ b/engines/sci/engine/kernel_types.h @@ -64,30 +64,36 @@ namespace Sci { #define KSIG_ALLOW_INV 0x20 #define KSIG_INVALID KSIG_ALLOW_INV -int kernel_matches_signature(EngineState *s, const char *sig, int argc, reg_t *argv); -/* Determines whether a list of registers matches a given signature -** Parameters: (EngineState *) s: The state to operate on -** (char *) sig: The signature to test against -** (int) argc: Number of arguments to test -** (reg_t *) argv: Argument list -** Returns : (int) 0 iff the signature was not matched -*/ +/** + * Determines whether a list of registers matches a given signature. + * If no signature is given (i.e., if sig is NULL), this is always + * treated as a match. + * + * @param s state to operate on + * @param sig signature to test against + * @param argc number of arguments to test + * @param argv argument list + * @return true if the signature was matched, false otherwise + */ +bool kernel_matches_signature(EngineState *s, const char *sig, int argc, const reg_t *argv); -int determine_reg_type(EngineState *s, reg_t reg, int allow_invalid); -/* Determines the type of the object indicated by reg -** Parameters: (EngineState *) s: The state to operate on -** (reg_t) reg: The register to check -** (int) allow_invalid: Allow invalid pointer values -** Returns : one of KSIG_* below KSIG_NULL. -** KSIG_INVALID set if the type of reg can be determined, but is invalid. -** 0 on error. -*/ +/** + * Determines the type of the object indicated by reg. + * @param s state to operate on + * @param reg register to check + * @param allow_invalid determines whether invalid pointer (=offset) values are allowed + * @return one of KSIG_* below KSIG_NULL. + * KSIG_INVALID set if the type of reg can be determined, but is invalid. + * 0 on error. + */ +int determine_reg_type(EngineState *s, reg_t reg, bool allow_invalid); +/** + * Returns a textual description of the type of an object. + * @param type type value to describe + * @return pointer to a (static) descriptive string + */ const char *kernel_argtype_description(int type); -/* Returns a textual description of the type of an object -** Parameters: (int) type: The type value to describe -** Returns: (const char *) Pointer to a (static) descriptive string -*/ } // End of namespace Sci diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index c0a137469e..66395035c8 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -28,13 +28,12 @@ #include "sci/engine/kernel.h" #include "sci/gfx/gfx_widgets.h" #include "sci/gfx/gfx_state_internal.h" // required for GfxPort, GfxVisual -#include "sci/console.h" // for debug_simulated_key +#include "sci/console.h" +#include "sci/debug.h" // for g_debug_simulated_key namespace Sci { -int stop_on_event = 0; -extern int debug_simulated_key; -extern bool debug_track_mouse_clicks; +int g_stop_on_event = 0; #define SCI_VARIABLE_GAME_SPEED 3 @@ -43,7 +42,7 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t obj = argv[1]; sci_event_t e; int oldx, oldy; - int modifier_mask = s->version <= SCI_VERSION_0 ? SCI_EVM_ALL : SCI_EVM_NO_FOOLOCK; + int modifier_mask = s->_version <= SCI_VERSION_0 ? SCI_EVM_ALL : SCI_EVM_NO_FOOLOCK; if (s->kernel_opt_flags & KERNEL_OPT_FLAG_GOT_2NDEVENT) { // Penalty time- too many requests to this function without waiting! @@ -53,13 +52,13 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) { // If there's a simkey pending, and the game wants a keyboard event, use the // simkey instead of a normal event - if (debug_simulated_key && (mask & SCI_EVT_KEYBOARD)) { + if (g_debug_simulated_key && (mask & SCI_EVT_KEYBOARD)) { PUT_SEL32V(obj, type, SCI_EVT_KEYBOARD); // Keyboard event - PUT_SEL32V(obj, message, debug_simulated_key); + PUT_SEL32V(obj, message, g_debug_simulated_key); PUT_SEL32V(obj, modifiers, SCI_EVM_NUMLOCK); // Numlock on PUT_SEL32V(obj, x, s->gfx_state->pointer_pos.x); PUT_SEL32V(obj, y, s->gfx_state->pointer_pos.y); - debug_simulated_key = 0; + g_debug_simulated_key = 0; return make_reg(0, 1); } @@ -91,10 +90,10 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) { case SCI_EVT_KEYBOARD: if ((e.buckybits & SCI_EVM_LSHIFT) && (e.buckybits & SCI_EVM_RSHIFT) && (e.data == '-')) { sciprintf("Debug mode activated\n"); - _debug_seeking = _debug_step_running = 0; + g_debug_seeking = g_debug_step_running = 0; } else if ((e.buckybits & SCI_EVM_CTRL) && (e.data == '`')) { sciprintf("Debug mode activated\n"); - _debug_seeking = _debug_step_running = 0; + g_debug_seeking = g_debug_step_running = 0; } else { PUT_SEL32V(obj, type, SCI_EVT_KEYBOARD); // Keyboard event s->r_acc = make_reg(0, 1); @@ -110,7 +109,7 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) { int extra_bits = 0; // track left buttton clicks, if requested - if (e.type == SCI_EVT_MOUSE_PRESS && e.data == 1 && debug_track_mouse_clicks) { + if (e.type == SCI_EVT_MOUSE_PRESS && e.data == 1 && g_debug_track_mouse_clicks) { ((SciEngine *)g_engine)->getDebugger()->DebugPrintf("Mouse clicked at %d, %d\n", s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y); } @@ -138,8 +137,8 @@ reg_t kGetEvent(EngineState *s, int funct_nr, int argc, reg_t *argv) { s->r_acc = NULL_REG; // Unknown or no event } - if ((s->r_acc.offset) && (stop_on_event)) { - stop_on_event = 0; + if ((s->r_acc.offset) && (g_stop_on_event)) { + g_stop_on_event = 0; } return s->r_acc; diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 11d1cb457e..87ddb46e50 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -654,7 +654,7 @@ reg_t kRestoreGame(EngineState *s, int funct_nr, int argc, reg_t *argv) { if (newstate) { s->successor = newstate; - script_abort_flag = SCRIPT_ABORT_WITH_REPLAY; // Abort current game + script_abort_flag = 2; // Abort current game with replay shrink_execution_stack(s, s->execution_stack_base + 1); } else { s->r_acc = make_reg(0, 1); diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 4c4be0242c..1e0e675603 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -27,7 +27,7 @@ #include "common/events.h" #include "sci/sci.h" -#include "sci/console.h" // for debug_sleeptime_factor +#include "sci/debug.h" // for g_debug_sleeptime_factor #include "sci/resource.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" @@ -163,7 +163,7 @@ int _find_view_priority(EngineState *s, int y) { return j; return 14; // Maximum } else { - if (!(s->flags & GF_SCI0_OLDGFXFUNCS)) + if (!(s->_flags & GF_SCI0_OLDGFXFUNCS)) return SCI0_VIEW_PRIORITY_14_ZONES(y); else return SCI0_VIEW_PRIORITY(y) == 15 ? 14 : SCI0_VIEW_PRIORITY(y); @@ -171,7 +171,7 @@ int _find_view_priority(EngineState *s, int y) { } int _find_priority_band(EngineState *s, int nr) { - if (!(s->flags & GF_SCI0_OLDGFXFUNCS) && (nr < 0 || nr > 14)) { + if (!(s->_flags & GF_SCI0_OLDGFXFUNCS) && (nr < 0 || nr > 14)) { if (nr == 15) return 0xffff; else { @@ -180,7 +180,7 @@ int _find_priority_band(EngineState *s, int nr) { return 0; } - if ((s->flags & GF_SCI0_OLDGFXFUNCS) && (nr < 0 || nr > 15)) { + if ((s->_flags & GF_SCI0_OLDGFXFUNCS) && (nr < 0 || nr > 15)) { warning("Attempt to get priority band %d", nr); return 0; } @@ -190,7 +190,7 @@ int _find_priority_band(EngineState *s, int nr) { else { int retval; - if (!(s->flags & GF_SCI0_OLDGFXFUNCS)) + if (!(s->_flags & GF_SCI0_OLDGFXFUNCS)) retval = SCI0_PRIORITY_BAND_FIRST_14_ZONES(nr); else retval = SCI0_PRIORITY_BAND_FIRST(nr); @@ -303,8 +303,8 @@ static gfx_color_t graph_map_color(EngineState *s, int color, int priority, int reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) { switch (argc) { case 1 : - if (s->version < SCI_VERSION_1_1) { - if (SKPV(0) == 0 || SKPV(0) == 1 || SKPV(0) == -1) { + if (s->_version < SCI_VERSION_1_1) { + if (SKPV(0) <= 1) { // Newer (SCI1.1) semantics: show/hide cursor g_system->showMouse(SKPV(0) != 0); } else { @@ -317,7 +317,7 @@ reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) { } break; case 2 : - if (s->version < SCI_VERSION_1_1) { + if (s->_version < SCI_VERSION_1_1) { // Pre-SCI1.1: set cursor according to the first parameter, and toggle its // visibility based on the second parameter // Some late SCI1 games actually use the SCI1.1 version of this call (EcoQuest 1 @@ -329,7 +329,7 @@ reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) { // this would open the menu on top. LSL5 is an exception, as the game can open // the menu when the player presses a button during the intro, but the cursor is // not placed on (x, 0) or (x, 1) - if (SKPV(1) == 0 || SKPV(1) == 1 || SKPV(1) == -1) { + if (SKPV(1) <= 1) { GFX_ASSERT(gfxop_set_pointer_cursor(s->gfx_state, SKPV(1) == 0 ? GFXOP_NO_POINTER : SKPV(0))); } else { // newer (SCI1.1) semantics: set pointer position @@ -369,8 +369,6 @@ reg_t kSetCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } -extern int oldx, oldy; - reg_t kMoveCursor(EngineState *s, int funct_nr, int argc, reg_t *argv) { Common::Point newpos; @@ -647,8 +645,6 @@ reg_t kTextSize(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } -extern int debug_sleeptime_factor; - reg_t kWait(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint32 time; int sleep_time = UKPV(0); @@ -660,7 +656,7 @@ reg_t kWait(EngineState *s, int funct_nr, int argc, reg_t *argv) { // Reset optimization flags: Game is playing along nicely anyway s->kernel_opt_flags &= ~(KERNEL_OPT_FLAG_GOT_EVENT | KERNEL_OPT_FLAG_GOT_2NDEVENT); - sleep_time *= debug_sleeptime_factor; + sleep_time *= g_debug_sleeptime_factor; GFX_ASSERT(gfxop_sleep(s->gfx_state, sleep_time * 1000 / 60)); return s->r_acc; @@ -689,7 +685,7 @@ void _k_dirloop(reg_t obj, uint16 angle, EngineState *s, int funct_nr, int argc, angle %= 360; - if (!(s->flags & GF_SCI0_OLD)) { + if (!(s->_flags & GF_SCI0_OLD)) { if (angle < 45) loop = 3; else if (angle < 136) @@ -773,7 +769,7 @@ static int collides_with(EngineState *s, Common::Rect area, reg_t other_obj, int return 0; } -reg_t kCanBeHere(EngineState *s, int funct_nr, int argc, reg_t * argv) { +reg_t kCanBeHere(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t obj = argv[0]; reg_t cliplist_ref = KP_ALT(1, NULL_REG); List *cliplist = NULL; @@ -1001,7 +997,7 @@ reg_t kDrawPic(EngineState *s, int funct_nr, int argc, reg_t *argv) { if ((argc > 1) && (UKPV(1) & K_DRAWPIC_FLAG_MIRRORED)) picFlags |= DRAWPIC1_FLAG_MIRRORED; - if (s->flags & GF_SCI0_OLDGFXFUNCS) { + if (s->_flags & GF_SCI0_OLDGFXFUNCS) { if (!SKPV_OR_ALT(2, 0)) add_to_pic = 0; } else { @@ -1054,7 +1050,7 @@ reg_t kDrawPic(EngineState *s, int funct_nr, int argc, reg_t *argv) { s->priority_first = 42; - if (s->flags & GF_SCI0_OLDGFXFUNCS) + if (s->_flags & GF_SCI0_OLDGFXFUNCS) s->priority_last = 200; else s->priority_last = 190; @@ -1139,7 +1135,7 @@ void _k_base_setter(EngineState *s, reg_t object) { // does not exist (earliest one was KQ4 SCI, version 0.000.274). This code is left here // for reference only #if 0 - if (s->version <= SCI_VERSION_0) + if (s->_version <= SCI_VERSION_0) --absrect.top; // Compensate for early SCI OB1 'bug' #endif @@ -1350,7 +1346,7 @@ static void _k_disable_delete_for_now(EngineState *s, reg_t obj) { * that game - bringing the save/load dialog on a par with SCI0. */ if (type == K_CONTROL_BUTTON && text && (s->_gameName == "sq4") && - s->version < SCI_VERSION_1_1 && !strcmp(text, " Delete ")) { + s->_version < SCI_VERSION_1_1 && !strcmp(text, " Delete ")) { PUT_SEL32V(obj, state, (state | kControlStateDisabled) & ~kControlStateEnabled); } } diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index 029954d00f..43d1f25e01 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -310,7 +310,7 @@ reg_t kAddToFront(EngineState *s, int funct_nr, int argc, reg_t *argv) { } reg_t kAddAfter(EngineState *s, int funct_nr, int argc, reg_t *argv) { - List *l =lookup_list(s, argv[0]); + List *l = lookup_list(s, argv[0]); Node *firstnode = argv[1].isNull() ? NULL : lookup_node(s, argv[1]); Node *newnode = lookup_node(s, argv[2]); @@ -341,12 +341,11 @@ reg_t kAddAfter(EngineState *s, int funct_nr, int argc, reg_t *argv) { else lookup_node(s, oldnext)->pred = argv[2]; - return s->r_acc; } else { // !firstnode - // Prepare call to AddToFront... - argv[1] = argv[0]; - return kAddToFront(s, funct_nr, 2, argv + 1); // Set as initial list node + _k_add_to_front(s, argv[0], argv[2]); // Set as initial list node } + + return s->r_acc; } reg_t kAddToEnd(EngineState *s, int funct_nr, int argc, reg_t *argv) { diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 34d8b5397c..2e86362404 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -28,6 +28,7 @@ #include <time.h> // FIXME: For struct tm #include "sci/sci.h" +#include "sci/debug.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/engine/gc.h" @@ -95,7 +96,7 @@ reg_t kFlushResources(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kSetDebug(EngineState *s, int funct_nr, int argc, reg_t *argv) { sciprintf("Debug mode activated\n"); - _debug_seeking = _debug_step_running = 0; + g_debug_seeking = g_debug_step_running = 0; return s->r_acc; } @@ -120,7 +121,7 @@ reg_t kGetTime(EngineState *s, int funct_nr, int argc, reg_t *argv) { g_system->getTimeAndDate(loc_time); start_time = g_system->getMillis() - s->game_start_time; - if ((s->flags & GF_SCI0_OLDGETTIME) && argc) { // Use old semantics + if ((s->_flags & GF_SCI0_OLDGETTIME) && argc) { // Use old semantics retval = (loc_time.tm_hour % 12) * 3600 + loc_time.tm_min * 60 + loc_time.tm_sec; debugC(2, kDebugLevelTime, "GetTime(timeofday) returns %d", retval); return make_reg(0, retval); @@ -248,7 +249,7 @@ reg_t kstub(EngineState *s, int funct_nr, int argc, reg_t *argv) { } reg_t kNOP(EngineState *s, int funct_nr, int argc, reg_t *argv) { - warning("Kernel function 0x%02x (%s) invoked: unmapped", funct_nr, s->_kernel->_kfuncTable[funct_nr].orig_name.c_str()); + warning("Kernel function 0x%02x (%s) invoked: unmapped", funct_nr, s->_kernel->_kernelFuncs[funct_nr].orig_name.c_str()); return NULL_REG; } diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index cd4307678b..b116fa4093 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -273,7 +273,7 @@ static void bresenham_autodetect(EngineState *s) { } buf = s->seg_manager->getScript(fptr.segment)->buf + fptr.offset; - handle_movecnt = (s->version <= SCI_VERSION_0 || checksum_bytes(buf, 8) == 0x216) ? INCREMENT_MOVECNT : IGNORE_MOVECNT; + handle_movecnt = (s->_version <= SCI_VERSION_0 || checksum_bytes(buf, 8) == 0x216) ? INCREMENT_MOVECNT : IGNORE_MOVECNT; sciprintf("b-moveCnt action based on checksum: %s\n", handle_movecnt == IGNORE_MOVECNT ? "ignore" : "increment"); } else { warning("bresenham_autodetect failed"); @@ -292,7 +292,7 @@ reg_t kDoBresen(EngineState *s, int funct_nr, int argc, reg_t *argv) { int completed = 0; int max_movcnt = GET_SEL32V(client, moveSpeed); - if (s->version > SCI_VERSION_0) + if (s->_version > SCI_VERSION_0) signal &= ~_K_VIEW_SIG_FLAG_HIT_OBSTACLE; if (handle_movecnt == UNINITIALIZED) @@ -379,7 +379,7 @@ reg_t kDoBresen(EngineState *s, int funct_nr, int argc, reg_t *argv) { completed = 1; } - if (s->version > SCI_VERSION_0) + if (s->_version > SCI_VERSION_0) if (completed) invoke_selector(INV_SEL(mover, moveDone, kStopOnInvalidSelector), 0); diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index abdf2b0447..e400cb0827 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -169,7 +169,7 @@ reg_t kResCheck(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint seq = UKPV(5); warning("ResCheck: checking for currently unsupported %s resource: module %i; tuple (%i, %i, %i, %i)", getResourceTypeName(restype), module, noun, verb, cond, seq); - return NULL_REG; + return make_reg(0, 1); } default: Resource *res = s->resmgr->testResource(restype, UKPV(1)); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 3586b6b1ed..b0fbda36f9 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -154,7 +154,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their song_handle_t handle; int cue; - if (s->version >= SCI_VERSION_01) + if (s->_version >= SCI_VERSION_01) return; /* SCI01 and later explicitly poll for everything */ @@ -964,9 +964,9 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { } reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { - if (s->version >= SCI_VERSION_1_1 || s->flags & GF_SCI1_NEWDOSOUND) + if (s->_version >= SCI_VERSION_1_1 || s->_flags & GF_SCI1_NEWDOSOUND) return kDoSound_SCI1(s, funct_nr, argc, argv); - else if (s->version >= SCI_VERSION_01) + else if (s->_version >= SCI_VERSION_01) return kDoSound_SCI01(s, funct_nr, argc, argv); else return kDoSound_SCI0(s, funct_nr, argc, argv); @@ -978,7 +978,7 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) { int sampleLen = 0; if (!s->_sound._audioResource) - s->_sound._audioResource = new AudioResource(s->resmgr, s->version); + s->_sound._audioResource = new AudioResource(s->resmgr, s->_version); switch (UKPV(0)) { case kSciAudioWPlay: diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 20f0f4793b..3898664921 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -713,7 +713,7 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { case K_MESSAGE_NEXT: { reg_t bufferReg; char *buffer = NULL; - const char *str; + Common::String str; reg_t retval; if (func == K_MESSAGE_GET) { @@ -735,18 +735,18 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { else retval = make_reg(0, s->_msgState.getTalker()); } else { - str = DUMMY_MESSAGE; + str = Common::String(DUMMY_MESSAGE); retval = NULL_REG; } if (!bufferReg.isNull()) { - int len = strlen(str) + 1; + int len = str.size() + 1; buffer = kernel_dereference_char_pointer(s, bufferReg, len); if (buffer) { - strcpy(buffer, str); + strcpy(buffer, str.c_str()); } else { - warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str); + warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str.c_str()); // Set buffer to empty string if possible buffer = kernel_dereference_char_pointer(s, bufferReg, 1); @@ -763,7 +763,7 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { MessageState tempState; if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple) && tempState.getMessage()) - return make_reg(0, strlen(tempState.getText()) + 1); + return make_reg(0, tempState.getText().size() + 1); else return NULL_REG; } diff --git a/engines/sci/engine/memobj.cpp b/engines/sci/engine/memobj.cpp new file mode 100644 index 0000000000..c0775ae51e --- /dev/null +++ b/engines/sci/engine/memobj.cpp @@ -0,0 +1,413 @@ +/* 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 "common/endian.h" + +#include "sci/sci.h" +#include "sci/engine/memobj.h" +#include "sci/engine/intmap.h" +#include "sci/engine/seg_manager.h" +#include "sci/engine/state.h" +#include "sci/tools.h" + +namespace Sci { + +MemObject *MemObject::createMemObject(MemObjectType type) { + MemObject *mem = 0; + switch (type) { + case MEM_OBJ_SCRIPT: + mem = new Script(); + break; + case MEM_OBJ_CLONES: + mem = new CloneTable(); + break; + case MEM_OBJ_LOCALS: + mem = new LocalVariables(); + break; + case MEM_OBJ_SYS_STRINGS: + mem = new SystemStrings(); + break; + case MEM_OBJ_STACK: + mem = new DataStack(); + break; + case MEM_OBJ_HUNK: + mem = new HunkTable(); + break; + case MEM_OBJ_STRING_FRAG: + mem = new StringFrag(); + break; + case MEM_OBJ_LISTS: + mem = new ListTable(); + break; + case MEM_OBJ_NODES: + mem = new NodeTable(); + break; + case MEM_OBJ_DYNMEM: + mem = new DynMem(); + break; + default: + error("Unknown MemObject type %d", type); + break; + } + + assert(mem); + mem->_type = type; + return mem; +} + +void Script::freeScript() { + free(buf); + buf = NULL; + buf_size = 0; + + _objects.clear(); + + delete obj_indices; + obj_indices = 0; + _codeBlocks.clear(); +} + +void Script::incrementLockers() { + lockers++; +} + +void Script::decrementLockers() { + if (lockers > 0) + lockers--; +} + +int Script::getLockers() const { + return lockers; +} + +void Script::setLockers(int lockers_) { + lockers = lockers_; +} + +void Script::setExportTableOffset(int offset) { + if (offset) { + export_table = (uint16 *)(buf + offset + 2); + exports_nr = READ_LE_UINT16((byte *)(export_table - 1)); + } else { + export_table = NULL; + exports_nr = 0; + } +} + +void Script::setSynonymsOffset(int offset) { + synonyms = buf + offset; +} + +byte *Script::getSynonyms() const { + return synonyms; +} + +void Script::setSynonymsNr(int n) { + synonyms_nr = n; +} + +int Script::getSynonymsNr() const { + return synonyms_nr; +} + +// memory operations + +void Script::mcpyInOut(int dst, const void *src, size_t n) { + if (buf) { + assert(dst + n <= buf_size); + memcpy(buf + dst, src, n); + } +} + +int16 Script::getHeap(uint16 offset) const { + assert(offset + 1 < (int)buf_size); + return READ_LE_UINT16(buf + offset); +// return (buf[offset] | (buf[offset+1]) << 8); +} + +byte *MemObject::dereference(reg_t pointer, int *size) { + error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment", + PRINT_REG(pointer)); + return NULL; +} + +bool Script::isValidOffset(uint16 offset) const { + return offset < buf_size; +} + +byte *Script::dereference(reg_t pointer, int *size) { + if (pointer.offset > buf_size) { + sciprintf("Error: Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)\n", + PRINT_REG(pointer), (uint)buf_size); + return NULL; + } + if (size) + *size = buf_size - pointer.offset; + return buf + pointer.offset; +} + +bool LocalVariables::isValidOffset(uint16 offset) const { + return offset < _locals.size() * sizeof(reg_t); +} + +byte *LocalVariables::dereference(reg_t pointer, int *size) { + if (size) + *size = _locals.size() * sizeof(reg_t); + + // FIXME: The following doesn't seem to be endian safe. + // To fix this, we'd have to always treat the reg_t + // values stored here as in the little endian format. + byte *base = (byte *)&_locals[0]; + return base + pointer.offset; +} + +bool DataStack::isValidOffset(uint16 offset) const { + return offset < nr * sizeof(reg_t); +} + +byte *DataStack::dereference(reg_t pointer, int *size) { + if (size) + *size = nr * sizeof(reg_t); + + byte *base = (byte *)entries; + return base + pointer.offset; +} + +bool DynMem::isValidOffset(uint16 offset) const { + return offset < _size; +} + +byte *DynMem::dereference(reg_t pointer, int *size) { + if (size) + *size = _size; + + byte *base = (byte *)_buf; + return base + pointer.offset; +} + +bool SystemStrings::isValidOffset(uint16 offset) const { + return offset < SYS_STRINGS_MAX && strings[offset].name; +} + +byte *SystemStrings::dereference(reg_t pointer, int *size) { + if (size) + *size = strings[pointer.offset].max_size; + if (pointer.offset < SYS_STRINGS_MAX && strings[pointer.offset].name) + return (byte *)(strings[pointer.offset].value); + + // This occurs in KQ5CD when interacting with certain objects + warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); + return NULL; +} + + +//-------------------- script -------------------- +reg_t Script::findCanonicAddress(SegManager *segmgr, reg_t addr) { + addr.offset = 0; + return addr; +} + +void Script::freeAtAddress(SegManager *segmgr, reg_t addr) { + /* + sciprintf("[GC] Freeing script %04x:%04x\n", PRINT_REG(addr)); + if (locals_segment) + sciprintf("[GC] Freeing locals %04x:0000\n", locals_segment); + */ + + if (_markedAsDeleted) + segmgr->deallocateScript(nr); +} + +void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { + (*note)(param, make_reg(segId, 0)); +} + +void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { + Script *script = this; + + if (addr.offset <= script->buf_size && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(script->buf + addr.offset)) { + int idx = RAW_GET_CLASS_INDEX(script, addr); + if (idx >= 0 && (uint)idx < script->_objects.size()) { + // Note all local variables, if we have a local variable environment + if (script->locals_segment) + (*note)(param, make_reg(script->locals_segment, 0)); + + Object &obj = script->_objects[idx]; + for (uint i = 0; i < obj._variables.size(); i++) + (*note)(param, obj._variables[i]); + } else { + warning("Request for outgoing script-object reference at %04x:%04x yielded invalid index %d", PRINT_REG(addr), idx); + } + } else { + /* warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/ + /* Happens e.g. when we're looking into strings */ + } +} + + +//-------------------- clones -------------------- + +template<typename T> +void Table<T>::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { + for (uint i = 0; i < _table.size(); i++) + if (isValidEntry(i)) + (*note)(param, make_reg(segId, i)); +} + +void CloneTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { + CloneTable *clone_table = this; + Clone *clone; + +// assert(addr.segment == _segId); + + if (!clone_table->isValidEntry(addr.offset)) { + warning("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr)); +// BREAKPOINT(); + return; + } + + clone = &(clone_table->_table[addr.offset]); + + // Emit all member variables (including references to the 'super' delegate) + for (uint i = 0; i < clone->_variables.size(); i++) + (*note)(param, clone->_variables[i]); + + // Note that this also includes the 'base' object, which is part of the script and therefore also emits the locals. + (*note)(param, clone->pos); + //sciprintf("[GC] Reporting clone-pos %04x:%04x\n", PRINT_REG(clone->pos)); +} + +void CloneTable::freeAtAddress(SegManager *segmgr, reg_t addr) { + CloneTable *clone_table = this; + Object *victim_obj; + +// assert(addr.segment == _segId); + + victim_obj = &(clone_table->_table[addr.offset]); + +#ifdef GC_DEBUG + if (!(victim_obj->flags & OBJECT_FLAG_FREED)) + sciprintf("[GC] Warning: Clone %04x:%04x not reachable and not freed (freeing now)\n", PRINT_REG(addr)); +#ifdef GC_DEBUG_VERBOSE + else + sciprintf("[GC-DEBUG] Clone %04x:%04x: Freeing\n", PRINT_REG(addr)); +#endif +#endif + /* + sciprintf("[GC] Clone %04x:%04x: Freeing\n", PRINT_REG(addr)); + sciprintf("[GC] Clone had pos %04x:%04x\n", PRINT_REG(victim_obj->pos)); + */ + clone_table->freeEntry(addr.offset); +} + + +//-------------------- locals -------------------- +reg_t LocalVariables::findCanonicAddress(SegManager *segmgr, reg_t addr) { + // Reference the owning script + SegmentId owner_seg = segmgr->segGet(script_id); + + assert(owner_seg >= 0); + + return make_reg(owner_seg, 0); +} + +void LocalVariables::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { +// assert(addr.segment == _segId); + + for (uint i = 0; i < _locals.size(); i++) + (*note)(param, _locals[i]); +} + + +//-------------------- stack -------------------- +reg_t DataStack::findCanonicAddress(SegManager *segmgr, reg_t addr) { + addr.offset = 0; + return addr; +} + +void DataStack::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { + fprintf(stderr, "Emitting %d stack entries\n", nr); + for (int i = 0; i < nr; i++) + (*note)(param, entries[i]); + fprintf(stderr, "DONE"); +} + + +//-------------------- lists -------------------- +void ListTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) { + freeEntry(sub_addr.offset); +} + +void ListTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { + if (!isValidEntry(addr.offset)) { + warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); + return; + } + + List *list = &(_table[addr.offset]); + + note(param, list->first); + note(param, list->last); + // We could probably get away with just one of them, but + // let's be conservative here. +} + + +//-------------------- nodes -------------------- +void NodeTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) { + freeEntry(sub_addr.offset); +} + +void NodeTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { + if (!isValidEntry(addr.offset)) { + warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); + return; + } + 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 + note(param, node->pred); + note(param, node->succ); + note(param, node->key); + note(param, node->value); +} + + +//-------------------- hunk -------------------- + +//-------------------- dynamic memory -------------------- + +reg_t DynMem::findCanonicAddress(SegManager *segmgr, reg_t addr) { + addr.offset = 0; + return addr; +} + +void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { + (*note)(param, make_reg(segId, 0)); +} + + +} // End of namespace Sci diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h new file mode 100644 index 0000000000..c006caaddc --- /dev/null +++ b/engines/sci/engine/memobj.h @@ -0,0 +1,572 @@ +/* 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_ENGINE_MEMOBJ_H +#define SCI_ENGINE_MEMOBJ_H + +#include "common/serializer.h" +#include "sci/engine/vm_types.h" // for reg_t + +//#include "common/util.h" + +namespace Sci { + +enum MemObjectType { + MEM_OBJ_INVALID = 0, + MEM_OBJ_SCRIPT = 1, + MEM_OBJ_CLONES = 2, + MEM_OBJ_LOCALS = 3, + MEM_OBJ_STACK = 4, + MEM_OBJ_SYS_STRINGS = 5, + MEM_OBJ_LISTS = 6, + MEM_OBJ_NODES = 7, + MEM_OBJ_HUNK = 8, + MEM_OBJ_DYNMEM = 9, + MEM_OBJ_STRING_FRAG = 10, + + MEM_OBJ_MAX // For sanity checking +}; + +struct MemObject : public Common::Serializable { + MemObjectType _type; + int _segmgrId; /**< Internal value used by the seg_manager's hash map */ + + typedef void (*NoteCallback)(void *param, reg_t addr); // FIXME: Bad choice of name + +public: + static MemObject *createMemObject(MemObjectType type); + +public: + virtual ~MemObject() {} + + inline MemObjectType getType() const { return _type; } + inline int getSegMgrId() const { return _segmgrId; } + + /** + * Check whether the given offset into this memory object is valid, + * i.e., suitable for passing to dereference. + */ + virtual bool isValidOffset(uint16 offset) const = 0; + + /** + * Dereferences a raw memory pointer. + * @param reg reference to dereference + * @param size if not NULL, set to the theoretical maximum size of the referenced data block + * @return the data block referenced + */ + virtual byte *dereference(reg_t pointer, int *size); + + /** + * Finds the canonic address associated with sub_reg. + * + * For each valid address a, there exists a canonic address c(a) such that c(a) = c(c(a)). + * This address "governs" a in the sense that deallocating c(a) will deallocate a. + * + * @param sub_addr base address whose canonic address is to be found + */ + virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr) { return sub_addr; } + + /** + * Deallocates all memory associated with the specified address. + * @param sub_addr address (within the given segment) to deallocate + */ + virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr) {} + + /** + * Iterates over and reports all addresses within the current segment. + * @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) {} + + /** + * Iterates over all references reachable from the specified object. + * @param object object (within the current segment) to analyse + * @param param parameter passed to 'note' + * @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(EngineState *s, reg_t object, void *param, NoteCallback note) {} +}; + + +// TODO: Implement the following class +struct StringFrag : public MemObject { + virtual bool isValidOffset(uint16 offset) const { return false; } + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + +struct IntMapper; + +enum { + SYS_STRINGS_MAX = 4, + + SYS_STRING_SAVEDIR = 0, + SYS_STRING_PARSER_BASE = 1, + + MAX_PARSER_BASE = 64 +}; + +struct SystemString { + char *name; + int max_size; + reg_t *value; +}; + +struct SystemStrings : public MemObject { + SystemString strings[SYS_STRINGS_MAX]; + +public: + SystemStrings() { + memset(strings, 0, sizeof(strings)); + } + ~SystemStrings() { + for (int i = 0; i < SYS_STRINGS_MAX; i++) { + SystemString *str = &strings[i]; + if (str->name) { + free(str->name); + str->name = NULL; + + free(str->value); + str->value = NULL; + + str->max_size = 0; + } + } + } + + virtual bool isValidOffset(uint16 offset) const; + virtual byte *dereference(reg_t pointer, int *size); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + +/** This struct is used to buffer the list of send calls in send_selector() */ +struct CallsStruct { + union { + reg_t func; + reg_t *var; + } address; + StackPtr argp; + int argc; + Selector selector; + StackPtr sp; /**< Stack pointer */ + int type; /**< Same as ExecStack.type */ +}; + +struct LocalVariables : public MemObject { + int script_id; /**< Script ID this local variable block belongs to */ + Common::Array<reg_t> _locals; + +public: + LocalVariables() { + script_id = 0; + } + + virtual bool isValidOffset(uint16 offset) const; + virtual byte *dereference(reg_t pointer, int *size); + virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + +/** Clone has been marked as 'freed' */ +#define OBJECT_FLAG_FREED (0x1 << 0) + +struct Object { + int flags; + reg_t pos; /**< Object offset within its script; for clones, this is their base */ + int variable_names_nr; /**< Number of variable names, may be less than variables_nr */ + int methods_nr; + byte *base; /**< Points to a buffer all relative references (code, strings) point to */ + byte *base_obj; /**< base + object offset within base */ + uint16 *base_method; /**< Pointer to the method selector area for this object */ + uint16 *base_vars; /**< Pointer to the varselector area for this object */ + Common::Array<reg_t> _variables; +}; + +struct CodeBlock { + reg_t pos; + int size; +}; + +#define VM_OBJECT_GET_VARSELECTOR(obj, i) \ + (s->_version < SCI_VERSION_1_1 ? \ + READ_LE_UINT16(obj->base_obj + obj->_variables.size() * 2 + i*2) : \ + *(obj->base_vars + i)) +#define VM_OBJECT_READ_PROPERTY(obj, i) (obj->_variables[i]) +#define VM_OBJECT_GET_FUNCSELECTOR(obj, i) \ + (s->_version < SCI_VERSION_1_1 ? \ + READ_LE_UINT16((byte *) (obj->base_method + i)) : \ + READ_LE_UINT16((byte *) (obj->base_method + i*2 + 1))) +#define VM_OBJECT_READ_FUNCTION(obj, i) \ + (s->_version < SCI_VERSION_1_1 ? \ + make_reg(obj->pos.segment, \ + READ_LE_UINT16((byte *) (obj->base_method \ + + obj->methods_nr + 1 \ + + i))) : \ + make_reg(obj->pos.segment, \ + READ_LE_UINT16((byte *) (obj->base_method \ + + i * 2 + 2)))) + + + + +struct Script : public MemObject { + int nr; /**< Script number */ + byte *buf; /**< Static data buffer, or NULL if not used */ + size_t buf_size; + size_t script_size; + size_t heap_size; + + byte *synonyms; /**< Synonyms block or 0 if not present*/ + byte *heap_start; /**< Start of heap if SCI1.1, NULL otherwise */ + uint16 *export_table; /**< Abs. offset of the export table or 0 if not present */ + + IntMapper *obj_indices; + + int exports_nr; /**< Number of entries in the exports table */ + int synonyms_nr; /**< Number of entries in the synonyms block */ + int lockers; /**< Number of classes and objects that require this script */ + + /** + * Table for objects, contains property variables. + * Indexed by the value stored at SCRIPT_LOCALVARPTR_OFFSET, + * see VM_OBJECT_[GS]ET_INDEX() + */ + Common::Array<Object> _objects; + + int locals_offset; + int locals_segment; /**< The local variable segment */ + LocalVariables *locals_block; + + Common::Array<CodeBlock> _codeBlocks; + int relocated; + bool _markedAsDeleted; + +public: + Script() { + nr = 0; + buf = NULL; + buf_size = 0; + script_size = 0; + heap_size = 0; + + synonyms = NULL; + heap_start = NULL; + export_table = NULL; + + obj_indices = NULL; + + locals_offset = 0; + locals_segment = 0; + locals_block = NULL; + + relocated = 0; + _markedAsDeleted = 0; + } + + ~Script() { + freeScript(); + } + + void freeScript(); + + virtual bool isValidOffset(uint16 offset) const; + virtual byte *dereference(reg_t pointer, int *size); + virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); + virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); + + // script lock operations + + /** Increments the number of lockers of this script by one. */ + void incrementLockers(); + + /** Decrements the number of lockers of this script by one. */ + void decrementLockers(); + + /** + * Retrieves the number of locks held on this script. + * @return the number of locks held on the previously identified script + */ + int getLockers() const; + + /** Sets the number of locks held on this script. */ + void setLockers(int lockers); + + /** + * Retrieves a pointer to the synonyms associated with this script + * @return pointer to the synonyms, in non-parsed format. + */ + byte *getSynonyms() const; + + /** + * 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); + + /** + * 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 + * either unreachable (resulting in its eventual deletion) or reloaded (resulting + * in its data being updated). + */ + void markDeleted() { + _markedAsDeleted = true; + } + + /** + * Marks the script as not deleted. + */ + void unmarkDeleted() { + _markedAsDeleted = false; + } + + /** + * Determines whether the script is marked as being deleted. + */ + bool isMarkedAsDeleted() const { + return _markedAsDeleted; + } + + /** + * Copies a byte string into a script's heap representation. + * @param dst script-relative offset of the destination area + * @param src pointer to the data source location + * @param n number of bytes to copy + */ + void mcpyInOut(int dst, const void *src, size_t n); + + + /** + * Retrieves a 16 bit value from within a script's heap representation. + * @param offset offset to read from + * @return the value read from the specified location + */ + int16 getHeap(uint16 offset) const; +}; + +/** Data stack */ +struct DataStack : MemObject { + int nr; /**< Number of stack entries */ + reg_t *entries; + +public: + DataStack() { + nr = 0; + entries = NULL; + } + ~DataStack() { + free(entries); + entries = NULL; + } + + virtual bool isValidOffset(uint16 offset) const; + virtual byte *dereference(reg_t pointer, int *size); + virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + +#define CLONE_USED -1 +#define CLONE_NONE -1 + +typedef Object Clone; + +struct Node { + reg_t pred; /**< Predecessor node */ + reg_t succ; /**< Successor node */ + reg_t key; + reg_t value; +}; /* List nodes */ + +struct List { + reg_t first; + reg_t last; +}; + +struct Hunk { + void *mem; + unsigned int size; + const char *type; +}; + +template<typename T> +struct Table : public MemObject { + typedef T value_type; + struct Entry : public T { + int next_free; /* Only used for free entries */ + }; + enum { HEAPENTRY_INVALID = -1 }; + + + int first_free; /**< Beginning of a singly linked list for entries */ + int entries_used; /**< Statistical information */ + + Common::Array<Entry> _table; + +public: + Table() { + initTable(); + } + + void initTable() { + entries_used = 0; + first_free = HEAPENTRY_INVALID; + _table.clear(); + } + + int allocEntry() { + entries_used++; + if (first_free != HEAPENTRY_INVALID) { + int oldff = first_free; + first_free = _table[oldff].next_free; + + _table[oldff].next_free = oldff; + return oldff; + } else { + uint newIdx = _table.size(); + _table.push_back(Entry()); + _table[newIdx].next_free = newIdx; // Tag as 'valid' + return newIdx; + } + } + + virtual bool isValidOffset(uint16 offset) const { + return isValidEntry(offset); + } + + bool isValidEntry(int idx) const { + return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx; + } + + virtual void freeEntry(int idx) { + if (idx < 0 || (uint)idx >= _table.size()) + ::error("Table::freeEntry: Attempt to release invalid table index %d", idx); + + _table[idx].next_free = first_free; + first_free = idx; + entries_used--; + } + + virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); +}; + + +/* CloneTable */ +struct CloneTable : public Table<Clone> { + virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + + +/* NodeTable */ +struct NodeTable : public Table<Node> { + virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + + +/* ListTable */ +struct ListTable : public Table<List> { + virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + + +/* HunkTable */ +struct HunkTable : public Table<Hunk> { + virtual void freeEntry(int idx) { + Table<Hunk>::freeEntry(idx); + + free(_table[idx].mem); + } + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + + +// Free-style memory +struct DynMem : public MemObject { + int _size; + char *_description; + byte *_buf; + +public: + DynMem() : _size(0), _description(0), _buf(0) {} + ~DynMem() { + free(_description); + _description = NULL; + free(_buf); + _buf = NULL; + } + + virtual bool isValidOffset(uint16 offset) const; + virtual byte *dereference(reg_t pointer, int *size); + virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); + virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); + + virtual void saveLoadWithSerializer(Common::Serializer &ser); +}; + + +} // End of namespace Sci + +#endif // SCI_ENGINE_VM_H diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp index 61151e3218..4f5efa106c 100644 --- a/engines/sci/engine/message.cpp +++ b/engines/sci/engine/message.cpp @@ -153,9 +153,59 @@ int MessageState::getLastModule() { return _lastReturnedModule; } -char *MessageState::getText() { - int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); - return (char *)_currentResource->data + offset; +Common::String MessageState::getText() { + char *str = (char *)_currentResource->data + READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); + + Common::String strippedStr; + Common::String skippedSubstr; + bool skipping = false; + + for (uint i = 0; i < strlen(str); i++) { + if (skipping) { + // Skip stage direction + skippedSubstr += str[i]; + + // Hopefully these locale-dependant functions are good enough + if (islower(str[i]) || isdigit(str[i])) { + // Lowercase or digit found, this is not a stage direction + strippedStr += skippedSubstr; + skipping = false; + } else if (str[i] == ')') { + // End of stage direction, skip trailing white space + while ((i + 1 < strlen(str)) && isspace(str[i + 1])) + i++; + skipping = false; + } + } else { + if (str[i] == '(') { + // Start skipping stage direction + skippedSubstr = str[i]; + skipping = true; + } else if (str[i] == '\\') { + // Escape sequence + if ((i + 2 < strlen(str)) && isdigit(str[i + 1]) && isdigit(str[i + 2])) { + // Hex escape sequence + char hexStr[3]; + + hexStr[0] = str[++i]; + hexStr[1] = str[++i]; + hexStr[2] = 0; + + char *endptr; + int hexNr = strtol(hexStr, &endptr, 16); + if (*endptr == 0) + strippedStr += hexNr; + } else if (i + 1 < strlen(str)) { + // Literal escape sequence + strippedStr += str[++i]; + } + } else { + strippedStr += str[i]; + } + } + } + + return strippedStr; } void MessageState::gotoNext() { diff --git a/engines/sci/engine/message.h b/engines/sci/engine/message.h index b1cdb8ad99..5e30095a0c 100644 --- a/engines/sci/engine/message.h +++ b/engines/sci/engine/message.h @@ -54,7 +54,7 @@ public: MessageTuple getRefTuple(); int getMessage(); void gotoNext(); - char *getText(); + Common::String getText(); int getTalker(); int getLength(); MessageTuple &getLastTuple(); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index bf099816e3..a69e96eb3d 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -458,7 +458,7 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename SavegameMetadata meta; meta.savegame_version = CURRENT_SAVEGAME_VERSION; meta.savegame_name = savename; - meta.version = s->version; + meta.version = s->_version; meta.game_version = s->game_version; meta.savegame_date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); meta.savegame_time = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF); @@ -497,7 +497,7 @@ static SegmentId find_unique_seg_by_type(SegManager *self, int type) { } static byte *find_unique_script_block(EngineState *s, byte *buf, int type) { - if (s->flags & GF_SCI0_OLD) + if (s->_flags & GF_SCI0_OLD) buf += 2; do { @@ -545,7 +545,7 @@ static void load_script(EngineState *s, SegmentId seg) { assert(scr->buf); script = s->resmgr->findResource(kResourceTypeScript, scr->nr, 0); - if (s->version >= SCI_VERSION_1_1) + if (s->_version >= SCI_VERSION_1_1) heap = s->resmgr->findResource(kResourceTypeHeap, scr->nr, 0); memcpy(scr->buf, script->data, script->size); @@ -759,11 +759,9 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { } // FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch. - retval = new EngineState(); + retval = new EngineState(s->resmgr, s->_version, s->_flags); // Copy some old data - retval->version = s->version; - retval->flags = s->flags; retval->gfx_state = s->gfx_state; retval->sound_mute = s->sound_mute; retval->sound_volume = s->sound_volume; @@ -781,8 +779,6 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { retval->gfx_state = s->gfx_state; retval->old_screen = 0; - retval->resmgr = s->resmgr; - temp = retval->_sound._songlib; retval->_sound.sfx_init(retval->resmgr, s->sfx_init_flags); retval->sfx_init_flags = s->sfx_init_flags; diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 1f750abe58..26ba01b440 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -26,6 +26,7 @@ // Script debugger functionality. Absolutely not threadsafe. #include "sci/sci.h" +#include "sci/debug.h" #include "sci/engine/state.h" #include "sci/engine/gc.h" #include "sci/engine/kernel_types.h" @@ -46,13 +47,12 @@ namespace Sci { -int _debugstate_valid = 0; // Set to 1 while script_debug is running -int _debug_step_running = 0; // Set to >0 to allow multiple stepping -int _debug_commands_not_hooked = 1; // Commands not hooked to the console yet? -int _debug_seeking = 0; // Stepping forward until some special condition is met -int _debug_seek_level = 0; // Used for seekers that want to check their exec stack depth -int _debug_seek_special = 0; // Used for special seeks(1) -reg_t _debug_seek_reg = NULL_REG; // Used for special seeks(2) +int g_debugstate_valid = 0; // Set to 1 while script_debug is running +int g_debug_step_running = 0; // Set to >0 to allow multiple stepping +static bool s_debug_commands_hooked = false; // Commands hooked to the console yet? +int g_debug_seeking = 0; // Stepping forward until some special condition is met +static int s_debug_seek_level = 0; // Used for seekers that want to check their exec stack depth +static int s_debug_seek_special = 0; // Used for special seeks(1) #define _DEBUG_SEEK_NOTHING 0 #define _DEBUG_SEEK_CALLK 1 // Step forward until callk is found @@ -91,88 +91,20 @@ struct cmd_command_t : public cmd_mm_entry_t { const char *param; }; -#if 0 -// Unused -#define LOOKUP_SPECIES(species) (\ - (species >= 1000) ? species : *(s->_classtable[species].scriptposp) \ - + s->_classtable[species].class_offset) -#endif - // Dummy function, so that it compiles int con_hook_command(ConCommand command, const char *name, const char *param, const char *description) { return 0; } -static const char *_debug_get_input() { - char newinpbuf[256]; - - printf("> "); - if (!fgets(newinpbuf, 254, stdin)) - return NULL; - - size_t l = strlen(newinpbuf); - if (l > 0 && newinpbuf[0] != '\n') { - if (newinpbuf[l-1] == '\n') newinpbuf[l-1] = 0; - memcpy(inputbuf, newinpbuf, 256); - } - - return inputbuf; -} - int c_step(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - _debugstate_valid = 0; + g_debugstate_valid = 0; if (cmdParams.size() && (cmdParams[0].val > 0)) - _debug_step_running = cmdParams[0].val - 1; + g_debug_step_running = cmdParams[0].val - 1; return 0; } -#if 0 -// TODO Re-implement con:so -int c_stepover(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - int opcode, opnumber; - - if (!_debugstate_valid) { - sciprintf("Not in debug state\n"); - return 1; - } - - _debugstate_valid = 0; - opcode = s->_heap[*p_pc]; - opnumber = opcode >> 1; - if (opnumber == 0x22 /* callb */ || opnumber == 0x23 /* calle */ || - opnumber == 0x25 /* send */ || opnumber == 0x2a /* self */ || opnumber == 0x2b /* super */) { - _debug_seeking = _DEBUG_SEEK_SO; - _debug_seek_level = s->_executionStack.size()-1; - // Store in _debug_seek_special the offset of the next command after send - switch (opcode) { - case 0x46: // calle W - _debug_seek_special = *p_pc + 5; - break; - - case 0x44: // callb W - case 0x47: // calle B - case 0x56: // super W - _debug_seek_special = *p_pc + 4; - break; - - case 0x45: // callb B - case 0x57: // super B - case 0x4A: // send W - case 0x54: // self W - _debug_seek_special = *p_pc + 3; - break; - - default: - _debug_seek_special = *p_pc + 2; - } - } - - return 0; -} -#endif - enum { _parse_eoi, _parse_token_pareno, @@ -270,7 +202,7 @@ int prop_ofs_to_id(EngineState *s, int prop_ofs, reg_t objp) { selectors = obj->_variables.size(); - if (s->version < SCI_VERSION_1_1) + if (s->_version < SCI_VERSION_1_1) selectoroffset = ((byte *)(obj->base_obj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2; else { if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS)) { @@ -319,7 +251,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod opsize = scr[pos.offset]; opcode = opsize >> 1; - if (!_debugstate_valid) { + if (!g_debugstate_valid) { sciprintf("Not in debug state\n"); return retval; } @@ -410,7 +342,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod } if (opcode == op_callk) - sciprintf(" %s[%x]", (param_value < s->_kernel->_kfuncTable.size()) ? + sciprintf(" %s[%x]", (param_value < s->_kernel->_kernelFuncs.size()) ? ((param_value < s->_kernel->getKernelNamesSize()) ? s->_kernel->getKernelName(param_value).c_str() : "[Unknown(postulated)]") : "<invalid>", param_value); else @@ -465,7 +397,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod int stackframe = (scr[pos.offset + 2] >> 1) + (*p_restadjust); int argc = ((*p_sp)[- stackframe - 1]).offset; - if (!(s->flags & GF_SCI0_OLD)) + if (!(s->_flags & GF_SCI0_OLD)) argc += (*p_restadjust); sciprintf(" Kernel params: ("); @@ -535,103 +467,6 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod return retval; } -#ifdef GFXW_DEBUG_WIDGETS -extern GfxWidget *debug_widgets[]; -extern int debug_widget_pos; - -static int c_gfx_print_widget(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - if (!_debugstate_valid) { - sciprintf("Not in debug state\n"); - return 1; - } - - if (cmdParams.size()) { - unsigned int i; - for (i = 0; i < cmdParams.size() ; i++) { - int widget_nr = cmdParams[i].val; - - sciprintf("===== Widget #%d:\n", widget_nr); - debug_widgets[widget_nr]->print(0); - } - - } else if (debug_widget_pos > 1) - sciprintf("Widgets 0-%d are active\n", debug_widget_pos - 1); - else if (debug_widget_pos == 1) - sciprintf("Widget 0 is active\n"); - else - sciprintf("No widgets are active\n"); - - return 0; -} -#endif - -#define GETRECT(ll, rr, tt, bb) \ - ll = GET_SELECTOR(pos, ll); \ - rr = GET_SELECTOR(pos, rr); \ - tt = GET_SELECTOR(pos, tt); \ - bb = GET_SELECTOR(pos, bb); - -#if 0 -// Unreferenced - removed -static int c_gfx_draw_viewobj(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { -// TODO: Re-implement gfx_draw_viewobj -#if 0 - HeapPtr pos = (HeapPtr)(cmdParams[0].val); - int is_view; - int x, y, priority; - int nsLeft, nsRight, nsBottom, nsTop; - int brLeft, brRight, brBottom, brTop; - - if (!s) { - sciprintf("Not in debug state!\n"); - return 1; - } - - if ((pos < 4) || (pos > 0xfff0)) { - sciprintf("Invalid address.\n"); - return 1; - } - - if (((int16)READ_LE_UINT16(s->heap + pos + SCRIPT_OBJECT_MAGIC_OFFSET)) != SCRIPT_OBJECT_MAGIC_NUMBER) { - sciprintf("Not an object.\n"); - return 0; - } - - - is_view = (lookup_selector(s, pos, s->_kernel->_selectorMap.x, NULL) == kSelectorVariable) && - (lookup_selector(s, pos, s->_kernel->_selectorMap.brLeft, NULL) == kSelectorVariable) && - (lookup_selector(s, pos, s->_kernel->_selectorMap.signal, NULL) == kSelectorVariable) && - (lookup_selector(s, pos, s->_kernel->_selectorMap.nsTop, NULL) == kSelectorVariable); - - if (!is_view) { - sciprintf("Not a dynamic View object.\n"); - return 0; - } - - x = GET_SELECTOR(pos, x); - y = GET_SELECTOR(pos, y); - priority = GET_SELECTOR(pos, priority); - GETRECT(brLeft, brRight, brBottom, brTop); - GETRECT(nsLeft, nsRight, nsBottom, nsTop); - gfxop_set_clip_zone(s->gfx_state, gfx_rect_fullscreen); - - brTop += 10; - brBottom += 10; - nsTop += 10; - nsBottom += 10; - - gfxop_fill_box(s->gfx_state, gfx_rect(nsLeft, nsTop, nsRight - nsLeft + 1, nsBottom - nsTop + 1), s->ega_colors[2]); - gfxop_fill_box(s->gfx_state, gfx_rect(brLeft, brTop, brRight - brLeft + 1, brBottom - brTop + 1), s->ega_colors[1]); - gfxop_fill_box(s->gfx_state, gfx_rect(x - 1, y - 1, 3, 3), s->ega_colors[0]); - gfxop_fill_box(s->gfx_state, gfx_rect(x - 1, y, 3, 1), s->ega_colors[priority]); - gfxop_fill_box(s->gfx_state, gfx_rect(x, y - 1, 1, 3), s->ega_colors[priority]); - gfxop_update(s->gfx_state); - - return 0; -#endif -} -#endif - static int c_disasm_addr(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { reg_t vpc = cmdParams[0].reg; int op_count = 1; @@ -695,9 +530,9 @@ static int c_disasm(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) } static int c_sg(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - _debug_seeking = _DEBUG_SEEK_GLOBAL; - _debug_seek_special = cmdParams[0].val; - _debugstate_valid = 0; + g_debug_seeking = _DEBUG_SEEK_GLOBAL; + s_debug_seek_special = cmdParams[0].val; + g_debugstate_valid = 0; return 0; } @@ -706,7 +541,7 @@ static int c_snk(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { int callk_index; char *endptr; - if (!_debugstate_valid) { + if (!g_debugstate_valid) { sciprintf("Not in debug state\n"); return 1; } @@ -730,27 +565,27 @@ static int c_snk(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { } } - _debug_seeking = _DEBUG_SEEK_SPECIAL_CALLK; - _debug_seek_special = callk_index; - _debugstate_valid = 0; + g_debug_seeking = _DEBUG_SEEK_SPECIAL_CALLK; + s_debug_seek_special = callk_index; + g_debugstate_valid = 0; } else { - _debug_seeking = _DEBUG_SEEK_CALLK; - _debugstate_valid = 0; + g_debug_seeking = _DEBUG_SEEK_CALLK; + g_debugstate_valid = 0; } return 0; } static int c_sret(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - _debug_seeking = _DEBUG_SEEK_LEVEL_RET; - _debug_seek_level = s->_executionStack.size()-1; - _debugstate_valid = 0; + g_debug_seeking = _DEBUG_SEEK_LEVEL_RET; + s_debug_seek_level = s->_executionStack.size()-1; + g_debugstate_valid = 0; return 0; } static int c_go(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - _debug_seeking = 0; - _debugstate_valid = 0; + g_debug_seeking = 0; + g_debugstate_valid = 0; return 0; } @@ -810,97 +645,11 @@ static int c_send(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { return 0; } - -#define GETRECT(ll, rr, tt, bb) \ - ll = GET_SELECTOR(pos, ll); \ - rr = GET_SELECTOR(pos, rr); \ - tt = GET_SELECTOR(pos, tt); \ - bb = GET_SELECTOR(pos, bb); - -#if 0 -#ifdef __GNUC__ -#warning "Re-implement viewobjinfo" -#endif -static void viewobjinfo(EngineState *s, HeapPtr pos) { - char *signals[16] = { - "stop_update", - "updated", - "no_update", - "hidden", - "fixed_priority", - "always_update", - "force_update", - "remove", - "frozen", - "is_extra", - "hit_obstacle", - "doesnt_turn", - "no_cycler", - "ignore_horizon", - "ignore_actor", - "dispose!" - }; - - int x, y, z, priority; - int cel, loop, view, signal; - int nsLeft, nsRight, nsBottom, nsTop; - int lsLeft, lsRight, lsBottom, lsTop; - int brLeft, brRight, brBottom, brTop; - int i; - int have_rects = 0; - Common::Rect nsrect, nsrect_clipped, brrect; - - if (lookup_selector(s, pos, s->_kernel->_selectorMap.nsBottom, NULL) == kSelectorVariable) { - GETRECT(nsLeft, nsRight, nsBottom, nsTop); - GETRECT(lsLeft, lsRight, lsBottom, lsTop); - GETRECT(brLeft, brRight, brBottom, brTop); - have_rects = 1; - } - - GETRECT(view, loop, signal, cel); - - sciprintf("\n-- View information:\ncel %d/%d/%d at ", view, loop, cel); - - x = GET_SELECTOR(pos, x); - y = GET_SELECTOR(pos, y); - priority = GET_SELECTOR(pos, priority); - if (s->_kernel->_selectorMap.z > 0) { - z = GET_SELECTOR(pos, z); - sciprintf("(%d,%d,%d)\n", x, y, z); - } else - sciprintf("(%d,%d)\n", x, y); - - if (priority == -1) - sciprintf("No priority.\n\n"); - else - sciprintf("Priority = %d (band starts at %d)\n\n", priority, PRIORITY_BAND_FIRST(priority)); - - if (have_rects) { - sciprintf("nsRect: [%d..%d]x[%d..%d]\n", nsLeft, nsRight, nsTop, nsBottom); - sciprintf("lsRect: [%d..%d]x[%d..%d]\n", lsLeft, lsRight, lsTop, lsBottom); - sciprintf("brRect: [%d..%d]x[%d..%d]\n", brLeft, brRight, brTop, brBottom); - } - - nsrect = get_nsrect(s, pos, 0); - nsrect_clipped = get_nsrect(s, pos, 1); - brrect = set_base(s, pos); - sciprintf("new nsRect: [%d..%d]x[%d..%d]\n", nsrect.x, nsrect.xend, nsrect.y, nsrect.yend); - sciprintf("new clipped nsRect: [%d..%d]x[%d..%d]\n", nsrect_clipped.x, nsrect_clipped.xend, nsrect_clipped.y, nsrect_clipped.yend); - sciprintf("new brRect: [%d..%d]x[%d..%d]\n", brrect.x, brrect.xend, brrect.y, brrect.yend); - sciprintf("\n signals = %04x:\n", signal); - - for (i = 0; i < 16; i++) - if (signal & (1 << i)) - sciprintf(" %04x: %s\n", 1 << i, signals[i]); -} -#endif -#undef GETRECT - // Breakpoint commands int c_se(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) { - stop_on_event = 1; - _debugstate_valid = 0; + g_stop_on_event = 1; + g_debugstate_valid = 0; return 0; } @@ -909,7 +658,7 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * SegmentId *segids, reg_t **variables, reg_t **variables_base, int *variables_nr, int bp) { // Do we support a separate console? - int old_debugstate = _debugstate_valid; + int old_debugstate = g_debugstate_valid; p_var_segs = segids; p_vars = variables; @@ -921,15 +670,15 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * p_objp = objp; p_restadjust = restadjust; sciprintf("%d: acc=%04x:%04x ", script_step_counter, PRINT_REG(s->r_acc)); - _debugstate_valid = 1; + g_debugstate_valid = 1; disassemble(s, *pc, 0, 1); - if (_debug_seeking == _DEBUG_SEEK_GLOBAL) - sciprintf("Global %d (0x%x) = %04x:%04x\n", _debug_seek_special, - _debug_seek_special, PRINT_REG(s->script_000->locals_block->_locals[_debug_seek_special])); + if (g_debug_seeking == _DEBUG_SEEK_GLOBAL) + sciprintf("Global %d (0x%x) = %04x:%04x\n", s_debug_seek_special, + s_debug_seek_special, PRINT_REG(s->script_000->locals_block->_locals[s_debug_seek_special])); - _debugstate_valid = old_debugstate; + g_debugstate_valid = old_debugstate; - if (_debug_seeking && !bp) { // Are we looking for something special? + if (g_debug_seeking && !bp) { // Are we looking for something special? MemObject *mobj = GET_SEGMENT(*s->seg_manager, pc->segment, MEM_OBJ_SCRIPT); if (mobj) { @@ -941,9 +690,9 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * int paramb1 = pc->offset + 1 >= code_buf_size ? 0 : code_buf[pc->offset + 1]; int paramf1 = (opcode & 1) ? paramb1 : (pc->offset + 2 >= code_buf_size ? 0 : (int16)READ_LE_UINT16(code_buf + pc->offset + 1)); - switch (_debug_seeking) { + switch (g_debug_seeking) { case _DEBUG_SEEK_SPECIAL_CALLK: - if (paramb1 != _debug_seek_special) + if (paramb1 != s_debug_seek_special) return; case _DEBUG_SEEK_CALLK: { @@ -953,38 +702,32 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * } case _DEBUG_SEEK_LEVEL_RET: { - if ((op != op_ret) || (_debug_seek_level < (int)s->_executionStack.size()-1)) + if ((op != op_ret) || (s_debug_seek_level < (int)s->_executionStack.size()-1)) return; break; } - case _DEBUG_SEEK_SO: - if ((*pc != _debug_seek_reg) || (int)s->_executionStack.size()-1 != _debug_seek_level) - return; - break; - case _DEBUG_SEEK_GLOBAL: - if (op < op_sag) return; if ((op & 0x3) > 1) return; // param or temp if ((op & 0x3) && s->_executionStack.back().local_segment > 0) return; // locals and not running in script.000 - if (paramf1 != _debug_seek_special) + if (paramf1 != s_debug_seek_special) return; // CORRECT global? break; } - _debug_seeking = _DEBUG_SEEK_NOTHING; + g_debug_seeking = _DEBUG_SEEK_NOTHING; // OK, found whatever we were looking for } } - _debugstate_valid = (_debug_step_running == 0); + g_debugstate_valid = (g_debug_step_running == 0); - if (_debugstate_valid) { + if (g_debugstate_valid) { p_pc = pc; p_sp = sp; p_pp = pp; @@ -998,15 +741,11 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * sciprintf("Step #%d\n", script_step_counter); disassemble(s, *pc, 0, 1); - if (_debug_commands_not_hooked) { - _debug_commands_not_hooked = 0; + if (!s_debug_commands_hooked) { + s_debug_commands_hooked = true; con_hook_command(c_step, "s", "i*", "Executes one or several operations\n\nEXAMPLES\n\n" " s 4\n\n Execute 4 commands\n\n s\n\n Execute next command"); -#if 0 - // TODO Re-implement con:so - con_hook_command(c_stepover, "so", "", "Executes one operation skipping over sends"); -#endif con_hook_command(c_disasm_addr, "disasm-addr", "!as*", "Disassembles one or more commands\n\n" "USAGE\n\n disasm-addr [startaddr] <options>\n\n" " Valid options are:\n" @@ -1022,50 +761,15 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * con_hook_command(c_go, "go", "", "Executes the script.\n"); con_hook_command(c_set_parse_nodes, "set_parse_nodes", "s*", "Sets the contents of all parse nodes.\n" " Input token must be separated by\n blanks."); - -#ifdef GFXW_DEBUG_WIDGETS - con_hook_command(c_gfx_print_widget, "gfx_print_widget", "i*", "If called with no parameters, it\n shows which widgets are active.\n" - " With parameters, it lists the\n widget corresponding to the\n numerical index specified (for\n each parameter)."); -#endif - -#if 0 - // TODO: Re-enable con:draw_viewobj - con_hook_command(c_gfx_draw_viewobj, "draw_viewobj", "i", "Draws the nsRect and brRect of a\n dynview object.\n\n nsRect is green, brRect\n" - " is blue.\n"); -#endif con_hook_command(c_sg, "sg", "!i", "Steps until the global variable with the\n" "specified index is modified.\n\nSEE ALSO\n\n" " s.1, snk.1, so.1, bpx.1"); -/* - con_hook_int(&script_abort_flag, "script_abort_flag", "Set != 0 to abort execution\n"); -*/ } // If commands were not hooked up } - if (_debug_step_running) - _debug_step_running--; - - while (_debugstate_valid) { - int skipfirst = 0; - const char *commandstring; - - // Suspend music playing - s->_sound.sfx_suspend(true); - - commandstring = _debug_get_input(); - - // Check if a specific destination has been given - if (commandstring && (commandstring[0] == '.' || commandstring[0] == ':')) - skipfirst = 1; - - //if (commandstring && commandstring[0] != ':') - // con_parse(s, commandstring + skipfirst); - sciprintf("\n"); - - // Resume music playing - s->_sound.sfx_suspend(false); - } + if (g_debug_step_running) + g_debug_step_running--; } } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 69a939dae9..dcf7180501 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -135,13 +135,13 @@ void SegManager::setScriptSize(Script &scr, EngineState *s, int script_nr) { scr.script_size = script->size; scr.heap_size = 0; // Set later - if (!script || (s->version >= SCI_VERSION_1_1 && !heap)) { + if (!script || (s->_version >= SCI_VERSION_1_1 && !heap)) { error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap"); } - if (s->flags & GF_SCI0_OLD) { + if (s->_flags & GF_SCI0_OLD) { scr.buf_size = script->size + READ_LE_UINT16(script->data) * 2; //locals_size = READ_LE_UINT16(script->data) * 2; - } else if (s->version < SCI_VERSION_1_1) { + } else if (s->_version < SCI_VERSION_1_1) { scr.buf_size = script->size; } else { scr.buf_size = script->size + heap->size; @@ -189,7 +189,7 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) { scr.obj_indices = new IntMapper(); - if (s->version >= SCI_VERSION_1_1) + if (s->_version >= SCI_VERSION_1_1) scr.heap_start = scr.buf + scr.script_size; else scr.heap_start = scr.buf; @@ -232,49 +232,6 @@ int SegManager::deallocateScript(int script_nr) { return 1; } -MemObject *MemObject::createMemObject(MemObjectType type) { - MemObject *mem = 0; - switch (type) { - case MEM_OBJ_SCRIPT: - mem = new Script(); - break; - case MEM_OBJ_CLONES: - mem = new CloneTable(); - break; - case MEM_OBJ_LOCALS: - mem = new LocalVariables(); - break; - case MEM_OBJ_SYS_STRINGS: - mem = new SystemStrings(); - break; - case MEM_OBJ_STACK: - mem = new DataStack(); - break; - case MEM_OBJ_HUNK: - mem = new HunkTable(); - break; - case MEM_OBJ_STRING_FRAG: - mem = new StringFrag(); - break; - case MEM_OBJ_LISTS: - mem = new ListTable(); - break; - case MEM_OBJ_NODES: - mem = new NodeTable(); - break; - case MEM_OBJ_DYNMEM: - mem = new DynMem(); - break; - default: - error("Unknown MemObject type %d", type); - break; - } - - assert(mem); - mem->_type = type; - return mem; -} - MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectType type) { MemObject *mem = MemObject::createMemObject(type); if (!mem) { @@ -294,33 +251,6 @@ MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectTyp return mem; } -void Script::freeScript() { - free(buf); - buf = NULL; - buf_size = 0; - - _objects.clear(); - - delete obj_indices; - obj_indices = 0; - _codeBlocks.clear(); -} - -// memory operations - -void Script::mcpyInOut(int dst, const void *src, size_t n) { - if (buf) { - assert(dst + n <= buf_size); - memcpy(buf + dst, src, n); - } -} - -int16 Script::getHeap(uint16 offset) const { - VERIFY(offset + 1 < (int)buf_size, "invalid offset\n"); - return READ_LE_UINT16(buf + offset); -// return (buf[offset] | (buf[offset+1]) << 8); -} - // return the seg if script_id is valid and in the map, else -1 SegmentId SegManager::segGet(int script_id) const { return id_seg_map->lookupKey(script_id); @@ -367,53 +297,10 @@ bool SegManager::scriptIsLoaded(SegmentId seg) { return getScriptIfLoaded(seg) != 0; } -void Script::incrementLockers() { - lockers++; -} - -void Script::decrementLockers() { - if (lockers > 0) - lockers--; -} - -int Script::getLockers() const { - return lockers; -} - -void Script::setLockers(int lockers_) { - lockers = lockers_; -} - -void Script::setExportTableOffset(int offset) { - if (offset) { - export_table = (uint16 *)(buf + offset + 2); - exports_nr = READ_LE_UINT16((byte *)(export_table - 1)); - } else { - export_table = NULL; - exports_nr = 0; - } -} - void SegManager::setExportWidth(int flag) { exports_wide = flag; } -void Script::setSynonymsOffset(int offset) { - synonyms = buf + offset; -} - -byte *Script::getSynonyms() const { - return synonyms; -} - -void Script::setSynonymsNr(int n) { - synonyms_nr = n; -} - -int Script::getSynonymsNr() const { - return synonyms_nr; -} - int SegManager::relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location) { int rel = location - block_location; @@ -925,67 +812,6 @@ Hunk *SegManager::alloc_Hunk(reg_t *addr) { return &(table->_table[offset]); } -byte *MemObject::dereference(reg_t pointer, int *size) { - error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment", - PRINT_REG(pointer)); - return NULL; -} - -byte *Script::dereference(reg_t pointer, int *size) { - if (pointer.offset > buf_size) { - sciprintf("Error: Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)\n", - PRINT_REG(pointer), (uint)buf_size); - return NULL; - } - if (size) - *size = buf_size - pointer.offset; - return (byte *)(buf + pointer.offset); -} - -byte *LocalVariables::dereference(reg_t pointer, int *size) { - // FIXME: The following doesn't seem to be endian safe. - // To fix this, we'd have to always treat the reg_t - // values stored here as in the little endian format. - int count = _locals.size() * sizeof(reg_t); - byte *base = (byte *)&_locals[0]; - - if (size) - *size = count; - - return base + pointer.offset; -} - -byte *DataStack::dereference(reg_t pointer, int *size) { - int count = nr * sizeof(reg_t); - byte *base = (byte *)entries; - - if (size) - *size = count; - - return base + pointer.offset; -} - -byte *DynMem::dereference(reg_t pointer, int *size) { - int count = _size; - byte *base = (byte *)_buf; - - if (size) - *size = count; - - return base + pointer.offset; -} - -byte *SystemStrings::dereference(reg_t pointer, int *size) { - if (size) - *size = strings[pointer.offset].max_size; - if (pointer.offset < SYS_STRINGS_MAX && strings[pointer.offset].name) - return (byte *)(strings[pointer.offset].value); - - // This occurs in KQ5CD when interacting with certain objects - warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); - return NULL; -} - byte *SegManager::dereference(reg_t pointer, int *size) { if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) { // This occurs in KQ5CD when interacting with certain objects @@ -1048,191 +874,5 @@ void SegManager::dbgPrint(const char* msg, void *i) { } -//-------------------- script -------------------- -reg_t Script::findCanonicAddress(SegManager *segmgr, reg_t addr) { - addr.offset = 0; - return addr; -} - -void Script::freeAtAddress(SegManager *segmgr, reg_t addr) { - /* - sciprintf("[GC] Freeing script %04x:%04x\n", PRINT_REG(addr)); - if (locals_segment) - sciprintf("[GC] Freeing locals %04x:0000\n", locals_segment); - */ - - if (_markedAsDeleted) - segmgr->deallocateScript(nr); -} - -void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { - (*note)(param, make_reg(segId, 0)); -} - -void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { - Script *script = this; - - if (addr.offset <= script->buf_size && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(script->buf + addr.offset)) { - int idx = RAW_GET_CLASS_INDEX(script, addr); - if (idx >= 0 && (uint)idx < script->_objects.size()) { - // Note all local variables, if we have a local variable environment - if (script->locals_segment) - (*note)(param, make_reg(script->locals_segment, 0)); - - Object &obj = script->_objects[idx]; - for (uint i = 0; i < obj._variables.size(); i++) - (*note)(param, obj._variables[i]); - } else { - warning("Request for outgoing script-object reference at %04x:%04x yielded invalid index %d", PRINT_REG(addr), idx); - } - } else { - /* warning("Unexpected request for outgoing script-object references at %04x:%04x", PRINT_REG(addr));*/ - /* Happens e.g. when we're looking into strings */ - } -} - - -//-------------------- clones -------------------- - -template<typename T> -void Table<T>::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { - for (uint i = 0; i < _table.size(); i++) - if (isValidEntry(i)) - (*note)(param, make_reg(segId, i)); -} - -void CloneTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { - CloneTable *clone_table = this; - Clone *clone; - -// assert(addr.segment == _segId); - - if (!clone_table->isValidEntry(addr.offset)) { - warning("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr)); -// BREAKPOINT(); - return; - } - - clone = &(clone_table->_table[addr.offset]); - - // Emit all member variables (including references to the 'super' delegate) - for (uint i = 0; i < clone->_variables.size(); i++) - (*note)(param, clone->_variables[i]); - - // Note that this also includes the 'base' object, which is part of the script and therefore also emits the locals. - (*note)(param, clone->pos); - //sciprintf("[GC] Reporting clone-pos %04x:%04x\n", PRINT_REG(clone->pos)); -} - -void CloneTable::freeAtAddress(SegManager *segmgr, reg_t addr) { - CloneTable *clone_table = this; - Object *victim_obj; - -// assert(addr.segment == _segId); - - victim_obj = &(clone_table->_table[addr.offset]); - -#ifdef GC_DEBUG - if (!(victim_obj->flags & OBJECT_FLAG_FREED)) - sciprintf("[GC] Warning: Clone %04x:%04x not reachable and not freed (freeing now)\n", PRINT_REG(addr)); -#ifdef GC_DEBUG_VERBOSE - else - sciprintf("[GC-DEBUG] Clone %04x:%04x: Freeing\n", PRINT_REG(addr)); -#endif -#endif - /* - sciprintf("[GC] Clone %04x:%04x: Freeing\n", PRINT_REG(addr)); - sciprintf("[GC] Clone had pos %04x:%04x\n", PRINT_REG(victim_obj->pos)); - */ - clone_table->freeEntry(addr.offset); -} - - -//-------------------- locals -------------------- -reg_t LocalVariables::findCanonicAddress(SegManager *segmgr, reg_t addr) { - // Reference the owning script - SegmentId owner_seg = segmgr->segGet(script_id); - - assert(owner_seg >= 0); - - return make_reg(owner_seg, 0); -} - -void LocalVariables::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { -// assert(addr.segment == _segId); - - for (uint i = 0; i < _locals.size(); i++) - (*note)(param, _locals[i]); -} - - -//-------------------- stack -------------------- -reg_t DataStack::findCanonicAddress(SegManager *segmgr, reg_t addr) { - addr.offset = 0; - return addr; -} - -void DataStack::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { - fprintf(stderr, "Emitting %d stack entries\n", nr); - for (int i = 0; i < nr; i++) - (*note)(param, entries[i]); - fprintf(stderr, "DONE"); -} - - -//-------------------- lists -------------------- -void ListTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) { - freeEntry(sub_addr.offset); -} - -void ListTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { - if (!isValidEntry(addr.offset)) { - warning("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); - return; - } - - List *list = &(_table[addr.offset]); - - note(param, list->first); - note(param, list->last); - // We could probably get away with just one of them, but - // let's be conservative here. -} - - -//-------------------- nodes -------------------- -void NodeTable::freeAtAddress(SegManager *segmgr, reg_t sub_addr) { - freeEntry(sub_addr.offset); -} - -void NodeTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { - if (!isValidEntry(addr.offset)) { - warning("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr)); - return; - } - 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 - note(param, node->pred); - note(param, node->succ); - note(param, node->key); - note(param, node->value); -} - - -//-------------------- hunk -------------------- - -//-------------------- dynamic memory -------------------- - -reg_t DynMem::findCanonicAddress(SegManager *segmgr, reg_t addr) { - addr.offset = 0; - return addr; -} - -void DynMem::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { - (*note)(param, make_reg(segId, 0)); -} - } // End of namespace Sci diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 643385fd74..dc91d60e69 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -29,6 +29,7 @@ #include "common/scummsys.h" #include "common/serializer.h" #include "sci/engine/vm.h" +#include "sci/engine/memobj.h" namespace Sci { diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index 5936c4fedb..0e4b63acee 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -27,11 +27,10 @@ namespace Sci { -EngineState::EngineState() : _dirseeker(this) { +EngineState::EngineState(ResourceManager *res, sci_version_t version, uint32 flags) +: resmgr(res), _version(version), _flags(flags), _dirseeker(this) { widget_serial_counter = 0; - resmgr = 0; - game_version = 0; gfx_state = 0; @@ -80,9 +79,6 @@ EngineState::EngineState() : _dirseeker(this) { last_wait_time = 0; - version = 0; - flags = 0; - kernel_opt_flags = 0; _fileHandles.resize(5); @@ -126,5 +122,8 @@ EngineState::EngineState() : _dirseeker(this) { EngineState::~EngineState() { } +uint16 EngineState::currentRoomNumber() const { + return KP_UINT(script_000->locals_block->_locals[13]); +} } // End of namespace Sci diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 0623aa35fd..15c1c2e63e 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -48,7 +48,6 @@ namespace Common { namespace Sci { class Menubar; -struct kfunct_sig_pair_t; // from kernel.h struct GfxState; struct GfxPort; @@ -110,7 +109,7 @@ public: struct EngineState : public Common::Serializable { public: - EngineState(); + EngineState(ResourceManager *res, sci_version_t version, uint32 flags); virtual ~EngineState(); virtual void saveLoadWithSerializer(Common::Serializer &ser); @@ -119,6 +118,9 @@ public: ResourceManager *resmgr; /**< The resource manager */ + const sci_version_t _version; /**< The approximated patchlevel of the version to emulate */ + const uint32 _flags; /**< Specific game flags */ + Common::String _gameName; /**< Designation of the primary object (which inherits from Game) */ char *game_version; @@ -175,9 +177,6 @@ public: uint32 game_start_time; /**< The time at which the interpreter was started */ uint32 last_wait_time; /**< The last time the game invoked Wait() */ - sci_version_t version; /**< The approximated patchlevel of the version to emulate */ - uint32 flags; /**< Specific game flags */ - unsigned int kernel_opt_flags; /**< Kernel optimization flags- used for performance tweaking */ /* Kernel File IO stuff */ @@ -208,7 +207,7 @@ public: reg_t parser_event; /**< The event passed to Parse() and later used by Said() */ Script *script_000; /**< script 000, e.g. for globals */ - uint16 currentRoomNumber() const { return KP_UINT(script_000->locals_block->_locals[13]); } + uint16 currentRoomNumber() const; /* Debugger data: */ Breakpoint *bp_list; /**< List of breakpoints */ @@ -250,6 +249,13 @@ public: */ PaletteEntry get_pic_color(EngineState *s, int color); +// FIXME: Document this strange function. +// It seems to negate the given register but only if the "cantBeHere" exists. +// My guess: Since some SCI versions have cantBeHere and some have canBeHere, +// this function allows unifying the code, making it look identical for both +// kinds of SCI games. That's fine, but the name not_register is rather +// misleading. A different name (and a different place for declaring this) +// would be highly welcome. static inline reg_t not_register(EngineState *s, reg_t r) { if (s->_kernel->_selectorMap.cantBeHere != -1) return make_reg(0, !r.offset); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 18e1ef7866..fd8ce33f51 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -27,7 +27,7 @@ #include "common/stack.h" #include "sci/sci.h" -#include "sci/console.h" // for debug_weak_validations +#include "sci/debug.h" // for g_debug_weak_validations #include "sci/resource.h" #include "sci/engine/state.h" #include "sci/engine/intmap.h" @@ -46,17 +46,13 @@ reg_t NULL_REG = {0, 0}; #undef STRICT_READ // Disallows reading from out-of-bounds parameters and locals -int script_abort_flag = 0; // Set to 1 to abort execution -int script_step_counter = 0; // Counts the number of steps executed -int script_gc_interval = GC_INTERVAL; // Number of steps in between gcs +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 -extern int _debug_step_running; -extern int _debug_seeking; -extern bool debug_weak_validations; - -static bool breakpointFlag = false; -static reg_t _dummy_register; +static bool breakpointFlag = false; // FIXME: Avoid non-const global vars +static reg_t _dummy_register; // FIXME: Avoid non-const global vars // validation functionality @@ -90,7 +86,7 @@ static StackPtr validate_stack_addr(EngineState *s, StackPtr sp) { static int validate_arithmetic(reg_t reg) { if (reg.segment) { - if (debug_weak_validations) + if (g_debug_weak_validations) warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); else error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); @@ -102,7 +98,7 @@ static int validate_arithmetic(reg_t reg) { static int signed_validate_arithmetic(reg_t reg) { if (reg.segment) { - if (debug_weak_validations) + if (g_debug_weak_validations) warning("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); else error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]\n", reg.segment); @@ -121,17 +117,15 @@ static int validate_variable(reg_t *r, reg_t *stack_base, int type, int max, int if (index < 0 || index >= max) { char txt[200]; char tmp[40]; - sprintf(txt, "[VM] Attempt to use invalid %s variable %04x ", names[type], index); + sprintf(txt, "[VM] validate_variable(): Attempt to use invalid %s variable %04x ", names[type], index); if (max == 0) strcat(txt, "(variable type invalid)"); else { sprintf(tmp, "(out of range [%d..%d])", 0, max - 1); strcat(txt, tmp); } - sprintf(tmp, " in %s, line %d\n", __FILE__, line); - strcat(txt, tmp); - if (debug_weak_validations) + if (g_debug_weak_validations) warning(txt); else error(txt); @@ -402,7 +396,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt default: sciprintf("Send error: Variable selector %04x in %04x:%04x called with %04x params\n", selector, PRINT_REG(send_obj), argc); script_debug_flag = 1; // Enter debug mode - _debug_seeking = _debug_step_running = 0; + g_debug_seeking = g_debug_step_running = 0; #endif } break; @@ -977,24 +971,24 @@ void run_vm(EngineState *s, int restoring) { gc_countdown(s); xs->sp -= (opparams[1] >> 1) + 1; - if (!(s->flags & GF_SCI0_OLD)) { + if (!(s->_flags & GF_SCI0_OLD)) { xs->sp -= restadjust; s->r_amp_rest = 0; // We just used up the restadjust, remember? } - if (opparams[0] >= (int)s->_kernel->_kfuncTable.size()) { + if (opparams[0] >= (int)s->_kernel->_kernelFuncs.size()) { error("Invalid kernel function 0x%x requested\n", opparams[0]); } else { int argc = ASSERT_ARITHMETIC(xs->sp[0]); - if (!(s->flags & GF_SCI0_OLD)) + if (!(s->_flags & GF_SCI0_OLD)) argc += restadjust; - if (s->_kernel->_kfuncTable[opparams[0]].signature - && !kernel_matches_signature(s, s->_kernel->_kfuncTable[opparams[0]].signature, argc, xs->sp + 1)) { + if (s->_kernel->_kernelFuncs[opparams[0]].signature + && !kernel_matches_signature(s, s->_kernel->_kernelFuncs[opparams[0]].signature, argc, xs->sp + 1)) { error("[VM] Invalid arguments to kernel call %x\n", opparams[0]); } else { - s->r_acc = s->_kernel->_kfuncTable[opparams[0]].fun(s, opparams[0], argc, xs->sp + 1); + s->r_acc = s->_kernel->_kernelFuncs[opparams[0]].fun(s, opparams[0], argc, xs->sp + 1); } // Call kernel function @@ -1004,7 +998,7 @@ void run_vm(EngineState *s, int restoring) { xs_new = &(s->_executionStack.back()); s->_executionStackPosChanged = true; - if (!(s->flags & GF_SCI0_OLD)) + if (!(s->_flags & GF_SCI0_OLD)) restadjust = s->r_amp_rest; } @@ -1207,10 +1201,10 @@ void run_vm(EngineState *s, int restoring) { case 0x39: // lofsa s->r_acc.segment = xs->addr.pc.segment; - if (s->version >= SCI_VERSION_1_1) { + if (s->_version >= SCI_VERSION_1_1) { s->r_acc.offset = opparams[0] + local_script->script_size; } else { - if (s->flags & GF_SCI1_LOFSABSOLUTE) + if (s->_flags & GF_SCI1_LOFSABSOLUTE) s->r_acc.offset = opparams[0]; else s->r_acc.offset = xs->addr.pc.offset + opparams[0]; @@ -1227,7 +1221,7 @@ void run_vm(EngineState *s, int restoring) { case 0x3a: // lofss r_temp.segment = xs->addr.pc.segment; - if (s->flags & GF_SCI1_LOFSABSOLUTE) + if (s->_flags & GF_SCI1_LOFSABSOLUTE) r_temp.offset = opparams[0]; else r_temp.offset = xs->addr.pc.offset + opparams[0]; @@ -1433,8 +1427,8 @@ void run_vm(EngineState *s, int restoring) { #if 0 if (script_error_flag) { - _debug_step_running = 0; // Stop multiple execution - _debug_seeking = 0; // Stop special seeks + g_debug_step_running = 0; // Stop multiple execution + g_debug_seeking = 0; // Stop special seeks xs->addr.pc.offset = old_pc_offset; xs->sp = old_sp; } else @@ -1447,7 +1441,7 @@ static int _obj_locate_varselector(EngineState *s, Object *obj, Selector slc) { // Determines if obj explicitly defines slc as a varselector // Returns -1 if not found - if (s->version < SCI_VERSION_1_1) { + if (s->_version < SCI_VERSION_1_1) { int varnum = obj->variable_names_nr; int selector_name_offset = varnum * 2 + SCRIPT_SELECTOR_OFFSET; int i; @@ -1520,7 +1514,7 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select // 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 (s->flags & GF_SCI0_OLD) + if (s->_flags & GF_SCI0_OLD) selector_id &= ~1; if (!obj) { @@ -1614,12 +1608,12 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script, *was_new = 1; *script = s->resmgr->findResource(kResourceTypeScript, script_nr, 0); - if (s->version >= SCI_VERSION_1_1) + if (s->_version >= SCI_VERSION_1_1) *heap = s->resmgr->findResource(kResourceTypeHeap, script_nr, 0); - if (!*script || (s->version >= SCI_VERSION_1_1 && !heap)) { + if (!*script || (s->_version >= SCI_VERSION_1_1 && !heap)) { sciprintf("Script 0x%x requested but not found\n", script_nr); - if (s->version >= SCI_VERSION_1_1) { + if (s->_version >= SCI_VERSION_1_1) { if (*heap) sciprintf("Inconsistency: heap resource WAS found\n"); else if (*script) @@ -1686,7 +1680,7 @@ int script_instantiate_sci0(EngineState *s, int script_nr) { Script *scr = s->seg_manager->getScript(seg_id); - if (s->flags & GF_SCI0_OLD) { + if (s->_flags & GF_SCI0_OLD) { // int locals_nr = READ_LE_UINT16(script->data); @@ -1855,14 +1849,14 @@ int script_instantiate_sci11(EngineState *s, int script_nr) { } int script_instantiate(EngineState *s, int script_nr) { - if (s->version >= SCI_VERSION_1_1) + if (s->_version >= SCI_VERSION_1_1) return script_instantiate_sci11(s, script_nr); else return script_instantiate_sci0(s, script_nr); } void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) { - reg_t reg = make_reg(seg, (s->flags & GF_SCI0_OLD) ? 2 : 0); + reg_t reg = make_reg(seg, (s->_flags & GF_SCI0_OLD) ? 2 : 0); int objtype, objlength; Script *scr = s->seg_manager->getScript(seg); @@ -1906,7 +1900,7 @@ void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) { } void script_uninstantiate(EngineState *s, int script_nr) { - reg_t reg = make_reg(0, (s->flags & GF_SCI0_OLD) ? 2 : 0); + reg_t reg = make_reg(0, (s->_flags & GF_SCI0_OLD) ? 2 : 0); reg.segment = s->seg_manager->segGet(script_nr); Script *scr = script_locate_by_segment(s, reg.segment); @@ -1927,7 +1921,7 @@ void script_uninstantiate(EngineState *s, int script_nr) { if (s->_classtable[i].reg.segment == reg.segment) s->_classtable[i].reg = NULL_REG; - if (s->version < SCI_VERSION_1_1) + if (s->_version < SCI_VERSION_1_1) script_uninstantiate_sci0(s, script_nr, reg.segment); else sciprintf("FIXME: Add proper script uninstantiation for SCI 1.1\n"); @@ -1965,7 +1959,7 @@ static EngineState *_game_run(EngineState *s, int restoring) { game_exit(s); script_free_engine(s); - script_init_engine(s, s->version); + script_init_engine(s); game_init(s); sfx_reset_player(); _init_stack_base_with_selector(s, s->_kernel->_selectorMap.play); @@ -1984,7 +1978,7 @@ static EngineState *_game_run(EngineState *s, int restoring) { s = successor; g_EngineState = s; - if (script_abort_flag == SCRIPT_ABORT_WITH_REPLAY) { + if (script_abort_flag == 2) { sciprintf("Restarting with replay()\n"); s->_executionStack.clear(); // Restart with replay @@ -2067,9 +2061,9 @@ const char *obj_get_name(EngineState *s, reg_t pos) { void quit_vm() { script_abort_flag = 1; // Terminate VM - _debugstate_valid = 0; - _debug_seeking = 0; - _debug_step_running = 0; + g_debugstate_valid = 0; + g_debug_seeking = 0; + g_debug_step_running = 0; } void shrink_execution_stack(EngineState *s, uint size) { diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 84e6cc4923..5bfbe71ce9 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -28,7 +28,6 @@ /* VM and kernel declarations */ -#include "common/serializer.h" #include "sci/engine/vm_types.h" // for reg_t #include "common/util.h" @@ -38,128 +37,8 @@ namespace Sci { class SegManager; struct EngineState; typedef int sci_version_t; - -enum MemObjectType { - MEM_OBJ_INVALID = 0, - MEM_OBJ_SCRIPT = 1, - MEM_OBJ_CLONES = 2, - MEM_OBJ_LOCALS = 3, - MEM_OBJ_STACK = 4, - MEM_OBJ_SYS_STRINGS = 5, - MEM_OBJ_LISTS = 6, - MEM_OBJ_NODES = 7, - MEM_OBJ_HUNK = 8, - MEM_OBJ_DYNMEM = 9, - MEM_OBJ_STRING_FRAG = 10, - - MEM_OBJ_MAX // For sanity checking -}; - -struct MemObject : public Common::Serializable { - MemObjectType _type; - int _segmgrId; /**< Internal value used by the seg_manager's hash map */ - - typedef void (*NoteCallback)(void *param, reg_t addr); // FIXME: Bad choice of name - -public: - static MemObject *createMemObject(MemObjectType type); - -public: - virtual ~MemObject() {} - - inline MemObjectType getType() const { return _type; } - inline int getSegMgrId() const { return _segmgrId; } - - /** - * Dereferences a raw memory pointer. - * @param reg reference to dereference - * @param size if not NULL, set to the theoretical maximum size of the referenced data block - * @return the data block referenced - */ - virtual byte *dereference(reg_t pointer, int *size); - - /** - * Finds the canonic address associated with sub_reg. - * - * For each valid address a, there exists a canonic address c(a) such that c(a) = c(c(a)). - * This address "governs" a in the sense that deallocating c(a) will deallocate a. - * - * @param sub_addr base address whose canonic address is to be found - */ - virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr) { return sub_addr; } - - /** - * Deallocates all memory associated with the specified address. - * @param sub_addr address (within the given segment) to deallocate - */ - virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr) {} - - /** - * Iterates over and reports all addresses within the current segment. - * @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) {} - - /** - * Iterates over all references reachable from the specified object. - * @param object object (within the current segment) to analyse - * @param param parameter passed to 'note' - * @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(EngineState *s, reg_t object, void *param, NoteCallback note) {} -}; - - -// TODO: Implement the following class -struct StringFrag : public MemObject { - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - struct IntMapper; - -enum { - SYS_STRINGS_MAX = 4, - - SYS_STRING_SAVEDIR = 0, - SYS_STRING_PARSER_BASE = 1, - - MAX_PARSER_BASE = 64 -}; - -struct SystemString { - char *name; - int max_size; - reg_t *value; -}; - -struct SystemStrings : public MemObject { - SystemString strings[SYS_STRINGS_MAX]; - -public: - SystemStrings() { - memset(strings, 0, sizeof(strings)); - } - ~SystemStrings() { - for (int i = 0; i < SYS_STRINGS_MAX; i++) { - SystemString *str = &strings[i]; - if (str->name) { - free(str->name); - str->name = NULL; - - free(str->value); - str->value = NULL; - - str->max_size = 0; - } - } - } - - virtual byte *dereference(reg_t pointer, int *size); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; +struct Object; /** Number of bytes to be allocated for the stack */ #define VM_STACK_SIZE 0x1000 @@ -188,12 +67,12 @@ public: #define SCRIPT_FUNCTAREAPTR_MAGIC 8 -8 /** Offset of the name pointer */ -#define SCRIPT_NAME_OFFSET (s->version < SCI_VERSION_1_1 ? 14 -8 : 16) -#define SCRIPT_NAME_SELECTOR (s->version < SCI_VERSION_1_1 ? 3 : 8) +#define SCRIPT_NAME_OFFSET (s->_version < SCI_VERSION_1_1 ? 14 -8 : 16) +#define SCRIPT_NAME_SELECTOR (s->_version < SCI_VERSION_1_1 ? 3 : 8) /** Object-relative offset of the -info- selector */ -#define SCRIPT_INFO_OFFSET (s->version < SCI_VERSION_1_1 ? 12 -8 : 14) -#define SCRIPT_INFO_SELECTOR (s->version < SCI_VERSION_1_1 ? 2 : 7) +#define SCRIPT_INFO_OFFSET (s->_version < SCI_VERSION_1_1 ? 12 -8 : 14) +#define SCRIPT_INFO_SELECTOR (s->_version < SCI_VERSION_1_1 ? 2 : 7) /** Flag fo the -info- selector */ #define SCRIPT_INFO_CLONE 0x0001 @@ -205,18 +84,18 @@ public: /** Magical object identifier */ #define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234 /** Offset of this identifier */ -#define SCRIPT_OBJECT_MAGIC_OFFSET (s->version < SCI_VERSION_1_1 ? -8 : 0) +#define SCRIPT_OBJECT_MAGIC_OFFSET (s->_version < SCI_VERSION_1_1 ? -8 : 0) /** Script-relative offset of the species ID */ #define SCRIPT_SPECIES_OFFSET 8 -8 -#define SCRIPT_SUPERCLASS_OFFSET (s->version < SCI_VERSION_1_1 ? 10 -8 : 12) +#define SCRIPT_SUPERCLASS_OFFSET (s->_version < SCI_VERSION_1_1 ? 10 -8 : 12) /*---------------------------------*/ /* Script selector index variables */ /*---------------------------------*/ -#define SCRIPT_SPECIES_SELECTOR (s->version < SCI_VERSION_1_1 ? 0 : 5) -#define SCRIPT_SUPERCLASS_SELECTOR (s->version < SCI_VERSION_1_1 ? 1 : 6) +#define SCRIPT_SPECIES_SELECTOR (s->_version < SCI_VERSION_1_1 ? 0 : 5) +#define SCRIPT_SUPERCLASS_SELECTOR (s->_version < SCI_VERSION_1_1 ? 1 : 6) #define SCRIPT_CLASSSCRIPT_SELECTOR 4 /** Magic adjustment value for lofsa and lofss */ @@ -243,400 +122,6 @@ struct Class { #define IS_CLASS(obj) (obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS) -/** This struct is used to buffer the list of send calls in send_selector() */ -struct CallsStruct { - union { - reg_t func; - reg_t *var; - } address; - StackPtr argp; - int argc; - Selector selector; - StackPtr sp; /**< Stack pointer */ - int type; /**< Same as ExecStack.type */ -}; - -struct LocalVariables : public MemObject { - int script_id; /**< Script ID this local variable block belongs to */ - Common::Array<reg_t> _locals; - -public: - LocalVariables() { - script_id = 0; - } - - virtual byte *dereference(reg_t pointer, int *size); - virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - -/** Clone has been marked as 'freed' */ -#define OBJECT_FLAG_FREED (0x1 << 0) - -struct Object { - int flags; - reg_t pos; /**< Object offset within its script; for clones, this is their base */ - int variable_names_nr; /**< Number of variable names, may be less than variables_nr */ - int methods_nr; - byte *base; /**< Points to a buffer all relative references (code, strings) point to */ - byte *base_obj; /**< base + object offset within base */ - uint16 *base_method; /**< Pointer to the method selector area for this object */ - uint16 *base_vars; /**< Pointer to the varselector area for this object */ - Common::Array<reg_t> _variables; -}; - -struct CodeBlock { - reg_t pos; - int size; -}; - -#define VM_OBJECT_GET_VARSELECTOR(obj, i) \ - (s->version < SCI_VERSION_1_1 ? \ - READ_LE_UINT16(obj->base_obj + obj->_variables.size() * 2 + i*2) : \ - *(obj->base_vars + i)) -#define VM_OBJECT_READ_PROPERTY(obj, i) (obj->_variables[i]) -#define VM_OBJECT_GET_FUNCSELECTOR(obj, i) \ - (s->version < SCI_VERSION_1_1 ? \ - READ_LE_UINT16((byte *) (obj->base_method + i)) : \ - READ_LE_UINT16((byte *) (obj->base_method + i*2 + 1))) -#define VM_OBJECT_READ_FUNCTION(obj, i) \ - (s->version < SCI_VERSION_1_1 ? \ - make_reg(obj->pos.segment, \ - READ_LE_UINT16((byte *) (obj->base_method \ - + obj->methods_nr + 1 \ - + i))) : \ - make_reg(obj->pos.segment, \ - READ_LE_UINT16((byte *) (obj->base_method \ - + i * 2 + 2)))) - - - - -struct Script : public MemObject { - int nr; /**< Script number */ - byte *buf; /**< Static data buffer, or NULL if not used */ - size_t buf_size; - size_t script_size; - size_t heap_size; - - byte *synonyms; /**< Synonyms block or 0 if not present*/ - byte *heap_start; /**< Start of heap if SCI1.1, NULL otherwise */ - uint16 *export_table; /**< Abs. offset of the export table or 0 if not present */ - - IntMapper *obj_indices; - - int exports_nr; /**< Number of entries in the exports table */ - int synonyms_nr; /**< Number of entries in the synonyms block */ - int lockers; /**< Number of classes and objects that require this script */ - - /** - * Table for objects, contains property variables. - * Indexed by the value stored at SCRIPT_LOCALVARPTR_OFFSET, - * see VM_OBJECT_[GS]ET_INDEX() - */ - Common::Array<Object> _objects; - - int locals_offset; - int locals_segment; /**< The local variable segment */ - LocalVariables *locals_block; - - Common::Array<CodeBlock> _codeBlocks; - int relocated; - bool _markedAsDeleted; - -public: - Script() { - nr = 0; - buf = NULL; - buf_size = 0; - script_size = 0; - heap_size = 0; - - synonyms = NULL; - heap_start = NULL; - export_table = NULL; - - obj_indices = NULL; - - locals_offset = 0; - locals_segment = 0; - locals_block = NULL; - - relocated = 0; - _markedAsDeleted = 0; - } - - ~Script() { - freeScript(); - } - - void freeScript(); - - virtual byte *dereference(reg_t pointer, int *size); - virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); - virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); - - // script lock operations - - /** Increments the number of lockers of this script by one. */ - void incrementLockers(); - - /** Decrements the number of lockers of this script by one. */ - void decrementLockers(); - - /** - * Retrieves the number of locks held on this script. - * @return the number of locks held on the previously identified script - */ - int getLockers() const; - - /** Sets the number of locks held on this script. */ - void setLockers(int lockers); - - /** - * Retrieves a pointer to the synonyms associated with this script - * @return pointer to the synonyms, in non-parsed format. - */ - byte *getSynonyms() const; - - /** - * 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); - - /** - * 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); - - - /** - * Copies a byte string into a script's heap representation. - * @param dst script-relative offset of the destination area - * @param src pointer to the data source location - * @param n number of bytes to copy - */ - void mcpyInOut(int dst, const void *src, size_t n); - - - /** - * 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 - * either unreachable (resulting in its eventual deletion) or reloaded (resulting - * in its data being updated). - */ - void markDeleted() { - _markedAsDeleted = true; - } - - /** - * Marks the script as not deleted. - */ - void unmarkDeleted() { - _markedAsDeleted = false; - } - - /** - * Determines whether the script is marked as being deleted. - */ - bool isMarkedAsDeleted() const { - return _markedAsDeleted; - } - - /** - * Retrieves a 16 bit value from within a script's heap representation. - * @param offset offset to read from - * @return the value read from the specified location - */ - int16 getHeap(uint16 offset) const; - -}; - -/** Data stack */ -struct DataStack : MemObject { - int nr; /**< Number of stack entries */ - reg_t *entries; - -public: - DataStack() { - nr = 0; - entries = NULL; - } - ~DataStack() { - free(entries); - entries = NULL; - } - - virtual byte *dereference(reg_t pointer, int *size); - virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - -#define CLONE_USED -1 -#define CLONE_NONE -1 - -typedef Object Clone; - -struct Node { - reg_t pred; /**< Predecessor node */ - reg_t succ; /**< Successor node */ - reg_t key; - reg_t value; -}; /* List nodes */ - -struct List { - reg_t first; - reg_t last; -}; - -struct Hunk { - void *mem; - unsigned int size; - const char *type; -}; - -template<typename T> -struct Table : public MemObject { - typedef T value_type; - struct Entry : public T { - int next_free; /* Only used for free entries */ - }; - enum { HEAPENTRY_INVALID = -1 }; - - - int first_free; /**< Beginning of a singly linked list for entries */ - int entries_used; /**< Statistical information */ - - Common::Array<Entry> _table; - -public: - Table() { - initTable(); - } - - void initTable() { - entries_used = 0; - first_free = HEAPENTRY_INVALID; - _table.clear(); - } - - int allocEntry() { - entries_used++; - if (first_free != HEAPENTRY_INVALID) { - int oldff = first_free; - first_free = _table[oldff].next_free; - - _table[oldff].next_free = oldff; - return oldff; - } else { - uint newIdx = _table.size(); - _table.push_back(Entry()); - _table[newIdx].next_free = newIdx; // Tag as 'valid' - return newIdx; - } - } - - bool isValidEntry(int idx) { - return idx >= 0 && (uint)idx < _table.size() && _table[idx].next_free == idx; - } - - virtual void freeEntry(int idx) { - if (idx < 0 || (uint)idx >= _table.size()) - ::error("Table::freeEntry: Attempt to release invalid table index %d", idx); - - _table[idx].next_free = first_free; - first_free = idx; - entries_used--; - } - - virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); -}; - - -/* CloneTable */ -struct CloneTable : public Table<Clone> { - virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - - -/* NodeTable */ -struct NodeTable : public Table<Node> { - virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - - -/* ListTable */ -struct ListTable : public Table<List> { - virtual void freeAtAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllOutgoingReferences(EngineState *s, reg_t object, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - - -/* HunkTable */ -struct HunkTable : public Table<Hunk> { - virtual void freeEntry(int idx) { - Table<Hunk>::freeEntry(idx); - - free(_table[idx].mem); - } - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; - - -// Free-style memory -struct DynMem : public MemObject { - int _size; - char *_description; - byte *_buf; - -public: - DynMem() : _size(0), _description(0), _buf(0) {} - ~DynMem() { - free(_description); - _description = NULL; - free(_buf); - _buf = NULL; - } - - virtual byte *dereference(reg_t pointer, int *size); - virtual reg_t findCanonicAddress(SegManager *segmgr, reg_t sub_addr); - virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); - - virtual void saveLoadWithSerializer(Common::Serializer &ser); -}; /** Contains selector IDs for a few selected selectors */ struct selector_map_t { @@ -769,13 +254,13 @@ enum BreakpointType { * Break when selector is executed. data contains (char *) selector name * (in the format Object::Method) */ - BREAK_SELECTOR = 1, + BREAK_SELECTOR, /** * Break when an exported function is called. data contains * script_no << 16 | export_no. */ - BREAK_EXPORT = 2 + BREAK_EXPORT }; struct Breakpoint { @@ -787,17 +272,17 @@ struct Breakpoint { Breakpoint *next; }; -#define SCRIPT_ABORT_WITH_REPLAY 1025 - /** * Set this to 1 to abort script execution immediately. Aborting will leave the * debug exec stack intact. - * Set it to SCRIPT_ABORT_WITH_REPLAY to force a replay afterwards. + * Set it to 2 to force a replay afterwards. */ extern int script_abort_flag; /** Number of kernel calls in between gcs; should be < 50000 */ -#define GC_INTERVAL 32768 +enum { + GC_INTERVAL = 32768 +}; /** Initially GC_DELAY, can be set at runtime */ extern int script_gc_interval; @@ -806,16 +291,6 @@ extern int script_gc_interval; extern int script_step_counter; -extern int _debugstate_valid; -extern int _debug_seeking; -extern int _debug_step_running; - - -typedef int kernel_function(struct EngineState *s); - -extern kernel_function* kfuncs[]; -extern int max_instance; - /** * Executes function pubfunct of the specified script. * Parameters: (EngineState *) s: The state which is to be executed with @@ -925,7 +400,7 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * ** Returns : (void) */ -int script_init_engine(EngineState *s, sci_version_t version); +int script_init_engine(EngineState *s); /* Initializes a EngineState block ** Parameters: (EngineState *) s: The state to initialize ** Returns : 0 on success, 1 if vocab.996 (the class table) is missing or corrupted diff --git a/engines/sci/gfx/gfx_driver.cpp b/engines/sci/gfx/gfx_driver.cpp index 2418f45824..fcac77245e 100644 --- a/engines/sci/gfx/gfx_driver.cpp +++ b/engines/sci/gfx/gfx_driver.cpp @@ -36,7 +36,6 @@ namespace Sci { struct _scummvm_driver_state { gfx_pixmap_t *priority[2]; byte *visual[2]; - uint8 *pointer_data; int xsize, ysize; }; @@ -53,7 +52,6 @@ static int scummvm_init(gfx_driver_t *drv, int xfact, int yfact, int bytespp) { S->xsize = xfact * 320; S->ysize = yfact * 200; - S->pointer_data = NULL; //S->buckystate = 0; for (i = 0; i < 2; i++) { @@ -94,9 +92,6 @@ static void scummvm_exit(gfx_driver_t *drv) { S->visual[i] = NULL; } - delete[] S->pointer_data; - S->pointer_data = NULL; - delete S; } } @@ -284,8 +279,7 @@ static int scummvm_set_pointer(gfx_driver_t *drv, gfx_pixmap_t *pointer, Common: if ((pointer == NULL) || (hotspot == NULL)) { g_system->showMouse(false); } else { - delete[] S->pointer_data; - S->pointer_data = create_cursor(drv, pointer, 1); + uint8 *cursorData = create_cursor(drv, pointer, 1); // FIXME: The palette size check is a workaround for cursors using non-palette colour GFX_CURSOR_TRANSPARENT // Note that some cursors don't have a palette in SQ5 @@ -297,8 +291,11 @@ static int scummvm_set_pointer(gfx_driver_t *drv, gfx_pixmap_t *pointer, Common: if (!pointer->palette) color_key = 63; - g_system->setMouseCursor(S->pointer_data, pointer->width, pointer->height, hotspot->x, hotspot->y, color_key); + g_system->setMouseCursor(cursorData, pointer->width, pointer->height, hotspot->x, hotspot->y, color_key); g_system->showMouse(true); + + delete[] cursorData; + cursorData = 0; } return GFX_OK; @@ -306,9 +303,6 @@ static int scummvm_set_pointer(gfx_driver_t *drv, gfx_pixmap_t *pointer, Common: gfx_driver_t gfx_driver_scummvm = { NULL, - 0, 0, - 0, - NULL, scummvm_init, scummvm_exit, scummvm_draw_line, diff --git a/engines/sci/gfx/gfx_driver.h b/engines/sci/gfx/gfx_driver.h index 254f619b34..47b5e7de21 100644 --- a/engines/sci/gfx/gfx_driver.h +++ b/engines/sci/gfx/gfx_driver.h @@ -38,10 +38,6 @@ enum gfx_buffer_t { }; -/* graphics driver hints */ -#define GFX_CAPABILITY_SHADING (1<<0) -#define GFX_CAPABILITY_STIPPLED_LINES (1<<6) - /* Principial graphics driver architecture ** --------------------------------------- ** @@ -71,38 +67,8 @@ struct gfx_driver_t { /* Graphics driver */ gfx_mode_t *mode; /* Currently active mode, NULL if no mode is active */ - int pointer_x, pointer_y; /* Mouse pointer position */ - - int capabilities; /* The driver's capabilities: A list of flags that may - ** be pre-defined or set after a successful initialization. - */ - /* Capability flags: - ** - ** The words MUST, SHOULD and MAY are to be interpreted as described in - ** the IETF RFC 1123. - ** - ** GFX_CAPABILITY_SHADING: draw_filled_rect() supports drawing shaded - ** rectangles. - ** GFX_CAPABILITY_STIPPLED_LINES: The driver is able to draw stippled lines - ** horizontally and vertically (xl = 0 or yl = 0). - */ - /*** Initialization ***/ - int (*set_parameter)(gfx_driver_t *drv, char *attribute, char *value); - /* Sets a driver-specific parameter - ** Parameters: (gfx_driver_t *) drv: Pointer to the affected driver - ** (char *) attribute: Name of the attribute/parameter to set - ** (char *) value: The value to set, or NULL to query the value - ** Returns : (int) GFX_OK or GFX_FATAL, which signals a fatal error - ** condition. - ** This function should make extensive use of sciprintf() to signal invalid - ** values or unapplicable attributes. - ** Note that it may be called either before initialization (to interpret - ** config file or command line parameters) or afterwars (from the command - ** console). - */ - int (*init)(gfx_driver_t *drv, int xres, int yres, int bytespp); /* Attempts to initialize a specific graphics mode diff --git a/engines/sci/gfx/gfx_widgets.cpp b/engines/sci/gfx/gfx_widgets.cpp index ad9464811e..e17ffae6f1 100644 --- a/engines/sci/gfx/gfx_widgets.cpp +++ b/engines/sci/gfx/gfx_widgets.cpp @@ -49,10 +49,8 @@ GfxWidget *debug_widgets[GFXW_DEBUG_WIDGETS]; int debug_widget_pos = 0; static void _gfxw_debug_add_widget(GfxWidget *widget) { - if (debug_widget_pos == GFXW_DEBUG_WIDGETS) { - GFXERROR("WIDGET DEBUG: Allocated the maximum number of %d widgets- Aborting!\n", GFXW_DEBUG_WIDGETS); - BREAKPOINT(); - } + if (debug_widget_pos == GFXW_DEBUG_WIDGETS) + error("WIDGET DEBUG: Allocated the maximum number of %d widgets- Aborting!\n", GFXW_DEBUG_WIDGETS); debug_widgets[debug_widget_pos++] = widget; } @@ -68,13 +66,11 @@ static void _gfxw_debug_remove_widget(GfxWidget *widget) { } if (found > 1) { - GFXERROR("While removing widget: Found it %d times!\n", found); - BREAKPOINT(); + error("While removing widget: Found it %d times!\n", found); } if (found == 0) { - GFXERROR("Attempted removal of unregistered widget!\n"); - BREAKPOINT(); + error("Attempted removal of unregistered widget!\n"); } } #else // !GFXW_DEBUG_WIDGETS diff --git a/engines/sci/gfx/gfx_widgets.h b/engines/sci/gfx/gfx_widgets.h index 5b43c2cad6..6c8e848664 100644 --- a/engines/sci/gfx/gfx_widgets.h +++ b/engines/sci/gfx/gfx_widgets.h @@ -51,7 +51,7 @@ struct GfxWidget; /* Enable the next line to keep a list of pointers to all widgets, with up to the specified amount ** of members (/SLOW/) */ -/* #define GFXW_DEBUG_WIDGETS 2048 */ +//#define GFXW_DEBUG_WIDGETS 2048 /* Our strategy for dirty rectangle management */ #define GFXW_DIRTY_STRATEGY GFXOP_DIRTY_FRAMES_CLUSTERS diff --git a/engines/sci/gfx/operations.cpp b/engines/sci/gfx/operations.cpp index 7ab1bc28cd..d9dc539c79 100644 --- a/engines/sci/gfx/operations.cpp +++ b/engines/sci/gfx/operations.cpp @@ -265,8 +265,9 @@ static int _gfxop_draw_pixmap(gfx_driver_t *driver, gfx_pixmap_t *pxm, int prior } static void _gfxop_full_pointer_refresh(GfxState *state) { - state->pointer_pos.x = state->driver->pointer_x / state->driver->mode->xfact; - state->pointer_pos.y = state->driver->pointer_y / state->driver->mode->yfact; + Common::Point mousePoint = g_system->getEventManager()->getMousePos(); + state->pointer_pos.x = mousePoint.x / state->driver->mode->xfact; + state->pointer_pos.y = mousePoint.y / state->driver->mode->yfact; } static int _gfxop_buffer_propagate_box(GfxState *state, rect_t box, gfx_buffer_t buffer); @@ -450,12 +451,6 @@ int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, return GFX_OK; } -int gfxop_set_parameter(GfxState *state, char *attribute, char *value) { - BASIC_CHECKS(GFX_FATAL); - - return state->driver->set_parameter(state->driver, attribute, value); -} - int gfxop_exit(GfxState *state) { BASIC_CHECKS(GFX_ERROR); @@ -822,8 +817,7 @@ static int _gfxop_draw_line_clipped(GfxState *state, Common::Point start, Common GFXWARN("Attempt to draw stippled line which is neither an hbar nor a vbar: (%d,%d) -- (%d,%d)\n", start.x, start.y, end.x, end.y); return GFX_ERROR; } - if (!(state->driver->capabilities & GFX_CAPABILITY_STIPPLED_LINES)) - return simulate_stippled_line_draw(state->driver, skipone, start, end, color, line_mode); + return simulate_stippled_line_draw(state->driver, skipone, start, end, color, line_mode); } if ((retval = state->driver->draw_line(state->driver, start, end, color, line_mode, line_style))) { @@ -923,8 +917,7 @@ int gfxop_draw_box(GfxState *state, rect_t box, gfx_color_t color1, gfx_color_t BASIC_CHECKS(GFX_FATAL); _gfxop_full_pointer_refresh(state); - if (PALETTE_MODE || !(state->driver->capabilities & GFX_CAPABILITY_SHADING)) - shade_type = GFX_BOX_SHADE_FLAT; + shade_type = GFX_BOX_SHADE_FLAT; _gfxop_add_dirty(state, box); @@ -1244,9 +1237,7 @@ int gfxop_set_pointer_position(GfxState *state, Common::Point pos) { return 0; // Not fatal } - state->driver->pointer_x = pos.x * state->driver->mode->xfact; - state->driver->pointer_y = pos.y * state->driver->mode->yfact; - g_system->warpMouse(state->driver->pointer_x, state->driver->pointer_y); + g_system->warpMouse(pos.x * state->driver->mode->xfact, pos.y * state->driver->mode->yfact); _gfxop_full_pointer_refresh(state); return 0; @@ -1326,28 +1317,8 @@ int _gfxop_shiftify(int c) { } } - switch (c) { - case SCI_K_F1 : - return SCI_K_SHIFT_F1; - case SCI_K_F2 : - return SCI_K_SHIFT_F2; - case SCI_K_F3 : - return SCI_K_SHIFT_F3; - case SCI_K_F4 : - return SCI_K_SHIFT_F4; - case SCI_K_F5 : - return SCI_K_SHIFT_F5; - case SCI_K_F6 : - return SCI_K_SHIFT_F6; - case SCI_K_F7 : - return SCI_K_SHIFT_F7; - case SCI_K_F8 : - return SCI_K_SHIFT_F8; - case SCI_K_F9 : - return SCI_K_SHIFT_F9; - case SCI_K_F10 : - return SCI_K_SHIFT_F10; - } + if (c >= SCI_K_F1 && c <= SCI_K_F10) + return c + 25; return c; } @@ -1393,8 +1364,6 @@ static sci_event_t scummvm_get_event(gfx_driver_t *drv) { // Don't generate events for mouse movement while (found && ev.type == Common::EVENT_MOUSEMOVE) { - drv->pointer_x = ev.mouse.x; - drv->pointer_y = ev.mouse.y; found = em->pollEvent(ev); } @@ -1488,7 +1457,7 @@ static sci_event_t scummvm_get_event(gfx_driver_t *drv) { // SCI_K_SHIFT_F1 == 84 << 8 input.data = SCI_K_F1 + ((input.data - Common::KEYCODE_F1)<<8); if (input.buckybits & (SCI_EVM_LSHIFT | SCI_EVM_RSHIFT)) - input.character = input.data + SCI_K_SHIFT_F1 - SCI_K_F1; + input.character = input.data + 25; else input.character = input.data; } else { @@ -1558,26 +1527,18 @@ static sci_event_t scummvm_get_event(gfx_driver_t *drv) { case Common::EVENT_LBUTTONDOWN: input.type = SCI_EVT_MOUSE_PRESS; input.data = 1; - drv->pointer_x = p.x; - drv->pointer_y = p.y; break; case Common::EVENT_RBUTTONDOWN: input.type = SCI_EVT_MOUSE_PRESS; input.data = 2; - drv->pointer_x = p.x; - drv->pointer_y = p.y; break; case Common::EVENT_LBUTTONUP: input.type = SCI_EVT_MOUSE_RELEASE; input.data = 1; - drv->pointer_x = p.x; - drv->pointer_y = p.y; break; case Common::EVENT_RBUTTONUP: input.type = SCI_EVT_MOUSE_RELEASE; input.data = 2; - drv->pointer_x = p.x; - drv->pointer_y = p.y; break; // Misc events diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index 2f4a443509..88af32c624 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -152,15 +152,6 @@ int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, ** to provide any useful graphics support */ -int gfxop_set_parameter(GfxState *state, char *attribute, char *value); -/* Sets a driver-specific parameter -** Parameters: (GfxState *) state: The state, encapsulating the driver object to manipulate -** (char *) attribute: The attribute to set -** (char *) value: The value the attribute should be set to -** Returns : (int) GFX_OK on success, GFX_FATAL on fatal error conditions triggered -** by the command -*/ - int gfxop_exit(GfxState *state); /* Deinitializes a currently active driver ** Parameters: (GfxState *) state: The state encapsulating the driver in question diff --git a/engines/sci/module.mk b/engines/sci/module.mk index f67d81e6e9..f2c58bcd8d 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -27,6 +27,7 @@ MODULE_OBJS = \ engine/ksound.o \ engine/kstring.o \ engine/message.o \ + engine/memobj.o \ engine/said.o \ engine/savegame.o \ engine/script.o \ diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index f9ae45b6cd..24b4d9beed 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -63,7 +63,7 @@ enum SolFlags { kSolFlagIsSigned = 1 << 3 }; -const char *sci_error_types[] = { +static const char *sci_error_types[] = { "No error", "I/O error", "Resource is empty (size 0)", @@ -78,7 +78,7 @@ const char *sci_error_types[] = { }; // These are the 20 resource types supported by SCI1.1 -const char *resourceTypeNames[] = { +static const char *resourceTypeNames[] = { "view", "pic", "script", "text", "sound", "memory", "vocab", "font", "cursor", "patch", "bitmap", "palette", "cdaudio", @@ -86,7 +86,7 @@ const char *resourceTypeNames[] = { "audio36", "sync36" }; -const char *resourceTypeSuffixes[] = { +static const char *resourceTypeSuffixes[] = { "v56", "p56", "scr", "tex", "snd", " ", "voc", "fon", "cur", "pat", "bit", "pal", "cda", "aud", "syn", @@ -97,13 +97,6 @@ const char *getResourceTypeName(ResourceType restype) { return resourceTypeNames[restype]; } -const char *getResourceTypeSuffix(ResourceType restype) { - return resourceTypeSuffixes[restype]; -} - -typedef int decomp_funct(Resource *result, Common::ReadStream &stream, int sci_version); -typedef void patch_sprintf_funct(char *string, Resource *res); - //-- Resource main functions -- Resource::Resource() { data = NULL; @@ -290,7 +283,7 @@ int sci0_get_compression_method(Common::ReadStream &stream) { return compressionMethod; } -int sci_test_view_type(ResourceManager *mgr) { +int ResourceManager::guessSciVersion() { Common::File file; char filename[MAXPATHLEN]; int compression; @@ -298,7 +291,7 @@ int sci_test_view_type(ResourceManager *mgr) { int i; for (i = 0; i < 1000; i++) { - res = mgr->testResource(kResourceTypeView, i); + res = testResource(kResourceTypeView, i); if (!res) continue; @@ -322,7 +315,7 @@ int sci_test_view_type(ResourceManager *mgr) { // Try the same thing with pics for (i = 0; i < 1000; i++) { - res = mgr->testResource(kResourceTypePic, i); + res = testResource(kResourceTypePic, i); if (!res) continue; @@ -442,14 +435,14 @@ ResourceManager::ResourceManager(int version, int maxMemory) { switch (_mapVersion) { case SCI_VERSION_0: if (testResource(kResourceTypeVocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB)) { - version = sci_test_view_type(this) ? SCI_VERSION_01_VGA : SCI_VERSION_0; + version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0; } else if (testResource(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB)) { - version = sci_test_view_type(this); + version = guessSciVersion(); if (version != SCI_VERSION_01_VGA) { version = testResource(kResourceTypeVocab, 912) ? SCI_VERSION_0 : SCI_VERSION_01; } } else { - version = sci_test_view_type(this) ? SCI_VERSION_01_VGA : SCI_VERSION_0; + version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0; } break; case SCI_VERSION_01_VGA_ODD: @@ -586,7 +579,7 @@ void ResourceManager::freeOldResources(int last_invulnerable) { } } -Resource *ResourceManager::findResource(ResourceType type, int number, int lock) { +Resource *ResourceManager::findResource(ResourceType type, int number, bool lock) { Resource *retval; if (number >= sci_max_resource_nr[_sciVersion]) { @@ -863,7 +856,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) { SearchMan.listMatchingMembers(files, mask); // SCI1 and later naming - nnn.typ mask = "*."; - mask += getResourceTypeSuffix((ResourceType)i); + mask += resourceTypeSuffixes[i]; SearchMan.listMatchingMembers(files, mask); for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); x++) { bAdd = false; @@ -1178,7 +1171,7 @@ void ResourceSync::stopSync() { AudioResource::AudioResource(ResourceManager *resMgr, int sciVersion) { _resMgr = resMgr; _sciVersion = sciVersion; - _audioRate = 0; + _audioRate = 11025; _lang = 0; _audioMapSCI1 = 0; _audioMapSCI11 = 0; @@ -1238,7 +1231,7 @@ bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &o return false; byte *ptr = _audioMapSCI1; - while ((n = READ_UINT16(ptr)) != 0xFFFF) { + while ((n = READ_LE_UINT16(ptr)) != 0xFFFF) { if (n == audioNumber) { off = READ_LE_UINT32(ptr + 2); size = READ_LE_UINT32(ptr + 6); @@ -1252,14 +1245,8 @@ bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &o return false; } -bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync, uint32 *size) { - // 65535.MAP structure: - // ========= - // 6 byte entries: - // w nEntry - // dw offset - - // Other map files: +bool AudioResource::findAudEntrySCI11Late(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size) { + // Map structure: // =============== // Header: // dw baseOffset @@ -1269,8 +1256,116 @@ bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 // b cond // b seq // tb cOffset (cumulative offset) - // w syncSize (iff seq has bits 7 and 6 set) - // w syncAscSize (iff seq has bits 7 and 6 set) + // w syncSize (iff seq has bit 7 set) + // w syncAscSize (iff seq has bit 6 set) + + uint32 n; + offset = 0; + + byte *ptr = _audioMapSCI11->data; + + offset = READ_LE_UINT32(ptr); + ptr += 4; + + while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) { + n = READ_BE_UINT32(ptr); + ptr += 4; + + if (n == 0xffffffff) + break; + + offset += READ_LE_UINT24(ptr); + ptr += 3; + + int syncSkip = 0; + + if (n & 0x80) { + n ^= 0x80; + + if (getSync) { + if (size) + *size = READ_LE_UINT16(ptr); + } else { + syncSkip = READ_LE_UINT16(ptr); + } + + ptr += 2; + + if (n & 0x40) { + n ^= 0x40; + + if (!getSync) + syncSkip += READ_LE_UINT16(ptr); + + ptr += 2; + } + + offset += syncSkip; + + if (n == audioNumber) + return true; + + } else { + if (n == audioNumber) + return !getSync; + } + + offset -= syncSkip; + } + + return false; +} + +bool AudioResource::findAudEntrySCI11Early(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size) { + // Map structure: + // =============== + // 10-byte entries: + // b noun + // b verb + // b cond + // b seq + // dw offset + // w syncSize + syncAscSize + + uint32 n; + offset = 0; + + byte *ptr = _audioMapSCI11->data; + + while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) { + n = READ_BE_UINT32(ptr); + ptr += 4; + + if (n == 0xffffffff) + break; + + offset = READ_LE_UINT32(ptr); + ptr += 4; + + int syncSize = READ_LE_UINT16(ptr); + ptr += 2; + + if (n == audioNumber) { + if (getSync) { + if (size) + *size = syncSize; + return true; + } else { + offset += syncSize; + return true; + } + } + } + + return false; +} + +bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync, uint32 *size) { + // 65535.MAP structure: + // ========= + // 6 byte entries: + // w nEntry + // dw offset uint32 n; offset = 0; @@ -1288,65 +1383,93 @@ bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 if (volume == 65535) { while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) { - n = READ_UINT16(ptr); + n = READ_LE_UINT16(ptr); ptr += 2; if (n == 0xffff) break; - offset = READ_UINT32(ptr); + offset = READ_LE_UINT32(ptr); ptr += 4; if (n == audioNumber) return true; } } else { - offset = READ_UINT32(ptr); - ptr += 4; + // In early SCI1.1 the map is terminated with 10x 0xff, in late SCI1.1 + // with 11x 0xff. If we look at the 11th last byte in an early SCI1.1 + // map, this will be the high byte of the Sync length of the last entry. + // As Sync resources are relative small, we should never encounter a + // Sync with a size of 0xffnn. As such, the following heuristic should be + // sufficient to tell these map formats apart. + if (_audioMapSCI11->size >= 11 && (ptr[_audioMapSCI11->size - 11] == 0xff)) + return findAudEntrySCI11Late(audioNumber, offset, getSync, size); + else { + return findAudEntrySCI11Early(audioNumber, offset, getSync, size); + } + } - while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) { - n = READ_BE_UINT32(ptr); - ptr += 4; + return false; +} - if (n == 0xffffffff) - break; +// FIXME: Move this to sound/adpcm.cpp? +// Note that the 16-bit version is also used in coktelvideo.cpp +static const uint16 tableDPCM16[128] = { + 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, + 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, + 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, + 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, + 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, + 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, + 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, + 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, + 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, + 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, + 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, + 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, + 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 +}; - offset += (READ_UINT16(ptr) | (ptr[2] << 16)); - ptr += 3; +static const byte tableDPCM8[8] = {0, 1, 2, 3, 6, 10, 15, 21}; - int syncSkip = 0; +static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { + int16 *out = (int16 *) soundBuf; - if ((n & 0xc0) == 0xc0) { - n ^= 0xc0; + int32 s = 0; + for (uint32 i = 0; i < n; i++) { + byte b = audioStream.readByte(); + if (b & 0x80) + s -= tableDPCM16[b & 0x7f]; + else + s += tableDPCM16[b]; - if (getSync) { - if (size) - *size = READ_UINT16(ptr); - } else { - syncSkip = READ_UINT16(ptr) + READ_UINT16(ptr + 2); - offset += syncSkip; - } + s = CLIP<int32>(s, -32768, 32767); + *out++ = TO_BE_16(s); + } +} - if (n == audioNumber) - return true; +static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) { + if (b & 8) + s -= tableDPCM8[7 - (b & 7)]; + else + s += tableDPCM8[b & 7]; + s = CLIP<int32>(s, 0, 255); + *soundBuf = s; +} - ptr += 4; - } else { - if (n == audioNumber) - return !getSync; - } +static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { + int32 s = 0x80; - offset -= syncSkip; - } - } + for (uint i = 0; i < n; i++) { + byte b = audioStream.readByte(); - return false; + deDPCM8Nibble(soundBuf++, s, b >> 4); + deDPCM8Nibble(soundBuf++, s, b & 0xf); + } } // Sierra SOL audio file reader // Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio -// TODO: improve this for later versions of the format, as this currently only reads -// raw PCM encoded files (not ADPCM compressed ones) byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16 *audioRate, byte *flags) { byte audioFlags; byte type = audioStream->readByte(); @@ -1357,6 +1480,12 @@ byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16 } int headerSize = audioStream->readByte(); + + if (headerSize != 11 && headerSize != 12) { + warning("SOL audio header of size %i not supported", headerSize); + return NULL; + } + audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes) *audioRate = audioStream->readUint16LE(); audioFlags = audioStream->readByte(); @@ -1365,36 +1494,25 @@ byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16 *flags = 0; if (audioFlags & kSolFlag16Bit) *flags |= Audio::Mixer::FLAG_16BITS; - if ((audioFlags & kSolFlagCompressed) || !(audioFlags & kSolFlagIsSigned)) + if (!(audioFlags & kSolFlagIsSigned)) *flags |= Audio::Mixer::FLAG_UNSIGNED; - *size = audioStream->readUint16LE(); + *size = audioStream->readUint32LE(); - if (headerSize == 12) - *size |= audioStream->readByte() << 16; + if (headerSize == 12) { + // Unknown byte + audioStream->readByte(); + } byte *buffer; if (audioFlags & kSolFlagCompressed) { - if (audioFlags & kSolFlag16Bit) { - warning("Unsupported DPCM mode"); - return NULL; - } - buffer = new byte[*size * 2]; - byte sample = 0x80; - - for (uint i = 0; i < *size; i++) { - const int delta[] = {0, 1, 2, 3, 6, 10, 15, 21, -21, -15, -10, -6, -3, -2, -1, -0}; - - byte b = audioStream->readByte(); - - sample += delta[b >> 4]; - buffer[i * 2] = sample; - sample += delta[b & 0xf]; - buffer[i * 2 + 1] = sample; - } + if (audioFlags & kSolFlag16Bit) + deDPCM16(buffer, *audioStream, *size); + else + deDPCM8(buffer, *audioStream, *size); *size *= 2; } else { @@ -1498,7 +1616,10 @@ Audio::AudioStream* AudioResource::getAudioStream(uint32 audioNumber, uint32 vol } } - *sampleLen = size * 60 / _audioRate; + *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate; + } else { + warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (audioNumber >> 24) & 0xff, + (audioNumber >> 16) & 0xff, (audioNumber >> 8) & 0xff, audioNumber & 0xff); } return audioStream; diff --git a/engines/sci/resource.h b/engines/sci/resource.h index a693f696db..eade4acbd0 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -88,7 +88,6 @@ enum ResSourceType { #define SCI1_RESMAP_ENTRIES_SIZE 6 #define SCI11_RESMAP_ENTRIES_SIZE 5 -extern const char *sci_error_types[]; extern const char *sci_version_types[]; extern const int sci_max_resource_nr[]; /**< Highest possible resource numbers */ @@ -118,8 +117,6 @@ enum ResourceType { }; const char *getResourceTypeName(ResourceType restype); -// Suffixes for SCI1 patch files -const char *getResourceTypeSuffix(ResourceType restype); #define sci0_last_resource kResourceTypePatch #define sci1_last_resource kResourceTypeHeap @@ -141,8 +138,11 @@ struct ResourceSource { ResourceSource *next; }; +class ResourceManager; + /** Class for storing resources in memory */ class Resource { + friend class ResourceManager; public: Resource(); ~Resource(); @@ -155,10 +155,11 @@ public: uint16 number; ResourceType type; uint32 id; //!< contains number and type. - unsigned int size; - unsigned int file_offset; /**< Offset in file */ + uint32 size; +protected: + uint32 file_offset; /**< Offset in file */ ResourceStatus status; - unsigned short lockers; /**< Number of places where this resource was locked */ + uint16 lockers; /**< Number of places where this resource was locked */ ResourceSource *source; }; @@ -191,7 +192,7 @@ public: * @note Locked resources are guaranteed not to have their contents freed until * they are unlocked explicitly (by unlockResource). */ - Resource *findResource(ResourceType type, int number, int lock); + Resource *findResource(ResourceType type, int number, bool lock); /* Unlocks a previously locked resource ** (Resource *) res: The resource to free @@ -291,6 +292,8 @@ protected: void printLRU(); void addToLRU(Resource *res); void removeFromLRU(Resource *res); + + int guessSciVersion(); }; /** @@ -343,6 +346,8 @@ private: bool findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size); bool findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync = false, uint32 *size = NULL); + bool findAudEntrySCI11Late(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size); + bool findAudEntrySCI11Early(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size); }; } // End of namespace Sci diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index eb75beab8f..8083ddad73 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -124,11 +124,10 @@ Common::Error SciEngine::run() { // FIXME/TODO: Move some of the stuff below to init() - sci_version_t version; + const sci_version_t version = getVersion(); + const uint32 flags = getFlags(); int res_version = getResourceVersion(); - version = getVersion(); - _resmgr = new ResourceManager(res_version, 256 * 1024); if (!_resmgr) { @@ -144,37 +143,34 @@ Common::Error SciEngine::run() { map_MIDI_instruments(_resmgr); #endif - _gamestate = new EngineState(); - _gamestate->resmgr = _resmgr; - _gamestate->gfx_state = NULL; - _gamestate->flags = getFlags(); + _gamestate = new EngineState(_resmgr, version, flags); // Verify that we haven't got an invalid game detection entry if (version < SCI_VERSION_1_EARLY) { // SCI0/SCI01 - if (_gamestate->flags & GF_SCI1_EGA || - _gamestate->flags & GF_SCI1_LOFSABSOLUTE || - _gamestate->flags & GF_SCI1_NEWDOSOUND) { + if (flags & GF_SCI1_EGA || + flags & GF_SCI1_LOFSABSOLUTE || + flags & GF_SCI1_NEWDOSOUND) { error("This game entry is erroneous. It's marked as SCI0/SCI01, but it has SCI1 flags set"); } } else if (version >= SCI_VERSION_1_EARLY && version <= SCI_VERSION_1_LATE) { // SCI1 - if (_gamestate->flags & GF_SCI0_OLD || - _gamestate->flags & GF_SCI0_OLDGFXFUNCS || - _gamestate->flags & GF_SCI0_OLDGETTIME) { + if (flags & GF_SCI0_OLD || + flags & GF_SCI0_OLDGFXFUNCS || + flags & GF_SCI0_OLDGETTIME) { error("This game entry is erroneous. It's marked as SCI1, but it has SCI0 flags set"); } } else if (version == SCI_VERSION_1_1 || version == SCI_VERSION_32) { - if (_gamestate->flags & GF_SCI1_EGA || - _gamestate->flags & GF_SCI1_LOFSABSOLUTE || - _gamestate->flags & GF_SCI1_NEWDOSOUND) { + if (flags & GF_SCI1_EGA || + flags & GF_SCI1_LOFSABSOLUTE || + flags & GF_SCI1_NEWDOSOUND) { error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI1 flags set"); } - if (_gamestate->flags & GF_SCI0_OLD || - _gamestate->flags & GF_SCI0_OLDGFXFUNCS || - _gamestate->flags & GF_SCI0_OLDGETTIME) { + if (flags & GF_SCI0_OLD || + flags & GF_SCI0_OLDGFXFUNCS || + flags & GF_SCI0_OLDGETTIME) { error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI0 flags set"); } @@ -183,7 +179,7 @@ Common::Error SciEngine::run() { error ("Unknown SCI version in game entry"); } - if (script_init_engine(_gamestate, version)) + if (script_init_engine(_gamestate)) return Common::kUnknownError; diff --git a/engines/sci/sfx/core.cpp b/engines/sci/sfx/core.cpp index f4e07d3b84..7e3395b7d3 100644 --- a/engines/sci/sfx/core.cpp +++ b/engines/sci/sfx/core.cpp @@ -807,14 +807,14 @@ void SfxState::sfx_add_song(SongIterator *it, int priority, song_handle_t handle setSongStatus( song, SOUND_STATUS_STOPPED); fprintf(stderr, "Overwriting old song (%08lx) ...\n", handle); - if (song->status == SOUND_STATUS_PLAYING - || song->status == SOUND_STATUS_SUSPENDED) { + if (song->status == SOUND_STATUS_PLAYING || song->status == SOUND_STATUS_SUSPENDED) { delete it; error("Unexpected (error): Song %ld still playing/suspended (%d)", handle, song->status); return; - } else + } else { song_lib_remove(_songlib, handle); /* No duplicates */ + } } diff --git a/engines/sci/uinput.h b/engines/sci/uinput.h index 165396a889..062265186b 100644 --- a/engines/sci/uinput.h +++ b/engines/sci/uinput.h @@ -72,17 +72,20 @@ struct sci_event_t { #define SCI_K_TAB '\t' #define SCI_K_SHIFT_TAB (0xf << 8) -#define SCI_K_END (79 << 8) -#define SCI_K_DOWN (80 << 8) -#define SCI_K_PGDOWN (81 << 8) -#define SCI_K_LEFT (75 << 8) -#define SCI_K_CENTER (76 << 8) -#define SCI_K_RIGHT (77 << 8) -#define SCI_K_HOME (71 << 8) -#define SCI_K_UP (72 << 8) -#define SCI_K_PGUP (73 << 8) -#define SCI_K_INSERT (82 << 8) -#define SCI_K_DELETE (83 << 8) +#define SCI_K_HOME (71 << 8) // 7 +#define SCI_K_UP (72 << 8) // 8 +#define SCI_K_PGUP (73 << 8) // 9 +// +#define SCI_K_LEFT (75 << 8) // 4 +#define SCI_K_CENTER (76 << 8) // 5 +#define SCI_K_RIGHT (77 << 8) // 6 +// +#define SCI_K_END (79 << 8) // 1 +#define SCI_K_DOWN (80 << 8) // 2 +#define SCI_K_PGDOWN (81 << 8) // 3 +// +#define SCI_K_INSERT (82 << 8) // 0 +#define SCI_K_DELETE (83 << 8) // . #define SCI_K_F1 (59<<8) #define SCI_K_F2 (60<<8) @@ -95,17 +98,6 @@ struct sci_event_t { #define SCI_K_F9 (67<<8) #define SCI_K_F10 (68<<8) -#define SCI_K_SHIFT_F1 (84<<8) -#define SCI_K_SHIFT_F2 (85<<8) -#define SCI_K_SHIFT_F3 (86<<8) -#define SCI_K_SHIFT_F4 (87<<8) -#define SCI_K_SHIFT_F5 (88<<8) -#define SCI_K_SHIFT_F6 (89<<8) -#define SCI_K_SHIFT_F7 (90<<8) -#define SCI_K_SHIFT_F8 (91<<8) -#define SCI_K_SHIFT_F9 (92<<8) -#define SCI_K_SHIFT_F10 (93<<8) - /*Values for buckybits */ #define SCI_EVM_RSHIFT (1<<0) #define SCI_EVM_LSHIFT (1<<1) diff --git a/engines/sci/vocabulary.cpp b/engines/sci/vocabulary.cpp index 216ab211be..b12114d845 100644 --- a/engines/sci/vocabulary.cpp +++ b/engines/sci/vocabulary.cpp @@ -93,7 +93,7 @@ Vocabulary::Vocabulary(ResourceManager *resmgr) : _resmgr(resmgr) { if (_resmgr->_sciVersion < SCI_VERSION_01_VGA && loadParserWords()) { loadSuffixes(); - if (getBranches()) + if (loadBranches()) // Now build a GNF grammar out of this _parserRules = buildGNF(); } else { @@ -241,13 +241,13 @@ void Vocabulary::freeSuffixes() { else resource = _resmgr->findResource(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_SUFFIX_VOCAB, 0); - if (resource && resource->status == kResStatusLocked) + if (resource) _resmgr->unlockResource(resource, resource->number, kResourceTypeVocab); _parserSuffixes.clear(); } -bool Vocabulary::getBranches() { +bool Vocabulary::loadBranches() { Resource *resource = NULL; if (_vocabVersion == kVocabularySCI0) diff --git a/engines/sci/vocabulary.h b/engines/sci/vocabulary.h index c8ed146917..9f0d277ef2 100644 --- a/engines/sci/vocabulary.h +++ b/engines/sci/vocabulary.h @@ -278,7 +278,7 @@ private: * @param branches The rules are stored into this Array * @return true on success, false on error */ - bool getBranches(); + bool loadBranches(); /* Frees a parser rule list as returned by vocab_build_gnf() ** Parameters: (parse_rule_list_t *) rule_list: The rule list to free diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index 90f2764b3d..fc27c338b2 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -2507,7 +2507,7 @@ void ScummEngine_v100he::o100_getWizData() { x = pop(); state = pop(); resId = pop(); - push(_wiz->getWizPixelColor(resId, state, x, y, 0)); + push(_wiz->getWizPixelColor(resId, state, x, y)); break; case 26: resId = pop(); diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp index c6b919f554..7a7a1ff58b 100644 --- a/engines/scumm/he/script_v90he.cpp +++ b/engines/scumm/he/script_v90he.cpp @@ -1300,7 +1300,7 @@ void ScummEngine_v90he::o90_getWizData() { x = pop(); state = pop(); resId = pop(); - push(_wiz->getWizPixelColor(resId, state, x, y, 0)); + push(_wiz->getWizPixelColor(resId, state, x, y)); break; case 130: h = pop(); diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp index c5a8988edb..67248f4c22 100644 --- a/engines/scumm/he/sound_he.cpp +++ b/engines/scumm/he/sound_he.cpp @@ -158,6 +158,7 @@ void SoundHE::stopSound(int sound) { if (_heChannel[i].sound == sound) { _heChannel[i].sound = 0; _heChannel[i].priority = 0; + _heChannel[i].rate = 0; _heChannel[i].timer = 0; _heChannel[i].sbngBlock = 0; _heChannel[i].codeOffs = 0; @@ -196,6 +197,7 @@ void SoundHE::stopSoundChannel(int chan) { _heChannel[chan].sound = 0; _heChannel[chan].priority = 0; + _heChannel[chan].rate = 0; _heChannel[chan].timer = 0; _heChannel[chan].sbngBlock = 0; _heChannel[chan].codeOffs = 0; @@ -254,7 +256,7 @@ int SoundHE::getSoundPos(int sound) { } if (_mixer->isSoundHandleActive(_heSoundChannels[chan]) && chan != -1) { - int time = _vm->getHETimer(chan + 4) * 11025 / 1000; + int time = _vm->getHETimer(chan + 4) * _heChannel[chan].rate / 1000; return time; } else { return 0; @@ -360,7 +362,7 @@ void SoundHE::processSoundCode() { continue; } - tmr = _vm->getHETimer(chan + 4) * 11025 / 1000; + tmr = _vm->getHETimer(chan + 4) * _heChannel[chan].rate / 1000; tmr += _vm->VAR(_vm->VAR_SOUNDCODE_TMR); if (tmr < 0) tmr = 0; @@ -407,6 +409,7 @@ void SoundHE::processSoundCode() { _heChannel[chan].sound = 0; _heChannel[chan].priority = 0; + _heChannel[chan].rate = 0; _heChannel[chan].timer = 0; _heChannel[chan].sbngBlock = 0; _heChannel[chan].codeOffs = 0; @@ -625,6 +628,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) _vm->setHETimer(heChannel + 4); _heChannel[heChannel].sound = soundID; _heChannel[heChannel].priority = priority; + _heChannel[heChannel].rate = rate; _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0; _heChannel[heChannel].codeOffs = codeOffs; memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars)); @@ -646,6 +650,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) size *= 2; // 16bits. delete voxStream; + _heChannel[heChannel].rate = rate; if (_heChannel[heChannel].timer) _heChannel[heChannel].timer = size * 1000 / rate; @@ -696,6 +701,7 @@ void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) _vm->setHETimer(heChannel + 4); _heChannel[heChannel].sound = soundID; _heChannel[heChannel].priority = priority; + _heChannel[heChannel].rate = rate; _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0; _heChannel[heChannel].codeOffs = codeOffs; memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars)); diff --git a/engines/scumm/he/sound_he.h b/engines/scumm/he/sound_he.h index 47ff145e6b..f3a881972e 100644 --- a/engines/scumm/he/sound_he.h +++ b/engines/scumm/he/sound_he.h @@ -53,6 +53,7 @@ public: // Used by createSound() int sound; int codeOffs; int priority; + int rate; int timer; int sbngBlock; int soundVars[27]; diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp index 1e694ff067..aed03f746b 100644 --- a/engines/scumm/he/sprite_he.cpp +++ b/engines/scumm/he/sprite_he.cpp @@ -151,6 +151,7 @@ int Sprite::findSpriteWithClassOf(int x_pos, int y_pos, int spriteGroupId, int t if (spi->maskImage) { int32 x1, x2, y1, y2; + image = spi->maskImage; imageState = spi->curImageState % _vm->_wiz->getWizImageStates(spi->maskImage); pos[0].x = x_pos - spi->pos.x; diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp index e91eb48cd4..8bc196ee08 100644 --- a/engines/scumm/he/wiz_he.cpp +++ b/engines/scumm/he/wiz_he.cpp @@ -2399,7 +2399,7 @@ int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags return ret; } -uint8 Wiz::getWizPixelColor(int resNum, int state, int x, int y, int flags) { +uint16 Wiz::getWizPixelColor(int resNum, int state, int x, int y) { uint16 color = 0; uint8 *data = _vm->getResourceAddress(rtImage, resNum); assert(data); diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h index 0a320e2426..4a5dd74e38 100644 --- a/engines/scumm/he/wiz_he.h +++ b/engines/scumm/he/wiz_he.h @@ -188,7 +188,7 @@ public: void getWizImageDim(int resNum, int state, int32 &w, int32 &h); int getWizImageStates(int resnum); int isWizPixelNonTransparent(int resnum, int state, int x, int y, int flags); - uint8 getWizPixelColor(int resnum, int state, int x, int y, int flags); + uint16 getWizPixelColor(int resnum, int state, int x, int y); int getWizImageData(int resNum, int state, int type); void flushWizBuffer(); |