void ScummEngine_v0::o_doSentence() { byte verb = fetchScriptByte(); int obj, obj2; byte b; b = fetchScriptByte(); if (b == 0xFF) { obj = _cmdObject2; } else if (b == 0xFE) { obj = _cmdObject; } else { obj = OBJECT_V0(b, (_opcode & 0x80) ? kObjectV0TypeBG : kObjectV0TypeFG); } b = fetchScriptByte(); if (b == 0xFF) { obj2 = _cmdObject2; } else if (b == 0xFE) { obj2 = _cmdObject; } else { obj2 = OBJECT_V0(b, (_opcode & 0x40) ? kObjectV0TypeBG : kObjectV0TypeFG); } doSentence(verb, obj, obj2); }
void ScummEngine_v2::decodeParseString() { byte buffer[512]; byte *ptr = buffer; byte c; bool insertSpace = false; while ((c = fetchScriptByte())) { insertSpace = (c & 0x80) != 0; c &= 0x7f; if (c < 8) { // Special codes as seen in CHARSET_1 etc. My guess is that they // have a similar function as the corresponding embedded stuff in modern // games. Hence for now we convert them to the modern format. // This might allow us to reuse the existing code. *ptr++ = 0xFF; *ptr++ = c; if (c > 3) { *ptr++ = fetchScriptByte(); *ptr++ = 0; } } else *ptr++ = c; if (insertSpace) *ptr++ = ' '; } *ptr = 0; int textSlot = 0; _string[textSlot].xpos = 0; _string[textSlot].ypos = 0; _string[textSlot].right = _screenWidth - 1; _string[textSlot].center = false; _string[textSlot].overhead = false; if (_game.id == GID_MANIAC && _actorToPrintStrFor == 0xFF) { if (_game.platform == Common::kPlatformC64) { _string[textSlot].color = 14; } else if (_game.features & GF_DEMO) { _string[textSlot].color = (_game.version == 2) ? 15 : 1; } } actorTalk(buffer); }
void ScummEngine_v71he::o71_polygonOps() { int vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y; int id, fromId, toId; bool flag; byte subOp = fetchScriptByte(); switch (subOp) { case 68: // HE 100 case 69: // HE 100 case 246: case 248: vert4y = pop(); vert4x = pop(); vert3y = pop(); vert3x = pop(); vert2y = pop(); vert2x = pop(); vert1y = pop(); vert1x = pop(); flag = (subOp == 69 || subOp == 248); id = pop(); _wiz->polygonStore(id, flag, vert1x, vert1y, vert2x, vert2y, vert3x, vert3y, vert4x, vert4y); break; case 28: // HE 100 case 247: toId = pop(); fromId = pop(); _wiz->polygonErase(fromId, toId); break; default: error("o71_polygonOps: default case %d", subOp); } }
void ScummEngine_v0::decodeParseString() { byte buffer[512]; byte *ptr = buffer; byte c; bool insertSpace = false; while ((c = fetchScriptByte())) { insertSpace = (c & 0x80) != 0; c &= 0x7f; if (c == '/') { *ptr++ = 13; } else { *ptr++ = c; } if (insertSpace) *ptr++ = ' '; } *ptr = 0; int textSlot = 0; _string[textSlot].xpos = 0; _string[textSlot].ypos = 0; _string[textSlot].right = _screenWidth - 1; _string[textSlot].center = false; _string[textSlot].overhead = false; if (_actorToPrintStrFor == 0xFF) _string[textSlot].color = 14; actorTalk(buffer); }
void ScummEngine_v0::o_animateActor() { int act = getVarOrDirectByte(PARAM_1); int anim = getVarOrDirectByte(PARAM_2); int8 repeat = (int8) fetchScriptByte(); Actor_v0 *a = (Actor_v0*) derefActor(act, "o_animateActor"); a->_animFrameRepeat = repeat; switch (anim) { case 0xFE: // 0x6993 a->_speaking = 0x80; // Enabled, but not switching return; case 0xFD: // 0x69A3 a->_speaking = 0x00; return; case 0xFF: a->stopActorMoving(); return; } a->animateActor(anim); }
void ScummEngine_v70he::o70_isResourceLoaded() { // Reports percentage of resource loaded by queue int type; byte subOp = fetchScriptByte(); /* int idx = */ pop(); switch (subOp) { case 18: type = rtImage; break; case 226: type = rtRoom; break; case 227: type = rtCostume; break; case 228: type = rtSound; break; case 229: type = rtScript; break; default: error("o70_isResourceLoaded: default case %d", subOp); } push(100); }
void ScummEngine_v70he::o70_startSound() { int var, value; byte subOp = fetchScriptByte(); switch (subOp) { case 9: _heSndFlags |= 4; break; case 23: value = pop(); var = pop(); _heSndSoundId = pop(); ((SoundHE *)_sound)->setSoundVar(_heSndSoundId, var, value); break; case 25: value = pop(); _heSndSoundId = pop(); _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); case 56: _heSndFlags |= 16; break; case 164: _heSndFlags |= 2; break; case 222: // WORKAROUND: For errors in room script 240 (room 4) of maze break; case 224: _heSndSoundFreq = pop(); break; case 230: _heSndChannel = pop(); break; case 231: _heSndOffset = pop(); break; case 232: _heSndSoundId = pop(); _heSndOffset = 0; _heSndSoundFreq = 11025; _heSndChannel = VAR(VAR_SOUND_CHANNEL); break; case 245: _heSndFlags |= 1; break; case 255: _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); _heSndFlags = 0; break; default: error("o70_startSound invalid case %d", subOp); } }
void ScummEngine_v0::o_loadRoomWithEgo() { Actor_v0 *a; int obj, room, x, y, dir; obj = fetchScriptByte(); room = fetchScriptByte(); a = (Actor_v0 *)derefActor(VAR(VAR_EGO), "o_loadRoomWithEgo"); //0x634F if (a->_miscflags & kActorMiscFlagFreeze) { stopObjectCode(); return; } // The original interpreter sets the actors new room X/Y to the last rooms X/Y // This fixes a problem with MM: script 158 in room 12, the 'Oomph!' script // This scripts runs before the actor position is set to the correct room entry location a->putActor(a->getPos().x, a->getPos().y, room); _egoPositioned = false; startScene(a->_room, a, obj); getObjectXYPos(obj, x, y, dir); AdjustBoxResult r = a->adjustXYToBeInBox(x, y); x = r.x; y = r.y; a->putActor(x, y, _currentRoom); camera._dest.x = camera._cur.x = a->getPos().x; setCameraAt(a->getPos().x, a->getPos().y); setCameraFollows(a); _fullRedraw = true; resetSentence(); if (x >= 0 && y >= 0) { a->startWalkActor(x, y, -1); } }
void ScummEngine_v0::o_setObjectName() { int obj; int objId = fetchScriptByte(); if (!objId) { obj = _cmdObject; } else { if (_opcode & 0x80) obj = OBJECT_V0(objId, kObjectV0TypeBG); else obj = OBJECT_V0(objId, kObjectV0TypeFG); } setObjectName(obj); }
void ScummEngine_v0::o_walkActorToObject() { int actor = getVarOrDirectByte(PARAM_1); int objId = fetchScriptByte(); int obj; if (_opcode & 0x40) obj = OBJECT_V0(objId, kObjectV0TypeBG); else obj = OBJECT_V0(objId, kObjectV0TypeFG); if (whereIsObject(obj) != WIO_NOT_FOUND) { walkActorToObject(actor, obj); } }
void ScummEngine_v2::o2_setObjPreposition() { int obj = getVarOrDirectWord(PARAM_1); int unk = fetchScriptByte(); if (_game.platform == Common::kPlatformNES) return; if (whereIsObject(obj) != WIO_NOT_FOUND) { // FIXME: this might not work properly the moment we save and restore the game. byte *ptr = getOBCDFromObject(obj) + 12; *ptr &= 0x1F; *ptr |= unk << 5; } }
void ScummEngine_v70he::o70_systemOps() { byte *src, string[256]; int id, len; byte subOp = fetchScriptByte(); switch (subOp) { case 158: restart(); break; case 160: // Confirm shutdown quitGame(); break; case 244: quitGame(); break; case 250: id = pop(); src = getStringAddress(id); len = resStrLen(src) + 1; memcpy(string, src, len); debug(0, "Start executable (%s)", string); break; case 251: convertMessageToString(_scriptPointer, string, sizeof(string)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; debug(0, "Start executable (%s)", string); break; case 252: convertMessageToString(_scriptPointer, string, sizeof(string)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; debug(0, "Start game (%s)", string); break; case 253: id = pop(); src = getStringAddress(id); len = resStrLen(src) + 1; memcpy(string, src, len); debug(0, "Start game (%s)", string); break; default: error("o70_systemOps invalid case %d", subOp); } }
void ScummEngine_v0::o_pickupObject() { int obj = fetchScriptByte(); if (!obj) obj = _cmdObject; /* Don't take an object twice */ if (whereIsObject(obj) == WIO_INVENTORY) return; addObjectToInventory(obj, _roomResource); markObjectRectAsDirty(obj); putOwner(obj, VAR(VAR_EGO)); putState(obj, getState(obj) | kObjectState_08 | kObjectStateUntouchable); clearDrawObjectQueue(); runInventoryScript(1); }
void ScummEngine_v4::o4_oldRoomEffect() { int a; _opcode = fetchScriptByte(); if ((_opcode & 0x1F) == 3) { a = getVarOrDirectWord(PARAM_1); if (_game.platform == Common::kPlatformFMTowns && _game.version == 3) { if (a == 4) { _textSurface.fillRect(Common::Rect(0, 0, _textSurface.w * _textSurfaceMultiplier, _textSurface.h * _textSurfaceMultiplier), 0); #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE if (_townsScreen) _townsScreen->clearLayer(1); #endif return; } } if (a) { _switchRoomEffect = (byte)(a & 0xFF); _switchRoomEffect2 = (byte)(a >> 8); } else {
void ScummEngine_v70he::o70_setSystemMessage() { int len; byte name[255]; byte subOp = fetchScriptByte(); convertMessageToString(_scriptPointer, name, sizeof(name)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; switch (subOp) { case 240: debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); break; case 241: // Set Version debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); break; case 242: debug(1,"o70_setSystemMessage: (%d) %s", subOp, name); break; case 243: // Set Window Caption // TODO: The 'name' string can contain non-ASCII data. This can lead to // problems, because (a) the encoding used for "name" is not clear, // (b) OSystem::setWindowCaption only supports ASCII. As a result, odd // behavior can occur, from strange wrong titles, up to crashes (happens // under Mac OS X). // // Possible fixes/workarounds: // - Simply stop using this. It's a rather unimportant "feature" anyway. // - Try to translate the text to ASCII. // - Refine OSystem to accept window captions that are non-ASCII, e.g. // by enhancing all backends to deal with UTF-8 data. Of course, then // one still would have to convert 'name' to the correct encoding. //_system->setWindowCaption((const char *)name); break; default: error("o70_setSystemMessage: default case %d", subOp); } }
void ScummEngine_v0::o_putActorAtObject() { int obj, x, y; Actor *a; a = derefActor(getVarOrDirectByte(PARAM_1), "o_putActorAtObject"); int objId = fetchScriptByte(); if (_opcode & 0x40) obj = OBJECT_V0(objId, kObjectV0TypeBG); else obj = OBJECT_V0(objId, kObjectV0TypeFG); if (whereIsObject(obj) != WIO_NOT_FOUND) { getObjectXYPos(obj, x, y); AdjustBoxResult r = a->adjustXYToBeInBox(x, y); x = r.x; y = r.y; } else { x = 30; y = 60; } a->putActor(x, y); }
void ScummEngine_v70he::o70_resourceRoutines() { int objidx, resid; byte subOp = fetchScriptByte(); switch (subOp) { case 100: // SO_LOAD_SCRIPT resid = pop(); ensureResourceLoaded(rtScript, resid); break; case 101: // SO_LOAD_SOUND resid = pop(); ensureResourceLoaded(rtSound, resid); break; case 102: // SO_LOAD_COSTUME resid = pop(); ensureResourceLoaded(rtCostume, resid); break; case 103: // SO_LOAD_ROOM resid = pop(); ensureResourceLoaded(rtRoomImage, resid); ensureResourceLoaded(rtRoom, resid); break; case 104: // SO_NUKE_SCRIPT resid = pop(); _res->nukeResource(rtScript, resid); break; case 105: // SO_NUKE_SOUND resid = pop(); _res->nukeResource(rtSound, resid); break; case 106: // SO_NUKE_COSTUME resid = pop(); _res->nukeResource(rtCostume, resid); break; case 107: // SO_NUKE_ROOM resid = pop(); _res->nukeResource(rtRoom, resid); _res->nukeResource(rtRoomImage, resid); break; case 108: // SO_LOCK_SCRIPT resid = pop(); if (resid >= _numGlobalScripts) break; _res->lock(rtScript, resid); break; case 109: // SO_LOCK_SOUND resid = pop(); _res->lock(rtSound, resid); break; case 110: // SO_LOCK_COSTUME resid = pop(); _res->lock(rtCostume, resid); break; case 111: // SO_LOCK_ROOM resid = pop(); if (_game.heversion <= 71 && resid > 0x7F) resid = _resourceMapper[resid & 0x7F]; _res->lock(rtRoom, resid); _res->lock(rtRoomImage, resid); break; case 112: // SO_UNLOCK_SCRIPT resid = pop(); if (resid >= _numGlobalScripts) break; _res->unlock(rtScript, resid); break; case 113: // SO_UNLOCK_SOUND resid = pop(); _res->unlock(rtSound, resid); break; case 114: // SO_UNLOCK_COSTUME resid = pop(); _res->unlock(rtCostume, resid); break; case 115: // SO_UNLOCK_ROOM resid = pop(); if (_game.heversion <= 71 && resid > 0x7F) resid = _resourceMapper[resid & 0x7F]; _res->unlock(rtRoom, resid); _res->unlock(rtRoomImage, resid); break; case 116: // TODO: Clear Heap break; case 117: // SO_LOAD_CHARSET resid = pop(); loadCharset(resid); break; case 118: // SO_NUKE_CHARSET resid = pop(); nukeCharset(resid); break; case 119: // SO_LOAD_OBJECT { int obj = pop(); int room = getObjectRoom(obj); loadFlObject(obj, room); break; } case 120: resid = pop(); if (resid >= _numGlobalScripts) break; //queueLoadResource(rtScript, resid); break; case 121: resid = pop(); //queueLoadResource(rtSound, resid); break; case 122: resid = pop(); //queueLoadResource(rtCostume, resid); break; case 123: resid = pop(); //queueLoadResource(rtRoomImage, resid); break; case 159: resid = pop(); _res->unlock(rtImage, resid); break; case 192: resid = pop(); _res->nukeResource(rtImage, resid); break; case 201: resid = pop(); ensureResourceLoaded(rtImage, resid); break; case 202: resid = pop(); _res->lock(rtImage, resid); break; case 203: resid = pop(); //queueLoadResource(rtImage, resid); break; case 233: resid = pop(); objidx = getObjectIndex(resid); if (objidx == -1) break; _res->lock(rtFlObject, _objs[objidx].fl_object_index); break; case 235: resid = pop(); objidx = getObjectIndex(resid); if (objidx == -1) break; _res->unlock(rtFlObject, _objs[objidx].fl_object_index); break; case 239: // Used in airport break; default: error("o70_resourceRoutines: default case %d", subOp); } }
void ScummEngine_v2::o2_assignVarByte() { getResultPos(); setResult(fetchScriptByte()); }
void ScummEngine_v2::getResultPos() { _resultVarNumber = fetchScriptByte(); }
void ScummEngine_v2::getResultPosIndirect() { _resultVarNumber = _scummVars[fetchScriptByte()]; }
void ScummEngine_v0::o_lockSound() { int resid = fetchScriptByte(); _res->lock(rtSound, resid); }
int ScummEngine_v2::getVar() { return readVar(fetchScriptByte()); }
void ScummEngine_v0::o_unlockRoom() { int resid = fetchScriptByte(); _res->unlock(rtRoom, resid); }
void ScummEngine_v0::o_setMode() { setMode(fetchScriptByte()); }
void ScummEngine_v60he::o60_roomOps() { int a, b, c, d, e; byte subOp = fetchScriptByte(); switch (subOp) { case 172: // SO_ROOM_SCROLL b = pop(); a = pop(); if (a < (_screenWidth / 2)) a = (_screenWidth / 2); if (b < (_screenWidth / 2)) b = (_screenWidth / 2); if (a > _roomWidth - (_screenWidth / 2)) a = _roomWidth - (_screenWidth / 2); if (b > _roomWidth - (_screenWidth / 2)) b = _roomWidth - (_screenWidth / 2); VAR(VAR_CAMERA_MIN_X) = a; VAR(VAR_CAMERA_MAX_X) = b; break; case 174: // SO_ROOM_SCREEN b = pop(); a = pop(); if (_game.heversion >= 71) initScreens(a, _screenHeight); else initScreens(a, b); break; case 175: // SO_ROOM_PALETTE d = pop(); c = pop(); b = pop(); a = pop(); setPalColor(d, a, b, c); break; case 176: // SO_ROOM_SHAKE_ON setShake(1); break; case 177: // SO_ROOM_SHAKE_OFF setShake(0); break; case 179: // SO_ROOM_INTENSITY c = pop(); b = pop(); a = pop(); darkenPalette(a, a, a, b, c); break; case 180: // SO_ROOM_SAVEGAME _saveTemporaryState = true; _saveLoadSlot = pop(); _saveLoadFlag = pop(); break; case 181: // SO_ROOM_FADE a = pop(); if (_game.heversion >= 70) { // Defaults to 1 but doesn't use fade effects } else if (a) { _switchRoomEffect = (byte)(a & 0xFF); _switchRoomEffect2 = (byte)(a >> 8); } else { fadeIn(_newEffect); } break; case 182: // SO_RGB_ROOM_INTENSITY e = pop(); d = pop(); c = pop(); b = pop(); a = pop(); darkenPalette(a, b, c, d, e); break; case 183: // SO_ROOM_SHADOW e = pop(); d = pop(); c = pop(); b = pop(); a = pop(); if (_game.heversion == 60) setShadowPalette(a, b, c, d, e, 0, 256); break; case 186: // SO_ROOM_TRANSFORM d = pop(); c = pop(); b = pop(); a = pop(); palManipulateInit(a, b, c, d); break; case 187: // SO_CYCLE_SPEED b = pop(); a = pop(); assertRange(1, a, 16, "o60_roomOps: 187: color cycle"); _colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0; break; case 213: // SO_ROOM_NEW_PALETTE a = pop(); setCurrentPalette(a); break; case 220: a = pop(); b = pop(); copyPalColor(a, b); break; case 221: byte buffer[100]; int len, r; convertMessageToString(_scriptPointer, buffer, sizeof(buffer)); len = resStrLen(_scriptPointer); _scriptPointer += len + 1; r = convertFilePath(buffer, sizeof(buffer)); memcpy(_saveLoadFileName, buffer + r, sizeof(buffer) - r); debug(1, "o60_roomOps: case 221: filename %s", _saveLoadFileName); _saveLoadFlag = pop(); _saveLoadSlot = 255; _saveTemporaryState = true; break; case 234: // HE 7.1 b = pop(); a = pop(); swapObjects(a, b); break; case 236: // HE 7.1 b = pop(); a = pop(); setRoomPalette(a, b); break; default: error("o60_roomOps: default case %d", subOp); }
bool ScummEngine_v0::ifEqualActiveObject2Common(bool checkType) { byte obj = fetchScriptByte(); if (!checkType || (OBJECT_V0_TYPE(_cmdObject2) == kObjectV0TypeFG)) return (obj == OBJECT_V0_ID(_cmdObject2)); return false; }
void ScummEngine_v0::o_unlockCostume() { int resid = fetchScriptByte(); _res->unlock(rtCostume, resid); }
void ScummEngine_v0::o_print() { _actorToPrintStrFor = fetchScriptByte(); decodeParseString(); }
void ScummEngine_v4::o4_oldRoomEffect() { int a; _opcode = fetchScriptByte(); if ((_opcode & 0x1F) == 3) { a = getVarOrDirectWord(PARAM_1); #if 1 if (_game.platform == Common::kPlatformFMTowns && _game.version == 3) { // FIXME / TODO: OK the first thing to note is: at least in Zak256, // maybe also in other games, this opcode does a bit more. I added // some stubs here, but somebody with a full IDA or more knowledge // about this will have to fill in the gaps. At least now we know // that something is missing here :-) if (a == 4) { //printf("o5_oldRoomEffect ODDBALL: _opcode = 0x%x, a = 0x%x\n", _opcode, a); // No idea what byte_2FCCF is, but it's a globale boolean flag. // I only add it here as a temporary hack to make the pseudo code compile. // Maybe it is just there as a reentry protection guard, given // how it is used? It might also correspond to _screenEffectFlag. int byte_2FCCF = 0; // For now, we force a redraw of the screen background. This // way the Zak end credits seem to work mostly correct. VirtScreen *vs = &_virtscr[kMainVirtScreen]; restoreBackground(Common::Rect(0, vs->topline, vs->w, vs->topline + vs->h)); vs->setDirtyRange(0, vs->h); updateDirtyScreen(kMainVirtScreen); if (byte_2FCCF) { // Here now "sub_1C44" is called, which sets byte_2FCCF to 0 then // calls yet another sub (which also reads byte_2FCCF): byte_2FCCF = 0; //call sub_0BB3 // Now sub_085C is called. This is quite simply: it sets // 0xF000 bytes. starting at 0x40000 to 0. No idea what that // buffer is, maybe a screen buffer, though. Note that // 0xF000 = 320*192. // Maybe this is also the charset mask being cleaned? // call sub_085C // And then sub_1C54 is called, which is almost identical to // the above sub_1C44, only it sets byte_2FCCF to 1: byte_2FCCF = 1; // call sub_0BB3 } else { // Here only sub_085C is called (see comment above) // call sub_085C } return; } #endif } if (a) { _switchRoomEffect = (byte)(a & 0xFF); _switchRoomEffect2 = (byte)(a >> 8); } else {
void ScummEngine_v0::o_unlockScript() { int resid = fetchScriptByte(); _res->unlock(rtScript, resid); }