//---------------------------------------------------------------------------
// VENOMOUS
//---------------------------------------------------------------------------
#include "weapons.h"
#include "venomous.h"

// model defs
#define MDL_APPEAR            MDL_SPECIAL+0
#define MDL_STAND             MDL_SPECIAL+1
#define MDL_DISSIPATE         MDL_SPECIAL+2

// sound defs
#define SND_ATTACK1           0
#define SND_ATTACK2           1
#define	SND_HISS			2

// frame defs
#define ANIM_AMBIENT2         ANIM_SPECIAL+0
#define ANIM_SHOOT2           ANIM_SPECIAL+1

// weapon info def
weaponInfo_t venomousWeaponInfo = {
      // names, net names, icon
      "weapon_venomous",
      "Venomous",
      "ammo_ionpack",
      "shock-sphere",
      "iconname",

      // model files
      {"models/venomous/venomous.md2",
       "models/g_appear/g_appear.sp2",
       "models/g_stand/g_stand.sp2",
       "models/g_dissapate/g_dissapate.sp2",
       NULL},

      // sound files
      {"weapons/venomous/venomousattack1.wav",
       "weapons/venomous/venomousattack2.wav",
       "weapons/venomous/venomoushiss.wav",
       NULL},

      // frame names
      {MDL_WEAPON_STD,"readya",0,0,
               -1,"away",0,0,
               -1,"shootb",0,0,
               -1,"amb",0,0,
               -1,"amba",0,0,
               -1,"shoota",0,0,
       0,NULL},

      // commands
      {"weapon_venomous",(void (*)())give,
       "select_venomous",(void (*)())select,
       NULL},

       use,
       command,
       sizeof(venomous_t),

       400,

      FL_LOOPAMBIENT,			// special flag
	  SND_HISS					// sound for ambient looping
};

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

static userEntity_t *player=NULL;

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

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

//---------------------------------------------------------------------------
// command()
//---------------------------------------------------------------------------
static void *command(struct userInventory_s *inv, char *commandStr, void *data)
{
	ammo_t *ammo=(ammo_t *)inv;
   userEntity_t *self=(userEntity_t *)data;
   playerHook_t *phook=(playerHook_t *)self->userHook;
	
	if (!stricmp(commandStr, "death_msg"))
	{
		killerInfo_t	*ki = (killerInfo_t *) data;
		char			msg [80];

		if (rnd () < 0.5)
			sprintf (msg, "%s takes %s's snake to the head.\n", ki->victim->netname, ki->attacker->netname);
		else
			sprintf (msg, "%s shoves a snake up %s's yam! (and he likes it! HEHE) .\n", ki->attacker->netname, ki->victim->netname);
	}
   else
      winfoGenericCommand(winfo,inv,commandStr,data);

	return(NULL);
}

//---------------------------------------------------------------------------
// use()
//---------------------------------------------------------------------------
static void use(userInventory_s *ptr, userEntity_t *self)
{
   playerHook_t *phook=(playerHook_t *)self->userHook;
   Vector start,end,dir;
	trace_t tr;

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

   // hit anything?
   dir=Vector(self->client->v_angle);
   dir.AngleVectors(forward,right,up);
	start=Vector(self->s.origin)+up*4;
   end=start+forward*100;
	tr=gstate->trace_q2(start.vec(),self->s.mins,self->s.maxs,end.vec(),self,MASK_SHOT);
   end=Vector(tr.endpos);

   if (!strcmp(tr.ent->className,"worldspawn"))       // blow poison
   {
      winfoPlay(SND_ATTACK1,255);

      winfoAnimDelay(self,winfo,ANIM_SHOOT2,0.05);

      phook->fxFrameNum=winfoFirstFrame(ANIM_SHOOT2)+10;
      phook->fxFrameFunc=shoot_func;
   }
   else                                               // short-range attack
   {
      winfoPlay(SND_ATTACK2,255);

      winfoAnimDelay(self,winfo,ANIM_SHOOT_STD,0.05);
      phook->attack_finished=gstate->time+1;             // until short-range attack is finished

      phook->fxFrameNum=winfoFirstFrame(ANIM_SHOOT_STD)+VEN_BITE1_FRAME;
      phook->fxFrameFunc=bite_func;
   }
}

//---------------------------------------------------------------------------
// shoot_func()
//---------------------------------------------------------------------------
static void shoot_func(userEntity_t *self)
{
   playerHook_t *phook=(playerHook_t *)self->userHook;

   phook->fxFrameFunc=NULL;

   blowPoison(self,Vector(10,10,20));
   blowPoison(self,Vector(-10,10,20));
}

//---------------------------------------------------------------------------
// bite_func()
//---------------------------------------------------------------------------
static void bite_func(userEntity_t *self)
{
   playerHook_t *phook=(playerHook_t *)self->userHook;
   Vector start,end,dir;
	trace_t tr;

   if (phook->fxFrameNum==winfoFirstFrame(ANIM_SHOOT_STD)+VEN_BITE1_FRAME)
      phook->fxFrameNum==winfoFirstFrame(ANIM_SHOOT_STD)+VEN_BITE2_FRAME;
   else
      phook->fxFrameFunc=NULL;

   // hit anything?
   dir=Vector(self->client->v_angle);
   dir.AngleVectors(forward,right,up);
	start=Vector(self->s.origin)+up*4;
   end=start+forward*100;
	tr=gstate->trace_q2(start.vec(),self->s.mins,self->s.maxs,end.vec(),self,MASK_SHOT);

   if (tr.ent->takedamage != DAMAGE_NO)
   {
      com->Damage(tr.ent,self,self,tr.endpos,dir.vec(),40,DAMAGE_INERTIAL);

      gstate->WriteByte(SVC_TEMP_ENTITY);
      gstate->WriteByte(TE_BLOOD);
      gstate->WritePosition(end.vec());
      gstate->WriteDir(dir.vec());
      gstate->MultiCast(self->s.origin,MULTICAST_ALL);
   }
}

//---------------------------------------------------------------------------
// blowPoison()
//---------------------------------------------------------------------------
static void blowPoison(userEntity_t *self,Vector &pos)
{
   venomousHook_t *hook;
   userEntity_t *ent;
   Vector angles,vel;

   angles=Vector(self->client->v_angle);
   angles.Normalize();

   ent=weapon_spawn_projectile(self,pos,0,0,winfo->ammoName);
	ent->solid=SOLID_BBOX;
   ent->movetype=MOVETYPE_FLY;
	ent->clipmask=MASK_SHOT;
   ent->think=think_poison;
   ent->nextthink=gstate->time+.1;
   ent->touch=touch_poison;
//   ent->s.effects=EF_POISON;
   ent->s.renderfx=RF_TRANSLUCENT;
   ent->s.alpha=.9;
   gstate->SetSize(ent,-24,-24,-24,24,24,24);
   com->SetVector(ent->s.render_scale,2,2,2);

   vel=Vector(self->velocity);
   vel=vel+forward*VEN_START_SPEED;
   vel.set(ent->velocity);

   winfoSetModel(ent,MDL_APPEAR);

	ent->userHook=com->malloc_hook(sizeof(venomousHook_t),MEM_MALLOC);
   hook=(venomousHook_t *)ent->userHook;
   hook->killtime=gstate->time+5;
   hook->forward=forward;
   hook->mode=VEN_MODE_APPEAR;
}

//---------------------------------------------------------------------------
// think_poison()
//---------------------------------------------------------------------------
static void think_poison(userEntity_t *self)
{
   venomousHook_t *hook=(venomousHook_t *)self->userHook;
   Vector pos,vel;

   self->s.frame++;
   if (hook->mode==VEN_MODE_APPEAR)
   {
      if (self->s.frame>=MAX_VEN_APPEAR_FRAMES)
      {
         hook->mode=VEN_MODE_STAND;
         self->s.frame=0;
         winfoSetModel(self,MDL_STAND);
      }
   }
   else if (hook->mode==VEN_MODE_STAND)
   {
      if (self->s.frame>=MAX_VEN_STAND_FRAMES)
         self->s.frame=0;
   }
   else if (hook->mode==VEN_MODE_DISSIPATE)
   {
      if (self->s.frame>=MAX_VEN_DISSIPATE_FRAMES)
      {
         com->free(self->userHook);
         gstate->RemoveEntity(self);
         return;
      }
   }

   vel=Vector(self->velocity);
   vel=vel*.9;
   vel.set(self->velocity);

   if (gstate->time >= hook->killtime)
   {
      hook->mode=VEN_MODE_DISSIPATE;
      self->s.frame=0;
      winfoSetModel(self,MDL_DISSIPATE);
      hook->killtime=gstate->time+9999;
   }

   self->nextthink=gstate->time+.1;
}

//---------------------------------------------------------------------------
// touch_poison()
//---------------------------------------------------------------------------
static void touch_poison(userEntity_t *self, userEntity_t *other,cplane_t *plane, csurface_t *surf)
{
   venomousHook_t *hook=(venomousHook_t *)self->userHook;
   playerHook_t *ohook=(playerHook_t *)other->userHook;
   Vector vel;
   short loop;

   vel=Vector(0,0,0);
   vel.set(self->velocity);

   if (other->takedamage != DAMAGE_NO)
   {
      if (gstate->time > ohook->poison_time)
      {
         com->Damage(other,self,self,other->s.origin,zero_vector,30,DAMAGE_INERTIAL);
         com->Poison(other, 10, gstate->time + 99999, 1);
      }
   }
   else
   {
      for (loop=0; loop<3; loop++)
         self->s.origin[loop] += plane->normal[loop];
   }
}
