/* 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() { _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 = 0; _priorFrameTime = 0; } EventsManager::~EventsManager() { _vm->_globals.freeMemory(_objectBuf); _vm->_globals.freeMemory(_mouseCursor); } void EventsManager::setParent(HopkinsEngine *vm) { _vm = vm; } 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->_fileManager.loadFile("SOUAN.SPR"); else _mouseCursor = _vm->_fileManager.loadFile("LSOUAN.SPR"); break; case LANG_FR: if (!_mouseLinuxFl) _mouseCursor = _vm->_fileManager.loadFile("SOUFR.SPR"); else _mouseCursor = _vm->_fileManager.loadFile("LSOUFR.SPR"); break; case LANG_SP: _mouseCursor = _vm->_fileManager.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.NOMARCHE) cursorId = 0; if (cursorId == 25) cursorId = 5; if (_oldIconId != cursorId || !cursorId) { _oldIconId = cursorId; _mouseSpriteId = cursorId; updateCursor(); } } /** * Check Events */ void EventsManager::refreshEvents() { _vm->_soundManager.checkSounds(); pollEvents(); } void EventsManager::checkForNextFrameCounter() { // 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; g_system->updateScreen(); // Signal the ScummVM debugger _vm->_debugger.onFrame(); } } void EventsManager::delay(int totalMilli) { uint32 delayEnd = g_system->getMillis() + totalMilli; while (!g_system->getEventManager()->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(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->_debugger.attach(); _vm->_debugger.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 = ' '; VBL(); } // Wait for keypress release while (_keyState[(byte)foundChar] && !_vm->shouldQuit()) { VBL(); g_system->delayMillis(10); } // Return character return foundChar; } void EventsManager::VBL() { 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->_globals._objectWidth; height = _vm->_globals._objectHeight; } else { if (_breakoutFl) { if (xp < _vm->_graphicsManager._minX) xp = _vm->_graphicsManager._minX; if (_mousePos.y < _vm->_graphicsManager._minY) yp = _vm->_graphicsManager._minY; if (_mouseSizeX + xp >= _vm->_graphicsManager._maxX) width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsManager._maxX); if (yp + _mouseSizeY >= _vm->_graphicsManager._maxY) height = _vm->_graphicsManager._maxY - yp; } else { if (xp < _vm->_graphicsManager._minX) xp = _vm->_graphicsManager._minX - mouseWidth; mouseHeight = (int16)mouseHeight; if (_mousePos.y < _vm->_graphicsManager._minY - mouseHeight) yp = _vm->_graphicsManager._minY - mouseHeight; if (_mouseSizeX + xp >= _vm->_graphicsManager._maxX) width = _mouseSizeX - (_mouseSizeX + xp - _vm->_graphicsManager._maxX - mouseWidth); if (yp + _mouseSizeY >= mouseHeight + _vm->_graphicsManager._maxY) height = _vm->_graphicsManager._maxY - mouseHeight - yp; } right = xp + width; bottom = yp + height; } } if (!_vm->_globals._linuxEndDemoFl) _vm->_objectsManager.displaySprite(); if (!_mouseFl) { updateCursor(); } else if (_mouseCursorId == 23) { if (yp < _vm->_graphicsManager._maxY && xp < _vm->_graphicsManager._maxX) { if (width + xp > _vm->_graphicsManager._maxX) width = _vm->_graphicsManager._maxX - xp; if (yp + height > _vm->_graphicsManager._maxY) height = _vm->_graphicsManager._maxY - yp; if (width > 1 && height > 1) { _vm->_eventsManager.updateCursor(); } } } else if (yp < _vm->_graphicsManager._maxY && xp < _vm->_graphicsManager._maxX && width > 1 && height > 1) { _vm->_eventsManager.updateCursor(); _vm->_graphicsManager.addVesaSegment(xp, yp, right, bottom); } _vm->_globals._speed = 2; bool externalLoopFl = false; do { while (!_vm->shouldQuit()) { checkForNextFrameCounter(); bool innerLoopFl = false; while (_breakoutFl || _vm->_globals.iRegul != 1) { 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.iRegul == 3 && _rateCounter <= 15); _vm->_globals._speed = 2; _rateCounter = 0; if (!_vm->_graphicsManager._largeScreenFl || _vm->_graphicsManager._scrollStatus == 1) { _vm->_graphicsManager.displayVesaSegment(); } else { if (_vm->_graphicsManager._scrollStatus != 2) { if (getMouseX() > _vm->_graphicsManager._scrollPosX + 620) _vm->_graphicsManager._scrollPosX += _vm->_graphicsManager._scrollSpeed; if (getMouseX() < _vm->_graphicsManager._scrollPosX + 10) _vm->_graphicsManager._scrollPosX -= _vm->_graphicsManager._scrollSpeed; } if (_vm->_graphicsManager._scrollPosX < 0) _vm->_graphicsManager._scrollPosX = 0; if (_vm->_graphicsManager._scrollPosX > SCREEN_WIDTH) _vm->_graphicsManager._scrollPosX = SCREEN_WIDTH; if (_vm->_graphicsManager._oldScrollPosX == _vm->_graphicsManager._scrollPosX) { _vm->_graphicsManager.displayVesaSegment(); } else { _vm->_fontManager.hideText(9); _vm->_graphicsManager.lockScreen(); _vm->_graphicsManager.m_scroll16(_vm->_graphicsManager._vesaBuffer, _vm->_graphicsManager._scrollPosX, 20, SCREEN_WIDTH, 440, 0, 20); _vm->_graphicsManager.unlockScreen(); _vm->_graphicsManager.dstrect[0] = Common::Rect(0, 20, SCREEN_WIDTH, 460); _vm->_graphicsManager.resetVesaSegment(); _startPos.x = _vm->_graphicsManager._scrollPosX; _vm->_graphicsManager._scrollOffset = _vm->_graphicsManager._scrollPosX; _vm->_graphicsManager._scrollPosX = _vm->_graphicsManager._scrollPosX; } _vm->_graphicsManager._oldScrollPosX = _vm->_graphicsManager._scrollPosX; _startPos.x = _vm->_graphicsManager._scrollPosX; _vm->_graphicsManager._scrollOffset = _vm->_graphicsManager._scrollPosX; } _curMouseButton = _mouseButton; _mouseButton = 0; _vm->_soundManager.checkSoundEnd(); refreshEvents(); } void EventsManager::updateCursor() { // Backup the current sprite clipping bounds and reset them Common::Rect clipBounds(_vm->_graphicsManager._minX, _vm->_graphicsManager._minY, _vm->_graphicsManager._maxX, _vm->_graphicsManager._maxY); _vm->_graphicsManager._minX = _vm->_graphicsManager._minY = 0; _vm->_graphicsManager._maxX = _vm->_globals._objectWidth; _vm->_graphicsManager._maxY = _vm->_globals._objectHeight; int pitch = _vm->_graphicsManager._lineNbr2; _vm->_graphicsManager._lineNbr2 = _vm->_globals._objectWidth; // Create the temporary cursor surface byte *cursorSurface = new byte[_vm->_globals._objectHeight * _vm->_globals._objectWidth]; Common::fill(cursorSurface, cursorSurface + _vm->_globals._objectHeight * _vm->_globals._objectWidth, 0); if (_mouseCursorId != 23) { // Draw standard cursor _vm->_graphicsManager.Sprite_Vesa(cursorSurface, _mouseCursor, 300, 300, _mouseSpriteId); } else { // Draw the active inventory object _vm->_graphicsManager.Affiche_Perfect(cursorSurface, _objectBuf, 300, 300, 0, 0, 0, false); } // Reset the clipping bounds _vm->_graphicsManager._minX = clipBounds.left; _vm->_graphicsManager._minY = clipBounds.top; _vm->_graphicsManager._maxX = clipBounds.right; _vm->_graphicsManager._maxY = clipBounds.bottom; _vm->_graphicsManager._lineNbr2 = pitch; // Create a cursor palette Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); byte *cursorPalette = new byte[3 * PALETTE_SIZE]; uint16 *paletteColors = (uint16 *)_vm->_graphicsManager.PAL_PIXELS; 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->_globals._objectWidth, _vm->_globals._objectHeight, xOffset, 0, 0, true); // Delete the cursor surface and palette delete[] cursorPalette; delete[] cursorSurface; } } // End of namespace Hopkins