| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772 |
- /*
- ** 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 : Combat *
- * *
- * $Archive:: /Commando/Code/Combat/pathaction.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 11/16/01 1:51p $*
- * *
- * $Revision:: 18 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "pathaction.h"
- #include "smartgameobj.h"
- #include "soldier.h"
- #include "doors.h"
- #include "humanphys.h"
- #include "obbox.h"
- #include "path.h"
- #include "chunkio.h"
- #include "saveload.h"
- ////////////////////////////////////////////////////////////////
- // Save/Load constants
- ////////////////////////////////////////////////////////////////
- enum
- {
- CHUNKID_GAMEOBJ_REF = 0x11020954,
- CHUNKID_VARIABLES
- };
- enum
- {
- VARID_ELEVATOR_STATE = 0,
- VARID_DOOR_STATE,
- VARID_STATE,
- VARID_TYPE,
- VARID_PATH_PTR,
- VARID_MECHANISM_PTR,
- VARID_DESTINATION,
- VARID_FACEPOS,
- VARID_GAME_OBJ_PTR,
- VARID_LADDER_STATE,
- VARID_LADDER_INDEX
- };
- ////////////////////////////////////////////////////////////////
- // Static member initialization
- ////////////////////////////////////////////////////////////////
- DynamicVectorClass<GameObjReference> PathActionClass::LadderList;
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // PathActionClass
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- PathActionClass::PathActionClass (void) :
- ElevatorState (ELEVATOR_STATE_NONE),
- DoorState (DOOR_STATE_NONE),
- LadderState (LADDER_STATE_NONE),
- State (STATE_FINISHED),
- Type (TYPE_UNKNOWN),
- Mechanism (NULL),
- GameObj (NULL),
- Path (NULL),
- LadderIndex (-1),
- Destination (0, 0, 0),
- FacePos (0, 0, 0),
- Timer (0)
- {
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // ~PathActionClass
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- PathActionClass::~PathActionClass (void)
- {
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Initialize
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Initialize
- (
- TYPE type,
- PathClass * path,
- SmartGameObj * game_obj,
- StaticPhysClass * mechanism
- )
- {
- Type = type;
- GameObj = game_obj;
- Mechanism = mechanism;
- Path = path;
- //
- // Reset the states
- //
- State = STATE_WAITING;
- ElevatorState = ELEVATOR_STATE_WAITING;
- DoorState = DOOR_STATE_GETTING_IN_POSITION;
- LadderState = LADDER_STATE_WAITING;
- Timer = 5;
- assert(Path != NULL);
- assert(Path->Get_Path_Vector_Length() >= Path->Get_Path_Vector_Count());
- Path->Get_Action_Entrance (Destination);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Process
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- bool
- PathActionClass::Process (void)
- {
- switch (Type)
- {
- case TYPE_JUMPING:
- Handle_Jump ();
- break;
- case TYPE_LADDER:
- Handle_Ladder ();
- break;
- case TYPE_ELEVATOR:
- Handle_Elevator ();
- break;
- case TYPE_DOOR:
- Handle_Door ();
- break;
- default:
- Set_Finished ();
- break;
- }
- return (State == STATE_FINISHED);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Handle_Ladder
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Handle_Ladder (void)
- {
- SoldierGameObj *soldier = GameObj->As_SoldierGameObj ();
- WWASSERT (soldier != NULL);
- switch (LadderState)
- {
- case LADDER_STATE_WAITING:
- {
- //
- // Is there already someone on the ladder?
- //
- if (Get_Ladder_Occupant (LadderIndex) == NULL) {
- Set_Ladder_Occupant (LadderIndex, GameObj);
- //
- // Get on the ladder
- //
- soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
- LadderState = LADDER_STATE_GETTING_ON;
- }
- break;
- }
- case LADDER_STATE_GETTING_ON:
- //
- // Have we gotten on yet?
- //
- if (soldier->Is_On_Ladder ()) {
- //
- // Start climbing
- //
- State = STATE_MOVING;
- LadderState = LADDER_STATE_CLIMBING;
- assert(Path != NULL);
- assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
- Path->Get_Action_Destination (Destination);
- Path->Set_Movement_Directions (PathClass::MOVE_Z);
- } else {
- soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
- }
- break;
- case LADDER_STATE_CLIMBING:
- //
- // Have we finished climbing yet?
- //
- if (soldier->Is_On_Ladder () == false) {
- LadderState = LADDER_STATE_NONE;
- Set_Ladder_Occupant (LadderIndex, NULL);
- Set_Finished ();
- } else {
- //
- // Get the object's current position
- //
- Vector3 curr_pos;
- GameObj->Get_Position (&curr_pos);
- //
- // Is the object within a small distance of the destination?
- //
- float dist = WWMath::Fabs(curr_pos.Z - Destination.Z);
- if (dist < 0.25F) {
- //
- // Tell the object to get off the ladder (he may not be able to
- // if someone is blocking his way)
- //
- soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
- State = STATE_WAITING;
- }
- }
- break;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Handle_Jump
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Handle_Jump (void)
- {
- //
- // Is this a human?
- //
- SoldierGameObj *soldier_obj = GameObj->As_SoldierGameObj ();
- if (soldier_obj != NULL) {
- HumanPhysClass *human_phys = soldier_obj->Peek_Physical_Object ()->As_HumanPhysClass ();
- if (human_phys != NULL) {
- //
- // If we are still in the air, then turn to face
- // our destination point.
- //
- if (soldier_obj->Is_Airborne ()) {
- Vector3 dest(0,0,0);
- assert(Path != NULL);
- assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
- Path->Get_Action_Destination (dest);
- Vector3 face_pt = dest + Vector3 (0, 0, soldier_obj->Get_Bullseye_Offset_Z() );
- soldier_obj->Set_Targeting (face_pt, false);
- }
- //
- // Revert when we've finished landing
- //
- if ( human_phys->Has_Just_Jumped () == false &&
- soldier_obj->Get_Human_State ()->Get_State () == HumanStateClass::UPRIGHT)
- {
- Set_Finished ();
- }
- }
- } else {
- Set_Finished ();
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Handle_Elevator
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Handle_Elevator (void)
- {
- ElevatorPhysClass *elevator = Mechanism->As_ElevatorPhysClass ();
- WWASSERT (elevator != NULL);
- switch (ElevatorState)
- {
- case ELEVATOR_STATE_WAITING:
- //
- // Switch states if the elevator has arrived
- //
- if (elevator->Can_Object_Enter (GameObj)) {
- elevator->Set_Current_Rider (GameObj);
- ElevatorState = ELEVATOR_STATE_ENTERING;
- State = STATE_MOVING;
- //
- // Calculate where we want the unit to walk to in order
- // to enter the elevator
- //
- if (elevator->Get_Floor () == 0) {
- Get_Elevator_Zone_Pos (ZONE_LOWER_INSIDE, &Destination);
- Get_Elevator_Zone_Pos (ZONE_UPPER_CALL, &FacePos);
- } else {
- Get_Elevator_Zone_Pos (ZONE_UPPER_INSIDE, &Destination);
- Get_Elevator_Zone_Pos (ZONE_LOWER_CALL, &FacePos);
- }
- } else {
- elevator->Request_Elevator (GameObj);
- }
- break;
- case ELEVATOR_STATE_RIDING:
- //
- // Switch states if the elevator has arrived
- //
- if (elevator->Can_Object_Exit (GameObj)) {
- ElevatorState = ELEVATOR_STATE_EXITING;
- State = STATE_MOVING;
- Timer = 5.0F;
- assert(Path != NULL);
- assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
- Path->Get_Action_Destination (Destination);
- } else {
- //
- // Make the unit face the exit
- //
- GameObj->Set_Targeting (FacePos, false);
- }
- break;
- case ELEVATOR_STATE_ENTERING:
- //
- // Switch states if the elevator has started moving
- //
- if (elevator->Is_Moving ()) {
- ElevatorState = ELEVATOR_STATE_RIDING;
- State = STATE_WAITING;
- } else if (Has_Arrived ()) {
- //
- // Make the unit face the exit
- //
- GameObj->Set_Targeting (FacePos, false);
- State = STATE_WAITING;
- //
- // Make the elevator start moving
- //
- elevator->Request_Elevator (GameObj);
- }
- break;
- case ELEVATOR_STATE_EXITING:
- //
- // Has the unit made it through the elevator door, or has time expired?
- //
- Timer -= TimeManager::Get_Frame_Seconds ();
- if (Has_Arrived () || Timer <= 0) {
- //
- // Let the elevator know that its rider has left
- //
- if (elevator->Get_Current_Rider () == GameObj) {
- elevator->Set_Current_Rider (NULL);
- }
- //
- // Reset the state
- //
- ElevatorState = ELEVATOR_STATE_NONE;
- Set_Finished ();
- }
- break;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Handle_Door
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Handle_Door (void)
- {
- DoorPhysClass *door = Mechanism->As_DoorPhysClass ();
- WWASSERT (door != NULL);
- switch (DoorState)
- {
- case DOOR_STATE_GETTING_IN_POSITION:
- {
- //
- // Has the unit made it into position, or has time expired?
- //
- Timer -= TimeManager::Get_Frame_Seconds ();
- if (Has_Arrived () || Timer <= 0) {
- DoorState = DOOR_STATE_WAITING;
- State = STATE_WAITING;
- } else {
- State = STATE_MOVING;
- }
- break;
- }
- case DOOR_STATE_WAITING:
- //
- // Keep the door open for as long as we need it
- //
- door->Request_Door_Open ();
- //
- // If the door is opened, then move onto the next state
- //
- if (door->Is_Door_Open ()) {
- DoorState = DOOR_STATE_ENTERING;
- State = STATE_MOVING;
- Timer = 5.0F;
- assert(Path != NULL);
- assert(Path->Get_Path_Vector_Length() >= Path->Get_Path_Vector_Count());
- Path->Get_Action_Destination (Destination);
- }
- break;
- case DOOR_STATE_ENTERING:
- //
- // Has the unit made it through the door, or has time expired?
- //
- Timer -= TimeManager::Get_Frame_Seconds ();
- if (Has_Arrived () || Timer <= 0) {
- DoorState = DOOR_STATE_NONE;
- Set_Finished ();
- }
- break;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Has_Arrived
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- bool
- PathActionClass::Has_Arrived (void)
- {
- bool retval = false;
- //
- // Get the object's current position
- //
- Vector3 curr_pos;
- GameObj->Get_Position (&curr_pos);
- //
- // Is the object within a small distance of the destination?
- //
- Vector3 delta = curr_pos - Destination;
- delta.Z = 0;
- float dist2 = delta.Length2 ();
- if (dist2 < 0.0225F) {
- retval = true;
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Elevator_Zone_Pos
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Get_Elevator_Zone_Pos (ELEVATOR_ZONE zone_id, Vector3 *position)
- {
- WWASSERT (position != NULL);
- //
- // Make sure we have an elevator
- //
- ElevatorPhysClass *elevator = Mechanism->As_ElevatorPhysClass ();
- WWASSERT (elevator != NULL);
- //
- // Get information about this type of elevator
- //
- const ElevatorPhysDefClass *definition = elevator->Get_ElevatorPhysDef ();
- //
- // Transform the requested zone into world-space
- //
- const Matrix3D &tm = elevator->Get_Transform ();
- OBBoxClass zone_box;
- OBBoxClass::Transform (tm, definition->Get_Zone (zone_id), &zone_box);
- //
- // Return the center of the zone to the caller
- //
- (*position) = zone_box.Center;
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Save
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Save (ChunkSaveClass &csave)
- {
- csave.Begin_Chunk (CHUNKID_VARIABLES);
- //
- // Save each variable to its own microchunk
- //
- WRITE_MICRO_CHUNK (csave, VARID_ELEVATOR_STATE, ElevatorState);
- WRITE_MICRO_CHUNK (csave, VARID_DOOR_STATE, DoorState);
- WRITE_MICRO_CHUNK (csave, VARID_STATE, State);
- WRITE_MICRO_CHUNK (csave, VARID_TYPE, Type);
- WRITE_MICRO_CHUNK (csave, VARID_PATH_PTR, Path);
- WRITE_MICRO_CHUNK (csave, VARID_MECHANISM_PTR, Mechanism);
- WRITE_MICRO_CHUNK (csave, VARID_DESTINATION, Destination);
- WRITE_MICRO_CHUNK (csave, VARID_FACEPOS, FacePos);
- WRITE_MICRO_CHUNK (csave, VARID_GAME_OBJ_PTR, GameObj);
- WRITE_MICRO_CHUNK (csave, VARID_LADDER_STATE, LadderState);
- WRITE_MICRO_CHUNK (csave, VARID_LADDER_INDEX, LadderIndex);
- csave.End_Chunk ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Load
- //
- ////////////////////////////////////////////////////////////////////////////////////////////
- void
- PathActionClass::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
- PathActionClass::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_ELEVATOR_STATE, ElevatorState);
- READ_MICRO_CHUNK (cload, VARID_DOOR_STATE, DoorState);
- READ_MICRO_CHUNK (cload, VARID_STATE, State);
- READ_MICRO_CHUNK (cload, VARID_TYPE, Type);
- READ_MICRO_CHUNK (cload, VARID_PATH_PTR, Path);
- READ_MICRO_CHUNK (cload, VARID_MECHANISM_PTR, Mechanism);
- READ_MICRO_CHUNK (cload, VARID_DESTINATION, Destination);
- READ_MICRO_CHUNK (cload, VARID_FACEPOS, FacePos);
- READ_MICRO_CHUNK (cload, VARID_GAME_OBJ_PTR, GameObj);
- READ_MICRO_CHUNK (cload, VARID_LADDER_STATE, LadderState);
- READ_MICRO_CHUNK (cload, VARID_LADDER_INDEX, LadderIndex);
- }
- cload.Close_Micro_Chunk ();
- }
- //
- // Request that the mechanism ptr gets remapped
- //
- if (GameObj != NULL) {
- REQUEST_POINTER_REMAP ((void **)&GameObj);
- }
- //
- // Request that the mechanism ptr gets remapped
- //
- if (Mechanism != NULL) {
- REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&Mechanism);
- }
- //
- // Request that the path ptr gets remapped
- //
- if (Path != NULL) {
- REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&Path);
- }
- return ;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Set_Ladder_Occupant
- //
- ///////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Set_Ladder_Occupant (int ladder_index, ScriptableGameObj *object)
- {
- WWASSERT (ladder_index < 256);
- if (ladder_index < 0) {
- return ;
- }
- //
- // Grow the ladder list until it contains enough entries
- //
- while (ladder_index >= LadderList.Count ()) {
- LadderList.Add (NULL);
- }
- //
- // Fill in this slot in the list
- //
- LadderList[ladder_index] = object;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Get_Ladder_Occupant
- //
- ///////////////////////////////////////////////////////////////////////
- ScriptableGameObj *
- PathActionClass::Get_Ladder_Occupant (int ladder_index)
- {
- ScriptableGameObj *object = NULL;
- //
- // Return the object that's in this slot
- //
- if (ladder_index >= 0 && ladder_index < LadderList.Count ()) {
- object = LadderList[ladder_index];
- }
- return object;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Reset
- //
- ///////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Reset (void)
- {
- if (GameObj != NULL) {
-
- //
- // Check to see if this unit is "reserving" any of the ladders...
- //
- for (int index = 0; index < LadderList.Count (); index ++) {
- if (LadderList[index] == GameObj) {
-
- //
- // Clear the ladder reservation
- //
- LadderList[index] = NULL;
- break;
- }
- }
- }
- GameObj = NULL;
- Mechanism = NULL;
- Path = NULL;
- State = STATE_FINISHED;
- Type = TYPE_UNKNOWN;
- return ;
- }
- ///////////////////////////////////////////////////////////////////////
- //
- // Set_Finished
- //
- ///////////////////////////////////////////////////////////////////////
- void
- PathActionClass::Set_Finished (void)
- {
- State = STATE_FINISHED;
- Reset ();
- return ;
- }
|