This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Combat/weaponview.cpp

848 lines
24 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Combat/weaponview.cpp $*
* *
* $Author:: Byon_g $*
* *
* $Modtime:: 1/16/02 11:46a $*
* *
* $Revision:: 56 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "weaponview.h"
#include "assets.h"
#include "hanim.h"
#include "combat.h"
#include "pscene.h"
#include "ccamera.h"
#include "texture.h"
#include "physicalgameobj.h"
#include "debug.h"
#include "animobj.h"
#include "soldier.h"
#include "wwprofile.h"
#include "weapons.h"
#include "decophys.h"
#include "stealtheffect.h"
#include "animcontrol.h"
/*
**
*/
enum {
WEAPON_STATE_IDLE,
WEAPON_STATE_FIRE,
WEAPON_STATE_RELOAD,
WEAPON_STATE_ENTER,
WEAPON_STATE_EXIT,
// WEAPON_STATE_SPIN_DOWN,
NUM_WEAPON_STATES,
};
int WeaponViewEnabled;
int WeaponState;
bool LastMuzzleFlash;
DecorationPhysClass*HandsPhysObj;
RenderObjClass* WeaponModel;
RenderObjClass* ClipModel;
Vector3 HandsOffset;
HAnimClass * HandsAnims[ NUM_WEAPON_STATES ];
HAnimClass * WeaponAnims[ NUM_WEAPON_STATES ];
// Anim controls that provide blending
SimpleAnimControlClass HandAnimControl;
SimpleAnimControlClass WeaponAnimControl;
// Hands Bob
enum {
BOB_NONE,
BOB_IDLE,
BOB_WALK,
BOB_RUN,
};
int BobState;
HTreeClass * BobHTree;
HAnimClass * BobHAnim;
float BobFrame;
float BobRecoil;
static void Set_Bob( int bob_state );
static void Set_Bob_Recoil( float amount );
static void Aquire_Hands_Assets( void );
static void Release_Hands_Assets( void );
static void Aquire_Weapon_Assets( const WeaponClass * weapon );
static void Release_Weapon_Assets( void );
/*
**
*/
void WeaponViewClass::Init()
{
WeaponModel = NULL;
HandsPhysObj = NULL;
HandAnimControl.Set_Model( NULL );
WeaponAnimControl.Set_Model( NULL );
ClipModel = NULL;
for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
WeaponAnims[i] = NULL;
HandsAnims[i] = NULL;
}
WeaponState = -1;
BobState = BOB_NONE;
BobHTree = NULL;
BobHAnim = NULL;
BobFrame = 0;
BobRecoil = 0;
WeaponViewEnabled = false;
}
/*
**
*/
void WeaponViewClass::Shutdown()
{
Set_Bob( BOB_NONE );
Release_Weapon_Assets();
Release_Hands_Assets();
}
/*
**
*/
void WeaponViewClass::Reset()
{
Set_Bob( BOB_NONE );
Release_Weapon_Assets();
Release_Hands_Assets();
}
enum {
CHUNKID_VARIABLES = 730011054,
MICROCHUNKID_HANDS_PHYS_OBJ = 1,
MICROCHUNKID_ENABLED,
};
bool WeaponViewClass::Save( ChunkSaveClass &csave )
{
csave.Begin_Chunk( CHUNKID_VARIABLES );
// If the scene has our hands, we must save and swizzle them
if ( HandsPhysObj != NULL && COMBAT_SCENE->Contains( HandsPhysObj ) ) {
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_HANDS_PHYS_OBJ, HandsPhysObj );
}
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ENABLED, WeaponViewEnabled );
csave.End_Chunk();
return true;
}
bool WeaponViewClass::Load( ChunkLoadClass &cload )
{
Release_Weapon_Assets();
Release_Hands_Assets();
while (cload.Open_Chunk()) {
switch(cload.Cur_Chunk_ID()) {
case CHUNKID_VARIABLES:
{
while (cload.Open_Micro_Chunk()) {
switch(cload.Cur_Micro_Chunk_ID()) {
READ_MICRO_CHUNK( cload, MICROCHUNKID_HANDS_PHYS_OBJ, HandsPhysObj );
READ_MICRO_CHUNK( cload, MICROCHUNKID_ENABLED, WeaponViewEnabled );
default:
Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Micro_Chunk();
}
break;
}
default:
Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
break;
}
cload.Close_Chunk();
}
if ( HandsPhysObj != NULL ) {
REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&HandsPhysObj);
}
return true;
}
/*
**
*/
void WeaponViewClass::Enable( bool enable )
{
WeaponViewEnabled = enable;
}
/*
** called each time through the main loop
*/
void WeaponViewClass::Think()
{
WWPROFILE( "WeaponView Think" );
bool bail = false;
if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Star_Sniping() ) {
bail = true;
}
if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Using_Host_Model() ) {
bail = true;
}
if ( COMBAT_STAR == NULL ) {
bail = true;
}
if ( !WeaponViewEnabled ) {
bail = true;
}
// No first person weapon in vehicles
if ( COMBAT_STAR && COMBAT_STAR->Get_Vehicle() != NULL ) {
bail = true;
}
// not if in trans (camera lerping )
if ( COMBAT_CAMERA && COMBAT_CAMERA->Is_Lerping() ) {
bail = true;
}
WeaponClass * weapon = NULL;
if ( COMBAT_STAR != NULL ) {
weapon = COMBAT_STAR->Get_Weapon();
}
if ( weapon == NULL && WeaponModel == NULL ) {
bail = true;
}
if ( weapon != NULL ) {
if ( ( weapon->Get_Style() == WEAPON_HOLD_STYLE_C4 ) ||
( weapon->Get_Style() == WEAPON_HOLD_STYLE_BEACON ) ) {
if ( weapon->Get_Total_Rounds() == 0 ) {
if ( WeaponModel == NULL || WeaponState == WEAPON_STATE_IDLE ) {
bail = true;
}
}
}
}
// If not in first person mode, hide the model and bail
if ( bail ) {
if ( HandsPhysObj != NULL && COMBAT_SCENE->Contains( HandsPhysObj ) ) {
COMBAT_SCENE->Remove_Object( HandsPhysObj );
}
// To force an enter when we come back
WeaponState = WEAPON_STATE_EXIT;
Release_Weapon_Assets();
return;
}
// Setup camera bob
if ( COMBAT_STAR ) {
Vector3 vel;
COMBAT_STAR->Get_Velocity( vel );
if ( vel.Length() > WWMATH_EPSILON ) {
if ( COMBAT_STAR->Is_Slow() ) {
Set_Bob( BOB_WALK );
} else {
Set_Bob( BOB_RUN );
}
} else {
Set_Bob( BOB_IDLE );
}
// Setup weapon State
if ( weapon != NULL && weapon->Is_Firing() ) {
Set_Bob_Recoil( 0.15f );
}
}
// is the current (non-looping) animation completed
bool is_current_complete = true;
#if 0
if ( HandsPhysObj != NULL && (WeaponState != WEAPON_STATE_IDLE) ) {
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
if ( hands_model != NULL && ( hands_model->Peek_Animation() != NULL ) &&
((Animatable3DObjClass*)hands_model)->Is_Animation_Complete() == false ) {
is_current_complete = false;
}
}
#else
if ( HandsPhysObj != NULL && (WeaponState != WEAPON_STATE_IDLE) ) {
is_current_complete = HandAnimControl.Is_Complete();
}
#endif
bool muzzle_flash_on = false;
static bool ForceFireLoop = false;
// What state are we going to?
int new_weapon_state = WEAPON_STATE_IDLE;
if ( COMBAT_STAR ) {
WeaponClass * star_weapon = COMBAT_STAR->Get_Weapon();
if ( star_weapon != NULL ) {
if ( star_weapon->Is_Reloading() ) {
new_weapon_state = WEAPON_STATE_RELOAD;
} else if ( star_weapon->Is_Firing() ) {
if ( WeaponState == WEAPON_STATE_FIRE ) {
ForceFireLoop = true;
}
new_weapon_state = WEAPON_STATE_FIRE;
if ( WeaponState == WEAPON_STATE_RELOAD ) {
is_current_complete = true; // Force a fire during reload
}
muzzle_flash_on = true;
if ( WeaponModel != NULL ) {
// if this gun has an eject bone, eject a shell.
int eject_index = WeaponModel->Get_Bone_Index( "eject" );
if ( eject_index > 0 ) {
star_weapon->Make_Shell_Eject( WeaponModel->Get_Bone_Transform( eject_index ) );
}
}
}
}
}
const char* cur_weapon_model_name="";
if ( WeaponModel ) {
cur_weapon_model_name = WeaponModel->Get_Name();
}
StringClass new_weapon_model_name(true);
if ( weapon ) {
Get_Render_Obj_Name_From_Filename( new_weapon_model_name, weapon->Get_First_Person_Model_Name() );
}
// If we need to change the assets,
if ( stricmp( cur_weapon_model_name,new_weapon_model_name)!=0) {
// if ( cur_weapon_model_name.Compare_No_Case( new_weapon_model_name ) != 0 ) {
// If we don't have a weapon, switch!
if ( WeaponModel == NULL ) {
WeaponState = WEAPON_STATE_EXIT;
is_current_complete = true;
}
if ( WeaponState != WEAPON_STATE_EXIT ) { // If we have a current weapon, exit it
new_weapon_state = WEAPON_STATE_EXIT;
} else {
if ( is_current_complete ) {
// If we are done exiting, switch and enter
Release_Weapon_Assets();
Aquire_Weapon_Assets( COMBAT_STAR->Get_Weapon() );
new_weapon_state = WEAPON_STATE_ENTER;
}
}
}
if ( WeaponModel ) {
// Update the muzzle flash
RenderObjClass * model = WeaponModel;
if ( model && (LastMuzzleFlash != muzzle_flash_on)) {
for (int i=0; i<model->Get_Num_Sub_Objects(); i++) {
RenderObjClass * robj = model->Get_Sub_Object(i);
if (strstr(robj->Get_Name(),"MUZZLEFLASH") || strstr(robj->Get_Name(),"MZ")) {
robj->Set_Hidden( !muzzle_flash_on );
}
robj->Release_Ref();
}
LastMuzzleFlash = muzzle_flash_on;
}
}
if ( HandsPhysObj != NULL && WeaponModel != NULL ) {
// make sure the "hands" object has the stealth effect
if (COMBAT_STAR->Peek_Stealth_Effect() != NULL) {
HandsPhysObj->Add_Effect_To_Me(COMBAT_STAR->Peek_Stealth_Effect());
}
// Add all rendobjs from the scene
if ( !COMBAT_SCENE->Contains( HandsPhysObj ) ) {
COMBAT_SCENE->Add_Dynamic_Object( HandsPhysObj );
if ( new_weapon_state == WEAPON_STATE_ENTER ) {
new_weapon_state = WEAPON_STATE_IDLE;
is_current_complete = true;
}
}
// When stopping, go to spin down
if ( is_current_complete &&
WeaponState == WEAPON_STATE_FIRE &&
new_weapon_state == WEAPON_STATE_IDLE ) {
// if the anims exist...
// new_weapon_state = WEAPON_STATE_SPIN_DOWN;
}
if ( WeaponState != WEAPON_STATE_IDLE ) {
if ( is_current_complete ) {
// If done playing the current non-looping anim, go to next state
if ( WeaponState == WEAPON_STATE_FIRE && ForceFireLoop ) {
ForceFireLoop = false; // Clear any force fire
// Keep it by restarting the fire anim
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
if ( hands_model != NULL ) {
// hands_model->Set_Animation( HandsAnims[ WeaponState ], 0, RenderObjClass::ANIM_MODE_ONCE );
HandAnimControl.Set_Animation( HandsAnims[ WeaponState ] );
HandAnimControl.Set_Mode( ANIM_MODE_ONCE, 0 );
HandAnimControl.Update(0);
}
// WeaponModel->Set_Animation( WeaponAnims[ WeaponState ], 0, RenderObjClass::ANIM_MODE_ONCE );
WeaponAnimControl.Set_Animation( WeaponAnims[ WeaponState ] );
WeaponAnimControl.Set_Mode( ANIM_MODE_ONCE, 0 );
WeaponAnimControl.Update(0);
} else {
WeaponState = -1;
}
}
}
if ( new_weapon_state == WEAPON_STATE_EXIT ) {
WeaponState = -1; // force a change
}
// If playing a looping anim, switch if needed
if ( (WeaponState == -1) || ( WeaponState == WEAPON_STATE_IDLE ) ) {
if ( new_weapon_state != WeaponState ) {
WeaponState = new_weapon_state;
float anim_blend_time = 0.15f;
if ( new_weapon_state == WEAPON_STATE_FIRE ) {
anim_blend_time = 0; // No blend when firing
}
int mode = ( WeaponState == WEAPON_STATE_IDLE ) ? RenderObjClass::ANIM_MODE_LOOP : RenderObjClass::ANIM_MODE_ONCE;
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
if ( hands_model != NULL ) {
mode = ( WeaponState == WEAPON_STATE_IDLE ) ? ANIM_MODE_LOOP : ANIM_MODE_ONCE;
// hands_model->Set_Animation( HandsAnims[ WeaponState ], 0, mode );
HandAnimControl.Set_Animation( HandsAnims[ WeaponState ], anim_blend_time );
HandAnimControl.Set_Mode( (AnimMode)mode );
}
// WeaponModel->Set_Animation( WeaponAnims[ WeaponState ], 0, mode );
WeaponAnimControl.Set_Animation( WeaponAnims[ WeaponState ], anim_blend_time );
mode = ( WeaponState == WEAPON_STATE_IDLE ) ? ANIM_MODE_LOOP : ANIM_MODE_ONCE;
WeaponAnimControl.Set_Mode( (AnimMode)mode );
// if ( HandsAnims[ WeaponState ] != NULL ) {
// Debug_Say(( "Playing %s\n", HandsAnims[ WeaponState ]->Get_Name() ));
// }
}
}
// Lets put the gun relative to the camera
Matrix3D tm = COMBAT_CAMERA->Get_Transform();
// Add bobing position
if ( BobHTree != NULL && BobHAnim != NULL ) {
BobFrame += TimeManager::Get_Frame_Seconds() * BobHAnim->Get_Frame_Rate();
if ( BobFrame > BobHAnim->Get_Num_Frames()-1 ) {
BobFrame -= BobHAnim->Get_Num_Frames()-1;
}
#if 0 // no more programatic recoil
tm.Translate( 0, 0, BobRecoil );
if ( BobRecoil > 0 ) {
BobRecoil -= TimeManager::Get_Frame_Real_Seconds() * 2;
if ( BobRecoil < 0 ) {
BobRecoil = 0;
}
}
#endif
BobHTree->Anim_Update( tm, BobHAnim, BobFrame );
// Now get the camera bone
// Debug_Say(( "%f %f %f\n", tm.Get_Translation().X, tm.Get_Translation().Y, tm.Get_Translation().Z ));
tm = BobHTree->Get_Transform( BobHTree->Get_Bone_Index( "CAMERA" ) );
// Debug_Say(( "%f %f %f\n", tm.Get_Translation().X, tm.Get_Translation().Y, tm.Get_Translation().Z ));
}
// Convert from camera to world convention
tm.Rotate_Z( DEG_TO_RADF(90.0) );
tm.Rotate_Y( DEG_TO_RADF(90.0) );
Vector3 fp_offset = HandsOffset + COMBAT_CAMERA->Get_First_Person_Offset_Tweak();
tm.Translate( fp_offset );
//WWASSERT(COMBAT_STAR != NULL);//TSS
if (COMBAT_STAR != NULL) {
//
// COMBAT_STAR may be NULL during MP game intermission
//
Matrix3D obj_convention_camera = COMBAT_CAMERA->Get_Transform();
obj_convention_camera.Rotate_Z( DEG_TO_RADF(90.0) );
obj_convention_camera.Rotate_Y( DEG_TO_RADF(90.0) );
Vector3 camera_space_target;
Vector3 camera_space_source;
Vector3 target_pos = COMBAT_STAR->Get_Targeting_Pos();
// Always look at a point a constant distance ahead, to avoid the gun poping around
target_pos = COMBAT_CAMERA->Get_Transform() * Vector3( 0,0,-100 );
Matrix3D::Inverse_Transform_Vector( obj_convention_camera, target_pos, &camera_space_target );
Matrix3D::Inverse_Transform_Vector( obj_convention_camera, tm.Get_Translation(), &camera_space_source );
Matrix3D camera_space_aim;
camera_space_aim.Obj_Look_At( camera_space_source, camera_space_target, 0 );
Matrix3D::Multiply( obj_convention_camera, camera_space_aim, &tm );
}
HandsPhysObj->Set_Transform( tm );
// Now, pull the hands backwards enough to clear any walls
if ( WeaponModel && COMBAT_CAMERA) {
const Matrix3D & muzzle_tm = WeaponModel->Get_Bone_Transform( "muzzlea0" );
Vector3 ray_end = muzzle_tm * Vector3( 0.1f, 0, 0 );
Vector3 ray_start = COMBAT_CAMERA->Get_Transform().Get_Translation();
ray_start.Z = ray_end.Z;
LineSegClass ray;
ray.Set( ray_start, ray_end );
CastResultStruct result;
PhysRayCollisionTestClass raytest(ray, &result, BULLET_COLLISION_GROUP, COLLISION_TYPE_PROJECTILE);
{
if (COMBAT_STAR != NULL && COMBAT_STAR->Peek_Physical_Object()!=NULL) {
COMBAT_STAR->Peek_Physical_Object()->Inc_Ignore_Counter();
}
WWPROFILE( "Cast Ray" );
WWASSERT(COMBAT_SCENE != NULL);
COMBAT_SCENE->Cast_Ray( raytest );
if (COMBAT_STAR != NULL && COMBAT_STAR->Peek_Physical_Object()!=NULL) {
COMBAT_STAR->Peek_Physical_Object()->Dec_Ignore_Counter();
}
}
/* if ( raytest.CollidedPhysObj != NULL && raytest.CollidedPhysObj->Get_Observer() != NULL ) {
DamageableGameObj * obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_DamageableGameObj();
if ( obj ) {
Debug_Say(( "Hit %s\n", obj->Get_Definition().Get_Name() ));
}
}*/
// Determine the Camera Target Point and object
Vector3 collision_pt;
ray.Compute_Point( raytest.Result->Fraction, &collision_pt );
collision_pt -= ray_end;
float pullback = collision_pt.Length();
// Debug_Say(( "Pullback = %f\n", pullback ));
tm.Translate( Vector3( -pullback, 0, 0 ) );
HandsPhysObj->Set_Transform( tm );
}
}
if ( HandsPhysObj && HandsPhysObj->Peek_Model() ) {
HandAnimControl.Update( TimeManager::Get_Frame_Seconds() );
}
if ( WeaponModel ) {
WeaponAnimControl.Update( TimeManager::Get_Frame_Seconds() );
}
}
Vector3 WeaponViewClass::Get_Muzzle_Pos()
{
if ( WeaponModel ) {
return WeaponModel->Get_Bone_Transform( "muzzlea0" ).Get_Translation();
}
return COMBAT_CAMERA->Get_Transform().Get_Translation();
}
const char * WeaponActionNames[ NUM_WEAPON_STATES ] = {
"IDLE", //WEAPON_STATE_IDLE,
"FIRE", //WEAPON_STATE_FIRE,
"RELOD", //WEAPON_STATE_RELOAD,
"ENTER", //WEAPON_STATE_ENTER,
"EXIT", //WEAPON_STATE_EXIT,
// "EFIRE", //WEAPON_STATE_SPIN_DOWN,
};
/*
** Get and release the Weapon specific assets
** Each weapon has a name ie: PIST
** The weapon model is in the form F_GM_<NAME> ie: F_GM_PIST
** The clip model is in the form F_CM_<NAME> ie: F_CM_PIST
** The weapon states are IDLE, FIRE, RELOAD, ENTER, EXIT
** For each weapon state, except ENTER and EXIT, we have a weapon anim tied to the weapon model (use IDLE anim for ENTER/EXIT )
** The weapon anims are in the form F_GA_<NAME>_<STATE> ie: F_GA_PIST_IDLE, F_GA_PIST_FIRE
** For each weapon state, we have a hand anim tied to the F_SKELETON
** The hand anims are in the form F_GA_<NAME>_<STATE> ie: F_GA_PIST_IDLE, F_GA_PIST_FIRE
** Weapon anims should be the same duration (number of frames) and the corresponding hand anim (except looping +IDLES)
*/
static void Aquire_Weapon_Assets( const WeaponClass * weapon )
{
if ( HandsPhysObj == NULL ) {
Aquire_Hands_Assets();
} else {
HandAnimControl.Set_Model( HandsPhysObj->Peek_Model() );
HandAnimControl.Set_Animation( (HAnimClass*)NULL );
}
if ( HandsPhysObj == NULL || HandsPhysObj->Peek_Model() == NULL ) {
return;
}
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
StringClass weapon_name;
if ( weapon ) {
// Debug_Say(( "Loading Weapon from %s\n", weapon->Get_First_Person_Model_Name() ));
WeaponModel = ::Create_Render_Obj_From_Filename( weapon->Get_First_Person_Model_Name() );
LastMuzzleFlash = true; // force it off
// Debug_Say(( "Loaded %s\n", WeaponModel ? WeaponModel->Get_Name() : "NONE" ));
// Use model name
if ( WeaponModel != NULL ) {
weapon_name = WeaponModel->Get_Name() + 5; // Get the weapon name from the model
Debug_Say(( "weapon_name is %s\n", (const char *)weapon_name ));
StringClass clip_name;
clip_name = WeaponModel->Get_Name();
if ( clip_name.Get_Length() > 4 ) {
clip_name[2] = 'C';
clip_name[3] = 'M';
}
ClipModel = WW3DAssetManager::Get_Instance()->Create_Render_Obj( clip_name );
if ( ClipModel != NULL ) {
hands_model->Add_Sub_Object_To_Bone( ClipModel, "CLIPBONE" );
}
}
}
WeaponAnimControl.Set_Model( WeaponModel );
WeaponAnimControl.Set_Animation( (HAnimClass*)NULL );
if ( WeaponModel != NULL ) {
// Add the model
hands_model->Add_Sub_Object_To_Bone( WeaponModel, "GUNBONE" );
HandsOffset = weapon->Get_First_Person_Model_Offset();
StringClass weapon_htree_name;
if ( WeaponModel->Get_HTree() != NULL ) {
weapon_htree_name = WeaponModel->Get_HTree()->Get_Name();
}
SET_REF_OWNER( WeaponModel );
for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
StringClass anim_name;
// Get Weapon Anims, use the idle anim for enter and exit
int state = ( i >= WEAPON_STATE_ENTER ) ? WEAPON_STATE_IDLE : i;
anim_name.Format( "%s.F_GA_%s_%s", weapon_htree_name, weapon_name, WeaponActionNames[state] );
// Debug_Say(( "Loading Weapon Anim %s\n", anim_name ));
WeaponAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( anim_name );
if ( WeaponAnims[i] == NULL ) {
Debug_Say(( "Missing Weapon Anim %s\n", anim_name ));
}
// Get Hands Anims
anim_name.Format( "F_SKELETON.F_HA_%s_%s", weapon_name, WeaponActionNames[i] );
// Debug_Say(( "Loading Hands Anim %s\n", anim_name ));
HandsAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( anim_name );
if ( HandsAnims[i] == NULL ) {
Debug_Say(( "Missing Hands Anim %s\n", anim_name ));
HandsAnims[i] = WW3DAssetManager::Get_Instance()->Get_HAnim( "F_SKELETON.F_HA_PIST_IDLE" );
}
}
}
}
static void Release_Weapon_Assets( void )
{
WeaponAnimControl.Set_Model( NULL );
WeaponAnimControl.Set_Animation( (HAnimClass*)NULL );
if ( WeaponModel != NULL ) {
// Remove
WWASSERT( HandsPhysObj != NULL );
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
WWASSERT( hands_model != NULL );
hands_model->Remove_Sub_Objects_From_Bone( "GUNBONE" );
WeaponModel->Release_Ref();
WeaponModel = NULL;
}
if ( ClipModel != NULL ) {
// Remove
WWASSERT( HandsPhysObj != NULL );
RenderObjClass * hands_model = HandsPhysObj->Peek_Model();
WWASSERT( hands_model != NULL );
hands_model->Remove_Sub_Objects_From_Bone( "CLIPBONE" );
ClipModel->Release_Ref();
ClipModel = NULL;
}
for ( int i = 0; i < NUM_WEAPON_STATES; i++ ) {
if ( WeaponAnims[i] != NULL ) {
WeaponAnims[i]->Release_Ref();
WeaponAnims[i] = NULL;
}
if ( HandsAnims[i] != NULL ) {
HandsAnims[i]->Release_Ref();
HandsAnims[i] = NULL;
}
}
}
/*
** Get and release the Hand assets
** All hand models are built on the F_SKELETON HTree, which has a GUNBONE and CLIPBONE
** The hand models can be different for each player model, and are in the form F_HM_XXX ie: F_HM_HAVOC
** The hand anims are created from the particular weapon model loaded.
*/
static void Aquire_Hands_Assets( void )
{
StringClass name = COMBAT_STAR->Get_First_Person_Hands_Model_Name();
// Debug_Say(( "Loading Hands from %s\n", name ));
HandsPhysObj = new DecorationPhysClass();
if ( HandsPhysObj != NULL ) {
HandsPhysObj->Set_Collision_Group( UNCOLLIDEABLE_GROUP );
RenderObjClass * model = ::Create_Render_Obj_From_Filename( name );
if ( model != NULL ) {
HandAnimControl.Set_Model( model );
HandAnimControl.Set_Animation( (HAnimClass*)NULL );
HandsPhysObj->Set_Model( model );
model->Release_Ref();
}
}
}
static void Release_Hands_Assets( void )
{
HandAnimControl.Set_Model( NULL );
HandAnimControl.Set_Animation( (HAnimClass*)NULL );
if ( HandsPhysObj != NULL ) {
if ( COMBAT_SCENE->Contains( HandsPhysObj ) ) {
COMBAT_SCENE->Remove_Object( HandsPhysObj );
}
HandsPhysObj->Release_Ref();
HandsPhysObj = NULL;
}
}
/*
**
*/
static const char * BobNames[] = {
"", // BOB_NONE
"F_CA_IDLE", // BOB_IDLE
"F_CA_WALK", // BOB_WALK
"F_CA_RUN", // BOB_RUN
};
static void Set_Bob( int bob_state )
{
if ( BobState != bob_state ) {
BobState = bob_state;
// Release the old copys, if any
BobHTree = NULL;
REF_PTR_RELEASE( BobHAnim );
StringClass name(BobNames[ BobState ],true);
// Debug_Say(( "New Camera Bob State %d \"%s\"\n", BobState, name ));
if ( !name.Is_Empty() ) {
BobHTree = WW3DAssetManager::Get_Instance()->Get_HTree( name );
StringClass anim(0,true);
anim.Format( "%s.%s", name,name );
BobHAnim = WW3DAssetManager::Get_Instance()->Get_HAnim( anim );
}
}
}
static void Set_Bob_Recoil( float amount )
{
BobRecoil = amount;
}