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

DEFINE _WALKDIST,SKILL27;	// distance per walk cycle
DEFINE _RUNDIST,SKILL28;	// distance per run cycle



//@ Animate Vars
var anim_attack_ticks = 16;// time for one attack animation cycle

var anim_stand_ticks = 16;	// time for one standing anim cycle
var anim_jump_ticks = 6; 	// time for one jump animation cycle
var anim_duck_ticks = 8; 	// time for one duck animation cycle

var anim_walk_dist = 1; 	// dist per model width per walk cycle
var anim_run_dist = 1.5;	// dist per model width per run cycle
var anim_crawl_dist = 0.8; // dist per model width per crawl cycle
var anim_wade_dist = 0.8;	// dist per model width per crawl cycle
var anim_swim_dist = 1; 	// dist per model width per swim cycle

var walk_or_run = 12; 	// max quants per tick to switch from walk to run animation


// strings for defining the animation frames
STRING anim_stand_str,"stand";
STRING anim_walk_str,"walk";
STRING anim_run_str,"run";
STRING anim_duck_str,"duck";
STRING anim_swim_str,"swim";
STRING anim_dive_str,"dive";
STRING anim_jump_str,"jump";
STRING anim_crawl_str,"crawl";
STRING anim_wade_str,"walk";

// string synonyms for defining the animation frames (and their default values)
STRING anim_default_death_str,"death";
STRING anim_default_attack_str,"attack";
//SYNONYM anim_attack_str { TYPE STRING; DEFAULT anim_default_attack_str;}
string* anim_attack_str = anim_default_attack_str;
//SYNONYM anim_death_str { TYPE STRING; DEFAULT anim_default_death_str;}
string* anim_death_str = anim_default_death_str;

//SYNONYM anim_str { TYPE STRING; }
string* anim_str;



//@ Function prototypes

function anim_airborne();   // animate 'airborne' entity
function anim_init();		// initialize the actor animation style
function actor_anim();		// handle actor animation
function	actor_anim_transition(str_anim_target);	// handle transition animation between states
function actor_anim_old_style_anim();	// old animation style (for compatability)

//#ACTION drop_shadow;			// create a shadow sprite under entity (use move_shadow() to move)
function move_shadow();		// move shadow sprite under entity
function attach_entity();	// attach an entity with same origin/frames

//@ Function code

/////////////////////////////////////////////////////////////////////////
// Desc: animate 'airborne' entity
function anim_airborne()
{
	// standing animation
	if(MY._POWER > 0)	// engine running
	{
		MY._ANIMDIST += TIME * MY._POWER;
		// wrap animation time to a value between zero and anim_stand_ticks
		if(MY._ANIMDIST > anim_stand_ticks)
		{
			MY._ANIMDIST -= anim_stand_ticks;
		}
		// calculate a percentage out of the animation time
		temp =  100 * MY._ANIMDIST / anim_stand_ticks;
		// set the frame from the percentage
		ent_cycle(anim_stand_str,temp);
		return;
	}
	return;
}


/////////////////////////////////////////////////////////////////////////
// Desc: set up for animation
// 		scale entity by actor_scale
//			if using the "old style animation"
//	      	- split the integer and fractional parts of the animation
//				  frame numbers, and store distance factors
//
function anim_init()
{
	vec_scale(MY.SCALE_X,actor_scale);

	if(int(MY._WALKFRAMES) < 0) { return; }	// use adv animation

	temp = frc(MY._WALKFRAMES) * 1000;
	if(temp != 0)
	{
		// old style animation
		MY._WALKFRAMES = int(MY._WALKFRAMES);
		if(MY._WALKFRAMES == 0) { MY._WALKFRAMES = 13; }
		MY._WALKDIST = MY._WALKFRAMES / temp;

		temp = frc(MY._RUNFRAMES) * 1000;
		MY._RUNFRAMES = int(MY._RUNFRAMES);
		if(MY._RUNFRAMES == 0) { MY._RUNFRAMES = 5; }
		MY._RUNDIST = MY._RUNFRAMES / temp;
	}
}



////////////////////////////////////////////////////////////////////////
// Desc: *ADVANCED* actor animation function
//

DEFINE _ADVANIM_TICK,SKILL1;	// 'tick' related animation
DEFINE _ADVANIM_DIST,SKILL2;  // 'dist' related animation

// Define Masks
DEFINE MASK_ANIM_ATTACK_TICKS,2093056;	// upper 9 (less topbit)
DEFINE MASK_ANIM_JUMP_TICKS,4032; 		// mid 6
DEFINE MASK_ANIM_DUCK_TICKS,63; 			// lower 6

DEFINE MASK_ANIM_RUN_DIST,	2064384;	// upper 6 (less topbit)
DEFINE MASK_ANIM_WALK_DIST, 31744;	// next 5
DEFINE MASK_ANIM_CRAWL_DIST, 992;	// next 5
DEFINE MASK_ANIM_SWIM_DIST, 31;		// bottom 5


// Desc: 'Advanced' animation function. This allows the user to set animation
//		cycle distances and timing on an individual entity level.See the
//		"Scriptless Shooter" tutorial for details.
//
function actor_adv_anim()
{
	// START ADVANCED STYLE ANIMATIONS (frame names)

	// Check to see if player is attacking
	if(( ME == PLAYER) && (MY._FIREMODE != 0))
	{
		// if you have more than one attacking animation, here's where you would test for it...
		// calculate a percentage out of the animation time
//opt.	temp2 = 4*INT(((-MY._ADVANIM_TICK)&MASK_ANIM_ATTACK_TICKS)>>12);// anim_attack_ticks
		temp2 = INT(((-MY._ADVANIM_TICK)&MASK_ANIM_ATTACK_TICKS)>>10);// anim_attack_ticks
		temp =  100 * MY._ANIMDIST / temp2;
		// set the frame from the percentage
		// -old- set_frame ME,anim_attack_str,temp;
		ent_frame(anim_attack_str,temp);

		// increment _ANIMDIST by elapsed time
		MY._ANIMDIST += TIME;
		// check to see if we finished the attack animation
		if(MY._ANIMDIST > temp2)
		{
			MY._ANIMDIST = 0; // reset animation distance
			MY._FIREMODE = 0;	// reset firemode
		}
		return;
	}      //==
	else // not firing
	{
		/////////////////////////////////////////////////////////////////////
		// Animations that can take place standing still (jumping, ducking, etc.)
		/////////////////////////////////////////////////////////////////////
   	// the jumping animation
		if(MY._MOVEMODE == _MODE_JUMPING)
		{
//opt. 			temp2 = 4*INT(((-MY._ADVANIM_TICK)&MASK_ANIM_JUMP_TICKS)>>6);// anim_jump_ticks
 			temp2 = INT(((-MY._ADVANIM_TICK)&MASK_ANIM_JUMP_TICKS)>>4);// anim_jump_ticks
			// calculate a percentage out of the animation time
			temp =  100 * MY._ANIMDIST / temp2;
			// set the frame from the percentage
			// -old- set_frame ME,anim_jump_str,temp;
			ent_frame(anim_jump_str,temp);
			// increment _ANIMDIST by elapsed time
			MY._ANIMDIST += TIME;
			// check to see if we finished jump animation
			if(MY._ANIMDIST > temp2)
			{
				MY._ANIMDIST = 0;
				MY._MOVEMODE = _MODE_WALKING;
			}
			return;
		}

   	// the ducking animation
		if(MY._MOVEMODE == _MODE_DUCKING)
		{
 		 	temp2 = (frc(-MY._ADVANIM_DIST)<<10);// walk_or_run
   		// you can only duck at walking speeds or below.
			if(my_dist >= temp2*TIME*movement_scale)	// to fast to duck?
			{
				MY._MOVEMODE = _MODE_WALKING; // catch the walking mode below this one
 			}
			else
			{ // ducking
 		 		temp2 = 4*INT(((-MY._ADVANIM_TICK)&MASK_ANIM_DUCK_TICKS));// anim_duck_ticks
				// calculate a percentage out of the animation time
				temp =  100 * MY._ANIMDIST / temp2;
				// set the frame from the percentage
				// -old - set_frame ME,anim_duck_str,temp;
				ent_frame(anim_duck_str,temp);
				// increment _ANIMDIST by elapsed time
				MY._ANIMDIST += TIME;
				// check to see if we finished ducking
				if(MY._ANIMDIST > temp2)
				{
					MY._ANIMDIST = 0;
					MY._MOVEMODE = _MODE_CRAWLING;
				}
				return;
			}
		}

		// the crawling animation
		if(MY._MOVEMODE == _MODE_CRAWLING)
		{
 		 	temp2 = (frc(-MY._ADVANIM_DIST)<<10);// walk_or_run
			// you can only crawl at walking speeds or below.
			if(my_dist >= temp2*TIME*movement_scale)	// to fast to crawl?
			{
				MY._MOVEMODE = _MODE_WALKING; // catch the walking mode below this one
 			}
			else
			{ // crawling
//opt. 		 		temp2 = 0.25*INT(((-MY._ADVANIM_DIST)&MASK_ANIM_CRAWL_DIST)>>5);// anim_crawl_dist
 		 		temp2 = (((-MY._ADVANIM_DIST)&MASK_ANIM_CRAWL_DIST)>>7);// anim_crawl_dist

 				// set the distance covered, in percent of the model width
				covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 				// calculate the real cycle distance from the model size
				while(covered_dist > temp2)
				{
					covered_dist -= temp2;
				}

				if(force.X < 0)	// moving backwards?
				{
					temp = 100 - temp;
				}
				temp = 100 * covered_dist / temp2;
				//-old- set_cycle ME,anim_crawl_str,temp;
				ent_cycle(anim_crawl_str,temp);

				MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
				return;
			}

		}

		// the swimming animation
		if(MY._MOVEMODE == _MODE_SWIMMING)
		{
//opt. 		 		temp2 = 0.25*INT(((-MY._ADVANIM_DIST)&MASK_ANIM_SWIM_DIST));// anim_swim_dist
 		 		temp2 = 0.25*(((-MY._ADVANIM_DIST)&MASK_ANIM_SWIM_DIST));// anim_swim_dist

 			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 			// calculate the real cycle distance from the model size
			while(covered_dist > temp2)
			{
				covered_dist -= temp2;
			}

			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}
			temp = 100 * covered_dist / temp2;
			// -old- set_cycle ME,anim_swim_str,temp;
			ent_cycle(anim_swim_str,temp);

			MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
			return;
		}


		// the wading animation  (NOTE! uses same distance as crawling)
		if(MY._MOVEMODE == _MODE_WADING)
		{
//opt. 		 		temp2 = 0.25*INT(((-MY._ADVANIM_DIST)&MASK_ANIM_CRAWL_DIST)>>5);// anim_crawl_dist == anim_crawl_dist
 		 		temp2 = (((-MY._ADVANIM_DIST)&MASK_ANIM_CRAWL_DIST)>>7);// anim_crawl_dist == anim_crawl_dist

 			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 			// calculate the real cycle distance from the model size
			while(covered_dist > temp2)
			{
				covered_dist -= temp2;
			}

			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}

			temp = 100 * covered_dist / temp2;
			// -old- set_cycle ME,anim_wade_str,temp;
			ent_cycle(anim_wade_str,temp);

			MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
			return;
		}

		// the standing still animation
		// NOTE: the must be *before* _MODE_WALKING but after any other mode
		//      that can animate while the player is not moving (swimming,
		//		  ducking, jumping, etc.)
		if((my_dist < 0.01) || (MY._MOVEMODE == _MODE_STILL))
		{
//opt. 			temp2 = 4*((FRC(-MY._ADVANIM_TICK))<<10);// anim_stand_ticks
 			temp2 = ((FRC(-MY._ADVANIM_TICK))<<12);// anim_stand_ticks

 			MY._ANIMDIST += TIME;
			// wrap animation time to a value between zero and anim_stand_ticks
			if(MY._ANIMDIST > temp2)
			{
				MY._ANIMDIST -= temp2;
			}
			// calculate a percentage out of the animation time
			temp =  100 * MY._ANIMDIST / temp2;
			// set the frame from the percentage
			// -old- set_cycle ME,anim_stand_str,temp;
			ent_cycle(anim_stand_str,temp);

			return;
 		}


		// walking animation
		if(MY._MOVEMODE == _MODE_WALKING)
		{
			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);

 		 	temp2 = (frc(-MY._ADVANIM_DIST)<<10);// walk_or_run
			// decide whether to play the walk or run animation
			if(my_dist < temp2*TIME*movement_scale)	// Walking
			{
//opt. 		 		anim_dist = 0.25*INT(((-MY._ADVANIM_DIST)&MASK_ANIM_WALK_DIST)>>10);// anim_walk_dist
 		 		anim_dist = (((-MY._ADVANIM_DIST)&MASK_ANIM_WALK_DIST)>>12);// anim_walk_dist
				anim_str = anim_walk_str;
			}
			else
			{ // running
//opt. 		 		anim_dist = 0.25*INT(((-MY._ADVANIM_DIST)&MASK_ANIM_RUN_DIST)>>15);// anim_run_dist
 		 		anim_dist = (((-MY._ADVANIM_DIST)&MASK_ANIM_RUN_DIST)>>17);// anim_run_dist
				anim_str = anim_run_str;
			}

			// calculate the real cycle distance from the model size
			if(covered_dist > anim_dist)
			{
				covered_dist -= anim_dist;
			}


			temp = 100 * covered_dist / anim_dist;
			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}

			ent_cycle(anim_str,temp);

			if (covered_dist < MY._WALKDIST)
			{
				_play_walksound();	// sound for right foot
			}
			if ((covered_dist > anim_dist*0.5) && (MY._WALKDIST < anim_dist*0.5))
			{
				_play_walksound();	// sound for left foot
			}
			MY._WALKDIST = covered_dist;
			return;
		}
		return;
		// END OF ADVANCED STYLE ANIMATIONS (frame names)
	}
} // END actor_adv_anim()


/////////////////////////////////////////////////////////////////////////
// Desc: Main action to animate a walking actor, depending on dist
//		  covered (my_dist)
//
function actor_anim()
{
	// check for *ADVANCED ANIMATION* (frame names and entity tick/dist values)
	if(int(MY._WALKFRAMES) < 0) { actor_adv_anim(); return; }

	// decide whether it's a frame number (old) or frame name (new) animation
	if(frc(MY._WALKFRAMES) > 0) { actor_anim_old_style_anim(); return; }


	// START NEW STYLE ANIMATIONS (frame names)

	// Check to see if player is attacking
	if(( ME == PLAYER) && (MY._FIREMODE != 0))
	{
		// if you have more than one attacking animation, here's where you would test for it...
		// calculate a percentage out of the animation time
		temp =  100 * MY._ANIMDIST / anim_attack_ticks;
		// set the frame from the percentage
		// -old- set_frame ME,anim_attack_str,temp;
		ent_frame(anim_attack_str,temp);

		// increment _ANIMDIST by elapsed time
		MY._ANIMDIST += TIME;
		// check to see if we finished the attack animation
		if(MY._ANIMDIST > anim_attack_ticks)
		{
			MY._ANIMDIST = 0; // reset animation distance
			MY._FIREMODE = 0;	// reset firemode
		}
		return;
	}
	else // not firing
	{
		/////////////////////////////////////////////////////////////////////
		// Animations that can take place standing still (jumping, ducking, etc.)
		/////////////////////////////////////////////////////////////////////
   	// the jumping animation
		if(MY._MOVEMODE == _MODE_JUMPING)
		{
			// calculate a percentage out of the animation time
			temp =  100 * MY._ANIMDIST / anim_jump_ticks;
			// set the frame from the percentage
			// -old- set_frame ME,anim_jump_str,temp;
			ent_frame(anim_jump_str,temp);
			// increment _ANIMDIST by elapsed time
			MY._ANIMDIST += TIME;
			// check to see if we finished jump animation
			if(MY._ANIMDIST > anim_jump_ticks)
			{
				MY._ANIMDIST = 0;
				MY._MOVEMODE = _MODE_WALKING;
			}
			return;
		}

   	// the ducking animation
		if(MY._MOVEMODE == _MODE_DUCKING)
		{
   		// you can only duck at walking speeds or below.
			if(my_dist >= walk_or_run*TIME*movement_scale)	// to fast to duck?
			{
				MY._MOVEMODE = _MODE_WALKING; // catch the walking mode below this one
 			}
			else
			{ // ducking
				// calculate a percentage out of the animation time
				temp =  100 * MY._ANIMDIST / anim_duck_ticks;
				// set the frame from the percentage
				// -old - set_frame ME,anim_duck_str,temp;
				ent_frame(anim_duck_str,temp);
				// increment _ANIMDIST by elapsed time
				MY._ANIMDIST += TIME;
				// check to see if we finished ducking
				if(MY._ANIMDIST > anim_duck_ticks)
				{
					MY._ANIMDIST = 0;
					MY._MOVEMODE = _MODE_CRAWLING;
				}
				return;
			}
		}

		// the crawling animation
		if(MY._MOVEMODE == _MODE_CRAWLING)
		{

			// you can only crawl at walking speeds or below.
			if(my_dist >= walk_or_run*TIME*movement_scale)	// to fast to crawl?
			{
				MY._MOVEMODE = _MODE_WALKING; // catch the walking mode below this one
 			}
			else
			{ // crawling
 				// set the distance covered, in percent of the model width
				covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 				// calculate the real cycle distance from the model size
				while(covered_dist > anim_crawl_dist)
				{
					covered_dist -= anim_crawl_dist;
				}

				if(force.X < 0)	// moving backwards?
				{
					temp = 100 - temp;
				}
				temp = 100 * covered_dist / anim_crawl_dist;
				//-old- set_cycle ME,anim_crawl_str,temp;
				ent_cycle(anim_crawl_str,temp);

				MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
				return;
			}

		}

		// the swimming animation
		if(MY._MOVEMODE == _MODE_SWIMMING)
		{
 			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 			// calculate the real cycle distance from the model size
			while(covered_dist > anim_swim_dist)
			{
				covered_dist -= anim_swim_dist;
			}

			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}
			temp = 100 * covered_dist / anim_swim_dist;
			// -old- set_cycle ME,anim_swim_str,temp;
			ent_cycle(anim_swim_str,temp);

			MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
			return;
		}


		// the wading animation
		if(MY._MOVEMODE == _MODE_WADING)
		{
 			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);
 			// calculate the real cycle distance from the model size
			while(covered_dist > anim_wade_dist)
			{
				covered_dist -= anim_wade_dist;
			}

			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}

			temp = 100 * covered_dist / anim_wade_dist;
			// -old- set_cycle ME,anim_wade_str,temp;
			ent_cycle(anim_wade_str,temp);

			MY._WALKDIST = covered_dist;     // save for next 'frame' of animation
			return;
		}

		// the standing still animation
		// NOTE: the must be *before* _MODE_WALKING but after any other mode
		//      that can animate while the player is not moving (swimming,
		//		  ducking, jumping, etc.)
		if((my_dist < 0.01) || (MY._MOVEMODE == _MODE_STILL))
		{
 			MY._ANIMDIST += TIME;
			// wrap animation time to a value between zero and anim_stand_ticks
			if(MY._ANIMDIST > anim_stand_ticks)
			{
				MY._ANIMDIST -= anim_stand_ticks;
			}
			// calculate a percentage out of the animation time
			temp =  100 * MY._ANIMDIST / anim_stand_ticks;
			// set the frame from the percentage
			// -old- set_cycle ME,anim_stand_str,temp;
			ent_cycle(anim_stand_str,temp);

			return;
 		}


		// walking animation
		if(MY._MOVEMODE == _MODE_WALKING)
		{
			// set the distance covered, in percent of the model width
			covered_dist = MY._WALKDIST + my_dist / (MY.MAX_X-MY.MIN_X);

			// decide whether to play the walk or run animation
			if(my_dist < walk_or_run*TIME*movement_scale)	// Walking
			{
				anim_dist = anim_walk_dist;
				anim_str = anim_walk_str;
			}
			else
			{ // running
				anim_dist = anim_run_dist;
				anim_str = anim_run_str;
			}

			// calculate the real cycle distance from the model size
			if(covered_dist > anim_dist)
			{
				covered_dist -= anim_dist;
			}


			temp = 100 * covered_dist / anim_dist;
			if(force.X < 0)	// moving backwards?
			{
				temp = 100 - temp;
			}

			ent_cycle(anim_str,temp);

			if (covered_dist < MY._WALKDIST)
			{
				_play_walksound();	// sound for right foot
			}
			if ((covered_dist > anim_dist*0.5) && (MY._WALKDIST < anim_dist*0.5))
			{
				_play_walksound();	// sound for left foot
			}
			MY._WALKDIST = covered_dist;
			return;
		}
		return;
		// END OF NEW STYLE ANIMATIONS (frame names)
	}

	/* ??? No longer needed ???
	if((MY._MOVEMODE == _MODE_STILL) || (my_dist < 0.01))
	{
		// if the entity has a standing animation, instead of just one frame,
		// place it here. Otherwise...
		MY.FRAME = 1;	// standing
		return;
	}
	*/
}


/////////////////////////////////////////////////////////////////////////
// Desc: Handle transitions between states
//
// *** WORK IN PROGRESS ***
var	anim_trans_cycle = 0;  // "local" var
function	actor_anim_transition(str_anim_target)
{
//	ME = player;
//	wait(1);     // let calling function finish one loop

	MY._ANIMDIST = 0;

	// set the frame and next_frame values
	temp = MY.frame;
//--	ent_frame("swim",0);
	ent_frame(str_anim_target,0);
	MY.next_frame = MY.frame;
	MY.frame = temp;

	anim_trans_cycle = MY._MOVEMODE;
	MY._MOVEMODE = _MODE_TRANSITION;

	// do .25 sec transition (4 ticks)
	while(MY._ANIMDIST < 4)
	{
		MY.frame = int(MY.frame) + (MY._ANIMDIST / 4.0);
//tst_value_3 = MY.frame * 10;

		MY._ANIMDIST += TIME;
//tst_value_4 = MY._ANIMDIST;
		wait(1);
	}
	MY._ANIMDIST = 0;
 	MY._MOVEMODE = anim_trans_cycle;
}


/////////////////////////////////////////////////////////////////////////
// Desc: Handle 'old' A4 style of animation
//			Called from "actor_anim()"
//
function actor_anim_old_style_anim()
{
	if(MY._MOVEMODE == _MODE_WALKING)
	{
		// decide whether to play the walk or run animation
		if((MY._RUNFRAMES <= 0) || (my_dist < walk_or_run*TIME*movement_scale))	// Walking
		{
			if(MY.FRAME < 2) { MY.FRAME = 2; }

			MY.FRAME += MY._WALKDIST*my_dist;

			// this is one of the expert exceptions where you can use WHILE without WAIT!
			while(MY.FRAME >= 2 + MY._WALKFRAMES)
			{
				// sound for right foot
				if(MY.__SOUND == ON) { _play_walksound(); MY.__SOUND = OFF; }
				// cycle the animation
				MY.FRAME -= MY._WALKFRAMES;
			}

			if(MY.FRAME > 1 + MY._WALKFRAMES*0.5) {
				// sound for left foot
				if(MY.__SOUND == OFF) { _play_walksound(); MY.__SOUND = ON; }
			}

			if(MY.FRAME > 1 + MY._WALKFRAMES)
			{
				MY.NEXT_FRAME = 2;	// inbetween to the first walking frame
			}
			else
			{
				MY.NEXT_FRAME = 0;	// inbetween to the real next frame
			}
			return;
		}
		else
		{	// Running
			if(MY.FRAME < 2 + MY._WALKFRAMES) { MY.FRAME = 2 + MY._WALKFRAMES; }

			MY.FRAME += MY._RUNDIST*my_dist;

			while(MY.FRAME >= 2 + MY._WALKFRAMES + MY._RUNFRAMES)
			{
				if(MY.__SOUND == ON) { _play_walksound(); MY.__SOUND = OFF; }
				MY.FRAME -= MY._RUNFRAMES;
			}

			if(MY.FRAME > 1 + MY._WALKFRAMES + MY._RUNFRAMES*0.5)
			{
				if(MY.__SOUND == OFF) { _play_walksound(); MY.__SOUND = ON; }
			}

			if(MY.FRAME > 1 + MY._WALKFRAMES + MY._RUNFRAMES)
			{
				MY.NEXT_FRAME = 2 + MY._WALKFRAMES;
			}
			else
			{
				MY.NEXT_FRAME = 0;
			}

			return;
		}
	}
}


/////////////////////////////////////////////////////////////////////////
// Desc: create a shadow below the entity
ACTION drop_shadow
{
IFDEF CAPS_FLARE;
	if(VIDEO_DEPTH >= 16)
	{
		create(SHADOWSPRITE,MY.POS,move_shadow);
	}
	else
	{
		create(SHADOWFLAT,MY.POS,move_shadow);
	}
IFELSE;
	create(SHADOWFLAT,MY.POS,move_shadow);
ENDIF;
}



/////////////////////////////////////////////////////////////////////////
//	Desc: function used to move shadow
//
function move_shadow()
{
	MY.flare = ON;
	MY.transparent = ON; //inverse alpha
	MY.passable = ON;
	MY.oriented = ON;
	MY.ambient = -100; // shadow should be totally black
	MY.unlit = ON;		 //(plus UNLIT flag in version 4.20)

	// scale the shadow so that it matches its master's (YOU) size
	MY.scale_x = (YOU.MAX_X - YOU.MIN_X)/(MY.MAX_X - MY.MIN_X);
	MY.scale_y = MY.scale_x * 0.8;
	MY.scale_z = 1.0;
	while(YOU != NULL)
	{
		if ((YOU.invisible == ON)
		|| (YOU._MOVEMODE == _MODE_SWIMMING)
		|| (YOU._MOVEMODE == _MODE_WADING))
		{
			MY.invisible = ON;
		}
		else
		{
			MY.invisible = OFF;
  			temp_ent = YOU;


			//-old-sonar temp_ent,500; // get height above the floor
			trace_mode = IGNORE_PASSENTS
			  	+ IGNORE_ME
			  	+ IGNORE_YOU
			  	+ IGNORE_MODELS;
			vec_set(vecFrom,YOU.X);
			vec_set(vecTo,vecFrom);
			vecTo.Z -= 500;
			result = trace(vecFrom,vecTo);

			YOU = temp_ent; // YOU (the entity itself) is changed by SONAR

			if(result > 0)
			{
				// place shadow 2 quants above the floor
				MY.z = YOU.z - RESULT + 2; //YOUR.min_z*/ + 2 - RESULT;
				MY.x = YOU.x;
				MY.y = YOU.y;
//--	 		 	MY.pan = YOU.pan;

				// adapt shadow orientation to floor slope
				if ((NORMAL.x != 0) || (NORMAL.y != 0))
				{ // we're on a slope
					// conform shadow to slope
					MY.PAN = 0;
					MY.tilt = - asin(NORMAL.x);
					MY.roll = - asin(NORMAL.y);
					temp.pan = YOU.PAN;
					temp.tilt = 90;
					temp.roll = 0;
					rotate(my,temp,nullvector);
 				}
				else
				{
					MY.pan = YOU.pan;
					MY.tilt = 90; // set it flat onto the floor
					MY.roll = 0;
				}
			}
			else
			{
				MY.INVISIBLE = ON;
			}
		}
		wait(1);
	} // end while(YOU != NULL)
	remove(ME);
}


/////////////////////////////////////////////////////////////////////////
// Desc: attaches an entity that has the same origin and the same frame cycles
//
function attach_entity()
{
   my.passable = on;
   while(you)	// prevent empty synoym error if parent entity was removed
   {
   	if(your.shadow == on) { my.shadow = on; }
   	if(you == player && person_3rd == 0)
		{
      	my.invisible = on;
   	}
		else
		{
      	my.invisible = off;
   	}

   	vec_set(my.x,you.x);
   	vec_set(my.pan,you.pan);
   	my.frame = you.frame;
   	my.next_frame = you.next_frame;
   	wait(1);
   }
	remove(my);
}


///////////////////////////////////////////////////////////////////////
// Desc: Shakes the player, used for hits and death
function player_shake()
{
	if(random(1) > 0.5)
	{
		MY.ROLL += 8;
		MY.TILT += 8;
		waitt(2);
		MY.TILT -= 5;
		waitt(2);
		MY.ROLL -= 8;
		MY.TILT -= 3;
	}
	else
	{
		MY.ROLL -= 8;
		MY.TILT += 8;
		waitt(2);
		MY.TILT -= 5;
		waitt(2);
		MY.ROLL += 8;
		MY.TILT -= 3;
	}
}