diff options
Diffstat (limited to 'engines/sherlock/tattoo/tattoo_map.cpp')
-rw-r--r-- | engines/sherlock/tattoo/tattoo_map.cpp | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp new file mode 100644 index 0000000000..21abf7d3c0 --- /dev/null +++ b/engines/sherlock/tattoo/tattoo_map.cpp @@ -0,0 +1,439 @@ +/* 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 "sherlock/tattoo/tattoo_map.h" +#include "sherlock/tattoo/tattoo_scene.h" +#include "sherlock/tattoo/tattoo.h" + +namespace Sherlock { + +namespace Tattoo { + +#define MAP_NAME_COLOR 131 +#define CLOSEUP_STEPS 30 +#define SCROLL_SPEED 16 + +/*-------------------------------------------------------------------------*/ + +void MapEntry::clear() { + _iconNum = -1; + _description = ""; +} + +/*-------------------------------------------------------------------------*/ + +TattooMap::TattooMap(SherlockEngine *vm) : Map(vm), _mapTooltip(vm) { + _iconImages = nullptr; + _bgFound = _oldBgFound = 0; + + loadData(); +} + +int TattooMap::show() { + Debugger &debugger = *_vm->_debugger; + Events &events = *_vm->_events; + Music &music = *_vm->_music; + Resources &res = *_vm->_res; + TattooScene &scene = *(TattooScene *)_vm->_scene; + Screen &screen = *_vm->_screen; + int result = 0; + + // Check if we need to keep track of how many times player has been to the map + for (uint idx = 0; idx < scene._sceneTripCounters.size(); ++idx) { + SceneTripEntry &entry = scene._sceneTripCounters[idx]; + + if (entry._sceneNumber == OVERHEAD_MAP || entry._sceneNumber == OVERHEAD_MAP2) { + if (--entry._numTimes == 0) { + _vm->setFlagsDirect(entry._flag); + scene._sceneTripCounters.remove_at(idx); + } + } + } + + if (music._midiOption) { + // See if Holmes or Watson is the active character + Common::String song; + if (_vm->readFlags(FLAG_PLAYER_IS_HOLMES)) + // Player is Holmes + song = "Cue9"; + else if (_vm->readFlags(FLAG_ALT_MAP_MUSIC)) + song = "Cue8"; + else + song = "Cue7"; + + if (music.loadSong(song)) { + music.setMIDIVolume(music._musicVolume); + if (music._musicOn) + music.startSong(); + } + } + + screen.initPaletteFade(1364485); + + // Load the custom mouse cursors for the map + ImageFile cursors("omouse.vgs"); + events.setCursor(cursors[0]._frame); + events.warpMouse(Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2)); + + // Load the data for the map + _iconImages = new ImageFile("mapicons.vgs"); + loadData(); + + // Load the palette + Common::SeekableReadStream *stream = res.load("map.pal"); + stream->read(screen._cMap, PALETTE_SIZE); + screen.translatePalette(screen._cMap); + delete stream; + + // Load the map image and draw it to the back buffer + ImageFile *map = new ImageFile("map.vgs"); + screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); + screen._backBuffer1.blitFrom((*map)[0], Common::Point(0, 0)); + delete map; + + screen.clear(); + screen.setPalette(screen._cMap); + drawMapIcons(); + + // Copy the map drawn in the back buffer to the secondary back buffer + screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2); + screen._backBuffer2.blitFrom(screen._backBuffer1); + + // Display the built map to the screen + screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + + // Set initial scroll position + _targetScroll = _bigPos; + screen._currentScroll = Common::Point(-1, -1); + + do { + // Allow for event processing and get the current mouse position + events.pollEventsAndWait(); + events.setButtonState(); + Common::Point mousePos = events.screenMousePos(); + + if (debugger._showAllLocations == LOC_REFRESH) { + drawMapIcons(); + screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_WIDTH); + } + + checkMapNames(true); + + if (mousePos.x < (SHERLOCK_SCREEN_WIDTH / 6)) + _targetScroll.x -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_WIDTH / 6 - mousePos.x) / (SHERLOCK_SCREEN_WIDTH / 6); + if (mousePos.x > (SHERLOCK_SCREEN_WIDTH * 5 / 6)) + _targetScroll.x += 2 * SCROLL_SPEED * (mousePos.x - (SHERLOCK_SCREEN_WIDTH * 5 / 6)) / (SHERLOCK_SCREEN_WIDTH / 6); + if (mousePos.y < (SHERLOCK_SCREEN_HEIGHT / 6)) + _targetScroll.y -= 2 * SCROLL_SPEED * (SHERLOCK_SCREEN_HEIGHT / 6 - mousePos.y) / (SHERLOCK_SCREEN_HEIGHT / 6); + if (mousePos.y > (SHERLOCK_SCREEN_HEIGHT * 5 / 6)) + _targetScroll.y += 2 * SCROLL_SPEED * (mousePos.y - SHERLOCK_SCREEN_HEIGHT * 5 / 6) / (SHERLOCK_SCREEN_HEIGHT / 6); + + if (_targetScroll.x < 0) + _targetScroll.x = 0; + if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.w()) + _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; + if (_targetScroll.y < 0) + _targetScroll.y = 0; + if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.h()) + _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + + // Check the keyboard + if (events.kbHit()) { + Common::KeyState keyState = events.getKey(); + + switch (keyState.keycode) { + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + _targetScroll.x = 0; + _targetScroll.y = 0; + break; + + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH; + _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + break; + + case Common::KEYCODE_PAGEUP: + case Common::KEYCODE_KP9: + _targetScroll.y -= SHERLOCK_SCREEN_HEIGHT; + if (_targetScroll.y < 0) + _targetScroll.y = 0; + break; + + case Common::KEYCODE_PAGEDOWN: + case Common::KEYCODE_KP3: + _targetScroll.y += SHERLOCK_SCREEN_HEIGHT; + if (_targetScroll.y > (screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT)) + _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT; + break; + + case Common::KEYCODE_SPACE: + events._pressed = false; + events._oldButtons = 0; + events._released = true; + break; + + default: + break; + } + } + + // Handle any scrolling of the map + if (screen._currentScroll != _targetScroll) { + // If there is a Text description being displayed, restore the area under it + _mapTooltip.erase(); + + screen._currentScroll = _targetScroll; + + checkMapNames(false); + screen.slamArea(_targetScroll.x, _targetScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + } + + // Handling if a location has been clicked on + if (events._released && _bgFound != -1) { + // If there is a Text description being displayed, restore the area under it + _mapTooltip.erase(); + + // Save the current scroll position on the map + _bigPos = screen._currentScroll; + + showCloseUp(_bgFound); + result = _bgFound + 1; + } + } while (!result && !_vm->shouldQuit()); + + music.stopMusic(); + events.clearEvents(); + _mapTooltip.banishWindow(); + + // Reset the back buffers back to standard size + screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); + + return result; +} + +void TattooMap::loadData() { + Resources &res = *_vm->_res; + char c; + + Common::SeekableReadStream *stream = res.load("map.txt"); + + _data.resize(100); + for (uint idx = 0; idx < _data.size(); ++idx) + _data[idx].clear(); + + do + { + // Find the start of the number + do { + c = stream->readByte(); + if (stream->pos() >= stream->size()) + return; + } while (c < '0' || c > '9'); + + // Get the scene number + Common::String locStr; + locStr += c; + while ((c = stream->readByte()) != '.') + locStr += c; + MapEntry &mapEntry = _data[atoi(locStr.c_str()) - 1]; + + // Get the location name + while (stream->readByte() != '"') + ; + + while ((c = stream->readByte()) != '"') + mapEntry._description += c; + + // Find the ( specifying the (X,Y) position of the Icon + while (stream->readByte() != '(') + ; + + // Get the X Position of the icon + Common::String numStr; + while ((c = stream->readByte()) != ',') + numStr += c; + mapEntry.x = atoi(numStr.c_str()); + + // Get the Y position of the icon + numStr = ""; + while ((c = stream->readByte()) != ')') + numStr += c; + mapEntry.y = atoi(numStr.c_str()); + + // Find and get the location's icon number + while (stream->readByte() != '#') + ; + + Common::String iconStr; + while (stream->pos() < stream->size() && (c = stream->readByte()) != '\r') + iconStr += c; + + mapEntry._iconNum = atoi(iconStr.c_str()) - 1; + } while (stream->pos() < stream->size()); + + delete stream; +} + +void TattooMap::drawMapIcons() { + Debugger &debugger = *_vm->_debugger; + Screen &screen = *_vm->_screen; + + for (uint idx = 0; idx < _data.size(); ++idx) { + if (debugger._showAllLocations != LOC_DISABLED) + _vm->setFlagsDirect(idx + 1); + + if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) { + MapEntry &mapEntry = _data[idx]; + ImageFrame &img = (*_iconImages)[mapEntry._iconNum]; + screen._backBuffer1.transBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2, + mapEntry.y - img._height / 2)); + } + } + + if (debugger._showAllLocations == LOC_REFRESH) + debugger._showAllLocations = LOC_ALL; +} + +void TattooMap::checkMapNames(bool slamIt) { + Events &events = *_vm->_events; + Common::Point mapPos = events.mousePos(); + + // See if the mouse is pointing at any of the map locations + _bgFound = -1; + + for (uint idx = 0; idx < _data.size(); ++idx) { + if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) { + MapEntry &mapEntry = _data[idx]; + ImageFrame &img = (*_iconImages)[mapEntry._iconNum]; + Common::Rect r(mapEntry.x - img._width / 2, mapEntry.y - img._height / 2, + mapEntry.x + img._width / 2, mapEntry.y + img._height / 2); + + if (r.contains(mapPos)) { + _bgFound = idx; + break; + } + } + } + + // Handle updating the tooltip + if (_bgFound != _oldBgFound) { + if (_bgFound == -1) { + _mapTooltip.setText(""); + } else { + const Common::String &desc = _data[_bgFound]._description; + _mapTooltip.setText(desc); + } + + _oldBgFound = _bgFound; + } + + _mapTooltip.handleEvents(); + if (slamIt) + _mapTooltip.draw(); +} + +void TattooMap::restoreArea(const Common::Rect &bounds) { + Screen &screen = *_vm->_screen; + + Common::Rect r = bounds; + r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h())); + + if (!r.isEmpty()) + screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r); +} + +void TattooMap::showCloseUp(int closeUpNum) { + Events &events = *_vm->_events; + Screen &screen = *_vm->_screen; + + // Reset scroll position + screen._currentScroll = Common::Point(0, 0); + + // Get the closeup images + Common::String fname = Common::String::format("res%02d.vgs", closeUpNum + 1); + ImageFile pic(fname); + + Point32 closeUp(_data[closeUpNum].x * 100, _data[closeUpNum].y * 100); + Point32 delta((SHERLOCK_SCREEN_WIDTH / 2 - closeUp.x / 100) * 100 / CLOSEUP_STEPS, + (SHERLOCK_SCREEN_HEIGHT / 2 - closeUp.y / 100) * 100 / CLOSEUP_STEPS); + Common::Rect oldBounds(closeUp.x / 100, closeUp.y / 100, closeUp.x / 100 + 1, closeUp.y / 100 + 1); + int size = 64; + int n = 256; + int deltaVal = 512; + bool minimize = false; + int scaleVal, newSize; + + do { + scaleVal = n; + newSize = pic[0].sDrawXSize(n); + + if (newSize > size) { + if (minimize) + deltaVal /= 2; + n += deltaVal; + } else { + minimize = true; + deltaVal /= 2; + n -= deltaVal; + if (n < 1) + n = 1; + } + } while (deltaVal && size != newSize); + + int deltaScale = (SCALE_THRESHOLD - scaleVal) / CLOSEUP_STEPS; + + for (int step = 0; step < CLOSEUP_STEPS; ++step) { + Common::Point picSize(pic[0].sDrawXSize(scaleVal), pic[0].sDrawYSize(scaleVal)); + Common::Point pt(closeUp.x / 100 - picSize.x / 2, closeUp.y / 100 - picSize.y / 2); + + restoreArea(oldBounds); + screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal); + + screen.slamRect(oldBounds); + screen.slamArea(pt.x, pt.y, picSize.x, picSize.y); + + oldBounds = Common::Rect(pt.x, pt.y, pt.x + picSize.x + 1, pt.y + picSize.y + 1); + closeUp += delta; + scaleVal += deltaScale; + + events.wait(1); + } + + // Handle final drawing of closeup + // TODO: Handle scrolling + Common::Rect r(SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2, SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2, + SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2 + pic[0]._width, + SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2 + pic[0]._height); + + restoreArea(oldBounds); + screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top)); + screen.slamRect(oldBounds); + screen.slamRect(r); + events.wait(2); +} + +} // End of namespace Tattoo + +} // End of namespace Sherlock |