/*
* 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_Spider.h"
#include "Player.h"
#include "AttackHandler.h"
#include "EffectHandler.h"
#include "GameMusicHandler.h"
#include "GameSwingDoor.h"
#include "MapHandler.h"
//////////////////////////////////////////////////////////////////////////
// BASE STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
iGameEnemyState_Spider_Base::iGameEnemyState_Spider_Base(int alId, cInit *apInit, iGameEnemy *apEnemy)
: iGameEnemyState(alId,apInit,apEnemy)
{
mpEnemySpider = static_cast(mpEnemy);
}
//-----------------------------------------------------------------------
void iGameEnemyState_Spider_Base::OnSeePlayer(const cVector3f &avPosition, float afChance)
{
if(mpPlayer->GetHealth() <=0) return;
if(afChance >= mpEnemySpider->mfIdleMinSeeChance)
{
mpEnemy->ChangeState(STATE_HUNT);
mpEnemySpider->PlaySound(mpEnemySpider->msIdleFoundPlayerSound);
}
}
bool iGameEnemyState_Spider_Base::OnHearNoise(const cVector3f &avPosition, float afVolume)
{
float afDistance = (mpMover->GetCharBody()->GetPosition() - avPosition).Length();
if(afVolume >= mpEnemySpider->mfIdleMinHearVolume && afDistance > 0.4f)
{
//mpEnemy->SetTempPosition(avPosition);
//mpEnemy->ChangeState(STATE_INVESTIGATE);
return true;
}
return false;
}
void iGameEnemyState_Spider_Base::OnTakeHit(float afDamage)
{
if(afDamage >= 5)
{
mpEnemy->ChangeState(STATE_KNOCKDOWN);
}
}
void iGameEnemyState_Spider_Base::OnFlashlight(const cVector3f &avPosition)
{
//mpInit->mpEffectHandler->GetSubTitle()->Add("Flashlight!",0.5f);
//OnSeePlayer(mpPlayer->GetCharacterBody()->GetFeetPosition(),1.0f);
if(mlId == STATE_KNOCKDOWN) return;
if(mpEnemySpider->mbFleeFromFlashlight) mpEnemy->ChangeState(STATE_FLEE);
}
void iGameEnemyState_Spider_Base::OnDeath(float afDamage)
{
mpEnemy->ChangeState(STATE_KNOCKDOWN);
//mpEnemy->ChangeState(STATE_DEAD);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// IDLE STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Idle::OnEnterState(iGameEnemyState *apPrevState)
{
//Animation
mpEnemy->PlayAnim("Idle",false,0.2f);
//Setup body
mpEnemy->SetupBody();
//Setup enemy
mpEnemy->SetFOV(mpEnemySpider->mfIdleFOV);
mpInit->mpMusicHandler->RemoveAttacker(mpEnemy);
mbStopped = true;
mfNextWalkTime = cMath::RandRectf( mpEnemySpider->mfIdleMinWaitLength,
mpEnemySpider->mfIdleMaxWaitLength);
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Idle::OnLeaveState(iGameEnemyState *apNextState)
{
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Idle::OnUpdate(float afTimeStep)
{
if(mpMover->IsMoving()==false || mpMover->GetStuckCounter() > 2.0f)
{
mpMover->ResetStuckCounter();
if(mbStopped==false)
{
mbStopped = true;
mpEnemy->PlayAnim("Idle",false,0.9f);
mfNextWalkTime = cMath::RandRectf( mpEnemySpider->mfIdleMinWaitLength,
mpEnemySpider->mfIdleMaxWaitLength);
}
else if(mfNextWalkTime <=0)
{
mbStopped = false;
//Animation
mpEnemy->UseMoveStateAnimations();
//Setup body
mpEnemy->SetupBody();
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed);
cAINode *pNode = NULL;
if(mpEnemy->GetPatrolNodeNum()==0)
{
pNode = mpMover->GetAINodeInRange( 1, 5);
}
else
{
int lNodeNum = cMath::RandRectl(0,mpEnemy->GetPatrolNodeNum()-1);
tString sName = mpEnemy->GetPatrolNode(lNodeNum)->msNodeName;
pNode = mpMover->GetNodeContainer()->GetNodeFromName(sName);
}
if(pNode)
{
mpMover->MoveToPos(pNode->GetPosition());
}
else
{
mpEnemy->ChangeState(STATE_IDLE);
}
}
else
{
mfNextWalkTime -= afTimeStep;
}
}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// HUNT STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Hunt::OnEnterState(iGameEnemyState *apPrevState)
{
//Animation
mpEnemy->UseMoveStateAnimations();
//Setup body
float fMul = 1.0f;
if(mpInit->mbHasHaptics) fMul = 0.6f;
mpEnemy->SetupBody();
if(mpInit->mDifficulty == eGameDifficulty_Easy)
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed*0.7f*fMul);
else if(mpInit->mDifficulty == eGameDifficulty_Normal)
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed*fMul);
else
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed*1.2f*fMul);
//Setup enemy
mpEnemy->SetFOV(mpEnemySpider->mfHuntFOV);
mfUpdatePathCount =0;
mfUpdateFreq = 1.0f;
mbFreePlayerPath = false;
mbLostPlayer = false;
mfLostPlayerCount =0;
mfMaxLostPlayerCount = mpEnemySpider->mfHuntForLostPlayerTime;
mpInit->mpMusicHandler->AddAttacker(mpEnemy);
if(mpEnemySpider->mbPathFind==false) mpMover->Stop();
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Hunt::OnLeaveState(iGameEnemyState *apNextState)
{
mpMover->SetMaxDoorToughness(-1);
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Hunt::OnUpdate(float afTimeStep)
{
if(mpPlayer->GetHealth() <=0){
mpEnemy->ChangeState(STATE_IDLE);
return;
}
if(mpMover->GetStuckCounter() > 2.1f)
{
mpEnemy->ChangeState(STATE_FLEE);
mpMover->ResetStuckCounter();
return;
}
//Check if he should attack.
if(mpMover->DistanceToChar2D(mpPlayer->GetCharacterBody()) < mpEnemySpider->mfAttackDistance)
{
mpEnemy->ChangeState(STATE_ATTACK);
}
if(mpEnemySpider->mbPathFind)
{
if(mfUpdatePathCount <=0)
{
mfUpdatePathCount = mfUpdateFreq;
cAINodeContainer *pNodeCont = mpEnemy->GetMover()->GetNodeContainer();
//Check if there is a free path to the player
if(mbLostPlayer == false && mpMover->FreeDirectPathToChar(mpPlayer->GetCharacterBody()))
{
mbFreePlayerPath = true;
mpMover->Stop();
}
else
{
mbFreePlayerPath = false;
}
//Get path to player
if(mbFreePlayerPath==false && mbLostPlayer == false)
{
if(mpMover->MoveToPos(mpEnemy->GetLastPlayerPos())==false)
{
mfUpdatePathCount *= 5.0f;
}
}
}
else
{
mfUpdatePathCount -= afTimeStep;
}
}
else
{
mbFreePlayerPath = true;
if(mpEnemy->CanSeePlayer()==false)
{
mfLostPlayerCount-= afTimeStep;
if(mfLostPlayerCount <= 0 || mpMover->GetStuckCounter()>0.5f)
{
mpEnemy->ChangeState(STATE_IDLE);
}
}
else
{
mfLostPlayerCount = mfMaxLostPlayerCount*2;
}
}
////////////////////////////////
//Go directly towards the player
if(mbFreePlayerPath)
{
//Go towards player
mpMover->MoveDirectToPos(mpPlayer->GetCharacterBody()->GetFeetPosition(),afTimeStep);
}
////////////////////////////////
//Update path search
else
{
if(mbLostPlayer==false && mpMover->IsMoving()==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_Spider_Hunt::OnSeePlayer(const cVector3f &avPosition, float afChance)
{
if(mbLostPlayer && afChance >= mpEnemySpider->mfHuntMinSeeChance)
{
mbLostPlayer = false;
mfUpdatePathCount =0;
}
}
//-----------------------------------------------------------------------
bool cGameEnemyState_Spider_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 >= mpEnemySpider->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_Spider_Hunt::OnDraw()
{
//mpInit->mpDefaultFont->Draw(cVector3f(230,10,100),14,cColor(1,1,1,1),eFontAlign_Left,
// "Freepath: %d",mbFreePlayerPath);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// ATTACK STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Attack::OnEnterState(iGameEnemyState *apPrevState)
{
//Setup body
mpEnemy->SetupBody();
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed);
//Animation
mpEnemy->PlayAnim("Attack",false,0.2f);
mpEnemySpider->PlaySound(mpEnemySpider->msAttackStartSound);
mfJumpTimer = mpEnemySpider->mfAttackJumpTime;
mfDamageTimer = mpEnemySpider->mfAttackDamageTime;
mbAttacked = false;
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Attack::OnLeaveState(iGameEnemyState *apNextState)
{
//mpMover->GetCharBody()->SetForce(0);
mpEnemySpider->SetSkipSoundTriggerCount(2.0f);
mpMover->ResetStuckCounter();
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Attack::OnUpdate(float afTimeStep)
{
if(mfJumpTimer >0)
{
mfJumpTimer -= afTimeStep;
if(mfJumpTimer <= 0)
{
cVector3f vDirection = mpInit->mpPlayer->GetCamera()->GetPosition() -
mpMover->GetCharBody()->GetPosition();
float fHeight = cMath::Abs(vDirection.y);
vDirection.Normalise();
cVector3f vForce = vDirection * mpEnemySpider->mfAttackForce;
vForce.y = fHeight * 0.5f * mpEnemySpider->mfAttackForce;
mpMover->GetCharBody()->AddForce(vForce);
}
}
cVector3f vStart = mpPlayer->GetCharacterBody()->GetPosition();
vStart.y =0;
cVector3f vEnd = mpMover->GetCharBody()->GetPosition();
vEnd.y = 0;
float fDist2D = cMath::Vector3DistSqr(vStart,vEnd);
float fMinRange = mpEnemySpider->mfAttackDamageRange + 0.4f;
if(fDist2D <= fMinRange*fMinRange && mfDamageTimer <=0)
{
if(mbAttacked == false)
{
cVector3f vPos = mpMover->GetCharBody()->GetPosition() +
mpMover->GetCharBody()->GetForward() *
mpEnemySpider->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(mpEnemySpider->GetAttackShape(),
mtxOffset,
mpMover->GetCharBody()->GetPosition(),
cMath::RandRectf( mpEnemySpider->mfAttackMinDamage,
mpEnemySpider->mfAttackMaxDamage),
mpEnemySpider->mfAttackMinMass, mpEnemySpider->mfAttackMaxMass,
mpEnemySpider->mfAttackMinImpulse, mpEnemySpider->mfAttackMaxImpulse,
mpEnemySpider->mlAttackStrength,
target,NULL))
{
mpEnemySpider->PlaySound(mpEnemySpider->msAttackHitSound);
}
mpInit->mpPlayer->mbDamageFromPos = false;
mbAttacked = true;
}
}
else if(mfDamageTimer >0)
{
mfDamageTimer -= afTimeStep;
}
}
void cGameEnemyState_Spider_Attack::OnFlashlight(const cVector3f &avPosition)
{
if(mfJumpTimer >0 && mpEnemySpider->mbFleeFromFlashlight) mpEnemy->ChangeState(STATE_FLEE);
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Attack::OnAnimationOver(const tString &asName)
{
mpEnemy->ChangeState(STATE_HUNT);
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Attack::OnPostSceneDraw()
{
cCamera3D *pCamera = static_cast(mpInit->mpGame->GetScene()->GetCamera());
cVector3f vPos = mpMover->GetCharBody()->GetPosition() +
mpMover->GetCharBody()->GetForward() *
mpEnemySpider->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 = mpEnemySpider->GetAttackShape()->GetSize();
mpInit->mpGame->GetGraphics()->GetLowLevel()->DrawBoxMaxMin(vSize*0.5f,vSize*-0.5f,
cColor(1,0,1,1));
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// FLEE STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Flee::OnEnterState(iGameEnemyState *apPrevState)
{
//Animation
mpEnemy->UseMoveStateAnimations();
//Setup body
mpEnemy->SetupBody();
mpMover->GetCharBody()->SetMaxPositiveMoveSpeed(eCharDir_Forward,mpEnemySpider->mfHuntSpeed);
cVector3f vDir = mpMover->GetCharBody()->GetPosition() - mpPlayer->GetCharacterBody()->GetPosition();
vDir.Normalise();
cVector3f vStart = mpMover->GetCharBody()->GetPosition() + vDir*mpEnemySpider->mfFleeMaxDistance;
cAINode *pNode = mpMover->GetAINodeAtPosInRange(vStart,
mpEnemySpider->mfFleeMinDistance,
mpEnemySpider->mfFleeMaxDistance,
false,0);
if(pNode)
{
mpMover->MoveToPos(pNode->GetPosition());
}
else
{
mpEnemy->ChangeState(STATE_HUNT);
}
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Flee::OnLeaveState(iGameEnemyState *apNextState)
{
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Flee::OnUpdate(float afTimeStep)
{
//Move forward
if(mpMover->IsMoving()==false || mpMover->GetStuckCounter() > 2.3f)
{
mpMover->ResetStuckCounter();
if(mlPreviousState != STATE_FLEE && mlPreviousState != STATE_ATTACK)
mpEnemy->ChangeState(mlPreviousState);
else
mpEnemy->ChangeState(STATE_HUNT);
}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// KNOCK DOWN STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_KnockDown::OnEnterState(iGameEnemyState *apPrevState)
{
//Animation
mpEnemy->PlayAnim("Idle",true,0.7f);
//Sound
mpEnemy->PlaySound(mpEnemySpider->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;
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_KnockDown::OnLeaveState(iGameEnemyState *apNextState)
{
mpEnemy->GetMover()->GetCharBody()->SetEntity(mpEnemy->GetMeshEntity());
mpEnemy->GetMover()->GetCharBody()->SetActive(true);
mpMover->ResetStuckCounter();
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_KnockDown::OnUpdate(float afTimeStep)
{
if(mbCheckAnim)
{
}
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());
//Play animation and fade physics
float fFadeTime = 0.7f;
mbCheckAnim = true;
mpEnemy->GetMeshEntity()->Stop();
if(mpEnemy->GetHealth() >0)
mpEnemy->PlayAnim("Walk",false,fFadeTime);
else
mpEnemy->PlayAnim("Death",false,fFadeTime);
mpEnemy->GetMeshEntity()->FadeSkeletonPhysicsWeight(fFadeTime);
//Calculate values
cVector3f vPosition;
cVector3f vAngles;
cMatrixf mtxTransform = mpEnemy->GetMeshEntity()->CalculateTransformFromSkeleton(&vPosition,&vAngles);
cVector3f vGroundPos = vPosition;
bool bFoundGround = mpEnemy->GetGroundFinder()->GetGround(vPosition,cVector3f(0,-1,0),&vGroundPos,NULL);
//Set body
iCharacterBody *pCharBody = mpEnemy->GetMover()->GetCharBody();
vGroundPos.z -= pCharBody->GetEntityOffset().GetTranslation().z;
pCharBody->SetFeetPosition(vGroundPos);
pCharBody->SetYaw(vAngles.y - mpEnemy->GetModelOffsetAngles().y);
pCharBody->SetEntity(mpEnemy->GetMeshEntity());
pCharBody->SetActive(true);
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);
}
if(mpEnemy->GetHealth() > 0)
mpEnemy->ChangeState(STATE_HUNT);
else
mpEnemy->ChangeState(STATE_DEAD);
}
}
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_KnockDown::OnAnimationOver(const tString &asName)
{
if(mpEnemy->GetHealth() >0)
mpEnemy->ChangeState(STATE_HUNT);
else
mpEnemy->ChangeState(STATE_DEAD);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// DEAD STATE
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Dead::OnEnterState(iGameEnemyState *apPrevState)
{
//Animation
mpEnemy->PlayAnim("Death",false,0.7f);
//Sound
mpEnemy->PlaySound(mpEnemySpider->msDeathSound);
//Setup body
mpEnemy->SetupBody();
mpInit->mpMusicHandler->RemoveAttacker(mpEnemy);
//Temp:
//mpMover->GetCharBody()->GetBody()->SetCollideCharacter(false);
mpMover->GetCharBody()->GetBody()->SetActive(false);
mpEnemy->GetMover()->Stop();
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Dead::OnLeaveState(iGameEnemyState *apNextState)
{
}
//-----------------------------------------------------------------------
void cGameEnemyState_Spider_Dead::OnUpdate(float afTimeStep)
{
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cGameEnemy_Spider::cGameEnemy_Spider(cInit *apInit,const tString& asName,TiXmlElement *apGameElem) : iGameEnemy(apInit,asName,apGameElem)
{
LoadBaseProperties(apGameElem);
//////////////////////////////
//State properties
mbPathFind = cString::ToBool(apGameElem->Attribute("PathFind"),true);
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);
mfIdleMinWaitLength = cString::ToFloat(apGameElem->Attribute("IdleMinWaitLength"),0);
mfIdleMaxWaitLength = cString::ToFloat(apGameElem->Attribute("IdleMaxWaitLength"),0);
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);
mfAttackForce = cString::ToFloat(apGameElem->Attribute("AttackForce"),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);
mfFleeMinDistance = cString::ToFloat(apGameElem->Attribute("FleeMinDistance"),0);
mfFleeMaxDistance = cString::ToFloat(apGameElem->Attribute("FleeMaxDistance"),0);
mbFleeFromFlashlight = cString::ToBool(apGameElem->Attribute("FleeFromFlashlight"),true);
msKnockDownSound = cString::ToString(apGameElem->Attribute("KnockDownSound"),"");
mvPreloadSounds.push_back(msKnockDownSound);
msDeathSound = cString::ToString(apGameElem->Attribute("DeathSound"),"");
mvPreloadSounds.push_back(msDeathSound);
//////////////////////////////
//Set up states
AddState(hplNew( cGameEnemyState_Spider_Idle,(STATE_IDLE,mpInit,this)) );
AddState(hplNew( cGameEnemyState_Spider_Hunt,(STATE_HUNT,mpInit,this)) );
AddState(hplNew( cGameEnemyState_Spider_Attack,(STATE_ATTACK,mpInit,this)) );
AddState(hplNew( cGameEnemyState_Spider_Flee,(STATE_FLEE,mpInit,this)) );
AddState(hplNew( cGameEnemyState_Spider_KnockDown,(STATE_KNOCKDOWN,mpInit,this)) );
AddState(hplNew( cGameEnemyState_Spider_Dead,(STATE_DEAD,mpInit,this)) );
}
//-----------------------------------------------------------------------
cGameEnemy_Spider::~cGameEnemy_Spider()
{
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameEnemy_Spider::OnLoad()
{
//Create attack shape
iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
mpAttackShape = pPhysicsWorld->CreateBoxShape(mvAttackDamageSize,NULL);
//Set up shape
ChangeState(STATE_IDLE);
}
//-----------------------------------------------------------------------
void cGameEnemy_Spider::OnUpdate(float afTimeStep)
{
}
//-----------------------------------------------------------------------
void cGameEnemy_Spider::ShowPlayer(const cVector3f& avPlayerFeetPos)
{
if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL ||
mlCurrentState == STATE_INVESTIGATE)
{
mvLastPlayerPos = avPlayerFeetPos;
ChangeState(STATE_HUNT);
}
}
//-----------------------------------------------------------------------
bool cGameEnemy_Spider::MoveToPos(const cVector3f& avFeetPos)
{
if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL)
{
//SetTempPosition(avFeetPos);
//ChangeState(STATE_INVESTIGATE);
//return true;
return false;
}
else
{
return false;
}
}
//-----------------------------------------------------------------------
bool cGameEnemy_Spider::IsFighting()
{
if( mfHealth <= 0 || IsActive()==false) return false;
if( mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL ||
mlCurrentState == STATE_INVESTIGATE) return false;
return true;
}
//-----------------------------------------------------------------------