/* ** 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/powerup.cpp $* * * * $Author:: Byon_g $* * * * $Modtime:: 12/17/01 10:57a $* * * * $Revision:: 93 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "powerup.h" #include "debug.h" #include "combat.h" #include "phys.h" #include "persistfactory.h" #include "combatchunkid.h" #include "simpledefinitionfactory.h" #include "wwhack.h" #include "weaponbag.h" #include "damage.h" #include "gameobjmanager.h" #include "colmath.h" #include "movephys.h" #include "wwaudio.h" #include "audiblesound.h" #include "hanim.h" #include "timemgr.h" #include "assetmgr.h" #include "animcontrol.h" #include "soldier.h" #include "wwprofile.h" #include "objlibrary.h" #include "gameobjobserver.h" #include "diaglog.h" #include "weaponmanager.h" #include "weapons.h" #include "hud.h" #include "playerdata.h" #include "physinttest.h" #include "encyclopediamgr.h" #include "vehicle.h" #include "combatmaterialeffectmanager.h" #include "transitioneffect.h" #include "apppackettypes.h" #include "hudinfo.h" #include "string_ids.h" #include "translatedb.h" /* ** PowerUpGameObjDef */ DECLARE_FORCE_LINK( PowerUp ) SimplePersistFactoryClass _PowerUpGameObjDefPersistFactory; DECLARE_DEFINITION_FACTORY(PowerUpGameObjDef, CLASSID_GAME_OBJECT_DEF_POWERUP, "PowerUp") _PowerUpGameObjDefDefFactory; PowerUpGameObjDef::PowerUpGameObjDef( void ) : GrantShieldType( 0 ), GrantShieldStrength( 0 ), GrantShieldStrengthMax( 0 ), GrantHealth( 0 ), GrantHealthMax( 0 ), GrantWeaponID( 0 ), GrantWeapon( true ), GrantWeaponClips( false ), GrantWeaponRounds( 0 ), Persistent( false ), //IsCaptureTheFlag( false ), GrantKey( 0 ), GrantSoundID( 0 ), IdleSoundID( 0 ), AlwaysAllowGrant( false ) { #ifdef PARAM_EDITING_ON // EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantShieldType ); EnumParameterClass *param; param = new EnumParameterClass( &GrantShieldType ); param->Set_Name ( "GrantShieldType" ); for ( int param_counter = 0; param_counter < ArmorWarheadManager::Get_Num_Armor_Types(); param_counter++ ) { param->Add_Value(ArmorWarheadManager::Get_Armor_Name(param_counter), param_counter); } GENERIC_EDITABLE_PARAM( PowerUpGameObjDef, param ) EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantShieldStrength ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantShieldStrengthMax ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantHealth ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantHealthMax ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_WEAPONOBJDEFINITIONID, GrantWeaponID ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, GrantWeapon ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, GrantWeaponClips ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantWeaponRounds ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, Persistent ); //EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, false );//IsCaptureTheFlag ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantKey ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, AlwaysAllowGrant ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_STRING, GrantAnimationName ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_STRING, IdleAnimationName ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_SOUNDDEFINITIONID, GrantSoundID ); EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_SOUNDDEFINITIONID, IdleSoundID ); #endif //PARAM_EDITING_ON } uint32 PowerUpGameObjDef::Get_Class_ID (void) const { return CLASSID_GAME_OBJECT_DEF_POWERUP; } PersistClass * PowerUpGameObjDef::Create( void ) const { PowerUpGameObj * obj = new PowerUpGameObj; obj->Init( *this ); return obj; } enum { CHUNKID_DEF_PARENT = 909991656, CHUNKID_DEF_VARIABLES, XXXMICROCHUNKID_DEF_PARAMETERS = 1, MICROCHUNKID_DEF_PERSISTENT, MICROCHUNKID_DEF_GRANT_SHIELD_TYPE, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH, XXXMICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX, MICROCHUNKID_DEF_GRANT_HEALTH, XXXMICROCHUNKID_DEF_GRANT_HEALTH_MAX, MICROCHUNKID_DEF_GRANT_WEAPON_ID, MICROCHUNKID_DEF_GRANT_WEAPON, MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS, XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG, XXXMICROCHUNKID_DEF_GRANT_KEY_MASK, MICROCHUNKID_DEF_GRANT_ANIMATION_NAME, MICROCHUNKID_DEF_GRANT_SOUNDID, MICROCHUNKID_DEF_IDLE_ANIMATION_NAME, MICROCHUNKID_DEF_IDLE_SOUNDID, MICROCHUNKID_DEF_GRANT_KEY, MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT, MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX, MICROCHUNKID_DEF_GRANT_HEALTH_MAX, }; bool PowerUpGameObjDef::Save( ChunkSaveClass & csave ) { csave.Begin_Chunk( CHUNKID_DEF_PARENT ); SimpleGameObjDef::Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_DEF_VARIABLES ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_TYPE, GrantShieldType ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH, GrantShieldStrength ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX,GrantShieldStrengthMax ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_HEALTH, GrantHealth ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_HEALTH_MAX, GrantHealthMax ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_ID, GrantWeaponID ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON, GrantWeapon ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS, GrantWeaponClips ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS, GrantWeaponRounds ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_PERSISTENT, Persistent ); //WRITE_MICRO_CHUNK( csave, XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG, IsCaptureTheFlag ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_KEY, GrantKey ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SOUNDID, GrantSoundID ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IDLE_SOUNDID, IdleSoundID ); WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_GRANT_ANIMATION_NAME, GrantAnimationName ); WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_IDLE_ANIMATION_NAME, IdleAnimationName ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT, AlwaysAllowGrant ); csave.End_Chunk(); return true; } bool PowerUpGameObjDef::Load( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case CHUNKID_DEF_PARENT: SimpleGameObjDef::Load( cload ); break; case CHUNKID_DEF_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_TYPE, GrantShieldType ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH, GrantShieldStrength ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX, GrantShieldStrengthMax ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_HEALTH, GrantHealth ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_HEALTH_MAX, GrantHealthMax ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_ID, GrantWeaponID ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON, GrantWeapon ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS, GrantWeaponClips ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS, GrantWeaponRounds ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_PERSISTENT, Persistent ); //READ_MICRO_CHUNK( cload, XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG, IsCaptureTheFlag ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_KEY, GrantKey ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SOUNDID, GrantSoundID ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IDLE_SOUNDID, IdleSoundID ); READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_GRANT_ANIMATION_NAME, GrantAnimationName ); READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_IDLE_ANIMATION_NAME, IdleAnimationName ); READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT, AlwaysAllowGrant ); default: Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__)); break; } cload.Close_Micro_Chunk(); } break; default: Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__)); break; } cload.Close_Chunk(); } return true; } const PersistFactoryClass & PowerUpGameObjDef::Get_Factory (void) const { return _PowerUpGameObjDefPersistFactory; } bool PowerUpGameObjDef::Grant( SmartGameObj * obj, PowerUpGameObj * p_powerup, bool hud_display ) const { int no_grant_message = 0; bool granted = false; WWASSERT(CombatManager::I_Am_Server()); DefenseObjectClass * defense = obj->Get_Defense_Object(); // Grant the shield if ( GrantShieldType != 0 ) { if ( GrantShieldType > (int)defense->Get_Shield_Type() ) { defense->Set_Shield_Type( GrantShieldType ); granted = true; } else { no_grant_message = IDS_M00DSGN_DSGN1015I1DSGN_TXT; //"You are already at full shield." } } if ( GrantShieldStrengthMax != 0 ) { float add = GrantShieldStrengthMax * (float)obj->Get_Definition().Get_DefenseObjectDef().ShieldStrengthMax; switch ( CombatManager::Get_Difficulty_Level() ) { case 0: add *= 2.0f; break; case 2: add *= 0.75f; break; }; // Round up to next int add = (int)(add + 0.95f); defense->Set_Shield_Strength_Max( defense->Get_Shield_Strength_Max() + add ); granted = true; if ( hud_display && obj == COMBAT_STAR ) { HUDClass::Add_Shield_Upgrade_Grant( add ); } } if ( GrantShieldStrength != 0 ) { if ( (defense->Get_Shield_Strength() < defense->Get_Shield_Strength_Max()) ) { defense->Add_Shield_Strength( GrantShieldStrength ); granted = true; if ( obj == COMBAT_STAR ) { Vector3 pos; obj->Get_Position( &pos ); DIAG_LOG(( "AMPU", "%1.2f; %1.2f; %1.2f; %1.2f; %1.2f", pos.X, pos.Y, pos.Z, defense->Get_Shield_Strength(), defense->Get_Health() )); } } else { no_grant_message = IDS_M00DSGN_DSGN1015I1DSGN_TXT; //"You are already at full shield." } } if ( granted && hud_display ) { if ( obj == COMBAT_STAR ) { if ( GrantShieldStrengthMax == 0 ) { HUDClass::Add_Shield_Grant( GrantShieldStrength ); } } } // Grant the Health if ( GrantHealthMax != 0 ) { float add = GrantHealthMax * (float)obj->Get_Definition().Get_DefenseObjectDef().HealthMax; switch ( CombatManager::Get_Difficulty_Level() ) { case 0: add *= 2.0f; break; case 2: add *= 0.75f; break; }; // Round up to next int add = (int)(add + 0.95f); defense->Set_Health_Max( defense->Get_Health_Max() + add ); granted = true; if ( hud_display && obj == COMBAT_STAR ) { HUDClass::Add_Health_Upgrade_Grant( add ); } } if ( GrantHealth != 0 ) { if ( defense->Get_Health() < defense->Get_Health_Max() ) { defense->Add_Health( GrantHealth ); granted = true; if ( obj == COMBAT_STAR && hud_display ) { if ( GrantHealthMax == 0 ) { HUDClass::Add_Health_Grant( GrantHealth ); } } if ( obj == COMBAT_STAR ) { Vector3 pos; obj->Get_Position( &pos ); DIAG_LOG(( "HEPU", "%1.2f; %1.2f; %1.2f; %1.2f; %1.2f", pos.X, pos.Y, pos.Z, defense->Get_Shield_Strength(), defense->Get_Health() )); } } else { no_grant_message = IDS_M00DSGN_DSGN1014I1DSGN_TXT; //"You are already at full health." } } // Grant the Weapon if ( GrantWeaponID != 0 ) { if ( ( GrantWeapon && !obj->Get_Weapon_Bag()->Is_Weapon_Owned( GrantWeaponID ) ) || ( !obj->Get_Weapon_Bag()->Is_Ammo_Full( GrantWeaponID ) ) ) { if ( obj == COMBAT_STAR && hud_display ) { if ( GrantWeapon && !obj->Get_Weapon_Bag()->Is_Weapon_Owned( GrantWeaponID ) ) { HUDClass::Add_Powerup_Weapon( GrantWeaponID, GrantWeaponRounds ); } else { if ( !obj->Get_Weapon_Bag()->Is_Ammo_Full( GrantWeaponID ) ) { HUDClass::Add_Powerup_Ammo( GrantWeaponID, GrantWeaponRounds ); } } } obj->Get_Weapon_Bag()->Add_Weapon( GrantWeaponID, GrantWeaponRounds, GrantWeapon ); granted = true; if ( obj == COMBAT_STAR ) { Vector3 pos; obj->Get_Position( &pos ); const char * grant_name = ""; const WeaponDefinitionClass * def = WeaponManager::Find_Weapon_Definition( GrantWeaponID ); if ( def ) { grant_name = def->Get_Name(); } const char * weapon_name = ""; int ammo = 0; if ( obj->Get_Weapon() ) { weapon_name = obj->Get_Weapon()->Get_Definition()->Get_Name(); ammo = obj->Get_Weapon()->Get_Total_Rounds(); } DIAG_LOG(( "WEPU", "%1.2f; %1.2f; %1.2f; %s; %d; %s; %d", pos.X, pos.Y, pos.Z, grant_name, GrantWeaponRounds, weapon_name, ammo )); } } else { no_grant_message = IDS_M00DSGN_DSGN1016I1DSGN_TXT; //"Your weapon is full." } } else if ( GrantWeaponClips ) { // // Loop over all the weapons in the owner's bag // WeaponBagClass *weapon_bag = obj->Get_Weapon_Bag(); for ( int weapon_index = 0; weapon_index < weapon_bag->Get_Count(); weapon_index ++ ) { WeaponClass *weapon = weapon_bag->Peek_Weapon( weapon_index ); if( weapon != NULL && weapon->Get_Definition ()->CanReceiveGenericCnCAmmo ) { // // Grant "x" number of clips to the weapon // int clip_rounds = weapon->Get_Definition()->ClipSize; weapon->Add_Rounds( clip_rounds * GrantWeaponRounds ); } } } // Grant the key if ( GrantKey != 0 ) { SoldierGameObj * soldier = obj->As_SoldierGameObj(); if ( soldier && soldier->Is_Human_Controlled() ) { if ( !soldier->Has_Key( GrantKey ) ) { soldier->Give_Key( GrantKey ); granted = true; } } if ( obj == COMBAT_STAR ) { Vector3 pos; obj->Get_Position( &pos ); DIAG_LOG(( "KEPU", "%1.2f; %1.2f; %1.2f; %d", pos.X, pos.Y, pos.Z, GrantKey )); } if ( granted && hud_display && obj == COMBAT_STAR ) { HUDClass::Add_Key_Grant( GrantKey ); } } /* // Handle Capture the Flag if ( IsCaptureTheFlag && p_powerup != NULL && obj->As_SoldierGameObj() != NULL ) { CombatManager::Soldier_Contacts_Flag( obj->As_SoldierGameObj(), p_powerup ); granted = true; } */ if ( AlwaysAllowGrant ) { granted = true; } if ( granted && p_powerup != NULL ) { p_powerup->Set_State( PowerUpGameObj::STATE_GRANTING ); // // Reveal this object to the player // if ( COMBAT_STAR == obj ) { EncyclopediaMgrClass::Reveal_Object( p_powerup ); } } // Stats if ( granted && obj->Get_Player_Data() ) { obj->Get_Player_Data()->Stats_Add_Powerup(); } if ( !granted && ( COMBAT_STAR == obj ) && no_grant_message != 0 ) { HUDInfo::Set_HUD_Help_Text( TRANSLATE( no_grant_message ), Vector3( 0,1,0 ) ); } return granted; } /* ** PowerUpGameObj */ SimplePersistFactoryClass _PowerUpGameObjPersistFactory; PowerUpGameObj::PowerUpGameObj (void) : IdleSoundObj( NULL ), State( STATE_BECOMING_IDLE ), WeaponBag( NULL ) { Set_App_Packet_Type(APPPACKETTYPE_POWERUP); } PowerUpGameObj::~PowerUpGameObj (void) { // // Cleanup the idle sound // if ( IdleSoundObj != NULL ) { IdleSoundObj->Remove_From_Scene(); IdleSoundObj->Release_Ref(); IdleSoundObj = NULL; } if ( WeaponBag != NULL ) { delete WeaponBag; WeaponBag = NULL; } return ; } const PersistFactoryClass & PowerUpGameObj::Get_Factory (void) const { return _PowerUpGameObjPersistFactory; } /* ** */ void PowerUpGameObj::Init( void ) { Init( Get_Definition() ); } /* ** */ void PowerUpGameObj::Init( const PowerUpGameObjDef & definition ) { SimpleGameObj::Init( definition ); // Only collide with terrain! Peek_Physical_Object()->Set_Collision_Group( TERRAIN_ONLY_COLLISION_GROUP ); } const PowerUpGameObjDef & PowerUpGameObj::Get_Definition( void ) const { return (const PowerUpGameObjDef &)BaseGameObj::Get_Definition(); } /* ** PowerUpGameObj Save and Load */ enum { CHUNKID_PARENT = 927991635, CHUNKID_VARIABLES, CHUNKID_WEAPONBAG, MICROCHUNKID_STATE = 1, MICROCHUNKID_STATE_END_TIMER, }; bool PowerUpGameObj::Save( ChunkSaveClass & csave ) { csave.Begin_Chunk( CHUNKID_PARENT ); SimpleGameObj::Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( CHUNKID_VARIABLES ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State ); WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_END_TIMER, StateEndTimer ); csave.End_Chunk(); if ( WeaponBag != NULL ) { csave.Begin_Chunk( CHUNKID_WEAPONBAG ); WeaponBag->Save( csave ); csave.End_Chunk(); } // We don't save IdleSoundObj return true; } bool PowerUpGameObj::Load( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case CHUNKID_PARENT: SimpleGameObj::Load( cload ); break; case CHUNKID_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State ); READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_END_TIMER, StateEndTimer ); default: Debug_Say(( "Unrecognized PowerupGameObj Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } break; case CHUNKID_WEAPONBAG: WWASSERT( WeaponBag == NULL ); WeaponBag = new WeaponBagClass( NULL ); WeaponBag->Load( cload ); break; default: Debug_Say(( "Unrecognized PowerUpGameObj chunkID\n" )); break; } cload.Close_Chunk(); } SaveLoadSystemClass::Register_Post_Load_Callback(this); // MOVED return true; } void PowerUpGameObj::On_Post_Load( void ) { SimpleGameObj::On_Post_Load(); Peek_Physical_Object()->Set_Collision_Group( UNCOLLIDEABLE_GROUP ); // MOVED if ( Peek_Physical_Object()->As_MoveablePhysClass() != NULL ) { Peek_Physical_Object()->As_MoveablePhysClass()->Set_Gravity_Multiplier( 0 ); } // This allows the idle sound and animation to start after loading if ( State == STATE_IDLING ) { State = STATE_BECOMING_IDLE; } } void PowerUpGameObj::Set_State( int state ) { if (state != State) { State = state; StateEndTimer = 0; if ( State == STATE_GRANTING ) { // // Stop the idling sound (if necessary) // if ( IdleSoundObj != NULL ) { IdleSoundObj->Remove_From_Scene(); IdleSoundObj->Stop(); } // // Play the grant sound (if exists) // if ( Get_Definition ().GrantSoundID != 0 ) { WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_Definition ().GrantSoundID, Get_Transform () ); } // // Play the grant animation (if exists) // if ( Get_Definition ().GrantAnimationName.Get_Length () > 0 ) { Set_Animation( Get_Definition ().GrantAnimationName, false ); HAnimClass *animation = WW3DAssetManager::Get_Instance ()->Get_HAnim( Get_Anim_Control ()->Get_Animation_Name () ); if ( animation != NULL ) { StateEndTimer = animation->Get_Total_Time(); REF_PTR_RELEASE( animation ); } } } } return ; } void PowerUpGameObj::Update_State( void ) { switch ( State ) { case STATE_IDLING: break; case STATE_BECOMING_IDLE: // // Start playing the idle sound // if ( Get_Definition ().IdleSoundID != 0 ) { if ( IdleSoundObj == NULL ) { IdleSoundObj = WWAudioClass::Get_Instance ()->Create_Continuous_Sound( Get_Definition ().IdleSoundID ); } if ( IdleSoundObj != NULL ) { IdleSoundObj->Set_Transform( Get_Transform () ); IdleSoundObj->Add_To_Scene( true ); } } // // Start playing the idle animation // if ( Get_Definition ().IdleAnimationName.Get_Length () > 0 ) { Set_Animation( Get_Definition ().IdleAnimationName, true ); } State = STATE_IDLING; break; case STATE_GRANTING: // // If the granting animation has finished, then change to another state (or remove // the powerup from the world). // StateEndTimer -= TimeManager::Get_Frame_Seconds(); if ( StateEndTimer <= 0 ) { //if ( Get_Definition().IsCaptureTheFlag || Get_Definition().Persistent ) { if ( Get_Definition().Persistent ) { Set_State ( STATE_BECOMING_IDLE ); } else { Set_Delete_Pending(); } } break; case STATE_EXPIRING: // // If the granting animation has finished, then change to another state (or remove // the powerup from the world). // StateEndTimer -= TimeManager::Get_Frame_Seconds(); if ( StateEndTimer <= 0 ) { Set_Delete_Pending(); } break; } return ; } void PowerUpGameObj::Grant( SmartGameObj * obj ) { WWASSERT ( State != STATE_GRANTING ); WWASSERT( obj ); // Grant Def Get_Definition().Grant( obj, this ); // If we have a weapon bag, move it if ( WeaponBag != NULL ) { WWASSERT( obj->Get_Weapon_Bag() ); if ( obj->Get_Weapon_Bag()->Move_Contents( WeaponBag ) ) { Set_State( PowerUpGameObj::STATE_GRANTING ); } } if ( State == STATE_GRANTING ) { const GameObjObserverList & observer_list = Get_Observers(); for( int index = 0; index < observer_list.Count(); index++ ) { observer_list[ index ]->Custom( this, CUSTOM_EVENT_POWERUP_GRANTED, 0, obj ); } } } void PowerUpGameObj::Think( void ) { SimpleGameObj::Think(); WWPROFILE( "PowerUp Think" ); // // Make sure the powerup is playing its correct animation and sound // Update_State(); // // If this powerup isn't currently granting itself to a player, then check // to see if it should! // // The server grants the prize, but allow the client to destroy // the powerup before being instructed to do so, // so that this doesn't lag // if ( CombatManager::I_Am_Server() && State != STATE_GRANTING ) { // Check my bounding box for collisions with Soldiers AABoxClass box = Peek_Model()->Get_Bounding_Box(); SLNode * smart_objnode; for (smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); smart_objnode; smart_objnode = smart_objnode->Next()) { SmartGameObj * obj = smart_objnode->Data(); WWASSERT( obj != NULL ); SoldierGameObj * soldier = obj->As_SoldierGameObj(); if ( obj->As_VehicleGameObj() ) { soldier = obj->As_VehicleGameObj()->Get_Driver(); } if ( soldier && soldier->Wants_Powerups() ) { PhysAABoxIntersectionTestClass test( box, DEFAULT_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL ); bool result = obj->Peek_Physical_Object()->Intersection_Test(test); if ( result ) { Grant( soldier ); // Don't grant any more break; } } } } return ; } PowerUpGameObj * PowerUpGameObj::Create_Backpack( ArmedGameObj * provider ) { WWASSERT( provider ); // Debug_Say(( "Creating a Backpack\n" )); PowerUpGameObj * backpack = (PowerUpGameObj *)ObjectLibraryManager::Create_Object( "Backpack" ); if ( backpack != NULL ) { Matrix3D tm(1); tm.Set_Translation( provider->Get_Bullseye_Position() ); backpack->Set_Transform(tm); backpack->WeaponBag = new WeaponBagClass( NULL ); backpack->WeaponBag->Move_Contents( provider->Get_Weapon_Bag() ); backpack->Start_Observers(); } return backpack; } //void PowerUpGameObj::Get_Extended_Information( StringClass & description ) void PowerUpGameObj::Get_Description( StringClass & description ) { // // Construct a diagnostic string // StringClass line; line.Format("ID: %d\n", Get_ID()); description += line; line.Format("Name: %s\n", Get_Definition().Get_Name()); description += line; Vector3 position; Get_Position(&position); line.Format("POS: %-5.2f, %-5.2f, %-5.2f\n", position.X, position.Y, position.Z); description += line; if (Get_Defense_Object() != NULL) { line.Format("HLTH: %-5.2f\n", Get_Defense_Object()->Get_Health()); description += line; } line.Format("HIB: %d\n", Is_Hibernating()); description += line; line.Format("ISC: %d\n", Get_Import_State_Count()); description += line; } void PowerUpGameObj::Expire( void ) { #define EXPIRE_TIME 2 if ( State != STATE_EXPIRING ) { /* ** If the definition calls for it, add a material effect to the object */ PhysClass * physobj = Peek_Physical_Object(); if (physobj != NULL) { TransitionEffectClass * effect = CombatMaterialEffectManager::Get_Death_Effect(); effect->Set_Transition_Time( EXPIRE_TIME ); physobj->Add_Effect_To_Me(effect); REF_PTR_RELEASE(effect); } State = STATE_EXPIRING; StateEndTimer = EXPIRE_TIME; } }