diff options
author | Matthew Stewart | 2018-05-17 19:35:31 -0400 |
---|---|---|
committer | Eugene Sandulenko | 2018-08-09 08:37:30 +0200 |
commit | 6117a8919432e7223f3e263f7d9c2f84840f76b9 (patch) | |
tree | 5a605ac102264ce9ea41bc11ba14299a10d0460f /engines | |
parent | 02485484c31bee3101ecd3ac7ccb86e2db7b029b (diff) | |
download | scummvm-rg350-6117a8919432e7223f3e263f7d9c2f84840f76b9.tar.gz scummvm-rg350-6117a8919432e7223f3e263f7d9c2f84840f76b9.tar.bz2 scummvm-rg350-6117a8919432e7223f3e263f7d9c2f84840f76b9.zip |
STARTREK: Inventory menu and hotspots
Action buttons now react when hovering over hotspots.
Diffstat (limited to 'engines')
-rw-r--r-- | engines/startrek/awaymission.cpp | 58 | ||||
-rw-r--r-- | engines/startrek/awaymission.h | 3 | ||||
-rw-r--r-- | engines/startrek/graphics.cpp | 28 | ||||
-rw-r--r-- | engines/startrek/graphics.h | 1 | ||||
-rw-r--r-- | engines/startrek/items.h | 184 | ||||
-rw-r--r-- | engines/startrek/menu.cpp | 11 | ||||
-rw-r--r-- | engines/startrek/room.h | 19 | ||||
-rw-r--r-- | engines/startrek/sprite.cpp | 22 | ||||
-rw-r--r-- | engines/startrek/sprite.h | 2 | ||||
-rw-r--r-- | engines/startrek/startrek.cpp | 326 | ||||
-rw-r--r-- | engines/startrek/startrek.h | 24 |
11 files changed, 644 insertions, 34 deletions
diff --git a/engines/startrek/awaymission.cpp b/engines/startrek/awaymission.cpp index aba01c075b..ae05485dcd 100644 --- a/engines/startrek/awaymission.cpp +++ b/engines/startrek/awaymission.cpp @@ -157,7 +157,7 @@ void StarTrekEngine::handleAwayMissionEvents() { case TREKEVENT_TICK: updateObjectAnimations(); // sub_236bb(); - // sub_2325d(); + updateMouseBitmap(); // doSomethingWithBanData1(); _gfx->drawAllSprites(); // doSomethingWithBanData2(); @@ -169,11 +169,13 @@ void StarTrekEngine::handleAwayMissionEvents() { if (_roomFrameCounter >= 2) _gfx->incPaletteFadeLevel(); break; + case TREKEVENT_LBUTTONDOWN: if (_awayMission.transitioningIntoRoom != 0) break; + switch (_awayMission.activeAction) { - case 1: + case ACTION_WALK: if (_awayMission.field1c == 0) { _kirkObject->sprite.drawMode = 1; // Hide these objects for function call below? _spockObject->sprite.drawMode = 1; @@ -193,7 +195,33 @@ void StarTrekEngine::handleAwayMissionEvents() { objectWalkToPosition(0, animFilename, _kirkObject->pos.x, _kirkObject->pos.y, mousePos.x, mousePos.y); } break; - case 2: + + case ACTION_USE: + if (_awayMission.activeItem != OBJECT_REDSHIRT + || (!_awayMission.redshirtDead && !(_awayMission.field24 & 8))) { + int clickedObject = findObjectAt(_gfx->getMousePos()); + hideInventoryIcons(); + + if (clickedObject == OBJECT_INVENTORY_ICON) + clickedObject = showInventoryMenu(50, 50, false); + + if (clickedObject == -1) + clickedObject = -2; + + _awayMission.passiveItem = clickedObject; + if (clickedObject != -2) { + // TODO + } + + // if (!sub_2330c()) // TODO + { + if (clickedObject != -2) + addCommand(Command(_awayMission.activeAction, _awayMission.activeItem, _awayMission.passiveItem, 0)); + + if (!(_awayMission.field24 & 1)) + showInventoryIcons(true); + } + } break; case 3: break; @@ -203,37 +231,39 @@ void StarTrekEngine::handleAwayMissionEvents() { break; } break; + case TREKEVENT_MOUSEMOVE: break; + case TREKEVENT_RBUTTONDOWN: // TODO: also triggered by key press? - /* if (_awayMission.field1d) break; - */ - //sub_2394b(); + hideInventoryIcons(); playSoundEffectIndex(0x07); _awayMission.activeAction = showActionMenu(); - /* - if (awayMission.activeAction == ACTION_USE) { + if (_awayMission.activeAction == ACTION_USE) { + /* int16 clickedObject = sub_22f08(); if (clickedObject == -1) break; else - _awayMission.field20 = clickedObject; + _awayMission.activeItem = clickedObject; + */ } if (_awayMission.activeAction == ACTION_USE - && _awayMission.field20 == 0x47 && (_awayMission.field24 & 1) == 0) { + && _awayMission.activeItem == 0x47 && (_awayMission.field24 & 1) == 0) { + /* if (sub_2330c() == 0) { - addCommand(Command(_awayMission.activeAction, _awayMission.field20, 0, 0)); + addCommand(Command(_awayMission.activeAction, _awayMission.activeItem, 0, 0)); _sound->playVoc("communic"); _awayMission.activeAction = ACTION_WALK; } + */ } else if (_awayMission.activeAction == ACTION_LOOK) - sub_2383a(0); + showInventoryIcons(false); else if (_awayMission.activeAction == ACTION_USE && (_awayMission.field24 & 1) == 0) - sub_2383a(1); - */ + showInventoryIcons(true); break; case TREKEVENT_KEYDOWN: break; diff --git a/engines/startrek/awaymission.h b/engines/startrek/awaymission.h index cb5dfed0f6..c75960334b 100644 --- a/engines/startrek/awaymission.h +++ b/engines/startrek/awaymission.h @@ -32,7 +32,8 @@ struct AwayMission { byte transitioningIntoRoom; // Set while beaming in or walking into a room bool redshirtDead; byte activeAction; - byte field20; + byte activeItem; // The item that is going to be used on something + byte passiveItem; // The item that the active item is used on (or the item looked at, etc). byte field24; int8 field25[4]; diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index a51999e4d3..e33fa519a4 100644 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -552,6 +552,34 @@ void Graphics::drawAllSprites(bool updateScreen) { } } +/** + * Returns the sprite at the given position (ignores mouse). + */ +Sprite *Graphics::getSpriteAt(int16 x, int16 y) { + for (int i = _numSprites - 1; i >= 0; i--) { + Sprite *sprite = _sprites[i]; + + if (sprite == &_lockedMouseSprite) + continue; + if (sprite->drawMode == 1) // Invisible + continue; + + if (sprite->drawRect.contains(Common::Point(x, y))) { + if (sprite->drawMode == 2 || sprite->drawMode == 3) // Button or text + return sprite; + + // For draw mode 0 only, check that we're not clicking on a transparent part. + int16 relX = x - sprite->drawX; + int16 relY = y - sprite->drawY; + byte pixel = sprite->bitmap->pixels[relY * sprite->bitmap->width + relX]; + if (pixel != 0) + return sprite; + } + } + + return nullptr; +} + void Graphics::addSprite(Sprite *sprite) { if (_numSprites >= MAX_SPRITES) error("addSprite: too many sprites"); diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index f58e444a61..5c09cfa702 100644 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -76,6 +76,7 @@ public: void drawSprite(const Sprite &sprite); void drawSprite(const Sprite &sprite, const Common::Rect &rect); void drawAllSprites(bool updateScreen=true); + Sprite *getSpriteAt(int16 x, int16 y); void addSprite(Sprite *sprite); void delSprite(Sprite *sprite); diff --git a/engines/startrek/items.h b/engines/startrek/items.h new file mode 100644 index 0000000000..6ef69cf8ab --- /dev/null +++ b/engines/startrek/items.h @@ -0,0 +1,184 @@ +/* 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_ITEMS_H +#define STARTREK_ITEMS_H + +namespace StarTrek { + +struct Item { + bool have; + int16 field2; + char name[10]; + int16 index; +}; + +// This is copied to StarTrekEngine::_itemList when the engine initializes. +// (TODO: it's possible that only the "have" variable ever changes, in which case the +// whole thing doesn't need to be copied.) +const Item g_itemList[] = { + { true, 0x40, "iphasers", 0x00 }, + { true, 0x41, "iphaserk", 0x01 }, + { false, 0x42, "ihand", 0x02 }, + { false, 0x43, "irock", 0x03 }, + { true, 0x44, "istricor", 0x04 }, + { true, 0x45, "imtricor", 0x05 }, + { false, 0x46, "ideadguy", 0x06 }, + { true, 0x47, "icomm", 0x07 }, + { false, 0x48, "ipbc", 0x08 }, + { false, 0x49, "iRLG", 0x09 }, + { false, 0x4A, "iWrench", 0x0A }, + { false, 0x4B, "iInsulat", 0x0B }, + { false, 0x4C, "iSample", 0x0C }, + { false, 0x4D, "iCure", 0x0D }, + { false, 0x4E, "iDishes", 0x0E }, + { false, 0x4F, "iRT", 0x0F }, + { false, 0x50, "iRTWB", 0x10 }, + { false, 0x51, "iCombBit", 0x11 }, + { false, 0x52, "iJnkmetl", 0x12 }, + { false, 0x53, "iWiring", 0x13 }, + { false, 0x54, "iWirscrp", 0x14 }, + { false, 0x55, "iPWF", 0x15 }, + { false, 0x56, "iPWE", 0x16 }, + { false, 0x57, "iDeadPh", 0x17 }, + { false, 0x58, "iBomb", 0x18 }, + { false, 0x59, "iMetal", 0x19 }, + { false, 0x5A, "iSkull", 0x1A }, + { false, 0x5B, "iMineral", 0x1B }, + { false, 0x5C, "iMeteor", 0x1C }, + { false, 0x5D, "iShells", 0x1D }, + { false, 0x5E, "iDeGrime", 0x1E }, + { false, 0x5F, "iLenses", 0x1F }, + { false, 0x60, "iDisks", 0x20 }, + { false, 0x61, "iAntigra", 0x21 }, + { false, 0x62, "iN2gas", 0x22 }, + { false, 0x63, "iO2gas", 0x23 }, + { false, 0x64, "iH2gas", 0x24 }, + { false, 0x65, "iN2O", 0x25 }, + { false, 0x66, "iNH3", 0x26 }, + { false, 0x67, "iH2O", 0x27 }, + { false, 0x68, "iWRod", 0x28 }, + { false, 0x69, "iIRod", 0x29 }, + { false, 0x6A, "iRedGem", 0x2A }, + { false, 0x6B, "iRedGem", 0x2B }, + { false, 0x6C, "iRedGem", 0x2C }, + { false, 0x6D, "iGrnGem", 0x2D }, + { false, 0x6E, "iGrnGem", 0x2E }, + { false, 0x6F, "iGrnGem", 0x2F }, + { false, 0x70, "iBluGem", 0x30 }, + { false, 0x71, "iBluGem", 0x31 }, + { false, 0x72, "iBluGem", 0x32 }, + { false, 0x73, "iConect", 0x33 }, + { false, 0x74, "iS8Rocks", 0x34 }, + { false, 0x75, "iIDCard", 0x35 }, + { false, 0x76, "iSnake", 0x36 }, + { false, 0x77, "iFern", 0x37 }, + { false, 0x78, "iCrystal", 0x38 }, + { false, 0x79, "iKnife", 0x39 }, + { false, 0x7A, "idetoxin", 0x3A }, + { false, 0x7B, "iberry", 0x3B }, + { false, 0x7C, "idoover", 0x3C }, + { false, 0x7D, "ialiendv", 0x3D }, + { false, 0x7E, "icapsule", 0x3E }, + { true, 0x7F, "imedkit", 0x3F }, + { false, 0x80, "iBeam", 0x40 }, + { false, 0x81, "iDrill", 0x41 }, + { false, 0x82, "iHypo", 0x42 }, + { false, 0x83, "iFusion", 0x43 }, + { false, 0x84, "iCable1", 0x44 }, + { false, 0x85, "iCable2", 0x45 }, + { false, 0x86, "iLMD", 0x46 }, + { false, 0x87, "iDeck", 0x47 }, + { false, 0x88, "iTech", 0x48 }, + + // 64 blank rows? + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, + { false, 0x00, "", 0x00 }, +}; + +const int NUM_ITEMS = sizeof(g_itemList) / sizeof(struct Item); + +} + +#endif diff --git a/engines/startrek/menu.cpp b/engines/startrek/menu.cpp index acd41549f3..50661be8ed 100644 --- a/engines/startrek/menu.cpp +++ b/engines/startrek/menu.cpp @@ -31,9 +31,9 @@ namespace StarTrek { /** * Returns the index of the button at the given position, or -1 if none. */ -int StarTrekEngine::getMenuButtonAt(const Menu &menu, int x, int y) { - for (int i = 0; i < menu.numButtons; i++) { - const Sprite &spr = menu.sprites[i]; +int StarTrekEngine::getMenuButtonAt(Sprite *sprites, int numSprites, int x, int y) { + for (int i = 0; i < numSprites; i++) { + const Sprite &spr = sprites[i]; if (spr.drawMode != 2) continue; @@ -130,7 +130,6 @@ void StarTrekEngine::chooseMousePositionFromSprites(Sprite *sprites, int numSpri && (mouseX1 == 0x7fff || vCenter >= mouseY1)) { mouseX1 = hCenter; mouseY1 = vCenter; - debug("Try %d %d", mouseX1, mouseY1); } if (mouseX2 == 0x7fff || vCenter > mouseY2 || (hCenter == mouseX2 && vCenter == mouseY2)) { @@ -656,7 +655,7 @@ int StarTrekEngine::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4 case TREKEVENT_TICK: { case TREKEVENT_MOUSEMOVE: // FIXME: actual game only uses TICK event here Common::Point mousePos = _gfx->getMousePos(); - int buttonIndex = getMenuButtonAt(*_activeMenu, mousePos.x, mousePos.y); + int buttonIndex = getMenuButtonAt(_activeMenu->sprites, _activeMenu->numButtons, mousePos.x, mousePos.y); if (buttonIndex != -1) { if (_activeMenu->disabledButtons & (1<<buttonIndex)) buttonIndex = -1; @@ -704,7 +703,7 @@ int StarTrekEngine::handleMenuEvents(uint32 ticksUntilClickingEnabled, bool arg4 } else { Common::Point mouse = _gfx->getMousePos(); - if (getMenuButtonAt(*_activeMenu, mouse.x, mouse.y) == -1) { + if (getMenuButtonAt(_activeMenu->sprites, _activeMenu->numButtons, mouse.x, mouse.y) == -1) { playSoundEffectIndex(0x10); return MENUEVENT_LCLICK_OFFBUTTON; } diff --git a/engines/startrek/room.h b/engines/startrek/room.h index e9bbbd01db..b6a69c38b9 100644 --- a/engines/startrek/room.h +++ b/engines/startrek/room.h @@ -50,16 +50,19 @@ public: uint16 readRdfWord(int offset); // Scale-related stuff (rename these later) - int16 getVar06() { return readRdfWord(0x06); } - int16 getVar08() { return readRdfWord(0x08); } - int16 getVar0a() { return readRdfWord(0x0a); } - int16 getVar0c() { return readRdfWord(0x0c); } + uint16 getVar06() { return readRdfWord(0x06); } + uint16 getVar08() { return readRdfWord(0x08); } + uint16 getVar0a() { return readRdfWord(0x0a); } + uint16 getVar0c() { return readRdfWord(0x0c); } + + uint16 getFirstHotspot() { return readRdfWord(0x12); } + uint16 getHotspotEnd() { return readRdfWord(0x14); } // Warp-related stuff - int16 getFirstWarpPolygonOffset() { return readRdfWord(0x16); } - int16 getWarpPolygonEndOffset() { return readRdfWord(0x18); } - int16 getFirstDoorPolygonOffset() { return readRdfWord(0x1a); } - int16 getDoorPolygonEndOffset() { return readRdfWord(0x1c); } + uint16 getFirstWarpPolygonOffset() { return readRdfWord(0x16); } + uint16 getWarpPolygonEndOffset() { return readRdfWord(0x18); } + uint16 getFirstDoorPolygonOffset() { return readRdfWord(0x1a); } + uint16 getDoorPolygonEndOffset() { return readRdfWord(0x1c); } Common::Point getBeamInPosition(int crewmanIndex); diff --git a/engines/startrek/sprite.cpp b/engines/startrek/sprite.cpp index 8c1c2f6b78..580447501c 100644 --- a/engines/startrek/sprite.cpp +++ b/engines/startrek/sprite.cpp @@ -18,15 +18,31 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://scummvm-startrek.googlecode.com/svn/trunk/graphics.h $ - * $Id: graphics.h 2 2009-09-12 20:13:40Z clone2727 $ - * */ #include "startrek/sprite.h" namespace StarTrek { +Sprite::Sprite() : + pos(), + drawPriority(), + drawPriority2(), + field8(), + bitmap(), + drawMode(), + textColor(), + bitmapChanged(), + rect2Valid(), + isOnScreen(), + field16(), + lastDrawRect(), + drawRect(), + rectangle2(), + drawX(), + drawY() + {} + void Sprite::setBitmap(SharedPtr<Bitmap> b) { bitmap = b; bitmapChanged = true; diff --git a/engines/startrek/sprite.h b/engines/startrek/sprite.h index f2e3780330..ce53372906 100644 --- a/engines/startrek/sprite.h +++ b/engines/startrek/sprite.h @@ -58,7 +58,7 @@ struct Sprite { Common::Rect rectangle2; int16 drawX,drawY; - Sprite() { memset(this, 0, sizeof(Sprite)); } + Sprite(); void setBitmap(SharedPtr<Bitmap> b); void dontDrawNextFrame(); diff --git a/engines/startrek/startrek.cpp b/engines/startrek/startrek.cpp index 8147ecaefc..02c80efee1 100644 --- a/engines/startrek/startrek.cpp +++ b/engines/startrek/startrek.cpp @@ -78,6 +78,9 @@ StarTrekEngine::StarTrekEngine(OSystem *syst, const StarTrekGameDescription *gam _missionToLoad = "DEMON"; _roomIndexToLoad = 0; + + for (int i = 0; i < NUM_ITEMS; i++) + _itemList[i] = g_itemList[i]; } StarTrekEngine::~StarTrekEngine() { @@ -805,6 +808,56 @@ bool StarTrekEngine::directPathExists(int16 srcX, int16 srcY, int16 destX, int16 return true; } +int StarTrekEngine::findObjectAt(int x, int y) { + Sprite *sprite = _gfx->getSpriteAt(x, y); + + if (sprite != nullptr) { + if (sprite == &_inventoryIconSprite) + return OBJECT_INVENTORY_ICON; + else if (sprite == &_itemIconSprite) + return _awayMission.activeItem; + + for (int i = 0; i < MAX_OBJECTS; i++) { + Object *object = &_objectList[i]; + if (sprite == &object->sprite) + return i; + } + + error("findObject: Clicked on an unknown sprite"); + } + + // word_4b418 = 0; + int actionBit = 1 << (_awayMission.activeAction - 1); + int offset = _room->getFirstHotspot(); + + while (offset != _room->getHotspotEnd()) { + uint16 word = _room->readRdfWord(offset); + if (word & 0x8000) { + if ((word & actionBit) && isPointInPolygon((int16 *)(_room->_rdfData + offset + 6), x, y)) { + int objectIndex = _room->readRdfWord(offset + 6); + // word_4b418 = 1; + // word_4a792 = _room->readRdfWord(offset + 2); + // word_4a796 = _room->readRdfWord(offset + 4); + return objectIndex; + } + + int numVertices = _room->readRdfWord(offset + 8); + offset = offset + 10 + numVertices * 4; + } + else { + if (isPointInPolygon((int16 *)(_room->_rdfData + offset), x, y)) { + int objectIndex = _room->readRdfWord(offset); + return objectIndex; + } + + int numVertices = _room->readRdfWord(offset + 2); + offset = offset + 4 + numVertices * 4; + } + } + + return -1; +} + /** * Loads a bitmap for the animation frame with the given scale. */ @@ -911,6 +964,279 @@ Common::String StarTrekEngine::getCrewmanAnimFilename(int objectIndex, const Com } /** + * Checks whether to change the mouse bitmap to have the red outline. + */ +void StarTrekEngine::updateMouseBitmap() { + const bool worksOnCrewmen[] = { // True if the action reacts with crewmen + false, // ACTION_WALK + true, // ACTION_USE + false, // ACTION_GET + true, // ACTION_LOOK + true // ACTION_TALK + }; + const bool worksOnObjects[] = { // True if the action reacts with other objects + false, // ACTION_WALK + true, // ACTION_USE + true, // ACTION_GET + true, // ACTION_LOOK + true // ACTION_TALK + }; + const bool worksOnHotspots[] = { // True if the action reacts with hotspots? + false, // ACTION_WALK + true, // ACTION_USE + true, // ACTION_GET + true, // ACTION_LOOK + false // ACTION_TALK + }; + + Common::Point mousePos = _gfx->getMousePos(); + int selected = findObjectAt(mousePos.x, mousePos.y); + int action = _awayMission.activeAction; + assert(action >= 1 && action <= 5); + + bool withRedOutline; + + if (selected >= 0 && selected <= 3 && worksOnCrewmen[action - 1]) + withRedOutline = true; + else if (selected > 3 && selected < MAX_OBJECTS && worksOnObjects[action - 1]) + withRedOutline = true; + else if (selected >= MAX_OBJECTS && selected < MAX_OBJECTS_2 && worksOnHotspots[action - 1]) + withRedOutline = true; + else + withRedOutline = false; + + chooseMouseBitmapForAction(action, withRedOutline); +} + +void StarTrekEngine::showInventoryIcons(bool showItem) { + const char *crewmanFilenames[] = { + "ikirk", + "ispock", + "imccoy", + "iredshir" + }; + + Common::String itemFilename; + + if (showItem) { + int i = _awayMission.activeItem; + if (i >= 0 && i <= 3) + itemFilename = crewmanFilenames[i]; + else { + // TODO + } + } + + if (itemFilename.empty()) + _inventoryIconSprite.pos.x = 10; + else { + _gfx->addSprite(&_itemIconSprite); + _itemIconSprite.drawMode = 2; + _itemIconSprite.pos.x = 10; + _itemIconSprite.pos.y = 10; + _itemIconSprite.drawPriority = 15; + _itemIconSprite.drawPriority2 = 8; + _itemIconSprite.setBitmap(_gfx->loadBitmap(itemFilename)); + + _inventoryIconSprite.pos.x = 46; + } + + _gfx->addSprite(&_inventoryIconSprite); + + _inventoryIconSprite.pos.y = 10; + _inventoryIconSprite.drawMode = 2; + _inventoryIconSprite.drawPriority = 15; + _inventoryIconSprite.drawPriority2 = 15; + _inventoryIconSprite.setBitmap(_gfx->loadBitmap("inv00")); +} + +void StarTrekEngine::hideInventoryIcons() { + // Clear these sprites from the screen + if (_itemIconSprite.drawMode == 2) + _itemIconSprite.dontDrawNextFrame(); + if (_inventoryIconSprite.drawMode == 2) + _inventoryIconSprite.dontDrawNextFrame(); + + _gfx->drawAllSprites(); + + if (_itemIconSprite.drawMode == 2) { + _gfx->delSprite(&_itemIconSprite); + _itemIconSprite.drawMode = 0; + _itemIconSprite.bitmap.reset(); + } + + if (_inventoryIconSprite.drawMode == 2) { + _gfx->delSprite(&_inventoryIconSprite); + _inventoryIconSprite.drawMode = 0; + _inventoryIconSprite.bitmap.reset(); + } +} + +int StarTrekEngine::showInventoryMenu(int x, int y, bool restoreMouse) { + const int ITEMS_PER_ROW = 5; + + Common::Point oldMousePos = _gfx->getMousePos(); + bool keyboardControlledMouse = _keyboardControlsMouse; + _keyboardControlsMouse = false; + + int itemIndex = 0; + int numItems = 0; + + char itemNames[NUM_ITEMS][10]; + Common::Point itemPositions[NUM_ITEMS]; + int16 itemIndices[NUM_ITEMS]; + + while (itemIndex < NUM_ITEMS) { + if (_itemList[itemIndex].have) { + strcpy(itemNames[numItems], _itemList[itemIndex].name); + + int16 itemX = (numItems % ITEMS_PER_ROW) * 32 + x; + int16 itemY = (numItems / ITEMS_PER_ROW) * 32 + y; + itemPositions[numItems] = Common::Point(itemX, itemY); + itemIndices[numItems] = _itemList[itemIndex].field2; + + numItems++; + } + itemIndex++; + } + + Sprite itemSprites[NUM_ITEMS]; + + for (int i = 0; i < numItems; i++) { + _gfx->addSprite(&itemSprites[i]); + + itemSprites[i].drawMode = 2; + itemSprites[i].pos.x = itemPositions[i].x; + itemSprites[i].pos.y = itemPositions[i].y; + itemSprites[i].drawPriority = 15; + itemSprites[i].drawPriority2 = 8; + itemSprites[i].setBitmap(_gfx->loadBitmap(itemNames[i])); + } + + chooseMousePositionFromSprites(itemSprites, numItems, -1, 4); + bool displayMenu = true; + int lastItemIndex = -1; + + while (displayMenu) { + _sound->checkLoopMusic(); + + TrekEvent event; + if (!getNextEvent(&event)) + continue; + + switch (event.type) { + case TREKEVENT_TICK: { + Common::Point mousePos = _gfx->getMousePos(); + itemIndex = getMenuButtonAt(itemSprites, numItems, mousePos.x, mousePos.y); + if (itemIndex != lastItemIndex) { + if (lastItemIndex != -1) { + drawMenuButtonOutline(itemSprites[lastItemIndex].bitmap, 0); + itemSprites[lastItemIndex].bitmapChanged = true; + } + if (itemIndex != -1) { + drawMenuButtonOutline(itemSprites[itemIndex].bitmap, 15); + itemSprites[itemIndex].bitmapChanged = true; + } + lastItemIndex = itemIndex; + } + _gfx->drawAllSprites(); + break; + } + + case TREKEVENT_LBUTTONDOWN: +exitWithSelection: + displayMenu = false; + break; + + case TREKEVENT_RBUTTONDOWN: +exitWithoutSelection: + displayMenu = false; + lastItemIndex = -1; + break; + + case TREKEVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_F2: + goto exitWithoutSelection; + + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_F1: + goto exitWithSelection; + + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 4); + break; + + case Common::KEYCODE_UP: + case Common::KEYCODE_KP8: + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 2); + break; + + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 1); + break; + + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 0); + break; + + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 5); + break; + + case Common::KEYCODE_DOWN: + case Common::KEYCODE_KP2: + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + chooseMousePositionFromSprites(itemSprites, numItems, lastItemIndex, 3); + break; + + default: + break; + } + break; + + default: + break; + } + + removeNextEvent(); + } + + playSoundEffectIndex(0x10); + if (lastItemIndex >= 0) + drawMenuButtonOutline(itemSprites[lastItemIndex].bitmap, 0); + + for (int i = 0; i < numItems; i++) + itemSprites[i].dontDrawNextFrame(); + + _gfx->drawAllSprites(); + + for (int i = 0; i < numItems; i++) { + itemSprites[i].bitmap.reset(); + _gfx->delSprite(&itemSprites[i]); + } + + if (lastItemIndex >= 0) { + lastItemIndex = itemIndices[lastItemIndex]; + } + + if (restoreMouse) + _gfx->warpMouse(oldMousePos.x, oldMousePos.y); + + _keyboardControlsMouse = keyboardControlledMouse; + return lastItemIndex; +} + +/** * A scale of 256 is the baseline. */ SharedPtr<Bitmap> StarTrekEngine::scaleBitmap(SharedPtr<Bitmap> bitmap, uint16 scale) { diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index b146df8c8f..1e1dbc7598 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -39,6 +39,7 @@ #include "startrek/awaymission.h" #include "startrek/filestream.h" #include "startrek/graphics.h" +#include "startrek/items.h" #include "startrek/object.h" #include "startrek/room.h" #include "startrek/sound.h" @@ -58,6 +59,8 @@ class StarTrekEngine; typedef String (StarTrekEngine::*TextGetterFunc)(int, uintptr, String *); const int MAX_OBJECTS = 32; +const int MAX_OBJECTS_2 = 64; // TODO: better name; indices 32 and above used for something + const int MAX_MENUBUTTONS = 32; const int TEXTBOX_WIDTH = 26; const int MAX_TEXTBOX_LINES = 12; @@ -185,6 +188,15 @@ enum Acton { ACTION_OPTIONS = 13 // Not really an action, but selectable from action menu }; +// First 4 objects are reserved for crewmen +enum Objects { + OBJECT_KIRK = 0, + OBJECT_SPOCK = 1, + OBJECT_MCCOY = 2, + OBJECT_REDSHIRT = 3, + OBJECT_INVENTORY_ICON = 31 +}; + struct StarTrekGameDescription; class Graphics; @@ -246,8 +258,14 @@ public: void chooseObjectDirectionForWalking(Object *object, int16 srcX, int16 srcY, int16 destX, int16 destY); bool directPathExists(int16 srcX, int16 srcY, int16 destX, int16 destY); + int findObjectAt(int x, int y); + int findObjectAt(Common::Point p) { return findObjectAt(p.x, p.y); } SharedPtr<Bitmap> loadAnimationFrame(const Common::String &filename, uint16 arg2); Common::String getCrewmanAnimFilename(int objectIndex, const Common::String &basename); + void updateMouseBitmap(); + void showInventoryIcons(bool showItem); + void hideInventoryIcons(); + int showInventoryMenu(int x, int y, bool restoreMouse); SharedPtr<Bitmap> scaleBitmap(SharedPtr<Bitmap> bitmap, uint16 scale); void scaleBitmapRow(byte *src, byte *dest, uint16 origWidth, uint16 scaledWidth); @@ -301,7 +319,7 @@ public: // menu.cpp public: - int getMenuButtonAt(const Menu &menu, int x, int y); + int getMenuButtonAt(Sprite *sprites, int numSprites, int x, int y); void chooseMousePositionFromSprites(Sprite *sprites, int numSprites, int spriteIndex, int mode); void drawMenuButtonOutline(SharedPtr<Bitmap> bitmap, byte color); void showOptionsMenu(int x, int y); @@ -375,6 +393,8 @@ public: int16 _activeDoorWarpHotspot; int16 _lookActionBitmapIndex; + Item _itemList[NUM_ITEMS]; + Object _objectList[MAX_OBJECTS]; Object * const _kirkObject; Object * const _spockObject; @@ -384,6 +404,8 @@ public: SharedPtr<FileStream> _objectBanFiles[MAX_OBJECTS / 2]; uint16 _objectBanVar2[MAX_OBJECTS / 2]; // TODO: initialize? + Sprite _inventoryIconSprite; + Sprite _itemIconSprite; // _clockTicks is based on DOS interrupt 1A, AH=0; read system clock counter. // Updates 18.206 times every second. |