/* 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 "asylum/scriptman.h" #include "common/system.h" DECLARE_SINGLETON(Asylum::ScriptManager); namespace Asylum { static bool g_initialized = false; ScriptManager::ScriptManager() { if (!g_initialized) { g_initialized = true; _currentLine = 0; _currentLoops = 0; _processing = false; _delayedSceneIndex = -1; _delayedVideoIndex = -1; _allowInput = true; memset(_gameFlags, 0, 1512); } } void ScriptManager::setScript(ActionDefinitions *action) { _currentScript = action; if (_currentScript) { for (uint8 i = 0; i < _currentScript->commands[0].numLines; i++) { debugC(kDebugLevelScripts, "Line: %02d/%02d :: 0x%02X (%d, %d, %d, %d, %d, %d, %d, %d, %d)", i, _currentScript->commands[0].numLines - 1, _currentScript->commands[i].opcode, _currentScript->commands[i].param1, _currentScript->commands[i].param2, _currentScript->commands[i].param3, _currentScript->commands[i].param4, _currentScript->commands[i].param5, _currentScript->commands[i].param6, _currentScript->commands[i].param7, _currentScript->commands[i].param8, _currentScript->commands[i].param9); } } } void ScriptManager::setScene(Scene* scene) { _scene = scene; } void ScriptManager::setScriptIndex(uint32 index) { _currentScript = 0; _currentLine = 0; setScript(_scene->getActionList(index)); } void ScriptManager::setGameFlag(int flag) { _gameFlags[flag] &= ~(1 << flag); } void ScriptManager::processActionList() { bool done = false, waitCycle = false; int lineIncrement = 1; _processing = true; if (_currentScript) { while (!done && !waitCycle) { lineIncrement = 1; // Reset line increment value if (_currentLoops > 1000) { // TODO - processActionLists has run too many iterations } // TODO: this should be a pointer to allow changes in commands array ActionCommand *currentCommand = &_currentScript->commands[_currentLine]; switch (currentCommand->opcode) { /* 0x00 */ case kReturn0: done = true; lineIncrement = 0; break; /* 0x01 */ case kSetGameFlag: setGameFlag(currentCommand->param1); break; /* 0x02 */ case kClearGameFlag: { int flagNum = currentCommand->param1; _gameFlags[flagNum] &= ~(1 << flagNum); } break; /* 0x03 */ //case kToogleGameFlag: /* 0x04 */ case kJumpIfGameFlag: if (currentCommand->param1) { bool doJump = false; if (currentCommand->param2) doJump = _gameFlags[currentCommand->param1] == 0; else doJump = _gameFlags[currentCommand->param1] != 0; if (doJump) _currentLine = currentCommand->param3; } break; /* 0x05 */ case kHideCursor: _scene->_screen->hideCursor(); _allowInput = false; break; /* 0x06 */ case kShowCursor: _scene->_screen->showCursor(); _allowInput = true; break; /* 0x07 */ case kPlayAnimation: { int barrierIndex = _scene->_sceneResource->getBarrierIndexById(currentCommand->param1); if (barrierIndex >= 0) _scene->_sceneResource->getWorldStats()->barriers[barrierIndex].flags |= 0x20; // TODO - enums for flags (0x20 is visible/playing?) else debugC(kDebugLevelScripts, "Requested invalid object ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x08 */ //case kMoveScenePosition: /* 0x09 */ case kHideActor: { uint32 actorIndex = 0; if (currentCommand->param1 == -1) ;//actorIndex = _scene->getWorldStats()->playerActor; else actorIndex = currentCommand->param1; if ((actorIndex >= 0) && (actorIndex < _scene->_sceneResource->getWorldStats()->numActors)) _scene->actorVisible(actorIndex, false); else debugC(kDebugLevelScripts, "Requested invalid actor ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x0A */ case kShowActor: { uint32 actorIndex = 0; if (currentCommand->param1 == -1) ;//actorIndex = _scene->getWorldStats()->playerActor; else actorIndex = currentCommand->param1; if ((actorIndex >= 0) && (actorIndex < _scene->_sceneResource->getWorldStats()->numActors)) _scene->actorVisible(actorIndex, true); else debugC(kDebugLevelScripts, "Requested invalid actor ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x0B */ case kSetActorStats: { uint32 actorIndex = 0; if (currentCommand->param1 == -1) ;//actorIndex = _scene->getWorldStats()->playerActor; else actorIndex = currentCommand->param1; if ((actorIndex >= 0) && (actorIndex < _scene->_sceneResource->getWorldStats()->numActors)) { _scene->setActorPosition(actorIndex, currentCommand->param2, currentCommand->param3); _scene->setActorAction(actorIndex, currentCommand->param4); } else debugC(kDebugLevelScripts, "Requested invalid actor ID:0x%02X in Scene %d Script %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x0C */ //case kSetSceneMotionStat: /* 0x0D */ //case kDisableActor: /* 0x0E */ case kEnableActor: { int actorIndex = 0; if (currentCommand->param1 == -1) ;//actorIndex = _scene->getWorldStats()->playerActor; else actorIndex = currentCommand->param1; if (_scene->_sceneResource->getWorldStats()->actors[actorIndex].field_40 == 5) { enableActorSub(actorIndex, 4); } } break; /* 0x0F */ case kEnableBarriers: { int barIdx = _scene->_sceneResource->getBarrierIndexById(currentCommand->param1); uint32 sndIdx = currentCommand->param3; uint32 v59 = currentCommand->param2; if (!_currentScript->counter && _scene->getSceneIndex() != 13 && sndIdx != 0) { // TODO // Find a script that actually has a valid param3 // to see if this code is accurate :P ResourcePack *tmpRes = new ResourcePack(12); _scene->_sound->playSfx(tmpRes, ((int)(sndIdx != 0) & 5) + 0x80120001); delete tmpRes; } if (_currentScript->counter >= 3 * v59 - 1) { _currentScript->counter = 0; _scene->_sceneResource->getWorldStats()->barriers[barIdx].field_67C = 0; processActionListSub02(_currentScript, currentCommand, 2); _currentLoops = 1; // v4 = 1; } else { int v64; int v62 = _currentScript->counter + 1; _currentScript->counter = v62; if (sndIdx) { v64 = 1; int v170 = 3 - v62 / v59; _scene->_sceneResource->getWorldStats()->barriers[barIdx].field_67C = v170; } else { v64 = 0; _scene->_sceneResource->getWorldStats()->barriers[barIdx].field_67C = v62 / v59 + 1; } processActionListSub02(_currentScript, currentCommand, v64); } } break; /* 0x10 */ case kReturn: done = true; lineIncrement = 0; break; /* 0x11 */ case kDestroyObject: { int barrierIndex = _scene->_sceneResource->getBarrierIndexById(currentCommand->param1); if (barrierIndex >= 0) _scene->_sceneResource->getWorldStats()->barriers[barrierIndex].flags &= 0xFFFFDF; // TODO - enums for flags (0x20 is visible/playing?) else debugC(kDebugLevelScripts, "Requested invalid object ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x12 */ //case k_unk12_JMP_WALK_ACTOR: /* 0x13 */ //case k_unk13_JMP_WALK_ACTOR: /* 0x14 */ //case k_unk14_JMP_WALK_ACTOR: /* 0x15 */ //case k_unk15: /* 0x16 */ //case kResetAnimation: /* 0x17 */ //case kClearFlag1Bit0: /* 0x18 */ //case k_unk18_PLAY_SND: /* 0x19 */ //case kJumpIfFlag2Bit0: /* 0x1A */ //case kSetFlag2Bit0: /* 0x1B */ //case kClearFlag2Bit0: /* 0x1C */ //case kJumpIfFlag2Bit2: /* 0x1D */ //case kSetFlag2Bit2: /* 0x1E */ //case kClearFlag2Bit2: /* 0x1F */ //case kJumpIfFlag2Bit1: /* 0x20 */ //case kSetFlag2Bit1: /* 0x21 */ //case kClearFlag2Bit1: /* 0x22 */ //case k_unk22: /* 0x23 */ //case k_unk23: /* 0x24 */ //case k_unk24: /* 0x25 */ //case kRunEncounter: /* 0x26 */ //case kJumpIfFlag2Bit4: /* 0x27 */ //case kSetFlag2Bit4: /* 0x28 */ //case kClearFlag2Bit4: /* 0x29 */ //case kSetActorField638: /* 0x2A */ //case kJumpIfActorField638: /* 0x2B */ case kChangeScene: _delayedSceneIndex = currentCommand->param1 + 4; debug(kDebugLevelScripts, "Queueing Scene Change to scene %d...", _delayedSceneIndex); break; /* 0x2C */ //case k_unk2C_ActorSub: /* 0x2D */ case kPlayMovie: _delayedVideoIndex = currentCommand->param1; break; /* 0x2E */ case kStopAllBarriersSounds: // TODO: do this for all barriers that have sfx playing _scene->_sound->stopSfx(); break; /* 0x2F */ //case kSetActionFlag01: /* 0x30 */ //case kClearActionFlag01: /* 0x31 */ //case kResetSceneRect: /* 0x32 */ //case kChangeMusicById: /* 0x33 */ case kStopMusic: _scene->_sound->stopMusic(); break; /* 0x34 */ //case k_unk34_Status: /* 0x35 */ //case k_unk35: /* 0x36 */ //case k_unk36: /* 0x37 */ case kRunBlowUpPuzzle: { int blowUpPuzzleIdx = currentCommand->param1; _scene->setBlowUpPuzzle(new BlowUpPuzzleVCR(_scene)); _scene->getBlowUpPuzzle()->openBlowUp(); } break; /* 0x38 */ //case kJumpIfFlag2Bit3: /* 0x39 */ //case kSetFlag2Bit3: /* 0x3A */ //case kClearFlag2Bit3: /* 0x3B */ //case k_unk3B_PALETTE_MOD: /* 0x3C */ //case k_unk3C_CMP_VAL: /* 0x3D */ case kWaitUntilFramePlayed: { int barrierIndex = _scene->_sceneResource->getBarrierIndexById(currentCommand->param1); if (barrierIndex >= 0) { uint32 frameNum = 0; if (currentCommand->param2 == -1) frameNum = _scene->_sceneResource->getWorldStats()->barriers[barrierIndex].frameCount - 1; else frameNum = currentCommand->param2; if (_scene->_sceneResource->getWorldStats()->barriers[barrierIndex].tickCount < frameNum) { lineIncrement = 0; waitCycle = true; } } else debugC(kDebugLevelScripts, "Requested invalid object ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x3E */ case kUpdateWideScreen: { int barSize = currentCommand->param1; if(barSize >= 22) { currentCommand->param1 = 0; } else { _scene->_screen->drawWideScreen(4 * barSize); currentCommand->param1++; } } break; /* 0x3F */ //case k_unk3F: /* 0x40 */ //case k_unk40_SOUND: /* 0x41 */ case kPlaySpeech: { // TODO - Add support for other param options uint32 sndIdx = currentCommand->param1; if ((int)sndIdx >= 0) { if (sndIdx >= 259) { sndIdx -= 9; _scene->_sound->playSfx(_scene->_speechPack, sndIdx - 0x7FFD0000); } else { _scene->_sound->playSfx(_scene->_speechPack, sndIdx); } } else debugC(kDebugLevelScripts, "Requested invalid sound ID:0x%02X in Scene %d Line %d.", currentCommand->param1, _scene->getSceneIndex(), _currentLine); } break; /* 0x42 */ //case k_unk42: /* 0x43 */ //case k_unk43: /* 0x44 */ //case kPaletteFade: /* 0x45 */ //case kStartPaletteFadeThread: /* 0x46 */ //case k_unk46: /* 0x47 */ //case kActorFaceObject: /* 0x48 */ //case k_unk48_MATTE_01: /* 0x49 */ //case k_unk49_MATTE_90: /* 0x4A */ //case kJumpIfSoundPlaying: /* 0x4B */ //case kChangePlayerCharacterIndex: /* 0x4C */ case kChangeActorField40: { // TODO: figure out what is this field and what values are set int actorIdx = currentCommand->param1; int fieldType = currentCommand->param2; if(fieldType) { if(_scene->getResources()->getWorldStats()->actors[actorIdx].field_40 < 11) { _scene->getResources()->getWorldStats()->actors[actorIdx].field_40 = 14; } } else { _scene->getResources()->getWorldStats()->actors[actorIdx].field_40 = 4; } } break; /* 0x4D */ //case kStopSound: /* 0x4E */ //case k_unk4E_RANDOM_COMMAND: /* 0x4F */ case kClearScreen: if(currentCommand->param1) { _scene->_screen->clearScreen(); } break; /* 0x50 */ //case kQuit: /* 0x51 */ //case kJumpObjectFrame: /* 0x52 */ //case k_unk52: /* 0x53 */ //case k_unk53: /* 0x54 */ //case k_unk54_SET_ACTIONLIST_6EC: /* 0x55 */ //case k_unk55: /* 0x56 */ //case k_unk56: /* 0x57 */ //case k_unk57: /* 0x58 */ //case k_unk58: /* 0x59 */ //case k_unk59: /* 0x5A */ //case k_unk5A: /* 0x5B */ //case k_unk5B: /* 0x5C */ //case k_unk5C: /* 0x5D */ //case k_unk5D: /* 0x5E */ //case k_unk5E: /* 0x5F */ //case k_unk5F: /* 0x60 */ //case k_unk60_SET_OR_CLR_ACTIONAREA_FLAG: /* 0x61 */ //case k_unk61: /* 0x62 */ //case k_unk62_SHOW_OPTIONS_SCREEN: default: debugC(kDebugLevelScripts, "Unhandled opcode 0x%02X in Scene %d Line %d.", currentCommand->opcode, _scene->getSceneIndex(), _currentLine); break; } // end switch _currentLine += lineIncrement; _currentLoops++; } // end while if (done) { _currentLine = 0; _currentLoops = 0; _currentScript = 0; } } _processing = false; } void ScriptManager::processActionListSub02(ActionDefinitions* script, ActionCommand *command, int a4) { int v4 = 0; int result; int barrierIdx = 0; if (a4) { if (a4 == 1) { ; } else { result = a4 - 2; int v8 = command->param4; for (int i = 7; i > 0; i--) { barrierIdx = _scene->getResources()->getBarrierIndexById(v8); if (barrierIdx) _scene->getResources()->getWorldStats()->barriers[barrierIdx].field_67C = 0; v8 += 4; } } // TODO switch (_scene->getSceneIndex()) { case 7: warning("Scene 7 / v4 != 0 Not Implemented"); break; case 6: warning("Scene 6 / v4 != 0 Not Implemented"); break; case 8: warning("Scene 8 / v4 != 0 Not Implemented"); break; case 3: warning("Scene 3 / v4 != 0 Not Implemented"); break; case 4: warning("Scene 4 / v4 != 0 Not Implemented"); break; default: return; } } else { int v13 = command->param4; int v4 = script->counter / command->param2 + 4; for (int i = 7; i > 0; i--) { barrierIdx = _scene->getResources()->getBarrierIndexById(v13); if (barrierIdx >= 0) _scene->getResources()->getWorldStats()->barriers[barrierIdx].field_67C = v4; v13 += 4; } // TODO switch (_scene->getSceneIndex()) { case 7: warning("Scene 7 / v4 = 0 Not Implemented"); break; case 6: warning("Scene 6 / v4 = 0 Not Implemented"); break; case 8: warning("Scene 8 / v4 = 0 Not Implemented"); break; case 3: warning("Scene 3 / v4 = 0 Not Implemented"); break; case 4: warning("Scene 4 / v4 = 0 Not Implemented"); break; default: return; } } } void ScriptManager::enableActorSub(int actorIndex, int condition) { } ScriptManager::~ScriptManager() { // TODO Auto-generated destructor stub } } // end of namespace Asylum