/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. */ #include "hpl1/penumbra-overture/PlayerState_Interact.h" #include "hpl1/engine/engine.h" #include "hpl1/penumbra-overture/GameStickArea.h" #include "hpl1/penumbra-overture/Init.h" #include "hpl1/penumbra-overture/MapHandler.h" #include "hpl1/penumbra-overture/Player.h" ////////////////////////////////////////////////////////////////////////// // GRAB STATE ////////////////////////////////////////////////////////////////////////// float cPlayerState_Grab::mfMassDiv = 5.0f; cPlayerState_Grab::cPlayerState_Grab(cInit *apInit, cPlayer *apPlayer) : iPlayerState(apInit, apPlayer, ePlayerState_Grab) { mpPushBody = NULL; // Init controllers mGrabPid.SetErrorNum(20); mRotatePid.SetErrorNum(20); mRotatePid.p = 0.8f; mRotatePid.i = 0.0f; mRotatePid.d = 0.0f; // Get variables mfMaxPidForce = mpInit->mpGameConfig->GetFloat("Interaction_Grab", "MaxPidForce", 0); mfMinThrowMass = mpInit->mpGameConfig->GetFloat("Interaction_Grab", "MinThrowMass", 0); mfMaxThrowMass = mpInit->mpGameConfig->GetFloat("Interaction_Grab", "MaxThrowMass", 0); mfMinThrowImpulse = mpInit->mpGameConfig->GetFloat("Interaction_Grab", "MinThrowImpulse", 0); mfMaxThrowImpulse = mpInit->mpGameConfig->GetFloat("Interaction_Grab", "MaxThrowImpulse", 0); // Get font mpFont = mpInit->mpGame->GetResources()->GetFontManager()->CreateFontData("verdana.fnt"); } //----------------------------------------------------------------------- void cPlayerState_Grab::OnUpdate(float afTimeStep) { cCamera3D *pCamera = mpPlayer->GetCamera(); iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); cInput *pInput = mpInit->mpGame->GetInput(); // cVector3f vToCharDir = if (pInput->IsTriggerd("WheelUp")) { if (mfGrabDist < mpPlayer->mfCurrentMaxInteractDist * 0.8f) mfGrabDist += 0.1f; } if (pInput->IsTriggerd("WheelDown")) { if (mfGrabDist > mpPlayer->GetSize().x / 2.0f + 0.25f) { // TODO: Collison check? (might be a bit complex) mfGrabDist -= 0.1f; } } /////////////////////////////////// // Get the current position. float fAngleDist = cMath::GetAngleDistanceRad(mfStartYaw, mpPlayer->GetCamera()->GetYaw()); // Det the desired position cVector3f vCurrentPoint; if (mbPickAtPoint) { vCurrentPoint = cMath::MatrixMul(mpPushBody->GetLocalMatrix(), mvRelPickPoint); } else { vCurrentPoint = cMath::MatrixMul(cMath::MatrixRotateY(fAngleDist), mvRelPickPoint); vCurrentPoint = cMath::MatrixMul(mpPushBody->GetWorldMatrix(), mpPushBody->GetMassCentre()) + vCurrentPoint; } ////////////////////////////////////// // Check if player is close enough cVector3f vEnd = vCurrentPoint; cVector3f vStart = mpPlayer->GetCamera()->GetPosition(); float fDistance = cMath::Vector3Dist(vStart, vEnd); if (fDistance > mpPlayer->mfCurrentMaxInteractDist * 1.4f) { mpPlayer->ChangeState(mPrevState); return; } ////////////////////////////////////// // Move the object into position. // Setup PID if (mbPickAtPoint) { mGrabPid.p = 80.0f; mGrabPid.i = 0.0f; mGrabPid.d = 8.0f; } else { mGrabPid.p = 180.0f; mGrabPid.i = 0.0f; mGrabPid.d = 40.0f; } /////////////////////////////////////// // Get the desired position cVector3f vForward = pCamera->UnProject(mpPlayer->GetCrossHairPos(), mpInit->mpGame->GetGraphics()->GetLowLevel()); cVector3f vDesired = pCamera->GetPosition() + vForward * mfGrabDist; /////////////////////////////////////// // Calculate the force to add. cVector3f vForce(0, 0, 0); // Remove gravity if (mpPushBody->GetGravity()) vForce = pPhysicsWorld->GetGravity() * -1.0f; // get force from PID vForce += mGrabPid.Output(vDesired - vCurrentPoint, afTimeStep); float fForceSize = vForce.Length(); if (fForceSize > mfMaxPidForce) { vForce = (vForce / fForceSize) * mfMaxPidForce; } if (mbPickAtPoint) { // mpPushBody->AddForceAtPosition(vForce * mpPushBody->GetMass()*mpPlayer->mfGrabMassMul, vCurrentPoint); // TODO: User intertia instead. cVector3f vLocalPos = vCurrentPoint - mpPushBody->GetLocalPosition(); cVector3f vMassCentre = mpPushBody->GetMassCentre(); vMassCentre = cMath::MatrixMul(mpPushBody->GetLocalMatrix().GetRotation(), vMassCentre); vLocalPos -= vMassCentre; mpPushBody->AddForce(vForce * mpPushBody->GetMass() * mpPlayer->mfGrabMassMul); cVector3f vTorque = cMath::Vector3Cross(vLocalPos, vForce); vTorque = cMath::MatrixMul(mpPushBody->GetInertiaMatrix(), vTorque); mpPushBody->AddTorque(vTorque); } else { mpPushBody->AddForce(vForce * mpPushBody->GetMass() * mpPlayer->mfGrabMassMul); } //////////////////////////// // The rotation cVector3f vOmega = mpPushBody->GetAngularVelocity(); // Set speed to 0 if (ABS(mfYRotation) < 0.001f || mbRotateWithPlayer == false) { cVector3f vTorque = mRotatePid.Output(cVector3f(0, 0, 0) - vOmega, afTimeStep); vTorque = vTorque / 5.0f; mpPushBody->AddTorque(vTorque * powf(mpPushBody->GetMass(), 1.8f)); // vTorque = cMath::MatrixMul(mpPushBody->GetInertiaMatrix(),vTorque); // mpPushBody->AddTorque(vTorque); } else { float fWantedSpeed = mfYRotation * 6; cVector3f vTorque = mRotatePid.Output(cVector3f(0, fWantedSpeed, 0) - vOmega, afTimeStep); vTorque = vTorque / 5.0f; mpPushBody->AddTorque(vTorque * powf(mpPushBody->GetMass(), 1.8f)); // vTorque = cMath::MatrixMul(mpPushBody->GetInertiaMatrix(),vTorque); // mpPushBody->AddTorque(vTorque); mfYRotation -= vOmega.y * afTimeStep; } // the above magic numbers 1.8f and 5.0f are a result of changes in the physics library. // All credits for discovery and testing go to https://github.com/zenmumbler } //----------------------------------------------------------------------- void cPlayerState_Grab::OnDraw() { // mpFont->Draw(cVector3f(5,30,0),12,cColor(1,1),eFontAlign_Left,"YRotate: %f",mfYRotation); } //----------------------------------------------------------------------- void cPlayerState_Grab::OnPostSceneDraw() { /*iLowLevelGraphics *pLowGfx = */ mpInit->mpGame->GetGraphics()->GetLowLevel(); /*cVector3f vPickPoint = */ cMath::MatrixMul(mpPushBody->GetWorldMatrix(), mvRelPickPoint); // pLowGfx->DrawSphere(vPickPoint, 0.2f, cColor(1,1,1,1)); // pLowGfx->DrawSphere(mvCurrentDisered, 0.2f, cColor(1,1,1,1)); } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnJump() { return true; } //----------------------------------------------------------------------- void cPlayerState_Grab::OnStartInteractMode() { mbMoveHand = !mbMoveHand; if (mbMoveHand) { mPrevState = ePlayerState_InteractMode; } else { mPrevState = ePlayerState_Normal; mpPlayer->ResetCrossHairPos(); } } //----------------------------------------------------------------------- void cPlayerState_Grab::OnStartInteract() { } void cPlayerState_Grab::OnStopInteract() { mpPlayer->ChangeState(mPrevState); } //----------------------------------------------------------------------- void cPlayerState_Grab::OnStartExamine() { mpPlayer->ChangeState(mPrevState); if (mpPlayer->mbCanBeThrown == false) return; // Reset linear and angular speed. mpPushBody->SetLinearVelocity(0); mpPushBody->SetAngularVelocity(0); // Get the forward vector cVector3f vForward = mpPlayer->GetCamera()->UnProject(mpPlayer->GetCrossHairPos(), mpInit->mpGame->GetGraphics()->GetLowLevel()); // Get the point which you hare grabbing at. cVector3f vPickPoint = cMath::MatrixMul(mpPushBody->GetLocalMatrix(), mvRelPickPoint); // Calculate the impulse float fT = 0; float fMass = mpPushBody->GetMass(); if (fMass <= mfMinThrowMass) fT = 1; else if (fMass >= mfMaxThrowMass) fT = 0; else fT = 1 - (fMass - mfMinThrowMass) / (mfMaxThrowMass - mfMinThrowMass); float fImpulse = mfMinThrowImpulse * (1 - fT) + mfMaxThrowImpulse * fT; // Log("Mass: %f Impulse: %f\n",fMass,fImpulse); // Add the impulse if (mbPickAtPoint) { mpPushBody->AddImpulseAtPosition(vForward * fImpulse, vPickPoint); } else { mpPushBody->AddImpulse(vForward * fImpulse); } } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnAddYaw(float afVal) { afVal *= mfSpeedMul * 0.75f; if (mbMoveHand) { if (mpPlayer->AddCrossHairPos(cVector2f(afVal * 800.0f, 0))) { mpPlayer->GetCamera()->AddYaw(-afVal * mpPlayer->GetLookSpeed()); mpPlayer->GetCharacterBody()->SetYaw(mpPlayer->GetCamera()->GetYaw()); mfYRotation += -afVal * mpPlayer->GetLookSpeed(); } return false; } else { mpPlayer->GetCamera()->AddYaw(-afVal * mpPlayer->GetLookSpeed()); mpPlayer->GetCharacterBody()->SetYaw(mpPlayer->GetCamera()->GetYaw()); mfYRotation += -afVal * mpPlayer->GetLookSpeed(); return false; } } bool cPlayerState_Grab::OnAddPitch(float afVal) { float fInvert = 1; if (mpInit->mpButtonHandler->GetInvertMouseY()) fInvert = -1; afVal *= mfSpeedMul * 0.75f; if (mbMoveHand) { if (mpPlayer->AddCrossHairPos(cVector2f(0, afVal * 600.0f))) { mpPlayer->GetCamera()->AddPitch(-afVal * mpPlayer->GetLookSpeed()); } return false; } else { mpPlayer->GetCamera()->AddPitch(-afVal * fInvert * mpPlayer->GetLookSpeed()); return false; } } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnMoveForwards(float afMul, float afTimeStep) { return true; } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnMoveSideways(float afMul, float afTimeStep) { return true; } //----------------------------------------------------------------------- void cPlayerState_Grab::EnterState(iPlayerState *apPrevState) { // Detach the body if stuck to a sticky area cGameStickArea *pStickArea = mpInit->mpMapHandler->GetBodyStickArea(mpPlayer->GetPushBody()); if (pStickArea) { if (pStickArea->GetCanDeatch()) { pStickArea->DetachBody(); } else { mpPlayer->ChangeState(apPrevState->mType); return; } } cCamera3D *pCamera = mpPlayer->GetCamera(); // Make sure the player is not running if (mpPlayer->GetMoveState() == ePlayerMoveState_Run || mPrevMoveState == ePlayerMoveState_Jump) mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); // Get last state, if this is a message use the last previous state instead. if (apPrevState->mType != ePlayerState_Message) mPrevState = apPrevState->mType; mbPickAtPoint = mpPlayer->mbPickAtPoint; mbRotateWithPlayer = mpPlayer->mbRotateWithPlayer; if (mPrevState == ePlayerState_InteractMode) mbMoveHand = true; else mbMoveHand = false; // Get the body to push mpPushBody = mpPlayer->GetPushBody(); mbHasGravity = mpPushBody->GetGravity(); if (mbPickAtPoint == false) mpPushBody->SetGravity(false); mpPushBody->SetAutoDisable(false); mbHasPlayerGravityPush = mpPushBody->GetPushedByCharacterGravity(); mpPushBody->SetPushedByCharacterGravity(true); // Set a newer player mass mpPlayer->SetMass(mpPlayer->GetMass() + mpPushBody->GetMass()); // Lower the mass while holding mfDefaultMass = mpPushBody->GetMass(); mpPushBody->SetMass(mpPushBody->GetMass() / mfMassDiv); // Set the player speed mul float fMass = mpPushBody->GetMass(); mfSpeedMul = 1; if (fMass > 3) { float fMul = 1 - ((fMass - 3.0f) / 37.0f) * 0.34f; fMul = cMath::Min(fMul, 0.66f); mfSpeedMul = fMul; } mpPlayer->SetSpeedMul(mfSpeedMul); // If we want to use the normal mass, reset the division if (mpPlayer->mbUseNormalMass) mpPushBody->SetMass(mfDefaultMass); // Get the orientation of the body cMatrixf mtxInvModel = cMath::MatrixInverse(mpPushBody->GetLocalMatrix()); mvObjectUp = mtxInvModel.GetUp(); mvObjectRight = mtxInvModel.GetRight(); mfGrabDist = cMath::Vector3Dist(mpPlayer->GetCamera()->GetPosition(), mpPlayer->GetPickedPos()); // mfGrabDist = mpPlayer->GetPickedDist(); // reset PID controller mGrabPid.Reset(); // The pick point relative to the body if (mbPickAtPoint) mvRelPickPoint = cMath::MatrixMul(mtxInvModel, mpPlayer->GetPickedPos()); else mvRelPickPoint = mpPlayer->GetPickedPos() - cMath::MatrixMul(mpPushBody->GetWorldMatrix(), mpPushBody->GetMassCentre()); // Set cross hair image. mpPlayer->SetCrossHairState(eCrossHairState_Grab); // The amount of rotation we wanna apply to the object, increases/decrease // when the player turn left/right mfYRotation = 0; // Reset pid controllers mRotatePid.Reset(); mGrabPid.Reset(); mfStartYaw = pCamera->GetYaw(); } //----------------------------------------------------------------------- void cPlayerState_Grab::LeaveState(iPlayerState *apNextState) { mpPushBody->SetPushedByCharacterGravity(mbHasPlayerGravityPush); mpPushBody->SetGravity(mbHasGravity); mpPushBody->SetActive(true); mpPushBody->SetAutoDisable(true); mpPushBody->AddForce(cVector3f(0, 1, 0) * mpPushBody->GetMass()); if (mpPlayer->mbUseNormalMass == false) mpPushBody->SetMass(mfDefaultMass); // Reset newer player mass mpPlayer->SetMass(mpPlayer->GetDefaultMass()); mpPlayer->SetSpeedMul(1.0f); } //----------------------------------------------------------------------- void cPlayerState_Grab::OnStartCrouch() { if (mpPlayer->GetMoveState() == ePlayerMoveState_Jump) return; if (mpInit->mpButtonHandler->GetToggleCrouch()) { if (mpPlayer->GetMoveState() == ePlayerMoveState_Crouch) mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); else mpPlayer->ChangeMoveState(ePlayerMoveState_Crouch); } else { mpPlayer->ChangeMoveState(ePlayerMoveState_Crouch); } } void cPlayerState_Grab::OnStopCrouch() { if (mpPlayer->GetMoveState() == ePlayerMoveState_Crouch && mpInit->mpButtonHandler->GetToggleCrouch() == false) { mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); } } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnStartInventory() { return false; } //----------------------------------------------------------------------- bool cPlayerState_Grab::OnStartInventoryShortCut(int alNum) { return false; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // MOVE STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerState_Move_BodyCallback::cPlayerState_Move_BodyCallback(cPlayer *apPlayer, float afTimeStep) { mpPlayer = apPlayer; mfTimeStep = afTimeStep; mlBackCount = 0; } bool cPlayerState_Move_BodyCallback::OnBeginCollision(iPhysicsBody *apBody, iPhysicsBody *apCollideBody) { return true; } void cPlayerState_Move_BodyCallback::OnCollide(iPhysicsBody *apBody, iPhysicsBody *apCollideBody, cPhysicsContactData *apContactData) { if (mpPlayer->GetCharacterBody()->GetBody() == apCollideBody) { mlBackCount = 5; } } //----------------------------------------------------------------------- cPlayerState_Move::cPlayerState_Move(cInit *apInit, cPlayer *apPlayer) : iPlayerState(apInit, apPlayer, ePlayerState_Move) { mpPushBody = NULL; mpCallback = hplNew(cPlayerState_Move_BodyCallback, (apPlayer, apInit->mpGame->GetStepSize())); } cPlayerState_Move::~cPlayerState_Move() { hplDelete(mpCallback); } //----------------------------------------------------------------------- void cPlayerState_Move::OnUpdate(float afTimeStep) { ////////////////////////////////////// // Check if the player is supposed to back if (mpCallback->mlBackCount > 0) { mpCallback->mlBackCount--; mpPlayer->GetCharacterBody()->Move(eCharDir_Forward, -1, afTimeStep); } ////////////////////////////////////// // Calculate the pick position mvPickPoint = cMath::MatrixMul(mpPushBody->GetLocalMatrix(), mvRelPickPoint); ////////////////////////////////////// // Check if player is close enough cVector3f vEnd = mvPickPoint; cVector3f vStart = mpPlayer->GetCamera()->GetPosition(); float fDistance = cMath::Vector3Dist(vStart, vEnd); if (fDistance > mpPlayer->mfCurrentMaxInteractDist * 1.7f) { // Log("Out of here %f!\n",mpPlayer->mfCurrentMaxInteractDist); mpPlayer->ChangeState(mPrevState); return; } ///////////////////////////////////////// // Check if the body should be stopped if (mlMoveCount <= 0) { mpPushBody->SetAngularVelocity(0); mpPushBody->SetLinearVelocity(0); } /////////////////////////////////////////////////////////////////////// // Project the position of the pick point and set is as crosshair pos cVector3f vProjPos = cMath::MatrixMul(mpPlayer->GetCamera()->GetViewMatrix(), mvPickPoint); vProjPos = cMath::MatrixMulDivideW(mpPlayer->GetCamera()->GetProjectionMatrix(), vProjPos); mpPlayer->SetCrossHairPos(cVector2f((vProjPos.x + 1) * 0.5f * 800.0f, ((-vProjPos.y) + 1) * 0.5f * 600.0f)); ///////////////////////////////////////////////// // Check if the camera should be turned cVector2f vCrossPos = mpPlayer->GetCrossHairPos(); cVector2f vBorder = mpPlayer->GetInteractMoveBorder(); if (vCrossPos.x < vBorder.x) mpPlayer->GetCamera()->AddYaw((vBorder.x - vCrossPos.x) / 800 * mpPlayer->GetLookSpeed()); if (vCrossPos.x > (799 - vBorder.x)) mpPlayer->GetCamera()->AddYaw(-(vCrossPos.x - (799 - vBorder.x)) / 800 * mpPlayer->GetLookSpeed()); mpPlayer->GetCharacterBody()->SetYaw(mpPlayer->GetCamera()->GetYaw()); if (vCrossPos.y < vBorder.y) mpPlayer->GetCamera()->AddPitch((vBorder.y - vCrossPos.y) / 600 * mpPlayer->GetLookSpeed()); if (vCrossPos.y > (599 - vBorder.y)) mpPlayer->GetCamera()->AddPitch(-(vCrossPos.y - (599 - vBorder.y)) / 600 * mpPlayer->GetLookSpeed()); } //----------------------------------------------------------------------- void cPlayerState_Move::OnStartInteract() { // mpPlayer->ChangeState(ePlayerState_Normal); } void cPlayerState_Move::OnStopInteract() { mpPlayer->ChangeState(mPrevState); } //----------------------------------------------------------------------- bool cPlayerState_Move::OnJump() { return false; } //----------------------------------------------------------------------- void cPlayerState_Move::OnStartExamine() { if (mpPlayer->mbCanBeThrown) { cVector3f vForward = mpPlayer->GetCamera()->UnProject(mpPlayer->GetCrossHairPos(), mpInit->mpGame->GetGraphics()->GetLowLevel()); float fMassMul = mpPushBody->GetMass(); if (fMassMul > 3) fMassMul = 3; mpPushBody->AddForce(vForward * 500 * fMassMul); } mpPlayer->ChangeState(mPrevState); } //----------------------------------------------------------------------- bool cPlayerState_Move::OnMoveForwards(float afMul, float afTimeStep) { cVector3f vForce = (mvForward * (afMul * 4.0f)); mpPushBody->AddForceAtPosition(vForce, mvPickPoint); mlMoveCount = 20; return true; } //----------------------------------------------------------------------- bool cPlayerState_Move::OnMoveSideways(float afMul, float afTimeStep) { cVector3f vForce = (mvRight * (afMul * 4.0f)); mpPushBody->AddForceAtPosition(vForce, mvPickPoint); mlMoveCount = 20; return true; } //----------------------------------------------------------------------- bool cPlayerState_Move::OnAddYaw(float afVal) { if (ABS(afVal) > kEpsilonf) { cVector3f vForce = (mvRight * (afVal * 100.0f * mpPlayer->mfRightMul)); mpPushBody->AddForceAtPosition(vForce, mvPickPoint); mlMoveCount = 20; } else { if (mlMoveCount > 0) mlMoveCount--; } return false; } //----------------------------------------------------------------------- bool cPlayerState_Move::OnAddPitch(float afVal) { if (ABS(afVal) > kEpsilonf) { cVector3f vForce = (mvUp * (-afVal * 100.0f * mpPlayer->mfUpMul)) + (mvForward * (afVal * -80.0f * mpPlayer->mfForwardUpMul)); mpPushBody->AddForceAtPosition(vForce, mvPickPoint); mlMoveCount = 20; } else { if (mlMoveCount > 0) mlMoveCount--; } return false; } //----------------------------------------------------------------------- void cPlayerState_Move::EnterState(iPlayerState *apPrevState) { // Detach the body if stuck to a sticky area cGameStickArea *pStickArea = mpInit->mpMapHandler->GetBodyStickArea(mpPlayer->GetPushBody()); if (pStickArea && pStickArea->GetCanDeatch()) { if (pStickArea->GetCanDeatch()) { pStickArea->DetachBody(); } else { mpPlayer->ChangeState(apPrevState->mType); return; } } cCamera3D *pCamera = mpPlayer->GetCamera(); // Change move state so the player is still mPrevMoveState = mpPlayer->GetMoveState(); // mpPlayer->ChangeMoveState(ePlayerMoveState_Still); mpPlayer->SetSpeedMul(0.3f); mpPlayer->SetHeadMoveSizeMul(0.2f); mpPlayer->SetHeadMoveSpeedMul(0.2f); // Get last state, if this is a message use the last previous state instead. if (apPrevState->mType != ePlayerState_Message) mPrevState = apPrevState->mType; // Set the directions to move the body in mvForward = pCamera->GetForward(); mvRight = pCamera->GetRight(); mvUp = pCamera->GetUp(); // make forward non y dependant mvForward.y = 0; mvForward.Normalise(); // Get the body to push mpPushBody = mpPlayer->GetPushBody(); mpPushBody->SetAutoDisable(false); // The pick point relative to the body mvPickPoint = mpPlayer->GetPickedPos(); ///////////////////////////////////////// // Check if all controllers should be paused. iGameEntity *pEntity = (iGameEntity *)mpPushBody->GetUserData(); if (pEntity->GetPauseControllers()) { for (int i = 0; i < mpPushBody->GetJointNum(); ++i) { mpPushBody->GetJoint(i)->SetAllControllersPaused(true); } } ///////////////////////////////////////// // Check if gravtty should be paused. if (mpPushBody->GetGravity() && pEntity->GetPauseGravity()) { mpPushBody->SetGravity(false); bPausedGravity = true; } else { bPausedGravity = false; } cMatrixf mtxInvModel = cMath::MatrixInverse(mpPushBody->GetLocalMatrix()); mvRelPickPoint = cMath::MatrixMul(mtxInvModel, mvPickPoint); // Set cross hair image. mpPlayer->SetCrossHairState(eCrossHairState_Grab); // Add callback to body if needed /*if(mpPushBody->GetCollideCharacter()) { mpPushBody->AddBodyCallback(mpCallback); }*/ mpCallback->mlBackCount = 0; mlMoveCount = 0; } //----------------------------------------------------------------------- void cPlayerState_Move::LeaveState(iPlayerState *apNextState) { // Remove callback to body if needed /*if(mpPushBody->GetCollideCharacter()) { mpPushBody->RemoveBodyCallback(mpCallback); }*/ //////////////////////////// // Pause controllers iGameEntity *pObject = (iGameEntity *)mpPushBody->GetUserData(); if (pObject->GetPauseControllers()) { for (int i = 0; i < mpPushBody->GetJointNum(); ++i) { mpPushBody->GetJoint(i)->SetAllControllersPaused(false); } } //////////////////////////// // Pause gravity if (bPausedGravity) { mpPushBody->SetGravity(true); } mpPushBody->SetAutoDisable(true); if (mPrevMoveState != ePlayerMoveState_Run && mPrevMoveState != ePlayerMoveState_Jump) mpPlayer->ChangeMoveState(mPrevMoveState); else mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); mpPlayer->SetSpeedMul(1.0f); mpPlayer->SetHeadMoveSizeMul(1.0f); mpPlayer->SetHeadMoveSpeedMul(1.0f); if (mPrevState == ePlayerState_Normal) mpPlayer->ResetCrossHairPos(); } //----------------------------------------------------------------------- void cPlayerState_Move::OnPostSceneDraw() { // mpInit->mpGame->GetGraphics()->GetLowLevel()->DrawSphere(mvPickPoint,0.1f,cColor(1,1,1,1)); } //----------------------------------------------------------------------- bool cPlayerState_Move::OnStartInventory() { return false; } //----------------------------------------------------------------------- bool cPlayerState_Move::OnStartInventoryShortCut(int alNum) { return false; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUSH STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerState_Push::cPlayerState_Push(cInit *apInit, cPlayer *apPlayer) : iPlayerState(apInit, apPlayer, ePlayerState_Push) { mpPushBody = NULL; } //----------------------------------------------------------------------- void cPlayerState_Push::OnUpdate(float afTimeStep) { ////////////////////////////////////// // Check if player is close enough cVector3f vEnd = mpPushBody->GetLocalPosition() + mvRelPickPoint; cVector3f vStart = mpPlayer->GetCamera()->GetPosition(); float fDistance = cMath::Vector3Dist(vStart, vEnd); if (fDistance > mpPlayer->mfCurrentMaxInteractDist * 1.2f) { mpPlayer->ChangeState(mPrevState); return; } ////////////////////////////////////// // Update player movement cVector3f vPosAdd = mpPushBody->GetLocalPosition() - mvLastBodyPos; // No need for the y value. vPosAdd.y = 0; iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); cVector3f vPlayerPos = mpPlayer->GetCharacterBody()->GetPosition() + vPosAdd; // mpPlayer->GetCharacterBody()->SetPosition(vPlayerPos,true); // Not really needed. character body should fix. cVector3f vNewPos = vPlayerPos; iPhysicsBody *pBody = mpPlayer->GetCharacterBody()->GetBody(); pPhysicsWorld->CheckShapeWorldCollision(&vNewPos, pBody->GetShape(), cMath::MatrixTranslate(vPlayerPos), pBody, false, true, NULL, true); mpPlayer->GetCharacterBody()->SetPosition(vNewPos, true); mvLastBodyPos = mpPushBody->GetLocalPosition(); } //----------------------------------------------------------------------- bool cPlayerState_Push::OnJump() { return false; } //----------------------------------------------------------------------- void cPlayerState_Push::OnStartInteract() { // mpPlayer->ChangeState(mPrevState); } void cPlayerState_Push::OnStopInteract() { mpPlayer->ChangeState(mPrevState); } //----------------------------------------------------------------------- void cPlayerState_Push::OnStartExamine() { mpPlayer->ChangeState(mPrevState); if (mpPlayer->mbCanBeThrown) { float fMassMul = mpPushBody->GetMass(); if (fMassMul > 40) fMassMul = 40; mpPushBody->AddForce(mvForward * 233 * fMassMul); } } //----------------------------------------------------------------------- bool cPlayerState_Push::OnMoveForwards(float afMul, float afTimeStep) { if (afMul < 0) { if (mpPlayer->mbCanBePulled == false) return false; afMul *= 0.7f; } float fSpeed = mpPushBody->GetLinearVelocity().Length(); /////////////////////////////////// // Set the direction and if it is newer add extra force if (afMul > 0) { if (mlForward != 1 && fSpeed < 0.01f) afMul *= 0.6f * mpPushBody->GetMass(); mlForward = 1; } else if (afMul < 0) { // If player is to close, push him back. if (mlForward != -1) { float fPosAdd = (mfMaxSpeed)*afTimeStep; iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); iCharacterBody *pPlayerBody = mpPlayer->GetCharacterBody(); cMatrixf mtxBodyMove = mpPushBody->GetLocalMatrix(); mtxBodyMove.SetTranslation(mtxBodyMove.GetTranslation() + (mvForward * -1 * fPosAdd)); cCollideData collData; collData.SetMaxSize(32); bool bCollide = pPhysicsWorld->CheckShapeCollision( pPlayerBody->GetShape(), cMath::MatrixTranslate(pPlayerBody->GetPosition()), mpPushBody->GetShape(), mtxBodyMove, collData, 32); if (bCollide) { cVector3f vPos = mpPlayer->GetCharacterBody()->GetPosition(); // cVector3f vOldPos = vPos; // cVector3f vNewPos; vPos += mvForward * -1 * (fPosAdd + 0.1f); mpPlayer->GetCharacterBody()->SetPosition(vPos); // Not good since slopes does not work: /*pPhysicsWorld->CheckShapeWorldCollision(&vNewPos, pPlayerBody->GetShape(), cMath::MatrixTranslate(pPlayerBody->GetPosition()), mpPushBody,false,true,NULL,false); if(vNewPos.x != vPos.x || vNewPos.y != vPos.y) { mpPlayer->GetCharacterBody()->SetPosition(vOldPos); }*/ } } if (mlForward != -1 && fSpeed < 0.01f) afMul *= 1.2f * mpPushBody->GetMass(); mlForward = -1; } else { mlForward = 0; return false; } // Log("Mul: %f\n",afMul); ///////////////////////////////////// // If the velocity is not to high add force. if (fSpeed < mfMaxSpeed) { if (mpPlayer->mbPickAtPoint) { // NON WORKING ATM: /*cVector3f vForce = mvForward * afMul*100.0f*0.5f; cVector3f vPos = cMath::MatrixMul( mpPushBody->GetLocalMatrix(), mvLocalPickPoint); vPos.y = mpPushBody->GetLocalPosition().y; mpPushBody->AddForceAtPosition(vForce,vPos);*/ } else { cVector3f vForce = mvForward * afMul * 100.0f; //*0.5f; // mpPushBody->AddForceAtPosition(vForce,mpPushBody->GetLocalPosition() + mvRight*0.4f); // mpPushBody->AddForceAtPosition(vForce,mpPushBody->GetLocalPosition() + mvRight*-0.4f); mpPushBody->AddForce(vForce); } } // returning true calls move state as well. return true; } //----------------------------------------------------------------------- bool cPlayerState_Push::OnMoveSideways(float afMul, float afTimeStep) { cVector3f vVel = mpPushBody->GetLinearVelocity(); if (vVel.Length() < mfMaxSpeed) { // mpPushBody->AddForce(mvRight * afMul*100.0f); cVector3f vForce = mvRight * afMul * 100.0f; //*0.5f; // mpPushBody->AddForceAtPosition(vForce,mpPushBody->GetLocalPosition() + mvForward*0.4f); // mpPushBody->AddForceAtPosition(vForce,mpPushBody->GetLocalPosition() + mvForward*-0.4f); mpPushBody->AddForce(vForce); } // returning true calls move state as well. return true; } //----------------------------------------------------------------------- void cPlayerState_Push::EnterState(iPlayerState *apPrevState) { // Detach the body if stuck to a sticky area cGameStickArea *pStickArea = mpInit->mpMapHandler->GetBodyStickArea(mpPlayer->GetPushBody()); if (pStickArea && pStickArea->GetCanDeatch()) { if (pStickArea->GetCanDeatch()) { pStickArea->DetachBody(); } else { mpPlayer->ChangeState(apPrevState->mType); return; } } cCamera3D *pCamera = mpPlayer->GetCamera(); mfMaxSpeed = mpPlayer->GetMaxPushSpeed(); if (mpPlayer->GetMoveState() == ePlayerMoveState_Crouch) mfMaxSpeed *= 0.5f; // Change move state so the player is still mPrevMoveState = mpPlayer->GetMoveState(); mpPlayer->ChangeMoveState(ePlayerMoveState_Still); // Get last state, if this is a message use the last previous state instead. if (apPrevState->mType != ePlayerState_Message) mPrevState = apPrevState->mType; // Set the directions to move the body in mvForward = pCamera->GetForward(); mvForward.y = 0; mvForward.Normalise(); mvRight = pCamera->GetRight(); mvRight.y = 0; mvRight.Normalise(); // Get the body to push mpPushBody = mpPlayer->GetPushBody(); // All pushed bodies shall be affected by player gravity. mbHasPlayerGravityPush = mpPushBody->GetPushedByCharacterGravity(); mpPushBody->SetPushedByCharacterGravity(true); // The pick point relative to the body mvRelPickPoint = mpPlayer->GetPickedPos() - mpPushBody->GetLocalPosition(); // Set the last position. mvLastBodyPos = mpPushBody->GetLocalPosition(); // Set cross hair image. mpPlayer->SetCrossHairState(eCrossHairState_Grab); // Set newer yaw and pitch limits mvPrevPitchLimits = pCamera->GetPitchLimits(); cVector2f vMaxHeadLimits = mpPlayer->GetMaxPushHeadMovement(); cVector2f vMinHeadLimits = mpPlayer->GetMinPushHeadMovement(); float fXmax = pCamera->GetYaw() + vMaxHeadLimits.x; float fYmax = pCamera->GetPitch() + vMaxHeadLimits.y; float fXmin = pCamera->GetYaw() + vMinHeadLimits.x; float fYmin = pCamera->GetPitch() + vMinHeadLimits.y; pCamera->SetPitchLimits(cVector2f(fYmax, fYmin)); pCamera->SetYawLimits(cVector2f(fXmax, fXmin)); // Create a little effect when grabbing the body mpPushBody->SetAutoDisable(false); // mpPushBody->AddForce(cVector3f(0,-1,0) *60.0f *mpPushBody->GetMass()); // This is to check the last used direction mlForward = 0; mlSideways = 0; cMatrixf mtxInvWorld = cMath::MatrixInverse(mpPushBody->GetLocalMatrix()); mvLocalPickPoint = cMath::MatrixMul(mtxInvWorld, mpPlayer->GetPickedPos()); } //----------------------------------------------------------------------- void cPlayerState_Push::LeaveState(iPlayerState *apNextState) { mpPushBody->SetPushedByCharacterGravity(mbHasPlayerGravityPush); if (mPrevMoveState != ePlayerMoveState_Run && mPrevMoveState != ePlayerMoveState_Jump) mpPlayer->ChangeMoveState(mPrevMoveState); else mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); mpPlayer->GetCamera()->SetPitchLimits(mvPrevPitchLimits); mpPlayer->GetCamera()->SetYawLimits(cVector2f(0, 0)); // Create a little effect when letting go of the body mpPushBody->SetAutoDisable(true); // mpPushBody->AddForce(cVector3f(0,-1,0) *60.0f *mpPushBody->GetMass()); } //----------------------------------------------------------------------- void cPlayerState_Push::OnPostSceneDraw() { return; cVector3f vPos = cMath::MatrixMul(mpPushBody->GetLocalMatrix(), mvLocalPickPoint); mpInit->mpGame->GetGraphics()->GetLowLevel()->DrawSphere(vPos, 0.3f, cColor(1, 0, 1)); } //----------------------------------------------------------------------- bool cPlayerState_Push::OnStartInventory() { return false; } //----------------------------------------------------------------------- bool cPlayerState_Push::OnStartInventoryShortCut(int alNum) { return false; }