elevator.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/elevator.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 9/13/01 12:03p $*
  29. * *
  30. * $Revision:: 25 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "elevator.h"
  36. #include "simpledefinitionfactory.h"
  37. #include "persistfactory.h"
  38. #include "wwphysids.h"
  39. #include "bitstream.h"
  40. #include "debug.h"
  41. #include "hanim.h"
  42. #include "wwhack.h"
  43. #include "combat.h"
  44. #include "smartgameobj.h"
  45. #include "gameobjmanager.h"
  46. #include "soldier.h"
  47. #include "wwprofile.h"
  48. #include "audiblesound.h"
  49. #include "wwaudio.h"
  50. #include "bitpackids.h"
  51. DECLARE_FORCE_LINK( elevatorphys );
  52. /*
  53. ** Local constants
  54. */
  55. enum
  56. {
  57. EFFECT_DOOR_OPENING,
  58. EFFECT_DOOR_CLOSING,
  59. EFFECT_DOOR_UNLOCKED,
  60. EFFECT_ACCESS_DENIED,
  61. EFFECT_ELEVATOR_MOVING,
  62. EFFECT_ELEVATOR_STOPPED_MOVING,
  63. };
  64. /*
  65. ** ElevatorPhysDefClass
  66. */
  67. SimplePersistFactoryClass<ElevatorPhysDefClass, PHYSICS_CHUNKID_ELEVATORPHYSDEF> _ElevatorPhysDefPersistFactory;
  68. DECLARE_DEFINITION_FACTORY(ElevatorPhysDefClass, CLASSID_ELEVATORPHYSDEF, "ElevatorPhys") _ElevatorPhysDefDefFactory;
  69. ElevatorPhysDefClass::ElevatorPhysDefClass( void ) :
  70. AccessiblePhysDefClass(),
  71. CloseDelay( 2 ),
  72. /*LowerCallZone( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
  73. LowerInsideZone( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
  74. UpperCallZone( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
  75. UpperInsideZone( Vector3( 0,0,0), Vector3( 1,1,1 ) ),*/
  76. DoorClosedTop_FrameNum( -1 ),
  77. DoorOpeningBottom_FrameNum( -1 ),
  78. ElevatorStartTop_FrameNum( -1 ),
  79. ElevatorStoppedBottom_FrameNum( -1 ),
  80. DoorOpenSoundDefID( 0 ),
  81. DoorCloseSoundDefID( 0 ),
  82. DoorUnlockSoundDefID( 0 ),
  83. DoorAccessDeniedSoundDefID( 0 ),
  84. ElevatorMovingSoundDefID( 0 )
  85. {
  86. for (int index = 0; index < ZONE_MAX; index ++) {
  87. CallZones[index].Center = Vector3( 0, 0, 0 );
  88. CallZones[index].Extent = Vector3( 1, 1, 1 );
  89. }
  90. ZONE_PARAM(ElevatorPhysDefClass, CallZones[ZONE_LOWER_CALL], "LowerCallZone" );
  91. ZONE_PARAM(ElevatorPhysDefClass, CallZones[ZONE_LOWER_INSIDE], "LowerInsideZone" );
  92. ZONE_PARAM(ElevatorPhysDefClass, CallZones[ZONE_UPPER_CALL], "UpperCallZone" );
  93. ZONE_PARAM(ElevatorPhysDefClass, CallZones[ZONE_UPPER_INSIDE], "UpperInsideZone" );
  94. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_FLOAT, CloseDelay );
  95. PARAM_SEPARATOR(ElevatorPhysDefClass, "Frame Numbers");
  96. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_FLOAT, DoorClosedTop_FrameNum );
  97. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_FLOAT, DoorOpeningBottom_FrameNum );
  98. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_FLOAT, ElevatorStartTop_FrameNum );
  99. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_FLOAT, ElevatorStoppedBottom_FrameNum );
  100. PARAM_SEPARATOR(ElevatorPhysDefClass, "Sounds");
  101. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, DoorOpenSoundDefID );
  102. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, DoorCloseSoundDefID );
  103. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, DoorUnlockSoundDefID );
  104. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, DoorAccessDeniedSoundDefID );
  105. EDITABLE_PARAM(ElevatorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, ElevatorMovingSoundDefID );
  106. }
  107. uint32 ElevatorPhysDefClass::Get_Class_ID (void) const
  108. {
  109. return CLASSID_ELEVATORPHYSDEF;
  110. }
  111. bool ElevatorPhysDefClass::Is_Type(const char * type_name)
  112. {
  113. if (stricmp(type_name,ElevatorPhysDefClass::Get_Type_Name()) == 0) {
  114. return true;
  115. } else {
  116. return AccessiblePhysDefClass::Is_Type(type_name);
  117. }
  118. }
  119. PersistClass * ElevatorPhysDefClass::Create( void ) const
  120. {
  121. ElevatorPhysClass * elevator = new ElevatorPhysClass;
  122. elevator->Init( *this );
  123. return elevator;
  124. }
  125. enum {
  126. CHUNKID_DEF_OLD_PARENT = 714001418,
  127. CHUNKID_DEF_VARIABLES,
  128. CHUNKID_DEF_PARENT,
  129. MICROCHUNKID_DEF_CLOSE_DELAY = 1,
  130. MICROCHUNKID_DEF_LOCK_CODE,
  131. MICROCHUNKID_DEF_UPPER_CALL_ZONE,
  132. MICROCHUNKID_DEF_UPPER_INSIDE_ZONE,
  133. MICROCHUNKID_DEF_LOWER_CALL_ZONE,
  134. MICROCHUNKID_DEF_LOWER_INSIDE_ZONE,
  135. MICROCHUNKID_DEF_DOORCLOSED_FRAMENUM,
  136. MICROCHUNKID_DEF_DOOROPENING_FRAMENUM,
  137. MICROCHUNKID_DEF_ELEVATOR_START_FRAMENUM,
  138. MICROCHUNKID_DEF_ELEVATOR_STOPPED_FRAMENUM,
  139. MICROCHUNKID_DEF_DOOR_OPEN_SOUNDID,
  140. MICROCHUNKID_DEF_DOOR_CLOSE_SOUNDID,
  141. MICROCHUNKID_DEF_DOOR_UNLOCK_SOUNDID,
  142. MICROCHUNKID_DEF_DOOR_ACCESS_DENIED_SOUNDID,
  143. MICROCHUNKID_DEF_ELEVATOR_MOVING_SOUNDID
  144. };
  145. bool ElevatorPhysDefClass::Save( ChunkSaveClass & csave )
  146. {
  147. csave.Begin_Chunk( CHUNKID_DEF_PARENT );
  148. AccessiblePhysDefClass::Save( csave );
  149. csave.End_Chunk();
  150. csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
  151. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
  152. //WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_LOCK_CODE, LockCode );
  153. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_LOWER_CALL_ZONE, CallZones[ZONE_LOWER_CALL] );
  154. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_LOWER_INSIDE_ZONE, CallZones[ZONE_LOWER_INSIDE] );
  155. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_UPPER_CALL_ZONE, CallZones[ZONE_UPPER_CALL] );
  156. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_UPPER_INSIDE_ZONE, CallZones[ZONE_UPPER_INSIDE] );
  157. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOORCLOSED_FRAMENUM, DoorClosedTop_FrameNum );
  158. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOROPENING_FRAMENUM, DoorOpeningBottom_FrameNum );
  159. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ELEVATOR_START_FRAMENUM, ElevatorStartTop_FrameNum );
  160. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ELEVATOR_STOPPED_FRAMENUM, ElevatorStoppedBottom_FrameNum );
  161. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_OPEN_SOUNDID, DoorOpenSoundDefID );
  162. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_CLOSE_SOUNDID, DoorCloseSoundDefID );
  163. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_UNLOCK_SOUNDID, DoorUnlockSoundDefID );
  164. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_ACCESS_DENIED_SOUNDID, DoorAccessDeniedSoundDefID );
  165. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ELEVATOR_MOVING_SOUNDID, ElevatorMovingSoundDefID );
  166. csave.End_Chunk();
  167. return true;
  168. }
  169. bool ElevatorPhysDefClass::Load( ChunkLoadClass &cload )
  170. {
  171. while (cload.Open_Chunk()) {
  172. switch(cload.Cur_Chunk_ID()) {
  173. case CHUNKID_DEF_OLD_PARENT:
  174. StaticAnimPhysDefClass::Load( cload );
  175. break;
  176. case CHUNKID_DEF_PARENT:
  177. AccessiblePhysDefClass::Load( cload );
  178. break;
  179. case CHUNKID_DEF_VARIABLES:
  180. while (cload.Open_Micro_Chunk()) {
  181. switch(cload.Cur_Micro_Chunk_ID()) {
  182. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
  183. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_LOCK_CODE, LockCode );
  184. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_LOWER_CALL_ZONE, CallZones[ZONE_LOWER_CALL] );
  185. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_LOWER_INSIDE_ZONE, CallZones[ZONE_LOWER_INSIDE] );
  186. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_UPPER_CALL_ZONE, CallZones[ZONE_UPPER_CALL] );
  187. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_UPPER_INSIDE_ZONE, CallZones[ZONE_UPPER_INSIDE] );
  188. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOORCLOSED_FRAMENUM, DoorClosedTop_FrameNum );
  189. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOROPENING_FRAMENUM, DoorOpeningBottom_FrameNum );
  190. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ELEVATOR_START_FRAMENUM, ElevatorStartTop_FrameNum );
  191. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ELEVATOR_STOPPED_FRAMENUM, ElevatorStoppedBottom_FrameNum );
  192. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_OPEN_SOUNDID, DoorOpenSoundDefID );
  193. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_CLOSE_SOUNDID, DoorCloseSoundDefID );
  194. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_UNLOCK_SOUNDID, DoorUnlockSoundDefID );
  195. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_ACCESS_DENIED_SOUNDID, DoorAccessDeniedSoundDefID );
  196. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ELEVATOR_MOVING_SOUNDID, ElevatorMovingSoundDefID );
  197. default:
  198. Debug_Say(( "Unrecognized ElevatorPhys Variable chunkID\n" ));
  199. break;
  200. }
  201. cload.Close_Micro_Chunk();
  202. }
  203. break;
  204. default:
  205. Debug_Say(( "Unrecognized ElevatorPhys chunkID\n" ));
  206. break;
  207. }
  208. cload.Close_Chunk();
  209. }
  210. return true;
  211. }
  212. const PersistFactoryClass & ElevatorPhysDefClass::Get_Factory (void) const
  213. {
  214. return _ElevatorPhysDefPersistFactory;
  215. }
  216. /*
  217. **
  218. */
  219. SimplePersistFactoryClass<ElevatorPhysClass, PHYSICS_CHUNKID_ELEVATORPHYS> _ElevatorPhysPersistFactory;
  220. const PersistFactoryClass & ElevatorPhysClass::Get_Factory (void) const
  221. {
  222. return _ElevatorPhysPersistFactory;
  223. }
  224. /*
  225. **
  226. */
  227. ElevatorPhysClass::ElevatorPhysClass( void ) :
  228. CheckTimer( 0 ),
  229. State( STATE_UP ),
  230. MovingSoundObj( NULL ),
  231. PrevFrame( 0 ),
  232. IsCallTimerSet( false ),
  233. CallTimer( 0 ),
  234. TriggerRequest( 0 )
  235. {
  236. DoorStates[TOP] = DOOR_STATE_NORMAL;
  237. DoorStates[BOTTOM] = DOOR_STATE_NORMAL;
  238. }
  239. ElevatorPhysClass::~ElevatorPhysClass( void )
  240. {
  241. if ( MovingSoundObj != NULL ) {
  242. MovingSoundObj->Stop();
  243. MovingSoundObj->Remove_From_Scene();
  244. REF_PTR_RELEASE( MovingSoundObj );
  245. }
  246. }
  247. void ElevatorPhysClass::Init( const ElevatorPhysDefClass & def )
  248. {
  249. AccessiblePhysClass::Init(def);
  250. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  251. AnimManager.Set_Target_Frame( 0 );
  252. }
  253. /*
  254. ** Save and Load
  255. */
  256. enum {
  257. CHUNKID_PARENT = 714001438,
  258. CHUNKID_VARIABLES,
  259. CHUNKID_RIDER_OBJECT,
  260. MICROCHUNKID_ = 1,
  261. MICROCHUNKID_STATE,
  262. MICROCHUNKID_TOP_DOOR_STATE,
  263. MICROCHUNKID_BOTTOM_DOOR_STATE
  264. };
  265. bool ElevatorPhysClass::Save( ChunkSaveClass & csave )
  266. {
  267. csave.Begin_Chunk( CHUNKID_PARENT );
  268. AccessiblePhysClass::Save( csave );
  269. csave.End_Chunk();
  270. csave.Begin_Chunk( CHUNKID_VARIABLES );
  271. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
  272. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TOP_DOOR_STATE, DoorStates[TOP] );
  273. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_BOTTOM_DOOR_STATE, DoorStates[BOTTOM] );
  274. csave.End_Chunk();
  275. if ( CurrentAIRider != NULL ) {
  276. csave.Begin_Chunk( CHUNKID_RIDER_OBJECT );
  277. CurrentAIRider.Save( csave );
  278. csave.End_Chunk();
  279. }
  280. return true;
  281. }
  282. bool ElevatorPhysClass::Load( ChunkLoadClass &cload )
  283. {
  284. while (cload.Open_Chunk()) {
  285. switch(cload.Cur_Chunk_ID()) {
  286. case CHUNKID_PARENT:
  287. AccessiblePhysClass::Load( cload );
  288. break;
  289. case CHUNKID_RIDER_OBJECT:
  290. CurrentAIRider.Load( cload );
  291. break;
  292. case CHUNKID_VARIABLES:
  293. while (cload.Open_Micro_Chunk()) {
  294. switch(cload.Cur_Micro_Chunk_ID()) {
  295. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
  296. READ_MICRO_CHUNK( cload, MICROCHUNKID_TOP_DOOR_STATE, DoorStates[TOP] );
  297. READ_MICRO_CHUNK( cload, MICROCHUNKID_BOTTOM_DOOR_STATE, DoorStates[BOTTOM] );
  298. default:
  299. Debug_Say(( "Unrecognized ElevatorPhys Variable chunkID\n" ));
  300. break;
  301. }
  302. cload.Close_Micro_Chunk();
  303. }
  304. break;
  305. default:
  306. Debug_Say(( "Unrecognized ElevatorPhys chunkID\n" ));
  307. break;
  308. }
  309. cload.Close_Chunk();
  310. }
  311. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  312. AnimManager.Set_Target_Frame( 0 );
  313. return true;
  314. }
  315. void ElevatorPhysClass::Save_State( ChunkSaveClass & csave )
  316. {
  317. csave.Begin_Chunk( CHUNKID_PARENT );
  318. AccessiblePhysClass::Save_State( csave );
  319. csave.End_Chunk();
  320. csave.Begin_Chunk( CHUNKID_VARIABLES );
  321. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
  322. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TOP_DOOR_STATE, DoorStates[TOP] );
  323. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_BOTTOM_DOOR_STATE, DoorStates[BOTTOM] );
  324. csave.End_Chunk();
  325. if ( CurrentAIRider != NULL ) {
  326. csave.Begin_Chunk( CHUNKID_RIDER_OBJECT );
  327. CurrentAIRider.Save( csave );
  328. csave.End_Chunk();
  329. }
  330. }
  331. #define LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER 0x01170012
  332. void ElevatorPhysClass::Load_State( ChunkLoadClass &cload )
  333. {
  334. while (cload.Open_Chunk()) {
  335. switch(cload.Cur_Chunk_ID()) {
  336. case CHUNKID_PARENT:
  337. AccessiblePhysClass::Load_State( cload );
  338. break;
  339. case CHUNKID_RIDER_OBJECT:
  340. CurrentAIRider.Load( cload );
  341. break;
  342. case CHUNKID_VARIABLES:
  343. while (cload.Open_Micro_Chunk()) {
  344. switch(cload.Cur_Micro_Chunk_ID()) {
  345. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
  346. READ_MICRO_CHUNK( cload, MICROCHUNKID_TOP_DOOR_STATE, DoorStates[TOP] );
  347. READ_MICRO_CHUNK( cload, MICROCHUNKID_BOTTOM_DOOR_STATE, DoorStates[BOTTOM] );
  348. default:
  349. Debug_Say(( "Unrecognized ElevatorPhys Variable chunkID\n" ));
  350. break;
  351. }
  352. cload.Close_Micro_Chunk();
  353. }
  354. break;
  355. case LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER:
  356. AnimManager.Load(cload);
  357. break;
  358. default:
  359. Debug_Say(( "Unrecognized ElevatorPhys chunkID\n" ));
  360. break;
  361. }
  362. cload.Close_Chunk();
  363. }
  364. }
  365. void ElevatorPhysClass::Timestep( float dt )
  366. {
  367. AccessiblePhysClass::Timestep( dt );
  368. /*const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  369. for (int index = 0; index < ZONE_MAX; index ++) {
  370. OBBoxClass world_box;
  371. OBBoxClass::Transform( Get_Transform(), def->CallZones[index], &world_box );
  372. PhysicsSceneClass::Get_Instance ()->Add_Debug_OBBox (world_box, Vector3 (1, 0, 0));
  373. }*/
  374. {
  375. WWPROFILE("ElevatorPhys::Timestep");
  376. // Delayed Open/close
  377. if ( AnimManager.Peek_Animation() != NULL ) {
  378. //
  379. // Make sure the door sounds play at the appropriate times
  380. //
  381. Update_Sound_Effects();
  382. if ( IsCallTimerSet ) {
  383. CallTimer -= dt;
  384. }
  385. //
  386. // Should we evaluate the state of the elevator?
  387. //
  388. CheckTimer -= dt;
  389. if ( CheckTimer <= 0 ) {
  390. CheckTimer = 0.5F;
  391. Update_State();
  392. }
  393. }
  394. }
  395. return ;
  396. }
  397. void ElevatorPhysClass::Set_Door_State( int new_state, int door_id )
  398. {
  399. if ( new_state != DoorStates[door_id] ) {
  400. switch ( new_state )
  401. {
  402. case DOOR_STATE_NORMAL:
  403. break;
  404. case DOOR_STATE_UNLOCKED:
  405. Play_Effect( EFFECT_DOOR_UNLOCKED, door_id == TOP );
  406. break;
  407. case DOOR_STATE_ACCESS_DENIED:
  408. Play_Effect( EFFECT_ACCESS_DENIED, door_id == TOP );
  409. break;
  410. }
  411. DoorStates[door_id] = new_state;
  412. }
  413. return ;
  414. }
  415. void ElevatorPhysClass::Set_State( int new_state )
  416. {
  417. if ( new_state != State ) {
  418. switch ( new_state )
  419. {
  420. case STATE_DOWN:
  421. case STATE_UP:
  422. //
  423. // Leave the elevator in this state for at least 4 seconds (before it checks
  424. // to see if it should move to the next level).
  425. //
  426. //Timer = 4;
  427. break;
  428. case STATE_MOVING_UP:
  429. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  430. AnimManager.Set_Target_Frame( 0 );
  431. break;
  432. case STATE_MOVING_DOWN:
  433. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  434. AnimManager.Set_Target_Frame( AnimManager.Peek_Animation()->Get_Num_Frames() - 1 );
  435. break;
  436. }
  437. State = new_state;
  438. }
  439. return ;
  440. }
  441. void ElevatorPhysClass::Update_State(void)
  442. {
  443. switch ( State ) {
  444. case STATE_MOVING_UP:
  445. if ( AnimManager.Get_Current_Frame() == 0 ) {
  446. Set_State( STATE_UP );
  447. }
  448. break;
  449. case STATE_MOVING_DOWN:
  450. if ( AnimManager.Get_Current_Frame() == AnimManager.Peek_Animation()->Get_Num_Frames() - 1 ) {
  451. Set_State( STATE_DOWN );
  452. }
  453. break;
  454. case STATE_UP:
  455. if ( CombatManager::I_Am_Server() ) {
  456. if ( IsCallTimerSet && CallTimer <= 0 ) {
  457. IsCallTimerSet = false;
  458. if ( Triggered( ZONE_LOWER_CALL ) || Triggered( ZONE_UPPER_INSIDE ) ) {
  459. Set_State( STATE_MOVING_DOWN );
  460. TriggerRequest = 0;
  461. }
  462. } else if ( IsCallTimerSet == false ) {
  463. bool in_call = Triggered( ZONE_LOWER_CALL );
  464. bool in_inside = Triggered( ZONE_UPPER_INSIDE );
  465. if ( in_call && !in_inside ) {
  466. IsCallTimerSet = true;
  467. CallTimer = 1.0F;
  468. } else if ( in_call || in_inside ) {
  469. IsCallTimerSet = true;
  470. CallTimer = 1.0F;
  471. }
  472. }
  473. }
  474. break;
  475. case STATE_DOWN:
  476. if ( CombatManager::I_Am_Server() ) {
  477. if ( IsCallTimerSet && CallTimer <= 0 ) {
  478. IsCallTimerSet = false;
  479. if ( Triggered( ZONE_LOWER_INSIDE ) || Triggered( ZONE_UPPER_CALL ) ) {
  480. Set_State( STATE_MOVING_UP );
  481. TriggerRequest = 0;
  482. }
  483. } else if ( IsCallTimerSet == false ) {
  484. bool in_call = Triggered( ZONE_UPPER_CALL );
  485. bool in_inside = Triggered( ZONE_LOWER_INSIDE );
  486. if ( in_call && !in_inside ) {
  487. IsCallTimerSet = true;
  488. CallTimer = 1.0F;
  489. } else if ( in_call || in_inside ) {
  490. IsCallTimerSet = true;
  491. CallTimer = 1.0F;
  492. }
  493. }
  494. }
  495. break;
  496. }
  497. return ;
  498. }
  499. inline bool Is_Top_Zone ( int zone_id )
  500. {
  501. return ((zone_id > ZONE_LOWER_INSIDE) && (zone_id <= ZONE_UPPER_INSIDE));
  502. }
  503. inline bool Is_Call_Zone ( int zone_id )
  504. {
  505. return (zone_id == ZONE_LOWER_CALL) || (zone_id == ZONE_UPPER_CALL);
  506. }
  507. bool ElevatorPhysClass::Triggered( int zone_id )
  508. {
  509. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  510. OBBoxClass world_box;
  511. OBBoxClass::Transform( Get_Transform(), def->CallZones[zone_id], &world_box );
  512. //
  513. // Get information about the zone we are checking
  514. //
  515. bool is_top = ::Is_Top_Zone( zone_id );
  516. bool is_call = ::Is_Call_Zone( zone_id );
  517. //
  518. // Quick return if an AI is requesting the elevator
  519. //
  520. if (TriggerRequest & (1 << zone_id)) {
  521. return true;
  522. }
  523. //
  524. // Get the list of all the players in the world
  525. //
  526. SList<SoldierGameObj> *player_list = GameObjManager::Get_Star_Game_Obj_List();
  527. //
  528. // Loop over each player
  529. //
  530. SLNode<SoldierGameObj> *objnode;
  531. for ( objnode = player_list->Head(); objnode; objnode = objnode->Next()) {
  532. SoldierGameObj *soldier = objnode->Data();
  533. if ( soldier != NULL ) {
  534. //
  535. // Is this player inside the trigger zone?
  536. //
  537. Vector3 pos;
  538. soldier->Get_Position( &pos );
  539. if ( CollisionMath::Overlap_Test(world_box, pos) == CollisionMath::INSIDE ) {
  540. //
  541. // Is the door locked?
  542. //
  543. if ( Get_ElevatorPhysDef()->LockCode != 0 ) {
  544. bool open_door = true;
  545. if ( is_call ) {
  546. if ( soldier->Has_Key( Get_ElevatorPhysDef()->LockCode ) ) {
  547. //
  548. // The player just unlocked this door...
  549. //
  550. Set_Door_State( DOOR_STATE_UNLOCKED, is_top ? TOP : BOTTOM );
  551. } else {
  552. //
  553. // Someone tried to enter this door without unlocking it...
  554. //
  555. Set_Door_State( DOOR_STATE_ACCESS_DENIED, is_top ? TOP : BOTTOM );
  556. open_door = false;
  557. }
  558. }
  559. if ( open_door ) {
  560. return true;
  561. }
  562. } else {
  563. //
  564. // Reset the state of the door to 'normal'
  565. //
  566. if ( is_call ) {
  567. Set_Door_State( DOOR_STATE_NORMAL, is_top ? TOP : BOTTOM );
  568. }
  569. return true;
  570. }
  571. }
  572. }
  573. }
  574. //
  575. // Reset the state of the door to 'normal'
  576. //
  577. if ( is_call ) {
  578. Set_Door_State( DOOR_STATE_NORMAL, is_top ? TOP : BOTTOM );
  579. }
  580. return false;
  581. }
  582. inline bool Has_Frame_Occured (float prev_frame, float current_frame, float target_frame)
  583. {
  584. bool retval = false;
  585. //
  586. // Check to see if the animation passed the target frame in either direction
  587. //
  588. if ( target_frame >= 0 ) {
  589. retval = ((prev_frame <= target_frame) && (current_frame >= target_frame));
  590. retval |= ((prev_frame >= target_frame) && (current_frame <= target_frame));
  591. }
  592. return retval;
  593. }
  594. void ElevatorPhysClass::Update_Sound_Effects( void )
  595. {
  596. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  597. float curr_frame = AnimManager.Get_Current_Frame();
  598. float prev_frame = PrevFrame;
  599. if ( State == STATE_MOVING_DOWN ) {
  600. //
  601. // Check to see if we should play the opening or closing sounds on the door
  602. //
  603. if ( Has_Frame_Occured( prev_frame, curr_frame, 0 ) ) {
  604. Play_Effect( EFFECT_DOOR_CLOSING, true );
  605. } else if ( Has_Frame_Occured( prev_frame, curr_frame, def->DoorOpeningBottom_FrameNum ) ) {
  606. Play_Effect( EFFECT_DOOR_OPENING, false );
  607. }
  608. //
  609. // Check to see if we should start or stop the elevator moving sound
  610. //
  611. if ( Has_Frame_Occured( prev_frame, curr_frame, def->ElevatorStartTop_FrameNum ) ) {
  612. Play_Effect( EFFECT_ELEVATOR_MOVING, true );
  613. } else if ( Has_Frame_Occured( prev_frame, curr_frame, def->ElevatorStoppedBottom_FrameNum ) ) {
  614. Play_Effect( EFFECT_ELEVATOR_STOPPED_MOVING, false );
  615. }
  616. } else if ( State == STATE_MOVING_UP ) {
  617. //
  618. // Check to see if we should play the opening or closing sounds on the door
  619. //
  620. if ( Has_Frame_Occured( prev_frame, curr_frame, AnimManager.Peek_Animation()->Get_Num_Frames()-1 ) ) {
  621. Play_Effect( EFFECT_DOOR_CLOSING, false );
  622. } else if ( Has_Frame_Occured( prev_frame, curr_frame, def->DoorClosedTop_FrameNum ) ) {
  623. Play_Effect( EFFECT_DOOR_OPENING, true );
  624. }
  625. //
  626. // Check to see if we should start or stop the elevator moving sound
  627. //
  628. if ( Has_Frame_Occured( prev_frame, curr_frame, def->ElevatorStoppedBottom_FrameNum ) ) {
  629. Play_Effect( EFFECT_ELEVATOR_MOVING, false );
  630. } else if ( Has_Frame_Occured( prev_frame, curr_frame, def->ElevatorStartTop_FrameNum ) ) {
  631. Play_Effect( EFFECT_ELEVATOR_STOPPED_MOVING, true );
  632. }
  633. }
  634. PrevFrame = curr_frame;
  635. return ;
  636. }
  637. void ElevatorPhysClass::Play_Effect( int effect_id, bool is_top )
  638. {
  639. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  640. switch ( effect_id )
  641. {
  642. case EFFECT_DOOR_OPENING:
  643. {
  644. Matrix3D tm(1);
  645. Get_Door_Transform( is_top, tm );
  646. WWAudioClass::Get_Instance()->Create_Instant_Sound( def->DoorOpenSoundDefID, tm );
  647. }
  648. break;
  649. case EFFECT_DOOR_CLOSING:
  650. {
  651. Matrix3D tm(1);
  652. Get_Door_Transform( is_top, tm );
  653. WWAudioClass::Get_Instance()->Create_Instant_Sound( def->DoorCloseSoundDefID, tm );
  654. }
  655. break;
  656. case EFFECT_DOOR_UNLOCKED:
  657. {
  658. Matrix3D tm(1);
  659. Get_Door_Transform( is_top, tm );
  660. WWAudioClass::Get_Instance()->Create_Instant_Sound( def->DoorUnlockSoundDefID, tm );
  661. }
  662. break;
  663. case EFFECT_ACCESS_DENIED:
  664. {
  665. Matrix3D tm(1);
  666. Get_Door_Transform( is_top, tm );
  667. WWAudioClass::Get_Instance()->Create_Instant_Sound( def->DoorAccessDeniedSoundDefID, tm );
  668. }
  669. break;
  670. case EFFECT_ELEVATOR_MOVING:
  671. {
  672. if ( def->ElevatorMovingSoundDefID != 0 ) {
  673. RenderObjClass *model = Peek_Model ();
  674. if (model != NULL) {
  675. //
  676. // Lookup the bone we need to attach this sound to
  677. //
  678. int bone_index = model->Get_Bone_Index( "ELESOUND" );
  679. if ( bone_index > 0) {
  680. //
  681. // Create the sound object (if necessary)
  682. //
  683. if ( MovingSoundObj == NULL ) {
  684. MovingSoundObj = WWAudioClass::Get_Instance ()->Create_Continuous_Sound( def->ElevatorMovingSoundDefID );
  685. }
  686. //
  687. // Attach the sound to the elevator car and insert it into the scene
  688. //
  689. if ( MovingSoundObj != NULL ) {
  690. MovingSoundObj->Attach_To_Object( model, bone_index );
  691. MovingSoundObj->Add_To_Scene( true );
  692. }
  693. }
  694. }
  695. }
  696. }
  697. break;
  698. case EFFECT_ELEVATOR_STOPPED_MOVING:
  699. {
  700. if ( MovingSoundObj != NULL ) {
  701. MovingSoundObj->Stop();
  702. MovingSoundObj->Remove_From_Scene();
  703. }
  704. }
  705. break;
  706. }
  707. return ;
  708. }
  709. void ElevatorPhysClass::Get_Door_Transform( bool is_top, Matrix3D &tm )
  710. {
  711. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  712. tm.Make_Identity();
  713. Matrix3D curr_tm = Get_Transform();
  714. //
  715. // We assume the door is 'about' halfway between the call and inside zones.
  716. //
  717. if ( is_top ) {
  718. Vector3 zone_vector = def->CallZones[ZONE_UPPER_CALL].Center - def->CallZones[ZONE_UPPER_INSIDE].Center;
  719. Vector3 center_point = def->CallZones[ZONE_UPPER_INSIDE].Center + (zone_vector * 0.5F);
  720. tm.Set_Translation( center_point + curr_tm.Get_Translation () );
  721. } else {
  722. Vector3 zone_vector = def->CallZones[ZONE_LOWER_CALL].Center - def->CallZones[ZONE_LOWER_INSIDE].Center;
  723. Vector3 center_point = def->CallZones[ZONE_LOWER_INSIDE].Center + (zone_vector * 0.5F);
  724. tm.Set_Translation( center_point + curr_tm.Get_Translation () );
  725. }
  726. return ;
  727. }
  728. void ElevatorPhysClass::Set_Precision(void)
  729. {
  730. cEncoderList::Set_Precision( BITPACK_ELEVATOR_STATE, 0, (int)ElevatorPhysClass::STATE_MAX );
  731. cEncoderList::Set_Precision( BITPACK_ELEVATOR_TOP_DOOR_STATE, 0, (int)ElevatorPhysClass::DOOR_STATE_MAX );
  732. cEncoderList::Set_Precision( BITPACK_ELEVATOR_BOTTOM_DOOR_STATE, 0, (int)ElevatorPhysClass::DOOR_STATE_MAX );
  733. return ;
  734. }
  735. bool ElevatorPhysClass::Can_Object_Enter (SmartGameObj *game_obj)
  736. {
  737. bool retval = false;
  738. WWASSERT( game_obj != NULL && game_obj->Peek_Physical_Object () != NULL );
  739. if( game_obj == NULL || game_obj->Peek_Physical_Object () == NULL ) {
  740. return false;
  741. }
  742. //
  743. // Don't let other objects on if we've already got an AI rider
  744. //
  745. if (CurrentAIRider != NULL) {
  746. return false;
  747. }
  748. //
  749. // Get the object's bounding box
  750. //
  751. RenderObjClass *model = game_obj->Peek_Physical_Object()->Peek_Model ();
  752. const AABoxClass &obj_box = model->Get_Bounding_Box ();
  753. //
  754. // Get the bottom and top call zones
  755. //
  756. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  757. OBBoxClass bottom_box;
  758. OBBoxClass top_box;
  759. OBBoxClass::Transform( Get_Transform(), def->CallZones[STATE_DOWN], &bottom_box );
  760. OBBoxClass::Transform( Get_Transform(), def->CallZones[STATE_UP], &top_box );
  761. //
  762. // Which floor is the object waiting on?
  763. //
  764. if( CollisionMath::Intersection_Test( bottom_box, obj_box ) ) {
  765. retval = (State == STATE_DOWN);
  766. } else if( CollisionMath::Intersection_Test( top_box, obj_box ) ) {
  767. retval = (State == STATE_UP);
  768. }
  769. return retval;
  770. }
  771. bool ElevatorPhysClass::Can_Object_Exit (SmartGameObj * /*game_obj*/)
  772. {
  773. bool retval = false;
  774. //
  775. // If the elevator is at rest, then the object can exit
  776. //
  777. if (State == STATE_DOWN || State == STATE_UP) {
  778. retval = true;
  779. }
  780. return retval;
  781. }
  782. void ElevatorPhysClass::Request_Elevator (SmartGameObj *game_obj)
  783. {
  784. WWASSERT( game_obj != NULL && game_obj->Peek_Physical_Object () != NULL );
  785. if( game_obj == NULL || game_obj->Peek_Physical_Object () == NULL ) {
  786. return ;
  787. }
  788. //
  789. // Get the object's bounding box
  790. //
  791. RenderObjClass *model = game_obj->Peek_Physical_Object()->Peek_Model ();
  792. const AABoxClass &obj_box = model->Get_Bounding_Box ();
  793. //
  794. // Get the bottom and top call zones
  795. //
  796. const ElevatorPhysDefClass *def = Get_ElevatorPhysDef();
  797. //
  798. // See what trigger zone the object is in...
  799. //
  800. for ( int index = 0; index < ZONE_MAX; index ++) {
  801. //
  802. // Transform the trigger zone into world space
  803. //
  804. OBBoxClass world_box;
  805. OBBoxClass::Transform( Get_Transform(), def->CallZones[index], &world_box );
  806. //
  807. // Is this the trigger zone the object is standing in?
  808. //
  809. if( CollisionMath::Intersection_Test( world_box, obj_box ) ) {
  810. TriggerRequest |= (1 << index);
  811. }
  812. }
  813. return ;
  814. }
  815. int ElevatorPhysClass::Get_Floor (void)
  816. {
  817. int floor = 13;
  818. //
  819. // Return 0 if the elevator is currently sitting on the bottom floor
  820. // or return 1 if the elevator is sitting at the top floor
  821. //
  822. if (State == STATE_DOWN) {
  823. floor = 0;
  824. } else if (State == STATE_UP) {
  825. floor = 1;
  826. }
  827. return floor;
  828. }