scummvm/engines/m4/events.cpp

369 lines
9.8 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.
*
* $URL$
* $Id$
*
*/
// TODO: There is a 'please_hyperwalk' variable that gets accessed that is meant to be global, but
// at the moment it's implemented as a local variable
#include "graphics/cursorman.h"
#include "m4/events.h"
#include "m4/graphics.h"
#include "m4/scene.h"
#include "m4/viewmgr.h"
#include "m4/m4.h"
namespace M4 {
bool please_hyperwalk = false;
/*--------------------------------------------------------------------------*
* Events *
* *
* Implements an interface to the event system *
*--------------------------------------------------------------------------*/
Events::Events(MadsM4Engine *vm) : _vm(vm) {
_mouseState = MSTATE_NO_EVENT;
quitFlag = false;
_keyCode = 0;
_mouseButtons = 0;
_ctrlFlag = false;
if (_vm->isM4())
_console = new M4Console(_m4Vm);
else
_console = new MadsConsole(_madsVm);
}
Events::~Events() {
delete _console;
}
M4EventType Events::handleEvents() {
static int oldX = -1, oldY = -1;
static uint32 dclickTime = 0;
// Handle event types
while (g_system->getEventManager()->pollEvent(_event)) {
switch (_event.type) {
case Common::EVENT_QUIT:
quitFlag = true;
break;
case Common::EVENT_KEYDOWN:
// Note: The Ctrl-D ScummVM shortcut has been specialised so it will only activate the debugger
// if it's the first key pressed after the Ctrl key is held down
if ((_event.kbd.keycode == Common::KEYCODE_LCTRL) || (_event.kbd.keycode == Common::KEYCODE_RCTRL))
_ctrlFlag = true;
else if (_event.kbd.hasFlags(Common::KBD_CTRL)) {
if ((_event.kbd.keycode == Common::KEYCODE_d) && _ctrlFlag) {
_console->attach();
_console->onFrame();
}
_ctrlFlag = false;
}
_keyCode = (int32)_event.kbd.keycode | ((_event.kbd.flags & (Common::KBD_CTRL | Common::KBD_ALT | Common::KBD_SHIFT)) << 24);
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_MBUTTONUP:
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
_vm->_mouse->handleEvent(_event);
break;
default:
break;
}
}
_mouseButtons = g_system->getEventManager()->getButtonState();
// State machine for moving between states
switch (_mouseState) {
case MSTATE_NO_EVENT:
if (_mouseButtons & LEFT_BUTTON_DOWN) {
if ((dclickTime != 0) && (g_system->getMillis() < dclickTime)) {
_mouseState = MSTATE_DOUBLECLICK_DOWN;
dclickTime = 0;
return MEVENT_DOUBLECLICK;
}
dclickTime = 0;
_mouseState = MSTATE_LEFT_CLICK_DOWN;
return MEVENT_LEFT_CLICK;
}
if (_mouseButtons & RIGHT_BUTTON_DOWN) {
_mouseState = MSTATE_RIGHT_CLICK_DOWN;
return MEVENT_RIGHT_CLICK;
}
if ((_event.mouse.x != oldX) || (_event.mouse.y != oldY)) {
oldX = _event.mouse.x; oldY = _event.mouse.y;
return MEVENT_MOVE;
}
return MEVENT_NO_EVENT;
case MSTATE_LEFT_CLICK_DOWN:
if (!(_mouseButtons & LEFT_BUTTON_DOWN)) {
dclickTime = g_system->getMillis() + 1000 * 15 / 60;
_mouseState = MSTATE_NO_EVENT;
return MEVENT_LEFT_RELEASE;
}
if ((_event.mouse.x != oldX) || (_event.mouse.y != oldY)) {
oldX = _event.mouse.x; oldY = _event.mouse.y;
return MEVENT_LEFT_DRAG;
}
return MEVENT_LEFT_HOLD;
case MSTATE_RIGHT_CLICK_DOWN:
if (!(_mouseButtons & RIGHT_BUTTON_DOWN)) {
_mouseState = MSTATE_NO_EVENT;
please_hyperwalk = true;
return MEVENT_RIGHT_RELEASE;
}
if ((_event.mouse.x != oldX) || (_event.mouse.y != oldY)) {
oldX = _event.mouse.x; oldY = _event.mouse.y;
return MEVENT_RIGHT_DRAG;
}
return MEVENT_RIGHT_HOLD;
case MSTATE_DOUBLECLICK_DOWN:
if (!(_mouseButtons & LEFT_BUTTON_DOWN)) {
_mouseState = MSTATE_NO_EVENT;
return MEVENT_DOUBLECLICK_RELEASE;
}
if ((_event.mouse.x != oldX) || (_event.mouse.y != oldY)) {
oldX = _event.mouse.x; oldY = _event.mouse.y;
return MEVENT_DOUBLECLICK_DRAG;
}
return MEVENT_DOUBLECLICK_HOLD;
default:
return MEVENT_NO_EVENT;
}
}
bool Events::kbdCheck(uint32 &keyCode) {
if (_keyCode == 0)
return false;
keyCode = _keyCode;
_keyCode = 0;
return true;
}
/*--------------------------------------------------------------------------*
* Mouse *
* *
* Implements an interface to the mouse *
*--------------------------------------------------------------------------*/
Mouse::Mouse(MadsM4Engine *vm) : _vm(vm) {
_locked = false;
_cursorOn = false;
_cursor = NULL;
_cursorSprites = NULL;
resetMouse();
}
Mouse::~Mouse() {
delete _cursorSprites;
}
bool Mouse::init(const char *seriesName, RGB8 *palette) {
Common::SeekableReadStream *stream = _vm->res()->get(seriesName);
int colorCount = 0;
RGB8* cursorPalette;
_cursorSprites = new SpriteAsset(_vm, stream, stream->size(), seriesName);
// Remove cursor special pixels and set the mouse cursor hotspot in MADS games
if (!_vm->isM4()) {
byte *data = NULL;
for (int i = 0; i < _cursorSprites->getCount(); i++) {
bool hotSpotSet = false;
for (int x = 0; x < _cursorSprites->getFrame(i)->width(); x++) {
for (int y = 0; y < _cursorSprites->getFrame(i)->height(); y++) {
data = _cursorSprites->getFrame(i)->getBasePtr(x, y);
if (*data == 1) {
// It seems that some cursors have more than one hotspot
// In such a case, the first hotspot seems to set the x and
// the second one the y hotspot offset
if (!hotSpotSet) {
_cursorSprites->getFrame(i)->xOffset = x;
_cursorSprites->getFrame(i)->yOffset = y;
hotSpotSet = true;
} else {
_cursorSprites->getFrame(i)->yOffset = y;
}
*data = 0;
}
} // for y
} // for x
} // for i
}
colorCount = _cursorSprites->getColorCount();
cursorPalette = _cursorSprites->getPalette();
_vm->_palette->setPalette(cursorPalette, 0, colorCount);
//printf("Cursor count: %d\n", _cursorSprites->getCount());
_vm->res()->toss(seriesName);
_currentCursor = -1;
return true;
}
bool Mouse::setCursorNum(int cursorIndex) {
if ((cursorIndex < 0) || (cursorIndex >= (int)_cursorSprites->getCount()))
return false;
_lockedCursor = cursorIndex;
if (_locked)
// Cursor is locked, so don't go ahead with changing cursor
return true;
_currentCursor = _lockedCursor;
_cursor = _cursorSprites->getFrame(cursorIndex);
// Set the cursor to the sprite
CursorMan.replaceCursor((const byte *)_cursor->getBasePtr(), _cursor->width(), _cursor->height(),
_cursor->xOffset, _cursor->yOffset, TRANSPARENT_COLOUR_INDEX);
return true;
}
int Mouse::cursorCount() {
return _cursorSprites->getCount();
}
void Mouse::cursorOn() {
_cursorOn = true;
CursorMan.showMouse(!inHideArea());
}
void Mouse::cursorOff() {
_cursorOn = false;
CursorMan.showMouse(false);
}
void Mouse::lockCursor(int cursorIndex) {
_locked = false;
setCursorNum(cursorIndex);
_locked = true;
}
void Mouse::unlockCursor() {
_locked = false;
setCursorNum(_lockedCursor);
}
const char *Mouse::getVerb() {
switch (_vm->_mouse->getCursorNum()) {
case CURSOR_LOOK:
return "LOOK AT";
case CURSOR_TAKE:
return "TAKE";
case CURSOR_USE:
return "GEAR";
default:
return NULL;
}
}
void Mouse::resetMouse() {
_hideRect.left = -1;
_hideRect.top = -1;
_hideRect.right = -1;
_hideRect.bottom = -1;
_showRect.left = -1;
_showRect.top = -1;
_showRect.right = -1;
_showRect.bottom = -1;
}
void Mouse::setHideRect(Common::Rect &r) {
_hideRect = r;
}
void Mouse::setShowRect(Common::Rect &r) {
_showRect = r;
}
const Common::Rect *Mouse::getHideRect() {
return &_hideRect;
}
const Common::Rect *Mouse::getShowRect() {
if ((_showRect.top == -1) || (_showRect.left == -1)) {
// Show rectangle uninitialised - set it to current screen dimensions
_showRect.top = 0;
_showRect.left = 0;
_showRect.right = _vm->_screen->width() - 1;
_showRect.bottom = _vm->_screen->height() -1;
}
return &_showRect;
}
void Mouse::handleEvent(Common::Event &event) {
_currentPos.x = event.mouse.x;
_currentPos.y = event.mouse.y;
// If mouse is turned on, check to see if the position is in the hide rect, or outside the show rect.
// If so, handle toggling the visibility of the mouse
bool showFlag = !inHideArea();
if (_cursorOn && (CursorMan.isVisible() != showFlag)) {
CursorMan.showMouse(showFlag);
}
}
bool Mouse::inHideArea() {
// Returns true if the mouse is inside a specified hide rect, or if a show rect is specified and
// the mouse is currently outside it
if ((_currentPos.x >= _hideRect.left) && (_currentPos.x <= _hideRect.right) &&
(_currentPos.y >= _hideRect.top) && (_currentPos.y <= _hideRect.bottom))
// Inside a hide area
return true;
if ((_showRect.top == -1) && (_showRect.left == -1))
// No show rect defined
return false;
// Return true if the mouse is outside the show area
return (_currentPos.x < _showRect.left) || (_currentPos.x > _showRect.right) ||
(_currentPos.y < _showRect.top) || (_currentPos.y > _showRect.bottom);
}
} // End of namespace M4