| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- /*
- ** 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/armedgameobj.cpp $*
- * *
- * $Author:: Greg_h $*
- * *
- * $Modtime:: 12/20/01 7:10p $*
- * *
- * $Revision:: 38 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- /*
- ** Includes
- */
- #include "armedgameobj.h"
- #include "debug.h"
- #include "weaponbag.h"
- #include "weapons.h"
- #include "rendobj.h"
- #include "bitpackids.h"
- #include "wwprofile.h"
- #include "smartgameobj.h"
- /*
- ** ArmedGameObjDef
- */
- ArmedGameObjDef::ArmedGameObjDef( void ) :
- WeaponTiltRate( 1.0f ),
- WeaponTiltMin( -10000.0f ),
- WeaponTiltMax( 10000.0f ),
- WeaponTurnRate( 1.0f ),
- WeaponTurnMin( -10000.0f ),
- WeaponTurnMax( 10000.0f ),
- WeaponError( 0 ),
- WeaponDefID( 0 ),
- SecondaryWeaponDefID( 0 ),
- WeaponRounds( -1 )
- {
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTiltRate );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTiltMin );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTiltMax );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTurnRate );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTurnMin );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponTurnMax );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_ANGLE, WeaponError );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_WEAPONOBJDEFINITIONID, WeaponDefID );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_INT, WeaponRounds );
- EDITABLE_PARAM( ArmedGameObjDef, ParameterClass::TYPE_WEAPONOBJDEFINITIONID, SecondaryWeaponDefID );
- }
- enum {
- CHUNKID_DEF_PARENT = 418001829,
- CHUNKID_DEF_VARIABLES,
- MICROCHUNKID_DEF_WEAPON_TILT_RATE = 1,
- MICROCHUNKID_DEF_WEAPON_TILT_MIN,
- MICROCHUNKID_DEF_WEAPON_TILT_MAX,
- MICROCHUNKID_DEF_WEAPON_TURN_RATE,
- MICROCHUNKID_DEF_WEAPON_TURN_MIN,
- MICROCHUNKID_DEF_WEAPON_TURN_MAX,
- XXXMICROCHUNKID_DEF_PRIMARY_ROUNDS,
- XXXMICROCHUNKID_DEF_PRIMARY_AMMO_WEAPON_DEF_ID,
- XXXMICROCHUNKID_DEF_SECONDARY_AMMO_WEAPON_DEF_ID,
- XXXMICROCHUNKID_DEF_SECONDARY_ROUNDS,
- MICROCHUNKID_DEF_WEAPON_DEF_ID,
- MICROCHUNKID_DEF_WEAPON_ROUNDS,
- MICROCHUNKID_DEF_WEAPON_ERROR,
- MICROCHUNKID_DEF_SECONDARY_WEAPON_DEF_ID,
- };
- bool ArmedGameObjDef::Save( ChunkSaveClass & csave )
- {
- csave.Begin_Chunk( CHUNKID_DEF_PARENT );
- PhysicalGameObjDef::Save( csave );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TILT_RATE, WeaponTiltRate );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TILT_MIN, WeaponTiltMin );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TILT_MAX, WeaponTiltMax );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TURN_RATE, WeaponTurnRate );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TURN_MIN, WeaponTurnMin );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_TURN_MAX, WeaponTurnMax );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_DEF_ID, WeaponDefID );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SECONDARY_WEAPON_DEF_ID, SecondaryWeaponDefID );
- WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_ROUNDS, WeaponRounds, int );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_WEAPON_ERROR, WeaponError );
- csave.End_Chunk();
- return true;
- }
- bool ArmedGameObjDef::Load( ChunkLoadClass &cload )
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_DEF_PARENT:
- PhysicalGameObjDef::Load( cload );
- break;
- case CHUNKID_DEF_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TILT_RATE, WeaponTiltRate );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TILT_MIN, WeaponTiltMin );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TILT_MAX, WeaponTiltMax );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TURN_RATE, WeaponTurnRate );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TURN_MIN, WeaponTurnMin );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_TURN_MAX, WeaponTurnMax );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_DEF_ID, WeaponDefID );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SECONDARY_WEAPON_DEF_ID, SecondaryWeaponDefID );
- READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_ROUNDS, WeaponRounds, int );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_WEAPON_ERROR, WeaponError );
- default:
- Debug_Say(( "Unrecognized ArmedDef Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID() ));
- break;
- }
- cload.Close_Micro_Chunk();
- }
- break;
- default:
- Debug_Say(( "Unrecognized ArmedDef chunkID\n" ));
- break;
- }
- cload.Close_Chunk();
- }
- return true;
- }
- /*
- ** ArmedGameObj
- */
- ArmedGameObj::ArmedGameObj( void ) :
- MuzzleA0Bone( 0 ),
- MuzzleA1Bone( 0 ),
- MuzzleB0Bone( 0 ),
- MuzzleB1Bone( 0 ),
- TargetingPos(0,0,0)
- {
- WeaponBag = new WeaponBagClass( this );
- }
- ArmedGameObj::~ArmedGameObj( void )
- {
- delete WeaponBag;
- }
- /*
- **
- */
- void ArmedGameObj::Init( const ArmedGameObjDef & definition )
- {
- PhysicalGameObj::Init( definition );
- Copy_Settings( definition );
- return ;
- }
- /*
- **
- */
- void ArmedGameObj::Copy_Settings( const ArmedGameObjDef & definition )
- {
- WeaponClass * weapon = NULL;
- if ( definition.WeaponDefID != 0 ) {
- weapon = WeaponBag->Add_Weapon( definition.WeaponDefID, definition.WeaponRounds );
- }
- if ( definition.SecondaryWeaponDefID != 0 ) {
- WeaponClass * s_weapon = WeaponBag->Add_Weapon( definition.SecondaryWeaponDefID, definition.WeaponRounds );
- if ( weapon == NULL ) {
- weapon = s_weapon;
- }
- }
- if ( weapon != NULL ) {
- WeaponBag->Select_Weapon( weapon );
- }
- Init_Muzzle_Bones();
- return ;
- }
- /*
- **
- */
- void ArmedGameObj::Re_Init( const ArmedGameObjDef & definition )
- {
- PhysicalGameObj::Re_Init( definition );
- //
- // Remove all non-beacon entries from the weapon bag...
- //
- WeaponBagClass *old_bag = WeaponBag;
- if ( WeaponBag != NULL ) {
- //
- // Loop over all the weapons in the bag
- //
- int weapon_index = WeaponBag->Get_Count();
- while (weapon_index --) {
- WeaponClass *weapon = WeaponBag->Peek_Weapon( weapon_index );
-
- //
- // If this isn't a beacon, then remove it
- //
- if (weapon != NULL && weapon->Get_Definition ()->Style != WEAPON_HOLD_STYLE_BEACON) {
- WeaponBag->Remove_Weapon( weapon_index );
- }
- }
- WeaponBag = NULL;
- }
- //
- // Re-initialize the weapon bag
- //
- WeaponBag = new WeaponBagClass( this );
- //
- // Copy any internal settings from the definition
- //
- Copy_Settings( definition );
- //
- // Now add any beacons back into the weapon bag
- //
- if ( old_bag != NULL ) {
- WeaponBag->Move_Contents( old_bag );
- delete old_bag;
- }
- return ;
- }
- const ArmedGameObjDef & ArmedGameObj::Get_Definition( void ) const
- {
- return (const ArmedGameObjDef &)BaseGameObj::Get_Definition();
- }
- /*
- ** ArmedGameObj Save and Load
- */
- enum {
- CHUNKID_PARENT = 418001841,
- CHUNKID_VARIABLES,
- CHUNKID_WEAPONBAG,
- MICROCHUNKID_TARGETING_POS = 1,
- };
- bool ArmedGameObj::Save( ChunkSaveClass & csave )
- {
- csave.Begin_Chunk( CHUNKID_PARENT );
- PhysicalGameObj::Save( csave );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_VARIABLES );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TARGETING_POS, TargetingPos );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_WEAPONBAG );
- WeaponBag->Save( csave );
- csave.End_Chunk();
- return true;
- }
- bool ArmedGameObj::Load( ChunkLoadClass &cload )
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_PARENT:
- PhysicalGameObj::Load( cload );
- break;
- case CHUNKID_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK( cload, MICROCHUNKID_TARGETING_POS, TargetingPos );
- default:
- Debug_Say(( "Unrecognized ArmedGameObj Variable chunkID\n" ));
- break;
- }
- cload.Close_Micro_Chunk();
- }
- break;
- case CHUNKID_WEAPONBAG:
- WeaponBag->Load( cload );
- break;
- default:
- Debug_Say(( "Unrecognized ArmedGameObj chunkID\n" ));
- break;
- }
- cload.Close_Chunk();
- }
- SaveLoadSystemClass::Register_Post_Load_Callback(this);
- return true;
- }
- void ArmedGameObj::On_Post_Load( void )
- {
- PhysicalGameObj::On_Post_Load();
- Init_Muzzle_Bones();
- }
- //-----------------------------------------------------------------------------
- void ArmedGameObj::Import_Frequent(BitStreamClass & packet)
- {
- PhysicalGameObj::Import_Frequent( packet );
- Vector3 targeting_pos;
- packet.Get(targeting_pos.X, BITPACK_WORLD_POSITION_X);
- packet.Get(targeting_pos.Y, BITPACK_WORLD_POSITION_Y);
- packet.Get(targeting_pos.Z, BITPACK_WORLD_POSITION_Z);
- //
- // Don't force the targetting if the object is controlled
- // by this player
- //
- SmartGameObj *smart_game_obj = As_SmartGameObj ();
- if (smart_game_obj == NULL || smart_game_obj->Is_Controlled_By_Me() == false) {
- Set_Targeting(targeting_pos);
- }
- return ;
- }
- //-----------------------------------------------------------------------------
- void ArmedGameObj::Export_Frequent(BitStreamClass & packet)
- {
- PhysicalGameObj::Export_Frequent( packet );
- packet.Add(TargetingPos.X, BITPACK_WORLD_POSITION_X);
- packet.Add(TargetingPos.Y, BITPACK_WORLD_POSITION_Y);
- packet.Add(TargetingPos.Z, BITPACK_WORLD_POSITION_Z);
- }
- //-----------------------------------------------------------------------------
- void ArmedGameObj::Export_State_Cs(BitStreamClass & packet)
- {
- #if 1
- Vector3 my_pos;
- Get_Position( &my_pos );
- Vector3 rel_target = TargetingPos - my_pos;
- packet.Add(rel_target.X, BITPACK_WORLD_POSITION_X);
- packet.Add(rel_target.Y, BITPACK_WORLD_POSITION_Y);
- packet.Add(rel_target.Z, BITPACK_WORLD_POSITION_Z);
- #else
- packet.Add(TargetingPos.X, BITPACK_WORLD_POSITION_X);
- packet.Add(TargetingPos.Y, BITPACK_WORLD_POSITION_Y);
- packet.Add(TargetingPos.Z, BITPACK_WORLD_POSITION_Z);
- #endif
- }
- //-----------------------------------------------------------------------------
- void ArmedGameObj::Import_State_Cs(BitStreamClass & packet)
- {
- #if 1
- Vector3 rel_target;
- packet.Get(rel_target.X, BITPACK_WORLD_POSITION_X);
- packet.Get(rel_target.Y, BITPACK_WORLD_POSITION_Y);
- packet.Get(rel_target.Z, BITPACK_WORLD_POSITION_Z);
- Vector3 my_pos;
- Get_Position( &my_pos );
- Vector3 targeting_pos = rel_target + my_pos;
- Set_Targeting(targeting_pos);
- #else
- Vector3 targeting_pos;
- packet.Get(targeting_pos.X, BITPACK_WORLD_POSITION_X);
- packet.Get(targeting_pos.Y, BITPACK_WORLD_POSITION_Y);
- packet.Get(targeting_pos.Z, BITPACK_WORLD_POSITION_Z);
- Set_Targeting(targeting_pos);
- #endif
- }
- void ArmedGameObj::Post_Think( void )
- {
- PhysicalGameObj::Post_Think();
- WWPROFILE( "Armed PostThink" );
- if ( Is_Delete_Pending() ) { // don't update if destroying... (so we don't create a new laser!)
- return;
- }
- if ( Get_Weapon() != NULL ) { // Update the weapon after the commands and update_human_animation
- Get_Weapon()->Update();
- }
- // allow any recoil animation to progress
- if (Peek_Model() != NULL) {
- for (int i=0; i<MAX_MUZZLES; i++) {
- MuzzleRecoilController[i].Update(Peek_Model());
- }
- }
- }
- /*
- ** Weapons
- */
- WeaponClass * ArmedGameObj::Get_Weapon( void )
- {
- return WeaponBag->Get_Weapon();
- }
- void ArmedGameObj::Init_Muzzle_Bones( void )
- {
- MuzzleA0Bone = Peek_Model()->Get_Bone_Index( "muzzlea0" );
- MuzzleA1Bone = Peek_Model()->Get_Bone_Index( "muzzlea1" );
- MuzzleB0Bone = Peek_Model()->Get_Bone_Index( "muzzleb0" );
- MuzzleB1Bone = Peek_Model()->Get_Bone_Index( "muzzleb1" );
- if (MuzzleA1Bone == 0) {
- MuzzleA1Bone = MuzzleA0Bone;
- }
- if (MuzzleB0Bone == 0) {
- MuzzleB0Bone = MuzzleA0Bone;
- }
- if (MuzzleB1Bone == 0) {
- MuzzleB1Bone = MuzzleB0Bone;
- }
- MuzzleRecoilController[0].Init(MuzzleA0Bone);
- MuzzleRecoilController[1].Init(MuzzleA1Bone);
- MuzzleRecoilController[2].Init(MuzzleB0Bone);
- MuzzleRecoilController[3].Init(MuzzleB1Bone);
- // Let the weapon learn about muzzle flashes
- if ( Get_Weapon() ) {
- Get_Weapon()->Set_Model( Peek_Model() );
- }
- }
- bool ArmedGameObj::Set_Targeting( const Vector3 & pos, bool do_tilt )
- {
- TargetingPos = pos;
- // Move the turret to match the target
- return true;
- }
- const Matrix3D & ArmedGameObj::Get_Muzzle( int index )
- {
- RenderObjClass * model = Peek_Model();
- if ( index == 3 && MuzzleB1Bone != 0 ) {
- return model->Get_Bone_Transform( MuzzleB1Bone );
- }
- if ( index >= 2 && MuzzleB0Bone != 0 ) {
- return model->Get_Bone_Transform( MuzzleB0Bone );
- }
- if ( index == 1 && MuzzleA1Bone != 0 ) {
- return model->Get_Bone_Transform( MuzzleA1Bone );
- }
- if ( MuzzleA0Bone != 0 ) {
- return model->Get_Bone_Transform( MuzzleA0Bone );
- }
- return Get_Transform();
- }
- bool ArmedGameObj::Muzzle_Exists( int index )
- {
- if ( index == 0 ) {
- return MuzzleA0Bone != 0;
- }
- if ( index == 1 ) {
- return MuzzleA1Bone != 0;
- }
- if ( index == 2 ) {
- return MuzzleB0Bone != 0;
- }
- if ( index == 3 ) {
- return MuzzleB1Bone != 0;
- }
- return false;
- }
- void ArmedGameObj::Start_Recoil( int muzzle_index,float recoil_scale,float recoil_time )
- {
- WWASSERT(muzzle_index >= 0);
- WWASSERT(muzzle_index < MAX_MUZZLES);
- MuzzleRecoilController[muzzle_index].Start_Recoil(recoil_scale,recoil_time);
- }
|