mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 12:39:56 +00:00
87b79f2124
This fixes bug #3539019.
675 lines
18 KiB
C++
675 lines
18 KiB
C++
/* 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 "common/scummsys.h"
|
|
|
|
#include "common/config-manager.h"
|
|
#include "common/events.h"
|
|
#include "common/file.h"
|
|
#include "common/random.h"
|
|
#include "common/fs.h"
|
|
#include "common/keyboard.h"
|
|
#include "common/substream.h"
|
|
|
|
#include "graphics/cursorman.h"
|
|
#include "graphics/surface.h"
|
|
#include "graphics/pixelformat.h"
|
|
#include "graphics/wincursor.h"
|
|
|
|
#include "engines/util.h"
|
|
#include "engines/advancedDetector.h"
|
|
|
|
#include "audio/audiostream.h"
|
|
|
|
#include "composer/composer.h"
|
|
#include "composer/graphics.h"
|
|
#include "composer/resource.h"
|
|
|
|
namespace Composer {
|
|
|
|
ComposerEngine::ComposerEngine(OSystem *syst, const ComposerGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
|
|
_rnd = new Common::RandomSource("composer");
|
|
_audioStream = NULL;
|
|
}
|
|
|
|
ComposerEngine::~ComposerEngine() {
|
|
DebugMan.clearAllDebugChannels();
|
|
|
|
stopPipes();
|
|
for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++)
|
|
delete *i;
|
|
for (Common::List<Animation *>::iterator i = _anims.begin(); i != _anims.end(); i++)
|
|
delete *i;
|
|
for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++)
|
|
delete i->_archive;
|
|
for (Common::List<Sprite>::iterator i = _sprites.begin(); i != _sprites.end(); i++)
|
|
i->_surface.free();
|
|
|
|
delete _rnd;
|
|
}
|
|
|
|
Common::Error ComposerEngine::run() {
|
|
Common::Event event;
|
|
|
|
_vars.resize(1000);
|
|
for (uint i = 0; i < _vars.size(); i++)
|
|
_vars[i] = 0;
|
|
|
|
_queuedScripts.resize(10);
|
|
for (uint i = 0; i < _queuedScripts.size(); i++) {
|
|
_queuedScripts[i]._count = 0;
|
|
_queuedScripts[i]._scriptId = 0;
|
|
}
|
|
|
|
_mouseVisible = true;
|
|
_mouseEnabled = false;
|
|
_mouseSpriteId = 0;
|
|
_lastButton = NULL;
|
|
|
|
_directoriesToStrip = 1;
|
|
if (!_bookIni.loadFromFile("book.ini")) {
|
|
_directoriesToStrip = 0;
|
|
if (!_bookIni.loadFromFile("programs/book.ini")) {
|
|
// mac version?
|
|
if (!_bookIni.loadFromFile("Darby the Dragon.ini"))
|
|
if (!_bookIni.loadFromFile("Gregory.ini"))
|
|
error("failed to find book.ini");
|
|
}
|
|
}
|
|
|
|
uint width = 640;
|
|
if (_bookIni.hasKey("Width", "Common"))
|
|
width = atoi(getStringFromConfig("Common", "Width").c_str());
|
|
uint height = 480;
|
|
if (_bookIni.hasKey("Height", "Common"))
|
|
height = atoi(getStringFromConfig("Common", "Height").c_str());
|
|
initGraphics(width, height, true);
|
|
_surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
|
|
_needsUpdate = true;
|
|
|
|
Graphics::Cursor *cursor = Graphics::makeDefaultWinCursor();
|
|
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(),
|
|
cursor->getHotspotY(), cursor->getKeyColor());
|
|
CursorMan.replaceCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
|
|
|
|
loadLibrary(0);
|
|
|
|
_currentTime = 0;
|
|
_lastTime = 0;
|
|
|
|
uint fps = atoi(getStringFromConfig("Common", "FPS").c_str());
|
|
uint frameTime = 1000 / fps;
|
|
uint32 lastDrawTime = 0;
|
|
|
|
while (!shouldQuit()) {
|
|
for (uint i = 0; i < _pendingPageChanges.size(); i++) {
|
|
if (_pendingPageChanges[i]._remove)
|
|
unloadLibrary(_pendingPageChanges[i]._pageId);
|
|
else
|
|
loadLibrary(_pendingPageChanges[i]._pageId);
|
|
|
|
lastDrawTime = _system->getMillis();
|
|
}
|
|
_pendingPageChanges.clear();
|
|
|
|
uint32 thisTime = _system->getMillis();
|
|
// maintain our own internal timing, since otherwise we get
|
|
// confused when starved of CPU (for example when the user
|
|
// is dragging the scummvm window around)
|
|
if (thisTime > _lastTime + frameTime)
|
|
_currentTime += frameTime;
|
|
else
|
|
_currentTime += thisTime - _lastTime;
|
|
_lastTime = thisTime;
|
|
|
|
for (uint i = 0; i < _queuedScripts.size(); i++) {
|
|
QueuedScript &script = _queuedScripts[i];
|
|
if (!script._count)
|
|
continue;
|
|
if (script._baseTime + script._duration > _currentTime)
|
|
continue;
|
|
if (script._count != 0xffffffff)
|
|
script._count--;
|
|
script._baseTime = _currentTime;
|
|
runScript(script._scriptId, i, 0, 0);
|
|
}
|
|
|
|
if (lastDrawTime + frameTime <= thisTime) {
|
|
// catch up if we're more than 2 frames behind
|
|
if (lastDrawTime + (frameTime * 2) <= thisTime)
|
|
lastDrawTime = thisTime;
|
|
else
|
|
lastDrawTime += frameTime;
|
|
|
|
redraw();
|
|
|
|
tickOldScripts();
|
|
processAnimFrame();
|
|
} else if (_needsUpdate) {
|
|
redraw();
|
|
}
|
|
|
|
while (_eventMan->pollEvent(event)) {
|
|
switch (event.type) {
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
onMouseDown(event.mouse);
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONUP:
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
break;
|
|
|
|
case Common::EVENT_MOUSEMOVE:
|
|
onMouseMove(event.mouse);
|
|
break;
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
switch (event.kbd.keycode) {
|
|
case Common::KEYCODE_d:
|
|
/*if (event.kbd.hasFlags(Common::KBD_CTRL)) {
|
|
// Start the debugger
|
|
getDebugger()->attach();
|
|
getDebugger()->onFrame();
|
|
}*/
|
|
break;
|
|
|
|
case Common::KEYCODE_q:
|
|
if (event.kbd.hasFlags(Common::KBD_CTRL))
|
|
quitGame();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
onKeyDown(event.kbd.keycode);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
_system->delayMillis(20);
|
|
}
|
|
|
|
return Common::kNoError;
|
|
}
|
|
|
|
void ComposerEngine::onMouseDown(const Common::Point &pos) {
|
|
if (!_mouseEnabled || !_mouseVisible)
|
|
return;
|
|
|
|
const Sprite *sprite = getSpriteAtPos(pos);
|
|
const Button *button = getButtonFor(sprite, pos);
|
|
if (!button)
|
|
return;
|
|
|
|
debug(3, "mouseDown on button id %d", button->_id);
|
|
|
|
// TODO: other buttons?
|
|
uint16 buttonsDown = 1; // MK_LBUTTON
|
|
|
|
uint16 spriteId = sprite ? sprite->_id : 0;
|
|
runScript(button->_scriptId, (getGameType() == GType_ComposerV1) ? 0 : button->_id, buttonsDown, spriteId);
|
|
}
|
|
|
|
void ComposerEngine::onMouseMove(const Common::Point &pos) {
|
|
_lastMousePos = pos;
|
|
|
|
if (!_mouseEnabled || !_mouseVisible)
|
|
return;
|
|
|
|
// TODO: do we need to keep track of this?
|
|
uint buttonsDown = 0;
|
|
|
|
const Sprite *sprite = getSpriteAtPos(pos);
|
|
const Button *button = getButtonFor(sprite, pos);
|
|
if (_lastButton != button) {
|
|
if (_lastButton && _lastButton->_scriptIdRollOff)
|
|
runScript(_lastButton->_scriptIdRollOff, (getGameType() == GType_ComposerV1) ? 0 : _lastButton->_id, buttonsDown, 0);
|
|
_lastButton = button;
|
|
if (_lastButton && _lastButton->_scriptIdRollOn)
|
|
runScript(_lastButton->_scriptIdRollOn, (getGameType() == GType_ComposerV1) ? 0 : _lastButton->_id, buttonsDown, 0);
|
|
}
|
|
|
|
if (_mouseSpriteId) {
|
|
addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset);
|
|
}
|
|
_needsUpdate = true;
|
|
}
|
|
|
|
void ComposerEngine::onKeyDown(uint16 keyCode) {
|
|
runEvent(kEventKeyDown, keyCode, 0, 0);
|
|
runEvent(kEventChar, keyCode, 0, 0);
|
|
|
|
for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) {
|
|
for (Common::List<KeyboardHandler>::iterator j = i->_keyboardHandlers.begin(); j != i->_keyboardHandlers.end(); j++) {
|
|
const KeyboardHandler &handler = *j;
|
|
if (keyCode != handler.keyId)
|
|
continue;
|
|
|
|
int modifiers = g_system->getEventManager()->getModifierState();
|
|
switch (handler.modifierId) {
|
|
case 0x10: // shift
|
|
if (!(modifiers & Common::KBD_SHIFT))
|
|
continue;
|
|
break;
|
|
case 0x11: // control
|
|
if (!(modifiers & Common::KBD_CTRL))
|
|
continue;
|
|
break;
|
|
case 0:
|
|
break;
|
|
default:
|
|
warning("unknown keyb modifier %d", handler.modifierId);
|
|
continue;
|
|
}
|
|
|
|
runScript(handler.scriptId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ComposerEngine::setCursor(uint16 id, const Common::Point &offset) {
|
|
_mouseOffset = offset;
|
|
if (_mouseSpriteId == id)
|
|
return;
|
|
|
|
if (_mouseSpriteId && _mouseVisible) {
|
|
removeSprite(_mouseSpriteId, 0);
|
|
}
|
|
_mouseSpriteId = id;
|
|
if (_mouseSpriteId && _mouseVisible) {
|
|
addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset);
|
|
}
|
|
}
|
|
|
|
void ComposerEngine::setCursorVisible(bool visible) {
|
|
if (visible && !_mouseVisible) {
|
|
_mouseVisible = true;
|
|
if (_mouseSpriteId)
|
|
addSprite(_mouseSpriteId, 0, 0, _lastMousePos - _mouseOffset);
|
|
else
|
|
CursorMan.showMouse(true);
|
|
onMouseMove(_lastMousePos);
|
|
} else if (!visible && _mouseVisible) {
|
|
_mouseVisible = false;
|
|
if (_mouseSpriteId)
|
|
removeSprite(_mouseSpriteId, 0);
|
|
else
|
|
CursorMan.showMouse(false);
|
|
}
|
|
}
|
|
|
|
Common::String ComposerEngine::getStringFromConfig(const Common::String §ion, const Common::String &key) {
|
|
Common::String value;
|
|
if (!_bookIni.getKey(key, section, value))
|
|
error("failed to find key '%s' in section '%s' of book config", key.c_str(), section.c_str());
|
|
return value;
|
|
}
|
|
|
|
Common::String ComposerEngine::getFilename(const Common::String §ion, uint id) {
|
|
Common::String key = Common::String::format("%d", id);
|
|
Common::String filename = getStringFromConfig(section, key);
|
|
|
|
return mangleFilename(filename);
|
|
}
|
|
|
|
Common::String ComposerEngine::mangleFilename(Common::String filename) {
|
|
while (filename.size() && (filename[0] == '~' || filename[0] == ':' || filename[0] == '\\'))
|
|
filename = filename.c_str() + 1;
|
|
|
|
uint slashesToStrip = _directoriesToStrip;
|
|
while (slashesToStrip--) {
|
|
for (uint i = 0; i < filename.size(); i++) {
|
|
if (filename[i] != '\\' && filename[i] != ':')
|
|
continue;
|
|
filename = filename.c_str() + i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Common::String outFilename;
|
|
for (uint i = 0; i < filename.size(); i++) {
|
|
if (filename[i] == '\\' || filename[i] == ':')
|
|
outFilename += '/';
|
|
else
|
|
outFilename += filename[i];
|
|
}
|
|
return outFilename;
|
|
}
|
|
|
|
void ComposerEngine::loadLibrary(uint id) {
|
|
if (getGameType() == GType_ComposerV1 && !_libraries.empty()) {
|
|
// kill the previous page, starting with any scripts running on it
|
|
|
|
for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++)
|
|
delete *i;
|
|
_oldScripts.clear();
|
|
|
|
Library *library = &_libraries.front();
|
|
unloadLibrary(library->_id);
|
|
}
|
|
|
|
Common::String filename;
|
|
|
|
if (getGameType() == GType_ComposerV1) {
|
|
if (!id || _bookGroup.empty())
|
|
filename = getStringFromConfig("Common", "StartPage");
|
|
else
|
|
filename = getStringFromConfig(_bookGroup, Common::String::format("%d", id));
|
|
filename = mangleFilename(filename);
|
|
|
|
// bookGroup is the basename of the path.
|
|
// TODO: tidy this up.
|
|
_bookGroup.clear();
|
|
for (uint i = 0; i < filename.size(); i++) {
|
|
if (filename[i] == '~' || filename[i] == '/' || filename[i] == ':')
|
|
continue;
|
|
for (uint j = 0; j < filename.size(); j++) {
|
|
if (filename[j] == '/') {
|
|
_bookGroup.clear();
|
|
continue;
|
|
}
|
|
if (filename[j] == '.')
|
|
break;
|
|
_bookGroup += filename[j];
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
if (!id)
|
|
id = atoi(getStringFromConfig("Common", "StartUp").c_str());
|
|
filename = getFilename("Libs", id);
|
|
}
|
|
|
|
Library library;
|
|
|
|
library._id = id;
|
|
library._archive = new ComposerArchive();
|
|
if (!library._archive->openFile(filename))
|
|
error("failed to open '%s'", filename.c_str());
|
|
_libraries.push_front(library);
|
|
|
|
Library &newLib = _libraries.front();
|
|
|
|
Common::Array<uint16> buttonResources = library._archive->getResourceIDList(ID_BUTN);
|
|
for (uint i = 0; i < buttonResources.size(); i++) {
|
|
uint16 buttonId = buttonResources[i];
|
|
Common::SeekableReadStream *stream = library._archive->getResource(ID_BUTN, buttonId);
|
|
Button button(stream, buttonId, getGameType());
|
|
|
|
bool inserted = false;
|
|
for (Common::List<Button>::iterator b = newLib._buttons.begin(); b != newLib._buttons.end(); b++) {
|
|
if (button._zorder < b->_zorder)
|
|
continue;
|
|
newLib._buttons.insert(b, button);
|
|
inserted = true;
|
|
break;
|
|
}
|
|
if (!inserted)
|
|
newLib._buttons.push_back(button);
|
|
}
|
|
|
|
Common::Array<uint16> ambientResources = library._archive->getResourceIDList(ID_AMBI);
|
|
for (uint i = 0; i < ambientResources.size(); i++) {
|
|
Common::SeekableReadStream *stream = library._archive->getResource(ID_AMBI, ambientResources[i]);
|
|
Button button(stream);
|
|
newLib._buttons.insert(newLib._buttons.begin(), button);
|
|
}
|
|
|
|
Common::Array<uint16> accelResources = library._archive->getResourceIDList(ID_ACEL);
|
|
for (uint i = 0; i < accelResources.size(); i++) {
|
|
Common::SeekableReadStream *stream = library._archive->getResource(ID_ACEL, accelResources[i]);
|
|
KeyboardHandler handler;
|
|
handler.keyId = stream->readUint16LE();
|
|
handler.modifierId = stream->readUint16LE();
|
|
handler.scriptId = stream->readUint16LE();
|
|
newLib._keyboardHandlers.push_back(handler);
|
|
}
|
|
|
|
Common::Array<uint16> randResources = library._archive->getResourceIDList(ID_RAND);
|
|
for (uint i = 0; i < randResources.size(); i++) {
|
|
Common::SeekableReadStream *stream = library._archive->getResource(ID_RAND, randResources[i]);
|
|
Common::Array<RandomEvent> &events = _randomEvents[randResources[i]];
|
|
uint16 count = stream->readUint16LE();
|
|
for (uint j = 0; j < count; j++) {
|
|
RandomEvent random;
|
|
random.scriptId = stream->readUint16LE();
|
|
random.weight = stream->readUint16LE();
|
|
events.push_back(random);
|
|
}
|
|
delete stream;
|
|
}
|
|
|
|
// add background sprite, if it exists
|
|
if (hasResource(ID_BMAP, 1000))
|
|
setBackground(1000);
|
|
|
|
// TODO: better CTBL logic
|
|
loadCTBL(1000, 100);
|
|
|
|
// Run the startup script.
|
|
runScript(1000, 0, 0, 0);
|
|
|
|
_mouseEnabled = true;
|
|
onMouseMove(_lastMousePos);
|
|
|
|
runEvent(kEventLoad, id, 0, 0);
|
|
}
|
|
|
|
void ComposerEngine::unloadLibrary(uint id) {
|
|
for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++) {
|
|
if (i->_id != id)
|
|
continue;
|
|
|
|
for (Common::List<Animation *>::iterator j = _anims.begin(); j != _anims.end(); j++) {
|
|
delete *j;
|
|
}
|
|
_anims.clear();
|
|
stopPipes();
|
|
|
|
_randomEvents.clear();
|
|
|
|
for (Common::List<Sprite>::iterator j = _sprites.begin(); j != _sprites.end(); j++) {
|
|
j->_surface.free();
|
|
}
|
|
_sprites.clear();
|
|
i->_buttons.clear();
|
|
|
|
_lastButton = NULL;
|
|
|
|
_mixer->stopAll();
|
|
_audioStream = NULL;
|
|
|
|
for (uint j = 0; j < _queuedScripts.size(); j++) {
|
|
_queuedScripts[j]._count = 0;
|
|
_queuedScripts[j]._scriptId = 0;
|
|
}
|
|
|
|
delete i->_archive;
|
|
_libraries.erase(i);
|
|
|
|
runEvent(kEventUnload, id, 0, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
error("tried to unload library %d, which isn't loaded", id);
|
|
}
|
|
|
|
bool ComposerEngine::hasResource(uint32 tag, uint16 id) {
|
|
for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++)
|
|
if (i->_archive->hasResource(tag, id))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
Common::SeekableReadStream *ComposerEngine::getResource(uint32 tag, uint16 id) {
|
|
for (Common::List<Library>::iterator i = _libraries.begin(); i != _libraries.end(); i++)
|
|
if (i->_archive->hasResource(tag, id))
|
|
return i->_archive->getResource(tag, id);
|
|
|
|
error("No loaded library contains '%s' %04x", tag2str(tag), id);
|
|
}
|
|
|
|
Button::Button(Common::SeekableReadStream *stream, uint16 id, uint gameType) {
|
|
_id = id;
|
|
|
|
_type = stream->readUint16LE();
|
|
_active = (_type & 0x8000) ? true : false;
|
|
bool hasRollover = (gameType == GType_ComposerV1) && (_type & 0x4000);
|
|
_type &= 0xfff;
|
|
debug(9, "button %d: type %d, active %d", id, _type, _active);
|
|
|
|
uint16 size = 4;
|
|
if (gameType == GType_ComposerV1) {
|
|
stream->skip(2);
|
|
|
|
_zorder = 0;
|
|
_scriptId = stream->readUint16LE();
|
|
_scriptIdRollOn = 0;
|
|
_scriptIdRollOff = 0;
|
|
} else {
|
|
_zorder = stream->readUint16LE();
|
|
_scriptId = stream->readUint16LE();
|
|
_scriptIdRollOn = stream->readUint16LE();
|
|
_scriptIdRollOff = stream->readUint16LE();
|
|
|
|
stream->skip(4);
|
|
|
|
size = stream->readUint16LE();
|
|
}
|
|
|
|
switch (_type) {
|
|
case kButtonRect:
|
|
case kButtonEllipse:
|
|
if (size != 4)
|
|
error("button %d of type %d had %d points, not 4", id, _type, size);
|
|
_rect.left = stream->readSint16LE();
|
|
_rect.top = stream->readSint16LE();
|
|
_rect.right = stream->readSint16LE();
|
|
_rect.bottom = stream->readSint16LE();
|
|
break;
|
|
case kButtonSprites:
|
|
if (gameType == GType_ComposerV1)
|
|
error("encountered kButtonSprites in V1 data");
|
|
for (uint i = 0; i < size; i++) {
|
|
_spriteIds.push_back(stream->readUint16LE());
|
|
}
|
|
break;
|
|
default:
|
|
error("unknown button type %d", _type);
|
|
}
|
|
|
|
if (hasRollover) {
|
|
_scriptIdRollOn = stream->readUint16LE();
|
|
_scriptIdRollOff = stream->readUint16LE();
|
|
}
|
|
|
|
delete stream;
|
|
}
|
|
|
|
// AMBI-style button
|
|
Button::Button(Common::SeekableReadStream *stream) {
|
|
_id = 0;
|
|
_zorder = 0;
|
|
_active = true;
|
|
_type = kButtonSprites;
|
|
_scriptIdRollOn = 0;
|
|
_scriptIdRollOff = 0;
|
|
|
|
_scriptId = stream->readUint16LE();
|
|
|
|
uint16 count = stream->readUint16LE();
|
|
for (uint j = 0; j < count; j++) {
|
|
uint16 spriteId = stream->readUint16LE();
|
|
_spriteIds.push_back(spriteId);
|
|
}
|
|
|
|
delete stream;
|
|
}
|
|
|
|
bool Button::contains(const Common::Point &pos) const {
|
|
switch (_type) {
|
|
case kButtonRect:
|
|
return _rect.contains(pos);
|
|
case kButtonEllipse:
|
|
if (!_rect.contains(pos))
|
|
return false;
|
|
{
|
|
int16 a = _rect.width() / 2;
|
|
int16 b = _rect.height() / 2;
|
|
if (!a || !b)
|
|
return false;
|
|
Common::Point adjustedPos = pos - Common::Point(_rect.left + a, _rect.top + b);
|
|
return ((adjustedPos.x*adjustedPos.x)/(a*a) + (adjustedPos.y*adjustedPos.y)/(b*b) < 1);
|
|
}
|
|
case kButtonSprites:
|
|
return false;
|
|
default:
|
|
error("internal error (button type %d)", _type);
|
|
}
|
|
}
|
|
|
|
const Button *ComposerEngine::getButtonFor(const Sprite *sprite, const Common::Point &pos) {
|
|
for (Common::List<Library>::iterator l = _libraries.begin(); l != _libraries.end(); l++) {
|
|
for (Common::List<Button>::iterator i = l->_buttons.reverse_begin(); i != l->_buttons.end(); --i) {
|
|
if (!i->_active)
|
|
continue;
|
|
|
|
if (i->_spriteIds.empty()) {
|
|
if (i->contains(pos))
|
|
return &(*i);
|
|
continue;
|
|
}
|
|
|
|
if (!sprite)
|
|
continue;
|
|
|
|
for (uint j = 0; j < i->_spriteIds.size(); j++) {
|
|
if (i->_spriteIds[j] == sprite->_id)
|
|
return &(*i);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ComposerEngine::setButtonActive(uint16 id, bool active) {
|
|
for (Common::List<Library>::iterator l = _libraries.begin(); l != _libraries.end(); l++) {
|
|
for (Common::List<Button>::iterator i = l->_buttons.begin(); i != l->_buttons.end(); i++) {
|
|
if (i->_id != id)
|
|
continue;
|
|
i->_active = active;
|
|
}
|
|
}
|
|
|
|
onMouseMove(_lastMousePos);
|
|
}
|
|
|
|
} // End of namespace Composer
|