diff --git a/Core/GameEngine/Include/GameClient/CommandXlat.h b/Core/GameEngine/Include/GameClient/CommandXlat.h index 3d46fefa252..db988f8150d 100644 --- a/Core/GameEngine/Include/GameClient/CommandXlat.h +++ b/Core/GameEngine/Include/GameClient/CommandXlat.h @@ -51,10 +51,12 @@ class CommandTranslator : public GameMessageTranslator Bool m_teamExists; ///< is there a currently selected "team"? // these are for determining if a drag occurred or it was just a sloppy click - ICoord2D m_mouseRightDragAnchor; // the location of a possible mouse drag start - ICoord2D m_mouseRightDragLift; // the location of a possible mouse drag end - UnsignedInt m_mouseRightDown; // when the mouse down happened - UnsignedInt m_mouseRightUp; // when the mouse up happened + ICoord2D m_rightMouseDownAnchor; // the location of a possible mouse drag start + ICoord2D m_rightMouseUpAnchor; // the location of a possible mouse drag end + UnsignedInt m_rightMouseDownTimeMs; // when the mouse down happened + UnsignedInt m_rightMouseUpTimeMs; // when the mouse up happened + Coord3D m_rightMouseDownCameraPos; + Coord3D m_rightMouseUpCameraPos; GameMessage::Type createMoveToLocationMessage( Drawable *draw, const Coord3D *dest, CommandEvaluateType commandType ); GameMessage::Type createAttackMessage( Drawable *draw, Drawable *other, CommandEvaluateType commandType ); diff --git a/Core/GameEngine/Include/GameClient/Mouse.h b/Core/GameEngine/Include/GameClient/Mouse.h index 849a933f37f..19e00fc3730 100644 --- a/Core/GameEngine/Include/GameClient/Mouse.h +++ b/Core/GameEngine/Include/GameClient/Mouse.h @@ -321,7 +321,14 @@ class Mouse : public SubsystemInterface void onGameModeChanged(GameMode prev, GameMode next); void onGamePaused(Bool paused); - Bool isClick(const ICoord2D *anchor, const ICoord2D *dest, UnsignedInt previousMouseClick, UnsignedInt currentMouseClick); + Bool isClick( + const ICoord2D &mouseAnchor0, + const ICoord2D &mouseAnchor1, + const Coord3D &cameraPos0, + const Coord3D &cameraPos1, + UnsignedInt mouseClickTimeMs0, + UnsignedInt mouseClickTimeMs1 + ); AsciiString m_tooltipFontName; ///< tooltip font Int m_tooltipFontSize; ///< tooltip font diff --git a/Core/GameEngine/Include/GameClient/SelectionXlat.h b/Core/GameEngine/Include/GameClient/SelectionXlat.h index cdb6f56698b..63830b4cac0 100644 --- a/Core/GameEngine/Include/GameClient/SelectionXlat.h +++ b/Core/GameEngine/Include/GameClient/SelectionXlat.h @@ -44,17 +44,16 @@ class SelectionTranslator : public GameMessageTranslator Bool m_leftMouseButtonIsDown; Bool m_dragSelecting; + Bool m_displayedMaxWarning; // did we already display a warning about selecting too many units? UnsignedInt m_lastGroupSelTime; Int m_lastGroupSelGroup; - ICoord2D m_selectFeedbackAnchor; // Note: Used for drawing feedback only. - ICoord2D m_deselectFeedbackAnchor; // Note: Used for drawing feedback only. - Bool m_displayedMaxWarning; // did we already display a warning about selecting too many units? - UnsignedInt m_lastClick; ///< timer used for checking double click for type selection + ICoord2D m_leftMouseDownAnchor; // Note: Used for drawing feedback only. + ICoord2D m_rightMouseDownAnchor; // Note: Used for drawing feedback only. + UnsignedInt m_rightMouseDownTimeMs; ///< timer used for checking double click for type selection + Coord3D m_rightMouseDownCameraPos; SelectCountMap m_selectCountMap; - Coord3D m_deselectDownCameraPosition; - Bool selectFriends( Drawable *draw, GameMessage *createTeamMsg, Bool dragSelecting ); Bool killThemKillThemAll( Drawable *draw, GameMessage *killThemAllMsg ); diff --git a/Core/GameEngine/Source/GameClient/Input/Mouse.cpp b/Core/GameEngine/Source/GameClient/Input/Mouse.cpp index a1c2cb97a4e..ee17f585757 100644 --- a/Core/GameEngine/Source/GameClient/Input/Mouse.cpp +++ b/Core/GameEngine/Source/GameClient/Input/Mouse.cpp @@ -384,18 +384,23 @@ void Mouse::checkForDrag() //------------------------------------------------------------------------------------------------- /** Check for mouse click, using allowed drag forgiveness */ //------------------------------------------------------------------------------------------------- -Bool Mouse::isClick(const ICoord2D *anchor, const ICoord2D *dest, UnsignedInt previousMouseClick, UnsignedInt currentMouseClick) +Bool Mouse::isClick( + const ICoord2D &mouseAnchor0, + const ICoord2D &mouseAnchor1, + const Coord3D &cameraPos0, + const Coord3D &cameraPos1, + UnsignedInt mouseClickTimeMs0, + UnsignedInt mouseClickTimeMs1) { - ICoord2D delta; - delta.x = anchor->x - dest->x; - delta.y = anchor->y - dest->y; - + ICoord2D mouseAnchorDelta = mouseAnchor1 - mouseAnchor0; + Coord3D cameraPosDelta = cameraPos1 - cameraPos0; + UnsignedInt timeMsDelta = mouseClickTimeMs1 - mouseClickTimeMs0; // 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) + if ( timeMsDelta > m_dragToleranceMS + || mouseAnchorDelta.lengthSqr() > sqr(m_dragTolerance) + || cameraPosDelta.lengthSqr() > sqr(m_dragTolerance3D) ) { return FALSE; } diff --git a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index fa0d78a384f..eba114867bc 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -1445,13 +1445,13 @@ GameMessage::Type CommandTranslator::createEnterMessage( Drawable *enter, CommandTranslator::CommandTranslator() : m_objective(0), m_teamExists(false), - m_mouseRightDown(0), - m_mouseRightUp(0) + m_rightMouseDownTimeMs(0), + m_rightMouseUpTimeMs(0) { - m_mouseRightDragAnchor.x = 0; - m_mouseRightDragAnchor.y = 0; - m_mouseRightDragLift.x = 0; - m_mouseRightDragLift.y = 0; + m_rightMouseDownAnchor.zero(); + m_rightMouseUpAnchor.zero(); + m_rightMouseDownCameraPos.zero(); + m_rightMouseUpCameraPos.zero(); } //==================================================================================== @@ -3864,11 +3864,13 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage case GameMessage::MSG_RAW_MOUSE_RIGHT_DOUBLE_CLICK: case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_DOWN: { - // There are two ways in which we can ignore this as a deselect: + // There are three ways in which we can ignore this as a deselect: // 1) 2-D position on screen // 2) Time has exceeded the time which we allow for this to be a click. - m_mouseRightDragAnchor = msg->getArgument( 0 )->pixel; - m_mouseRightDown = (UnsignedInt) msg->getArgument( 2 )->integer; + // 3) 3-D camera position has changed + m_rightMouseDownAnchor = msg->getArgument( 0 )->pixel; + m_rightMouseDownTimeMs = (UnsignedInt) msg->getArgument( 2 )->integer; + m_rightMouseDownCameraPos = TheTacticalView->getPosition(); break; } @@ -3877,14 +3879,18 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: { // register this event for determining if the click was fast or short enough not to be a drag - m_mouseRightDragLift = msg->getArgument( 0 )->pixel; - m_mouseRightUp = (UnsignedInt) msg->getArgument( 2 )->integer; + m_rightMouseUpAnchor = msg->getArgument( 0 )->pixel; + m_rightMouseUpTimeMs = (UnsignedInt) msg->getArgument( 2 )->integer; + m_rightMouseUpCameraPos = TheTacticalView->getPosition(); //Kris: July 7, 2003. Added this code to deselect build placement mode when right clicked. This fixes //a bug where you couldn't cancel the sneak attack mode via right click. This only happened when you //didn't have anything selected which is possible via the shortcut bar. Normally, it would get deselected //via the deselect drawable code. - if( TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp) ) + if( TheMouse->isClick( + m_rightMouseDownAnchor, m_rightMouseUpAnchor, + m_rightMouseDownCameraPos, m_rightMouseUpCameraPos, + m_rightMouseDownTimeMs, m_rightMouseUpTimeMs) ) { TheInGameUI->placeBuildAvailable( nullptr, nullptr ); } @@ -3916,7 +3922,10 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage { // right click is only actioned here if we're in alternate mouse mode if (TheGlobalData->m_useAlternateMouse - && TheMouse->isClick(&m_mouseRightDragAnchor, &m_mouseRightDragLift, m_mouseRightDown, m_mouseRightUp)) + && TheMouse->isClick( + m_rightMouseDownAnchor, m_rightMouseUpAnchor, + m_rightMouseDownCameraPos, m_rightMouseUpCameraPos, + m_rightMouseDownTimeMs, m_rightMouseUpTimeMs)) { Bool isPoint = (msg->getArgument(0)->pixelRegion.height() == 0 && msg->getArgument(0)->pixelRegion.width() == 0); diff --git a/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp index caca08f832a..6cba0cd85a0 100644 --- a/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp +++ b/Core/GameEngine/Source/GameClient/MessageStream/SelectionXlat.cpp @@ -259,12 +259,10 @@ SelectionTranslator::SelectionTranslator() m_dragSelecting = FALSE; m_lastGroupSelTime = 0; m_lastGroupSelGroup = -1; - m_selectFeedbackAnchor.x = 0; - m_selectFeedbackAnchor.y = 0; - m_deselectFeedbackAnchor.x = 0; - m_deselectFeedbackAnchor.y = 0; - m_lastClick = 0; - m_deselectDownCameraPosition.zero(); + m_leftMouseDownAnchor.zero(); + m_rightMouseDownAnchor.zero(); + m_rightMouseDownTimeMs = 0; + m_rightMouseDownCameraPos.zero(); m_displayedMaxWarning = FALSE; m_selectCountMap.clear(); @@ -403,8 +401,8 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa { ICoord2D delta; - delta.x = abs(pixel.x - m_selectFeedbackAnchor.x); - delta.y = abs(pixel.y - m_selectFeedbackAnchor.y); + delta.x = abs(pixel.x - m_leftMouseDownAnchor.x); + delta.y = abs(pixel.y - m_leftMouseDownAnchor.y); // if mouse has moved while left button is down, begin drag selection if (delta.x > TheMouse->m_dragTolerance || delta.y > TheMouse->m_dragTolerance) @@ -425,7 +423,7 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa // build rectangular region defined by the drag selection IRegion2D pixelRegion; - buildRegion( &m_selectFeedbackAnchor, &pixel, &pixelRegion ); + buildRegion( &m_leftMouseDownAnchor, &pixel, &pixelRegion ); hintMsg->appendPixelRegionArgument( pixelRegion ); } } @@ -883,7 +881,7 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa { // cannot actually start area selection yet - have to wait for cursor to move a bit m_leftMouseButtonIsDown = true; - m_selectFeedbackAnchor = msg->getArgument( 0 )->pixel; + m_leftMouseDownAnchor = msg->getArgument( 0 )->pixel; break; } @@ -907,7 +905,7 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa GameMessage *dragMsg = TheMessageStream->appendMessage( GameMessage::MSG_END_AREA_SELECTION_HINT ); IRegion2D selectionRegion; - buildRegion( &m_selectFeedbackAnchor, &msg->getArgument(0)->pixel, &selectionRegion ); + buildRegion( &m_leftMouseDownAnchor, &msg->getArgument(0)->pixel, &selectionRegion ); dragMsg->appendPixelRegionArgument( selectionRegion ); } else @@ -946,9 +944,9 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa // 1) 2-D position on screen // 2) Time has exceeded the time which we allow for this to be a click. // 3) 3-D camera position has changed - m_deselectFeedbackAnchor = msg->getArgument( 0 )->pixel; - m_lastClick = (UnsignedInt) msg->getArgument( 2 )->integer; - m_deselectDownCameraPosition = TheTacticalView->getPosition(); + m_rightMouseDownAnchor = msg->getArgument( 0 )->pixel; + m_rightMouseDownTimeMs = (UnsignedInt) msg->getArgument( 2 )->integer; + m_rightMouseDownCameraPos = TheTacticalView->getPosition(); break; } @@ -956,14 +954,12 @@ GameMessageDisposition SelectionTranslator::translateGameMessage(const GameMessa //----------------------------------------------------------------------------- case GameMessage::MSG_RAW_MOUSE_RIGHT_BUTTON_UP: { - Coord3D cameraPos = TheTacticalView->getPosition(); - cameraPos.sub(&m_deselectDownCameraPosition); - - ICoord2D pixel = msg->getArgument( 0 )->pixel; - UnsignedInt currentTime = (UnsignedInt) msg->getArgument( 2 )->integer; + const ICoord2D anchor = msg->getArgument( 0 )->pixel; + const UnsignedInt timeMs = (UnsignedInt) msg->getArgument( 2 )->integer; + const Coord3D cameraPos = TheTacticalView->getPosition(); // right click behavior (not right drag) - if (TheMouse->isClick(&m_deselectFeedbackAnchor, &pixel, m_lastClick, currentTime)) + if (TheMouse->isClick(m_rightMouseDownAnchor, anchor, m_rightMouseDownCameraPos, cameraPos, m_rightMouseDownTimeMs, timeMs)) { //Added support to cancel the GUI command without deselecting the unit(s) involved //when you right click. diff --git a/Core/Libraries/Include/Lib/BaseType.h b/Core/Libraries/Include/Lib/BaseType.h index 2cb718c9e27..a2de160cc1f 100644 --- a/Core/Libraries/Include/Lib/BaseType.h +++ b/Core/Libraries/Include/Lib/BaseType.h @@ -298,8 +298,55 @@ struct Coord2D Real toAngle() const; ///< turn 2D vector into angle (where angle 0 is down the +x axis) + void add( const Coord2D *a ) + { + x += a->x; + y += a->y; + } + + void sub( const Coord2D *a ) + { + x -= a->x; + y -= a->y; + } + + void operator+=(const Coord2D& a) + { + add(&a); + } + + void operator-=(const Coord2D& a) + { + sub(&a); + } + + void set( const Coord2D *a ) + { + x = a->x; + y = a->y; + } + + void set( Real ax, Real ay ) + { + x = ax; + y = ay; + } }; +inline Coord2D operator+(const Coord2D& a, const Coord2D& b) +{ + Coord2D c = a; + c.add(&b); + return c; +} + +inline Coord2D operator-(const Coord2D& a, const Coord2D& b) +{ + Coord2D c = a; + c.sub(&b); + return c; +} + inline Real Coord2D::toAngle() const { #if RTS_GENERALS /*&& RETAIL_COMPATIBLE_CRC*/ @@ -376,8 +423,57 @@ struct ICoord2D } Int length() const { return (Int)sqrt( (double)(x*x + y*y) ); } + Real lengthSqr() const { return x*x + y*y; } + + void add( const ICoord2D *a ) + { + x += a->x; + y += a->y; + } + + void sub( const ICoord2D *a ) + { + x -= a->x; + y -= a->y; + } + + void operator+=(const ICoord2D& a) + { + add(&a); + } + + void operator-=(const ICoord2D& a) + { + sub(&a); + } + + void set( const ICoord2D *a ) + { + x = a->x; + y = a->y; + } + + void set( Int ax, Int ay ) + { + x = ax; + y = ay; + } }; +inline ICoord2D operator+(const ICoord2D& a, const ICoord2D& b) +{ + ICoord2D c = a; + c.add(&b); + return c; +} + +inline ICoord2D operator-(const ICoord2D& a, const ICoord2D& b) +{ + ICoord2D c = a; + c.sub(&b); + return c; +} + struct Region2D { Coord2D lo, hi; // bounds of 2D rectangular region @@ -471,6 +567,16 @@ struct Coord3D z -= a->z; } + void operator+=(const Coord3D& a) + { + add(&a); + } + + void operator-=(const Coord3D& a) + { + sub(&a); + } + void set( const Coord3D *a ) { x = a->x; @@ -507,6 +613,20 @@ struct Coord3D } }; +inline Coord3D operator+(const Coord3D& a, const Coord3D& b) +{ + Coord3D c = a; + c.add(&b); + return c; +} + +inline Coord3D operator-(const Coord3D& a, const Coord3D& b) +{ + Coord3D c = a; + c.sub(&b); + return c; +} + struct ICoord3D { Int x, y, z; @@ -524,8 +644,60 @@ struct ICoord3D { return x == value && y == value && z == value; } + + void add( const ICoord3D *a ) + { + x += a->x; + y += a->y; + z += a->z; + } + + void sub( const ICoord3D *a ) + { + x -= a->x; + y -= a->y; + z -= a->z; + } + + void operator+=(const ICoord3D& a) + { + add(&a); + } + + void operator-=(const ICoord3D& a) + { + sub(&a); + } + + void set( const ICoord3D *a ) + { + x = a->x; + y = a->y; + z = a->z; + } + + void set( Int ax, Int ay, Int az ) + { + x = ax; + y = ay; + z = az; + } }; +inline ICoord3D operator+(const ICoord3D& a, const ICoord3D& b) +{ + ICoord3D c = a; + c.add(&b); + return c; +} + +inline ICoord3D operator-(const ICoord3D& a, const ICoord3D& b) +{ + ICoord3D c = a; + c.sub(&b); + return c; +} + // For alternative see AABoxClass struct Region3D {