/* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. * * Penumbra Overture 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. * * Penumbra Overture 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 Penumbra Overture. If not, see . */ #ifndef GAME_PLAYER_MOVE_STATES_H #define GAME_PLAYER_MOVE_STATES_H class cPlayer; ////////////////////////////////////////////////////////////////////////// // BASE STATE ////////////////////////////////////////////////////////////////////////// iPlayerMoveState::iPlayerMoveState(cPlayer *apPlayer, cInit *apInit) { mpPlayer = apPlayer; mpInit = apInit; mpGameConfig = mpInit->mpGameConfig; mpHeadMove = mpPlayer->GetHeadMove(); //Speed setup mfForwardSpeed=3.0f; mfBackwardSpeed=1.5f; mfSidewaySpeed=2.0f; mfForwardAcc = 6.0f; mfForwardDeacc = 12.0f; mfSidewayAcc = 6.0f; mfSidewayDeacc = 12.0f; mbActive = false; //Head move setup mfMaxHeadMove = 0.05f; mfMinHeadMove = -0.06f; mfHeadMoveSpeed = 0.38f; mfHeadMoveBackSpeed = 0.23f; mfHeightAdd =0; mfHeightAddSpeed = 1.5f; mfSpeedMul = 1; //FootStep multiplier mfFootStepMul = 1.0f; msStepType = "walk"; } void iPlayerMoveState::SetupBody() { iCharacterBody* pCharBody = mpPlayer->GetCharacterBody(); float fMul = mpPlayer->GetSpeedMul() * mpPlayer->GetHealthSpeedMul(); pCharBody->SetMaxPositiveMoveSpeed(eCharDir_Forward,mfForwardSpeed * fMul); pCharBody->SetMaxNegativeMoveSpeed(eCharDir_Forward,-mfBackwardSpeed * fMul); pCharBody->SetMaxPositiveMoveSpeed(eCharDir_Right,mfSidewaySpeed * fMul); pCharBody->SetMaxNegativeMoveSpeed(eCharDir_Right,-mfSidewaySpeed * fMul); pCharBody->SetMoveAcc(eCharDir_Forward,mfForwardAcc); pCharBody->SetMoveDeacc(eCharDir_Forward,mfForwardDeacc); pCharBody->SetMoveAcc(eCharDir_Right,mfSidewayAcc); pCharBody->SetMoveDeacc(eCharDir_Right,mfSidewayDeacc); } void iPlayerMoveState::InitState(iPlayerMoveState* apPrevState) { if(apPrevState){ apPrevState->LeaveState(apPrevState); apPrevState->mbActive = false; } EnterState(apPrevState); //Set up body SetupBody(); mpHeadMove->mfMaxHeadMove = mfMaxHeadMove; mpHeadMove->mfMinHeadMove = mfMinHeadMove; mpHeadMove->mfHeadMoveSpeed = mfHeadMoveSpeed; mpHeadMove->mfHeadMoveBackSpeed = mfHeadMoveBackSpeed; mpHeadMove->mfFootStepMul = mfFootStepMul; } void iPlayerMoveState::Start() { if(mbActive==false) { mbActive = true; //Set up body iCharacterBody* pCharBody = mpPlayer->GetCharacterBody(); float fMul = mpPlayer->GetSpeedMul(); pCharBody->SetMaxPositiveMoveSpeed(eCharDir_Forward,mfForwardSpeed * fMul); pCharBody->SetMaxNegativeMoveSpeed(eCharDir_Forward,-mfBackwardSpeed * fMul); pCharBody->SetMaxPositiveMoveSpeed(eCharDir_Right,mfSidewaySpeed * fMul); pCharBody->SetMaxNegativeMoveSpeed(eCharDir_Right,-mfSidewaySpeed * fMul); pCharBody->SetMoveAcc(eCharDir_Forward,mfForwardAcc); pCharBody->SetMoveDeacc(eCharDir_Forward,mfForwardDeacc); pCharBody->SetMoveAcc(eCharDir_Right,mfSidewayAcc); pCharBody->SetMoveDeacc(eCharDir_Right,mfSidewayDeacc); mpHeadMove->mfMaxHeadMove = mfMaxHeadMove; mpHeadMove->mfMinHeadMove = mfMinHeadMove; mpHeadMove->mfHeadMoveSpeed = mfHeadMoveSpeed; mpHeadMove->mfHeadMoveBackSpeed = mfHeadMoveBackSpeed; mpHeadMove->mfFootStepMul = mfFootStepMul; mpHeadMove->Start(); } } void iPlayerMoveState::Stop() { mpHeadMove->Stop(); mbActive = false; } void iPlayerMoveState::Update(float afTimeStep) { //Update height add float fPlayerHeightAdd = mpPlayer->GetHeightAdd(); if(fPlayerHeightAdd < mfHeightAdd){ fPlayerHeightAdd+=mfHeightAddSpeed*afTimeStep; if(fPlayerHeightAdd > mfHeightAdd) fPlayerHeightAdd = mfHeightAdd; } if(fPlayerHeightAdd > mfHeightAdd){ fPlayerHeightAdd -= mfHeightAddSpeed*afTimeStep; if(fPlayerHeightAdd < mfHeightAdd) fPlayerHeightAdd = mfHeightAdd; } mpPlayer->SetHeightAdd(fPlayerHeightAdd); OnUpdate(afTimeStep); } ////////////////////////////////////////////////////////////////////////// // WALK STATE ////////////////////////////////////////////////////////////////////////// class cPlayerMoveState_Walk : public iPlayerMoveState { public: cPlayerMoveState_Walk(cPlayer *apPlayer, cInit *apInit) : iPlayerMoveState(apPlayer, apInit) { mfForwardSpeed = mpGameConfig->GetFloat("Movement_Walk","ForwardSpeed",0); mfBackwardSpeed= mpGameConfig->GetFloat("Movement_Walk","BackwardSpeed",0); mfSidewaySpeed = mpGameConfig->GetFloat("Movement_Walk","SidewaySpeed",0); mfForwardAcc = mpGameConfig->GetFloat("Movement_Walk","ForwardAcc",0); mfForwardDeacc = mpGameConfig->GetFloat("Movement_Walk","ForwardDeacc",0); mfSidewayAcc = mpGameConfig->GetFloat("Movement_Walk","SidewayAcc",0); mfSidewayDeacc = mpGameConfig->GetFloat("Movement_Walk","SidewayDeacc",0); //Head move setup mfMaxHeadMove = mpGameConfig->GetFloat("Movement_Walk","MaxHeadMove",0); mfMinHeadMove = mpGameConfig->GetFloat("Movement_Walk","MinHeadMove",0); mfHeadMoveSpeed =mpGameConfig->GetFloat("Movement_Walk","HeadMoveSpeed",0); mfHeadMoveBackSpeed = 0.23f; //FootStep multiplier mfFootStepMul = 1.0f; msStepType = "walk"; mType = ePlayerMoveState_Walk; } }; ////////////////////////////////////////////////////////////////////////// // RUN STATE ////////////////////////////////////////////////////////////////////////// class cPlayerMoveState_Run : public iPlayerMoveState { public: cPlayerMoveState_Run(cPlayer *apPlayer, cInit *apInit) : iPlayerMoveState(apPlayer, apInit) { mfForwardSpeed = mpGameConfig->GetFloat("Movement_Run","ForwardSpeed",0); mfBackwardSpeed= mpGameConfig->GetFloat("Movement_Run","BackwardSpeed",0); mfSidewaySpeed = mpGameConfig->GetFloat("Movement_Run","SidewaySpeed",0); mfForwardAcc = mpGameConfig->GetFloat("Movement_Run","ForwardAcc",0); mfForwardDeacc = mpGameConfig->GetFloat("Movement_Run","ForwardDeacc",0); mfSidewayAcc = mpGameConfig->GetFloat("Movement_Run","SidewayAcc",0); mfSidewayDeacc = mpGameConfig->GetFloat("Movement_Run","SidewayDeacc",0); //Head move setup mfMaxHeadMove = mpGameConfig->GetFloat("Movement_Run","MaxHeadMove",0); mfMinHeadMove = mpGameConfig->GetFloat("Movement_Run","MinHeadMove",0); mfHeadMoveSpeed =mpGameConfig->GetFloat("Movement_Run","HeadMoveSpeed",0); mfHeadMoveBackSpeed = 0.23f; //FootStep multiplier mfFootStepMul = 1.0f; msStepType = "run"; mType = ePlayerMoveState_Run; } }; ////////////////////////////////////////////////////////////////////////// // STILL STATE ////////////////////////////////////////////////////////////////////////// class cPlayerMoveState_Still : public iPlayerMoveState { public: cPlayerMoveState_Still(cPlayer *apPlayer, cInit *apInit) : iPlayerMoveState(apPlayer, apInit) { mfForwardSpeed=0.0f; mfBackwardSpeed=0.0f; mfSidewaySpeed=0.0f; mfForwardAcc = 0.0f; mfForwardDeacc = 6.0f; mfSidewayAcc = 0.0f; mfSidewayDeacc = 6.0f; //Head move setup mfMaxHeadMove = 0.03f; mfMinHeadMove = -0.03f; mfHeadMoveSpeed = 0.12f; mfHeadMoveBackSpeed = 0.23f; //FootStep multiplier mfFootStepMul = 0.6f; msStepType = "walk"; mType = ePlayerMoveState_Still; } void EnterState(iPlayerMoveState* apPrevState) { if(apPrevState) { mfHeightAdd = apPrevState->mfHeightAdd; mfHeightAddSpeed = apPrevState->mfHeightAddSpeed; } } }; ////////////////////////////////////////////////////////////////////////// // JUMP STATE ////////////////////////////////////////////////////////////////////////// class cPlayerMoveState_Jump : public iPlayerMoveState { public: bool mbFirstUpdate; float mfStartForce; float mfMaxForward; float mfMaxSide; float mfDefaultFowardSpeed; float mfDefaultSidewaySpeed; cPlayerMoveState_Jump(cPlayer *apPlayer, cInit *apInit) : iPlayerMoveState(apPlayer, apInit) { mfForwardSpeed = mpGameConfig->GetFloat("Movement_Jump","ForwardSpeed",0); mfDefaultFowardSpeed = mfForwardSpeed; mfBackwardSpeed= mpGameConfig->GetFloat("Movement_Jump","BackwardSpeed",0); mfSidewaySpeed = mpGameConfig->GetFloat("Movement_Jump","SidewaySpeed",0); mfDefaultSidewaySpeed = mfSidewaySpeed; mfForwardAcc = mpGameConfig->GetFloat("Movement_Jump","ForwardAcc",0); mfForwardDeacc = mpGameConfig->GetFloat("Movement_Jump","ForwardDeacc",0); mfSidewayAcc = mpGameConfig->GetFloat("Movement_Jump","SidewayAcc",0); mfSidewayDeacc = mpGameConfig->GetFloat("Movement_Jump","SidewayDeacc",0); //Head move setup mfMaxHeadMove = 0.00f; mfMinHeadMove = 0.00f; mfHeadMoveSpeed = 0.0f; mfHeadMoveBackSpeed = 0.33f; //mfHeightAdd =-0.3f; //mfHeightAddSpeed = 1.2f; //FootStep multiplier mfFootStepMul = 0.0f; msStepType = "run"; mfStartForce = mpInit->mpGameConfig->GetFloat("Player","JumpStartForce",1); mType = ePlayerMoveState_Jump; } void EnterState(iPlayerMoveState* apPrevState) { iCharacterBody *pBody = mpPlayer->GetCharacterBody(); if(apPrevState) mPrevMoveState = apPrevState->mType; else mPrevMoveState = ePlayerMoveState_Walk; float fForce = mfStartForce; if(mPrevMoveState==ePlayerMoveState_Crouch) { fForce *= 0.5f; mfForwardSpeed = mfDefaultFowardSpeed * 0.6f; mfSidewaySpeed = mfDefaultSidewaySpeed *0.6f; } else { mfForwardSpeed = mfDefaultFowardSpeed; mfSidewaySpeed = mfDefaultSidewaySpeed; } //Set the current move speed as force speed. cVector3f vVel = 0; cVector3f vForward = pBody->GetMoveMatrix().GetForward() *-1.0f; cVector3f vRight = pBody->GetMoveMatrix().GetRight(); vVel += vForward * pBody->GetMoveSpeed(eCharDir_Forward); vVel += vRight * pBody->GetMoveSpeed(eCharDir_Right); pBody->AddForceVelocity(vVel); pBody->SetMoveSpeed(eCharDir_Forward,0); pBody->SetMoveSpeed(eCharDir_Right,0); //Add jump force pBody->AddForce(cVector3f(0,fForce * mpPlayer->GetDefaultMass(),0)); mbFirstUpdate = true; //Get the maximum speed allowed. if(mPrevMoveState == ePlayerMoveState_Still || mPrevMoveState == ePlayerMoveState_Walk) { mfMaxForward = mpPlayer->GetMoveStateData(ePlayerMoveState_Walk)->mfForwardSpeed; mfMaxSide = mpPlayer->GetMoveStateData(ePlayerMoveState_Walk)->mfSidewaySpeed; } else { mfMaxForward = apPrevState->mfForwardSpeed; mfMaxSide = apPrevState->mfSidewaySpeed; } } void LeaveState(iPlayerMoveState* apNextState) { iCharacterBody *pBody = mpPlayer->GetCharacterBody(); pBody->AddForceVelocity(pBody->GetForceVelocity() * -0.7f); } void OnUpdate(float afTimeStep) { iCharacterBody *pBody = mpPlayer->GetCharacterBody(); if(mbFirstUpdate){ mbFirstUpdate = false; return; } //Check so that speed is correct cVector3f vForceVel = pBody->GetForceVelocity(); float fSpeed = vForceVel.Length(); if(fSpeed > mfMaxForward) { float fNeg = fSpeed - mfMaxForward; float fForwardSpeed = pBody->GetMoveSpeed(eCharDir_Forward); /*if(fForwardSpeed>0){ fForwardSpeed -= fNeg; if(fForwardSpeed<0)fForwardSpeed =0; } else { fForwardSpeed += fNeg; if(fForwardSpeed>0)fForwardSpeed =0; }*/ pBody->SetMoveSpeed(eCharDir_Forward,fForwardSpeed); } //Skip sideways here, it is sucha strange way to jump anyway. //Check if the jumpbutton is down. if( mpPlayer->GetJumpButtonDown() && mpPlayer->GetJumpCount() < mpPlayer->GetMaxJumpCount()) { float fMul = 0.4f + 0.5f * (1 - mpPlayer->GetJumpCount() / mpPlayer->GetMaxJumpCount()); pBody->AddForce(cVector3f(0,-pBody->GetCustomGravity().y * pBody->GetMass() * fMul,0)); } else if(pBody->GetForceVelocity().y >0) { //Add some extra gravity pBody->AddForce(cVector3f(0,-20.0f * pBody->GetMass(),0)); } //check if the body is on ground, and if so end jump. if(pBody->IsOnGround() && pBody->GetForceVelocity().y==0) { mpPlayer->ChangeMoveState(mPrevMoveState); } else if(mpPlayer->GetLandedFromJump()) { mpPlayer->SetLandedFromJump(false); mpPlayer->ChangeMoveState(mPrevMoveState); } } }; ////////////////////////////////////////////////////////////////////////// // CROUCH STATE ////////////////////////////////////////////////////////////////////////// class cPlayerMoveState_Crouch : public iPlayerMoveState { public: bool mbFirstUpdate; cPlayerMoveState_Crouch(cPlayer *apPlayer, cInit *apInit) : iPlayerMoveState(apPlayer,apInit) { mfForwardSpeed = mpGameConfig->GetFloat("Movement_Crouch","ForwardSpeed",0); mfBackwardSpeed= mpGameConfig->GetFloat("Movement_Crouch","BackwardSpeed",0); mfSidewaySpeed = mpGameConfig->GetFloat("Movement_Crouch","SidewaySpeed",0); mfForwardAcc = mpGameConfig->GetFloat("Movement_Crouch","ForwardAcc",0); mfForwardDeacc = mpGameConfig->GetFloat("Movement_Crouch","ForwardDeacc",0); mfSidewayAcc = mpGameConfig->GetFloat("Movement_Crouch","SidewayAcc",0); mfSidewayDeacc = mpGameConfig->GetFloat("Movement_Crouch","SidewayDeacc",0); //Head move setup mfMaxHeadMove = mpGameConfig->GetFloat("Movement_Crouch","MaxHeadMove",0); mfMinHeadMove = mpGameConfig->GetFloat("Movement_Crouch","MinHeadMove",0); mfHeadMoveSpeed =mpGameConfig->GetFloat("Movement_Crouch","HeadMoveSpeed",0); mfHeadMoveBackSpeed = 0.23f; mfHeightAdd = -(mpPlayer->GetSize().y - mpPlayer->GetCrouchHeight()); mfHeightAddSpeed = 1.8f; //FootStep multiplier mfFootStepMul = 1.0f; msStepType = "sneak"; mType = ePlayerMoveState_Crouch; } void EnterState(iPlayerMoveState* apPrevState) { iCharacterBody *pBody = mpPlayer->GetCharacterBody(); cVector3f vFeetPos = pBody->GetPosition() - cVector3f(0,pBody->GetShape()->GetSize().y/2,0); pBody->SetActiveSize(1); pBody->SetPosition(vFeetPos + cVector3f(0,pBody->GetShape()->GetSize().y/2,0)); //pBody->SetGravityActive(false); } void LeaveState(iPlayerMoveState* apNextState) { iCharacterBody *pBody = mpPlayer->GetCharacterBody(); cVector3f vFeetPos = pBody->GetPosition() - cVector3f(0,pBody->GetShape()->GetSize().y/2,0); pBody->SetActiveSize(0); pBody->SetPosition(vFeetPos + cVector3f(0,pBody->GetShape()->GetSize().y/2,0)); ///////////////////////////////////////////////// //Check if the player will fit with the newer size cInit *pInit = mpPlayer->GetInit(); iPhysicsWorld *pWorld = pInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); pBody->SetPosition(pBody->GetPosition() + cVector3f(0,0.005f,0)); //Check with both bodies. This removes some bugs. for(int i=0; i<2; ++i) { iCollideShape *pShape = pBody->GetExtraBody(i)->GetShape(); cVector3f vNewPos = pBody->GetPosition(); bool bCollide = pWorld->CheckShapeWorldCollision(&vNewPos,pShape, cMath::MatrixTranslate(pBody->GetPosition()), pBody->GetBody(),false,true); /*Log("Collide when leaving crouch: %d. NewPos: %s OldPos: %s\n",bCollide, vNewPos.ToString().c_str(), pBody->GetPosition().ToString().c_str());*/ //If the body is pushed down, then something is colliding from above. //if so, set crouch mode again. if(vNewPos != pBody->GetPosition()) { pBody->SetPosition(pBody->GetPosition() - cVector3f(0,0.005f,0)); mpPlayer->ChangeMoveState(ePlayerMoveState_Crouch); return; } } pBody->SetPosition(pBody->GetPosition() - cVector3f(0,0.005f,0)); } void OnUpdate(float afTimeStep) { } }; #endif // GAME_PLAYER_MOVE_STATES_H