/* * 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 . */ #include "GameEnemy_Dog.h" #include "Player.h" #include "AttackHandler.h" #include "EffectHandler.h" #include "GameMusicHandler.h" #include "GameSwingDoor.h" #include "MapHandler.h" ////////////////////////////////////////////////////////////////////////// // BASE STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- iGameEnemyState_Dog_Base::iGameEnemyState_Dog_Base(int alId, cInit *apInit, iGameEnemy *apEnemy) : iGameEnemyState(alId,apInit,apEnemy) { mpEnemyDog = static_cast(mpEnemy); } //----------------------------------------------------------------------- void iGameEnemyState_Dog_Base::OnSeePlayer(const cVector3f &avPosition, float afChance) { //return; if(mpPlayer->GetHealth() <=0) return; if(afChance >= mpEnemyDog->mfIdleMinSeeChance) { /*if( (mlId == STATE_IDLE || mlId == STATE_INVESTIGATE || mlId == STATE_PATROL) && cMath::RandRectf(0,1) < mpEnemyDog->mfIdleCallBackupChance && mpEnemy->CheckForTeamMate(8,true)==false) { mpEnemy->ChangeState(STATE_CALLBACKUP); } else { //mpEnemy->ChangeState(STATE_HUNT); //mpEnemyDog->PlaySound(mpEnemyDog->msIdleFoundPlayerSound); }*/ float fDist = cMath::Vector3Dist(mpMover->GetCharBody()->GetFeetPosition(), mpPlayer->GetCharacterBody()->GetFeetPosition()); if(fDist >= mpEnemyDog->mfAttentionMinDist) { mpEnemy->ChangeState(STATE_ATTENTION); } else { mpEnemy->ChangeState(STATE_HUNT); mpEnemyDog->PlaySound(mpEnemyDog->msIdleFoundPlayerSound); } } } bool iGameEnemyState_Dog_Base::OnHearNoise(const cVector3f &avPosition, float afVolume) { //return false; float afDistance = (mpMover->GetCharBody()->GetPosition() - avPosition).Length(); if(afVolume >= mpEnemyDog->mfIdleMinHearVolume && afDistance > 0.4f) { mpEnemy->SetTempPosition(avPosition); mpEnemy->ChangeState(STATE_INVESTIGATE); return true; } return false; } void iGameEnemyState_Dog_Base::OnTakeHit(float afDamage) { if(afDamage >= mpEnemyDog->mfMinKnockDamage) { if(mpInit->mbWeaponAttacking) { float fChance = afDamage / mpEnemyDog->mfCertainKnockDamage;//(mpEnemyDog->mfCertainKnockDamage*4); if(fChance > cMath::RandRectf(0,1)) { mpEnemy->ChangeState(STATE_KNOCKDOWN); } } else { if(afDamage >= mpEnemyDog->mfCertainKnockDamage) { mpEnemy->ChangeState(STATE_KNOCKDOWN); } else { float fChance = afDamage / mpEnemyDog->mfCertainKnockDamage; if(fChance > cMath::RandRectf(0,1)) { mpEnemy->ChangeState(STATE_KNOCKDOWN); } } } } } void iGameEnemyState_Dog_Base::OnFlashlight(const cVector3f &avPosition) { //mpInit->mpEffectHandler->GetSubTitle()->Add("Flashlight!",0.5f,true); //OnSeePlayer(mpPlayer->GetCharacterBody()->GetFeetPosition(),1.0f); //mpEnemy->SetLastPlayerPos(mpPlayer->GetCharacterBody()->GetFeetPosition()); //mpEnemy->ChangeState(STATE_HUNT); mpEnemy->SetTempPosition(avPosition); mpEnemy->ChangeState(STATE_INVESTIGATE); } void iGameEnemyState_Dog_Base::OnDeath(float afDamage) { mpEnemy->ChangeState(STATE_DEAD); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // IDLE STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Idle::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfIdleFOV); mpInit->mpMusicHandler->RemoveAttacker(mpEnemy); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Idle::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Idle::OnUpdate(float afTimeStep) { if(mpEnemy->GetPatrolNodeNum()>0) { mpEnemy->ChangeState(STATE_PATROL); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PATROL STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Patrol::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfIdleFOV); //Setup patrol cEnemyPatrolNode *pPatrolNode = mpEnemy->CurrentPatrolNode(); cAINode *pNode = mpMover->GetNodeContainer()->GetNodeFromName(pPatrolNode->msNodeName); if(mpEnemy->GetDoorBreakCount()> 3.0f) { mpEnemy->SetDoorBreakCount(0); mpMover->SetMaxDoorToughness(0); } mbWaiting = false; mbAnimation = false; mlStuckAtMaxCount =0; mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mpMover->SetMaxDoorToughness(-1); if(mpMover->MoveToPos(pNode->GetPosition())==false) { //tString sStr = "Could not get to path node "+pPatrolNode->msNodeName; //mpInit->mpEffectHandler->GetSubTitle()->Add(sStr,3,true); mpEnemy->IncCurrentPatrolNode(); mbWaiting = true; mpEnemy->SetWaitTime(1.0f); } else { //tString sStr = "Moving to path node "+pPatrolNode->msNodeName; //mpInit->mpEffectHandler->GetSubTitle()->Add(sStr,3,true); } mpInit->mpMusicHandler->RemoveAttacker(mpEnemy); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Patrol::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Patrol::OnUpdate(float afTimeStep) { ///////////////////////////////// //Waiting for timer or animation to end if(mbWaiting) { ////////////////////////////// //Play idle sound if(mfIdleSoundTime<=0) { mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mpEnemy->PlaySound(mpEnemyDog->msIdleSound); } else { mfIdleSoundTime -= afTimeStep; } ////////////////////////////// // Timer is up if(mpEnemy->GetWaitTimeCount() >= mpEnemy->GetWaitTime()) { if(mbAnimation==false) { mpEnemy->SetWaitTimeCount(0); cEnemyPatrolNode *pPatrolNode = mpEnemy->CurrentPatrolNode(); cAINode *pNode = mpMover->GetNodeContainer()->GetNodeFromName(pPatrolNode->msNodeName); mpEnemy->UseMoveStateAnimations(); mbWaiting = false; if(mpMover->MoveToPos(pNode->GetPosition())==false) { //tString sStr = "Could not get to path node "+pPatrolNode->msNodeName; //mpInit->mpEffectHandler->GetSubTitle()->Add(sStr,3,false); mpEnemy->IncCurrentPatrolNode(); mbWaiting = true; mpEnemy->SetWaitTime(1.0f); } else { //tString sStr = "Moving to path node "+pPatrolNode->msNodeName; //mpInit->mpEffectHandler->GetSubTitle()->Add(sStr,3,false); } } else { mpEnemy->GetCurrentAnimation()->SetLoop(false); } } else { mpEnemy->AddWaitTimeCount(afTimeStep); } } ///////////////////////////////// //Check if path is over else { ////////////////////////////// //Play idle sound if(mfIdleSoundTime<=0) { mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mpEnemy->PlaySound(mpEnemyDog->msIdleSound); } else { mfIdleSoundTime -= afTimeStep; } ////////////////////////////// //Stuck counter if(mpMover->GetStuckCounter() > 1.7f) { if(mpEnemy->CheckForDoor()) { mpEnemy->ChangeState(STATE_BREAKDOOR); } else { mlStuckAtMaxCount++; if(mlStuckAtMaxCount >= 6) { mpEnemy->ChangeState(STATE_IDLE); mpEnemy->SetWaitTime(1.0f); mpEnemy->IncCurrentPatrolNode(); } } mpMover->ResetStuckCounter(); } ////////////////////////////// //Got to ned of path if(mpMover->IsMoving()==false) { cEnemyPatrolNode *pPatrolNode = mpEnemy->CurrentPatrolNode(); mpEnemy->SetWaitTime(pPatrolNode->mfWaitTime); mpEnemy->IncCurrentPatrolNode(); if(pPatrolNode->msAnimation != "") { mpEnemy->PlayAnim(pPatrolNode->msAnimation,true,0.2f); mbAnimation = true; } mbWaiting = true; } } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Patrol::OnAnimationOver(const tString &asName) { mbAnimation = false; } ////////////////////////////////////////////////////////////////////////// // ATTENTION STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attention::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->PlayAnim("Angry",true,0.2f); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfIdleFOV); mpMover->Stop(); mpMover->TurnToPos(mpPlayer->GetCharacterBody()->GetFeetPosition()); mpEnemy->PlaySound(mpEnemyDog->msAttentionSound); mfTime = mpEnemyDog->mfAttentionTime; #ifndef DEMO_VERSION if(mpInit->mDifficulty == eGameDifficulty_Easy) mfTime *=1.7f; if(mpInit->mbHasHaptics) mfTime *= 1.3f; #endif } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attention::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attention::OnUpdate(float afTimeStep) { mpMover->TurnToPos(mpPlayer->GetCharacterBody()->GetFeetPosition()); mfTime -= afTimeStep; if(mfTime <=0) { if(mpEnemy->CanSeePlayer()) { mpEnemy->ChangeState(STATE_HUNT); mpEnemy->PlaySound(mpEnemyDog->msIdleFoundPlayerSound); } else { if(mlPreviousState == STATE_ATTENTION) mpEnemy->ChangeState(STATE_IDLE); else mpEnemy->ChangeState(mlPreviousState); } } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attention::OnSeePlayer(const cVector3f &avPosition, float afChance) { } bool cGameEnemyState_Dog_Attention::OnHearNoise(const cVector3f &avPosition, float afVolume) { return false; } void cGameEnemyState_Dog_Attention::OnFlashlight(const cVector3f &avPosition) { mpEnemy->ChangeState(STATE_HUNT); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attention::OnDraw() { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // EAT STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Eat::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->PlayAnim("Eating",true,0.2f); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfEatFOV); mfTime = mpEnemy->GetTempFloat(); mpMover->GetCharBody()->SetMoveSpeed(eCharDir_Forward,0); mpMover->Stop(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Eat::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Eat::OnUpdate(float afTimeStep) { mfTime -= afTimeStep; if(mfTime <=0) { mpEnemy->ChangeState(mlPreviousState);//STATE_IDLE); } } //----------------------------------------------------------------------- bool cGameEnemyState_Dog_Eat::OnHearNoise(const cVector3f &avPosition, float afVolume) { //return false; if( afVolume >= mpEnemyDog->mfEatMinHearVolume) { mpEnemy->SetTempPosition(avPosition); mpEnemy->ChangeState(STATE_INVESTIGATE); return true; } return false; } void cGameEnemyState_Dog_Eat::OnSeePlayer(const cVector3f &avPosition, float afChance) { //return; if(mpPlayer->GetHealth() <=0) return; if(afChance >= mpEnemyDog->mfEatMinSeeChance) { mpEnemy->ChangeState(STATE_HUNT); mpEnemyDog->PlaySound(mpEnemyDog->msIdleFoundPlayerSound); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // INVESTIGATE STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Investigate::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfIdleFOV); //Play sound mpEnemy->PlaySound(mpEnemyDog->msInvestigateSound); cAINode *pNode = mpMover->GetAINodeAtPosInRange(mpEnemy->GetTempPosition(),0.0f,5.0f,true, 0.1f); if(mpEnemy->GetDoorBreakCount()> 6.0f) { mpEnemy->SetDoorBreakCount(0); mpMover->SetMaxDoorToughness(0); } if(pNode) { if(mpMover->MoveToPos(pNode->GetPosition())==false) { mpEnemy->ChangeState(STATE_IDLE); } } else { mpEnemy->ChangeState(STATE_IDLE); } mpMover->SetMaxDoorToughness(-1); mpInit->mpMusicHandler->RemoveAttacker(mpEnemy); mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); if(apPrevState->GetId() != STATE_INVESTIGATE) { mfHighestVolume = 0.0f; } mfHearSoundCount = 5.0f; } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Investigate::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Investigate::OnUpdate(float afTimeStep) { if(mfHearSoundCount >0){ mfHearSoundCount-=afTimeStep; if(mfHearSoundCount<=0)mfHearSoundCount=0; } //////////////////////////////// //Play idle sound if(mfIdleSoundTime<=0) { mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mpEnemy->PlaySound(mpEnemyDog->msIdleSound); } else { mfIdleSoundTime -= afTimeStep; } //////////////////////////////// //Stuck counter if(mpMover->GetStuckCounter() > 1.5f) { if(mlKnockCount == 1){ mpEnemy->ChangeState(STATE_IDLE); mlKnockCount =0; } else { if(mpEnemy->CheckForDoor()) { mpEnemy->ChangeState(STATE_BREAKDOOR); } mpMover->ResetStuckCounter(); mlKnockCount++; } } if(mpMover->IsMoving()==false) { mlKnockCount =0; mpEnemy->ChangeState(STATE_IDLE); } } //----------------------------------------------------------------------- bool cGameEnemyState_Dog_Investigate::OnHearNoise(const cVector3f &avPosition, float afVolume) { if( mfHearSoundCount<=0 && mfHighestVolume < afVolume && afVolume >= mpEnemyDog->mfIdleMinHearVolume) { mfHighestVolume = afVolume; mpEnemy->SetTempPosition(avPosition); OnEnterState(this); return true; } return false; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // MOVE TO STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_MoveTo::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfIdleFOV); //Play sound mpEnemy->PlaySound(mpEnemyDog->msInvestigateSound); if(mpMover->MoveToPos(mpEnemy->GetTempPosition())==false) { //mpInit->mpEffectHandler->GetSubTitle()->Add("Could not move to pos!\n",3,true); mpEnemy->ChangeState(apPrevState->GetId()); return; } else { //mpInit->mpEffectHandler->GetSubTitle()->Add("Moving to pos!\n",3,true); } mpInit->mpMusicHandler->RemoveAttacker(mpEnemy); mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mlBreakCount = 0; } //----------------------------------------------------------------------- void cGameEnemyState_Dog_MoveTo::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_MoveTo::OnUpdate(float afTimeStep) { //////////////////////////////// //Play idle sound if(mfIdleSoundTime<=0) { mfIdleSoundTime = cMath::RandRectf( mpEnemyDog->mfIdleSoundMinInteraval, mpEnemyDog->mfIdleSoundMaxInteraval); mpEnemy->PlaySound(mpEnemyDog->msIdleSound); } else { mfIdleSoundTime -= afTimeStep; } //////////////////////////////// //Stuck counter if(mpMover->GetStuckCounter() > 1.5f) { if(mlBreakCount ==1) { mpEnemy->ChangeState(STATE_IDLE); } else { if(mpEnemy->CheckForDoor()) { mpEnemy->ChangeState(STATE_BREAKDOOR); } mpMover->ResetStuckCounter(); mlBreakCount++; } } if(mpMover->IsMoving()==false) { mpEnemy->ChangeState(STATE_IDLE); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // HUNT STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Hunt::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); #ifndef DEMO_VERSION float fMul = 1.0f; if(mpInit->mbHasHaptics) fMul = 0.6f; if(mpInit->mDifficulty == eGameDifficulty_Easy) mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfHuntSpeed*0.7f*fMul); else if(mpInit->mDifficulty == eGameDifficulty_Normal) mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfHuntSpeed*fMul); else mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfHuntSpeed*1.25f*fMul); #else mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfHuntSpeed); #endif //Setup enemy mpEnemy->SetFOV(mpEnemyDog->mfHuntFOV); mfUpdatePathCount =0; mfUpdateFreq = 1.0f; mbFreePlayerPath = false; if(mbBreakingDoor && mpEnemy->CanSeePlayer()==false) { mlBreakDoorCount++; if(mlBreakDoorCount>=3) { mpEnemy->ChangeState(STATE_IDLE); return; } } else { mlBreakDoorCount =0; } mbBreakingDoor = false; mbFoundNoPath = false; mbLostPlayer = false; mfLostPlayerCount =0; mfMaxLostPlayerCount = mpEnemyDog->mfHuntForLostPlayerTime; mlStuckAtMaxCount =0; mpInit->mpMusicHandler->AddAttacker(mpEnemy); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Hunt::OnLeaveState(iGameEnemyState *apNextState) { mpMover->SetMaxDoorToughness(-1); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Hunt::OnUpdate(float afTimeStep) { if(mpPlayer->GetHealth() <=0){ mpEnemy->ChangeState(STATE_IDLE); return; } if(mpMover->GetStuckCounter() > 1.1f) { if(mpEnemy->CheckForDoor()) { mbBreakingDoor = true; mpEnemy->ChangeState(STATE_BREAKDOOR); } else { mlStuckAtMaxCount++; if(mlStuckAtMaxCount >= 6) { mpEnemy->ChangeState(STATE_IDLE); } } mpMover->ResetStuckCounter(); } if(mfUpdatePathCount <=0) { mbFoundNoPath = false; //mpInit->mpEffectHandler->GetSubTitle()->Add("Update Path!",1.0f,true); mfUpdatePathCount = mfUpdateFreq; cAINodeContainer *pNodeCont = mpEnemy->GetMover()->GetNodeContainer(); //Log("%s: Checking free path\n",mpEnemy->GetName().c_str()); //Check if there is a free path to the player if(mbLostPlayer == false && mpMover->FreeDirectPathToChar(mpPlayer->GetCharacterBody())) { mbFreePlayerPath = true; mpMover->Stop(); mpMover->SetMaxDoorToughness(-1); } else { mbFreePlayerPath = false; } //Get path to player if(mbFreePlayerPath==false && mbLostPlayer == false) { if(mpEnemy->GetDoorBreakCount()> 6.0f) { mpMover->SetMaxDoorToughness(0); } //Log("%s: Move to pos\n",mpEnemy->GetName().c_str()); if(mpMover->MoveToPos(mpEnemy->GetLastPlayerPos())==false) { bool bFoundAnotherWay = false; /*float fHeight = mpMover->GetCharBody()->GetPosition().y - mpPlayer->GetCharacterBody()->GetPosition().y; if(cMath::Abs(fHeight) > mpMover->GetNodeContainer()->GetMaxHeight()) { cVector3f vPos = mpEnemy->GetLastPlayerPos(); vPos.y = mpMover->GetCharBody()->GetFeetPosition().y+0.1f; if(mpMover->MoveToPos(vPos)) { bFoundAnotherWay = true; } }*/ if(bFoundAnotherWay == false) { mfUpdatePathCount = mfUpdateFreq*5.0f; mpMover->Stop(); //Set this so the enemey at least runs toward the player. mbFoundNoPath = true; } } //Log("%s: Done with that.\n",mpEnemy->GetName().c_str()); } } else { mfUpdatePathCount -= afTimeStep; } //////////////////////////////// //Go directly towards the player if(mbFreePlayerPath || (mbFoundNoPath && mpMover->IsMoving()==false)) { //Go towards player mpMover->MoveDirectToPos(mpPlayer->GetCharacterBody()->GetFeetPosition(),afTimeStep); //Check if he should attack. if(mpMover->DistanceToChar2D(mpPlayer->GetCharacterBody()) < mpEnemyDog->mfAttackDistance) { float fHeight = mpMover->GetCharBody()->GetPosition().y - mpPlayer->GetCharacterBody()->GetPosition().y; //Player is above if(fHeight < 0) { fHeight += mpMover->GetCharBody()->GetSize().y/2.0f; float fMax = mpEnemyDog->mvAttackDamageSize.y;///2.0f; if(fHeight > -fMax) { mpEnemy->ChangeState(STATE_ATTACK); } else { //random attack if player is not too far up. if(cMath::RandRectf(0,1)<0.2f)//fHeight*2 > -fMax && mpEnemy->ChangeState(STATE_ATTACK); else mpEnemy->ChangeState(STATE_FLEE); } } else { mpEnemy->ChangeState(STATE_ATTACK); } } } //////////////////////////////// //Update path search else if(mbFreePlayerPath==false) { if( mbLostPlayer==false && mpMover->IsMoving()==false && mpEnemy->CanSeePlayer()==false) { mbLostPlayer = true; mfLostPlayerCount = mfMaxLostPlayerCount; } if(mbLostPlayer) { mpMover->GetCharBody()->Move(eCharDir_Forward,1.0f,afTimeStep); mfLostPlayerCount -= afTimeStep; if(mfLostPlayerCount <= 0 || mpMover->GetStuckCounter()>0.5f) { mpEnemy->ChangeState(STATE_IDLE); } } } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Hunt::OnSeePlayer(const cVector3f &avPosition, float afChance) { if(mbLostPlayer && afChance >= mpEnemyDog->mfHuntMinSeeChance) { mbLostPlayer = false; mfUpdatePathCount =0; } } //----------------------------------------------------------------------- bool cGameEnemyState_Dog_Hunt::OnHearNoise(const cVector3f &avPosition, float afVolume) { ////////////////////////////////// //If player is lost the sound might be of help if(mbLostPlayer) { //Check if sound can be heard if(afVolume >= mpEnemyDog->mfHuntMinHearVolume) { //Check if a node is found near the sound. cAINode *pNode = mpMover->GetAINodeAtPosInRange(avPosition,0.0f,5.0f,true, 0.1f); if(pNode) { //Update last player postion. mbLostPlayer = false; mfUpdatePathCount =0; mpEnemy->SetLastPlayerPos(pNode->GetPosition()); return true; } } } return false; } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Hunt::OnDraw() { float fWantedSpeed = mpMover->GetCharBody()->GetMoveSpeed(eCharDir_Forward); float fRealSpeed = cMath::Vector3Dist( mpMover->GetCharBody()->GetPosition(), mpMover->GetCharBody()->GetLastPosition()); fRealSpeed = fRealSpeed / (1.0f/60.0f); float fDist = mpMover->DistanceToChar2D(mpPlayer->GetCharacterBody()); mpInit->mpDefaultFont->Draw(cVector3f(0,110,100),14,cColor(1,1,1,1),eFontAlign_Left, _W("LostPlayerCount: %f FreePath: %d NoPath: %d MaxStuck: %d Dist: %f / %f"), mfLostPlayerCount,mbFreePlayerPath, mbFoundNoPath, mlStuckAtMaxCount, fDist, mpEnemyDog->mfAttackDistance); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // ATTACK STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attack::OnEnterState(iGameEnemyState *apPrevState) { /////////////// //Setup body mpEnemy->SetupBody(); if(mpEnemyDog->mfAttackSpeed>0) { mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfAttackSpeed); mpMover->SetMaxTurnSpeed(10000.0f); //mpMover->SetMinBreakAngle(cMath::ToRad(140)); } /////////////// //Animation float fHeight = mpPlayer->GetCharacterBody()->GetPosition().y - mpMover->GetCharBody()->GetPosition().y; //Player is above if(fHeight > 0.1f) mpEnemy->PlayAnim("Attack",false,0.2f); else mpEnemy->PlayAnim("AttackLow",false,0.2f); /////////////// //Other mpEnemyDog->PlaySound(mpEnemyDog->msAttackStartSound); mfDamageTimer = mpEnemyDog->mfAttackDamageTime; mfJumpTimer = mpEnemyDog->mfAttackJumpTime; mbAttacked = false; if(mpEnemy->GetOnAttackCallback() != "") { tString sCommand = mpEnemy->GetOnAttackCallback() + "(\""+mpEnemy->GetName()+"\")"; mpInit->RunScriptCommand(sCommand); } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attack::OnLeaveState(iGameEnemyState *apNextState) { mpEnemyDog->SetSkipSoundTriggerCount(2.0f); mpMover->ResetStuckCounter(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attack::OnUpdate(float afTimeStep) { //Move forward if(mpEnemyDog->mfAttackSpeed>0) { if(mfJumpTimer <=0) { mpMover->MoveDirectToPos(mpPlayer->GetCharacterBody()->GetFeetPosition(),afTimeStep); } else { mpMover->TurnToPos(mpPlayer->GetCharacterBody()->GetFeetPosition()); mfJumpTimer-= afTimeStep; } } if(mbAttacked) return; ////////////////////////////////////// //Get the 2D distance to the player cVector3f vStart = mpPlayer->GetCharacterBody()->GetPosition(); vStart.y =0; cVector3f vEnd = mpMover->GetCharBody()->GetPosition(); vEnd.y = 0; float fDist2D = cMath::Vector3DistSqr(vStart,vEnd); float fMinRange = mpEnemyDog->mfAttackDamageRange; //////////////////////////////////////// // Check if dog is in range of player if(fDist2D <= fMinRange*fMinRange && mfDamageTimer <=0 ) { if(mbAttacked == false) { cVector3f vPos = mpMover->GetCharBody()->GetPosition() + mpMover->GetCharBody()->GetForward() * mpEnemyDog->mfAttackDamageRange; cVector3f vRot = cVector3f(0,mpMover->GetCharBody()->GetYaw(),0); cMatrixf mtxOffset = cMath::MatrixRotate(vRot,eEulerRotationOrder_XYZ); mtxOffset.SetTranslation(vPos); eAttackTargetFlag target = eAttackTargetFlag_Player | eAttackTargetFlag_Bodies; mpInit->mpPlayer->mbDamageFromPos = true; mpInit->mpPlayer->mvDamagePos = mpMover->GetCharBody()->GetPosition(); if(mpInit->mpAttackHandler->CreateShapeAttack(mpEnemyDog->GetAttackShape(), mtxOffset, mpMover->GetCharBody()->GetPosition(), cMath::RandRectf( mpEnemyDog->mfAttackMinDamage, mpEnemyDog->mfAttackMaxDamage), mpEnemyDog->mfAttackMinMass, mpEnemyDog->mfAttackMaxMass, mpEnemyDog->mfAttackMinImpulse, mpEnemyDog->mfAttackMaxImpulse, mpEnemyDog->mlAttackStrength, target,NULL)) { mpEnemyDog->PlaySound(mpEnemyDog->msAttackHitSound); } mpInit->mpPlayer->mbDamageFromPos = false; mbAttacked = true; } } else { mfDamageTimer -= afTimeStep; } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attack::OnAnimationOver(const tString &asName) { if(mpPlayer->GetHealth() <=0) { float fDist = mpMover->DistanceToChar2D(mpInit->mpPlayer->GetCharacterBody()); if(fDist < 2.3f) { mpEnemy->SetTempFloat(60.0f); mpEnemy->ChangeState(STATE_EAT); } else { mpEnemy->ChangeState(STATE_FLEE); } } else { mpEnemy->ChangeState(STATE_FLEE); } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Attack::OnPostSceneDraw() { cCamera3D *pCamera = static_cast(mpInit->mpGame->GetScene()->GetCamera()); cVector3f vPos = mpMover->GetCharBody()->GetPosition() + mpMover->GetCharBody()->GetForward() * mpEnemyDog->mfAttackDamageRange; cVector3f vRot = cVector3f(0,mpMover->GetCharBody()->GetYaw(),0); cMatrixf mtxOffset = cMath::MatrixRotate(vRot,eEulerRotationOrder_XYZ); mtxOffset.SetTranslation(vPos); cMatrixf mtxCollider = cMath::MatrixMul(pCamera->GetViewMatrix(),mtxOffset); mpInit->mpGame->GetGraphics()->GetLowLevel()->SetMatrix(eMatrix_ModelView,mtxCollider); cVector3f vSize = mpEnemyDog->GetAttackShape()->GetSize(); mpInit->mpGame->GetGraphics()->GetLowLevel()->DrawBoxMaxMin(vSize*0.5f,vSize*-0.5f, cColor(1,0,1,1)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // FLEE STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Flee::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->UseMoveStateAnimations(); //Setup body mpEnemy->SetupBody(); mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfHuntSpeed); mpMover->GetCharBody()->SetMaxNegativeMoveSpeed(eCharDir_Forward,-mpEnemyDog->mfFleeBackSpeed); float fPosMul = 1; if(apPrevState->GetId() == STATE_KNOCKDOWN) fPosMul = 4.0f; mbBackingFromBreakDoor = false; if(apPrevState->GetId() == STATE_BREAKDOOR) mbBackingFromBreakDoor = true; /////////////////////////////////////// // The dog has just broken a door if(mbBackingFromBreakDoor) { mfBackAngle = mpMover->GetCharBody()->GetYaw(); mbBackwards = true; mfTimer = mpEnemyDog->mfFleeBackTime; mfCheckBehindTime = 1.0f / 10.0f; } /////////////////////////////////////// // Normal flee else { if( ( apPrevState->GetId() == STATE_KNOCKDOWN || apPrevState->GetId() == STATE_HUNT || cMath::RandRectf(0,1) < 0)//mpEnemyDog->mfFleePositionChance) ) { cAINode *pNode = mpMover->GetAINodeInRange( mpEnemyDog->mfFleePositionMinDistance * fPosMul, mpEnemyDog->mfFleePositionMaxDistance * fPosMul); if(pNode) { mpMover->MoveToPos(pNode->GetPosition()); } else { mpEnemy->ChangeState(STATE_HUNT); } mfTimer = mpEnemyDog->mfFleePositionMaxTime; mbBackwards = false; } else if(cMath::RandRectf(0,1) < mpEnemyDog->mfFleeBackChance) { mfBackAngle = mpMover->GetCharBody()->GetYaw(); mbBackwards = true; mfTimer = mpEnemyDog->mfFleeBackTime; mfCheckBehindTime = 1.0f / 10.0f; } else { mpEnemy->ChangeState(STATE_HUNT); } } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Flee::OnLeaveState(iGameEnemyState *apNextState) { mpMover->ResetStuckCounter(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Flee::OnUpdate(float afTimeStep) { mfTimer -= afTimeStep; if(mbBackwards) { if(mfCheckBehindTime <= 0) { mfCheckBehindTime = 1.0f / 20.0f; bool bHit = mpEnemy->GetGroundFinder()->GetGround(mpMover->GetCharBody()->GetPosition(), mpMover->GetCharBody()->GetForward() *-1, NULL, NULL, 1.9f); if(bHit) { if(mbBackingFromBreakDoor) { if(mlPreviousState == STATE_FLEE) mpEnemy->ChangeState(STATE_HUNT); else mpEnemy->ChangeState(mlPreviousState); } else { mpEnemy->ChangeState(STATE_HUNT); } } } else { mfCheckBehindTime -= afTimeStep; } if(mfTimer <=0) { if(mbBackingFromBreakDoor) mpEnemy->ChangeState(mlPreviousState); else mpEnemy->ChangeState(STATE_HUNT); } mpMover->GetCharBody()->Move(eCharDir_Forward,-1.0f,afTimeStep); mpMover->TurnToPos(mpInit->mpPlayer->GetCharacterBody()->GetFeetPosition()); } else { //Move forward if(mpMover->IsMoving()==false || mpMover->GetStuckCounter() > 0.3f || mfTimer <=0) { //Check if there is any enemies nearaby and if anyone is allready fighting if( mpEnemy->CheckForTeamMate(mpEnemyDog->mfCallBackupRange*1.5f,false) && mpEnemy->CheckForTeamMate(8,true)==false) { float fPlayerDist = mpMover->DistanceToChar(mpInit->mpPlayer->GetCharacterBody()); //Log("Dist: %f\n",fPlayerDist); if(fPlayerDist > 8) { mpEnemy->ChangeState(STATE_CALLBACKUP); } else { mpEnemy->ChangeState(STATE_HUNT); } //Log("Back from flee!!\n"); } else { //if(mpInit->mpMusicHandler->AttackerExist(mpEnemy)) { mpEnemy->ChangeState(STATE_HUNT); } //else //{ // mpEnemy->ChangeState(STATE_IDLE); //} } } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CALL BACKUP STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_CallBackup::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->PlayAnim(mpEnemyDog->msCallBackupAnimation,false,0.2f); //Sound mpEnemyDog->PlaySound(mpEnemyDog->msCallBackupSound); //Iterate enemies and show them the player cVector3f vPostion = mpMover->GetCharBody()->GetFeetPosition(); tGameEnemyIterator it = mpInit->mpMapHandler->GetGameEnemyIterator(); while(it.HasNext()) { iGameEnemy *pEnemy = it.Next(); if(pEnemy->GetEnemyType() != mpEnemy->GetEnemyType()) continue; if(pEnemy == mpEnemy || pEnemy->IsActive()==false || pEnemy->GetHealth()<=0) continue; cGameEnemy_Dog *pDog = static_cast(pEnemy); float fDist = cMath::Vector3Dist(pDog->GetMover()->GetCharBody()->GetPosition(), vPostion); if(fDist <= mpEnemyDog->mfCallBackupRange) { pDog->ShowPlayer(mpEnemyDog->GetLastPlayerPos()); break; // Call only for one dog backup! } } mpMover->Stop(); mpMover->GetCharBody()->SetMoveSpeed(eCharDir_Forward,0); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_CallBackup::OnLeaveState(iGameEnemyState *apNextState) { mpMover->ResetStuckCounter(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_CallBackup::OnUpdate(float afTimeStep) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_CallBackup::OnAnimationOver(const tString &asName) { mpEnemy->ChangeState(STATE_HUNT); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // BREAK DOOR STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_BreakDoor::OnEnterState(iGameEnemyState *apPrevState) { //Setup body mpEnemy->SetupBody(); if(mpEnemyDog->mfBreakDoorSpeed>0) mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemyDog->mfBreakDoorSpeed); //Animation mpEnemy->PlayAnim(mpEnemyDog->msBreakDoorAnimation,false,0.2f); mpEnemyDog->PlaySound(mpEnemyDog->msBreakDoorStartSound); mfDamageTimer = mpEnemyDog->mfBreakDoorDamageTime; mfStopMoveTimer = mpEnemyDog->mfBreakDoorDamageTime + 1.1f; mbAttacked = false; mbStopped = false; mlCount =0; } //----------------------------------------------------------------------- void cGameEnemyState_Dog_BreakDoor::OnLeaveState(iGameEnemyState *apNextState) { mpEnemyDog->SetSkipSoundTriggerCount(2.0f); mpMover->ResetStuckCounter(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_BreakDoor::OnUpdate(float afTimeStep) { //Move forward if(mpEnemyDog->mfBreakDoorSpeed>0 && mlCount==0 && mbAttacked == false) { //Skip this for now //mpMover->GetCharBody()->Move(eCharDir_Forward,1.0f,afTimeStep); } if(mfDamageTimer <=0 ) { if(!mbStopped) { mpMover->Stop(); mbStopped = true; } } else { mfDamageTimer -= afTimeStep; } if(mfDamageTimer <=0 ) { if(mbAttacked == false) { cVector3f vPos = mpMover->GetCharBody()->GetPosition() + mpMover->GetCharBody()->GetForward() * mpEnemyDog->mfBreakDoorDamageRange; cVector3f vRot = cVector3f(0,mpMover->GetCharBody()->GetYaw(),0); cMatrixf mtxOffset = cMath::MatrixRotate(vRot,eEulerRotationOrder_XYZ); mtxOffset.SetTranslation(vPos); eAttackTargetFlag target = eAttackTargetFlag_Player | eAttackTargetFlag_Bodies; if(mpInit->mpAttackHandler->CreateShapeAttack(mpEnemyDog->GetBreakDoorShape(), mtxOffset, mpMover->GetCharBody()->GetPosition(), cMath::RandRectf( mpEnemyDog->mfBreakDoorMinDamage, mpEnemyDog->mfBreakDoorMaxDamage), mpEnemyDog->mfBreakDoorMinMass, mpEnemyDog->mfBreakDoorMaxMass, mpEnemyDog->mfBreakDoorMinImpulse, mpEnemyDog->mfBreakDoorMaxImpulse, mpEnemyDog->mlBreakDoorStrength, target,NULL)) { mpEnemyDog->PlaySound(mpEnemyDog->msBreakDoorHitSound); cGameSwingDoor *pDoor = mpInit->mpAttackHandler->GetLastSwingDoor(); if(pDoor) { ///////////////////////////// //The door is unbreakable if(pDoor->GetToughness() - mpEnemyDog->mlBreakDoorStrength >= 4) { cMatrixf mtxDoor = pDoor->GetBody(0)->GetWorldMatrix(); cMatrixf mtxInvDoor = cMath::MatrixInverse(mtxDoor); cVector3f vDoorForward = mtxInvDoor.GetForward(); cVector3f vEnemyForward = mpMover->GetCharBody()->GetForward(); if(cMath::Vector3Dot(vDoorForward,vEnemyForward) < 0) { mpEnemy->AddDoorBreakCount(2);//8); //mpInit->mpEffectHandler->GetSubTitle()->Add("Cannot break this door! On BAD side",4); } else { mpEnemy->AddDoorBreakCount(2); //Just continue hitting it since it is just barricaded. //mpInit->mpEffectHandler->GetSubTitle()->Add("Cannot break this door! On GOOD side",4); } } ///////////////////////////// //The door is breakable else { mpEnemy->AddDoorBreakCount(2); } } } mbAttacked = true; } } else { mfDamageTimer -= afTimeStep; } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_BreakDoor::OnAnimationOver(const tString &asName) { if(mlCount ==0) { if(mpEnemyDog->mbBreakDoorRiseAtEnd) { mpEnemy->PlayAnim("RiseRight",false,0.2f); mlCount++; } else { //mpEnemy->ChangeState(mlPreviousState); mpEnemy->ChangeState(STATE_FLEE); mpEnemy->GetState(STATE_FLEE)->SetPreviousState(mlPreviousState); } } else { //mpEnemy->ChangeState(mlPreviousState); mpEnemy->ChangeState(STATE_FLEE); mpEnemy->GetState(STATE_FLEE)->SetPreviousState(mlPreviousState); } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_BreakDoor::OnPostSceneDraw() { cCamera3D *pCamera = static_cast(mpInit->mpGame->GetScene()->GetCamera()); cVector3f vPos = mpMover->GetCharBody()->GetPosition() + mpMover->GetCharBody()->GetForward() * mpEnemyDog->mfBreakDoorDamageRange; cVector3f vRot = cVector3f(0,mpMover->GetCharBody()->GetYaw(),0); cMatrixf mtxOffset = cMath::MatrixRotate(vRot,eEulerRotationOrder_XYZ); mtxOffset.SetTranslation(vPos); cMatrixf mtxCollider = cMath::MatrixMul(pCamera->GetViewMatrix(),mtxOffset); mpInit->mpGame->GetGraphics()->GetLowLevel()->SetMatrix(eMatrix_ModelView,mtxCollider); cVector3f vSize = mpEnemyDog->GetBreakDoorShape()->GetSize(); mpInit->mpGame->GetGraphics()->GetLowLevel()->DrawBoxMaxMin(vSize*0.5f,vSize*-0.5f, cColor(1,0,1,1)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // KNOCK DOWN STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_KnockDown::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->PlayAnim("Idle",true,0.7f); //Sound mpEnemy->PlaySound(mpEnemyDog->msKnockDownSound); //Setup body mpEnemy->SetupBody(); //Go to rag doll mpEnemy->GetMeshEntity()->AlignBodiesToSkeleton(false); mpEnemy->GetMeshEntity()->SetSkeletonPhysicsActive(true); mpEnemy->GetMeshEntity()->Stop(); mpEnemy->GetMover()->GetCharBody()->SetEntity(NULL); mpEnemy->GetMover()->GetCharBody()->SetActive(false); mpEnemy->GetMover()->Stop(); mfTimer = 2.0f; mbCheckAnim = false; mlPrevToughness = mpEnemy->GetToughness(); mpEnemy->SetToughness(12); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_KnockDown::OnLeaveState(iGameEnemyState *apNextState) { mpEnemy->SetToughness(mlPrevToughness); mpEnemy->GetMover()->GetCharBody()->SetEntity(mpEnemy->GetMeshEntity()); mpEnemy->GetMover()->GetCharBody()->SetActive(true); mpMover->ResetStuckCounter(); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_KnockDown::OnUpdate(float afTimeStep) { if(mbCheckAnim) { iCharacterBody *pCharBody = mpEnemy->GetMover()->GetCharBody(); cBoundingVolume *pBV = pCharBody->GetBody()->GetBoundingVolume(); //////////////////////////////////////////////// //Add a force to all objects around dog. iPhysicsWorld *pWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); std::list lstBodies; cPhysicsBodyIterator bodyIt = pWorld->GetBodyIterator(); while(bodyIt.HasNext()) { lstBodies.push_back(bodyIt.Next()); } ////////////////////////// //Force Iteration std::list::iterator it = lstBodies.begin(); for(; it != lstBodies.end(); ++it) { iPhysicsBody *pBody = *it; if(pBody->GetCollideCharacter()==false) continue; if(pBody->IsActive()==false) continue; if(pBody == pCharBody->GetBody()) continue; if(cMath::CheckCollisionBV(*pBody->GetBoundingVolume(), *pBV)) { cVector3f vDir = pBody->GetWorldPosition() - pCharBody->GetPosition(); float fLength = vDir.Length(); //vDir.y *= 0.1f; //if(vDir.x ==0 && vDir.z ==0) vDir.x = 0.3f; vDir.Normalise(); if(fLength==0) fLength = 0.001f; float fForce = (1 / fLength) * 2; if(fForce > 300) fForce = 300; if( mpInit->mpPlayer->GetState() == ePlayerState_Grab && mpInit->mpPlayer->GetPushBody() == pBody) { fForce *= 40; } if(pBody->IsCharacter()) { pBody->GetCharacterBody()->AddForce(vDir * fForce *10 * pBody->GetCharacterBody()->GetMass()); } else { pBody->AddForce(vDir * fForce * pBody->GetMass()); } } } } else { mfTimer -= afTimeStep; if(mfTimer <=0) { //Get the forward vector from root bone (the right vector) cNodeIterator StateIt = mpEnemy->GetMeshEntity()->GetRootNode()->GetChildIterator(); cBoneState *pBoneState = static_cast(StateIt.Next()); cVector3f vRight = cMath::MatrixInverse(pBoneState->GetWorldMatrix()).GetForward(); //Play animation and fade physics float fFadeTime = 1.0f; mbCheckAnim = true; mpEnemy->GetMeshEntity()->Stop(); if(cMath::Vector3Dot(vRight,cVector3f(0,1,0))<0) mpEnemy->PlayAnim("RiseRight",false,fFadeTime); else mpEnemy->PlayAnim("RiseLeft",false,fFadeTime); mpEnemy->GetMeshEntity()->FadeSkeletonPhysicsWeight(fFadeTime); //Calculate values cVector3f vPosition; cVector3f vAngles; cMatrixf mtxTransform = mpEnemy->GetMeshEntity()->CalculateTransformFromSkeleton(&vPosition,&vAngles); //Seems to work better... vPosition = mpEnemy->GetMeshEntity()->GetBoundingVolume()->GetWorldCenter(); cVector3f vGroundPos = vPosition; bool bFoundGround = mpEnemy->GetGroundFinder()->GetGround(vPosition,cVector3f(0,-1,0),&vGroundPos,NULL); //Log("Found ground: %d | %s -> %s\n",bFoundGround,vPosition.ToString().c_str(), // vGroundPos.ToString().c_str()); //Set body iCharacterBody *pCharBody = mpEnemy->GetMover()->GetCharBody(); //vGroundPos -= pCharBody->GetEntityOffset().GetTranslation(); float fYAngle = vAngles.y - mpEnemy->GetModelOffsetAngles().y; //cVector3f vAdd = cVector3f(0,0,pCharBody->GetEntityOffset().GetTranslation().z); //vAdd = cMath::MatrixMul(cMath::MatrixRotateY(fYAngle),vAdd); //vGroundPos += vAdd; pCharBody->SetFeetPosition(vGroundPos); pCharBody->SetYaw(fYAngle); pCharBody->SetEntity(mpEnemy->GetMeshEntity()); pCharBody->SetActive(true); //pCharBody->Update(1.0f / 60.0f); //pCharBody->SetActive(false); for(int i=0; i<3; ++i) { pCharBody->Update(1.0f/60.0f); mpEnemy->GetMeshEntity()->UpdateLogic(1.0f/60.0f); mpEnemy->GetMeshEntity()->UpdateGraphics(NULL,1.0f/60.0f,NULL); } } } } //----------------------------------------------------------------------- void cGameEnemyState_Dog_KnockDown::OnAnimationOver(const tString &asName) { iCharacterBody *pCharBody = mpEnemy->GetMover()->GetCharBody(); if( mpEnemy->CheckForTeamMate(mpEnemyDog->mfCallBackupRange*1.5f,false) && mpEnemy->CheckForTeamMate(14,true)==false) { pCharBody->SetActive(true); mpEnemy->ChangeState(STATE_FLEE); } else { pCharBody->SetActive(true); //mpEnemy->ChangeState(STATE_HUNT); mpEnemy->ChangeState(STATE_FLEE); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // DEAD STATE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemyState_Dog_Dead::OnEnterState(iGameEnemyState *apPrevState) { //Animation mpEnemy->PlayAnim("Idle",true,0.7f); //Sound if(mpEnemy->IsLoading()==false) mpEnemy->PlaySound(mpEnemyDog->msDeathSound); //Setup body mpEnemy->SetupBody(); //Go to ragdoll if(mpEnemy->IsLoading()==false) mpEnemy->GetMeshEntity()->AlignBodiesToSkeleton(false); mpEnemy->GetMeshEntity()->SetSkeletonPhysicsActive(true); mpEnemy->GetMeshEntity()->Stop(); mpEnemy->GetMover()->GetCharBody()->SetEntity(NULL); mpEnemy->GetMover()->GetCharBody()->SetActive(false); mpEnemy->GetMover()->Stop(); mpInit->mpMusicHandler->RemoveAttacker(mpEnemy); } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Dead::OnLeaveState(iGameEnemyState *apNextState) { } //----------------------------------------------------------------------- void cGameEnemyState_Dog_Dead::OnUpdate(float afTimeStep) { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cGameEnemy_Dog::cGameEnemy_Dog(cInit *apInit,const tString& asName,TiXmlElement *apGameElem) : iGameEnemy(apInit,asName,apGameElem) { LoadBaseProperties(apGameElem); ////////////////////////////// //Special properties mfLengthBodyToAss = cString::ToFloat(apGameElem->Attribute("LengthBodyToAss"),1.5f); mfMinKnockDamage = cString::ToFloat(apGameElem->Attribute("MinKnockDamage"),0); mfCertainKnockDamage = cString::ToFloat(apGameElem->Attribute("CertainKnockDamage"),0); ////////////////////////////// //State properties mfIdleFOV = cMath::ToRad(cString::ToFloat(apGameElem->Attribute("IdleFOV"),0)); msIdleFoundPlayerSound = cString::ToString(apGameElem->Attribute("IdleFoundPlayerSound"),""); mfIdleMinSeeChance = cString::ToFloat(apGameElem->Attribute("IdleMinSeeChance"),0); mfIdleMinHearVolume = cString::ToFloat(apGameElem->Attribute("IdleMinHearVolume"),0); msIdleSound = cString::ToString(apGameElem->Attribute("IdleSound"),""); mfIdleSoundMinInteraval = cString::ToFloat(apGameElem->Attribute("IdleSoundMinInteraval"),0); mfIdleSoundMaxInteraval = cString::ToFloat(apGameElem->Attribute("IdleSoundMaxInteraval"),0); mfIdleCallBackupChance = cString::ToFloat(apGameElem->Attribute("IdleCallBackupChance"),0); mvPreloadSounds.push_back(msIdleSound); msInvestigateSound = cString::ToString(apGameElem->Attribute("InvestigateSound"),""); mvPreloadSounds.push_back(msInvestigateSound); msAttentionSound = cString::ToString(apGameElem->Attribute("AttentionSound"),""); mfAttentionTime = cString::ToFloat(apGameElem->Attribute("AttentionTime"),0); mfAttentionMinDist = cString::ToFloat(apGameElem->Attribute("AttentionMinDist"),0); mvPreloadSounds.push_back(msAttentionSound); mfHuntFOV = cMath::ToRad(cString::ToFloat(apGameElem->Attribute("HuntFOV"),0)); mfHuntSpeed = cString::ToFloat(apGameElem->Attribute("HuntSpeed"),0); mfHuntForLostPlayerTime = cString::ToFloat(apGameElem->Attribute("HuntForLostPlayerTime"),0); mfHuntMinSeeChance = cString::ToFloat(apGameElem->Attribute("IdleMinSeeChance"),0); mfHuntMinHearVolume = cString::ToFloat(apGameElem->Attribute("IdleMinHearVolume"),0); mfAttackDistance = cString::ToFloat(apGameElem->Attribute("AttackDistance"),0); mfAttackSpeed = cString::ToFloat(apGameElem->Attribute("AttackSpeed"),0); mfAttackJumpTime = cString::ToFloat(apGameElem->Attribute("AttackJumpTime"),0); mfAttackDamageTime = cString::ToFloat(apGameElem->Attribute("AttackDamageTime"),0); mvAttackDamageSize = cString::ToVector3f(apGameElem->Attribute("AttackDamageSize"),0); mfAttackDamageRange = cString::ToFloat(apGameElem->Attribute("AttackDamageRange"),0); mfAttackMinDamage = cString::ToFloat(apGameElem->Attribute("AttackMinDamage"),0); mfAttackMaxDamage = cString::ToFloat(apGameElem->Attribute("AttackMaxDamage"),0); msAttackStartSound = cString::ToString(apGameElem->Attribute("AttackStartSound"),""); msAttackHitSound = cString::ToString(apGameElem->Attribute("AttackHitSound"),""); mfAttackMinMass = cString::ToFloat(apGameElem->Attribute("AttackMinMass"),0); mfAttackMaxMass = cString::ToFloat(apGameElem->Attribute("AttackMaxMass"),0); mfAttackMinImpulse = cString::ToFloat(apGameElem->Attribute("AttackMinImpulse"),0); mfAttackMaxImpulse = cString::ToFloat(apGameElem->Attribute("AttackMaxImpulse"),0); mlAttackStrength = cString::ToInt(apGameElem->Attribute("AttackStrength"),0); mvPreloadSounds.push_back(msAttackStartSound); mvPreloadSounds.push_back(msAttackHitSound); msBreakDoorAnimation = cString::ToString(apGameElem->Attribute("BreakDoorAnimation"),""); mfBreakDoorSpeed = cString::ToFloat(apGameElem->Attribute("BreakDoorSpeed"),0); mfBreakDoorDamageTime = cString::ToFloat(apGameElem->Attribute("BreakDoorDamageTime"),0); mvBreakDoorDamageSize = cString::ToVector3f(apGameElem->Attribute("BreakDoorDamageSize"),0); mfBreakDoorDamageRange = cString::ToFloat(apGameElem->Attribute("BreakDoorDamageRange"),0); mfBreakDoorMinDamage = cString::ToFloat(apGameElem->Attribute("BreakDoorMinDamage"),0); mfBreakDoorMaxDamage = cString::ToFloat(apGameElem->Attribute("BreakDoorMaxDamage"),0); msBreakDoorStartSound = cString::ToString(apGameElem->Attribute("BreakDoorStartSound"),""); msBreakDoorHitSound = cString::ToString(apGameElem->Attribute("BreakDoorHitSound"),""); mfBreakDoorMinMass = cString::ToFloat(apGameElem->Attribute("BreakDoorMinMass"),0); mfBreakDoorMaxMass = cString::ToFloat(apGameElem->Attribute("BreakDoorMaxMass"),0); mfBreakDoorMinImpulse = cString::ToFloat(apGameElem->Attribute("BreakDoorMinImpulse"),0); mfBreakDoorMaxImpulse = cString::ToFloat(apGameElem->Attribute("BreakDoorMaxImpulse"),0); mlBreakDoorStrength = cString::ToInt(apGameElem->Attribute("BreakDoorStrength"),0); mbBreakDoorRiseAtEnd = cString::ToBool(apGameElem->Attribute("BreakDoorRiseAtEnd"),false); mvPreloadSounds.push_back(msBreakDoorStartSound); mvPreloadSounds.push_back(msBreakDoorHitSound); msKnockDownSound = cString::ToString(apGameElem->Attribute("KnockDownSound"),""); mvPreloadSounds.push_back(msKnockDownSound); msDeathSound = cString::ToString(apGameElem->Attribute("DeathSound"),""); mvPreloadSounds.push_back(msDeathSound); mfFleePositionChance = cString::ToFloat(apGameElem->Attribute("FleePositionChance"),0); mfFleePositionMaxTime = cString::ToFloat(apGameElem->Attribute("FleePositionMaxTime"),0); mfFleePositionMinDistance = cString::ToFloat(apGameElem->Attribute("FleePositionMinDistance"),0); mfFleePositionMaxDistance = cString::ToFloat(apGameElem->Attribute("FleePositionMaxDistance"),0); mfFleeBackChance = cString::ToFloat(apGameElem->Attribute("FleeBackChance"),0); mfFleeBackTime = cString::ToFloat(apGameElem->Attribute("FleeBackTime"),0); mfFleeBackSpeed = cString::ToFloat(apGameElem->Attribute("FleeBackSpeed"),0); msCallBackupAnimation = cString::ToString(apGameElem->Attribute("CallBackupAnimation"),""); msCallBackupSound = cString::ToString(apGameElem->Attribute("CallBackupSound"),""); mfCallBackupRange = cString::ToFloat(apGameElem->Attribute("CallBackupRange"),0); mvPreloadSounds.push_back(msCallBackupSound); mfEatFOV = cMath::ToRad(cString::ToFloat(apGameElem->Attribute("EatFOV"),0)); mfEatMinSeeChance = cString::ToFloat(apGameElem->Attribute("EatMinSeeChance"),0); mfEatMinHearVolume = cString::ToFloat(apGameElem->Attribute("EatMinHearVolume"),0); ////////////////////////////// //Set up states AddState(hplNew( cGameEnemyState_Dog_Idle,(STATE_IDLE,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Hunt,(STATE_HUNT,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Attack,(STATE_ATTACK,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Flee,(STATE_FLEE,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_KnockDown,(STATE_KNOCKDOWN,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Dead,(STATE_DEAD,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Patrol,(STATE_PATROL,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Investigate,(STATE_INVESTIGATE,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_BreakDoor,(STATE_BREAKDOOR,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_CallBackup,(STATE_CALLBACKUP,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_MoveTo,(STATE_MOVETO,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Eat,(STATE_EAT,mpInit,this)) ); AddState(hplNew( cGameEnemyState_Dog_Attention,(STATE_ATTENTION,mpInit,this)) ); } //----------------------------------------------------------------------- cGameEnemy_Dog::~cGameEnemy_Dog() { } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameEnemy_Dog::OnLoad() { //Create attack shape iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); mpAttackShape = pPhysicsWorld->CreateBoxShape(mvAttackDamageSize,NULL); mpBreakDoorShape = pPhysicsWorld->CreateBoxShape(mvBreakDoorDamageSize,NULL); //Set up shape ChangeState(STATE_IDLE); } //----------------------------------------------------------------------- void cGameEnemy_Dog::OnUpdate(float afTimeStep) { if(IsActive()==false) return; /////////////////////////////////// //Regenerate health: if(mfHealth > 0) { if( mpInit->mDifficulty != eGameDifficulty_Easy && mfHealth <= mfMaxHealth *0.5f) { mfHealth += afTimeStep * (10.0f / 60.0f); //10 heal units / min } } /////////////////////////////////// //Check for ass in wall if(mfHealth >0 && mpMover->GetCharBody()->IsActive()) { float fMaxMove = afTimeStep * 2; static int lAssCount =0; lAssCount++; if(lAssCount % 2 == 0) { iCharacterBody *pCharBody = mpMover->GetCharBody(); cVector3f vPos, vNormal; mFindGround.GetGround(pCharBody->GetPosition(), pCharBody->GetForward()*-1, &vPos,&vNormal,mfLengthBodyToAss); float fDist = cMath::Vector3Dist(pCharBody->GetPosition(), vPos); if(fDist < mfLengthBodyToAss) { float fAdd = mfLengthBodyToAss - fDist; if(fAdd > fMaxMove) fAdd = fMaxMove; cVector3f vAdd = pCharBody->GetForward() * fAdd; pCharBody->SetPosition(pCharBody->GetPosition() + vAdd); } } } } //----------------------------------------------------------------------- void cGameEnemy_Dog::ShowPlayer(const cVector3f& avPlayerFeetPos) { if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL || mlCurrentState == STATE_INVESTIGATE) { mvLastPlayerPos = avPlayerFeetPos; ChangeState(STATE_HUNT); } } //----------------------------------------------------------------------- bool cGameEnemy_Dog::MoveToPos(const cVector3f& avFeetPos) { if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL) { SetTempPosition(avFeetPos); ChangeState(STATE_MOVETO); return true; } else { return false; } } //----------------------------------------------------------------------- bool cGameEnemy_Dog::IsFighting() { if( mfHealth <= 0 || IsActive()==false) return false; if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL || mlCurrentState == STATE_INVESTIGATE) return false; return true; } //-----------------------------------------------------------------------