| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** 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 3 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, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 : LevelEdit *
- * *
- * $Archive:: /Commando/Code/Combat/pilot.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 11/26/01 5:07p $*
- * *
- * $Revision:: 18 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "pilot.h"
- #include "smartgameobj.h"
- #include "matrix3d.h"
- #include "movephys.h"
- #include "vehiclephys.h"
- #include "path.h"
- #include "pscene.h"
- #include "vehicle.h"
- #include "soldier.h"
- #include "heightdb.h"
- #include "debug.h"
- ////////////////////////////////////////////////////////////////
- // Save/Load constants
- ////////////////////////////////////////////////////////////////
- enum
- {
- CHUNKID_VARIABLES = 0x11040504,
- };
- enum
- {
- VARID_FINAL_DEST = 1,
- VARID_NEXT_POINT,
- VARID_CURRENT_TM,
- VARID_OBJ_SPACE_DEST,
- VARID_OBJ_SPACE_WPOINT,
- VARID_GAMEOBJ_PTR,
- VARID_MAX_SPEED,
- VARID_SPEED_FACTOR,
- VARID_AGGRESSIVENESS,
- VARID_ARRIVED_DIST,
- VARID_HOVERDIST,
- VARID_FACE_TARGET,
- VARID_TARGET_LOCATION,
- VARID_MODE,
- VARID_FORWARD_SPEED,
- VARID_STRAFE_SPEED,
- VARID_LIFT_SPEED,
- VARID_TURN_SHARPNESS,
- VARID_CIRCLE_ANGLE,
- VARID_CIRCLE_DIST,
- VARID_MIN_CIRCLE_ANGLE,
- VARID_MAX_CIRCLE_ANGLE,
- VARID_ISEXACT_Z_IMPORT,
- VARID_PATH_PTR
- };
- ////////////////////////////////////////////////////////////////
- // Constants
- ////////////////////////////////////////////////////////////////
- const float MAX_HEIGHT_DELTA = 2.5F;
- const float MAX_STRAFE_DELTA = 10.0F;
- const float MAX_FORWARD_DELTA = 10.0F;
- ////////////////////////////////////////////////////////////////
- // Clamp_Angle
- ////////////////////////////////////////////////////////////////
- inline float
- Clamp_Angle (float angle, float min_angle, float max_angle)
- {
- //
- // Make sure all the parameters are in the same range
- //
- angle = WWMath::Wrap (angle, 0, DEG_TO_RADF (360));
- min_angle = WWMath::Wrap (min_angle, 0, DEG_TO_RADF (360));
- max_angle = WWMath::Wrap (max_angle, 0, DEG_TO_RADF (360));
- float result = angle;
- if (min_angle <= max_angle) {
-
- //
- // Handle the 'typical' case where there is no 360-mark wrap-around
- //
- if (angle < min_angle) {
- result = min_angle;
- } else if (angle > max_angle) {
- result = max_angle;
- }
- } else {
-
- //
- // Handle the 360-mark wrap-around case
- //
- if (angle < min_angle && angle > max_angle) {
- float min_delta = min_angle - angle;
- float max_delta = angle - max_angle;
- //
- // Which edge is the angle closer to?
- //
- if (min_delta < max_delta) {
- result = min_angle;
- } else {
- result = max_angle;
- }
- }
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////
- //
- // PilotClass
- //
- ////////////////////////////////////////////////////////////////
- PilotClass::PilotClass (void)
- : m_FinalDest (0, 0, 0),
- m_NextPoint (0, 0, 0),
- m_GameObj (NULL),
- m_MaxSpeed (20.0F),
- m_SpeedFactor (1.0F),
- m_Aggressiveness (0.25F),
- m_ArrivedDist (0),
- m_HoverDist (15.0F),
- m_FaceTarget (false),
- m_TargetLocation (0, 0, 0),
- m_Mode (MODE_HOVER),
- m_ForwardSpeed (0),
- m_StrafeSpeed (0),
- m_LiftSpeed (0),
- m_TurnSharpness (0),
- m_CurrentPath (NULL),
- m_CircleAngle (0),
- m_CircleDist (0),
- m_MinCircleAngle (-DEG_TO_RADF(180)),
- m_MaxCircleAngle (DEG_TO_RADF(180)),
- m_IsExactZImportant (false)
- {
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Object_Space_Velocity
- //
- // Returns the object-space velocity vector
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Get_Object_Space_Velocity (Vector3 &vel_vector) const
- {
- //
- // Get a pointer to the physics object for this vehicle
- //
- MoveablePhysClass *phys_obj = m_GameObj->Peek_Physical_Object()->As_MoveablePhysClass ();
- WWASSERT (phys_obj != NULL);
- //
- // Get the world-space velocity vector for this vehicle and transform
- // it into object space.
- //
- Vector3 vel_vector_world;
- phys_obj->Get_Velocity (&vel_vector_world);
- Matrix3D::Inverse_Rotate_Vector (m_GameObj->Get_Transform (), vel_vector_world, &vel_vector);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Target
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Set_Target (const Vector3 *target)
- {
- if (target != NULL) {
- m_TargetLocation = *target;
-
- if (m_Mode != MODE_CIRCLE_POINT) {
- m_FaceTarget = true;
- }
- } else {
- m_FaceTarget = false;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Initialize
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Initialize (SmartGameObj *game_obj)
- {
- m_GameObj = game_obj;
- m_CurrentPath = NULL;
- //
- // If the game object is flying a vehicle, then get the vehicle instead
- //
- SoldierGameObj *soldier_game_obj = game_obj->As_SoldierGameObj ();
- if (soldier_game_obj != NULL) {
- VehicleGameObj *vehicle_game_obj = soldier_game_obj->Get_Profile_Vehicle ();
- if (vehicle_game_obj != NULL) {
- m_GameObj = vehicle_game_obj;
- }
- }
- //
- // By default assume our final destination is our current location
- //
- game_obj->Get_Position (&m_FinalDest);
- game_obj->Get_Position (&m_NextPoint);
- //
- // Determine if this game object is a vehicle or not (it better be...)
- //
- VehicleGameObj *vehicle = m_GameObj->As_VehicleGameObj ();
- if (vehicle != NULL) {
-
- //
- // Start this vehicle's engine's running
- //
- if (vehicle->Is_Engine_Enabled () == false) {
- vehicle->Enable_Engine (true);
- }
- }
-
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Calculate_Desired_Relative_Facing
- //
- ////////////////////////////////////////////////////////////////
- float
- PilotClass::Calculate_Desired_Relative_Facing (void)
- {
- float base_angle = 0;
-
- //
- // Should we be facing the destination or the current target?
- //
- if (m_FaceTarget) {
- //
- // Convert the target location from world to object space
- //
- Vector3 target_pos;
- Matrix3D::Inverse_Transform_Vector (m_CurrentTM, m_TargetLocation, &target_pos);
-
- //
- // Calculate the absolute turn angle
- //
- base_angle = WWMath::Atan2 (target_pos.Y, target_pos.X);
- base_angle = WWMath::Wrap (base_angle, 0, WWMATH_PI * 2);
- } else if (m_Mode != MODE_HOVER) {
- //
- // Calculate the absolute turn angle
- //
- base_angle = WWMath::Atan2 (m_ObjSpaceWaypoint.Y, m_ObjSpaceWaypoint.X);
- base_angle = WWMath::Wrap (base_angle, 0, WWMATH_PI * 2);
-
- }
-
- //
- // Convert the angle from [0, 360] to [-180, 180]
- //
- return WWMath::Wrap (base_angle, -WWMATH_PI, WWMATH_PI);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Think
- //
- ////////////////////////////////////////////////////////////////
- bool
- PilotClass::Think (void)
- {
- //
- // Update the current
- //
- if (m_CurrentPath != NULL) {
- m_FinalDest = m_CurrentPath->Get_Dest_Pos ();
- m_NextPoint = m_CurrentPath->Get_Next_Pos ();
- }
- //
- // Let each mode think independently
- //
- switch (m_Mode)
- {
- case MODE_HOVER:
- Process_Hover ();
- break;
- case MODE_FLY_TO_POINT:
- Process_Fly_To_Point ();
- break;
- case MODE_CIRCLE_POINT:
- Process_Circle_Point ();
- break;
- }
- //
- // Pass the current controls onto the game object
- //
- Apply_Controls ();
- //
- // Return true when we've arrived at the destination
- //
- return Has_Arrived ();
- }
- ////////////////////////////////////////////////////////////////
- //
- // Calculate_Strafe_Speed
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Calculate_Strafe_Speed (void)
- {
- m_StrafeSpeed = 0;
- bool should_strafe = m_FaceTarget;
- if (should_strafe) {
- m_StrafeSpeed = m_ObjSpaceWaypoint.Y / MAX_STRAFE_DELTA;
- m_StrafeSpeed = WWMath::Clamp (m_StrafeSpeed, -1.0F, 1.0F);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Calculate_Forward_Speed
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Calculate_Forward_Speed (float distance)
- {
- m_ForwardSpeed = 0;
- //
- // Pick a speed based on our distance from the destination
- //
- m_ForwardSpeed = distance / MAX_FORWARD_DELTA;
- m_ForwardSpeed = WWMath::Clamp (m_ForwardSpeed, -1.0F, 1.0F);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Calculate_Lift_Speed
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Calculate_Lift_Speed (void)
- {
- //bool is_exact_height_important = (m_NextPoint != m_FinalDest);
- //
- // Determine what z position we should aim for
- //
- float preferred_height = m_NextPoint.Z;
- float flight_floor = -5000.0F;
- if (m_IsExactZImportant == false) {
- flight_floor = Determine_Preferred_Height ();
- preferred_height = flight_floor;
- if (preferred_height < m_NextPoint.Z) {
- preferred_height = m_NextPoint.Z;
- }
- } else {
- preferred_height = m_NextPoint.Z;
- }
- //
- // Get the vehicle's current position
- //
- Vector3 curr_pos;
- m_GameObj->Get_Position (&curr_pos);
- //
- // Calculate the lift speed based on the change in altitude
- // Once the height delta is within MAX_HIEGHT_DELTA, we set the desired velocity to zero
- // and try to let the hovering code maintain the desired altitude.
- //
- float delta_z = preferred_height - curr_pos.Z;
- float abs_delta_z = WWMath::Fabs(delta_z);
- if (m_Mode != MODE_HOVER || abs_delta_z > MAX_HEIGHT_DELTA) {
- m_LiftSpeed = delta_z / MAX_HEIGHT_DELTA;
- m_LiftSpeed = WWMath::Clamp (m_LiftSpeed, -1.0F, 1.0F);
- } else {
- m_LiftSpeed = 0.0f;
- }
- //
- // Keep the vehicle from 'sinking' sharply
- //
- if ( m_IsExactZImportant == false &&
- m_Mode == MODE_FLY_TO_POINT &&
- delta_z < 0)
- {
- m_LiftSpeed = m_LiftSpeed * 0.25f;
- }
- //
- // Slow down our forward speed to give us time to change altitude (if necessary)
- //
- if (curr_pos.Z < flight_floor) {
- //float new_speed = WWMath::Clamp (1.0F - m_LiftSpeed, 0.5F, 1.0F);
- //m_ForwardSpeed = min (m_ForwardSpeed, new_speed);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Calculate_Turn_Sharpness
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Calculate_Turn_Sharpness (void)
- {
- float facing_angle = Calculate_Desired_Relative_Facing ();
- //
- // Calculate how sharp we should turn to make this facing
- //
- m_TurnSharpness = facing_angle / DEG_TO_RADF (45);
- m_TurnSharpness = WWMath::Clamp (m_TurnSharpness, -1.0F, 1.0F);
- //
- // If the vehicle needs to face its target, then make it turn faster then normal
- //
- if (m_FaceTarget || m_Mode == MODE_CIRCLE_POINT) {
- m_TurnSharpness *= 2.0F;
- m_TurnSharpness = min (m_TurnSharpness, 1.0F);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Process_Hover
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Process_Hover (void)
- {
- //
- // Update the "simplified" transform
- //
- Update_Transform ();
- //
- // When hovering, we want to maintain a zero horizontal velocity
- // while moving towards our desired altitude
- //
- m_ForwardSpeed = 0.0f;
- m_StrafeSpeed = 0.0f;
- //
- // Update the "simplified" transform
- //
- Update_Transform ();
- //
- // When hovering, we want to maintain a zero horizontal velocity
- // while moving towards our desired altitude
- //
- m_ForwardSpeed = 0.0f;
- m_StrafeSpeed = 0.0f;
- //
- // When hovering its valid to face a target, so update
- // the vehicle's facing
- //
- if (m_FaceTarget) {
- Calculate_Turn_Sharpness ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Process_Circle_Point
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Process_Circle_Point (void)
- {
- //
- // Reset all control inputs
- //
- m_ForwardSpeed = 0;
- m_StrafeSpeed = 0;
- m_LiftSpeed = 0;
- //
- // When hovering its valid to face a target, so update
- // the vehicle's facing
- //
- Update_Transform ();
- //
- // Make sure we are facing the destination
- //
- Calculate_Turn_Sharpness ();
- //
- // If we are facing the destination, then we can
- // start our 'circling' movement
- //
- if (::fabs (m_TurnSharpness) < 0.1F) {
- //
- // Make sure the vehicle is the appropriate distance from the circle point
- //
- Calculate_Forward_Speed (m_ObjSpaceDest.X - m_CircleDist);
- Calculate_Lift_Speed ();
- //
- // Calculate what our current circling angle is
- //
- Vector3 curr_pos;
- m_GameObj->Get_Position (&curr_pos);
- Vector3 delta = curr_pos - m_FinalDest;
- float curr_angle = WWMath::Atan2 (delta.Y, delta.X);
- float angle_delta = WWMath::Wrap (curr_angle - m_CircleAngle, -WWMATH_PI, WWMATH_PI);
- //
- // Calculate how fast we should strafe in order to circle the target
- //
- m_StrafeSpeed = angle_delta / DEG_TO_RADF (5);
- m_StrafeSpeed = WWMath::Clamp (m_StrafeSpeed, -1.0F, 1.0F);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Process_Fly_To_Point
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Process_Fly_To_Point (void)
- {
- //
- // Get the vehicle's current transform and check to see if
- // the vehicle has arrived at its destination yet
- //
- Update_Transform ();
- Check_Completion ();
- //
- // Calculate how sharp the vehicle needs to turn
- //
- Calculate_Turn_Sharpness ();
- //
- // Calculate how fast the vehicle needs to move in each direction
- //
- Calculate_Strafe_Speed ();
-
- //
- // If we are on a path then we need to calculate the forward speed
- // as if we are going full speed the whole way there
- //
- bool is_on_path = (m_NextPoint != m_FinalDest);
- if (is_on_path) {
- //
- // Clamp the speed to -1, 0, or 1.
- //
- m_ForwardSpeed = m_ObjSpaceWaypoint.X;
- if (m_ForwardSpeed > 0) {
- m_ForwardSpeed = 1.0F;
- } else if (m_ForwardSpeed < 0) {
- m_ForwardSpeed = -1.0F;
- } else {
- m_ForwardSpeed = 0.0F;
- }
- //
- // Reduce forward/back speed if we are mostly strafing.
- //
- if (WWMath::Fabs (m_StrafeSpeed) > 0.25f) {
- m_ForwardSpeed = m_ForwardSpeed * (1.25F - WWMath::Fabs (m_StrafeSpeed));
- }
- //
- // Let the pilot slow down to handle sharp corners
- //
- if (WWMath::Fabs (m_TurnSharpness) > 0.65F) {
- m_ForwardSpeed = m_ForwardSpeed * (1.25F - WWMath::Fabs (m_TurnSharpness));
- }
- } else {
- Calculate_Forward_Speed (m_ObjSpaceDest.X);
- }
- Calculate_Lift_Speed ();
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Check_Completion
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Check_Completion (void)
- {
- //
- // Get the vehicle's bounding box
- //
- MoveablePhysClass *phys_obj = m_GameObj->Peek_Physical_Object ()->As_MoveablePhysClass ();
- RenderObjClass *render_obj = phys_obj->Peek_Model ();
- AABoxClass bounding_box;
- render_obj->Get_Obj_Space_Bounding_Box (bounding_box);
- //
- // Calculate the distance remaining on the path
- //
- float dist_to_goal = 0;
- if (m_CurrentPath != NULL) {
- float dist_on_path = m_CurrentPath->Get_Remaining_Path_Length ();
- dist_to_goal = (m_ObjSpaceWaypoint.Length () + dist_on_path);
- } else {
- dist_to_goal = m_ObjSpaceDest.Length ();
- }
- //
- // Take into account the 'arrived distance' setting. We basically fly towards the
- // closest point on a sphere around the destination point. m_ObjSpaceDest will
- // be initialized to that point transformed into the vehicle's coordinate system.
- //
- if (dist_to_goal > m_ArrivedDist * m_ArrivedDist) {
- Vector3 arrived_len = m_ObjSpaceDest;
- arrived_len.Normalize ();
- arrived_len *= m_ArrivedDist;
- m_ObjSpaceDest -= arrived_len;
- m_ObjSpaceDest += bounding_box.Center;
- }
- //
- // Once we come within m_HoverDist of the desired position we switch into "hover" mode.
- //
- if (dist_to_goal < m_HoverDist && m_NextPoint == m_FinalDest) {
- Vector2 xy_delta(m_ObjSpaceWaypoint.X, m_ObjSpaceWaypoint.Y);
- if (xy_delta.Length2() < m_HoverDist * m_HoverDist) {
- Set_Mode(MODE_HOVER);
- //
- // If we don't have a target, we need to create a fake target so that
- // the orientation of the vehicle doesn't drift.
- //
- if (m_FaceTarget == false) {
- Vector3 fake_target;
- Matrix3D::Transform_Vector(m_CurrentTM,Vector3(1000.0f,0.0f,0.0f),&fake_target);
- Set_Target(&fake_target);
- }
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Update_Transform
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Update_Transform (void)
- {
- Matrix3D obj_tm = m_GameObj->Get_Transform ();
-
- //
- // Build a transform that only uses the facing and position
- // of the vehicle.
- //
- m_CurrentTM.Make_Identity ();
- m_CurrentTM.Rotate_Z (obj_tm.Get_Z_Rotation ());
- m_CurrentTM.Set_Translation (obj_tm.Get_Translation ());
- //
- // Now convert the destination from world space to object space
- //
- Matrix3D::Inverse_Transform_Vector (m_CurrentTM, m_FinalDest, &m_ObjSpaceDest);
- Matrix3D::Inverse_Transform_Vector (m_CurrentTM, m_NextPoint, &m_ObjSpaceWaypoint);
- //
- // If its not important for the vehicle to tightly follow the Z value
- // of its points, then simply zero out the Z component
- //
- if (m_IsExactZImportant == false) {
- m_ObjSpaceWaypoint.Z = 0;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Determine_Preferred_Height
- //
- ////////////////////////////////////////////////////////////////
- float
- PilotClass::Determine_Preferred_Height (void)
- {
- float height = m_NextPoint.Z;
- if (m_Mode != MODE_FLY_TO_POINT) {
- return height;
- }
- //
- // Get a pointer to the physics object for this vehicle
- //
- MoveablePhysClass *phys_obj = m_GameObj->Peek_Physical_Object()->As_MoveablePhysClass ();
- WWASSERT (phys_obj != NULL);
- //
- // Get the world-space velocity vector for this vehicle and transform
- // it into object space.
- //
- Vector3 vel_vector_world;
- phys_obj->Get_Velocity (&vel_vector_world);
- //
- // Try to determine where the aircraft will be in 1 and 2 seconds
- // from now.
- //
- Vector3 curr_pos;
- m_GameObj->Get_Position (&curr_pos);
- RenderObjClass *render_obj = phys_obj->Peek_Model ();
- const AABoxClass &bounding_box = render_obj->Get_Bounding_Box ();
- Vector3 curr_pos1 = curr_pos;
- Vector3 curr_pos2 = curr_pos + Vector3 (bounding_box.Extent.X, bounding_box.Extent.Y, 0);
- Vector3 curr_pos3 = curr_pos + Vector3 (-bounding_box.Extent.X, -bounding_box.Extent.Y, 0);
- Vector3 curr_pos4 = curr_pos + Vector3 (bounding_box.Extent.X, -bounding_box.Extent.Y, 0);
- Vector3 curr_pos5 = curr_pos + Vector3 (-bounding_box.Extent.X, bounding_box.Extent.Y, 0);
- Vector3 future_pos1 = curr_pos1 + (vel_vector_world * 1.25F);
- Vector3 future_pos2 = curr_pos2 + (vel_vector_world * 1.25F);
- Vector3 future_pos3 = curr_pos3 + (vel_vector_world * 1.25F);
- Vector3 future_pos4 = curr_pos4 + (vel_vector_world * 1.25F);
- Vector3 future_pos5 = curr_pos5 + (vel_vector_world * 1.25F);
- Vector3 future_pos6 = curr_pos1 + (vel_vector_world * 2.25F);
- Vector3 future_pos7 = curr_pos2 + (vel_vector_world * 2.25F);
- Vector3 future_pos8 = curr_pos3 + (vel_vector_world * 2.25F);
- Vector3 future_pos9 = curr_pos4 + (vel_vector_world * 2.25F);
- Vector3 future_pos10 = curr_pos5 + (vel_vector_world * 2.25F);
- future_pos1.Z = curr_pos.Z;
- future_pos2.Z = curr_pos.Z;
- future_pos3.Z = curr_pos.Z;
- future_pos4.Z = curr_pos.Z;
- future_pos5.Z = curr_pos.Z;
- future_pos6.Z = curr_pos.Z;
- future_pos7.Z = curr_pos.Z;
- future_pos8.Z = curr_pos.Z;
- future_pos9.Z = curr_pos.Z;
- future_pos10.Z = curr_pos.Z;
-
- //
- // Now, lookup the preferred height for these future positions
- //
- float height1 = HeightDBClass::Get_Height (future_pos1);
- float height2 = HeightDBClass::Get_Height (future_pos2);
- float height3 = HeightDBClass::Get_Height (future_pos3);
- float height4 = HeightDBClass::Get_Height (future_pos4);
- float height5 = HeightDBClass::Get_Height (future_pos5);
- float height6 = HeightDBClass::Get_Height (future_pos6);
- float height7 = HeightDBClass::Get_Height (future_pos7);
- float height8 = HeightDBClass::Get_Height (future_pos8);
- float height9 = HeightDBClass::Get_Height (future_pos9);
- float height10 = HeightDBClass::Get_Height (future_pos10);
- //
- // Return the largest height to the caller
- //
- height = max (height1, height2);
- height = max (height, height3);
- height = max (height, height4);
- height = max (height, height5);
- height = max (height, height6);
- height = max (height, height7);
- height = max (height, height8);
- height = max (height, height9);
- height = max (height, height10);
- return height;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Apply_Controls
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Apply_Controls (void)
- {
- //
- // If the vehicle has a driver, then pass the controls onto the driver
- // instead...
- //
- SmartGameObj *game_obj = m_GameObj;
- VehicleGameObj *vehicle = m_GameObj->As_VehicleGameObj ();
- if (vehicle != NULL) {
- if (vehicle->Get_Driver () != NULL) {
- //game_obj = vehicle->Get_Driver ();
- }
- }
- //
- // Calculate our (current) normalized speeds
- //
- Vector3 vel_vector;
- Get_Object_Space_Velocity (vel_vector);
- float curr_forward_speed = WWMath::Clamp ((vel_vector.X / m_MaxSpeed), -1.0F, 1.0F);
- float curr_strafe_speed = WWMath::Clamp ((vel_vector.Y / m_MaxSpeed), -1.0F, 1.0F);
- float curr_lift_speed = WWMath::Clamp ((vel_vector.Z / m_MaxSpeed), -1.0F, 1.0F);
- //
- // Calculate how much we need to accelerate or decelerate in the three directions
- // in order to meet our target speeds
- //
- float forward_accel = 0.0f;
- float strafe_accel = 0.0f;
- float lift_accel = 0.0f;
- if (m_Mode == MODE_HOVER) {
- forward_accel = 5.5f * (m_ForwardSpeed - curr_forward_speed) + 0.25f * m_ObjSpaceDest.X;
- strafe_accel = 3.0f * (m_StrafeSpeed - curr_strafe_speed) + 0.5f * m_ObjSpaceDest.Y;
- lift_accel = 1.0f * (m_LiftSpeed - curr_lift_speed) + 0.5f * m_ObjSpaceDest.Z;
- forward_accel = WWMath::Clamp(forward_accel,-1.0f,1.0f);
- strafe_accel = WWMath::Clamp(strafe_accel,-1.0f,1.0f);
- lift_accel = WWMath::Clamp(lift_accel,-1.0f,1.0f);
- } else {
- forward_accel = WWMath::Clamp (5.0f * (m_ForwardSpeed - curr_forward_speed), -1.0F, 1.0F);
- strafe_accel = WWMath::Clamp (1.0f * (m_StrafeSpeed - curr_strafe_speed), -1.0F, 1.0F);
- lift_accel = WWMath::Clamp (3.0f * (m_LiftSpeed - curr_lift_speed), -1.0F, 1.0F);
- }
- //
- // Make the vehicle go forward/backward
- //
- game_obj->Set_Analog_Control (ControlClass::ANALOG_MOVE_FORWARD, forward_accel);
- //
- // Make the vehicle strafe left/right
- //
- game_obj->Set_Analog_Control (ControlClass::ANALOG_MOVE_LEFT, strafe_accel);
- //
- // Make the vehicle go up/down
- //
- game_obj->Set_Analog_Control (ControlClass::ANALOG_MOVE_UP, lift_accel);
- //
- // Make the vehicle turn
- //
- game_obj->Set_Analog_Control (ControlClass::ANALOG_TURN_LEFT, m_TurnSharpness);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Mode
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Set_Mode (PilotClass::MODE mode)
- {
- if (m_Mode != mode) {
- switch (mode)
- {
- case MODE_HOVER:
- break;
- case MODE_FLY_TO_POINT:
- break;
- case MODE_CIRCLE_POINT:
- {
- m_FaceTarget = false;
-
- //
- // Initialize the circling distance
- //
- Vector3 curr_pos;
- m_GameObj->Get_Position (&curr_pos);
- m_CircleDist = (curr_pos - m_FinalDest).Length ();
- }
- break;
- }
- //
- // When we change modes, we reset the target in case we had
- // a fake target from hover mode
- //
- Set_Target(NULL);
- m_Mode = mode;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Circle_Pos
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Set_Circle_Pos (const Vector3 &pos)
- {
- Vector3 delta = pos - m_FinalDest;
- m_CircleAngle = WWMath::Atan2 (delta.Y, delta.X);
- m_CircleAngle = WWMath::Wrap (m_CircleAngle, 0, DEG_TO_RADF (360));
- m_CircleAngle = ::Clamp_Angle (m_CircleAngle, m_MinCircleAngle, m_MaxCircleAngle);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Circle_Angle
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Set_Circle_Angle (float angle)
- {
- m_CircleAngle = WWMath::Wrap (angle, 0, DEG_TO_RADF (360));
- m_CircleAngle = ::Clamp_Angle (m_CircleAngle, m_MinCircleAngle, m_MaxCircleAngle);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Circle_Bounds
- //
- ////////////////////////////////////////////////////////////////
- void
- PilotClass::Set_Circle_Bounds (float min_angle, float max_angle)
- {
- m_MinCircleAngle = min_angle;
- m_MaxCircleAngle = max_angle;
- m_CircleAngle = ::Clamp_Angle (m_CircleAngle, m_MinCircleAngle, m_MaxCircleAngle);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Has_Arrived
- //
- ////////////////////////////////////////////////////////////////
- bool
- PilotClass::Has_Arrived (void) const
- {
- bool has_arrived = false;
- if (m_Mode == MODE_HOVER) {
- /*bool
- if (m_CurrentPath != NULL) {
- m_ObjSpaceDest.Length ()
- }*/
-
- //
- // In hovering mode, we have 'arrived' if we have mostly finished moving
- //
- Vector3 vel_vector;
- Get_Object_Space_Velocity (vel_vector);
- has_arrived = (WWMath::Fabs (vel_vector.X) < 0.5F &&
- WWMath::Fabs (vel_vector.Y) < 0.5F &&
- WWMath::Fabs (vel_vector.Z) < 0.5F);
- }
- return has_arrived;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Current_Circle_Angle
- //
- ////////////////////////////////////////////////////////////////
- float
- PilotClass::Get_Current_Circle_Angle (void) const
- {
- Vector3 curr_pos;
- m_GameObj->Get_Position (&curr_pos);
- Vector3 delta = curr_pos - m_FinalDest;
- return WWMath::Atan2 (delta.Y, delta.X);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Save
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PilotClass::Save (ChunkSaveClass &csave)
- {
- csave.Begin_Chunk (CHUNKID_VARIABLES);
- //
- // Save each variable to its own microchunk
- //
-
- WRITE_MICRO_CHUNK (csave, VARID_FINAL_DEST, m_FinalDest);
- WRITE_MICRO_CHUNK (csave, VARID_NEXT_POINT, m_NextPoint);
- WRITE_MICRO_CHUNK (csave, VARID_CURRENT_TM, m_CurrentTM);
- WRITE_MICRO_CHUNK (csave, VARID_OBJ_SPACE_DEST, m_ObjSpaceDest);
- WRITE_MICRO_CHUNK (csave, VARID_OBJ_SPACE_WPOINT, m_ObjSpaceWaypoint);
- WRITE_MICRO_CHUNK (csave, VARID_PATH_PTR, m_CurrentPath);
- WRITE_MICRO_CHUNK (csave, VARID_GAMEOBJ_PTR, m_GameObj);
- WRITE_MICRO_CHUNK (csave, VARID_MAX_SPEED, m_MaxSpeed);
- WRITE_MICRO_CHUNK (csave, VARID_SPEED_FACTOR, m_SpeedFactor);
- WRITE_MICRO_CHUNK (csave, VARID_AGGRESSIVENESS, m_Aggressiveness);
- WRITE_MICRO_CHUNK (csave, VARID_ARRIVED_DIST, m_ArrivedDist);
- WRITE_MICRO_CHUNK (csave, VARID_HOVERDIST, m_HoverDist);
- WRITE_MICRO_CHUNK (csave, VARID_ISEXACT_Z_IMPORT, m_IsExactZImportant);
- WRITE_MICRO_CHUNK (csave, VARID_FACE_TARGET, m_FaceTarget);
- WRITE_MICRO_CHUNK (csave, VARID_TARGET_LOCATION, m_TargetLocation);
- WRITE_MICRO_CHUNK (csave, VARID_MODE, m_Mode);
- WRITE_MICRO_CHUNK (csave, VARID_FORWARD_SPEED, m_ForwardSpeed);
- WRITE_MICRO_CHUNK (csave, VARID_STRAFE_SPEED, m_StrafeSpeed);
- WRITE_MICRO_CHUNK (csave, VARID_LIFT_SPEED, m_LiftSpeed);
- WRITE_MICRO_CHUNK (csave, VARID_TURN_SHARPNESS, m_TurnSharpness);
- WRITE_MICRO_CHUNK (csave, VARID_CIRCLE_ANGLE, m_CircleAngle);
- WRITE_MICRO_CHUNK (csave, VARID_CIRCLE_DIST, m_CircleDist);
- WRITE_MICRO_CHUNK (csave, VARID_MIN_CIRCLE_ANGLE, m_MinCircleAngle);
- WRITE_MICRO_CHUNK (csave, VARID_MAX_CIRCLE_ANGLE, m_MaxCircleAngle);
- csave.End_Chunk ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Load
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PilotClass::Load (ChunkLoadClass &cload)
- {
- while (cload.Open_Chunk ()) {
- switch (cload.Cur_Chunk_ID ()) {
- case CHUNKID_VARIABLES:
- Load_Variables (cload);
- break;
- }
- cload.Close_Chunk ();
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Load_Variables
- //
- ///////////////////////////////////////////////////////////////////////
- void
- PilotClass::Load_Variables (ChunkLoadClass &cload)
- {
- //
- // Loop through all the microchunks that define the variables
- //
- while (cload.Open_Micro_Chunk ()) {
- switch (cload.Cur_Micro_Chunk_ID ()) {
- READ_MICRO_CHUNK (cload, VARID_FINAL_DEST, m_FinalDest);
- READ_MICRO_CHUNK (cload, VARID_NEXT_POINT, m_NextPoint);
- READ_MICRO_CHUNK (cload, VARID_CURRENT_TM, m_CurrentTM);
- READ_MICRO_CHUNK (cload, VARID_OBJ_SPACE_DEST, m_ObjSpaceDest);
- READ_MICRO_CHUNK (cload, VARID_OBJ_SPACE_WPOINT, m_ObjSpaceWaypoint);
- READ_MICRO_CHUNK (cload, VARID_PATH_PTR, m_CurrentPath);
- READ_MICRO_CHUNK (cload, VARID_GAMEOBJ_PTR, m_GameObj);
- READ_MICRO_CHUNK (cload, VARID_MAX_SPEED, m_MaxSpeed);
- READ_MICRO_CHUNK (cload, VARID_SPEED_FACTOR, m_SpeedFactor);
- READ_MICRO_CHUNK (cload, VARID_AGGRESSIVENESS, m_Aggressiveness);
- READ_MICRO_CHUNK (cload, VARID_ARRIVED_DIST, m_ArrivedDist);
- READ_MICRO_CHUNK (cload, VARID_HOVERDIST, m_HoverDist);
- READ_MICRO_CHUNK (cload, VARID_ISEXACT_Z_IMPORT, m_IsExactZImportant);
- READ_MICRO_CHUNK (cload, VARID_FACE_TARGET, m_FaceTarget);
- READ_MICRO_CHUNK (cload, VARID_TARGET_LOCATION, m_TargetLocation);
- READ_MICRO_CHUNK (cload, VARID_MODE, m_Mode);
- READ_MICRO_CHUNK (cload, VARID_FORWARD_SPEED, m_ForwardSpeed);
- READ_MICRO_CHUNK (cload, VARID_STRAFE_SPEED, m_StrafeSpeed);
- READ_MICRO_CHUNK (cload, VARID_LIFT_SPEED, m_LiftSpeed);
- READ_MICRO_CHUNK (cload, VARID_TURN_SHARPNESS, m_TurnSharpness);
- READ_MICRO_CHUNK (cload, VARID_CIRCLE_ANGLE, m_CircleAngle);
- READ_MICRO_CHUNK (cload, VARID_CIRCLE_DIST, m_CircleDist);
- READ_MICRO_CHUNK (cload, VARID_MIN_CIRCLE_ANGLE, m_MinCircleAngle);
- READ_MICRO_CHUNK (cload, VARID_MAX_CIRCLE_ANGLE, m_MaxCircleAngle);
- }
- cload.Close_Micro_Chunk ();
- }
- //
- // Request that the game object ptr gets remapped
- //
- if (m_GameObj != NULL) {
- REQUEST_POINTER_REMAP ((void **)&m_GameObj);
- }
- //
- // Request that the path object ptr gets remapped
- //
- if (m_CurrentPath != NULL) {
- REQUEST_POINTER_REMAP ((void **)&m_CurrentPath);
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Reset
- //
- ///////////////////////////////////////////////////////////////////////
- void
- PilotClass::Reset (void)
- {
- m_CurrentPath = NULL;
- m_GameObj = NULL;
- m_Mode = MODE_HOVER,
- m_IsExactZImportant = false;
- return ;
- }
|