// Template file v5.202 (02/20/02)
////////////////////////////////////////////////////////////////////////
// File: camera.wdl
//		WDL prefabs for camera movment
////////////////////////////////////////////////////////////////////////
// Use:
//		Include AFTER "movment.wdl"
//

IFNDEF CAMERA_ORBIT_DEFS;
	DEFINE kOrbitCameraPanInc, 5;
	DEFINE kOrbitCameraDistInc, 5;
	DEFINE kOrbitCameraZOffInc, 5;
ENDIF;

//@ Camera Vars
//#var person_3rd	= 0;		// 0: 1st person mode; 0.5-1: 3rd person mode  DEFINED in movement.wdl

var camera_solidpass = 0;			// 0: avoid passing into solids (may cause
											//   shaky camera)
											// 1: pass through solids

var camera_dist[3] = 90,0,0;   			// camera distance to entity in 3rd person view

var chase_camera_dist[3] = -20,90,0;  // camera distance to entity in chase view


var orbit_camera_pan = 180;   // pan around center point
var orbit_camera_dist = 150;  // distance from center point
var orbit_camera_zOff = 5;		// distance up

///////////////////////////////////////////////////////////////////////
var camera_speed[3] = 0,0,0;	// cartesian speed, entity coordinates
var camera_aspeed[3];		// angular speed

var	current_fog_index	= 0;	// the current fog color index

var walk_rate = 3; 	// for head wave, 360 / step width
var wave_rate = 25; 	// same for swimming, 360 / wave time
var walk_ampl = 4;	// walking head wave amplitude
var wave_ampl = 2; 	// swimming head wave amplitude






//@ Function prototypes
//ACTION camera_move	- Attach to entity in a level without player, free move camera
function move_view_1st();	// Handles first person camera view
function move_view_3rd();  // Handles third person camera view
function move_view_orbit();// Handles the 'orbit' camera
function move_view_chase();// Handles the 'chase' camera
function move_view();		// Call the appropriate function to move the camera
function toggle_person();	// Toggle between 1st and 3rd person views
function cycle_person_view();// Cycle from 1st to 3rd to orbit person views
function set_pos_ahead();  // Calculate a position directly ahead of the camera
function _set_pos_ahead_xyz();	// Calculate a position ahead of the player


//@ Function Code

/////////////////////////////////////////////////////////////////////////
// Desc: This is the main movement action for the camera
//
ACTION camera_move
{
	_camera = 1;
	while(_camera == 1)
	{
		_player_intentions();     // set force and aforce value from user input

 		// -old method- ACCEL	aspeed,aforce,0.9;
		camera_aspeed.pan  += (TIME * aforce.pan)  - (0.9 * camera_aspeed.pan);
		camera_aspeed.tilt += (TIME * aforce.tilt) - (0.9 * camera_aspeed.tilt);
		camera_aspeed.roll += (TIME * aforce.roll) - (0.9 * camera_aspeed.roll);

		CAMERA.PAN += camera_aspeed.PAN * TIME;
		CAMERA.TILT += camera_aspeed.TILT * TIME;
		CAMERA.ROLL += camera_aspeed.ROLL * TIME;

		// Calculate camera's new speed
 		// -old method- ACCEL	speed,force,0.9;
		camera_speed.x += (TIME * force.x) - (0.9 * camera_speed.x);
		camera_speed.y += (TIME * force.y) - (0.9 * camera_speed.y);
		camera_speed.z += (TIME * force.z) - (0.9 * camera_speed.z);

		// calculate relative distance
   	dist.x = camera_speed.x * TIME;
 	 	dist.y = camera_speed.y * TIME;
 	 	dist.z = camera_speed.z * TIME;

		// Replace move_view with XYZ displacement
		//move_view CAMERA,dist,NULLSKILL;
		vec_rotate(dist.x,CAMERA.pan);
		vec_add(CAMERA.X, dist.X);

		wait(1);
	}
}


///////////////////////////////////////////////////////////////////////
// First person camera view
// This should be a client-only action!!
//
function move_view_1st()
{
	if(_camera == 0) // If the camera does not move itself
	{
		// Position the camera

		CAMERA.DIAMETER = 0;		// make the camera passable
		CAMERA.GENIUS = player;	// don't display parts of ME
	  	CAMERA.X = player.X;    // place camera at player's location
		CAMERA.Y = player.Y;
		CAMERA.Z = player.Z + player.MIN_Z;  // start at 'feet', move up later...

		// Move the eye height up depending on the _MOVEMODE (start at feet)
 		if(player._MOVEMODE == _MODE_SWIMMING)
		{
			// adjust eye height for swimming
		  	CAMERA.Z += (player.MAX_Z-player.MIN_Z)*eye_height_swim;
		}
		else  // not swimming
		{

 			if((player._MOVEMODE == _MODE_DUCKING) || (player._MOVEMODE == _MODE_CRAWLING))
			{
				// adjust eye height for ducking and crawling
				CAMERA.Z += (player.MAX_Z-player.MIN_Z)*eye_height_duck;
			}
			else
			{
				// adjust eye height for 'normal' modes
				CAMERA.Z += (player.MAX_Z-player.MIN_Z)*eye_height_up;
			}
 		}

		CAMERA.PAN = player.PAN;
		CAMERA.TILT = player.TILT + head_angle.TILT;
		CAMERA.ROLL = player.ROLL;

		// Handle head-bob

		if(my_height < 5 || (player._MOVEMODE == _MODE_SWIMMING) )
		{
			// use
			headwave = sin(player_dist*walk_rate);

			if((player._MOVEMODE == 0)	// moving on client?
				|| (player._MOVEMODE == _MODE_WALKING))
			{
				// Play the right and left foot sound
				if(((headwave > 0) && (walkwave <= 0))
					|| ((headwave <= 0) && (walkwave > 0)))
				{
					play_sound(thud,30);
				}
				// head bobbing
				walkwave = headwave;
				headwave = walk_ampl*(abs(headwave)-0.5);
			}

			if((player._MOVEMODE == _MODE_SWIMMING) && (ent_content(NULL,CAMERA.x) != CONTENT_PASSABLE))//(on_passable_ == ON))
			{
				if((headwave > 0) && (walkwave <= 0))
				{
					play_sound(splash,30);
				}
				// in-water wave movement
				walkwave = headwave;
				headwave = wave_ampl*sin(TOTAL_TICKS*wave_rate);
				head_angle.TILT += 0.1*wave_ampl*sin(TOTAL_TICKS*wave_rate - 60);
			}
		} // END if(my_height < 5 || (player._MOVEMODE == _MODE_SWIMMING) )


		if(player.__BOB == ON) { CAMERA.Z += headwave;	}



// check to see if camera is located in a passable block and set fog color index
//jcl 07-22-00  old fog is saved
		if (ent_content(NULL,CAMERA.x) == CONTENT_PASSABLE)
		{
			if (FOG_COLOR != _FOG_UNDERWATER)
			{
				current_fog_index = FOG_COLOR;	// save old fog
				FOG_COLOR = _FOG_UNDERWATER;	// set fog color to underwater fog
			}
		}
		else
		{
			if (FOG_COLOR == _FOG_UNDERWATER)
			{
				// else restore current_fog_index
				FOG_COLOR = current_fog_index;
			}
		}

		person_3rd = 0;  // we are in first person mode

	} // END if(_camera == 0) // If the camera does not move itself
}

/////////////////////////////////////////////////////////////////////////
// Desc: Third person camera view
//
function move_view_3rd()
{
	if ((_camera == 0) && (player != NULL))
	{

 		CAMERA.DIAMETER = 0;		// make the camera passable
		CAMERA.genius = player;
		CAMERA.pan += 0.2 * ang(player.pan-CAMERA.pan);

		// tilt the camera differently if we are using a vehicle
 		if ( (player._MOVEMODE == _MODE_PLANE)
 			||(player._MOVEMODE == _MODE_CHOPPER))
 		{
 			CAMERA.tilt += 0.2 * ang(player.tilt-CAMERA.tilt);
 		}
		else
		{
			// walking, swimming etc.
			CAMERA.TILT = head_angle.TILT;

  		  	if((person_3rd < 1) && (camera_dist.Z == 0))	// switching to 3rd person
			{
				camera_dist.Z = -(player.MAX_Z-player.MIN_Z)*eye_height_up;//- player.MAX_Z;
			}


		}

		vec_set(temp,temp_cdist);      // temp = temp_cdist
		// don't tilt camera if swimming
		if(player._MOVEMODE == _MODE_SWIMMING)
		{
			temp2 = player.TILT;
			player.TILT = 0;
			vec_rotate(temp,player.PAN);
			player.TILT = temp2;
		}
		else
		{
			vec_rotate(temp,player.PAN);
		}
      CAMERA.X += 0.3*(player.X - temp.X - CAMERA.X);
      CAMERA.Y += 0.3*(player.Y - temp.Y - CAMERA.Y);
      CAMERA.Z += 0.3*(player.Z - temp.Z - CAMERA.Z);

 		// test if camera is IN_PASSABLE or IN_SOLID
		temp = ent_content(NULL,CAMERA.X);

		// if camera moved into a wall...
		if((temp == CONTENT_SOLID) && (camera_solidpass == 0))
		{
			temp_cdist.X *= 0.7;	// place it closer to the player
			temp_cdist.Y *= 0.7;
			temp_cdist.Z *= 0.7;
		}
		else
		{
			temp_cdist.X += 0.2*(player.MAX_X + camera_dist.X - temp_cdist.X);
			temp_cdist.Y += 0.2*(player.MAX_Y + camera_dist.Y - temp_cdist.Y);
			temp_cdist.Z += 0.2*(player.MAX_Z + camera_dist.Z - temp_cdist.Z);
		}

		// check to see if camera is located in a passable block and set fog color index
		if (temp == CONTENT_PASSABLE)
		{
			if (FOG_COLOR != _FOG_UNDERWATER)
			{
				current_fog_index = FOG_COLOR;	// save old fog
				FOG_COLOR = _FOG_UNDERWATER; 		// set fog color to underwater fog
			}
		}
		else
		{
			if (FOG_COLOR == _FOG_UNDERWATER)
			{
				// else restore current_fog_index
				FOG_COLOR = current_fog_index;
			}
		}
		person_3rd = 1; 	// fully 3rd person
	}

}

/////////////////////////////////////////////////////////////////////////
// Desc: functions used to change the orbit camera values
function inc_orbit_camera_pan()
{
	orbit_camera_pan += kOrbitCameraPanInc;
	IF (orbit_camera_pan > 360)
	{
		orbit_camera_pan -= 360;
	}
}
function dec_orbit_camera_pan()
{
	orbit_camera_pan -= kOrbitCameraPanInc;
	IF (orbit_camera_pan < 0)
	{
		orbit_camera_pan += 360;
	}
}
function inc_orbit_camera_dist()
{
	orbit_camera_dist += kOrbitCameraDistInc;
}
function dec_orbit_camera_dist()
{
	orbit_camera_dist -= kOrbitCameraZOffInc;
	IF (orbit_camera_pan < 0)
	{
		orbit_camera_pan = 0;
	}
}
function inc_orbit_camera_zOff()
{
	orbit_camera_zOff += kOrbitCameraDistInc;
}
function dec_orbit_camera_zOff()
{
	orbit_camera_zOff -= kOrbitCameraZOffInc;
}

/////////////////////////////////////////////////////////////////////////
// Desc: Orbit camera
//
function move_view_orbit()
{
 	CAMERA.DIAMETER = 0;		// make the camera passable
 	CAMERA.GENIUS = PLAYER;
 	CAMERA.X = PLAYER.X + (orbit_camera_dist * SIN(orbit_camera_pan));
 	CAMERA.Y = PLAYER.Y + (orbit_camera_dist * COS(orbit_camera_pan));
 	CAMERA.Z = PLAYER.Z + orbit_camera_zOff;

 	// if the camera is IN_PASSABLE (set by TOUCH) assume it is underwater
	TOUCH	NULL,CAMERA.POS;
 	IF (IN_PASSABLE)
 	{
 	 	FOG_COLOR = _FOG_UNDERWATER;  // set fog color to underwater
 	}
 	ELSE
 	{
 		// else restore the current_fog_index
 		FOG_COLOR = current_fog_index;
 	}

 	// face the player
 	temp.X = player.X - camera.X;
   temp.Y = player.Y - camera.Y;
   temp.Z = player.Z - camera.Z;
 	TO_ANGLE temp,temp;
 	camera.PAN = temp.PAN;
 	camera.TILT = temp.TILT;
}



/////////////////////////////////////////////////////////////////////////
// Desc: Chase camera
//

var	chase_camera_ang[3];

function move_view_chase()
{
	if ((_camera == 0) && (player != NULL))
	{

 		CAMERA.DIAMETER = 0;		// make the camera passable
		CAMERA.genius = player;



  		// calculate the camera view direction angles to the player
   	vec_diff(temp,nullvector,chase_camera_dist);    // temp = -camera_dist
   	vec_to_angle(chase_camera_ang,temp);      // chase_camera_ang points towards player
   	chase_camera_ang.roll = 0; 					// zero out roll angle

		// place the camera at the right position to the ship
      vec_set(camera.x,chase_camera_dist);
      vec_rotate(camera.x,player.pan);
      vec_add(camera.x,player.x);
		// set the camera angles to the player's angles
      vec_set(camera.pan,player.pan);
		// and quaternion rotate them by the camera view direction angles
      ang_rotate(camera.pan,chase_camera_ang);
	}
}

/////////////////////////////////////////////////////////////////////
// Desc: Call the appropriate function to move the camera
//
//	Uses person_3rd value for branching
function move_view()
{
	if(player == NULL) { player = ME; }	// this action needs the player pointer
	if(player == NULL) { return; }			// still no player -> can't work

	if(person_3rd > 2)
	{
		move_view_chase();
		return;
	}

	if(person_3rd > 1)
	{
		move_view_orbit();
		return;
	}

	if(person_3rd > 0)
  	{
		move_view_3rd();
		return;
	}

	// default 1st person view
	move_view_1st();

}


/////////////////////////////////////////////////////////////////////
// Desc: Toggle between 1st and 3rd person views
//
//	Effects 'person_3rd' value
function toggle_person()
{
	if(person_3rd > 0)
	{
		person_3rd = 0;
	}
	else
	{
		person_3rd = 0.5;
	}
}

/////////////////////////////////////////////////////////////////////
// Desc: Cycle from 1st to 3rd to orbit person views
//
//	Effects 'person_3rd' value
function cycle_person_view()
{
	if(person_3rd > 2)   // in 'chase' range
	{
		person_3rd = 0; // switch to 1st person view
		return;
	}

	if(person_3rd > 1)   // in 'orbit' range
	{
		person_3rd = 3; // switch to chase person view
		return;
	}

	if(person_3rd > 0)  // 3rd person veiw
	{
		person_3rd = 2;  // switch to orbit
   	return;
	}

 	person_3rd = 0.5; // switch to 3rd person view

 }


/////////////////////////////////////////////////////////////
// Desc: Calculate a position directly ahead of the camera
// Input:  p (distance)
// Output: MY_POS
function set_pos_ahead()
{
	temp.X = cos(CAMERA.PAN);
	temp.Y = sin(CAMERA.PAN);
	temp.Z = p*cos(CAMERA.TILT);
	MY_POS.X = CAMERA.X + temp.Z*temp.X;
	MY_POS.Y = CAMERA.Y + temp.Z*temp.Y;
	MY_POS.Z = CAMERA.Z + p*sin(CAMERA.TILT);
}

/////////////////////////////////////////////////////////////
// Desc: Calculate a 3d position relative to the camera angles
// Input:  MY_POS
// Output: MY_POS
//
function _set_pos_ahead_xyz()
{
	vec_rotate(MY_POS,CAMERA.PAN);
	if(person_3rd != 0)
	{
		MY_POS.X += player.X;
		MY_POS.Y += player.Y;
		MY_POS.Z += player.Z;
	}
	else
	{
		MY_POS.X += CAMERA.X;
		MY_POS.Y += CAMERA.Y;
		MY_POS.Z += CAMERA.Z;
	}
}





// Define ON_KEY functions
//ON_F7 toggle_person;
ON_F7	cycle_person_view;