aboutsummaryrefslogtreecommitdiff
path: root/engines/sherlock/tattoo/tattoo_map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sherlock/tattoo/tattoo_map.cpp')
-rw-r--r--engines/sherlock/tattoo/tattoo_map.cpp439
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