pathaction.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/pathaction.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 11/16/01 1:51p $*
  29. * *
  30. * $Revision:: 18 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "pathaction.h"
  36. #include "smartgameobj.h"
  37. #include "soldier.h"
  38. #include "doors.h"
  39. #include "humanphys.h"
  40. #include "obbox.h"
  41. #include "path.h"
  42. #include "chunkio.h"
  43. #include "saveload.h"
  44. ////////////////////////////////////////////////////////////////
  45. // Save/Load constants
  46. ////////////////////////////////////////////////////////////////
  47. enum
  48. {
  49. CHUNKID_GAMEOBJ_REF = 0x11020954,
  50. CHUNKID_VARIABLES
  51. };
  52. enum
  53. {
  54. VARID_ELEVATOR_STATE = 0,
  55. VARID_DOOR_STATE,
  56. VARID_STATE,
  57. VARID_TYPE,
  58. VARID_PATH_PTR,
  59. VARID_MECHANISM_PTR,
  60. VARID_DESTINATION,
  61. VARID_FACEPOS,
  62. VARID_GAME_OBJ_PTR,
  63. VARID_LADDER_STATE,
  64. VARID_LADDER_INDEX
  65. };
  66. ////////////////////////////////////////////////////////////////
  67. // Static member initialization
  68. ////////////////////////////////////////////////////////////////
  69. DynamicVectorClass<GameObjReference> PathActionClass::LadderList;
  70. ////////////////////////////////////////////////////////////////////////////////////////////
  71. //
  72. // PathActionClass
  73. //
  74. ////////////////////////////////////////////////////////////////////////////////////////////
  75. PathActionClass::PathActionClass (void) :
  76. ElevatorState (ELEVATOR_STATE_NONE),
  77. DoorState (DOOR_STATE_NONE),
  78. LadderState (LADDER_STATE_NONE),
  79. State (STATE_FINISHED),
  80. Type (TYPE_UNKNOWN),
  81. Mechanism (NULL),
  82. GameObj (NULL),
  83. Path (NULL),
  84. LadderIndex (-1),
  85. Destination (0, 0, 0),
  86. FacePos (0, 0, 0),
  87. Timer (0)
  88. {
  89. return ;
  90. }
  91. ////////////////////////////////////////////////////////////////////////////////////////////
  92. //
  93. // ~PathActionClass
  94. //
  95. ////////////////////////////////////////////////////////////////////////////////////////////
  96. PathActionClass::~PathActionClass (void)
  97. {
  98. return ;
  99. }
  100. ////////////////////////////////////////////////////////////////////////////////////////////
  101. //
  102. // Initialize
  103. //
  104. ////////////////////////////////////////////////////////////////////////////////////////////
  105. void
  106. PathActionClass::Initialize
  107. (
  108. TYPE type,
  109. PathClass * path,
  110. SmartGameObj * game_obj,
  111. StaticPhysClass * mechanism
  112. )
  113. {
  114. Type = type;
  115. GameObj = game_obj;
  116. Mechanism = mechanism;
  117. Path = path;
  118. //
  119. // Reset the states
  120. //
  121. State = STATE_WAITING;
  122. ElevatorState = ELEVATOR_STATE_WAITING;
  123. DoorState = DOOR_STATE_GETTING_IN_POSITION;
  124. LadderState = LADDER_STATE_WAITING;
  125. Timer = 5;
  126. assert(Path != NULL);
  127. assert(Path->Get_Path_Vector_Length() >= Path->Get_Path_Vector_Count());
  128. Path->Get_Action_Entrance (Destination);
  129. return ;
  130. }
  131. ////////////////////////////////////////////////////////////////////////////////////////////
  132. //
  133. // Process
  134. //
  135. ////////////////////////////////////////////////////////////////////////////////////////////
  136. bool
  137. PathActionClass::Process (void)
  138. {
  139. switch (Type)
  140. {
  141. case TYPE_JUMPING:
  142. Handle_Jump ();
  143. break;
  144. case TYPE_LADDER:
  145. Handle_Ladder ();
  146. break;
  147. case TYPE_ELEVATOR:
  148. Handle_Elevator ();
  149. break;
  150. case TYPE_DOOR:
  151. Handle_Door ();
  152. break;
  153. default:
  154. Set_Finished ();
  155. break;
  156. }
  157. return (State == STATE_FINISHED);
  158. }
  159. ////////////////////////////////////////////////////////////////////////////////////////////
  160. //
  161. // Handle_Ladder
  162. //
  163. ////////////////////////////////////////////////////////////////////////////////////////////
  164. void
  165. PathActionClass::Handle_Ladder (void)
  166. {
  167. SoldierGameObj *soldier = GameObj->As_SoldierGameObj ();
  168. WWASSERT (soldier != NULL);
  169. switch (LadderState)
  170. {
  171. case LADDER_STATE_WAITING:
  172. {
  173. //
  174. // Is there already someone on the ladder?
  175. //
  176. if (Get_Ladder_Occupant (LadderIndex) == NULL) {
  177. Set_Ladder_Occupant (LadderIndex, GameObj);
  178. //
  179. // Get on the ladder
  180. //
  181. soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
  182. LadderState = LADDER_STATE_GETTING_ON;
  183. }
  184. break;
  185. }
  186. case LADDER_STATE_GETTING_ON:
  187. //
  188. // Have we gotten on yet?
  189. //
  190. if (soldier->Is_On_Ladder ()) {
  191. //
  192. // Start climbing
  193. //
  194. State = STATE_MOVING;
  195. LadderState = LADDER_STATE_CLIMBING;
  196. assert(Path != NULL);
  197. assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
  198. Path->Get_Action_Destination (Destination);
  199. Path->Set_Movement_Directions (PathClass::MOVE_Z);
  200. } else {
  201. soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
  202. }
  203. break;
  204. case LADDER_STATE_CLIMBING:
  205. //
  206. // Have we finished climbing yet?
  207. //
  208. if (soldier->Is_On_Ladder () == false) {
  209. LadderState = LADDER_STATE_NONE;
  210. Set_Ladder_Occupant (LadderIndex, NULL);
  211. Set_Finished ();
  212. } else {
  213. //
  214. // Get the object's current position
  215. //
  216. Vector3 curr_pos;
  217. GameObj->Get_Position (&curr_pos);
  218. //
  219. // Is the object within a small distance of the destination?
  220. //
  221. float dist = WWMath::Fabs(curr_pos.Z - Destination.Z);
  222. if (dist < 0.25F) {
  223. //
  224. // Tell the object to get off the ladder (he may not be able to
  225. // if someone is blocking his way)
  226. //
  227. soldier->Set_Boolean_Control (ControlClass::BOOLEAN_ACTION);
  228. State = STATE_WAITING;
  229. }
  230. }
  231. break;
  232. }
  233. return ;
  234. }
  235. ////////////////////////////////////////////////////////////////////////////////////////////
  236. //
  237. // Handle_Jump
  238. //
  239. ////////////////////////////////////////////////////////////////////////////////////////////
  240. void
  241. PathActionClass::Handle_Jump (void)
  242. {
  243. //
  244. // Is this a human?
  245. //
  246. SoldierGameObj *soldier_obj = GameObj->As_SoldierGameObj ();
  247. if (soldier_obj != NULL) {
  248. HumanPhysClass *human_phys = soldier_obj->Peek_Physical_Object ()->As_HumanPhysClass ();
  249. if (human_phys != NULL) {
  250. //
  251. // If we are still in the air, then turn to face
  252. // our destination point.
  253. //
  254. if (soldier_obj->Is_Airborne ()) {
  255. Vector3 dest(0,0,0);
  256. assert(Path != NULL);
  257. assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
  258. Path->Get_Action_Destination (dest);
  259. Vector3 face_pt = dest + Vector3 (0, 0, soldier_obj->Get_Bullseye_Offset_Z() );
  260. soldier_obj->Set_Targeting (face_pt, false);
  261. }
  262. //
  263. // Revert when we've finished landing
  264. //
  265. if ( human_phys->Has_Just_Jumped () == false &&
  266. soldier_obj->Get_Human_State ()->Get_State () == HumanStateClass::UPRIGHT)
  267. {
  268. Set_Finished ();
  269. }
  270. }
  271. } else {
  272. Set_Finished ();
  273. }
  274. return ;
  275. }
  276. ////////////////////////////////////////////////////////////////////////////////////////////
  277. //
  278. // Handle_Elevator
  279. //
  280. ////////////////////////////////////////////////////////////////////////////////////////////
  281. void
  282. PathActionClass::Handle_Elevator (void)
  283. {
  284. ElevatorPhysClass *elevator = Mechanism->As_ElevatorPhysClass ();
  285. WWASSERT (elevator != NULL);
  286. switch (ElevatorState)
  287. {
  288. case ELEVATOR_STATE_WAITING:
  289. //
  290. // Switch states if the elevator has arrived
  291. //
  292. if (elevator->Can_Object_Enter (GameObj)) {
  293. elevator->Set_Current_Rider (GameObj);
  294. ElevatorState = ELEVATOR_STATE_ENTERING;
  295. State = STATE_MOVING;
  296. //
  297. // Calculate where we want the unit to walk to in order
  298. // to enter the elevator
  299. //
  300. if (elevator->Get_Floor () == 0) {
  301. Get_Elevator_Zone_Pos (ZONE_LOWER_INSIDE, &Destination);
  302. Get_Elevator_Zone_Pos (ZONE_UPPER_CALL, &FacePos);
  303. } else {
  304. Get_Elevator_Zone_Pos (ZONE_UPPER_INSIDE, &Destination);
  305. Get_Elevator_Zone_Pos (ZONE_LOWER_CALL, &FacePos);
  306. }
  307. } else {
  308. elevator->Request_Elevator (GameObj);
  309. }
  310. break;
  311. case ELEVATOR_STATE_RIDING:
  312. //
  313. // Switch states if the elevator has arrived
  314. //
  315. if (elevator->Can_Object_Exit (GameObj)) {
  316. ElevatorState = ELEVATOR_STATE_EXITING;
  317. State = STATE_MOVING;
  318. Timer = 5.0F;
  319. assert(Path != NULL);
  320. assert(Path->Get_Path_Vector_Length() > Path->Get_Path_Vector_Count());
  321. Path->Get_Action_Destination (Destination);
  322. } else {
  323. //
  324. // Make the unit face the exit
  325. //
  326. GameObj->Set_Targeting (FacePos, false);
  327. }
  328. break;
  329. case ELEVATOR_STATE_ENTERING:
  330. //
  331. // Switch states if the elevator has started moving
  332. //
  333. if (elevator->Is_Moving ()) {
  334. ElevatorState = ELEVATOR_STATE_RIDING;
  335. State = STATE_WAITING;
  336. } else if (Has_Arrived ()) {
  337. //
  338. // Make the unit face the exit
  339. //
  340. GameObj->Set_Targeting (FacePos, false);
  341. State = STATE_WAITING;
  342. //
  343. // Make the elevator start moving
  344. //
  345. elevator->Request_Elevator (GameObj);
  346. }
  347. break;
  348. case ELEVATOR_STATE_EXITING:
  349. //
  350. // Has the unit made it through the elevator door, or has time expired?
  351. //
  352. Timer -= TimeManager::Get_Frame_Seconds ();
  353. if (Has_Arrived () || Timer <= 0) {
  354. //
  355. // Let the elevator know that its rider has left
  356. //
  357. if (elevator->Get_Current_Rider () == GameObj) {
  358. elevator->Set_Current_Rider (NULL);
  359. }
  360. //
  361. // Reset the state
  362. //
  363. ElevatorState = ELEVATOR_STATE_NONE;
  364. Set_Finished ();
  365. }
  366. break;
  367. }
  368. return ;
  369. }
  370. ////////////////////////////////////////////////////////////////////////////////////////////
  371. //
  372. // Handle_Door
  373. //
  374. ////////////////////////////////////////////////////////////////////////////////////////////
  375. void
  376. PathActionClass::Handle_Door (void)
  377. {
  378. DoorPhysClass *door = Mechanism->As_DoorPhysClass ();
  379. WWASSERT (door != NULL);
  380. switch (DoorState)
  381. {
  382. case DOOR_STATE_GETTING_IN_POSITION:
  383. {
  384. //
  385. // Has the unit made it into position, or has time expired?
  386. //
  387. Timer -= TimeManager::Get_Frame_Seconds ();
  388. if (Has_Arrived () || Timer <= 0) {
  389. DoorState = DOOR_STATE_WAITING;
  390. State = STATE_WAITING;
  391. } else {
  392. State = STATE_MOVING;
  393. }
  394. break;
  395. }
  396. case DOOR_STATE_WAITING:
  397. //
  398. // Keep the door open for as long as we need it
  399. //
  400. door->Request_Door_Open ();
  401. //
  402. // If the door is opened, then move onto the next state
  403. //
  404. if (door->Is_Door_Open ()) {
  405. DoorState = DOOR_STATE_ENTERING;
  406. State = STATE_MOVING;
  407. Timer = 5.0F;
  408. assert(Path != NULL);
  409. assert(Path->Get_Path_Vector_Length() >= Path->Get_Path_Vector_Count());
  410. Path->Get_Action_Destination (Destination);
  411. }
  412. break;
  413. case DOOR_STATE_ENTERING:
  414. //
  415. // Has the unit made it through the door, or has time expired?
  416. //
  417. Timer -= TimeManager::Get_Frame_Seconds ();
  418. if (Has_Arrived () || Timer <= 0) {
  419. DoorState = DOOR_STATE_NONE;
  420. Set_Finished ();
  421. }
  422. break;
  423. }
  424. return ;
  425. }
  426. ////////////////////////////////////////////////////////////////////////////////////////////
  427. //
  428. // Has_Arrived
  429. //
  430. ////////////////////////////////////////////////////////////////////////////////////////////
  431. bool
  432. PathActionClass::Has_Arrived (void)
  433. {
  434. bool retval = false;
  435. //
  436. // Get the object's current position
  437. //
  438. Vector3 curr_pos;
  439. GameObj->Get_Position (&curr_pos);
  440. //
  441. // Is the object within a small distance of the destination?
  442. //
  443. Vector3 delta = curr_pos - Destination;
  444. delta.Z = 0;
  445. float dist2 = delta.Length2 ();
  446. if (dist2 < 0.0225F) {
  447. retval = true;
  448. }
  449. return retval;
  450. }
  451. ////////////////////////////////////////////////////////////////////////////////////////////
  452. //
  453. // Get_Elevator_Zone_Pos
  454. //
  455. ////////////////////////////////////////////////////////////////////////////////////////////
  456. void
  457. PathActionClass::Get_Elevator_Zone_Pos (ELEVATOR_ZONE zone_id, Vector3 *position)
  458. {
  459. WWASSERT (position != NULL);
  460. //
  461. // Make sure we have an elevator
  462. //
  463. ElevatorPhysClass *elevator = Mechanism->As_ElevatorPhysClass ();
  464. WWASSERT (elevator != NULL);
  465. //
  466. // Get information about this type of elevator
  467. //
  468. const ElevatorPhysDefClass *definition = elevator->Get_ElevatorPhysDef ();
  469. //
  470. // Transform the requested zone into world-space
  471. //
  472. const Matrix3D &tm = elevator->Get_Transform ();
  473. OBBoxClass zone_box;
  474. OBBoxClass::Transform (tm, definition->Get_Zone (zone_id), &zone_box);
  475. //
  476. // Return the center of the zone to the caller
  477. //
  478. (*position) = zone_box.Center;
  479. return ;
  480. }
  481. ////////////////////////////////////////////////////////////////////////////////////////////
  482. //
  483. // Save
  484. //
  485. ////////////////////////////////////////////////////////////////////////////////////////////
  486. void
  487. PathActionClass::Save (ChunkSaveClass &csave)
  488. {
  489. csave.Begin_Chunk (CHUNKID_VARIABLES);
  490. //
  491. // Save each variable to its own microchunk
  492. //
  493. WRITE_MICRO_CHUNK (csave, VARID_ELEVATOR_STATE, ElevatorState);
  494. WRITE_MICRO_CHUNK (csave, VARID_DOOR_STATE, DoorState);
  495. WRITE_MICRO_CHUNK (csave, VARID_STATE, State);
  496. WRITE_MICRO_CHUNK (csave, VARID_TYPE, Type);
  497. WRITE_MICRO_CHUNK (csave, VARID_PATH_PTR, Path);
  498. WRITE_MICRO_CHUNK (csave, VARID_MECHANISM_PTR, Mechanism);
  499. WRITE_MICRO_CHUNK (csave, VARID_DESTINATION, Destination);
  500. WRITE_MICRO_CHUNK (csave, VARID_FACEPOS, FacePos);
  501. WRITE_MICRO_CHUNK (csave, VARID_GAME_OBJ_PTR, GameObj);
  502. WRITE_MICRO_CHUNK (csave, VARID_LADDER_STATE, LadderState);
  503. WRITE_MICRO_CHUNK (csave, VARID_LADDER_INDEX, LadderIndex);
  504. csave.End_Chunk ();
  505. return ;
  506. }
  507. ////////////////////////////////////////////////////////////////////////////////////////////
  508. //
  509. // Load
  510. //
  511. ////////////////////////////////////////////////////////////////////////////////////////////
  512. void
  513. PathActionClass::Load (ChunkLoadClass &cload)
  514. {
  515. while (cload.Open_Chunk ()) {
  516. switch (cload.Cur_Chunk_ID ()) {
  517. case CHUNKID_VARIABLES:
  518. Load_Variables (cload);
  519. break;
  520. }
  521. cload.Close_Chunk ();
  522. }
  523. return ;
  524. }
  525. ///////////////////////////////////////////////////////////////////////
  526. //
  527. // Load_Variables
  528. //
  529. ///////////////////////////////////////////////////////////////////////
  530. void
  531. PathActionClass::Load_Variables (ChunkLoadClass &cload)
  532. {
  533. //
  534. // Loop through all the microchunks that define the variables
  535. //
  536. while (cload.Open_Micro_Chunk ()) {
  537. switch (cload.Cur_Micro_Chunk_ID ()) {
  538. READ_MICRO_CHUNK (cload, VARID_ELEVATOR_STATE, ElevatorState);
  539. READ_MICRO_CHUNK (cload, VARID_DOOR_STATE, DoorState);
  540. READ_MICRO_CHUNK (cload, VARID_STATE, State);
  541. READ_MICRO_CHUNK (cload, VARID_TYPE, Type);
  542. READ_MICRO_CHUNK (cload, VARID_PATH_PTR, Path);
  543. READ_MICRO_CHUNK (cload, VARID_MECHANISM_PTR, Mechanism);
  544. READ_MICRO_CHUNK (cload, VARID_DESTINATION, Destination);
  545. READ_MICRO_CHUNK (cload, VARID_FACEPOS, FacePos);
  546. READ_MICRO_CHUNK (cload, VARID_GAME_OBJ_PTR, GameObj);
  547. READ_MICRO_CHUNK (cload, VARID_LADDER_STATE, LadderState);
  548. READ_MICRO_CHUNK (cload, VARID_LADDER_INDEX, LadderIndex);
  549. }
  550. cload.Close_Micro_Chunk ();
  551. }
  552. //
  553. // Request that the mechanism ptr gets remapped
  554. //
  555. if (GameObj != NULL) {
  556. REQUEST_POINTER_REMAP ((void **)&GameObj);
  557. }
  558. //
  559. // Request that the mechanism ptr gets remapped
  560. //
  561. if (Mechanism != NULL) {
  562. REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&Mechanism);
  563. }
  564. //
  565. // Request that the path ptr gets remapped
  566. //
  567. if (Path != NULL) {
  568. REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&Path);
  569. }
  570. return ;
  571. }
  572. ///////////////////////////////////////////////////////////////////////
  573. //
  574. // Set_Ladder_Occupant
  575. //
  576. ///////////////////////////////////////////////////////////////////////
  577. void
  578. PathActionClass::Set_Ladder_Occupant (int ladder_index, ScriptableGameObj *object)
  579. {
  580. WWASSERT (ladder_index < 256);
  581. if (ladder_index < 0) {
  582. return ;
  583. }
  584. //
  585. // Grow the ladder list until it contains enough entries
  586. //
  587. while (ladder_index >= LadderList.Count ()) {
  588. LadderList.Add (NULL);
  589. }
  590. //
  591. // Fill in this slot in the list
  592. //
  593. LadderList[ladder_index] = object;
  594. return ;
  595. }
  596. ///////////////////////////////////////////////////////////////////////
  597. //
  598. // Get_Ladder_Occupant
  599. //
  600. ///////////////////////////////////////////////////////////////////////
  601. ScriptableGameObj *
  602. PathActionClass::Get_Ladder_Occupant (int ladder_index)
  603. {
  604. ScriptableGameObj *object = NULL;
  605. //
  606. // Return the object that's in this slot
  607. //
  608. if (ladder_index >= 0 && ladder_index < LadderList.Count ()) {
  609. object = LadderList[ladder_index];
  610. }
  611. return object;
  612. }
  613. ///////////////////////////////////////////////////////////////////////
  614. //
  615. // Reset
  616. //
  617. ///////////////////////////////////////////////////////////////////////
  618. void
  619. PathActionClass::Reset (void)
  620. {
  621. if (GameObj != NULL) {
  622. //
  623. // Check to see if this unit is "reserving" any of the ladders...
  624. //
  625. for (int index = 0; index < LadderList.Count (); index ++) {
  626. if (LadderList[index] == GameObj) {
  627. //
  628. // Clear the ladder reservation
  629. //
  630. LadderList[index] = NULL;
  631. break;
  632. }
  633. }
  634. }
  635. GameObj = NULL;
  636. Mechanism = NULL;
  637. Path = NULL;
  638. State = STATE_FINISHED;
  639. Type = TYPE_UNKNOWN;
  640. return ;
  641. }
  642. ///////////////////////////////////////////////////////////////////////
  643. //
  644. // Set_Finished
  645. //
  646. ///////////////////////////////////////////////////////////////////////
  647. void
  648. PathActionClass::Set_Finished (void)
  649. {
  650. State = STATE_FINISHED;
  651. Reset ();
  652. return ;
  653. }