/* ** 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 . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/Combat/smartgameobj.cpp $* * * * $Author:: Greg_h $* * * * $Modtime:: 1/05/02 4:00p $* * * * $Revision:: 246 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* ** Includes */ #include "smartgameobj.h" #include "gameobjmanager.h" #include "weapons.h" #include "bittype.h" #include "combat.h" #include "movephys.h" #include "damage.h" #include "wwpacket.h" #include "assets.h" #include "debug.h" #include "scripts.h" #include "pscene.h" #include "physcoltest.h" #include "chunkio.h" #include "weaponbag.h" #include "matinfo.h" #include "vehicle.h" #include "ccamera.h" #include "soldier.h" #include "parameter.h" #include "crandom.h" #include "playertype.h" #include "wwaudio.h" #include "logicallistener.h" #include "combatsound.h" #include "logicalsound.h" #include "wwprofile.h" #include "playerdata.h" #include "persistfactory.h" #include "persistfactory.h" #include "diaglog.h" #include "clientcontrol.h" #include "stealtheffect.h" #include "hud.h" const float STEALTH_FIRING_TIME = 5.0f; // amount of time an object stays un-stealthed after firing /* ** SmartGameObjDef */ SmartGameObjDef::SmartGameObjDef( void ) : SightRange( 0 ), SightArc( DEG_TO_RADF( 0 ) ), ListenerScale( 1 ) { EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_FLOAT, SightRange ); EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_ANGLE, SightArc ); EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_FLOAT, ListenerScale ); EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_BOOL, IsStealthUnit ); } enum { XXX_CHUNKID_DEF_PHYSICALGAMEOBJ_PARENT = 909991656, CHUNKID_DEF_VARIABLES, CHUNKID_DEF_ARMEDGAMEOBJ_PARENT, MICROCHUNKID_DEF_SIGHT_RANGE = 9, MICROCHUNKID_DEF_SIGHT_ARC, MICROCHUNKID_DEF_LISTENER_SCALE = 17, LEGACY_MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME, MICROCHUNKID_DEF_IS_STEALTH_UNIT, }; bool SmartGameObjDef::Save( ChunkSaveClass & csave ) { csave.Begin_Chunk( CHUNKID_DEF_ARMEDGAMEOBJ_PARENT ); ArmedGameObjDef::Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_DEF_VARIABLES ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SIGHT_RANGE, SightRange ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SIGHT_ARC, SightArc ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_LISTENER_SCALE, ListenerScale ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_STEALTH_UNIT, IsStealthUnit ); csave.End_Chunk(); return true; } bool SmartGameObjDef::Load( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case CHUNKID_DEF_ARMEDGAMEOBJ_PARENT: ArmedGameObjDef::Load( cload ); break; case CHUNKID_DEF_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SIGHT_RANGE, SightRange ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SIGHT_ARC, SightArc ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_LISTENER_SCALE, ListenerScale ); READ_MICRO_CHUNK_WWSTRING( cload, LEGACY_MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME, InfoIconTextureFilename ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_STEALTH_UNIT, IsStealthUnit ); default: Debug_Say(( "Unrecognized SmartDef Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID() )); break; } cload.Close_Micro_Chunk(); } break; default: Debug_Say(( "Unrecognized SmartDef chunkID\n" )); break; } cload.Close_Chunk(); } return true; } float SmartGameObj::GlobalSightRangeScale = 1.0f; /* ** SmartGameObj */ SmartGameObj::SmartGameObj( void ) : Action( this ), ControlOwner( SERVER_CONTROL_OWNER ), ControlEnabled( true ), IsEnemySeenEnabled( false ), MovingSoundTimer( 0 ), PlayerData( NULL ), StealthEnabled( false ), StealthPowerupTimer( 0.0f ), StealthFiringTimer( 0.0f ), StealthEffect( NULL ) { GameObjManager::Add_Smart( this ); Listener = WWAudioClass::Get_Instance()->Create_Logical_Listener(); SET_REF_OWNER( Listener ); Listener->Register_Callback( AudioCallbackClass::EVENT_LOGICAL_HEARD, this ); } SmartGameObj::~SmartGameObj( void ) { GameObjManager::Remove_Smart( this ); Listener->Remove_From_Scene(); Listener->Release_Ref(); REF_PTR_RELEASE(StealthEffect); } /* ** */ void SmartGameObj::Init( const SmartGameObjDef & definition ) { ArmedGameObj::Init( definition ); Copy_Settings( definition ); return ; } /* ** */ void SmartGameObj::Copy_Settings( const SmartGameObjDef & definition ) { WWASSERT( Peek_Physical_Object() ); MoveablePhysClass * moveable = Peek_Physical_Object()->As_MoveablePhysClass(); if (moveable != NULL) { Peek_Physical_Object()->As_MoveablePhysClass()->Set_Controller( &Controller ); } Register_Listener(); if (definition.IsStealthUnit) { Enable_Stealth(true); } return ; } /* ** */ void SmartGameObj::Re_Init( const SmartGameObjDef & definition ) { ArmedGameObj::Re_Init( definition ); // // Remove the listener from the scene // if ( Listener != NULL ) { Listener->Remove_From_Scene(); } // // Free the stealth effect as necessary // if (StealthEffect != NULL) { REF_PTR_RELEASE (StealthEffect); StealthEnabled = false; StealthPowerupTimer = 0.0F; StealthFiringTimer = 0.0F; } // // Copy any internal settings from the definition // Copy_Settings( definition ); return ; } const SmartGameObjDef & SmartGameObj::Get_Definition( void ) const { return (const SmartGameObjDef &)BaseGameObj::Get_Definition(); } /* ** SmartGameObj Save and Load */ enum { OLD_CHUNKID_PHYSICALGAMEOBJ_PARENT = 910991113, CHUNKID_VARIABLES, CHUNKID_CONTROL, CHUNKID_CONTROLLER, CHUNKID_ACTION, XXXCHUNKID_WEAPONBAG, CHUNKID_ARMEDGAMEOBJ_PARENT, XXXCHUNKID_PLAYER_DATA, CHUNKID_STEALTH_EFFECT, MICROCHUNKID_CONTROL_ENABLED = 1, XXXMICROCHUNKID_WEAPON_TILT, XXXMICROCHUNKID_WEAPON_TURN, MICROCHUNKID_CONTROL_OWNER, XXX_MICROCHUNKID_IS_GHOST, MICROCHUNKID_IMPORT_STATE_COUNT, MICROCHUNKID_TINT_COLOR, MICROCHUNKID_CONTROLLER_PTR, MICROCHUNKID_IS_ENEMY_SEEN_ENABLED, XXXMICROCHUNKID_TARGETING_POS, MICROCHUNKID_MOVING_SOUND_TIMER, MICROCHUNKID_PLAYER_DATA, MICROCHUNKID_STEALTH_ENABLED, MICROCHUNKID_STEALTH_POWERUP_TIMER, MICROCHUNKID_STEALTH_FIRING_TIMER, }; bool SmartGameObj::Save( ChunkSaveClass & csave ) { csave.Begin_Chunk( CHUNKID_ARMEDGAMEOBJ_PARENT ); ArmedGameObj::Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_VARIABLES ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROL_ENABLED, ControlEnabled ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROL_OWNER, ControlOwner ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_ENEMY_SEEN_ENABLED, IsEnemySeenEnabled ); void * ptr = &Controller; WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROLLER_PTR, ptr ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_MOVING_SOUND_TIMER, MovingSoundTimer ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PLAYER_DATA, PlayerData ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_ENABLED, StealthEnabled ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_POWERUP_TIMER, StealthPowerupTimer ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_FIRING_TIMER, StealthFiringTimer ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_CONTROL ); Control.Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_CONTROLLER ); Controller.Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_ACTION ); Action.Save( csave ); csave.End_Chunk(); if (StealthEffect != NULL) { csave.Begin_Chunk(CHUNKID_STEALTH_EFFECT); StealthEffect->Save(csave); csave.End_Chunk(); } // Don't need to save Listener return true; } bool SmartGameObj::Load( ChunkLoadClass &cload ) { WWASSERT( PlayerData == NULL ); int new_control_owner = 0; while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case OLD_CHUNKID_PHYSICALGAMEOBJ_PARENT: Debug_Say(( "Loading old SmartGameObj format\n" )); PhysicalGameObj::Load( cload ); break; case CHUNKID_ARMEDGAMEOBJ_PARENT: ArmedGameObj::Load( cload ); break; case CHUNKID_VARIABLES: void * old_controller_ptr; old_controller_ptr = NULL; while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROL_ENABLED, ControlEnabled ); READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROL_OWNER, new_control_owner ); READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_ENEMY_SEEN_ENABLED, IsEnemySeenEnabled ); READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROLLER_PTR, old_controller_ptr ); READ_MICRO_CHUNK( cload, MICROCHUNKID_MOVING_SOUND_TIMER, MovingSoundTimer ); READ_MICRO_CHUNK( cload, MICROCHUNKID_PLAYER_DATA, PlayerData ); READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_ENABLED, StealthEnabled ); READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_POWERUP_TIMER, StealthPowerupTimer ); READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_FIRING_TIMER, StealthFiringTimer ); default: Debug_Say(( "Unrecognized SmartGameObj Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } if ( old_controller_ptr ) { SaveLoadSystemClass::Register_Pointer(old_controller_ptr, &Controller); } break; case CHUNKID_CONTROL: Control.Load( cload ); break; case CHUNKID_CONTROLLER: Controller.Load( cload ); break; case CHUNKID_ACTION: Action.Load( cload ); break; case CHUNKID_STEALTH_EFFECT: Alloc_Stealth_Effect(); StealthEffect->Load(cload); break; default: Debug_Say(( "Unrecognized SoldierGameObj chunkID\n" )); break; } cload.Close_Chunk(); } if ( PlayerData != NULL ) { REQUEST_POINTER_REMAP ((void **)&PlayerData); } Set_Control_Owner( new_control_owner ); // Be sure soldier virtual function calls SaveLoadSystemClass::Register_Post_Load_Callback(this); return true; } void SmartGameObj::On_Post_Load(void) { ArmedGameObj::On_Post_Load(); if ( StealthEffect != NULL ) { Peek_Physical_Object()->Add_Effect_To_Me(StealthEffect); } Register_Listener(); if ( PlayerData ) { Set_Player_Data( PlayerData ); // make sure we re map each other } } void SmartGameObj::Set_Player_Data( PlayerDataClass * player_data ) { if ( PlayerData ) { PlayerData->Set_GameObj( NULL ); } PlayerData = player_data; if ( PlayerData ) { PlayerData->Set_GameObj( this ); } } //----------------------------------------------------------------------------- void SmartGameObj::Import_Frequent(BitStreamClass & packet) { WWASSERT(CombatManager::I_Am_Only_Client()); /*TSS091301 // // Update the player data structure from the server // if (PlayerData != NULL) { PlayerData->Import_Frequent( packet ); } */ // // Import all data from the base classes // ArmedGameObj::Import_Frequent(packet); // // Don't import the controller if the player is controlling // this object // if (Is_Controlled_By_Me()) { packet.Flush(); } else { Import_Control_Sc(packet); } WWASSERT(packet.Is_Flushed()); return ; } //----------------------------------------------------------------------------- void SmartGameObj::Export_Frequent(BitStreamClass & packet) { /*TSS091301 // // Send the player data to the client // if (PlayerData != NULL) { PlayerData->Export_Frequent( packet ); } */ // // Send data from the base class to the client // ArmedGameObj::Export_Frequent(packet); Export_Control_Sc(packet); return ; } //----------------------------------------------------------------------------- void SmartGameObj::Export_State_Cs(BitStreamClass & packet) { ArmedGameObj::Export_State_Cs(packet); } //----------------------------------------------------------------------------- void SmartGameObj::Import_State_Cs(BitStreamClass & packet) { ArmedGameObj::Import_State_Cs(packet); } //----------------------------------------------------------------------------- void SmartGameObj::Generate_Control(void) { if (CombatManager::I_Am_Server() && (ControlOwner == SERVER_CONTROL_OWNER || !Is_Human_Controlled())) { Action.Act(); } if (CombatManager::I_Am_Client() && ControlOwner == CombatManager::Get_My_Id()) { Action.Act(); // // Notify server // /* if (PClientControl != NULL && !Is_Delete_Pending()) { PClientControl->Set_Update_Flag(Get_ID()); } */ //TSS092101 if (PClientControl != NULL) { if (Is_Delete_Pending()) { PClientControl->Set_Update_Flag(-1); } else { PClientControl->Set_Update_Flag(Get_ID()); } } } } //----------------------------------------------------------------------------- bool SmartGameObj::Is_Control_Data_Dirty(cPacket & packet) { // // future optimization // return true; } bool SmartGameObj::Has_Player(void) { // There is a cPlayer object for this smart object return (ControlOwner != SERVER_CONTROL_OWNER); } bool SmartGameObj::Is_Human_Controlled(void) { // There is a human cPlayer object for this smart object //return ControlOwner >= 0 && !CombatManager::Player_Is_Afk(ControlOwner); return ControlOwner >= 0; } bool SmartGameObj::Is_Controlled_By_Me(void) { // WWASSERT(CombatManager::I_Am_Client()); if (!CombatManager::I_Am_Client()) { return false; } SmartGameObj *game_obj = this; // // If this is a vehicle, then passthru to the driver // VehicleGameObj *vehicle = As_VehicleGameObj(); if (vehicle != NULL) { SoldierGameObj *driver = vehicle->Get_Driver(); if (driver != NULL) { game_obj = driver; } } return game_obj->Is_Human_Controlled() && (game_obj->ControlOwner == CombatManager::Get_My_Id()); } void SmartGameObj::Apply_Control( void ) { bool switched = false; const char * change_type = NULL; if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_NEXT ) ) { if ( COMBAT_CAMERA != NULL ) { COMBAT_CAMERA->Reset_First_Person_Offset_Tweak(); } WeaponBag->Select_Next(); switched = true; change_type = "Next"; } if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_PREV ) ) { if ( COMBAT_CAMERA != NULL ) { COMBAT_CAMERA->Reset_First_Person_Offset_Tweak(); } WeaponBag->Select_Prev(); switched = true; change_type = "Prev"; } // -1 is no weapon for ( int weapon_key_num = -1; weapon_key_num <= 9; weapon_key_num++ ) { if ( Control.Get_Boolean( (ControlClass::BooleanControl)((int)ControlClass::BOOLEAN_SELECT_WEAPON_0 + weapon_key_num) ) ) { if ( this == COMBAT_STAR ) { HUDClass::Force_Weapon_Chart_Display(); } if ( COMBAT_CAMERA != NULL ) { COMBAT_CAMERA->Reset_First_Person_Offset_Tweak(); } WeaponBag->Select_Key_Number( weapon_key_num ); switched = true; change_type = "Key"; } } if ( this == COMBAT_STAR && change_type != NULL ) { Vector3 pos; Get_Position( &pos ); const char * weapon_name = ""; int ammo = 0; if ( Get_Weapon() ) { weapon_name = Get_Weapon()->Get_Definition()->Get_Name(); ammo = Get_Weapon()->Get_Total_Rounds(); } DIAG_LOG(( "WCHN", "%1.2f; %1.2f; %1.2f; %s; %d; %s", pos.X, pos.Y, pos.Z, weapon_name, ammo, change_type )); } // This is kinda ugly.... SoldierGameObj * p_soldier = As_SoldierGameObj(); if (switched && p_soldier != NULL && p_soldier->Is_Sniping()) { // If sniping, and you cannot snipe for the current weapon, exit sniping if ( Get_Weapon() == NULL || !Get_Weapon()->Get_Can_Snipe() ) { Debug_Say(( "Force Sniper exit\n" )); p_soldier->Get_Human_State()->Toggle_State_Flag( HumanStateClass::SNIPING_FLAG ); } } Controller.Reset(); Controller.Set_Turn_Left( Control.Get_Analog( ControlClass::ANALOG_TURN_LEFT ) ); Controller.Set_Move_Up( Control.Get_Analog( ControlClass::ANALOG_MOVE_UP ) ); Controller.Set_Move_Forward(Control.Get_Analog( ControlClass::ANALOG_MOVE_FORWARD ) ); Controller.Set_Move_Left( Control.Get_Analog( ControlClass::ANALOG_MOVE_LEFT ) ); if ( ControlEnabled ) { if ( ( Get_Weapon() != NULL ) && ( !Is_Delete_Pending() ) ) { Get_Weapon()->Set_Primary_Triggered( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY ) ); Get_Weapon()->Set_Secondary_Triggered( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY ) ); if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_USE ) ) { Get_Weapon()->Next_C4_Detonation_Mode(); } if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_RELOAD ) ) { Get_Weapon()->Force_Reload(); } // If we fire a weapon, we de-cloak for a certain amount of time if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY ) || Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY )) { StealthFiringTimer = STEALTH_FIRING_TIME; } } } else { Get_Weapon()->Set_Primary_Triggered( false ); Get_Weapon()->Set_Secondary_Triggered( false ); } } void SmartGameObj::Think() { { WWPROFILE( "Smart Think" ); // React to the controls { WWPROFILE("Controls"); if ( ControlEnabled ) { Apply_Control(); } else { Controller.Reset(); if ( Get_Weapon() != NULL ) { Get_Weapon()->Set_Primary_Triggered( false ); Get_Weapon()->Set_Secondary_Triggered( false ); } } } MovingSoundTimer -= TimeManager::Get_Frame_Seconds(); if ( MovingSoundTimer < 0 ) { WWPROFILE("See"); // MovingSoundTimer += FreeRandom.Get_Float( 1, 2 ); // sound every 1-2 seconds MovingSoundTimer += FreeRandom.Get_Float( 0.5f, 1 ); // sound every 0.5 - 1 seconds // if I have sight, see who I see if ( Is_Enemy_Seen_Enabled() ) { // for all physicalgameobjs SLNode *objnode; for ( objnode = GameObjManager::Get_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) { SmartGameObj *obj = objnode->Data()->As_SmartGameObj(); if ( obj ) { if ( obj == this ) continue; if ( !Is_Enemy( obj ) ) continue; if ( !obj->Is_Visible() ) continue; // Don't see hidden models if ( obj != COMBAT_STAR && obj->Peek_Model() && obj->Peek_Model()->Is_Hidden() ) { continue; } if ( Is_Obj_Visible( obj ) ) { const GameObjObserverList & observer_list = Get_Observers(); for( int index = 0; index < observer_list.Count(); index++ ) { observer_list[ index ]->Enemy_Seen( this, obj ); } } } } } } // Stealth logic if (StealthPowerupTimer > 0.0f) { StealthPowerupTimer -= TimeManager::Get_Frame_Seconds(); } if (StealthFiringTimer > 0.0f) { StealthFiringTimer -= TimeManager::Get_Frame_Seconds(); } if ( (StealthEffect != NULL ) && COMBAT_STAR) { StealthEffect->Set_Friendly( Is_Teammate( COMBAT_STAR ) ); } if (((StealthPowerupTimer > 0.0f) || (StealthEnabled)) && (StealthFiringTimer <= 0.0f)) { WWPROFILE("Stealh"); Alloc_Stealth_Effect(); WWASSERT(StealthEffect != NULL); Peek_Physical_Object()->Add_Effect_To_Me(StealthEffect); StealthEffect->Enable_Stealth(true); const float STEALTH_BROKEN_FRACTION = 0.25f; DefenseObjectClass * defobj = Get_Defense_Object(); if (defobj != NULL) { StealthEffect->Set_Broken((defobj->Get_Health() / defobj->Get_Health_Max()) < STEALTH_BROKEN_FRACTION); } } else { if (StealthEffect != NULL) { StealthEffect->Enable_Stealth(false); } } } { WWPROFILE("Embedded Armed think in smart think"); ArmedGameObj::Think(); } } void SmartGameObj::Post_Think( void ) { ArmedGameObj::Post_Think(); WWPROFILE( "Smart PostThink" ); if ( Is_Delete_Pending() ) { // don't update if destroying... (so we don't create a new laser!) return; } // Reset the one time booleans Control.Clear_One_Time_Boolean(); } void SmartGameObj::Apply_Damage(const OffenseObjectClass & damager, float scale, int alternate_skin) { float damage = damager.Get_Damage() * scale; if ((damage > 0) && (StealthEffect != NULL)) { StealthEffect->Damage_Occured(); } PhysicalGameObj::Apply_Damage(damager,scale,alternate_skin); } bool SmartGameObj::Is_Obj_Visible( PhysicalGameObj *obj ) { Vector3 diff = obj->Get_Bullseye_Position(); Matrix3D look_tm = Get_Look_Transform(); Matrix3D::Inverse_Transform_Vector( look_tm, diff, &diff ); float dist = diff.Length(); if ( dist < Get_Definition().SightRange * GlobalSightRangeScale) { // find view angle diff.Z = 0; diff.Normalize(); float angle = WWMath::Fast_Acos( diff.X ); if ( WWMath::Fabs( angle ) < Get_Definition().SightArc/2 ) { // if it passes this test, do a raycast to see if we see it. Vector3 me = look_tm.Get_Translation(); Vector3 him = obj->Get_Bullseye_Position(); Peek_Physical_Object()->Inc_Ignore_Counter(); CastResultStruct res; LineSegClass ray( me, him ); PhysRayCollisionTestClass raytest(ray, &res, BULLET_COLLISION_GROUP); { WWPROFILE( "Cast Ray" ); PhysicsSceneClass::Get_Instance()->Cast_Ray(raytest); } Peek_Physical_Object()->Dec_Ignore_Counter(); #if 0 if (raytest.Result->StartBad) { // Debug_Say(( "Is_Vis Start Bad\n" )); } else if ( raytest.CollidedPhysObj == obj->Peek_Physical_Object() ) { return true; } #else return ((raytest.Result->Fraction == 1.0f ) || ( raytest.CollidedPhysObj == obj->Peek_Physical_Object() )); #endif } } return false; } /* ** */ void SmartGameObj::On_Logical_Heard (LogicalListenerClass *listener, LogicalSoundClass *sound_obj) { CombatSound sound; sound.Type = (CombatSoundType)sound_obj->Get_Type_Mask(); sound.Position = sound_obj->Get_Position(); // // Dig the sound creator out from the logical sound object // RefCountedGameObjReference *creator = (RefCountedGameObjReference *)sound_obj->Peek_User_Obj(); if (creator != NULL) { sound.Creator = creator->Get_Ptr (); } else { sound.Creator = NULL; } // Notify observers if (CombatManager::Are_Observers_Active()) { const GameObjObserverList & observer_list = Get_Observers(); for( int index = 0; index < observer_list.Count(); index++ ) { observer_list[ index ]->Sound_Heard( this, sound ); } } } void SmartGameObj::Register_Listener(void) { if (Listener != NULL) { const SmartGameObjDef& definition = Get_Definition(); Listener->Set_Scale(definition.ListenerScale); Listener->Set_DropOff_Radius( 0.001f ); Listener->Attach_To_Object(Peek_Model()); Listener->Add_To_Scene(); } } void SmartGameObj::Begin_Hibernation( void ) { ArmedGameObj::Begin_Hibernation(); // Reset our physics controller Controller.Reset(); // // Stop listening for sounds // if (Listener != NULL) { Listener->Remove_From_Scene (); } // // Let the action prepare itself for hibernation // Action.Begin_Hibernation (); return ; } void SmartGameObj::End_Hibernation( void ) { ArmedGameObj::End_Hibernation(); // // Make sure we are listening for logical sounds // if (Listener != NULL) { Listener->Add_To_Scene (); } // // Let the action prepare itself for activation // Action.End_Hibernation (); return ; } //------------------------------------------------------------------------------------ void SmartGameObj::Get_Information( StringClass & string ) { ArmedGameObj::Get_Information( string ); StringClass temp; temp.Format( "Observer:%d\n", Action.Get_Parameters().ObserverID ); string += temp; temp.Format( "Priority:%d\n", Action.Get_Parameters().Priority ); string += temp; if ( Action.Get_Parameters().WaypathID ) { temp.Format( "Waypath:%d\n", Action.Get_Parameters().WaypathID ); string += temp; } } /* ** */ void SmartGameObj::Export_Creation( BitStreamClass &packet ) { ArmedGameObj::Export_Creation( packet ); // // Send the control owner to the client // int control_owner = Get_Control_Owner(); packet.Add( control_owner ); return ; } /* ** */ void SmartGameObj::Import_Creation( BitStreamClass &packet ) { ArmedGameObj::Import_Creation( packet ); // // Get the control owner from the server // int control_owner = 0; packet.Get( control_owner ); Set_Control_Owner( control_owner ); // // Hookup the control input for this player // if (control_owner == CombatManager::Get_My_Id() ) { ActionParamsStruct parameters; Get_Action()->Follow_Input( parameters ); CombatManager::Set_The_Star( As_SoldierGameObj() ); } return ; } void SmartGameObj::Enable_Stealth(bool onoff) { StealthEnabled = onoff; if (StealthEnabled) { Alloc_Stealth_Effect (); } return ; } void SmartGameObj::Toggle_Stealth(void) { StealthEnabled = !StealthEnabled; } bool SmartGameObj::Is_Stealth_Enabled(void) { return StealthEnabled; } bool SmartGameObj::Is_Stealthed(void) const { if (StealthEffect != NULL) { return StealthEffect->Is_Stealthed(); } else { return false; } } void SmartGameObj::Grant_Stealth_Powerup(float seconds) { StealthPowerupTimer = seconds; } float SmartGameObj::Remaining_Stealth_Powerup_Time(void) { return StealthPowerupTimer; } StealthEffectClass * SmartGameObj::Peek_Stealth_Effect(void) { return StealthEffect; } void SmartGameObj::Alloc_Stealth_Effect(void) { if (StealthEffect == NULL) { StealthEffect = NEW_REF(StealthEffectClass,()); StealthEffect->Set_Fade_Distance( Get_Stealth_Fade_Distance() ); } } void SmartGameObj::Reset_Controller( void ) { Controller.Reset(); } /* CombatManager::Send_Control_Packet(this); CombatManager::Send_State_Packet(this); */