aboutsummaryrefslogtreecommitdiff
path: root/sword2/mouse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sword2/mouse.cpp')
-rw-r--r--sword2/mouse.cpp1466
1 files changed, 1466 insertions, 0 deletions
diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp
new file mode 100644
index 0000000000..7332b5b39b
--- /dev/null
+++ b/sword2/mouse.cpp
@@ -0,0 +1,1466 @@
+/* Copyright (C) 1994-2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+#include "driver/driver96.h"
+#include "build_display.h"
+#include "console.h"
+#include "controls.h"
+#include "debug.h"
+#include "defs.h"
+#include "events.h"
+#include "icons.h"
+#include "interpreter.h"
+#include "layers.h"
+#include "maketext.h"
+#include "mouse.h" //assure integrety
+#include "object.h"
+#include "protocol.h"
+#include "resman.h"
+#include "sound.h"
+#include "sword2.h" // for PauseGame() & UnpauseGame()
+//------------------------------------------------------------------------------------
+// pointer resource id's
+
+#define CROSHAIR 18
+#define EXIT0 788
+#define EXIT1 789
+#define EXIT2 790
+#define EXIT3 791
+#define EXIT4 792
+#define EXIT5 793
+#define EXIT6 794
+#define EXIT7 795
+#define EXITDOWN 796
+#define EXITUP 797
+#define MOUTH 787
+#define NORMAL 17
+#define PICKUP 3099
+#define SCROLL_L 1440
+#define SCROLL_R 1441
+#define USE 3100
+//------------------------------------------------------------------------------------
+//the mouse list stuff
+uint32 cur_mouse;
+Mouse_unit mouse_list[TOTAL_mouse_list];
+
+uint32 mouse_touching=0; //set by Check_mouse_list
+uint32 old_mouse_touching=0;
+
+uint32 menu_selected_pos;
+uint8 examining_menu_icon=0;
+
+uint32 mouse_pointer_res=0; // if it's NORMAL_MOUSE_ID (ie. normal pointer) then it's over a floor area (or hidden hot-zone
+uint32 mouse_mode=0; //0 normal in game
+ //1 top menu down (bottom!)
+ //2 dragging luggage
+ //3 system menu chooser (top)
+ //4 speech chooser
+
+//Object_mouse old_mouse_object; //copy structure from list when moving onto a mouse area
+
+uint32 menu_status; //0 available - 1 unavailable
+uint32 mouse_status; //human 0 on/1 off
+
+uint32 mouse_mode_locked=0; //0 not !0 mode cannot be changed from normal mouse to top menu (i.e. when carrying big objects)
+uint32 current_luggage_resource=0;
+
+uint32 subject_status; //0 off 1 on
+
+uint32 old_button=0; //for the re-click stuff - must be same button you see
+uint32 button_click=0;
+
+uint32 pointer_text_bloc_no=0;
+uint32 pointerTextSelected=0;
+
+uint32 player_activity_delay=0; // player activity delay counter
+
+uint32 real_luggage_item=0; //last minute for pause mode
+
+//------------------------------------------------------------------------------------
+/*
+#define RD_LEFTBUTTONDOWN 0x01
+#define RD_LEFTBUTTONUP 0x02
+#define RD_RIGHTBUTTONDOWN 0x04
+#define RD_RIGHTBUTTONUP 0x08
+*/
+//------------------------------------------------------------------------------------
+// local function prototypes
+
+//uint8 Check_sprite_pixel( uint32 j );
+void CreatePointerText(uint32 TextId, uint32 pointerRes); // James16jun97
+void ClearPointerText(void); // James16jun97
+void Monitor_player_activity(void); // James23july97
+
+int32 FN_no_human(int32 *params);
+void No_human(void);
+
+//------------------------------------------------------------------------------------
+void Reset_mouse_list(void) //Tony26Sept96
+{
+//call at beginning of gameloop
+
+ cur_mouse=1;
+}
+//------------------------------------------------------------------------------------
+void Mouse_engine(void) //Tony30Sept96
+{
+
+ Monitor_player_activity(); // James23july97
+
+ ClearPointerText(); // James16jun97
+
+
+ if (DEAD) //George is dead ;)
+ {
+ if (mouse_mode!=MOUSE_system_menu)
+ {
+ mouse_mode=MOUSE_system_menu;
+ if (mouse_touching)
+ {
+// get off
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+ }
+
+ Set_mouse(NORMAL_MOUSE_ID);
+
+ Build_system_menu(); //Tony19Mar97
+ }
+ System_menu();
+
+ return;
+ }
+
+
+ if (mouse_status) //no human
+ return;
+
+
+ switch(mouse_mode)
+ {
+ case MOUSE_normal: //0 normal in game
+ Normal_mouse();
+ break;
+
+ case MOUSE_top: //1 top menu down
+ Top_menu_mouse();
+ break;
+
+ case MOUSE_drag: //2 dragging luggage
+ Drag_mouse();
+ break;
+
+ case MOUSE_system_menu: //3 in game bottom menu - save/restore, etc?
+ System_menu();
+ break;
+
+ case MOUSE_holding: //4 wait for mouse to move off bottom menu - after speech
+ if (mousey<400)
+ { mouse_mode=MOUSE_normal;
+ Zdebug(" releasing");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}
+//------------------------------------------------------------------------------------
+void System_menu(void) //Tony19Mar97
+{
+ uint32 safe_looping_music_id;
+ _mouseEvent *me;
+ int j,hit;
+ uint8 *icon;
+ uint32 rv; // for drivers return value
+ int32 pars[2];
+ uint32 icon_list[5] =
+ {
+ OPTIONS_ICON,
+ QUIT_ICON,
+ SAVE_ICON,
+ RESTORE_ICON,
+ RESTART_ICON
+ };
+
+
+
+ if ((mousey>0)&&(!DEAD)) //can't close when player is dead
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_TOP);
+
+ return;
+ }
+
+ me = MouseEvent(); //get mouse event
+
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+
+// clicked on a top mouse pointer?
+
+ if ((mousex>=24)&&(mousex<640-24)&&(mousey<0))
+ {
+ hit=(mousex-24)/40; //which are we over?
+
+ if ((hit==2)&&(DEAD))
+ return; //no save when dead
+
+ if (hit<5) //there are 5 system menus
+ { for (j=0;j<5;j++) //build them all high in full colour - when on eis clicked on all the rest will grey out
+ if (j!=hit) //change all others to grey
+ {
+ icon = res_man.Res_open( icon_list[j] ) + sizeof(_standardHeader);
+ SetMenuIcon(RDMENU_TOP, j, icon);
+ res_man.Res_close( icon_list[j] );
+ }
+
+ //------------------------
+ rv = PauseFx();
+ if (rv != RD_OK)
+ Zdebug("ERROR: PauseFx() returned %.8x in SystemMenu()", rv);
+ //------------------------
+ // NB. Need to keep a safe copy of 'looping_music_id' for savegame
+ // & for playing when returning from control panels
+ // because control panel music will overwrite it!
+ safe_looping_music_id = looping_music_id;
+ pars[0] = 221; // SystemM234 (M234.wav)
+ pars[1] = FX_LOOP;
+ FN_play_music(pars);
+ looping_music_id = safe_looping_music_id; // restore proper looping_music_id
+ //------------------------
+ //------------------------
+ // clear the screen & set up the new palette for the menus
+
+ EraseBackBuffer();
+ ProcessMenu(); // drivers to redraw menu over this blank screen!
+ FlipScreens();
+ ResetRenderEngine();
+ //------------------------
+
+ switch(hit) //call the relevent screen
+ {
+ case 0: // options
+ Option_control(); // game options
+ break;
+
+ case 1: // quit
+ Quit_control(); // quit to windows
+ break;
+
+ case 2: // save
+ Save_control(); // save the game
+ break;
+
+ case 3: // restore
+ Restore_control(); // restore a game
+ break;
+
+ case 4: // restart
+ Restart_control(); // restart the game
+ break;
+
+ }
+ //------------------------
+// start the menu coming down
+ if (!DEAD) //not death screen
+ { mouse_mode=MOUSE_normal; //close menu
+ HideMenu(RDMENU_TOP); //but not when dead
+ }
+ else
+ { Set_mouse(NORMAL_MOUSE_ID);
+ Build_system_menu(); //reset top menu
+ }
+ //------------------------
+ // clear the screen & restore the location palette
+
+ EraseBackBuffer();
+ ProcessMenu(); // drivers to redraw menu over this blank screen!
+ FlipScreens();
+
+ //------------------------
+ // reset game palette, but not after a successful restore or restart!
+
+ if (this_screen.new_palette != 99) // see RestoreFromBuffer() in save_rest.cpp
+ {
+ SetFullPalette(0); // '0' means put back game screen palette; see Build_display.cpp (James17jun97)
+ this_screen.new_palette=0; //stop the engine fading in the restored screens palette
+ }
+ else
+ this_screen.new_palette=1;
+
+ //------------------------
+ rv = UnpauseFx();
+ if (rv != RD_OK)
+ Zdebug("ERROR: UnpauseFx() returned %.8x in SystemMenu()", rv);
+ //------------------------
+ // If there was looping music before coming into the control panels then restart it!
+ // NB. This will also start music required when a game has been restored
+
+ if (looping_music_id)
+ {
+ pars[0] = looping_music_id;
+ pars[1] = FX_LOOP;
+ FN_play_music(pars);
+ // cross-fades into the required music:
+ // - either a restored game tune
+ // - or music playing prior to entering control panels
+ }
+ else
+ FN_stop_music(NULL); // stop the control panel music
+ //------------------------
+ }
+ }
+ }
+
+}
+//------------------------------------------------------------------------------------
+void Drag_mouse(void) //Tony21Nov96
+{
+ _mouseEvent *me;
+ uint32 pos;
+// uint32 null_pc=1; //script 1 is combine script
+
+
+ if ((mousey<400)&&(!menu_status))
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_BOTTOM);
+
+ return;
+ }
+
+
+ Mouse_on_off(); //handles cursors and the luggage on/off according to type
+
+
+
+// now do the normal click stuff
+
+ me = MouseEvent(); //get mouse event
+
+
+// we only care about left clicks when the mouse is over an object
+// we ignore mouse releases
+
+ if ((me!=NULL)&&(me->buttons&RD_LEFTBUTTONDOWN)) //there's a mouse event to be processed
+ {
+
+// could be clicking on an on screen object or on the top menu which is currently displayed
+
+ if (mouse_touching) //mouse is over an on screen object - and we have luggage
+ { //depending on type we'll maybe kill the object_held - like for exits
+ if (me->buttons&RD_LEFTBUTTONDOWN) // set global script variable 'button'
+ {
+ LEFT_BUTTON = 1;
+ RIGHT_BUTTON = 0;
+ }
+ else
+ {
+ LEFT_BUTTON = 0;
+ RIGHT_BUTTON = 1;
+ }
+
+ MOUSE_X=(uint32)mousex+this_screen.scroll_offset_x;
+ MOUSE_Y=(uint32)mousey+this_screen.scroll_offset_y; //these might be required by the action script about to be run
+
+ CLICKED_ID = mouse_touching; // for scripts to know what's been clicked (21jan97). First used for 'room_13_turning_script' in object 'biscuits_13'
+
+
+
+ Set_player_action_event(CUR_PLAYER_ID, mouse_touching); //Tony4Dec96
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"USED \"%s\" ICON ON %s", FetchObjectName(OBJECT_HELD), FetchObjectName(CLICKED_ID));
+ #endif
+ //--------------------------------------
+
+
+ HideMenu(RDMENU_BOTTOM); //hide menu too
+ mouse_mode=MOUSE_normal; //back to normal menu mode
+ }
+ else //better check for combine/cancel cancel puts us back in Top_menu_mouse mode
+ {
+ if ((mousex>=24)&&(mousex<640-24))
+ {
+ pos=(mousex-24)/40; //which are we over?
+
+ if (master_menu_list[pos].icon_resource) //clicked on something - what button?
+ {
+ mouse_mode=MOUSE_top; //always back into top menu mode
+
+ Set_luggage(0); // remove luggage
+
+ if (pos==menu_selected_pos) // if we've clicked on the same icon as the one we're dragging
+ {
+ OBJECT_HELD=0; // reset first icon
+ menu_selected_pos=0;
+ }
+ else // combine the 2 icons
+ {
+// Zdebug("combine");
+ COMBINE_BASE=master_menu_list[pos].icon_resource; //what we clicked on, not what we're dragging
+
+ Set_player_action_event(CUR_PLAYER_ID, MENU_MASTER_OBJECT); //Tony4Dec96
+
+ No_human(); // turn off mouse now, to prevent player trying to click elsewhere BUT leave the bottom menu open
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"USED \"%s\" ICON ON \"%s\" ICON", FetchObjectName(OBJECT_HELD), FetchObjectName(COMBINE_BASE));
+ #endif
+ //--------------------------------------
+ }
+
+ Build_top_menu(); // refresh the menu
+
+
+// Zdebug("switch to top mode");
+ }
+ }
+ }
+ }
+
+
+}
+//------------------------------------------------------------------------------------
+void Top_menu_mouse(void) //Tony3Oct96
+{
+//top menu is down
+ _mouseEvent *me;
+ uint32 pos;
+
+ if ((mousey<400)&&(!menu_status))
+ { mouse_mode=MOUSE_normal; //close menu
+
+// start the menu coming down
+ HideMenu(RDMENU_BOTTOM);
+
+ return;
+ }
+
+ me=MouseEvent(); //get mouse event
+
+
+
+// we only care about left clicks when the mouse is over an object
+// we ignore mouse releases
+
+ if (me!=NULL) //there's a mouse event to be processed
+ {
+// now check if we've clicked on an actual icon
+
+ if ((mousex>=24)&&(mousex<640-24))
+ {
+ pos=(mousex-24)/40; //which are we over?
+
+ if (master_menu_list[pos].icon_resource) //clicked on something - what button?
+ {
+
+ if (me->buttons&RD_RIGHTBUTTONDOWN) //right button look
+ {
+ examining_menu_icon=1;
+ OBJECT_HELD = master_menu_list[pos].icon_resource; //id the object via its graphic
+ EXIT_CLICK_ID=0; // (JEL09oct97) must clear this so next click on exit becomes 1st click again
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ Zdebug(0,"RIGHT-CLICKED ON \"%s\" ICON", FetchObjectName(OBJECT_HELD));
+ #endif
+ //--------------------------------------
+
+ Set_player_action_event(CUR_PLAYER_ID, MENU_MASTER_OBJECT); //Tony4Dec96
+
+ Build_top_menu(); // refresh the menu
+ No_human(); // turn off mouse now, to prevent player trying to click elsewhere BUT leave the bottom menu open
+ }
+ else if (me->buttons&RD_LEFTBUTTONDOWN) //left button - highlight the object and bung us into drag luggage mode
+ {
+ menu_selected_pos=pos; //menu slot we clicked on - derive luggage resource from this in mouse_on_off()
+ current_luggage_resource=master_menu_list[pos].luggage_resource;
+
+ mouse_mode=MOUSE_drag;
+// Zdebug("setting OH in top menu");
+ OBJECT_HELD = master_menu_list[pos].icon_resource; //id the object via its graphic
+ EXIT_CLICK_ID=0; // (JEL09oct97) must clear this so next click on exit becomes 1st click again
+
+ Build_top_menu(); // refresh the menu
+
+ Set_luggage(master_menu_list[pos].luggage_resource);
+
+// Zdebug("switch to drag mode");
+ }
+ }
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
+void Normal_mouse(void) //Tony30Sept96
+{
+//the gane is playing and none of the menus are activated - but, we need to check if the top menu is to start
+//note, wont have luggage
+
+ _mouseEvent *me;
+
+
+
+
+ if ((mousey<0)&&(!menu_status)&&(!mouse_mode_locked)&&(!OBJECT_HELD)) //no save in big-object menu lock situation
+ {
+ mouse_mode=MOUSE_system_menu;
+
+ if (mouse_touching)
+ {
+// get off
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+
+ }
+
+// reset mouse cursor - in case we're between mice
+ Set_mouse(NORMAL_MOUSE_ID);
+
+ Build_system_menu(); //Tony19Mar97
+ }
+
+
+
+
+
+ if ((mousey>399)&&(!menu_status)&&(!mouse_mode_locked))
+ {
+
+
+ if (!OBJECT_HELD) //why are we testing for this?
+ {
+ mouse_mode=MOUSE_top; //bring down top menu
+ }
+ else
+ {
+ mouse_mode=MOUSE_drag;
+ }
+
+// if mouse is moving off an object and onto the top menu then do a standard get-off
+ if (mouse_touching)
+ {
+// get off
+
+ old_mouse_touching=0; //we've moved off
+ mouse_touching=0; //we were on something but not anymore
+
+ }
+
+// reset mouse cursor
+ Set_mouse(NORMAL_MOUSE_ID);
+
+// build menu and start the menu coming down
+
+ Build_top_menu();
+
+ return;
+ }
+
+
+//check also for bringing the bottom menu up
+
+
+
+
+ Mouse_on_off(); //handles
+
+
+
+// now do the normal click stuff
+
+ me = MouseEvent(); //get mouse event
+
+ //-----------------------------------------------------
+#ifdef _DEBUG
+ if (definingRectangles)
+ {
+ if (draggingRectangle==0) // not yet dragging a rectangle, so need click to start
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) )
+ {
+ rect_x1 = rect_x2 = (uint32)mousex+this_screen.scroll_offset_x; // set both (x1,y1)
+ rect_y1 = rect_y2 = (uint32)mousey+this_screen.scroll_offset_y; // & (x2,y2) to this point
+ draggingRectangle=1;
+ }
+ }
+ else if (draggingRectangle==1) // currently dragging a rectangle
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) ) // click means reset
+ {
+ draggingRectangle=2; // lock rectangle, so you can let go of mouse to type in the coords
+ }
+ else // drag rectangle
+ {
+ rect_x2 = (uint32)mousex+this_screen.scroll_offset_x;
+ rect_y2 = (uint32)mousey+this_screen.scroll_offset_y;
+ }
+ }
+ else // currently locked to avoid knocking out of place while reading off the coords
+ {
+ if ( (me!=NULL) && ((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN)) ) // click means reset
+ {
+ draggingRectangle=0; // back to start again
+ }
+ }
+ }
+ else
+#endif // _DEBUG
+ //-----------------------------------------------------
+ {
+
+ // we only care about down clicks when the mouse is over an object
+ // we ignore mouse releases
+
+ if ((me!=NULL)&&((me->buttons&RD_LEFTBUTTONDOWN)||(me->buttons&RD_RIGHTBUTTONDOWN))&&(mouse_touching)) //there's a mouse event to be processed and the mouse is on something
+ {
+// ok, 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 = mouse_touching; //PLAYER_ACTION script variable - whatever catches this must reset to 0 again
+ //idle or router-anim will catch it
+
+
+ if (me->buttons&RD_LEFTBUTTONDOWN) // set global script variable 'button'
+ {
+ LEFT_BUTTON = 1;
+ RIGHT_BUTTON = 0;
+ button_click=0; //for re-click
+ }
+ else
+ {
+ LEFT_BUTTON = 0;
+ RIGHT_BUTTON = 1;
+ button_click=1; //for re-click
+ }
+
+ MOUSE_X=(uint32)mousex+this_screen.scroll_offset_x;
+ MOUSE_Y=(uint32)mousey+this_screen.scroll_offset_y; //these might be required by the action script about to be run
+
+
+ if ((mouse_touching==EXIT_CLICK_ID)&&(me->buttons&RD_LEFTBUTTONDOWN)) //only left button
+ {
+// its the exit double click situation
+// let the existing interaction continue and start fading down - switch the human off too
+
+ FN_no_human(NULL);
+ FN_fade_down(NULL);
+ EXIT_FADING=1; //tell the walker
+
+ }
+ else if ((old_button==button_click)&&(mouse_touching==CLICKED_ID)&&(mouse_pointer_res!=NORMAL_MOUSE_ID))
+ { //re-click - do nothing - except on floors
+ }
+ else //allow the click
+ {
+ old_button=button_click; //for re-click
+
+ CLICKED_ID = mouse_touching; // for scripts to know what's been clicked (21jan97). First used for 'room_13_turning_script' in object 'biscuits_13'
+ EXIT_CLICK_ID=0; //must clear these two double-click control flags - do it here so reclicks after exit clicks are cleared up
+ EXIT_FADING=0;
+ Set_player_action_event(CUR_PLAYER_ID, mouse_touching); //Tony4Dec96
+
+ //--------------------------------------
+ // Write to walkthrough file (zebug0.txt)
+ #ifdef _DEBUG
+ if (OBJECT_HELD)
+ Zdebug(0,"USED \"%s\" ICON ON %s", FetchObjectName(OBJECT_HELD), FetchObjectName(CLICKED_ID));
+ else if (LEFT_BUTTON)
+ Zdebug(0,"LEFT-CLICKED ON %s", FetchObjectName(CLICKED_ID));
+ else // RIGHT BUTTON
+ Zdebug(0,"RIGHT-CLICKED ON %s", FetchObjectName(CLICKED_ID));
+ #endif
+ //--------------------------------------
+ }
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+void Mouse_on_off(void) //Tony30Sept96
+{
+ //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;
+
+
+ old_mouse_touching=mouse_touching;
+
+
+ if ((mousey<0)||(mousey>399)) // don't detect objects that are hidden behind the menu bars (ie. in the scrolled-off areas of the screen)
+ {
+ pointer_type=0;
+ mouse_touching=0;
+ }
+ else
+ pointer_type = Check_mouse_list(); // set 'mouse_touching' & return pointer_type
+
+
+
+
+ if ((!mouse_flicked_off)&&(old_mouse_touching==mouse_touching)) //same as previous cycle?
+ return; //yes, so nothing to do BUT CARRY ON IF MOUSE WAS FLICKED OFF!
+
+ mouse_flicked_off=0; // can reset this now
+
+
+ if ((!old_mouse_touching)&&(mouse_touching)) //the cursor has moved onto something
+ {
+
+// 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
+
+// memcpy( &old_mouse_object, &mouse_list[mouse_touching], sizeof(Object_mouse));
+
+ old_mouse_touching=mouse_touching; //
+
+// run get on
+
+ if (pointer_type)
+ {
+ Set_mouse(pointer_type); // 'pointer_type' holds the resource id of the pointer anim
+
+ if (OBJECT_HELD) // setup luggage icon
+// Set_luggage(master_menu_list[menu_selected_pos].luggage_resource);
+ Set_luggage(current_luggage_resource);
+
+ }
+ else
+ Con_fatal_error("ERROR: mouse.pointer==0 for object %d (%s) - update logic script!", mouse_touching, FetchObjectName(mouse_touching));
+ }
+ else if ((old_mouse_touching)&&(!mouse_touching)) // the cursor has moved off something
+ {
+ old_mouse_touching=0; // we've moved off
+ Set_mouse(NORMAL_MOUSE_ID); // reset cursor to normal pointer
+ // reset luggage only when necessary
+ }
+ else if ((old_mouse_touching)&&(mouse_touching)) // the cursor has moved off something and onto something else
+ { // flip to a blank cursor for a cycle
+ mouse_touching=0; // ignore the new id this cycle - should hit next cycle
+ old_mouse_touching=0; // we've moved off
+ Set_mouse(NULL); // blank cursor
+ mouse_flicked_off=1; // 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)
+
+ // reset luggage only when necessary
+ }
+ else // for when mouse was flicked off for one cycle, but then moved onot nothing before 2nd hot-spot registered
+ {
+ // both 'old_mouse_touching' & 'mouse_touching' will be zero
+ Set_mouse(NORMAL_MOUSE_ID); // reset cursor to normal pointer
+ }
+
+ // possible check for edge of screen more-to-scroll here on large screens
+
+}
+//------------------------------------------------------------------------------------
+void Set_mouse(uint32 res) // (4dec96 JEL)
+{
+ uint8 *icon;
+ uint32 len;
+
+ mouse_pointer_res=res; //high level - whats the mouse - for the engine
+
+ if (res) // if it's not NULL
+ {
+ icon = res_man.Res_open( res ) + sizeof(_standardHeader);
+ len = res_man.resList[res]->size - sizeof(_standardHeader);
+
+ if (res == NORMAL_MOUSE_ID) // don't pulse the normal pointer
+ SetMouseAnim(icon, len, RDMOUSE_NOFLASH); // 0 means don't pulse this pointer, just do the regular anim loop
+ else
+ SetMouseAnim(icon, len, RDMOUSE_FLASH); // 1 mean pulse before starting regular anim loop
+
+ res_man.Res_close( res );
+ }
+ else
+ SetMouseAnim(NULL,0,0); // blank cursor
+}
+//------------------------------------------------------------------------------------
+void Set_luggage(uint32 res) //Tony26Nov96
+{
+ uint8 *icon;
+ uint32 len;
+
+ if (res) // if not NULL
+ {
+ real_luggage_item=res;
+
+ icon = res_man.Res_open( res ) + sizeof(_standardHeader);
+ len = res_man.resList[res]->size - sizeof(_standardHeader);
+
+ SetLuggageAnim(icon, len);
+
+ res_man.Res_close( res );
+ }
+ else
+ { real_luggage_item=0;
+ SetLuggageAnim(NULL, 0);
+ }
+}
+//------------------------------------------------------------------------------------
+uint32 Check_mouse_list(void) //Tony30Sept96
+{
+ int32 priority=0;
+ uint32 j=1;
+
+
+ if (cur_mouse>1)
+ {
+ while(priority<10) //number of priorities subject to implementation needs
+ {
+ if ((mouse_list[j].priority==priority) && // if the mouse pointer is over this mouse-detection-box
+ (mousex+this_screen.scroll_offset_x >= mouse_list[j].x1) &&
+ (mousex+this_screen.scroll_offset_x <= mouse_list[j].x2) &&
+ (mousey+this_screen.scroll_offset_y >= mouse_list[j].y1) &&
+ (mousey+this_screen.scroll_offset_y <= mouse_list[j].y2))
+ {
+
+/*
+ if (mouse_list[j].anim_resource) // want to use sprite as a mouse mask, for better accuracy of detection (25oct96 JEL)
+ {
+ // only works for uncompressed sprite data!!
+ // THIS IS NEVER USED IN SWORD2
+
+ if (Check_sprite_pixel(j)) // if the mouse is touching a non-zero pixel of the sprite
+ {
+ mouse_touching=mouse_list[j].id; // record id
+ CreatePointerText(mouse_list[j].pointer_text); // James16jun97
+ return(mouse_list[j].pointer); //return pointer type
+ }
+ }
+ else // ok, we're touching the detection-box
+*/
+ {
+ mouse_touching=mouse_list[j].id; // record id
+
+ // change all COGS pointers to CROSHAIR
+ if (mouse_list[j].pointer == USE)
+ mouse_list[j].pointer = CROSHAIR;
+ CreatePointerText(mouse_list[j].pointer_text, mouse_list[j].pointer); // James16jun97
+ return(mouse_list[j].pointer); //return pointer type
+ }
+ }
+
+ j++; //next
+ if (j==cur_mouse)
+ {
+ j=0;
+ priority++; //next priority - 0 being the highest, 9 the lowest
+ }
+ }
+ }
+
+ mouse_touching=0; // touching nothing
+ return(0); // no pointer to return
+}
+//------------------------------------------------------------------------------------
+
+void CreatePointerText(uint32 textId, uint32 pointerRes) // James16jun97
+{
+ uint32 local_text;
+ uint32 text_res;
+ uint8 *text;
+ int16 xOffset, yOffset; // offsets for pointer text sprite from pointer position
+ uint8 justification;
+
+ #define POINTER_TEXT_WIDTH 640 // just in case!
+ #define POINTER_TEXT_PEN 184 // white
+
+ if (pointerTextSelected)
+ {
+ if (textId)
+ {
+ //-------------------------------------------
+ // check what the pointer is, to set offsets correctly for text position
+
+ switch(pointerRes)
+ {
+ case CROSHAIR:
+ yOffset = -7; // above (above & to the right of the pointer coordinate)
+ xOffset = +10; // right
+ break;
+
+ case EXIT0:
+ yOffset = +15; // below
+ xOffset = +20; // right
+ break;
+
+ case EXIT1:
+ yOffset = +16; // below
+ xOffset = -10; // left
+ break;
+
+ case EXIT2:
+ yOffset = +10; // below
+ xOffset = -22; // left
+ break;
+
+ case EXIT3:
+ yOffset = -16; // above
+ xOffset = -10; // left
+ break;
+
+ case EXIT4:
+ yOffset = -15; // above
+ xOffset = +15; // right
+ break;
+
+ case EXIT5:
+ yOffset = -12; // above
+ xOffset = +10; // right
+ break;
+
+ case EXIT6:
+ yOffset = +10; // below
+ xOffset = +25; // right
+ break;
+
+ case EXIT7:
+ yOffset = +16; // below
+ xOffset = +20; // right
+ break;
+
+ case EXITDOWN:
+ yOffset = -20; // above
+ xOffset = -10; // left
+ break;
+
+ case EXITUP:
+ yOffset = +20; // below
+ xOffset = +20; // right
+ break;
+
+ case MOUTH:
+ yOffset = -10; // above
+ xOffset = +15; // right
+ break;
+
+ case NORMAL:
+ yOffset = -10; // above
+ xOffset = +15; // right
+ break;
+
+ case PICKUP:
+ yOffset = -40; // above
+ xOffset = +10; // right
+ break;
+
+ case SCROLL_L:
+ yOffset = -20; // above
+ xOffset = +20; // right
+ break;
+
+ case SCROLL_R:
+ yOffset = -20; // above
+ xOffset = -20; // left
+ break;
+
+ case USE:
+ yOffset = -8; // above
+ xOffset = +20; // right
+ break;
+
+ default: // shouldn't happen if we cover all the different mouse pointers above
+ yOffset = -10; // above
+ xOffset = +10; // right
+ }
+
+ //-------------------------------------------
+ // set up justification for text sprite,
+ // based on it's offsets from the pointer position
+
+ // from maketext.h
+ //#define NO_JUSTIFICATION 0 // only for debug text, since it doesn't keep text inside the screen margin!
+ //#define POSITION_AT_CENTRE_OF_BASE 1 // these all force text inside the screen edge margin when necessary
+ //#define POSITION_AT_CENTRE_OF_TOP 2
+ //#define POSITION_AT_LEFT_OF_TOP 3
+ //#define POSITION_AT_RIGHT_OF_TOP 4
+ //#define POSITION_AT_LEFT_OF_BASE 5
+ //#define POSITION_AT_RIGHT_OF_BASE 6
+ //#define POSITION_AT_LEFT_OF_CENTRE 7
+ //#define POSITION_AT_RIGHT_OF_CENTRE 8
+
+ //-----------------------------------------
+ if (yOffset < 0) // if 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; // text sprite is justified from it's bottom-left corner
+ }
+ else // (xOffset==0) // above centre
+ {
+ justification = POSITION_AT_CENTRE_OF_BASE;
+ }
+ }
+ //-----------------------------------------
+ else if (yOffset > 0) // if 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 // (xOffset==0) // below centre
+ {
+ justification = POSITION_AT_CENTRE_OF_TOP;
+ }
+ }
+ //-----------------------------------------
+ else // if at 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 // (xOffset==0) // centre centre
+ {
+ justification = POSITION_AT_LEFT_OF_CENTRE; // shouldn't happen anyway!
+ }
+ }
+ //-------------------------------------------
+
+ text_res = textId/SIZE; // text resource number
+ local_text = textId&0xffff; // text line number within the resource
+
+ text = FetchTextLine( res_man.Res_open(text_res), local_text ); // open text file & get the line
+
+ // 'text+2' to skip the first 2 bytes which form the line reference number
+ pointer_text_bloc_no = Build_new_block(text+2, mousex+xOffset, mousey+yOffset, POINTER_TEXT_WIDTH, POINTER_TEXT_PEN, RDSPR_TRANS+RDSPR_DISPLAYALIGN, speech_font_id, justification);
+
+ res_man.Res_close(text_res); // now ok to close the text file
+ }
+ }
+}
+//------------------------------------------------------------------------------------
+void ClearPointerText(void) // James16jun97
+{
+ if (pointer_text_bloc_no)
+ {
+ Kill_text_bloc(pointer_text_bloc_no);
+ pointer_text_bloc_no=0;
+ }
+}
+//------------------------------------------------------------------------------------
+/* NOT USED IN SWORD2
+uint8 Check_sprite_pixel( uint32 j ) // (25oct96 JEL)
+{
+ // only works for uncompressed sprite data!!
+
+ uint8 *file;
+ uint8 hit;
+ _frameHeader *frame_head;
+ int16 sprite_x, sprite_y;
+ int16 in_sprite_x, in_sprite_y;
+ uint8 *sprite_data;
+
+
+ sprite_x = mouse_list[j].x1; // sprite coords have been copied to mouse area coords by FN_register_X_frame (X = sort, back or fore)
+ sprite_y = mouse_list[j].y1; // so easier to get them from there than from the anim file again
+
+
+ file = res_man.Res_open(mouse_list[j].anim_resource); // open the anim file & point to start of it
+ frame_head = FetchFrameHeader(file,mouse_list[j].anim_pc); // point to frame header of current frame
+ sprite_data = (uint8 *)(frame_head + 1); // point to start of frame data
+
+ in_sprite_x = mousex + this_screen.scroll_offset_x - sprite_x; // x-coord of mouse from origin at top-left of sprite
+ in_sprite_y = mousey + this_screen.scroll_offset_y - sprite_y; // y-coord of mouse from origin at top-left of sprite
+
+ hit = sprite_data[in_sprite_y * frame_head->width + in_sprite_x]; // hit = value of pixel to which the mouse is pointing
+
+ res_man.Res_close(mouse_list[j].anim_resource); // close anim file
+
+ return (hit); // we are touching the sprite if 'hit' is non-zero
+}
+*/
+//------------------------------------------------------------------------------------
+int32 FN_no_human(int32 *params) //Tony30Sept96
+{
+//param none
+
+ MOUSE_AVAILABLE = 0; // for logic scripts (James21may97)
+
+ ClearPointerText();
+
+ mouse_status=1; //human/mouse off
+
+ Set_mouse(NULL); // blank cursor
+ Set_luggage(NULL); // blank cursor
+
+
+//must be normal mouse situation or a largely neutral situation - special menus use No_human
+ if (TALK_FLAG==0) //dont hide menu in conversations
+ HideMenu(RDMENU_BOTTOM);
+
+
+ if (mouse_mode==MOUSE_system_menu)
+ {
+ mouse_mode=MOUSE_normal; //close menu
+ HideMenu(RDMENU_TOP); // start the menu coming down
+ }
+
+
+ if (params);
+
+
+ return(1); //script continue
+}
+//------------------------------------------------------------------------------------
+void No_human(void) //Tony4June97
+{
+//leaves the menus open
+//used by the system when clicking right on a menu item to examine it and
+//when combining objects
+
+ MOUSE_AVAILABLE = 0; // for logic scripts (James21may97)
+
+ mouse_status=1; //human/mouse off
+
+ Set_mouse(NULL); // blank cursor
+ Set_luggage(NULL); // blank cursor
+}
+//------------------------------------------------------------------------------------
+int32 FN_add_human(int32 *params) //Tony30Sept96
+{
+ //param none
+#ifdef _DEBUG
+ uint8 black[4] = {0,0,0,0};
+ uint8 white[4] = {255,255,255,0};
+#endif // ('0' means don't print to console, but console isn't up anyway)
+
+
+
+ MOUSE_AVAILABLE = 1; // for logic scripts (James21may97)
+
+
+ if (mouse_status) //off
+ {
+ mouse_status=0; //on
+ mouse_touching=1; //forces engine to choose a cursor
+ }
+
+ CLICKED_ID=0; //clear this to reset no-second-click system
+
+ // this is now done outside the OBJECT_HELD check in case it's set to zero before now! (James 10july97)
+ mouse_mode_locked=0; //unlock the mouse from possible large object lock situtations - see syphon in rm 3
+
+ if (OBJECT_HELD) //was dragging something around
+ {
+ OBJECT_HELD=0; // need to clear this again
+
+ examining_menu_icon=0; // and these may also need clearing
+ COMBINE_BASE=0; // - just in case
+
+
+ Set_luggage(NULL); // blank cursor
+ }
+
+
+
+ if ((mousey>399)&&(mouse_mode!=MOUSE_holding)) // if mouse is over menu area
+ {
+ mouse_mode=MOUSE_normal; // VITAL - reset things & rebuild the menu
+ Set_mouse(NORMAL_MOUSE_ID);
+ }
+ else if (mousey>399)
+ Set_mouse(NORMAL_MOUSE_ID);
+
+
+ //----------------------------------------------------------------------------------------------
+ // enabled/disabled from console; status printed with on-screen debug info
+#ifdef _DEBUG
+ if (testingSnR) // testing logic scripts by simulating an instant Save & Restore
+ {
+ SetPalette(0, 1, white, RDPAL_INSTANT);
+
+ Clear_fx_queue(); // stops all fx & clears the queue - eg. when leaving a location
+ res_man.Kill_all_objects(0); // ie. trashing all object resources so they load in fresh & restart their logic scripts
+
+ SetPalette(0, 1, black, RDPAL_INSTANT);
+ }
+#endif // ('0' means don't print to console, but console isn't up anyway)
+ //----------------------------------------------------------------------------------------------
+ if (params);
+
+ return(1); //script continue
+}
+//------------------------------------------------------------------------------------
+int32 FN_register_mouse(int32 *params) //Tony29Oct96
+{
+//this call would be made from an objects service script 0
+//the object would be one with no graphic but with a mouse - i.e. a floor
+// or one whose mouse area is manually defined rather than intended to fit sprite shape
+
+//param 0 pointer to Object_mouse or 0 for no write to mouse list
+
+// Zdebug(1,"cur_mouse = %d", cur_mouse);
+
+
+ Object_mouse *ob_mouse;
+
+ ob_mouse = (Object_mouse *) params[0]; // param 1 is pointer to mouse structure
+
+ if (ob_mouse->pointer) // only if 'pointer' isn't NULL
+ {
+ #ifdef _DEBUG
+ if (cur_mouse==TOTAL_mouse_list)
+ Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
+ #endif
+
+ mouse_list[cur_mouse].x1 = ob_mouse->x1;
+ mouse_list[cur_mouse].y1 = ob_mouse->y1;
+ mouse_list[cur_mouse].x2 = ob_mouse->x2;
+ mouse_list[cur_mouse].y2 = ob_mouse->y2;
+
+ mouse_list[cur_mouse].priority = ob_mouse->priority;
+ mouse_list[cur_mouse].pointer = ob_mouse->pointer;
+
+ //-----------------------------------------------
+ // (James17jun97)
+ // check if pointer text field is set due to previous object using this slot (ie. not correct for this one)
+ if ((mouse_list[cur_mouse].pointer_text) && (mouse_list[cur_mouse].id != (int32)ID)) // if 'pointer_text' field is set, but the 'id' field isn't same is current id
+ mouse_list[cur_mouse].pointer_text=0; // then we don't want this "left over" pointer text
+ //-----------------------------------------------
+
+ mouse_list[cur_mouse].id = ID; // get id from system variable 'id' which is correct for current object
+
+ mouse_list[cur_mouse].anim_resource = 0; // not using sprite as mask - this is only done from FN_register_frame()
+ mouse_list[cur_mouse].anim_pc = 0;
+
+ //Zdebug("mouse id %d", mouse_list[cur_mouse].id);
+
+ cur_mouse++;
+ }
+
+ return(IR_CONT); // continue script
+}
+//------------------------------------------------------------------------------------
+// use this in the object's service script prior to registering the mouse area
+// ie. before FN_register_mouse or FN_register_frame
+// - best if kept at very top of service script
+
+int32 FN_register_pointer_text(int32 *params) // James16jun97
+{
+// param 0 local id of text line to use as pointer text
+
+ #ifdef _DEBUG
+ if (cur_mouse==TOTAL_mouse_list)
+ Con_fatal_error("ERROR: mouse_list full [%s line %u]",__FILE__,__LINE__);
+ #endif
+
+ mouse_list[cur_mouse].id = ID; // current object id - used for checking pointer_text when mouse area registered (in FN_register_mouse & FN_register_frame)
+ mouse_list[cur_mouse].pointer_text = params[0];
+
+ return(IR_CONT); // continue script
+
+}
+//------------------------------------------------------------------------------------
+int32 FN_blank_mouse(int32 *params) //Tony29Oct96
+{
+//set mouse to normal pointer - used in speech
+
+//no params
+
+
+ Set_mouse(NULL);
+
+ if (params);
+
+ return(1); //cont
+}
+//------------------------------------------------------------------------------------
+int32 FN_init_floor_mouse(int32 *params) // James29nov96
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+ ob_mouse->x1 = 0;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.screen_wide-1;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 9; // floor is always lowest priority
+ ob_mouse->pointer = NORMAL_MOUSE_ID; // normal pointer
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+//---------------------------------------------------------------------------------------------------------------------
+#define SCROLL_MOUSE_WIDTH 20 // James13feb97 (updated by James 25mar97)
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_scroll_left_mouse(int32 *params) // James13feb97
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+
+ ob_mouse->x1 = 0;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.scroll_offset_x + SCROLL_MOUSE_WIDTH;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 0; // highest priority
+
+ if (this_screen.scroll_offset_x > 0) // if not fully scrolled to the left
+ ob_mouse->pointer = SCROLL_LEFT_MOUSE_ID;
+ else
+ ob_mouse->pointer = 0; // so the mouse area doesn't get registered
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_scroll_right_mouse(int32 *params) // James13feb97
+{
+ // params 0 pointer to object's mouse structure
+
+ Object_mouse *ob_mouse = (Object_mouse *) params[0];
+
+
+ ob_mouse->x1 = this_screen.scroll_offset_x + screenWide - SCROLL_MOUSE_WIDTH;
+ ob_mouse->y1 = 0;
+ ob_mouse->x2 = this_screen.screen_wide-1;
+ ob_mouse->y2 = this_screen.screen_deep-1;
+ ob_mouse->priority = 0; // highest priority
+
+ if (this_screen.scroll_offset_x < this_screen.max_scroll_offset_x) // if not fully scrolled to the right
+ ob_mouse->pointer = SCROLL_RIGHT_MOUSE_ID;
+ else
+ ob_mouse->pointer = 0; // so the mouse area doesn't get registered
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_set_object_held(int32 *params) //tony19May97
+{
+//params 0 luggage icon to set
+
+ Set_luggage(params[0]);
+
+ OBJECT_HELD=params[0];
+ current_luggage_resource=params[0];
+
+ mouse_mode_locked=1; //mode locked - no top menu available
+
+
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+// called from speech scripts to remove the chooser bar when it's not appropriate to keep it displayed
+int32 FN_remove_chooser(int32 *params) // James13aug97
+{
+ HideMenu(RDMENU_BOTTOM);
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_disable_menu(int32 *params) //Tony1Oct96
+{
+ mouse_mode_locked=1; //mode locked - no top menu available
+ mouse_mode=MOUSE_normal;
+
+ HideMenu(RDMENU_TOP);
+ HideMenu(RDMENU_BOTTOM);
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_enable_menu(int32 *params) //tony4June97
+{
+
+
+ mouse_mode_locked=0; //mode locked - no top menu available
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_check_player_activity(int32 *params) // James23july97
+{
+// Used to decide when to trigger music cues described as "no player activity for a while"
+
+// params 0 threshold delay in seconds, ie. what we want to check the actual delay against
+
+ uint32 threshold = params[0]*12; // in game cycles
+
+ if (player_activity_delay >= threshold) // if the actual delay is at or above the given threshold
+ {
+ player_activity_delay=0; // reset activity delay counter, now that we've got a positive check
+ RESULT=1;
+ }
+ else
+ RESULT=0;
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+int32 FN_reset_player_activity_delay(int32 *params) // James23july97
+{
+// Use if you want to deliberately reset the "no player activity" counter for any reason
+
+// no params
+
+ player_activity_delay=0; // reset activity delay counter
+
+ return(IR_CONT); // continue script
+}
+//---------------------------------------------------------------------------------------------------------------------
+void Monitor_player_activity(void) // James23july97
+{
+ if (CheckForMouseEvents()) // if there is at least one mouse event outstanding
+ player_activity_delay=0; // reset activity delay counter
+ else
+ player_activity_delay++; // no. of game cycles since mouse event queue last empty
+}
+//---------------------------------------------------------------------------------------------------------------------
+