powerup.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Combat/powerup.cpp $*
  25. * *
  26. * $Author:: Byon_g $*
  27. * *
  28. * $Modtime:: 12/17/01 10:57a $*
  29. * *
  30. * $Revision:: 93 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "powerup.h"
  36. #include "debug.h"
  37. #include "combat.h"
  38. #include "phys.h"
  39. #include "persistfactory.h"
  40. #include "combatchunkid.h"
  41. #include "simpledefinitionfactory.h"
  42. #include "wwhack.h"
  43. #include "weaponbag.h"
  44. #include "damage.h"
  45. #include "gameobjmanager.h"
  46. #include "colmath.h"
  47. #include "movephys.h"
  48. #include "wwaudio.h"
  49. #include "audiblesound.h"
  50. #include "hanim.h"
  51. #include "timemgr.h"
  52. #include "assetmgr.h"
  53. #include "animcontrol.h"
  54. #include "soldier.h"
  55. #include "wwprofile.h"
  56. #include "objlibrary.h"
  57. #include "gameobjobserver.h"
  58. #include "diaglog.h"
  59. #include "weaponmanager.h"
  60. #include "weapons.h"
  61. #include "hud.h"
  62. #include "playerdata.h"
  63. #include "physinttest.h"
  64. #include "encyclopediamgr.h"
  65. #include "vehicle.h"
  66. #include "combatmaterialeffectmanager.h"
  67. #include "transitioneffect.h"
  68. #include "apppackettypes.h"
  69. #include "hudinfo.h"
  70. #include "string_ids.h"
  71. #include "translatedb.h"
  72. /*
  73. ** PowerUpGameObjDef
  74. */
  75. DECLARE_FORCE_LINK( PowerUp )
  76. SimplePersistFactoryClass<PowerUpGameObjDef, CHUNKID_GAME_OBJECT_DEF_POWERUP> _PowerUpGameObjDefPersistFactory;
  77. DECLARE_DEFINITION_FACTORY(PowerUpGameObjDef, CLASSID_GAME_OBJECT_DEF_POWERUP, "PowerUp") _PowerUpGameObjDefDefFactory;
  78. PowerUpGameObjDef::PowerUpGameObjDef( void ) :
  79. GrantShieldType( 0 ),
  80. GrantShieldStrength( 0 ),
  81. GrantShieldStrengthMax( 0 ),
  82. GrantHealth( 0 ),
  83. GrantHealthMax( 0 ),
  84. GrantWeaponID( 0 ),
  85. GrantWeapon( true ),
  86. GrantWeaponClips( false ),
  87. GrantWeaponRounds( 0 ),
  88. Persistent( false ),
  89. //IsCaptureTheFlag( false ),
  90. GrantKey( 0 ),
  91. GrantSoundID( 0 ),
  92. IdleSoundID( 0 ),
  93. AlwaysAllowGrant( false )
  94. {
  95. #ifdef PARAM_EDITING_ON
  96. // EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantShieldType );
  97. EnumParameterClass *param;
  98. param = new EnumParameterClass( &GrantShieldType );
  99. param->Set_Name ( "GrantShieldType" );
  100. for ( int param_counter = 0; param_counter < ArmorWarheadManager::Get_Num_Armor_Types(); param_counter++ ) {
  101. param->Add_Value(ArmorWarheadManager::Get_Armor_Name(param_counter), param_counter);
  102. }
  103. GENERIC_EDITABLE_PARAM( PowerUpGameObjDef, param )
  104. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantShieldStrength );
  105. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantShieldStrengthMax );
  106. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantHealth );
  107. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_FLOAT, GrantHealthMax );
  108. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_WEAPONOBJDEFINITIONID, GrantWeaponID );
  109. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, GrantWeapon );
  110. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, GrantWeaponClips );
  111. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantWeaponRounds );
  112. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, Persistent );
  113. //EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, false );//IsCaptureTheFlag );
  114. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_INT, GrantKey );
  115. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_BOOL, AlwaysAllowGrant );
  116. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_STRING, GrantAnimationName );
  117. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_STRING, IdleAnimationName );
  118. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_SOUNDDEFINITIONID, GrantSoundID );
  119. EDITABLE_PARAM( PowerUpGameObjDef, ParameterClass::TYPE_SOUNDDEFINITIONID, IdleSoundID );
  120. #endif //PARAM_EDITING_ON
  121. }
  122. uint32 PowerUpGameObjDef::Get_Class_ID (void) const
  123. {
  124. return CLASSID_GAME_OBJECT_DEF_POWERUP;
  125. }
  126. PersistClass * PowerUpGameObjDef::Create( void ) const
  127. {
  128. PowerUpGameObj * obj = new PowerUpGameObj;
  129. obj->Init( *this );
  130. return obj;
  131. }
  132. enum {
  133. CHUNKID_DEF_PARENT = 909991656,
  134. CHUNKID_DEF_VARIABLES,
  135. XXXMICROCHUNKID_DEF_PARAMETERS = 1,
  136. MICROCHUNKID_DEF_PERSISTENT,
  137. MICROCHUNKID_DEF_GRANT_SHIELD_TYPE,
  138. MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH,
  139. XXXMICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX,
  140. MICROCHUNKID_DEF_GRANT_HEALTH,
  141. XXXMICROCHUNKID_DEF_GRANT_HEALTH_MAX,
  142. MICROCHUNKID_DEF_GRANT_WEAPON_ID,
  143. MICROCHUNKID_DEF_GRANT_WEAPON,
  144. MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS,
  145. XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG,
  146. XXXMICROCHUNKID_DEF_GRANT_KEY_MASK,
  147. MICROCHUNKID_DEF_GRANT_ANIMATION_NAME,
  148. MICROCHUNKID_DEF_GRANT_SOUNDID,
  149. MICROCHUNKID_DEF_IDLE_ANIMATION_NAME,
  150. MICROCHUNKID_DEF_IDLE_SOUNDID,
  151. MICROCHUNKID_DEF_GRANT_KEY,
  152. MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT,
  153. MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS,
  154. MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX,
  155. MICROCHUNKID_DEF_GRANT_HEALTH_MAX,
  156. };
  157. bool PowerUpGameObjDef::Save( ChunkSaveClass & csave )
  158. {
  159. csave.Begin_Chunk( CHUNKID_DEF_PARENT );
  160. SimpleGameObjDef::Save( csave );
  161. csave.End_Chunk();
  162. csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
  163. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_TYPE, GrantShieldType );
  164. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH, GrantShieldStrength );
  165. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX,GrantShieldStrengthMax );
  166. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_HEALTH, GrantHealth );
  167. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_HEALTH_MAX, GrantHealthMax );
  168. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_ID, GrantWeaponID );
  169. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON, GrantWeapon );
  170. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS, GrantWeaponClips );
  171. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS, GrantWeaponRounds );
  172. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_PERSISTENT, Persistent );
  173. //WRITE_MICRO_CHUNK( csave, XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG, IsCaptureTheFlag );
  174. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_KEY, GrantKey );
  175. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_GRANT_SOUNDID, GrantSoundID );
  176. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IDLE_SOUNDID, IdleSoundID );
  177. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_GRANT_ANIMATION_NAME, GrantAnimationName );
  178. WRITE_MICRO_CHUNK_WWSTRING( csave, MICROCHUNKID_DEF_IDLE_ANIMATION_NAME, IdleAnimationName );
  179. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT, AlwaysAllowGrant );
  180. csave.End_Chunk();
  181. return true;
  182. }
  183. bool PowerUpGameObjDef::Load( ChunkLoadClass &cload )
  184. {
  185. while (cload.Open_Chunk()) {
  186. switch(cload.Cur_Chunk_ID()) {
  187. case CHUNKID_DEF_PARENT:
  188. SimpleGameObjDef::Load( cload );
  189. break;
  190. case CHUNKID_DEF_VARIABLES:
  191. while (cload.Open_Micro_Chunk()) {
  192. switch(cload.Cur_Micro_Chunk_ID()) {
  193. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_TYPE, GrantShieldType );
  194. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH, GrantShieldStrength );
  195. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SHIELD_STRENGTH_MAX, GrantShieldStrengthMax );
  196. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_HEALTH, GrantHealth );
  197. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_HEALTH_MAX, GrantHealthMax );
  198. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_ID, GrantWeaponID );
  199. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON, GrantWeapon );
  200. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_CLIPS, GrantWeaponClips );
  201. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_WEAPON_ROUNDS, GrantWeaponRounds );
  202. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_PERSISTENT, Persistent );
  203. //READ_MICRO_CHUNK( cload, XXXMICROCHUNKID_DEF_IS_CAPTURE_THE_FLAG, IsCaptureTheFlag );
  204. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_KEY, GrantKey );
  205. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_GRANT_SOUNDID, GrantSoundID );
  206. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IDLE_SOUNDID, IdleSoundID );
  207. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_GRANT_ANIMATION_NAME, GrantAnimationName );
  208. READ_MICRO_CHUNK_WWSTRING( cload, MICROCHUNKID_DEF_IDLE_ANIMATION_NAME, IdleAnimationName );
  209. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ALWAYS_ALLOW_GRANT, AlwaysAllowGrant );
  210. default:
  211. Debug_Say(("Unhandled Micro Chunk:%d File:%s Line:%d\r\n",cload.Cur_Micro_Chunk_ID(),__FILE__,__LINE__));
  212. break;
  213. }
  214. cload.Close_Micro_Chunk();
  215. }
  216. break;
  217. default:
  218. Debug_Say(("Unhandled Chunk:%d File:%s Line:%d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  219. break;
  220. }
  221. cload.Close_Chunk();
  222. }
  223. return true;
  224. }
  225. const PersistFactoryClass & PowerUpGameObjDef::Get_Factory (void) const
  226. {
  227. return _PowerUpGameObjDefPersistFactory;
  228. }
  229. bool PowerUpGameObjDef::Grant( SmartGameObj * obj, PowerUpGameObj * p_powerup, bool hud_display ) const
  230. {
  231. int no_grant_message = 0;
  232. bool granted = false;
  233. WWASSERT(CombatManager::I_Am_Server());
  234. DefenseObjectClass * defense = obj->Get_Defense_Object();
  235. // Grant the shield
  236. if ( GrantShieldType != 0 ) {
  237. if ( GrantShieldType > (int)defense->Get_Shield_Type() ) {
  238. defense->Set_Shield_Type( GrantShieldType );
  239. granted = true;
  240. } else {
  241. no_grant_message = IDS_M00DSGN_DSGN1015I1DSGN_TXT; //"You are already at full shield."
  242. }
  243. }
  244. if ( GrantShieldStrengthMax != 0 ) {
  245. float add = GrantShieldStrengthMax * (float)obj->Get_Definition().Get_DefenseObjectDef().ShieldStrengthMax;
  246. switch ( CombatManager::Get_Difficulty_Level() ) {
  247. case 0: add *= 2.0f; break;
  248. case 2: add *= 0.75f; break;
  249. };
  250. // Round up to next int
  251. add = (int)(add + 0.95f);
  252. defense->Set_Shield_Strength_Max( defense->Get_Shield_Strength_Max() + add );
  253. granted = true;
  254. if ( hud_display && obj == COMBAT_STAR ) {
  255. HUDClass::Add_Shield_Upgrade_Grant( add );
  256. }
  257. }
  258. if ( GrantShieldStrength != 0 ) {
  259. if ( (defense->Get_Shield_Strength() < defense->Get_Shield_Strength_Max()) ) {
  260. defense->Add_Shield_Strength( GrantShieldStrength );
  261. granted = true;
  262. if ( obj == COMBAT_STAR ) {
  263. Vector3 pos;
  264. obj->Get_Position( &pos );
  265. 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() ));
  266. }
  267. } else {
  268. no_grant_message = IDS_M00DSGN_DSGN1015I1DSGN_TXT; //"You are already at full shield."
  269. }
  270. }
  271. if ( granted && hud_display ) {
  272. if ( obj == COMBAT_STAR ) {
  273. if ( GrantShieldStrengthMax == 0 ) {
  274. HUDClass::Add_Shield_Grant( GrantShieldStrength );
  275. }
  276. }
  277. }
  278. // Grant the Health
  279. if ( GrantHealthMax != 0 ) {
  280. float add = GrantHealthMax * (float)obj->Get_Definition().Get_DefenseObjectDef().HealthMax;
  281. switch ( CombatManager::Get_Difficulty_Level() ) {
  282. case 0: add *= 2.0f; break;
  283. case 2: add *= 0.75f; break;
  284. };
  285. // Round up to next int
  286. add = (int)(add + 0.95f);
  287. defense->Set_Health_Max( defense->Get_Health_Max() + add );
  288. granted = true;
  289. if ( hud_display && obj == COMBAT_STAR ) {
  290. HUDClass::Add_Health_Upgrade_Grant( add );
  291. }
  292. }
  293. if ( GrantHealth != 0 ) {
  294. if ( defense->Get_Health() < defense->Get_Health_Max() ) {
  295. defense->Add_Health( GrantHealth );
  296. granted = true;
  297. if ( obj == COMBAT_STAR && hud_display ) {
  298. if ( GrantHealthMax == 0 ) {
  299. HUDClass::Add_Health_Grant( GrantHealth );
  300. }
  301. }
  302. if ( obj == COMBAT_STAR ) {
  303. Vector3 pos;
  304. obj->Get_Position( &pos );
  305. 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() ));
  306. }
  307. } else {
  308. no_grant_message = IDS_M00DSGN_DSGN1014I1DSGN_TXT; //"You are already at full health."
  309. }
  310. }
  311. // Grant the Weapon
  312. if ( GrantWeaponID != 0 ) {
  313. if ( ( GrantWeapon && !obj->Get_Weapon_Bag()->Is_Weapon_Owned( GrantWeaponID ) ) ||
  314. ( !obj->Get_Weapon_Bag()->Is_Ammo_Full( GrantWeaponID ) ) ) {
  315. if ( obj == COMBAT_STAR && hud_display ) {
  316. if ( GrantWeapon && !obj->Get_Weapon_Bag()->Is_Weapon_Owned( GrantWeaponID ) ) {
  317. HUDClass::Add_Powerup_Weapon( GrantWeaponID, GrantWeaponRounds );
  318. } else {
  319. if ( !obj->Get_Weapon_Bag()->Is_Ammo_Full( GrantWeaponID ) ) {
  320. HUDClass::Add_Powerup_Ammo( GrantWeaponID, GrantWeaponRounds );
  321. }
  322. }
  323. }
  324. obj->Get_Weapon_Bag()->Add_Weapon( GrantWeaponID, GrantWeaponRounds, GrantWeapon );
  325. granted = true;
  326. if ( obj == COMBAT_STAR ) {
  327. Vector3 pos;
  328. obj->Get_Position( &pos );
  329. const char * grant_name = "";
  330. const WeaponDefinitionClass * def = WeaponManager::Find_Weapon_Definition( GrantWeaponID );
  331. if ( def ) {
  332. grant_name = def->Get_Name();
  333. }
  334. const char * weapon_name = "";
  335. int ammo = 0;
  336. if ( obj->Get_Weapon() ) {
  337. weapon_name = obj->Get_Weapon()->Get_Definition()->Get_Name();
  338. ammo = obj->Get_Weapon()->Get_Total_Rounds();
  339. }
  340. 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 ));
  341. }
  342. } else {
  343. no_grant_message = IDS_M00DSGN_DSGN1016I1DSGN_TXT; //"Your weapon is full."
  344. }
  345. } else if ( GrantWeaponClips ) {
  346. //
  347. // Loop over all the weapons in the owner's bag
  348. //
  349. WeaponBagClass *weapon_bag = obj->Get_Weapon_Bag();
  350. for ( int weapon_index = 0; weapon_index < weapon_bag->Get_Count(); weapon_index ++ ) {
  351. WeaponClass *weapon = weapon_bag->Peek_Weapon( weapon_index );
  352. if( weapon != NULL && weapon->Get_Definition ()->CanReceiveGenericCnCAmmo ) {
  353. //
  354. // Grant "x" number of clips to the weapon
  355. //
  356. int clip_rounds = weapon->Get_Definition()->ClipSize;
  357. weapon->Add_Rounds( clip_rounds * GrantWeaponRounds );
  358. }
  359. }
  360. }
  361. // Grant the key
  362. if ( GrantKey != 0 ) {
  363. SoldierGameObj * soldier = obj->As_SoldierGameObj();
  364. if ( soldier && soldier->Is_Human_Controlled() ) {
  365. if ( !soldier->Has_Key( GrantKey ) ) {
  366. soldier->Give_Key( GrantKey );
  367. granted = true;
  368. }
  369. }
  370. if ( obj == COMBAT_STAR ) {
  371. Vector3 pos;
  372. obj->Get_Position( &pos );
  373. DIAG_LOG(( "KEPU", "%1.2f; %1.2f; %1.2f; %d", pos.X, pos.Y, pos.Z, GrantKey ));
  374. }
  375. if ( granted && hud_display && obj == COMBAT_STAR ) {
  376. HUDClass::Add_Key_Grant( GrantKey );
  377. }
  378. }
  379. /*
  380. // Handle Capture the Flag
  381. if ( IsCaptureTheFlag && p_powerup != NULL && obj->As_SoldierGameObj() != NULL ) {
  382. CombatManager::Soldier_Contacts_Flag( obj->As_SoldierGameObj(), p_powerup );
  383. granted = true;
  384. }
  385. */
  386. if ( AlwaysAllowGrant ) {
  387. granted = true;
  388. }
  389. if ( granted && p_powerup != NULL ) {
  390. p_powerup->Set_State( PowerUpGameObj::STATE_GRANTING );
  391. //
  392. // Reveal this object to the player
  393. //
  394. if ( COMBAT_STAR == obj ) {
  395. EncyclopediaMgrClass::Reveal_Object( p_powerup );
  396. }
  397. }
  398. // Stats
  399. if ( granted && obj->Get_Player_Data() ) {
  400. obj->Get_Player_Data()->Stats_Add_Powerup();
  401. }
  402. if ( !granted && ( COMBAT_STAR == obj ) && no_grant_message != 0 ) {
  403. HUDInfo::Set_HUD_Help_Text( TRANSLATE( no_grant_message ), Vector3( 0,1,0 ) );
  404. }
  405. return granted;
  406. }
  407. /*
  408. ** PowerUpGameObj
  409. */
  410. SimplePersistFactoryClass<PowerUpGameObj, CHUNKID_GAME_OBJECT_POWERUP> _PowerUpGameObjPersistFactory;
  411. PowerUpGameObj::PowerUpGameObj (void) :
  412. IdleSoundObj( NULL ),
  413. State( STATE_BECOMING_IDLE ),
  414. WeaponBag( NULL )
  415. {
  416. Set_App_Packet_Type(APPPACKETTYPE_POWERUP);
  417. }
  418. PowerUpGameObj::~PowerUpGameObj (void)
  419. {
  420. //
  421. // Cleanup the idle sound
  422. //
  423. if ( IdleSoundObj != NULL ) {
  424. IdleSoundObj->Remove_From_Scene();
  425. IdleSoundObj->Release_Ref();
  426. IdleSoundObj = NULL;
  427. }
  428. if ( WeaponBag != NULL ) {
  429. delete WeaponBag;
  430. WeaponBag = NULL;
  431. }
  432. return ;
  433. }
  434. const PersistFactoryClass & PowerUpGameObj::Get_Factory (void) const
  435. {
  436. return _PowerUpGameObjPersistFactory;
  437. }
  438. /*
  439. **
  440. */
  441. void PowerUpGameObj::Init( void )
  442. {
  443. Init( Get_Definition() );
  444. }
  445. /*
  446. **
  447. */
  448. void PowerUpGameObj::Init( const PowerUpGameObjDef & definition )
  449. {
  450. SimpleGameObj::Init( definition );
  451. // Only collide with terrain!
  452. Peek_Physical_Object()->Set_Collision_Group( TERRAIN_ONLY_COLLISION_GROUP );
  453. }
  454. const PowerUpGameObjDef & PowerUpGameObj::Get_Definition( void ) const
  455. {
  456. return (const PowerUpGameObjDef &)BaseGameObj::Get_Definition();
  457. }
  458. /*
  459. ** PowerUpGameObj Save and Load
  460. */
  461. enum {
  462. CHUNKID_PARENT = 927991635,
  463. CHUNKID_VARIABLES,
  464. CHUNKID_WEAPONBAG,
  465. MICROCHUNKID_STATE = 1,
  466. MICROCHUNKID_STATE_END_TIMER,
  467. };
  468. bool PowerUpGameObj::Save( ChunkSaveClass & csave )
  469. {
  470. csave.Begin_Chunk( CHUNKID_PARENT );
  471. SimpleGameObj::Save( csave );
  472. csave.End_Chunk();
  473. csave.Begin_Chunk( CHUNKID_VARIABLES );
  474. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE, State );
  475. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STATE_END_TIMER, StateEndTimer );
  476. csave.End_Chunk();
  477. if ( WeaponBag != NULL ) {
  478. csave.Begin_Chunk( CHUNKID_WEAPONBAG );
  479. WeaponBag->Save( csave );
  480. csave.End_Chunk();
  481. }
  482. // We don't save IdleSoundObj
  483. return true;
  484. }
  485. bool PowerUpGameObj::Load( ChunkLoadClass &cload )
  486. {
  487. while (cload.Open_Chunk()) {
  488. switch(cload.Cur_Chunk_ID()) {
  489. case CHUNKID_PARENT:
  490. SimpleGameObj::Load( cload );
  491. break;
  492. case CHUNKID_VARIABLES:
  493. while (cload.Open_Micro_Chunk()) {
  494. switch(cload.Cur_Micro_Chunk_ID()) {
  495. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE, State );
  496. READ_MICRO_CHUNK( cload, MICROCHUNKID_STATE_END_TIMER, StateEndTimer );
  497. default:
  498. Debug_Say(( "Unrecognized PowerupGameObj Variable chunkID\n" ));
  499. break;
  500. }
  501. cload.Close_Micro_Chunk();
  502. }
  503. break;
  504. case CHUNKID_WEAPONBAG:
  505. WWASSERT( WeaponBag == NULL );
  506. WeaponBag = new WeaponBagClass( NULL );
  507. WeaponBag->Load( cload );
  508. break;
  509. default:
  510. Debug_Say(( "Unrecognized PowerUpGameObj chunkID\n" ));
  511. break;
  512. }
  513. cload.Close_Chunk();
  514. }
  515. SaveLoadSystemClass::Register_Post_Load_Callback(this); // MOVED
  516. return true;
  517. }
  518. void PowerUpGameObj::On_Post_Load( void )
  519. {
  520. SimpleGameObj::On_Post_Load();
  521. Peek_Physical_Object()->Set_Collision_Group( UNCOLLIDEABLE_GROUP ); // MOVED
  522. if ( Peek_Physical_Object()->As_MoveablePhysClass() != NULL ) {
  523. Peek_Physical_Object()->As_MoveablePhysClass()->Set_Gravity_Multiplier( 0 );
  524. }
  525. // This allows the idle sound and animation to start after loading
  526. if ( State == STATE_IDLING ) {
  527. State = STATE_BECOMING_IDLE;
  528. }
  529. }
  530. void PowerUpGameObj::Set_State( int state )
  531. {
  532. if (state != State) {
  533. State = state;
  534. StateEndTimer = 0;
  535. if ( State == STATE_GRANTING ) {
  536. //
  537. // Stop the idling sound (if necessary)
  538. //
  539. if ( IdleSoundObj != NULL ) {
  540. IdleSoundObj->Remove_From_Scene();
  541. IdleSoundObj->Stop();
  542. }
  543. //
  544. // Play the grant sound (if exists)
  545. //
  546. if ( Get_Definition ().GrantSoundID != 0 ) {
  547. WWAudioClass::Get_Instance()->Create_Instant_Sound( Get_Definition ().GrantSoundID, Get_Transform () );
  548. }
  549. //
  550. // Play the grant animation (if exists)
  551. //
  552. if ( Get_Definition ().GrantAnimationName.Get_Length () > 0 ) {
  553. Set_Animation( Get_Definition ().GrantAnimationName, false );
  554. HAnimClass *animation = WW3DAssetManager::Get_Instance ()->Get_HAnim( Get_Anim_Control ()->Get_Animation_Name () );
  555. if ( animation != NULL ) {
  556. StateEndTimer = animation->Get_Total_Time();
  557. REF_PTR_RELEASE( animation );
  558. }
  559. }
  560. }
  561. }
  562. return ;
  563. }
  564. void PowerUpGameObj::Update_State( void )
  565. {
  566. switch ( State )
  567. {
  568. case STATE_IDLING:
  569. break;
  570. case STATE_BECOMING_IDLE:
  571. //
  572. // Start playing the idle sound
  573. //
  574. if ( Get_Definition ().IdleSoundID != 0 ) {
  575. if ( IdleSoundObj == NULL ) {
  576. IdleSoundObj = WWAudioClass::Get_Instance ()->Create_Continuous_Sound( Get_Definition ().IdleSoundID );
  577. }
  578. if ( IdleSoundObj != NULL ) {
  579. IdleSoundObj->Set_Transform( Get_Transform () );
  580. IdleSoundObj->Add_To_Scene( true );
  581. }
  582. }
  583. //
  584. // Start playing the idle animation
  585. //
  586. if ( Get_Definition ().IdleAnimationName.Get_Length () > 0 ) {
  587. Set_Animation( Get_Definition ().IdleAnimationName, true );
  588. }
  589. State = STATE_IDLING;
  590. break;
  591. case STATE_GRANTING:
  592. //
  593. // If the granting animation has finished, then change to another state (or remove
  594. // the powerup from the world).
  595. //
  596. StateEndTimer -= TimeManager::Get_Frame_Seconds();
  597. if ( StateEndTimer <= 0 ) {
  598. //if ( Get_Definition().IsCaptureTheFlag || Get_Definition().Persistent ) {
  599. if ( Get_Definition().Persistent ) {
  600. Set_State ( STATE_BECOMING_IDLE );
  601. } else {
  602. Set_Delete_Pending();
  603. }
  604. }
  605. break;
  606. case STATE_EXPIRING:
  607. //
  608. // If the granting animation has finished, then change to another state (or remove
  609. // the powerup from the world).
  610. //
  611. StateEndTimer -= TimeManager::Get_Frame_Seconds();
  612. if ( StateEndTimer <= 0 ) {
  613. Set_Delete_Pending();
  614. }
  615. break;
  616. }
  617. return ;
  618. }
  619. void PowerUpGameObj::Grant( SmartGameObj * obj )
  620. {
  621. WWASSERT ( State != STATE_GRANTING );
  622. WWASSERT( obj );
  623. // Grant Def
  624. Get_Definition().Grant( obj, this );
  625. // If we have a weapon bag, move it
  626. if ( WeaponBag != NULL ) {
  627. WWASSERT( obj->Get_Weapon_Bag() );
  628. if ( obj->Get_Weapon_Bag()->Move_Contents( WeaponBag ) ) {
  629. Set_State( PowerUpGameObj::STATE_GRANTING );
  630. }
  631. }
  632. if ( State == STATE_GRANTING ) {
  633. const GameObjObserverList & observer_list = Get_Observers();
  634. for( int index = 0; index < observer_list.Count(); index++ ) {
  635. observer_list[ index ]->Custom( this, CUSTOM_EVENT_POWERUP_GRANTED, 0, obj );
  636. }
  637. }
  638. }
  639. void PowerUpGameObj::Think( void )
  640. {
  641. SimpleGameObj::Think();
  642. WWPROFILE( "PowerUp Think" );
  643. //
  644. // Make sure the powerup is playing its correct animation and sound
  645. //
  646. Update_State();
  647. //
  648. // If this powerup isn't currently granting itself to a player, then check
  649. // to see if it should!
  650. //
  651. // The server grants the prize, but allow the client to destroy
  652. // the powerup before being instructed to do so,
  653. // so that this doesn't lag
  654. //
  655. if ( CombatManager::I_Am_Server() && State != STATE_GRANTING ) {
  656. // Check my bounding box for collisions with Soldiers
  657. AABoxClass box = Peek_Model()->Get_Bounding_Box();
  658. SLNode<SmartGameObj> * smart_objnode;
  659. for (smart_objnode = GameObjManager::Get_Smart_Game_Obj_List()->Head(); smart_objnode; smart_objnode = smart_objnode->Next()) {
  660. SmartGameObj * obj = smart_objnode->Data();
  661. WWASSERT( obj != NULL );
  662. SoldierGameObj * soldier = obj->As_SoldierGameObj();
  663. if ( obj->As_VehicleGameObj() ) {
  664. soldier = obj->As_VehicleGameObj()->Get_Driver();
  665. }
  666. if ( soldier && soldier->Wants_Powerups() ) {
  667. PhysAABoxIntersectionTestClass test( box, DEFAULT_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL );
  668. bool result = obj->Peek_Physical_Object()->Intersection_Test(test);
  669. if ( result ) {
  670. Grant( soldier ); // Don't grant any more
  671. break;
  672. }
  673. }
  674. }
  675. }
  676. return ;
  677. }
  678. PowerUpGameObj * PowerUpGameObj::Create_Backpack( ArmedGameObj * provider )
  679. {
  680. WWASSERT( provider );
  681. // Debug_Say(( "Creating a Backpack\n" ));
  682. PowerUpGameObj * backpack = (PowerUpGameObj *)ObjectLibraryManager::Create_Object( "Backpack" );
  683. if ( backpack != NULL ) {
  684. Matrix3D tm(1);
  685. tm.Set_Translation( provider->Get_Bullseye_Position() );
  686. backpack->Set_Transform(tm);
  687. backpack->WeaponBag = new WeaponBagClass( NULL );
  688. backpack->WeaponBag->Move_Contents( provider->Get_Weapon_Bag() );
  689. backpack->Start_Observers();
  690. }
  691. return backpack;
  692. }
  693. //void PowerUpGameObj::Get_Extended_Information( StringClass & description )
  694. void PowerUpGameObj::Get_Description( StringClass & description )
  695. {
  696. //
  697. // Construct a diagnostic string
  698. //
  699. StringClass line;
  700. line.Format("ID: %d\n", Get_ID());
  701. description += line;
  702. line.Format("Name: %s\n", Get_Definition().Get_Name());
  703. description += line;
  704. Vector3 position;
  705. Get_Position(&position);
  706. line.Format("POS: %-5.2f, %-5.2f, %-5.2f\n", position.X, position.Y, position.Z);
  707. description += line;
  708. if (Get_Defense_Object() != NULL) {
  709. line.Format("HLTH: %-5.2f\n", Get_Defense_Object()->Get_Health());
  710. description += line;
  711. }
  712. line.Format("HIB: %d\n", Is_Hibernating());
  713. description += line;
  714. line.Format("ISC: %d\n", Get_Import_State_Count());
  715. description += line;
  716. }
  717. void PowerUpGameObj::Expire( void )
  718. {
  719. #define EXPIRE_TIME 2
  720. if ( State != STATE_EXPIRING ) {
  721. /*
  722. ** If the definition calls for it, add a material effect to the object
  723. */
  724. PhysClass * physobj = Peek_Physical_Object();
  725. if (physobj != NULL) {
  726. TransitionEffectClass * effect = CombatMaterialEffectManager::Get_Death_Effect();
  727. effect->Set_Transition_Time( EXPIRE_TIME );
  728. physobj->Add_Effect_To_Me(effect);
  729. REF_PTR_RELEASE(effect);
  730. }
  731. State = STATE_EXPIRING;
  732. StateEndTimer = EXPIRE_TIME;
  733. }
  734. }