doors.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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/doors.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 1/15/02 3:07p $*
  29. * *
  30. * $Revision:: 47 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "doors.h"
  36. #include "simpledefinitionfactory.h"
  37. #include "persistfactory.h"
  38. #include "wwphysids.h"
  39. #include "debug.h"
  40. #include "hanim.h"
  41. #include "wwhack.h"
  42. #include "combat.h"
  43. #include "smartgameobj.h"
  44. #include "gameobjmanager.h"
  45. #include "soldier.h"
  46. #include "wwaudio.h"
  47. #include "wwprofile.h"
  48. #include "bitpackids.h"
  49. #include "diaglog.h"
  50. #include "vehicle.h"
  51. DECLARE_FORCE_LINK( doorphys );
  52. /*
  53. ** DoorPhysDefClass
  54. */
  55. SimplePersistFactoryClass<DoorPhysDefClass, PHYSICS_CHUNKID_DOORPHYSDEF> _DoorPhysDefPersistFactory;
  56. DECLARE_DEFINITION_FACTORY(DoorPhysDefClass, CLASSID_DOORPHYSDEF, "DoorPhys") _DoorPhysDefDefFactory;
  57. DoorPhysDefClass::DoorPhysDefClass( void ) :
  58. AccessiblePhysDefClass(),
  59. CloseDelay( 2 ),
  60. TriggerZone1( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
  61. TriggerZone2( Vector3( 0,0,0), Vector3( 1,1,1 ) ),
  62. OpenSoundDefID( 0 ),
  63. CloseSoundDefID( 0 ),
  64. UnlockSoundDefID( 0 ),
  65. AccessDeniedSoundDefID( 0 ),
  66. DoorOpensForVehicles( false )
  67. {
  68. ZONE_PARAM(DoorPhysDefClass, TriggerZone1, "TriggerZone1" );
  69. ZONE_PARAM(DoorPhysDefClass, TriggerZone2, "TriggerZone2" );
  70. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_FLOAT, CloseDelay );
  71. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, OpenSoundDefID);
  72. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, CloseSoundDefID);
  73. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, UnlockSoundDefID);
  74. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_SOUNDDEFINITIONID, AccessDeniedSoundDefID);
  75. EDITABLE_PARAM(DoorPhysDefClass, ParameterClass::TYPE_BOOL, DoorOpensForVehicles);
  76. }
  77. uint32 DoorPhysDefClass::Get_Class_ID (void) const
  78. {
  79. return CLASSID_DOORPHYSDEF;
  80. }
  81. bool DoorPhysDefClass::Is_Type(const char * type_name)
  82. {
  83. if (stricmp(type_name,DoorPhysDefClass::Get_Type_Name()) == 0) {
  84. return true;
  85. } else {
  86. return AccessiblePhysDefClass::Is_Type(type_name);
  87. }
  88. }
  89. PersistClass * DoorPhysDefClass::Create( void ) const
  90. {
  91. DoorPhysClass * door = new DoorPhysClass;
  92. door->Init( *this );
  93. return door;
  94. }
  95. enum {
  96. CHUNKID_DEF_OLD_PARENT = 320001902,
  97. CHUNKID_DEF_VARIABLES,
  98. CHUNKID_DEF_PARENT,
  99. XXXMICROCHUNKID_DEF_TRIGGER_RADIUS = 1,
  100. MICROCHUNKID_DEF_CLOSE_DELAY,
  101. MICROCHUNKID_DEF_TRIGGER_ZONE1,
  102. MICROCHUNKID_DEF_OLD_LOCK_CODE,
  103. MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID,
  104. MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID,
  105. MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID,
  106. MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID,
  107. MICROCHUNKID_DEF_TRIGGER_ZONE2,
  108. MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES,
  109. };
  110. bool DoorPhysDefClass::Save( ChunkSaveClass & csave )
  111. {
  112. csave.Begin_Chunk( CHUNKID_DEF_PARENT );
  113. AccessiblePhysDefClass::Save( csave );
  114. csave.End_Chunk();
  115. csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
  116. // WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_RADIUS, TriggerRadius );
  117. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
  118. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_ZONE1, TriggerZone1 );
  119. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRIGGER_ZONE2, TriggerZone2 );
  120. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID, OpenSoundDefID );
  121. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID, CloseSoundDefID );
  122. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID, UnlockSoundDefID );
  123. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID, AccessDeniedSoundDefID );
  124. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES, DoorOpensForVehicles );
  125. csave.End_Chunk();
  126. return true;
  127. }
  128. bool DoorPhysDefClass::Load( ChunkLoadClass &cload )
  129. {
  130. while (cload.Open_Chunk()) {
  131. switch(cload.Cur_Chunk_ID()) {
  132. case CHUNKID_DEF_OLD_PARENT:
  133. StaticAnimPhysDefClass::Load( cload );
  134. break;
  135. case CHUNKID_DEF_PARENT:
  136. AccessiblePhysDefClass::Load( cload );
  137. break;
  138. case CHUNKID_DEF_VARIABLES:
  139. while (cload.Open_Micro_Chunk()) {
  140. switch(cload.Cur_Micro_Chunk_ID()) {
  141. // READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_RADIUS, TriggerRadius );
  142. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CLOSE_DELAY, CloseDelay );
  143. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_ZONE1, TriggerZone1 );
  144. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRIGGER_ZONE2, TriggerZone2 );
  145. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_OLD_LOCK_CODE, LockCode );
  146. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_OPEN_SOUND_DEF_ID, OpenSoundDefID );
  147. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CLOSE_SOUND_DEF_ID, CloseSoundDefID );
  148. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_UNLOCK_SOUND_DEF_ID, UnlockSoundDefID );
  149. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ACCESS_DENIED_SOUND_DEF_ID, AccessDeniedSoundDefID );
  150. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DOOR_OPENS_FOR_VEHICLES, DoorOpensForVehicles );
  151. default:
  152. Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
  153. break;
  154. }
  155. cload.Close_Micro_Chunk();
  156. }
  157. break;
  158. default:
  159. Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
  160. break;
  161. }
  162. cload.Close_Chunk();
  163. }
  164. return true;
  165. }
  166. const PersistFactoryClass & DoorPhysDefClass::Get_Factory (void) const
  167. {
  168. return _DoorPhysDefPersistFactory;
  169. }
  170. /*
  171. **
  172. */
  173. SimplePersistFactoryClass<DoorPhysClass, PHYSICS_CHUNKID_DOORPHYS> _DoorPhysPersistFactory;
  174. const PersistFactoryClass & DoorPhysClass::Get_Factory (void) const
  175. {
  176. return _DoorPhysPersistFactory;
  177. }
  178. /*
  179. **
  180. */
  181. DoorPhysClass::DoorPhysClass( void ) :
  182. Timer( 0 ),
  183. CheckTimer( 0 ),
  184. State( STATE_CLOSED_DOOR ),
  185. LockState( false ),
  186. OpenRequestPending( false )
  187. {
  188. }
  189. DoorPhysClass::~DoorPhysClass( void )
  190. {
  191. }
  192. void DoorPhysClass::Init( const DoorPhysDefClass & def )
  193. {
  194. AccessiblePhysClass::Init(def);
  195. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  196. AnimManager.Set_Target_Frame( 0 );
  197. }
  198. /*
  199. ** Save and Load
  200. */
  201. enum {
  202. CHUNKID_OLD_PARENT = 320002202,
  203. CHUNKID_VARIABLES,
  204. CHUNKID_PARENT,
  205. XXXMICROCHUNKID_ = 1,
  206. MICROCHUNKID_STATE = 2,
  207. MICROCHUNKID_TIMER = 3,
  208. MICROCHUNKID_CHECK_TIMER = 4,
  209. MICROCHUNKID_OPEN_REQUEST_PENDING = 5,
  210. };
  211. bool DoorPhysClass::Save( ChunkSaveClass & csave )
  212. {
  213. csave.Begin_Chunk( CHUNKID_PARENT );
  214. AccessiblePhysClass::Save( csave );
  215. csave.End_Chunk();
  216. csave.Begin_Chunk( CHUNKID_VARIABLES );
  217. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
  218. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TIMER, Timer );
  219. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CHECK_TIMER, CheckTimer );
  220. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
  221. csave.End_Chunk();
  222. return true;
  223. }
  224. bool DoorPhysClass::Load( ChunkLoadClass &cload )
  225. {
  226. while (cload.Open_Chunk()) {
  227. switch(cload.Cur_Chunk_ID()) {
  228. case CHUNKID_OLD_PARENT:
  229. StaticAnimPhysClass::Load( cload );
  230. break;
  231. case CHUNKID_PARENT:
  232. AccessiblePhysClass::Load( cload );
  233. break;
  234. case CHUNKID_VARIABLES:
  235. while (cload.Open_Micro_Chunk()) {
  236. switch(cload.Cur_Micro_Chunk_ID()) {
  237. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
  238. READ_MICRO_CHUNK( cload, MICROCHUNKID_TIMER, Timer );
  239. READ_MICRO_CHUNK( cload, MICROCHUNKID_CHECK_TIMER, CheckTimer );
  240. READ_MICRO_CHUNK( cload, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
  241. default:
  242. Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
  243. break;
  244. }
  245. cload.Close_Micro_Chunk();
  246. }
  247. break;
  248. default:
  249. Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
  250. break;
  251. }
  252. cload.Close_Chunk();
  253. }
  254. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  255. AnimManager.Set_Target_Frame( 0 );
  256. return true;
  257. }
  258. void DoorPhysClass::Save_State( ChunkSaveClass & csave )
  259. {
  260. csave.Begin_Chunk( CHUNKID_PARENT );
  261. AccessiblePhysClass::Save_State( csave );
  262. csave.End_Chunk();
  263. csave.Begin_Chunk( CHUNKID_VARIABLES );
  264. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
  265. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TIMER, Timer );
  266. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CHECK_TIMER, CheckTimer );
  267. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
  268. csave.End_Chunk();
  269. }
  270. #define LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER 0x01170012
  271. void DoorPhysClass::Load_State( ChunkLoadClass &cload )
  272. {
  273. while (cload.Open_Chunk()) {
  274. switch(cload.Cur_Chunk_ID()) {
  275. case CHUNKID_OLD_PARENT:
  276. StaticAnimPhysClass::Load_State( cload );
  277. break;
  278. case CHUNKID_PARENT:
  279. AccessiblePhysClass::Load_State( cload );
  280. break;
  281. case CHUNKID_VARIABLES:
  282. while (cload.Open_Micro_Chunk()) {
  283. switch(cload.Cur_Micro_Chunk_ID()) {
  284. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
  285. READ_MICRO_CHUNK( cload, MICROCHUNKID_TIMER, Timer );
  286. READ_MICRO_CHUNK( cload, MICROCHUNKID_CHECK_TIMER, CheckTimer );
  287. READ_MICRO_CHUNK( cload, MICROCHUNKID_OPEN_REQUEST_PENDING, OpenRequestPending );
  288. default:
  289. Debug_Say(( "Unrecognized DoorPhys Variable chunkID\n" ));
  290. break;
  291. }
  292. cload.Close_Micro_Chunk();
  293. }
  294. break;
  295. case LEGACY_STATICANIMPHYS_CHUNK_ANIMMANAGER:
  296. AnimManager.Load(cload);
  297. break;
  298. default:
  299. Debug_Say(( "Unrecognized DoorPhys chunkID\n" ));
  300. break;
  301. }
  302. cload.Close_Chunk();
  303. }
  304. }
  305. void DoorPhysClass::Timestep( float dt )
  306. {
  307. AccessiblePhysClass::Timestep( dt );
  308. {
  309. WWPROFILE("DoorPhys::Timestep");
  310. //
  311. // If we are configured correctly with an animation,
  312. // then evaluate our state and determine if we need to
  313. // do anything.
  314. //
  315. if ( AnimManager.Peek_Animation() != NULL ) {
  316. Update_State( dt );
  317. }
  318. //
  319. // Reset the open request flag
  320. //
  321. OpenRequestPending = false;
  322. }
  323. return ;
  324. }
  325. bool DoorPhysClass::Set_State( int new_state )
  326. {
  327. bool retval = false;
  328. if ( State != new_state ) {
  329. switch ( new_state )
  330. {
  331. case STATE_OPENING_DOOR:
  332. {
  333. //
  334. // Did someone just unlock the door?
  335. //
  336. if ( Get_DoorPhysDef()->LockCode != 0 ) {
  337. WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->UnlockSoundDefID, Get_Transform() );
  338. }
  339. //
  340. // Play the 'door-opening' sound
  341. //
  342. WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->OpenSoundDefID, Get_Transform() );
  343. //
  344. // Open the door
  345. //
  346. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  347. AnimManager.Set_Target_Frame( AnimManager.Peek_Animation()->Get_Num_Frames() - 1 );
  348. }
  349. break;
  350. case STATE_CLOSING_DOOR:
  351. {
  352. //
  353. // Play the 'door-closing' sound
  354. //
  355. WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->CloseSoundDefID, Get_Transform() );
  356. //
  357. // Close the door
  358. //
  359. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  360. AnimManager.Set_Target_Frame( 0 );
  361. }
  362. break;
  363. case STATE_OPENED_DOOR:
  364. {
  365. //
  366. // Set a timer that we can use to close the door
  367. //
  368. Timer = Get_DoorPhysDef()->CloseDelay;
  369. //
  370. // Make sure the door is open (net games, may not see the "opening" state)
  371. //
  372. // Clients *must* see the opening - it's a guaranteed packet. ST - 1/15/2002 12:59PM
  373. //
  374. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  375. AnimManager.Set_Target_Frame( AnimManager.Peek_Animation()->Get_Num_Frames() - 1 );
  376. }
  377. break;
  378. case STATE_CLOSED_DOOR:
  379. //
  380. // Make sure the door is closed (in net games, we may not get
  381. // the "closing" state)
  382. //
  383. AnimManager.Set_Animation_Mode( AnimCollisionManagerClass::ANIMATE_TARGET );
  384. AnimManager.Set_Target_Frame( 0 );
  385. break;
  386. case STATE_ACCESS_DENIED:
  387. {
  388. //
  389. // Play the 'access denied' sound
  390. //
  391. WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_DoorPhysDef()->AccessDeniedSoundDefID, Get_Transform() );
  392. }
  393. break;
  394. }
  395. State = new_state;
  396. retval = true;
  397. }
  398. return retval;
  399. }
  400. enum
  401. {
  402. DOOR_OPEN_OK = 0,
  403. DOOR_OPEN_LOCKED,
  404. DOOR_OPEN_NOONE
  405. };
  406. void DoorPhysClass::Update_State( float dt )
  407. {
  408. switch ( State )
  409. {
  410. case STATE_OPENING_DOOR:
  411. {
  412. //
  413. // Has the door finished opening?
  414. //
  415. if (AnimManager.Get_Current_Frame() == AnimManager.Peek_Animation()->Get_Num_Frames() - 1) {
  416. Set_State( STATE_OPENED_DOOR );
  417. }
  418. }
  419. break;
  420. case STATE_OPENED_DOOR:
  421. {
  422. //
  423. // Has the door been in 'opened' state long enough?
  424. //
  425. // Client shouldn't be able to close his own door unless he hears from the server. ST - 1/15/2002 12:58PM
  426. //
  427. if ( CombatManager::I_Am_Server() ) {
  428. Timer -= dt;
  429. if ( Timer < 0 &&
  430. LockState == false &&
  431. OpenRequestPending == false &&
  432. Can_Open_Door() != DOOR_OPEN_OK)
  433. {
  434. //
  435. // Switch to closing state
  436. //
  437. Set_State( STATE_CLOSING_DOOR );
  438. }
  439. }
  440. }
  441. break;
  442. case STATE_CLOSING_DOOR:
  443. {
  444. //
  445. // Has the door finished closing?
  446. //
  447. if ( AnimManager.Get_Current_Frame() == 0 ) {
  448. Set_State( STATE_CLOSED_DOOR );
  449. }
  450. }
  451. case STATE_CLOSED_DOOR:
  452. case STATE_ACCESS_DENIED:
  453. {
  454. //
  455. // We only do this if we are the server
  456. //
  457. if ( CombatManager::I_Am_Server() ) {
  458. //
  459. // Should we check to see if someone wants to open the door?
  460. //
  461. CheckTimer -= dt;
  462. if ( CheckTimer <= 0 ) {
  463. CheckTimer = 0.3f; // Check every 1/3 second
  464. //
  465. // Check to see if we should open the door
  466. //
  467. if ( LockState == false ) {
  468. bool update_clients = false;
  469. int result = Can_Open_Door();
  470. if ( OpenRequestPending || result == DOOR_OPEN_OK ) {
  471. update_clients = Set_State( STATE_OPENING_DOOR );
  472. } else if ( result == DOOR_OPEN_LOCKED ) {
  473. update_clients = Set_State( STATE_ACCESS_DENIED );
  474. } else if ( State == STATE_ACCESS_DENIED ) {
  475. update_clients = Set_State( STATE_CLOSED_DOOR );
  476. }
  477. //
  478. // If the server has decided on a new state, then
  479. // notify the clients
  480. //
  481. if ( update_clients ) {
  482. Enable_Is_State_Dirty( true );
  483. }
  484. }
  485. }
  486. }
  487. }
  488. break;
  489. }
  490. return ;
  491. }
  492. void DoorPhysClass::Lock_Door_Open( bool onoff )
  493. {
  494. if ( CombatManager::I_Am_Server() ) {
  495. //
  496. // Force the door open...
  497. //
  498. if ( onoff && Set_State( STATE_OPENING_DOOR ) ) {
  499. Enable_Is_State_Dirty( true );
  500. }
  501. //
  502. // Lock the state
  503. //
  504. LockState = onoff;
  505. }
  506. return ;
  507. }
  508. int DoorPhysClass::Can_Open_Door( void )
  509. {
  510. //
  511. // Transform both trigger zones into world space
  512. //
  513. OBBoxClass trigger_zone1;
  514. OBBoxClass trigger_zone2;
  515. OBBoxClass::Transform( Get_Transform(), Get_DoorPhysDef()->TriggerZone1, &trigger_zone1 );
  516. OBBoxClass::Transform( Get_Transform(), Get_DoorPhysDef()->TriggerZone2, &trigger_zone2 );
  517. //
  518. // Check the zone's to see if we should open the door
  519. //
  520. int result1 = Check_Door_Trigger( trigger_zone1 );
  521. int result2 = DOOR_OPEN_NOONE;
  522. if (result1 != DOOR_OPEN_OK) {
  523. result2 = Check_Door_Trigger( trigger_zone2 );
  524. }
  525. //
  526. // Now determine what information to return about the trigger check
  527. //
  528. int result = DOOR_OPEN_NOONE;
  529. if ( result1 == DOOR_OPEN_OK || result2 == DOOR_OPEN_OK ) {
  530. result = DOOR_OPEN_OK;
  531. } else if ( result1 == DOOR_OPEN_LOCKED || result2 == DOOR_OPEN_LOCKED ) {
  532. result = DOOR_OPEN_LOCKED;
  533. }
  534. return result;
  535. }
  536. int DoorPhysClass::Check_Door_Trigger( const OBBoxClass &trigger_zone )
  537. {
  538. int result = DOOR_OPEN_NOONE;
  539. #if 0
  540. //
  541. // Get the list of all the players in the world
  542. //
  543. SList<SoldierGameObj> *player_list = GameObjManager::Get_Star_Game_Obj_List();
  544. //
  545. // Loop over each player
  546. //
  547. SLNode<SoldierGameObj> *objnode;
  548. for ( objnode = player_list->Head(); objnode; objnode = objnode->Next()) {
  549. SoldierGameObj *soldier = objnode->Data();
  550. if ( soldier != NULL ) {
  551. //
  552. // Is this player inside the trigger zone?
  553. //
  554. Vector3 pos;
  555. soldier->Get_Position( &pos );
  556. if ( CollisionMath::Overlap_Test( trigger_zone, pos ) == CollisionMath::INSIDE ) {
  557. //
  558. // Is the door locked?
  559. //
  560. if ( Get_DoorPhysDef()->LockCode != 0 ) {
  561. if ( soldier == COMBAT_STAR ) {
  562. Vector3 pos;
  563. soldier->Get_Position( &pos );
  564. const char * desc = soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ? "KEUS" : "KEDE";
  565. DIAG_LOG(( desc, "%1.2f; %1.2f; %1.2f; %d; %d", pos.X, pos.Y, pos.Z, Get_ID(), Get_DoorPhysDef()->LockCode ));
  566. }
  567. //
  568. // Can the soldier unlock this door?
  569. //
  570. if ( soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ) {
  571. result = DOOR_OPEN_OK;
  572. break;
  573. } else {
  574. result = DOOR_OPEN_LOCKED;
  575. }
  576. } else {
  577. result = DOOR_OPEN_OK;
  578. break;
  579. }
  580. }
  581. }
  582. }
  583. #else
  584. NonRefPhysListClass obj_list;
  585. WWASSERT(PhysicsSceneClass::Get_Instance() != NULL);
  586. PhysicsSceneClass::Get_Instance()->Collect_Objects(trigger_zone,false,true,&obj_list);
  587. NonRefPhysListIterator it(&obj_list);
  588. while (!it.Is_Done() && result == DOOR_OPEN_NOONE) {
  589. CombatPhysObserverClass * observer = (CombatPhysObserverClass *)it.Peek_Obj()->Get_Observer();
  590. //WWASSERT(observer != NULL);
  591. //if (observer->As_PhysicalGameObj()) {
  592. if (observer != NULL && observer->As_PhysicalGameObj()) {
  593. SoldierGameObj * soldier = observer->As_PhysicalGameObj()->As_SoldierGameObj();
  594. VehicleGameObj * vehicle = observer->As_PhysicalGameObj()->As_VehicleGameObj();
  595. //
  596. // Check if this is a soldier who can open the door
  597. //
  598. if ((soldier != NULL) && soldier->Is_Human_Controlled()) {
  599. WWASSERT(Get_DoorPhysDef() != NULL);
  600. if ( Get_DoorPhysDef()->LockCode == 0 ) {
  601. result = DOOR_OPEN_OK;
  602. } else {
  603. if (Can_Unlock_Me(soldier)) {
  604. result = DOOR_OPEN_OK;
  605. break;
  606. } else {
  607. result = DOOR_OPEN_LOCKED;
  608. }
  609. }
  610. }
  611. //
  612. // Check if this is a vehicle that is allowed to open the door
  613. //
  614. WWASSERT(Get_DoorPhysDef() != NULL);
  615. if ((vehicle != NULL) && (Get_DoorPhysDef()->DoorOpensForVehicles)) {
  616. if ( Get_DoorPhysDef()->LockCode == 0 ) {
  617. result = DOOR_OPEN_OK;
  618. } else {
  619. SoldierGameObj * driver = vehicle->Get_Driver();
  620. if ((driver != NULL) && (Can_Unlock_Me(driver))) {
  621. result = DOOR_OPEN_OK;
  622. break;
  623. } else {
  624. result = DOOR_OPEN_LOCKED;
  625. }
  626. }
  627. }
  628. }
  629. it.Next();
  630. }
  631. #endif
  632. return result;
  633. }
  634. bool DoorPhysClass::Can_Unlock_Me(SoldierGameObj * soldier) const
  635. {
  636. if ( soldier == COMBAT_STAR ) {
  637. Vector3 pos;
  638. soldier->Get_Position( &pos );
  639. const char * desc = soldier->Has_Key( Get_DoorPhysDef()->LockCode ) ? "KEUS" : "KEDE";
  640. DIAG_LOG(( desc, "%1.2f; %1.2f; %1.2f; %d; %d", pos.X, pos.Y, pos.Z, Get_ID(), Get_DoorPhysDef()->LockCode ));
  641. }
  642. //
  643. // Can the soldier unlock this door?
  644. //
  645. return (Get_DoorPhysDef()->LockCode == 0) || (soldier->Has_Key( Get_DoorPhysDef()->LockCode ));
  646. }
  647. void DoorPhysClass::Set_Precision(void)
  648. {
  649. cEncoderList::Set_Precision( BITPACK_DOOR_STATE, 0, (int)STATE_MAX );
  650. return ;
  651. }
  652. bool DoorPhysClass::Is_Door_Open( void ) const
  653. {
  654. return (State == STATE_OPENED_DOOR);
  655. }