| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /*
- ** 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/damageablegameobj.cpp $*
- * *
- * $Author:: Tom_s $*
- * *
- * $Modtime:: 12/18/01 3:02p $*
- * *
- * $Revision:: 19 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "damageablegameobj.h"
- #include "debug.h"
- #include "armedgameobj.h"
- #include "playertype.h"
- #include "colors.h"
- /*
- ** DamageableGameObjDef - Defintion class for a DamageableGameObj
- */
- DamageableGameObjDef::DamageableGameObjDef( void ) :
- TranslatedNameID( 0 ),
- EncyclopediaType( EncyclopediaMgrClass::TYPE_UNKNOWN ),
- EncyclopediaID( 0 ),
- NotTargetable( false ),
- DefaultPlayerType( PLAYERTYPE_NEUTRAL )
- {
- DEFENSEOBJECTDEF_EDITABLE_PARAMS( DamageableGameObjDef, DefenseObjectDef );
- EDITABLE_PARAM( DamageableGameObjDef, ParameterClass::TYPE_STRINGSDB_ID, TranslatedNameID );
- FILENAME_PARAM( DamageableGameObjDef, InfoIconTextureFilename, "InfoIconTextureFilename", ".TGA" );
- #ifdef PARAM_EDITING_ON
- EnumParameterClass *param = new EnumParameterClass( (int *)&EncyclopediaType );
- param->Set_Name( "Encyclopedia Type" );
- param->Add_Value( "<NA>", 0 );
- param->Add_Value( "Character", EncyclopediaMgrClass::TYPE_CHARACTER );
- param->Add_Value( "Weapon", EncyclopediaMgrClass::TYPE_WEAPON );
- param->Add_Value( "Vehicle", EncyclopediaMgrClass::TYPE_VEHICLE );
- param->Add_Value( "Building", EncyclopediaMgrClass::TYPE_BUILDING );
- GENERIC_EDITABLE_PARAM( DamageableGameObjDef, param )
- param = new EnumParameterClass( &DefaultPlayerType );
- param->Set_Name ("PlayerType");
- param->Add_Value ( "Mutant", PLAYERTYPE_MUTANT );
- param->Add_Value ( "Unteamed", PLAYERTYPE_NEUTRAL );
- param->Add_Value ( "Renegade", PLAYERTYPE_RENEGADE );
- param->Add_Value ( "Nod", PLAYERTYPE_NOD );
- param->Add_Value ( "GDI", PLAYERTYPE_GDI );
- GENERIC_EDITABLE_PARAM(DamageableGameObjDef,param)
- #endif
- EDITABLE_PARAM( DamageableGameObjDef, ParameterClass::TYPE_INT, EncyclopediaID );
- EDITABLE_PARAM( DamageableGameObjDef, ParameterClass::TYPE_BOOL, NotTargetable );
- return ;
- }
- enum {
- CHUNKID_DEF_PARENT = 207011205,
- CHUNKID_DEF_VARIABLES,
- CHUNKID_DEF_DEFENSEOBJECTDEF,
- MICROCHUNKID_DEF_TRANSLATED_NAME_ID = 1,
- MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME,
- MICROCHUNKID_DEF_ENCY_TYPE,
- MICROCHUNKID_DEF_ENCY_ID,
- MICROCHUNKID_DEF_NOT_TARGETABLE,
- MICROCHUNKID_DEF_DEFAULT_PLAYER_TYPE,
- };
- bool DamageableGameObjDef::Save( ChunkSaveClass & csave )
- {
- csave.Begin_Chunk( CHUNKID_DEF_PARENT );
- ScriptableGameObjDef::Save( csave );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_TRANSLATED_NAME_ID, TranslatedNameID );
- WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME, InfoIconTextureFilename );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ENCY_TYPE, EncyclopediaType );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ENCY_ID, EncyclopediaID );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_NOT_TARGETABLE, NotTargetable );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_DEFAULT_PLAYER_TYPE, DefaultPlayerType );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_DEF_DEFENSEOBJECTDEF );
- DefenseObjectDef.Save(csave);
- csave.End_Chunk();
- return true;
- }
- bool DamageableGameObjDef::Load( ChunkLoadClass &cload )
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_DEF_PARENT:
- ScriptableGameObjDef::Load( cload );
- break;
-
- case CHUNKID_DEF_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_TRANSLATED_NAME_ID, TranslatedNameID );
- READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME, InfoIconTextureFilename );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ENCY_TYPE, EncyclopediaType );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ENCY_ID, EncyclopediaID );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_NOT_TARGETABLE, NotTargetable );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_DEFAULT_PLAYER_TYPE, DefaultPlayerType );
- default:
- Debug_Say(( "Unhandled MicroChunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
- break;
- }
- cload.Close_Micro_Chunk();
- }
- break;
- case CHUNKID_DEF_DEFENSEOBJECTDEF:
- DefenseObjectDef.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();
- }
- return true;
- }
- /*
- ** DamageableGameObj
- */
- DamageableGameObj::DamageableGameObj( void ) :
- IsHealthBarDisplayed( true )
- {
- Set_Player_Type(PLAYERTYPE_NEUTRAL);
- }
- DamageableGameObj::~DamageableGameObj( void )
- {
- Remove_All_Observers();
- }
- /*
- **
- */
- void DamageableGameObj::Init( const DamageableGameObjDef & definition )
- {
- ScriptableGameObj::Init( definition );
- Copy_Settings( definition );
- return ;
- }
- /*
- **
- */
- void DamageableGameObj::Copy_Settings( const DamageableGameObjDef & definition )
- {
- Set_Player_Type(definition.DefaultPlayerType);
- DefenseObject.Init(definition.DefenseObjectDef, this );
- return ;
- }
- /*
- **
- */
- void DamageableGameObj::Re_Init( const DamageableGameObjDef & definition )
- {
- int old_player_type = PlayerType;
- //
- // Record the health and shield percent so we can restore the
- // appropriate amount of health and shield after we've re-initialized
- //
- //float health_percent = DefenseObject.Get_Health() / DefenseObject.Get_Health_Max();
- //float shield_percent = DefenseObject.Get_Shield_Strength() / DefenseObject.Get_Shield_Strength_Max();
- //
- // Re-initialize the base class
- //
- ScriptableGameObj::Re_Init( definition );
- //
- // Copy any internal settings from the definition
- //
- Copy_Settings( definition );
- //
- // Reset the health and shield to appropriate values
- //
- //DefenseObject.Set_Health (DefenseObject.Get_Health_Max () * health_percent);
- //DefenseObject.Set_Shield_Strength (DefenseObject.Get_Shield_Strength_Max () * shield_percent);
- Set_Player_Type( old_player_type );
- return ;
- }
- const DamageableGameObjDef & DamageableGameObj::Get_Definition( void ) const
- {
- return (const DamageableGameObjDef &)BaseGameObj::Get_Definition();
- }
- /*
- ** DamageableGameObj Save and Load
- */
- enum {
- CHUNKID_PARENT = 207011212,
- CHUNKID_DEFENSEOBJECT,
- CHUNKID_VARIABLES,
- MICROCHUNKID_PLAYER_TYPE = 1,
- MICROCHUNKID_IS_HEALTH_BAR_DISPLAYED,
- };
- bool DamageableGameObj::Save( ChunkSaveClass & csave )
- {
- csave.Begin_Chunk( CHUNKID_PARENT );
- ScriptableGameObj::Save( csave );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_VARIABLES );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PLAYER_TYPE, PlayerType );
- WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_HEALTH_BAR_DISPLAYED, IsHealthBarDisplayed );
- csave.End_Chunk();
- csave.Begin_Chunk( CHUNKID_DEFENSEOBJECT );
- DefenseObject.Save(csave);
- csave.End_Chunk();
- return true;
- }
- bool DamageableGameObj::Load( ChunkLoadClass &cload )
- {
- while (cload.Open_Chunk()) {
- switch(cload.Cur_Chunk_ID()) {
- case CHUNKID_PARENT:
- ScriptableGameObj::Load( cload );
- break;
- case CHUNKID_VARIABLES:
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK( cload, MICROCHUNKID_PLAYER_TYPE, PlayerType );
- READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_HEALTH_BAR_DISPLAYED, IsHealthBarDisplayed );
- default:
- Debug_Say(( "Unhandled MicroChunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
- break;
- }
- cload.Close_Micro_Chunk();
- }
- break;
-
- case CHUNKID_DEFENSEOBJECT:
- DefenseObject.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();
- }
- return true;
- }
- void DamageableGameObj::Apply_Damage( const OffenseObjectClass & damager, float scale, int alternate_skin )
- {
- if ( DefenseObject.Get_Health() <= 0 ) {
- return;
- }
- if (Is_Delete_Pending()) {
- return;
- }
- float old_health = DefenseObject.Get_Health();
- float old_shield = DefenseObject.Get_Shield_Strength();
- DefenseObject.Apply_Damage( damager, scale, alternate_skin );
- float new_health = DefenseObject.Get_Health();
- float new_shield = DefenseObject.Get_Shield_Strength();
- float diff = old_health + old_shield - new_health - new_shield;
- // Notify the observers
- const GameObjObserverList & observer_list = Get_Observers();
- for( int index = 0; index < observer_list.Count(); index++ ) {
- observer_list[ index ]->Damaged( this, damager.Get_Owner(), diff );
- }
- if ( DefenseObject.Get_Health() <= 0 ) {
- // notify the observers
- for( int index = 0; index < observer_list.Count(); index++ ) {
- observer_list[ index ]->Killed( this, damager.Get_Owner() );
- }
- Completely_Damaged( damager );
- }
- }
- //------------------------------------------------------------------------------------
- /*void DamageableGameObj::Get_Information( StringClass & string )
- {
- // If we just came from the editor, call created on all out observers
- const GameObjObserverList & observer_list = Get_Observers();
- for( int index = 0; index < observer_list.Count(); index++ ) {
- StringClass temp;
- temp.Format( "%s\n", observer_list[ index ]->Get_Name() );
- string += temp;
- }
- } */
- /*
- **
- */
- void DamageableGameObj::Export_Occasional( BitStreamClass &packet )
- {
- ScriptableGameObj::Export_Occasional( packet );
- //
- // Export the defense object's state
- //
- DefenseObject.Export (packet);
- }
- /*
- **
- */
- void DamageableGameObj::Import_Occasional( BitStreamClass &packet )
- {
- ScriptableGameObj::Import_Occasional( packet );
- //
- // Update the defense object's state
- //
- float old_health = DefenseObject.Get_Health();
- DefenseObject.Import (packet);
- float new_health = DefenseObject.Get_Health();
- /*
- //
- // Hack !
- //
- if ( Is_Delete_Pending() ) {
- if ( new_health != 0 ) {
- DefenseObject.Set_Health( 0 );
- new_health = DefenseObject.Get_Health();
- }
- } else {
- if ( new_health == 0 ) {
- DefenseObject.Set_Health( 0.01f );
- new_health = DefenseObject.Get_Health();
- }
- }
- */
- if (old_health > 0 && old_health > new_health) {
- // Notify the observers that we are damaged
- const GameObjObserverList& observer_list = Get_Observers();
- int count = observer_list.Count();
- for (int index = 0; index < count; ++index) {
- observer_list[index]->Damaged(this, NULL, old_health - new_health);
- }
- }
- //
- // Check to see if the object is completely damaged
- //
- if ( old_health > 0 && new_health <= 0 ) {
- // Notify the observers that the building has been destroyed
- const GameObjObserverList& observer_list = Get_Observers();
- int count = observer_list.Count();
- for (int index = 0; index < count; ++index) {
- observer_list[index]->Killed(this, NULL);
- }
- OffenseObjectClass dummy_offense_obj;
- Completely_Damaged( dummy_offense_obj );
- }
- }
- //-----------------------------------------------------------------------------
- bool DamageableGameObj::Is_Team_Player(void)
- {
- return PlayerType == PLAYERTYPE_NOD || PlayerType == PLAYERTYPE_GDI;
- }
- //-----------------------------------------------------------------------------
- Vector3 DamageableGameObj::Get_Team_Color(void)
- {
- return Get_Color_For_Team(PlayerType);
- }
- //-----------------------------------------------------------------------------
- void DamageableGameObj::Set_Player_Type(int id)
- {
- PlayerType = id;
- Set_Object_Dirty_Bit( NetworkObjectClass::BIT_RARE, true );
- }
- //-----------------------------------------------------------------------------
- bool DamageableGameObj::Is_Teammate(DamageableGameObj * p_obj)
- {
- WWASSERT(p_obj != NULL);
- return ((p_obj == this) ||
- (Is_Team_Player() && Get_Player_Type() == p_obj->Get_Player_Type()));
- }
- bool DamageableGameObj::Is_Enemy(DamageableGameObj * p_obj)
- {
- WWASSERT(p_obj != NULL);
- return ( (p_obj != this) && Player_Types_Are_Enemies( Get_Player_Type(), p_obj->Get_Player_Type() ) );
- }
|