/* 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 "hopkins/events.h" #include "hopkins/files.h" #include "hopkins/globals.h" #include "hopkins/hopkins.h" #include "hopkins/sound.h" #include "common/system.h" #include "common/textconsole.h" #include "graphics/cursorman.h" namespace Hopkins { EventsManager::EventsManager(HopkinsEngine *vm) { _vm = vm; _mouseFl = false; _mouseLinuxFl = false; _mouseSizeX = _mouseSizeY = 0; _mouseOffset.x = _mouseOffset.y = 0; _startPos.x = _startPos.y = 0; _breakoutFl = false; _mouseSpriteId = 0; _curMouseButton = 0; _mouseButton = 0; _mouseCursor = NULL; _gameCounter = 0; _rateCounter = 0; _escKeyFl = false; _gameKey = KEY_NONE; _mouseCursorId = 0; _oldIconId = 0; _objectBuf = NULL; Common::fill(&_keyState[0], &_keyState[256], false); _priorCounterTime = _priorFrameTime = g_system->getMillis(); } EventsManager::~EventsManager() { _vm->_globals->freeMemory(_objectBuf); _vm->_globals->freeMemory(_mouseCursor); } void EventsManager::clearAll() { _vm->_globals->freeMemory(_objectBuf); _objectBuf = _vm->_globals->allocMemory(2500); } void EventsManager::initMouseData() { if (_vm->getPlatform() == Common::kPlatformLinux) _mouseLinuxFl = true; else _mouseLinuxFl = false; if (_mouseLinuxFl) { _mouseSizeX = 52; _mouseSizeY = 32; } else { _mouseSizeX = 34; _mouseSizeY = 20; } switch (_vm->_globals->_language) { case LANG_EN: if (!_mouseLinuxFl) _mouseCursor = _vm->_fileIO->loadFile("SOUAN.SPR"); else _mouseCursor = _vm->_fileIO->loadFile("LSOUAN.SPR"); break; case LANG_FR: if (!_mouseLinuxFl) _mouseCursor = _vm->_fileIO->loadFile("SOUFR.SPR"); else _mouseCursor = _vm->_fileIO->loadFile("LSOUFR.SPR"); break; case LANG_SP: _mouseCursor = _vm->_fileIO->loadFile("SOUES.SPR"); break; } } // Mouse On void EventsManager::setMouseOn() { _mouseFl = true; if (_mouseLinuxFl) { _mouseSizeX = 52; _mouseSizeY = 32; } else { _mouseSizeX = 34; _mouseSizeY = 20; } _mouseOffset.x = 0; _mouseOffset.y = 0; if (!_breakoutFl) setMouseXY(300, 200); else setMouseXY(150, 100); } /** * Set Mouse position */ void EventsManager::setMouseXY(Common::Point pos) { g_system->warpMouse(pos.x, pos.y); } /** * Set Mouse position */ void EventsManager::setMouseXY(int xp, int yp) { g_system->warpMouse(xp, yp); } /** * Get Mouse X */ int EventsManager::getMouseX() { _mousePos.x = _startPos.x + g_system->getEventManager()->getMousePos().x; _mousePos.y = g_system->getEventManager()->getMousePos().y; return _mousePos.x + _mouseOffset.x; } /** * Get Mouse Y */ int EventsManager::getMouseY() { _mousePos.x = _startPos.x + g_system->getEventManager()->getMousePos().x; _mousePos.y = g_system->getEventManager()->getMousePos().y; return _mousePos.y + _mouseOffset.y; } /** * Get Mouse Button */ int EventsManager::getMouseButton() { refreshEvents(); return _curMouseButton; } /** * Mouse Off */ void EventsManager::mouseOff() { _mouseFl = false; CursorMan.showMouse(false); } /** * Mouse On */ void EventsManager::mouseOn() { setMouseOn(); _mouseFl = true; CursorMan.showMouse(true); } /** * Change Mouse Cursor */ void EventsManager::changeMouseCursor(int id) { int cursorId = id; if (_mouseCursorId == 23) return; if (id == 4 && _mouseCursorId == 4 && _vm->_globals->_freezeCharacterFl) cursorId = 0; if (cursorId == 25) cursorId = 5; if (_oldIconId != cursorId || !cursorId) { _oldIconId = cursorId; _mouseSpriteId = cursorId; updateCursor(); } } /** * Check Events */ void EventsManager::refreshEvents() { _vm->_soundMan->checkSounds(); pollEvents(); } void EventsManager::checkForNextFrameCounter() { int32 delayAmount = 10 - (g_system->getMillis() - _priorCounterTime); if (delayAmount > 0) _vm->_system->delayMillis(delayAmount); // Check for whether to increment the game counter uint32 milli = g_system->getMillis(); while ((milli - _priorCounterTime) >= 10) { _priorCounterTime += 10; _rateCounter += 3; } // Check for next game frame if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) { ++_gameCounter; _priorFrameTime = milli; _vm->_graphicsMan->updateScreen(); // Signal the ScummVM debugger _vm->_debug->onFrame(); } } void EventsManager::delay(int totalMilli) { uint32 delayEnd = g_system->getMillis() + totalMilli; while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) { g_system->delayMillis(10); } } void EventsManager::pollEvents() { checkForNextFrameCounter(); Common::Event event; while (g_system->getEventManager()->pollEvent(event)) { // Handle keypress switch (event.type) { case Common::EVENT_QUIT: case Common::EVENT_RTL: return; case Common::EVENT_KEYDOWN: _keyState[(byte)toupper(event.kbd.ascii)] = true; handleKey(event); return; case Common::EVENT_KEYUP: _keyState[(byte)toupper(event.kbd.ascii)] = false; return; case Common::EVENT_LBUTTONDOWN: _mouseButton = 1; return; case Common::EVENT_RBUTTONDOWN: _mouseButton = 2; return; case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: _mouseButton = 0; return; default: break; } } for (char chr = 'A'; chr <= 'Z'; chr++) _keyState[(byte)chr] = false; for (char chr = '0'; chr <= '9'; chr++) _keyState[(byte)chr] = false; } void EventsManager::handleKey(const Common::Event &event) { _escKeyFl = (event.kbd.keycode == Common::KEYCODE_ESCAPE); if (event.kbd.keycode == Common::KEYCODE_i || event.kbd.keycode == Common::KEYCODE_TAB) _gameKey = KEY_INVENTORY; else if (event.kbd.keycode == Common::KEYCODE_F5) _gameKey = KEY_SAVE; else if (event.kbd.keycode == Common::KEYCODE_F7) _gameKey = KEY_LOAD; else if (event.kbd.keycode == Common::KEYCODE_F1 || event.kbd.keycode == Common::KEYCODE_o) _gameKey = KEY_OPTIONS; // Check for debugger if ((event.kbd.keycode == Common::KEYCODE_d) && (event.kbd.flags & Common::KBD_CTRL)) { // Attach to the debugger _vm->_debug->attach(); _vm->_debug->onFrame(); } } /** * Waits for a keypress, ignoring mouse events * @return Keypress, or -1 if game quit was requested */ int EventsManager::waitKeyPress() { char foundChar = '\0'; while (!foundChar) { if (_vm->shouldQuit()) return -1; for (char ch = 'A'; ch <= 'Z'; ++ch) { if (_keyState[(byte)ch]) { foundChar = ch; break; } } for (char ch = '0'; ch <= '9'; ++ch) { if (_keyState[(byte)ch]) { foundChar = ch; break; } } if (_keyState[(byte)'.']) foundChar = '.'; else if (_keyState[8]) // BACKSPACE foundChar = 8; else if (_keyState[13]) // ENTER foundChar = 13; else if (_keyState[(byte)' ']) foundChar = ' '; refreshScreenAndEvents(); } // Wait for keypress release while (_keyState[(byte)foundChar] && !_vm->shouldQuit()) { refreshScreenAndEvents(); g_system->delayMillis(10); } // Return character return foundChar; } void EventsManager::refreshScreenAndEvents() { int bottom = 0; int right = 0; int height = 0; int width = 0; int xp = 0; int yp = 0; if (_mouseFl) { int mouseWidth = 20; if (!_mouseLinuxFl) mouseWidth = 10; int mouseHeight = 20; if (!_mouseLinuxFl) mouseHeight = 15; xp = _mousePos.x - mouseWidth; yp = _mousePos.y; width = _mouseSizeX; height = _mouseSizeY; if (_mouseCursorId == 23) { width = _vm->_objectsMan->getObjectWidth(); height = _vm->_objectsMan->getObjectHeight(); } else { if (_breakoutFl) { if (xp < _vm->_graphicsMan->_minX) xp = _vm->_graphicsMan->_minX; if (_mousePos.y < _vm->_graphicsMan->_minY) yp = _vm->_graphicsMan->_minY; if (_mouseSizeX + xp >= _vm->_graphicsMan->_maxX) width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsMan->_maxX); if (yp + _mouseSizeY >= _vm->_graphicsMan->_maxY) height = _vm->_graphicsMan->_maxY - yp; } else { if (xp < _vm->_graphicsMan->_minX) xp = _vm->_graphicsMan->_minX - mouseWidth; mouseHeight = (int16)mouseHeight; if (_mousePos.y < _vm->_graphicsMan->_minY - mouseHeight) yp = _vm->_graphicsMan->_minY - mouseHeight; if (_mouseSizeX + xp >= _vm->_graphicsMan->_maxX) width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsMan->_maxX - mouseWidth); if (yp + _mouseSizeY >= mouseHeight + _vm->_graphicsMan->_maxY) height = _vm->_graphicsMan->_maxY - mouseHeight - yp; } right = xp + width; bottom = yp + height; } } if (!_vm->_globals->_linuxEndDemoFl) _vm->_objectsMan->displaySprite(); if (!_mouseFl) { updateCursor(); } else if (_mouseCursorId == 23) { if (yp < _vm->_graphicsMan->_maxY && xp < _vm->_graphicsMan->_maxX) { if (width + xp > _vm->_graphicsMan->_maxX) width = _vm->_graphicsMan->_maxX - xp; if (yp + height > _vm->_graphicsMan->_maxY) height = _vm->_graphicsMan->_maxY - yp; if (width > 1 && height > 1) { updateCursor(); } } } else if (yp < _vm->_graphicsMan->_maxY && xp < _vm->_graphicsMan->_maxX && width > 1 && height > 1) { updateCursor(); _vm->_graphicsMan->addDirtyRect(xp, yp, right, bottom); } _vm->_globals->_speed = 2; bool externalLoopFl = false; do { while (!_vm->shouldQuit()) { checkForNextFrameCounter(); bool innerLoopFl = false; while (!_vm->shouldQuit() && (_breakoutFl || _vm->_globals->_eventMode != EVENTMODE_IGNORE)) { checkForNextFrameCounter(); if (!_breakoutFl) { innerLoopFl = true; break; } if (_rateCounter > 1) { externalLoopFl = true; break; } } if (innerLoopFl || _vm->_globals->_speed != 2) break; if (externalLoopFl ||_rateCounter > 9) { externalLoopFl = true; break; } } if (externalLoopFl) break; } while (!_vm->shouldQuit() && _vm->_globals->_eventMode == EVENTMODE_CREDITS && _rateCounter <= 15); _vm->_globals->_speed = 2; _rateCounter = 0; if (!_vm->_graphicsMan->_largeScreenFl || _vm->_graphicsMan->_scrollStatus == 1) { _vm->_graphicsMan->displayDirtyRects(); } else { if (_vm->_graphicsMan->_scrollStatus != 2) { if (getMouseX() > _vm->_graphicsMan->_scrollPosX + 620) _vm->_graphicsMan->_scrollPosX += _vm->_graphicsMan->_scrollSpeed; if (getMouseX() < _vm->_graphicsMan->_scrollPosX + 10) _vm->_graphicsMan->_scrollPosX -= _vm->_graphicsMan->_scrollSpeed; } _vm->_graphicsMan->_scrollPosX = CLIP(_vm->_graphicsMan->_scrollPosX, 0, SCREEN_WIDTH); if (_vm->_graphicsMan->_oldScrollPosX == _vm->_graphicsMan->_scrollPosX) { _vm->_graphicsMan->displayDirtyRects(); } else { _vm->_fontMan->hideText(9); _vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_scrollPosX, 20, SCREEN_WIDTH, 440, 0, 20); _vm->_graphicsMan->resetRefreshRects(); _vm->_graphicsMan->addRefreshRect(0, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 20); _vm->_graphicsMan->resetDirtyRects(); _startPos.x = _vm->_graphicsMan->_scrollPosX; _vm->_graphicsMan->_scrollOffset = _vm->_graphicsMan->_scrollPosX; } _vm->_graphicsMan->_oldScrollPosX = _vm->_graphicsMan->_scrollPosX; _startPos.x = _vm->_graphicsMan->_scrollPosX; _vm->_graphicsMan->_scrollOffset = _vm->_graphicsMan->_scrollPosX; } _curMouseButton = _mouseButton; _mouseButton = 0; _vm->_soundMan->checkSoundEnd(); refreshEvents(); } void EventsManager::updateCursor() { // Backup the current sprite clipping bounds and reset them Common::Rect clipBounds(_vm->_graphicsMan->_minX, _vm->_graphicsMan->_minY, _vm->_graphicsMan->_maxX, _vm->_graphicsMan->_maxY); _vm->_graphicsMan->_minX = _vm->_graphicsMan->_minY = 0; _vm->_graphicsMan->_maxX = _vm->_objectsMan->getObjectWidth(); _vm->_graphicsMan->_maxY = _vm->_objectsMan->getObjectHeight(); int pitch = _vm->_graphicsMan->_lineNbr2; _vm->_graphicsMan->_lineNbr2 = _vm->_objectsMan->getObjectWidth(); // Create the temporary cursor surface byte *cursorSurface = new byte[_vm->_objectsMan->getObjectHeight() * _vm->_objectsMan->getObjectWidth()]; Common::fill(cursorSurface, cursorSurface + _vm->_objectsMan->getObjectHeight() * _vm->_objectsMan->getObjectWidth(), 0); if (_mouseCursorId != 23) { // Draw standard cursor _vm->_graphicsMan->drawVesaSprite(cursorSurface, _mouseCursor, 300, 300, _mouseSpriteId); } else { // Draw the active inventory object _vm->_graphicsMan->drawCompressedSprite(cursorSurface, _objectBuf, 300, 300, 0, 0, 0, false); } // Reset the clipping bounds _vm->_graphicsMan->_minX = clipBounds.left; _vm->_graphicsMan->_minY = clipBounds.top; _vm->_graphicsMan->_maxX = clipBounds.right; _vm->_graphicsMan->_maxY = clipBounds.bottom; _vm->_graphicsMan->_lineNbr2 = pitch; // Create a cursor palette Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); byte *cursorPalette = new byte[3 * PALETTE_SIZE]; uint16 *paletteColors = (uint16 *)_vm->_graphicsMan->_palettePixels; for (int i = 0; i < PALETTE_SIZE; i++) { uint8 r, g, b; pixelFormat.colorToRGB(READ_LE_UINT16(&paletteColors[i]), r, g, b); cursorPalette[3 * i] = r; cursorPalette[3 * i + 1] = g; cursorPalette[3 * i + 2] = b; } // Calculate the X offset within the pointer image to the actual cursor data int xOffset = !_mouseLinuxFl ? 10 : 20; // Set the ScummVM cursor from the surface CursorMan.replaceCursorPalette(cursorPalette, 0, PALETTE_SIZE - 1); CursorMan.replaceCursor(cursorSurface, _vm->_objectsMan->getObjectWidth(), _vm->_objectsMan->getObjectHeight(), xOffset, 0, 0, true); // Delete the cursor surface and palette delete[] cursorPalette; delete[] cursorSurface; } } // End of namespace Hopkins