#include "actor.h"
#include "m_random.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "s_sound.h"
#include "a_strifeglobal.h"
#include "doomdata.h"

void A_BeShadowyFoe (AActor *);
void A_AcolyteBits (AActor *);
void A_AcolyteDie (AActor *);
void A_HideDecepticon (AActor *);

void A_ShootGun (AActor *);
void A_TossGib (AActor *);
void A_ClearShadow (AActor *);
void A_SetShadow (AActor *);

// Base class for the acolytes ----------------------------------------------

class AAcolyte : public AStrifeHumanoid
{
	DECLARE_ACTOR (AAcolyte, AStrifeHumanoid)
};

FState AAcolyte::States[] =
{
#define S_ACOLYTE_STND 0
	S_NORMAL (AGRD, 'A',	5, A_Look2,				&States[S_ACOLYTE_STND]),
	S_NORMAL (AGRD, 'B',	8, A_ClearShadow,		&States[S_ACOLYTE_STND]),
	S_NORMAL (AGRD, 'D',	8, NULL,				&States[S_ACOLYTE_STND]),

#define S_ACOLYTE_WANDER (S_ACOLYTE_STND+3)
	S_NORMAL (AGRD, 'A',	5, A_Wander,			&States[S_ACOLYTE_WANDER+1]),
	S_NORMAL (AGRD, 'B',	5, A_Wander,			&States[S_ACOLYTE_WANDER+2]),
	S_NORMAL (AGRD, 'C',	5, A_Wander,			&States[S_ACOLYTE_WANDER+3]),
	S_NORMAL (AGRD, 'D',	5, A_Wander,			&States[S_ACOLYTE_WANDER+4]),
	S_NORMAL (AGRD, 'A',	5, A_Wander,			&States[S_ACOLYTE_WANDER+5]),
	S_NORMAL (AGRD, 'B',	5, A_Wander,			&States[S_ACOLYTE_WANDER+6]),
	S_NORMAL (AGRD, 'C',	5, A_Wander,			&States[S_ACOLYTE_WANDER+7]),
	S_NORMAL (AGRD, 'D',	5, A_Wander,			&States[S_ACOLYTE_STND]),

#define S_ACOLYTE_ALTCHASE (S_ACOLYTE_WANDER+8)
	S_NORMAL (AGRD, 'A',	6, A_BeShadowyFoe,		&States[S_ACOLYTE_ALTCHASE+2]),

#define S_ACOLYTE_CHASE (S_ACOLYTE_ALTCHASE+1)
	S_NORMAL (AGRD, 'A',	6, A_AcolyteBits,		&States[S_ACOLYTE_CHASE+1]),
	S_NORMAL (AGRD, 'B',	6, A_Chase,				&States[S_ACOLYTE_CHASE+2]),
	S_NORMAL (AGRD, 'C',	6, A_Chase,				&States[S_ACOLYTE_CHASE+3]),
	S_NORMAL (AGRD, 'D',	6, A_Chase,				&States[S_ACOLYTE_CHASE]),

#define S_ACOLYTE_ATK (S_ACOLYTE_CHASE+4)
	S_NORMAL (AGRD, 'E',	8, A_FaceTarget,		&States[S_ACOLYTE_ATK+1]),
	S_NORMAL (AGRD, 'F',	4, A_ShootGun,			&States[S_ACOLYTE_ATK+2]),
	S_NORMAL (AGRD, 'E',	4, A_ShootGun,			&States[S_ACOLYTE_ATK+3]),
	S_NORMAL (AGRD, 'F',	6, A_ShootGun,			&States[S_ACOLYTE_CHASE]),

#define S_ACOLYTE_ALTPAIN (S_ACOLYTE_ATK+4)
	S_NORMAL (AGRD, 'O',	0, A_SetShadow,			&States[S_ACOLYTE_ALTPAIN+1]),
	S_NORMAL (AGRD, 'O',	8, A_Pain,				&States[S_ACOLYTE_ALTCHASE]),

#define S_ACOLYTE_PAIN (S_ACOLYTE_ALTPAIN+2)
	S_NORMAL (AGRD, 'O',	8, A_Pain,				&States[S_ACOLYTE_CHASE]),

#define S_ACOLYTE_DIE (S_ACOLYTE_PAIN+1)
	S_NORMAL (AGRD, 'G',	4, NULL,				&States[S_ACOLYTE_DIE+1]),
	S_NORMAL (AGRD, 'H',	4, A_Scream,			&States[S_ACOLYTE_DIE+2]),
	S_NORMAL (AGRD, 'I',	4, NULL,				&States[S_ACOLYTE_DIE+3]),
	S_NORMAL (AGRD, 'J',	3, NULL,				&States[S_ACOLYTE_DIE+4]),
	S_NORMAL (AGRD, 'K',	3, A_NoBlocking,		&States[S_ACOLYTE_DIE+5]),
	S_NORMAL (AGRD, 'L',	3, NULL,				&States[S_ACOLYTE_DIE+6]),
	S_NORMAL (AGRD, 'M',	3, A_AcolyteDie,		&States[S_ACOLYTE_DIE+7]),
	S_NORMAL (AGRD, 'N', 1400, NULL,				NULL),

#define S_ACOLYTE_XDIE (S_ACOLYTE_DIE+8)
	S_NORMAL (GIBS, 'A',	5, A_NoBlocking,		&States[S_ACOLYTE_XDIE+1]),
	S_NORMAL (GIBS, 'B',	5, A_TossGib,			&States[S_ACOLYTE_XDIE+2]),
	S_NORMAL (GIBS, 'C',	5, A_TossGib,			&States[S_ACOLYTE_XDIE+3]),
	S_NORMAL (GIBS, 'D',	4, A_TossGib,			&States[S_ACOLYTE_XDIE+4]),
	S_NORMAL (GIBS, 'E',	4, A_XScream,			&States[S_ACOLYTE_XDIE+5]),
	S_NORMAL (GIBS, 'F',	4, A_TossGib,			&States[S_ACOLYTE_XDIE+6]),
	S_NORMAL (GIBS, 'G',	4, NULL,				&States[S_ACOLYTE_XDIE+7]),
	S_NORMAL (GIBS, 'H',	4, NULL,				&States[S_ACOLYTE_XDIE+8]),
	S_NORMAL (GIBS, 'I',	5, NULL,				&States[S_ACOLYTE_XDIE+9]),
	S_NORMAL (GIBS, 'J',	5, A_AcolyteDie,		&States[S_ACOLYTE_XDIE+10]),
	S_NORMAL (GIBS, 'K',	5, NULL,				&States[S_ACOLYTE_XDIE+11]),
	S_NORMAL (GIBS, 'L', 1400, NULL,				NULL),
};

IMPLEMENT_ACTOR (AAcolyte, Strife, -1, 0)
	PROP_SpawnState (S_ACOLYTE_STND)
	PROP_SeeState (S_ACOLYTE_CHASE)
	PROP_PainState (S_ACOLYTE_PAIN)
	PROP_MissileState (S_ACOLYTE_ATK)
	PROP_DeathState (S_ACOLYTE_DIE)
	PROP_XDeathState (S_ACOLYTE_XDIE)

	PROP_SpawnHealth (70)
	PROP_PainChance (150)
	PROP_SpeedFixed (7)
	PROP_RadiusFixed (24)
	PROP_HeightFixed (64)
	PROP_Mass (400)
	PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL)
	PROP_Flags2 (MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_PUSHWALL|MF2_MCROSS)
	PROP_Flags4 (MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
	PROP_MinMissileChance (150)
	PROP_Tag ("ACOLYTE")

	PROP_SeeSound ("acolyte/sight")
	PROP_PainSound ("acolyte/pain")
	PROP_AttackSound ("acolyte/rifle")
	PROP_DeathSound ("acolyte/death")
	PROP_ActiveSound ("acolyte/active")
END_DEFAULTS

// Acolyte 1 ----------------------------------------------------------------

class AAcolyteTan : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteTan, AAcolyte)
public:
	void NoBlockingSet ();
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteTan, Strife, 3002, 0)
	PROP_StrifeType (53)
	PROP_StrifeTeaserType (52)
	PROP_StrifeTeaserType2 (53)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

//============================================================================
//
// AAcolyteTan :: NoBlockingSet
//
// This and the shadow acolyte are the only ones that drop clips by default.
//
//============================================================================

void AAcolyteTan::NoBlockingSet ()
{
	P_DropItem (this, "ClipOfBullets", -1, 256);
}

// Acolyte 2 ----------------------------------------------------------------

class AAcolyteRed : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteRed, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteRed, Strife, 142, 0)
	PROP_Translation (TRANSLATION_Standard, 0)
	PROP_StrifeType (54)
	PROP_StrifeTeaserType (53)
	PROP_StrifeTeaserType2 (54)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

// Acolyte 3 ----------------------------------------------------------------

class AAcolyteRust : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteRust, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteRust, Strife, 143, 0)
	PROP_Translation (TRANSLATION_Standard, 1)
	PROP_StrifeType (55)
	PROP_StrifeTeaserType (54)
	PROP_StrifeTeaserType2 (55)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

// Acolyte 4 ----------------------------------------------------------------

class AAcolyteGray : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteGray, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteGray, Strife, 146, 0)
	PROP_Translation (TRANSLATION_Standard, 2)
	PROP_StrifeType (56)
	PROP_StrifeTeaserType (55)
	PROP_StrifeTeaserType2 (56)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

// Acolyte 5 ----------------------------------------------------------------

class AAcolyteDGreen : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteDGreen, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteDGreen, Strife, 147, 0)
	PROP_Translation (TRANSLATION_Standard, 3)
	PROP_StrifeType (57)
	PROP_StrifeTeaserType (56)
	PROP_StrifeTeaserType2 (57)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

// Acolyte 6 ----------------------------------------------------------------

class AAcolyteGold : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteGold, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteGold, Strife, 148, 0)
	PROP_Translation (TRANSLATION_Standard, 4)
	PROP_StrifeType (58)
	PROP_StrifeTeaserType (57)
	PROP_StrifeTeaserType2 (58)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_MISSILEEVENMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

// Acolyte 7 ----------------------------------------------------------------

class AAcolyteLGreen : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteLGreen, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteLGreen, Strife, 232, 0)
	PROP_Translation (TRANSLATION_Standard, 5)
	PROP_SpawnHealth (60)
	PROP_StrifeType (59)
END_DEFAULTS

// Acolyte 8 ----------------------------------------------------------------

class AAcolyteBlue : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteBlue, AAcolyte)
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteBlue, Strife, 231, 0)
	PROP_Translation (TRANSLATION_Standard, 6)
	PROP_SpawnHealth (60)
	PROP_StrifeType (60)
END_DEFAULTS

// Shadow Acolyte -----------------------------------------------------------

class AAcolyteShadow : public AAcolyte
{
	DECLARE_STATELESS_ACTOR (AAcolyteShadow, AAcolyte)
public:
	void NoBlockingSet ();
};

IMPLEMENT_STATELESS_ACTOR (AAcolyteShadow, Strife, 58, 0)
	PROP_SeeState (S_ACOLYTE_ALTCHASE)
	PROP_PainState (S_ACOLYTE_ALTPAIN)
	PROP_StrifeType (61)
	PROP_StrifeTeaserType (58)
	PROP_StrifeTeaserType2 (59)
	PROP_Flags4 (MF4_MISSILEMORE|MF4_SEESDAGGERS|MF4_NOSPLASHALERT)
END_DEFAULTS

//============================================================================
//
// AAcolyteShadow :: NoBlockingSet
//
// This and the tan acolyte are the only ones that drop clips by default.
//
//============================================================================

void AAcolyteShadow::NoBlockingSet ()
{
	P_DropItem (this, "ClipOfBullets", -1, 256);
}

// Some guy turning into an acolyte -----------------------------------------

class AAcolyteToBe : public AAcolyte
{
	DECLARE_ACTOR (AAcolyteToBe, AAcolyte)
};

FState AAcolyteToBe::States[] =
{
#define S_BECOMING_STND 0
	S_NORMAL (ARMR, 'A',   -1, NULL,				NULL),

#define S_BECOMING_PAIN (S_BECOMING_STND+1)
	S_NORMAL (ARMR, 'A',   -1, A_HideDecepticon,	NULL),

#define S_BECOMING_DIEJUMP (S_BECOMING_PAIN+1)
	S_NORMAL (GIBS, 'A',	0, NULL,				&AAcolyte::States[S_ACOLYTE_XDIE]),
};

IMPLEMENT_ACTOR (AAcolyteToBe, Strife, 201, 0)
	PROP_SpawnState (S_BECOMING_STND)
	PROP_PainState (S_BECOMING_PAIN)
	PROP_DeathState (S_BECOMING_DIEJUMP)

	PROP_SpawnHealth (61)
	PROP_PainChance (255)
	PROP_RadiusFixed (20)
	PROP_HeightFixed (56)
	PROP_StrifeType (29)

	PROP_DeathSound ("becoming/death")
END_DEFAULTS

//============================================================================
//
// A_HideDecepticon
//
// Hide the Acolyte-to-be							->
// Hide the guy transforming into an Acolyte		->
// Hide the transformer								->
// Transformers are Autobots and Decepticons, and
// Decepticons are the bad guys, so...				->
//
// Hide the Decepticon!
//
//============================================================================

void A_HideDecepticon (AActor *self)
{
	EV_DoDoor (DDoor::doorClose, NULL, self, 999, 8*FRACUNIT, 0, 0, 0);
	if (self->target != NULL && self->target->player != NULL)
	{
		P_NoiseAlert (self->target, self);
	}
}

//============================================================================
//
// A_AcolyteDie
//
//============================================================================

void A_AcolyteDie (AActor *self)
{
	int i;

	// Only the Blue Acolyte does extra stuff on death.
	if (!self->IsKindOf (RUNTIME_CLASS(AAcolyteBlue)))
		return;

	// Make sure somebody is still alive
	for (i = 0; i < MAXPLAYERS; ++i)
	{
		if (playeringame[i] && players[i].health > 0)
			break;
	}
	if (i == MAXPLAYERS)
		return;

	// Make sure all the other blue acolytes are dead.
	TThinkerIterator<AAcolyteBlue> iterator;
	AActor *other;

	while ( (other = iterator.Next ()) )
	{
		if (other != self && other->health > 0)
		{ // Found a living one
			return;
		}
	}

	players[0].mo->GiveInventoryType (QuestItemClasses[6]);
	players[0].SetLogNumber (14);
	S_StopSound ((fixed_t *)NULL, CHAN_VOICE);
	S_Sound (CHAN_VOICE, "svox/voc14", 1, ATTN_NORM);
}

//============================================================================
//
// A_BeShadowyFoe
//
//============================================================================

void A_BeShadowyFoe (AActor *self)
{
	self->RenderStyle = STYLE_Translucent;
	self->alpha = HR_SHADOW;
	self->flags &= ~MF_FRIENDLY;
}

//============================================================================
//
// A_AcolyteBits
//
//============================================================================

void A_AcolyteBits (AActor *self)
{
	if (self->SpawnFlags & MTF_SHADOW)
	{
		self->RenderStyle = STYLE_Translucent;
		self->alpha = HR_SHADOW;
		self->flags |= MF_SHADOW;
	}
	if (self->SpawnFlags & MTF_ALTSHADOW)
	{
		//self->flags |= MF_STRIFEx8000000;
		if (self->flags & MF_SHADOW)
		{
			// I dunno.
		}
		else
		{
			self->RenderStyle = STYLE_None;
		}
	}
}
