// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" ////////////// // Includes // ////////////// // 3D Interface. #include "nel/3d/u_driver.h" #include "nel/3d/u_scene.h" #include "nel/3d/u_camera.h" #include "nel/3d/u_transform.h" // GAME SHARE #include "game_share/bot_chat_types.h" // Client. #include "user_controls.h" #include "../actions_client.h" #include "../user_entity.h" #include "../cursor_functions.h" #include "../time_client.h" #include "../interface_v3/interface_manager.h" #include "../entities.h" #include "../view.h" #include "../input.h" // Misc #include "nel/misc/mouse_device.h" // Std #include // #include "../r2/editor.h" /////////// // Using // /////////// using namespace std; using namespace NLMISC; using namespace NL3D; ///////////// // Externs // ///////////// extern UDriver *Driver; extern UScene *Scene; extern CEventsListener EventsListener; // Inputs Manager ///////////// // Globals // ///////////// // User Controls (mouse, keyboard, interfaces, ...) CUserControls UserControls; // Hierachical timer H_AUTO_DECL ( RZ_Client_User_Controls_Update ) // ---------------------------------------------------------------------------- static bool isSwimming() { if (UserEntity != NULL) return (UserEntity->mode() == MBEHAV::SWIM || UserEntity->mode() == MBEHAV::MOUNT_SWIM); else return false; } static bool isSit() { if (UserEntity) return UserEntity->isSit(); else return false; } static bool isRiding() { if (UserEntity) return UserEntity->isRiding(); else return false; } /////////////// // Functions // /////////////// //--------------------------------------------------- // CUserControls : // Constructor. //--------------------------------------------------- CUserControls::CUserControls() { init(); }// CUserControls // //--------------------------------------------------- // init : // Initialize all the components. //--------------------------------------------------- void CUserControls::init() { // Default Mode is Interface Mode. _LastMode = _Mode = InterfaceMode; _LeftClickStart = 0; _LeftClickEnd = 0; _RightClickStart = 0; _RightClickEnd = 0; _TimeBeforeMouseSlide = 50; _TimeLongClick = 200; _TransSpeed = 1.f; _UpdateView = false; _ZOscil = 0; _Acc = 0; _T0 = 0; _T = 0; _V0 = _TransSpeed; _T0View = 0; _TView = 0; _TurnBack = false; _ClickMove = false; _Start = CVector(0,0,0); _Destination = _Start; _Dist = -1; _DirectionMove = none; _Locked = false; // Move is not locked. _FreeLook = false; _InternalView = true; _LastFrameBackward = false; _LastFrameForward = false; _LastFrameAutowalk = false; _LastFrameStrafeLeft = false; _LastFrameStrafeRight = false; _LastFrameTurnLeft = false; _LastFrameTurnRight = false; _LastFrameLeftButtonDown= false; _LastFrameMousePosX = 0.f; _LastFrameMousePosY = 0.f; _CameraAuto = false; _UserCameraDeltaYaw = 0; _ResetSmoothCameraDeltaYaw= ResetCDYOff; _CurrentFrameFreeLookCalled= false; _RotateUserLRVelocity= 0.f; _RotateUserUDVelocity= 0.f; _RotateCameraLRVelocity= 0.f; _MouseCaptured = false; _NeedReleaseForward = false; _NextForwardCancelMoveTo = false; }// init // //----------------------------------------------- // needReleaseForward : //----------------------------------------------- void CUserControls::needReleaseForward() { if( Actions.valide("forward") ) { _NeedReleaseForward = true; } } //----------------------------------------------- // autowalkState : //----------------------------------------------- void CUserControls::autowalkState(bool enable) { if(enable) { _DirectionMove |= autowalk; // If not backward, default is forward. if(!(_DirectionMove & backward)) _DirectionMove |= forward; } else _DirectionMove &= ~(autowalk|forward|backward); }// autowalkState // //----------------------------------------------- // update : // Main function of the Class -> Call it each frame. //----------------------------------------------- void CUserControls::update() { H_AUTO_USE ( RZ_Client_User_Controls_Update ); View.update(); // Reset the moving direction. _DirectionMove &= ~(left | right); // if not locked, move if(!_Locked) { // What is the current _Mode ? switch(_Mode) { // Interface Mode. case InterfaceMode: interfaceMode(); break; // AI Mode case AIMode: aiMode(); break; // Death Mode case DeathMode: deathMode(); break; // Mount Mode case MountMode: mountMode(); break; // Third Person View Mode case ThirdMode: thirdMode(); break; } _LastFrameForward = Actions.valide("forward") && !_NeedReleaseForward; if( UserEntity->mode() != MBEHAV::MOUNT_SWIM ) { _LastFrameBackward = Actions.valide("backward"); } _LastFrameAutowalk = Actions.valide("toggle_auto_walk"); if( isSit() || UserEntity->isAFK() ) { if( _LastFrameForward || _LastFrameBackward ) { UserEntity->sit(false); UserEntity->setAFK(false); } } if (isSwimming() || isRiding()) { _LastFrameStrafeLeft = false; _LastFrameStrafeRight = false; } else { _LastFrameStrafeLeft = Actions.valide("strafe_left"); _LastFrameStrafeRight = Actions.valide("strafe_right"); } _LastFrameTurnLeft = Actions.valide("turn_left"); _LastFrameTurnRight = Actions.valide("turn_right"); _LastFrameLeftButtonDown= EventsListener.isMouseButtonDown(leftButton); _LastFrameMousePosX = EventsListener.getMousePosX(); _LastFrameMousePosY = EventsListener.getMousePosY(); } // update the refinePos (for landscape refining...) // In fly mode, take the view pos. if(_Mode == AIMode) View.refinePos(View.viewPos()); // Else take the entity pos (for less update if 3rd personn) else View.refinePos(UserEntity->pos()); // update camera collision once per frame View.updateCameraCollision(); CInterfaceManager::getInstance()->getDbProp("UI:VARIABLES:MK_MOVE")->setValue32(autowalkState()); }// update // //----------------------------------------------- // Acceleration helper //----------------------------------------------- void CUserControls::updateVelocity (float deltaTime, float acceleration, float brake, float speedMax, float &speed) { speed += acceleration * deltaTime; // No acclereration, brake if (acceleration == 0) { brake *= deltaTime; if (speed < 0) { if (speed > -brake) speed = 0; else speed += brake; } else { if (speed < brake) speed = 0; else speed -= brake; } } // Clamp the speed clamp (speed, -speedMax, speedMax); }// updateVelocity // //----------------------------------------------- // keyboardRotation : // Manage keyboard rotation //----------------------------------------------- void CUserControls::keyboardRotationLR (bool left, bool right) { if (left || right) { float accel = 0; if (left) { accel += ClientCfg.RotAccel; _RotateUserLRVelocity = std::max (_RotateUserLRVelocity, ClientCfg.RotKeySpeedMin); } if (right) { accel -= ClientCfg.RotAccel; _RotateUserLRVelocity = std::min (_RotateUserLRVelocity, -ClientCfg.RotKeySpeedMin); } updateVelocity (DT, accel, ClientCfg.RotAccel, ClientCfg.RotKeySpeedMax, _RotateUserLRVelocity); // Rotate the body. UserEntity->rotate(DT*_RotateUserLRVelocity); } else _RotateUserLRVelocity = 0; }// keyboardRotation // //----------------------------------------------- // keyboardRotationUD : //----------------------------------------------- void CUserControls::keyboardRotationUD (bool up, bool down) { if (up || down) { float accel = 0; if (up) { accel += ClientCfg.RotAccel; _RotateUserUDVelocity = std::max (_RotateUserUDVelocity, ClientCfg.RotKeySpeedMin); } if (down) { accel -= ClientCfg.RotAccel; _RotateUserUDVelocity = std::min (_RotateUserUDVelocity, -ClientCfg.RotKeySpeedMin); } updateVelocity (DT, accel, ClientCfg.RotAccel, ClientCfg.RotKeySpeedMax, _RotateUserUDVelocity); UserEntity->rotHeadVertically(DT*_RotateUserUDVelocity); UserEntity->stopForceHeadPitchInFollow(); } else _RotateUserUDVelocity = 0; }// keyboardRotationUD // //----------------------------------------------- // keyboardRotationCameraLR : //----------------------------------------------- void CUserControls::keyboardRotationCameraLR (bool left, bool right) { if (left || right) { float accel = 0; if (left) { accel += ClientCfg.RotAccel; _RotateCameraLRVelocity = std::max (_RotateCameraLRVelocity, ClientCfg.RotKeySpeedMin); } if (right) { accel -= ClientCfg.RotAccel; _RotateCameraLRVelocity = std::min (_RotateCameraLRVelocity, -ClientCfg.RotKeySpeedMin); } updateVelocity (DT, accel, ClientCfg.RotAccel, ClientCfg.RotKeySpeedMax, _RotateCameraLRVelocity); // Rotate the camera appendCameraDeltaYaw(DT*_RotateCameraLRVelocity); } else _RotateCameraLRVelocity = 0; } //----------------------------------------------- // getMouseAngleMove //----------------------------------------------- void CUserControls::getMouseAngleMove(float &dx, float &dy) { dx = 0.0f; dy = 0.0f; // The mouse may still "StandardMove" ie through a CEventMouseMove // This can happens cause DirectInputDisabled, or because of the "Rotation Anti-Lag system" // which start to rotate before the mouse is hid and message mode passed to RawMode // // If we are not on Windows; on X11 there is always StandardMove/CEventMouseMove. // Currently, there is only a direct input IMouseDevice, not available on X11. #ifdef NL_OS_WINDOWS extern IMouseDevice *MouseDevice; if (MouseDevice) { if( EventsListener.getMousePosX() != _LastFrameMousePosX || EventsListener.getMousePosY() != _LastFrameMousePosY ) { float dmpx= EventsListener.getMousePosX() - _LastFrameMousePosX; float dmpy= EventsListener.getMousePosY() - _LastFrameMousePosY; // simulate mickeys mode MouseDevice->convertStdMouseMoveInMickeys(dmpx, dmpy); if(ClientCfg.FreeLookInverted) dmpy = -dmpy; // update free look EventsListener.updateFreeLookPos(dmpx, dmpy); } } #else // On X11 and Mac, do the thing without IMouseDevice implementation if( EventsListener.getMousePosX() != _LastFrameMousePosX || EventsListener.getMousePosY() != _LastFrameMousePosY ) { float dmpx, dmpy; #ifndef NL_MAC_NATIVE // On X11 in free look mode, the mouse is pulled back to (0.5, 0.5) // every update to prevent reaching a border and get stuck. if(IsMouseFreeLook()) { /* TODO use setCapture to not fake it */ dmpx = EventsListener.getMousePosX() - 0.5; dmpy = EventsListener.getMousePosY() - 0.5; } else #endif { dmpx = EventsListener.getMousePosX() - _LastFrameMousePosX; dmpy = EventsListener.getMousePosY() - _LastFrameMousePosY; } // TODO: read desktop mouse speed value on X11 / implement X11MouseDevice dmpx *= 450.0f; dmpy *= 450.0f; if(ClientCfg.FreeLookInverted) dmpy = -dmpy; // update free look EventsListener.updateFreeLookPos(dmpx, dmpy); } #endif // If the mouse move on the axis X, with a CGDMouseMove if(EventsListener.isMouseAngleX()) dx = -EventsListener.getMouseAngleX (); // If the mouse move on the axis Y, with a CGDMouseMove if(EventsListener.isMouseAngleY()) dy = EventsListener.getMouseAngleY (); } //----------------------------------------------- // freeLook : // Manage a free look. //----------------------------------------------- void CUserControls::freeLook(bool fullMode) { static bool leftButtonDownInFullMode = false; EventsListener.enableMouseSmoothing(true); // **** Mouse rotation => apply to user float dx,dy; getMouseAngleMove(dx,dy); // apply if(dx != 0.f) { if( UserEntity->canChangeFront() ) { UserEntity->rotate(dx); } else { appendCameraDeltaYaw(dx); } } if(dy != 0.f) { UserEntity->rotHeadVertically(dy); UserEntity->stopForceHeadPitchInFollow(); } // **** Only in fullMode (longClick for instance) if(fullMode) { _CurrentFrameFreeLookCalled= true; CInterfaceManager *IM = CInterfaceManager::getInstance (); // FREE LOOK : Hide the cursor // disable interface mouse handling. IM->enableMouseHandling(false); // Get the cursor instance CViewPointer *cursor = IM->getPointer(); if(cursor) { // Hide the Cursor. SetMouseFreeLook(); } // **** special actions keys while in free look if (isSwimming() || isRiding()) keyboardRotationLR (false, false); else keyboardRotationLR (Actions.valide("strafe_left"), Actions.valide("strafe_right")); // Strafe Left if(Actions.valide("turn_left")) _DirectionMove |= left; // Strafe Right if(Actions.valide("turn_right")) _DirectionMove |= right; // **** Left mouse click while in freelook: forward // NB: in commonMove() the case "rightButtonDown+leftButtonDown" is managed. // but still important to test it here, in case of FreeLook mode (no right button down needed) if(EventsListener.isMouseButtonDown (leftButton)) { // Forward. _DirectionMove |= forward; _DirectionMove &= ~backward; // Quit autowalk if first frame in this mode if( !leftButtonDownInFullMode ) _DirectionMove &= ~autowalk; // Moving Break any Follow Mode UserEntity->disableFollow(); UserEntity->moveTo(CLFECOMMON::INVALID_SLOT, 0.0, CUserEntity::None); leftButtonDownInFullMode = true; } else { leftButtonDownInFullMode = false; } if( UserEntity->canChangeFront() ) { // **** reset delta camera applyCameraDeltaYawToUser(); } } }// freeLook // //----------------------------------------------- // cameraLook : // Manage the camera look. //----------------------------------------------- void CUserControls::cameraLook(bool fullMode) { EventsListener.enableMouseSmoothing(true); // **** Mouse rotation => apply X to camera, Y to user float dx,dy; getMouseAngleMove(dx,dy); // apply if(dx != 0.f) appendCameraDeltaYaw(dx); // If the mouse move on the axis Y, cahnge the actual user pitch (not the delta camera) if(dy != 0.f) { UserEntity->rotHeadVertically(dy); UserEntity->stopForceHeadPitchInFollow(); } // **** Only in fullMode (longClick for instance) if(fullMode) { CInterfaceManager *IM = CInterfaceManager::getInstance (); // CAMERA LOOK : Hide the cursor // disable interface mouse handling. IM->enableMouseHandling(false); // Get the cursor instance CViewPointer *cursor = IM->getPointer(); if(cursor) { // Hide the Cursor. SetMouseFreeLook(); } } }// cameraLook // //----------------------------------------------- // commonMove : // Manage some common actions. // \todo GUIGUI : manage control before entities update, but view only after move //----------------------------------------------- void CUserControls::commonMove() { CInterfaceManager *IM = CInterfaceManager::getInstance (); ///////////////// // RESET USER CAMERA YAW testApplyCameraYawToUser(); ///////////////// // MOUSE WHEEL // CEventsListener::TWheelState wheelState = EventsListener.getWheelState(); // Done all the time, to reset the state View.changeCameraDist((wheelState == CEventsListener::foreward), (wheelState == CEventsListener::backward)); // Camera Up/Down. View.changeCameraHeight(Actions.valide("camera_up"), Actions.valide("camera_down")); ////////////////// // LOOK UP/DOWN // keyboardRotationUD(Actions.valide("look_up"), Actions.valide("look_down")); ///////////// // FORWARD // // ON if(Actions.valide("forward") && !_NeedReleaseForward) { // Forward _DirectionMove |= forward; _DirectionMove &= ~backward; // Start Action if(!_LastFrameForward) { // Start autowalk mode. if(Actions.valide("toggle_auto_walk")) _DirectionMove |= autowalk; // Leave autowalk mode. else _DirectionMove &= ~autowalk; } if( _NextForwardCancelMoveTo ) { _NextForwardCancelMoveTo = false; UserEntity->moveTo(CLFECOMMON::INVALID_SLOT, 0.0, CUserEntity::None); applyCameraDeltaYawToUser(); } } // OFF else { if(_LastFrameForward) if(!(_DirectionMove & autowalk)) _DirectionMove &= ~forward; // since forward is released, forward is now enable again if( !Actions.valide("forward") && _NeedReleaseForward) { _NeedReleaseForward = false; _NextForwardCancelMoveTo = true; } } ////////////// // BACKWARD // // ON if(Actions.valide("backward")) { if( UserEntity->mode()!=MBEHAV::MOUNT_SWIM ) { // Backward _DirectionMove |= backward; _DirectionMove &= ~forward; } // Start Action if(!_LastFrameBackward) { // Start autowalk mode. if(Actions.valide("toggle_auto_walk")) _DirectionMove |= autowalk; // Leave autowalk mode. else _DirectionMove &= ~autowalk; } } // OFF else { if(_LastFrameBackward) if(!(_DirectionMove & autowalk)) _DirectionMove &= ~backward; } // turn left or right will break the move-to, so forward is enable again here if(Actions.valide("turn_left") || Actions.valide("turn_right")) { if( _NeedReleaseForward ) { _NeedReleaseForward = false; _NextForwardCancelMoveTo = false; // if free cam mode reset the view because move if target turned around camera may be if( !ClientCfg.AutomaticCamera ) { resetSmoothCameraDeltaYaw(); } } } ////////////// // AUTOWALK // // Must be after forward and backward to know the autowalk direction // ON if(Actions.valide("toggle_auto_walk")) { // Action start if(!_LastFrameAutowalk) { // Leave autowalk if forward and backward not pushed and only if autowalk just pushed. if((_DirectionMove & autowalk) && !Actions.valide("forward") && !Actions.valide("backward")) _DirectionMove &= ~(autowalk|forward|backward); else { // Start Autowalk _DirectionMove |= autowalk; // If not backward, default is forward. if(!(_DirectionMove & backward)) _DirectionMove |= forward; } } } ////////////// // MOUSE MANAGEMENT ////////////// // Left Click and Dbl Click bool dblClickLeft = false; if(EventsListener.isMouseButtonPushed(leftButton)) { _LeftClickStart = T1; } if( EventsListener.isMouseButtonReleased (leftButton) ) { if(T1 <= _LeftClickEnd+IM->getUserDblClickDelay()) { dblClickLeft = true; } _LeftClickEnd = T1; } // Right Click and Dbl Click bool dblClickRight = false; if(EventsListener.isMouseButtonPushed(rightButton)) { _RightClickStart = T1; } if( EventsListener.isMouseButtonReleased (rightButton) ) { if(T1 <= _RightClickEnd+IM->getUserDblClickDelay()) { dblClickRight = true; } _RightClickEnd = T1; } _CurrentFrameFreeLookCalled= false; if(_FreeLook) { if(EventsListener.isMouseButtonReleased (rightButton)) { // stop FreeLook (and restore mouse/cursor) stopFreeLook(); } else { // if we are in follow mode, do a cameraLook instead if(UserEntity->follow() || UserEntity->moveTo()) cameraLook(true); else freeLook(true); } } else { if (!_MouseCaptured) { // if rightbutton release while left MouseButton UP if ( EventsListener.isMouseButtonReleased (rightButton) && EventsListener.isMouseButtonUp (leftButton)) { // Cursor mode. SetMouseCursor (); // Short Right Click -> Check Action if((T1-_RightClickStart) <= _TimeLongClick) { if(ClientCfg.SelectWithRClick || R2::isEditionCurrent()) { // nb : the ring editor also need that kind of events execActionCursorPos(true,dblClickRight); } // Launch Context Menu if (R2::getEditor().getMode() != R2::CEditor::EditionMode) { IM->launchContextMenuInGame("ui:interface:game_context_menu"); } } // Give back the mouse handling to the interface. IM->enableMouseHandling(true); EventsListener.enableMouseSmoothing(false); } // if leftbutton release while right MouseButton UP if ( EventsListener.isMouseButtonReleased (leftButton) && EventsListener.isMouseButtonUp (rightButton)) { // Cursor mode. SetMouseCursor (); // Short Left Click -> Check Action if((T1-_LeftClickStart) <= _TimeLongClick) { execActionCursorPos(false, dblClickLeft); } // Give back the mouse handling to the interface. IM->enableMouseHandling(true); EventsListener.enableMouseSmoothing(false); } // if Right button down if (EventsListener.isMouseButtonDown (rightButton)) { // NB: start the freeLook sooner than a longclick if((T1-_RightClickStart) > _TimeBeforeMouseSlide) { // if we are in follow mode, do a cameraLook on RightSlide, else do a freeLook if(UserEntity->follow() || UserEntity->moveTo() || UserEntity->isSit() || UserEntity->isAFK()) // FullMode (hide mouse...) only if longClick cameraLook(T1-_RightClickStart > _TimeLongClick); else { // FullMode (hide mouse...) only if longClick freeLook(T1-_RightClickStart > _TimeLongClick); if( _NeedReleaseForward ) { _NeedReleaseForward = false; _NextForwardCancelMoveTo = false; // if free cam mode reset the view because move if target turned around camera may be if( !ClientCfg.AutomaticCamera ) { resetSmoothCameraDeltaYaw(); } } } } } // if Right Mouse button is up else { // mouse camera look: when the user hold down the left button for a time, while the right button is up if (EventsListener.isMouseButtonDown (leftButton)) { // NB: start the freeLook sooner than a longclick if((T1 -_LeftClickStart ) > _TimeBeforeMouseSlide) // FullMode (hide mouse...) only if longClick cameraLook(T1-_LeftClickStart > _TimeLongClick); } if ( ! (isSwimming() || isRiding())) { // Strafe Left if(Actions.valide("strafe_left")) _DirectionMove |= left; // Strafe Right if(Actions.valide("strafe_right")) _DirectionMove |= right; } if( !UserEntity->isSit() && !UserEntity->isAFK() ) { // Test rotation keys if( UserEntity->canChangeFront() ) { keyboardRotationLR (Actions.valide("turn_left"), Actions.valide("turn_right")); } else { keyboardRotationCameraLR (Actions.valide("turn_left"), Actions.valide("turn_right")); } } } } } if (!_MouseCaptured) { // If both button are pressed in any case (whatever the _TimeBeforeMouseSlide time), treat as "forward" static bool bothButtonPressed = false; if(EventsListener.isMouseButtonDown (leftButton) && EventsListener.isMouseButtonDown (rightButton)) { // Forward. _DirectionMove |= forward; _DirectionMove &= ~backward; // quit autowalk if entering both button pressed mode if( !bothButtonPressed ) { _DirectionMove &= ~autowalk; } // Moving Break any Follow Mode UserEntity->disableFollow(); UserEntity->moveTo(CLFECOMMON::INVALID_SLOT, 0.0, CUserEntity::None); // if sit, stand up UserEntity->sit(false); // and no more in afk mode UserEntity->setAFK(false); bothButtonPressed = true; } else { bothButtonPressed = false; } } // Manage here the Release of Forward in any of third case (keyUP, leftButton in freeLook, and both buttons down) if( (_DirectionMove & forward) && (_DirectionMove & autowalk)==0) { // freeLook() called and leftButton down => walk bool walkInFreeLook= _CurrentFrameFreeLookCalled && EventsListener.isMouseButtonDown(leftButton); // both button down => walk too bool walkWithBothButton= (EventsListener.isMouseButtonDown (leftButton) && EventsListener.isMouseButtonDown (rightButton)); // if no forward action valid, quit forward if(! (Actions.valide("forward") || walkInFreeLook || walkWithBothButton) ) _DirectionMove &= ~forward; } //////////////////// // CAMERA DELTA YAW ADDS //////////////////// if (!_MouseCaptured) { // reset too if middle button clicked if(EventsListener.isMouseButtonReleased(middleButton)) { resetSmoothCameraDeltaYaw(); } // Handle rotations with keys bool cameraLeft,cameraRight; if( UserEntity->isSit() || UserEntity->isAFK() ) { cameraLeft = Actions.valide("camera_turn_left") || Actions.valide("turn_left"); cameraRight = Actions.valide("camera_turn_right") || Actions.valide("turn_right"); } else { cameraLeft = Actions.valide("camera_turn_left"); cameraRight = Actions.valide("camera_turn_right"); } keyboardRotationCameraLR (cameraLeft, cameraRight); // reset over time if(_ResetSmoothCameraDeltaYaw!=ResetCDYOff) { // normalize in -Pi/Pi _UserCameraDeltaYaw = float(fmod(_UserCameraDeltaYaw, 2.0f*(float)Pi)); if(_UserCameraDeltaYaw>Pi) _UserCameraDeltaYaw-= 2*float(Pi); else if(_UserCameraDeltaYaw<-Pi) _UserCameraDeltaYaw+= 2*float(Pi); // reset over time if(_UserCameraDeltaYaw<0) { _UserCameraDeltaYaw+= DT*ClientCfg.CameraResetSpeed; if(_UserCameraDeltaYaw>=0) { _UserCameraDeltaYaw= 0; _ResetSmoothCameraDeltaYaw= ResetCDYOff; } } else { _UserCameraDeltaYaw-= DT*ClientCfg.CameraResetSpeed; if(_UserCameraDeltaYaw<=0) { _UserCameraDeltaYaw= 0; _ResetSmoothCameraDeltaYaw= ResetCDYOff; } } } } //////////////////// // APPLY MOTION. //////////////////// move(); }// commonMove // //----------------------------------------------- // move : // Move the caracter according to the inputs. //----------------------------------------------- void CUserControls::move() { // If the user is sit(), remove any move if( UserEntity->isSit() || UserEntity->isAFK() ) _DirectionMove= none; if( _DirectionMove != none ) { cancelActionsWhenMoving(); } // Forward/backward motion. float direction = 0; if(_DirectionMove&forward) direction += 1; if( UserEntity->mode() != MBEHAV::MOUNT_SWIM ) { if(_DirectionMove&backward) direction -= 1; } // Changes the front velocity for the user. UserEntity->frontVelocity(direction); // Strafe motion. float directionStrafe = 0; if( ! (isSwimming() || isRiding()) ) { if(_DirectionMove&left) directionStrafe += 1; if(_DirectionMove&right) directionStrafe -= 1; } else if ( isRiding() ) { // Check if the mount is able to run, and force walking mode if not, because the player can always switch the mode UserEntity->checkMountAbleToRun(); } // Changes the lateral velocity for the user. UserEntity->lateralVelocity(directionStrafe); }// move // //----------------------------------------------- // mode : // Change the current Mode. //----------------------------------------------- void CUserControls::mode(const TMoveMode mode) { // Unlock the motion; _Locked = false; // If the mode didn't change -> return. if(_Mode == mode) return; // Write that the last Mode end. switch(_Mode) { case InterfaceMode: interfaceModeStop(); break; case AIMode: aiModeStop(); break; // Death Mode case DeathMode: deathModeStop(); break; // Mount Mode case MountMode: mountModeStop(); break; // Third Person View Mode case ThirdMode: thirdModeStop(); break; } // Backup the last Mode. _LastMode = _Mode; // Set the new mode. _Mode = mode; // Write that the new Mode Start. switch(_Mode) { case InterfaceMode: interfaceModeStart(); break; // AI Mode case AIMode: aiModeStart(); break; // Death Mode case DeathMode: deathModeStart(); break; // Mount Mode case MountMode: mountModeStart(); break; // Third Person View Mode case ThirdMode: thirdModeStart(); break; } }// mode // //----------------------------------------------- // modeStr : // Return the string associated to the motion Mode. //----------------------------------------------- string CUserControls::modeStr() const { switch(mode()) { // Interface Mode case CUserControls::InterfaceMode: return "InterfaceMode"; // Camera Mode case CUserControls::AIMode: return "AIMode"; // Death Mode case CUserControls::DeathMode: return "DeathMode"; // Mount Mode case CUserControls::MountMode: return "MountMode"; // Third Person View Mode case CUserControls::ThirdMode: return "Third Person View Mode"; // Unknown Mode default: return "Unknown Control Mode"; } }// modeStr // //----------------------------------------------- //----------------------------------------------- // execActionCursorPos : // Execute action depending on the cursor position (left/right click). //----------------------------------------------- void CUserControls::execActionCursorPos(bool rightClick, bool dblClick) { // Check there is no interface under the cursor. CInterfaceManager *IM = CInterfaceManager::getInstance(); if(IM->isMouseOverWindow()) return; // Update the cursor. ContextCur.check(); // Execute Action. ContextCur.execute(rightClick,dblClick); }// execActionCursorPos // //----------------------------------------------- // resetCameraDeltaYaw() //----------------------------------------------- void CUserControls::resetCameraDeltaYaw() { _UserCameraDeltaYaw= 0.f; _ResetSmoothCameraDeltaYaw= ResetCDYOff; } //----------------------------------------------- // appendCameraDeltaYaw() //----------------------------------------------- void CUserControls::appendCameraDeltaYaw(float dYaw) { _UserCameraDeltaYaw+= dYaw; // Stop the smooth reset if any _ResetSmoothCameraDeltaYaw= ResetCDYOff; } //----------------------------------------------- // resetSmoothCameraDeltaYaw() //----------------------------------------------- void CUserControls::resetSmoothCameraDeltaYaw() { // Force the reset if the user currently in follow/moveTo if(UserEntity->follow() || UserEntity->moveTo()) _ResetSmoothCameraDeltaYaw= ResetCDYForced; else _ResetSmoothCameraDeltaYaw= ResetCDYOn; } //----------------------------------------------- // applyCameraDeltaYawToUser(); //----------------------------------------------- void CUserControls::applyCameraDeltaYawToUser() { // apply delta camera to the UserEntity UserEntity->rotate(_UserCameraDeltaYaw); // and reset _UserCameraDeltaYaw= 0.f; _ResetSmoothCameraDeltaYaw= ResetCDYOff; } //----------------------------------------------- // testApplyCameraYawToUser() //----------------------------------------------- void CUserControls::testApplyCameraYawToUser() { // only if not in "camera look" mode if(!EventsListener.isMouseButtonDown(leftButton)) { // if any of those actions start if( ( !_LastFrameForward && Actions.valide("forward") && !_NeedReleaseForward) || ( !_LastFrameBackward && Actions.valide("backward") ) || ( !_LastFrameAutowalk && Actions.valide("toggle_auto_walk") ) ) /*( !_LastFrameStrafeLeft && Actions.valide("strafe_left") ) || ( !_LastFrameStrafeRight && Actions.valide("strafe_right") ) || ( !_LastFrameTurnLeft && Actions.valide("turn_left") ) || ( !_LastFrameTurnRight && Actions.valide("turn_right") ) )*/ { applyCameraDeltaYawToUser(); } } // if both buttons are pressed, then reset. // This is for the case where right button is pressed while left button was down for cameraLook() if( EventsListener.isMouseButtonDown(leftButton) && EventsListener.isMouseButtonDown(rightButton)) { applyCameraDeltaYawToUser(); } } //----------------------------------------------- //commonSetView() //----------------------------------------------- void CUserControls::commonSetView() { // Set the view direction. CMatrix camMat; camMat.identity(); camMat.setRot(CVector(0,-1,0), CVector(1,0,0), CVector(0,0,1), true); camMat.rotateZ(UserEntity->frontYaw() + _UserCameraDeltaYaw); camMat.rotateX(float(UserEntity->getHeadPitch())); View.view(camMat.getJ()); // Update the mount direction. CEntityCL *mount = EntitiesMngr.entity(UserEntity->parent()); if(mount) { mount->front(UserEntity->front()); } } //----------------------------------------------- // startFreeLook() //----------------------------------------------- void CUserControls::startFreeLook() { _FreeLook= true; } //----------------------------------------------- // stopFreeLook() //----------------------------------------------- void CUserControls::stopFreeLook() { EventsListener.enableMouseSmoothing(false); _FreeLook= false; // Cursor mode SetMouseCursor (); // Give back the mouse handling to the interface. CInterfaceManager::getInstance()->enableMouseHandling(true); } //----------------------------------------------- // cancelActionsWhenMoving() //----------------------------------------------- void CUserControls::cancelActionsWhenMoving() { if( UserEntity->behaviour() == MBEHAV::EXTRACTING || (UserEntity->behaviour() >= MBEHAV::MAGIC_CASTING_BEHAVIOUR_BEGIN && UserEntity->behaviour() <= MBEHAV::MAGIC_CASTING_BEHAVIOUR_END) ) { UserEntity->cancelAllPhrases(); } if( UserEntity->behaviour() == MBEHAV::RANGE_ATTACK ) { //UserEntity->disengage(); } }