//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
// software: you can redistribute it and/or modify it under the terms of 
// the GNU General Public License as published by the Free Software Foundation, 
// either version 3 of the License, or (at your option) any later version.

// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
// in the hope that it will be useful, but with permitted additional restrictions 
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
// distributed with this program. You should have received a copy of the 
// GNU General Public License along with permitted additional restrictions 
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection

/* $Header: /CounterStrike/DRIVE.CPP 1     3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Command & Conquer                                            *
 *                                                                                             *
 *                    File Name : DRIVE.CPP                                                    *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic                                                *
 *                                                                                             *
 *                   Start Date : April 22, 1994                                               *
 *                                                                                             *
 *                  Last Update : October 31, 1996 [JLB]                                       *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   DriveClass::AI -- Processes unit movement and rotation.                                   *
 *   DriveClass::Approach_Target -- Handles approaching the target in order to attack it.      *
 *   DriveClass::Assign_Destination -- Set the unit's NavCom.                                  *
 *   DriveClass::Class_Of -- Fetches a reference to the class type for this object.            *
 *   DriveClass::Debug_Dump -- Displays status information to monochrome screen.               *
 *   DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction.              *
 *   DriveClass::DriveClass -- Constructor for drive class object.                             *
 *   DriveClass::Fixup_Path -- Adds smooth start path to normal movement path.                 *
 *   DriveClass::Force_Track -- Forces the unit to use the indicated track.                    *
 *   DriveClass::Lay_Track -- Handles track laying logic for the unit.                         *
 *   DriveClass::Limbo -- Prepares vehicle and then limbos it.                                 *
 *   DriveClass::Mark_Track -- Marks the midpoint of the track as occupied.                    *
 *   DriveClass::Ok_To_Move -- Checks to see if this object can begin moving.                  *
 *   DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell.          *
 *   DriveClass::Response_Attack -- Voice feedback when ordering the unit to attack a target.  *
 *   DriveClass::Response_Move -- Voice feedback when ordering the unit to move.               *
 *   DriveClass::Response_Select -- Voice feedback when selecting the unit.                    *
 *   DriveClass::Scatter -- Causes the unit to travel to a nearby safe cell.                   *
 *   DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic.        *
 *   DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell.                  *
 *   DriveClass::Stop_Driver -- Handles removing occupation bits when driving stops.           *
 *   DriveClass::Teleport_To -- Teleport object to specified location.                         *
 *   DriveClass::While_Moving -- Processes unit movement.                                      *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include	"function.h"


#ifdef NEVER
void test(void)
{
	enum nums {one, two, three};

   nums x;
   nums *ptr;

   ptr = &x;
}
#endif


/***********************************************************************************************
 * DriveClass::Response_Select -- Voice feedback when selecting the unit.                      *
 *                                                                                             *
 *    This is the voice to play when the unit is selected.                                     *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/30/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Response_Select(void)
{
	assert(IsActive);

	static VocType _response[] = {
		VOC_VEHIC,
		VOC_REPORT,
		VOC_YESSIR,
		VOC_YESSIR,
		VOC_YESSIR,
		VOC_AWAIT
	};
	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
	if (AllowVoice) {
		Sound_Effect(response, fixed(1), -(ID+1));
	}
}


/***********************************************************************************************
 * DriveClass::Response_Move -- Voice feedback when ordering the unit to move.                 *
 *                                                                                             *
 *    This plays the audio feedback when ordering this unit to move to a new destination.      *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/30/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Response_Move(void)
{
	assert(IsActive);

	static VocType _response[] = {
		VOC_ACKNOWL,
		VOC_AFFIRM,
	};
	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
	if (AllowVoice) {
		Sound_Effect(response, fixed(1), -(ID+1));
	}
}


/***********************************************************************************************
 * DriveClass::Response_Attack -- Voice feedback when ordering the unit to attack a target.    *
 *                                                                                             *
 *    This plays the audio feedback when ordering this unit to attack.                         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/30/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Response_Attack(void)
{
	assert(IsActive);

	static VocType _response[] = {
		VOC_AFFIRM,
		VOC_ACKNOWL
	};
	VocType response = _response[Sim_Random_Pick(0, ARRAY_SIZE(_response)-1)];
	if (AllowVoice) {
		Sound_Effect(response, fixed(1), -(ID+1));
	}
}


/***********************************************************************************************
 * DriveClass::Scatter -- Causes the unit to travel to a nearby safe cell.                     *
 *                                                                                             *
 *    This routine is called when the unit discovers that it should get out of the "hot seat"  *
 *    and move to an adjacent cell. Since the safety of the adjacent cell is not determined    *
 *    before the move begins, it will appear that the unit is just scattering (which it        *
 *    should).                                                                                 *
 *                                                                                             *
 * INPUT:   threat   -- The coordinate of the source of the threat. The unit will try to move  *
 *                      roughly away from the threat.                                          *
 *                                                                                             *
 *          forced   -- The threat is real and a serious effort to scatter should be made.     *
 *                                                                                             *
 *          nokidding-- The scatter should affect the player's infantry even if it otherwise   *
 *                      wouldn't have.                                                         *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/25/1994 JLB : Created.                                                                 *
 *   09/27/1995 JLB : Revised to never scatter if already moving.                              *
 *   07/09/1996 JLB : Moved to DriveClass so that ships will scatter too.                      *
 *   08/02/1996 JLB : Added the "nokidding" parameter.                                         *
 *=============================================================================================*/
void DriveClass::Scatter(COORDINATE threat, bool forced, bool nokidding)
{
	assert(IsActive);

	/*
	**	Certain missions prevent scattering regardless of whether it would be
	**	a good idea or not.
	*/
	if (MissionControl[Mission].IsParalyzed) return;

	if ((What_Am_I() != RTTI_UNIT || !((UnitClass *)this)->IsDumping) && (!Target_Legal(NavCom) || (nokidding && !IsRotating))) {
		if (!Target_Legal(TarCom) || forced || Random_Pick(1, 4) == 1) {
			FacingType	toface;
			FacingType	newface;
			CELL			newcell;

			if (threat != 0) {
				toface = Dir_Facing(Direction8(threat, Coord));
				toface = toface + FacingType(Random_Pick(0, 2)-1);
			} else {
				toface = Dir_Facing(PrimaryFacing.Current());
				toface = toface + FacingType(Random_Pick(0, 2)-1);
			}

			for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
				newface = toface + face;
				newcell = Adjacent_Cell(Coord_Cell(Coord), newface);

				if (Map.In_Radar(newcell) && Can_Enter_Cell(newcell) == MOVE_OK) {
					Assign_Destination(::As_Target(newcell));
				}
			}
		}
	}
}


/***********************************************************************************************
 * DriveClass::Limbo -- Prepares vehicle and then limbos it.                                   *
 *                                                                                             *
 *    This routine removes the occupation bits for the vehicle and also handles cleaning up    *
 *    any vehicle reservation bits. After this, it then proceeds with limboing the unit.       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the vehicle limboed?                                                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/22/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
bool DriveClass::Limbo(void)
{
	if (!IsInLimbo) {
		Stop_Driver();
		TrackNumber = -1;
	}
	return(FootClass::Limbo());
}


/***********************************************************************************************
 * DriveClass::Stop_Driver -- Handles removing occupation bits when driving stops.             *
 *                                                                                             *
 *    This routine will remove the "reservation" flag (if present) when the vehicle is         *
 *    required to stop movement.                                                               *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the vehicle stopped?                                                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/22/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
bool DriveClass::Stop_Driver(void)
{
	assert(IsActive);

	/*
	** We only need to do something if the vehicle is actually going
	** somewhere.
	*/
	if (Head_To_Coord()) {

		/*
		** Safe off whether the vehicle is down or not so we know whether
		** we have to put it back down.
		*/
		int temp = IsDown;

		/*
		** If the vehicle is down, pick it up so it doesn't interfere with
		** our flags.
		*/
		if (temp) {
			Mark(MARK_UP);
		}

		/*
		** Call the drive class function which will let us release the
		** reserved track.
		*/
		Mark_Track(Head_To_Coord(), MARK_UP);

		/*
		** If it was down it should be down when we are done.
		*/
		if (temp) {
			Mark(MARK_DOWN);
		}
	}
	return(FootClass::Stop_Driver());
}


/***********************************************************************************************
 * DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction.                *
 *                                                                                             *
 *    This routine will set the vehicle to rotate to the direction specified. For tracked      *
 *    vehicles, it is just a simple rotation. For wheeled vehicles, it performs a series       *
 *    of short drives (three point turn) to face the desired direction.                        *
 *                                                                                             *
 * INPUT:   dir   -- The direction that this vehicle should face.                              *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/29/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Do_Turn(DirType dir)
{
	assert(IsActive);

	if (dir != PrimaryFacing) {

#ifdef TOFIX
		/*
		**	Special rotation track is needed for units that
		**	cannot rotate in place.
		*/
		if (Special.IsThreePoint && TrackNumber == -1 && Techno_Type_Class()->Speed == SPEED_WHEEL) {
			int			facediff;	// Signed difference between current and desired facing.
			FacingType	face;			// Current facing (ordinal value).

			facediff = PrimaryFacing.Difference(dir) >> 5;
			facediff = Bound(facediff, -2, 2);
			if (facediff) {
				face = Dir_Facing(PrimaryFacing);

				IsOnShortTrack = true;
				Force_Track(face*FACING_COUNT + (face + facediff), Coord);

				Path[0] = FACING_NONE;
				Set_Speed(0xFF);		// Full speed.
			}
		} else {
			PrimaryFacing.Set_Desired(dir);
		}
#else
			PrimaryFacing.Set_Desired(dir);
//			IsRotating = true;
#endif
	}
}


/***********************************************************************************************
 * DriveClass::Teleport_To -- Teleport object to specified location.                           *
 *                                                                                             *
 *    This will teleport the object to the specified location or as close as possible to it    *
 *    if the destination is blocked.                                                           *
 *                                                                                             *
 * INPUT:   cell  -- The desired destination cell to teleport to.                              *
 *                                                                                             *
 * OUTPUT:  bool; Was the teleport successful?                                                 *
 *                                                                                             *
 * WARNINGS:   All current activity of this object will be terminated by the teleport. It will *
 *             arrive at the destination in static guard mode.                                 *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/21/1996 JLB : Created.                                                                 *
 *   10/31/1996 JLB : Handles flag teleport case.                                              *
 *=============================================================================================*/
bool DriveClass::Teleport_To(CELL cell)
{
	/*
	**	All cargo gets destroyed.
	*/
	if (Rule.IsChronoKill) {
		Kill_Cargo(NULL);
	}

	Stop_Driver();
	Force_Track(-1, 0);
	PrimaryFacing.Set_Current(PrimaryFacing.Desired());
	Transmit_Message(RADIO_OVER_OUT);
	Assign_Destination(TARGET_NONE);
	Assign_Target(TARGET_NONE);
	Assign_Mission(MISSION_NONE);
	Commence();
	Mark(MARK_UP);

	/*
	**	A teleported unit will drop the flag right where it's at.
	*/
	if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Flagged != HOUSE_NONE) {
		HouseClass::As_Pointer(((UnitClass *)this)->Flagged)->Flag_Attach(Coord_Cell(Coord));
	}

	if (Can_Enter_Cell(cell) != MOVE_OK) {
		cell = Map.Nearby_Location(cell, Techno_Type_Class()->Speed);
	}
	Coord = Cell_Coord(cell);
	Mark(MARK_DOWN);
	Look(false);
	Per_Cell_Process(PCP_END);
	return(true);
}


/***********************************************************************************************
 * DriveClass::Force_Track -- Forces the unit to use the indicated track.                      *
 *                                                                                             *
 *    This override (nuclear bomb) style routine is to be used when a unit needs to start      *
 *    on a movement track but is outside the normal movement system. This occurs when a        *
 *    harvester starts driving off of a refinery.                                              *
 *                                                                                             *
 * INPUT:   track -- The track number to start on.                                             *
 *                                                                                             *
 *          coord -- The coordinate that the unit will end up at when the movement track       *
 *                   is completed.                                                             *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   03/17/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Force_Track(int track, COORDINATE coord)
{
	assert(IsActive);

	TrackNumber = track;
	TrackIndex = 0;
	if (coord != 0) {
		Start_Driver(coord);
	}
}


/***********************************************************************************************
 * DriveClass::DriveClass -- Constructor for drive class object.                               *
 *                                                                                             *
 *    This will initialize the drive class to its default state. It is called as a result      *
 *    of creating a unit.                                                                      *
 *                                                                                             *
 * INPUT:   classid  -- The unit's ID class. It is passed on to the foot class constructor.    *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/13/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
DriveClass::DriveClass(RTTIType rtti, int id, HousesType house) :
	FootClass(rtti, id, house),
	IsMoebius(false),
	IsHarvesting(false),
	IsTurretLockedDown(false),
	IsOnShortTrack(false),
	SpeedAccum(0),
	MoebiusCountDown(0),
	MoebiusCell(0),
	TrackNumber(-1),
	TrackIndex(0)
{
}


#ifdef CHEAT_KEYS
/***********************************************************************************************
 * DriveClass::Debug_Dump -- Displays status information to monochrome screen.                 *
 *                                                                                             *
 *    This debug utility function will display the status of the drive class to the mono       *
 *    screen. It is through this information that bugs can be tracked down.                    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/31/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Debug_Dump(MonoClass * mono) const
{
	assert(IsActive);

	mono->Fill_Attrib(66, 14, 12, 1, IsMoebius ? MonoClass::INVERSE : MonoClass::NORMAL);
	FootClass::Debug_Dump(mono);
}
#endif


/***********************************************************************************************
 * DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic.          *
 *                                                                                             *
 *    This routine calculates the new coordinate value needed for the                          *
 *    smooth turn logic. The adjustment and flag values must be                                *
 *    determined prior to entering this routine.                                               *
 *                                                                                             *
 * INPUT:   adj      -- The adjustment coordinate as lifted from the                           *
 *                      correct smooth turn table.                                             *
 *                                                                                             *
 *          dir      -- Pointer to dir for possible modification                               *
 *                      according to the flag bits.                                            *
 *                                                                                             *
 * OUTPUT:  Returns with the coordinate the unit should positioned to.                         *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   03/14/1994 JLB : Created.                                                                 *
 *   07/13/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
COORDINATE DriveClass::Smooth_Turn(COORDINATE adj, DirType & dir)
{
	assert(IsActive);

	DirType workdir = dir;
	int x,y;
	int temp;
	TrackControlType flags = TrackControl[TrackNumber].Flag;

	x = Coord_X(adj);
	y = Coord_Y(adj);

	if (flags & F_T) {
		temp	= x;
		x		= y;
		y 		= temp;
		workdir = (DirType)(DIR_W - workdir);
	}

	if (flags & F_X) {
		x 		 = -x;
		workdir = (DirType)-workdir;
	}

	if (flags & F_Y) {
		y = -y;
		workdir = (DirType)(DIR_S - workdir);
	}

	dir = workdir;

	return(XY_Coord( (LEPTON)(Coord_X(Head_To_Coord()) + x), (LEPTON)(Coord_Y(Head_To_Coord()) + y)));
}


/***********************************************************************************************
 * DriveClass::Assign_Destination -- Set the unit's NavCom.                                    *
 *                                                                                             *
 *    This routine is used to set the unit's navigation computer to the                        *
 *    specified target. Once the navigation computer is set, the unit                          *
 *    will start planning and moving toward the destination.                                   *
 *                                                                                             *
 * INPUT:   target   -- The destination target for the unit to head to.                        *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/07/1992 JLB : Created.                                                                 *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
void DriveClass::Assign_Destination(TARGET target)
{
	assert(IsActive);

	/*
	**	Abort early if there is anything wrong with the parameters
	**	or the unit already is assigned the specified destination.
	*/
	if (target == NavCom) return;

	/*
	**	For harvesting type vehicles, it might go into a dock and unload procedure
	**	when the harvester is full and an empty refinery is selected as a target.
	*/
	BuildingClass * b = As_Building(target);

	/*
	**	If the player clicked on refinery but it is not busy, then assign
	**	it to unload at the refinery.
	*/
	if (b != NULL && *b == STRUCT_REFINERY && What_Am_I() == RTTI_UNIT && ((UnitTypeClass *)Techno_Type_Class())->IsToHarvest) {
		if (Contact_With_Whom() != b && !b->In_Radio_Contact()) {
			/*
			**	Establish radio contact protocol. If the facility responds correctly,
			**	then remain in radio contact and proceed toward the desired destination.
			*/
			if (Transmit_Message(RADIO_HELLO, b) == RADIO_ROGER) {
				if (Mission != MISSION_ENTER && Mission != MISSION_HARVEST) {
					Assign_Mission(MISSION_ENTER);
					target = TARGET_NONE;
				} else {
//					target = TARGET_NONE;
				}
			} else {
//				target = TARGET_NONE;
			}
		} else {
//			target = TARGET_NONE;
		}
	}

	/*
	**	Set the unit's navigation computer.
	*/
	FootClass::Assign_Destination(target);

	Path[0] = FACING_NONE;			// Force recalculation of path.
	if (!IsDriving && Mission != MISSION_UNLOAD) {
		Start_Of_Move();
	}
}


/***********************************************************************************************
 * DriveClass::While_Moving -- Processes unit movement.                                        *
 *                                                                                             *
 *    This routine is used to process movement for the units as they move.                     *
 *    It is called many times for each cell's worth of movement.   This                        *
 *    routine only applies after the next cell HeadTo has been determined.                     *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  true/false; Should this routine be called again?                                   *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   02/02/1992 JLB : Created.                                                                 *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
bool DriveClass::While_Moving(void)
{
	assert(IsActive);

	/*
	**	Perform quick legality checks.
	*/
	if (!IsDriving || TrackNumber == -1 || (IsRotating && !Techno_Type_Class()->IsTurretEquipped)) {
		SpeedAccum = 0;		// Kludge?  No speed should accumulate if movement is on hold.
		return(false);
	}

	/*
	**	If enough movement has accumulated so that the unit can
	**	visibly move on the map, then process accordingly.
	** Slow the unit down if he's carrying a flag.
	*/
	MPHType maxspeed = MPHType(min(Techno_Type_Class()->MaxSpeed * SpeedBias * House->GroundspeedBias, (int)MPH_LIGHT_SPEED));
	if (IsFormationMove) maxspeed = FormationMaxSpeed;

	int actual;			// Working movement addition value.
	if (((UnitClass *)this)->Flagged != HOUSE_NONE) {
		actual = SpeedAccum + ((int)maxspeed/2) * fixed(Speed, 256);
	} else {
		actual = SpeedAccum + maxspeed * fixed(Speed, 256);
	}

	if (actual > PIXEL_LEPTON_W) {
		TurnTrackType	const * track;	// Track control pointer.
		TrackType		const	* ptr;		// Pointer to coord offset values.
		int				tracknum;		// The track number being processed.
		FacingType		nextface;		// Next facing queued in path.
		bool				adj;				// Is a turn coming up?

		track = &TrackControl[TrackNumber];
		if (IsOnShortTrack) {
			tracknum = track->StartTrack;
		} else {
			tracknum = track->Track;
		}
		ptr = RawTracks[tracknum-1].Track;
		nextface = Path[0];

		/*
		**	Determine if there is a turn coming up. If there is
		**	a turn, then track jumping might occur.
		*/
		adj = false;
		if (nextface != FACING_NONE && Dir_Facing(track->Facing) != nextface) {
			adj = true;
		}

		/*
		**	Skip ahead the number of track steps required (limited only
		**	by track length). Set the unit to the new position and
		**	flag the unit accordingly.
		*/
		Mark(MARK_UP);
		while (actual > PIXEL_LEPTON_W) {
			COORDINATE		offset;
			DirType	dir;

			actual -= PIXEL_LEPTON_W;

			offset = ptr[TrackIndex].Offset;
			if (offset || !TrackIndex) {
				dir = ptr[TrackIndex].Facing;
				Coord = Smooth_Turn(offset, dir);

				PrimaryFacing.Set(dir);

				/*
				**	See if "per cell" processing is necessary.
				*/
				if (TrackIndex && RawTracks[tracknum-1].Cell == TrackIndex) {
					Mark(MARK_DOWN);
					Per_Cell_Process(PCP_DURING);
					if (!IsActive) {
						return(false);
					}
					Mark(MARK_UP);
				}

				/*
				**	The unit could "jump tracks". Check to see if the unit should
				**	do so.
				*/
				if (/**this != UNIT_GUNBOAT &&*/ nextface != FACING_NONE && adj && RawTracks[tracknum-1].Jump == TrackIndex && TrackIndex) {
					TurnTrackType const * newtrack;		// Proposed jump-to track.
					int	tnum;

					tnum = (int)(Dir_Facing(track->Facing) * FACING_COUNT) + (int)nextface;
					newtrack = &TrackControl[tnum];
					if (newtrack->Track && RawTracks[newtrack->Track-1].Entry) {
						COORDINATE	c = Head_To_Coord();
						int oldspeed = Speed;

						c = Adjacent_Cell(c, nextface);

						switch (Can_Enter_Cell(Coord_Cell(c), nextface)) {
							case MOVE_OK:
								IsOnShortTrack = false;		// Shouldn't be necessary, but...
								TrackNumber = tnum;
								track = newtrack;

								tracknum = track->Track;
								TrackIndex = RawTracks[tracknum-1].Entry-1;	// Anticipate increment.
								ptr = RawTracks[tracknum-1].Track;
								adj = false;

								Stop_Driver();
								IsDriving = true;
								Per_Cell_Process(PCP_END);
								IsDriving = false;
								if (!IsActive) return(false);
								if (Start_Driver(c)) {
									Set_Speed(oldspeed);
									memcpy((char*)&Path[0], (char*)&Path[1], CONQUER_PATH_MAX-1);
									Path[CONQUER_PATH_MAX-1] = FACING_NONE;
								} else {
									Path[0] = FACING_NONE;
									TrackNumber = -1;
									actual = 0;
								}
								break;

							case MOVE_CLOAK:
								Map[c].Shimmer();
								break;

							case MOVE_TEMP:
#ifdef TOFIX
								if (*this == UNIT_HARVESTER || !House->IsHuman) {
#else
								if (!House->IsHuman) {
#endif
									Map[c].Incoming(0, true, true);
								}
								break;
						}
					}
				}
				TrackIndex++;

			} else {
				actual = 0;
				Coord = Head_To_Coord();
				Stop_Driver();
				TrackNumber = -1;
				TrackIndex = NULL;

				/*
				**	Perform "per cell" activities.
				*/
				Mark(MARK_DOWN);
				Per_Cell_Process(PCP_END);
				if (!IsActive) return(false);
				Mark(MARK_UP);

				break;
			}
		}
		if (IsActive) {
			Mark(MARK_DOWN);
		}
	}

	/*
	**	Replace any remainder back into the unit's movement
	**	accumulator to be processed next pass.
	*/
	SpeedAccum = actual;
	return(true);
}


/***********************************************************************************************
 * DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell.            *
 *                                                                                             *
 *    This routine is called when a unit has mostly or completely                              *
 *    entered a cell. The unit might be in the middle of a movement track                      *
 *    when this routine is called. It's primary purpose is to perform                          *
 *    sighting and other "per cell" activities.                                                *
 *                                                                                             *
 * INPUT:   why   -- Specifies the circumstances under which this routine was called.          *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   11/03/1993 JLB : Created.                                                                 *
 *   03/30/1994 JLB : Revamped for track system.                                               *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *   06/18/1994 JLB : Converted to virtual function.                                           *
 *   06/18/1994 JLB : Distinguishes between center and near-center conditions.                 *
 *=============================================================================================*/
void DriveClass::Per_Cell_Process(PCPType why)
{
	assert(IsActive);

	if (why == PCP_END) {
		CELL	cell = Coord_Cell(Coord);

		/*
		**	Check to see if it has reached its destination. If so, then clear the NavCom
		**	regardless of the remaining path list.
		*/
		if (As_Cell(NavCom) == cell) {
			IsTurretLockedDown = false;
			NavCom = TARGET_NONE;
			Path[0] = FACING_NONE;
		}

		Lay_Track();
	}

	FootClass::Per_Cell_Process(why);
}


/***********************************************************************************************
 * DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell.                    *
 *                                                                                             *
 *    This will try to start a unit advancing toward the cell it is                            *
 *    facing. It will check for and handle legality and reserving of the                       *
 *    necessary cell.                                                                          *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  true/false; Should this routine be called again because                            *
 *                      initial start operation is temporarily delayed?                        *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   02/02/1992 JLB : Created.                                                                 *
 *   10/18/1993 JLB : This should be called repeatedly until HeadTo is not NULL.               *
 *   03/16/1994 JLB : Revamped for track logic.                                                *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *   06/19/1995 JLB : Fixed so that it won't fire on ground unnecessarily.                     *
 *   07/13/1995 JLB : Handles bumping into cloaked objects.                                    *
 *   09/22/1995 JLB : Breaks out of hopeless hunt mode.                                        *
 *   07/10/1996 JLB : Sets scan limit if necessary.                                            *
 *=============================================================================================*/
bool DriveClass::Start_Of_Move(void)
{
	assert(IsActive);

	FacingType		facing;				// Direction movement will commence.
	DirType			dir;				// Desired actual facing toward destination.
	int				facediff;			// Difference between current and desired facing.
	int				speed;				// Speed of unit.
	CELL				destcell;			// Cell of destination.
	LandType			ground;				// Ground unit is entering.
	COORDINATE				dest;					// Destination coordinate.

	facing = Path[0];

	if (!Target_Legal(NavCom) && facing == FACING_NONE) {
		IsTurretLockedDown = false;
		Stop_Driver();
		if (Mission == MISSION_MOVE) {
			Enter_Idle_Mode();
		}
		return(false);		// Why is it calling this routine!?!
	}

	/*
	**	Reduce the path length if the target is a unit and the
	**	range to the unit is less than the precalculated path steps.
	*/
	if (facing != FACING_NONE) {
		int	dist;

		if (Is_Target_Vessel(NavCom) || Is_Target_Unit(NavCom) || Is_Target_Infantry(NavCom)) {
			dist = Lepton_To_Cell((LEPTON)Distance(NavCom));

			if (dist < ARRAY_SIZE(Path)) {
				Path[dist] = FACING_NONE;
				facing = Path[0];		// Maybe needed.
			}
		}
	}

	/*
	**	If the path is invalid at this point, then generate one. If
	**	generating a new path fails, then abort NavCom.
	*/
	if (facing == FACING_NONE) {

		/*
		**	If after a path search, there is still no valid path, then set the
		**	NavCom to null and let the script take care of assigning a new
		**	navigation target.
		*/
		if (PathDelay != 0) {
			return(false);
		}

		if (!Basic_Path()) {

			/*
			**	If the unit is close enough to the target then just stop
			**	driving now. This prevents the fidgeting that would occur
			**	if they mindlessly kept trying to get to the exact location
			**	desired. This is quite necessary since it is typical to move
			**	several units with the same mouse click.
			*/
			if (!Is_On_Priority_Mission() && Distance(NavCom) < Rule.CloseEnoughDistance && (Mission == MISSION_MOVE || Mission == MISSION_GUARD_AREA)) {
				Assign_Destination(TARGET_NONE);
				if (!IsActive) return(false);
			} else {
				/*
				**	If a basic path could not be found, but the immediate move destination is
				**	blocked by a friendly temporary blockage, then cause that blockage
				**	to scatter.
				*/
				CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), PrimaryFacing.Current());
				if (Map.In_Radar(cell)) {
					MoveType ok = Can_Enter_Cell(cell);
					if (ok == MOVE_TEMP) {
						CellClass * cellptr = &Map[cell];
						TechnoClass * blockage = cellptr->Cell_Techno();
						if (blockage && House->Is_Ally(blockage)) {

							/*
							**	If the target can be told to get out of the way, only bother
							**	to do so if we aren't very close to the target and this
							**	object can just say "good enough" and stop here.
							*/
							if (Distance(NavCom) < Rule.CloseEnoughDistance && !In_Radio_Contact()) {
								Assign_Destination(TARGET_NONE);
								return(false);
							} else {
								cellptr->Incoming(0, true, false);
//								cellptr->Incoming(0, true, true);
							}
						}
					}
				}

				if (TryTryAgain > 0) {
					TryTryAgain--;
				} else {
					Assign_Destination(TARGET_NONE);
					if (!IsActive) return(false);
					if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
					IsNewNavCom = false;
				}
			}

			/*
			**	Since the path was blocked, check to make sure that it was completely
			**	blocked. If so and it has a valid TarCom and it is out of range of the
			**	TarCom, then give this unit a range limit so that it might not pick
			**	a "can't reach" target again.
			*/
			if (!Target_Legal(NavCom) && Target_Legal(TarCom) && !In_Range(TarCom)) {
				IsScanLimited = true;
				if (Team.Is_Valid()) Team->Scan_Limit();
				Assign_Target(TARGET_NONE);
			}

			/*
			**	Stop the movement, for now, and let the subsequent logic in later game
			**	frames resume movement as appropriate.
			*/
			Stop_Driver();
			TrackNumber = -1;
			IsTurretLockedDown = false;
			return(false);
		}

		/*
		**	If a basic path could be found, but the immediate move destination is
		**	blocked by a friendly temporary blockage, then cause that blockage
		**	to scatter.
		*/
		CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), Path[0]);
		if (Map.In_Radar(cell)) {
			MoveType ok = Can_Enter_Cell(cell);
			if (ok == MOVE_TEMP) {
				CellClass * cellptr = &Map[cell];
				TechnoClass * blockage = cellptr->Cell_Techno();
				if (blockage && House->Is_Ally(blockage)) {

					/*
					**	If the target can be told to get out of the way, only bother
					**	to do so if we aren't very close to the target and this
					**	object can just say "good enough" and stop here.
					*/
					if (Distance(NavCom) < Rule.CloseEnoughDistance && !In_Radio_Contact()) {
						Assign_Destination(TARGET_NONE);
						return(false);
					} else {
						cellptr->Incoming(0, true, false);
//						cellptr->Incoming(0, true, true);
					}
				}
			}
		}

		TryTryAgain = PATH_RETRY;
		facing = Path[0];
	}

	/*
	**	Determine the coordinate of the next cell to move into.
	*/
	dest = Adjacent_Cell(Coord, facing);
	dir = Facing_Dir(facing);

	/*
	**	Set the facing correctly if it isn't already correct. This
	**	means starting a rotation track if necessary.
	*/
	facediff = PrimaryFacing.Difference(dir);
	if (facediff) {

		/*
		**	Request a change of facing.
		*/
		Do_Turn(dir);
		return(true);

	} else {

		/* NOTE:  Beyond this point, actual track assignment can begin.
		**
		**	If the cell to move into is impassable (probably for some unexpected
		**	reason), then abort the path list and set the speed to zero. The
		** next time this routine is called, a new path will be generated.
		*/
		destcell = Coord_Cell(dest);
		Mark(MARK_UP);
		MoveType cando = Can_Enter_Cell(destcell, facing);
		Mark(MARK_DOWN);

		if (cando != MOVE_OK) {

			if (Mission == MISSION_MOVE /*KO&& House->IsHuman */&& Distance(NavCom) < Rule.CloseEnoughDistance) {
				Assign_Destination(TARGET_NONE);
				if (!IsActive) return(false);//BG
			}

			/*
			**	If a temporary friendly object is blocking the path, then cause it to
			**	get out of the way.
			*/
			if (cando == MOVE_TEMP) {
				Map[destcell].Incoming(0, true, true);
			}

			/*
			**	If a cloaked object is blocking, then shimmer the cell.
			*/
			if (cando == MOVE_CLOAK) {
				Map[destcell].Shimmer();
			}

			Stop_Driver();
			if (cando != MOVE_MOVING_BLOCK) {
			 	Path[0] = FACING_NONE;		// Path is blocked!
			}

			/*
			** If blocked by a moving block then just exit start of move and
			** try again next tick.
			*/
			if (cando == MOVE_DESTROYABLE) {
				if (Map[destcell].Cell_Object()) {
					if (!House->Is_Ally(Map[destcell].Cell_Object())) {
						Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
					}
				} else {
					if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
						Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
					}
				}
			} else {
				if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
			}
			IsNewNavCom = false;
			TrackNumber = -1;
			return(true);
		}

		/*
		**	Determine the speed that the unit can travel to the desired square.
		*/
		ground = Map[destcell].Land_Type();
		speed = Ground[ground].Cost[Techno_Type_Class()->Speed] * 255;

		/* change speed if it's related to a team move */
		if (IsFormationMove) speed = Ground[ground].Cost[FormationSpeed] * 255;
		if (!speed) speed = 128;

#ifdef NEVER
		/*
		**	Set the jiggle flag if the terrain would cause the unit
		**	to jiggle when travelled over.
		*/
		BaseF &= ~BASEF_JIGGLE;
		if (Ground[ground].Jiggle) {
			BaseF |= BASEF_JIGGLE;
		}
#endif

		/*
		**	A damaged unit has a reduced speed.
		*/
		if (Health_Ratio() <= Rule.ConditionYellow /*(Techno_Type_Class()->MaxStrength>>1) > Strength*/) {
			speed -= (speed/4);	// Three quarters speed.
		}
		if ((speed != Speed)/* || !SpeedAdd*/) {
			Set_Speed(speed);		// Full speed.
		}

		/*
		**	Reserve the destination cell so that it won't become
		**	occupied AS this unit is moving into it.
		*/
		if (cando != MOVE_OK) {
		 	Path[0] = FACING_NONE;		// Path is blocked!
			TrackNumber = -1;
		 	dest = NULL;
		} else {

			Overrun_Square(Coord_Cell(dest), true);

			/*
			**	Determine which track to use (based on recorded path).
			*/
			FacingType nextface = Path[1];
			if (nextface == FACING_NONE) nextface = facing;

			IsOnShortTrack = false;
			TrackNumber = facing * FACING_COUNT + (int)nextface;
			if (TrackControl[TrackNumber].Track == 0) {
				Path[0] = FACING_NONE;
				TrackNumber = -1;
				return(true);
			} else {
				if (TrackControl[TrackNumber].Flag & F_D) {
					/*
					**	If the middle cell of a two cell track contains a crate,
					**	the check for goodies before movement starts.
					*/
					if (!Map[destcell].Goodie_Check(this)) {
						cando = MOVE_NO;
						if (!IsActive) return(false);
					} else {
						if (!IsActive) return(false);
						dest = Adjacent_Cell(dest, nextface);
						destcell = Coord_Cell(dest);
						cando = Can_Enter_Cell(destcell);
					}
					if (!IsActive) return(false);

					if (cando != MOVE_OK) {

						/*
						**	If a temporary friendly object is blocking the path, then cause it to
						**	get out of the way.
						*/
						if (cando == MOVE_TEMP) {
							Map[destcell].Incoming(0, true, true);
						}

						/*
						**	If a cloaked object is blocking, then shimmer the cell.
						*/
						if (cando == MOVE_CLOAK) {
							Map[destcell].Shimmer();
						}

						Path[0] = FACING_NONE;		// Path is blocked!
						TrackNumber = -1;
						dest = NULL;
						if (cando == MOVE_DESTROYABLE) {

							if (Map[destcell].Cell_Object()) {
								if (!House->Is_Ally(Map[destcell].Cell_Object())) {
									Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
								}
							} else {
								if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
									Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
								}
							}
							IsNewNavCom = false;
							TrackIndex = 0;
							return(true);
						}
					} else {
						memcpy((char*)&Path[0], (char*)&Path[2], CONQUER_PATH_MAX-2);
						Path[CONQUER_PATH_MAX-2] = FACING_NONE;
						IsPlanningToLook = true;
					}
				} else {
					memcpy((char*)&Path[0], (char*)&Path[1], CONQUER_PATH_MAX-1);
				}
				Path[CONQUER_PATH_MAX-1] = FACING_NONE;
			}
		}

		IsNewNavCom = false;
		TrackIndex = 0;
		if (!Start_Driver(dest)) {
			TrackNumber = -1;
			Path[0] = FACING_NONE;
			Set_Speed(0);
		}
	}
	return(false);
}


/***********************************************************************************************
 * DriveClass::AI -- Processes unit movement and rotation.                                     *
 *                                                                                             *
 *    This routine is used to process unit movement and rotation. It                           *
 *    functions autonomously from the script system. Thus, once a unit                         *
 *    is give rotation command or movement path, it will follow this                           *
 *    until specifically instructed to stop. The advantage of this                             *
 *    method is that it allows smooth movement of units, faster game                           *
 *    execution, and reduced script complexity (since actual movement                          *
 *    dynamics need not be controlled directly by the scripts).                                *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   This routine relies on the process control bits for the                         *
 *             specified unit (for speed reasons). Thus, only setting                          *
 *             movement, rotation, or path list will the unit perform                          *
 *             any physics.                                                                    *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/26/1993 JLB : Created.                                                                 *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
void DriveClass::AI(void)
{
	assert(IsActive);

	FootClass::AI();
	if (!IsActive || Height > 0) return;

	/*
	** Is this a unit that's been teleported using the chronosphere, and if so,
	** has his timer expired such that he needs to teleport back?
	*/
	if (IsMoebius) {
#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
	 if (What_Am_I() != RTTI_UNIT || ((UnitClass *)this)->Class->Type != UNIT_CHRONOTANK) {
#endif
		if (MoebiusCountDown == 0) {
			IsMoebius = false;
			Teleport_To(MoebiusCell);
			MoebiusCell = 0;
		}
#ifdef FIXIT_CSII	//	checked - ajw 9/28/98
	 }
#endif
	}

	/*
	**	If the unit is following a track, then continue
	**	to do so -- mindlessly.
	*/
	if (TrackNumber != -1) {

		/*
		**	Perform the movement accumulation.
		*/
		While_Moving();
		if (!IsActive) return;
		if (TrackNumber == -1 && (Target_Legal(NavCom) || Path[0] != FACING_NONE) && (What_Am_I() != RTTI_UNIT || !((UnitClass*)this)->IsDumping)) {
			Start_Of_Move();
			if (!IsActive) return;
			While_Moving();
			if (!IsActive) return;
		}

	} else {

		/*
		**	For tracked units that are rotating in place, perform the rotation now.
		*/
#ifdef TOFIX
		if ((Class->Speed == SPEED_FLOAT || Class->Speed == SPEED_HOVER || Class->Speed == SPEED_TRACK || (Class->Speed == SPEED_WHEEL && !Special.IsThreePoint)) && PrimaryFacing.Is_Rotating()) {
			if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
				Mark(MARK_CHANGE);
			}
#else
		if (PrimaryFacing.Is_Rotating()) {
			Mark(MARK_CHANGE_REDRAW);
			if (PrimaryFacing.Rotation_Adjust(Techno_Type_Class()->ROT * House->GroundspeedBias)) {
				Mark(MARK_CHANGE_REDRAW);
			}
#endif
			if (!IsRotating) {
				Per_Cell_Process(PCP_ROTATION);
				if (!IsActive) return;
			}

		} else {

			/*
			**	The unit has no track to follow, but if there
			**	is a navigation target or a remaining path,
			**	then start on a new track.
			*/
			if ((Mission != MISSION_GUARD || Target_Legal(NavCom)) && Mission != MISSION_UNLOAD) {
				if (Target_Legal(NavCom) || Path[0] != FACING_NONE) {

					/*
					**	Double check to make sure that the movement destination is
					**	in a zone that this unit can travel to. If not, then abort
					**	the navigation target. Exception is to allow units to leave
					**	impassable cells regardless of zone checks.
					*/
					LandType land = LAND_NONE;
					if (What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_UNIT) {
						land = Map[Center_Coord()].Land_Type();
					}
					if (IsLocked && Mission != MISSION_ENTER && Target_Legal(NavCom) && !Is_In_Same_Zone(As_Cell(NavCom)) &&
						land != LAND_ROCK && land != LAND_WATER && land != LAND_RIVER && !Team) {
						Stop_Driver();
						Assign_Destination(TARGET_NONE);
					} else {
						Start_Of_Move();
						if (!IsActive) return;
						While_Moving();
						if (!IsActive) return;
					}
				} else {
					Stop_Driver();
				}
			}
		}
	}
}


/***********************************************************************************************
 * DriveClass::Fixup_Path -- Adds smooth start path to normal movement path.                   *
 *                                                                                             *
 *    This routine modifies the path of the specified unit so that it                          *
 *    will not start out with a rotation. This is necessary for those                          *
 *    vehicles that have difficulty with rotating in place. Typically,                         *
 *    this includes wheeled vehicles.                                                          *
 *                                                                                             *
 * INPUT:   unit  -- Pointer to the unit to adjust.                                            *
 *                                                                                             *
 *          path  -- Pointer to path structure.                                                *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Only units that require a fixup get modified. The                               *
 *             modification only occurs, if there is a legal path to                           *
 *             do so.                                                                          *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   04/03/1994 JLB : Created.                                                                 *
 *   04/06/1994 JLB : Uses path structure.                                                     *
 *   04/10/1994 JLB : Diagonal smooth turn added.                                              *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
void DriveClass::Fixup_Path(PathType * path)
{
	assert(IsActive);

	FacingType stage[6]={FACING_N,FACING_N,FACING_N,FACING_N,FACING_N,FACING_N};		// Prefix path elements.
	int	facediff;		// The facing difference value (0..4 | 0..-4).
	static FacingType _path[4][6] = {
		{(FacingType)2,(FacingType)0,(FacingType)2,(FacingType)0,(FacingType)0,(FacingType)0},
		{(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
		{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
		{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
	};
	static FacingType _dpath[4][6] = {
		{(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0},
		{(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
		{(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0},
		{(FacingType)5,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
	};

	int			index;
	int			counter;			// Path addition
	FacingType	* ptr;				// Path list pointer.
	FacingType	* ptr2;			// Copy of new path list pointer.
	FacingType	nextpath;		// Next path value.
	CELL			cell;				// Working cell value.
	bool			ok;

	/*
	**	Verify that the unit is valid and there is a path problem to resolve.
	*/
	if (!path || path->Command[0] == FACING_NONE) {
		return;
	}

	/*
	**	Only wheeled vehicles need a path fixup -- to avoid 3 point turns.
	*/
#ifdef TOFIX
	if (!Special.IsThreePoint || Class->Speed != SPEED_WHEEL) {
#else
	if (What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_VESSEL) {
//	if (What_Am_I() == RTTI_UNIT) {
#endif
		return;
	}

	/*
	**	If the original path starts in the same direction as the unit, then
	**	there is no problem to resolve -- abort.
	*/
	facediff = PrimaryFacing.Difference((DirType)(path->Command[0]<<5)) >> 5;

	if (!facediff) return;

	if (Dir_Facing(PrimaryFacing) & FACING_NE) {
		ptr = &_dpath[(FacingType)ABS((int)facediff)-FACING_NE][1];			// Pointer to path adjust list.
 		counter = (int)_dpath[(FacingType)ABS((int)facediff)-FACING_NE][0];		// Number of path adjusts.
	} else {
		ptr = &_path[(FacingType)ABS((int)facediff)-FACING_NE][1];			// Pointer to path adjust list.
 		counter = (int)_path[(FacingType)ABS((int)facediff)-FACING_NE][0];		// Number of path adjusts.
	}
	ptr2 = ptr;

	ok = true;										// Presume adjustment is all ok.
	cell = Coord_Cell(Coord);	// Starting cell.
	nextpath = Dir_Facing(PrimaryFacing);	// Starting path.
	for (index = 0; index < counter; index++) {

		/*
		**	Determine next path element and add it to the
		**	working path list.
		*/
		if (facediff > 0) {
			nextpath = nextpath + *ptr++;
		} else {
			nextpath = nextpath - *ptr++;
		}
		stage[index] = nextpath;
		cell = Adjacent_Cell(cell, nextpath);
		//cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));

		/*
		**	If it can't enter this cell, then abort the path
		**	building operation without adjusting the unit's
		**	path.
		*/
		if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
			ok = false;
			break;
		}
	}

	/*
	**	If veering to the left was not successful, then try veering
	**	to the right. This only makes sense if the vehicle is trying
	**	to turn 180 degrees.
	*/
	if (!ok && ABS(facediff) == 4) {
		ptr = ptr2;											// Pointer to path adjust list.
		facediff = -facediff;
		ok = true;											// Presume adjustment is all ok.
		cell = Coord_Cell(Coord);						// Starting cell.
		nextpath = Dir_Facing(PrimaryFacing);		// Starting path.
		for (index = 0; index < counter; index++) {

			/*
			**	Determine next path element and add it to the
			**	working path list.
			*/
			if (facediff > 0) {
				nextpath = nextpath + *ptr++;
			} else {
				nextpath = nextpath - *ptr++;
			}
			stage[index] = nextpath;
			cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));

			/*
			**	If it can't enter this cell, then abort the path
			**	building operation without adjusting the unit's
			**	path.
			*/
			if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
				ok = false;
				break;
			}
		}
	}

	/*
	**	If a legal path addition was created, then install it in place
	**	of the first path value. The initial path entry is to be replaced
	**	with a sequence of path entries that create smooth turning.
	*/
	if (ok) {
		if (path->Length <= 1) {
			memmove((char *)&stage[0], (char*)path->Command, max(counter, 1));
			path->Length = counter;
		} else {

			/*
			**	Optimize the transition path step from the smooth turn
			**	first part as it joins with the rest of the normal
			**	path. The normal prefix path steps are NOT to be optimized.
			*/
			if (counter) {
				counter--;
				path->Command[0] = stage[counter];
				Optimize_Moves(path, MOVE_OK);
			}

			/*
			**	If there is more than one prefix path element, then
			**	insert the rest now.
			*/
			if (counter) {
				memmove((char*)&path->Command[0], (char*)&path->Command[counter], 40-counter);
				memmove((char*)&stage[0], (char*)&path->Command[0], counter);
				path->Length += counter;
			}
		}
		path->Command[path->Length] = FACING_NONE;
	}
}


/***********************************************************************************************
 * DriveClass::Lay_Track -- Handles track laying logic for the unit.                           *
 *                                                                                             *
 *    This routine handles the track laying for the unit. This entails examining the unit's    *
 *    current location as well as the direction and whether this unit is allowed to lay        *
 *    tracks in the first place.                                                               *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/28/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Lay_Track(void)
{
	assert(IsActive);

#ifdef NEVER
	static IconCommandType * _trackdirs[8] = {
		TrackN_S,
		TrackNE_SW,
		TrackE_W,
		TrackNW_SE,
		TrackN_S,
		TrackNE_SW,
		TrackE_W,
		TrackNW_SE
	};

	if (!(ClassF & CLASSF_TRACKS)) return;

	Icon_Install(Coord_Cell(Coord), _trackdirs[Facing_To_8(BodyFacing)]);
#endif
}


/***********************************************************************************************
 * DriveClass::Mark_Track -- Marks the midpoint of the track as occupied.                      *
 *                                                                                             *
 *    This routine will ensure that the midpoint (if any) of the track that the unit is        *
 *    following, will be marked according to the mark type specified.                          *
 *                                                                                             *
 * INPUT:   headto   -- The head to coordinate.                                                *
 *                                                                                             *
 *          type     -- The type of marking to perform.                                        *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/30/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void DriveClass::Mark_Track(COORDINATE headto, MarkType type)
{
	assert(IsActive);

	int value;

	if (type == MARK_UP) {
		value = false;
	} else {
		value = true;
	}

	if (headto) {
		if (!IsOnShortTrack && TrackNumber != -1) {

			/*
			** If we have not passed the per cell process point we need
			** to deal with it.
			*/
			int tracknum = TrackControl[TrackNumber].Track;
			if (tracknum) {
				TrackType const * ptr = RawTracks[tracknum - 1].Track;
				int cellidx = RawTracks[tracknum - 1].Cell;
				if (cellidx > -1) {
					DirType dir = ptr[cellidx].Facing;

					if (TrackIndex < cellidx && cellidx != -1) {
						COORDINATE offset = Smooth_Turn(ptr[cellidx].Offset, dir);
						Map[offset].Flag.Occupy.Vehicle = value;
					}
				}
			}
		}
		Map[headto].Flag.Occupy.Vehicle = value;
	}
}


/***********************************************************************************************
 * DriveClass::Ok_To_Move -- Checks to see if this object can begin moving.                    *
 *                                                                                             *
 *    This routine is used to verify that this object is allowed to move. Some objects can     *
 *    be temporarily occupied and thus cannot move until the situation permits.                *
 *                                                                                             *
 * INPUT:   direction   -- The direction that movement would be desired.                       *
 *                                                                                             *
 * OUTPUT:  Can the unit move in the direction specified?                                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
bool DriveClass::Ok_To_Move(DirType ) const
{
	assert(IsActive);

	return true;
}


/***************************************************************************
**	Smooth turn track tables. These are coordinate offsets from the center
**	of the destination cell. These are the raw tracks that are modified
**	by negating the X and Y portions as necessary. Also for reverse travelling
**	direction, the track list can be processed backward.
**
**	Track 1 = N
**	Track 2 = NE
**	Track 3 = N->NE 45 deg (double path consumption)
**	Track 4 = N->E 90 deg (double path consumption)
**	Track 5 = NE->SE 90 deg (double path consumption)
** Track 6 = NE->N 45 deg (double path consumption)
**	Track 7 = N->NE (facing change only)
**	Track 8 = NE->E (facing change only)
**	Track 9 = N->E (facing change only)
**	Track 10= NE->SE (facing change only)
**	Track 11= back up into refinery
**	Track 12= drive out of refinery
*/
//#pragma warn -ias
DriveClass::TrackType const DriveClass::Track1[24] = {
	{0x00F50000L,(DirType)0},
	{0x00EA0000L,(DirType)0},
	{0x00DF0000L,(DirType)0},
	{0x00D40000L,(DirType)0},
	{0x00C90000L,(DirType)0},
	{0x00BE0000L,(DirType)0},
	{0x00B30000L,(DirType)0},
	{0x00A80000L,(DirType)0},
	{0x009D0000L,(DirType)0},
	{0x00920000L,(DirType)0},
	{0x00870000L,(DirType)0},
	{0x007C0000L,(DirType)0},		// Track jump check here.
	{0x00710000L,(DirType)0},
	{0x00660000L,(DirType)0},
	{0x005B0000L,(DirType)0},
	{0x00500000L,(DirType)0},
	{0x00450000L,(DirType)0},
	{0x003A0000L,(DirType)0},
	{0x002F0000L,(DirType)0},
	{0x00240000L,(DirType)0},
	{0x00190000L,(DirType)0},
	{0x000E0000L,(DirType)0},
	{0x00030000L,(DirType)0},
	{0x00000000L,(DirType)0}
};

DriveClass::TrackType const DriveClass::Track2[] = {
	{0x00F8FF08L,(DirType)32},
	{0x00F0FF10L,(DirType)32},
	{0x00E8FF18L,(DirType)32},
	{0x00E0FF20L,(DirType)32},
	{0x00D8FF28L,(DirType)32},
	{0x00D0FF30L,(DirType)32},
	{0x00C8FF38L,(DirType)32},
	{0x00C0FF40L,(DirType)32},
	{0x00B8FF48L,(DirType)32},
	{0x00B0FF50L,(DirType)32},
	{0x00A8FF58L,(DirType)32},
	{0x00A0FF60L,(DirType)32},
	{0x0098FF68L,(DirType)32},
	{0x0090FF70L,(DirType)32},
	{0x0088FF78L,(DirType)32},
	{0x0080FF80L,(DirType)32},		// Track jump check here.
	{0x0078FF88L,(DirType)32},
	{0x0070FF90L,(DirType)32},
	{0x0068FF98L,(DirType)32},
	{0x0060FFA0L,(DirType)32},
	{0x0058FFA8L,(DirType)32},
	{0x0050FFB0L,(DirType)32},
	{0x0048FFB8L,(DirType)32},
	{0x0040FFC0L,(DirType)32},
	{0x0038FFC8L,(DirType)32},
	{0x0030FFD0L,(DirType)32},
	{0x0028FFD8L,(DirType)32},
	{0x0020FFE0L,(DirType)32},
	{0x0018FFE8L,(DirType)32},
	{0x0010FFF0L,(DirType)32},
	{0x0008FFF8L,(DirType)32},
	{0x00000000L,(DirType)32}
};

DriveClass::TrackType const DriveClass::Track3[] = {
	{0x01F5FF00L,(DirType)0},
	{0x01EAFF00L,(DirType)0},
	{0x01DFFF00L,(DirType)0},
	{0x01D4FF00L,(DirType)0},
	{0x01C9FF00L,(DirType)0},
	{0x01BEFF00L,(DirType)0},
	{0x01B3FF00L,(DirType)0},
	{0x01A8FF00L,(DirType)0},
	{0x019DFF00L,(DirType)0},
	{0x0192FF00L,(DirType)0},
	{0x0187FF00L,(DirType)0},
	{0x0180FF00L,(DirType)0},
	{0x0175FF00L,(DirType)0},		// Jump entry point here.
	{0x016BFF00L,(DirType)0},
	{0x0160FF02L,(DirType)1},
	{0x0155FF04L,(DirType)3},
	{0x014CFF06L,(DirType)4},
	{0x0141FF08L,(DirType)5},
	{0x0137FF0BL,(DirType)7},
	{0x012EFF0FL,(DirType)8},
	{0x0124FF13L,(DirType)9},
	{0x011AFF17L,(DirType)11},
	{0x0110FF1BL,(DirType)12},
	{0x0107FF1FL,(DirType)13},		// Center cell processing here.
	{0x00FCFF24L,(DirType)15},
	{0x00F3FF28L,(DirType)16},
	{0x00ECFF2CL,(DirType)17},
	{0x00E0FF32L,(DirType)19},
	{0x00D7FF36L,(DirType)20},
	{0x00CFFF3DL,(DirType)21},
	{0x00C6FF42L,(DirType)23},
	{0x00BAFF49L,(DirType)24},
	{0x00B0FF4DL,(DirType)25},
	{0x00A8FF58L,(DirType)27},
	{0x00A0FF60L,(DirType)28},
	{0x0098FF68L,(DirType)29},
	{0x0090FF70L,(DirType)31},
	{0x0088FF78L,(DirType)32},
	{0x0080FF80L,(DirType)32},		// Track jump check here.
	{0x0078FF88L,(DirType)32},
	{0x0070FF90L,(DirType)32},
	{0x0068FF98L,(DirType)32},
	{0x0060FFA0L,(DirType)32},
	{0x0058FFA8L,(DirType)32},
	{0x0050FFB0L,(DirType)32},
	{0x0048FFB8L,(DirType)32},
	{0x0040FFC0L,(DirType)32},
	{0x0038FFC8L,(DirType)32},
	{0x0030FFD0L,(DirType)32},
	{0x0028FFD8L,(DirType)32},
	{0x0020FFE0L,(DirType)32},
	{0x0018FFE8L,(DirType)32},
	{0x0010FFF0L,(DirType)32},
	{0x0008FFF8L,(DirType)32},
	{0x00000000L,(DirType)32}
};

DriveClass::TrackType const DriveClass::Track4[] = {
	{0x00F5FF00L,(DirType)0},
	{0x00EBFF00L,(DirType)0},
	{0x00E0FF00L,(DirType)0},
	{0x00D5FF00L,(DirType)0},
	{0x00CBFF01L,(DirType)0},
	{0x00C0FF03L,(DirType)0},
	{0x00B5FF05L,(DirType)1},
	{0x00ABFF07L,(DirType)1},
	{0x00A0FF0AL,(DirType)2},
	{0x0095FF0DL,(DirType)3},
	{0x008BFF10L,(DirType)4},
	{0x0080FF14L,(DirType)5},		// Track entry here.
	{0x0075FF18L,(DirType)8},
	{0x006DFF1CL,(DirType)12},
	{0x0063FF22L,(DirType)16},
	{0x005AFF25L,(DirType)20},
	{0x0052FF2BL,(DirType)23},
	{0x0048FF32L,(DirType)27},
	{0x0040FF37L,(DirType)32},
	{0x0038FF3DL,(DirType)36},
	{0x0030FF46L,(DirType)39},
	{0x002BFF4FL,(DirType)43},
	{0x0024FF58L,(DirType)47},
	{0x0020FF60L,(DirType)51},
	{0x001BFF6DL,(DirType)54},
	{0x0017FF79L,(DirType)57},
	{0x0014FF82L,(DirType)60},		// Track jump here.
	{0x0011FF8FL,(DirType)62},
	{0x000DFF98L,(DirType)63},
	{0x0009FFA2L,(DirType)64},
	{0x0006FFACL,(DirType)64},
	{0x0004FFB5L,(DirType)66},
	{0x0003FFC0L,(DirType)64},
	{0x0002FFCBL,(DirType)64},
	{0x0001FFD5L,(DirType)64},
	{0x0000FFE0L,(DirType)64},
	{0x0000FFEBL,(DirType)64},
	{0x0000FFF5L,(DirType)64},
	{0x00000000L,(DirType)64}
};

DriveClass::TrackType const DriveClass::Track5[] = {
	{0xFFF8FE08L,(DirType)32},
	{0xFFF0FE10L,(DirType)32},
	{0xFFE8FE18L,(DirType)32},
	{0xFFE0FE20L,(DirType)32},
	{0xFFD8FE28L,(DirType)32},
	{0xFFD0FE30L,(DirType)32},
	{0xFFC8FE38L,(DirType)32},
	{0xFFC0FE40L,(DirType)32},
	{0xFFB8FE48L,(DirType)32},
	{0xFFB0FE50L,(DirType)32},
	{0xFFA8FE58L,(DirType)32},
	{0xFFA0FE60L,(DirType)32},
	{0xFF98FE68L,(DirType)32},
	{0xFF90FE70L,(DirType)32},
	{0xFF88FE78L,(DirType)32},
	{0xFF80FE80L,(DirType)32},		// Track entry here.
	{0xFF78FE88L,(DirType)32},
	{0xFF71FE90L,(DirType)32},
	{0xFF6AFE97L,(DirType)32},
	{0xFF62FE9FL,(DirType)32},
	{0xFF5AFEA8L,(DirType)32},
	{0xFF53FEB0L,(DirType)35},
	{0xFF4BFEB7L,(DirType)38},
	{0xFF44FEBEL,(DirType)41},
	{0xFF3EFEC4L,(DirType)44},
	{0xFF39FECEL,(DirType)47},
	{0xFF34FED8L,(DirType)50},
	{0xFF30FEE0L,(DirType)53},
	{0xFF2DFEEBL,(DirType)56},
	{0xFF2CFEF5L,(DirType)59},
	{0xFF2BFF00L,(DirType)62},
	{0xFF2CFF0BL,(DirType)66},
	{0xFF2DFF15L,(DirType)69},
	{0xFF30FF1FL,(DirType)72},
	{0xFF34FF28L,(DirType)75},
	{0xFF39FF30L,(DirType)78},
	{0xFF3EFF3AL,(DirType)81},
	{0xFF44FF44L,(DirType)84},
	{0xFF4BFF4BL,(DirType)87},
	{0xFF53FF50L,(DirType)90},
	{0xFF5AFF58L,(DirType)93},
	{0xFF62FF60L,(DirType)96},
	{0xFF6AFF68L,(DirType)96},
	{0xFF71FF70L,(DirType)96},
	{0xFF78FF78L,(DirType)96},
	{0xFF80FF80L,(DirType)96},		// Track jump check here.
	{0xFF88FF88L,(DirType)96},
	{0xFF90FF90L,(DirType)96},
	{0xFF98FF98L,(DirType)96},
	{0xFFA0FFA0L,(DirType)96},
	{0xFFA8FFA8L,(DirType)96},
	{0xFFB0FFB0L,(DirType)96},
	{0xFFB8FFB8L,(DirType)96},
	{0xFFC0FFC0L,(DirType)96},
	{0xFFC8FFC8L,(DirType)96},
	{0xFFD0FFD0L,(DirType)96},
	{0xFFD8FFD8L,(DirType)96},
	{0xFFE0FFE0L,(DirType)96},
	{0xFFE8FFE8L,(DirType)96},
	{0xFFF0FFF0L,(DirType)96},
	{0xFFF8FFF8L,(DirType)96},
	{0x00000000L,(DirType)96}
};

DriveClass::TrackType const DriveClass::Track6[] = {
	{0x0100FE00L,(DirType)32},
	{0x00F8FE08L,(DirType)32},
	{0x00F0FE10L,(DirType)32},
	{0x00E8FE18L,(DirType)32},
	{0x00E0FE20L,(DirType)32},
	{0x00D8FE28L,(DirType)32},
	{0x00D0FE30L,(DirType)32},
	{0x00C8FE38L,(DirType)32},
	{0x00C0FE40L,(DirType)32},
	{0x00B8FE48L,(DirType)32},
	{0x00B0FE50L,(DirType)32},
	{0x00A8FE58L,(DirType)32},
	{0x00A0FE60L,(DirType)32},
	{0x0098FE68L,(DirType)32},
	{0x0090FE70L,(DirType)32},
	{0x0088FE78L,(DirType)32},
	{0x0080FE80L,(DirType)32},		// Jump entry point here.
	{0x0078FE88L,(DirType)32},
	{0x0070FE90L,(DirType)32},
	{0x0068FE98L,(DirType)32},
	{0x0060FEA0L,(DirType)32},
	{0x0058FEA8L,(DirType)32},
	{0x0055FEAEL,(DirType)32},
	{0x004EFEB8L,(DirType)35},
	{0x0048FEC0L,(DirType)37},
	{0x0042FEC9L,(DirType)40},
	{0x003BFED2L,(DirType)43},
	{0x0037FEDAL,(DirType)45},
	{0x0032FEE3L,(DirType)48},
	{0x002BFEEBL,(DirType)51},
	{0x0026FEF5L,(DirType)53},
	{0x0022FEFEL,(DirType)56},
	{0x001CFF08L,(DirType)59},
	{0x0019FF12L,(DirType)61},
	{0x0015FF1BL,(DirType)64},
	{0x0011FF26L,(DirType)64},
	{0x000EFF30L,(DirType)64},
	{0x000BFF39L,(DirType)64},
	{0x0009FF43L,(DirType)64},
	{0x0007FF4EL,(DirType)64},
	{0x0005FF57L,(DirType)64},
	{0x0003FF62L,(DirType)64},
	{0x0001FF6DL,(DirType)64},
	{0x0000FF77L,(DirType)64},
	{0x0000FF80L,(DirType)64},		// Track jump check here.
	{0x0000FF8BL,(DirType)64},
	{0x0000FF95L,(DirType)64},
	{0x0000FFA0L,(DirType)64},
	{0x0000FFABL,(DirType)64},
	{0x0000FFB5L,(DirType)64},
	{0x0000FFC0L,(DirType)64},
	{0x0000FFCBL,(DirType)64},
	{0x0000FFD5L,(DirType)64},
	{0x0000FFE0L,(DirType)64},
	{0x0000FFEBL,(DirType)64},
	{0x0000FFF5L,(DirType)64},
	{0x00000000L,(DirType)64}
};

DriveClass::TrackType const DriveClass::Track7[] = {
	{0x0006FFFFL,(DirType)0},
	{0x000CFFFEL,(DirType)4},
	{0x0011FFFCL,(DirType)8},
	{0x0018FFFAL,(DirType)12},
	{0x001FFFF6L,(DirType)16},
	{0x0024FFF3L,(DirType)19},
	{0x002BFFF0L,(DirType)22},
	{0x0030FFFDL,(DirType)23},
	{0x0035FFEBL,(DirType)24},
	{0x0038FFE8L,(DirType)25},
	{0x003CFFE6L,(DirType)26},
	{0x0040FFE3L,(DirType)27},
	{0x0043FFE0L,(DirType)28},
	{0x0046FFDDL,(DirType)29},
	{0x0043FFDFL,(DirType)30},
	{0x0040FFE1L,(DirType)30},
	{0x003CFFE3L,(DirType)30},
	{0x0038FFE5L,(DirType)30},
	{0x0035FFE7L,(DirType)31},
	{0x0030FFE9L,(DirType)31},
	{0x002BFFEBL,(DirType)31},
	{0x0024FFEDL,(DirType)31},
	{0x001FFFF1L,(DirType)31},
	{0x0018FFF4L,(DirType)32},
	{0x0011FFF7L,(DirType)32},
	{0x000CFFFAL,(DirType)32},
	{0x0006FFFDL,(DirType)32},
	{0x00000000L,(DirType)32}
};

DriveClass::TrackType const DriveClass::Track8[] = {
	{0x0003FFFCL,(DirType)32},
	{0x0006FFF7L,(DirType)36},
	{0x000AFFF1L,(DirType)40},
	{0x000CFFEBL,(DirType)44},
	{0x000DFFE4L,(DirType)46},
	{0x000EFFDCL,(DirType)48},
	{0x000FFFD5L,(DirType)50},
	{0x0010FFD0L,(DirType)52},
	{0x0011FFC9L,(DirType)54},
	{0x0012FFC2L,(DirType)56},
	{0x0011FFC0L,(DirType)58},
	{0x0010FFC2L,(DirType)60},
	{0x000EFFC9L,(DirType)62},
	{0x000CFFCFL,(DirType)64},
	{0x000AFFD5L,(DirType)64},
	{0x0008FFDAL,(DirType)64},
	{0x0006FFE2L,(DirType)64},
	{0x0004FFE9L,(DirType)64},
	{0x0002FFEFL,(DirType)64},
	{0x0001FFF5L,(DirType)64},
	{0x0000FFF9L,(DirType)64},
	{0x00000000L,(DirType)64}
};

DriveClass::TrackType const DriveClass::Track9[] = {
	{0xFFF50002L,(DirType)0},
	{0xFFEB0004L,(DirType)2},
	{0xFFE00006L,(DirType)4},
	{0xFFD50009L,(DirType)6},
	{0xFFCE000CL,(DirType)9},
	{0xFFC8000FL,(DirType)11},
	{0xFFC00012L,(DirType)13},
	{0xFFB80015L,(DirType)16},
	{0xFFC00012L,(DirType)18},
	{0xFFC8000EL,(DirType)20},
	{0xFFCE000AL,(DirType)22},
	{0xFFD50004L,(DirType)24},
	{0xFFDE0000L,(DirType)26},
	{0xFFE9FFF8L,(DirType)28},
	{0xFFEEFFF2L,(DirType)30},
	{0xFFF5FFEBL,(DirType)32},
	{0xFFFDFFE1L,(DirType)34},
	{0x0002FFD8L,(DirType)36},
	{0x0007FFD2L,(DirType)39},
	{0x000BFFCBL,(DirType)41},
	{0x0010FFC5L,(DirType)43},
	{0x0013FFBEL,(DirType)45},
	{0x0015FFB7L,(DirType)48},
	{0x0013FFBEL,(DirType)50},
	{0x0011FFC5L,(DirType)52},
	{0x000BFFCCL,(DirType)54},
	{0x0008FFD4L,(DirType)56},
	{0x0005FFDFL,(DirType)58},
	{0x0003FFEBL,(DirType)62},
	{0x0001FFF5L,(DirType)64},
	{0x00000000L,(DirType)64}
};

DriveClass::TrackType const DriveClass::Track10[] = {
	{0xFFF6000BL,(DirType)32},
	{0xFFF00015L,(DirType)37},
	{0xFFEB0020L,(DirType)42},
	{0xFFE9002BL,(DirType)47},
	{0xFFE50032L,(DirType)52},
	{0xFFE30038L,(DirType)57},
	{0xFFE00040L,(DirType)60},
	{0xFFE20038L,(DirType)62},
	{0xFFE40032L,(DirType)64},
	{0xFFE5002AL,(DirType)68},
	{0xFFE6001EL,(DirType)70},
	{0xFFE70015L,(DirType)72},
	{0xFFE8000BL,(DirType)74},
	{0xFFE90000L,(DirType)76},
	{0xFFE8FFF5L,(DirType)78},
	{0xFFE7FFEBL,(DirType)80},
	{0xFFE6FFE0L,(DirType)82},
	{0xFFE5FFD5L,(DirType)84},
	{0xFFE4FFCEL,(DirType)86},
	{0xFFE2FFC5L,(DirType)88},
	{0xFFE0FFC0L,(DirType)90},
	{0xFFE3FFC5L,(DirType)92},
	{0xFFE5FFCEL,(DirType)94},
	{0xFFE9FFD5L,(DirType)95},
	{0xFFEBFFE0L,(DirType)96},
	{0xFFF0FFEBL,(DirType)96},
	{0xFFF6FFF5L,(DirType)96},
	{0x00000000L,(DirType)96}
};

DriveClass::TrackType const DriveClass::Track11[] = {
	{0x01000000L,DIR_SW},
	{0x00F30008L,DIR_SW},
	{0x00E50010L,DIR_SW_X1},
	{0x00D60018L,DIR_SW_X1},
	{0x00C80020L,DIR_SW_X1},
	{0x00B90028L,DIR_SW_X1},
	{0x00AB0030L,DIR_SW_X2},
	{0x009C0038L,DIR_SW_X2},
	{0x008D0040L,DIR_SW_X2},
	{0x007F0048L,DIR_SW_X2},
	{0x00710050L,DIR_SW_X2},
	{0x00640058L,DIR_SW_X2},
	{0x00550060L,DIR_SW_X2},

	{0x00000000L,DIR_SW_X2}
};

DriveClass::TrackType const DriveClass::Track12[] = {
	{0xFF550060L,DIR_SW_X2},
	{0xFF640058L,DIR_SW_X2},
	{0xFF710050L,DIR_SW_X2},
	{0xFF7F0048L,DIR_SW_X2},
	{0xFF8D0040L,DIR_SW_X2},
	{0xFF9C0038L,DIR_SW_X2},
	{0xFFAB0030L,DIR_SW_X2},
	{0xFFB90028L,DIR_SW_X1},
	{0xFFC80020L,DIR_SW_X1},
	{0xFFD60018L,DIR_SW_X1},
	{0xFFE50010L,DIR_SW_X1},
	{0xFFF30008L,DIR_SW},

	{0x00000000L,DIR_SW}
};

#if(1)
/*
**	Drive out of weapon's factory.
*/
DriveClass::TrackType const DriveClass::Track13[] = {
	{XYP_COORD(0,-35),DIR_S},
	{XYP_COORD(0,-34),DIR_S},
	{XYP_COORD(0,-33),DIR_S},
	{XYP_COORD(0,-32),DIR_S},
	{XYP_COORD(0,-31),DIR_S},
	{XYP_COORD(0,-30),DIR_S},
	{XYP_COORD(0,-29),DIR_S},
	{XYP_COORD(0,-28),DIR_S},
	{XYP_COORD(0,-27),DIR_S},
	{XYP_COORD(0,-26),DIR_S},
	{XYP_COORD(0,-25),DIR_S},
	{XYP_COORD(0,-24),DIR_S},
	{XYP_COORD(0,-23),DIR_S},
	{XYP_COORD(0,-22),DIR_S},
	{XYP_COORD(0,-21),DIR_S},
	{XYP_COORD(0,-20),DIR_S},
	{XYP_COORD(0,-19),DIR_S},
	{XYP_COORD(0,-18),DIR_S},
	{XYP_COORD(0,-17),DIR_S},
	{XYP_COORD(0,-16),DIR_S},
	{XYP_COORD(0,-15),DIR_S},
	{XYP_COORD(0,-14),DIR_S},
	{XYP_COORD(0,-13),DIR_S},
	{XYP_COORD(0,-12),DIR_S},
	{XYP_COORD(0,-11),DIR_S},
	{XYP_COORD(0,-10),DIR_S},
	{XYP_COORD(0,-9),DIR_S},
	{XYP_COORD(0,-8),DIR_S},
	{XYP_COORD(0,-7),DIR_S},
	{XYP_COORD(0,-6),DIR_S},
	{XYP_COORD(0,-5),DIR_S},
	{XYP_COORD(0,-4),DIR_S},
	{XYP_COORD(0,-3),DIR_S},
	{XYP_COORD(0,-2),DIR_S},
	{XYP_COORD(0,-1),DIR_S},

	{0x00000000L,DIR_S}
};
#else
/*
**	Drive out of weapon's factory.
*/
DriveClass::TrackType const DriveClass::Track13[] = {
	{XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
	{XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
	{XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
	{XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
	{XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
	{XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
	{XYP_COORD(9,-17),(DirType)(DIR_SW-10)},
	{XYP_COORD(8,-16),(DirType)(DIR_SW-10)},
	{XYP_COORD(8,-15),(DirType)(DIR_SW-10)},
	{XYP_COORD(7,-14),(DirType)(DIR_SW-10)},
	{XYP_COORD(7,-13),(DirType)(DIR_SW-10)},
	{XYP_COORD(6,-12),(DirType)(DIR_SW-10)},
	{XYP_COORD(6,-11),(DirType)(DIR_SW-10)},
	{XYP_COORD(5,-10),(DirType)(DIR_SW-10)},
	{XYP_COORD(5,-9),(DirType)(DIR_SW-10)},
	{XYP_COORD(4,-8),(DirType)(DIR_SW-10)},
	{XYP_COORD(4,-7),(DirType)(DIR_SW-10)},
	{XYP_COORD(3,-6),(DirType)(DIR_SW-10)},
	{XYP_COORD(3,-5),(DirType)(DIR_SW-9)},
	{XYP_COORD(2,-4),(DirType)(DIR_SW-7)},
	{XYP_COORD(2,-3),(DirType)(DIR_SW-5)},
	{XYP_COORD(1,-2),(DirType)(DIR_SW-3)},
	{XYP_COORD(1,-1),(DirType)(DIR_SW-1)},

	{0x00000000L,DIR_SW}
};
#endif

/*
**	There are a limited basic number of tracks that a vehicle can follow. These
**	are they. Each track can be interpreted differently but this is controlled
**	by the TrackControl structure elaborated elsewhere.
*/
DriveClass::RawTrackType const DriveClass::RawTracks[13] = {
	{Track1, -1, 0, -1},
	{Track2, -1, 0, -1},
	{Track3, 37, 12, 22},
	{Track4, 26, 11, 19},
	{Track5, 45, 15, 31},
	{Track6, 44, 16, 27},
	{Track7, -1, 0, -1},
	{Track8, -1, 0, -1},
	{Track9, -1, 0, -1},
	{Track10, -1, 0, -1},
	{Track11, -1, 0, -1},
	{Track12, -1, 0, -1},
	{Track13, -1, 0, -1}
};


/***************************************************************************
**	Smooth turning control table. Given two directions in a path list, this
**	table determines which track to use and what modifying operations need
**	be performed on the track data.
*/
DriveClass::TurnTrackType const DriveClass::TrackControl[67] = {
	{1,	0,		DIR_N,	F_},																//	0-0
	{3,	7,		DIR_NE,	F_D},																//	0-1 (raw chart)
	{4,	9,		DIR_E,	F_D},																//	0-2 (raw chart)
	{0,	0,		DIR_SE,	F_},																//	0-3 !
	{0,	0,		DIR_S,	F_},																//	0-4 !
	{0,	0,		DIR_SW,	F_},																//	0-5 !
	{4,	9,		DIR_W,	(DriveClass::TrackControlType)(F_X|F_D)},				//	0-6
	{3,	7,		DIR_NW,	(DriveClass::TrackControlType)(F_X|F_D)},				//	0-7
	{6,	8,		DIR_N,	(DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)},	//	1-0
	{2,	0,		DIR_NE,	F_},																//	1-1 (raw chart)
	{6,	8,		DIR_E,	F_D},																//	1-2 (raw chart)
	{5,	10,	DIR_SE,	F_D},																//	1-3 (raw chart)
	{0,	0,		DIR_S,	F_},																//	1-4 !
	{0,	0,		DIR_SW,	F_},																//	1-5 !
	{0,	0,		DIR_W,	F_},																//	1-6 !
	{5,	10,	DIR_NW,	(DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)},	//	1-7
	{4,	9,		DIR_N,	(DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)},	//	2-0
	{3,	7,		DIR_NE,	(DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)},	//	2-1
	{1,	0,		DIR_E,	(DriveClass::TrackControlType)(F_T|F_X)},				//	2-2
	{3,	7,		DIR_SE,	(DriveClass::TrackControlType)(F_T|F_X|F_D)},		//	2-3
	{4,	9,		DIR_S,	(DriveClass::TrackControlType)(F_T|F_X|F_D)},		//	2-4
	{0,	0,		DIR_SW,	F_},																//	2-5 !
	{0,	0,		DIR_W,	F_},																//	2-6 !
	{0,	0,		DIR_NW,	F_},																//	2-7 !
	{0,	0,		DIR_N,	F_},																//	3-0 !
	{5,	10,	DIR_NE,	(DriveClass::TrackControlType)(F_Y|F_D)},				//	3-1
	{6,	8,		DIR_E,	(DriveClass::TrackControlType)(F_Y|F_D)},				//	3-2
	{2,	0,		DIR_SE,	F_Y},																//	3-3
	{6,	8,		DIR_S,	(DriveClass::TrackControlType)(F_T|F_X|F_D)},		//	3-4
	{5,	10,	DIR_SW,	(DriveClass::TrackControlType)(F_T|F_X|F_D)},		//	3-5
	{0,	0,		DIR_W,	F_},																//	3-6 !
	{0,	0,		DIR_NW,	F_},																//	3-7 !
	{0,	0,		DIR_N,	F_},																//	4-0 !
	{0,	0,		DIR_NE,	F_},																//	4-1 !
	{4,	9,		DIR_E,	(DriveClass::TrackControlType)(F_Y|F_D)},				//	4-2
	{3,	7,		DIR_SE,	(DriveClass::TrackControlType)(F_Y|F_D)},				//	4-3
	{1,	0,		DIR_S,	F_Y},																//	4-4
	{3,	7,		DIR_SW,	(DriveClass::TrackControlType)(F_X|F_Y|F_D)},		//	4-5
	{4,	9,		DIR_W,	(DriveClass::TrackControlType)(F_X|F_Y|F_D)},		//	4-6
	{0,	0,		DIR_NW,	F_},																//	4-7 !
	{0,	0,		DIR_N,	F_},																//	5-0 !
	{0,	0,		DIR_NE,	F_},																//	5-1 !
	{0,	0,		DIR_E,	F_},																//	5-2 !
	{5,	10,	DIR_SE,	(DriveClass::TrackControlType)(F_T|F_D)},				//	5-3
	{6,	8,		DIR_S,	(DriveClass::TrackControlType)(F_T|F_D)},				//	5-4
	{2,	0,		DIR_SW,	F_T},																//	5-5
	{6,	8,		DIR_W,	(DriveClass::TrackControlType)(F_X|F_Y|F_D)},		//	5-6
	{5,	10,	DIR_NW,	(DriveClass::TrackControlType)(F_X|F_Y|F_D)},		//	5-7
	{4,	9,		DIR_N,	(DriveClass::TrackControlType)(F_T|F_Y|F_D)},		//	6-0
	{0,	0,		DIR_NE,	F_},																//	6-1 !
	{0,	0,		DIR_E,	F_},																//	6-2 !
	{0,	0,		DIR_SE,	F_},																//	6-3 !
	{4,	9,		DIR_S,	(DriveClass::TrackControlType)(F_T|F_D)},				//	6-4
	{3,	7,		DIR_SW,	(DriveClass::TrackControlType)(F_T|F_D)},				//	6-5
	{1,	0,		DIR_W,	F_T},																//	6-6
	{3,	7,		DIR_NW,	(DriveClass::TrackControlType)(F_T|F_Y|F_D)},		//	6-7
	{6,	8,		DIR_N,	(DriveClass::TrackControlType)(F_T|F_Y|F_D)},		//	7-0
	{5,	10,	DIR_NE,	(DriveClass::TrackControlType)(F_T|F_Y|F_D)},		//	7-1
	{0,	0,		DIR_E,	F_},																//	7-2 !
	{0,	0,		DIR_SE,	F_},																//	7-3 !
	{0,	0,		DIR_S,	F_},																//	7-4 !
	{5,	10,	DIR_SW,	(DriveClass::TrackControlType)(F_X|F_D)},				//	7-5
	{6,	8,		DIR_W,	(DriveClass::TrackControlType)(F_X|F_D)},				//	7-6
	{2,	0,		DIR_NW,	F_X},																//	7-7

	{11,	11,	DIR_SW,	F_},																// Backup harvester into refinery.
	{12,	12,	DIR_SW_X2,	F_},															// Drive back into refinery.
	{13,	13,	DIR_SW,	F_}																// Drive out of weapons factory.
};