//---------------------------------------------------------------------------
// DISCUS OF DAEDALUS
//---------------------------------------------------------------------------
#include "weapons.h"
#include "discus.h"

#define MIKE_SHIT             1          // for debugging ... slows velocity of disc (velocity / MIKE_SHIT)

#define DISCUS_SPEED          1000

// model defs
#define MDL_DISC              MDL_SPECIAL+0
#define MDL_TRAIL             MDL_SPECIAL+1

// sound defs
#define SND_THROW             0
#define SND_CLANG1            1
#define SND_CLANG2            2
#define SND_CLANG3            3
#define SND_CLANG4            4
#define SND_CLANG5            5
#define SND_HIT               6
#define SND_CATCH             7
#define SND_BLADESIN          8
#define SND_BLADESOUT			9
#define SND_DISCUSLOOP			10
#define SND_HITWALL				11

// frame defs
#define ANIM_AMBIENT2         ANIM_SPECIAL+0
#define ANIM_AMBIENT3         ANIM_SPECIAL+1
#define ANIM_AMBIENT4         ANIM_SPECIAL+2
#define ANIM_AWAY2            ANIM_SPECIAL+3
#define ANIM_SHOOT2           ANIM_SPECIAL+4
#define ANIM_AMBIENT5         ANIM_SPECIAL+5
#define ANIM_AMBIENT6         ANIM_SPECIAL+6
#define ANIM_AMBIENT7         ANIM_SPECIAL+7
#define ANIM_AMBIENT8         ANIM_SPECIAL+8
#define ANIM_BLADESIN         ANIM_SPECIAL+9
#define ANIM_BLADESOUT        ANIM_SPECIAL+10

// weapon info def
weaponInfo_t discusWeaponInfo = {
      // names, net names, icon
      "weapon_discus",
      "Discus Of Daedalus",
      "ammo_discus",
      "Discus",
      "iconname",

      // model files
      {"models/discus/discus.md2",
       "models/game_disc/game_disc.md2",
       NULL},

      // sound files
      {"weapons/discus/discusthrow.wav",
       "weapons/discus/discusclang1.wav",
       "weapons/discus/discusclang2.wav",
       "weapons/discus/discusclang3.wav",
       "weapons/discus/discusclang4.wav",
       "weapons/discus/discusclang5.wav",
       "weapons/discus/discushit.wav",
       "weapons/discus/discuscatch.wav",
       "weapons/discus/bladesin.wav",
       "weapons/discus/bladesout.wav",
       "weapons/discus/discusloop.wav",
       "weapons/discus/discushitnew2.wav",
       NULL},

      // frame names
      {MDL_WEAPON_STD,"readya",0,0,
               -1,"awaya",0,0,
               -1,"shoota",0,0,
               -1,"amba",0,0,
               -1,"ambb",0,0,
               -1,"ambc",0,0,
               -1,"ambd",0,0,
               -1,"awayb",0,0,
               -1,"shootb",0,0,
               -1,"ambe",0,0,
               -1,"ambf",0,0,
               -1,"ambg",0,0,
               -1,"ambh",0,0,
               -1,"bladesin",0,0,
               -1,"bladesout",0,0,
       0,NULL},

      // commands
      {"weapon_discus",(void (*)())discus_give,
       "select_discus",(void (*)())discus_select,
       NULL},

   discus_use,
   weapon_command,
   sizeof(discus_t),

   100,
};

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

//---------------------------------------------------------------------------
// discus_give()
//---------------------------------------------------------------------------
static userInventory_t *discus_give (userEntity_t *self)
{
   discus_t *discus;
   
   discus=(discus_t *)weaponGive(self,winfo,1);
   discus->bladesout=false;

   return((userInventory_t *)discus);
}

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

	if (!(invItem=gstate->InventoryFindItem(self->inventory,winfo->weaponName)))
      return;

   if (invItem==self->curWeapon)
      toggleBlades(self);
   else
   {
      weaponSelect(self,winfo);
      phook->weapon_next=discus_selectFinish;
   }
}

//---------------------------------------------------------------------------
// discus_selectFinish()
//---------------------------------------------------------------------------
static void discus_selectFinish(userEntity_t *self)
{
   weaponSelectFinish(self);

   if (!weaponUseAmmo(self->curWeapon,0))
   {
      short frame=winfoLastFrame(ANIM_SHOOT_STD);

      weapon_animate(self,frame,frame,.01);
   }
}

//---------------------------------------------------------------------------
// weapon_command()
//---------------------------------------------------------------------------
static void *weapon_command (struct userInventory_s *ptr,char *commandStr,void *data)
{
   userEntity_t *self=(userEntity_t *)data;
   playerHook_t *phook=(playerHook_t *)self->userHook;
   discus_t *discus=(discus_t *)self->curWeapon;

	if (!stricmp (commandStr, "death_msg"))
	{
		killerInfo_t	*ki = (killerInfo_t *) data;
		char			msg [80];

		if (ki->victim->netname && ki->attacker->netname)
		{
			if (rnd () < 0.5)
				sprintf (msg, "%s drops a dime in %s's slot.\n", ki->attacker->netname, ki->victim->netname);
			else
				sprintf (msg, "%s makes change on %s's head.\n", ki->attacker->netname, ki->victim->netname);

			gstate->bprint (msg);
		}
	}
   else if (!stricmp(commandStr,"ambient"))
   {
      if (weaponUseAmmo(self->curWeapon,0))
		{
         short animlist1[]={ANIM_AMBIENT_STD,ANIM_AMBIENT2,ANIM_AMBIENT3,ANIM_AMBIENT4};
         short animlist2[]={ANIM_AMBIENT5,ANIM_AMBIENT6,ANIM_AMBIENT7,ANIM_AMBIENT8};
         short animnum;

         if (discus->bladesout)
            animnum=animlist2[(short)(rnd()*3.9)];
         else
            animnum=animlist1[(short)(rnd()*3.9)];

         winfoAnim(self,animnum,.05);
         phook->ambient_time=gstate->time+winfoNumFrames(animnum)*.05+2.0+(rnd()*6);

		 // Don't make a sound for non-discus-spinning ambients
		 if (animnum != ANIM_AMBIENT_STD && animnum != ANIM_AMBIENT5)
			gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);
      }
   }
	else if (!stricmp(commandStr, "change"))
	{
      if (!weaponUseAmmo(self->curWeapon,0))
      {
         // make engine think it's animating something
      	phook->vm_startFrame=winfoLastFrame(ANIM_SHOOT_STD);
      	phook->vm_endFrame=phook->vm_startFrame;
      	phook->vm_frameTime=.01;
      	phook->vm_next_frameTime=0;
      	phook->vm_frameFlags=FRAME_ONCE;
      	phook->vm_frameInc=1;
		   return(NULL);
      }

      if (discus->bladesout)
         winfoAnimDelay((userEntity_t *)data,winfo,ANIM_AWAY2,.05);
      else
         winfoAnimDelay((userEntity_t *)data,winfo,ANIM_AWAY_STD,.05);
	}
	else if (!stricmp(commandStr, "change_time"))
	{
      *(float *)data=(winfoNumFrames(ANIM_AWAY2)) * 0.05;
	}
   else
      winfoGenericCommand(winfo,ptr,commandStr,data);

	return(NULL);
}

//---------------------------------------------------------------------------
// toggleBlades()
//---------------------------------------------------------------------------
static void toggleBlades(userEntity_t *self)
{
   discus_t *discus=(discus_t *)self->curWeapon;

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

   if (discus->bladesout)
   {
      winfoAnimDelay(self,winfo,ANIM_BLADESIN,.05);
      gstate->sound (self, CHAN_WEAPON, winfoSound(SND_BLADESIN), 255, ATTN_NORM);
   }
   else
   {
      winfoAnimDelay(self,winfo,ANIM_BLADESOUT,.05);
      gstate->sound (self, CHAN_WEAPON, winfoSound(SND_BLADESOUT), 255, ATTN_NORM);
   }

   discus->bladesout ^= 1;
}

//---------------------------------------------------------------------------
// discus_visible()
//---------------------------------------------------------------------------
static	int	discus_visible (userEntity_t *self, userEntity_t *ent)
{
	Vector			org, end;
	userTrace_t		trace;

	// get center of bmodel as origin
	if (self->movetype == MOVETYPE_PUSH || self->solid == SOLID_BSP)
		org = Vector (self->absmin) + Vector (self->absmax) * 0.5;
	else 
		org = Vector (self->s.origin);

	if (ent->movetype == MOVETYPE_PUSH || self->solid == SOLID_BSP)
		end = Vector (ent->absmin) + Vector (ent->absmax) * 0.5;
	else 
		end = Vector (ent->s.origin);

	gstate->TraceLine (org.vec (), end.vec (), FALSE, self, &trace);

	if (trace.fraction == 1.0 || trace.ent == ent)
	{
		org = org - Vector (trace.endpos);
		return	org.vlen ();
	}
	else
		return	FALSE;
}

//---------------------------------------------------------------------------
// discus_catch()
//---------------------------------------------------------------------------
static void discus_catch(userEntity_t *self, userEntity_t *other)
{
   playerHook_t *phook=(playerHook_t *)other->userHook;
	discus_t		*discus = (discus_t *) other->curWeapon;
   int amount;

   if (self->userHook)
	   com->free(self->userHook);
   self->userHook=NULL;

   if (!discus)
      return;

   amount=1;
   discus->weapon.ammo->command((userInventory_t *)discus->weapon.ammo,"give_ammo",&amount);
   if (discus->bladesout)
      winfoAnim(other,ANIM_AMBIENT5,.05);
   else
      winfoAnim(other,ANIM_AMBIENT_STD,.05);
   phook->attack_finished=gstate->time+.1;
}

//---------------------------------------------------------------------------
// discus_find_target()
//---------------------------------------------------------------------------
int		discus_find_target (userEntity_t *self)
{
	userEntity_t	*head;
	userEntity_t	*enemy;
	int				dist, enemy_d;
	playerHook_t	*phook;
	discusHook_t		*hook = (discusHook_t *) self->userHook;

	enemy = NULL;
	enemy_d = 32767;
	head = gstate->FirstEntity ();

	while (head)
	{
		// is this a client or a bot?
		if (head->flags & FL_CLIENT || head->flags & FL_BOT || head->flags & FL_MONSTER)
		{
			phook = (playerHook_t *) head->userHook;

			// don't attack owner's bots!
			if (phook->owner != hook->owner && hook->hit_ent != head)
			{
				// don't attack anything owned by the player who threw the discus
				if (head != hook->owner && head->health > 0 && head->takedamage)
				{
					dist = discus_visible (self, head);
	
					if ((dist && dist < enemy_d) && (head->deadflag == DEAD_NO))
					{
						enemy = head;
						enemy_d = dist;
					}
				}
			}
		}

		head = gstate->NextEntity (head);
	}

	if (enemy)
	{
		self->goalentity = enemy;
		return	TRUE;
	}
	return	FALSE;
}

//---------------------------------------------------------------------------
// discus_pickup()
//---------------------------------------------------------------------------
void	discus_pickup (userEntity_t *self, userEntity_t *other)
{
	playerHook_t	*ohook = (playerHook_t *) other->userHook;
	userInventory_t	*invItem;
   discus_t *weapon=(discus_t *)other->curWeapon;

	if (!com->ValidTouch (self, other))
		return;

   discus_kill_trails(self);
   discus_catch(self,other);
	gstate->RemoveEntity (self);
}

//---------------------------------------------------------------------------
// discus_drop()
//---------------------------------------------------------------------------
void	discus_drop (userEntity_t *self)
{
   discus_kill_trails(self);

	com->ZeroVector (self->velocity);
	self->movetype = MOVETYPE_TOSS;
	self->touch = (touch_t)discus_pickup;
	self->solid = SOLID_TRIGGER;
   self->clipmask=MASK_SOLID;

	self->netname = "Discus of Daedalus";
	self->className = "weapon_discus";
	self->client->ps.gunindex = gstate->ModelIndex("models/discus/discus.md2");

   winfoSetModel(self,MDL_DISC);
//	self->origin_z_ofs = 0;
	gstate->SetSize(self, -6.0, -6.0, -6.0, 6.0, 6.0, 6.0);

   self->s.renderfx &= ~RF_TRAILS;     // kill trails
   self->s.modelindex2=0;              //  '    '

   self->s.frame=1;                    // force non-bladed version

	self->flags=FL_ITEM;
	self->think=discus_spin;
	self->nextthink=gstate->time+.1;
   self->s.angles[0]=90;
   self->s.angles[1]=0;

   if (gstate->GetCvar("g_unlimited_ammo") || WEAPON_UNLIMITED_AMMO)
      gstate->RemoveEntity(self);
}

//---------------------------------------------------------------------------
// discus_spin()
//---------------------------------------------------------------------------
static void discus_spin(userEntity_t *self)
{
   self->s.angles[2] += 45;
   self->nextthink=gstate->time+.1;
}

//---------------------------------------------------------------------------
// discus_seek_think()
//---------------------------------------------------------------------------
void	discus_seek_think (userEntity_t *self)
{
	Vector	next_org, dir;
	Vector  forward, right, up;
	discusHook_t	*hook = (discusHook_t *) self->userHook;
   float len;

	// make sure the disc doesn't slow down
   len=qv_len(self->velocity);
	if (len<(DISCUS_SPEED-10)/MIKE_SHIT)
	{
		dir = Vector (self->velocity);
		dir.Normalize ();
		dir = dir * (DISCUS_SPEED/MIKE_SHIT);
		dir.set (self->velocity);
	}

	self->think = discus_seek_think;
	self->nextthink = gstate->time + 0.1;
    gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);

   discus_place_trails(self);

	// if time is up, drop to the ground and become a trigger

   // force drop if stuck
   if (!memcmp(hook->lastpos,self->s.origin,sizeof(hook->lastpos)))
      hook->drop_time=-1;
   com->CopyVector(hook->lastpos,self->s.origin);

	if (hook->drop_time <= gstate->time)
	{
		discus_drop (self);
		return;
	}

	// if no goal, we're out of here
	if (!self->goalentity)
		return;

	if (self->goalentity->health <=0 || !self->goalentity->takedamage)
		return;

	// predict target's position 0.1 seconds from now

	if (self->goalentity == hook->owner)
	{
		next_org = Vector (self->goalentity->velocity) * 0.1 + Vector (self->goalentity->s.origin) + Vector (0, 0, 16.0);

		if (!hook->return_sound_played)
		{
			if (qv_dist (self->goalentity->s.origin, self->s.origin) < 128)
			{
				gstate->sound (self, CHAN_WEAPON, winfoSound(SND_CATCH), 255, ATTN_NORM);
				hook->return_sound_played = TRUE;
			}
		}
	}
	else
		next_org = (Vector (self->goalentity->absmax) + Vector (self->goalentity->absmin)) * 0.5 + Vector (0, 0, 16.0);
	
	dir = next_org - Vector (self->s.origin);
	// adjust the discus angle to match direction of travel
	dir.Normalize ();
	com->VecToAngles (up, dir);
	up.set (self->s.angles);
	dir = dir * (DISCUS_SPEED/MIKE_SHIT);
	dir.set (self->velocity);

   discus_place_trails(self);

   if (self->goalentity == hook->owner)
   {
      vec3_t v1,v2;

      VectorCopy(self->goalentity->s.origin,v1);
      VectorCopy(self->s.origin,v2);

      len=100; //qv_dist(v1,v2);
      if (len < 80)
      {
         discus_kill_trails(self);
	   	discus_catch(self,self->goalentity);
		   gstate->RemoveEntity(self);
      }
   }
}

//---------------------------------------------------------------------------
// discus_bounce_think()
//---------------------------------------------------------------------------
void	discus_bounce_think (userEntity_t *self)
{
	int			pc;
	discusHook_t	*hook = (discusHook_t *) self->userHook;
	Vector		dir, forward, right, up;;
	userTrace_t	trace;
   short findowner=false;

	// make sure we don't loose velocity
	if (qv_len (self->velocity) < 490)
	{
		dir = Vector (self->velocity);
		dir.Normalize ();
		dir = dir * 500;
		dir.set (self->velocity);
	}

	self->nextthink = gstate->time + 0.1;
	self->think = discus_seek_think;
    gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);

	if (hook->hit_count > 0)
	{
      if (discus_find_target(self))
      {
   		// decrement the count to show we tried for an enemy
	   	hook->hit_count--;
		   dir = (Vector (self->goalentity->s.origin) + Vector (0, 0, 32.0)) - Vector (self->s.origin);
   		dir.Normalize ();
	   	dir = dir * 500;
		   dir.set (self->velocity);
      }
      else
         findowner=true;
	}
   else
      findowner=true;
	
   if (hook->return_time<=gstate->time)
      findowner=true;

   if (findowner && discus_visible(self, hook->owner))
	{
   	// return to owner
		self->goalentity = hook->owner;
		dir = (Vector (hook->owner->s.origin) + Vector (0, 0, 32.0)) - Vector (self->s.origin);
		dir.Normalize ();
		dir = dir * 500;
		dir.set (self->velocity);
	}

	// adjust the discus angle to match direction of travel
	dir = Vector (self->velocity);
	com->VecToAngles (up, dir);
	up.set (self->s.angles);

   discus_place_trails(self);
}

//---------------------------------------------------------------------------
// discus_touch()
//---------------------------------------------------------------------------
void	discus_touch (userEntity_t *self, userEntity_t *other,cplane_t *plane, csurface_t *surf)
{
	discusHook_t		*hook = (discusHook_t *) self->userHook;
	playerHook_t	*phook = (playerHook_t *) hook->owner->userHook;
	int r;
	char *sound_name;

	self->owner = NULL;

	if (other == hook->owner)
	{
      discus_kill_trails(self);
		discus_catch(self,other);
		gstate->RemoveEntity (self);
		return;
	}
	else if (other->takedamage && hook->hit_time <= gstate->time)
	{
		if (surf && (surf->flags & SURF_SKY))
			gstate->sound (self, CHAN_WEAPON, winfoSound(SND_HIT), 255, ATTN_NORM);

		//	pass zero_vector as dir since DAMAGE_INFLICTOR_VEL will override it
		com->Damage (other, self, hook->owner, self->s.origin, zero_vector, 35, DAMAGE_INERTIAL | DAMAGE_INFLICTOR_VEL);
		
		phook->hit++;

		self->goalentity = NULL;
		hook->hit_ent = other;
		hook->return_time = gstate->time + 1.0;
		hook->hit_time = gstate->time + 0.2;
	}
	else
	{
		if (surf && (surf->flags & SURF_SKY))
         gstate->sound (self, CHAN_WEAPON, winfoSound(SND_HITWALL), 255, ATTN_NORM);
	}

   gstate->WriteByte(SVC_TEMP_ENTITY);
   gstate->WriteByte(TE_SHIELD_SPARKS);
   gstate->WritePosition(self->s.origin);
   gstate->WriteDir(plane->normal);
   gstate->MultiCast(self->s.origin,MULTICAST_ALL);

	self->think = discus_bounce_think;
	self->nextthink = gstate->time + 0.05;
   gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);
}

//---------------------------------------------------------------------------
// discus_use_think()
//---------------------------------------------------------------------------
void	discus_use_think (userEntity_t *self)
{
	Vector	next_org, dir, temp;
	Vector  forward, right, up;
	int		pc;
	discusHook_t	*hook = (discusHook_t *) self->userHook;

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

	temp = Vector (hook->owner->s.origin) + forward * 16.0 + right * 8.0;
	temp.z += 16.0;
	temp.set (self->s.origin);

	pc = gstate->PointContents (self->s.origin);
	if (pc == CONTENTS_WATER || pc == CONTENTS_LAVA || pc == CONTENTS_SLIME)
		temp = forward * ((DISCUS_SPEED/2)/MIKE_SHIT);
	else
		temp = forward * (DISCUS_SPEED/MIKE_SHIT);
	temp.set (self->velocity);

	self->touch = (touch_t)discus_touch;
	self->nextthink = gstate->time + 0.1;
	self->think = discus_place_trails;     //NULL;
    gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);

	hook->return_time = gstate->time+4;
	hook->drop_time = gstate->time + (10.0*MIKE_SHIT);

	self->modelName = "models/gamedisc/gamediscus.md2";
   discus_place_trails(self);

   self->s.renderfx &= ~RF_INITTRAILS;
}

//---------------------------------------------------------------------------
// discus_use()
//---------------------------------------------------------------------------
void	discus_use (userInventory_t *ptr, userEntity_t *self)
{
	playerHook_t *phook;
	discus_t *discus=(discus_t *)self->curWeapon;
   short animnum;
   int count;

	phook = (playerHook_t *) self->userHook;

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

	gstate->sound (self, CHAN_WEAPON, winfoSound(SND_THROW), 255, ATTN_NORM);

   if (discus->bladesout)
      animnum=ANIM_SHOOT2;
   else
      animnum=ANIM_SHOOT_STD;

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

	phook->fired++;

   phook->fxFrameNum=winfoFirstFrame(animnum)+5;
   phook->fxFrameFunc=discus_throw;
}

//---------------------------------------------------------------------------
// discus_throw()
//---------------------------------------------------------------------------
static void discus_throw(userEntity_t *self)
{
   discus_t *curWeap=(discus_t *)self->curWeapon;
	userEntity_t	*discus;
	discusHook_t	*hook;
	playerHook_t	*phook;
   Vector temp;
   int count;

	phook = (playerHook_t *) self->userHook;
   phook->fxFrameFunc=NULL;

	discus = gstate->SpawnEntity ();
	discus->owner = self;
	discus->movetype = MOVETYPE_FLY;
	discus->solid = SOLID_SLIDEBOX;
   discus->clipmask=MASK_SHOT;
   discus->s.renderfx=RF_TRAILS|RF_INITTRAILS;
//   discus->s.modelindex2=gstate->ModelIndex(winfoModel(MDL_TRAIL));
   discus->s.frame=!curWeap->bladesout;

	discus->className = "discus";
	discus->flags = FL_EXPLOSIVE;
	
	discus->userHook = com->malloc_hook (sizeof (discusHook_t), MEM_MALLOC);
	hook = (discusHook_t *) discus->userHook;

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

//   temp=Vector(self->s.origin) + Vector(0,0,20) + weaponHandVector(self,forward*4,right*8);
   temp = Vector (self->s.origin) + forward * 4.0 + up * 20.0 + right * 8.0;
	temp.set(discus->s.origin);

	com->VecToAngles (temp, forward);
	temp.set (discus->s.angles);

	discus->touch = NULL;
	discus->nextthink = gstate->time + 0.20;
	discus->think = discus_use_think;
    gstate->sound (self, CHAN_WEAPON, winfoSound(SND_DISCUSLOOP), 255, ATTN_NORM);

	hook->return_time = -1;
	hook->hit_count = 1;
	hook->owner = self;
	hook->return_sound_played = FALSE;
	hook->hit_ent = NULL;
	hook->hit_time = 0;

   discus_spawn_trails(discus);
//   discus_place_trails(discus);

   dk2SetModel(discus,winfoModel(MDL_DISC));
//	self->origin_z_ofs = 0;
	gstate->SetSize (discus, -6.0, -6.0, -6.0, 6.0, 6.0, 6.0);
	discus->modelName = NULL;
	gstate->SetOrigin (discus, discus->s.origin [0], discus->s.origin [1], discus->s.origin [2]);

   // take a disc from inv
   count=1;
   curWeap->weapon.ammo->command((userInventory_t *)curWeap->weapon.ammo,"take_ammo",&count);

   gstate->LinkEntity(discus);
}

//---------------------------------------------------------------------------
// discus_spawn_trails() - old func
//---------------------------------------------------------------------------
static void discus_spawn_trails(userEntity_t *self)
{
}

//---------------------------------------------------------------------------
// discus_place_trails() - old func
//---------------------------------------------------------------------------
static void discus_place_trails(userEntity_t *self)
{
}

//---------------------------------------------------------------------------
// discus_kill_trails() - old func
//---------------------------------------------------------------------------
static void discus_kill_trails(userEntity_t *self)
{
}

