/*
+--------+
|Chasecam|
+--------+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| Scratch                                      Http://www.admdev.com/scratch |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| Chasecam. Follows player for above and back slightly.                      |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
*/

float SVC_SETVIEWPORT	= 5;
float SVC_SETVIEWANGLES	= 10;
float CHSCAM_ALT    = 4;
float CHSCAM_ON     = 2;

void() Keep_cam_chasing_owner;
float chasecam_alt, chasecam_dist = 82, chasecam_zofs = 24;
.entity acamera;

void(entity cam_owner) Start_chase_cam =
{
	local entity	chase_cam;

	chase_cam = spawn();
	chase_cam.owner=cam_owner;

	// turn on bit-flag
	chase_cam.owner.speed = chase_cam.owner.speed | CHSCAM_ON;
	
	chase_cam.solid = SOLID_NOT;
	chase_cam.movetype = MOVETYPE_FLYMISSILE;

	chase_cam.angles = chase_cam.owner.angles;

      setmodel (chase_cam, "progs/null.spr" ); // model of some kind required
	setsize (chase_cam, '0 0 0', '0 0 0');
	setorigin(chase_cam, chase_cam.owner.origin );
	chase_cam.classname = "chase_cam";
	
	chase_cam.nextthink = time + 0.1;	
	chase_cam.think = Keep_cam_chasing_owner;

	msg_entity = chase_cam.owner;
	WriteByte (MSG_ONE, SVC_SETVIEWPORT);  
	WriteEntity (MSG_ONE, chase_cam);

	// distance clipping
	chase_cam.ammo_shells = chasecam_dist;
	// offset choice
	chase_cam.ammo_cells = 0;
};

// secondary think for cam entities
void() Reable_chase_cam =
{
   self.nextthink = time + 0.1;

   if (self.owner.health <= 0)
   {
      remove( self );
      return;
   }

   if (self.owner.waterlevel) return;

   Start_chase_cam(self.owner);
   remove(self);

};

/*
###########
main think function for cam entities
 self.ammo_shells = distance clipping
 self.ammo_nails = hang-up flag
 self.ammo_cells = view offset direction
   0 = up
   1 = left
   2 = right
###########
*/
void() Keep_cam_chasing_owner =
{
	local vector	spot2, dir;
	local float dist, cap;
	local float  f_f, f_r;

	self.nextthink = time + 0.1; 
	
   dir_y = self.owner.v_angle_y;
   makevectors (dir);
   f_f = vlen((v_forward * 320) - self.owner.velocity);
   f_r = vlen((v_right * 320) - self.owner.velocity);

   // held for use after second makevectors call for
   // v_forward based only on yaw
   dir = v_forward;

   if (intermission_running) // check for intermission
   {
	// set view-point back to normal
	msg_entity = self.owner;      // target of message
	WriteByte (MSG_ONE, SVC_SETVIEWPORT);  
	WriteEntity (MSG_ONE, self.owner);           // view port
      remove( self );
   }

   if (self.owner.speed & CHSCAM_ALT)
   {
      if (f_f < 160 || self.owner.v_angle_x < -45) self.ammo_cells = 0;
      else if (f_r < 80) self.ammo_cells = 1;
      else if (f_r > 560) self.ammo_cells = 2;
   }
   else self.ammo_cells = 0;


   makevectors( self.owner.v_angle );

   // set spot before clipping
   spot2 = self.owner.origin - (v_forward * self.ammo_shells);

   if (!self.ammo_cells)
   {
      if (self.owner.v_angle_x > 16)
      {
         // dir is first v_forward based on yaw only
         spot2 = spot2 + (dir * (self.owner.v_angle_x - 16));
         cap = chasecam_zofs - ((self.owner.v_angle_x - 16) * 0.2);
         if (cap < 0) cap = 0;
         spot2_z = spot2_z + cap;
      }
      else spot2_z = spot2_z + chasecam_zofs;
   }
   else if (self.ammo_cells == 1) spot2 = spot2 - (v_right * (chasecam_zofs));
   else spot2 = spot2 + (v_right * (chasecam_zofs));

   traceline (self.owner.origin, spot2, FALSE, self.owner);

   // avoids most hang-ups along walls
   spot2 = trace_endpos + (v_forward * 2);

   // for fading from walls and up-aim auto rising
   self.ammo_shells = 10 + vlen(trace_endpos - self.owner.origin);

   // clip from ceiling if too close
   traceline (spot2, spot2 + '0 0 32', FALSE, self.owner );
   if (trace_fraction < 1)
   {
      dir = trace_endpos - '0 0 32';

      traceline (spot2, spot2 - '0 0 32', FALSE, self.owner );
      if (trace_fraction == 1)
         spot2 = dir;
   }

   dir = normalize(spot2 - self.origin);
   dist = vlen(spot2 - self.origin);
   
   traceline(self.origin, spot2, FALSE, self.owner);
	if (trace_fraction == 1)
	{
	      self.angles = self.owner.angles;

	      cap = dist * 0.2;

	      if (cap > 5.2) self.velocity = dir * dist * 5.2;
	      else if (cap > 1) self.velocity = dir * dist * cap;
	      else self.velocity = dir * dist;

	      // tighten up if owner running backwards
	      if (f_f > 560)
	      {
	         self.velocity = self.velocity * 2;
	      }      
	   }
         else setorigin( self, spot2 );

   // fade back from walls
   self.ammo_shells = self.ammo_shells + 4;
   if (self.ammo_shells > chasecam_dist) self.ammo_shells = chasecam_dist;

   if(self.oldorigin == self.origin)
   {
      if (dist > 30) self.ammo_nails = self.ammo_nails + 1;

   }
   if (self.ammo_nails > 3)
   {
      Start_chase_cam(self.owner);
      remove(self);
      return;
   }

   self.oldorigin = self.origin;
};


void() Chase_cam_lvlstart_think =
{
   if ((self.owner.speed & CHSCAM_ON)) Start_chase_cam(self.owner);
   remove( self );
};

void() Chase_cam_level_start =
{
	local entity e;

      e = spawn();
      e.owner = self;
      e.movetype = MOVETYPE_NONE;
      e.solid = SOLID_NOT;
      setmodel( e, "" );
      setsize( e, VEC_ORIGIN, VEC_ORIGIN );    
      setorigin( e, e.owner.origin );
      e.nextthink = time + 0.1;
      e.think = Chase_cam_lvlstart_think;
};

.vector camview;
 void () FirstPersonCamera_Chase = 
  {
     makevectors (self.v_angle);
	self.camview_z = 14;
     traceline ((self.origin + v_forward * 6),((((self.origin + v_forward * 6) + (v_forward * self.camview_x)) + (v_up * self.camview_z)) + (v_right * self.camview_y)),FALSE,self);
     setorigin (self.trigger_field,trace_endpos);
     WriteByte (MSG_ONE,5);
     WriteEntity (MSG_ONE,self.trigger_field);
     self.weaponmodel = "";
};

void () FirstPersonCamera = 
{
     local entity camera;

        camera = spawn ();
        camera.classname = "camera";
        camera.movetype = MOVETYPE_FLY;
        camera.solid = SOLID_NOT;
	  self.trigger_field = camera;
        setmodel (camera,"progs/null.spr");
        setsize (camera,'0 0 0','0 0 0');
        makevectors (self.v_angle);
        traceline ((self.origin + self.view_ofs),(((self.origin + self.view_ofs)
           + (v_forward * -64))),FALSE,self);
        self.camview = '0 0 0'; // added
        setorigin (camera,trace_endpos);
        camera.angles = self.angles;
	  self.aflag = TRUE; // bit flag for camera
        self.weaponmodel = "";
        msg_entity = self;
        WriteByte (MSG_ONE,5);
        WriteEntity (MSG_ONE,camera);
        WriteByte (MSG_ONE,10);
        WriteAngle (MSG_ONE,camera.angles_x);
        WriteAngle (MSG_ONE,camera.angles_y);
        WriteAngle (MSG_ONE,camera.angles_z);
};