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

void A_AlertOthers (AActor *);
void A_CloseUpShop (AActor *);
void A_ClearSoundTarget (AActor *);
void A_PlayActiveSound (AActor *);

// Base class for the merchants ---------------------------------------------

class AMerchant : public AActor
{
	DECLARE_ACTOR (AMerchant, AActor)
public:
	int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype);
};

FState AMerchant::States[] =
{
#define S_MERCHANT_YES 0
	S_NORMAL (MRYS, 'A',   20, NULL,				&States[S_MERCHANT_YES+6]),

#define S_MERCHANT_NO (S_MERCHANT_YES+1)
	S_NORMAL (MRNO, 'A',	6, NULL,				&States[S_MERCHANT_NO+1]),
	S_NORMAL (MRNO, 'B',	6, NULL,				&States[S_MERCHANT_NO+2]),
	S_NORMAL (MRNO, 'C',   10, NULL,				&States[S_MERCHANT_NO+3]),
	S_NORMAL (MRNO, 'B',	6, NULL,				&States[S_MERCHANT_NO+4]),
	S_NORMAL (MRNO, 'A',	6, NULL,				&States[S_MERCHANT_NO+5]),
	
#define S_MERCHANT_STND (S_MERCHANT_NO+5)
	S_NORMAL (MRST, 'A',   10, A_Look2,				&States[S_MERCHANT_STND]),

#define S_MERCHANT_LOOK1 (S_MERCHANT_STND+1)
	// This actually uses A_LoopActiveSound, but since that doesn't actually
	// loop in Strife, this is probably better, eh?
	S_NORMAL (MRLK, 'A',   30, A_PlayActiveSound,	&States[S_MERCHANT_STND]),

#define S_MERCHANT_LOOK2 (S_MERCHANT_LOOK1+1)
	S_NORMAL (MRLK, 'B',   30, NULL,				&States[S_MERCHANT_STND]),

#define S_MERCHANT_BD (S_MERCHANT_LOOK2+1)
	S_NORMAL (MRBD, 'A',	4, NULL,				&States[S_MERCHANT_BD+1]),
	S_NORMAL (MRBD, 'B',	4, NULL,				&States[S_MERCHANT_BD+2]),
	S_NORMAL (MRBD, 'C',	4, NULL,				&States[S_MERCHANT_BD+3]),
	S_NORMAL (MRBD, 'D',	4, NULL,				&States[S_MERCHANT_BD+4]),
	S_NORMAL (MRBD, 'E',	4, NULL,				&States[S_MERCHANT_BD+5]),
	S_NORMAL (MRBD, 'D',	4, NULL,				&States[S_MERCHANT_BD+6]),
	S_NORMAL (MRBD, 'C',	4, NULL,				&States[S_MERCHANT_BD+7]),
	S_NORMAL (MRBD, 'B',	4, NULL,				&States[S_MERCHANT_BD+8]),
	S_NORMAL (MRBD, 'A',	5, NULL,				&States[S_MERCHANT_BD+9]),
	S_NORMAL (MRBD, 'F',	6, NULL,				&States[S_MERCHANT_STND]),

#define S_MERCHANT_PAIN (S_MERCHANT_BD+10)
	S_NORMAL (MRPN, 'A',	3, A_AlertOthers,		&States[S_MERCHANT_PAIN+1]),
	S_NORMAL (MRPN, 'B',	3, A_Pain,				&States[S_MERCHANT_PAIN+2]),
	S_NORMAL (MRPN, 'C',	3, NULL,				&States[S_MERCHANT_PAIN+3]),
	S_NORMAL (MRPN, 'D',	9, A_CloseUpShop,		&States[S_MERCHANT_PAIN+4]),
	S_NORMAL (MRPN, 'C',	4, NULL,				&States[S_MERCHANT_PAIN+5]),
	S_NORMAL (MRPN, 'B',	3, NULL,				&States[S_MERCHANT_PAIN+6]),
	S_NORMAL (MRPN, 'A',	3, A_ClearSoundTarget,	&States[S_MERCHANT_STND]),

#define S_MERCHANT_GT (S_MERCHANT_PAIN+7)
	S_NORMAL (MRGT, 'A',	5, NULL,				&States[S_MERCHANT_GT+1]),
	S_NORMAL (MRGT, 'B',	5, NULL,				&States[S_MERCHANT_GT+2]),
	S_NORMAL (MRGT, 'C',	5, NULL,				&States[S_MERCHANT_GT+3]),
	S_NORMAL (MRGT, 'D',	5, NULL,				&States[S_MERCHANT_GT+4]),
	S_NORMAL (MRGT, 'E',	5, NULL,				&States[S_MERCHANT_GT+5]),
	S_NORMAL (MRGT, 'F',	5, NULL,				&States[S_MERCHANT_GT+6]),
	S_NORMAL (MRGT, 'G',	5, NULL,				&States[S_MERCHANT_GT+7]),
	S_NORMAL (MRGT, 'H',	5, NULL,				&States[S_MERCHANT_GT+8]),
	S_NORMAL (MRGT, 'I',	5, NULL,				&States[S_MERCHANT_STND])
};

IMPLEMENT_ACTOR (AMerchant, Strife, -1, 0)
	PROP_SpawnState (S_MERCHANT_STND)
	PROP_SeeState (S_MERCHANT_PAIN)
	PROP_PainState (S_MERCHANT_PAIN)
	PROP_GreetingsState (S_MERCHANT_GT)
	PROP_YesState (S_MERCHANT_YES)
	PROP_NoState (S_MERCHANT_NO)

	PROP_SpawnHealthLong (10000000)
	PROP_PainChance (150)
	PROP_RadiusFixed (20)
	PROP_HeightFixed (56)
	PROP_Mass (5000)
	PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH)
	PROP_Flags4 (MF4_NOSPLASHALERT)
END_DEFAULTS

int AMerchant::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype)
{
	target = source;
	if (PainState != NULL)
	{
		SetState (PainState);
	}
	return -1;
}

// Weapon Smith -------------------------------------------------------------

class AWeaponSmith : public AMerchant
{
	DECLARE_STATELESS_ACTOR (AWeaponSmith, AMerchant)
};

IMPLEMENT_STATELESS_ACTOR (AWeaponSmith, Strife, 116, 0)
	PROP_StrifeType (2)
	PROP_StrifeTeaserType (2)
	PROP_StrifeTeaserType2 (2)
	PROP_PainSound ("smith/pain")
	PROP_Tag ("Weapon_Smith")
END_DEFAULTS

// Bar Keep -----------------------------------------------------------------

class ABarKeep : public AMerchant
{
	DECLARE_STATELESS_ACTOR (ABarKeep, AMerchant)
};

IMPLEMENT_STATELESS_ACTOR (ABarKeep, Strife, 72, 0)
	PROP_Translation (TRANSLATION_Standard, 4)
	PROP_StrifeType (3)
	PROP_StrifeTeaserType (3)
	PROP_StrifeTeaserType2 (3)
	PROP_PainSound ("barkeep/pain")
	PROP_ActiveSound ("barkeep/active")
	PROP_Tag ("Bar_Keep")
END_DEFAULTS

// Armorer ------------------------------------------------------------------

class AArmorer : public AMerchant
{
	DECLARE_STATELESS_ACTOR (AArmorer, AMerchant)
};

IMPLEMENT_STATELESS_ACTOR (AArmorer, Strife, 73, 0)
	PROP_Translation (TRANSLATION_Standard, 5)
	PROP_StrifeType (4)
	PROP_StrifeTeaserType (4)
	PROP_StrifeTeaserType2 (4)
	PROP_PainSound ("armorer/pain")
	PROP_Tag ("Aromorer")
END_DEFAULTS

// Medic --------------------------------------------------------------------

class AMedic : public AMerchant
{
	DECLARE_STATELESS_ACTOR (AMedic, AMerchant)
};

IMPLEMENT_STATELESS_ACTOR (AMedic, Strife, 74, 0)
	PROP_Translation (TRANSLATION_Standard, 6)
	PROP_StrifeType (5)
	PROP_StrifeTeaserType (5)
	PROP_StrifeTeaserType2 (5)
	PROP_PainSound ("medic/pain")
	PROP_Tag ("Medic")
END_DEFAULTS


//============================================================================
//
// A_AlertOthers
//
// [RH] Split from A_CloseUpShop so that when merchants go into their pain
// state, the very first thing they do is send out an alert, which should
// prevent perpetual store closure. If we wait until A_CloseUpShop to do this,
// it is possible to set up a chain reaction where one merchant sends out the
// alert after another has already cleared their alert, causing that merchant
// to go back on the alert and send out their own alert 9 tics later.
//
//============================================================================

void A_AlertOthers (AActor *self)
{
	if (self->target != NULL && self->target->player != NULL)
	{
		P_NoiseAlert (self->target, self);
	}
}

//============================================================================
//
// A_CloseUpShop
//
//============================================================================

void A_CloseUpShop (AActor *self)
{
	EV_DoDoor (DDoor::doorCloseWaitOpen, NULL, self, 999, 8*FRACUNIT, 120*TICRATE, 0, 0);
}

//============================================================================
//
// A_ClearSoundTarget
//
//============================================================================

void A_ClearSoundTarget (AActor *self)
{
	AActor *actor;

	for (actor = self->Sector->thinglist; actor != NULL; actor = actor->snext)
	{
		actor->LastHeard = NULL;
	}
}

//============================================================================
//
// A_PlayActiveSound
//
//============================================================================

void A_PlayActiveSound (AActor *self)
{
	S_SoundID (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM);
}
