/* 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/system.h" #include "common/textconsole.h" #include "graphics/cursorman.h" #include "hopkins/events.h" #include "hopkins/files.h" #include "hopkins/globals.h" #include "hopkins/hopkins.h" #include "hopkins/sound.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; } // 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() { signed int v11 = 0; signed int v12 = 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; } v12 = width + xp; v11 = yp + height; } } if (!_vm->_globals.PUBEXIT) _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, v12, v11); } _vm->_globals._speed = 2; do { while (!_vm->shouldQuit()) { checkForNextFrameCounter(); while (_breakoutFl || _vm->_globals.iRegul != 1) { checkForNextFrameCounter(); if (!_breakoutFl) goto LABEL_63; if (_rateCounter > 1) goto LABEL_65; } if (_vm->_globals._speed != 2) break; if (_rateCounter > 9) goto LABEL_65; } LABEL_63: ; } while (!_vm->shouldQuit() && _vm->_globals.iRegul == 3 && _rateCounter <= 15); LABEL_65: _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); for (int i = 1; i < _vm->_globals.NBBLOC + 1; i++) { if (_vm->_globals.BLOC[i]._activeFl) _vm->_globals.BLOC[i]._activeFl = false; } _vm->_globals.NBBLOC = 0; _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; // Convert the cursor to the pixel format. At the moment, it's hardcoded // to expect the game to be in 16-bit mode uint16 *cursorPixels = new uint16[_vm->_globals._objectHeight * _vm->_globals._objectWidth]; const byte *srcP = cursorSurface; uint16 *destP = cursorPixels; for (int yp = 0; yp < _vm->_globals._objectHeight; ++yp) { const byte *lineSrcP = srcP; uint16 *lineDestP = destP; for (int xp = 0; xp < _vm->_globals._objectWidth; ++xp) *lineDestP++ = *(uint16 *)&_vm->_graphicsManager.PAL_PIXELS[*lineSrcP++ * 2]; srcP += _vm->_globals._objectWidth; destP += _vm->_globals._objectWidth; } // 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 Graphics::PixelFormat pixelFormat = g_system->getScreenFormat(); CursorMan.replaceCursor(cursorPixels, _vm->_globals._objectWidth, _vm->_globals._objectHeight, xOffset, 0, *((uint16 *)cursorPixels), true, &pixelFormat); // Delete the cursor surface delete[] cursorPixels; delete[] cursorSurface; } } // End of namespace Hopkins