/*
 * Baddie.cpp
 *
 *  Created on: 2009-07-12
 *      Author: wasyl
 */

#include <vector>
#include "Baddie.h"
#include "../prep/res/Resources.h"
#include "../misc/Controls.h"
#include "../prep/misc/Vector2D.h"
#include "../misc/Physics.h"
#include "../prep/Common.h"
#include "../prep/misc/Random.h"
#include "Particle.h"
#include "Level.h"
#include "Game.h"
#include "Bag.h"

Baddie::Baddie(bool feral)
	: mFeral(feral)
{
	Resources::load(mSheet, "media/badsheet.png");
	Resources::load(mSndDie, "media/die.wav");

	mState = STANDING;
	mFlip = false;
	mAnim = 0;
}

Baddie::~Baddie()
{
}

Rect Baddie::bbox()
{
	return Rect(mPos.x + 2.0, mPos.y + 7.0, mPos.x + 17.0, mPos.y + 20.0);
}

void Baddie::animate(double dt)
{
	double lastTime = mTime;
	mTime += dt;
	int frames = int(mTime * 8) - int(lastTime * 8);
	for (int i = 0; i < frames; i++)
		mAnim = (mAnim + 1) % 2;
}

void Baddie::update(double dt)
{
	animate(dt);

	// collisions
	Collision col = Physics::collisions(this);
	int retries = 0;
	while (col.dir != Collision::NONE && retries++ < 20)
	{
		if (mCarrier)
			mCarrier->dropCarried();

		switch (col.dir)
		{
		case Collision::LEFT:
		case Collision::RIGHT:
			// no walking into walls
			Physics::eject(this, col);
			mVel = Vec(0,0);
			if (mState == STANDING)
				mFlip = !mFlip;
			break;

		case Collision::DOWN:
			// landed in a floor
			if (mState == FALLING && mVel.y >= 0.0)
			{
				mState = STANDING;
				mFlip = mVel.x >= 0;
				al_play_sample(mSndLand, 1.0, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
			}

			Physics::eject(this, col);
			break;

		case Collision::UP:
			Physics::eject(this, col);
			mVel = Vec(0,0);
			break;

		default:
			break;
		}

		col = Physics::collisions(this);
	}

	// no floor? toggle to falling down
	if (mState == STANDING)
	{
		Level *lv = Game::get()->level();
		if (!lv->collision(mPos + Vec(10.0, 21.0)))
		{
			mVel = Vec(mFlip ? 70.0 : -70.0, 0.0);
			mState = FALLING;
		}

		if (mFlip)
		{
			mPos.x += 70.0 * dt;
			if (!lv->collision(mPos + Vec(19.0, 21.0)))
				mFlip = !mFlip;
		}
		else
		{
			mPos.x -= 70.0 * dt;
			if (!lv->collision(mPos + Vec(1.0, 21.0)))
				mFlip = !mFlip;
		}
	}

	if (mState == FALLING)
	{
		mFlip = mVel.x >= 0.0;
		mVel.y += dt * 600.0;
		if (mVel.y > 600.0)
			mVel.y = 600.0;
		mPos += mVel * dt;
	}

	if (mFeral)
	{
		Entity *avatar = mWorld->entity(ID("avat"));
		if (bbox().collide(avatar->bbox()))
		{
			((Avatar*)avatar)->die("have become a snack for a feral baddie.");
		}

		Entities &grbg = mWorld->index(ID("grbg"));
		FOREACH(vector,Entity*,b,grbg)
		{
			if (bbox().collide((*b)->bbox()))
			{
				al_play_sample(mSndDie, 1.0, 0.5, 1.0, ALLEGRO_PLAYMODE_ONCE, NULL);
				for (int i = 0; i < 20; i++)
				{
					Particle *p = new Particle(
							"media/puff.png",
							(*b)->pos() + Vec(randomFloat(-10.0, 10.0), randomFloat(-10.0, 10.0)),
							Vec(0.0,randomFloat(-7.0, -15.0)), 0.8, -0.02, ALLEGRO_INVERSE_ALPHA);
					mWorld->add(p);
				}

				(*b)->discard(); // eat garbage
			}
		}
	}
	else if (mState == STANDING)
	{
		Entities &grbg = mWorld->index(ID("grbg"));
		FOREACH(vector,Entity*,b,grbg)
		{
			// push bags
			Bag *bag = (Bag*)(*b);
			if ( (bag->x() > mPos.x) != mFlip )
				continue;

			if (bbox().collide(bag->bbox()) && bag->state() == Carryable::STANDING)
			{
				bag->setX(bag->x() + (mFlip ? 70.0 * dt : -70.0 * dt));
				if (bbox().collide(bag->bbox()))
				{
					Vec old = bag->pos();
					bag->setX(mPos.x + (mFlip?18.0:-18.0));
					if (Physics::collisions(bag).dir != Collision::NONE)
					{
						bag->setPos(old);
						mFlip = !mFlip;
					}
				}
			}
		}
	}
}

void Baddie::render()
{
	int frame = mFeral ? 2 : 0;
	al_draw_bitmap(mSheet->get(frame + mAnim), mPos.x, mPos.y, 0);
}

void Baddie::load(FILE *f)
{
	Entity::load(f);
	mFeral = loadByte(f);
}

void Baddie::save(FILE *f)
{
	Entity::save(f);
	saveByte(f, mFeral);
}
