/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. */ #include "hpl1/penumbra-overture/GameEnemy_Spider.h" #include "hpl1/penumbra-overture/AttackHandler.h" #include "hpl1/penumbra-overture/EffectHandler.h" #include "hpl1/penumbra-overture/GameMusicHandler.h" #include "hpl1/penumbra-overture/GameSwingDoor.h" #include "hpl1/penumbra-overture/MapHandler.h" #include "hpl1/penumbra-overture/Player.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; 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 position. 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) { // FIXME: Code identical in each branch. Development leftover? #if 0 if (mlCurrentState == STATE_IDLE || mlCurrentState == STATE_PATROL) { // SetTempPosition(avFeetPos); // ChangeState(STATE_INVESTIGATE); // return true; return false; } else { return false; } #else return false; #endif } //----------------------------------------------------------------------- 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; } //-----------------------------------------------------------------------