#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "p_enemy.h"
#include "a_action.h"
#include "p_pspr.h"
#include "gstrings.h"
#include "a_hexenglobal.h"

const int SHARDSPAWN_LEFT	= 1;
const int SHARDSPAWN_RIGHT	= 2;
const int SHARDSPAWN_UP		= 4;
const int SHARDSPAWN_DOWN	= 8;

static FRandom pr_cone ("FireConePL1");

void A_FireConePL1 (AActor *actor);
void A_ShedShard (AActor *);

// The Mage's Frost Cone ----------------------------------------------------

class AMWeapFrost : public AMageWeapon
{
	DECLARE_ACTOR (AMWeapFrost, AMageWeapon)
public:
	const char *PickupMessage ()
	{
		return GStrings (TXT_WEAPON_M2);
	}
};

FState AMWeapFrost::States[] =
{
#define S_COS1 0
	S_BRIGHT (WMCS, 'A',	8, NULL					    , &States[S_COS1+1]),
	S_BRIGHT (WMCS, 'B',	8, NULL					    , &States[S_COS1+2]),
	S_BRIGHT (WMCS, 'C',	8, NULL					    , &States[S_COS1]),

#define S_CONEREADY (S_COS1+3)
	S_NORMAL (CONE, 'A',	1, A_WeaponReady		    , &States[S_CONEREADY]),

#define S_CONEDOWN (S_CONEREADY+1)
	S_NORMAL (CONE, 'A',	1, A_Lower				    , &States[S_CONEDOWN]),

#define S_CONEUP (S_CONEDOWN+1)
	S_NORMAL (CONE, 'A',	1, A_Raise				    , &States[S_CONEUP]),

#define S_CONEATK (S_CONEUP+1)
	S_NORMAL (CONE, 'B',	3, NULL					    , &States[S_CONEATK+1]),
	S_NORMAL (CONE, 'C',	4, NULL					    , &States[S_CONEATK+2]),
	S_NORMAL (CONE, 'D',	3, NULL					    , &States[S_CONEATK+3]),
	S_NORMAL (CONE, 'E',	5, NULL					    , &States[S_CONEATK+4]),
	S_NORMAL (CONE, 'F',	3, A_FireConePL1		    , &States[S_CONEATK+5]),
	S_NORMAL (CONE, 'G',	3, NULL					    , &States[S_CONEATK+6]),
	S_NORMAL (CONE, 'A',	9, NULL					    , &States[S_CONEATK+7]),
	S_NORMAL (CONE, 'A',   10, A_ReFire				    , &States[S_CONEREADY]),
};

IMPLEMENT_ACTOR (AMWeapFrost, Hexen, 53, 36)
	PROP_Flags (MF_SPECIAL)
	PROP_SpawnState (S_COS1)

	PROP_Weapon_SelectionOrder (1700)
	PROP_Weapon_AmmoUse1 (3)
	PROP_Weapon_AmmoGive1 (25)
	PROP_Weapon_UpState (S_CONEUP)
	PROP_Weapon_DownState (S_CONEDOWN)
	PROP_Weapon_ReadyState (S_CONEREADY)
	PROP_Weapon_AtkState (S_CONEATK)
	PROP_Weapon_HoldAtkState (S_CONEATK+2)
	PROP_Weapon_Kickback (150)
	PROP_Weapon_YAdjust (20)
	PROP_Weapon_MoveCombatDist (19000000)
	PROP_Weapon_AmmoType1 ("Mana1")
	PROP_Weapon_ProjectileType ("FrostMissile")
END_DEFAULTS

// Frost Missile ------------------------------------------------------------

class AFrostMissile : public AActor
{
	DECLARE_ACTOR (AFrostMissile, AActor)
public:
	int DoSpecialDamage (AActor *victim, int damage);
};

FState AFrostMissile::States[] =
{
	S_BRIGHT (SHRD, 'A',	2, NULL					    , &States[1]),
	S_BRIGHT (SHRD, 'A',	3, A_ShedShard			    , &States[2]),
	S_BRIGHT (SHRD, 'B',	3, NULL					    , &States[3]),
	S_BRIGHT (SHRD, 'C',	3, NULL					    , &States[0]),

#define S_SHARDFXE1_1 (4)
	S_BRIGHT (SHEX, 'A',	5, NULL					    , &States[S_SHARDFXE1_1+1]),
	S_BRIGHT (SHEX, 'B',	5, NULL					    , &States[S_SHARDFXE1_1+2]),
	S_BRIGHT (SHEX, 'C',	5, NULL					    , &States[S_SHARDFXE1_1+3]),
	S_BRIGHT (SHEX, 'D',	5, NULL					    , &States[S_SHARDFXE1_1+4]),
	S_BRIGHT (SHEX, 'E',	5, NULL					    , NULL),
};

IMPLEMENT_ACTOR (AFrostMissile, Hexen, -1, 0)
	PROP_SpeedFixed (25)
	PROP_RadiusFixed (13)
	PROP_HeightFixed (8)
	PROP_Damage (1)
	PROP_DamageType (MOD_ICE)
	PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE)
	PROP_Flags2 (MF2_NOTELEPORT|MF2_IMPACT|MF2_PCROSS)

	PROP_SpawnState (0)
	PROP_DeathState (S_SHARDFXE1_1)

	PROP_DeathSound ("MageShardsExplode")
END_DEFAULTS

int AFrostMissile::DoSpecialDamage (AActor *victim, int damage)
{
	if (special2 > 0)
	{
		damage <<= special2;
	}
	return damage;
}

// Ice Shard ----------------------------------------------------------------

class AIceShard : public AFrostMissile
{
	DECLARE_ACTOR (AIceShard, AFrostMissile)
};

FState AIceShard::States[] =
{
	S_BRIGHT (SHRD, 'A',	3, NULL					    , &States[1]),
	S_BRIGHT (SHRD, 'B',	3, NULL					    , &States[2]),
	S_BRIGHT (SHRD, 'C',	3, NULL					    , &States[0]),
};

IMPLEMENT_ACTOR (AIceShard, Hexen, -1, 65)
	PROP_DamageType (MOD_ICE)
	PROP_Flags2 (MF2_NOTELEPORT)
	PROP_SpawnState (0)
END_DEFAULTS

//============================================================================
//
// A_FireConePL1
//
//============================================================================

void A_FireConePL1 (AActor *actor)
{
	angle_t angle;
	int damage;
	int slope;
	int i;
	AActor *mo;
	bool conedone=false;
	player_t *player;

	if (NULL == (player = actor->player))
	{
		return;
	}

	AWeapon *weapon = actor->player->ReadyWeapon;
	if (weapon != NULL)
	{
		if (!weapon->DepleteAmmo (weapon->bAltFire))
			return;
	}
	S_Sound (actor, CHAN_WEAPON, "MageShardsFire", 1, ATTN_NORM);

	damage = 90+(pr_cone()&15);
	for (i = 0; i < 16; i++)
	{
		angle = actor->angle+i*(ANG45/16);
		slope = P_AimLineAttack (actor, angle, MELEERANGE);
		if (linetarget)
		{
			P_DamageMobj (linetarget, actor, actor, damage, MOD_ICE);
			conedone = true;
			break;
		}
	}

	// didn't find any creatures, so fire projectiles
	if (!conedone)
	{
		mo = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(AFrostMissile));
		if (mo)
		{
			mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
				|SHARDSPAWN_RIGHT;
			mo->special2 = 3; // Set sperm count (levels of reproductivity)
			mo->target = actor;
			mo->args[0] = 3;		// Mark Initial shard as super damage
		}
	}
}

//============================================================================
//
// A_ShedShard
//
//============================================================================

void A_ShedShard (AActor *actor)
{
	AActor *mo;
	int spawndir = actor->special1;
	int spermcount = actor->special2;

	if (spermcount <= 0) return;				// No sperm left
	actor->special2 = 0;
	spermcount--;

	// every so many calls, spawn a new missile in its set directions
	if (spawndir & SHARDSPAWN_LEFT)
	{
		mo = P_SpawnMissileAngleZSpeed (actor, actor->z, RUNTIME_CLASS(AFrostMissile), actor->angle+(ANG45/9),
											 0, (20+2*spermcount)<<FRACBITS, actor->target);
		if (mo)
		{
			mo->special1 = SHARDSPAWN_LEFT;
			mo->special2 = spermcount;
			mo->momz = actor->momz;
			mo->args[0] = (spermcount==3)?2:0;
		}
	}
	if (spawndir & SHARDSPAWN_RIGHT)
	{
		mo = P_SpawnMissileAngleZSpeed (actor, actor->z, RUNTIME_CLASS(AFrostMissile), actor->angle-(ANG45/9),
											 0, (20+2*spermcount)<<FRACBITS, actor->target);
		if (mo)
		{
			mo->special1 = SHARDSPAWN_RIGHT;
			mo->special2 = spermcount;
			mo->momz = actor->momz;
			mo->args[0] = (spermcount==3)?2:0;
		}
	}
	if (spawndir & SHARDSPAWN_UP)
	{
		mo = P_SpawnMissileAngleZSpeed (actor, actor->z+8*FRACUNIT, RUNTIME_CLASS(AFrostMissile), actor->angle, 
											 0, (15+2*spermcount)<<FRACBITS, actor->target);
		if (mo)
		{
			mo->momz = actor->momz;
			if (spermcount & 1)			// Every other reproduction
				mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
			else
				mo->special1 = SHARDSPAWN_UP;
			mo->special2 = spermcount;
			mo->args[0] = (spermcount==3)?2:0;
		}
	}
	if (spawndir & SHARDSPAWN_DOWN)
	{
		mo = P_SpawnMissileAngleZSpeed (actor, actor->z-4*FRACUNIT, RUNTIME_CLASS(AFrostMissile), actor->angle, 
											 0, (15+2*spermcount)<<FRACBITS, actor->target);
		if (mo)
		{
			mo->momz = actor->momz;
			if (spermcount & 1)			// Every other reproduction
				mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
			else
				mo->special1 = SHARDSPAWN_DOWN;
			mo->special2 = spermcount;
			mo->target = actor->target;
			mo->args[0] = (spermcount==3)?2:0;
		}
	}
}
