//---------------------------------------------------------------------------
// KINETICORE
//---------------------------------------------------------------------------
#include "weapons.h"
#include "kineticore.h"

// model defs
#define MDL_SHOT              MDL_SPECIAL+0
#define MDL_EXPLOSION         MDL_SPECIAL+1

// sound defs
#define SND_FIRE1             0
#define SND_FIRE2             1
#define SND_EXPLODE           2
#define SND_FLYBY             3

// frame defs
#define ANIM_RELOAD           ANIM_SPECIAL+0

// weapon info def
weaponInfo_t kineticoreWeaponInfo = {
      // names, net names, icon
      "weapon_kineticore",
      "Kineticore",
      "ammo_railball",
      "Rail Ball",
      "iconname",

      // model files
      {"models/kcore/kcore.md2",
       "models/bullet/bullet.sp2",
       NULL},

      // sound files
      {"weapons/kineticore/kcorefire.wav",
       "weapons/kineticore/kcorefire2.wav",
       "weapons/kineticore/kcorewallhit.wav",
       "weapons/ionblaster/ionflyby.wav",
       NULL},

      // frame names
      {MDL_WEAPON_STD,"readya",0,0,
               -1,"goaway",0,0,
               -1,"shoota",0,0,
               -1,"amba",0,0,
               -1,"reload",0,0,
       0,NULL},

      // commands
      {"weapon_kcore",(void (*)())kineticore_give,
       "select_kcore",(void (*)())kineticore_select,
       NULL},

   kineticore_use,
   kineticore_command,
   sizeof(weapon_t),

   150,
};

// local weapon info access
static weaponInfo_t *winfo=&kineticoreWeaponInfo;

//---------------------------------------------------------------------------
// kineticore_give()
//---------------------------------------------------------------------------
static	userInventory_t	*kineticore_give (userEntity_t *self)
{
   return(weaponGive(self,winfo,50));
}

//---------------------------------------------------------------------------
// kineticore_select()
//---------------------------------------------------------------------------
static	void	kineticore_select (userEntity_t *self)
{
   weaponSelect(self,winfo);
}

//---------------------------------------------------------------------------
// kineticore_command()
//---------------------------------------------------------------------------
static	void *kineticore_command (struct userInventory_s *ptr, char *commandStr, void *data)
{
	
	ammo_t	*ammo = (ammo_t *) ptr;
	
	if (!stricmp (commandStr, "death_msg"))
	{
		killerInfo_t	*ki = (killerInfo_t *) data;
		char			msg [80];

		if (rnd () < 0.5)
			sprintf (msg, "%s takes %s's kineticore to the head.\n", ki->victim->netname, ki->attacker->netname);
		else
			sprintf (msg, "%s shoves an kineticore up %s's yam! (and he likes it! HEHE) .\n", ki->attacker->netname, ki->victim->netname);
	}
	else if (!stricmp (commandStr, "ambient"))
   {     // no ambient for this weapon... delete this section when it gets one
   }
   else
      winfoGenericCommand(winfo,ptr,commandStr,data);

	return(NULL);
}

//---------------------------------------------------------------------------
// kcore_impact_think()
//---------------------------------------------------------------------------
void	kcore_impact_think (userEntity_t *hit)
{
	hit->s.frame++;

	if (hit->s.frame > 9)
	{
		gstate->RemoveEntity (hit);
		return;
	}

	hit->nextthink = gstate->time + 0.1;
}

//---------------------------------------------------------------------------
// kcore_impact()
//---------------------------------------------------------------------------
void	kcore_impact (userEntity_t *self, Vector normal)
{
	Vector			ang, org;
	//userEntity_t	*hit;

	normal.Normalize ();

	com->VecToAngles (ang, normal);

	//	move out from wall a bit so we don't clip into it
	org = Vector (self->s.origin) + normal * 0.125;

	gstate->WriteByte (SVC_TEMP_ENTITY);
	gstate->WriteByte (TE_NOVAHIT);
	gstate->WritePosition (org.vec ());
	gstate->WriteAngle (ang.x);
	gstate->WriteAngle (ang.y);
	gstate->WriteAngle (ang.z);
	gstate->MultiCast (self->s.origin, MULTICAST_PVS);
}
			
//---------------------------------------------------------------------------
// kineticore_think()
//---------------------------------------------------------------------------
void	kineticore_think (userEntity_t *self)
{
	if (qv_len (self->velocity) == 0 || self->groundEntity)
	{
		com->free (self->userHook);
		gstate->RemoveEntity (self);
		return;
	}

   if (rnd() < .25)
      winfoPlay(SND_FLYBY,255);

	self->think = kineticore_think;
	self->nextthink = gstate->time + 0.1;
}

//---------------------------------------------------------------------------
// kineticore_touch()
//---------------------------------------------------------------------------
void	kineticore_touch (userEntity_t *self, userEntity_t *other, cplane_t *plane, csurface_t *surf)
{
	kcoreHook_t	*hook = (kcoreHook_t *) self->userHook;
	float		damage;

	if (surf && (surf->flags & SURF_SKY))
	{
		com->free (self->userHook);
		gstate->RemoveEntity (self);
		return;
	}

   winfoPlay(SND_EXPLODE,255);

	if (plane)
		kcore_impact (self, Vector (plane->normal));

	if (qv_len (self->velocity) == 0 || gstate->time >= hook->expire_time)
	{
		com->free (self->userHook);
		gstate->RemoveEntity (self);
		return;
	}

	if (other->takedamage == DAMAGE_NO)
	{
		//	so that reflected shots hit owner
		self->owner = self;

		hook->bounce_count++;
		if (hook->bounce_count >= MAX_BOUNCE)
		{
			com->free (self->userHook);
			gstate->RemoveEntity (self);
		}

		return;
	}

	//	calculate damage based on number of bounces
	damage = 15.0 - (BOUNCE_DAMAGE * (float) hook->bounce_count);
	com->Damage (other, self, self->owner, self->s.origin, zero_vector, damage, DAMAGE_INERTIAL | DAMAGE_INFLICTOR_VEL);

	com->free (self->userHook);
	gstate->RemoveEntity (self);
}

//---------------------------------------------------------------------------
// kineticore_postthink()
//---------------------------------------------------------------------------
void	kineticore_postthink (userEntity_t *self)
{
	Vector		temp;
	kcoreHook_t	*hook = (kcoreHook_t *) self->userHook;

	self->s.frame++;
	if (self->s.frame > 3)
		self->s.frame = 0;

	//	don't let speed decrease from bouncing
	if (qv_len (self->velocity) < 1250.0)
	{
		temp = Vector (self->velocity);
		temp.Normalize ();

		temp = temp * 1250.0;
		temp.set (self->velocity);
	}
}

//---------------------------------------------------------------------------
// kineticore_fire()
//---------------------------------------------------------------------------
void	kineticore_fire (userEntity_t *self)
{
	kcoreHook_t		*hook;
	userEntity_t	*proj;
	Vector			org, temp;

   winfoPlay(SND_FIRE1+rnd()*1.9,255);

	temp = Vector (self->client->v_angle);
	temp.AngleVectors (forward, right, up);

	org = Vector (12, 8, 8);
	proj = weapon_spawn_projectile (self, org, 1250.0, 0.0, "projectile_kineticore");

	proj->movetype = MOVETYPE_BOUNCEMISSILE;               // mdm q2fix
   proj->elasticity=1.9;

   winfoSetModel(proj,MDL_SHOT);
	proj->s.renderfx = SPR_ALPHACHANNEL | RF_TRANSLUCENT;// | SPR_ORIENTED;
	proj->s.render_scale [0] = proj->s.render_scale [1] = proj->s.render_scale [2] = 0.8;

//	com->SetVector(proj->s.render_scale,5,5,5);
	gstate->SetSize (proj, -2, -2, -2, 2, 2, 2);

	//	set up hook
	proj->userHook = (kcoreHook_t *) com->malloc_hook (sizeof (kcoreHook_t), MEM_MALLOC);
	hook = (kcoreHook_t *) proj->userHook;

	hook->bounce_count = 0;
	hook->expire_time = gstate->time + 3.0;

	proj->postthink = kineticore_postthink;
	proj->touch = (touch_t)kineticore_touch;
	proj->think = kineticore_think;
	proj->nextthink = gstate->time + 0.1;
}

//---------------------------------------------------------------------------
// kineticore_usethink()
//---------------------------------------------------------------------------
void	kineticore_usethink (userEntity_t *self)
{
   if (!weaponUseAmmo(self->owner->curWeapon,1))
      return;

	kineticore_fire(self->owner);

	self->team--;
	if (self->team > 0)
	{
		self->nextthink = gstate->time + 0.1;
		self->think = kineticore_usethink;
	}
	else
		gstate->RemoveEntity (self);
}

//---------------------------------------------------------------------------
// kineticore_use()
//---------------------------------------------------------------------------
static	void	kineticore_use (userInventory_s *ptr, userEntity_t *self)
{
	playerHook_t	*phook;
	userEntity_t	*fire_ent;
	int				hit, r;
	char			sound_name [40];

   if (!weaponUseAmmo(self->curWeapon,0))
      return;

	phook = (playerHook_t *) self->userHook;

   winfoAnimDelay(self,winfo,ANIM_SHOOT_STD,.05);

	fire_ent = gstate->SpawnEntity ();
	fire_ent->owner = self;
	fire_ent->modelName = NULL;
	fire_ent->movetype = MOVETYPE_NONE;
	fire_ent->solid = SOLID_NOT;

	fire_ent->team = 5;

	kineticore_usethink (fire_ent);
   gstate->LinkEntity(fire_ent);
}

