/* * 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; } //-----------------------------------------------------------------------