smartgameobj.cpp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  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/smartgameobj.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 1/05/02 4:00p $*
  29. * *
  30. * $Revision:: 246 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. /*
  36. ** Includes
  37. */
  38. #include "smartgameobj.h"
  39. #include "gameobjmanager.h"
  40. #include "weapons.h"
  41. #include "bittype.h"
  42. #include "combat.h"
  43. #include "movephys.h"
  44. #include "damage.h"
  45. #include "wwpacket.h"
  46. #include "assets.h"
  47. #include "debug.h"
  48. #include "scripts.h"
  49. #include "pscene.h"
  50. #include "physcoltest.h"
  51. #include "chunkio.h"
  52. #include "weaponbag.h"
  53. #include "matinfo.h"
  54. #include "vehicle.h"
  55. #include "ccamera.h"
  56. #include "soldier.h"
  57. #include "parameter.h"
  58. #include "crandom.h"
  59. #include "playertype.h"
  60. #include "wwaudio.h"
  61. #include "logicallistener.h"
  62. #include "combatsound.h"
  63. #include "logicalsound.h"
  64. #include "wwprofile.h"
  65. #include "playerdata.h"
  66. #include "persistfactory.h"
  67. #include "persistfactory.h"
  68. #include "diaglog.h"
  69. #include "clientcontrol.h"
  70. #include "stealtheffect.h"
  71. #include "hud.h"
  72. const float STEALTH_FIRING_TIME = 5.0f; // amount of time an object stays un-stealthed after firing
  73. /*
  74. ** SmartGameObjDef
  75. */
  76. SmartGameObjDef::SmartGameObjDef( void ) :
  77. SightRange( 0 ),
  78. SightArc( DEG_TO_RADF( 0 ) ),
  79. ListenerScale( 1 )
  80. {
  81. EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_FLOAT, SightRange );
  82. EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_ANGLE, SightArc );
  83. EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_FLOAT, ListenerScale );
  84. EDITABLE_PARAM( SmartGameObjDef, ParameterClass::TYPE_BOOL, IsStealthUnit );
  85. }
  86. enum {
  87. XXX_CHUNKID_DEF_PHYSICALGAMEOBJ_PARENT = 909991656,
  88. CHUNKID_DEF_VARIABLES,
  89. CHUNKID_DEF_ARMEDGAMEOBJ_PARENT,
  90. MICROCHUNKID_DEF_SIGHT_RANGE = 9,
  91. MICROCHUNKID_DEF_SIGHT_ARC,
  92. MICROCHUNKID_DEF_LISTENER_SCALE = 17,
  93. LEGACY_MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME,
  94. MICROCHUNKID_DEF_IS_STEALTH_UNIT,
  95. };
  96. bool SmartGameObjDef::Save( ChunkSaveClass & csave )
  97. {
  98. csave.Begin_Chunk( CHUNKID_DEF_ARMEDGAMEOBJ_PARENT );
  99. ArmedGameObjDef::Save( csave );
  100. csave.End_Chunk();
  101. csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
  102. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SIGHT_RANGE, SightRange );
  103. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_SIGHT_ARC, SightArc );
  104. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_LISTENER_SCALE, ListenerScale );
  105. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_STEALTH_UNIT, IsStealthUnit );
  106. csave.End_Chunk();
  107. return true;
  108. }
  109. bool SmartGameObjDef::Load( ChunkLoadClass &cload )
  110. {
  111. while (cload.Open_Chunk()) {
  112. switch(cload.Cur_Chunk_ID()) {
  113. case CHUNKID_DEF_ARMEDGAMEOBJ_PARENT:
  114. ArmedGameObjDef::Load( cload );
  115. break;
  116. case CHUNKID_DEF_VARIABLES:
  117. while (cload.Open_Micro_Chunk()) {
  118. switch(cload.Cur_Micro_Chunk_ID()) {
  119. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SIGHT_RANGE, SightRange );
  120. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_SIGHT_ARC, SightArc );
  121. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_LISTENER_SCALE, ListenerScale );
  122. READ_MICRO_CHUNK_WWSTRING( cload, LEGACY_MICROCHUNKID_DEF_INFO_ICON_TEXTURE_FILENAME, InfoIconTextureFilename );
  123. READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_STEALTH_UNIT, IsStealthUnit );
  124. default:
  125. Debug_Say(( "Unrecognized SmartDef Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID() ));
  126. break;
  127. }
  128. cload.Close_Micro_Chunk();
  129. }
  130. break;
  131. default:
  132. Debug_Say(( "Unrecognized SmartDef chunkID\n" ));
  133. break;
  134. }
  135. cload.Close_Chunk();
  136. }
  137. return true;
  138. }
  139. float SmartGameObj::GlobalSightRangeScale = 1.0f;
  140. /*
  141. ** SmartGameObj
  142. */
  143. SmartGameObj::SmartGameObj( void ) :
  144. Action( this ),
  145. ControlOwner( SERVER_CONTROL_OWNER ),
  146. ControlEnabled( true ),
  147. IsEnemySeenEnabled( false ),
  148. MovingSoundTimer( 0 ),
  149. PlayerData( NULL ),
  150. StealthEnabled( false ),
  151. StealthPowerupTimer( 0.0f ),
  152. StealthFiringTimer( 0.0f ),
  153. StealthEffect( NULL )
  154. {
  155. GameObjManager::Add_Smart( this );
  156. Listener = WWAudioClass::Get_Instance()->Create_Logical_Listener();
  157. SET_REF_OWNER( Listener );
  158. Listener->Register_Callback( AudioCallbackClass::EVENT_LOGICAL_HEARD, this );
  159. }
  160. SmartGameObj::~SmartGameObj( void )
  161. {
  162. GameObjManager::Remove_Smart( this );
  163. Listener->Remove_From_Scene();
  164. Listener->Release_Ref();
  165. REF_PTR_RELEASE(StealthEffect);
  166. }
  167. /*
  168. **
  169. */
  170. void SmartGameObj::Init( const SmartGameObjDef & definition )
  171. {
  172. ArmedGameObj::Init( definition );
  173. Copy_Settings( definition );
  174. return ;
  175. }
  176. /*
  177. **
  178. */
  179. void SmartGameObj::Copy_Settings( const SmartGameObjDef & definition )
  180. {
  181. WWASSERT( Peek_Physical_Object() );
  182. MoveablePhysClass * moveable = Peek_Physical_Object()->As_MoveablePhysClass();
  183. if (moveable != NULL) {
  184. Peek_Physical_Object()->As_MoveablePhysClass()->Set_Controller( &Controller );
  185. }
  186. Register_Listener();
  187. if (definition.IsStealthUnit) {
  188. Enable_Stealth(true);
  189. }
  190. return ;
  191. }
  192. /*
  193. **
  194. */
  195. void SmartGameObj::Re_Init( const SmartGameObjDef & definition )
  196. {
  197. ArmedGameObj::Re_Init( definition );
  198. //
  199. // Remove the listener from the scene
  200. //
  201. if ( Listener != NULL ) {
  202. Listener->Remove_From_Scene();
  203. }
  204. //
  205. // Free the stealth effect as necessary
  206. //
  207. if (StealthEffect != NULL) {
  208. REF_PTR_RELEASE (StealthEffect);
  209. StealthEnabled = false;
  210. StealthPowerupTimer = 0.0F;
  211. StealthFiringTimer = 0.0F;
  212. }
  213. //
  214. // Copy any internal settings from the definition
  215. //
  216. Copy_Settings( definition );
  217. return ;
  218. }
  219. const SmartGameObjDef & SmartGameObj::Get_Definition( void ) const
  220. {
  221. return (const SmartGameObjDef &)BaseGameObj::Get_Definition();
  222. }
  223. /*
  224. ** SmartGameObj Save and Load
  225. */
  226. enum {
  227. OLD_CHUNKID_PHYSICALGAMEOBJ_PARENT = 910991113,
  228. CHUNKID_VARIABLES,
  229. CHUNKID_CONTROL,
  230. CHUNKID_CONTROLLER,
  231. CHUNKID_ACTION,
  232. XXXCHUNKID_WEAPONBAG,
  233. CHUNKID_ARMEDGAMEOBJ_PARENT,
  234. XXXCHUNKID_PLAYER_DATA,
  235. CHUNKID_STEALTH_EFFECT,
  236. MICROCHUNKID_CONTROL_ENABLED = 1,
  237. XXXMICROCHUNKID_WEAPON_TILT,
  238. XXXMICROCHUNKID_WEAPON_TURN,
  239. MICROCHUNKID_CONTROL_OWNER,
  240. XXX_MICROCHUNKID_IS_GHOST,
  241. MICROCHUNKID_IMPORT_STATE_COUNT,
  242. MICROCHUNKID_TINT_COLOR,
  243. MICROCHUNKID_CONTROLLER_PTR,
  244. MICROCHUNKID_IS_ENEMY_SEEN_ENABLED,
  245. XXXMICROCHUNKID_TARGETING_POS,
  246. MICROCHUNKID_MOVING_SOUND_TIMER,
  247. MICROCHUNKID_PLAYER_DATA,
  248. MICROCHUNKID_STEALTH_ENABLED,
  249. MICROCHUNKID_STEALTH_POWERUP_TIMER,
  250. MICROCHUNKID_STEALTH_FIRING_TIMER,
  251. };
  252. bool SmartGameObj::Save( ChunkSaveClass & csave )
  253. {
  254. csave.Begin_Chunk( CHUNKID_ARMEDGAMEOBJ_PARENT );
  255. ArmedGameObj::Save( csave );
  256. csave.End_Chunk();
  257. csave.Begin_Chunk( CHUNKID_VARIABLES );
  258. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROL_ENABLED, ControlEnabled );
  259. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROL_OWNER, ControlOwner );
  260. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_IS_ENEMY_SEEN_ENABLED, IsEnemySeenEnabled );
  261. void * ptr = &Controller;
  262. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_CONTROLLER_PTR, ptr );
  263. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_MOVING_SOUND_TIMER, MovingSoundTimer );
  264. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PLAYER_DATA, PlayerData );
  265. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_ENABLED, StealthEnabled );
  266. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_POWERUP_TIMER, StealthPowerupTimer );
  267. WRITE_MICRO_CHUNK( csave, MICROCHUNKID_STEALTH_FIRING_TIMER, StealthFiringTimer );
  268. csave.End_Chunk();
  269. csave.Begin_Chunk( CHUNKID_CONTROL );
  270. Control.Save( csave );
  271. csave.End_Chunk();
  272. csave.Begin_Chunk( CHUNKID_CONTROLLER );
  273. Controller.Save( csave );
  274. csave.End_Chunk();
  275. csave.Begin_Chunk( CHUNKID_ACTION );
  276. Action.Save( csave );
  277. csave.End_Chunk();
  278. if (StealthEffect != NULL) {
  279. csave.Begin_Chunk(CHUNKID_STEALTH_EFFECT);
  280. StealthEffect->Save(csave);
  281. csave.End_Chunk();
  282. }
  283. // Don't need to save Listener
  284. return true;
  285. }
  286. bool SmartGameObj::Load( ChunkLoadClass &cload )
  287. {
  288. WWASSERT( PlayerData == NULL );
  289. int new_control_owner = 0;
  290. while (cload.Open_Chunk()) {
  291. switch(cload.Cur_Chunk_ID()) {
  292. case OLD_CHUNKID_PHYSICALGAMEOBJ_PARENT:
  293. Debug_Say(( "Loading old SmartGameObj format\n" ));
  294. PhysicalGameObj::Load( cload );
  295. break;
  296. case CHUNKID_ARMEDGAMEOBJ_PARENT:
  297. ArmedGameObj::Load( cload );
  298. break;
  299. case CHUNKID_VARIABLES:
  300. void * old_controller_ptr;
  301. old_controller_ptr = NULL;
  302. while (cload.Open_Micro_Chunk()) {
  303. switch(cload.Cur_Micro_Chunk_ID()) {
  304. READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROL_ENABLED, ControlEnabled );
  305. READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROL_OWNER, new_control_owner );
  306. READ_MICRO_CHUNK( cload, MICROCHUNKID_IS_ENEMY_SEEN_ENABLED, IsEnemySeenEnabled );
  307. READ_MICRO_CHUNK( cload, MICROCHUNKID_CONTROLLER_PTR, old_controller_ptr );
  308. READ_MICRO_CHUNK( cload, MICROCHUNKID_MOVING_SOUND_TIMER, MovingSoundTimer );
  309. READ_MICRO_CHUNK( cload, MICROCHUNKID_PLAYER_DATA, PlayerData );
  310. READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_ENABLED, StealthEnabled );
  311. READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_POWERUP_TIMER, StealthPowerupTimer );
  312. READ_MICRO_CHUNK( cload, MICROCHUNKID_STEALTH_FIRING_TIMER, StealthFiringTimer );
  313. default:
  314. Debug_Say(( "Unrecognized SmartGameObj Variable chunkID\n" ));
  315. break;
  316. }
  317. cload.Close_Micro_Chunk();
  318. }
  319. if ( old_controller_ptr ) {
  320. SaveLoadSystemClass::Register_Pointer(old_controller_ptr, &Controller);
  321. }
  322. break;
  323. case CHUNKID_CONTROL:
  324. Control.Load( cload );
  325. break;
  326. case CHUNKID_CONTROLLER:
  327. Controller.Load( cload );
  328. break;
  329. case CHUNKID_ACTION:
  330. Action.Load( cload );
  331. break;
  332. case CHUNKID_STEALTH_EFFECT:
  333. Alloc_Stealth_Effect();
  334. StealthEffect->Load(cload);
  335. break;
  336. default:
  337. Debug_Say(( "Unrecognized SoldierGameObj chunkID\n" ));
  338. break;
  339. }
  340. cload.Close_Chunk();
  341. }
  342. if ( PlayerData != NULL ) {
  343. REQUEST_POINTER_REMAP ((void **)&PlayerData);
  344. }
  345. Set_Control_Owner( new_control_owner ); // Be sure soldier virtual function calls
  346. SaveLoadSystemClass::Register_Post_Load_Callback(this);
  347. return true;
  348. }
  349. void SmartGameObj::On_Post_Load(void)
  350. {
  351. ArmedGameObj::On_Post_Load();
  352. if ( StealthEffect != NULL ) {
  353. Peek_Physical_Object()->Add_Effect_To_Me(StealthEffect);
  354. }
  355. Register_Listener();
  356. if ( PlayerData ) {
  357. Set_Player_Data( PlayerData ); // make sure we re map each other
  358. }
  359. }
  360. void SmartGameObj::Set_Player_Data( PlayerDataClass * player_data )
  361. {
  362. if ( PlayerData ) {
  363. PlayerData->Set_GameObj( NULL );
  364. }
  365. PlayerData = player_data;
  366. if ( PlayerData ) {
  367. PlayerData->Set_GameObj( this );
  368. }
  369. }
  370. //-----------------------------------------------------------------------------
  371. void SmartGameObj::Import_Frequent(BitStreamClass & packet)
  372. {
  373. WWASSERT(CombatManager::I_Am_Only_Client());
  374. /*TSS091301
  375. //
  376. // Update the player data structure from the server
  377. //
  378. if (PlayerData != NULL) {
  379. PlayerData->Import_Frequent( packet );
  380. }
  381. */
  382. //
  383. // Import all data from the base classes
  384. //
  385. ArmedGameObj::Import_Frequent(packet);
  386. //
  387. // Don't import the controller if the player is controlling
  388. // this object
  389. //
  390. if (Is_Controlled_By_Me()) {
  391. packet.Flush();
  392. } else {
  393. Import_Control_Sc(packet);
  394. }
  395. WWASSERT(packet.Is_Flushed());
  396. return ;
  397. }
  398. //-----------------------------------------------------------------------------
  399. void SmartGameObj::Export_Frequent(BitStreamClass & packet)
  400. {
  401. /*TSS091301
  402. //
  403. // Send the player data to the client
  404. //
  405. if (PlayerData != NULL) {
  406. PlayerData->Export_Frequent( packet );
  407. }
  408. */
  409. //
  410. // Send data from the base class to the client
  411. //
  412. ArmedGameObj::Export_Frequent(packet);
  413. Export_Control_Sc(packet);
  414. return ;
  415. }
  416. //-----------------------------------------------------------------------------
  417. void SmartGameObj::Export_State_Cs(BitStreamClass & packet)
  418. {
  419. ArmedGameObj::Export_State_Cs(packet);
  420. }
  421. //-----------------------------------------------------------------------------
  422. void SmartGameObj::Import_State_Cs(BitStreamClass & packet)
  423. {
  424. ArmedGameObj::Import_State_Cs(packet);
  425. }
  426. //-----------------------------------------------------------------------------
  427. void SmartGameObj::Generate_Control(void)
  428. {
  429. if (CombatManager::I_Am_Server() &&
  430. (ControlOwner == SERVER_CONTROL_OWNER || !Is_Human_Controlled())) {
  431. Action.Act();
  432. }
  433. if (CombatManager::I_Am_Client() &&
  434. ControlOwner == CombatManager::Get_My_Id()) {
  435. Action.Act();
  436. //
  437. // Notify server
  438. //
  439. /*
  440. if (PClientControl != NULL && !Is_Delete_Pending()) {
  441. PClientControl->Set_Update_Flag(Get_ID());
  442. }
  443. */
  444. //TSS092101
  445. if (PClientControl != NULL) {
  446. if (Is_Delete_Pending()) {
  447. PClientControl->Set_Update_Flag(-1);
  448. } else {
  449. PClientControl->Set_Update_Flag(Get_ID());
  450. }
  451. }
  452. }
  453. }
  454. //-----------------------------------------------------------------------------
  455. bool SmartGameObj::Is_Control_Data_Dirty(cPacket & packet)
  456. {
  457. //
  458. // future optimization
  459. //
  460. return true;
  461. }
  462. bool SmartGameObj::Has_Player(void)
  463. {
  464. // There is a cPlayer object for this smart object
  465. return (ControlOwner != SERVER_CONTROL_OWNER);
  466. }
  467. bool SmartGameObj::Is_Human_Controlled(void)
  468. {
  469. // There is a human cPlayer object for this smart object
  470. //return ControlOwner >= 0 && !CombatManager::Player_Is_Afk(ControlOwner);
  471. return ControlOwner >= 0;
  472. }
  473. bool SmartGameObj::Is_Controlled_By_Me(void)
  474. {
  475. // WWASSERT(CombatManager::I_Am_Client());
  476. if (!CombatManager::I_Am_Client()) {
  477. return false;
  478. }
  479. SmartGameObj *game_obj = this;
  480. //
  481. // If this is a vehicle, then passthru to the driver
  482. //
  483. VehicleGameObj *vehicle = As_VehicleGameObj();
  484. if (vehicle != NULL) {
  485. SoldierGameObj *driver = vehicle->Get_Driver();
  486. if (driver != NULL) {
  487. game_obj = driver;
  488. }
  489. }
  490. return game_obj->Is_Human_Controlled() && (game_obj->ControlOwner == CombatManager::Get_My_Id());
  491. }
  492. void SmartGameObj::Apply_Control( void )
  493. {
  494. bool switched = false;
  495. const char * change_type = NULL;
  496. if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_NEXT ) ) {
  497. if ( COMBAT_CAMERA != NULL ) {
  498. COMBAT_CAMERA->Reset_First_Person_Offset_Tweak();
  499. }
  500. WeaponBag->Select_Next();
  501. switched = true;
  502. change_type = "Next";
  503. }
  504. if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_PREV ) ) {
  505. if ( COMBAT_CAMERA != NULL ) {
  506. COMBAT_CAMERA->Reset_First_Person_Offset_Tweak();
  507. }
  508. WeaponBag->Select_Prev();
  509. switched = true;
  510. change_type = "Prev";
  511. }
  512. // -1 is no weapon
  513. for ( int weapon_key_num = -1; weapon_key_num <= 9; weapon_key_num++ ) {
  514. if ( Control.Get_Boolean( (ControlClass::BooleanControl)((int)ControlClass::BOOLEAN_SELECT_WEAPON_0 + weapon_key_num) ) ) {
  515. if ( this == COMBAT_STAR ) {
  516. HUDClass::Force_Weapon_Chart_Display();
  517. }
  518. if ( COMBAT_CAMERA != NULL ) {
  519. COMBAT_CAMERA->Reset_First_Person_Offset_Tweak();
  520. }
  521. WeaponBag->Select_Key_Number( weapon_key_num );
  522. switched = true;
  523. change_type = "Key";
  524. }
  525. }
  526. if ( this == COMBAT_STAR && change_type != NULL ) {
  527. Vector3 pos;
  528. Get_Position( &pos );
  529. const char * weapon_name = "";
  530. int ammo = 0;
  531. if ( Get_Weapon() ) {
  532. weapon_name = Get_Weapon()->Get_Definition()->Get_Name();
  533. ammo = Get_Weapon()->Get_Total_Rounds();
  534. }
  535. DIAG_LOG(( "WCHN", "%1.2f; %1.2f; %1.2f; %s; %d; %s", pos.X, pos.Y, pos.Z, weapon_name, ammo, change_type ));
  536. }
  537. // This is kinda ugly....
  538. SoldierGameObj * p_soldier = As_SoldierGameObj();
  539. if (switched && p_soldier != NULL && p_soldier->Is_Sniping()) {
  540. // If sniping, and you cannot snipe for the current weapon, exit sniping
  541. if ( Get_Weapon() == NULL || !Get_Weapon()->Get_Can_Snipe() ) {
  542. Debug_Say(( "Force Sniper exit\n" ));
  543. p_soldier->Get_Human_State()->Toggle_State_Flag( HumanStateClass::SNIPING_FLAG );
  544. }
  545. }
  546. Controller.Reset();
  547. Controller.Set_Turn_Left( Control.Get_Analog( ControlClass::ANALOG_TURN_LEFT ) );
  548. Controller.Set_Move_Up( Control.Get_Analog( ControlClass::ANALOG_MOVE_UP ) );
  549. Controller.Set_Move_Forward(Control.Get_Analog( ControlClass::ANALOG_MOVE_FORWARD ) );
  550. Controller.Set_Move_Left( Control.Get_Analog( ControlClass::ANALOG_MOVE_LEFT ) );
  551. if ( ControlEnabled ) {
  552. if ( ( Get_Weapon() != NULL ) && ( !Is_Delete_Pending() ) ) {
  553. Get_Weapon()->Set_Primary_Triggered( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY ) );
  554. Get_Weapon()->Set_Secondary_Triggered( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY ) );
  555. if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_USE ) ) {
  556. Get_Weapon()->Next_C4_Detonation_Mode();
  557. }
  558. if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_RELOAD ) ) {
  559. Get_Weapon()->Force_Reload();
  560. }
  561. // If we fire a weapon, we de-cloak for a certain amount of time
  562. if ( Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY ) ||
  563. Control.Get_Boolean( ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY ))
  564. {
  565. StealthFiringTimer = STEALTH_FIRING_TIME;
  566. }
  567. }
  568. } else {
  569. Get_Weapon()->Set_Primary_Triggered( false );
  570. Get_Weapon()->Set_Secondary_Triggered( false );
  571. }
  572. }
  573. void SmartGameObj::Think()
  574. {
  575. {
  576. WWPROFILE( "Smart Think" );
  577. // React to the controls
  578. {
  579. WWPROFILE("Controls");
  580. if ( ControlEnabled ) {
  581. Apply_Control();
  582. } else {
  583. Controller.Reset();
  584. if ( Get_Weapon() != NULL ) {
  585. Get_Weapon()->Set_Primary_Triggered( false );
  586. Get_Weapon()->Set_Secondary_Triggered( false );
  587. }
  588. }
  589. }
  590. MovingSoundTimer -= TimeManager::Get_Frame_Seconds();
  591. if ( MovingSoundTimer < 0 ) {
  592. WWPROFILE("See");
  593. // MovingSoundTimer += FreeRandom.Get_Float( 1, 2 ); // sound every 1-2 seconds
  594. MovingSoundTimer += FreeRandom.Get_Float( 0.5f, 1 ); // sound every 0.5 - 1 seconds
  595. // if I have sight, see who I see
  596. if ( Is_Enemy_Seen_Enabled() ) {
  597. // for all physicalgameobjs
  598. SLNode<BaseGameObj> *objnode;
  599. for ( objnode = GameObjManager::Get_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
  600. SmartGameObj *obj = objnode->Data()->As_SmartGameObj();
  601. if ( obj ) {
  602. if ( obj == this ) continue;
  603. if ( !Is_Enemy( obj ) ) continue;
  604. if ( !obj->Is_Visible() ) continue;
  605. // Don't see hidden models
  606. if ( obj != COMBAT_STAR && obj->Peek_Model() && obj->Peek_Model()->Is_Hidden() ) {
  607. continue;
  608. }
  609. if ( Is_Obj_Visible( obj ) ) {
  610. const GameObjObserverList & observer_list = Get_Observers();
  611. for( int index = 0; index < observer_list.Count(); index++ ) {
  612. observer_list[ index ]->Enemy_Seen( this, obj );
  613. }
  614. }
  615. }
  616. }
  617. }
  618. }
  619. // Stealth logic
  620. if (StealthPowerupTimer > 0.0f) {
  621. StealthPowerupTimer -= TimeManager::Get_Frame_Seconds();
  622. }
  623. if (StealthFiringTimer > 0.0f) {
  624. StealthFiringTimer -= TimeManager::Get_Frame_Seconds();
  625. }
  626. if ( (StealthEffect != NULL ) && COMBAT_STAR) {
  627. StealthEffect->Set_Friendly( Is_Teammate( COMBAT_STAR ) );
  628. }
  629. if (((StealthPowerupTimer > 0.0f) || (StealthEnabled)) && (StealthFiringTimer <= 0.0f)) {
  630. WWPROFILE("Stealh");
  631. Alloc_Stealth_Effect();
  632. WWASSERT(StealthEffect != NULL);
  633. Peek_Physical_Object()->Add_Effect_To_Me(StealthEffect);
  634. StealthEffect->Enable_Stealth(true);
  635. const float STEALTH_BROKEN_FRACTION = 0.25f;
  636. DefenseObjectClass * defobj = Get_Defense_Object();
  637. if (defobj != NULL) {
  638. StealthEffect->Set_Broken((defobj->Get_Health() / defobj->Get_Health_Max()) < STEALTH_BROKEN_FRACTION);
  639. }
  640. } else {
  641. if (StealthEffect != NULL) {
  642. StealthEffect->Enable_Stealth(false);
  643. }
  644. }
  645. }
  646. {
  647. WWPROFILE("Embedded Armed think in smart think");
  648. ArmedGameObj::Think();
  649. }
  650. }
  651. void SmartGameObj::Post_Think( void )
  652. {
  653. ArmedGameObj::Post_Think();
  654. WWPROFILE( "Smart PostThink" );
  655. if ( Is_Delete_Pending() ) { // don't update if destroying... (so we don't create a new laser!)
  656. return;
  657. }
  658. // Reset the one time booleans
  659. Control.Clear_One_Time_Boolean();
  660. }
  661. void SmartGameObj::Apply_Damage(const OffenseObjectClass & damager, float scale, int alternate_skin)
  662. {
  663. float damage = damager.Get_Damage() * scale;
  664. if ((damage > 0) && (StealthEffect != NULL)) {
  665. StealthEffect->Damage_Occured();
  666. }
  667. PhysicalGameObj::Apply_Damage(damager,scale,alternate_skin);
  668. }
  669. bool SmartGameObj::Is_Obj_Visible( PhysicalGameObj *obj )
  670. {
  671. Vector3 diff = obj->Get_Bullseye_Position();
  672. Matrix3D look_tm = Get_Look_Transform();
  673. Matrix3D::Inverse_Transform_Vector( look_tm, diff, &diff );
  674. float dist = diff.Length();
  675. if ( dist < Get_Definition().SightRange * GlobalSightRangeScale) {
  676. // find view angle
  677. diff.Z = 0;
  678. diff.Normalize();
  679. float angle = WWMath::Fast_Acos( diff.X );
  680. if ( WWMath::Fabs( angle ) < Get_Definition().SightArc/2 ) {
  681. // if it passes this test, do a raycast to see if we see it.
  682. Vector3 me = look_tm.Get_Translation();
  683. Vector3 him = obj->Get_Bullseye_Position();
  684. Peek_Physical_Object()->Inc_Ignore_Counter();
  685. CastResultStruct res;
  686. LineSegClass ray( me, him );
  687. PhysRayCollisionTestClass raytest(ray, &res, BULLET_COLLISION_GROUP);
  688. { WWPROFILE( "Cast Ray" );
  689. PhysicsSceneClass::Get_Instance()->Cast_Ray(raytest);
  690. }
  691. Peek_Physical_Object()->Dec_Ignore_Counter();
  692. #if 0
  693. if (raytest.Result->StartBad) {
  694. // Debug_Say(( "Is_Vis Start Bad\n" ));
  695. } else if ( raytest.CollidedPhysObj == obj->Peek_Physical_Object() ) {
  696. return true;
  697. }
  698. #else
  699. return ((raytest.Result->Fraction == 1.0f ) ||
  700. ( raytest.CollidedPhysObj == obj->Peek_Physical_Object() ));
  701. #endif
  702. }
  703. }
  704. return false;
  705. }
  706. /*
  707. **
  708. */
  709. void SmartGameObj::On_Logical_Heard (LogicalListenerClass *listener, LogicalSoundClass *sound_obj)
  710. {
  711. CombatSound sound;
  712. sound.Type = (CombatSoundType)sound_obj->Get_Type_Mask();
  713. sound.Position = sound_obj->Get_Position();
  714. //
  715. // Dig the sound creator out from the logical sound object
  716. //
  717. RefCountedGameObjReference *creator = (RefCountedGameObjReference *)sound_obj->Peek_User_Obj();
  718. if (creator != NULL) {
  719. sound.Creator = creator->Get_Ptr ();
  720. } else {
  721. sound.Creator = NULL;
  722. }
  723. // Notify observers
  724. if (CombatManager::Are_Observers_Active()) {
  725. const GameObjObserverList & observer_list = Get_Observers();
  726. for( int index = 0; index < observer_list.Count(); index++ ) {
  727. observer_list[ index ]->Sound_Heard( this, sound );
  728. }
  729. }
  730. }
  731. void SmartGameObj::Register_Listener(void)
  732. {
  733. if (Listener != NULL) {
  734. const SmartGameObjDef& definition = Get_Definition();
  735. Listener->Set_Scale(definition.ListenerScale);
  736. Listener->Set_DropOff_Radius( 0.001f );
  737. Listener->Attach_To_Object(Peek_Model());
  738. Listener->Add_To_Scene();
  739. }
  740. }
  741. void SmartGameObj::Begin_Hibernation( void )
  742. {
  743. ArmedGameObj::Begin_Hibernation();
  744. // Reset our physics controller
  745. Controller.Reset();
  746. //
  747. // Stop listening for sounds
  748. //
  749. if (Listener != NULL) {
  750. Listener->Remove_From_Scene ();
  751. }
  752. //
  753. // Let the action prepare itself for hibernation
  754. //
  755. Action.Begin_Hibernation ();
  756. return ;
  757. }
  758. void SmartGameObj::End_Hibernation( void )
  759. {
  760. ArmedGameObj::End_Hibernation();
  761. //
  762. // Make sure we are listening for logical sounds
  763. //
  764. if (Listener != NULL) {
  765. Listener->Add_To_Scene ();
  766. }
  767. //
  768. // Let the action prepare itself for activation
  769. //
  770. Action.End_Hibernation ();
  771. return ;
  772. }
  773. //------------------------------------------------------------------------------------
  774. void SmartGameObj::Get_Information( StringClass & string )
  775. {
  776. ArmedGameObj::Get_Information( string );
  777. StringClass temp;
  778. temp.Format( "Observer:%d\n", Action.Get_Parameters().ObserverID );
  779. string += temp;
  780. temp.Format( "Priority:%d\n", Action.Get_Parameters().Priority );
  781. string += temp;
  782. if ( Action.Get_Parameters().WaypathID ) {
  783. temp.Format( "Waypath:%d\n", Action.Get_Parameters().WaypathID );
  784. string += temp;
  785. }
  786. }
  787. /*
  788. **
  789. */
  790. void SmartGameObj::Export_Creation( BitStreamClass &packet )
  791. {
  792. ArmedGameObj::Export_Creation( packet );
  793. //
  794. // Send the control owner to the client
  795. //
  796. int control_owner = Get_Control_Owner();
  797. packet.Add( control_owner );
  798. return ;
  799. }
  800. /*
  801. **
  802. */
  803. void SmartGameObj::Import_Creation( BitStreamClass &packet )
  804. {
  805. ArmedGameObj::Import_Creation( packet );
  806. //
  807. // Get the control owner from the server
  808. //
  809. int control_owner = 0;
  810. packet.Get( control_owner );
  811. Set_Control_Owner( control_owner );
  812. //
  813. // Hookup the control input for this player
  814. //
  815. if (control_owner == CombatManager::Get_My_Id() ) {
  816. ActionParamsStruct parameters;
  817. Get_Action()->Follow_Input( parameters );
  818. CombatManager::Set_The_Star( As_SoldierGameObj() );
  819. }
  820. return ;
  821. }
  822. void SmartGameObj::Enable_Stealth(bool onoff)
  823. {
  824. StealthEnabled = onoff;
  825. if (StealthEnabled) {
  826. Alloc_Stealth_Effect ();
  827. }
  828. return ;
  829. }
  830. void SmartGameObj::Toggle_Stealth(void)
  831. {
  832. StealthEnabled = !StealthEnabled;
  833. }
  834. bool SmartGameObj::Is_Stealth_Enabled(void)
  835. {
  836. return StealthEnabled;
  837. }
  838. bool SmartGameObj::Is_Stealthed(void) const
  839. {
  840. if (StealthEffect != NULL) {
  841. return StealthEffect->Is_Stealthed();
  842. } else {
  843. return false;
  844. }
  845. }
  846. void SmartGameObj::Grant_Stealth_Powerup(float seconds)
  847. {
  848. StealthPowerupTimer = seconds;
  849. }
  850. float SmartGameObj::Remaining_Stealth_Powerup_Time(void)
  851. {
  852. return StealthPowerupTimer;
  853. }
  854. StealthEffectClass * SmartGameObj::Peek_Stealth_Effect(void)
  855. {
  856. return StealthEffect;
  857. }
  858. void SmartGameObj::Alloc_Stealth_Effect(void)
  859. {
  860. if (StealthEffect == NULL) {
  861. StealthEffect = NEW_REF(StealthEffectClass,());
  862. StealthEffect->Set_Fade_Distance( Get_Stealth_Fade_Distance() );
  863. }
  864. }
  865. void SmartGameObj::Reset_Controller( void )
  866. {
  867. Controller.Reset();
  868. }
  869. /*
  870. CombatManager::Send_Control_Packet(this);
  871. CombatManager::Send_State_Packet(this);
  872. */