/* ** 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 . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Combat * * * * $Archive:: /Commando/Code/Combat/buildingaggregate.cpp $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Bhayes $* * * * $Modtime:: 1/07/03 1:38p $* * * * $Revision:: 14 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * BuildingAggregateClass::BuildingAggregateClass -- Constructor * * BuildingAggregateClass::BuildingAggregateClass -- Constructor * * BuildingAggregateClass::~BuildingAggregateClass -- Destructor * * BuildingAggregateClass::Init -- Initialze from a definition * * BuildingAggregateClass::Get_Current_State -- returns the current state * * BuildingAggregateClass::Set_Current_State -- Sets the current state * * BuildingAggregateClass::Is_MCT -- is this aggregate an MCT? * * BuildingAggregateClass::Save -- Get the persist factory for this clas * * BuildingAggregateClass::Save -- Save the state of this object * * BuildingAggregateClass::Load -- Load the state of this object * * BuildingAggregateClass::On_Post_Load -- post-load processing * * BuildingAggregateDefClass::BuildingAggregateDefClass -- Constructor * * BuildingAggregateDefClass::Get_Class_ID -- returns the definition class ID * * BuildingAggregateDefClass::Create -- creates an instance of a BuildingAggregateClass * * BuildingAggregateDefClass::Get_Factory -- returns the persist factory * * BuildingAggregateDefClass::Save -- Saves the contents of this object * * BuildingAggregateDefClass::Save_State_Animation_Data -- Save the data for one of the buil * * BuildingAggregateDefClass::Load -- Load the contents of this object * * BuildingAggregateDefClass::Load_State_Animation_Data -- Load anim data for a building sta * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "buildingaggregate.h" #include "simpledefinitionfactory.h" #include "persistfactory.h" #include "wwphysids.h" #include "hanim.h" #include "combat.h" #include "wwaudio.h" #include "wwdebug.h" #include "wwhack.h" #include "wwprofile.h" DECLARE_FORCE_LINK( buildingaggregate ); /************************************************************************************************************* ** ** BuildingAggregateClass (BAG) Implementation ** *************************************************************************************************************/ SimplePersistFactoryClass _BuildingAggregatePersistFactory; enum { BAG_CHUNK_STATICANIMPHYS = 8281529, BAG_CHUNK_VARIABLES, BAG_VARIABLE_CURRENTSTATE = 0, }; /*********************************************************************************************** * BuildingAggregateClass::BuildingAggregateClass -- Constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ BuildingAggregateClass::BuildingAggregateClass(void) : CurrentState(BuildingStateClass::HEALTH100_POWERON) { } /*********************************************************************************************** * BuildingAggregateClass::~BuildingAggregateClass -- Destructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ BuildingAggregateClass::~BuildingAggregateClass(void) { } /*********************************************************************************************** * BuildingAggregateClass::Init -- Initialze from a definition * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ void BuildingAggregateClass::Init(const BuildingAggregateDefClass & def) { StaticAnimPhysClass::Init(def); AnimCollisionManagerClass & anim_mgr = Get_Animation_Manager(); anim_mgr.Set_Current_Frame(def.Frame0[CurrentState]); } /*********************************************************************************************** * BuildingAggregateClass::Get_Current_State -- returns the current state * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/8/2000 gth : Created. * *=============================================================================================*/ int BuildingAggregateClass::Get_Current_State(void) { return CurrentState; } /*********************************************************************************************** * BuildingAggregateClass::Set_Current_State -- Sets the current state * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/8/2000 gth : Created. * *=============================================================================================*/ void BuildingAggregateClass::Set_Current_State(int new_state,bool force_update) { if ((new_state != CurrentState) || (force_update == true)) { AnimCollisionManagerClass & anim_mgr = Get_Animation_Manager(); const BuildingAggregateDefClass * def = Get_BuildingAggregateDef(); WWASSERT(def != NULL); switch (def->AnimLogicMode) { case BuildingAggregateDefClass::ANIM_LOGIC_LOOP: { /* ** Calculate the fractional position in our current loop */ float normalized_frame = 0.0f; float cur_loop_len = def->Frame1[CurrentState] - def->Frame0[CurrentState]; if (cur_loop_len > 0.0f) { normalized_frame = (anim_mgr.Get_Current_Frame() - def->Frame0[CurrentState]) / (def->Frame1[CurrentState] - def->Frame0[CurrentState]); } /* ** Switch the loop start and end */ anim_mgr.Set_Loop_Start(def->Frame0[new_state]); anim_mgr.Set_Loop_End(def->Frame1[new_state]); /* ** Jump to the same fractional position in the new loop */ anim_mgr.Set_Current_Frame(def->Frame0[new_state] + normalized_frame * (def->Frame1[new_state] - def->Frame0[new_state])); /* ** If animation is disabled, set the animation mode to manual, otherwise set it to loop */ if (def->AnimationEnabled[new_state] == true) { anim_mgr.Set_Animation_Mode(AnimCollisionManagerClass::ANIMATE_LOOP); } else { anim_mgr.Set_Animation_Mode(AnimCollisionManagerClass::ANIMATE_MANUAL); } break; } case BuildingAggregateDefClass::ANIM_LOGIC_LINEAR: { /* ** The new target frame is determined by the new state */ anim_mgr.Set_Target_Frame(def->Frame0[new_state]); anim_mgr.Set_Animation_Mode(AnimCollisionManagerClass::ANIMATE_TARGET); /* ** If we changed power states or animation is disabled, then we need to warp the current frame */ if ( (BuildingStateClass::Is_Power_On(new_state) != BuildingStateClass::Is_Power_On(CurrentState)) || (def->AnimationEnabled[new_state] == false)) { anim_mgr.Set_Current_Frame(def->Frame0[new_state]); } break; } case BuildingAggregateDefClass::ANIM_LOGIC_SEQUENCE: { /* ** The current and target frames are determined by the new state. If the new sequence ** is the same as the previous sequence, don't do anything. */ if ((def->Frame0[CurrentState] != def->Frame0[new_state]) || (def->Frame1[CurrentState] != def->Frame1[new_state])) { anim_mgr.Set_Animation_Mode(AnimCollisionManagerClass::ANIMATE_TARGET); anim_mgr.Set_Current_Frame(def->Frame0[new_state]); anim_mgr.Set_Target_Frame(def->Frame1[new_state]); } break; } } CurrentState = new_state; } } /*********************************************************************************************** * BuildingAggregateClass::Is_MCT -- is this aggregate an MCT? * * * * MCT's are weak points for the building. The building will use an alternate skin type * * when applying damage that was done to the MCT. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/24/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateClass::Is_MCT(void) { return Get_BuildingAggregateDef()->IsMCT; } /* ** Save and Load */ /*********************************************************************************************** * BuildingAggregateClass::Save -- Get the persist factory for this class * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ const PersistFactoryClass & BuildingAggregateClass::Get_Factory(void) const { return _BuildingAggregatePersistFactory; } /*********************************************************************************************** * BuildingAggregateClass::Save -- Save the state of this object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateClass::Save(ChunkSaveClass & csave) { csave.Begin_Chunk(BAG_CHUNK_STATICANIMPHYS); StaticAnimPhysClass::Save(csave); csave.End_Chunk(); csave.Begin_Chunk(BAG_CHUNK_VARIABLES); WRITE_MICRO_CHUNK(csave, BAG_VARIABLE_CURRENTSTATE, CurrentState ); csave.End_Chunk(); return true; } /*********************************************************************************************** * BuildingAggregateClass::Load -- Load the state of this object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateClass::Load( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case BAG_CHUNK_STATICANIMPHYS: StaticAnimPhysClass::Load( cload ); break; case BAG_CHUNK_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK(cload, BAG_VARIABLE_CURRENTSTATE, CurrentState ); default: WWDEBUG_SAY(( "Unrecognized BuildingAggregate Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } break; default: WWDEBUG_SAY(("Unrecognized BuildingAggregate Chunk: 0x%x in file %s, line %d\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__)); break; } cload.Close_Chunk(); } SaveLoadSystemClass::Register_Post_Load_Callback(this); return true; } /*********************************************************************************************** * BuildingAggregateClass::On_Post_Load -- post-load processing * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 9/8/2000 gth : Created. * *=============================================================================================*/ void BuildingAggregateClass::On_Post_Load(void) { StaticAnimPhysClass::On_Post_Load(); Set_Current_State(CurrentState,true); } /* ** */ void BuildingAggregateClass::Save_State( ChunkSaveClass & csave ) { csave.Begin_Chunk( BAG_CHUNK_STATICANIMPHYS ); StaticAnimPhysClass::Save_State(csave); csave.End_Chunk(); csave.Begin_Chunk(BAG_CHUNK_VARIABLES); WRITE_MICRO_CHUNK(csave, BAG_VARIABLE_CURRENTSTATE, CurrentState ); csave.End_Chunk(); } /* ** */ void BuildingAggregateClass::Load_State( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case BAG_CHUNK_STATICANIMPHYS: StaticAnimPhysClass::Load_State( cload ); break; case BAG_CHUNK_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK(cload, BAG_VARIABLE_CURRENTSTATE, CurrentState ); default: WWDEBUG_SAY(( "Unrecognized BuildingAggregate Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } break; default: WWDEBUG_SAY(( "Unrecognized BuildingAggregate chunkID\n" )); break; } cload.Close_Chunk(); } } /************************************************************************************************* ** ** BuildingAggregateDefClass Implementation ** *************************************************************************************************/ /* ** Persist Factory for BuildingAggregateDefClass, this makes them save and load. */ SimplePersistFactoryClass _BuildingAggregateDefPersistFactory; /* ** Definition Factory for BuildingAggregateDefClass, this makes them show up in the editor */ DECLARE_DEFINITION_FACTORY(BuildingAggregateDefClass, CLASSID_BUILDINGAGGREGATEDEF, "BuildingAggregate") _BuildingAggregateDefDefFactory; /* ** Chunk ID's used by BuildingAggregateDefClass */ enum { BAGDEF_CHUNK_STATICANIMPHYS = 8281441, BAGDEF_CHUNK_VARIABLES, BAGDEF_CHUNK_HEALTH100_POWERON_VARIABLES, BAGDEF_CHUNK_HEALTH75_POWERON_VARIABLES, BAGDEF_CHUNK_HEALTH50_POWERON_VARIABLES, BAGDEF_CHUNK_HEALTH25_POWERON_VARIABLES, BAGDEF_CHUNK_DESTROYED_POWERON_VARIABLES, BAGDEF_CHUNK_HEALTH100_POWEROFF_VARIABLES, BAGDEF_CHUNK_HEALTH75_POWEROFF_VARIABLES, BAGDEF_CHUNK_HEALTH50_POWEROFF_VARIABLES, BAGDEF_CHUNK_HEALTH25_POWEROFF_VARIABLES, BAGDEF_CHUNK_DESTROYED_POWEROFF_VARIABLES, BAGDEF_VARIABLE_ANIMLOGICMODE = 0, BAGDEF_VARIABLE_FRAME0, BAGDEF_VARIABLE_FRAME1, BAGDEF_VARIABLE_ANIMATIONENABLED, BAGDEF_VARIABLE_ISMCT, }; /*********************************************************************************************** * BuildingAggregateDefClass::BuildingAggregateDefClass -- Constructor * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ BuildingAggregateDefClass::BuildingAggregateDefClass( void ) : StaticAnimPhysDefClass(), AnimLogicMode(ANIM_LOGIC_LOOP), IsMCT(false) { int i; for (i=0; iSet_Name ("AnimLogicMode"); anim_logic_param->Add_Value("ANIM_LOGIC_LINEAR",ANIM_LOGIC_LINEAR); anim_logic_param->Add_Value("ANIM_LOGIC_LOOP",ANIM_LOGIC_LOOP); anim_logic_param->Add_Value("ANIM_LOGIC_SEQUENCE",ANIM_LOGIC_SEQUENCE); GENERIC_EDITABLE_PARAM( BuildingAggregateDefClass, anim_logic_param); EDITABLE_PARAM(BuildingAggregateDefClass, ParameterClass::TYPE_BOOL, IsMCT); for (i=0; iInit( *this ); return obj; } /* ** Save and Load */ /*********************************************************************************************** * BuildingAggregateDefClass::Get_Factory -- returns the persist factory * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ const PersistFactoryClass & BuildingAggregateDefClass::Get_Factory(void) const { return _BuildingAggregateDefPersistFactory; } /*********************************************************************************************** * BuildingAggregateDefClass::Save -- Saves the contents of this object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateDefClass::Save(ChunkSaveClass & csave) { csave.Begin_Chunk( BAGDEF_CHUNK_STATICANIMPHYS ); StaticAnimPhysDefClass::Save( csave ); csave.End_Chunk(); csave.Begin_Chunk( BAGDEF_CHUNK_VARIABLES ); WRITE_MICRO_CHUNK( csave, BAGDEF_VARIABLE_ANIMLOGICMODE, AnimLogicMode ); WRITE_MICRO_CHUNK( csave, BAGDEF_VARIABLE_ISMCT, IsMCT ); csave.End_Chunk(); for (int i=0; i= 0); WWASSERT(state_index < BuildingStateClass::STATE_COUNT); csave.Begin_Chunk(BAGDEF_CHUNK_HEALTH100_POWERON_VARIABLES + state_index); WRITE_MICRO_CHUNK(csave,BAGDEF_VARIABLE_FRAME0,Frame0[state_index]); WRITE_MICRO_CHUNK(csave,BAGDEF_VARIABLE_FRAME1,Frame1[state_index]); WRITE_MICRO_CHUNK(csave,BAGDEF_VARIABLE_ANIMATIONENABLED,AnimationEnabled[state_index]); csave.End_Chunk(); return true; } /*********************************************************************************************** * BuildingAggregateDefClass::Load -- Load the contents of this object * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateDefClass::Load( ChunkLoadClass &cload ) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case BAGDEF_CHUNK_STATICANIMPHYS: StaticAnimPhysDefClass::Load( cload ); break; case BAGDEF_CHUNK_VARIABLES: while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK( cload, BAGDEF_VARIABLE_ANIMLOGICMODE,AnimLogicMode ); READ_MICRO_CHUNK( cload, BAGDEF_VARIABLE_ISMCT, IsMCT ); default: WWDEBUG_SAY(( "Unrecognized BuildingAggregateDef Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } break; case BAGDEF_CHUNK_HEALTH100_POWERON_VARIABLES: case BAGDEF_CHUNK_HEALTH75_POWERON_VARIABLES: case BAGDEF_CHUNK_HEALTH50_POWERON_VARIABLES: case BAGDEF_CHUNK_HEALTH25_POWERON_VARIABLES: case BAGDEF_CHUNK_DESTROYED_POWERON_VARIABLES: case BAGDEF_CHUNK_HEALTH100_POWEROFF_VARIABLES: case BAGDEF_CHUNK_HEALTH75_POWEROFF_VARIABLES: case BAGDEF_CHUNK_HEALTH50_POWEROFF_VARIABLES: case BAGDEF_CHUNK_HEALTH25_POWEROFF_VARIABLES: case BAGDEF_CHUNK_DESTROYED_POWEROFF_VARIABLES: Load_State_Animation_Data(cload,cload.Cur_Chunk_ID() - BAGDEF_CHUNK_HEALTH100_POWERON_VARIABLES); break; default: WWDEBUG_SAY(( "Unrecognized BuildingAggregateDef chunkID\n" )); break; } cload.Close_Chunk(); } return true; } /*********************************************************************************************** * BuildingAggregateDefClass::Load_State_Animation_Data -- Load anim data for a building state * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 8/29/2000 gth : Created. * *=============================================================================================*/ bool BuildingAggregateDefClass::Load_State_Animation_Data(ChunkLoadClass & cload,int state_index) { WWASSERT(state_index >= 0); WWASSERT(state_index < BuildingStateClass::STATE_COUNT); while (cload.Open_Micro_Chunk()) { switch(cload.Cur_Micro_Chunk_ID()) { READ_MICRO_CHUNK(cload,BAGDEF_VARIABLE_FRAME0,Frame0[state_index]); READ_MICRO_CHUNK(cload,BAGDEF_VARIABLE_FRAME1,Frame1[state_index]); READ_MICRO_CHUNK(cload,BAGDEF_VARIABLE_ANIMATIONENABLED,AnimationEnabled[state_index]); default: WWDEBUG_SAY(( "Unrecognized BuildingAggregateDef Variable chunkID\n" )); break; } cload.Close_Micro_Chunk(); } return true; }