/* 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$ * */ #include "common/stdafx.h" #include "common/events.h" #include "gob/gob.h" #include "gob/util.h" #include "gob/global.h" #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" #include "gob/imd.h" #include "gob/sound.h" #include "gob/video.h" namespace Gob { Util::Util(GobEngine *vm) : _vm(vm) { _mouseButtons = 0; for (int i = 0; i < KEYBUFSIZE; i++) _keyBuffer[i] = 0; _keyBufferHead = 0; _keyBufferTail = 0; _fastMode = 0; } uint32 Util::getTimeKey(void) { return g_system->getMillis() * _vm->_global->_speedFactor; } int16 Util::getRandom(int16 max) { return _vm->_rnd.getRandomNumber(max - 1); } void Util::beep(int16 freq) { if (_vm->_global->_soundFlags == 0) return; _vm->_snd->speakerOn(freq, 50); } void Util::delay(uint16 msecs) { g_system->delayMillis(msecs / _vm->_global->_speedFactor); } void Util::longDelay(uint16 msecs) { uint32 time = g_system->getMillis() * _vm->_global->_speedFactor + msecs; do { _vm->_video->waitRetrace(); processInput(); delay(15); } while (!_vm->_quitRequested && ((g_system->getMillis() * _vm->_global->_speedFactor) < time)); } void Util::initInput(void) { _mouseButtons = 0; _keyBufferHead = _keyBufferTail = 0; } void Util::processInput(bool scroll) { Common::Event event; Common::EventManager *eventMan = g_system->getEventManager(); int16 x = 0, y = 0; bool hasMove = false; while (eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: hasMove = true; x = event.mouse.x; y = event.mouse.y; break; case Common::EVENT_LBUTTONDOWN: _mouseButtons |= 1; break; case Common::EVENT_RBUTTONDOWN: _mouseButtons |= 2; break; case Common::EVENT_LBUTTONUP: _mouseButtons &= ~1; break; case Common::EVENT_RBUTTONUP: _mouseButtons &= ~2; break; case Common::EVENT_KEYDOWN: if (event.kbd.flags == Common::KBD_CTRL) { if (event.kbd.keycode == 'f') _fastMode ^= 1; else if (event.kbd.keycode == 'g') _fastMode ^= 2; break; } addKeyToBuffer(event.kbd.ascii); break; case Common::EVENT_KEYUP: break; case Common::EVENT_QUIT: _vm->_quitRequested = true; break; default: break; } } _vm->_global->_speedFactor = MIN(_fastMode + 1, 3); if (scroll && hasMove) { if (y >= (200 - _vm->_video->_splitHeight2)) { y = 200 - _vm->_video->_splitHeight2 - 1; _vm->_util->setMousePos(x, y); } _vm->_game->evaluateScroll(x, y); } } void Util::clearKeyBuf(void) { processInput(); _keyBufferHead = _keyBufferTail = 0; } bool Util::keyBufferEmpty() { return (_keyBufferHead == _keyBufferTail); } void Util::addKeyToBuffer(int16 key) { if ((_keyBufferHead + 1) % KEYBUFSIZE == _keyBufferTail) { warning("key buffer overflow"); return; } _keyBuffer[_keyBufferHead] = key; _keyBufferHead = (_keyBufferHead + 1) % KEYBUFSIZE; } bool Util::getKeyFromBuffer(int16& key) { if (_keyBufferHead == _keyBufferTail) return false; key = _keyBuffer[_keyBufferTail]; _keyBufferTail = (_keyBufferTail + 1) % KEYBUFSIZE; return true; } int16 Util::translateKey(int16 key) { static struct keyS { int16 from; int16 to; } keys[] = { {8, 0x0E08}, // Backspace {32, 0x3920}, // Space {13, 0x1C0D}, // Enter {27, 0x011B}, // ESC {127, 0x5300}, // Del {Common::KEYCODE_UP, 0x4800}, // Up arrow {Common::KEYCODE_DOWN, 0x5000}, // Down arrow {Common::KEYCODE_RIGHT, 0x4D00}, // Right arrow {Common::KEYCODE_LEFT, 0x4B00}, // Left arrow {Common::ASCII_F1, 0x3B00}, // F1 {Common::ASCII_F2, 0x3C00}, // F2 {Common::ASCII_F3, 0x3D00}, // F3 {Common::ASCII_F4, 0x3E00}, // F4 {Common::ASCII_F5, 0x011B}, // F5 {Common::ASCII_F6, 0x4000}, // F6 {Common::ASCII_F7, 0x4100}, // F7 {Common::ASCII_F8, 0x4200}, // F8 {Common::ASCII_F9, 0x4300}, // F9 {Common::ASCII_F10, 0x4400} // F10 }; for (int i = 0; i < ARRAYSIZE(keys); i++) if (key == keys[i].from) return keys[i].to; if ((key < 32) || (key >= 128)) return 0; return key; } int16 Util::getKey(void) { int16 key; while (!getKeyFromBuffer(key)) { processInput(); if (keyBufferEmpty()) g_system->delayMillis(10 / _vm->_global->_speedFactor); } return translateKey(key); } int16 Util::checkKey(void) { int16 key; if (!getKeyFromBuffer(key)) key = 0; return translateKey(key); } void Util::getMouseState(int16 *pX, int16 *pY, int16 *pButtons) { Common::Point mouse = g_system->getEventManager()->getMousePos(); *pX = mouse.x + _vm->_video->_scrollOffsetX; *pY = mouse.y + _vm->_video->_scrollOffsetY; if (pButtons != 0) *pButtons = _mouseButtons; } void Util::setMousePos(int16 x, int16 y) { g_system->warpMouse(x, y); } void Util::waitMouseUp(void) { do { processInput(); if (_mouseButtons != 0) delay(10); } while (_mouseButtons != 0); } void Util::waitMouseDown(void) { int16 x; int16 y; int16 buttons; do { processInput(); getMouseState(&x, &y, &buttons); if (buttons == 0) delay(10); } while (buttons == 0); } void Util::waitMouseRelease(char drawMouse) { int16 buttons; int16 mouseX; int16 mouseY; do { _vm->_game->checkKeys(&mouseX, &mouseY, &buttons, drawMouse); if (drawMouse != 0) _vm->_draw->animateCursor(2); delay(10); } while (buttons != 0); } void Util::forceMouseUp(bool onlyWhenSynced) { if (onlyWhenSynced && (_vm->_game->_mouseButtons != _mouseButtons)) return; _vm->_game->_mouseButtons = 0; _mouseButtons = 0; } void Util::clearPalette(void) { int16 i; byte colors[768]; _vm->validateVideoMode(_vm->_global->_videoMode); if (_vm->_global->_setAllPalette) { for (i = 0; i < 768; i++) colors[i] = 0; g_system->setPalette(colors, 0, 256); return; } for (i = 0; i < 16; i++) _vm->_video->setPalElem(i, 0, 0, 0, 0, _vm->_global->_videoMode); } void Util::setFrameRate(int16 rate) { if (rate == 0) rate = 1; _vm->_global->_frameWaitTime = 1000 / rate; _vm->_global->_startFrameTime = getTimeKey(); _vm->_imdPlayer->_frameDelay = 0; } void Util::waitEndFrame() { int32 time; _vm->_video->waitRetrace(); time = getTimeKey() - _vm->_global->_startFrameTime; if ((time > 1000) || (time < 0)) { _vm->_global->_startFrameTime = getTimeKey(); _vm->_imdPlayer->_frameDelay = 0; return; } if (_vm->_global->_frameWaitTime - time > 0) { _vm->_imdPlayer->_frameDelay = 0; delay(_vm->_global->_frameWaitTime - _vm->_imdPlayer->_frameDelay - time); } _vm->_global->_startFrameTime = getTimeKey(); _vm->_imdPlayer->_frameDelay = time - _vm->_global->_frameWaitTime; } void Util::setScrollOffset(int16 x, int16 y) { processInput(); _vm->_video->_scrollOffsetX = x >= 0 ? x : _vm->_draw->_scrollOffsetX; _vm->_video->_scrollOffsetY = y >= 0 ? y : _vm->_draw->_scrollOffsetY; _vm->_video->waitRetrace(); } Video::FontDesc *Util::loadFont(const char *path) { Video::FontDesc *fontDesc = new Video::FontDesc; byte *data; if (!fontDesc) return 0; data = _vm->_dataIO->getData(path); if (!data) { delete fontDesc; return 0; } fontDesc->dataPtr = data + 4; fontDesc->itemWidth = data[0] & 0x7F; fontDesc->itemHeight = data[1]; fontDesc->startItem = data[2]; fontDesc->endItem = data[3]; fontDesc->itemSize = ((fontDesc->itemWidth - 1) / 8 + 1) * fontDesc->itemHeight; fontDesc->bitWidth = fontDesc->itemWidth; if (data[0] & 0x80) fontDesc->extraData = data + 4 + fontDesc->itemSize * (fontDesc->endItem - fontDesc->startItem + 1); else fontDesc->extraData = 0; return fontDesc; } void Util::freeFont(Video::FontDesc *fontDesc) { delete[] (fontDesc->dataPtr - 4); delete fontDesc; } void Util::insertStr(const char *str1, char *str2, int16 pos) { int len1 = strlen(str1); int len2 = strlen(str2); int from = MIN((int) pos, len2); for (int i = len2; i >= from; i--) str2[len1 + i] = str2[i]; for (int i = 0; i < len1; i++) str2[i + from] = str1[i]; } void Util::cutFromStr(char *str, int16 from, int16 cutlen) { int len = strlen(str); if (from >= len) return; if ((from + cutlen) > len) { str[from] = 0; return; } int i = from; do { str[i] = str[i + cutlen]; i++; } while (str[i] != 0); } void Util::replaceChar(char *str, char c1, char c2) { while ((str = strchr(str, c1))) *str = c2; } static const char trStr1[] = " ' + - :0123456789: <=> abcdefghijklmnopqrstuvwxyz " "abcdefghijklmnopqrstuvwxyz "; static const char trStr2[] = " ueaaaaceeeiii ooouu aioun" " "; static const char trStr3[] = " "; void Util::prepareStr(char *str) { char *start, *end; char buf[300]; strcpy(buf, trStr1); strcat(buf, trStr2); strcat(buf, trStr3); for (size_t i = 0; i < strlen(str); i++) str[i] = buf[str[i] - 32]; while (str[0] == ' ') cutFromStr(str, 0, 1); while ((strlen(str) > 0) && (str[strlen(str) - 1] == ' ')) cutFromStr(str, strlen(str) - 1, 1); start = strchr(str, ' '); while (start) { if (start[1] == ' ') { cutFromStr(str, start - str, 1); continue; } end = strchr(start + 1, ' '); start = end ? end + 1 : 0; } } void Util::listInsertFront(List *list, void *data) { ListNode *node; node = new ListNode; if (list->pHead) { node->pData = data; node->pNext = list->pHead; node->pPrev = 0; list->pHead->pPrev = node; list->pHead = node; } else { list->pHead = node; list->pTail = node; node->pData = data; node->pNext = 0; node->pPrev = 0; } } void Util::listInsertBack(List *list, void *data) { ListNode *node; if (list->pHead != 0) { if (list->pTail == 0) { list->pTail = list->pHead; warning("Util::listInsertBack(): Broken list"); } node = new ListNode; node->pData = data; node->pPrev = list->pTail; node->pNext = 0; list->pTail->pNext = node; list->pTail = node; } else listInsertFront(list, data); } void Util::listDropFront(List *list) { if (list->pHead->pNext == 0) { delete list->pHead; list->pHead = 0; list->pTail = 0; } else { list->pHead = list->pHead->pNext; delete list->pHead->pPrev; list->pHead->pPrev = 0; } } void Util::deleteList(List *list) { while (list->pHead) listDropFront(list); delete list; } /* NOT IMPLEMENTED */ void Util::checkJoystick() { _vm->_global->_useJoystick = 0; } } // End of namespace Gob