From bd1b9f66cb7073a0548d67bca3f41dbb21606a69 Mon Sep 17 00:00:00 2001 From: Matthew Stewart Date: Fri, 3 Aug 2018 05:16:57 -0400 Subject: STARTREK: Implement republic map screen --- engines/startrek/graphics.cpp | 191 +++++++++++++++++----------------- engines/startrek/graphics.h | 1 + engines/startrek/menu.cpp | 218 +++++++++++++++++++++++++++++++++++++++ engines/startrek/room.cpp | 4 + engines/startrek/room.h | 4 + engines/startrek/rooms/veng0.cpp | 2 +- engines/startrek/startrek.h | 14 +++ 7 files changed, 339 insertions(+), 95 deletions(-) diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index 53bdf38680..023ca99b57 100644 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -221,6 +221,10 @@ void Graphics::clearPri() { memset(_priData, 0, sizeof(_priData)); } +void Graphics::setPri(byte val) { + memset(_priData, val, sizeof(_priData)); +} + byte Graphics::getPriValue(int x, int y) { assert(_screenRect.contains(x, y)); @@ -459,128 +463,127 @@ bool compareSpritesByLayer(Sprite *s1, Sprite *s2) { void Graphics::drawAllSprites(bool updateScreen) { // TODO: different video modes? - if (_numSprites == 0) - return; - - // Sort sprites by layer - Common::sort(_sprites, _sprites + _numSprites, &compareSpritesByLayer); - - // Update sprite rectangles - for (int i = 0; i < _numSprites; i++) { - Sprite *spr = _sprites[i]; - Common::Rect rect; - - rect.left = spr->pos.x - spr->bitmap->xoffset; - rect.top = spr->pos.y - spr->bitmap->yoffset; - rect.right = rect.left + spr->bitmap->width; - rect.bottom = rect.top + spr->bitmap->height; - - spr->drawX = rect.left; - spr->drawY = rect.top; - - spr->drawRect = rect.findIntersectingRect(_screenRect); - - if (!spr->drawRect.isEmpty()) { // At least partly on-screen - if (spr->lastDrawRect.left < spr->lastDrawRect.right) { - // If the sprite's position is close to where it was last time it was - // drawn, combine the two rectangles and redraw that whole section. - // Otherwise, redraw the old position and current position separately. - rect = spr->drawRect.findIntersectingRect(spr->lastDrawRect); - - if (rect.isEmpty()) - spr->rect2Valid = 0; - else { - spr->rectangle2 = getRectEncompassing(spr->drawRect, spr->lastDrawRect); + if (_numSprites != 0) { + // Sort sprites by layer + Common::sort(_sprites, _sprites + _numSprites, &compareSpritesByLayer); + + // Update sprite rectangles + for (int i = 0; i < _numSprites; i++) { + Sprite *spr = _sprites[i]; + Common::Rect rect; + + rect.left = spr->pos.x - spr->bitmap->xoffset; + rect.top = spr->pos.y - spr->bitmap->yoffset; + rect.right = rect.left + spr->bitmap->width; + rect.bottom = rect.top + spr->bitmap->height; + + spr->drawX = rect.left; + spr->drawY = rect.top; + + spr->drawRect = rect.findIntersectingRect(_screenRect); + + if (!spr->drawRect.isEmpty()) { // At least partly on-screen + if (spr->lastDrawRect.left < spr->lastDrawRect.right) { + // If the sprite's position is close to where it was last time it was + // drawn, combine the two rectangles and redraw that whole section. + // Otherwise, redraw the old position and current position separately. + rect = spr->drawRect.findIntersectingRect(spr->lastDrawRect); + + if (rect.isEmpty()) + spr->rect2Valid = 0; + else { + spr->rectangle2 = getRectEncompassing(spr->drawRect, spr->lastDrawRect); + spr->rect2Valid = 1; + } + } else { + spr->rectangle2 = spr->drawRect; spr->rect2Valid = 1; } - } else { - spr->rectangle2 = spr->drawRect; - spr->rect2Valid = 1; - } - spr->isOnScreen = 1; - } else { // Off-screen - spr->rect2Valid = 0; - spr->isOnScreen = 0; + spr->isOnScreen = 1; + } else { // Off-screen + spr->rect2Valid = 0; + spr->isOnScreen = 0; + } } - } - // Determine what portions of the screen need to be updated - Common::Rect dirtyRects[MAX_SPRITES * 2]; - int numDirtyRects = 0; + // Determine what portions of the screen need to be updated + Common::Rect dirtyRects[MAX_SPRITES * 2]; + int numDirtyRects = 0; - for (int i = 0; i < _numSprites; i++) { - Sprite *spr = _sprites[i]; + for (int i = 0; i < _numSprites; i++) { + Sprite *spr = _sprites[i]; - if (spr->bitmapChanged) { - if (spr->isOnScreen) { - if (spr->rect2Valid) { - dirtyRects[numDirtyRects++] = spr->rectangle2; + if (spr->bitmapChanged) { + if (spr->isOnScreen) { + if (spr->rect2Valid) { + dirtyRects[numDirtyRects++] = spr->rectangle2; + } else { + dirtyRects[numDirtyRects++] = spr->drawRect; + dirtyRects[numDirtyRects++] = spr->lastDrawRect; + } } else { - dirtyRects[numDirtyRects++] = spr->drawRect; dirtyRects[numDirtyRects++] = spr->lastDrawRect; } - } else { - dirtyRects[numDirtyRects++] = spr->lastDrawRect; } } - } - // Redraw the background on every dirty rectangle - const ::Graphics::PixelFormat format = ::Graphics::PixelFormat::createFormatCLUT8(); - ::Graphics::Surface surface; - surface.create(SCREEN_WIDTH, SCREEN_HEIGHT, format); + // Redraw the background on every dirty rectangle + const ::Graphics::PixelFormat format = ::Graphics::PixelFormat::createFormatCLUT8(); + ::Graphics::Surface surface; + surface.create(SCREEN_WIDTH, SCREEN_HEIGHT, format); - for (int i = 0; i < numDirtyRects; i++) { - Common::Rect &r = dirtyRects[i]; - if (r.width() == 0 || r.height() == 0) - continue; + for (int i = 0; i < numDirtyRects; i++) { + Common::Rect &r = dirtyRects[i]; + if (r.width() == 0 || r.height() == 0) + continue; - int offset = r.top * SCREEN_WIDTH + r.left; - surface.copyRectToSurface(_backgroundImage->pixels + offset, SCREEN_WIDTH, r.left, r.top, r.width(), r.height()); - } + int offset = r.top * SCREEN_WIDTH + r.left; + surface.copyRectToSurface(_backgroundImage->pixels + offset, SCREEN_WIDTH, r.left, r.top, r.width(), r.height()); + } - // For each sprite, merge the rectangles that overlap with it and redraw the sprite. - for (int i = 0; i < _numSprites; i++) { - Sprite *spr = _sprites[i]; + // For each sprite, merge the rectangles that overlap with it and redraw the sprite. + for (int i = 0; i < _numSprites; i++) { + Sprite *spr = _sprites[i]; - if (!spr->field16 && spr->isOnScreen) { - bool mustRedrawSprite = false; - Common::Rect rect2; + if (!spr->field16 && spr->isOnScreen) { + bool mustRedrawSprite = false; + Common::Rect rect2; - for (int j = 0; j < numDirtyRects; j++) { - Common::Rect rect1 = spr->drawRect.findIntersectingRect(dirtyRects[j]); + for (int j = 0; j < numDirtyRects; j++) { + Common::Rect rect1 = spr->drawRect.findIntersectingRect(dirtyRects[j]); - if (rect1.width() != 0 && rect1.height() != 0) { - if (mustRedrawSprite) - rect2 = getRectEncompassing(rect1, rect2); - else - rect2 = rect1; - mustRedrawSprite = true; + if (rect1.width() != 0 && rect1.height() != 0) { + if (mustRedrawSprite) + rect2 = getRectEncompassing(rect1, rect2); + else + rect2 = rect1; + mustRedrawSprite = true; + } } + + if (mustRedrawSprite) + drawSprite(*spr, &surface, rect2); } - if (mustRedrawSprite) - drawSprite(*spr, &surface, rect2); + spr->field16 = false; + spr->bitmapChanged = false; + spr->lastDrawRect = spr->drawRect; } - spr->field16 = false; - spr->bitmapChanged = false; - spr->lastDrawRect = spr->drawRect; - } + // Copy dirty rects to screen + for (int j = 0; j < numDirtyRects; j++) { + Common::Rect &r = dirtyRects[j]; + if (r.width() == 0 || r.height() == 0) + continue; - // Copy dirty rects to screen - for (int j = 0; j < numDirtyRects; j++) { - Common::Rect &r = dirtyRects[j]; - if (r.width() == 0 || r.height() == 0) - continue; + int offset = r.left + r.top * SCREEN_WIDTH; + _vm->_system->copyRectToScreen((byte *)surface.getPixels() + offset, SCREEN_WIDTH, r.left, r.top, r.width(), r.height()); + } - int offset = r.left + r.top * SCREEN_WIDTH; - _vm->_system->copyRectToScreen((byte *)surface.getPixels() + offset, SCREEN_WIDTH, r.left, r.top, r.width(), r.height()); + surface.free(); } - surface.free(); - if (updateScreen) this->updateScreen(); } diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index 46709cdd38..8ba46f2d66 100644 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -81,6 +81,7 @@ public: void loadPri(const Common::String &priFile); void clearPri(); + void setPri(byte val); byte getPriValue(int x, int y); SharedPtr loadBitmap(String basename); diff --git a/engines/startrek/menu.cpp b/engines/startrek/menu.cpp index 13ca59bc60..72730fdc1e 100644 --- a/engines/startrek/menu.cpp +++ b/engines/startrek/menu.cpp @@ -1010,4 +1010,222 @@ void StarTrekEngine::saveTextDisplayMode(int value) { // TODO; } +void StarTrekEngine::showRepublicMap(int16 arg0, int16 turbolift) { + _gfx->fadeoutScreen(); + _sound->stopAllVocSounds(); + + bool spriteLoaded = false; + int16 clickedArea = 0; + + actorFunc1(); + _gfx->pushSprites(); + + if (!_awayMission.veng.scannedComputerBank) { + _gfx->setBackgroundImage(_gfx->loadBitmap("veng9b")); + _gfx->copyBackgroundScreen(); + _system->updateScreen(); + _gfx->setPri(15); + _gfx->fadeinScreen(); + + // TODO: hide mouse sprite? + + bool exitLoop = 0; + int16 var54 = 0x2d; + + while (!exitLoop) { + TrekEvent event; + if (!popNextEvent(&event)) + continue; + + switch (event.type) { + case TREKEVENT_TICK: + if (--var54 == 0) + exitLoop = true; + break; + + case TREKEVENT_LBUTTONDOWN: + case TREKEVENT_RBUTTONDOWN: + exitLoop = true; + break; + + case TREKEVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_SPACE: + exitLoop = true; + break; + + default: + break; + } + break; + + default: + break; + } + } + + _awayMission.veng.scannedComputerBank = true; // FIXME? + _gfx->fadeoutScreen(); + } + + _gfx->setBackgroundImage(_gfx->loadBitmap("veng9")); + _gfx->copyBackgroundScreen(); + _system->updateScreen(); + _gfx->setPri(15); + + Sprite someSprite; + _gfx->drawAllSprites(); + _gfx->warpMouse(_gfx->getMousePos().x, 96); + _gfx->fadeinScreen(); + + bool exitLoop = false; + + while (!exitLoop) { + TrekEvent event; + if (!popNextEvent(&event)) + continue; + + switch (event.type) { + case TREKEVENT_TICK: + _frameIndex++; + // sub_12fff(); + _gfx->drawAllSprites(); + break; + + case TREKEVENT_LBUTTONDOWN: { +lclick: + clickedArea = getRepublicMapAreaOrFailure(turbolift); + if (clickedArea == 0) { + } else if (clickedArea == 6) { + Common::String text = "#GENE\\GENE_F14#Turbolift access is blocked by an extremely high radiation level."; + showTextbox("", text, 50, 50, TEXTCOLOR_YELLOW, 0); + } else if (clickedArea == 7) { + Common::String text = "#GENE\\GENE_F15#This turbolift cannot reach that area of the ship."; + showTextbox("", text, 50, 50, TEXTCOLOR_YELLOW, 0); + } else + exitLoop = true; + break; + } + + case TREKEVENT_MOUSEMOVE: { + if (_gfx->getMousePos().y < 96) // TODO: more elegant solution + _gfx->warpMouse(_gfx->getMousePos().x, 96); + + clickedArea = getRepublicMapAreaAtMouse(); + if (clickedArea != 0) { + if (!spriteLoaded) { + _gfx->addSprite(&someSprite); + someSprite.setXYAndPriority(3, 168, 15); + someSprite.bitmap = _gfx->loadBitmap(Common::String::format("turbo%d", clickedArea)); + spriteLoaded = true; + } + } else { + if (spriteLoaded) { + someSprite.dontDrawNextFrame(); + _gfx->drawAllSprites(); + _gfx->delSprite(&someSprite); + someSprite.bitmap.reset(); + spriteLoaded = false; + } + } + break; + } + + case TREKEVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_F1: + goto lclick; + + default: + break; + } + break; + + default: + break; + } + } + + _gfx->fadeoutScreen(); + someSprite.bitmap.reset(); + _gfx->popSprites(); + + _gfx->loadPri(_screenName); + _gfx->setBackgroundImage(_gfx->loadBitmap(_screenName)); + _gfx->copyBackgroundScreen(); + _system->updateScreen(); + + _gfx->drawAllSprites(); + + int16 roomIndex, spawnIndex; + if (clickedArea == 1) { + roomIndex = 0; + spawnIndex = 1; + } else if (clickedArea == 2) { + roomIndex = 1; + spawnIndex = 1; + } else if (clickedArea == 3 && turbolift == 0) { + roomIndex = 3; + spawnIndex = 1; + } else if (clickedArea == 3 && turbolift == 1) { + roomIndex = 3; + spawnIndex = 0; + } else if (clickedArea == 4) { + roomIndex = 5; + spawnIndex = 1; + } else if (clickedArea == 5) { + roomIndex = 7; + spawnIndex = 1; + } else { + warning("Unknown room selected"); + roomIndex = 0; + spawnIndex = 1; + } + + _roomIndexToLoad = roomIndex; + _spawnIndexToLoad = spawnIndex; +} + +int StarTrekEngine::getRepublicMapAreaAtMouse() { + Common::Point mouse = _gfx->getMousePos(); + + if (mouse.x >= 0x7f && mouse.x <= 0x91 && mouse.y >= 0x78 && mouse.y <= 0x7b) + return 1; + else if (mouse.x >= 0x6e && mouse.x <= 0x7e && mouse.y >= 0x83 && mouse.y <= 0x87) + return 2; + else if (mouse.x >= 0x95 && mouse.x <= 0xad && mouse.y >= 0x8f && mouse.y <= 0x93) + return 3; + else if (mouse.x >= 0xef && mouse.x <= 0xfd && mouse.y >= 0x98 && mouse.y <= 0xa0) + return 4; + else if (mouse.x >= 0x6b && mouse.x <= 0x80 && mouse.y >= 0xa3 && mouse.y <= 0xa7) + return 5; + else if (mouse.x >= 0x6e && mouse.x <= 0x88 && mouse.y >= 0xab && mouse.y <= 0xaf) + return 6; + else + return 0; +} + +int StarTrekEngine::getRepublicMapAreaOrFailure(int16 turbolift) { + Common::Point mouse = _gfx->getMousePos(); + + if (mouse.x >= 0x7f && mouse.x <= 0x91 && mouse.y >= 0x78 && mouse.y <= 0x7b) + return turbolift == 0 ? 1 : 7; + else if (mouse.x >= 0x6e && mouse.x <= 0x7e && mouse.y >= 0x83 && mouse.y <= 0x87) + return turbolift == 0 ? 2 : 7; + else if (mouse.x >= 0x95 && mouse.x <= 0xad && mouse.y >= 0x8f && mouse.y <= 0x93) + return 3; + else if (mouse.x >= 0xef && mouse.x <= 0xfd && mouse.y >= 0x98 && mouse.y <= 0xa0) + return turbolift == 1 ? 4 : 7; + else if (mouse.x >= 0x6b && mouse.x <= 0x80 && mouse.y >= 0xa3 && mouse.y <= 0xa7) + return turbolift == 1 ? 5 : 7; + else if (mouse.x >= 0x6e && mouse.x <= 0x88 && mouse.y >= 0xab && mouse.y <= 0xaf) + return 6; + return 0; +} + } // End of namespace StarTrek diff --git a/engines/startrek/room.cpp b/engines/startrek/room.cpp index 6a72537b46..a86d31b3d0 100644 --- a/engines/startrek/room.cpp +++ b/engines/startrek/room.cpp @@ -503,6 +503,10 @@ int Room::showCodeInputBox(const char * const *codes) { return retval; } +void Room::showRepublicMap(int16 arg0, int16 arg2) { + _vm->showRepublicMap(arg0, arg2); +} + void Room::playVoc(Common::String filename) { _vm->_sound->playVoc(filename); } diff --git a/engines/startrek/room.h b/engines/startrek/room.h index 876ffe14d0..9712ee97f4 100644 --- a/engines/startrek/room.h +++ b/engines/startrek/room.h @@ -245,6 +245,10 @@ private: * code (plus one), or 0 if no code was matched. */ int showCodeInputBox(const char * const *codes); + /** + * Cmd 0x14: Show a map of the republic for mission 7 + */ + void showRepublicMap(int16 arg0, int16 arg2); /** * Cmd 0x15 */ diff --git a/engines/startrek/rooms/veng0.cpp b/engines/startrek/rooms/veng0.cpp index 76d960381a..c29033655c 100644 --- a/engines/startrek/rooms/veng0.cpp +++ b/engines/startrek/rooms/veng0.cpp @@ -144,7 +144,7 @@ void Room::veng0Tick50() { void Room::veng0TouchedDoor() { playSoundEffectIndex(SND_DOOR1); - // TODO + showRepublicMap(0, 0); } void Room::veng0UseSTricorderOnComputerBank() { diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index f96c7b88f3..373778e36a 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -626,6 +626,20 @@ public: int loadTextDisplayMode(); void saveTextDisplayMode(int value); + /** + * Show the republic map, only used in mission 7. + */ + void showRepublicMap(int16 arg0, int16 turbolift); + /** + * Checks the mouse position to return and index for the area selected. + */ + int getRepublicMapAreaAtMouse(); + /** + * Same as above, but returns 6 or 7 as error conditions (can't reach due to radiation + * or wrong turbolift). + */ + int getRepublicMapAreaOrFailure(int16 turbolift); + private: int16 _textDisplayMode; -- cgit v1.2.3