// Template file v5.202 (02/20/02)
////////////////////////////////////////////////////////////////////////
// File: move.wdl
//		WDL prefabs for player movement
////////////////////////////////////////////////////////////////////////
// Use:
//		Include AFTER "movment.wdl"
//
//
// Mod Date: 02/12/02 DCP
//			player_move(): Increased distance (by 3) that entity must be "above"
//		a passable surface to not swim.
//
// Mod Date: 02/20/02 DCP
//			move_gravity(): Improved jumping code (no longer frame rate dependent)


//@ Move Defines


//@ Move Vars

//@ Move Actions
//	Each of these three actions call 'player_move'
//		player_walk -	player walk (basic move) action
//		player_swim -	player swim action
//		player_drive -	player drive action


/////////////////////////////////////////////////////////////////////////
// Desc: player walk action
//
//
// no WED defined skills
// uses _WALKFRAMES, _RUNFRAMES, _WALKSOUND
ACTION player_walk
{
	MY._MOVEMODE = _MODE_WALKING;
	MY._FORCE = 0.75;
	MY._BANKING = -0.1;
	MY.__JUMP = ON;
	MY.__DUCK = ON;
	MY.__STRAFE = ON;
	MY.__BOB = ON;
	MY.__TRIGGER = ON;

	player_move();
}

/////////////////////////////////////////////////////////////////////////
// Desc: player swim action
//
// uses _WALKFRAMES, _RUNFRAMES, _WALKSOUND
ACTION player_swim
{
	MY._MOVEMODE = _MODE_SWIMMING;
	MY._FORCE = 0.75;
	MY._BANKING = 0;
	MY.__JUMP = ON;
	MY.__DUCK = ON;
	MY.__STRAFE = OFF;
	MY.__BOB = ON;

	player_move();
}

/////////////////////////////////////////////////////////////////////////
// Desc: player drive action
//
//
// uses _WALKFRAMES, _RUNFRAMES, _WALKSOUND
ACTION player_drive
{
	MY._MOVEMODE = _MODE_DRIVING;
	MY._FORCE = 1.5;
	MY._BANKING = 0.5;
	MY.__SLOPES = ON;
	MY.__TRIGGER = ON;

	player_move();
}



//@ Move Function Protypes
//ACTION player_move  - This is the main movement function, it handles the player movement
//@@ player_move helper functions
function move_gravity();	// handle movement on solids
function wade_gravity();	// handle movement while wading
function swim_gravity();	// handle movement in passables
function scan_floor();		// scan surface under ME entity, sets values (also called from actor_move)
function	fall_damage();		// return damage from falling
function _player_force();	// set the values for force and aforce

function client_move();	// handles client entity movement


function move_airborne();	// Airborne movement function


//@ Move Functions

////////////////////////////////////////////////////////////////////////
// Desc: main player movement action
//			called from 'player_walk', 'player_drive', & 'player_swim'
//
//
// Mod Date: 02/12/02 DCP
//				Increased distance that entity must be "above" a passable surface
//			to not swim (previous vers allowed "Jesus Walk")
//
// uses _FORCE, _MOVEMODE, _BANKING, _WALKFRAMES, _RUNFRAMES, _WALKSOUND
// uses __FALL, __WHEELS, __SLOPES, __JUMP, __DUCK, __STRAFE, __BOB, __TRIGGER
ACTION player_move
{
	if(MY.CLIENT == 0) { player = ME; } // created on the server?

	MY._TYPE = _TYPE_PLAYER;
	MY.ENABLE_SCAN = ON;	// so that enemies can detect me
	if((MY.TRIGGER_RANGE == 0) && (MY.__TRIGGER == ON)) { MY.TRIGGER_RANGE = 32; }

	if(MY._FORCE == 0) {  MY._FORCE = 1.5; }
	if(MY._MOVEMODE == 0) { MY._MOVEMODE = _MODE_WALKING; }
	if(MY._WALKFRAMES == 0) { MY._WALKFRAMES = DEFAULT_WALK; }
	if(MY._RUNFRAMES == 0) { MY._RUNFRAMES = DEFAULT_RUN; }
	if(MY._WALKSOUND == 0) { MY._WALKSOUND = _SOUND_WALKER; }

	anim_init();      // init old style animation
	perform_handle();	// react on pressing the handle key


	// while we are in a valid movemode
	while((MY._MOVEMODE > 0)&&(MY._MOVEMODE <= _MODE_STILL))
	{
		// if we are not in 'still' mode
		if(MY._MOVEMODE != _MODE_STILL)
		{
			// Get the angular and translation forces (set aforce & force values)
			_player_force();

			// find ground below (set my_height, my_floornormal, & my_floorspeed)
			scan_floor();

			// if they are on or in a passable block...
			if( ((ON_PASSABLE != 0) && (my_height_passable < (-MY.MIN_Z + 19)))    // upped from 16 to 19 (3q 'buffer')
				|| (IN_PASSABLE != 0) )
			{

				// if not already swimming or wading...
				if((MY._MOVEMODE != _MODE_SWIMMING) && (MY._MOVEMODE != _MODE_WADING))
				{
  					play_sound(splash,50);
  					MY._MOVEMODE = _MODE_SWIMMING;
//---					actor_anim_transition(anim_swim_str);	//!!!!!

					// stay on/near surface of water
					MY._SPEED_Z = 0;
  				}

				// if swimming...
  				if(MY._MOVEMODE == _MODE_SWIMMING) // swimming on/in a passable block
				{
					if(ON_PASSABLE == ON) // && (IN_PASSABLE != ON)) -> Not need with version 4.193+
					{
						// check for wading
						temp.X = MY.X;
    					temp.Y = MY.Y;
    		  			temp.Z = MY.Z + MY.MIN_Z - my_height_passable;	// can my feet touch? (mod: 080801)
						trace_mode = IGNORE_ME + IGNORE_PASSABLE + IGNORE_PASSENTS;
						trace(MY.POS,temp);

						if(RESULT > 0)
						{
							// switch to wading
							MY._MOVEMODE = _MODE_WADING;
 				 			MY.TILT = 0;       // stop tilting
							my_height = RESULT + MY.MIN_Z;	// calculate wading height
//---							actor_anim_transition(anim_wade_str);	//!!!!!
						}

 					}

				}// END swimming on/in a passable block
				else
				{	// not swimming

					// if wading...
 					if(MY._MOVEMODE == _MODE_WADING) // wading on/in a passable block
					{
 	/*
  						// check for swimming
						temp.X = MY.X;
    					temp.Y = MY.Y;
    					temp.Z = MY.Z + MY.MIN_Z;	// can my feet touch?

    					//SHOOT MY.POS,temp;  // NOTE: ignore passable blocks
						trace_mode = IGNORE_ME + IGNORE_PASSABLE + IGNORE_PASSENTS;
						trace(MY.POS,temp);
 	*/
						// NEW if model center is in the water switch to swimming mode
						result = content(MY.POS);
						if (result == content_passable)
	 	//				if(RESULT == 0)
						{
							// switch to swimming
							MY._MOVEMODE = _MODE_SWIMMING;
						}
						else	// use SOLID surface for height (can't walk on water)
						{
  							// get height to solid underwater surface
							temp.X = MY.X;
    						temp.Y = MY.Y;
    						temp.Z = MY.Z - 1000;//-- + MY.MIN_Z;	// can my feet touch?

							trace_mode = IGNORE_SPRITES + IGNORE_ME + IGNORE_PASSABLE + IGNORE_PASSENTS;
							result = trace(MY.POS,temp);
  							my_height = RESULT + MY.MIN_Z;    // calculate wading height
						}
					} // END wading on/in a passable block
				}



	 		} // END if they are on or in a passable block...
			else  // not in or on a passable block
			{
				// if wading or swimming while *not* on/in a passable block...
				if(   (MY._MOVEMODE == _MODE_SWIMMING)
					|| ( (ON_PASSABLE == 0) && (MY._MOVEMODE == _MODE_WADING) )
				  )
				{
					// get out of the water (go to walk mode)
					MY._MOVEMODE = _MODE_WALKING;
					MY.TILT = 0;       // stop tilting
				}
 			} // END not in or above water


  			// if he is on a slope, change his angles, and maybe let him slide down
			if(MY.__SLOPES == ON)
			{
				// Adapt the player angle to the floor slope
				MY_ANGLE.TILT = 0;
				MY_ANGLE.ROLL = 0;
				if((my_height < 10) && ((my_floornormal.X != 0) || (my_floornormal.Y != 0) ))
				{	// on a slope?
					// rotate the floor normal relative to the player
					MY_ANGLE.PAN = -MY.PAN;
					vec_rotate(my_floornormal,MY_ANGLE);
					// calculate the destination tilt and roll angles
					MY_ANGLE.TILT = -ASIN(my_floornormal.X);
					MY_ANGLE.ROLL = -ASIN(my_floornormal.Y);
				}
				// change the player angles towards the destination angles
				MY.TILT += 0.2 * ANG(MY_ANGLE.TILT-MY.TILT);
				MY.ROLL += 0.2 * ANG(MY_ANGLE.ROLL-MY.ROLL);
			}
			else
			{
				// If the ROLL angle was not equal to zero,
				// apply a ROLL force to set the angle back
				//jcl 07-08-00 fix loopings on < 3 fps systems
				MY.ROLL -= 0.2*ANG(MY.ROLL);
			}

			// Now accelerate the angular speed, and change his angles
			// -old method- ACCEL	MY._ASPEED,aforce,ang_fric;
			temp = max(1-TIME*ang_fric,0);     // replaced min with max (to eliminate 'creep')
			MY._ASPEED_PAN  = (TIME * aforce.pan)  + (temp * MY._ASPEED_PAN);    // vp = ap * dt + max(1-(af*dt),0)  * vp
			MY._ASPEED_TILT = (TIME * aforce.tilt) + (temp * MY._ASPEED_TILT);
			MY._ASPEED_ROLL = (TIME * aforce.roll) + (temp * MY._ASPEED_ROLL);

  			temp = MY._ASPEED_PAN * MY._SPEED_X * 0.05;
			if(MY.__WHEELS)
			{	// Turn only if moving ahead
				//jcl 07-03-00 patch to fix movement
				MY.PAN += temp * TIME;
			}
			else
			{
				MY.PAN += MY._ASPEED_PAN * TIME;
			}
			MY.ROLL += (temp * MY._BANKING + MY._ASPEED_ROLL) * TIME;

			// the head angle is only set on the player in a single player system.
			if (ME == player)
			{
				head_angle.TILT += MY._ASPEED_TILT * TIME;
				//jcl 07-03-00 end of patcht

				// Limit the TILT value
				head_angle.TILT = ang(head_angle.TILT);
				if(head_angle.TILT > 80) { head_angle.TILT = 80; }
				if(head_angle.TILT < -80) { head_angle.TILT = -80; }
			}

			// disable strafing
			if(MY.__STRAFE == OFF)
			{
				force.Y = 0;	// no strafe
			}


			// if swimming...
			if(MY._MOVEMODE == _MODE_SWIMMING)
			{
 				// move in water
  				swim_gravity();
			}
			else // not swimming
			{
				// if wading...
				if(MY._MOVEMODE == _MODE_WADING)
				{
					wade_gravity();
				}
				else // not swimming or wading (not in water)
				{
					// Ducking or crawling...
					if((MY._MOVEMODE == _MODE_DUCKING) || (MY._MOVEMODE == _MODE_CRAWLING))
					{
						if(force.Z >= 0)
						{
							MY._MOVEMODE = _MODE_WALKING;
						}
						else	// still ducking
						{
							// reduce height by ducking value
							my_height += duck_height;
						}

					}
					else  // not ducking or crawling
					{
						// if we have a ducking force and are not already ducking or crawling...
						if((force.Z < 0) && (MY.__DUCK == ON))		// dcp 7/28/00 added __DUCK
						{
							// ...switch to ducking mode
							MY._MOVEMODE = _MODE_DUCKING;
							MY._ANIMDIST = 0;
							force.Z = 0;
						}
					}

					// Decide whether the actor can jump or not. He can't if he is in the air
					if((jump_height <= 0)
						|| (MY.__JUMP == OFF)
						|| (my_height > 4)
						|| (force.Z <= 0))
					{
						force.Z = 0;
					}

					// move on land
					move_gravity();
				}  // END (not in water)
			}// END not swimming

		} // END not in 'still' mode

		if(MY._MOVEMODE != _MODE_TRANSITION)
		{
			// animate the actor
			actor_anim();
		}

		// If I'm the only player, draw the camera and weapon with ME
		if(client_moving == 0) { move_view(); }

		carry();		// action pointer used to carry items with the player (eg. a gun or sword)

		// Wait one tick, then repeat
		wait(1);
	}  // END while((MY._MOVEMODE > 0)&&(MY._MOVEMODE <= _MODE_STILL))
}




/////////////////////////////////////////////////////////////////////////
// Desc: on ground movement action
//			use when player is not swimming or wading
//
//
// Mod Date: 02/20/02 DCP
//				Improved jumping code (no longer frame dependent)
function move_gravity()
{
	// Filter the forces and frictions dependent on the state of the actor,
	// and then apply them, and move him

	// First, decide whether the actor is standing on the floor or not
	if(my_height < 5)
	{

		// Calculate falling damage
 		if((MY.__FALL == ON) && (MY._FALLTIME > fall_time))
  		{
			MY._HEALTH -= fall_damage();		// take damage depending on fall_time
 		}
		MY._FALLTIME = 0; 	// reset falltime

		friction = gnd_fric;
		if(MY._MOVEMODE == _MODE_DRIVING)
		{
			// Driving - less friction, less force
			friction *= 0.3;
			force.X *= 0.3;
		}

		// reset absolute forces
		absforce.X = 0;
		absforce.Y = 0;
		absforce.Z = 0;

		// If on a slope, apply gravity to draw him downwards:
		if(my_floornormal.Z < 0.9)
		{
			// reduce ahead force because player force it is now deflected upwards
			force.x *= my_floornormal.z;
			force.y *= my_floornormal.z;
			// gravity draws him down the slope
			absforce.X = my_floornormal.x * gravity * slopefac;
			absforce.Y = my_floornormal.y * gravity * slopefac;
		}
	}
	else	// (my_height >= 5)
	{
		// airborne - reduce all relative forces
		// to prevent him from jumping or further moving in the air
		friction = air_fric;
		//jcl 10-08-00
		force.X *= 0.2; // don't set the force completely to zero, otherwise
		force.Y *= 0.2; // player could be stuck on top of a non-wmb entity
		force.Z = 0;

		absforce.X = 0;
		absforce.Y = 0;
		// Add the world gravity force
		absforce.Z = -gravity;

		// only falling if moving downward (but not if ducking)
		if( (MY._SPEED_Z <= 0) && ((MY._MOVEMODE != _MODE_DUCKING) && (MY._MOVEMODE != _MODE_CRAWLING)) )
		{
			MY._FALLTIME += TIME;   // add falling time
		}
	}

	// accelerate the entity relative speed by the force
	// -old method- ACCEL	speed,force,friction;
 	// replaced min with max (to eliminate 'creep')
	temp = max((1-TIME*friction),0);
	MY._SPEED_X = (TIME * force.x) + (temp * MY._SPEED_X);    // vx = ax*dt + max(1-f*dt,0) * vx
	MY._SPEED_Y = (TIME * force.y) + (temp * MY._SPEED_Y);    // vy = ay*dt + max(1-f*dt,0) * vy
	MY._SPEED_Z = (TIME * absforce.z) + (temp * MY._SPEED_Z);

	// calculate relative distances to move
	dist.x = MY._SPEED_X * TIME;  	// dx = vx * dt
	dist.y = MY._SPEED_Y * TIME;     // dy = vy * dt
	dist.z = 0;                      // dz = 0  (only gravity and jumping)

	// calculate absolute distance to move
	absdist.x = absforce.x * TIME * TIME;   // dx = ax*dt^2
	absdist.y = absforce.y * TIME * TIME;   // dy = ay*dt^2
	absdist.z = MY._SPEED_Z * TIME;         // dz = vz*dt

	// Add the speed given by the ground elasticity and the jumping force
	if(my_height < 5)
	{
		// bring to ground level - only if slope not too steep
		//jcl 10-08-00
  		if(my_floornormal.Z > slopefac/4)
		{
			absdist.z = -max(my_height,-10);
		}

		// if we have a jumping force...
		if(force.Z > 0)
		{
			MY._JUMPTARGET = jump_height - my_height;	// calculate jump delta

			// ...switch to jumping mode
			MY._MOVEMODE = _MODE_JUMPING;
			MY._ANIMDIST = 0;
		}

		// If the actor is standing on a moving platform, add it's horizontal displacement
		absdist.X += my_floorspeed.X;
		absdist.Y += my_floorspeed.Y;
	}

	// if we are still 'jumping'
	if(MY._JUMPTARGET > 0)
	{
		// calculate velocity

		// predict the current speed required to reach the jump height
 		MY._SPEED_Z = sqrt((MY._JUMPTARGET)*2*gravity);

		// scale distance from jump (absdist.z) by movement_scale
		absdist.z = MY._SPEED_Z * TIME * movement_scale;
		MY._JUMPTARGET -= absdist.z;
	}

	// Restrict the vertical distance to the maximum jumping height
	// (scale jump_height by movement_scale)
	if((MY.__JUMP == ON) && (absdist.z > 0) && (absdist.z + my_height > (jump_height * movement_scale)))
	{
		absdist.z = max((jump_height * movement_scale)- my_height,0);
	}

	// Now move ME by the relative and the absolute speed
	YOU = NULL;	// YOU entity is considered passable by MOVE

	vec_scale(dist,movement_scale);	// scale distance by movement_scale
	// jcl: removed absdist scaling because absdist is calculated from external forces
	//--- vec_scale(absdist,movement_scale);	// scale absolute distance by movement_scale


	// Replaced the double MOVE with a single MOVE and a distance check
	move_mode = ignore_you + ignore_passable + ignore_push + activate_trigger + glide;
	result = ent_move(dist,absdist);
	if(result > 0)
	{
		// only use the relative distance traveled (for animation)
		my_dist = vec_length(dist);
	}
	else
	{
		// player is not moving, do not animate
		my_dist = 0;
	}


	// Store the distance for player 1st person head bobbing
	// (only for single player system)
	if(ME == player)
	{
		player_dist += SQRT(dist.X*dist.X + dist.Y*dist.Y);
	}
}


/////////////////////////////////////////////////////////////////////////
// Desc: wading movement action
//       this action should be called when the player is wading (_MODE_WADING)
//
function wade_gravity()
{
	// basic friction
	friction = gnd_fric;

	MY._FALLTIME = 0;	// reset falltime (no falling damage in water)

	//adjust player force depending on depth of water
	temp = (my_height_passable / max(1,-MY.MIN_Z));	// MY.min_z can be 0!!
	if(temp < 0.1)	// minimum speed
	{
		temp = 0.1;
	}
	force.X *= temp;
	force.Y *= temp;
	force.Z *= temp;

	// reset absforce
	absforce.X = 0;
	absforce.Y = 0;
	absforce.Z = 0;

	// If on a slope, apply gravity to draw him downwards:
	if(my_floornormal.Z < 0.9)
	{
		// reduce ahead force because player force it is now deflected upwards
		force.x *= my_floornormal.z;
		force.y *= my_floornormal.z;
		// gravity draws him down the slope (but only at 1/4 of above water)
		absforce.X = my_floornormal.x * gravity * slopefac * 0.25;
		absforce.Y = my_floornormal.y * gravity * slopefac * 0.25;
	}

	// -old method- ACCEL	speed,force,friction;
 	// replaced min with max (to eliminate 'creep')
	temp = max((1-TIME*friction),0);
	MY._SPEED_X = (TIME * force.x) + (temp * MY._SPEED_X);    // vx = ax*dt + max(1-f*dt,0) * vx
	MY._SPEED_Y = (TIME * force.y) + (temp * MY._SPEED_Y);    // vy = ay*dt + max(1-f*dt,0) * vy
	MY._SPEED_Z = (TIME * absforce.z) + (temp * MY._SPEED_Z);


	// calculate relative distances
	dist.x = MY._SPEED_X * TIME; 		// dx = vx * dt
	dist.y = MY._SPEED_Y * TIME;     // dy = vy * dt
	dist.z = 0;                      // dz = 0

	// calculate absolute distances
	absdist.x = absforce.x * TIME * TIME; 		// dx = ax * dt^2
	absdist.y = absforce.y * TIME * TIME;     // dy = ay * dt^2
	absdist.z = 0; // NO JUMPING WHILE WADING

 	// Add the speed given by the ground elasticity
 	if(my_height < -5)
	{
		temp = my_height;
		if(temp < -10)  { temp = -10; }
 		absdist.Z -= (temp - 5);
	}
	else
	{
 		// Pull back down to the underwater surface
		absdist.Z = max(-my_height,-gravity);

	}

	// Now move ME by the relative and the absolute speed
	YOU = NULL;	// YOU entity is considered passable by MOVE
	vec_scale(dist,movement_scale);	// scale distance by movement_scale
	//--vec_scale(absdist,movement_scale);	// scale absolute distance by movement_scale
	move_mode = ignore_you + ignore_passable + ignore_push + activate_trigger + glide;
	result = ent_move(dist,absdist);

	// Store the distance covered, for animation
	my_dist = RESULT;
	// Store the distance for player 1st person head bobbing
	// (only for single player system)
	if(ME == player)
	{
		player_dist = my_dist;
	}
}


/////////////////////////////////////////////////////////////////////////
// Desc: gravity / buoyancy effect on the player in water (IN_PASSABLE)
//       this action should be called when the player is swimming (_MODE_SWIMMING)
//
function swim_gravity()
{
	friction = water_fric;     // set friction to water friction

	MY._FALLTIME = 0;	// no falling damage in water

	// force.Z is used for diving/surfacing
	if(force.Z == 0)
	{
		// level out player
		if(MY.TILT < 0)
		{
			MY.TILT += 3 * TIME;
			if(MY.TILT > 0)
			{
				MY.TILT = 0;
			}
		}
		else
		{
			if(MY.TILT > 0)
			{
				MY.TILT -= 3 * TIME;
				if(MY.TILT < 0)
				{
					MY.TILT = 0;
				}
 			}
		}
	}
	else
	{
		// surface player
		if(force.Z > 0)
		{
			MY.TILT += 3 * TIME;
			if(MY.TILT > 30)
			{
				MY.TILT = 30;
			}
		}
  		else
		{
			// player diving
			MY.TILT -= 3 * TIME;
			if(MY.TILT < -30)
			{
				MY.TILT = -30;
			}
		}
	}

/*	NO absforce needed in this swim_gravity
	// reset absolute forces
  	absforce.X = 0;
	absforce.Y = 0;
	absforce.Z = 0;
*/
	// Swimming - rhythmic acceleration
	force.X *= 0.5 + (0.25*walkwave);
	force.Y *= 0.5;
	force.Z *= 0.025;   // surface/diving force


	// accelerate the entity relative speed by the force
	// replaced min with max (to eliminate 'creep')
	temp = max((1-TIME*friction),0);
	MY._SPEED_X = (TIME * force.x) + (temp * MY._SPEED_X);    // vx = ax*dt - min(f*dt,1) * vx
	MY._SPEED_Y = (TIME * force.y) + (temp * MY._SPEED_Y);    // vy = ay*dt - min(f*dt,1) * vy
	MY._SPEED_Z = (TIME * force.z) + (temp * MY._SPEED_Z);    // vz = az*dt - min(f*dt,1) * vz


	// calculate relative distances
	dist.x = MY._SPEED_X * TIME; 		// dx = vx * dt
	dist.y = MY._SPEED_Y * TIME;     // dy = vy * dt
	dist.z = MY._SPEED_Z * TIME;     // dz = vz * dt


//jcl 07-22-00  scan_floor changed
	if( (on_passable_ == ON) )
	{
		// reset absolute distance
		absdist.x = 0;
		absdist.y = 0;
		absdist.z = 0;

		// if MY center (use passable height) is greater than the surface level...
		if(((my_height_passable) > 5))// (MY.MIN_Z + 21)))   // 21 = 16 "hull" + 5 "float value"
		{
			 // pull down to the surface of the water
  			absdist.Z -= min(gravity,my_height_passable);
		}


		// restrict climbing rotation on surface and check for edge...
		if(MY.TILT > 5)
		{
			MY.TILT = 5;   // shallow climb


			// If the user is near a solid edge and trying to swim up try to hop out
			// scan ahead of ME
			vec_set(vecFrom,MY.X);
			vecFrom.X += (MY.MAX_X + 25) * cos(MY.PAN);
			vecFrom.Y += (MY.MAX_X + 25) * sin(MY.PAN);
			vec_set(vecTo,vecFrom);
			vecFrom.Z += MY.MAX_Z;		// adjust this to adjust height

			trace_mode = IGNORE_ME + IGNORE_SPRITES + IGNORE_PASSENTS + IGNORE_MODELS + IGNORE_PASSABLE;
			if( (trace(vecFrom,vecTo)) != 0)
			{
				// hop out of water
				temp.X = 0; temp.Y = 0; temp.Z = MY.MAX_Z;
				//--move(ME,temp,NULLSKILL);
				move_mode = ignore_you + ignore_passable + ignore_push + activate_trigger + glide;
				ent_move(temp,NULLSKILL); // move up ..

				temp.X = MY.MAX_X; temp.Z = 0;
				//--move(ME,temp,NULLSKILL);
				result = ent_move(temp,NULLSKILL);// ... and over

			}
		}

		// Now move ME by the relative and the absolute speed
		YOU = NULL;	// YOU entity is considered passable by MOVE
		vec_scale(dist,movement_scale);	// scale distance by movement_scale
		//	Removed absdist movement_scale because absdist is calculated from external forces
		//---vec_scale(absdist,movement_scale);	// scale absolute distance by movement_scale
		//--move(ME,dist,absdist);
		move_mode = ignore_you + ignore_passable + ignore_push + activate_trigger + glide;
		result = ent_move(dist,absdist);
	}
	else   // underwater
	{
 		// NOTE: this is where we would add buoyancy (using absforce)
		// right now we are assuming zero buoyancy

		// NOTE: this is where we could add the effect of currents (using absforce)

		// Now move ME by the relative and the absolute speed
		YOU = NULL;	// YOU entity is considered passable by MOVE
		vec_scale(dist,movement_scale);	// scale distance by movement_scale
	  //--	move(ME,dist,NULLSKILL);
		move_mode = ignore_you + ignore_passable + ignore_push + activate_trigger + glide;
		result = ent_move(dist,NULLSKILL);
	}



	// Store the distance covered, for animation
	my_dist = RESULT;
	// Store the distance for player 1st person head bobbing
	// (only for single player system)
	if(ME == player)
	{
		player_dist += MY._SPEED_X;//SQRT(speed.X*speed.X + speed.Y*speed.Y);
	}
}

/////////////////////////////////////////////////////////////////////////
// Desc: scan for a surface below the ME entity
//       set my_floornormal vector to the normal of the surface
//			set my_height to the distance between ME.MIN_Z and the surface
//			set floorspeed to the X & Y speed of any platform ME is on.
//			set on_passable_, in_passable_, and in_solid_ to the 'offset SONAR'
//		values.
//
function scan_floor()
{
	// -old- SONAR	ME,4000;
//jcl 1-14-01: forgotten IGNORE_SPRITES fixed
	trace_mode = IGNORE_SPRITES + IGNORE_PASSENTS + IGNORE_MODELS + USE_BOX + ACTIVATE_SONAR;
	vec_set(vecFrom,MY.x);
	vec_set(vecTo,MY.x);
	vecTo.z -= 4000;
	my_height = trace(vecFrom,vecTo);  // this is the same as SONAR MY,distance;

	// if the first sonar shows we are in_passable or on_passable...
	if((IN_PASSABLE == ON) || (ON_PASSABLE == ON))
	{
		// the entity can be completely or partially under water
//--		vecFrom.z += 16;		// displace me upwards by the hull size - now my hull is outside the water
		vecFrom.z += (MY.MAX_Z + MY.MIN_Z);// displace upwards by model's vertical center
		trace_mode = IGNORE_SPRITES + IGNORE_PASSENTS + IGNORE_MODELS;
		my_height_passable = trace(vecFrom,vecTo);

	}
	else
	{
		my_height_passable = 0;
	}

	// save SONAR values for later use
	on_passable_ = ON_PASSABLE;
	in_passable_ = IN_PASSABLE;
	in_solid_ = IN_SOLID;

	my_floornormal.X = NORMAL.X; 	// set my_floornormal to the normal of the surface
	my_floornormal.Y = NORMAL.Y;
	my_floornormal.Z = NORMAL.Z;
//	my_height = RESULT;       		// set my_height to the distance between entity's MIN_Z and surface

	my_floorspeed.X = 0; 			// reset floorspeed to zero
	my_floorspeed.Y = 0;

	// if the player is standing on a platform, move him with it
	if(YOU != NULL)
	{
		if(YOUR._TYPE == _TYPE_ELEVATOR)
		{
			my_floorspeed.X = YOUR._SPEED_X;
			my_floorspeed.Y = YOUR._SPEED_Y;
			// Z speed is not necessary - this is done by the height adaption
		}
	}
}



/////////////////////////////////////////////////////////////////////////
// Desc: calculate the damage taken by a fall
//
//	Param: fall_time and MY must be set before calling
//
// Note: override this function if you want to use a different formula
//
// Called from 'move_gravity()'
function	fall_damage()
{
	// calculate damage depending on _FALLTIME
 	return(10 + INT((MY._FALLTIME - fall_time) * 1.75));
}



/////////////////////////////////////////////////////////////////////////
// Desc: set force and aforce values
//			these values come from _player_intentions (single player)
//		  or from the client (multiplayer)
//
//	Calls: _player_intentions
//
//	Called From: player_move()
//
function _player_force()
{
	// If the camera does not move itself
	if (_camera == 0)
	{
		// multiplayer mode
		if (client_moving)
		{
			// get forces from server
//jcl 03/15/01
			vec_set(force,MY._FORCE_X);
			vec_set(aforce,MY._AFORCE_PAN);
		}
		else
		{
			// get forces from user input
			_player_intentions();
		}

		vec_scale(aforce,MY._FORCE);
		vec_scale(force,MY._FORCE);
	}
	else
	{ // player controls camera - set actor forces to zero
		vec_set(aforce,nullvector);
		vec_set(force,nullvector);
	}
}



/////////////////////////////////////////////////////////////////////////
// Desc: used in multiplayer (client/server) games
//			set client_moving var to 1
//			take user input use that to adjust the 'player' forces
//			SEND player forces to the server
//       move the camera
//
// Call: _player_intentions
//			move_view
function client_move()
{
	client_moving = 1;
	while(1)
	{
		_player_intentions();// user key/mouse input sets force and aforce values

		// player created on the client?
		if (player)
		{
			vec_set(player._FORCE_X,force);
			vec_set(player._AFORCE_PAN,aforce);

		// send player forces to server
			send_vec(player._FORCE_X);
			send_vec(player._AFORCE_PAN);

		// move the camera
			move_view();
		}
		wait(1);
	}
}






/////////////////////////////////////////////////////////////////////
// Desc: aitborne movement function
function move_airborne()
{
	MY._POWER += 0.1*force.Z;
	if(MY._POWER < 0) { MY._POWER = 0; }
	if(MY._POWER > power_max) { MY._POWER = power_max; }
	absforce.X = 0;
	absforce.Y = 0;
	absforce.Z = 0;

	friction = air_fric;
	force.X = 0;
	force.Y = 0;
	force.Z = 0;
}