diff options
Diffstat (limited to 'sword2/mouse.cpp')
| -rw-r--r-- | sword2/mouse.cpp | 1437 |
1 files changed, 0 insertions, 1437 deletions
diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp deleted file mode 100644 index f8c315a47f..0000000000 --- a/sword2/mouse.cpp +++ /dev/null @@ -1,1437 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 The ScummVM project - * - * 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 "sword2/sword2.h" -#include "sword2/console.h" -#include "sword2/controls.h" -#include "sword2/defs.h" -#include "sword2/logic.h" -#include "sword2/maketext.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -namespace Sword2 { - -// Pointer resource id's - -enum { - CROSHAIR = 18, - EXIT0 = 788, - EXIT1 = 789, - EXIT2 = 790, - EXIT3 = 791, - EXIT4 = 792, - EXIT5 = 793, - EXIT6 = 794, - EXIT7 = 795, - EXITDOWN = 796, - EXITUP = 797, - MOUTH = 787, - NORMAL = 17, - PICKUP = 3099, - SCROLL_L = 1440, - SCROLL_R = 1441, - USE = 3100 -}; - -Mouse::Mouse(Sword2Engine *vm) { - _vm = vm; - - setPos(0, 0); - resetMouseList(); - - _mouseTouching = 0; - _oldMouseTouching = 0; - _menuSelectedPos = 0; - _examiningMenuIcon = false; - _mousePointerRes = 0; - _mouseMode = 0; - _mouseStatus = false; - _mouseModeLocked = false; - _currentLuggageResource = 0; - _oldButton = 0; - _buttonClick = 0; - _pointerTextBlocNo = 0; - _playerActivityDelay = 0; - _realLuggageItem = 0; - - _mouseAnim.data = NULL; - _luggageAnim.data = NULL; - - // For the menus - _totalTemp = 0; - memset(_tempList, 0, sizeof(_tempList)); - - _totalMasters = 0; - memset(_masterMenuList, 0, sizeof(_masterMenuList)); - memset(_mouseList, 0, sizeof(_mouseList)); - memset(_subjectList, 0, sizeof(_subjectList)); - - _defaultResponseId = 0; - _choosing = false; - - _iconCount = 0; - - for (int i = 0; i < 2; i++) { - for (int j = 0; j < RDMENU_MAXPOCKETS; j++) { - _icons[i][j] = NULL; - _pocketStatus[i][j] = 0; - } - - _menuStatus[i] = RDMENU_HIDDEN; - } -} - -Mouse::~Mouse() { - free(_mouseAnim.data); - free(_luggageAnim.data); - for (int i = 0; i < 2; i++) - for (int j = 0; j < RDMENU_MAXPOCKETS; j++) - free(_icons[i][j]); -} - -void Mouse::getPos(int &x, int &y) { - x = _pos.x; - y = _pos.y; -} - -void Mouse::setPos(int x, int y) { - _pos.x = x; - _pos.y = y; -} - -/** - * Call at beginning of game loop - */ - -void Mouse::resetMouseList() { - _curMouse = 0; -} - -void Mouse::registerMouse(byte *ob_mouse, BuildUnit *build_unit) { - assert(_curMouse < TOTAL_mouse_list); - - ObjectMouse mouse; - - mouse.read(ob_mouse); - - if (!mouse.pointer) - return; - - if (build_unit) { - _mouseList[_curMouse].rect.left = build_unit->x; - _mouseList[_curMouse].rect.top = build_unit->y; - _mouseList[_curMouse].rect.right = 1 + build_unit->x + build_unit->scaled_width; - _mouseList[_curMouse].rect.bottom = 1 + build_unit->y + build_unit->scaled_height; - } else { - _mouseList[_curMouse].rect.left = mouse.x1; - _mouseList[_curMouse].rect.top = mouse.y1; - _mouseList[_curMouse].rect.right = 1 + mouse.x2; - _mouseList[_curMouse].rect.bottom = 1 + mouse.y2; - } - - _mouseList[_curMouse].priority = mouse.priority; - _mouseList[_curMouse].pointer = mouse.pointer; - - // Change all COGS pointers to CROSHAIR. I'm guessing that this was a - // design decision made in mid-development and they didn't want to go - // back and re-generate the resource files. - - if (_mouseList[_curMouse].pointer == USE) - _mouseList[_curMouse].pointer = CROSHAIR; - - // Check if pointer text field is set due to previous object using this - // slot (ie. not correct for this one) - - // If 'pointer_text' field is set, but the 'id' field isn't same is - // current id then we don't want this "left over" pointer text - - if (_mouseList[_curMouse].pointer_text && _mouseList[_curMouse].id != (int32)_vm->_logic->readVar(ID)) - _mouseList[_curMouse].pointer_text = 0; - - // Get id from system variable 'id' which is correct for current object - _mouseList[_curMouse].id = _vm->_logic->readVar(ID); - - _curMouse++; -} - -void Mouse::registerPointerText(int32 text_id) { - assert(_curMouse < TOTAL_mouse_list); - - // current object id - used for checking pointer_text when mouse area - // registered (in fnRegisterMouse and fnRegisterFrame) - - _mouseList[_curMouse].id = _vm->_logic->readVar(ID); - _mouseList[_curMouse].pointer_text = text_id; -} - -/** - * This function is called every game cycle. - */ - -void Mouse::mouseEngine() { - monitorPlayerActivity(); - clearPointerText(); - - // If George is dead, the system menu is visible all the time, and is - // the only thing that can be used. - - if (_vm->_logic->readVar(DEAD)) { - if (_mouseMode != MOUSE_system_menu) { - _mouseMode = MOUSE_system_menu; - - if (_mouseTouching) { - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - } - systemMenuMouse(); - return; - } - - // If the mouse is not visible, do nothing - - if (_mouseStatus) - return; - - switch (_mouseMode) { - case MOUSE_normal: - normalMouse(); - break; - case MOUSE_menu: - menuMouse(); - break; - case MOUSE_drag: - dragMouse(); - break; - case MOUSE_system_menu: - systemMenuMouse(); - break; - case MOUSE_holding: - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - debug(5, " releasing"); - } - break; - default: - break; - } -} - -#if RIGHT_CLICK_CLEARS_LUGGAGE -bool Mouse::heldIsInInventory() { - int32 object_held = (int32)_vm->_logic->readVar(OBJECT_HELD); - - for (uint i = 0; i < _totalMasters; i++) { - if (_masterMenuList[i].icon_resource == object_held) - return true; - } - return false; -} -#endif - -int Mouse::menuClick(int menu_items) { - if (_pos.x < RDMENU_ICONSTART) - return -1; - - if (_pos.x > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING) - return -1; - - return (_pos.x - RDMENU_ICONSTART) / (RDMENU_ICONWIDE + RDMENU_ICONSPACING); -} - -void Mouse::systemMenuMouse() { - uint32 safe_looping_music_id; - MouseEvent *me; - int hit; - byte *icon; - int32 pars[2]; - uint32 icon_list[5] = { - OPTIONS_ICON, - QUIT_ICON, - SAVE_ICON, - RESTORE_ICON, - RESTART_ICON - }; - - // If the mouse is moved off the menu, close it. Unless the player is - // dead, in which case the menu should always be visible. - - if (_pos.y > 0 && !_vm->_logic->readVar(DEAD)) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - return; - } - - // Check if the user left-clicks anywhere in the menu area. - - me = _vm->mouseEvent(); - - if (!me || !(me->buttons & RD_LEFTBUTTONDOWN)) - return; - - if (_pos.y > 0) - return; - - hit = menuClick(ARRAYSIZE(icon_list)); - - if (hit < 0) - return; - - // No save when dead - - if (icon_list[hit] == SAVE_ICON && _vm->_logic->readVar(DEAD)) - return; - - // Gray out all he icons, except the one that was clicked - - for (int i = 0; i < ARRAYSIZE(icon_list); i++) { - if (i != hit) { - icon = _vm->_resman->openResource(icon_list[i]) + ResHeader::size(); - setMenuIcon(RDMENU_TOP, i, icon); - _vm->_resman->closeResource(icon_list[i]); - } - } - - _vm->_sound->pauseFx(); - - // NB. Need to keep a safe copy of '_loopingMusicId' for savegame & for - // playing when returning from control panels because control panel - // music will overwrite it! - - safe_looping_music_id = _vm->_sound->getLoopingMusicId(); - - pars[0] = 221; - pars[1] = FX_LOOP; - _vm->_logic->fnPlayMusic(pars); - - // HACK: Restore proper looping_music_id - _vm->_sound->setLoopingMusicId(safe_looping_music_id); - - processMenu(); - - // call the relevant screen - - switch (hit) { - case 0: - { - OptionsDialog dialog(_vm); - dialog.runModal(); - } - break; - case 1: - { - QuitDialog dialog(_vm); - dialog.runModal(); - } - break; - case 2: - { - SaveDialog dialog(_vm); - dialog.runModal(); - } - break; - case 3: - { - RestoreDialog dialog(_vm); - dialog.runModal(); - } - break; - case 4: - { - RestartDialog dialog(_vm); - dialog.runModal(); - } - break; - } - - // Menu stays open on death screen. Otherwise it's closed. - - if (!_vm->_logic->readVar(DEAD)) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - } else { - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - } - - // Back to the game again - - processMenu(); - - // Reset game palette, but not after a successful restore or restart! - // See RestoreFromBuffer() in save_rest.cpp - - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - if (screenInfo->new_palette != 99) { - // 0 means put back game screen palette; see build_display.cpp - _vm->_screen->setFullPalette(0); - - // Stop the engine fading in the restored screens palette - screenInfo->new_palette = 0; - } else - screenInfo->new_palette = 1; - - _vm->_sound->unpauseFx(); - - // If there was looping music before coming into the control panels - // then restart it! NB. If a game has been restored the music will be - // restarted twice, but this shouldn't cause any harm. - - if (_vm->_sound->getLoopingMusicId()) { - pars[0] = _vm->_sound->getLoopingMusicId(); - pars[1] = FX_LOOP; - _vm->_logic->fnPlayMusic(pars); - } else - _vm->_logic->fnStopMusic(NULL); -} - -void Mouse::dragMouse() { - byte buf1[NAME_LEN], buf2[NAME_LEN]; - MouseEvent *me; - int hit; - - // We can use dragged object both on other inventory objects, or on - // objects in the scene, so if the mouse moves off the inventory menu, - // then close it. - - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_BOTTOM); - return; - } - - // Handles cursors and the luggage on/off according to type - - mouseOnOff(); - - // Now do the normal click stuff - - me = _vm->mouseEvent(); - - if (!me) - return; - -#if RIGHT_CLICK_CLEARS_LUGGAGE - if ((me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - _mouseMode = MOUSE_menu; - setLuggage(0); - buildMenu(); - return; - } -#endif - - if (!(me->buttons & RD_LEFTBUTTONDOWN)) - return; - - // there's a mouse event to be processed - - // could be clicking on an on screen object or on the menu - // which is currently displayed - - if (_mouseTouching) { - // mouse is over an on screen object - and we have luggage - - // Depending on type we'll maybe kill the object_held - like - // for exits - - // Set global script variable 'button'. We know that it was the - // left button, not the right one. - - _vm->_logic->writeVar(LEFT_BUTTON, 1); - _vm->_logic->writeVar(RIGHT_BUTTON, 0); - - // These might be required by the action script about to be run - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); - _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); - - // For scripts to know what's been clicked. First used for - // 'room_13_turning_script' in object 'biscuits_13' - - _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); - - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); - - // Hide menu - back to normal menu mode - - hideMenu(RDMENU_BOTTOM); - _mouseMode = MOUSE_normal; - - return; - } - - // Better check for combine/cancel. Cancel puts us back in MOUSE_menu - // mode - - hit = menuClick(TOTAL_engine_pockets); - - if (hit < 0 || !_masterMenuList[hit].icon_resource) - return; - - // Always back into menu mode. Remove the luggage as well. - - _mouseMode = MOUSE_menu; - setLuggage(0); - - if ((uint)hit == _menuSelectedPos) { - // If we clicked on the same icon again, reset the first icon - - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - } else { - // Otherwise, combine the two icons - - _vm->_logic->writeVar(COMBINE_BASE, _masterMenuList[hit].icon_resource); - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); - - // Turn off mouse now, to prevent player trying to click - // elsewhere BUT leave the bottom menu open - - hideMouse(); - - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(COMBINE_BASE), buf2)); - } - - // Refresh the menu - - buildMenu(); -} - -void Mouse::menuMouse() { - byte buf[NAME_LEN]; - MouseEvent *me; - int hit; - - // If the mouse is moved off the menu, close it. - - if (_pos.y < 400) { - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_BOTTOM); - return; - } - - me = _vm->mouseEvent(); - - if (!me) - return; - - hit = menuClick(TOTAL_engine_pockets); - - // Check if we clicked on an actual icon. - - if (hit < 0 || !_masterMenuList[hit].icon_resource) - return; - - if (me->buttons & RD_RIGHTBUTTONDOWN) { - // Right button - examine an object, identified by its icon - // resource id. - - _examiningMenuIcon = true; - _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); - - // Must clear this so next click on exit becomes 1st click - // again - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, MENU_MASTER_OBJECT); - - // Refresh the menu - - buildMenu(); - - // Turn off mouse now, to prevent player trying to click - // elsewhere BUT leave the bottom menu open - - hideMouse(); - - debug(2, "Right-click on \"%s\" icon", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); - - return; - } - - if (me->buttons & RD_LEFTBUTTONDOWN) { - // Left button - bung us into drag luggage mode. The object is - // identified by its icon resource id. We need the luggage - // resource id for mouseOnOff - - _mouseMode = MOUSE_drag; - - _menuSelectedPos = hit; - _vm->_logic->writeVar(OBJECT_HELD, _masterMenuList[hit].icon_resource); - _currentLuggageResource = _masterMenuList[hit].luggage_resource; - - // Must clear this so next click on exit becomes 1st click - // again - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - - // Refresh the menu - - buildMenu(); - - setLuggage(_masterMenuList[hit].luggage_resource); - - debug(2, "Left-clicked on \"%s\" icon - switch to drag mode", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf)); - } -} - -void Mouse::normalMouse() { - // The gane is playing and none of the menus are activated - but, we - // need to check if a menu is to start. Note, won't have luggage - - MouseEvent *me; - - // Check if the cursor has moved onto the system menu area. No save in - // big-object menu lock situation, of if the player is dragging an - // object. - - if (_pos.y < 0 && !_mouseModeLocked && !_vm->_logic->readVar(OBJECT_HELD)) { - _mouseMode = MOUSE_system_menu; - - if (_mouseTouching) { - // We were on something, but not anymore - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - // Reset mouse cursor - in case we're between mice - - setMouse(NORMAL_MOUSE_ID); - buildSystemMenu(); - return; - } - - // Check if the cursor has moved onto the inventory menu area. No - // inventory in big-object menu lock situation, - - if (_pos.y > 399 && !_mouseModeLocked) { - // If an object is being held, i.e. if the mouse cursor has a - // luggage, go to drag mode instead of menu mode, but the menu - // is still opened. - // - // That way, we can still use an object on another inventory - // object, even if the inventory menu was closed after the - // first object was selected. - - if (!_vm->_logic->readVar(OBJECT_HELD)) - _mouseMode = MOUSE_menu; - else - _mouseMode = MOUSE_drag; - - // If mouse is moving off an object and onto the menu then do a - // standard get-off - - if (_mouseTouching) { - _oldMouseTouching = 0; - _mouseTouching = 0; - } - - // Reset mouse cursor - - setMouse(NORMAL_MOUSE_ID); - buildMenu(); - return; - } - - // Check for moving the mouse on or off things - - mouseOnOff(); - - me = _vm->mouseEvent(); - - if (!me) - return; - - bool button_down = (me->buttons & (RD_LEFTBUTTONDOWN | RD_RIGHTBUTTONDOWN)) != 0; - - // For debugging. We can draw a rectangle on the screen and see its - // coordinates. This was probably used to help defining hit areas. - - if (_vm->_debugger->_definingRectangles) { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - if (_vm->_debugger->_draggingRectangle == 0) { - // Not yet dragging a rectangle, so need click to start - - if (button_down) { - // set both (x1,y1) and (x2,y2) to this point - _vm->_debugger->_rectX1 = _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; - _vm->_debugger->_draggingRectangle = 1; - } - } else if (_vm->_debugger->_draggingRectangle == 1) { - // currently dragging a rectangle - click means reset - - if (button_down) { - // lock rectangle, so you can let go of mouse - // to type in the coords - _vm->_debugger->_draggingRectangle = 2; - } else { - // drag rectangle - _vm->_debugger->_rectX2 = (uint32)_pos.x + screenInfo->scroll_offset_x; - _vm->_debugger->_rectY2 = (uint32)_pos.y + screenInfo->scroll_offset_y; - } - } else { - // currently locked to avoid knocking out of place - // while reading off the coords - - if (button_down) { - // click means reset - back to start again - _vm->_debugger->_draggingRectangle = 0; - } - } - - return; - } - -#if RIGHT_CLICK_CLEARS_LUGGAGE - if (_vm->_logic->readVar(OBJECT_HELD) && (me->buttons & RD_RIGHTBUTTONDOWN) && heldIsInInventory()) { - _vm->_logic->writeVar(OBJECT_HELD, 0); - _menuSelectedPos = 0; - setLuggage(0); - return; - } -#endif - - // Now do the normal click stuff - - // We only care about down clicks when the mouse is over an object. - - if (!_mouseTouching || !button_down) - return; - - // There's a mouse event to be processed and the mouse is on something. - // Notice that the floor itself is considered an object. - - // There are no menus about so its nice and simple. This is as close to - // the old advisor_188 script as we get, I'm sorry to say. - - // If player is walking or relaxing then those need to terminate - // correctly. Otherwise set player run the targets action script or, do - // a special walk if clicking on the scroll-more icon - - // PLAYER_ACTION script variable - whatever catches this must reset to - // 0 again - // _vm->_logic->writeVar(PLAYER_ACTION, _mouseTouching); - - // Idle or router-anim will catch it - - // Set global script variable 'button' - - if (me->buttons & RD_LEFTBUTTONDOWN) { - _vm->_logic->writeVar(LEFT_BUTTON, 1); - _vm->_logic->writeVar(RIGHT_BUTTON, 0); - _buttonClick = 0; // for re-click - } else { - _vm->_logic->writeVar(LEFT_BUTTON, 0); - _vm->_logic->writeVar(RIGHT_BUTTON, 1); - _buttonClick = 1; // for re-click - } - - // These might be required by the action script about to be run - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - _vm->_logic->writeVar(MOUSE_X, _pos.x + screenInfo->scroll_offset_x); - _vm->_logic->writeVar(MOUSE_Y, _pos.y + screenInfo->scroll_offset_y); - - if (_mouseTouching == _vm->_logic->readVar(EXIT_CLICK_ID) && (me->buttons & RD_LEFTBUTTONDOWN)) { - // It's the exit double click situation. Let the existing - // interaction continue and start fading down. Switch the human - // off too - - noHuman(); - _vm->_logic->fnFadeDown(NULL); - - // Tell the walker - - _vm->_logic->writeVar(EXIT_FADING, 1); - } else if (_oldButton == _buttonClick && _mouseTouching == _vm->_logic->readVar(CLICKED_ID) && _mousePointerRes != NORMAL_MOUSE_ID) { - // Re-click. Do nothing, except on floors - } else { - // For re-click - - _oldButton = _buttonClick; - - // For scripts to know what's been clicked. First used for - // 'room_13_turning_script' in object 'biscuits_13' - - _vm->_logic->writeVar(CLICKED_ID, _mouseTouching); - - // Must clear these two double-click control flags - do it here - // so reclicks after exit clicks are cleared up - - _vm->_logic->writeVar(EXIT_CLICK_ID, 0); - _vm->_logic->writeVar(EXIT_FADING, 0); - - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); - - byte buf1[NAME_LEN], buf2[NAME_LEN]; - - if (_vm->_logic->readVar(OBJECT_HELD)) - debug(2, "Used \"%s\" on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(OBJECT_HELD), buf1), - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf2)); - else if (_vm->_logic->readVar(LEFT_BUTTON)) - debug(2, "Left-clicked on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); - else // RIGHT BUTTON - debug(2, "Right-clicked on \"%s\"", - _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID), buf1)); - } -} - -uint32 Mouse::chooseMouse() { - // Unlike the other mouse "engines", this one is called directly by the - // fnChoose() opcode. - - uint i; - - _vm->_logic->writeVar(AUTO_SELECTED, 0); - - uint32 in_subject = _vm->_logic->readVar(IN_SUBJECT); - uint32 object_held = _vm->_logic->readVar(OBJECT_HELD); - - if (object_held) { - // The player used an object on a person. In this case it - // triggered a conversation menu. Act as if the user tried to - // talk to the person about that object. If the person doesn't - // know anything about it, use the default response. - - uint32 response = _defaultResponseId; - - for (i = 0; i < in_subject; i++) { - if (_subjectList[i].res == object_held) { - response = _subjectList[i].ref; - break; - } - } - - // The user won't be holding the object any more, and the - // conversation menu will be closed. - - _vm->_logic->writeVar(OBJECT_HELD, 0); - _vm->_logic->writeVar(IN_SUBJECT, 0); - return response; - } - - if (_vm->_logic->readVar(CHOOSER_COUNT_FLAG) == 0 && in_subject == 1 && _subjectList[0].res == EXIT_ICON) { - // This is the first time the chooser is coming up in this - // conversation, there is only one subject and that's the - // EXIT icon. - // - // In other words, the player doesn't have anything to talk - // about. Skip it. - - // The conversation menu will be closed. We set AUTO_SELECTED - // because the speech script depends on it. - - _vm->_logic->writeVar(AUTO_SELECTED, 1); - _vm->_logic->writeVar(IN_SUBJECT, 0); - return _subjectList[0].ref; - } - - byte *icon; - - if (!_choosing) { - // This is a new conversation menu. - - if (!in_subject) - error("fnChoose with no subjects"); - - for (i = 0; i < in_subject; i++) { - icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size() + RDMENU_ICONWIDE * RDMENU_ICONDEEP; - setMenuIcon(RDMENU_BOTTOM, i, icon); - _vm->_resman->closeResource(_subjectList[i].res); - } - - for (; i < 15; i++) - setMenuIcon(RDMENU_BOTTOM, (uint8) i, NULL); - - showMenu(RDMENU_BOTTOM); - setMouse(NORMAL_MOUSE_ID); - _choosing = true; - return (uint32)-1; - } - - // The menu is there - we're just waiting for a click. We only care - // about left clicks. - - MouseEvent *me = _vm->mouseEvent(); - int mouseX, mouseY; - - getPos(mouseX, mouseY); - - if (!me || !(me->buttons & RD_LEFTBUTTONDOWN) || mouseY < 400) - return (uint32)-1; - - // Check for click on a menu. - - int hit = _vm->_mouse->menuClick(in_subject); - if (hit < 0) - return (uint32)-1; - - // Hilight the clicked icon by greying the others. This can look a bit - // odd when you click on the exit icon, but there are also cases when - // it looks strange if you don't do it. - - for (i = 0; i < in_subject; i++) { - if ((int)i != hit) { - icon = _vm->_resman->openResource(_subjectList[i].res) + ResHeader::size(); - _vm->_mouse->setMenuIcon(RDMENU_BOTTOM, i, icon); - _vm->_resman->closeResource(_subjectList[i].res); - } - } - - // For non-speech scripts that manually call the chooser - _vm->_logic->writeVar(RESULT, _subjectList[hit].res); - - // The conversation menu will be closed - - _choosing = false; - _vm->_logic->writeVar(IN_SUBJECT, 0); - setMouse(0); - - return _subjectList[hit].ref; -} - -void Mouse::mouseOnOff() { - // this handles the cursor graphic when moving on and off mouse areas - // it also handles the luggage thingy - - uint32 pointer_type; - static uint8 mouse_flicked_off = 0; - - _oldMouseTouching = _mouseTouching; - - // don't detect objects that are hidden behind the menu bars (ie. in - // the scrolled-off areas of the screen) - - if (_pos.y < 0 || _pos.y > 399) { - pointer_type = 0; - _mouseTouching = 0; - } else { - // set '_mouseTouching' & return pointer_type - pointer_type = checkMouseList(); - } - - // same as previous cycle? - if (!mouse_flicked_off && _oldMouseTouching == _mouseTouching) { - // yes, so nothing to do - // BUT CARRY ON IF MOUSE WAS FLICKED OFF! - return; - } - - // can reset this now - mouse_flicked_off = 0; - - //the cursor has moved onto something - if (!_oldMouseTouching && _mouseTouching) { - // make a copy of the object we've moved onto because one day - // we'll move back off again! (but the list positioning could - // theoretically have changed) - - // we can only move onto something from being on nothing - we - // stop the system going from one to another when objects - // overlap - - _oldMouseTouching = _mouseTouching; - - // run get on - - if (pointer_type) { - // 'pointer_type' holds the resource id of the - // pointer anim - - setMouse(pointer_type); - - // setup luggage icon - if (_vm->_logic->readVar(OBJECT_HELD)) { - setLuggage(_currentLuggageResource); - } - } else { - byte buf[NAME_LEN]; - - error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->_resman->fetchName(_mouseTouching, buf)); - } - } else if (_oldMouseTouching && !_mouseTouching) { - // the cursor has moved off something - reset cursor to - // normal pointer - - _oldMouseTouching = 0; - setMouse(NORMAL_MOUSE_ID); - - // reset luggage only when necessary - } else if (_oldMouseTouching && _mouseTouching) { - // The cursor has moved off something and onto something - // else. Flip to a blank cursor for a cycle. - - // ignore the new id this cycle - should hit next cycle - _mouseTouching = 0; - _oldMouseTouching = 0; - setMouse(0); - - // so we know to set the mouse pointer back to normal if 2nd - // hot-spot doesn't register because mouse pulled away - // quickly (onto nothing) - - mouse_flicked_off = 1; - - // reset luggage only when necessary - } else { - // Mouse was flicked off for one cycle, but then moved onto - // nothing before 2nd hot-spot registered - - // both '_oldMouseTouching' & '_mouseTouching' will be zero - // reset cursor to normal pointer - - setMouse(NORMAL_MOUSE_ID); - } - - // possible check for edge of screen more-to-scroll here on large - // screens -} - -void Mouse::setMouse(uint32 res) { - // high level - whats the mouse - for the engine - _mousePointerRes = res; - - if (res) { - byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); - uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); - - // don't pulse the normal pointer - just do the regular anim - // loop - - if (res == NORMAL_MOUSE_ID) - setMouseAnim(icon, len, RDMOUSE_NOFLASH); - else - setMouseAnim(icon, len, RDMOUSE_FLASH); - - _vm->_resman->closeResource(res); - } else { - // blank cursor - setMouseAnim(NULL, 0, 0); - } -} - -void Mouse::setLuggage(uint32 res) { - _realLuggageItem = res; - - if (res) { - byte *icon = _vm->_resman->openResource(res) + ResHeader::size(); - uint32 len = _vm->_resman->fetchLen(res) - ResHeader::size(); - - setLuggageAnim(icon, len); - _vm->_resman->closeResource(res); - } else - setLuggageAnim(NULL, 0); -} - -void Mouse::setObjectHeld(uint32 res) { - setLuggage(res); - - _vm->_logic->writeVar(OBJECT_HELD, res); - _currentLuggageResource = res; - - // mode locked - no menu available - _mouseModeLocked = true; -} - -uint32 Mouse::checkMouseList() { - ScreenInfo *screenInfo = _vm->_screen->getScreenInfo(); - - Common::Point mousePos(_pos.x + screenInfo->scroll_offset_x, _pos.y + screenInfo->scroll_offset_y); - - // Number of priorities subject to implementation needs - for (int priority = 0; priority < 10; priority++) { - for (uint i = 0; i < _curMouse; i++) { - // If the mouse pointer is over this - // mouse-detection-box - - if (_mouseList[i].priority == priority && _mouseList[i].rect.contains(mousePos)) { - // Record id - _mouseTouching = _mouseList[i].id; - - createPointerText(_mouseList[i].pointer_text, _mouseList[i].pointer); - - // Return pointer type - return _mouseList[i].pointer; - } - } - } - - // Touching nothing; no pointer to return - _mouseTouching = 0; - return 0; -} - -#define POINTER_TEXT_WIDTH 640 // just in case! -#define POINTER_TEXT_PEN 184 // white - -void Mouse::createPointerText(uint32 text_id, uint32 pointer_res) { - uint32 local_text; - uint32 text_res; - byte *text; - // offsets for pointer text sprite from pointer position - int16 xOffset, yOffset; - uint8 justification; - - if (!_objectLabels || !text_id) - return; - - // Check what the pointer is, to set offsets correctly for text - // position - - switch (pointer_res) { - case CROSHAIR: - yOffset = -7; - xOffset = +10; - break; - case EXIT0: - yOffset = +15; - xOffset = +20; - break; - case EXIT1: - yOffset = +16; - xOffset = -10; - break; - case EXIT2: - yOffset = +10; - xOffset = -22; - break; - case EXIT3: - yOffset = -16; - xOffset = -10; - break; - case EXIT4: - yOffset = -15; - xOffset = +15; - break; - case EXIT5: - yOffset = -12; - xOffset = +10; - break; - case EXIT6: - yOffset = +10; - xOffset = +25; - break; - case EXIT7: - yOffset = +16; - xOffset = +20; - break; - case EXITDOWN: - yOffset = -20; - xOffset = -10; - break; - case EXITUP: - yOffset = +20; - xOffset = +20; - break; - case MOUTH: - yOffset = -10; - xOffset = +15; - break; - case NORMAL: - yOffset = -10; - xOffset = +15; - break; - case PICKUP: - yOffset = -40; - xOffset = +10; - break; - case SCROLL_L: - yOffset = -20; - xOffset = +20; - break; - case SCROLL_R: - yOffset = -20; - xOffset = -20; - break; - case USE: - yOffset = -8; - xOffset = +20; - break; - default: - // Shouldn't happen if we cover all the different mouse - // pointers above - yOffset = -10; - xOffset = +10; - break; - } - - // Set up justification for text sprite, based on its offsets from the - // pointer position - - if (yOffset < 0) { - // Above pointer - if (xOffset < 0) { - // Above left - justification = POSITION_AT_RIGHT_OF_BASE; - } else if (xOffset > 0) { - // Above right - justification = POSITION_AT_LEFT_OF_BASE; - } else { - // Above centre - justification = POSITION_AT_CENTRE_OF_BASE; - } - } else if (yOffset > 0) { - // Below pointer - if (xOffset < 0) { - // Below left - justification = POSITION_AT_RIGHT_OF_TOP; - } else if (xOffset > 0) { - // Below right - justification = POSITION_AT_LEFT_OF_TOP; - } else { - // Below centre - justification = POSITION_AT_CENTRE_OF_TOP; - } - } else { - // Same y-coord as pointer - if (xOffset < 0) { - // Centre left - justification = POSITION_AT_RIGHT_OF_CENTRE; - } else if (xOffset > 0) { - // Centre right - justification = POSITION_AT_LEFT_OF_CENTRE; - } else { - // Centre centre - shouldn't happen anyway! - justification = POSITION_AT_LEFT_OF_CENTRE; - } - } - - // Text resource number, and line number within the resource - - text_res = text_id / SIZE; - local_text = text_id & 0xffff; - - // open text file & get the line - text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text); - - // 'text+2' to skip the first 2 bytes which form the - // line reference number - - _pointerTextBlocNo = _vm->_fontRenderer->buildNewBloc( - text + 2, _pos.x + xOffset, - _pos.y + yOffset, - POINTER_TEXT_WIDTH, POINTER_TEXT_PEN, - RDSPR_TRANS | RDSPR_DISPLAYALIGN, - _vm->_speechFontId, justification); - - // now ok to close the text file - _vm->_resman->closeResource(text_res); -} - -void Mouse::clearPointerText() { - if (_pointerTextBlocNo) { - _vm->_fontRenderer->killTextBloc(_pointerTextBlocNo); - _pointerTextBlocNo = 0; - } -} - -void Mouse::hideMouse() { - // leaves the menus open - // used by the system when clicking right on a menu item to examine - // it and when combining objects - - // for logic scripts - _vm->_logic->writeVar(MOUSE_AVAILABLE, 0); - - // human/mouse off - _mouseStatus = true; - - setMouse(0); - setLuggage(0); -} - -void Mouse::noHuman() { - hideMouse(); - clearPointerText(); - - // Must be normal mouse situation or a largely neutral situation - - // special menus use hideMouse() - - // Don't hide menu in conversations - if (_vm->_logic->readVar(TALK_FLAG) == 0) - hideMenu(RDMENU_BOTTOM); - - if (_mouseMode == MOUSE_system_menu) { - // Close menu - _mouseMode = MOUSE_normal; - hideMenu(RDMENU_TOP); - } -} - -void Mouse::addHuman() { - // For logic scripts - _vm->_logic->writeVar(MOUSE_AVAILABLE, 1); - - if (_mouseStatus) { - // Force engine to choose a cursor - _mouseStatus = false; - _mouseTouching = 1; - } - - // Clear this to reset no-second-click system - _vm->_logic->writeVar(CLICKED_ID, 0); - - // This is now done outside the OBJECT_HELD check in case it's set to - // zero before now! - - // Unlock the mouse from possible large object lock situtations - see - // syphon in rm 3 - - _mouseModeLocked = false; - - if (_vm->_logic->readVar(OBJECT_HELD)) { - // Was dragging something around - need to clear this again - _vm->_logic->writeVar(OBJECT_HELD, 0); - - // And these may also need clearing, just in case - _examiningMenuIcon = false; - _vm->_logic->writeVar(COMBINE_BASE, 0); - - setLuggage(0); - } - - // If mouse is over menu area - if (_pos.y > 399) { - if (_mouseMode != MOUSE_holding) { - // VITAL - reset things & rebuild the menu - _mouseMode = MOUSE_normal; - } - setMouse(NORMAL_MOUSE_ID); - } - - // Enabled/disabled from console; status printed with on-screen debug - // info - - if (_vm->_debugger->_testingSnR) { - uint8 black[4] = { 0, 0, 0, 0 }; - uint8 white[4] = { 255, 255, 255, 0 }; - - // Testing logic scripts by simulating instant Save & Restore - - _vm->_screen->setPalette(0, 1, white, RDPAL_INSTANT); - - // Stops all fx & clears the queue - eg. when leaving a room - _vm->_sound->clearFxQueue(); - - // Trash all object resources so they load in fresh & restart - // their logic scripts - - _vm->_resman->killAllObjects(false); - - _vm->_screen->setPalette(0, 1, black, RDPAL_INSTANT); - } -} - -void Mouse::refreshInventory() { - // Can reset this now - _vm->_logic->writeVar(COMBINE_BASE, 0); - - // Cause 'object_held' icon to be greyed. The rest are coloured. - _examiningMenuIcon = true; - buildMenu(); - _examiningMenuIcon = false; -} - -void Mouse::startConversation() { - if (_vm->_logic->readVar(TALK_FLAG) == 0) { - // See fnChooser & speech scripts - _vm->_logic->writeVar(CHOOSER_COUNT_FLAG, 0); - } - - noHuman(); -} - -void Mouse::endConversation() { - hideMenu(RDMENU_BOTTOM); - - if (_pos.y > 399) { - // Will wait for cursor to move off the bottom menu - _mouseMode = MOUSE_holding; - } - - // In case DC forgets - _vm->_logic->writeVar(TALK_FLAG, 0); -} - -void Mouse::monitorPlayerActivity() { - // if there is at least one mouse event outstanding - if (_vm->checkForMouseEvents()) { - // reset activity delay counter - _playerActivityDelay = 0; - } else { - // no. of game cycles since mouse event queue last empty - _playerActivityDelay++; - } -} - -void Mouse::checkPlayerActivity(uint32 seconds) { - // Convert seconds to game cycles - uint32 threshold = seconds * 12; - - // If the actual delay is at or above the given threshold, reset the - // activity delay counter now that we've got a positive check. - - if (_playerActivityDelay >= threshold) { - _playerActivityDelay = 0; - _vm->_logic->writeVar(RESULT, 1); - } else - _vm->_logic->writeVar(RESULT, 0); -} - -void Mouse::pauseGame() { - // Make the mouse cursor normal. This is the only place where we are - // allowed to clear the luggage this way. - - clearPointerText(); - setLuggageAnim(NULL, 0); - setMouse(0); - setMouseTouching(1); -} - -void Mouse::unpauseGame() { - if (_vm->_logic->readVar(OBJECT_HELD) && _realLuggageItem) - setLuggage(_realLuggageItem); -} - -} // End of namespace Sword2 |
