| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951 |
- /*
- ** 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/weapons.cpp $*
- * *
- * $Author:: Byon_g $*
- * *
- * $Modtime:: 3/27/02 4:43p $*
- * *
- * $Revision:: 270 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "weapons.h"
- #include "weaponmanager.h"
- #include "debug.h"
- #include "soldier.h"
- #include "combat.h"
- #include "gameobjmanager.h"
- #include "line3d.h"
- #include "physcoltest.h"
- #include "pscene.h"
- #include "rendobj.h"
- #include "quat.h"
- #include "combatsound.h"
- #include "slnode.h"
- #include "scripts.h"
- #include "WWAudio.H"
- #include "Sound3D.H"
- #include "chunkio.h"
- #include "assets.h"
- #include "bullet.h"
- #include "crandom.h"
- #include "damage.h"
- #include "ccamera.h"
- #include "rbody.h"
- #include "timeddecophys.h"
- #include "wwphysids.h"
- #include "part_emt.h"
- #include "vehicle.h"
- #include "c4.h"
- #include "objlibrary.h"
- #include "wwprofile.h"
- #include "hudinfo.h"
- #include "projectile.h"
- #include "combatphysobserver.h"
- #include "surfaceeffects.h"
- #include "beacongameobj.h"
- #include "weaponview.h"
- #include "diaglog.h"
- #include "playerdata.h"
- #include "cheatmgr.h"
- /*
- **
- */
- #define RANDOM_VECTOR( spread ) Vector3( FreeRandom.Get_Float( -(spread), (spread) ), \
- FreeRandom.Get_Float( -(spread), (spread) ), \
- FreeRandom.Get_Float( -(spread), (spread) ) )
- /**
- ** EjectCasingObserverClass
- ** This is a class which observes all eject casings and creates sound effects when they
- ** collide. Since the task of this observer is so simple, I am creating a single static
- ** instance of it and pluging it into all eject casings.
- */
- class EjectCasingObserverClass : public CombatPhysObserverClass
- {
- public:
- virtual CollisionReactionType Collision_Occurred(const CollisionEventClass & event)
- {
- /*
- SurfaceEffectsManager::Apply_Effect(event.CollisionResult->SurfaceType,
- SurfaceEffectsManager::HITTER_TYPE_EJECT_CASING,
- Matrix3D(event.CollisionResult->ContactPoint),
- event.OtherObj, NULL, false);
- */
- return COLLISION_REACTION_DEFAULT;
- }
- };
- static EjectCasingObserverClass _TheEjectCasingObserver;
- /*
- **
- */
- WeaponClass::WeaponClass( const WeaponDefinitionClass *def ) :
- Definition( NULL ),
- PrimaryAmmoDefinition( NULL ),
- SecondaryAmmoDefinition( NULL ),
- Model( NULL ),
- State( STATE_IDLE ),
- StateTimer( 0.0f ),
- UpdateModel( WEAPON_MODEL_UPDATE_IS_NEEDED ),
- NextAnimState( WEAPON_ANIM_NOT_FIRING ),
- CurrentAnimState( WEAPON_ANIM_NOT_FIRING ),
- LastFrameIsPrimaryTriggered( false ),
- LastFrameIsSecondaryTriggered( false ),
- IsPrimaryTriggered( false ),
- IsSecondaryTriggered( false ),
- TotalRoundsFired( 0 ),
- ClipRounds( 0 ),
- InventoryRounds( 0 ),
- BurstDelayTimer( 0 ),
- BurstCount( 0 ),
- BulletBumpTime( 0 ),
- DidFire( false ),
- ContinuousEmitters( NULL ),
- ContinuousSound( NULL ),
- C4DetonationMode( 1 ),
- Target( 0, 0, 0 ),
- FiringSound( NULL ),
- FiringSoundDefID( 0 ),
- WeaponExists( true ),
- SafetySet( false ),
- LockTriggers( false ),
- EmptySoundTimer( 0 )
- {
- if ( def != NULL ) {
- Init( def );
- }
- }
- WeaponClass::~WeaponClass( void )
- {
- if (FiringSound != NULL) {
- FiringSound->Remove_From_Scene ();
- FiringSoundDefID = 0;
- }
- REF_PTR_RELEASE( Model );
- REF_PTR_RELEASE( FiringSound );
- Do_Continuous_Effects( false );
- }
- void WeaponClass::Init( const WeaponDefinitionClass *weapon_def )
- {
- WWASSERT( Definition == NULL );
- Definition = weapon_def;
- WWASSERT( Definition != NULL );
- // Setup the ammo defs
- WWASSERT( Definition->PrimaryAmmoDefID != 0 );
- PrimaryAmmoDefinition = WeaponManager::Find_Ammo_Definition( Definition->PrimaryAmmoDefID );
- WWASSERT( Definition->SecondaryAmmoDefID != 0 );
- SecondaryAmmoDefinition = WeaponManager::Find_Ammo_Definition( Definition->SecondaryAmmoDefID );
- }
- /*
- ** Weapon Save and Load
- */
- enum {
- CHUNKID_VARIABLES = 910991544,
- XXX_CHUNKID_AMMO,
- CHUNKID_OWNER_REF,
- XXXCHUNKID_TARGET_REF,
- XXXCHUNKID_DESIRED_TARGET_REF,
- CHUNKID_TARGET_OBJECT,
- MICROCHUNKID_IN_FLY_MODE = 1,
- MICROCHUNKID_STATE,
- MICROCHUNKID_STATE_TIMER,
- MICROCHUNKID_IS_PRIMARY_TRIGGERED,
- XXXMICROCHUNKID_IS_SNIPING,
- MICROCHUNKID_ROUNDS_FIRED,
- MICROCHUNKID_NEXT_ANIM_STATE,
- MICROCHUNKID_CURR_ANIM_STATE,
- MICROCHUNKID_UPDATE_MODEM,
- XXXXMICROCHUNKID_LAST_MUZZLE,
- XXXMICROCHUNKID_PENDING_TIMER,
- XXXMICROCHUNKID_TARGETING_MUZZLE,
- XXXMICROCHUNKID_TARGET_POSITION,
- XXXMICROCHUNKID_WEAPON_PARAMS_NAME,
- XXXMICROCHUNKID_MODEL_NAME,
- MICROCHUNKID_MODEL_PTR,
- XXXMICROCHUNKID_DYNAMIC_ERROR_ANGLE,
- MICROCHUNKID_CLIP_ROUNDS,
- MICROCHUNKID_INVENTORY_ROUNDS,
- MICROCHUNKID_BURST_TIMER,
- MICROCHUNKID_BURST_COUNT,
- XXX_MICROCHUNKID_AMMO_PARAMS_NAME,
- XXXMICROCHUNKID_AMMO_DEFINITION_NAME,
- XXXMICROCHUNKID_DEFINITION_NAME,
- XXXMICROCHUNKID_AMMO_DEFINITION_ID,
- MICROCHUNKID_DEFINITION_ID,
- MICROCHUNKID_IS_SECONDARY_TRIGGERED,
- MICROCHUNKID_C4_DETONATION_MODE,
- MICROCHUNKID_TARGET_LOCATION,
- MICROCHUNKID_WEAPON_EXISTS,
- MICROCHUNKID_SAFETY_SET,
- XXXMICROCHUNKID_OWNER_ERROR_ANGLE,
- };
- bool WeaponClass::Save( ChunkSaveClass & csave )
- {
- csave.Begin_Chunk( CHUNKID_VARIABLES );
- if ( Model ) {
- #if 0
- csave.Begin_Micro_Chunk( MICROCHUNKID_MODEL_NAME );
- const char * model_name = Model->Get_Name();
- csave.Write( model_name, strlen( model_name ) + 1 );
- csave.End_Micro_Chunk();
- #endif
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_MODEL_PTR, Model );
- }
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_TIMER, StateTimer );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_PRIMARY_TRIGGERED, IsPrimaryTriggered );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_SECONDARY_TRIGGERED, IsSecondaryTriggered );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_ROUNDS_FIRED, TotalRoundsFired );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_NEXT_ANIM_STATE, NextAnimState );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CURR_ANIM_STATE, CurrentAnimState );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_UPDATE_MODEM, UpdateModel );
- WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_CLIP_ROUNDS, ClipRounds, int );
- WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_INVENTORY_ROUNDS, InventoryRounds, int );
- WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_BURST_TIMER, BurstDelayTimer, float );
- WRITE_SAFE_MICRO_CHUNK( csave, MICROCHUNKID_BURST_COUNT, BurstCount, int );
- int def_id = Definition->Get_ID();
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEFINITION_ID, def_id );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_C4_DETONATION_MODE, C4DetonationMode );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_TARGET_LOCATION, Target );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_WEAPON_EXISTS, WeaponExists );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_SAFETY_SET, SafetySet );
- csave.End_Chunk();
- if ( Owner != NULL ) {
- csave.Begin_Chunk( CHUNKID_OWNER_REF );
- Owner.Save( csave );
- csave.End_Chunk();
- }
- if ( TargetObject != NULL ) {
- csave.Begin_Chunk( CHUNKID_TARGET_OBJECT );
- TargetObject.Save( csave );
- csave.End_Chunk();
- }
- // Don't need to save DidFire
- // Don't need to save ContinuousEmitters;
- // Don't need to save ContinuousSound;
- // Don't need to save FiringSound;
- // Dont need to save BulletBumpTime
- return true;
- }
- bool WeaponClass::Load( ChunkLoadClass &cload )
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_VARIABLES:
- {
- int def_id = 0;
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_TIMER, StateTimer );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_PRIMARY_TRIGGERED, IsPrimaryTriggered );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_SECONDARY_TRIGGERED, IsSecondaryTriggered );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_ROUNDS_FIRED, TotalRoundsFired );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_NEXT_ANIM_STATE, NextAnimState );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_CURR_ANIM_STATE, CurrentAnimState );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_UPDATE_MODEM, UpdateModel );
- READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_CLIP_ROUNDS, ClipRounds, int );
- READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_INVENTORY_ROUNDS, InventoryRounds, int );
- READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_BURST_TIMER, BurstDelayTimer, float );
- READ_SAFE_MICRO_CHUNK( cload, MICROCHUNKID_BURST_COUNT, BurstCount, int );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEFINITION_ID, def_id );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_C4_DETONATION_MODE, C4DetonationMode );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_TARGET_LOCATION, Target );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_WEAPON_EXISTS, WeaponExists );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_SAFETY_SET, SafetySet );
- #if 0
- case XXX_MICROCHUNKID_MODEL_NAME:
- {
- WWASSERT( Model == NULL );
- char model_name[80];
- cload.Read( model_name, cload.Cur_Micro_Chunk_Length() );
- RenderObjClass * robj = WW3DAssetManager::Get_Instance()->Create_Render_Obj( model_name );
- Set_Model( robj );
- cload.Close_Micro_Chunk();
- cload.Open_Micro_Chunk();
- WWASSERT( cload.Cur_Micro_Chunk_ID() == MICROCHUNKID_MODEL_PTR );
- void * old_ptr = NULL;
- cload.Read( &old_ptr, sizeof( old_ptr ) );
- SaveLoadSystemClass::Register_Pointer( old_ptr, robj );
- REF_PTR_RELEASE( robj );
- break;
- }
- #endif
- READ_MICRO_CHUNK( cload, MICROCHUNKID_MODEL_PTR, Model );
- 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();
- }
- Init( WeaponManager::Find_Weapon_Definition( def_id ) );
- break;
- }
- case CHUNKID_OWNER_REF:
- Owner.Load( cload );
- break;
- case CHUNKID_TARGET_OBJECT:
- TargetObject.Load( cload );
- break;
- default:
- Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
- break;
- }
- cload.Close_Chunk();
- }
- if (Model != NULL) {
- REQUEST_REF_COUNTED_POINTER_REMAP ((RefCountClass **)&Model);
- }
- // Legacy
- if ( ClipRounds == 0 && InventoryRounds < 0 ) {
- ClipRounds = Definition->ClipSize;
- }
- return true;
- }
- void WeaponClass::Set_Owner( ArmedGameObj *owner )
- {
- Owner = owner;
- }
- void WeaponClass::Set_Target_Object( PhysicalGameObj * obj )
- {
- TargetObject = obj;
- }
- PhysicalGameObj * WeaponClass::Get_Target_Object( PhysicalGameObj * obj )
- {
- return ( PhysicalGameObj * )TargetObject.Get_Ptr();
- }
- void WeaponClass::Set_Model( RenderObjClass *model )
- {
- if ( Model != NULL ) {
- Model->Release_Ref();
- }
- Model = model;
- if ( Model != NULL ) {
- Model->Add_Ref();
- Init_Muzzle_Flash( Model );
- }
- }
- void WeaponClass::Select( void )
- {
- // Debug_Say(( "Weapon Selected\n" ));
- Set_State( STATE_START_SWITCH );
- UpdateModel = WEAPON_MODEL_UPDATE_WILL_BE_NEEDED;
- }
- void WeaponClass::Deselect( void )
- {
- Do_Continuous_Effects( false );
- IsPrimaryTriggered = false;
- IsSecondaryTriggered = false;
- LastFrameIsPrimaryTriggered = false;
- LastFrameIsSecondaryTriggered = false;
- }
- void WeaponClass::Next_C4_Detonation_Mode( void )
- {
- #define LAST_C4_DETONATION_MODE 3
- if ( ++C4DetonationMode > LAST_C4_DETONATION_MODE ) {
- C4DetonationMode = 1;
- }
- Debug_Say(( "Weapon Next C4 Detonation Mode %d\n", C4DetonationMode ));
- }
- /*
- **
- */
- void WeaponClass::Set_Primary_Triggered( bool triggered )
- {
- if ( !LockTriggers ) {
- IsPrimaryTriggered = triggered;
- }
- }
- void WeaponClass::Set_Secondary_Triggered( bool triggered )
- {
- if ( !LockTriggers ) {
- IsSecondaryTriggered = triggered;
- }
- }
- /*
- ** AMMO
- */
- void WeaponClass::Add_Rounds( int num )
- {
- // If we have an empty clip ( first time ) load directly
- if ( ClipRounds == 0 ) {
- if ( num < 0 ) {
- ClipRounds = Definition->ClipSize;
- } else if ( InventoryRounds >= 0 ) {
- int count = MIN( num, (int)Definition->ClipSize );
- num -= count;
- ClipRounds = count;
- }
- }
- if ( CheatMgrClass::Get_Instance () != NULL &&
- CheatMgrClass::Get_Instance ()->Is_Cheat_Enabled( CheatMgrClass::CHEAT_INFINITE_AMMO ) && Owner == COMBAT_STAR )
- {
- InventoryRounds = Definition->MaxInventoryRounds ;
- } else if ( num < 0 ) {
- InventoryRounds = -1;
- } else if ( InventoryRounds >= 0 ) {
- InventoryRounds += num;
- }
- if ( (InventoryRounds != -1) && (InventoryRounds > (int)Definition->MaxInventoryRounds) ) {
- InventoryRounds = Definition->MaxInventoryRounds ;
- }
- }
- int WeaponClass::Get_Total_Rounds( void )
- {
- if ( InventoryRounds < 0 ) {
- return -1;
- }
- //
- // Check to see if the infinite ammo cheat is enabled
- //
- if ( CheatMgrClass::Get_Instance () != NULL &&
- CheatMgrClass::Get_Instance ()->Is_Cheat_Enabled( CheatMgrClass::CHEAT_INFINITE_AMMO ) && Owner == COMBAT_STAR )
- {
- return -1;
- }
- return ClipRounds + InventoryRounds;
- }
- void WeaponClass::Set_Total_Rounds( int num )
- {
- if ( CheatMgrClass::Get_Instance () != NULL &&
- CheatMgrClass::Get_Instance ()->Is_Cheat_Enabled( CheatMgrClass::CHEAT_INFINITE_AMMO ) && Owner == COMBAT_STAR )
- {
- InventoryRounds = Definition->MaxInventoryRounds;
- } else if ( num == -1 ) {
- InventoryRounds = -1;
- } else {
- // Assume what you have in inventory is correct
- num -= (int)InventoryRounds;
- // And the rest goes in the clip
- ClipRounds = num;
- // Fix a negative clip
- if ( ClipRounds < 0 ) {
- InventoryRounds += ClipRounds;
- ClipRounds = 0;
- }
- // Fix overloaded clip
- if ( ClipRounds > Definition->ClipSize ) {
- InventoryRounds += ClipRounds - Definition->ClipSize;
- ClipRounds -= ClipRounds - Definition->ClipSize;
- }
- // Fix Overloaded inventory
- if ( InventoryRounds > (int)Definition->MaxInventoryRounds ) {
- InventoryRounds = Definition->MaxInventoryRounds;
- }
- }
- }
- bool WeaponClass::Is_Ammo_Maxed( void )
- {
- if (InventoryRounds == -1) return true;
- // Special case for C4
- if (((int)Definition->MaxInventoryRounds == 0) && (ClipRounds == 0)) return false;
- return (InventoryRounds == (int)Definition->MaxInventoryRounds);
- }
- void WeaponClass::Decrement_Rounds( int rounds )
- {
- if ( ClipRounds != -1 ) {
- ClipRounds -= rounds;
- if ( ClipRounds <= 0 ) {
- ClipRounds = 0;
- }
- }
- }
- void WeaponClass::Do_Reload( void )
- {
- int added = (int)Definition->ClipSize - (int)ClipRounds;
- //
- // Check to see if the infinite ammo cheat is enabled
- //
- bool apply_cheat = false;
- if ( CheatMgrClass::Get_Instance () != NULL &&
- CheatMgrClass::Get_Instance ()->Is_Cheat_Enabled( CheatMgrClass::CHEAT_INFINITE_AMMO ) && Owner == COMBAT_STAR )
- {
- apply_cheat = true;
- }
- if ( apply_cheat == false && InventoryRounds >= 0 ) {
- if ( InventoryRounds < added ) {
- added = InventoryRounds;
- }
- InventoryRounds -= added;
- }
- ClipRounds += added;
- }
- float WeaponClass::Get_Range( void )
- {
- return ( PrimaryAmmoDefinition != NULL ) ? PrimaryAmmoDefinition->Range : 0;
- }
- /*
- ** Fire_C4
- */
- void WeaponClass::Fire_C4( const AmmoDefinitionClass *ammo_def )
- {
- #define C4_OBJECT_NAME "Tossed C4"
- // C4 special case
- C4GameObj *c4 = (C4GameObj *)ObjectLibraryManager::Create_Object( C4_OBJECT_NAME );
- if ( c4 ) {
- c4->Init_C4( ammo_def, Get_Owner()->As_SoldierGameObj(), C4DetonationMode, Get_Muzzle() );
- }
- return ;
- }
- /*
- ** Fire_Beacon
- */
- bool WeaponClass::Fire_Beacon( const AmmoDefinitionClass *ammo_def )
- {
- bool retval = false;
- // only for server
- if ( CombatManager::I_Am_Server() ) {
- //
- // Create the beacon
- //
- BeaconGameObj *beacon = (BeaconGameObj *)ObjectLibraryManager::Create_Object( ammo_def->BeaconDefID );
- if ( beacon != NULL ) {
- //
- // Get the position of the owner
- //
- Vector3 pos;
- Get_Owner()->Get_Position( &pos );
- beacon->Init_Beacon( Definition, Get_Owner()->As_SoldierGameObj(), pos );
- beacon->Start_Observers ();
- //
- // Begin arming the beacon
- //
- if ( beacon->Can_Place_Here ( pos ) ) {
- beacon->Begin_Arming();
- retval = true;
- } else {
- beacon->Set_Delete_Pending ();
- }
- }
- }
- return retval;
- }
- /*
- **
- */
- void WeaponClass::Do_Fire( bool primary )
- {
- WWPROFILE( "Do Fire" );
- // Stats
- if ( Get_Owner() &&
- Get_Owner()->As_SoldierGameObj() &&
- Get_Owner()->As_SoldierGameObj()->Get_Player_Data() ) {
- Get_Owner()->As_SoldierGameObj()->Get_Player_Data()->Stats_Add_Shot_Fired();
- Get_Owner()->As_SoldierGameObj()->Get_Player_Data()->Stats_Add_Weapon_Fired(
- this->Get_Definition()->Get_ID() );
- }
- // Debug_Say(( "Fire at %f\n", (float)WW3D::Get_Sync_Time() ));
- const AmmoDefinitionClass *ammo_def;
- if ( primary ) {
- ammo_def = PrimaryAmmoDefinition;
- } else {
- ammo_def = SecondaryAmmoDefinition;
- }
- // Debug_Say(( "Firing from %f %f %f\n", muzzle_pos.X, muzzle_pos.Y, muzzle_pos.Z ));
- // Debug_Say(( "Firing at %f %f %f\n", target_pos.X, target_pos.Y, target_pos.Z ));
- // Debug_Say(( " %d Clips %d in Clip\n", NumClips, ClipContents ));
- //
- // Handle each weapon type differently
- //
- if ( Get_Style() == WEAPON_HOLD_STYLE_BEACON ) {
- //
- // Try to fire the beacon
- //
- if ( Fire_Beacon( ammo_def ) ) {
- //
- // Decrement the rounds
- //
- // WWASSERT( BurstCount != 0 );
- BurstCount--;
- // WWASSERT( ClipRounds != 0 );
- Decrement_Rounds( ammo_def->SprayBulletCost );
- }
- } else {
- //
- // Decrement the rounds
- //
- // WWASSERT( BurstCount != 0 );
- BurstCount--;
- // WWASSERT( ClipRounds != 0 );
- Decrement_Rounds( ammo_def->SprayBulletCost );
- if ( Get_Style() == WEAPON_HOLD_STYLE_C4 ) {
- if ( CombatManager::I_Am_Server() ) { // Only on servers
- Fire_C4( ammo_def );
- }
- } else {
- Fire_Bullet( ammo_def, primary );
- }
- }
- return ;
- }
- /*
- ** Fire_Bullet
- */
- void WeaponClass::Fire_Bullet( const AmmoDefinitionClass *ammo_def, bool primary )
- {
- WWPROFILE( "Fire Bullet" );
- if ( Get_Owner() == COMBAT_STAR ) {
- Vector3 pos;
- COMBAT_STAR->Get_Position( &pos );
- DIAG_LOG(( "WFRD", "%1.2f; %1.2f; %1.2f; %s; %d; %d", pos.X, pos.Y, pos.Z, Get_Definition()->Get_Name(), !primary, Get_Total_Rounds() ));
- }
- int spray_count = ammo_def->SprayCount;
- if ( spray_count < 1 ) {
- spray_count = 1;
- }
- int muzzle_index = (Get_Total_Rounds_Fired() & 1) + ( primary ? 0 : 2 );
- if ( !Get_Owner()->Muzzle_Exists( muzzle_index ) ) {
- // if the second muzzle doesn't exist, use the first
- if ( muzzle_index & 1 ) {
- muzzle_index--;
- }
- }
- Matrix3D muzzle = Get_Muzzle( muzzle_index );
- // Special test for first person
- if ( CombatManager::Is_First_Person() && Get_Owner() == COMBAT_STAR ) {
- Vector3 fp_muzzle_pos = WeaponViewClass::Get_Muzzle_Pos();
- // cast to see what we hit
- Vector3 start = fp_muzzle_pos;
- Vector3 end = Get_Owner()->Get_Targeting_Pos();
- LineSegClass ray( start, end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- { WWPROFILE( "Cast_Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- // If the hit point is near the targeting_pos, use the first person muzzle
- if ( raytest.Result->Fraction >= 0.99F ) {
- muzzle.Obj_Look_At( fp_muzzle_pos, Get_Owner()->Get_Targeting_Pos(), 0 );
- }
- }
- Vector3 bullet_target(0,0,0);
- DamageableGameObj * target_obj = NULL;
- if ( ammo_def->IsTracking ) {
- // determine the target
- Vector3 start = muzzle.Get_Translation();
- // (gth) this modification makes bikes able to target anything even though their muzzle doesn't rotate...
- Vector3 end = Get_Owner()->Get_Targeting_Pos(); //muzzle * Vector3( ammo_def->Range, 0, 0 );
- LineSegClass ray( start, end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- { WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- ray.Compute_Point( raytest.Result->Fraction, &end );
- bullet_target = end;
- if ( raytest.CollidedPhysObj != NULL && raytest.CollidedPhysObj->Get_Observer() != NULL ) {
- target_obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_DamageableGameObj();
- // No homing on buildings
- if ( target_obj->As_BuildingGameObj() != NULL ) {
- target_obj = NULL;
- }
- }
- }
- for ( int count = 0; count < spray_count; count++ ) {
- Vector3 velocity = muzzle.Get_X_Vector() * ammo_def->Velocity;
- #if 0
- if ( ammo_def->SprayAngle ) {
- // Use Spray Angle
- Vector3 spray_adjust = RANDOM_VECTOR( 1.0 );
- spray_adjust.Normalize();
- spray_adjust = spray_adjust * ammo_def->Velocity;
- spray_adjust *= ammo_def->SprayAngle / (float)(2*WWMATH_PI);
- velocity += spray_adjust;
- velocity.Normalize();
- velocity = velocity * ammo_def->Velocity;
- }
- if ( DynamicErrorAngle ) {
- velocity += RANDOM_VECTOR( DynamicErrorAngle / 2 );
- velocity.Normalize();
- velocity = velocity * ammo_def->Velocity;
- }
- #else
- Matrix3D VelTM;
- // Look at backwards with random roll
- VelTM.Look_At( velocity, Vector3( 0,0,0 ), FreeRandom.Get_Float( DEG_TO_RADF( 360.0f ) ) );
- #define SPRAY_CHEAT 0
- #if SPRAY_CHEAT
- float error_angle = 0;
- #else
- float error_angle = ammo_def->SprayAngle;
- #endif
- float rand_angle = FreeRandom.Get_Float() * error_angle;
- VelTM.Rotate_Y( rand_angle );
- velocity = VelTM.Get_Z_Vector();
- velocity.Normalize();
- velocity *= ammo_def->Velocity;
- #endif
- //Vector3 position = muzzle.Get_Translation();
- Vector3 position;
- Compute_Bullet_Start_Point(muzzle,&position);
- BulletBumpTime += ammo_def->AliasedSpeed * TimeManager::Get_Frame_Seconds() * 1.3f;
- BulletBumpTime = WWMath::Wrap( BulletBumpTime, 0, TimeManager::Get_Frame_Seconds() );
- float bump_time = BulletBumpTime;
- if ( (float)ammo_def->Velocity != 0 ) {
- bump_time += 1 / (float)ammo_def->Velocity; // Skip the first meter
- }
- //Debug_Say(( "%f %f\n", BulletBumpTime,bump_time ));
- if ( Target.Length2() != 0 || !ammo_def->IsTracking ) {
- bullet_target = Target;
- }
- // Bullets from vehicles belong to the gunner
- ArmedGameObj * bullet_owner = Get_Owner();
- if ( bullet_owner != NULL && bullet_owner->As_SmartGameObj() ) {
- VehicleGameObj * vehicle = bullet_owner->As_SmartGameObj()->As_VehicleGameObj();
- if ( ( vehicle ) && ( vehicle->Get_Actual_Gunner() != NULL ) ) {
- bullet_owner = vehicle->Get_Actual_Gunner();
- }
- }
- // Create a bullet
- BulletManager::Create_Bullet( ammo_def, position, velocity, bullet_owner, bump_time, bullet_target, target_obj );
- }
- if ( ammo_def->DisplayLaser ) {
- TimedDecorationPhysClass * laser_obj = NEW_REF( TimedDecorationPhysClass, () );
- if ( laser_obj ) {
- // Find where the laser should stop
- Vector3 start = muzzle.Get_Translation();
- Vector3 end = muzzle * Vector3( ammo_def->Range, 0, 0 );
- LineSegClass ray( start, end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- { WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- ray.Compute_Point( raytest.Result->Fraction, &end );
- // Create a laser
- RenderObjClass * model = NEW_REF( Line3DClass, ( start, end, 0.1f, 0.8f,0,0, 0.8f ) );
- laser_obj->Set_Model( model );
- model->Release_Ref();
- laser_obj->Set_Lifetime( 0.6f );
- laser_obj->Update_Cull_Box(); // htis may be needed due to a bug in Line3DClass
- COMBAT_SCENE->Add_Dynamic_Object( laser_obj );
- laser_obj->Release_Ref();
- }
- }
- // Initiate recoil effects on our parent object.
- Get_Owner()->Start_Recoil(muzzle_index,Get_Recoil_Scale(),Get_Recoil_Time());
- TotalRoundsFired++;
- }
- bool WeaponClass::Is_Muzzle_Clear()
- {
- int primary = 1;
- int muzzle_index = Get_Total_Rounds_Fired() & 1 + ( primary ? 0 : 2 );
- Matrix3D muzzle = Get_Muzzle( muzzle_index );
- Vector3 start_pt;
- Vector3 end_pt;
- muzzle.Get_Translation( &end_pt );
- if ( Get_Owner() == NULL ) {
- return true;
- }
- if ((Get_Owner() == COMBAT_STAR) && CombatManager::Is_First_Person()) {
- return true;
- }
- if (Get_Owner()->As_SoldierGameObj() != NULL) {
-
- start_pt = Get_Owner()->Get_Bullseye_Position();
- } else {
- // Estimate the distance we need to sweep back along the muzzle in order to be inside the vehicle.
- Vector3 owner_pos;
- Get_Owner()->Get_Position( &owner_pos );
- owner_pos -= end_pt;
- owner_pos.Z = 0.0f;
- float dist = owner_pos.Quick_Length();
- // Compute the starting point for a ray to test if the muzzle is inside anything.
- Vector3 offset;
- Matrix3D::Rotate_Vector(muzzle,Vector3(-dist,0.0f,0.0f),&offset);
- start_pt = end_pt + offset;
- }
- // Cast the ray
- LineSegClass ray( start_pt, end_pt );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- raytest.CheckDynamicObjs = false;
- {
- WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- return raytest.Result->Fraction == 1.0f;
- }
- void WeaponClass::Compute_Bullet_Start_Point(const Matrix3D & muzzle,Vector3 * set_start_point)
- {
- //
- // The default behavior is to start the bullet at the position of the muzzle.
- //
- muzzle.Get_Translation(set_start_point);
- //
- // If this weapon is owned by a vehicle, try to ensure the bullet starts in front
- // of any dynamic objects that may be between the muzzle point and the body of the vehicle
- //
- if (Get_Owner()->As_VehicleGameObj() != NULL) {
- Vector3 ray_start;
- Vector3 ray_end;
- muzzle.Get_Translation( &ray_end );
- // Estimate the distance we need to sweep back along the muzzle in order to be inside the vehicle.
- Vector3 owner_pos;
- Get_Owner()->Get_Position( &owner_pos );
- owner_pos -= ray_end;
- owner_pos.Z = 0.0f;
- float dist = owner_pos.Quick_Length();
- // Compute the starting point for a ray to test if the muzzle is inside anything.
- Vector3 offset;
- Matrix3D::Rotate_Vector(muzzle,Vector3(-dist,0.0f,0.0f),&offset);
- ray_start = ray_end + offset;
- // Cast the ray
- LineSegClass ray( ray_start, ray_end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- raytest.CheckStaticObjs = false;
- {
- Ignore_Owner();
- WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- Unignore_Owner();
- }
- if (res.Fraction < 1.0f) {
- ray.Compute_Point(res.Fraction,set_start_point);
- }
- }
- }
- void WeaponClass::Do_Firing_Effects( void )
- {
- if ( TimeManager::Get_Frame_Seconds() == 0 ) {
- return; // No sounds when time stops
- }
- WWPROFILE( "Firing Effects" );
- Matrix3D muzzle = Get_Muzzle();
- // Don't do these two if fired by the star in First Person Mode
- if ( (Get_Owner() != COMBAT_STAR) || !CombatManager::Is_First_Person() ) {
- #if 01
- // create muzzle flash
- if ( Definition->MuzzleFlashPhysDefID != 0 ) {
- DefinitionClass * def = DefinitionMgrClass::Find_Definition( Definition->MuzzleFlashPhysDefID );
- if ( def != NULL ) {
- WWASSERT( ((PhysDefClass *)def)->Is_Type( "TimedDecorationPhysDef" ) );
- TimedDecorationPhysClass * muzzle_flash = (TimedDecorationPhysClass *)def->Create();
- if ( muzzle_flash ) {
- RenderObjClass * model = muzzle_flash->Peek_Model();
- if ( model != NULL ) {
- // muzzle.Rotate_X( FreeRandom.Get_Float( DEG_TO_RAD( 360 ) ) );
- muzzle_flash->Set_Transform( muzzle );
- COMBAT_SCENE->Add_Dynamic_Object( muzzle_flash );
- // If this is an emitter, start it
- if ( model->Class_ID() == RenderObjClass::CLASSID_PARTICLEEMITTER ) {
- ParticleEmitterClass * pe = (ParticleEmitterClass *)model;
- pe->Start();
- }
- } else {
- Debug_Say(( "Missing muzzle flash for %s\n", Definition->Get_Name() ));
- }
- muzzle_flash->Release_Ref();
- }
- } else {
- //Debug_Say(( "Couldn't find muzzle flash def for %s\n", Definition->Get_Name() ));
- }
- }
- #endif
- // if this gun is fired by the STAR and they have an eject bone, eject a shell.
- if ((Get_Owner() == COMBAT_STAR) && (Model != NULL)) {
- WWPROFILE( "Eject" );
- int eject_index = Model->Get_Bone_Index( "eject" );
- if ( eject_index > 0 ) {
- Make_Shell_Eject( Model->Get_Bone_Transform( eject_index ) );
- }
- }
- }
- // Make the Gunshot sound
- //
- // Determine which sound to play, the primary or secondary firing sound?
- //
- int sound_id = 0;
- if ( IsPrimaryTriggered && PrimaryAmmoDefinition != NULL ) {
- sound_id = PrimaryAmmoDefinition->FireSoundDefID;
- } else if ( IsSecondaryTriggered && SecondaryAmmoDefinition != NULL ) {
- sound_id = SecondaryAmmoDefinition->FireSoundDefID;
- }
- //
- // Release the old firing sound (if necessary)
- //
- bool release_curr_sound = false;
- if ( sound_id != FiringSoundDefID && FiringSound != NULL ) {
- release_curr_sound = true;
- }
- //
- // For first-person we make the weapon sounds "2D", so check to see
- // if we need to re-create the sound...
- //
- if ( FiringSound != NULL ) {
- if ( Get_Owner() == COMBAT_STAR && CombatManager::Is_First_Person() ) {
-
- //
- // In first person, we need the sound to be "2D"
- //
- if ( FiringSound->Get_Class_ID () != CLASSID_2D ) {
- release_curr_sound = true;
- }
- } else {
- //
- // In third person, we need the sound to be "3D"
- //
- if ( FiringSound->Get_Class_ID () == CLASSID_2D ) {
- release_curr_sound = true;
- }
- }
- }
- //
- // Release the currently playing sound as necessary
- //
- if ( release_curr_sound ) {
- FiringSound->Remove_From_Scene ();
- REF_PTR_RELEASE (FiringSound);
- FiringSoundDefID = 0;
- }
- //
- // Do we need to recreate the firing sound object, or can we just
- // reuse the one we already have?
- //
- if ( FiringSound != NULL ) {
- //
- // Stop the current sound
- //
- //FiringSound->Set_Transform( muzzle );
- //FiringSound->Stop();
- if ( FiringSound->Get_Class_ID () == CLASSID_3D ) {
- FiringSound->Stop();
- } else {
- FiringSound->Seek( 0 );
- }
-
-
- //
- // Force the sound to play
- //
- if ( Get_Owner() != COMBAT_STAR || CombatManager::Is_First_Person() == false ) {
- FiringSound->Add_To_Scene( true );
- FiringSound->Play();
- } else {
- FiringSound->Play();
- }
- //
- // Play the sound (or add it to the scene)
- //
- /*if ( Get_Owner() == COMBAT_STAR && CombatManager::Is_First_Person() ) {
- FiringSound->Play();
- } else {
- FiringSound->Remove_From_Scene();
- FiringSound->Add_To_Scene( true );
- }*/
- } else {
- //
- // Create a pseudo-3d sound effect for this firing sound and
- // add it to the sound scene.
- //
- if ( sound_id != 0 ) {
-
- //
- // Determine whether to play the sound as 2D or 3D
- //
- int classid_hint = CLASSID_3D;
- if ( Get_Owner() == COMBAT_STAR && CombatManager::Is_First_Person() ) {
- classid_hint = CLASSID_2D;
- }
- //
- // Create the sound
- //
- RefCountedGameObjReference *owner_ref = new RefCountedGameObjReference;
- owner_ref->Set_Ptr( Get_Owner() );
- FiringSound = WWAudioClass::Get_Instance()->Create_Sound( sound_id, owner_ref, 0, classid_hint );
- REF_PTR_RELEASE( owner_ref );
- }
- if ( FiringSound != NULL ) {
- FiringSoundDefID = sound_id;
- FiringSound->Set_Transform( muzzle );
- FiringSound->Attach_To_Object( Model );
- FiringSound->Add_To_Scene( true );
- }
- }
- // (gth) Apply an Impulse to tanks when they fires a bullet
- // Byon, this can be done with any RigidBody derived physics object (all vehicles)
- // I suggest making it a parameter of the weapon and having the strength be a
- // multiple of the mass of the vehicle.
- ArmedGameObj * owner = Get_Owner();
- VehicleGameObj * vehicle_game_obj = owner->As_VehicleGameObj();
- if (vehicle_game_obj != NULL) {
- PhysClass * vehicle = vehicle_game_obj->Peek_Physical_Object();
- if (vehicle->As_TrackedVehicleClass() != NULL) {
- RigidBodyClass * rbody = (RigidBodyClass *)vehicle;
- Vector3 impulse_pos;
- muzzle.Get_Translation(&impulse_pos);
- Vector3 impulse;
- muzzle.Get_X_Vector(&impulse);
- impulse *= -Definition->RecoilImpulse * rbody->Get_Mass();
- rbody->Apply_Impulse(impulse,impulse_pos);
- }
- }
- // Play an anim on the human owner
- if ( owner != NULL && owner->As_SoldierGameObj() ) {
- if ( !Definition->HumanFiringAnimation.Is_Empty() ) {
- owner->As_SoldierGameObj()->Set_Animation( Definition->HumanFiringAnimation, 0, 0 );
- }
- }
- }
- void WeaponClass::Make_Shell_Eject( const Matrix3D & tm )
- {
- DefinitionClass * def = DefinitionMgrClass::Find_Definition( Definition->EjectPhysDefID );
- if ((def != NULL) && ((PhysDefClass *)def)->Is_Type( "ProjectileDef" )) {
- // Create the object
- ProjectileClass * PhysicalObject = (ProjectileClass *)def->Create();
- // Set its transform, collision group, observer, and initial velocity
- PhysicalObject->Set_Transform( tm );
- PhysicalObject->Set_Observer(&_TheEjectCasingObserver);
- PhysicalObject->Set_Collision_Group( DEFAULT_COLLISION_GROUP );
- PhysicalObject->Set_Velocity( tm.Rotate_Vector( Vector3( 2,0,0 ) ) );
- // Add it to the scene
- COMBAT_SCENE->Add_Dynamic_Object( PhysicalObject );
- PhysicalObject->Release_Ref();
- }
- }
- /*
- **
- */
- void WeaponClass::Do_Continuous_Effects( bool enable )
- {
- if ( !enable ) {
- for ( int i = 0; i < ContinuousEmitters.Length(); i++ ) {
- if ( ContinuousEmitters[i] != NULL ) {
- // Check if it is in the scene, it may ahve already been remove by completion
- if ( ContinuousEmitters[i]->Peek_Scene() != NULL ) {
- PhysicsSceneClass::Get_Instance()->Remove_Render_Object( ContinuousEmitters[i] );
- }
- ContinuousEmitters[i]->Stop();
- ContinuousEmitters[i]->Release_Ref();
- ContinuousEmitters[i] = NULL;
- }
- }
- if ( ContinuousSound != NULL ) {
- ContinuousSound->Stop();
- ContinuousSound->Remove_From_Scene();
- ContinuousSound->Release_Ref();
- ContinuousSound = NULL;
- }
- }
- if ( enable ) {
- const AmmoDefinitionClass *ammo_def = PrimaryAmmoDefinition;
- if (IsPrimaryTriggered == false && IsSecondaryTriggered) {
- ammo_def = SecondaryAmmoDefinition;
- }
- int i;
- if ( ContinuousEmitters.Length() == 0 ) {
- int num_muzzles = 1;
- if ( Get_Muzzle( 0 ) != Get_Muzzle( 1 ) ) {
- num_muzzles = 2;
- }
- ContinuousEmitters.Resize( num_muzzles );
- for ( int i = 0; i < ContinuousEmitters.Length(); i++ ) {
- ContinuousEmitters[i] = NULL;
- }
- }
- for ( i = 0; i < ContinuousEmitters.Length(); i++ ) {
- if ( ContinuousEmitters[i] == NULL && !ammo_def->ContinuousEmitterName.Is_Empty() ) {
- RenderObjClass * renderobj = Create_Render_Obj_From_Filename( ammo_def->ContinuousEmitterName );
- if ( renderobj ) {
- WWASSERT( renderobj->Class_ID() == RenderObjClass::CLASSID_PARTICLEEMITTER );
- ContinuousEmitters[i] = (ParticleEmitterClass *)renderobj;
- ContinuousEmitters[i]->Set_Velocity_Inheritance_Factor( 1 );
- }
- if ( ContinuousEmitters[i] ) {
- SET_REF_OWNER( ContinuousEmitters[i] );
- ContinuousEmitters[i]->Start();
- PhysicsSceneClass::Get_Instance()->Add_Render_Object( ContinuousEmitters[i] );
- }
- }
- }
- if ( ContinuousSound == NULL && ammo_def->ContinuousSoundDefID != 0 ) {
- ContinuousSound = WWAudioClass::Get_Instance()->Create_Continuous_Sound( ammo_def->ContinuousSoundDefID );
- if ( ContinuousSound != NULL ) {
- ContinuousSound->Add_To_Scene( true );
- }
- }
- // if first person star, use first muzzle
- if ( (Get_Owner() == COMBAT_STAR) && CombatManager::Is_First_Person() ) {
- Vector3 fp_muzzle_pos = WeaponViewClass::Get_Muzzle_Pos();
- Matrix3D muzzle;
- muzzle.Obj_Look_At( fp_muzzle_pos, Get_Owner()->Get_Targeting_Pos(), 0 );
- for ( i = 0; i < ContinuousEmitters.Length(); i++ ) {
- if ( ContinuousEmitters[i] != NULL ) {
- ContinuousEmitters[i]->Set_Transform( muzzle );
- }
- }
- if ( ContinuousSound != NULL ) {
- ContinuousSound->Set_Transform( muzzle );
- }
- } else {
- for ( i = 0; i < ContinuousEmitters.Length(); i++ ) {
- if ( ContinuousEmitters[i] != NULL ) {
- ContinuousEmitters[i]->Set_Transform( Get_Muzzle( i ) );
- }
- }
- if ( ContinuousSound != NULL ) {
- ContinuousSound->Set_Transform( Get_Muzzle() );
- }
- }
- }
- }
- #define WEAPON_RATE_CHEAT 0
- /*
- ** Weapon State
- */
- void WeaponClass::Set_State( WeaponStateType new_state )
- {
- #define SWITCH_TIME 1.0f
- #define RELOAD_TIME Definition->ReloadTime
- #define READY_TIME 25.0f
- // Debug_Say(( "Weapon switching from state %d to %d\n", State, new_state ));
- State = new_state;
- if ( State == STATE_START_SWITCH ) StateTimer = SWITCH_TIME/2.0f;
- if ( State == STATE_END_SWITCH ) StateTimer = SWITCH_TIME/2.0f;
- if ( State == STATE_RELOAD ) StateTimer = (float) RELOAD_TIME;
- if ( State == STATE_READY ) StateTimer = READY_TIME; // delay til IDLE
- if ( State == STATE_FIRE_PRIMARY ) StateTimer = 1.0f / PrimaryAmmoDefinition->RateOfFire;
- if ( State == STATE_FIRE_SECONDARY )StateTimer = 1.0f / SecondaryAmmoDefinition->RateOfFire;
- if ( State == STATE_CHARGE ) StateTimer = PrimaryAmmoDefinition->ChargeTime; // Charge Time
- #if WEAPON_RATE_CHEAT
- if ( Get_Owner() == COMBAT_STAR ) {
- StateTimer *= 0.2f;
- }
- #endif
- }
- void WeaponClass::Update_State( float pending_time )
- {
- LockTriggers = false; // Unlock triggers
- WWPROFILE( "Update weapon state" );
- while ( pending_time > 0.0f ) {
- bool trigger_ok = true;
- // Only fire beacon if state is upright
- if ( Get_Style() == WEAPON_HOLD_STYLE_BEACON &&
- Get_Owner() && Get_Owner()->As_SoldierGameObj() &&
- !Get_Owner()->As_SoldierGameObj()->Is_Upright() ) {
- trigger_ok = false;
- }
- // If we can fire, start charging, it will fire and go back to READY
- if ( (State == STATE_READY) || (State == STATE_IDLE) ) {
- if ( (IsPrimaryTriggered || IsSecondaryTriggered) && (BurstCount != 0) && CombatManager::Is_Gameplay_Permitted() && trigger_ok ) {
- if ( SafetySet ) {
- LockTriggers = true;
- } else {
- if ( Is_Loaded() ) {
- Set_State( STATE_CHARGE );
- } else {
- // We are not loaded, play the empty sound
- #if 0
- AudibleSoundClass * sound = WWAudioClass::Get_Instance()->Create_Sound( "Pistol_Empty_Click" );
- if ( sound ) {
- sound->Play();
- sound->Release_Ref();
- }
- #else
- if ( Definition->EmptySoundDefID != 0 ) {
- EmptySoundTimer -= TimeManager::Get_Frame_Seconds();
- if ( EmptySoundTimer <= 0 ) {
- EmptySoundTimer = 0.3f;
- Matrix3D muzzle = Get_Muzzle();
- RefCountedGameObjReference *owner_ref = new RefCountedGameObjReference;
- owner_ref->Set_Ptr( Get_Owner() );
- AudibleSoundClass * sound = WWAudioClass::Get_Instance()->Create_Sound( Definition->EmptySoundDefID, owner_ref );
- if ( sound != NULL ) {
- sound->Set_Transform( muzzle );
- sound->Attach_To_Object( Model );
- sound->Add_To_Scene( true );
- sound->Release_Ref();
- }
- REF_PTR_RELEASE( owner_ref );
- }
- }
- #endif
- }
- }
- }
- // Force a reload when empty
- if ( Is_Reload_Needed() ) {
- Force_Reload();
- }
- }
- float useable_time = min( StateTimer, pending_time );
- StateTimer -= useable_time;
- pending_time -= useable_time;
- if ( StateTimer <= 0 ) { // Time for new state
- switch ( State ) {
- case STATE_IDLE:
- StateTimer = 0;
- pending_time = 0;
- break;
- case STATE_READY:
- Set_State( STATE_IDLE );
- break;
- case STATE_CHARGE:
- if ( IsPrimaryTriggered || !IsSecondaryTriggered ) {
- Set_State( STATE_FIRE_PRIMARY );
- } else {
- Set_State( STATE_FIRE_SECONDARY );
- }
- if ( IsPrimaryTriggered || IsSecondaryTriggered ) {
- if ( Is_Muzzle_Clear() ) {
- Do_Fire( IsPrimaryTriggered );
- DidFire = true;
- }
- }
- break;
- case STATE_FIRE_PRIMARY:
- case STATE_FIRE_SECONDARY:
- Set_State( STATE_READY );
- break;
- case STATE_RELOAD:
- Do_Reload();
- Set_State( STATE_READY );
- break;
- case STATE_START_SWITCH:
- if ( UpdateModel == WEAPON_MODEL_UPDATE_WILL_BE_NEEDED ) {
- UpdateModel = WEAPON_MODEL_UPDATE_IS_NEEDED;
- }
- Set_State( STATE_END_SWITCH );
- break;
- case STATE_END_SWITCH:
- Set_State( STATE_IDLE );
- break;
- }
- }
- }
- }
- void WeaponClass::Force_Reload( void )
- {
- // Stop reloading on last bullet to fire faster
- // if ( Is_Reload_OK() && State != STATE_RELOAD ) {
- if ( Is_Reload_OK() && State <= STATE_READY ) {
- Set_State( STATE_RELOAD );
- if ( Definition->ReloadSoundDefID != 0 ) {
- // Make the reload sound
- Matrix3D muzzle = Get_Muzzle();
- RefCountedGameObjReference *owner_ref = new RefCountedGameObjReference;
- owner_ref->Set_Ptr( Get_Owner() );
- AudibleSoundClass * sound = WWAudioClass::Get_Instance()->Create_Sound( Definition->ReloadSoundDefID, owner_ref );
- if ( sound != NULL ) {
- sound->Set_Transform( muzzle );
- sound->Attach_To_Object( Model );
- sound->Add_To_Scene( true );
- sound->Release_Ref();
- }
- REF_PTR_RELEASE( owner_ref );
- }
- }
- }
- /*
- **
- */
- void WeaponClass::Update( void )
- {
- // Remove player weapons from vehicle drivers
- if ( Get_Owner() &&
- Get_Owner()->As_SoldierGameObj() &&
- Get_Owner()->As_SoldierGameObj()->Is_In_Vehicle() ) {
- IsPrimaryTriggered = false;
- IsSecondaryTriggered = false;
- }
- if ( Get_Style() == WEAPON_HOLD_STYLE_C4 ||
- Get_Style() == WEAPON_HOLD_STYLE_BEACON ||
- Get_Can_Snipe() )
- {
- IsSecondaryTriggered = false;
- }
- WWASSERT( PrimaryAmmoDefinition != NULL );
- // Update Burst logic
- if ( (int)PrimaryAmmoDefinition->BurstMax == 0 ) { // if not using bursts
- BurstCount = -1;
- } else {
- BurstDelayTimer -= TimeManager::Get_Frame_Seconds();
- if ( (!IsPrimaryTriggered && !IsSecondaryTriggered) || ( BurstDelayTimer <= 0.0f ) ) {
- BurstDelayTimer = PrimaryAmmoDefinition->BurstDelayTime * FreeRandom.Get_Float( 0.50f, 1.0f );
- BurstCount = PrimaryAmmoDefinition->BurstMax;
- }
- }
- if ( TimeManager::Get_Frame_Seconds() != 0 ) {
- DidFire = false; // reset the did fire flag for this frame
- }
- Update_State( TimeManager::Get_Frame_Seconds() );
- // If star in first person, force no muzzle flashes on 3rd person model
- if ( (Get_Owner() == COMBAT_STAR) && CombatManager::Is_First_Person() ) {
- Update_Muzzle_Flash( false, false );
- } else {
- Update_Muzzle_Flash( DidFire && (TotalRoundsFired & 1), DidFire && (~TotalRoundsFired & 1) );
- }
- if ( DidFire ) {
- Do_Firing_Effects(); // Create muzzle flash and sounds
- NextAnimState = (TotalRoundsFired & 1) ? WEAPON_ANIM_FIRING_0 : WEAPON_ANIM_FIRING_1;
- } else {
- NextAnimState = WEAPON_ANIM_NOT_FIRING;
- }
- //
- // Remove any continuous effects if the trigger state has changed since last frame
- //
- if ( (IsPrimaryTriggered == false && LastFrameIsPrimaryTriggered == true) ||
- (IsSecondaryTriggered == false && LastFrameIsSecondaryTriggered == true) )
- {
- Do_Continuous_Effects( false );
- } else {
- //
- // Determine whether or not to trigger the continuous effects (emitters) for
- // this weapon.
- //
- bool emitters_on = IsPrimaryTriggered || IsSecondaryTriggered;
- if ( State == STATE_START_SWITCH || State == STATE_END_SWITCH ||
- State == STATE_RELOAD || Get_Clip_Rounds() == 0 ) {
- emitters_on = false;
- }
- Do_Continuous_Effects( emitters_on );
- }
- //
- // Remember what our state last frame was...
- //
- LastFrameIsPrimaryTriggered = IsPrimaryTriggered;
- LastFrameIsSecondaryTriggered = IsSecondaryTriggered;
- return ;
- }
- /*
- ** Simulate firing straight down the muzzle and see where in the world we hit
- */
- bool WeaponClass::Cast_Weapon_Down_Muzzle( Vector3 & hit_pos )
- {
- int muzzle_index = Get_Total_Rounds_Fired() & 1;
- Matrix3D muzzle = Get_Muzzle( muzzle_index );
- //
- // Determine the start and end positions of the ray
- //
- Vector3 start = muzzle.Get_Translation();
- Vector3 end = muzzle * Vector3( Get_Range(), 0, 0 );
- LineSegClass ray( start, end );
- //
- // Cast the ray into the world
- //
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- { WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- //
- // Calculate where in the world this would hit
- //
- bool retval = false;
- if ( res.StartBad == false ) {
- hit_pos = start + (end * res.Fraction);
- retval = true;
- }
- return retval;
- }
- /*
- ** Simulate firing from muzzle to target, see where and if we hit
- */
- PhysicalGameObj * WeaponClass::Cast_Weapon( const Vector3 & target )
- {
- int muzzle_index = Get_Total_Rounds_Fired() & 1;
- Matrix3D muzzle = Get_Muzzle( muzzle_index );
- Vector3 start = muzzle.Get_Translation();
- // Vector3 end = muzzle * Vector3( Get_Range(), 0, 0 );
- Vector3 end = target;
- LineSegClass ray( start, end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- { WWPROFILE( "Cast Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- // Debug_Say(( "Weapon Focus %f %f %f\n", bullet_hit_position->X, bullet_hit_position->Y, bullet_hit_position->Z ));
- PhysicalGameObj * hit_obj = NULL;
- if ( raytest.CollidedPhysObj ) {
- if ( raytest.CollidedPhysObj->Get_Observer() != NULL ) {
- hit_obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_PhysicalGameObj();
- }
- }
- return hit_obj;
- }
- /*
- ** Check to see if this weapon can reload
- */
- bool
- WeaponClass::Is_Reload_OK( void )
- {
- bool retval = (InventoryRounds != 0);
- //
- // Allow reloads if the infinite ammo cheat is enabled
- //
- if ( CheatMgrClass::Get_Instance () != NULL &&
- CheatMgrClass::Get_Instance ()->Is_Cheat_Enabled( CheatMgrClass::CHEAT_INFINITE_AMMO ) && Owner == COMBAT_STAR )
- {
- retval = true;
- }
- return retval;
- }
- void WeaponClass::Stop_Firing_Sound( void )
- {
- if ( FiringSound == NULL ) {
- return ;
- }
- //
- // Stop the sound
- //
- FiringSound->Stop ();
- FiringSound->Remove_From_Scene ();
- REF_PTR_RELEASE (FiringSound);
- return ;
- }
- // This function calcuates the weapon information that must be displayed for the star's
- // weapon in the hud reticle & sniper view. This should only be called for the weapon
- // we want to show a reticle for.
- // The goal is to find the HitPosition, and HitPositionHot
- void WeaponClass::Display_Targeting( void )
- {
- WWPROFILE( "Cast_Star_Weapon" );
- int muzzle_index = Get_Total_Rounds_Fired() & 1;
- // vehicles that don't have a turret bone and do have homing weapons target from the camera
- Matrix3D muzzle;
- VehicleGameObj * vehicle = Get_Owner()->As_VehicleGameObj();;
- if (vehicle && (vehicle->Has_Turret() == false) && (PrimaryAmmoDefinition->IsTracking)) {
- muzzle = COMBAT_CAMERA->Get_Transform();
- muzzle.Rotate_Z( DEG_TO_RADF(90.0) );
- muzzle.Rotate_Y( DEG_TO_RADF(90.0) );
- } else {
- muzzle = Get_Muzzle( muzzle_index );
- }
- // Cast a ray to see what the weapon is pointing at
- Vector3 start = muzzle.Get_Translation();
- Vector3 end = muzzle * Vector3( Get_Range(), 0, 0 );
- LineSegClass ray( start, end );
- CastResultStruct res;
- PhysRayCollisionTestClass raytest(ray,&res,BULLET_COLLISION_GROUP,COLLISION_TYPE_PROJECTILE);
- Ignore_Owner();
- {
- WWPROFILE( "Cast_Ray" );
- COMBAT_SCENE->Cast_Ray( raytest );
- }
- Unignore_Owner();
- Vector3 pos;
- ray.Compute_Point( raytest.Result->Fraction, &pos );
- HUDInfo::Set_Weapon_Target_Position( pos );
- // Debug_Say(( "Weapon Focus %f %f %f\n", bullet_hit_position->X, bullet_hit_position->Y, bullet_hit_position->Z ));
- if ( raytest.CollidedPhysObj && raytest.CollidedPhysObj->Get_Observer() != NULL ) {
- DamageableGameObj * obj = ((CombatPhysObserverClass *)raytest.CollidedPhysObj->Get_Observer())->As_DamageableGameObj();
- if ( obj->Is_Targetable() == false ) {
- obj = NULL;
- }
- // if stealthed and enemy, it's not targetable
- if ( obj && obj->As_SmartGameObj() && obj->As_SmartGameObj()->Is_Stealthed() &&
- COMBAT_STAR && obj->Is_Enemy( COMBAT_STAR ) ) {
- obj = NULL;
- }
- HUDInfo::Set_Weapon_Target_Object( obj );
- // We have a problem here with a building here clearing the PT, so dont set
- // buildings here, assume they will be set from the ccamera
- // Mo, try pulling back the cast above
- if ( obj == NULL || obj->As_BuildingGameObj() == NULL ) {
- HUDInfo::Set_Info_Object( obj );
- }
- }
- }
- #if 0
- // Aquire
- if ( AmmoDefinition->AquireTime != 0.0f ) {
- SmartGameObj *target = weapon->Pointing_At_Target();
- if ( target ) {
- if ( AquireTarget != target ) { // locking onto someone new
- AquireTarget = target;
- AquireTimer = 0.0f;
- }
- AquireTimer += TimeManager::Get_Frame_Seconds(); // Bump the timer forward in seconds
- if (AquireTimer >= AmmoDefinition->AquireTime) {
- AquireTimer = AmmoDefinition->AquireTime;
- }
- } else {
- AquireTimer -= TimeManager::Get_Frame_Seconds(); // Bump the timer backwards in seconds
- if ( AquireTimer < 0.0f ) {
- AquireTimer = 0.0f;
- }
- }
- IsAquired = (target != NULL) &&
- (AquireTimer >= AmmoDefinition->AquireTime);
- }
- #endif
- const Matrix3D & WeaponClass::Get_Muzzle( int index )
- {
- WWASSERT( Get_Owner() != NULL );
- // Star's weapon in first person fires from the camera
- if ( Get_Owner() == COMBAT_STAR && CombatManager::Is_First_Person() ) {
- static Matrix3D _muzzle;
- _muzzle.Obj_Look_At( COMBAT_CAMERA->Get_Transform().Get_Translation(), Get_Owner()->Get_Targeting_Pos(), 0 );
- return _muzzle;
- }
- return Get_Owner()->Get_Muzzle( index );
- }
- void WeaponClass::Ignore_Owner( void )
- {
- if ( Get_Owner() != NULL ) {
- if ( Get_Owner()->Peek_Physical_Object() != NULL ) {
- Get_Owner()->Peek_Physical_Object()->Inc_Ignore_Counter();
- }
- // If Owner is a vehicle, inc all the occupants
- if ( Get_Owner()->As_VehicleGameObj() != NULL ) {
- Get_Owner()->As_VehicleGameObj()->Ignore_Occupants();
- }
- }
- }
- void WeaponClass::Unignore_Owner( void )
- {
- if ( Get_Owner() != NULL ) {
- if ( Get_Owner()->Peek_Physical_Object() != NULL ) {
- Get_Owner()->Peek_Physical_Object()->Dec_Ignore_Counter();
- }
- if ( Get_Owner()->As_VehicleGameObj() != NULL ) {
- Get_Owner()->As_VehicleGameObj()->Unignore_Occupants();
- }
- }
- }
- /*
- **
- */
- MuzzleFlashClass::MuzzleFlashClass( void ) :
- MuzzleA0Bone( 0 ),
- MuzzleA1Bone( 0 ),
- Rotation( 0 ),
- Model( 0 ),
- LastFlashA0( true ),
- LastFlashA1( true )
- {
- }
- MuzzleFlashClass::~MuzzleFlashClass( void )
- {
- REF_PTR_RELEASE( Model );
- }
- void MuzzleFlashClass::Init( RenderObjClass * model )
- {
- REF_PTR_SET( Model, model );
- if ( model != NULL ) {
- // Find the muzzle bone ( for rotation )
- MuzzleA0Bone = model->Get_Bone_Index( "muzzlea0" );
- MuzzleA1Bone = model->Get_Bone_Index( "muzzlea1" );
- if ( MuzzleA0Bone > 0 ) {
- // model->Capture_Bone( MuzzleA0Bone );
- }
- if ( MuzzleA1Bone > 0 ) {
- // model->Capture_Bone( MuzzleA1Bone );
- }
- Update( false, false );
- }
- }
- void MuzzleFlashClass::Update( bool flashA0, bool flashA1 )
- {
- if ( MuzzleA1Bone == 0 ) {
- flashA0 = flashA0 | flashA1;
- flashA1 = false;
- }
- if ( Model != NULL ) {
- if (( MuzzleA0Bone > 0 ) && (LastFlashA0 != flashA0)) {
- LastFlashA0 = flashA0;
- #if 0
- if ( flash ) {
- Rotation += TimeManager::Get_Frame_Seconds() * 10;
- Matrix3D tm(1);
- tm.Rotate_X( Rotation );
- Model->Control_Bone( MuzzleA0Bone, tm );
- }
- #endif
- for (int i=0; i<Model->Get_Num_Sub_Objects_On_Bone( MuzzleA0Bone ); i++) {
- RenderObjClass * robj = Model->Get_Sub_Object_On_Bone(i, MuzzleA0Bone );
-
- // hide all meshes named "muzzleflash"
- if (strstr(robj->Get_Name(),"MUZZLEFLASH") || strstr(robj->Get_Name(),"MZ")) {
- robj->Set_Hidden( !flashA0 );
- }
- robj->Release_Ref();
- }
- }
- if (( MuzzleA1Bone > 0 ) && (LastFlashA1 != flashA1)) {
-
- LastFlashA1 = flashA1;
- #if 0
- if ( flash ) {
- Rotation += TimeManager::Get_Frame_Seconds() * 10;
- Matrix3D tm(1);
- tm.Rotate_X( Rotation );
- Model->Control_Bone( MuzzleA1Bone, tm );
- }
- #endif
- for (int i=0; i<Model->Get_Num_Sub_Objects_On_Bone( MuzzleA1Bone ); i++) {
- RenderObjClass * robj = Model->Get_Sub_Object_On_Bone(i, MuzzleA1Bone );
- // hide all meshes named "muzzleflash"
- if (strstr(robj->Get_Name(),"MUZZLEFLASH") || strstr(robj->Get_Name(),"MZ")) {
- robj->Set_Hidden( !flashA1 );
- }
- robj->Release_Ref();
- }
- }
- }
- }
|