| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** 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 3 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, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: Mouse.cpp ////////////////////////////////////////////////////////////////////////////////
- // Created: Colin Day, June 2001
- // Desc: Basic mouse interactions
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/Debug.h"
- #include "Common/MessageStream.h"
- #include "Common/GameEngine.h"
- #include "Common/GlobalData.h"
- #include "Common/INI.h"
- #include "GameClient/Display.h"
- #include "GameClient/DisplayStringManager.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/GameText.h"
- #include "GameClient/GameWindow.h"
- #include "GameClient/InGameUI.h"
- #include "GameClient/Keyboard.h"
- #include "GameClient/Mouse.h"
- #include "GameClient/GlobalLanguage.h"
- #include "GameLogic/ScriptEngine.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- // PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
- Mouse *TheMouse = NULL;
- const char *Mouse::RedrawModeName[RM_MAX] = {
- "Mouse:Windows",
- "Mouse:W3D",
- "Mouse:Poly",
- "Mouse:DX8",
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- static const FieldParse TheMouseCursorFieldParseTable[] =
- {
- { "CursorText", INI::parseAsciiString, NULL, offsetof( CursorInfo, cursorText ) },
- { "CursorTextColor", INI::parseRGBAColorInt, NULL, offsetof( CursorInfo, cursorTextColor ) },
- { "CursorTextDropColor", INI::parseRGBAColorInt, NULL, offsetof( CursorInfo, cursorTextDropColor ) },
- { "W3DModel", INI::parseAsciiString, NULL, offsetof( CursorInfo, W3DModelName ) },
- { "W3DAnim", INI::parseAsciiString, NULL, offsetof( CursorInfo, W3DAnimName ) },
- { "W3DScale", INI::parseReal, NULL, offsetof( CursorInfo, W3DScale ) },
- { "Loop", INI::parseBool, NULL, offsetof( CursorInfo, loop ) },
- { "Image", INI::parseAsciiString, NULL, offsetof( CursorInfo, imageName ) },
- { "Texture", INI::parseAsciiString, NULL, offsetof( CursorInfo, textureName ) },
- { "HotSpot", INI::parseICoord2D, NULL, offsetof( CursorInfo, hotSpotPosition ) },
- { "Frames", INI::parseInt, NULL, offsetof( CursorInfo, numFrames ) },
- { "FPS", INI::parseReal, NULL, offsetof( CursorInfo, fps)},
- { "Directions", INI::parseInt, NULL, offsetof( CursorInfo, numDirections ) },
- };
- static const FieldParse TheMouseFieldParseTable[] =
- {
- { "TooltipFontName", INI::parseAsciiString,NULL, offsetof( Mouse, m_tooltipFontName ) },
- { "TooltipFontSize", INI::parseInt, NULL, offsetof( Mouse, m_tooltipFontSize ) },
- { "TooltipFontIsBold", INI::parseBool, NULL, offsetof( Mouse, m_tooltipFontIsBold ) },
- { "TooltipAnimateBackground", INI::parseBool, NULL, offsetof( Mouse, m_tooltipAnimateBackground ) },
- { "TooltipFillTime", INI::parseInt, NULL, offsetof( Mouse, m_tooltipFillTime ) },
- { "TooltipDelayTime", INI::parseInt, NULL, offsetof( Mouse, m_tooltipDelayTime ) },
- { "TooltipTextColor", INI::parseRGBAColorInt, NULL, offsetof( Mouse, m_tooltipColorText ) },
- { "TooltipHighlightColor", INI::parseRGBAColorInt, NULL, offsetof( Mouse, m_tooltipColorHighlight ) },
- { "TooltipShadowColor", INI::parseRGBAColorInt, NULL, offsetof( Mouse, m_tooltipColorShadow ) },
- { "TooltipBackgroundColor", INI::parseRGBAColorInt, NULL, offsetof( Mouse, m_tooltipColorBackground ) },
- { "TooltipBorderColor", INI::parseRGBAColorInt, NULL, offsetof( Mouse, m_tooltipColorBorder ) },
- { "TooltipWidth", INI::parsePercentToReal,NULL, offsetof( Mouse, m_tooltipWidth ) },
- { "CursorMode", INI::parseInt, NULL, offsetof( Mouse, m_currentRedrawMode ) },
- { "UseTooltipAltTextColor", INI::parseBool, NULL, offsetof( Mouse, m_useTooltipAltTextColor ) },
- { "UseTooltipAltBackColor", INI::parseBool, NULL, offsetof( Mouse, m_useTooltipAltBackColor ) },
- { "AdjustTooltipAltColor", INI::parseBool, NULL, offsetof( Mouse, m_adjustTooltipAltColor ) },
- { "OrthoCamera", INI::parseBool, NULL, offsetof( Mouse, m_orthoCamera ) },
- { "OrthoZoom", INI::parseReal, NULL, offsetof( Mouse, m_orthoZoom ) },
- { "DragTolerance", INI::parseUnsignedInt, NULL, offsetof( Mouse, m_dragTolerance) },
- { "DragTolerance3D", INI::parseUnsignedInt, NULL, offsetof( Mouse, m_dragTolerance3D) },
- { "DragToleranceMS", INI::parseUnsignedInt, NULL, offsetof( Mouse, m_dragToleranceMS) },
- };
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //-------------------------------------------------------------------------------------------------
- /** Move the mouse in either relative or absolute coords */
- //-------------------------------------------------------------------------------------------------
- void Mouse::moveMouse( Int x, Int y, Int relOrAbs )
- {
- if( relOrAbs == MOUSE_MOVE_RELATIVE )
- {
- m_currMouse.pos.x += x;
- m_currMouse.pos.y += y;
- }
- else
- {
- m_currMouse.pos.x = x;
- m_currMouse.pos.y = y;
- }
- if( m_currMouse.pos.x > m_maxX )
- m_currMouse.pos.x = m_maxX;
- else if( m_currMouse.pos.x < m_minX )
- m_currMouse.pos.x = m_minX;
- if( m_currMouse.pos.y > m_maxY )
- m_currMouse.pos.y = m_maxY;
- else if( m_currMouse.pos.y < m_minY )
- m_currMouse.pos.y = m_minY;
- } // end moveMouse
- //-------------------------------------------------------------------------------------------------
- /** Get the current information for the mouse from the device */
- //-------------------------------------------------------------------------------------------------
- void Mouse::updateMouseData( )
- {
- static Bool busy = FALSE;
- Int index = 0;
- UnsignedByte result;
- // prevent reentrancy in the event we make this mouse multi-threaded
- if( busy == FALSE )
- {
- busy = TRUE;
- // Get latest mouse events from DirectX
- do
- {
- do
- {
- result = getMouseEvent( &m_mouseEvents[ index ], TRUE );
- }
- while( result == MOUSE_LOST );
- index++;
- }
- while( (result != MOUSE_NONE) &&
- (index < sizeof( m_mouseEvents ) / sizeof( MouseIO )) );
- busy = FALSE;
- } // end if
- if( index > 0 )
- m_eventsThisFrame = index - 1;
- else
- m_eventsThisFrame = 0;
- if( index != 0 )
- m_deadInputFrame = m_inputFrame;
- } // end updateMouseData
- //-------------------------------------------------------------------------------------------------
- /** Combine mouse events into the main mouse variables */
- //-------------------------------------------------------------------------------------------------
- void Mouse::processMouseEvent( Int index )
- {
- Int movementType;
- m_currMouse.leftEvent = MOUSE_EVENT_NONE;
- m_currMouse.rightEvent = MOUSE_EVENT_NONE;
- m_currMouse.middleEvent = MOUSE_EVENT_NONE;
- m_currMouse.wheelPos = 0;
- // what type of movement commands are we setup for
- if( m_inputMovesAbsolute == TRUE )
- movementType = MOUSE_MOVE_ABSOLUTE;
- else
- movementType = MOUSE_MOVE_RELATIVE;
- // set the time of this event to the correct time
- m_currMouse.time = m_mouseEvents[ index ].time;
- if( index == 0 )
- checkForDrag();
- // add Mouse Position Changes to Master Position
- moveMouse( m_mouseEvents[ index ].pos.x,
- m_mouseEvents[ index ].pos.y,
- movementType );
- // Cumulate Wheel Adjustments
- m_currMouse.wheelPos += m_mouseEvents[ index ].wheelPos;
- // Check Left Mouse State
- if( m_mouseEvents[ index ].leftFrame )
- {
- if( m_currMouse.leftState != m_mouseEvents[ index ].leftState )
- {
- // State Change
- if( m_mouseEvents[ index ].leftState == MBS_Down )
- {
- // Mouse Down
- m_currMouse.leftEvent = GWM_LEFT_DOWN;
- m_currMouse.leftState = MBS_Down;
- m_currMouse.leftFrame = m_inputFrame;
- }
- else if ( m_mouseEvents[ index ].leftState == MBS_DoubleClick )
- {
- // Mouse Double Click
- m_currMouse.leftEvent = GWM_LEFT_DOUBLE_CLICK;
- m_currMouse.leftState = MBS_DoubleClick;
- m_currMouse.leftFrame = m_inputFrame;
- }
- else
- {
- // Mouse Up
- m_currMouse.leftEvent = GWM_LEFT_UP;
- m_currMouse.leftState = MBS_Up;
- m_currMouse.leftFrame = m_inputFrame;
- }
- }
- }
- else if( m_currMouse.leftState != MBS_Up &&
- ( (m_prevMouse.leftEvent == GWM_LEFT_DOWN) ||
- (m_prevMouse.leftEvent == GWM_LEFT_DRAG) ) )
- {
- m_currMouse.leftEvent = GWM_LEFT_DRAG;
- }
- // Check Right Mouse State
- if( m_mouseEvents[ index ].rightFrame )
- {
- if( m_currMouse.rightState != m_mouseEvents[ index ].rightState )
- {
- // State Change
- if( m_mouseEvents[ index ].rightState == MBS_Down )
- {
- // Mouse Down
- m_currMouse.rightEvent = GWM_RIGHT_DOWN;
- m_currMouse.rightState = MBS_Down;
- m_currMouse.rightFrame = m_inputFrame;
- }
- else if( m_mouseEvents[ index ].rightState == MBS_DoubleClick )
- {
- // Mouse Double Click
- m_currMouse.rightEvent = GWM_RIGHT_DOUBLE_CLICK;
- m_currMouse.rightState = MBS_DoubleClick;
- m_currMouse.rightFrame = m_inputFrame;
- }
- else
- {
- // Mouse Up
- m_currMouse.rightEvent = GWM_RIGHT_UP;
- m_currMouse.rightState = MBS_Up;
- m_currMouse.rightFrame = m_inputFrame;
- }
- }
- }
- else if( m_currMouse.rightState != MBS_Up &&
- ( (m_prevMouse.rightEvent == GWM_RIGHT_DOWN) ||
- (m_prevMouse.rightEvent == GWM_RIGHT_DRAG) ) )
- {
- m_currMouse.rightEvent = GWM_RIGHT_DRAG;
- }
- // Check Middle Mouse State
- if( m_mouseEvents[ index ].middleFrame )
- {
- if( m_currMouse.middleState != m_mouseEvents[index].middleState )
- {
- // State Change
- if( m_mouseEvents[index].middleState == MBS_Down )
- {
- m_currMouse.middleEvent = GWM_MIDDLE_DOWN;
- m_currMouse.middleState = MBS_Down;
- m_currMouse.middleFrame = m_inputFrame;
- }
- else if( m_mouseEvents[index].middleState == MBS_DoubleClick )
- {
- m_currMouse.middleEvent = GWM_MIDDLE_DOUBLE_CLICK;
- m_currMouse.middleState = MBS_DoubleClick;
- m_currMouse.middleFrame = m_inputFrame;
- }
- else
- {
- // Mouse Up
- m_currMouse.middleEvent = GWM_MIDDLE_UP;
- m_currMouse.middleState = MBS_Up;
- m_currMouse.middleFrame = m_inputFrame;
- }
- }
- }
- else if( m_currMouse.middleState != MBS_Up &&
- ( (m_prevMouse.middleEvent == GWM_MIDDLE_DOWN) ||
- (m_prevMouse.middleEvent == GWM_MIDDLE_DRAG) ) )
- {
- m_currMouse.middleEvent = GWM_MIDDLE_DRAG;
- }
- m_currMouse.deltaPos.x = m_currMouse.pos.x - m_prevMouse.pos.x;
- m_currMouse.deltaPos.y = m_currMouse.pos.y - m_prevMouse.pos.y;
- // DEBUG_LOG(("Mouse dx %d, dy %d, index %d, frame %d\n", m_currMouse.deltaPos.x, m_currMouse.deltaPos.y, index, m_inputFrame));
- // // check if mouse is still and flag tooltip
- // if( ((dx*dx) + (dy*dy)) < CURSOR_MOVE_TOL_SQ )
- // {
- // // cursor is still
- // //m_stillTime++;
- // Int delay = m_tooltipDelayTime;
- // if(m_tooltipDelay >= 0 )
- // delay = m_tooltipDelay;
- //
- // if( now - m_stillTime >= delay )
- // {
- // if (!m_displayTooltip)
- // {
- // m_highlightPos = 0;
- // m_highlightUpdateStart = timeGetTime();
- // }
- //
- // // display tooltip for current window
- // m_displayTooltip = TRUE;
- // }
- // }
- // else
- // {
- // // cursor moved
- // //m_stillTime = 0;
- // m_stillTime = now;
- // m_displayTooltip = FALSE;
- // }
- m_prevMouse = m_currMouse;
- } // end processMouseEvent
- //-------------------------------------------------------------------------------------------------
- /** Check for mouse drag */
- //-------------------------------------------------------------------------------------------------
- void Mouse::checkForDrag( void )
- {
- if( m_currMouse.leftState &&
- ( (m_prevMouse.leftEvent == GWM_LEFT_DOWN) ||
- (m_prevMouse.leftEvent == GWM_LEFT_DRAG) ) )
- {
- m_currMouse.leftEvent = GWM_LEFT_DRAG;
- }
- if( m_currMouse.rightState &&
- ( (m_prevMouse.rightEvent == GWM_RIGHT_DOWN) ||
- (m_prevMouse.rightEvent == GWM_RIGHT_DRAG) ) )
- {
- m_currMouse.rightEvent = GWM_RIGHT_DRAG;
- }
- if( m_currMouse.middleState &&
- ( (m_prevMouse.middleEvent == GWM_MIDDLE_DOWN) ||
- (m_prevMouse.middleEvent == GWM_MIDDLE_DRAG) ) )
- {
- m_currMouse.middleEvent = GWM_MIDDLE_DRAG;
- }
- } // end checkForDrag
- //-------------------------------------------------------------------------------------------------
- /** Check for mouse click, using allowed drag forgiveness */
- //-------------------------------------------------------------------------------------------------
- Bool Mouse::isClick(const ICoord2D *anchor, const ICoord2D *dest, UnsignedInt previousMouseClick, UnsignedInt currentMouseClick)
- {
- ICoord2D delta;
- delta.x = anchor->x - dest->x;
- delta.y = anchor->y - dest->y;
- // if the mouse hasn't moved further than the tolerance distance
- // or the click took less than the tolerance duration
- if ( abs(delta.x) > m_dragTolerance
- || abs(delta.y) > m_dragTolerance
- || currentMouseClick - previousMouseClick > m_dragToleranceMS)
- {
- return FALSE;
- }
- return TRUE;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- CursorInfo::CursorInfo( void )
- {
- // Added Sadullah Nader
- // Initializations missing and needed
-
- cursorName.clear();
- cursorText.clear();
- cursorTextColor.red = cursorTextColor.green = cursorTextColor.blue = 0;
- cursorTextDropColor.red = cursorTextDropColor.blue = cursorTextDropColor.green = 0;
-
- //
- textureName.clear();
- imageName.clear();
- W3DModelName.clear();
- W3DAnimName.clear();
- W3DScale = 1.0f;
- loop = TRUE;
- //Assume hotspot is at the center of a 32x32 image.
- hotSpotPosition.x=16;
- hotSpotPosition.y=16;
- numFrames = 1; //assume no animation
- fps=20.0f;
- numDirections=1;
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- Mouse::Mouse( void )
- {
- // device info
- m_numButtons = 0;
- m_numAxes = 0;
- m_forceFeedback = FALSE;
-
- //Added By Sadullah Nader
- //Initializations missing and needed
- m_dragTolerance = 0;
- m_dragTolerance3D = 0;
- m_dragToleranceMS = 0;
- //
-
- //m_tooltipString.clear(); // redundant
- m_displayTooltip = FALSE;
- m_tooltipDisplayString = NULL;
- m_tooltipDelay = -1; // default value
- // initialize all the mouse io data
- memset( m_mouseEvents, 0, sizeof( m_mouseEvents ) );
- memset( &m_currMouse, 0, sizeof( m_currMouse ) );
- memset( &m_prevMouse, 0, sizeof( m_prevMouse ) );
- m_minX = 0;
- m_maxX = 0;
- m_minY = 0;
- m_maxY = 0;
- m_eventsThisFrame = 0;
- m_inputFrame = 0;
- m_deadInputFrame =0;
- m_inputMovesAbsolute = FALSE;
- m_currentCursor = ARROW;
- if (TheGlobalData && TheGlobalData->m_winCursors)
- m_currentRedrawMode = RM_WINDOWS;
- else
- m_currentRedrawMode = RM_W3D;//RM_WINDOWS;
- m_visible = FALSE;
- m_tooltipFontName = "Times New Roman";
- m_tooltipFontSize = 12;
- m_tooltipFontIsBold = FALSE;
- m_tooltipAnimateBackground = TRUE;
- m_tooltipFillTime = 50;
- m_tooltipDelayTime = 50;
- #define setColor(x, r, g, b, a) { x.red = r; x.green = g; x.blue = b; x.alpha = a; }
- setColor(m_tooltipColorText, 220, 220, 220, 255);
- setColor(m_tooltipColorHighlight, 255, 255, 0, 255);
- setColor(m_tooltipColorShadow, 0, 0, 0, 255);
- setColor(m_tooltipColorBackground, 20, 20, 0, 127);
- setColor(m_tooltipColorBorder, 0, 0, 0, 255);
- #undef setColor
- m_tooltipWidth = 15.0f;
- m_lastTooltipWidth = 0.0f;
- m_useTooltipAltTextColor = FALSE;
- m_useTooltipAltBackColor = FALSE;
- m_adjustTooltipAltColor = FALSE;
- m_orthoCamera = FALSE;
- m_orthoZoom = 1.0f;
- m_isTooltipEmpty = TRUE;
- m_cursorTextDisplayString = NULL;
- m_cursorTextColor.red = 255;
- m_cursorTextColor.green = 255;
- m_cursorTextColor.blue = 255;
- m_cursorTextColor.alpha = 255;
- m_cursorTextDropColor.red = 255;
- m_cursorTextDropColor.green = 255;
- m_cursorTextDropColor.blue = 255;
- m_cursorTextDropColor.alpha = 255;
-
- m_highlightPos = 0;
- m_highlightUpdateStart = 0;
- m_stillTime = 0;
- m_tooltipTextColor.red = 255;
- m_tooltipTextColor.green = 255;
- m_tooltipTextColor.blue = 255;
- m_tooltipTextColor.alpha = 255;
- m_tooltipBackColor.red = 0;
- m_tooltipBackColor.green = 0;
- m_tooltipBackColor.blue = 0;
- m_tooltipBackColor.alpha = 255;
- } // end Mouse
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- Mouse::~Mouse( void )
- {
- if(m_tooltipDisplayString)
- TheDisplayStringManager->freeDisplayString(m_tooltipDisplayString);
- m_tooltipDisplayString = NULL;
- if( m_cursorTextDisplayString )
- TheDisplayStringManager->freeDisplayString( m_cursorTextDisplayString );
- m_cursorTextDisplayString = NULL;
- } // end ~Mouse
- /**Had to move this out of main init() because I need this data to properly initialize
- the Win32 version of the mouse (by preloading resources before D3D device is created).*/
- void Mouse::parseIni(void)
- {
- INI ini;
- ini.load( AsciiString( "Data\\INI\\Mouse.ini" ), INI_LOAD_OVERWRITE, NULL );
- }
- //-------------------------------------------------------------------------------------------------
- /** Initialize the mouse */
- //-------------------------------------------------------------------------------------------------
- void Mouse::init( void )
- {
- if (TheGlobalData && TheGlobalData->m_winCursors)
- m_currentRedrawMode = RM_WINDOWS;
- // device info
- m_numButtons = 2; // by default just have 2 buttons
- m_numAxes = 2; // by default a normal mouse moves in a 2d plane
- m_forceFeedback = FALSE;
- mouseNotifyResolutionChange();
- m_tooltipString.clear(); // redundant
- m_displayTooltip = FALSE;
- // initialize all the mouse io data
- memset( m_mouseEvents, 0, sizeof( m_mouseEvents ) );
- memset( &m_currMouse, 0, sizeof( m_currMouse ) );
- memset( &m_prevMouse, 0, sizeof( m_prevMouse ) );
- m_minX = 0;
- m_maxX = 799;
- m_minY = 0;
- m_maxY = 599;
- m_inputFrame = 0;
- m_deadInputFrame =0;
- m_inputMovesAbsolute = FALSE;
- m_eventsThisFrame = 0;
- m_currentCursor = ARROW;
- // allocate a new display string
- m_cursorTextDisplayString = TheDisplayStringManager->newDisplayString();
- } // end init
- //-------------------------------------------------------------------------------------------------
- /** Tell mouse system display resolution changed. */
- //-------------------------------------------------------------------------------------------------
- void Mouse::mouseNotifyResolutionChange( void )
- {
- if(m_tooltipDisplayString)
- TheDisplayStringManager->freeDisplayString(m_tooltipDisplayString);
- m_tooltipDisplayString = NULL;
- m_tooltipDisplayString = TheDisplayStringManager->newDisplayString();
- if (TheGlobalLanguageData && TheGlobalLanguageData->m_tooltipFontName.name.isNotEmpty())
- {
- m_tooltipDisplayString->setFont( TheFontLibrary->getFont(
- TheGlobalLanguageData->m_tooltipFontName.name,
- TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_tooltipFontName.size),
- TheGlobalLanguageData->m_tooltipFontName.bold) );
- }
- else
- {
- m_tooltipDisplayString->setFont( TheFontLibrary->getFont(
- m_tooltipFontName,
- TheGlobalLanguageData->adjustFontSize(m_tooltipFontSize),
- m_tooltipFontIsBold ) );
- }
- m_tooltipDisplayString->setWordWrap(120);
- } // end reset
- //-------------------------------------------------------------------------------------------------
- /** Reset mouse system */
- //-------------------------------------------------------------------------------------------------
- void Mouse::reset( void )
- {
- ///@ todo Write Mouse::reset() if there needs to be anything here
- // reset the text of the cursor text
- if ( m_cursorTextDisplayString )
- m_cursorTextDisplayString->reset();
- } // end reset
- //-------------------------------------------------------------------------------------------------
- /** Update the states of the mouse position and buttons */
- //-------------------------------------------------------------------------------------------------
- void Mouse::update( void )
- {
- // increment input frame
- m_inputFrame++;
- // update the mouse data
- updateMouseData( );
- } // end update
- //-------------------------------------------------------------------------------------------------
- /** Given the current state of this input device, turn the raw input
- * data into raw stream messages and place those messages on the stream.
- * NOTE that the click messages replace up messages in the mouse, so we
- * are going to propagate those click messages in addition to up messages */
- //-------------------------------------------------------------------------------------------------
- void Mouse::createStreamMessages( void )
- {
- // santiy
- if( TheMessageStream == NULL )
- return; // no place to put messages
- GameMessage *msg = NULL;
- UnsignedInt now = timeGetTime();
- // basic position messages are always created
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_POSITION );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- Int delay = m_tooltipDelayTime;
- if(m_tooltipDelay >= 0 )
- delay = m_tooltipDelay;
- if( TheGlobalData->m_scriptDebug )
- {
- //No delay while scriptdebugging!
- delay = 0;
- }
-
- if( now - m_stillTime >= delay )
- {
- if (!m_displayTooltip)
- {
- m_highlightPos = 0;
- m_highlightUpdateStart = timeGetTime();
- }
- // display tooltip for current window
- m_displayTooltip = TRUE;
- }
- else
- {
- //DEBUG_LOG(("%d %d %d %d\n", TheGameClient->getFrame(), delay, now, m_stillTime));
- m_displayTooltip = FALSE;
- }
-
- for (Int i = 0; i < m_eventsThisFrame; ++i)
- {
- processMouseEvent(i);
- if (m_currMouse.deltaPos.x || m_currMouse.deltaPos.y)
- m_stillTime = now;
- // button messages
- msg = NULL;
- switch( m_currMouse.leftEvent )
- {
- case GWM_LEFT_DOWN:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_DOWN );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_LEFT_DOUBLE_CLICK:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_LEFT_DOUBLE_CLICK );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_LEFT_UP:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_LEFT_BUTTON_UP );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_LEFT_DRAG:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_LEFT_DRAG );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendPixelArgument( m_currMouse.deltaPos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- break;
- } // end switch
- msg = NULL;
- switch( m_currMouse.middleEvent )
- {
- //-------------------------------------------------------------------------
- case GWM_MIDDLE_DOWN:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_DOWN );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_MIDDLE_DOUBLE_CLICK:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_MIDDLE_DOUBLE_CLICK );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_MIDDLE_UP:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_MIDDLE_BUTTON_UP );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_MIDDLE_DRAG:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_MIDDLE_DRAG );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendPixelArgument( m_currMouse.deltaPos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- break;
- } // end switch
- msg = NULL;
- switch( m_currMouse.rightEvent )
- {
- //-------------------------------------------------------------------------
- case GWM_RIGHT_DOWN:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_RIGHT_DOUBLE_CLICK:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_RIGHT_UP:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- msg->appendIntegerArgument( m_currMouse.time );
- break;
- case GWM_RIGHT_DRAG:
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_RIGHT_DRAG );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendPixelArgument( m_currMouse.deltaPos );
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- break;
- } // end switch
- // wheel pos
- msg = NULL;
- if( m_currMouse.wheelPos != 0 )
- {
- msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_MOUSE_WHEEL );
- msg->appendPixelArgument( m_currMouse.pos );
- msg->appendIntegerArgument( m_currMouse.wheelPos / 120 ); // wheel delta
- msg->appendIntegerArgument( TheKeyboard->getModifierFlags() );
- } // end if
-
- } // end for
- } // end createStreamMessages
- //-------------------------------------------------------------------------------------------------
- /** Set the string to display at the cursor for the tooltip */
- //-------------------------------------------------------------------------------------------------
- void Mouse::setCursorTooltip( UnicodeString tooltip, Int delay, const RGBColor *color, Real width )
- {
- //DEBUG_LOG(("%d Tooltip: %ls\n", TheGameClient->getFrame(), tooltip.str()));
- m_isTooltipEmpty = tooltip.isEmpty();
- m_tooltipDelay = delay;
- Bool forceRecalc = FALSE;
- if ( !tooltip.isEmpty() && width != m_lastTooltipWidth )
- {
- forceRecalc = TRUE;
- Int widthInPixels = (Int)(TheDisplay->getWidth()*m_tooltipWidth*width);
- if (widthInPixels < 10)
- {
- widthInPixels = 120;
- }
- else if (widthInPixels > TheDisplay->getWidth())
- {
- widthInPixels = TheDisplay->getWidth();
- }
- //DEBUG_LOG(("Setting tooltip width to %d pixels (%g%% of the normal tooltip width)\n", widthInPixels, width*100));
- m_tooltipDisplayString->setWordWrap( widthInPixels );
- m_lastTooltipWidth = width;
- }
- if (forceRecalc || !m_isTooltipEmpty && tooltip.compare(m_tooltipDisplayString->getText()))
- {
- m_tooltipDisplayString->setText(tooltip);
- //DEBUG_LOG(("Tooltip: %ls\n", tooltip.str()));
- }
- if (color)
- {
- if (m_useTooltipAltTextColor)
- {
- if (m_adjustTooltipAltColor)
- {
- m_tooltipTextColor.red = REAL_TO_INT((color->red + 1.0f) * 255.0f / 2.0f);
- m_tooltipTextColor.green = REAL_TO_INT((color->green + 1.0f) * 255.0f / 2.0f);
- m_tooltipTextColor.blue = REAL_TO_INT((color->blue + 1.0f) * 255.0f / 2.0f);
- }
- else
- {
- m_tooltipTextColor.red = REAL_TO_INT(color->red * 255.0f);
- m_tooltipTextColor.green = REAL_TO_INT(color->green * 255.0f);
- m_tooltipTextColor.blue = REAL_TO_INT(color->blue * 255.0f);
- }
- m_tooltipTextColor.alpha = m_tooltipColorText.alpha;
- }
- if (m_useTooltipAltBackColor)
- {
- if (m_adjustTooltipAltColor)
- {
- m_tooltipBackColor.red = REAL_TO_INT(color->red * 255.0f * 0.5f);
- m_tooltipBackColor.green = REAL_TO_INT(color->green * 255.0f * 0.5f);
- m_tooltipBackColor.blue = REAL_TO_INT(color->blue * 255.0f * 0.5f);
- }
- else
- {
- m_tooltipBackColor.red = REAL_TO_INT(color->red * 255.0f);
- m_tooltipBackColor.green = REAL_TO_INT(color->green * 255.0f);
- m_tooltipBackColor.blue = REAL_TO_INT(color->blue * 255.0f);
- }
- m_tooltipBackColor.alpha = m_tooltipColorBackground.alpha;
- }
- }
- else
- {
- m_tooltipTextColor = m_tooltipColorText;
- m_tooltipBackColor = m_tooltipColorBackground;
- }
- } // end setCursorTooltip
- // ------------------------------------------------------------------------------------------------
- /** Set the text for the mouse cursor ... note that this is *NOT* the tooltip text we
- * can set to be at the mouse position */
- // ------------------------------------------------------------------------------------------------
- void Mouse::setMouseText( UnicodeString text,
- const RGBAColorInt *color,
- const RGBAColorInt *dropColor )
- {
- // sanity, if no display string has been created, get out of here
- if( m_cursorTextDisplayString == NULL )
- return;
- // set the text into the cursor display string
- m_cursorTextDisplayString->setText( text );
- // save the colors to draw in
- if( color )
- m_cursorTextColor = *color;
- if( dropColor )
- m_cursorTextDropColor = *dropColor;
- } // end setMouseText
- //-------------------------------------------------------------------------------------------------
- /** Move the mouse to the position */
- //-------------------------------------------------------------------------------------------------
- void Mouse::setPosition( Int x, Int y )
- {
- m_currMouse.pos.x = x;
- m_currMouse.pos.y = y;
- } // end setPosition
- //-------------------------------------------------------------------------------------------------
- /** This default implemtation of SetMouseLimits will just set the limiting
- * rectangle to be the width and height of the game display with the
- * origin in the upper left at (0,0). However, if the game is running
- * in a windowed mode then these limits should reflect the SCREEN
- * coords that the mouse is allowed to move in. Also, if the game is in
- * a window you may want to adjust for any title bar available in
- * the operating system. For system specific limits and windows etc,
- * just override this function in the device implementation of the mouse */
- //-------------------------------------------------------------------------------------------------
- void Mouse::setMouseLimits( void )
- {
- m_minX = 0;
- m_minY = 0;
- if( TheDisplay )
- {
- m_maxX = TheDisplay->getWidth();
- m_maxY = TheDisplay->getHeight();
-
- } // end if
- } // end setMouseLimits
- //-------------------------------------------------------------------------------------------------
- /** Draw the mouse */
- //-------------------------------------------------------------------------------------------------
- void Mouse::draw( void )
- {
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void Mouse::resetTooltipDelay( void )
- {
- m_stillTime = timeGetTime();
- m_displayTooltip = FALSE;
- }
- //-------------------------------------------------------------------------------------------------
- /** Draw the mouse tooltip if one is set */
- //-------------------------------------------------------------------------------------------------
- void Mouse::drawTooltip( void )
- {
- if (TheScriptEngine->getFade()!=ScriptEngine::FADE_NONE) {
- return;
- }
- /// @todo: Still need to put in display logic so it puts the tool tips in a visable position on the edge of the screen
- if( m_displayTooltip && TheDisplay && m_tooltipDisplayString && (m_tooltipDisplayString->getTextLength() > 0) && !m_isTooltipEmpty)
- {
- Int width, xPos;
- Int height, yPos;
- m_tooltipDisplayString->getSize(&width,&height);
- xPos = m_currMouse.pos.x + 20;
- yPos = m_currMouse.pos.y;// + 20;
- if( xPos + width + 4 > m_maxX ) // +4 for spill
- {
- //xPos = m_maxX - width;
- xPos -= 20 + width;
- }
- if( yPos + height + 4 > m_maxY ) // +4 for spill
- {
- //yPos = m_maxY - height;
- yPos -= /*40 +*/ height;
- }
- Int boxWidth = (m_tooltipAnimateBackground)?(min(width, m_highlightPos)):width;
- #define GMC(x) GameMakeColor(x.red, x.green, x.blue, x.alpha)
- #define COLOR(x) GMC(m_tooltipColor##x)
- TheDisplay->drawFillRect(xPos, yPos, boxWidth + 2,height + 2, GMC(m_tooltipBackColor));//GameMakeColor(0,0,0,125));
- TheDisplay->drawOpenRect(xPos, yPos, boxWidth + 2,height + 2, 1.0, COLOR(Border));//GameMakeColor(20,20,20,255));
- // build clip rect
- IRegion2D clipRegion;
- clipRegion.lo.x = xPos+2;
- clipRegion.lo.y = yPos+1;
- clipRegion.hi.x = xPos+2+m_highlightPos;
- clipRegion.hi.y = yPos+1+height;
- m_tooltipDisplayString->setClipRegion(&clipRegion);
- m_tooltipDisplayString->draw(xPos +2, yPos +1, GMC(m_tooltipTextColor), COLOR(Shadow));//GameMakeColor(220,220,220,255),GameMakeColor(20,20,20,125));
- // highlight section
- const Int HIGHLIGHT_WIDTH = 15;
- clipRegion.lo.x = xPos+2+m_highlightPos-HIGHLIGHT_WIDTH;
- clipRegion.lo.y = yPos+1;
- clipRegion.hi.x = xPos+2+m_highlightPos;
- clipRegion.hi.y = yPos+1+height;
- m_tooltipDisplayString->setClipRegion(&clipRegion);
- m_tooltipDisplayString->draw(xPos +2, yPos +1, COLOR(Highlight), COLOR(Shadow));//GameMakeColor(255,255,0,255),GameMakeColor(20,20,20,125));
- // get ready for the next part of the anim
- if (m_highlightPos < width + HIGHLIGHT_WIDTH)
- {
- UnsignedInt now = timeGetTime();
- m_highlightPos = (width*(now-m_highlightUpdateStart))/m_tooltipFillTime;
- }
- } // end if
- } // end drawTooltip
- // ------------------------------------------------------------------------------------------------
- /** Draw the cursor text at the mouse position. Note that this is *NOT* the tooltip text */
- // ------------------------------------------------------------------------------------------------
- void Mouse::drawCursorText( void )
- {
- // sanity
- if( m_cursorTextDisplayString == NULL )
- return;
- // get the colors to draw the text in an acceptable format
- Color color, dropColor;
- color = GameMakeColor( m_cursorTextColor.red,
- m_cursorTextColor.green,
- m_cursorTextColor.blue,
- m_cursorTextColor.alpha );
- dropColor = GameMakeColor( m_cursorTextDropColor.red,
- m_cursorTextDropColor.green,
- m_cursorTextDropColor.blue,
- m_cursorTextDropColor.alpha );
- // get the size of the text to draw
- Int width, height;
- m_cursorTextDisplayString->getSize( &width, &height );
- // draw the text around the cursor position
- Int x, y;
- x = m_currMouse.pos.x - width / 2;
- y = m_currMouse.pos.y - height / 2;
- m_cursorTextDisplayString->draw( x, y, color, dropColor );
- } // end drawCursorText
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Int Mouse::getCursorIndex(const AsciiString& name)
- {
- if (name.isEmpty())
- return INVALID_MOUSE_CURSOR;
- /** @todo This is silly to have to define these names from INI in the code ...
- * that should be changed (CBD) */
- static char *CursorININames[NUM_MOUSE_CURSORS] =
- {
- //"InvalidMouseCursor", // this entry is not actually a mouse cursor, but just a
- // reminder that it does exist
- "None",
- "Normal",
- "Arrow",
- "Scroll",
- "Target",
- "Move",
- "AttackMove",
- "AttackObj",
- "ForceAttackObj",
- "ForceAttackGround",
- "Build",
- "InvalidBuild",
- "GenericInvalid",
- "Select",
- "EnterFriendly",
- "EnterAggressive",
- "SetRallyPoint",
- "GetRepaired",
- "GetHealed",
- "DoRepair",
- "ResumeConstruction",
- "CaptureBuilding",
- "SnipeVehicle",
- "LaserGuidedMissiles",
- "TankHunterTNTAttack",
- "StabAttack",
- "PlaceRemoteCharge",
- "PlaceTimedCharge",
- "Defector",
- #ifdef ALLOW_DEMORALIZE
- "Demoralize",
- #endif
- "Dock",
- #ifdef ALLOW_SURRENDER
- "PickUpPrisoner",
- "ReturnToPrison",
- #endif
- "FireFlame",
- #ifdef ALLOW_SURRENDER
- "FireTranqDarts",
- "FireStunBullets",
- #endif
- "FireBomb",
- "PlaceBeacon",
- "DisguiseAsVehicle",
- "Waypoint",
- "OutRange",
- "StabAttackInvalid",
- "PlaceChargeInvalid",
- "Hack",
- "ParticleUplinkCannon",
- };
- for (Int i=0; i<NUM_MOUSE_CURSORS; ++i)
- {
- if (name.compareNoCase(CursorININames[i]) == 0)
- return i;
- }
- DEBUG_CRASH(( "Mouse::getCursorIndex - Invalid cursor name '%s'\n", name.str() ));
- return INVALID_MOUSE_CURSOR;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- void Mouse::setCursor( MouseCursor cursor )
- {
-
- // if cursor has not changed do nothing
- if( m_currentCursor == cursor )
- return;
- // only if we have a display cursor do we do anything with mouse text
- if( m_cursorTextDisplayString != NULL )
- {
- CursorInfo *cursorInfo = &m_cursorInfo[ cursor ];
- //
- // if there is text present into the cursor info, set it into the mouse, otherwise
- // just clear out the text for the cursor text
- //
- if( cursorInfo->cursorText.isEmpty() == FALSE )
- setMouseText( TheGameText->fetch( cursorInfo->cursorText.str() ),
- &(cursorInfo->cursorTextColor),
- &(cursorInfo->cursorTextDropColor) );
- else
- setMouseText( UnicodeString( L"" ), NULL, NULL );
- } // end if
- } // end setCursor
- //-------------------------------------------------------------------------------------------------
- /** Parse MouseCursor entry */
- //-------------------------------------------------------------------------------------------------
- void INI::parseMouseCursorDefinition( INI* ini )
- {
- const char *c;
- AsciiString name;
- // read the name
- c = ini->getNextToken();
- name.set( c );
- if( TheMouse )
- {
- Int index = TheMouse->getCursorIndex(name);
- if (index != Mouse::INVALID_MOUSE_CURSOR)
- {
- CursorInfo *cursorInfo = &(TheMouse->m_cursorInfo[index]);
- cursorInfo->cursorName = name;
- // parse the ini weapon definition
- ini->initFromINI( cursorInfo, TheMouseCursorFieldParseTable );
- }
- }
- }
- //-------------------------------------------------------------------------------------------------
- /** Parse MouseCursor entry */
- //-------------------------------------------------------------------------------------------------
- void INI::parseMouseDefinition( INI* ini )
- {
- if( TheMouse )
- {
- // parse the ini weapon definition
- ini->initFromINI( TheMouse, TheMouseFieldParseTable );
- }
- }
|