cinematicgameobj.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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/cinematicgameobj.cpp $*
  25. * *
  26. * $Author:: Tom_s $*
  27. * *
  28. * $Modtime:: 10/10/01 11:37a $*
  29. * *
  30. * $Revision:: 32 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. /*
  36. ** Includes
  37. */
  38. #include "cinematicgameobj.h"
  39. #include "debug.h"
  40. #include "animcontrol.h"
  41. #include "Sound3D.H"
  42. #include "combat.h"
  43. #include "pscene.h"
  44. #include "persistfactory.h"
  45. #include "combatchunkid.h"
  46. #include "simpledefinitionfactory.h"
  47. #include "wwhack.h"
  48. #include "weapons.h"
  49. #include "gameobjmanager.h"
  50. #include "assets.h"
  51. #include "ccamera.h"
  52. #include "explosion.h"
  53. #include "damage.h"
  54. #include "dynamicanimphys.h"
  55. #include "wwprofile.h"
  56. #include "apppackettypes.h"
  57. /*
  58. ** CinematicGameObjDef
  59. */
  60. DECLARE_FORCE_LINK( Cinematic )
  61. SimplePersistFactoryClass<CinematicGameObjDef, CHUNKID_GAME_OBJECT_DEF_CINEMATIC> _CinematicGameObjDefPersistFactory;
  62. DECLARE_DEFINITION_FACTORY(CinematicGameObjDef, CLASSID_GAME_OBJECT_DEF_CINEMATIC, "Cinematic") _CinematicGameObjDefDefFactory;
  63. CinematicGameObjDef::CinematicGameObjDef( void ) :
  64. SoundDefID( 0 ),
  65. AutoFireWeapon( false ),
  66. DestroyAfterAnimation( true ),
  67. CameraRelative( false )
  68. {
  69. MODEL_DEF_PARAM( CinematicGameObjDef, PhysDefID, "DynamicAnimPhysDef" );
  70. EDITABLE_PARAM( CinematicGameObjDef, ParameterClass::TYPE_SOUNDDEFINITIONID, SoundDefID );
  71. EDITABLE_PARAM( CinematicGameObjDef, ParameterClass::TYPE_STRING, SoundBoneName );
  72. FILENAME_PARAM( CinematicGameObjDef, AnimationName, "Animation", ".W3D" );
  73. EDITABLE_PARAM( CinematicGameObjDef, ParameterClass::TYPE_BOOL, AutoFireWeapon );
  74. EDITABLE_PARAM( CinematicGameObjDef, ParameterClass::TYPE_BOOL, DestroyAfterAnimation );
  75. EDITABLE_PARAM( CinematicGameObjDef, ParameterClass::TYPE_BOOL, CameraRelative );
  76. }
  77. uint32 CinematicGameObjDef::Get_Class_ID (void) const
  78. {
  79. return CLASSID_GAME_OBJECT_DEF_CINEMATIC;
  80. }
  81. const PersistFactoryClass & CinematicGameObjDef::Get_Factory (void) const
  82. {
  83. return _CinematicGameObjDefPersistFactory;
  84. }
  85. PersistClass * CinematicGameObjDef::Create( void ) const
  86. {
  87. CinematicGameObj * obj = new CinematicGameObj;
  88. obj->Init( *this );
  89. return obj;
  90. }
  91. enum {
  92. CHUNKID_DEF_PARENT = 418001957,
  93. CHUNKID_DEF_VARIABLES,
  94. MICROCHUNKID_DEF_SOUND_DEF_ID = 1,
  95. MICROCHUNKID_DEF_SOUND_BONE_NAME,
  96. XXX_MICROCHUNKID_DEF_ANIMATION_NAME,
  97. MICROCHUNKID_DEF_AUTO_FIRE_WEAPON,
  98. MICROCHUNKID_DEF_DESTROY_AFTER_ANIMATION,
  99. MICROCHUNKID_DEF_CAMERA_RELATIVE,
  100. };
  101. bool CinematicGameObjDef::Save( ChunkSaveClass & csave )
  102. {
  103. csave.Begin_Chunk( CHUNKID_DEF_PARENT );
  104. ArmedGameObjDef::Save( csave );
  105. csave.End_Chunk();
  106. csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
  107. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SOUND_DEF_ID, SoundDefID );
  108. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_SOUND_BONE_NAME, SoundBoneName );
  109. WRITE_MICRO_CHUNK_WWSTRING( csave, XXX_MICROCHUNKID_DEF_ANIMATION_NAME, AnimationName );
  110. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_AUTO_FIRE_WEAPON,AutoFireWeapon );
  111. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DESTROY_AFTER_ANIMATION, DestroyAfterAnimation );
  112. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CAMERA_RELATIVE, CameraRelative );
  113. csave.End_Chunk();
  114. return true;
  115. }
  116. bool CinematicGameObjDef::Load( ChunkLoadClass &cload )
  117. {
  118. while (cload.Open_Chunk()) {
  119. switch(cload.Cur_Chunk_ID()) {
  120. case CHUNKID_DEF_PARENT:
  121. ArmedGameObjDef::Load( cload );
  122. break;
  123. case CHUNKID_DEF_VARIABLES:
  124. while (cload.Open_Micro_Chunk()) {
  125. switch(cload.Cur_Micro_Chunk_ID()) {
  126. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SOUND_DEF_ID, SoundDefID );
  127. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_SOUND_BONE_NAME, SoundBoneName );
  128. READ_MICRO_CHUNK_WWSTRING( cload, XXX_MICROCHUNKID_DEF_ANIMATION_NAME, AnimationName );
  129. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_AUTO_FIRE_WEAPON,AutoFireWeapon );
  130. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DESTROY_AFTER_ANIMATION, DestroyAfterAnimation );
  131. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CAMERA_RELATIVE, CameraRelative );
  132. default:
  133. Debug_Say(( "Unrecognized CinematicDef Variable chunkID\n" ));
  134. break;
  135. }
  136. cload.Close_Micro_Chunk();
  137. }
  138. break;
  139. default:
  140. Debug_Say(( "Unrecognized CinematicDef chunkID\n" ));
  141. break;
  142. }
  143. cload.Close_Chunk();
  144. }
  145. return true;
  146. }
  147. /*
  148. ** CinematicGameObj
  149. */
  150. SimplePersistFactoryClass<CinematicGameObj, CHUNKID_GAME_OBJECT_CINEMATIC> _CinematicGameObjPersistFactory;
  151. const PersistFactoryClass & CinematicGameObj::Get_Factory (void) const
  152. {
  153. return _CinematicGameObjPersistFactory;
  154. }
  155. CinematicGameObj::CinematicGameObj() :
  156. Sound( NULL )
  157. {
  158. Set_App_Packet_Type(APPPACKETTYPE_CINEMATIC);
  159. }
  160. CinematicGameObj::~CinematicGameObj()
  161. {
  162. Set_Sound( 0 );
  163. COMBAT_SCENE->Remove_From_Dirty_Cull_List( Peek_Physical_Object() );
  164. }
  165. /*
  166. **
  167. */
  168. void CinematicGameObj::Init( void )
  169. {
  170. Init( Get_Definition() );
  171. }
  172. /*
  173. **
  174. */
  175. void CinematicGameObj::Init( const CinematicGameObjDef & definition )
  176. {
  177. ArmedGameObj::Init( definition );
  178. Cinematic_Init();
  179. }
  180. void CinematicGameObj::Cinematic_Init( void )
  181. {
  182. /*
  183. ** (gth) cinematic game objects behave like animated terrain so they are in the
  184. ** terrain collision group
  185. */
  186. Peek_Physical_Object()->Set_Collision_Group( PhysicsSceneClass::COLLISION_GROUP_WORLD );
  187. // COMBAT_SCENE->Add_To_Dirty_Cull_List( Peek_Physical_Object() );
  188. Set_Sound( Get_Definition().SoundDefID, Get_Definition().SoundBoneName );
  189. }
  190. const CinematicGameObjDef & CinematicGameObj::Get_Definition( void ) const
  191. {
  192. return (const CinematicGameObjDef &)BaseGameObj::Get_Definition();
  193. }
  194. /*
  195. ** CinematicGameObj Save and Load
  196. */
  197. enum {
  198. CHUNKID_PARENT = 418002008,
  199. XXXCHUNKID_VARIABLES,
  200. XXXCHUNKID_ANIM_CONTROL,
  201. XXXMICROCHUNKID_PHYSICAL_OBJECT = 1,
  202. };
  203. bool CinematicGameObj::Save( ChunkSaveClass & csave )
  204. {
  205. csave.Begin_Chunk( CHUNKID_PARENT );
  206. ArmedGameObj::Save( csave );
  207. csave.End_Chunk();
  208. // We don't need to save the sound
  209. return true;
  210. }
  211. bool CinematicGameObj::Load( ChunkLoadClass &cload )
  212. {
  213. while (cload.Open_Chunk()) {
  214. switch(cload.Cur_Chunk_ID()) {
  215. case CHUNKID_PARENT:
  216. ArmedGameObj::Load( cload );
  217. break;
  218. default:
  219. Debug_Say(( "Unrecognized Cinematic chunkID\n" ));
  220. break;
  221. }
  222. cload.Close_Chunk();
  223. }
  224. SaveLoadSystemClass::Register_Post_Load_Callback(this);
  225. return true;
  226. }
  227. void CinematicGameObj::On_Post_Load( void )
  228. {
  229. ArmedGameObj::On_Post_Load();
  230. Cinematic_Init();
  231. }
  232. /*
  233. **
  234. */
  235. void CinematicGameObj::Set_Sound( int sound_def_id, const char * bone_name )
  236. {
  237. // Stop Old Sound
  238. if ( Sound != NULL ) {
  239. Sound->Stop();
  240. Sound->Attach_To_Object( NULL );
  241. Sound->Remove_From_Scene();
  242. Sound->Release_Ref();
  243. Sound = NULL;
  244. }
  245. // Start new Sound
  246. if ( sound_def_id != 0 ) {
  247. Sound = WWAudioClass::Get_Instance()->Create_Continuous_Sound( sound_def_id );
  248. if ( Sound != NULL ) {
  249. RenderObjClass * model = Peek_Model();
  250. WWASSERT( model );
  251. int bone_index = model->Get_Bone_Index( bone_name );
  252. Sound->Attach_To_Object( Peek_Model(), bone_index );
  253. Sound->Add_To_Scene( true );
  254. }
  255. }
  256. }
  257. void CinematicGameObj::Think( void )
  258. {
  259. { WWPROFILE( "Cinematic Think" );
  260. // If auto fire weapon
  261. if ( Get_Definition().AutoFireWeapon ) {
  262. PhysicalGameObj * enemy = NULL;
  263. Vector3 my_pos;
  264. Get_Position( &my_pos );
  265. // if any enemies can be found in range
  266. SLNode<BaseGameObj> *objnode;
  267. for ( objnode = GameObjManager::Get_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
  268. PhysicalGameObj *obj = objnode->Data()->As_PhysicalGameObj();
  269. if ( obj && obj->Peek_Physical_Object() ) { // zones have no phy obj CHANGE THIS
  270. if ( obj == this ) {
  271. continue;
  272. }
  273. if ( Is_Teammate( obj ) ) {
  274. continue;
  275. }
  276. Vector3 v;
  277. obj->Get_Position(&v);
  278. v -= my_pos;
  279. if ( v.Length() < Get_Weapon()->Get_Range() ) {
  280. enemy = obj;
  281. }
  282. }
  283. }
  284. if ( enemy != NULL ) {
  285. Vector3 enemy_pos;
  286. enemy->Get_Position( &enemy_pos );
  287. enemy_pos.Z += 1;
  288. if ( Set_Targeting( enemy_pos ) == false ) {
  289. Get_Weapon()->Set_Primary_Triggered( false );
  290. } else {
  291. Get_Weapon()->Set_Primary_Triggered( true ); // Fire Primary
  292. }
  293. } else {
  294. Get_Weapon()->Set_Primary_Triggered( false );
  295. }
  296. }
  297. if ( Get_Definition().CameraRelative && COMBAT_CAMERA != NULL ) {
  298. Matrix3D tm = COMBAT_CAMERA->Get_Transform();
  299. tm.Rotate_Z( DEG_TO_RADF(90.0) );
  300. tm.Rotate_Y( DEG_TO_RADF(90.0) );
  301. Set_Transform( tm );
  302. }
  303. }
  304. ArmedGameObj::Think();
  305. }
  306. void CinematicGameObj::Post_Think( void )
  307. {
  308. ArmedGameObj::Post_Think();
  309. WWPROFILE( "Cinematic PostThink" );
  310. // Animation is handled by the DynamicAnimPhysClass for this class
  311. WWASSERT(Get_Anim_Control() == NULL);
  312. if (Get_Definition().DestroyAfterAnimation) {
  313. PhysClass * pobj = Peek_Physical_Object();
  314. if (pobj != NULL) {
  315. DynamicAnimPhysClass * dpobj = pobj->As_DynamicAnimPhysClass();
  316. if ((dpobj != NULL) &&
  317. (dpobj->Get_Animation_Manager().Peek_Animation() != NULL) &&
  318. (dpobj->Get_Animation_Manager().Is_At_Target()) )
  319. {
  320. Set_Delete_Pending();
  321. }
  322. }
  323. }
  324. }
  325. void CinematicGameObj::Completely_Damaged( const OffenseObjectClass & damager )
  326. {
  327. if ( Get_Definition().KilledExplosion != 0 ) {
  328. Vector3 pos;
  329. Get_Position(&pos);
  330. WWASSERT(pos.Is_Valid());// most likely candidate for explosion damage bug....?
  331. // If the object has a moving bounding box, use its center point for the explosion
  332. RenderObjClass * model = Peek_Model();
  333. if (model != NULL) {
  334. RenderObjClass * bbox = model->Get_Sub_Object_By_Name("BoundingBox");
  335. if (bbox != NULL) {
  336. Matrix3D bbox_tm = bbox->Get_Transform();
  337. bbox_tm.Get_Translation(&pos);
  338. REF_PTR_RELEASE(bbox);
  339. }
  340. }
  341. ExplosionManager::Create_Explosion_At( Get_Definition().KilledExplosion, pos, damager.Get_Owner() ); // no one gets credit for this
  342. }
  343. Set_Delete_Pending();
  344. }
  345. float CinematicGameObj::Get_Animation_Length( void )
  346. {
  347. float length = 0;
  348. //
  349. // Try to get the dynamic anim phys object from the physics object
  350. //
  351. PhysClass *phys_obj = Peek_Physical_Object();
  352. if (phys_obj != NULL) {
  353. DynamicAnimPhysClass * dynamic_anim_phys = phys_obj->As_DynamicAnimPhysClass();
  354. if (dynamic_anim_phys != NULL) {
  355. //
  356. // Peek at this object's animation
  357. //
  358. AnimCollisionManagerClass &anim_mgr = dynamic_anim_phys->Get_Animation_Manager();
  359. HAnimClass *anim = anim_mgr.Peek_Animation();
  360. if (anim != NULL) {
  361. //
  362. // Return the length of the animation to the caller
  363. //
  364. length = anim->Get_Total_Time();
  365. }
  366. }
  367. }
  368. return length;
  369. }
  370. /*
  371. void
  372. CinematicGameObj::Import_Creation( BitStreamClass &packet )
  373. {
  374. ArmedGameObj::Import_Creation (packet);
  375. return ;
  376. }
  377. */
  378. void CinematicGameObj::Export_Rare( BitStreamClass &packet )
  379. {
  380. ArmedGameObj::Export_Rare( packet );
  381. StringClass animation_name;
  382. AnimCollisionManagerClass::AnimModeType anim_mode = AnimCollisionManagerClass::ANIMATE_TARGET;
  383. //
  384. // Dig the animation data out of the physics object
  385. //
  386. DynamicAnimPhysClass *dynanim = Peek_Physical_Object()->As_DynamicAnimPhysClass();
  387. if (dynanim != NULL) {
  388. AnimCollisionManagerClass &anim_mgr = dynanim->Get_Animation_Manager();
  389. //
  390. // Get the animation name
  391. //
  392. HAnimClass *anim = anim_mgr.Peek_Animation();
  393. if (anim != NULL) {
  394. animation_name = anim->Get_Name();
  395. }
  396. //
  397. // Get the animation mode
  398. //
  399. anim_mode = anim_mgr.Get_Animation_Mode ();
  400. }
  401. //
  402. // Send the animation data to the client
  403. //
  404. packet.Add_Terminated_String( (const char *)animation_name, true );
  405. packet.Add( anim_mode );
  406. return ;
  407. }
  408. void CinematicGameObj::Import_Rare( BitStreamClass &packet )
  409. {
  410. ArmedGameObj::Import_Rare( packet );
  411. //
  412. // Get information about the animation
  413. //
  414. StringClass animation_name;
  415. int anim_mode = AnimCollisionManagerClass::ANIMATE_TARGET;
  416. packet.Get_Terminated_String( animation_name.Get_Buffer( 256 ), 256, true );
  417. packet.Get( anim_mode );
  418. //
  419. // Pass the animation information onto the controller
  420. //
  421. DynamicAnimPhysClass *dynanim = Peek_Physical_Object()->As_DynamicAnimPhysClass();
  422. if (dynanim != NULL) {
  423. AnimCollisionManagerClass &anim_mgr = dynanim->Get_Animation_Manager();
  424. anim_mgr.Set_Animation( animation_name );
  425. anim_mgr.Set_Animation_Mode( (AnimCollisionManagerClass::AnimModeType)anim_mode );
  426. }
  427. return ;
  428. }