diff options
author | Le Philousophe | 2019-03-05 19:28:12 +0100 |
---|---|---|
committer | Eugene Sandulenko | 2019-06-01 22:43:48 +0200 |
commit | 531aa8392e40458d52f22edef71abf3506ca63da (patch) | |
tree | 5446a4eac74b59f3df4301cf4f0ed18f6ee5b586 /engines/cryomni3d/fixed_image.cpp | |
parent | 97397bdaffed7f7bdf97ccde20bbcd41df4e63fb (diff) | |
download | scummvm-rg350-531aa8392e40458d52f22edef71abf3506ca63da.tar.gz scummvm-rg350-531aa8392e40458d52f22edef71abf3506ca63da.tar.bz2 scummvm-rg350-531aa8392e40458d52f22edef71abf3506ca63da.zip |
CRYOMNI3D: Add engine for Versailles 1685
Diffstat (limited to 'engines/cryomni3d/fixed_image.cpp')
-rw-r--r-- | engines/cryomni3d/fixed_image.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp new file mode 100644 index 0000000000..fa2b4a2002 --- /dev/null +++ b/engines/cryomni3d/fixed_image.cpp @@ -0,0 +1,308 @@ +/* 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 "engines/cryomni3d/fixed_image.h" + +#include "common/file.h" +#include "common/system.h" +#include "graphics/surface.h" +#include "image/image_decoder.h" + +namespace CryOmni3D { + +ZonFixedImage::ZonFixedImage(CryOmni3DEngine &engine, + Inventory &inventory, + const Sprites &sprites, + const FixedImageConfiguration *configuration) : + _engine(engine), _inventory(inventory), _sprites(sprites), + _configuration(configuration), + _callback(nullptr), _imageDecoder(nullptr), _imageSurface(nullptr) { +} + +ZonFixedImage::~ZonFixedImage() { + delete _imageDecoder; +} + +void ZonFixedImage::run(const Common::Functor1<ZonFixedImage *, void> *callback) { + _exit = false; + _zonesMode = kZonesMode_None; + + _callback = callback; + + g_system->showMouse(true); + while (!_exit) { + (*_callback)(this); + } + _engine.waitMouseRelease(); + g_system->showMouse(false); + + // Deselect object + _inventory.setSelectedObject(nullptr); + + delete _callback; + _callback = nullptr; +} + +void ZonFixedImage::load(const Common::String &image) { + _imageSurface = nullptr; + delete _imageDecoder; + _imageDecoder = nullptr; + + _imageDecoder = _engine.loadHLZ(image); + if (!_imageDecoder) { + error("Can't display fixed image"); + } + _imageSurface = _imageDecoder->getSurface(); + + loadZones(image); +#if 0 + // This is not correct but to debug zones I think it's OK + Graphics::Surface *tmpSurf = (Graphics::Surface *) _imageSurface; + for (Common::Array<Zone>::const_iterator it = _zones.begin(); it != _zones.end(); it++) { + Common::Rect tmp = it->rect; + tmpSurf->frameRect(tmp, 244); + } +#endif + + _zonesMode = kZonesMode_Standard; + _refreshCursor = true; + + display(); + + // WORKAROUND: Wait for release after displaying the fixed image to avoid handling events due to mouse being pressed + // There is this bug in game + // Don't display cursor to prevent displaying an invalid cursor + g_system->showMouse(false); + g_system->updateScreen(); + _engine.waitMouseRelease(); + g_system->showMouse(true); +} + +void ZonFixedImage::display() const { + _engine.setupPalette(_imageDecoder->getPalette(), _imageDecoder->getPaletteStartIndex(), + _imageDecoder->getPaletteColorCount()); + + g_system->copyRectToScreen(_imageSurface->getPixels(), _imageSurface->pitch, 0, 0, + _imageSurface->w, _imageSurface->h); + g_system->updateScreen(); +} + +void ZonFixedImage::loadZones(const Common::String &image) { + _zones.clear(); + + Common::String fname(image); + + int lastDotPos = fname.size() - 1; + for (; lastDotPos >= 0; --lastDotPos) { + if (fname[lastDotPos] == '.') { + break; + } + } + if (lastDotPos > -1) { + fname.erase(lastDotPos); + fname += ".zon"; + } + + Common::File zonFile; + if (!zonFile.open(fname)) { + error("Can't open ZON file '%s'", fname.c_str()); + } + + int32 zonesNumber = zonFile.size() / 26; + _zones.reserve(zonesNumber); + + _highLeftId = -1; + _highRightId = -1; + + int leftSeen = 0x7fffffff; // MAX_INT + int rightSeen = 0; + Common::Array<Zone>::size_type index = 0; + + while (zonesNumber > 0) { + Zone zone; + zone.rect.left = zonFile.readSint16BE(); + zone.rect.top = zonFile.readSint16BE(); + zone.rect.right = zonFile.readSint16BE(); + zone.rect.bottom = zonFile.readSint16BE(); + zone.spriteId = zonFile.readSint16BE(); + zone.cursorId = _sprites.revMapSpriteId(zone.spriteId); + zone.valid = true; + zonFile.skip(16); + + _zones.push_back(zone); + + if (zone.cursorId == _configuration->spriteHigh) { + if (leftSeen > zone.rect.right) { + // The right side is at the leftest seen + leftSeen = zone.rect.right; + _highLeftId = index; + } + if (rightSeen < zone.rect.left) { + // The left side is at the rightest seen + rightSeen = zone.rect.left; + _highRightId = index; + } + } + + zonesNumber--; + index++; + } +} + +Common::Point ZonFixedImage::getZoneCenter(unsigned int zoneId) const { + if (zoneId >= _zones.size()) { + error("Invalid zoneId %u/%u", zoneId, _zones.size()); + } + const Common::Rect &rect = _zones[zoneId].rect; + + return Common::Point((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); +} + +void ZonFixedImage::manage() { + _currentZone = -1; + _zoneLow = false; + _zoneHigh = false; + _zoneHighLeft = false; + _zoneHighRight = false; + _zoneLeft = false; + _zoneRight = false; + _zoneQuestion = false; + _zoneListen = false; + _zoneSee = false; + _zoneUse = false; + _zoneSpeak = false; + _usedObject = nullptr; + + // Force poll events even when we must refresh the cursor + if (!_engine.pollEvents() && !_refreshCursor) { + g_system->updateScreen(); + // TODO: countdown even when no events + return; + } + _refreshCursor = false; + + // Feed the key for the caller + _key = _engine.getNextKey(); + Common::Point mousePos = _engine.getMousePos(); + + if (_key == Common::KEYCODE_ESCAPE) { + _exit = true; + return; + } else if (_engine.shouldAbort()) { + _exit = true; + return; + } + + if (_key == Common::KEYCODE_SPACE || + _engine.getCurrentMouseButton() == 2 || + mousePos.y > _configuration->toolbarTriggerY) { + bool mustRedraw = _engine.displayToolbar(_imageSurface); + // We just came back from toolbar: check if an object is selected and go into object mode + if (_inventory.selectedObject()) { + _zonesMode = kZonesMode_Object; + } + if (mustRedraw) { + display(); + } + // Return without any event to redo the loop and force refresh + _refreshCursor = true; + return; + } + + Common::Array<Zone>::iterator zoneIt; + for (zoneIt = _zones.begin(); zoneIt != _zones.end(); zoneIt++) { + if (zoneIt->valid && zoneIt->rect.contains(mousePos)) { + break; + } + } + + if (zoneIt != _zones.end()) { + _currentZone = zoneIt - _zones.begin(); + } else { + _currentZone = -1; + } + + if (_zonesMode == kZonesMode_Standard) { + if (zoneIt != _zones.end()) { + _engine.setCursor(zoneIt->cursorId); + if (_engine.getCurrentMouseButton() == 1) { + handleMouseZones(zoneIt); + } + } else { + _engine.setCursor(_configuration->spriteNothing); + } + } else if (_zonesMode == kZonesMode_Object) { + Object *selectedObj = _inventory.selectedObject(); + if (!selectedObj) { + // Normally useless but we never know + _engine.setCursor(_configuration->spriteNothing); + } else if (zoneIt != _zones.end()) { + _engine.setCursor(selectedObj->idSA()); + if (_engine.getDragStatus() == kDragStatus_Finished) { + // Just clicked, store the event and go back to standard mode + _usedObject = selectedObj; + _zonesMode = kZonesMode_Standard; + // We changed mode: need to refresh + _refreshCursor = true; + } + } else { + _engine.setCursor(selectedObj->idSl()); + } + + } + + // TODO: handle countdown + g_system->updateScreen(); +} + +void ZonFixedImage::handleMouseZones(const Common::Array<Zone>::const_iterator ¤tZone) { + if (currentZone->cursorId == _configuration->spriteLow) { + _zoneLow = true; + } else if (currentZone->cursorId == _configuration->spriteHigh) { + Common::Array<Zone>::size_type id = currentZone - _zones.begin(); + if (id == _highLeftId) { + _zoneHighLeft = true; + } else if (id == _highRightId) { + _zoneHighRight = true; + } else { + _zoneHigh = true; + } + } else if (currentZone->cursorId == _configuration->spriteLeft) { + _zoneLeft = true; + } else if (currentZone->cursorId == _configuration->spriteRight) { + _zoneRight = true; + } else if (currentZone->cursorId == _configuration->spriteQuestion) { + _zoneQuestion = true; + } else if (currentZone->cursorId == _configuration->spriteListen) { + _zoneListen = true; + } else if (currentZone->cursorId == _configuration->spriteSee) { + _zoneSee = true; + } else if (currentZone->cursorId == _configuration->spriteUse) { + _zoneUse = true; + } else if (currentZone->cursorId == _configuration->spriteSpeak) { + _zoneSpeak = true; + } else { + error("Invalid cursor ID: %d in ImgFix", currentZone->cursorId); + } +} + +} // End of namespace CryOmni3D |