diff options
Diffstat (limited to 'engines/mads/nebular/nebular_scenes.cpp')
-rw-r--r-- | engines/mads/nebular/nebular_scenes.cpp | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp new file mode 100644 index 0000000000..52b565016f --- /dev/null +++ b/engines/mads/nebular/nebular_scenes.cpp @@ -0,0 +1,628 @@ +/* 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. + * + */ + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "mads/mads.h" +#include "mads/compression.h" +#include "mads/resources.h" +#include "mads/scene.h" +#include "mads/nebular/game_nebular.h" +#include "mads/nebular/nebular_scenes.h" +#include "mads/nebular/nebular_scenes1.h" +#include "mads/nebular/nebular_scenes2.h" +#include "mads/nebular/nebular_scenes3.h" +#include "mads/nebular/nebular_scenes4.h" +#include "mads/nebular/nebular_scenes5.h" +#include "mads/nebular/nebular_scenes6.h" +#include "mads/nebular/nebular_scenes7.h" +#include "mads/nebular/nebular_scenes8.h" + +namespace MADS { + +namespace Nebular { + +SceneLogic *SceneFactory::createScene(MADSEngine *vm) { + Scene &scene = vm->_game->_scene; + + scene.addActiveVocab(NOUN_DROP); + scene.addActiveVocab(NOUN_DOLLOP); + scene.addActiveVocab(NOUN_DASH); + scene.addActiveVocab(NOUN_SPLASH); + scene.addActiveVocab(NOUN_ALCOHOL); + + switch (scene._nextSceneId) { + // Scene group #1 (ship, ocean, cave) + case 101: // Ship, cockpit + return new Scene101(vm); + case 102: // Ship, dining room + return new Scene102(vm); + case 103: // Ship, engine room + return new Scene103(vm); + case 104: // Ocean, northwest cliff + return new Scene104(vm); + case 105: // Ocean, northeast cliff with mine + return new Scene105(vm); + case 106: // Ocean, outside ship + return new Scene106(vm); + case 107: // Ocean, bushes + return new Scene107(vm); + case 108: // Ocean, southwest cliff + return new Scene108(vm); + case 109: // Ocean, tunnel + return new Scene109(vm); + case 110: // Ocean, cave with tunnel + return new Scene110(vm); + case 111: // Cave with pool and opening + return new Scene111(vm); + case 112: // cutscene, looking at view screen + return new Scene112(vm); + + // Scene group #2 (island) + case 201: // outside teleporter + return new Scene201(vm); + case 202: // village + return new Scene202(vm); + case 203: // tree with Rhotunda (fat woman) + return new Scene203(vm); + case 205: // village + return new Scene205(vm); + case 207: // outside witch doctor's hut + return new Scene207(vm); + case 208: // pit with leaves (trap) + return new Scene208(vm); + case 209: // palm tree and bamboo plant + return new Scene209(vm); + case 210: // outside native woman's hut + return new Scene210(vm); + case 211: // palm tree with monkey + return new Scene211(vm); + case 212: // outside cave + return new Scene212(vm); + case 213: // inside teleporter + return new Scene213(vm); + case 214: // inside witch doctor's hut + return new Scene214(vm); + case 215: // inside native woman's hut + return new Scene215(vm); + case 216: // cutscene, monitor showing Rex and native woman + return new Scene216(vm); + + // Scene group #3 (women's base, cell block) + case 301: // outside teleporter (before chaos) + return new Scene301(vm); + case 302: // room with statue (before chaos) + return new Scene302(vm); + case 303: // western corridor (before chaos) + return new Scene303(vm); + case 304: // crossing with traffic light (before chaos) + return new Scene304(vm); + case 307: // Rex's cell (before chaos) + return new Scene307(vm); + case 308: // sauropod's cell (before chaos) + return new Scene308(vm); + case 309: // multihand monster's cell (before chaos) + return new Scene309(vm); + case 310: // empty cell (before chaos) + return new Scene310(vm); + case 311: // warden's desk (before chaos) + return new Scene311(vm); + case 313: // air shaft overview + return new Scene313(vm); + case 316: // Gender Bender + return new Scene316(vm); + case 318: // doctor's gurney + return new Scene318(vm); + case 319: // doctor Slache closeup (lying on the gurney) + return new Scene319(vm); + case 320: // warden's desk closeup / monitors + return new Scene320(vm); + case 321: // gender bender sex change sequence + return new Scene321(vm); + case 322: // inside teleporter + return new Scene322(vm); + case 351: // outside teleporter (after chaos) + return new Scene351(vm); + case 352: // room with statue (after chaos) + return new Scene352(vm); + case 353: // western corridor (after chaos) + return new Scene353(vm); + case 354: // crossing with traffic light (after chaos) + return new Scene354(vm); + case 357: // Rex's cell (after chaos) + return new Scene357(vm); + case 358: // sauropod's cell (after chaos) + return new Scene358(vm); + case 359: // multihand monster's cell (after chaos) + return new Scene359(vm); + case 360: // empty cell (after chaos) + return new Scene360(vm); + case 361: // warden's desk (after chaos) + return new Scene361(vm); + case 366: // air shaft ending at Gender Bender + return new Scene366(vm); + case 387: // air shaft ending at cell + return new Scene387(vm); + case 388: // air shaft ending at sauropod's cell + return new Scene388(vm); + case 389: // air shaft ending at multihand monster's cell (before chaos) + return new Scene389(vm); + case 390: // air shaft ending at cell + return new Scene390(vm); + case 391: // air shaft ending at warden's desk + return new Scene391(vm); + case 399: // air shaft ending at multihand monster's cell (after chaos) + return new Scene399(vm); + + // Scene group #4 (women's base) + case 401: // outside bar + return new Scene401(vm); + case 402: // inside bar + return new Scene402(vm); + case 405: // outside armory + return new Scene405(vm); + case 406: // outside storage room + return new Scene406(vm); + case 407: // eastern corridor + return new Scene407(vm); + case 408: // inside armory + return new Scene408(vm); + case 409: // inside female only teleporter + return new Scene409(vm); + case 410: // inside storage room + return new Scene410(vm); + case 411: // lab + return new Scene411(vm); + case 413: // outside female only teleporter + return new Scene413(vm); + + // Scene group #5 (men's city, lower floor) + case 501: // outside car + return new Scene501(vm); + case 502: // inside male only teleporter + return new Scene502(vm); + case 503: // guard tower + return new Scene503(vm); + case 504: // inside car + return new Scene504(vm); + case 505: // car view screen + return new Scene505(vm); + case 506: // shopping street + return new Scene506(vm); + case 507: // inside software house + return new Scene507(vm); + case 508: // laser cannon + return new Scene508(vm); + case 511: // outside pleasure dome + return new Scene511(vm); + case 512: // inside pleasure dome + return new Scene512(vm); + case 513: // outside mall + return new Scene513(vm); + case 515: // overview + return new Scene515(vm); + case 551: // outside teleporter (with skeleton) + return new Scene551(vm); + + // Scene group #6 (men's city, upper floor) + case 601: // outside Bruce's house + return new Scene601(vm); + case 602: // Bruce's house, living room + return new Scene602(vm); + case 603: // Bruce's house, bedroom + return new Scene603(vm); + case 604: // viewport + return new Scene604(vm); + case 605: // viewport closeup + return new Scene605(vm); + case 607: // outside Abdul's garage + return new Scene607(vm); + case 608: // inside Abdul's garage + return new Scene608(vm); + case 609: // outside Buckluster video store + return new Scene609(vm); + case 610: // inside Buckluster video store + return new Scene610(vm); + case 611: // back alley + return new Scene611(vm); + case 612: // expressway / maintenance building + return new Scene612(vm); + case 620: // cutscene, viewport glass breaking + return new Scene620(vm); + + // Scene group #7 (submerged men's city / upper floor) + case 701: // outside elevator (after city is submerged) + return new Scene701(vm); + case 702: // outside teleporter (after city is submerged) + return new Scene702(vm); + case 703: // water + return new Scene703(vm); + case 704: // water, building in the distance + return new Scene704(vm); + case 705: // water, outside building + return new Scene705(vm); + case 706: // inside building, pedestral room, outside teleporter + return new Scene706(vm); + case 707: // teleporter + return new Scene707(vm); + case 710: // looking at pedestral room through binoculars + return new Scene710(vm); + case 711: // inside teleporter + return new Scene711(vm); + case 751: // outside elevator (before city is submerged) + return new Scene751(vm); + case 752: // outside teleporter (before city is submerged) + return new Scene752(vm); + + // Scene group #8 + case 801: // control room, outside teleporter + return new Scene801(vm); + case 802: // launch pad with destroyed ship + return new Scene802(vm); + case 803: // empty launch pad + return new Scene803(vm); + case 804: // inside Rex's ship - cockpit + return new Scene804(vm); + case 805: // service panel + return new Scene805(vm); + case 807: // teleporter + return new Scene807(vm); + case 808: // antigrav control + return new Scene808(vm); + case 810: // cutscene: Rex's ship leaving the planet + return new Scene810(vm); + + default: + error("Invalid scene %d called", scene._nextSceneId); + } +} + +/*------------------------------------------------------------------------*/ + +NebularScene::NebularScene(MADSEngine *vm) : SceneLogic(vm), + _globals(static_cast<GameNebular *>(vm->_game)->_globals), + _game(*static_cast<GameNebular *>(vm->_game)), + _action(vm->_game->_scene._action) { +} + +Common::String NebularScene::formAnimName(char sepChar, int suffixNum) { + return Resources::formatName(_scene->_currentSceneId, sepChar, suffixNum, + EXT_NONE, ""); +} + +/*------------------------------------------------------------------------*/ + +void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) { + File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT")); + MadsPack codesPack(&f); + Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1); + + loadCodes(depthSurface, stream); + + delete stream; + f.close(); +} + +void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { + byte *destP = depthSurface.getData(); + byte *endP = depthSurface.getBasePtr(0, depthSurface.h); + + byte runLength = stream->readByte(); + while (destP < endP && runLength > 0) { + byte runValue = stream->readByte(); + + // Write out the run length + Common::fill(destP, destP + runLength, runValue); + destP += runLength; + + // Get the next run length + runLength = stream->readByte(); + } + + if (destP < endP) + Common::fill(destP, endP, 0); +} + +/*------------------------------------------------------------------------*/ + +SceneTeleporter::SceneTeleporter(MADSEngine *vm) : NebularScene(vm) { + _buttonTyped = -1; + _curCode = -1; + _digitCount = -1; + _curMessageId = -1; + _handSpriteId = -1; + _handSequenceId = -1; + _finishedCodeCounter = -1; + _meteorologistNextPlace = -1; + _meteorologistCurPlace = -1; + _teleporterSceneId = -1; +} + +int SceneTeleporter::teleporterAddress(int code, bool working) { + int limit = working ? 6 : 10; + + for (int i = 0; i < limit; i++) { + if (code == _globals[kTeleporterCode + i]) + return _globals[kTeleporterRoom + i]; + } + + return -1; +} + +Common::Point SceneTeleporter::teleporterComputeLocation() { + Common::Point result; + + switch (_buttonTyped) { + case 0: + result = Common::Point(179, 200); + break; + + case 1: + result = Common::Point(166, 170); + break; + + case 2: + result = Common::Point(179, 170); + break; + + case 3: + result = Common::Point(192, 170); + break; + + case 4: + result = Common::Point(166, 180); + break; + + case 5: + result = Common::Point(179, 180); + break; + + case 6: + result = Common::Point(192, 180); + break; + + case 7: + result = Common::Point(166, 190); + break; + + case 8: + result = Common::Point(179, 190); + break; + + case 9: + result = Common::Point(192, 190); + break; + + case 10: + result = Common::Point(194, 200); + break; + + case 11: + result = Common::Point(164, 200); + break; + + default: + error("teleporterComputeLocation() - Unexpected button pressed"); + } + + return result; +} + +void SceneTeleporter::teleporterHandleKey() { + switch (_game._trigger) { + case 0: { + _game._player._stepEnabled = false; + Common::Point msgPos = teleporterComputeLocation(); + _handSequenceId = _scene->_sequences.startReverseCycle(_handSpriteId, false, 4, 2, 0, 0); + _scene->_sequences.setPosition(_handSequenceId, msgPos); + _scene->_sequences.setDepth(_handSequenceId, 2); + _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_LOOP, 0, 1); + _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_EXPIRE, 0, 2); + + if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) + _vm->_events->hideCursor(); + + } + break; + + case 1: + _scene->_sequences.addSubEntry(_handSequenceId, SEQUENCE_TRIGGER_SPRITE, 3, 3); + if (_buttonTyped <= 9) { + if (_digitCount < 4) { + _curCode *= 10; + _curCode += _buttonTyped; + _digitCount++; + _msgText = Common::String::format("%d", _curCode); + if (_digitCount < 4) + _msgText += "_"; + + if (_scene->_currentSceneId != 711) + _vm->_sound->command(32); + } + } else if (_buttonTyped == 11) { + _digitCount = 0; + _curCode = 0; + _msgText = "_"; + if (_scene->_currentSceneId != 711) + _vm->_sound->command(33); + } else if (_digitCount == 4) { + if (_scene->_currentSceneId != 711) + _finishedCodeCounter = 1; + + if (teleporterAddress(_curCode, true) > 0) { + _vm->_palette->setEntry(252, 0, 63, 0); + if (_scene->_currentSceneId != 711) + _vm->_sound->command(34); + } else { + _vm->_palette->setEntry(252, 63, 0, 0); + if (_scene->_currentSceneId != 711) + _vm->_sound->command(35); + } + } + + if (_scene->_currentSceneId != 711) { + if (_curMessageId >= 0) + _scene->_kernelMessages.remove(_curMessageId); + _curMessageId = _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText); + } + break; + + case 2: + if (_finishedCodeCounter == 1) { + _finishedCodeCounter++; + + if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) + _scene->_nextSceneId = 202; + else { + _vm->_events->showCursor(); + int destination = teleporterAddress(_curCode, true); + + if (destination > 0) { + _globals[kTeleporterCommand] = 2; + _scene->_nextSceneId = _teleporterSceneId; + _globals[kTeleporterDestination] = destination; + } else { + _globals[kTeleporterCommand] = 4; + _scene->_nextSceneId = _teleporterSceneId; + } + } + } else if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) + _scene->_sequences.addTimer(30, 230 + _meteorologistCurPlace); + + break; + + case 3: + if (!_finishedCodeCounter) { + if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) { + _game._player._stepEnabled = true; + _vm->_events->showCursor(); + } + } + break; + + default: + break; + } +} + +void SceneTeleporter::teleporterEnter() { + _game._player._visible = false; + _game._player._stepEnabled = (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL); + _scene->_kernelMessages._talkFont = _vm->_font->getFont(FONT_TELE); + _scene->_textSpacing = 0; + _curCode = 0; + _digitCount = 0; + _finishedCodeCounter = 0; + _curMessageId = -1; + _msgText = "_"; + + if (_scene->_priorSceneId == -2) + _scene->_priorSceneId = _globals[kTeleporterDestination]; + + if (_scene->_priorSceneId < 101) + _scene->_priorSceneId = 201; + + _globals[kTeleporterDestination] = _scene->_priorSceneId; + _vm->_palette->setEntry(252, 63, 63, 0); + _vm->_palette->setEntry(253, 0, 0, 0); + _teleporterSceneId = _scene->_priorSceneId; + if (_teleporterSceneId == 202) + _teleporterSceneId = 201; + + int tmpVal = 0; + for (int i = 0; i < 10; i++) { + if (_teleporterSceneId == _globals[kTeleporterRoom + i]) + tmpVal = _globals[kTeleporterRoom + i]; + + if (_globals[kTeleporterRoom + i] == 301) + _meteorologistNextPlace = _globals[kTeleporterCode + i]; + } + + Common::String msgText2 = Common::String::format("#%.4d", tmpVal); + + if (_scene->_currentSceneId != 711) { + _scene->_kernelMessages.add(Common::Point(133, 34), 0, 32, 0, 9999999, msgText2); + _scene->_kernelMessages.add(Common::Point(143, 61), 0xFDFC, 16, 0, 9999999, _msgText); + } + + _meteorologistCurPlace = 0; + + if (_globals[kMeteorologistWatch] != METEOROLOGIST_NORMAL) + _scene->_sequences.addTimer(30, 230); + + _vm->_sound->command(36); +} + +bool SceneTeleporter::teleporterActions() { + bool retVal = false; + static int _buttonList[12] = { NOUN_0_KEY, NOUN_1_KEY, NOUN_2_KEY, NOUN_3_KEY, NOUN_4_KEY, NOUN_5_KEY, NOUN_6_KEY, NOUN_7_KEY, NOUN_8_KEY, NOUN_9_KEY, NOUN_SMILE_KEY, NOUN_FROWN_KEY }; + + if (_action.isAction(VERB_PRESS) || _action.isAction(VERB_PUSH)) { + for (int i = 0; i < 12; i++) { + if (_action._activeAction._objectNameId == _buttonList[i]) + _buttonTyped = i; + } + teleporterHandleKey(); + retVal = true; + } + + if (_action.isAction(VERB_EXIT_FROM, NOUN_DEVICE)) { + _globals[kTeleporterCommand] = 3; + _scene->_nextSceneId = _teleporterSceneId; + retVal = true; + } + + return (retVal); +} + +void SceneTeleporter::teleporterStep() { + if (_globals[kMeteorologistWatch] == METEOROLOGIST_NORMAL) + return; + + if (_game._trigger >= 230) { + int place = _game._trigger - 230; + int digit; + + if (place < 4) { + digit = _meteorologistNextPlace; + for (int i = 0; i < (3 - place); i++) + digit = digit / 10; + + digit = digit % 10; + } else { + digit = 10; + } + _buttonTyped = digit; + _meteorologistCurPlace = place + 1; + _game._trigger = -1; + } + + if (_game._trigger) { + if (_game._trigger == -1) + _game._trigger = 0; + teleporterHandleKey(); + } +} + +} // End of namespace Nebular + +} // End of namespace MADS |