/***********************************************************************************************************/
/*                                                                                                         */
/* Skidoo Stuff                                                                             G.Rummery 1997 */
/*                                                                                                         */
/***********************************************************************************************************/

#include "game.h"

#define SMAN_SHOT_DAMAGE		10
#define SMAN_LARA_DAMAGE		50


/*** SKIDOO STUFF ***/

// straight out of lara.c (should be in lara.h but can't face a recompile)
#define DAMAGE_START  140
#define DAMAGE_LENGTH 14

enum skidoo_anims {SKID_SIT, SKID_GETON, SKID_LEFT, SKID_RIGHT, SKID_FALL, SKID_HIT, SKID_GETONL, SKID_GETOFFL,
	SKID_STILL, SKID_GETOFF, SKID_LETGO, SKID_DEATH, SKID_FALLOFF};

#define SKIDOO_GETON_ANIM 1
#define SKIDOO_GETONL_ANIM 18
#define SKIDOO_FALL_ANIM  8
#define SKIDOO_DEAD_ANIM  15

#define SKIDOO_HIT_LEFT  11
#define SKIDOO_HIT_RIGHT 12
#define SKIDOO_HIT_FRONT 13
#define SKIDOO_HIT_BACK  14


#define SKIDOO_GETOFF_DIST 330

#define SKIDOO_UNDO_TURN	(ONE_DEGREE*2)
#define SKIDOO_TURN			(ONE_DEGREE/2 + SKIDOO_UNDO_TURN)
#define SKIDOO_MAX_TURN		(ONE_DEGREE*6)

#define SKIDOO_MOMENTUM_TURN (ONE_DEGREE*3)
//#define SKIDOO_MAX_MOM_TURN (ONE_DEGREE*80)
#define SKIDOO_MAX_MOM_TURN (ONE_DEGREE*150)

#define SKIDOO_FAST_SPEED		150
#define SKIDOO_MAX_SPEED		100
#define SKIDOO_SLOW_SPEED		50
#define SKIDOO_MIN_SPEED		15
#define SKIDOO_ACCELERATION	10
#define SKIDOO_BRAKE				5
#define SKIDOO_SLOWDOWN			2
#define SKIDOO_REVERSE			-5
#define SKIDOO_MAX_BACK			-30

#define SKIDOO_MAX_KICK			-80

#define SKIDOO_SLIP 100
#define SKIDOO_SLIP_SIDE 50

#define SKIDOO_FRONT 550
#define SKIDOO_SIDE	260
#define SKIDOO_RADIUS 500
#define SKIDOO_SNOW 500

#define SKIDOO_MAX_HEIGHT (STEP_L)

//#define SKIDOO_MIN_BOUNCE 15
#define SKIDOO_MIN_BOUNCE (SKIDOO_MAX_SPEED/2)


/*** SKIDOO BAD GUY ***/

enum skidman_anims {SMAN_EMPTY, SMAN_WAIT, SMAN_MOVING, SMAN_STARTLEFT, SMAN_STARTRIGHT, SMAN_LEFT, SMAN_RIGHT, SMAN_DEATH};

#define SMAN_MIN_TURN (SKIDOO_MAX_TURN/3)

#define SMAN_TARGET_ANGLE (ONE_DEGREE*15)
#define SMAN_WAIT_RANGE SQUARE(WALL_L*4)

#define SMAN_DEATH_ANIM 10

BITE_INFO left_gun = {219,-71,550, 0};
BITE_INFO right_gun = {-235,-71,550, 0};

void SkidmanPush(ITEM_INFO *item, ITEM_INFO *laraitem, int radius);

/************************************ FUNCTION CODE ********************************************************/

void InitialiseSkidoo(sint16 item_number)
{
	ITEM_INFO *skidoo;
	SKIDOO_INFO *skinfo;

	/* Allocate extra data to store skidoo specific information */
	skidoo = &items[item_number];
	skinfo = (SKIDOO_INFO *)skidoo->data = game_malloc(sizeof(SKIDOO_INFO), SKIDOO_STUFF);
	skinfo->skidoo_turn = 0;
	skinfo->left_fallspeed = skinfo->right_fallspeed = 0;
	skinfo->momentum_angle = skidoo->pos.y_rot;
	skinfo->extra_rotation = 0;
	skinfo->track_mesh = 0;
	skinfo->pitch = 0;
}


int SkidooCheckGeton(sint16 item_number, COLL_INFO *coll)
{
	/* Returns 0 if no get on, 1 if right get on and 2 if left get on */
	int geton;
	sint16 rot, room_number;
	ITEM_INFO *skidoo;
	FLOOR_INFO *floor;

	/* Check if Lara is close enough and in right position to get onto skidoo */
	if (!(input & IN_ACTION) || lara.gun_status!=LG_ARMLESS || lara_item->gravity_status)
		return 0;

	skidoo = &items[item_number];

	rot = skidoo->pos.y_rot - lara_item->pos.y_rot;
	if (rot > 0x2000 && rot < 0x6000)
		geton = 1; //right
	else if (rot > -0x6000 && rot < -0x2000)
		geton = 2; //left
	else
		return 0;

	/* Is Lara actually close enough to get on the thing? */
	if (!TestBoundsCollide(skidoo, lara_item, coll->radius))
		return 0;

	if (!TestCollision(skidoo, lara_item))
		return 0;

	// SONY BUG FIX 10000001: if player stops in exactly right place and buries skidoo in avalanche, then they can get on it and crash the game
	room_number = skidoo->room_number;
	floor = GetFloor(skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos, &room_number);
	if (GetHeight(floor, skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos) < -32000)
		return 0;

	return geton;
}


void SkidooCollision(sint16 item_number, ITEM_INFO *litem, COLL_INFO *coll)
{
	/* This routine is only for when Lara is not on the skidoo and she would like to be */
	int geton;
	ITEM_INFO *skidoo;

	/* If Lara dead or already on the skidoo, then no collision */
	if (litem->hit_points < 0 || lara.skidoo != NO_ITEM)
		return;

	/* If player isn't pressing control or Lara is busy, then do normal object collision */
	geton = SkidooCheckGeton(item_number, coll);
	if (!geton)
	{
		ObjectCollision(item_number, litem, coll);
		return;
	}

	/* Yeeha! Get on that skidoo girly */
	lara.skidoo = item_number;

	/* Drop flare if in hand */
	if (lara.gun_type == LG_FLARE)
	{
		CreateFlare(0);
		undraw_flare_meshes();		
		lara.flare_control_left = 0;
		lara.request_gun_type = lara.gun_type = LG_ARMLESS;
	}

	if (geton == 1)
		litem->anim_number = objects[SKIDOO_ANIM].anim_index + SKIDOO_GETON_ANIM;
	else
		litem->anim_number = objects[SKIDOO_ANIM].anim_index + SKIDOO_GETONL_ANIM;

	litem->frame_number = anims[litem->anim_number].frame_base;
	litem->current_anim_state = SKID_GETON;
	lara.gun_status = LG_HANDSBUSY;

	skidoo = &items[item_number];
	litem->pos.y_rot = skidoo->pos.y_rot;
	litem->pos.x_pos = skidoo->pos.x_pos;
	litem->pos.y_pos = skidoo->pos.y_pos;
	litem->pos.z_pos = skidoo->pos.z_pos;

	skidoo->hit_points = 1; // needed so collision routines register it
}


void SkidooBaddieCollision(ITEM_INFO *skidoo)
{
#define TARGET_DIST		(WALL_L*2) // dist for more complex checks
	// copy of LaraBaddieCollision()
	int			i,x,y,z;
	ITEM_INFO	*item;
	OBJECT_INFO *object;
	sint16		roomies[12],numroom,*door;
	sint16		item_num;

	numroom = 1;
	roomies[0] = skidoo->room_number;
	door = room[skidoo->room_number].door;		// Get rooms around skidoo room
	if ( door )
	{
		for ( i=(int)*(door++); i>0; i-- )
		{
			roomies[numroom++] = *(door);
			door += 16;
		}
	}

	for ( i=0; i<numroom; i++ )
	{
		item_num = room[ roomies[i] ].item_number;						// Only do collision with Items on Draw list
		while ( item_num!=NO_ITEM )
		{
			item = &items[ item_num ];
			if ( item->collidable && item->status!=INVISIBLE && item!=lara_item && item!=skidoo) // Object Isnt Collidable so Exit now
			{
				object = &objects[item->object_number];
				if ( object->collision && (object->intelligent || item->object_number==AVALANCHE))   						
				{
					x = skidoo->pos.x_pos - item->pos.x_pos;			// Get Vector from Baddie to Lara
					y = skidoo->pos.y_pos - item->pos.y_pos;
					z = skidoo->pos.z_pos - item->pos.z_pos;
					if ( x > -TARGET_DIST && x < TARGET_DIST && z > -TARGET_DIST && z < TARGET_DIST && y > -TARGET_DIST && y < TARGET_DIST )
					{
						if (TestBoundsCollide(item, skidoo, SKIDOO_RADIUS))
						{
							if (item->object_number == BANDIT3)
								SkidmanPush(item, skidoo, SKIDOO_RADIUS);
							else if (item->object_number == AVALANCHE)
							{
								if (item->current_anim_state==TRAP_ACTIVATE)
								{
									lara_item->hit_status = 1;
									lara_item->hit_points -= 100;
								}
							}
							else
							{
								DoLotsOfBlood(item->pos.x_pos, skidoo->pos.y_pos-STEP_L, item->pos.z_pos, skidoo->speed, skidoo->pos.y_rot, item->room_number, 3);
								item->hit_points = 0; // die motherfucker!
							}
						}
					}
				}
			}
			item_num = item->next_item;
		}
	}
#undef TARGET_DIST
}


sint32 TestHeight(ITEM_INFO *item, sint32 z_off, sint32 x_off, PHD_VECTOR *pos)
{
	/* Get height at a position offset from the origin.
		Moves the vector in 'pos' to the required test position too */
	FLOOR_INFO *floor;
	sint32 s, c;
	sint16 room_number;

	/* Get y pos correctly, but don't bother changing z_off and x_off using x_rot and z_rot */
	pos->y = item->pos.y_pos -	(z_off * phd_sin(item->pos.x_rot) >> W2V_SHIFT) + 
		(x_off * phd_sin(item->pos.z_rot) >> W2V_SHIFT);

	c = phd_cos(item->pos.y_rot);
	s = phd_sin(item->pos.y_rot);

	pos->z = item->pos.z_pos + ((z_off * c - x_off * s) >> W2V_SHIFT);
	pos->x = item->pos.x_pos + ((z_off * s + x_off * c) >> W2V_SHIFT);

	room_number = item->room_number;
	floor = GetFloor(pos->x, pos->y, pos->z, &room_number);
	return GetHeight(floor, pos->x, pos->y, pos->z);
}


int DoShift(ITEM_INFO *skidoo, PHD_VECTOR *pos, PHD_VECTOR *old)
{
	/* Work out grid shift for skidoo based on old position v new position (given that new
		position is known to be bad). Return rotation to be applied. */
	int x, z, x_old, z_old, shift_x, shift_z;

	x = pos->x >> WALL_SHIFT;
	z = pos->z >> WALL_SHIFT;

	x_old = old->x >> WALL_SHIFT;
	z_old = old->z >> WALL_SHIFT;

	shift_x = pos->x & (WALL_L-1);
	shift_z = pos->z & (WALL_L-1);

	if (x == x_old)
	{
		if (z == z_old)
		{
			/* Neither shift; may have hit a very steep slope, so need to push back to old position */
			skidoo->pos.z_pos += (old->z - pos->z);
			skidoo->pos.x_pos += (old->x - pos->x);
		}
		else if (z > z_old)
		{
			/* Z shift left */
			skidoo->pos.z_pos -= shift_z+1;
			return (pos->x - skidoo->pos.x_pos);
		}
		else
		{
			/* Z shift right */
			skidoo->pos.z_pos += WALL_L-shift_z;
			return (skidoo->pos.x_pos - pos->x);
		}
	}
	else if (z == z_old)
	{
		if (x > x_old)
		{
			/* X shift up */
			skidoo->pos.x_pos -= shift_x+1;
			return (skidoo->pos.z_pos - pos->z);
		}
		else
		{
			/* X shift down */
			skidoo->pos.x_pos += WALL_L-shift_x;
			return (pos->z - skidoo->pos.z_pos);
		}
	}
	else
	{
		/* A diagonal hit; means a barrage of tests needed to determine best shift */
		sint16 room_number;
		FLOOR_INFO *floor;
		sint32 height;

		x = z = 0;

		room_number = skidoo->room_number;
		floor = GetFloor(old->x, pos->y, pos->z, &room_number);
		height = GetHeight(floor, old->x, pos->y, pos->z);
		if (height < old->y - STEP_L)
		{
			if (pos->z > old->z)
				z = -shift_z-1;
			else
				z = WALL_L-shift_z;
		}

		room_number = skidoo->room_number;
		floor = GetFloor(pos->x, pos->y, old->z, &room_number);
		height = GetHeight(floor, pos->x, pos->y, old->z);
		if (height < old->y - STEP_L)
		{
			if (pos->x > old->x)
				x = -shift_x-1;
			else
				x = WALL_L-shift_x;
		}

		if (x && z)
		{
			/* Corner or side collision */
			skidoo->pos.z_pos += z;
			skidoo->pos.x_pos += x;
		}
		else if (z)
		{
			skidoo->pos.z_pos += z;
			if (z > 0)
				return (skidoo->pos.x_pos - pos->x);
			else
				return (pos->x - skidoo->pos.x_pos);
		}
		else if (x)
		{
			skidoo->pos.x_pos += x;
			if (x > 0)
				return (pos->z - skidoo->pos.z_pos);
			else
				return (skidoo->pos.z_pos - pos->z);
		}
		else
		{
			/* Pure diagonal collision */
			skidoo->pos.z_pos += (old->z - pos->z);
			skidoo->pos.x_pos += (old->x - pos->x);
		}
	}

	return 0;
}


int DoDynamics(int height, int fallspeed, int *y)
{
	int kick;

	if (height > *y)
	{
		/* In air */
		*y += fallspeed;
		if (*y > height - SKIDOO_MIN_BOUNCE)
		{
			*y = height;
			fallspeed = 0;
		}
		else
			fallspeed += GRAVITY;
	}
	else
	{
		/* On ground: get up push from height change */
		kick = height - *y << 2;
		if (kick < SKIDOO_MAX_KICK)
			kick = SKIDOO_MAX_KICK;
		fallspeed += (kick - fallspeed >> 3);
		if (*y > height)
			*y = height;
	}

	return fallspeed;
}


int GetCollisionAnim(ITEM_INFO *skidoo, PHD_VECTOR *moved)
{
	sint32 c, s, front, side;

	moved->x = skidoo->pos.x_pos - moved->x;
	moved->z = skidoo->pos.z_pos - moved->z;
	if (moved->x || moved->z)
	{
		/* Get direction of movement relative to facing */
		c = phd_cos(skidoo->pos.y_rot);
		s = phd_sin(skidoo->pos.y_rot);
		front = (moved->z * c + moved->x * s) >> W2V_SHIFT;
		side = (-moved->z * s + moved->x * c) >> W2V_SHIFT;
		if (ABS(front) > ABS(side))
		{
			if (front > 0)
				return SKIDOO_HIT_BACK;
			else
				return SKIDOO_HIT_FRONT;
		}
		else
		{
			if (side > 0)
				return SKIDOO_HIT_LEFT;
			else
				return SKIDOO_HIT_RIGHT;
		}
	}

	return 0;
}


void DoSnowEffect(ITEM_INFO *skidoo)
{
	sint32 c, s, x, random;
	sint16 fx_number;
	FX_INFO *fx;

	fx_number = CreateEffect(skidoo->room_number);
	if (fx_number != NO_ITEM)
	{
		s = phd_sin(skidoo->pos.y_rot);
		c = phd_cos(skidoo->pos.y_rot);

		x = (GetRandomDraw() - 0x4000) * SKIDOO_SIDE >> 14;

		fx = &effects[fx_number];
		fx->pos.x_pos = skidoo->pos.x_pos - (SKIDOO_SNOW * s + x * c  >> W2V_SHIFT);
		fx->pos.y_pos = skidoo->pos.y_pos + (SKIDOO_SNOW * phd_sin(skidoo->pos.x_rot) >> W2V_SHIFT);
		fx->pos.z_pos = skidoo->pos.z_pos - (SKIDOO_SNOW * c - x * s >> W2V_SHIFT);
		fx->room_number = skidoo->room_number;
		fx->frame_number = 0;
		fx->object_number = SNOW_SPRITE;
		fx->speed = 0;
		if (skidoo->speed < 64)
		{
			random = ABS(skidoo->speed) - 64;
			fx->fallspeed = GetRandomDraw() * (ABS(skidoo->speed)-64) >> 15;
		}
		else
			fx->fallspeed = 0;
		*(phd_mxptr+M23) = 0; // no depthQ
		S_CalculateLight(fx->pos.x_pos, fx->pos.y_pos, fx->pos.z_pos, fx->room_number);
		fx->shade = ls_adder - 0x200;
		if (fx->shade < 0)
			fx->shade = 0;
	}
}


int SkidooDynamics(ITEM_INFO *skidoo)
{
	/* Does all skidoo movement and collision and returns if collide value */
	SKIDOO_INFO *skinfo;
	PHD_VECTOR moved, fl, fr, br, bl;
	PHD_VECTOR old, fl_old, fr_old, bl_old, br_old;
	sint32 hfl, hfr, hbr, hbl;
	sint32 hfr_old, hfl_old, hbr_old, hbl_old;
	FLOOR_INFO *floor;
	sint32 height, slip, collide;
	sint16 room_number, rot;
	int newspeed;

	skinfo = (SKIDOO_INFO *)skidoo->data;

	/* First get positions and heights of skidoo's corners + centre */
	hfl_old = TestHeight(skidoo, SKIDOO_FRONT, -SKIDOO_SIDE, &fl_old);
	hfr_old = TestHeight(skidoo, SKIDOO_FRONT, SKIDOO_SIDE, &fr_old);
	hbl_old = TestHeight(skidoo, -SKIDOO_FRONT, -SKIDOO_SIDE, &bl_old);
	hbr_old = TestHeight(skidoo, -SKIDOO_FRONT, SKIDOO_SIDE, &br_old);
	old.x = skidoo->pos.x_pos;
	old.y = skidoo->pos.y_pos;
	old.z = skidoo->pos.z_pos;

	/* Back left/right may be slightly below ground, so correct for this */
	if (bl_old.y > hbl_old)
		bl_old.y = hbl_old;
	if (br_old.y > hbr_old)
		br_old.y = hbr_old;
	if (fl_old.y > hfl_old)
		fl_old.y = hfl_old;
	if (fr_old.y > hfr_old)
		fr_old.y = hfr_old;

	/* First undo any turn the skidoo may have applied */
	if (skidoo->pos.y_pos > skidoo->floor - STEP_L)
	{
		if (skinfo->skidoo_turn < -SKIDOO_UNDO_TURN)
			skinfo->skidoo_turn += SKIDOO_UNDO_TURN;
		else if (skinfo->skidoo_turn > SKIDOO_UNDO_TURN)
			skinfo->skidoo_turn -= SKIDOO_UNDO_TURN;
		else
			skinfo->skidoo_turn = 0;
		skidoo->pos.y_rot += skinfo->skidoo_turn + skinfo->extra_rotation;

		/* Deal with momentum; do it with an angle that tracks direction of travel, but slower than turn */
		rot = skidoo->pos.y_rot - skinfo->momentum_angle;
		if (rot < -SKIDOO_MOMENTUM_TURN)
		{
			if (rot < -SKIDOO_MAX_MOM_TURN)
			{
				rot = -SKIDOO_MAX_MOM_TURN;
				skinfo->momentum_angle = skidoo->pos.y_rot - rot;
			}
			else
				skinfo->momentum_angle -= SKIDOO_MOMENTUM_TURN;
		}
		else if (rot > SKIDOO_MOMENTUM_TURN)
		{
			if (rot > SKIDOO_MAX_MOM_TURN)
			{
				rot = SKIDOO_MAX_MOM_TURN;
				skinfo->momentum_angle = skidoo->pos.y_rot - rot;
			}
			else
				skinfo->momentum_angle += SKIDOO_MOMENTUM_TURN;
		}
		else
			skinfo->momentum_angle = skidoo->pos.y_rot;
	}
	else
		skidoo->pos.y_rot += skinfo->skidoo_turn + skinfo->extra_rotation;

	/* Move skidoo according to speed */
	skidoo->pos.z_pos += skidoo->speed * phd_cos(skinfo->momentum_angle) >> W2V_SHIFT;
	skidoo->pos.x_pos += skidoo->speed * phd_sin(skinfo->momentum_angle) >> W2V_SHIFT;

	/* Slide skidoo according to tilts (to avoid getting stuck on slopes) */
	slip = SKIDOO_SLIP * phd_sin(skidoo->pos.x_rot) >> W2V_SHIFT;
	if (ABS(slip) > SKIDOO_SLIP/2)
	{
		skidoo->pos.z_pos -= slip * phd_cos(skidoo->pos.y_rot) >> W2V_SHIFT;
		skidoo->pos.x_pos -= slip * phd_sin(skidoo->pos.y_rot) >> W2V_SHIFT;
	}

	slip = SKIDOO_SLIP_SIDE * phd_sin(skidoo->pos.z_rot) >> W2V_SHIFT;
	if (ABS(slip) > SKIDOO_SLIP_SIDE/2)
	{
		skidoo->pos.z_pos -= slip * phd_sin(skidoo->pos.y_rot) >> W2V_SHIFT;
		skidoo->pos.x_pos += slip * phd_cos(skidoo->pos.y_rot) >> W2V_SHIFT;
	}


	/* Remember desired position in case of collisions moving us about */
	moved.x = skidoo->pos.x_pos;
	moved.z = skidoo->pos.z_pos;

	/* Test against bad guys too */
	if (!(skidoo->flags & ONESHOT)) // ONESHOT flag set if skidoo no longer travelling with Lara
		SkidooBaddieCollision(skidoo);


	/* Test new positions of points (one at a time) and shift skidoo accordingly */
	rot = 0;
	hbl = TestHeight(skidoo, -SKIDOO_FRONT, -SKIDOO_SIDE, &bl);
	if (hbl < bl_old.y - STEP_L)
		rot = DoShift(skidoo, &bl, &bl_old);

	hbr = TestHeight(skidoo, -SKIDOO_FRONT, SKIDOO_SIDE, &br);
	if (hbr < br_old.y - STEP_L)
		rot += DoShift(skidoo, &br, &br_old);

	hfl = TestHeight(skidoo, SKIDOO_FRONT, -SKIDOO_SIDE, &fl);
	if (hfl < fl_old.y - STEP_L)
		rot += DoShift(skidoo, &fl, &fl_old);

	hfr = TestHeight(skidoo, SKIDOO_FRONT, SKIDOO_SIDE, &fr);
	if (hfr < fr_old.y - STEP_L)
		rot += DoShift(skidoo, &fr, &fr_old);

	room_number = skidoo->room_number;
	floor = GetFloor(skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos, &room_number);
	height = GetHeight(floor, skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos);
	if (height < skidoo->pos.y_pos - STEP_L)
		DoShift(skidoo, (PHD_VECTOR *)&skidoo->pos, &old);

	skinfo->extra_rotation = rot;

	/* Get collision anim if skidoo has been moved from desired position by collisions */
	collide = GetCollisionAnim(skidoo, &moved);

	/* Check final actual movement; if speed is more than halved then reduce to zero */
	if (collide)
	{
		newspeed = (skidoo->pos.z_pos - old.z) * phd_cos(skinfo->momentum_angle) + (skidoo->pos.x_pos - old.x) * phd_sin(skinfo->momentum_angle) >> W2V_SHIFT;
		if (&items[lara.skidoo] == skidoo && skidoo->speed > SKIDOO_MAX_SPEED+SKIDOO_ACCELERATION && newspeed < skidoo->speed - 10)
		{
			lara_item->hit_points -= (skidoo->speed - newspeed) >> 1;
			lara_item->hit_status = 1;
		}

		if (skidoo->speed > 0 && newspeed < skidoo->speed)
			skidoo->speed = (newspeed<0)? 0 : newspeed;
		else if (skidoo->speed < 0 && newspeed > skidoo->speed)
			skidoo->speed = (newspeed>0)? 0 : newspeed;

		if (skidoo->speed < SKIDOO_MAX_BACK)
			skidoo->speed = SKIDOO_MAX_BACK;
	}

	return collide;
}


int SkidooUserControl(ITEM_INFO *skidoo, sint32 height, int *pitch)
{
	int drive=0, max_speed;
	SKIDOO_INFO *skinfo;

	skinfo = (SKIDOO_INFO *)skidoo->data;

	/* Deal with user input; will effect next frame, but relies on info calced this frame */
	if (skidoo->pos.y_pos >= height - STEP_L)
	{
		/* Engine pitch depends on speed + height off ground*/
		*pitch = skidoo->speed + (height-skidoo->pos.y_pos);

		if (skidoo->speed == 0 && (input & IN_LOOK))
			LookUpDown();

		/* If tracks on the ground, user has control; allow for reversing! */
		if ( ((input & IN_LEFT) && !(input & IN_BACK)) || ((input & IN_RIGHT) && (input & IN_BACK)) )
		{
			skinfo->skidoo_turn -= SKIDOO_TURN;
			if (skinfo->skidoo_turn < -SKIDOO_MAX_TURN)
				skinfo->skidoo_turn = -SKIDOO_MAX_TURN;
		}

		if ( ((input & IN_RIGHT) && !(input & IN_BACK)) || ((input & IN_LEFT) && (input & IN_BACK)) )
		{
			skinfo->skidoo_turn += SKIDOO_TURN;
			if (skinfo->skidoo_turn > SKIDOO_MAX_TURN)
				skinfo->skidoo_turn = SKIDOO_MAX_TURN;
		}

		if (input & IN_BACK)
		{
			if (skidoo->speed > 0)
				skidoo->speed -= SKIDOO_BRAKE;
			else
			{
				if (skidoo->speed > SKIDOO_MAX_BACK)
					skidoo->speed += SKIDOO_REVERSE;
				drive = 1;
			}
		}
		else if (input & IN_FORWARD)
		{
			if ((input & IN_ACTION) && !(skinfo->track_mesh & 4)) // red skidoo can go faster than bandit ones
				max_speed = SKIDOO_FAST_SPEED;
			else if (input & IN_SLOW)
				max_speed = SKIDOO_SLOW_SPEED;
			else
				max_speed = SKIDOO_MAX_SPEED;

			if (skidoo->speed < max_speed)
				skidoo->speed += SKIDOO_ACCELERATION/2 + SKIDOO_ACCELERATION * skidoo->speed / (2*max_speed);
			else if (skidoo->speed > max_speed + SKIDOO_SLOWDOWN)
				skidoo->speed -= SKIDOO_SLOWDOWN;
			drive = 1;
		}
		else if (skidoo->speed>=0 && skidoo->speed<SKIDOO_MIN_SPEED && (input & (IN_LEFT|IN_RIGHT)))
		{
			skidoo->speed = SKIDOO_MIN_SPEED; // If user wants to turn, skidoo will move forward
			drive = 1;
		}
		else if (skidoo->speed > SKIDOO_SLOWDOWN)
		{
			skidoo->speed -= SKIDOO_SLOWDOWN;
			if ((GetRandomDraw() & 0x7f) < skidoo->speed)
				drive = 1;
		}
		else
			skidoo->speed = 0;
	}
	else if (input & (IN_FORWARD|IN_BACK))
	{
		drive = 1;
		*pitch = skinfo->pitch + 50;
	}

	return drive;
}


int SkidooCheckGetOffOK(int direction)
{
	/* Check if getting off skidoo here is possible in the direction required by player */
	int x, y, z, height, ceiling;
	sint16 room_number, angle;
	ITEM_INFO *skidoo;
	FLOOR_INFO *floor;

	skidoo = &items[lara.skidoo];

	if (direction == SKID_GETOFFL)
		angle = skidoo->pos.y_rot + 0x4000;
	else
		angle = skidoo->pos.y_rot - 0x4000;

	x = skidoo->pos.x_pos - (SKIDOO_GETOFF_DIST * phd_sin(angle) >> W2V_SHIFT);
	y = skidoo->pos.y_pos;
	z = skidoo->pos.z_pos - (SKIDOO_GETOFF_DIST * phd_cos(angle) >> W2V_SHIFT); 

	room_number = skidoo->room_number;
	floor = GetFloor(x, y, z, &room_number);

	height = GetHeight(floor, x, y, z);

	// global var: height_type == BIG_SLOPE/SMALL_SLOPE or WALL
	if (height_type == BIG_SLOPE || height == NO_HEIGHT)
		return 0;

	if (ABS(height-skidoo->pos.y_pos) > WALL_L/2)
		return 0;

	ceiling = GetCeiling(floor, x, y, z);
	if (ceiling - skidoo->pos.y_pos > -LARA_HITE || height - ceiling < LARA_HITE)
		return 0;

	return 1;
}

void SkidooAnimation(ITEM_INFO *skidoo, int collide, int dead)
{
	sint16 cd;
	SKIDOO_INFO *skinfo;

	skinfo = (SKIDOO_INFO *)skidoo->data;

	/* Do animation stuff */
	if (skidoo->pos.y_pos!=skidoo->floor && skidoo->fallspeed > 0 && lara_item->current_anim_state!=SKID_FALL && !dead)
	{
		lara_item->anim_number = objects[SKIDOO_ANIM].anim_index + SKIDOO_FALL_ANIM;
		lara_item->frame_number = anims[lara_item->anim_number].frame_base;
		lara_item->current_anim_state = lara_item->goal_anim_state = SKID_FALL;
	}
	else if (collide && !dead && lara_item->current_anim_state!=SKID_FALL)
	{
		if (lara_item->current_anim_state != SKID_HIT)
		{
			if (collide == SKIDOO_HIT_FRONT)
				SoundEffect(202, &skidoo->pos, 0);
			else
				SoundEffect(201, &skidoo->pos, 0);
			lara_item->anim_number = (sint16)(objects[SKIDOO_ANIM].anim_index + collide);
			lara_item->frame_number = anims[lara_item->anim_number].frame_base;
			lara_item->current_anim_state = lara_item->goal_anim_state = SKID_HIT;
		}
	}
	else
	{
		switch (lara_item->current_anim_state)
		{
		case SKID_STILL:
			/* Play skidoo track if first go */
			cd = (skinfo->track_mesh & 4)? 53 : 52;
			if (!(cd_flags[cd] & ONESHOT))
			{
				S_CDPlay(cd, 0);
				cd_flags[cd] |= ONESHOT;
			}

			if (dead)
			{
				lara_item->goal_anim_state = SKID_DEATH;
				break;
			}

			lara_item->goal_anim_state = SKID_STILL; // needed because SKID_SIT == 0

			if (input & IN_JUMP)
			{
				if ((input & IN_RIGHT) && SkidooCheckGetOffOK(SKID_GETOFF))
				{
					lara_item->goal_anim_state = SKID_GETOFF;
					skidoo->speed = 0;
				}
				else if ((input & IN_LEFT) && SkidooCheckGetOffOK(SKID_GETOFFL))
				{
					lara_item->goal_anim_state = SKID_GETOFFL;
					skidoo->speed = 0;
				}
			}
			else if (input & IN_LEFT)
				lara_item->goal_anim_state = SKID_LEFT;
			else if (input & IN_RIGHT)
				lara_item->goal_anim_state = SKID_RIGHT;
			else if (input & (IN_FORWARD|IN_BACK))
				lara_item->goal_anim_state = SKID_SIT;
			break;

		case SKID_SIT:
			if (skidoo->speed == 0)
				lara_item->goal_anim_state = SKID_STILL;

			if (dead)
				lara_item->goal_anim_state = SKID_FALLOFF;
			else if (input & IN_LEFT)
				lara_item->goal_anim_state = SKID_LEFT;
			else if (input & IN_RIGHT)
				lara_item->goal_anim_state = SKID_RIGHT;
			break;

		case SKID_LEFT:
			if (!(input & IN_LEFT))
				lara_item->goal_anim_state = SKID_SIT;
			break;

		case SKID_RIGHT:
			if (!(input & IN_RIGHT))
				lara_item->goal_anim_state = SKID_SIT;
			break;

		case SKID_FALL:
			if (skidoo->fallspeed <= 0 || skinfo->left_fallspeed <= 0 || skinfo->right_fallspeed <= 0)
			{
				SoundEffect(203, &skidoo->pos, 0);
				lara_item->goal_anim_state = SKID_SIT;
			}
			else if (skidoo->fallspeed > DAMAGE_START+DAMAGE_LENGTH) // when Lara let's go, it's terminal
				lara_item->goal_anim_state = SKID_LETGO;
			break;
		}
	}
}


void SkidooExplode(ITEM_INFO *skidoo)
{
	int fx_number;
	FX_INFO *fx;

	fx_number = CreateEffect(skidoo->room_number);
	if (fx_number != NO_ITEM)
	{
		fx = &effects[fx_number];
		fx->pos.x_pos = skidoo->pos.x_pos;
		fx->pos.y_pos = skidoo->pos.y_pos;
		fx->pos.z_pos = skidoo->pos.z_pos;
		fx->speed = 0;
		fx->frame_number = 0;
		fx->counter = 0;
		fx->object_number = EXPLOSION1;
	}
	ExplodingDeath(lara.skidoo, 0xfffffffc, 0);
	SoundEffect(105, NULL, 0);
	lara.skidoo = NO_ITEM;			
}


int SkidooCheckGetOff(void)
{
	/* Check if Lara is still under skidoo control. Return 0 if she is in that limbo state of the skidoo still needing
		control (it is falling) and her needing normal control (so is she) */
	ITEM_INFO *skidoo;

	skidoo = &items[lara.skidoo];

	if ((lara_item->current_anim_state == SKID_GETOFF || lara_item->current_anim_state == SKID_GETOFFL) && 
		  lara_item->frame_number == anims[lara_item->anim_number].frame_end)
	{
		/* Wait for last frame of GETOFF anim before returning to normal Lara control */
		if (lara_item->current_anim_state == SKID_GETOFFL)
			lara_item->pos.y_rot += 0x4000;
		else
			lara_item->pos.y_rot -= 0x4000;

		lara_item->anim_number = STOP_A;
		lara_item->frame_number = STOP_F;
		lara_item->current_anim_state = lara_item->goal_anim_state = AS_STOP;
		lara_item->pos.x_pos -= SKIDOO_GETOFF_DIST * phd_sin(lara_item->pos.y_rot) >> W2V_SHIFT;
		lara_item->pos.z_pos -= SKIDOO_GETOFF_DIST * phd_cos(lara_item->pos.y_rot) >> W2V_SHIFT;
		lara_item->pos.x_rot = lara_item->pos.z_rot = 0;
		lara.skidoo = NO_ITEM;
		lara.gun_status = LG_ARMLESS;
	}
	else if (lara_item->current_anim_state == SKID_LETGO && (skidoo->pos.y_pos == skidoo->floor || lara_item->frame_number == anims[lara_item->anim_number].frame_end))
	{
		/* Has it hit the ground? If so, explode and kill Lara */
		lara_item->anim_number = FASTFALL_A;
		lara_item->frame_number = FASTFALL_F;
		lara_item->current_anim_state = AS_FASTFALL;

		if (skidoo->pos.y_pos == skidoo->floor)
		{
			lara_item->goal_anim_state = AS_DEATH;
			lara_item->fallspeed = DAMAGE_START+DAMAGE_LENGTH;
			lara_item->speed = 0;
			SkidooExplode(skidoo);
		}
		else
		{
			/* Or come off because skidoo has fallen too far */
			lara_item->goal_anim_state = AS_FASTFALL;
			lara_item->pos.y_pos -= 200;
			lara_item->fallspeed = skidoo->fallspeed;
			lara_item->speed = skidoo->speed;
			SoundEffect( 30, &lara_item->pos, 0 );
		}

		lara_item->pos.x_rot = lara_item->pos.z_rot = 0;
		lara_item->gravity_status = 1;
		lara.gun_status = LG_ARMLESS;
		lara.move_angle = skidoo->pos.y_rot;
		skidoo->flags |= ONESHOT; // flag that skidoo is dead
		skidoo->collidable = 0;

		return 0;
	}

	return 1;
}


void SkidooGuns(void)
{
	WEAPON_INFO	*winfo;
	PHD_ANGLE	angles[2];
	ITEM_INFO *skidoo;

	winfo = &weapons[LG_SKIDOO];

	/* Get Target Information; skidoo retargets all the time */
	LaraGetNewTarget(winfo);

	AimWeapon(winfo, &lara.right_arm);

	/* Skidoo guns don't animate; just fire */
	if (input & IN_ACTION)
	{
		angles[0] = lara.right_arm.y_rot + lara_item->pos.y_rot;
		angles[1] = lara.right_arm.x_rot;
		if (FireWeapon(LG_SKIDOO, lara.target, lara_item, angles))
		{
			lara.right_arm.flash_gun = winfo->flash_time;
			SoundEffect(winfo->sample_num, &lara_item->pos, 0);
			AddDynamicLight(lara_item->pos.x_pos + (phd_sin(lara_item->pos.y_rot) >> (W2V_SHIFT-10)), 
								 lara_item->pos.y_pos - WALL_L/2, 
								 lara_item->pos.z_pos + (phd_cos(lara_item->pos.y_rot) >> (W2V_SHIFT-10)), 
								 12, 11);

			skidoo = &items[lara.skidoo];
			CreatureEffect(skidoo, &left_gun, GunShot);
			CreatureEffect(skidoo, &right_gun, GunShot);
		}
	}
}


int SkidooControl(void)
{
	/* Returns 1 if this controls Lara too, 0 if skidoo is no longer moving with Lara (so need normal Lara control) */
	ITEM_INFO *skidoo;
	SKIDOO_INFO *skinfo;
	PHD_VECTOR fl, fr;
	sint32 hfl, hfr;
	FLOOR_INFO *floor;
	sint32 height, collide, drive;
	sint16 room_number, x_rot, z_rot, bandit_skidoo;
	int pitch, dead=0;

	skidoo = &items[lara.skidoo];
	skinfo = (SKIDOO_INFO *)skidoo->data;
	collide = SkidooDynamics(skidoo);

	/* Now got final position, so get heights under middle and corners (will only have changed
		from above if collision occurred, but recalc anyway as hardly big maths) */
	hfl = TestHeight(skidoo, SKIDOO_FRONT, -SKIDOO_SIDE, &fl);
	hfr = TestHeight(skidoo, SKIDOO_FRONT, SKIDOO_SIDE, &fr);

	room_number = skidoo->room_number;
	floor = GetFloor(skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos, &room_number);
	height = GetHeight(floor, skidoo->pos.x_pos, skidoo->pos.y_pos, skidoo->pos.z_pos);
	TestTriggers(trigger_index, 0 );

	/* Need to know what status Lara has w.r.t. the skidoo; has she died or fallen off? */
	if (lara_item->hit_points <= 0)
	{
		/* Disable user input if Lara is dead */
		input &= ~(IN_LEFT|IN_RIGHT|IN_BACK|IN_FORWARD);
		dead = 1;
	}
	else if (lara_item->current_anim_state == SKID_LETGO)
	{
		dead = 1;
		collide = 0;
	}


	/* Deal with user input (if allowed) */
	if (skidoo->flags & ONESHOT)
	{
		drive = 0;
		collide = 0;
	}
	else
	{
		switch (lara_item->current_anim_state)
		{
		case SKID_GETON:
		case SKID_GETOFF:
		case SKID_GETOFFL:
		case SKID_LETGO:
			/* No control */
			drive = -1;
			collide = 0;
			break;

		default:
			/* Reduce user input if Lara is dead */
			drive = SkidooUserControl(skidoo, height, &pitch);
		}
	}

	/* Do track meshes */
	bandit_skidoo = skinfo->track_mesh & 4;
	if (drive>0)
	{
		skinfo->track_mesh = ((skinfo->track_mesh & 3) == 1)? 2 : 1;

		/* Do engine noise */
		skinfo->pitch += (pitch - skinfo->pitch) >> 2;
		SoundEffect(155, &skidoo->pos, PITCH_SHIFT + (0x10000 - (SKIDOO_MAX_SPEED - skinfo->pitch)*100 <<8));
	}
	else
	{
		skinfo->track_mesh = 0;
		if (!drive)
			SoundEffect(153, &skidoo->pos, 0);
		skinfo->pitch = 0;
	}
	skinfo->track_mesh |= bandit_skidoo;

	skidoo->floor = height;

	/* Do fallspeed effects on skidoo */
	skinfo->left_fallspeed = DoDynamics(hfl, skinfo->left_fallspeed, &fl.y);
	skinfo->right_fallspeed = DoDynamics(hfr, skinfo->right_fallspeed, &fr.y);
	skidoo->fallspeed = DoDynamics(height, skidoo->fallspeed, &skidoo->pos.y_pos);

	/* Rotate skidoo to match these heights */
	height = fl.y + fr.y >> 1;
	x_rot = phd_atan(SKIDOO_FRONT, skidoo->pos.y_pos - height);
	z_rot = phd_atan(SKIDOO_SIDE, height - fl.y);

	skidoo->pos.x_rot += x_rot - skidoo->pos.x_rot >> 1;
	skidoo->pos.z_rot += z_rot - skidoo->pos.z_rot >> 1;

	if (skidoo->flags & ONESHOT)
	{
		/* This is a falling skidoo - Lara is elsewhere */
		if (room_number != skidoo->room_number)
			ItemNewRoom(lara.skidoo, room_number);

		/* Has it hit the ground? If so, explode */
		if (skidoo->pos.y_pos == skidoo->floor)
			SkidooExplode(skidoo);
		return 0;
	}

	SkidooAnimation(skidoo, collide, dead);

	if (room_number != skidoo->room_number)
	{
		ItemNewRoom(lara.skidoo, room_number);
		ItemNewRoom(lara.item_number, room_number);
	}

	/* Move Lara to the skidoo position */
	if (lara_item->current_anim_state != SKID_FALLOFF)
	{
		lara_item->pos.x_pos = skidoo->pos.x_pos;
		lara_item->pos.y_pos = skidoo->pos.y_pos;
		lara_item->pos.z_pos = skidoo->pos.z_pos;
		lara_item->pos.y_rot = skidoo->pos.y_rot;
		if (drive >= 0)
		{
			lara_item->pos.x_rot = skidoo->pos.x_rot;
			lara_item->pos.z_rot = skidoo->pos.z_rot;
		}
		else
			/* Don't tilt Lara during geton/off */
			lara_item->pos.x_rot = lara_item->pos.z_rot = 0;
	}
	else
		lara_item->pos.x_rot = lara_item->pos.z_rot = 0;

	AnimateItem(lara_item);

	if (!dead && drive>=0 && bandit_skidoo)
		SkidooGuns();

	/* Set skidoo on the exact same anim frame */
	if (!dead)
	{
		skidoo->anim_number = objects[SKIDOO].anim_index + (lara_item->anim_number - objects[SKIDOO_ANIM].anim_index);
		skidoo->frame_number = anims[skidoo->anim_number].frame_base + (lara_item->frame_number - anims[lara_item->anim_number].frame_base);
	}
	else
	{
		skidoo->anim_number = objects[SKIDOO].anim_index + SKIDOO_DEAD_ANIM;
		skidoo->frame_number = anims[skidoo->anim_number].frame_base;
	}

	/* If skidoo is moving, then set off a snow spray sprite */
	if (skidoo->speed && skidoo->floor == skidoo->pos.y_pos)
	{
		DoSnowEffect(skidoo);
		if (skidoo->speed < 50)
			DoSnowEffect(skidoo);
	}

	return SkidooCheckGetOff();
}


void	DrawSkidoo( ITEM_INFO *item )
{
	/* Whole huge copy of DrawAnimatingItem to deal with skidoo's changing tracks (sigh!) */
	int 		clip,i,poppush;
	OBJECT_INFO *object;
	sint32 		*bone;
	sint16		*rotation1, *rotation2;
	sint16		**meshpp, **track;
	sint16		*frmptr[2];
	int			rate,frac;
	sint16		flags=0;

	frac=GetFrames( item,frmptr,&rate );

	if (item->data)
		flags = *(sint16 *)item->data;

	if (flags & 4)
		object = &objects[BANDIT3]; // flag 4 implies Lara has nicked enemy skidoo
	else
		object = &objects[item->object_number];

	phd_PushMatrix();
	phd_TranslateAbs(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
	phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);

	if ( (clip=S_GetObjectBounds(frmptr[0])) )
	{
		CalculateObjectLighting( item,frmptr[0] );

		meshpp = &meshes[object->mesh_index];
		bone = bones + object->bone_index;

		/* Work out which track mesh to use; know it is the first thing after the body, so can just draw
			alternative mesh as 'track' and then reset to NULL so not drawn again (HACK,HACK,HACK) */
		track = NULL;
		if ((flags & 3) == 1)
			track = &meshes[objects[SKID_TRACK].mesh_index] + 1;
		else if ((flags & 3) == 2)
			track = &meshes[objects[SKID_TRACK].mesh_index] + 7;

		if ( !frac )
		{
			rotation1 = frmptr[0]+9;

			phd_TranslateRel((sint32)*(frmptr[0]+6), (sint32)*(frmptr[0]+7), (sint32)*(frmptr[0]+8));
			gar_RotYXZsuperpack(&rotation1, 0);
			phd_PutPolygons( *meshpp, clip );

			for ( i=object->nmeshes-1, meshpp++; i>0; i--,bone+=4,meshpp++ )
			{
				poppush = *(bone);							// Do Automated Hierarchy
				if (poppush & 1)                			// Push Pop
					phd_PopMatrix();
				if (poppush & 2)
					phd_PushMatrix();

				phd_TranslateRel( *(bone+1), *(bone+2), *(bone+3) );
				gar_RotYXZsuperpack(&rotation1, 0);

				if (track)
				{
					phd_PutPolygons( *track, clip);
					track = NULL;
				}
				else
					phd_PutPolygons( *meshpp, clip );
			}
		}
		else
		{
			rotation1 = frmptr[0]+9;
			rotation2 = frmptr[1]+9;

			InitInterpolate( frac,rate );
			phd_TranslateRel_ID( (sint32)*(frmptr[0]+6), (sint32)*(frmptr[0]+7), (sint32)*(frmptr[0]+8),
								 (sint32)*(frmptr[1]+6), (sint32)*(frmptr[1]+7), (sint32)*(frmptr[1]+8) );
			gar_RotYXZsuperpack_I(&rotation1, &rotation2, 0);
			phd_PutPolygons_I( *meshpp, clip );

			for ( i=object->nmeshes-1, meshpp++; i>0; i--,bone+=4,meshpp++ )
			{
				poppush = *(bone);						// Do Automated Hierarchy
				if (poppush & 1)                			// Push Pop
					phd_PopMatrix_I();
				if (poppush & 2)
					phd_PushMatrix_I();

				phd_TranslateRel_I(*(bone+1), *(bone+2), *(bone+3));
				gar_RotYXZsuperpack_I(&rotation1, &rotation2, 0);

				if (track)
				{
					phd_PutPolygons_I( *track, clip );
					track = NULL;
				}
				else
					phd_PutPolygons_I( *meshpp, clip );
			}
		}
	}
	phd_PopMatrix();
}

/************************************ SKIDOO RIDING BAD GUYS *********************************************/


void InitialiseSkidman(sint16 item_number)
{
	/* Skidman creates a skidoo object at startup */
	sint16 skidoo_item;
	ITEM_INFO *item, *skidoo;

	skidoo_item = CreateItem();
	if (skidoo_item != NO_ITEM)
	{
		item = &items[item_number];
		skidoo = &items[skidoo_item];
		skidoo->object_number = BANDIT3;
		skidoo->pos.x_pos = item->pos.x_pos;
		skidoo->pos.y_pos = item->pos.y_pos;
		skidoo->pos.z_pos = item->pos.z_pos;
		skidoo->pos.y_rot = item->pos.y_rot;
		skidoo->room_number = item->room_number;
		skidoo->flags = NOT_VISIBLE;
		skidoo->shade = -1;

		InitialiseItem(skidoo_item);

		// The skidman remembers his skidoo
		item->data = (void *)skidoo_item;

		level_items++;
	}
	else
		S_ExitSystem("FATAL: Cannot create SKIDOO for SKIDMAN");
}


void SkidManControl(sint16 rider_number)
{
	/* SKIDMAN calls this function, but then passes control to his skidoo which does all the anim stuff and tells him
		what position to be in. Unless he's dead, in which case the skidoo just travels off and he falls to the ground */
	ITEM_INFO *item, *rider;
	CREATURE_INFO *skidman;
	AI_INFO info;
	sint16 angle, item_number;
	int damage;

	rider = &items[rider_number];

	item_number = (int)rider->data;
	item = &items[item_number];

	/* Need to activate AI for skidoo (it's the skidoo that holds the brain) if not done yet */
	if (!item->data)
	{
		EnableBaddieAI(item_number, 1);
		item->status = ACTIVE;
	}
	skidman = (CREATURE_INFO *)item->data;

	angle = 0;

	if (item->hit_points <= 0)
	{
		if (rider->current_anim_state != SMAN_DEATH)
		{
			/* Separate skidoo from rider */
			rider->pos.x_pos = item->pos.x_pos;
			rider->pos.y_pos = item->pos.y_pos;
			rider->pos.z_pos = item->pos.z_pos;
			rider->pos.y_rot = item->pos.y_rot;
			rider->room_number = item->room_number;

			rider->anim_number = objects[SKIDMAN].anim_index + SMAN_DEATH_ANIM;
			rider->frame_number = anims[rider->anim_number].frame_base;
			rider->current_anim_state = SMAN_DEATH;

			/* Break Lara's lock */
			if (lara.target == item)
				lara.target = NULL;
		}
		else
			AnimateItem(rider);

		/* Make skidoo stop */
		if (item->current_anim_state == SMAN_MOVING || item->current_anim_state == SMAN_WAIT)
			item->goal_anim_state = SMAN_WAIT;
		else
			item->goal_anim_state = SMAN_MOVING;
	}
	else
	{
		/* As skidoo has the brain, it needs to know if the rider was hurt */
		CreatureAIInfo(item, &info);

		CreatureMood(item, &info, VIOLENT);

		angle = CreatureTurn(item, SKIDOO_MAX_TURN/2);

		switch (item->current_anim_state)
		{
		case SMAN_WAIT:
			if (skidman->mood == BORED_MOOD)
				break;
			else if (ABS(info.angle) < SMAN_TARGET_ANGLE && info.distance < SMAN_WAIT_RANGE)
				break;
			item->goal_anim_state = SMAN_MOVING;
			break;

		case SMAN_MOVING:
			if (skidman->mood == BORED_MOOD)
				item->goal_anim_state = SMAN_WAIT;
			else if (ABS(info.angle) < SMAN_TARGET_ANGLE && info.distance < SMAN_WAIT_RANGE)
				item->goal_anim_state = SMAN_WAIT;
			else if (angle < -SMAN_MIN_TURN)
				item->goal_anim_state = SMAN_STARTLEFT;
			else if (angle > SMAN_MIN_TURN)
				item->goal_anim_state = SMAN_STARTRIGHT;
			break;

		case SMAN_STARTLEFT:
		case SMAN_LEFT:
			if (angle < -SMAN_MIN_TURN)
				item->goal_anim_state = SMAN_LEFT;
			else
				item->goal_anim_state = SMAN_MOVING;
			break;

		case SMAN_STARTRIGHT:
		case SMAN_RIGHT:
			if (angle < -SMAN_MIN_TURN)
				item->goal_anim_state = SMAN_LEFT;
			else
				item->goal_anim_state = SMAN_MOVING;
			break;
		}
	}


	/* Shoot them guns */
	if (rider->current_anim_state != SMAN_DEATH)
	{
		if (!skidman->flags && ABS(info.angle) < SMAN_TARGET_ANGLE && lara_item->hit_points > 0)
		{
			damage = (lara.skidoo != NO_ITEM)? SMAN_SHOT_DAMAGE : SMAN_LARA_DAMAGE; // more damage if Lara on foot
				
			if (ShotLara(item, &info, &left_gun, 0, damage) +
				 ShotLara(item, &info, &right_gun, 0, damage))
				skidman->flags = 5;
		}

		if (skidman->flags)
		{
			SoundEffect(43, &item->pos, 0);
			skidman->flags--;
		}
	}

	/* Use 'head_rotation' to store which track is required */
	if (item->current_anim_state == SMAN_WAIT)
	{
		SoundEffect(153, &item->pos, 0);
		skidman->head_rotation = 0;
	}
	else
	{
		skidman->head_rotation = (skidman->head_rotation == 1)? 2 : 1;
		DoSnowEffect(item);
		SoundEffect(155, &item->pos, PITCH_SHIFT + (0x10000 - (SKIDOO_MAX_SPEED - item->speed)*100 <<8));
	}

	CreatureAnimation(item_number, angle, 0);

	/* Move rider to save position and animation as skidoo */
	if (rider->current_anim_state != SMAN_DEATH)
	{
		rider->pos.x_pos = item->pos.x_pos;
		rider->pos.y_pos = item->pos.y_pos;
		rider->pos.z_pos = item->pos.z_pos;
		rider->pos.y_rot = item->pos.y_rot;
		if (item->room_number != rider->room_number)
			ItemNewRoom(rider_number, item->room_number);

		rider->anim_number = item->anim_number + (objects[SKIDMAN].anim_index - objects[BANDIT3].anim_index);
		rider->frame_number = item->frame_number + (anims[rider->anim_number].frame_base - anims[item->anim_number].frame_base);
	}
	else if (rider->status == DEACTIVATED && item->speed == 0 && item->fallspeed == 0)
	{
		/* If rider has reached end of his death animation, turn his skidoo into one that Lara can ride */
		RemoveActiveItem(rider_number);
		rider->collidable = 0;
		rider->hit_points = DONT_TARGET;
		rider->flags |= ONESHOT;

		DisableBaddieAI(item_number);
		item->object_number = SKIDOO;
		item->status = DEACTIVATED;
		InitialiseSkidoo(item_number);
		*(sint16 *)item->data = 4; // flag as enemy skidoo
	}
}


void SkidRiderControl(sint16 item_number)
{
	/* Rider has parted company with his beloved skidoo; he's just doing his death anim */
	ITEM_INFO *item;

	item = &items[item_number];

	AnimateItem(item);

	if (item->status == DEACTIVATED)
		RemoveActiveItem(item_number);
}


void SkidmanPush(ITEM_INFO *item, ITEM_INFO *laraitem, int radius)
{
	int			x,z,rx,rz,c,s;
	int			minx,maxx,minz,maxz;
	int			l,r,t,b;
	OBJECT_INFO *object;
	sint16 		*bounds;

 	x = laraitem->pos.x_pos - item->pos.x_pos;		// Get Vector from Baddie to Lara
 	z = laraitem->pos.z_pos - item->pos.z_pos;
	c = phd_cos( item->pos.y_rot );					// Get Baddies Rotation
	s = phd_sin( item->pos.y_rot );
	rx = ( c*x - s*z ) >> W2V_SHIFT;            	// Rotate Lara Vector into Baddie Frame
	rz = ( c*z + s*x ) >> W2V_SHIFT;

 	object = &objects[item->object_number];
 	bounds = GetBestFrame( item );
	minx = *(bounds+0) - radius;
	maxx = *(bounds+1) + radius;
	minz = *(bounds+4) - radius;
	maxz = *(bounds+5) + radius;

	if ( rx>=minx && rx<=maxx && rz>=minz && rz<=maxz )
	{
		l = rx - minx;
		r = maxx - rx;
		t = maxz - rz;
		b = rz - minz;

		if ( l<=r && l<=t && l<=b )   			// Find Nearest Edge of Collide Box
			rx -= l;                            // and push Lara Vector to this Edge
		else if ( r<=l && r<=t && r<=b )
			rx += r;
		else if ( t<=l && t<=r && t<=b )
			rz += t;
		else
			rz -= b;

		laraitem->pos.x_pos = item->pos.x_pos + ((c*rx + s*rz)>>W2V_SHIFT);
		laraitem->pos.z_pos = item->pos.z_pos + ((c*rz - s*rx)>>W2V_SHIFT);
	}
}


void SkidmanCollision( sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll )
{
	ITEM_INFO *item;

	item = &items[ item_num ];
	if ( !TestBoundsCollide( item,laraitem,coll->radius ) )
		return;
	if ( !TestCollision( item, laraitem ) )
		return;

	if ( coll->enable_baddie_push )
	{
		if (item->speed > 0)
			ItemPushLara( item, laraitem, coll, coll->enable_spaz,0 );
		else
			ItemPushLara( item, laraitem, coll, 0,0 );
	}
		
	/* If Lara is walking and hit by skidoo, gets hurt a lot */
	if (lara.skidoo == NO_ITEM && item->speed > 0)
	{
		laraitem->hit_status = 1;
		laraitem->hit_points -= 100;
	}
}
