weaponview.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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/weaponview.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 1/16/02 11:46a $*
  29. * *
  30. * $Revision:: 56 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "weaponview.h"
  36. #include "assets.h"
  37. #include "hanim.h"
  38. #include "combat.h"
  39. #include "pscene.h"
  40. #include "ccamera.h"
  41. #include "texture.h"
  42. #include "physicalgameobj.h"
  43. #include "debug.h"
  44. #include "animobj.h"
  45. #include "soldier.h"
  46. #include "wwprofile.h"
  47. #include "weapons.h"
  48. #include "decophys.h"
  49. #include "stealtheffect.h"
  50. #include "animcontrol.h"
  51. /*
  52. **
  53. */
  54. enum {
  55. WEAPON_STATE_IDLE,
  56. WEAPON_STATE_FIRE,
  57. WEAPON_STATE_RELOAD,
  58. WEAPON_STATE_ENTER,
  59. WEAPON_STATE_EXIT,
  60. // WEAPON_STATE_SPIN_DOWN,
  61. NUM_WEAPON_STATES,
  62. };
  63. int WeaponViewEnabled;
  64. int WeaponState;
  65. bool LastMuzzleFlash;
  66. DecorationPhysClass*HandsPhysObj;
  67. RenderObjClass* WeaponModel;
  68. RenderObjClass* ClipModel;
  69. Vector3 HandsOffset;
  70. HAnimClass * HandsAnims[ NUM_WEAPON_STATES ];
  71. HAnimClass * WeaponAnims[ NUM_WEAPON_STATES ];
  72. // Anim controls that provide blending
  73. SimpleAnimControlClass HandAnimControl;
  74. SimpleAnimControlClass WeaponAnimControl;
  75. // Hands Bob
  76. enum {
  77. BOB_NONE,
  78. BOB_IDLE,
  79. BOB_WALK,
  80. BOB_RUN,
  81. };
  82. int BobState;
  83. HTreeClass * BobHTree;
  84. HAnimClass * BobHAnim;
  85. float BobFrame;
  86. float BobRecoil;
  87. static void Set_Bob( int bob_state );
  88. static void Set_Bob_Recoil( float amount );
  89. static void Aquire_Hands_Assets( void );
  90. static void Release_Hands_Assets( void );
  91. static void Aquire_Weapon_Assets( const WeaponClass * weapon );
  92. static void Release_Weapon_Assets( void );
  93. /*
  94. **
  95. */
  96. void WeaponViewClass::Init()
  97. {
  98. WeaponModel = NULL;
  99. HandsPhysObj = NULL;
  100. HandAnimControl.Set_Model( NULL );
  101. WeaponAnimControl.Set_Model( NULL );
  102. ClipModel = NULL;
  103. for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
  104. WeaponAnims[i] = NULL;
  105. HandsAnims[i] = NULL;
  106. }
  107. WeaponState = -1;
  108. BobState = BOB_NONE;
  109. BobHTree = NULL;
  110. BobHAnim = NULL;
  111. BobFrame = 0;
  112. BobRecoil = 0;
  113. WeaponViewEnabled = false;
  114. }
  115. /*
  116. **
  117. */
  118. void WeaponViewClass::Shutdown()
  119. {
  120. Set_Bob( BOB_NONE );
  121. Release_Weapon_Assets();
  122. Release_Hands_Assets();
  123. }
  124. /*
  125. **
  126. */
  127. void WeaponViewClass::Reset()
  128. {
  129. Set_Bob( BOB_NONE );
  130. Release_Weapon_Assets();
  131. Release_Hands_Assets();
  132. }
  133. enum {
  134. CHUNKID_VARIABLES = 730011054,
  135. MICROCHUNKID_HANDS_PHYS_OBJ = 1,
  136. MICROCHUNKID_ENABLED,
  137. };
  138. bool WeaponViewClass::Save( ChunkSaveClass &csave )
  139. {
  140. csave.Begin_Chunk( CHUNKID_VARIABLES );
  141. // If the scene has our hands, we must save and swizzle them
  142. if ( HandsPhysObj != NULL && COMBAT_SCENE->Contains( HandsPhysObj ) ) {
  143. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HANDS_PHYS_OBJ, HandsPhysObj );
  144. }
  145. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ENABLED, WeaponViewEnabled );
  146. csave.End_Chunk();
  147. return true;
  148. }
  149. bool WeaponViewClass::Load( ChunkLoadClass &cload )
  150. {
  151. Release_Weapon_Assets();
  152. Release_Hands_Assets();
  153. while (cload.Open_Chunk()) {
  154. switch(cload.Cur_Chunk_ID()) {
  155. case CHUNKID_VARIABLES:
  156. {
  157. while (cload.Open_Micro_Chunk()) {
  158. switch(cload.Cur_Micro_Chunk_ID()) {
  159. READ_MICRO_CHUNK( cload, MICROCHUNKID_HANDS_PHYS_OBJ, HandsPhysObj );
  160. READ_MICRO_CHUNK( cload, MICROCHUNKID_ENABLED, WeaponViewEnabled );
  161. default:
  162. Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
  163. break;
  164. }
  165. cload.Close_Micro_Chunk();
  166. }
  167. break;
  168. }
  169. default:
  170. Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  171. break;
  172. }
  173. cload.Close_Chunk();
  174. }
  175. if ( HandsPhysObj != NULL ) {
  176. REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&HandsPhysObj);
  177. }
  178. return true;
  179. }
  180. /*
  181. **
  182. */
  183. void WeaponViewClass::Enable( bool enable )
  184. {
  185. WeaponViewEnabled = enable;
  186. }
  187. /*
  188. ** called each time through the main loop
  189. */
  190. void WeaponViewClass::Think()
  191. {
  192. WWPROFILE( "WeaponView Think" );
  193. bool bail = false;
  194. if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Star_Sniping() ) {
  195. bail = true;
  196. }
  197. if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Using_Host_Model() ) {
  198. bail = true;
  199. }
  200. if ( COMBAT_STAR == NULL ) {
  201. bail = true;
  202. }
  203. if ( !WeaponViewEnabled ) {
  204. bail = true;
  205. }
  206. // No first person weapon in vehicles
  207. if ( COMBAT_STAR && COMBAT_STAR->Get_Vehicle() != NULL ) {
  208. bail = true;
  209. }
  210. // not if in trans (camera lerping )
  211. if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Lerping() ) {
  212. bail = true;
  213. }
  214. WeaponClass * weapon = NULL;
  215. if ( COMBAT_STAR != NULL ) {
  216. weapon = COMBAT_STAR->Get_Weapon();
  217. }
  218. if ( weapon == NULL && WeaponModel == NULL ) {
  219. bail = true;
  220. }
  221. if ( weapon != NULL ) {
  222. if ( ( weapon->Get_Style() == WEAPON_HOLD_STYLE_C4 ) ||
  223. ( weapon->Get_Style() == WEAPON_HOLD_STYLE_BEACON ) ) {
  224. if ( weapon->Get_Total_Rounds() == 0 ) {
  225. if ( WeaponModel == NULL || WeaponState == WEAPON_STATE_IDLE ) {
  226. bail = true;
  227. }
  228. }
  229. }
  230. }
  231. // If not in first person mode, hide the model and bail
  232. if ( bail ) {
  233. if ( HandsPhysObj != NULL && COMBAT_SCENE->Contains( HandsPhysObj ) ) {
  234. COMBAT_SCENE->Remove_Object( HandsPhysObj );
  235. }
  236. // To force an enter when we come back
  237. WeaponState = WEAPON_STATE_EXIT;
  238. Release_Weapon_Assets();
  239. return;
  240. }
  241. // Setup camera bob
  242. if ( COMBAT_STAR ) {
  243. Vector3 vel;
  244. COMBAT_STAR->Get_Velocity( vel );
  245. if ( vel.Length() > WWMATH_EPSILON ) {
  246. if ( COMBAT_STAR->Is_Slow() ) {
  247. Set_Bob( BOB_WALK );
  248. } else {
  249. Set_Bob( BOB_RUN );
  250. }
  251. } else {
  252. Set_Bob( BOB_IDLE );
  253. }
  254. // Setup weapon State
  255. if ( weapon != NULL && weapon->Is_Firing() ) {
  256. Set_Bob_Recoil( 0.15f );
  257. }
  258. }
  259. // is the current (non-looping) animation completed
  260. bool is_current_complete = true;
  261. #if 0
  262. if ( HandsPhysObj != NULL && (WeaponState != WEAPON_STATE_IDLE) ) {
  263. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  264. if ( hands_model != NULL && ( hands_model->Peek_Animation() != NULL ) &&
  265. ((Animatable3DObjClass*)hands_model)->Is_Animation_Complete() == false ) {
  266. is_current_complete = false;
  267. }
  268. }
  269. #else
  270. if ( HandsPhysObj != NULL && (WeaponState != WEAPON_STATE_IDLE) ) {
  271. is_current_complete = HandAnimControl.Is_Complete();
  272. }
  273. #endif
  274. bool muzzle_flash_on = false;
  275. static bool ForceFireLoop = false;
  276. // What state are we going to?
  277. int new_weapon_state = WEAPON_STATE_IDLE;
  278. if ( COMBAT_STAR ) {
  279. WeaponClass * star_weapon = COMBAT_STAR->Get_Weapon();
  280. if ( star_weapon != NULL ) {
  281. if ( star_weapon->Is_Reloading() ) {
  282. new_weapon_state = WEAPON_STATE_RELOAD;
  283. } else if ( star_weapon->Is_Firing() ) {
  284. if ( WeaponState == WEAPON_STATE_FIRE ) {
  285. ForceFireLoop = true;
  286. }
  287. new_weapon_state = WEAPON_STATE_FIRE;
  288. if ( WeaponState == WEAPON_STATE_RELOAD ) {
  289. is_current_complete = true; // Force a fire during reload
  290. }
  291. muzzle_flash_on = true;
  292. if ( WeaponModel != NULL ) {
  293. // if this gun has an eject bone, eject a shell.
  294. int eject_index = WeaponModel->Get_Bone_Index( "eject" );
  295. if ( eject_index > 0 ) {
  296. star_weapon->Make_Shell_Eject( WeaponModel->Get_Bone_Transform( eject_index ) );
  297. }
  298. }
  299. }
  300. }
  301. }
  302. const char* cur_weapon_model_name="";
  303. if ( WeaponModel ) {
  304. cur_weapon_model_name = WeaponModel->Get_Name();
  305. }
  306. StringClass new_weapon_model_name(true);
  307. if ( weapon ) {
  308. Get_Render_Obj_Name_From_Filename( new_weapon_model_name, weapon->Get_First_Person_Model_Name() );
  309. }
  310. // If we need to change the assets,
  311. if ( stricmp( cur_weapon_model_name,new_weapon_model_name)!=0) {
  312. // if ( cur_weapon_model_name.Compare_No_Case( new_weapon_model_name ) != 0 ) {
  313. // If we don't have a weapon, switch!
  314. if ( WeaponModel == NULL ) {
  315. WeaponState = WEAPON_STATE_EXIT;
  316. is_current_complete = true;
  317. }
  318. if ( WeaponState != WEAPON_STATE_EXIT ) { // If we have a current weapon, exit it
  319. new_weapon_state = WEAPON_STATE_EXIT;
  320. } else {
  321. if ( is_current_complete ) {
  322. // If we are done exiting, switch and enter
  323. Release_Weapon_Assets();
  324. Aquire_Weapon_Assets( COMBAT_STAR->Get_Weapon() );
  325. new_weapon_state = WEAPON_STATE_ENTER;
  326. }
  327. }
  328. }
  329. if ( WeaponModel ) {
  330. // Update the muzzle flash
  331. RenderObjClass * model = WeaponModel;
  332. if ( model && (LastMuzzleFlash != muzzle_flash_on)) {
  333. for (int i=0; i<model->Get_Num_Sub_Objects(); i++) {
  334. RenderObjClass * robj = model->Get_Sub_Object(i);
  335. if (strstr(robj->Get_Name(),"MUZZLEFLASH") || strstr(robj->Get_Name(),"MZ")) {
  336. robj->Set_Hidden( !muzzle_flash_on );
  337. }
  338. robj->Release_Ref();
  339. }
  340. LastMuzzleFlash = muzzle_flash_on;
  341. }
  342. }
  343. if ( HandsPhysObj != NULL && WeaponModel != NULL ) {
  344. // make sure the "hands" object has the stealth effect
  345. if (COMBAT_STAR->Peek_Stealth_Effect() != NULL) {
  346. HandsPhysObj->Add_Effect_To_Me(COMBAT_STAR->Peek_Stealth_Effect());
  347. }
  348. // Add all rendobjs from the scene
  349. if ( !COMBAT_SCENE->Contains( HandsPhysObj ) ) {
  350. COMBAT_SCENE->Add_Dynamic_Object( HandsPhysObj );
  351. if ( new_weapon_state == WEAPON_STATE_ENTER ) {
  352. new_weapon_state = WEAPON_STATE_IDLE;
  353. is_current_complete = true;
  354. }
  355. }
  356. // When stopping, go to spin down
  357. if ( is_current_complete &&
  358. WeaponState == WEAPON_STATE_FIRE &&
  359. new_weapon_state == WEAPON_STATE_IDLE ) {
  360. // if the anims exist...
  361. // new_weapon_state = WEAPON_STATE_SPIN_DOWN;
  362. }
  363. if ( WeaponState != WEAPON_STATE_IDLE ) {
  364. if ( is_current_complete ) {
  365. // If done playing the current non-looping anim, go to next state
  366. if ( WeaponState == WEAPON_STATE_FIRE && ForceFireLoop ) {
  367. ForceFireLoop = false; // Clear any force fire
  368. // Keep it by restarting the fire anim
  369. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  370. if ( hands_model != NULL ) {
  371. // hands_model->Set_Animation( HandsAnims[ WeaponState ], 0, RenderObjClass::ANIM_MODE_ONCE );
  372. HandAnimControl.Set_Animation( HandsAnims[ WeaponState ] );
  373. HandAnimControl.Set_Mode( ANIM_MODE_ONCE, 0 );
  374. HandAnimControl.Update(0);
  375. }
  376. // WeaponModel->Set_Animation( WeaponAnims[ WeaponState ], 0, RenderObjClass::ANIM_MODE_ONCE );
  377. WeaponAnimControl.Set_Animation( WeaponAnims[ WeaponState ] );
  378. WeaponAnimControl.Set_Mode( ANIM_MODE_ONCE, 0 );
  379. WeaponAnimControl.Update(0);
  380. } else {
  381. WeaponState = -1;
  382. }
  383. }
  384. }
  385. if ( new_weapon_state == WEAPON_STATE_EXIT ) {
  386. WeaponState = -1; // force a change
  387. }
  388. // If playing a looping anim, switch if needed
  389. if ( (WeaponState == -1) || ( WeaponState == WEAPON_STATE_IDLE ) ) {
  390. if ( new_weapon_state != WeaponState ) {
  391. WeaponState = new_weapon_state;
  392. float anim_blend_time = 0.15f;
  393. if ( new_weapon_state == WEAPON_STATE_FIRE ) {
  394. anim_blend_time = 0; // No blend when firing
  395. }
  396. int mode = ( WeaponState == WEAPON_STATE_IDLE ) ? RenderObjClass::ANIM_MODE_LOOP : RenderObjClass::ANIM_MODE_ONCE;
  397. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  398. if ( hands_model != NULL ) {
  399. mode = ( WeaponState == WEAPON_STATE_IDLE ) ? ANIM_MODE_LOOP : ANIM_MODE_ONCE;
  400. // hands_model->Set_Animation( HandsAnims[ WeaponState ], 0, mode );
  401. HandAnimControl.Set_Animation( HandsAnims[ WeaponState ], anim_blend_time );
  402. HandAnimControl.Set_Mode( (AnimMode)mode );
  403. }
  404. // WeaponModel->Set_Animation( WeaponAnims[ WeaponState ], 0, mode );
  405. WeaponAnimControl.Set_Animation( WeaponAnims[ WeaponState ], anim_blend_time );
  406. mode = ( WeaponState == WEAPON_STATE_IDLE ) ? ANIM_MODE_LOOP : ANIM_MODE_ONCE;
  407. WeaponAnimControl.Set_Mode( (AnimMode)mode );
  408. // if ( HandsAnims[ WeaponState ] != NULL ) {
  409. // Debug_Say(( "Playing %s\n", HandsAnims[ WeaponState ]->Get_Name() ));
  410. // }
  411. }
  412. }
  413. // Lets put the gun relative to the camera
  414. Matrix3D tm = COMBAT_CAMERA->Get_Transform();
  415. // Add bobing position
  416. if ( BobHTree != NULL && BobHAnim != NULL ) {
  417. BobFrame += TimeManager::Get_Frame_Seconds() * BobHAnim->Get_Frame_Rate();
  418. if ( BobFrame > BobHAnim->Get_Num_Frames()-1 ) {
  419. BobFrame -= BobHAnim->Get_Num_Frames()-1;
  420. }
  421. #if 0 // no more programatic recoil
  422. tm.Translate( 0, 0, BobRecoil );
  423. if ( BobRecoil > 0 ) {
  424. BobRecoil -= TimeManager::Get_Frame_Real_Seconds() * 2;
  425. if ( BobRecoil < 0 ) {
  426. BobRecoil = 0;
  427. }
  428. }
  429. #endif
  430. BobHTree->Anim_Update( tm, BobHAnim, BobFrame );
  431. // Now get the camera bone
  432. // Debug_Say(( "%f %f %f\n", tm.Get_Translation().X, tm.Get_Translation().Y, tm.Get_Translation().Z ));
  433. tm = BobHTree->Get_Transform( BobHTree->Get_Bone_Index( "CAMERA" ) );
  434. // Debug_Say(( "%f %f %f\n", tm.Get_Translation().X, tm.Get_Translation().Y, tm.Get_Translation().Z ));
  435. }
  436. // Convert from camera to world convention
  437. tm.Rotate_Z( DEG_TO_RADF(90.0) );
  438. tm.Rotate_Y( DEG_TO_RADF(90.0) );
  439. Vector3 fp_offset = HandsOffset + COMBAT_CAMERA->Get_First_Person_Offset_Tweak();
  440. tm.Translate( fp_offset );
  441. //WWASSERT(COMBAT_STAR != NULL);//TSS
  442. if (COMBAT_STAR != NULL) {
  443. //
  444. // COMBAT_STAR may be NULL during MP game intermission
  445. //
  446. Matrix3D obj_convention_camera = COMBAT_CAMERA->Get_Transform();
  447. obj_convention_camera.Rotate_Z( DEG_TO_RADF(90.0) );
  448. obj_convention_camera.Rotate_Y( DEG_TO_RADF(90.0) );
  449. Vector3 camera_space_target;
  450. Vector3 camera_space_source;
  451. Vector3 target_pos = COMBAT_STAR->Get_Targeting_Pos();
  452. // Always look at a point a constant distance ahead, to avoid the gun poping around
  453. target_pos = COMBAT_CAMERA->Get_Transform() * Vector3( 0,0,-100 );
  454. Matrix3D::Inverse_Transform_Vector( obj_convention_camera, target_pos, &camera_space_target );
  455. Matrix3D::Inverse_Transform_Vector( obj_convention_camera, tm.Get_Translation(), &camera_space_source );
  456. Matrix3D camera_space_aim;
  457. camera_space_aim.Obj_Look_At( camera_space_source, camera_space_target, 0 );
  458. Matrix3D::Multiply( obj_convention_camera, camera_space_aim, &tm );
  459. }
  460. HandsPhysObj->Set_Transform( tm );
  461. // Now, pull the hands backwards enough to clear any walls
  462. if ( WeaponModel && COMBAT_CAMERA) {
  463. const Matrix3D & muzzle_tm = WeaponModel->Get_Bone_Transform( "muzzlea0" );
  464. Vector3 ray_end = muzzle_tm * Vector3( 0.1f, 0, 0 );
  465. Vector3 ray_start = COMBAT_CAMERA->Get_Transform().Get_Translation();
  466. ray_start.Z = ray_end.Z;
  467. LineSegClass ray;
  468. ray.Set( ray_start, ray_end );
  469. CastResultStruct result;
  470. PhysRayCollisionTestClass raytest(ray, &result, BULLET_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
  471. {
  472. if (COMBAT_STAR != NULL && COMBAT_STAR->Peek_Physical_Object()!=NULL) {
  473. COMBAT_STAR->Peek_Physical_Object()->Inc_Ignore_Counter();
  474. }
  475. WWPROFILE( "Cast Ray" );
  476. WWASSERT(COMBAT_SCENE != NULL);
  477. COMBAT_SCENE->Cast_Ray( raytest );
  478. if (COMBAT_STAR != NULL && COMBAT_STAR->Peek_Physical_Object()!=NULL) {
  479. COMBAT_STAR->Peek_Physical_Object()->Dec_Ignore_Counter();
  480. }
  481. }
  482. /* if ( raytest.CollidedPhysObj != NULL && raytest.CollidedPhysObj->Get_Observer() != NULL ) {
  483. DamageableGameObj * obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_DamageableGameObj();
  484. if ( obj ) {
  485. Debug_Say(( "Hit %s\n", obj->Get_Definition().Get_Name() ));
  486. }
  487. }*/
  488. // Determine the Camera Target Point and object
  489. Vector3 collision_pt;
  490. ray.Compute_Point( raytest.Result->Fraction, &collision_pt );
  491. collision_pt -= ray_end;
  492. float pullback = collision_pt.Length();
  493. // Debug_Say(( "Pullback = %f\n", pullback ));
  494. tm.Translate( Vector3( -pullback, 0, 0 ) );
  495. HandsPhysObj->Set_Transform( tm );
  496. }
  497. }
  498. if ( HandsPhysObj && HandsPhysObj->Peek_Model() ) {
  499. HandAnimControl.Update( TimeManager::Get_Frame_Seconds() );
  500. }
  501. if ( WeaponModel ) {
  502. WeaponAnimControl.Update( TimeManager::Get_Frame_Seconds() );
  503. }
  504. }
  505. Vector3 WeaponViewClass::Get_Muzzle_Pos()
  506. {
  507. if ( WeaponModel ) {
  508. return WeaponModel->Get_Bone_Transform( "muzzlea0" ).Get_Translation();
  509. }
  510. return COMBAT_CAMERA->Get_Transform().Get_Translation();
  511. }
  512. const char * WeaponActionNames[ NUM_WEAPON_STATES ] = {
  513. "IDLE", //WEAPON_STATE_IDLE,
  514. "FIRE", //WEAPON_STATE_FIRE,
  515. "RELOD", //WEAPON_STATE_RELOAD,
  516. "ENTER", //WEAPON_STATE_ENTER,
  517. "EXIT", //WEAPON_STATE_EXIT,
  518. // "EFIRE", //WEAPON_STATE_SPIN_DOWN,
  519. };
  520. /*
  521. ** Get and release the Weapon specific assets
  522. ** Each weapon has a name ie: PIST
  523. ** The weapon model is in the form F_GM_<NAME> ie: F_GM_PIST
  524. ** The clip model is in the form F_CM_<NAME> ie: F_CM_PIST
  525. ** The weapon states are IDLE, FIRE, RELOAD, ENTER, EXIT
  526. ** For each weapon state, except ENTER and EXIT, we have a weapon anim tied to the weapon model (use IDLE anim for ENTER/EXIT )
  527. ** The weapon anims are in the form F_GA_<NAME>_<STATE> ie: F_GA_PIST_IDLE, F_GA_PIST_FIRE
  528. ** For each weapon state, we have a hand anim tied to the F_SKELETON
  529. ** The hand anims are in the form F_GA_<NAME>_<STATE> ie: F_GA_PIST_IDLE, F_GA_PIST_FIRE
  530. ** Weapon anims should be the same duration (number of frames) and the corresponding hand anim (except looping +IDLES)
  531. */
  532. static void Aquire_Weapon_Assets( const WeaponClass * weapon )
  533. {
  534. if ( HandsPhysObj == NULL ) {
  535. Aquire_Hands_Assets();
  536. } else {
  537. HandAnimControl.Set_Model( HandsPhysObj->Peek_Model() );
  538. HandAnimControl.Set_Animation( (HAnimClass*)NULL );
  539. }
  540. if ( HandsPhysObj == NULL || HandsPhysObj->Peek_Model() == NULL ) {
  541. return;
  542. }
  543. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  544. StringClass weapon_name;
  545. if ( weapon ) {
  546. // Debug_Say(( "Loading Weapon from %s\n", weapon->Get_First_Person_Model_Name() ));
  547. WeaponModel = ::Create_Render_Obj_From_Filename( weapon->Get_First_Person_Model_Name() );
  548. LastMuzzleFlash = true; // force it off
  549. // Debug_Say(( "Loaded %s\n", WeaponModel ? WeaponModel->Get_Name() : "NONE" ));
  550. // Use model name
  551. if ( WeaponModel != NULL ) {
  552. weapon_name = WeaponModel->Get_Name() + 5; // Get the weapon name from the model
  553. Debug_Say(( "weapon_name is %s\n", (const char *)weapon_name ));
  554. StringClass clip_name;
  555. clip_name = WeaponModel->Get_Name();
  556. if ( clip_name.Get_Length() > 4 ) {
  557. clip_name[2] = 'C';
  558. clip_name[3] = 'M';
  559. }
  560. ClipModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj( clip_name );
  561. if ( ClipModel != NULL ) {
  562. hands_model->Add_Sub_Object_To_Bone( ClipModel, "CLIPBONE" );
  563. }
  564. }
  565. }
  566. WeaponAnimControl.Set_Model( WeaponModel );
  567. WeaponAnimControl.Set_Animation( (HAnimClass*)NULL );
  568. if ( WeaponModel != NULL ) {
  569. // Add the model
  570. hands_model->Add_Sub_Object_To_Bone( WeaponModel, "GUNBONE" );
  571. HandsOffset = weapon->Get_First_Person_Model_Offset();
  572. StringClass weapon_htree_name;
  573. if ( WeaponModel->Get_HTree() != NULL ) {
  574. weapon_htree_name = WeaponModel->Get_HTree()->Get_Name();
  575. }
  576. SET_REF_OWNER( WeaponModel );
  577. for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
  578. StringClass anim_name;
  579. // Get Weapon Anims, use the idle anim for enter and exit
  580. int state = ( i >= WEAPON_STATE_ENTER ) ? WEAPON_STATE_IDLE : i;
  581. anim_name.Format( "%s.F_GA_%s_%s", weapon_htree_name, weapon_name, WeaponActionNames[state] );
  582. // Debug_Say(( "Loading Weapon Anim %s\n", anim_name ));
  583. WeaponAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( anim_name );
  584. if ( WeaponAnims[i] == NULL ) {
  585. Debug_Say(( "Missing Weapon Anim %s\n", anim_name ));
  586. }
  587. // Get Hands Anims
  588. anim_name.Format( "F_SKELETON.F_HA_%s_%s", weapon_name, WeaponActionNames[i] );
  589. // Debug_Say(( "Loading Hands Anim %s\n", anim_name ));
  590. HandsAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( anim_name );
  591. if ( HandsAnims[i] == NULL ) {
  592. Debug_Say(( "Missing Hands Anim %s\n", anim_name ));
  593. HandsAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( "F_SKELETON.F_HA_PIST_IDLE" );
  594. }
  595. }
  596. }
  597. }
  598. static void Release_Weapon_Assets( void )
  599. {
  600. WeaponAnimControl.Set_Model( NULL );
  601. WeaponAnimControl.Set_Animation( (HAnimClass*)NULL );
  602. if ( WeaponModel != NULL ) {
  603. // Remove
  604. WWASSERT( HandsPhysObj != NULL );
  605. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  606. WWASSERT( hands_model != NULL );
  607. hands_model->Remove_Sub_Objects_From_Bone( "GUNBONE" );
  608. WeaponModel->Release_Ref();
  609. WeaponModel = NULL;
  610. }
  611. if ( ClipModel != NULL ) {
  612. // Remove
  613. WWASSERT( HandsPhysObj != NULL );
  614. RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
  615. WWASSERT( hands_model != NULL );
  616. hands_model->Remove_Sub_Objects_From_Bone( "CLIPBONE" );
  617. ClipModel->Release_Ref();
  618. ClipModel = NULL;
  619. }
  620. for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
  621. if ( WeaponAnims[i] != NULL ) {
  622. WeaponAnims[i]->Release_Ref();
  623. WeaponAnims[i] = NULL;
  624. }
  625. if ( HandsAnims[i] != NULL ) {
  626. HandsAnims[i]->Release_Ref();
  627. HandsAnims[i] = NULL;
  628. }
  629. }
  630. }
  631. /*
  632. ** Get and release the Hand assets
  633. ** All hand models are built on the F_SKELETON HTree, which has a GUNBONE and CLIPBONE
  634. ** The hand models can be different for each player model, and are in the form F_HM_XXX ie: F_HM_HAVOC
  635. ** The hand anims are created from the particular weapon model loaded.
  636. */
  637. static void Aquire_Hands_Assets( void )
  638. {
  639. StringClass name = COMBAT_STAR->Get_First_Person_Hands_Model_Name();
  640. // Debug_Say(( "Loading Hands from %s\n", name ));
  641. HandsPhysObj = new DecorationPhysClass();
  642. if ( HandsPhysObj != NULL ) {
  643. HandsPhysObj->Set_Collision_Group( UNCOLLIDEABLE_GROUP );
  644. RenderObjClass * model = ::Create_Render_Obj_From_Filename( name );
  645. if ( model != NULL ) {
  646. HandAnimControl.Set_Model( model );
  647. HandAnimControl.Set_Animation( (HAnimClass*)NULL );
  648. HandsPhysObj->Set_Model( model );
  649. model->Release_Ref();
  650. }
  651. }
  652. }
  653. static void Release_Hands_Assets( void )
  654. {
  655. HandAnimControl.Set_Model( NULL );
  656. HandAnimControl.Set_Animation( (HAnimClass*)NULL );
  657. if ( HandsPhysObj != NULL ) {
  658. if ( COMBAT_SCENE->Contains( HandsPhysObj ) ) {
  659. COMBAT_SCENE->Remove_Object( HandsPhysObj );
  660. }
  661. HandsPhysObj->Release_Ref();
  662. HandsPhysObj = NULL;
  663. }
  664. }
  665. /*
  666. **
  667. */
  668. static const char * BobNames[] = {
  669. "", // BOB_NONE
  670. "F_CA_IDLE", // BOB_IDLE
  671. "F_CA_WALK", // BOB_WALK
  672. "F_CA_RUN", // BOB_RUN
  673. };
  674. static void Set_Bob( int bob_state )
  675. {
  676. if ( BobState != bob_state ) {
  677. BobState = bob_state;
  678. // Release the old copys, if any
  679. BobHTree = NULL;
  680. REF_PTR_RELEASE( BobHAnim );
  681. StringClass name(BobNames[ BobState ],true);
  682. // Debug_Say(( "New Camera Bob State %d \"%s\"\n", BobState, name ));
  683. if ( !name.Is_Empty() ) {
  684. BobHTree = WW3DAssetManager::Get_Instance()->Get_HTree( name );
  685. StringClass anim(0,true);
  686. anim.Format( "%s.%s", name,name );
  687. BobHAnim = WW3DAssetManager::Get_Instance()->Get_HAnim( anim );
  688. }
  689. }
  690. }
  691. static void Set_Bob_Recoil( float amount )
  692. {
  693. BobRecoil = amount;
  694. }