/* 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 <http://www.gnu.org/licenses/>.
 *
 */

/*
 * 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<cGameEnemy_Spider *>(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<cCamera3D *>(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<cBoneState *>(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;
}

//-----------------------------------------------------------------------
