//---------------------------------------------------------------------------
// NOVABEAM
//---------------------------------------------------------------------------
#include "weapons.h"
#include "novabeam.h"

static void think(userEntity_t *self);

//	for seeing damage totals
static	float	damage_total = 0;

// model defs

// sound defs
#define SND_FIRE              0
#define SND_FIRELOOP          1
#define SND_POWERDOWN         2
#define SND_BARRELIN          3
#define SND_BARRELOUT         4

// frame defs
#define ANIM_UNSHOOT          ANIM_SPECIAL+0

// weapon info def
weaponInfo_t novabeamWeaponInfo = {
      // names, net names, icon
      "weapon_novabeam",
      "Novabeam",
      "ammo_ionpack",
      "shock-sphere",
      "iconname",

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

      // sound files
      {"weapons/novabeam/novafire.wav",
       "weapons/novabeam/novaloop.wav",
       "weapons/novabeam/novapowerdown.wav",
       "weapons/novabeam/novabarrelin.wav",
       "weapons/novabeam/novabarrelout.wav",
       NULL},

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

      // commands
      {"weapon_novabeam",(void (*)())give,
       "select_novabeam",(void (*)())select,
       NULL},

   use,
   command,
   sizeof(novabeam_t),

   150,
};

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

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

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

//---------------------------------------------------------------------------
// command()
//---------------------------------------------------------------------------
static void *command(struct userInventory_s *inv, char *commandStr, void *data)
{
   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 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 if (!stricmp (commandStr, "ambient"))
   {     // no ambient for this weapon... delete this section when it gets one
   }
	else if (!stricmp(commandStr, "change"))
	{
      novabeam_t *novabeam=(novabeam_t *)self->curWeapon;

      winfoAnimDelay((userEntity_t *)data,winfo,ANIM_AWAY_STD,.05);

      if (novabeam->changekill & 1)
      {
         untrackEntity(novabeam->beam,NULL,MULTICAST_ALL);
         if (novabeam->changekill & 2)
            gstate->RemoveEntity(novabeam->beam);
      }
	}
   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;
   novabeam_t *novabeam=(novabeam_t *)self->curWeapon;
   vec3_t vec={0,0,0};
   int hit;
   short loop;

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

	damage_total = 0;

   winfoPlay(SND_FIRE,255);
   winfoPlay(SND_BARRELIN,255);

   winfoAnim(self,ANIM_SHOOT_STD,0.05);
   novabeam->killbeam=gstate->time+NOVABEAM_SHOOT_TIME;
   phook->attack_finished=novabeam->killbeam+2;

   phook->fxFrameNum=winfoLastFrame(ANIM_SHOOT_STD);
   phook->fxFrameFunc=startLaser;
}

//---------------------------------------------------------------------------
// startLaser()
//---------------------------------------------------------------------------
static void startLaser(userEntity_t *self)
{
   playerHook_t *phook=(playerHook_t *)self->userHook;
   novabeam_t *novabeam=(novabeam_t *)self->curWeapon;
   userEntity_t *laser,*went;

   // spawn laser
   laser=gstate->SpawnEntity();
   laser->prethink=think;
   laser->owner=self;
   laser->flags=RF_TRACKENT;        // drawn by client
   laser->s.effects=EF_GIB;         // not really GIBS, makes server send to clients
   laser->s.renderfx=RF_TRANSLUCENT|RF_SHAKE;
	laser->s.frame = 0;              // beam diameter, Nelno: changed for laser
	laser->s.skinnum = GC_RED;       // beam color
	laser->solid = SOLID_NOT;

   novabeam->first_think=true;
   novabeam->endeffect=false;
   novabeam->changekill=3;
   novabeam->beam=laser;
   think(laser);

   went=(userEntity_t *)self->client->ps.weapon;
   went->s.renderfx |= RF_SHAKE;

   phook->fxFrameFunc=NULL;
}

//---------------------------------------------------------------------------
// think()
//---------------------------------------------------------------------------
static void think(userEntity_t *self)
{
   trackInfo_t tinfo;
   novabeam_t *novabeam=(novabeam_t *)self->owner->curWeapon;
   userEntity_t *owner=self->owner,*went;
   weapon_t *weapon=(weapon_t *)owner->curWeapon;
   Vector start,end, dir, offset, ang;
	trace_t tr;
   float timeLeft;
   short ammo;

   timeLeft=novabeam->killbeam-gstate->time;
   ammo=weaponUseAmmo(owner->curWeapon,1);

   // kill beam??
   if (timeLeft <= 0 || !ammo)
   {
      if (!novabeam->endeffect)
      {
         winfoPlay(SND_POWERDOWN,255);

         novabeam->endeffect=true;
   
         // stop shaking weapon
         went=(userEntity_t *)owner->client->ps.weapon;
         went->s.renderfx &= ~RF_SHAKE;

         // stop tracking
         untrackEntity(self,NULL,MULTICAST_ALL);
         novabeam->changekill &= ~1;
      }
      else
      {
         if (timeLeft <= -.5)
         {
            // kill entity
            winfoPlay(SND_BARRELIN,255);
            winfoAnim(self->owner,ANIM_UNSHOOT,0.05);
            gstate->RemoveEntity(self);
            novabeam->changekill &= ~2;
            novabeam->beam=NULL;
         }
      }

//		gstate->Con_Printf ("damage_total = %.2f\n", damage_total);

      return;
   }

   self->s.alpha=timeLeft / NOVABEAM_SHOOT_TIME + .25;
   if (self->s.alpha > 1)
      self->s.alpha=1;

   // set start/end positions
   dir=Vector(owner->client->v_angle);
   dir.AngleVectors(forward,right,up);
	start=Vector(owner->s.origin)+Vector(0,0,20.6)+weaponHandVector(owner,forward*14,right*6);
   end=start+forward*2000;

	tr=gstate->trace_q2(start.vec(),self->s.mins,self->s.maxs,end.vec(),owner,MASK_SHOT);

   start.set(self->s.origin);
   end=Vector(tr.endpos);
   end.set(self->s.old_origin);
   dir.set(self->movedir);
   gstate->LinkEntity(self);

   // hit anything?
   if (tr.ent)
   {
	   if (tr.ent->takedamage)
	   {
			com->Damage (tr.ent, self, self->owner, tr.endpos, forward.vec (), timeLeft*4, DAMAGE_NONE);
//			for debugging damage... might come in useful if we have to readjust again
//			damage_total += timeLeft * 2;
	   }
   }

   // msg client to track this entity
   tinfo.flags=0;
   if (novabeam->first_think)
   {
      // send this info once
      tinfo.srcent=owner;
      tinfo.fru[0]=7;         // forward offset
      tinfo.fru[1]=2.7;       // right offset
      tinfo.fru[2]=.47;       // up offset
      tinfo.flags |= TEF_SRCINDEX|TEF_FRU;
      novabeam->first_think=false;
   }
   tinfo.ent=self;
   tinfo.length=start.vdist(end);
   tinfo.flags |= RF_LASERBEAM|TEF_LENGTH;
   trackEntity(&tinfo,MULTICAST_ALL);

   winfoPlay(SND_FIRELOOP,128);
}

