From d375429abef0109a483970975b053292efa4bd6e Mon Sep 17 00:00:00 2001 From: Matthew Stewart Date: Fri, 11 May 2018 02:17:57 -0400 Subject: STARTREK: Objects and animations. Testing them with the transporter room. --- engines/startrek/filestream.h | 2 +- engines/startrek/font.cpp | 2 +- engines/startrek/graphics.cpp | 121 +++++----- engines/startrek/graphics.h | 20 +- engines/startrek/module.mk | 1 + engines/startrek/object.cpp | 27 +++ engines/startrek/object.h | 83 +++++++ engines/startrek/room.cpp | 2 +- engines/startrek/sound.cpp | 7 +- engines/startrek/sound.h | 5 +- engines/startrek/sprite.h | 12 - engines/startrek/startrek.cpp | 517 ++++++++++++++++++++++++++++++++++++------ engines/startrek/startrek.h | 61 ++++- engines/startrek/text.cpp | 8 +- 14 files changed, 700 insertions(+), 168 deletions(-) create mode 100644 engines/startrek/object.cpp create mode 100644 engines/startrek/object.h diff --git a/engines/startrek/filestream.h b/engines/startrek/filestream.h index 475bbcfeea..dcc806043c 100644 --- a/engines/startrek/filestream.h +++ b/engines/startrek/filestream.h @@ -39,7 +39,7 @@ private: public: // ReadStream functions virtual bool eos() const; - virtual uint32 read(void* dataPtr, uint32 dataSize); + virtual uint32 read(void *dataPtr, uint32 dataSize); // SeekableReadStream functions virtual int32 pos() const; diff --git a/engines/startrek/font.cpp b/engines/startrek/font.cpp index db310425a0..8463841ece 100644 --- a/engines/startrek/font.cpp +++ b/engines/startrek/font.cpp @@ -31,7 +31,7 @@ static const byte CHARACTER_COUNT = 0x80; static const byte CHARACTER_SIZE = 0x40; Font::Font(StarTrekEngine *vm) : _vm(vm) { - SharedPtr fontStream = _vm->openFile("FONT.FNT"); + SharedPtr fontStream = _vm->loadFile("FONT.FNT"); _characters = new Character[CHARACTER_COUNT]; diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index ced8d82edb..457313cd51 100644 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -33,9 +33,7 @@ namespace StarTrek { Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) { _font = nullptr; - _egaData = nullptr; - _priData = nullptr; _lutData = nullptr; _screenRect = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT); @@ -50,6 +48,9 @@ Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) { _numSprites = 0; _textDisplayMode = TEXTDISPLAY_WAIT; + _textboxVar2 = 0; + _textboxVar6 = 0; + _textboxHasMultipleChoices = false; setMouseCursor(loadBitmap("pushbtn")); CursorMan.showMouse(true); @@ -57,58 +58,22 @@ Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) { Graphics::~Graphics() { delete[] _egaData; - delete[] _priData; delete[] _lutData; delete _font; } -void Graphics::loadEGAData(const char *filename) { - // Load EGA palette data - if (!_egaMode) - return; - - if (!_egaData) - _egaData = new byte[256]; - - SharedPtr egaStream = _vm->openFile(filename); - egaStream->read(_egaData, 256); +void Graphics::setBackgroundImage(SharedPtr bitmap) { + _backgroundImage = bitmap; } -void Graphics::drawBackgroundImage(const char *filename) { - // Draw an stjr BGD image (palette built-in) - - SharedPtr imageStream = _vm->openFile(filename); - byte *palette = new byte[256 * 3]; - imageStream->read(palette, 256 * 3); - - // Expand color components - for (uint16 i = 0; i < 256 * 3; i++) - palette[i] <<= 2; - - uint16 xoffset = imageStream->readUint16LE(); - uint16 yoffset = imageStream->readUint16LE(); - uint16 width = imageStream->readUint16LE(); - uint16 height = imageStream->readUint16LE(); - - byte *pixels = new byte[width * height]; - imageStream->read(pixels, width * height); - - _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); - _vm->_system->copyRectToScreen(pixels, width, xoffset, yoffset, width, height); - _vm->_system->updateScreen(); - - delete[] palette; -} - - void Graphics::loadPalette(const Common::String &paletteName) { // Set the palette from a PAL file Common::String palFile = paletteName + ".PAL"; Common::String lutFile = paletteName + ".LUT"; - SharedPtr palStream = _vm->openFile(palFile.c_str()); + SharedPtr palStream = _vm->loadFile(palFile.c_str()); byte *palette = new byte[256 * 3]; palStream->read(palette, 256 * 3); @@ -122,7 +87,7 @@ void Graphics::loadPalette(const Common::String &paletteName) { delete[] palette; // Load LUT file - SharedPtr lutStream = _vm->openFile(lutFile.c_str()); + SharedPtr lutStream = _vm->loadFile(lutFile.c_str()); delete[] _lutData; _lutData = new byte[256]; @@ -130,15 +95,27 @@ void Graphics::loadPalette(const Common::String &paletteName) { } void Graphics::loadPri(const char *priFile) { - SharedPtr priStream = _vm->openFile(priFile); - - delete[] _priData; - _priData = new byte[SCREEN_WIDTH*SCREEN_HEIGHT / 2]; + SharedPtr priStream = _vm->loadFile(priFile); priStream->read(_priData, SCREEN_WIDTH*SCREEN_HEIGHT / 2); } +void Graphics::clearPri() { + memset(_priData, 0, sizeof(_priData)); +} + +byte Graphics::getPriValue(int x, int y) { + assert(_screenRect.contains(x, y)); + + int priOffset = y * SCREEN_WIDTH + x; + byte b = _priData[priOffset / 2]; + if ((priOffset % 2) == 1) + return b & 0xf; + else + return b >> 4; +} + SharedPtr Graphics::loadBitmap(Common::String basename) { - return SharedPtr(new Bitmap(_vm->openFile(basename + ".BMP"))); + return SharedPtr(new Bitmap(_vm->loadFile(basename + ".BMP"))); } Common::Point Graphics::getMousePos() { @@ -150,11 +127,6 @@ void Graphics::setMouseCursor(SharedPtr bitmap) { _vm->_system->setMouseCursor(bitmap->pixels, bitmap->width, bitmap->height, bitmap->xoffset, bitmap->yoffset, 0); } -void Graphics::redrawScreen() { - _vm->_system->copyRectToScreen(_backgroundImage->pixels, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - drawAllSprites(); -} - void Graphics::drawSprite(const Sprite &sprite) { int left = sprite.drawX; int top = sprite.drawY; @@ -448,17 +420,50 @@ void Graphics::delSprite(Sprite *sprite) { } -void Graphics::drawBitmapToScreen(Bitmap *bitmap) { +void Graphics::drawDirectToScreen(SharedPtr bitmap) { int xoffset = bitmap->xoffset; int yoffset = bitmap->yoffset; - if (xoffset >= SCREEN_WIDTH) - xoffset = 0; - if (yoffset >= SCREEN_HEIGHT) - yoffset = 0; _vm->_system->copyRectToScreen(bitmap->pixels, bitmap->width, xoffset, yoffset, bitmap->width, bitmap->height); - _vm->_system->updateScreen(); } +void Graphics::loadEGAData(const char *filename) { + // Load EGA palette data + if (!_egaMode) + return; + + if (!_egaData) + _egaData = new byte[256]; + + SharedPtr egaStream = _vm->loadFile(filename); + egaStream->read(_egaData, 256); +} + +void Graphics::drawBackgroundImage(const char *filename) { + // Draw an stjr BGD image (palette built-in) + + SharedPtr imageStream = _vm->loadFile(filename); + byte *palette = new byte[256 * 3]; + imageStream->read(palette, 256 * 3); + + // Expand color components + for (uint16 i = 0; i < 256 * 3; i++) + palette[i] <<= 2; + + uint16 xoffset = imageStream->readUint16LE(); + uint16 yoffset = imageStream->readUint16LE(); + uint16 width = imageStream->readUint16LE(); + uint16 height = imageStream->readUint16LE(); + + byte *pixels = new byte[width * height]; + imageStream->read(pixels, width * height); + + _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); + _vm->_system->copyRectToScreen(pixels, width, xoffset, yoffset, width, height); + _vm->_system->updateScreen(); + + delete[] palette; +} + } diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index 277c63615c..758f327d6b 100644 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -70,18 +70,17 @@ public: Graphics(StarTrekEngine *vm); ~Graphics(); - void loadEGAData(const char *egaFile); - void drawBackgroundImage(const char *filename); - + void setBackgroundImage(SharedPtr bitmap); void loadPalette(const String &paletteFile); void loadPri(const char *priFile); + void clearPri(); + byte getPriValue(int x, int y); SharedPtr loadBitmap(String basename); Common::Point getMousePos(); void setMouseCursor(SharedPtr bitmap); - void redrawScreen(); void drawSprite(const Sprite &sprite); void drawSprite(const Sprite &sprite, const Common::Rect &rect); void drawAllSprites(); @@ -89,18 +88,19 @@ public: void addSprite(Sprite *sprite); void delSprite(Sprite *sprite); + + void drawDirectToScreen(SharedPtr bitmap); + void loadEGAData(const char *egaFile); + void drawBackgroundImage(const char *filename); private: - void drawBitmapToScreen(Bitmap *bitmap); - - StarTrekEngine *_vm; Font *_font; bool _egaMode; byte *_egaData; - byte *_priData; byte *_lutData; + byte _priData[SCREEN_WIDTH*SCREEN_HEIGHT / 2]; Common::Rect _screenRect; SharedPtr _backgroundImage; @@ -156,11 +156,13 @@ public: private: int16 _textDisplayMode; + +public: uint32 _textboxVar2; - uint32 _textboxVar3; uint16 _textboxVar6; bool _textboxHasMultipleChoices; +private: SharedPtr _activeMenu; // Saved value of StarTrekEngine::_keyboardControlsMouse when menus are up diff --git a/engines/startrek/module.mk b/engines/startrek/module.mk index 9114de4632..3b93fbc439 100644 --- a/engines/startrek/module.mk +++ b/engines/startrek/module.mk @@ -9,6 +9,7 @@ MODULE_OBJS = \ font.o \ lzss.o \ graphics.o \ + object.o \ room.o \ sound.o \ sprite.o \ diff --git a/engines/startrek/object.cpp b/engines/startrek/object.cpp new file mode 100644 index 0000000000..aafa138ffe --- /dev/null +++ b/engines/startrek/object.cpp @@ -0,0 +1,27 @@ +/* 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 "object.h" + +namespace StarTrek { + +} diff --git a/engines/startrek/object.h b/engines/startrek/object.h new file mode 100644 index 0000000000..41bf1f96c2 --- /dev/null +++ b/engines/startrek/object.h @@ -0,0 +1,83 @@ +/* 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. + * + */ + +#ifndef STARTREK_OBJECT_H +#define STARTREK_OBJECT_H + +#include "startrek/sprite.h" + +#include "common/scummsys.h" + +namespace StarTrek { + +class StarTrekEngine; +class FileStream; + + +struct Object { + uint16 spriteDrawn; + char animationString3[16]; + uint16 animType; + Sprite sprite; + char animationString4[10]; + uint16 scale; + SharedPtr animFile; + uint16 numAnimFrames; + uint16 animFrame; + uint32 frameToStartNextAnim; + uint16 field5e; + uint16 field60; + uint16 field62; + uint16 field64; + uint16 field66; + char animationString2[8]; + uint16 field70; + uint16 field72; + uint16 field74; + uint16 field76; + uint16 iwSrcPosition; + uint16 iwDestPosition; + uint16 field7c; + uint16 field7e; + uint16 field80; + uint16 field82; + uint16 field84; + uint16 field86; + uint16 field88; + uint16 field8a; + uint16 field8c; + uint16 field8e; + uint16 field90; + uint16 field92; + uint16 field94; + uint16 field96; + char animationString[9]; + uint8 fielda1; + uint16 fielda2; + uint16 fielda4; + uint16 fielda6; +}; + +} + +#endif + diff --git a/engines/startrek/room.cpp b/engines/startrek/room.cpp index 3516aaa437..a68737454f 100644 --- a/engines/startrek/room.cpp +++ b/engines/startrek/room.cpp @@ -31,7 +31,7 @@ namespace StarTrek { Room::Room(StarTrekEngine *vm, Common::String name) : _vm(vm) { - SharedPtr rdfFile = _vm->openFile(name + ".RDF"); + SharedPtr rdfFile = _vm->loadFile(name + ".RDF"); int size = rdfFile->size(); _rdfData = new byte[size]; diff --git a/engines/startrek/sound.cpp b/engines/startrek/sound.cpp index 2871a88613..105b3a0b7a 100644 --- a/engines/startrek/sound.cpp +++ b/engines/startrek/sound.cpp @@ -149,6 +149,9 @@ void Sound::playMidiMusicTracks(int startTrack, int loopTrack) { playMidiTrackInSlot(0, startTrack); } +/** + * TODO: original game had some caching of loaded voc files. + */ void Sound::playVoc(const Common::String &baseSoundName) { /* if (_vm->getPlatform() == Common::kPlatformAmiga) @@ -169,7 +172,7 @@ void Sound::playVoc(const Common::String &baseSoundName) { sub_2aaa3(); */ - for (int i=0; i_system->getMixer()->isSoundHandleActive(_sfxHandles[i])) continue; @@ -304,7 +307,7 @@ void Sound::loadPCMusicFile(const Common::String &baseSoundName) { } debugC(5, kDebugSound, "Loading midi \'%s\'\n", soundName.c_str()); - SharedPtr soundStream = _vm->openFile(soundName.c_str()); + SharedPtr soundStream = _vm->loadFile(soundName.c_str()); if (loadedSoundData != nullptr) delete[] loadedSoundData; diff --git a/engines/startrek/sound.h b/engines/startrek/sound.h index 2caa1d0010..6ce4e94a7c 100644 --- a/engines/startrek/sound.h +++ b/engines/startrek/sound.h @@ -82,11 +82,14 @@ private: uint32 _midiDevice; // VOC-related variables - Common::String _loopingAudioName; Audio::SoundHandle _sfxHandles[MAX_SFX_PLAYING]; Audio::SoundHandle _speechHandle; bool _playingSpeech; +public: + Common::String _loopingAudioName; + +private: // Driver callback static void midiDriverCallback(void *data); }; diff --git a/engines/startrek/sprite.h b/engines/startrek/sprite.h index 1e75cc416e..844fb80c35 100644 --- a/engines/startrek/sprite.h +++ b/engines/startrek/sprite.h @@ -63,18 +63,6 @@ struct Sprite { Common::Rect getRect(); }; - -class SpriteList { -public: - SpriteList(int n) { sprites = new Sprite[n]; } - ~SpriteList() { delete[] sprites; } - - Sprite &operator[](int i) const { return sprites[i]; } - -private: - Sprite *sprites; -}; - } #endif diff --git a/engines/startrek/startrek.cpp b/engines/startrek/startrek.cpp index 40fa8d76da..8b05a5a3d2 100644 --- a/engines/startrek/startrek.cpp +++ b/engines/startrek/startrek.cpp @@ -39,14 +39,24 @@ namespace StarTrek { -StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gamedesc) : Engine(syst), _gameDescription(gamedesc) { +StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gamedesc) : + Engine(syst), + _gameDescription(gamedesc), + _kirkObject(&_objectList[0]), + _spockObject(&_objectList[1]), + _mccoyObject(&_objectList[2]), + _redshirtObject(&_objectList[3]) { + DebugMan.addDebugChannel(kDebugSound, "sound", "Sound"); + DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics"); _gfx = nullptr; _sound = nullptr; _macResFork = nullptr; _room = nullptr; + _redshirtDead = false; + _clockTicks = 0; _musicEnabled = true; @@ -82,86 +92,190 @@ Common::Error StarTrekEngine::run() { } initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT); - initializeEventsAndMouse(); - -// Test graphics/music: - -// Music Status: -// DOS Full: Adlib and MT-32 Sounds supported -// DOS Demo: Adlib and MT-32 Sounds supported -// Amiga: Sound effects supported -// Macintosh: MIDI and sound effects playable, format not handled. - -// Graphics Status: -// DOS/Amiga/Macintosh/Demo Graphics: 100% -// Judgment Rites Backgrounds supported too -// EGA not supported + + _frameIndex = 0; + + _gameMode = -1; + _lastGameMode = -1; + + runGameMode(GAMEMODE_BEAMDOWN); + return Common::kNoError; + + #if 1 _room = new Room(this, "DEMON0"); - if (getGameType() == GType_ST25) { - _gfx->loadPalette("PALETTE"); - _gfx->loadPri("DEMON0.PRI"); - _gfx->redrawScreen(); - - _sound->loadMusicFile("GROUND"); - } else { - _gfx->drawBackgroundImage("BRIDGE.BGD"); - } + _gfx->loadPalette("PALETTE"); + _gfx->loadPri("DEMON0.PRI"); - // Sprite tests - - // Draw mode 0 - Sprite *spr = new Sprite; - _gfx->addSprite(spr); - spr->bitmap = _gfx->loadBitmap("MWALKE00"); - spr->drawPriority = 1; - spr->pos.x = 150; - spr->pos.y = 100; - spr->drawMode = 0; - - // Draw mode 2 (translucent background) - spr = new Sprite; - _gfx->addSprite(spr); - spr->bitmap = _gfx->loadBitmap("KWALKS00"); - spr->drawPriority = 1; - spr->pos.x = 230; - spr->pos.y = 100; - spr->drawMode = 2; - - /* - // Draw mode 3 (text) - spr = new Sprite; - _gfx->addSprite(spr); - spr->bitmap = SharedPtr(new TextBitmap(8*8,8*8)); - for (int i=0;i<8*8;i++) - spr->bitmap->pixels[i] = 0x40+i; - spr->pos.x = 8*10; - spr->pos.y = 50; - spr->textColor = 0xb3; - spr->drawMode = 3; - - // initTextSprite function - spr = new Sprite; - int x=0,y=0; - _gfx->initTextSprite(&x, &y, 0xb3, 3, false, spr); - spr->pos.y = 150; - */ + _sound->loadMusicFile("GROUND"); while (true) { _gfx->showOptionsMenu(0, 0); } - _gfx->showText(&Graphics::readTextFromRdf, 0x2220, 150, 160, 0xb3, 0, 10, 0); while (!shouldQuit()) { pollSystemEvents(); } + + return Common::kNoError; #endif +} + +Common::Error StarTrekEngine::runGameMode(int mode) { + _gameMode = mode; + + _sound->stopAllVocSounds(); + if (!_sound->_loopingAudioName.empty()) + _sound->playVoc(_sound->_loopingAudioName); + + if (_gameMode == GAMEMODE_START) + _gameMode = GAMEMODE_BRIDGE; + + while (true) { + if (_gameMode != _lastGameMode) { + // Cleanup previous game mode + switch (_lastGameMode) { + case GAMEMODE_BRIDGE: + //cleanupBridgeMode(); + break; + + case GAMEMODE_AWAYMISSION: + //cleanupAwayMissionMode(); + break; + + case GAMEMODE_BEAMDOWN: + case GAMEMODE_BEAMUP: + break; + } + + _lastGameMode = _gameMode; + + // Load next game mode + switch (_gameMode) { + case GAMEMODE_BRIDGE: + _sound->loadMusicFile("bridge"); + //initBridge(); + break; + + case GAMEMODE_AWAYMISSION: + //initAwayMission(); + break; + + case GAMEMODE_BEAMDOWN: + _redshirtDead = false; + _sound->loadMusicFile("ground"); + runTransportSequence("teled"); + _gameMode = GAMEMODE_AWAYMISSION; + continue; // Back to start of loop + + case GAMEMODE_BEAMUP: + runTransportSequence("teleb"); + _gameMode = GAMEMODE_BRIDGE; + //sub_15c61(); + _sound->stopAllVocSounds(); + _sound->playVoc("bridloop"); + continue; // Back to start of loop + } + } + + // Run current game mode + switch (_gameMode) { + case GAMEMODE_BRIDGE: + //runBridge(); + break; + + case GAMEMODE_AWAYMISSION: + //runAwayMission(); + break; + + case GAMEMODE_BEAMDOWN: + case GAMEMODE_BEAMUP: + error("Can't be here."); + break; + } + } return Common::kNoError; } +void StarTrekEngine::runTransportSequence(const Common::String &name) { + const uint16 crewmanTransportPositions[][2] = { + { 0x8e, 0x7c }, + { 0xbe, 0x7c }, + { 0x7e, 0x72 }, + { 0xaa, 0x72 } + }; + + _sound->stopAllVocSounds(); + // sub_1e70d(); + objectFunc1(); + initObjects(); + + SharedPtr bgImage = _gfx->loadBitmap("transprt"); + _gfx->setBackgroundImage(bgImage); + _gfx->clearPri(); + _gfx->loadPalette("palette"); + _gfx->drawDirectToScreen(bgImage); + _system->updateScreen(); + + for (int i = 0; i < (_redshirtDead ? 3 : 4); i++) { + Common::String filename = getCrewmanAnimFilename(i, name); + int x = crewmanTransportPositions[i][0]; + int y = crewmanTransportPositions[i][1]; + loadAnimationForObject(i, filename, x, y, 256); + _objectList[i].animationString[0] = '\0'; + } + + if (_missionToLoad.equalsIgnoreCase("feather") && name[4] == 'b') { + loadAnimationForObject(9, "qteleb", 0x61, 0x79, 0x100); + } + else if (_missionToLoad.equalsIgnoreCase("trial")) { + if (name[4] == 'd') { + loadAnimationForObject(9, "qteled", 0x61, 0x79, 0x100); + } + /* TODO + else if (word_51156 >= 3) { + loadAnimationForObject(9, "qteleb", 0x61, 0x79, 0x100); + } + */ + } + + loadAnimationForObject(8, "transc", 0, 0, 0x100); + + // TODO: redraw mouse and sprite_52c4e? + + _gfx->drawAllSprites(); + // sub_1e6ab(); + + playSoundEffectIndex(0x0a); + + if (name.equalsIgnoreCase("teled")) + playSoundEffectIndex(0x08); + else + playSoundEffectIndex(0x09); + + while (_objectList[0].field62 == 0) { + TrekEvent event; + if (popNextEvent(&event)) { + if (event.type == TREKEVENT_TICK) { + // TODO: redraw sprite_52c4e? + _frameIndex++; + updateObjectAnimations(); + _gfx->drawAllSprites(); + } + } + } + + // TODO: redraw sprite_52c4e? + + _gfx->drawAllSprites(); + // sub_1e70d(); + objectFunc1(); + initObjects(); +} + Room *StarTrekEngine::getRoom() { return _room; } @@ -191,13 +305,19 @@ void StarTrekEngine::pollSystemEvents() { break; } } - _gfx->drawAllSprites(); + + // FIXME: get the actual duration of a tick right + _clockTicks++; + TrekEvent tickEvent; + tickEvent.type = TREKEVENT_TICK; + tickEvent.tick = _clockTicks; + addEventToQueue(tickEvent); _system->delayMillis(1000/60); } void StarTrekEngine::playSoundEffectIndex(int index) { - switch(index) { + switch (index) { case 0x04: _sound->playVoc("tricorde"); break; @@ -256,14 +376,262 @@ void StarTrekEngine::stopPlayingSpeech() { _sound->stopPlayingSpeech(); } +void StarTrekEngine::initObjects() { + for (int i = 0; i < MAX_OBJECTS; i++) { + _objectList[i] = Object(); + } + for (int i = 0; i < MAX_OBJECTS / 2; i++) + _objectBanFiles[i].reset(); + + strcpy(_kirkObject->animationString, "kstnd"); + strcpy(_spockObject->animationString, "sstnd"); + strcpy(_mccoyObject->animationString, "mstnd"); + strcpy(_redshirtObject->animationString, "rstnd"); +} + +int StarTrekEngine::loadAnimationForObject(int objectIndex, const Common::String &animName, uint16 x, uint16 y, uint16 arg8) { + debugC(6, kDebugGraphics, "Load animation '%s' on object %d", animName.c_str(), objectIndex); + + Object *object; + + if (objectIndex == -1) { + // TODO + } + else + object = &_objectList[objectIndex]; + + if (object->spriteDrawn) { + releaseAnim(object); + drawObjectToScreen(object, animName, x, y, arg8, false); + } + else { + drawObjectToScreen(object, animName, x, y, arg8, true); + } + + object->field64 = 0; + object->field66 = 0; + + return objectIndex; +} + +void StarTrekEngine::updateObjectAnimations() { + for (int i = 0; i < MAX_OBJECTS; i++) { + Object *object = &_objectList[i]; + if (!object->spriteDrawn) + continue; + + switch (object->animType) { + case 0: + case 2: + if (object->frameToStartNextAnim >= _frameIndex) { + int nextAnimIndex = 0; // TODO: "chooseNextAnimFrame" function + object->animFile->seek(18 + nextAnimIndex + object->animFrame * 22, SEEK_SET); + byte nextAnimFrame = object->animFile->readByte(); + + debugC(7, kDebugGraphics, "Object %d animation frame %d", i, nextAnimFrame); + + if (object->animFrame != nextAnimFrame) { + if (nextAnimFrame == object->numAnimFrames - 1) { + object->field62++; + if (object->field64 != 0) { + // sub_20099(10, object->field66, 0, 0); + } + } + } + + object->animFrame = nextAnimFrame; + if (object->animFrame >= object->numAnimFrames) { + if (object->animationString[0] == '\0') + removeObjectFromScreen(i); + /* + else // TODO + initStandAnim(i); + */ + } + else { + Sprite *sprite = &object->sprite; + + object->animFile->seek(object->animFrame * 22, SEEK_SET); + char animFrameFilename[16]; + object->animFile->read(animFrameFilename, 16); + sprite->setBitmap(loadAnimationFrame(animFrameFilename, object->scale)); + + memset(object->animationString4, 0, 16); + strncpy(object->animationString4, animFrameFilename, 15); + + object->animFile->seek(10, SEEK_SET); + uint16 xOffset = object->animFile->readUint16(); + uint16 yOffset = object->animFile->readUint16(); + uint16 basePriority = object->animFile->readUint16(); + + sprite->pos.x = xOffset + object->field5e; + sprite->pos.y = yOffset + object->field60; + sprite->drawPriority = _gfx->getPriValue(0, yOffset + object->field60) + basePriority; + sprite->bitmapChanged = true; + + object->frameToStartNextAnim = object->animFile->readUint16() + _frameIndex; + } + } + break; + case 1: // TODO + warning("Unimplemented anim type %d", object->animType); + break; + default: + error("Invalid anim type."); + break; + } + } +} + +void StarTrekEngine::removeObjectFromScreen(int objectIndex) { + Object *object = &_objectList[objectIndex]; + + if (object->spriteDrawn != 1) + return; + + debugC(6, kDebugGraphics, "Stop drawing object %d", objectIndex); + + Sprite *sprite = &object->sprite; + sprite->field16 = true; + sprite->bitmapChanged = true; + _gfx->drawAllSprites(); + _gfx->delSprite(sprite); + releaseAnim(object); +} + +void StarTrekEngine::objectFunc1() { + for (int i = 0; i < MAX_OBJECTS; i++) { + if (_objectList[i].spriteDrawn == 1) { + removeObjectFromScreen(i); + } + } + + for (int i = 0; i < MAX_OBJECTS / 2; i++) { + _objectBanFiles[i].reset(); + } +} + +void StarTrekEngine::drawObjectToScreen(Object *object, const Common::String &_animName, uint16 x, uint16 y, uint16 arg8, bool addSprite) { + Common::String animFilename = _animName; + if (_animName.hasPrefixIgnoreCase("stnd") /* && word_45d20 == -1 */) // TODO + animFilename += 'j'; + memcpy(object->animationString3, _animName.c_str(), sizeof(object->animationString3)); + + object->animType = 2; + object->animFile = loadFile(animFilename + ".anm"); + object->numAnimFrames = object->animFile->size() / 22; + object->animFrame = 0; + object->field5e = x; + object->field60 = y; + object->field62 = 0; + object->scale = arg8; + + object->animFile->seek(16, SEEK_SET); + object->frameToStartNextAnim = object->animFile->readUint16() + _frameIndex; + + char firstFrameFilename[10]; + object->animFile->seek(0, SEEK_SET); + object->animFile->read(firstFrameFilename, 10); + + Sprite *sprite = &object->sprite; + if (addSprite) + _gfx->addSprite(sprite); + + sprite->setBitmap(loadAnimationFrame(firstFrameFilename, arg8)); + memset(object->animationString4, 0, sizeof(char) * 10); + strncpy(object->animationString4, firstFrameFilename, sizeof(char) * 9); + + object->scale = arg8; + + object->animFile->seek(10, SEEK_SET); + uint16 xOffset = object->animFile->readUint16(); + uint16 yOffset = object->animFile->readUint16(); + uint16 basePriority = object->animFile->readUint16(); + + sprite->pos.x = xOffset + object->field5e; + sprite->pos.y = yOffset + object->field60; + sprite->drawPriority = _gfx->getPriValue(0, yOffset + object->field60) + basePriority; + sprite->bitmapChanged = true; + + object->spriteDrawn = 1; +} + +void StarTrekEngine::releaseAnim(Object *object) { + switch (object->animType) { + case 0: + case 2: + object->sprite.bitmap.reset(); + object->animFile.reset(); + break; + case 1: // TODO + warning("Unimplemented anim type %d", object->animType); + break; + default: + error("Invalid anim type."); + break; + } + + object->spriteDrawn = 0; +} + +SharedPtr StarTrekEngine::loadAnimationFrame(const Common::String &filename, uint16 arg2) { + SharedPtr bitmapToReturn; + + char basename[5]; + strncpy(basename, filename.c_str()+1, 4); + basename[4] = '\0'; + + char c = filename[0]; + if ((strcmp(basename, "stnd") == 0 || strcmp(basename, "tele") == 0) + && (c == 'm' || c == 's' || c == 'k' || c == 'r')) { + if (c == 'm') { + bitmapToReturn = _gfx->loadBitmap(filename); + } + else { + // bitmapToReturn = _gfx->loadBitmap(filename + ".$bm"); // FIXME: should be this? + if (bitmapToReturn == nullptr) { + Common::String newFilename = filename; + newFilename.setChar('m', 0); // FIXME: original writes directly to argument; does that affect anything? + bitmapToReturn = _gfx->loadBitmap(newFilename); + } + } + } + else { + // TODO: when loading a bitmap, it passes a different argument than is standard to + // the "file loading with cache" function... + bitmapToReturn = _gfx->loadBitmap(filename); + } + + if (arg2 != 256) { + // TODO + // bitmapToReturn = scaleBitmap(bitmapToReturn, arg2); + } + + return bitmapToReturn; +} + +Common::String StarTrekEngine::getCrewmanAnimFilename(int objectIndex, const Common::String &basename) { + const char *crewmanChars = "ksmr"; + assert(objectIndex >= 0 && objectIndex < 4); + return crewmanChars[objectIndex] + basename; +} + void StarTrekEngine::updateClockTicks() { // TODO (based on DOS interrupt 1A, AH=0; read system clock counter) _clockTicks = 0; } -SharedPtr StarTrekEngine::openFile(Common::String filename, int fileIndex) { +/** + * TODO: + * - Should return nullptr on failure to open a file? + * - This is supposed to cache results, return same FileStream on multiple accesses. + * - This is supposed to read from a "patches" folder which overrides files in the + * packed blob. + */ +SharedPtr StarTrekEngine::loadFile(Common::String filename, int fileIndex) { filename.toUppercase(); + Common::String basename, extension; bool bigEndian = getPlatform() == Common::kPlatformAmiga; @@ -278,11 +646,18 @@ SharedPtr StarTrekEngine::openFile(Common::String filename, int file } } + // FIXME: don't know if this is right, or if it goes here + while (!basename.empty() && basename.lastChar() == ' ') { + basename.erase(basename.size() - 1, 1); + } + + filename = basename + '.' + extension; + // The Judgment Rites demo has its files not in the standard archive if (getGameType() == GType_STJR && (getFeatures() & GF_DEMO)) { Common::File *file = new Common::File(); if (!file->open(filename.c_str())) - error ("Could not find file \'%s\'", filename.c_str()); + error("Could not find file \'%s\'", filename.c_str()); return SharedPtr(new FileStream(file, bigEndian)); } @@ -291,7 +666,7 @@ SharedPtr StarTrekEngine::openFile(Common::String filename, int file if (getPlatform() == Common::kPlatformAmiga) { indexFile = SearchMan.createReadStreamForMember("data000.dir"); if (!indexFile) - error ("Could not open data000.dir"); + error("Could not open data000.dir"); } else if (getPlatform() == Common::kPlatformMacintosh) { indexFile = _macResFork->getResource("Directory"); if (!indexFile) @@ -299,7 +674,7 @@ SharedPtr StarTrekEngine::openFile(Common::String filename, int file } else { indexFile = SearchMan.createReadStreamForMember("data.dir"); if (!indexFile) - error ("Could not open data.dir"); + error("Could not open data.dir"); } uint32 indexOffset = 0; @@ -353,9 +728,9 @@ SharedPtr StarTrekEngine::openFile(Common::String filename, int file if ((basename.lastChar() >= '1' && basename.lastChar() <= '9') || (basename.lastChar() >= 'B' && basename.lastChar() <= 'Z')) { basename.setChar(basename.lastChar()-1, basename.size()-1); - return openFile(basename + "." + extension, fileIndex+1); + return loadFile(basename + "." + extension, fileIndex+1); } else - error ("Could not find file \'%s\'", filename.c_str()); + error("Could not find file \'%s\'", filename.c_str()); } if (fileIndex >= fileCount) diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index 5e81f77a26..6cb175c689 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -36,6 +36,7 @@ #include "startrek/filestream.h" #include "startrek/graphics.h" +#include "startrek/object.h" #include "startrek/room.h" #include "startrek/sound.h" @@ -58,10 +59,25 @@ enum StarTrekGameFeatures { }; enum kDebugLevels { - kDebugSound = 1 << 0 + kDebugSound = 1 << 0, + kDebugGraphics = 1 << 1 }; +enum GameMode { + GAMEMODE_START = 0, + GAMEMODE_BRIDGE, + GAMEMODE_AWAYMISSION, + GAMEMODE_BEAMDOWN, + GAMEMODE_BEAMUP +}; + +enum TextDisplayMode { + TEXTDISPLAY_WAIT = 0, // Wait for input before closing text + TEXTDISPLAY_SUBTITLES, // Automatically continue when speech is done + TEXTDISPLAY_NONE // No text displayed +}; + enum TrekEventType { TREKEVENT_TICK = 0, // DOS clock changes (see updateClockTicks) TREKEVENT_LBUTTONDOWN = 1, @@ -72,12 +88,6 @@ enum TrekEventType { TREKEVENT_KEYDOWN = 6 }; -enum TextDisplayMode { - TEXTDISPLAY_WAIT = 0, // Wait for input before closing text - TEXTDISPLAY_SUBTITLES, // Automatically continue when speech is done - TEXTDISPLAY_NONE // No text displayed -}; - struct TrekEvent { TrekEventType type; Common::KeyState kbd; @@ -85,6 +95,8 @@ struct TrekEvent { uint32 tick; }; +const int MAX_OBJECTS = 0x20; + struct StarTrekGameDescription; class Graphics; class Sound; @@ -93,6 +105,11 @@ class StarTrekEngine : public ::Engine { protected: Common::Error run(); +private: + // Game modes + Common::Error runGameMode(int mode); + void runTransportSequence(const Common::String &name); + public: StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gamedesc); virtual ~StarTrekEngine(); @@ -105,6 +122,18 @@ public: void playSpeech(const Common::String &filename); void stopPlayingSpeech(); + // Objects + void initObjects(); + int loadAnimationForObject(int objectIndex, const Common::String &animName, uint16 x, uint16 y, uint16 arg8); + void updateObjectAnimations(); + void removeObjectFromScreen(int objectIndex); + void objectFunc1(); + void drawObjectToScreen(Object *object, const Common::String &animName, uint16 field5e, uint16 field60, uint16 arg8, bool addSprite); + void releaseAnim(Object *object); + + SharedPtr loadAnimationFrame(const Common::String &filename, uint16 arg2); + Common::String getCrewmanAnimFilename(int objectIndex, const Common::String &basename); + // Events public: void initializeEventsAndMouse(); @@ -138,14 +167,30 @@ public: Common::Language getLanguage(); // Resource related functions - SharedPtr openFile(Common::String filename, int fileIndex=0); + SharedPtr loadFile(Common::String filename, int fileIndex=0); // Movie related functions void playMovie(Common::String filename); void playMovieMac(Common::String filename); +public: + int _gameMode; + int _lastGameMode; + bool _redshirtDead; + Common::String _missionToLoad; + + Object _objectList[MAX_OBJECTS]; + Object * const _kirkObject; + Object * const _spockObject; + Object * const _mccoyObject; + Object * const _redshirtObject; + + SharedPtr _objectBanFiles[MAX_OBJECTS / 2]; + uint16 _objectBanVar2[MAX_OBJECTS / 2]; // TODO: initialize? + uint32 _clockTicks; + uint32 _frameIndex; bool _musicEnabled; bool _sfxEnabled; diff --git a/engines/startrek/text.cpp b/engines/startrek/text.cpp index 923ebc6c8b..ef5a746756 100644 --- a/engines/startrek/text.cpp +++ b/engines/startrek/text.cpp @@ -68,7 +68,7 @@ int Graphics::showText(TextGetterFunc textGetter, uintptr var, int xoffset, int int16 tmpTextDisplayMode = _textDisplayMode; uint32 var7c = 8; - if (_textboxVar3 > _textboxVar2+1) { + if (_vm->_frameIndex > _textboxVar2+1) { var7c = 0x10; } @@ -291,7 +291,7 @@ reloadText: // sub_272B4 } - _textboxVar2 = _textboxVar3; + _textboxVar2 = _vm->_frameIndex; _vm->stopPlayingSpeech(); return choiceIndex; } @@ -347,7 +347,7 @@ int Graphics::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4) { } } // sub_1E88C(); - _textboxVar3++; + _vm->_frameIndex++; if (ticksUntilClickingEnabled != 0 && _vm->_clockTicks >= tickWhenClickingEnabled) return MENUEVENT_ENABLEINPUT; @@ -818,7 +818,7 @@ void Graphics::loadMenuButtons(String mnuFilename, int xpos, int ypos) { _activeMenu = SharedPtr(new Menu()); _activeMenu->nextMenu = oldMenu; - SharedPtr stream = _vm->openFile(mnuFilename + ".MNU"); + SharedPtr stream = _vm->loadFile(mnuFilename + ".MNU"); _activeMenu->menuFile = stream; _activeMenu->numButtons = _activeMenu->menuFile->size() / 16; -- cgit v1.2.3