//	Zombie.cpp - Class representing a zombie.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	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/>.
//	----------------------------------------------------------------------------

#include "drawing/Drawer.h"
#include "GamePlayState.h"
#include "MiscHelper.h"
#include "Random.h"
#include "Zombie.h"
#include "Puddle.h"
#include "Tank.h"

//------------------------------------------------------------------------------
Zombie::Zombie(const TwoFloats& pos, const ThreeFloats& col):
NPC(L"Zombie"),
position(pos),
colour(col),
globalSpeed(1.0f),
directionCount(0),
birthCount(60),
dead(false)
{
	direction.x = (Random::getGlobal().getRandomFloat() * 2.0f) - 1.0f;
	direction.y = (Random::getGlobal().getRandomFloat() * 2.0f) - 1.0f;
	direction = direction.normal();
}

//------------------------------------------------------------------------------
Zombie::~Zombie()
{

}

//------------------------------------------------------------------------------
void Zombie::update(GamePlayState& state)
{
	int i;
	float dist;
	TwoFloats tempDir;
	int nearestIndex = 0;
	float nearestDir = 10000.0f;

	//If directionCount is zero, point towards the nearest tank.
	if(directionCount <= 0)
	{
		directionCount = 60 + Random::getGlobal().getRandomInt(30);

		for(i=0;i<state.getNumTanks();++i)
		{
			dist = position.getDistance(state.getTank(i)->getPosition());

			if(dist < nearestDir)
			{
				nearestDir = dist;
				nearestIndex = i;
			}
		}
		desiredDirection = state.getTank(nearestIndex)->getPosition() - position;
	}
	else
		--directionCount;

	direction += (desiredDirection-direction) * 0.0001f;
	direction = direction.normal();

	//If direction has converged on desiredDirection, reset desiredDirection.
	if(direction.getDistance(desiredDirection) < 0.01f)
		direction = desiredDirection;

	//Move the Zombie along its direction vector.
	position += direction * globalSpeed;

	if(birthCount > 0)
		--birthCount;

	//Reset global speed.
	globalSpeed = 1.0f;
}

//------------------------------------------------------------------------------
void Zombie::draw(shared_ptr<Drawer>& d, float timestepInterp)
{
	std::wstring image;
	TwoFloats pivot(13.5f, 8.5f);
	TwoFloats tempPos(position-pivot);
	TwoFloats tempDir(direction.x, -direction.y);
	const float angle(tempDir.getAngle() + NIALL_PI);

	d->drawRotImage(L"ZombieBottom",
					tempPos,
					angle,
					pivot,
					1.0f,
					0.1875f);
	pivot.x += 3.0f;
	pivot.y += 2.5f;
	tempPos = position-pivot;
	d->drawRotImage(L"ZombieTop",
					tempPos,
					angle,
					pivot,
					1.0f,
					colour);
}

//------------------------------------------------------------------------------
void Zombie::multiplyGlobalSpeed(float val)
{
	globalSpeed *= val;
}

//------------------------------------------------------------------------------
void Zombie::setPosition(const TwoFloats& pos)
{
	position = pos;
}

//------------------------------------------------------------------------------
bool Zombie::interestedInCollisionsWith(const std::wstring& entity) const
{
	bool retval = false;

	if((entity == L"Wall") || (entity == L"MADButton") || (entity == L"Puddle"))
		retval = true;
	else if(((entity == L"Tank") ||
			 (entity == L"Bullet") ||
			 (entity == L"Bee") ||
			 (entity == L"Mine") ||
			 (entity == L"Shockwave")) &&
			(birthCount <= 0))
	{
		retval = true;
	}

	return retval;
}

//------------------------------------------------------------------------------
bool Zombie::collide(const shared_ptr<Collidable>& other, GamePlayState& state)
{
	bool retval = false;
	const std::wstring& n(other->getName());

	if((n == L"Wall") || (n == L"MADButton"))
	{
		float offset;
		const TwoFloats origin;
		TwoFloats diff(other->getPosition() - position);
		float dist = origin.getDistance(diff);
		float rad = 13.0f + other->getRadius();

		diff = diff.normal();
		offset = (rad - dist);
		position -= diff * offset;
	}
	else if(((n == L"Tank") ||
			 (n == L"Bullet") ||
			 (n == L"Bee") ||
			 (n == L"Mine") ||
			 (n == L"Shockwave")) &&
		    (birthCount <= 0))
	{
		retval = true;
		dead = true;
	}
	else if(n == L"Puddle")
	{
		shared_ptr<Puddle> puddle = dynamic_pointer_cast<Puddle>(other);

		dead = false;

		if(puddle)
			puddle->collideZombie(*this, state);
	}

	return false;
}
