aboutsummaryrefslogtreecommitdiff
path: root/sword2/mouse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sword2/mouse.cpp')
-rw-r--r--sword2/mouse.cpp1437
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