#include "igor.h"
#include "../stdai.h"
#include "../ai.h"
#include "../sym/smoke.h"
#include "../../ObjManager.h"
#include "../../trig.h"
#include "../ai.h"
#include "../../sound/sound.h"
#include "../../common/misc.h"

#include "../../game.h"
#include "../../player.h"
#include "../../autogen/sprites.h"


#define IGOR_DEFEAT_FRAME		12


INITFUNC(AIRoutines)
{
	ONTICK(OBJ_NPC_IGOR, ai_npc_igor);
	
	ONTICK(OBJ_BOSS_IGOR, ai_boss_igor);
	ONTICK(OBJ_IGOR_SHOT, ai_generic_angled_shot);
	
	ONTICK(OBJ_BOSS_IGOR_DEFEATED, ai_boss_igor_defeated);
}

/*
void c------------------------------() {}
*/

// cutscene igor
void ai_npc_igor(Object *o)
{
	switch(o->state)
	{
		case 0:		// init, standing/panting
			o->xinertia = 0;
			o->frame = 0;
			o->animtimer = 0;
			o->state = 1;
		case 1:
			ANIMATE(5, 0, 1);
		break;
		
		case 2:		// walking
			o->state = 3;
			o->frame = 2;
			o->animtimer = 0;
		case 3:
			ANIMATE(3, 2, 5);
			XMOVE(0x200);
		break;
		
		case 4:		// punch
			o->xinertia = 0;
			o->state = 5;
			o->timer = 0;
		case 5:
			o->frame = 6;
			if (++o->timer > 10)
			{
				o->timer = 0;
				o->state = 6;
				sound(SND_EXPL_SMALL);
			}
		break;
		case 6:
			o->frame = 7;
			if (++o->timer > 8)
			{
				o->state = 0;
				o->frame = 0;
			}
		break;
		
		case 7:
			o->state = 1;
		break;
	}
	
	o->yinertia += 0x40;
	LIMITY(0x5FF);
}

/*
void c------------------------------() {}
*/

// boss-fight igor
void ai_boss_igor(Object *o)
{
	enum
	{
		STATE_INIT = 0,
		STATE_STAND,
		
		STATE_BEGIN_ATTACK,
		STATE_WALK,
		
		STATE_JUMPING,
		STATE_LANDED,
		
		STATE_PUNCH,
		STATE_PUNCH_2,
		STATE_PUNCH_3,
		
		STATE_MOUTH_BLAST,
		STATE_MOUTH_BLAST_2
	};
	
	switch(o->state)
	{
		case STATE_INIT:
		{
			o->damage = 0;
			o->xinertia = 0;
			
			o->state = STATE_STAND;
			o->frame = 0;
			o->animtimer = 0;
		}
		case STATE_STAND:
		{
			ANIMATE(5, 0, 1);
			if (++o->timer > 50)
			{
				o->state = STATE_BEGIN_ATTACK;
			}
		}
		break;
		
		case STATE_BEGIN_ATTACK:
		{
			o->state = STATE_WALK;
			o->frame = 2;
			o->animtimer = 0;
			o->timer = 0;
			
			FACEPLAYER;
			o->igor.fireattack = false;
			
			// when health is less than halfway, then use
			// the mouth blast attack every third time.
			if (++o->timer2 >= 3 && \
				o->hp <= (objprop[o->type].initial_hp / 2))
			{
				o->timer2 = 0;
				o->igor.fireattack = true;
				o->dir ^= 1;	// walk away from player
			}
			
		}	// fall thru
		case STATE_WALK:
		{
			ANIMATE(3, 2, 5);
			XMOVE(0x200);
			
			if (o->igor.fireattack)
			{	// begin mouth-blast attack
				if (++o->timer > 16)
				{
					o->state = STATE_MOUTH_BLAST;
					o->xinertia = 0;
					o->frame = 10;
				}
			}
			else
			{
				if (o->dir == LEFT)
				{
					if (o->x <= player->x + player->Width())
						o->state = STATE_PUNCH;
				}
				else
				{
					if (o->x + o->Width() >= player->x)
						o->state = STATE_PUNCH;
				}
				
				// if we don't reach him after a while, do a jump
				if (++o->timer > 50)
				{
					o->frame = 10;
					o->yinertia = -0x400;
					o->state = STATE_JUMPING;
					o->timer = 0;
					
					o->xinertia *= 2;
					o->xinertia /= 3;
					
					o->damage = 2;
				}
			}
		}
		break;
		
		case STATE_PUNCH:
		{
			o->xinertia = 0;
			
			o->state = STATE_PUNCH_2;
			o->frame = 6;
			o->timer = 0;
		}
		case STATE_PUNCH_2:
		{
			if (++o->timer > 12)
			{
				sound(SND_EXPL_SMALL);
				
				// sprite appears identical, but has a wider bounding box.
				o->sprite = SPR_IGOR_PUNCHING;
				o->damage = 5;
				
				o->state = STATE_PUNCH_3;
				o->frame = 7;
				o->timer = 0;
			}
		}
		break;
		case STATE_PUNCH_3:
		{
			if (++o->timer > 10)
			{
				o->state = STATE_INIT;
				o->frame = 0;
				o->damage = 0;
				
				// return to normal-size bounding box
				o->sprite = SPR_IGOR;
			}
		}
		break;
		
		case STATE_JUMPING:
		{
			if (o->blockd)
			{
				sound(SND_QUAKE);
				SmokeSide(o, 4, DOWN);
				
				o->state = STATE_LANDED;
				o->frame = 11;
				o->timer = 0;
			}
		}
		break;
		
		case STATE_LANDED:
		{
			o->xinertia = 0;
			if (++o->timer > 10)
			{
				o->state = STATE_INIT;
				o->frame = 0;
				o->damage = 0;
			}
		}
		break;
		
		case STATE_MOUTH_BLAST:
		{
			FACEPLAYER;
			o->timer = 0;
			o->state++;
		}
		case STATE_MOUTH_BLAST_2:
		{
			o->timer++;
			
			// flash mouth
			o->frame = 8;
			if (o->timer > 50 && (o->timer & 2))
				o->frame = 9;
			
			// fire shots
			if (o->timer > 100)
			{
				if ((o->timer % 6) == 1)
				{
					sound(SND_BLOCK_DESTROY);
					Object *shot = SpawnObjectAtActionPoint(o, OBJ_IGOR_SHOT);
					
					int angle = (o->dir == LEFT) ? 136 : 248;
					angle += random(-16, 16);
					ThrowObjectAtAngle(shot, angle, 0x580);
				}
				
				if (o->timer > 132)		// fires 6 shots
				{
					o->state = STATE_INIT;
					o->timer = 0;
				}
			}
		}
		break;
	}
	
	o->yinertia += 0x40;
	LIMITY(0x5ff);
}


void ai_boss_igor_defeated(Object *o)
{
	switch(o->state)
	{
		case 0:
		{
			o->xinertia = 0;
			o->yinertia = 0;
			o->flags &= ~FLAG_SHOOTABLE;
			o->frame = IGOR_DEFEAT_FRAME;
			
			FACEPLAYER;
			sound(SND_BIG_CRASH);
			
			SmokeBoomUp(o);
			
			o->timer = 0;
			o->state = 1;
		}
		break;
		
		case 1:
		{
			if ((++o->timer % 5) == 0)
				smoke_puff(o, false);
			
			o->display_xoff = 0;
			if (o->timer & 2)
				o->display_xoff = -1;
			
			if (o->timer > 100)
			{
				o->xmark = o->x;
				o->ymark = o->y;
				
				o->timer = 0;
				o->state = 2;
			}
		}
		break;
		
		case 2:
		{
			if ((++o->timer % 9) == 0)
				smoke_puff(o, false);
			
			// alternate between big and small sprites
			// (frenzied/not-frenzied forms)
			if (o->timer & 2)
			{
				o->sprite = SPR_IGOR_DEFEATED;
				o->frame = 0;
				
				if (o->dir == LEFT)
					o->x = o->xmark + (12 * CSFI);
				else
					o->x = o->xmark + (2 * CSFI);
				
				o->y = o->ymark + (12 * CSFI);
			}
			else
			{
				o->sprite = SPR_IGOR;
				o->frame = IGOR_DEFEAT_FRAME;
				
				o->x = o->xmark;
				o->y = o->ymark;
			}
			
			if (o->timer > 150)
			{
				o->state = 3;
				o->frame = 0;
				o->timer = 0;
			}
		}
		break;
		
		case 3:
		{
			if (++o->timer > 50)
			{
				o->timer = 0;
				o->frame++;
				
				if (o->frame >= 2)
					o->state = 4;
			}
			
			if (o->frame == 0 && (o->timer % 16) == 0)
				smoke_puff(o, false);
		}
		break;
		
		case 4: break;
	}
	
	o->yinertia += 0x40;
	LIMITY(0x5ff);
}


static void smoke_puff(Object *o, bool initial)
{
Object *smoke;

	smoke = CreateObject(o->CenterX() + random(-16 * CSFI, 16 * CSFI),
						 o->CenterY() + random(-16 * CSFI, 16 * CSFI),
						 OBJ_SMOKE_CLOUD);
	
	if (initial)
	{
		smoke->xinertia = random(-0x155, 0x155);
		smoke->yinertia = random(-0x600, 0);
	}
	else
	{
		smoke->xinertia = random(-0x600, 0x600);
		smoke->yinertia = random(-0x600, 0x600);
	}
}
