Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

mouse.cpp

/* 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.
 *
 * Additional copyright for this file:
 * Copyright (C) 1994-1998 Revolution Software Ltd.
 *
 * 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/sword2/mouse.cpp $
 * $Id: mouse.cpp 30944 2008-02-23 22:50:18Z sev $
 */


#include "common/system.h"
#include "common/events.h"

#include "graphics/cursorman.h"

#include "sword2/sword2.h"
#include "sword2/console.h"
#include "sword2/controls.h"
#include "sword2/defs.h"
#include "sword2/header.h"
#include "sword2/logic.h"
#include "sword2/maketext.h"
#include "sword2/mouse.h"
#include "sword2/object.h"
#include "sword2/resman.h"
#include "sword2/screen.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;

      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) {
      Common::EventManager *eventMan = _vm->_system->getEventManager();
      Common::Point pos = eventMan->getMousePos();

      x = pos.x;
      y = pos.y - MENUDEEP;
}

int Mouse::getX() {
      int x, y;

      getPos(x, y);
      return x;
}

int Mouse::getY() {
      int x, y;

      getPos(x, y);
      return 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 (getY() < 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) {
      int x = getX();

      if (x < RDMENU_ICONSTART)
            return -1;

      if (x > RDMENU_ICONSTART + menu_items * (RDMENU_ICONWIDE + RDMENU_ICONSPACING) - RDMENU_ICONSPACING)
            return -1;

      return (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.

      int y = getY();

      if (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 (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 saveload.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.

      int x, y;

      getPos(x, y);

      if (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, x + screenInfo->scroll_offset_x);
            _vm->_logic->writeVar(MOUSE_Y, 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() {
      MouseEvent *me;
      int hit;

      // If the mouse is moved off the menu, close it.

      if (getY() < 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)));

            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)));
      }
}

void Mouse::normalMouse() {
      // The game 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.

      int x, y;

      getPos(x, y);

      if (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 (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)x + screenInfo->scroll_offset_x;
                        _vm->_debugger->_rectY1 = _vm->_debugger->_rectY2 = (uint32)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)x + screenInfo->scroll_offset_x;
                        _vm->_debugger->_rectY2 = (uint32)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, x + screenInfo->scroll_offset_x);
      _vm->_logic->writeVar(MOUSE_Y, 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)));
            else  // RIGHT BUTTON
                  debug(2, "Right-clicked on \"%s\"",
                        _vm->_resman->fetchName(_vm->_logic->readVar(CLICKED_ID)));
      }
}

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)

      int y = getY();

      if (y < 0 || 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 {
                  error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", _mouseTouching, _vm->_resman->fetchName(_mouseTouching));
            }
      } 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();
      int x, y;

      getPos(x, y);

      Common::Point mousePos(x + screenInfo->scroll_offset_x, 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

      int x, y;

      getPos(x, y);

      _pointerTextBlocNo = _vm->_fontRenderer->buildNewBloc(
            text + 2, x + xOffset,
            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 (getY() > 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(false);

            // 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 (getY() > 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);
}

#define MOUSEFLASHFRAME 6

void Mouse::decompressMouse(byte *decomp, byte *comp, uint8 frame, int width, int height, int pitch, int xOff, int yOff) {
      int32 size = width * height;
      int32 i = 0;
      int x = 0;
      int y = 0;

      comp = comp + READ_LE_UINT32(comp + frame * 4) - MOUSE_ANIM_HEADER_SIZE;

      while (i < size) {
            if (*comp > 183) {
                  decomp[(y + yOff) * pitch + x + xOff] = *comp++;
                  if (++x >= width) {
                        x = 0;
                        y++;
                  }
                  i++;
            } else {
                  x += *comp;
                  while (x >= width) {
                        y++;
                        x -= width;
                  }
                  i += *comp++;
            }
      }
}

void Mouse::drawMouse() {
      if (!_mouseAnim.data && !_luggageAnim.data)
            return;

      // When an object is used in the game, the mouse cursor should be a
      // combination of a standard mouse cursor and a luggage cursor.
      //
      // However, judging by the original code luggage cursors can also
      // appear on their own. I have no idea which cases though.

      uint16 mouse_width = 0;
      uint16 mouse_height = 0;
      uint16 hotspot_x = 0;
      uint16 hotspot_y = 0;
      int deltaX = 0;
      int deltaY = 0;

      if (_mouseAnim.data) {
            hotspot_x = _mouseAnim.xHotSpot;
            hotspot_y = _mouseAnim.yHotSpot;
            mouse_width = _mouseAnim.mousew;
            mouse_height = _mouseAnim.mouseh;
      }

      if (_luggageAnim.data) {
            if (!_mouseAnim.data) {
                  hotspot_x = _luggageAnim.xHotSpot;
                  hotspot_y = _luggageAnim.yHotSpot;
            }
            if (_luggageAnim.mousew > mouse_width)
                  mouse_width = _luggageAnim.mousew;
            if (_luggageAnim.mouseh > mouse_height)
                  mouse_height = _luggageAnim.mouseh;
      }

      if (_mouseAnim.data && _luggageAnim.data) {
            deltaX = _mouseAnim.xHotSpot - _luggageAnim.xHotSpot;
            deltaY = _mouseAnim.yHotSpot - _luggageAnim.yHotSpot;
      }

      assert(deltaX >= 0);
      assert(deltaY >= 0);

      mouse_width += deltaX;
      mouse_height += deltaY;

      byte *mouseData = (byte *)calloc(mouse_height, mouse_width);

      if (_luggageAnim.data)
            decompressMouse(mouseData, _luggageAnim.data, 0,
                  _luggageAnim.mousew, _luggageAnim.mouseh,
                  mouse_width, deltaX, deltaY);

      if (_mouseAnim.data)
            decompressMouse(mouseData, _mouseAnim.data, _mouseFrame,
                  _mouseAnim.mousew, _mouseAnim.mouseh, mouse_width);

      CursorMan.replaceCursor(mouseData, mouse_width, mouse_height, hotspot_x, hotspot_y, 0);

      free(mouseData);
}

/**
 * Animates the current mouse pointer
 */

int32 Mouse::animateMouse() {
      uint8 prevMouseFrame = _mouseFrame;

      if (!_mouseAnim.data)
            return RDERR_UNKNOWN;

      if (++_mouseFrame == _mouseAnim.noAnimFrames)
            _mouseFrame = MOUSEFLASHFRAME;

      if (_mouseFrame != prevMouseFrame)
            drawMouse();

      return RD_OK;
}

/**
 * Sets the mouse cursor animation.
 * @param ma a pointer to the animation data, or NULL to clear the current one
 * @param size the size of the mouse animation data
 * @param mouseFlash RDMOUSE_FLASH or RDMOUSE_NOFLASH, depending on whether
 * or not there is a lead-in animation
 */

int32 Mouse::setMouseAnim(byte *ma, int32 size, int32 mouseFlash) {
      free(_mouseAnim.data);
      _mouseAnim.data = NULL;

      if (ma)     {
            if (mouseFlash == RDMOUSE_FLASH)
                  _mouseFrame = 0;
            else
                  _mouseFrame = MOUSEFLASHFRAME;

            Common::MemoryReadStream readS(ma, size);

            _mouseAnim.runTimeComp = readS.readByte();
            _mouseAnim.noAnimFrames = readS.readByte();
            _mouseAnim.xHotSpot = readS.readSByte();
            _mouseAnim.yHotSpot = readS.readSByte();
            _mouseAnim.mousew = readS.readByte();
            _mouseAnim.mouseh = readS.readByte();

            _mouseAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE);
            if (!_mouseAnim.data)
                  return RDERR_OUTOFMEMORY;

            readS.read(_mouseAnim.data, size - MOUSE_ANIM_HEADER_SIZE);

            animateMouse();
            drawMouse();

            CursorMan.showMouse(true);
      } else {
            if (_luggageAnim.data)
                  drawMouse();
            else
                  CursorMan.showMouse(false);
      }

      return RD_OK;
}

/**
 * Sets the "luggage" animation to accompany the mouse animation. Luggage
 * sprites are of the same format as mouse sprites.
 * @param ma a pointer to the animation data, or NULL to clear the current one
 * @param size the size of the animation data
 */

int32 Mouse::setLuggageAnim(byte *ma, int32 size) {
      free(_luggageAnim.data);
      _luggageAnim.data = NULL;

      if (ma)     {
            Common::MemoryReadStream readS(ma, size);

            _luggageAnim.runTimeComp = readS.readByte();
            _luggageAnim.noAnimFrames = readS.readByte();
            _luggageAnim.xHotSpot = readS.readSByte();
            _luggageAnim.yHotSpot = readS.readSByte();
            _luggageAnim.mousew = readS.readByte();
            _luggageAnim.mouseh = readS.readByte();

            _luggageAnim.data = (byte *)malloc(size - MOUSE_ANIM_HEADER_SIZE);
            if (!_luggageAnim.data)
                  return RDERR_OUTOFMEMORY;

            readS.read(_luggageAnim.data, size - MOUSE_ANIM_HEADER_SIZE);

            animateMouse();
            drawMouse();

            CursorMan.showMouse(true);
      } else {
            if (_mouseAnim.data)
                  drawMouse();
            else
                  CursorMan.showMouse(false);
      }

      return RD_OK;
}

} // End of namespace Sword2

Generated by  Doxygen 1.6.0   Back to index