//---------------------------------------------------------------------------
// DISRUPTOR ROD
//---------------------------------------------------------------------------
#include "weapons.h"
#include "disruptor.h"

// model defs

// sound defs
#define SND_FIRE               0

// special frame defs

// weapon info def
weaponInfo_t disruptorWeaponInfo = {
      // names, net names, icon
      "weapon_disruptor",
      "Disruptor Rod",
      "ammo_none",
      "No ammo required",
      "iconname",

      // model files
      {"models/disruptor/disruptor.md2",
       NULL},

      // sound files
      {"weapons/disruptorrod/drodhit.wav",
       NULL},

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

      // commands
      {"weapon_disruptor",(void (*)())give,
       "select_disruptor",(void (*)())select,
       NULL},

      use,
      command,
      sizeof(disruptor_t),

      100,
};

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

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

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

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

		if (rnd () < 0.5)
			sprintf (msg, "%s takes %s's axe to the head.\n", ki->victim->netname, ki->attacker->netname);
		else
			sprintf (msg, "%s shoves an axe 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;

   winfoAnimDelay(self,winfo,ANIM_SHOOT_STD,0.05);

   // zap entity on frame 12
   phook->fxFrameNum=winfoFirstFrame(ANIM_SHOOT_STD)+8;
   phook->fxFrameFunc=zap_func;
}

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

   untrackLight(self);
   phook->fxFrameFunc=NULL;
}

//---------------------------------------------------------------------------
// zap_func()
//---------------------------------------------------------------------------
static void zap_func(userEntity_t *self)
{
   userEntity_t *weapon=(userEntity_t *)self->client->ps.weapon;
   disruptor_t *disruptor=(disruptor_t *)self->curWeapon;
   playerHook_t *phook=(playerHook_t *)self->userHook;
   stunInfo_t *stun;
   Vector start,end,dir;
	trace_t tr;
   short inlist=false;

   trackLight(self,200,0,0,1);
   phook->fxFrameNum += 4;
   phook->fxFrameFunc=zapFlashOff;

   winfoPlay(SND_FIRE,255);

   // 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 (tr.ent && tr.ent->takedamage && tr.ent->deadflag == DEAD_NO)
   {
      short loop;

      // ent already in list?
      for (loop=0; loop<MAX_STUN; loop++)
         if (disruptor->stun[loop].ent==tr.ent)
         {
            inlist=true;
            break;
         }

      if (!inlist)
         for (loop=0; loop<MAX_STUN; loop++)
            if (!disruptor->stun[loop].ent)
               break;

      if (loop != MAX_STUN)
      {
         Vector pos=Vector(self->s.origin)+Vector(0,0,10);

         gstate->WriteByte(SVC_TEMP_ENTITY);
         gstate->WriteByte(TE_BLUE_SPARKS);
         gstate->WritePosition(pos.vec());
         gstate->MultiCast(self->s.origin,MULTICAST_ALL);

			com->Damage(tr.ent,self,self,tr.endpos,dir.vec(),20,DAMAGE_INERTIAL);
         if (!inlist && tr.ent->health>0)
         {
            // save info, do damage
            stun=&disruptor->stun[loop];
            stun->ent=tr.ent;
            stun->time=gstate->time+5;

            // save state
            stun->old_prethink=stun->ent->prethink;
            stun->old_think=stun->ent->think;
            stun->old_pain=stun->ent->pain;
            stun->old_die=stun->ent->die;
            stun->old_movetype=stun->ent->movetype;
            VectorCopy(stun->ent->velocity,stun->old_velocity);
            VectorCopy(stun->ent->avelocity,stun->old_avelocity);

            stun->ent->pain=NULL;
            stun->ent->die=NULL;
            stun->ent->prethink=NULL;
            stun->ent->velocity[0]=stun->ent->velocity[1]=0;
            stun->ent->avelocity[0]=stun->ent->avelocity[1]=0;
            stun->ent->movetype=MOVETYPE_TOSS;
            stun->ent->clipmask=MASK_SOLID;
            stun->ent->owner=(userEntity_t *)self->curWeapon;

            // change entity's think to stunned
            stun->ent->think=stunned;
            stun->ent->nextthink=gstate->time+.1;
         }
      }
   }
}

//---------------------------------------------------------------------------
// stunned()
//---------------------------------------------------------------------------
static void stunned(userEntity_t *self)
{
   disruptor_t *disruptor=(disruptor_t *)self->owner;
   stunInfo_t *stun;
   Vector pos,angles;
   short loop;

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

   for (loop=0; loop<MAX_STUN; loop++)
      if (disruptor->stun[loop].ent==self)
         break;

   if (loop==MAX_STUN)
   {
      gstate->Con_Printf("stunned(): stunned entity not in list!!");
      return;
   }

   stun=&disruptor->stun[loop];

   stun->ent->clipmask=MASK_SOLID;
//   com->Damage(self,self,self,self->s.origin,zero_vector,20,DAMAGE_INERTIAL);

   angles=Vector(self->s.angles);
   angles.Normalize();

   pos=Vector(self->s.origin);
   forward = rnd() > .5 ? forward : -forward;
   right = rnd() > .5 ? right : -right;
   up = rnd() > .5 ? up : -up;
   pos=pos+Vector(0,0,self->size[2]*.5*rnd())+(forward*rnd()*8)+(right*rnd()*8);

   // sparks around enemy
   if (rnd() > .5)
   {
      gstate->WriteByte (SVC_TEMP_ENTITY);
      gstate->WriteByte (TE_BLUE_SPARKS);
      gstate->WritePosition (pos.vec());
      gstate->MultiCast (self->s.origin, MULTICAST_ALL);
   }

   // time to unstun?
   if (gstate->time >= stun->time)
   {
      playerHook_t *phook=(playerHook_t *)stun->ent->userHook;

      stun->ent->prethink=stun->old_prethink;
      stun->ent->think=stun->old_think;
      stun->ent->pain=stun->old_pain;
      stun->ent->die=stun->old_die;
      stun->ent->movetype=stun->old_movetype;
      phook->tempgoal_search_time=-1;
      phook->goal_search_time=-1;
      VectorCopy(stun->old_velocity,stun->ent->velocity);
      VectorCopy(stun->old_avelocity,stun->ent->avelocity);
      stun->ent->owner=NULL;
      stun->ent=NULL;
   }
}
