summaryrefslogtreecommitdiff
path: root/src/uqm/cyborg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/cyborg.c')
-rw-r--r--src/uqm/cyborg.c1339
1 files changed, 1339 insertions, 0 deletions
diff --git a/src/uqm/cyborg.c b/src/uqm/cyborg.c
new file mode 100644
index 0000000..a50f3b8
--- /dev/null
+++ b/src/uqm/cyborg.c
@@ -0,0 +1,1339 @@
+//Copyright Paul Reiche, Fred Ford. 1992-2002
+
+/*
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "colors.h"
+#include "collide.h"
+#include "element.h"
+#include "ship.h"
+#include "globdata.h"
+#include "intel.h"
+#include "setup.h"
+#include "units.h"
+#include "libs/mathlib.h"
+#include "libs/log.h"
+
+//#define DEBUG_CYBORG
+
+COUNT
+PlotIntercept (ELEMENT *ElementPtr0, ELEMENT *ElementPtr1,
+ COUNT max_turns, COUNT margin_of_error)
+{
+ SIZE dy;
+ SIZE time_y_0, time_y_1;
+ POINT dst[2];
+ RECT r0 = {{0, 0}, {0, 0}};
+ RECT r1 = {{0, 0}, {0, 0}};
+ SIZE dx_0, dy_0, dx_1, dy_1;
+
+ if ((ElementPtr0->state_flags | ElementPtr1->state_flags) & FINITE_LIFE)
+ {
+ if (!(ElementPtr0->state_flags & FINITE_LIFE))
+ {
+ if (ElementPtr1->life_span < max_turns)
+ max_turns = ElementPtr1->life_span;
+ }
+ else if (!(ElementPtr1->state_flags & FINITE_LIFE))
+ {
+ if (ElementPtr0->life_span < max_turns)
+ max_turns = ElementPtr0->life_span;
+ }
+ else
+ {
+ if (ElementPtr0->life_span < max_turns)
+ max_turns = ElementPtr0->life_span;
+ if (ElementPtr1->life_span < max_turns)
+ max_turns = ElementPtr1->life_span;
+ }
+ }
+
+ dst[0] = ElementPtr0->current.location;
+ GetCurrentVelocityComponents (&ElementPtr0->velocity, &dx_0, &dy_0);
+ dx_0 = (SIZE)VELOCITY_TO_WORLD ((long)dx_0 * (long)max_turns);
+ dy_0 = (SIZE)VELOCITY_TO_WORLD ((long)dy_0 * (long)max_turns);
+
+ dst[1] = ElementPtr1->current.location;
+ GetCurrentVelocityComponents (&ElementPtr1->velocity, &dx_1, &dy_1);
+ dx_1 = (SIZE)VELOCITY_TO_WORLD ((long)dx_1 * (long)max_turns);
+ dy_1 = (SIZE)VELOCITY_TO_WORLD ((long)dy_1 * (long)max_turns);
+
+ if (margin_of_error)
+ {
+ dst[1].y -= margin_of_error;
+ time_y_0 = 1;
+ time_y_1 = margin_of_error << 1;
+ }
+ else
+ {
+ GetFrameRect (ElementPtr0->IntersectControl.IntersectStamp.frame, &r0);
+ GetFrameRect (ElementPtr1->IntersectControl.IntersectStamp.frame, &r1);
+
+ dst[0].y += DISPLAY_TO_WORLD (r0.corner.y);
+ dst[1].y += DISPLAY_TO_WORLD (r1.corner.y);
+ time_y_0 = DISPLAY_TO_WORLD (r0.extent.height);
+ time_y_1 = DISPLAY_TO_WORLD (r1.extent.height);
+ }
+
+ dy = dst[1].y - dst[0].y;
+ time_y_0 = dy - time_y_0 + 1;
+ time_y_1 = dy + time_y_1 - 1;
+ dy = dy_0 - dy_1;
+
+ if ((time_y_0 <= 0 && time_y_1 >= 0)
+ || (time_y_0 > 0 && dy >= time_y_0)
+ || (time_y_1 < 0 && dy <= time_y_1))
+ {
+ SIZE dx;
+ SIZE time_x_0, time_x_1;
+
+ if (margin_of_error)
+ {
+ dst[1].x -= margin_of_error;
+ time_x_0 = 1;
+ time_x_1 = margin_of_error << 1;
+ }
+ else
+ {
+ dst[0].x += DISPLAY_TO_WORLD (r0.corner.x);
+ dst[1].x += DISPLAY_TO_WORLD (r1.corner.x);
+ time_x_0 = DISPLAY_TO_WORLD (r0.extent.width);
+ time_x_1 = DISPLAY_TO_WORLD (r1.extent.width);
+ }
+
+ dx = dst[1].x - dst[0].x;
+ time_x_0 = dx - time_x_0 + 1;
+ time_x_1 = dx + time_x_1 - 1;
+ dx = dx_0 - dx_1;
+
+ if ((time_x_0 <= 0 && time_x_1 >= 0)
+ || (time_x_0 > 0 && dx >= time_x_0)
+ || (time_x_1 < 0 && dx <= time_x_1))
+ {
+ if (dx == 0 && dy == 0)
+ time_y_0 = time_y_1 = 0;
+ else
+ {
+ SIZE t;
+ long time_beg, time_end, fract;
+
+ if (time_y_1 < 0)
+ {
+ t = time_y_0;
+ time_y_0 = -time_y_1;
+ time_y_1 = -t;
+ }
+ else if (time_y_0 <= 0)
+ {
+ if (dy < 0)
+ time_y_1 = -time_y_0;
+ time_y_0 = 0;
+ }
+ if (dy < 0)
+ dy = -dy;
+ if (dy < time_y_1)
+ time_y_1 = dy;
+
+ if (time_x_1 < 0)
+ {
+ t = time_x_0;
+ time_x_0 = -time_x_1;
+ time_x_1 = -t;
+ }
+ else if (time_x_0 <= 0)
+ {
+ if (dx < 0)
+ time_x_1 = -time_x_0;
+ time_x_0 = 0;
+ }
+ if (dx < 0)
+ dx = -dx;
+ if (dx < time_x_1)
+ time_x_1 = dx;
+
+ if (dx == 0)
+ {
+ time_beg = time_y_0;
+ time_end = time_y_1;
+ fract = dy;
+ }
+ else if (dy == 0)
+ {
+ time_beg = time_x_0;
+ time_end = time_x_1;
+ fract = dx;
+ }
+ else
+ {
+ long time_x, time_y;
+
+ time_x = (long)time_x_0 * (long)dy;
+ time_y = (long)time_y_0 * (long)dx;
+ time_beg = time_x < time_y ? time_y : time_x;
+
+ time_x = (long)time_x_1 * (long)dy;
+ time_y = (long)time_y_1 * (long)dx;
+ time_end = time_x > time_y ? time_y : time_x;
+
+ fract = (long)dx * (long)dy;
+ }
+
+ if ((time_beg *= max_turns) < fract)
+ time_y_0 = 0;
+ else
+ time_y_0 = (SIZE)(time_beg / fract);
+
+ if (time_end >= fract) /* just in case of overflow */
+ time_y_1 = max_turns - 1;
+ else
+ time_y_1 = (SIZE)((time_end * max_turns) / fract);
+ }
+
+ if (time_y_0 <= time_y_1)
+ {
+ if (margin_of_error != 0)
+ return ((COUNT)time_y_0 + 1);
+ else
+ {
+ POINT Pt0, Pt1;
+ VELOCITY_DESC Velocity0, Velocity1;
+ INTERSECT_CONTROL Control0, Control1;
+
+ Pt0 = ElementPtr0->current.location;
+ Velocity0 = ElementPtr0->velocity;
+ Control0 = ElementPtr0->IntersectControl;
+
+ Pt1 = ElementPtr1->current.location;
+ Velocity1 = ElementPtr1->velocity;
+ Control1 = ElementPtr1->IntersectControl;
+
+ if (time_y_0)
+ {
+ GetNextVelocityComponents (&Velocity0, &dx_0, &dy_0, time_y_0);
+ Pt0.x += dx_0;
+ Pt0.y += dy_0;
+ Control0.EndPoint.x = WORLD_TO_DISPLAY (Pt0.x);
+ Control0.EndPoint.y = WORLD_TO_DISPLAY (Pt0.y);
+
+ GetNextVelocityComponents (&Velocity1, &dx_1, &dy_1, time_y_0);
+ Pt1.x += dx_1;
+ Pt1.y += dy_1;
+ Control1.EndPoint.x = WORLD_TO_DISPLAY (Pt1.x);
+ Control1.EndPoint.y = WORLD_TO_DISPLAY (Pt1.y);
+ }
+
+ do
+ {
+ TIME_VALUE when;
+
+ ++time_y_0;
+
+ GetNextVelocityComponents (&Velocity0, &dx_0, &dy_0, 1);
+ Pt0.x += dx_0;
+ Pt0.y += dy_0;
+
+ GetNextVelocityComponents (&Velocity1, &dx_1, &dy_1, 1);
+ Pt1.x += dx_1;
+ Pt1.y += dy_1;
+
+ Control0.IntersectStamp.origin = Control0.EndPoint;
+ Control0.EndPoint.x = WORLD_TO_DISPLAY (Pt0.x);
+ Control0.EndPoint.y = WORLD_TO_DISPLAY (Pt0.y);
+
+ Control1.IntersectStamp.origin = Control1.EndPoint;
+ Control1.EndPoint.x = WORLD_TO_DISPLAY (Pt1.x);
+ Control1.EndPoint.y = WORLD_TO_DISPLAY (Pt1.y);
+ when = DrawablesIntersect (&Control0,
+ &Control1, MAX_TIME_VALUE);
+ if (when)
+ {
+ if (when == 1
+ && time_y_0 == 1
+ && ((ElementPtr0->state_flags
+ | ElementPtr1->state_flags) & APPEARING))
+ {
+ when = 0;
+ Control0.EndPoint.x = WORLD_TO_DISPLAY (Pt0.x);
+ Control0.EndPoint.y = WORLD_TO_DISPLAY (Pt0.y);
+
+ Control1.EndPoint.x = WORLD_TO_DISPLAY (Pt1.x);
+ Control1.EndPoint.y = WORLD_TO_DISPLAY (Pt1.y);
+ }
+
+ if (when)
+ return ((COUNT)time_y_0);
+ }
+ } while (time_y_0 < time_y_1);
+ }
+ }
+ }
+ }
+
+ return (0);
+}
+
+static void
+InitCyborg (STARSHIP *StarShipPtr)
+{
+ COUNT Index, Divisor;
+
+ Index = StarShipPtr->RaceDescPtr->characteristics.max_thrust
+ * StarShipPtr->RaceDescPtr->characteristics.thrust_increment;
+ if ((Divisor = StarShipPtr->RaceDescPtr->characteristics.turn_wait
+ + StarShipPtr->RaceDescPtr->characteristics.thrust_wait) > 0)
+ Index /= Divisor;
+ else
+ Index >>= 1;
+#ifdef PRINT_MI
+ {
+ char *shipName;
+
+ shipName = GetStringAddress (
+ StarShipPtr->RaceDescPtr->ship_data.race_strings);
+ log_add (log_Debug, "MI(%s) -- <%u:%u> = %u", shipName,
+ StarShipPtr->RaceDescPtr->characteristics.max_thrust *
+ StarShipPtr->RaceDescPtr->characteristics.thrust_increment,
+ Divisor, Index);
+ }
+#endif /* PRINT_MI */
+ StarShipPtr->RaceDescPtr->cyborg_control.ManeuverabilityIndex = Index;
+}
+
+static void
+ship_movement (ELEMENT *ShipPtr, EVALUATE_DESC *EvalDescPtr)
+{
+ if (EvalDescPtr->which_turn == 0)
+ EvalDescPtr->which_turn = 1;
+
+ switch (EvalDescPtr->MoveState)
+ {
+ case PURSUE:
+ Pursue (ShipPtr, EvalDescPtr);
+ break;
+ case AVOID:
+#ifdef NOTYET
+ Avoid (ShipPtr, EvalDescPtr);
+ break;
+#endif /* NOTYET */
+ case ENTICE:
+ Entice (ShipPtr, EvalDescPtr);
+ break;
+ case NO_MOVEMENT:
+ break;
+ }
+}
+
+BOOLEAN
+ship_weapons (ELEMENT *ShipPtr, ELEMENT *OtherPtr, COUNT margin_of_error)
+{
+ SIZE delta_x, delta_y;
+ COUNT n, num_weapons;
+ ELEMENT Ship;
+ HELEMENT Weapon[6];
+ STARSHIP *StarShipPtr;
+
+ if (OBJECT_CLOAKED (OtherPtr))
+ margin_of_error += DISPLAY_TO_WORLD (40);
+
+ Ship = *ShipPtr;
+ GetNextVelocityComponents (&Ship.velocity,
+ &delta_x, &delta_y, 1);
+ Ship.next.location.x =
+ Ship.current.location.x + delta_x;
+ Ship.next.location.y =
+ Ship.current.location.y + delta_y;
+ Ship.current.location = Ship.next.location;
+
+ GetElementStarShip (&Ship, &StarShipPtr);
+ num_weapons =
+ (*StarShipPtr->RaceDescPtr->init_weapon_func) (&Ship, Weapon);
+
+ if ((n = num_weapons))
+ {
+ HELEMENT *WeaponPtr, w;
+ //STARSHIP *StarShipPtr;
+ ELEMENT *EPtr;
+
+ WeaponPtr = &Weapon[0];
+ do
+ {
+ w = *WeaponPtr;
+ if (w)
+ {
+ LockElement (w, &EPtr);
+ if (EPtr->state_flags & APPEARING)
+ {
+ EPtr->next = EPtr->current;
+ InitIntersectStartPoint (EPtr);
+ InitIntersectEndPoint (EPtr);
+ InitIntersectFrame (EPtr);
+ }
+
+ if (PlotIntercept (EPtr, OtherPtr,
+ EPtr->life_span, margin_of_error))
+ {
+ UnlockElement (w);
+ break;
+ }
+
+ UnlockElement (w);
+ FreeElement (w);
+ }
+ ++WeaponPtr;
+ } while (--n);
+
+ if ((num_weapons = n))
+ {
+ do
+ {
+ w = *WeaponPtr++;
+ if (w)
+ FreeElement (w);
+ } while (--n);
+ }
+ }
+
+ return (num_weapons > 0);
+}
+
+void
+ship_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern,
+ COUNT ConcernCounter)
+{
+ BOOLEAN ShipMoved, ShipFired;
+ COUNT margin_of_error;
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+
+ ShipMoved = TRUE;
+ if (ShipPtr->turn_wait == 0)
+ ShipMoved = FALSE;
+ if (ShipPtr->thrust_wait == 0)
+ ShipMoved = FALSE;
+
+ ShipFired = TRUE;
+ if (StarShipPtr->weapon_counter == 0)
+ {
+ StarShipPtr->ship_input_state &= ~WEAPON;
+ if (!(StarShipPtr->RaceDescPtr->ship_info.ship_flags & SEEKING_WEAPON))
+ ShipFired = FALSE;
+ }
+
+ if (StarShipPtr->control & AWESOME_RATING)
+ margin_of_error = 0;
+ else if (StarShipPtr->control & GOOD_RATING)
+ margin_of_error = DISPLAY_TO_WORLD (20);
+ else /* if (StarShipPtr->control & STANDARD_RATING) */
+ margin_of_error = DISPLAY_TO_WORLD (40);
+
+ ObjectsOfConcern += ConcernCounter;
+ while (ConcernCounter--)
+ {
+ --ObjectsOfConcern;
+ if (ObjectsOfConcern->ObjectPtr)
+ {
+ if (!ShipMoved
+ && (ConcernCounter != ENEMY_WEAPON_INDEX
+ || ObjectsOfConcern->MoveState == PURSUE
+ || (ObjectsOfConcern->ObjectPtr->state_flags & CREW_OBJECT)
+ || MANEUVERABILITY (
+ &StarShipPtr->RaceDescPtr->cyborg_control
+ ) >= MEDIUM_SHIP))
+ {
+ ship_movement (ShipPtr, ObjectsOfConcern);
+ ShipMoved = TRUE;
+ }
+ if (!ShipFired
+ && (ConcernCounter == ENEMY_SHIP_INDEX
+ || (ConcernCounter == ENEMY_WEAPON_INDEX
+ && ObjectsOfConcern->MoveState != AVOID
+#ifdef NEVER
+ && !(StarShipPtr->control & STANDARD_RATING)
+#endif /* NEVER */
+ )))
+ {
+ ShipFired = ship_weapons (ShipPtr,
+ ObjectsOfConcern->ObjectPtr, margin_of_error);
+ if (ShipFired)
+ StarShipPtr->ship_input_state |= WEAPON;
+ }
+ }
+ }
+}
+
+BOOLEAN
+TurnShip (ELEMENT *ShipPtr, COUNT angle)
+{
+ COUNT f, ship_delta_facing;
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ f = StarShipPtr->ShipFacing;
+ ship_delta_facing = NORMALIZE_FACING (ANGLE_TO_FACING (angle) - f);
+ if (ship_delta_facing)
+ {
+ if (ship_delta_facing == ANGLE_TO_FACING (HALF_CIRCLE))
+ ship_delta_facing =
+ NORMALIZE_FACING (ship_delta_facing +
+ (TFB_Random () & 1 ?
+ ANGLE_TO_FACING (OCTANT >> 1) :
+ -ANGLE_TO_FACING (OCTANT >> 1)));
+
+ if (ship_delta_facing < ANGLE_TO_FACING (HALF_CIRCLE))
+ {
+ StarShipPtr->ship_input_state |= RIGHT;
+ ++f;
+ ShipPtr->next.image.frame =
+ IncFrameIndex (ShipPtr->current.image.frame);
+ }
+ else
+ {
+ StarShipPtr->ship_input_state |= LEFT;
+ --f;
+ ShipPtr->next.image.frame =
+ DecFrameIndex (ShipPtr->current.image.frame);
+ }
+
+#ifdef NOTYET
+ if (((StarShipPtr->ship_input_state & (LEFT | RIGHT))
+ ^ (StarShipPtr->cur_status_flags & (LEFT | RIGHT))) == (LEFT | RIGHT))
+ StarShipPtr->ship_input_state &= ~(LEFT | RIGHT);
+ else
+#endif /* NOTYET */
+ {
+ StarShipPtr->ShipFacing = NORMALIZE_FACING (f);
+
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+BOOLEAN
+ThrustShip (ELEMENT *ShipPtr, COUNT angle)
+{
+ BOOLEAN ShouldThrust;
+ STARSHIP *StarShipPtr;
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ if (StarShipPtr->ship_input_state & THRUST)
+ ShouldThrust = TRUE;
+ else if (NORMALIZE_FACING (ANGLE_TO_FACING (angle)
+ - ANGLE_TO_FACING (GetVelocityTravelAngle (&ShipPtr->velocity))) == 0
+ && (StarShipPtr->cur_status_flags
+ & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED))
+ && !(StarShipPtr->cur_status_flags & SHIP_IN_GRAVITY_WELL))
+ ShouldThrust = FALSE;
+ else
+ {
+ SIZE ship_delta_facing;
+
+ ship_delta_facing =
+ NORMALIZE_FACING (ANGLE_TO_FACING (angle)
+ - StarShipPtr->ShipFacing + ANGLE_TO_FACING (QUADRANT));
+ if (ship_delta_facing == ANGLE_TO_FACING (QUADRANT)
+ || ((StarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED)
+ && ship_delta_facing <= ANGLE_TO_FACING (HALF_CIRCLE)))
+ ShouldThrust = TRUE;
+ else
+ ShouldThrust = FALSE;
+ }
+
+ if (ShouldThrust)
+ {
+ inertial_thrust (ShipPtr);
+
+ StarShipPtr->ship_input_state |= THRUST;
+ }
+
+ return (ShouldThrust);
+}
+
+void
+Pursue (ELEMENT *ShipPtr, EVALUATE_DESC *EvalDescPtr)
+{
+ BYTE maneuver_state;
+ COUNT desired_thrust_angle, desired_turn_angle;
+ SIZE delta_x, delta_y;
+ SIZE ship_delta_x, ship_delta_y;
+ SIZE other_delta_x, other_delta_y;
+ ELEMENT *OtherObjPtr;
+ VELOCITY_DESC ShipVelocity, OtherVelocity;
+
+ ShipVelocity = ShipPtr->velocity;
+ GetNextVelocityComponents (&ShipVelocity,
+ &ship_delta_x, &ship_delta_y, EvalDescPtr->which_turn);
+ ShipPtr->next.location.x =
+ ShipPtr->current.location.x + ship_delta_x;
+ ShipPtr->next.location.y =
+ ShipPtr->current.location.y + ship_delta_y;
+
+ OtherObjPtr = EvalDescPtr->ObjectPtr;
+ OtherVelocity = OtherObjPtr->velocity;
+ GetNextVelocityComponents (&OtherVelocity,
+ &other_delta_x, &other_delta_y, EvalDescPtr->which_turn);
+
+ delta_x = (OtherObjPtr->current.location.x + other_delta_x)
+ - ShipPtr->next.location.x;
+ delta_y = (OtherObjPtr->current.location.y + other_delta_y)
+ - ShipPtr->next.location.y;
+ delta_x = WRAP_DELTA_X (delta_x);
+ delta_y = WRAP_DELTA_Y (delta_y);
+ desired_thrust_angle = ARCTAN (delta_x, delta_y);
+
+ maneuver_state = 0;
+ if (ShipPtr->turn_wait == 0)
+ maneuver_state |= LEFT | RIGHT;
+ if (ShipPtr->thrust_wait == 0
+ && ((OtherObjPtr->state_flags & PLAYER_SHIP)
+ || elementsOfSamePlayer (OtherObjPtr, ShipPtr)
+ || OtherObjPtr->preprocess_func == crew_preprocess))
+ maneuver_state |= THRUST;
+
+ desired_turn_angle = NORMALIZE_ANGLE (desired_thrust_angle + HALF_CIRCLE);
+ /* other player's ship */
+ if ((OtherObjPtr->state_flags & PLAYER_SHIP)
+ && OtherObjPtr->mass_points <= MAX_SHIP_MASS)
+ {
+ STARSHIP *StarShipPtr;
+ STARSHIP *EnemyStarShipPtr;
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ GetElementStarShip (OtherObjPtr, &EnemyStarShipPtr);
+ if ((MANEUVERABILITY (
+ &StarShipPtr->RaceDescPtr->cyborg_control
+ ) >= FAST_SHIP
+ && WEAPON_RANGE (&StarShipPtr->RaceDescPtr->cyborg_control)
+ > CLOSE_RANGE_WEAPON)
+ || (EvalDescPtr->which_turn >= 24
+ && (StarShipPtr->RaceDescPtr->characteristics.max_thrust * 2 / 3 <
+ EnemyStarShipPtr->RaceDescPtr->characteristics.max_thrust
+ || (EnemyStarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED))))
+ {
+ UWORD ship_flags;
+
+ ship_flags = EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags;
+ /* you're maneuverable */
+ if (MANEUVERABILITY (
+ &StarShipPtr->RaceDescPtr->cyborg_control
+ ) >= MEDIUM_SHIP)
+ {
+ UWORD fire_flags;
+ COUNT facing;
+
+ for (fire_flags = FIRES_FORE, facing = EvalDescPtr->facing;
+ fire_flags <= FIRES_LEFT;
+ fire_flags <<= 1, facing += QUADRANT)
+ {
+ if
+ (
+ /* he's dangerous in this direction */
+ (ship_flags & fire_flags)
+ /* he's facing direction you want to go */
+ && NORMALIZE_ANGLE (
+ desired_turn_angle - facing + OCTANT
+ ) <= QUADRANT
+ && (
+ /* he's moving */
+ (other_delta_x != 0 || other_delta_y != 0)
+ &&
+ /* he's coasting backwards */
+ NORMALIZE_ANGLE (
+ (GetVelocityTravelAngle (&OtherVelocity) + HALF_CIRCLE)
+ - facing + (OCTANT + (OCTANT >> 1)))
+ <= ((OCTANT + (OCTANT >> 1)) << 1))
+ )
+ {
+ /* catch him on the back side */
+ desired_thrust_angle = desired_turn_angle;
+ break;
+ }
+ }
+ }
+
+ if (desired_thrust_angle != desired_turn_angle
+ && (other_delta_x || other_delta_y)
+ && EvalDescPtr->which_turn >= 24
+ && NORMALIZE_ANGLE (desired_thrust_angle
+ - GetVelocityTravelAngle (&OtherVelocity)
+ + OCTANT) <= QUADRANT
+ && ((NORMALIZE_ANGLE (
+ GetVelocityTravelAngle (&OtherVelocity)
+ - GetVelocityTravelAngle (&ShipVelocity)
+ + OCTANT) <= QUADRANT
+ && (((StarShipPtr->cur_status_flags & SHIP_AT_MAX_SPEED)
+ && !(StarShipPtr->cur_status_flags & SHIP_BEYOND_MAX_SPEED))
+ || (ship_flags & DONT_CHASE)))
+ || NORMALIZE_ANGLE (
+ desired_turn_angle
+ - FACING_TO_ANGLE (StarShipPtr->ShipFacing)
+ + OCTANT) <= QUADRANT))
+ desired_thrust_angle = desired_turn_angle;
+ }
+ }
+
+ if (maneuver_state & (LEFT | RIGHT))
+ TurnShip (ShipPtr, desired_thrust_angle);
+
+ if (maneuver_state & THRUST)
+ ThrustShip (ShipPtr, desired_thrust_angle);
+}
+
+void
+Entice (ELEMENT *ShipPtr, EVALUATE_DESC *EvalDescPtr)
+{
+ BYTE maneuver_state;
+ COUNT desired_thrust_angle, desired_turn_angle;
+ COUNT cone_of_fire, travel_angle;
+ SIZE delta_x, delta_y;
+ SIZE ship_delta_x, ship_delta_y;
+ SIZE other_delta_x, other_delta_y;
+ ELEMENT *OtherObjPtr;
+ VELOCITY_DESC ShipVelocity, OtherVelocity;
+ STARSHIP *StarShipPtr;
+ RACE_DESC *RDPtr;
+
+ ShipVelocity = ShipPtr->velocity;
+ GetNextVelocityComponents (&ShipVelocity,
+ &ship_delta_x, &ship_delta_y, EvalDescPtr->which_turn);
+ ShipPtr->next.location.x =
+ ShipPtr->current.location.x + ship_delta_x;
+ ShipPtr->next.location.y =
+ ShipPtr->current.location.y + ship_delta_y;
+
+ OtherObjPtr = EvalDescPtr->ObjectPtr;
+ OtherVelocity = OtherObjPtr->velocity;
+ GetNextVelocityComponents (&OtherVelocity,
+ &other_delta_x, &other_delta_y, EvalDescPtr->which_turn);
+
+ delta_x = (OtherObjPtr->current.location.x + other_delta_x)
+ - ShipPtr->next.location.x;
+ delta_y = (OtherObjPtr->current.location.y + other_delta_y)
+ - ShipPtr->next.location.y;
+ delta_x = WRAP_DELTA_X (delta_x);
+ delta_y = WRAP_DELTA_Y (delta_y);
+ desired_thrust_angle = ARCTAN (delta_x, delta_y);
+
+ maneuver_state = 0;
+ if (ShipPtr->turn_wait == 0)
+ maneuver_state |= LEFT | RIGHT;
+ if (ShipPtr->thrust_wait == 0)
+ maneuver_state |= THRUST;
+
+ delta_x = ship_delta_x - other_delta_x;
+ delta_y = ship_delta_y - other_delta_y;
+ travel_angle = ARCTAN (delta_x, delta_y);
+ desired_turn_angle = NORMALIZE_ANGLE (desired_thrust_angle + HALF_CIRCLE);
+
+ GetElementStarShip (ShipPtr, &StarShipPtr);
+ RDPtr = StarShipPtr->RaceDescPtr;
+ if (EvalDescPtr->MoveState == AVOID)
+ {
+ desired_turn_angle =
+ NORMALIZE_ANGLE (desired_turn_angle - EvalDescPtr->facing);
+
+ if (NORMALIZE_FACING (ANGLE_TO_FACING (desired_turn_angle)))
+ {
+ if (desired_turn_angle <= HALF_CIRCLE)
+ desired_thrust_angle = RIGHT;
+ else /* if (desired_turn_angle > HALF_CIRCLE) */
+ desired_thrust_angle = LEFT;
+ }
+ else
+ {
+ desired_turn_angle = NORMALIZE_ANGLE (
+ FACING_TO_ANGLE (StarShipPtr->ShipFacing)
+ - EvalDescPtr->facing
+ );
+ if ((desired_turn_angle & (HALF_CIRCLE - 1)) == 0)
+ desired_thrust_angle = TFB_Random () & 1 ? RIGHT : LEFT;
+ else
+ desired_thrust_angle = desired_turn_angle < HALF_CIRCLE ? RIGHT : LEFT;
+ }
+
+ if (desired_thrust_angle == LEFT)
+ {
+#define FLANK_LEFT -QUADRANT
+#define SHIP_LEFT -OCTANT
+ desired_thrust_angle = EvalDescPtr->facing
+ + FLANK_LEFT - (SHIP_LEFT >> 1);
+ }
+ else
+ {
+#define FLANK_RIGHT QUADRANT
+#define SHIP_RIGHT OCTANT
+ desired_thrust_angle = EvalDescPtr->facing
+ + FLANK_RIGHT - (SHIP_RIGHT >> 1);
+ }
+
+ desired_thrust_angle = NORMALIZE_ANGLE (desired_thrust_angle);
+ }
+ else if (GRAVITY_MASS (OtherObjPtr->mass_points))
+ {
+ COUNT planet_facing;
+
+ planet_facing = NORMALIZE_FACING (ANGLE_TO_FACING (desired_thrust_angle));
+ cone_of_fire = NORMALIZE_FACING (
+ planet_facing
+ - StarShipPtr->ShipFacing
+ + ANGLE_TO_FACING (QUADRANT));
+
+ if (RDPtr->characteristics.thrust_increment !=
+ RDPtr->characteristics.max_thrust)
+ maneuver_state &= ~THRUST;
+
+ /* if not pointing towards planet */
+ if (cone_of_fire > ANGLE_TO_FACING (QUADRANT << 1))
+ desired_turn_angle = desired_thrust_angle;
+ /* if pointing directly at planet */
+ else if (cone_of_fire == ANGLE_TO_FACING (QUADRANT)
+ && NORMALIZE_FACING (ANGLE_TO_FACING (travel_angle)) != planet_facing)
+ desired_turn_angle = travel_angle;
+ else if (cone_of_fire == 0
+ || cone_of_fire == ANGLE_TO_FACING (QUADRANT << 1)
+ || (!(maneuver_state & THRUST)
+ && (cone_of_fire < ANGLE_TO_FACING (OCTANT)
+ || cone_of_fire > ANGLE_TO_FACING ((QUADRANT << 1) - OCTANT))))
+ {
+ desired_turn_angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing);
+ if (NORMALIZE_ANGLE (desired_turn_angle
+ - travel_angle + QUADRANT) > HALF_CIRCLE)
+ desired_turn_angle = travel_angle;
+ if (ShipPtr->thrust_wait == 0)
+ maneuver_state |= THRUST;
+ }
+
+ desired_thrust_angle = desired_turn_angle;
+ }
+ else
+ {
+ COUNT WRange;
+
+ WRange = WEAPON_RANGE (
+ &RDPtr->cyborg_control
+ );
+
+ cone_of_fire = NORMALIZE_ANGLE (desired_turn_angle
+ - EvalDescPtr->facing + OCTANT);
+ if (OtherObjPtr->state_flags & PLAYER_SHIP)
+ {
+ UWORD fire_flags, ship_flags;
+ COUNT facing;
+ STARSHIP *EnemyStarShipPtr;
+
+ GetElementStarShip (OtherObjPtr, &EnemyStarShipPtr);
+ ship_flags = EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags;
+ for (fire_flags = FIRES_FORE, facing = EvalDescPtr->facing;
+ fire_flags <= FIRES_LEFT;
+ fire_flags <<= 1, facing += QUADRANT)
+ {
+ if
+ (
+ /* he's dangerous in this direction */
+ (ship_flags & fire_flags)
+ /* he's facing direction you want to go */
+ && (cone_of_fire = NORMALIZE_ANGLE (
+ desired_turn_angle - facing + OCTANT
+ )) <= QUADRANT
+ /* he's moving */
+ && ((other_delta_x != 0 || other_delta_y != 0)
+ /* he's coasting backwards */
+ && NORMALIZE_ANGLE (
+ (GetVelocityTravelAngle (&OtherVelocity) + HALF_CIRCLE)
+ - facing + OCTANT) <= QUADRANT)
+ )
+ {
+ /* need to be close for a kill */
+ if (WRange < LONG_RANGE_WEAPON
+ && EvalDescPtr->which_turn <= 32)
+ {
+ /* catch him on the back side */
+ desired_thrust_angle = desired_turn_angle;
+ goto DoManeuver;
+ }
+
+ break;
+ }
+ }
+
+ if (EvalDescPtr->which_turn <= 8
+ && RDPtr->characteristics.max_thrust <=
+ EnemyStarShipPtr->RaceDescPtr->characteristics.max_thrust)
+ goto DoManeuver;
+ }
+
+ if
+ (
+#ifdef NOTYET
+ WRange < LONG_RANGE_WEAPON
+ &&
+#endif /* NOTYET */
+ /* not at full speed */
+ !(StarShipPtr->cur_status_flags
+ & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED))
+ && (PlotIntercept (
+ ShipPtr, OtherObjPtr, 40, CLOSE_RANGE_WEAPON << 1
+ )
+#ifdef NOTYET
+ ||
+ (
+ /* object's facing direction you want to go */
+ cone_of_fire <= QUADRANT
+ /* and you're basically going in that direction */
+ && (travel_angle == FULL_CIRCLE
+ || NORMALIZE_ANGLE (travel_angle
+ - desired_thrust_angle + QUADRANT) <= HALF_CIRCLE)
+ /* and object's in range */
+ && PlotIntercept (ShipPtr, OtherObjPtr, 1, WRange)
+ )
+#endif /* NOTYET */
+ )
+ )
+ {
+ if
+ (
+ /* pointed straight at him */
+ NORMALIZE_ANGLE (desired_thrust_angle
+ - FACING_TO_ANGLE (StarShipPtr->ShipFacing) + OCTANT) <= QUADRANT
+ /* or not exposed to business end */
+ || cone_of_fire > QUADRANT
+ )
+ {
+ desired_thrust_angle = desired_turn_angle;
+ }
+ else
+ {
+#ifdef NOTYET
+ if
+ (
+ travel_angle != FULL_CIRCLE
+ && NORMALIZE_ANGLE (travel_angle
+ - desired_turn_angle + OCTANT) <= QUADRANT
+ )
+ {
+ desired_turn_angle =
+ NORMALIZE_ANGLE ((EvalDescPtr->facing + HALF_CIRCLE)
+ + (travel_angle - desired_turn_angle));
+ if (!(maneuver_state & (LEFT | RIGHT)))
+ maneuver_state &= ~THRUST;
+ }
+
+ if (maneuver_state & (LEFT | RIGHT))
+ {
+ TurnShip (ShipPtr, desired_turn_angle);
+ maneuver_state &= ~(LEFT | RIGHT);
+ }
+#endif /* NOTYET */
+
+ desired_thrust_angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing);
+desired_turn_angle = desired_thrust_angle;
+ }
+ }
+ else if ((cone_of_fire = PlotIntercept (
+ ShipPtr, OtherObjPtr, 10, WRange
+#ifdef OLD
+ - (WRange >> 3)
+#else /* !OLD */
+ - (WRange >> 2)
+#endif /* OLD */
+ )))
+ {
+ if (RDPtr->characteristics.thrust_increment !=
+ RDPtr->characteristics.max_thrust
+ /* and already at full speed */
+ && (StarShipPtr->cur_status_flags
+ & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED))
+ /* and facing away from enemy */
+ && (NORMALIZE_ANGLE (desired_turn_angle
+ - ARCTAN (ship_delta_x, ship_delta_y)
+ + (OCTANT + 2)) <= ((OCTANT + 2) << 1)
+ /* or not on collision course */
+ || !PlotIntercept (
+ ShipPtr, OtherObjPtr, 30, CLOSE_RANGE_WEAPON << 1
+ )))
+ maneuver_state &= ~THRUST;
+ /* veer off */
+ else if (cone_of_fire == 1
+ || RDPtr->characteristics.thrust_increment !=
+ RDPtr->characteristics.max_thrust)
+ {
+ if (maneuver_state & (LEFT | RIGHT))
+ {
+ TurnShip (ShipPtr, desired_turn_angle);
+ maneuver_state &= ~(LEFT | RIGHT);
+ }
+
+ if (NORMALIZE_ANGLE (desired_thrust_angle
+ - ARCTAN (ship_delta_x, ship_delta_y)
+ + (OCTANT + 2)) <= ((OCTANT + 2) << 1))
+ desired_thrust_angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing);
+ else
+ desired_thrust_angle = desired_turn_angle;
+ }
+ }
+ }
+
+DoManeuver:
+ if (maneuver_state & (LEFT | RIGHT))
+ TurnShip (ShipPtr, desired_thrust_angle);
+
+ if (maneuver_state & THRUST)
+ ThrustShip (ShipPtr, desired_thrust_angle);
+}
+
+void
+Avoid (ELEMENT *ShipPtr, EVALUATE_DESC *EvalDescPtr)
+{
+ (void) ShipPtr; /* Satisfying compiler (unused parameter) */
+ (void) EvalDescPtr; /* Satisfying compiler (unused parameter) */
+}
+
+BATTLE_INPUT_STATE
+tactical_intelligence (ComputerInputContext *context, STARSHIP *StarShipPtr)
+{
+ ELEMENT *ShipPtr;
+ ELEMENT Ship;
+ COUNT ShipFacing;
+ HELEMENT hElement, hNextElement;
+ COUNT ConcernCounter;
+ EVALUATE_DESC ObjectsOfConcern[10];
+ BOOLEAN ShipMoved, UltraManeuverable;
+ STARSHIP *EnemyStarShipPtr;
+ RACE_DESC *RDPtr;
+ RACE_DESC *EnemyRDPtr;
+
+ RDPtr = StarShipPtr->RaceDescPtr;
+
+ if (RDPtr->cyborg_control.ManeuverabilityIndex == 0)
+ InitCyborg (StarShipPtr);
+
+ LockElement (StarShipPtr->hShip, &ShipPtr);
+ if (RDPtr->ship_info.crew_level == 0
+ || GetPrimType (&DisplayArray[ShipPtr->PrimIndex]) == NO_PRIM)
+ {
+ UnlockElement (StarShipPtr->hShip);
+ return (0);
+ }
+
+ ShipMoved = TRUE;
+ /* Disable ship's special completely for the Standard AI */
+ if (StarShipPtr->control & STANDARD_RATING)
+ ++StarShipPtr->special_counter;
+
+#ifdef DEBUG_CYBORG
+if (!(ShipPtr->state_flags & FINITE_LIFE)
+ && ShipPtr->life_span == NORMAL_LIFE)
+ ShipPtr->life_span += 2; /* make ship invulnerable */
+#endif /* DEBUG_CYBORG */
+ Ship = *ShipPtr;
+ UnlockElement (StarShipPtr->hShip);
+ ShipFacing = StarShipPtr->ShipFacing;
+
+ for (ConcernCounter = 0;
+ ConcernCounter <= FIRST_EMPTY_INDEX; ++ConcernCounter)
+ {
+ ObjectsOfConcern[ConcernCounter].ObjectPtr = 0;
+ ObjectsOfConcern[ConcernCounter].MoveState = NO_MOVEMENT;
+ ObjectsOfConcern[ConcernCounter].which_turn = (COUNT)~0;
+ }
+ --ConcernCounter;
+
+ UltraManeuverable = (BOOLEAN)(
+ RDPtr->characteristics.thrust_increment ==
+ RDPtr->characteristics.max_thrust
+ && MANEUVERABILITY (&RDPtr->cyborg_control) >= MEDIUM_SHIP
+ );
+
+ if (Ship.turn_wait == 0)
+ {
+ ShipMoved = FALSE;
+ StarShipPtr->ship_input_state &= ~(LEFT | RIGHT);
+ }
+ if (Ship.thrust_wait == 0)
+ {
+ ShipMoved = FALSE;
+ StarShipPtr->ship_input_state &= ~THRUST;
+ }
+
+ for (hElement = GetHeadElement ();
+ hElement != 0; hElement = hNextElement)
+ {
+ EVALUATE_DESC ed;
+
+ ed.MoveState = NO_MOVEMENT;
+
+ LockElement (hElement, &ed.ObjectPtr);
+ hNextElement = GetSuccElement (ed.ObjectPtr);
+ if (CollisionPossible (ed.ObjectPtr, &Ship))
+ {
+ SIZE dx, dy;
+
+ dx = ed.ObjectPtr->next.location.x
+ - Ship.next.location.x;
+ dy = ed.ObjectPtr->next.location.y
+ - Ship.next.location.y;
+ dx = WRAP_DELTA_X (dx);
+ dy = WRAP_DELTA_Y (dy);
+ if (GRAVITY_MASS (ed.ObjectPtr->mass_points))
+ {
+ COUNT maneuver_turn, ship_bounds;
+ RECT ship_footprint = {{0, 0}, {0, 0}};
+
+ if (UltraManeuverable)
+ maneuver_turn = 16;
+ else if (MANEUVERABILITY (&RDPtr->cyborg_control) <= MEDIUM_SHIP)
+ maneuver_turn = 48;
+ else
+ maneuver_turn = 32;
+
+ GetFrameRect (SetAbsFrameIndex (
+ Ship.IntersectControl.IntersectStamp.frame, 0
+ ), &ship_footprint);
+ ship_bounds = (COUNT)(ship_footprint.extent.width
+ + ship_footprint.extent.height);
+
+ if (!ShipMoved && (ed.which_turn =
+ PlotIntercept (ed.ObjectPtr, &Ship, maneuver_turn,
+ DISPLAY_TO_WORLD (30 + (ship_bounds * 3 /* << 2 */)))))
+ {
+ if (ed.which_turn > 1
+ || PlotIntercept (ed.ObjectPtr, &Ship, 1,
+ DISPLAY_TO_WORLD (35 + ship_bounds))
+ || PlotIntercept (ed.ObjectPtr, &Ship,
+ maneuver_turn << 1,
+ DISPLAY_TO_WORLD (40 + ship_bounds)) > 1)
+ {
+ ed.facing = ARCTAN (-dx, -dy);
+ if (UltraManeuverable)
+ ed.MoveState = AVOID;
+ else // Try a gravity whip
+ ed.MoveState = ENTICE;
+
+ ObjectsOfConcern[GRAVITY_MASS_INDEX] = ed;
+ }
+ else if (!UltraManeuverable &&
+ !IsVelocityZero (&Ship.velocity))
+ { // Try an orbital insertion, don't thrust
+ ++Ship.thrust_wait;
+ if (Ship.turn_wait)
+ ShipMoved = TRUE;
+ }
+ }
+ }
+ else if (ed.ObjectPtr->state_flags & PLAYER_SHIP)
+ {
+ GetElementStarShip (ed.ObjectPtr, &EnemyStarShipPtr);
+ EnemyRDPtr = EnemyStarShipPtr->RaceDescPtr;
+ if (EnemyRDPtr->cyborg_control.ManeuverabilityIndex == 0)
+ InitCyborg (EnemyStarShipPtr);
+
+ ed.which_turn = WORLD_TO_TURN (
+ square_root ((long)dx * dx + (long)dy * dy));
+ if (ed.which_turn >
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn)
+ {
+ UnlockElement (hElement);
+ continue;
+ }
+ else if (ed.which_turn == 0)
+ ed.which_turn = 1;
+
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].ObjectPtr = ed.ObjectPtr;
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].facing =
+#ifdef MAYBE
+ OBJECT_CLOAKED (ed.ObjectPtr) ?
+ GetVelocityTravelAngle (&ed.ObjectPtr->velocity) :
+#endif /* MAYBE */
+ FACING_TO_ANGLE (EnemyStarShipPtr->ShipFacing);
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn = ed.which_turn;
+
+ if (ShipMoved
+ || ed.ObjectPtr->mass_points > MAX_SHIP_MASS
+ || (WEAPON_RANGE (&RDPtr->cyborg_control) < LONG_RANGE_WEAPON
+ && (WEAPON_RANGE (&RDPtr->cyborg_control) <= CLOSE_RANGE_WEAPON
+ || (WEAPON_RANGE (&EnemyRDPtr->cyborg_control) >= LONG_RANGE_WEAPON
+ && (EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags & SEEKING_WEAPON))
+ || (
+#ifdef OLD
+ MANEUVERABILITY (&RDPtr->cyborg_control) <
+ MANEUVERABILITY (&EnemyRDPtr->cyborg_control)
+#else /* !OLD */
+ RDPtr->characteristics.max_thrust <
+ EnemyRDPtr->characteristics.max_thrust
+#endif /* !OLD */
+ && WEAPON_RANGE (&RDPtr->cyborg_control) <
+ WEAPON_RANGE (&EnemyRDPtr->cyborg_control)))))
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].MoveState = PURSUE;
+ else
+ ObjectsOfConcern[ENEMY_SHIP_INDEX].MoveState = ENTICE;
+
+ if ((EnemyStarShipPtr->RaceDescPtr->ship_info.ship_flags & IMMEDIATE_WEAPON)
+ && ship_weapons (ed.ObjectPtr, &Ship, 0))
+ {
+ ed.which_turn = 1;
+ ed.MoveState = AVOID;
+ ed.facing = ObjectsOfConcern[ENEMY_SHIP_INDEX].facing;
+
+ ObjectsOfConcern[ENEMY_WEAPON_INDEX] = ed;
+ }
+ }
+ else if (ed.ObjectPtr->pParent == 0)
+ {
+ if (!(ed.ObjectPtr->state_flags & FINITE_LIFE))
+ {
+ ed.which_turn = WORLD_TO_TURN (
+ square_root ((long)dx * dx + (long)dy * dy)
+ );
+
+ if (ed.which_turn <
+ ObjectsOfConcern[FIRST_EMPTY_INDEX].which_turn)
+ {
+ ed.MoveState = PURSUE;
+ ed.facing = GetVelocityTravelAngle (
+ &ed.ObjectPtr->velocity
+ );
+
+ ObjectsOfConcern[FIRST_EMPTY_INDEX] = ed;
+ }
+ }
+ }
+ else if (!elementsOfSamePlayer (ed.ObjectPtr, &Ship)
+ && ed.ObjectPtr->preprocess_func != crew_preprocess
+ && ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn > 1
+ && ed.ObjectPtr->life_span > 0)
+ {
+ GetElementStarShip (ed.ObjectPtr, &EnemyStarShipPtr);
+ EnemyRDPtr = EnemyStarShipPtr->RaceDescPtr;
+ if (((EnemyRDPtr->ship_info.ship_flags & SEEKING_WEAPON)
+ && ed.ObjectPtr->next.image.farray !=
+ EnemyRDPtr->ship_data.special)
+ || ((EnemyRDPtr->ship_info.ship_flags & SEEKING_SPECIAL)
+ && ed.ObjectPtr->next.image.farray ==
+ EnemyRDPtr->ship_data.special))
+ {
+ if ((!(ed.ObjectPtr->state_flags & (FINITE_LIFE | CREW_OBJECT))
+ && RDPtr->characteristics.max_thrust > DISPLAY_TO_WORLD (8))
+ || NORMALIZE_ANGLE (GetVelocityTravelAngle (
+ &ed.ObjectPtr->velocity
+ ) - ARCTAN (-dx, -dy)
+ + QUADRANT) > HALF_CIRCLE)
+ ed.which_turn = 0;
+ else
+ {
+ ed.which_turn = WORLD_TO_TURN (
+ square_root ((long)dx * dx + (long)dy * dy)
+ );
+
+ ed.MoveState = ENTICE;
+ if (UltraManeuverable)
+ {
+ if (ed.which_turn == 0)
+ ed.which_turn = 1;
+ else if (ed.which_turn > 16)
+ ed.which_turn = 0;
+ }
+ else if (ed.which_turn == 0)
+ ed.which_turn = 1;
+ else if (ed.which_turn > 16
+ || (MANEUVERABILITY (
+ &RDPtr->cyborg_control
+ ) > MEDIUM_SHIP
+ && ed.which_turn > 8))
+ ed.which_turn = 0;
+ }
+ }
+ else if (!(StarShipPtr->control & AWESOME_RATING))
+ ed.which_turn = 0;
+ else
+ {
+ ed.which_turn =
+ PlotIntercept (ed.ObjectPtr,
+ &Ship, ed.ObjectPtr->life_span,
+ DISPLAY_TO_WORLD (40));
+ ed.MoveState = AVOID;
+ }
+
+ if (ed.which_turn > 0
+ && (ed.which_turn <
+ ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn
+ || (ed.which_turn ==
+ ObjectsOfConcern[ENEMY_WEAPON_INDEX].which_turn
+ && ed.MoveState == AVOID)))
+ {
+ ed.facing = GetVelocityTravelAngle (
+ &ed.ObjectPtr->velocity
+ );
+
+ ObjectsOfConcern[ENEMY_WEAPON_INDEX] = ed;
+ }
+ }
+ else if ((ed.ObjectPtr->state_flags & CREW_OBJECT)
+ && ((!(ed.ObjectPtr->state_flags & IGNORE_SIMILAR)
+ && elementsOfSamePlayer (ed.ObjectPtr, &Ship))
+ || ed.ObjectPtr->preprocess_func == crew_preprocess)
+ && ObjectsOfConcern[CREW_OBJECT_INDEX].which_turn > 1)
+ {
+ ed.which_turn = WORLD_TO_TURN (
+ square_root ((long)dx * dx + (long)dy * dy)
+ );
+
+ if (ed.which_turn == 0)
+ ed.which_turn = 1;
+
+ if (ObjectsOfConcern[CREW_OBJECT_INDEX].which_turn >
+ ed.which_turn
+ && (ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn > 32
+ || (ObjectsOfConcern[ENEMY_SHIP_INDEX].which_turn > 8
+ && StarShipPtr->hShip == ed.ObjectPtr->hTarget)))
+ {
+ ed.MoveState = PURSUE;
+ ed.facing = 0;
+ ObjectsOfConcern[CREW_OBJECT_INDEX] = ed;
+ }
+ }
+ }
+ UnlockElement (hElement);
+ }
+
+ RDPtr->cyborg_control.intelligence_func (&Ship, ObjectsOfConcern,
+ ConcernCounter);
+#ifdef DEBUG_CYBORG
+StarShipPtr->ship_input_state &= ~SPECIAL;
+#endif /* DEBUG_CYBORG */
+
+ StarShipPtr->ShipFacing = ShipFacing;
+ {
+ BATTLE_INPUT_STATE InputState;
+
+ InputState = 0;
+ if (StarShipPtr->ship_input_state & LEFT)
+ InputState |= BATTLE_LEFT;
+ else if (StarShipPtr->ship_input_state & RIGHT)
+ InputState |= BATTLE_RIGHT;
+ if (StarShipPtr->ship_input_state & THRUST)
+ InputState |= BATTLE_THRUST;
+ if (StarShipPtr->ship_input_state & WEAPON)
+ InputState |= BATTLE_WEAPON;
+ if (StarShipPtr->ship_input_state & SPECIAL)
+ InputState |= BATTLE_SPECIAL;
+
+ (void) context;
+ return (InputState);
+ }
+}
+