basebuildingbase.c 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. //BASE BUILDING BASE
  2. class BaseBuildingBase extends ItemBase
  3. {
  4. const string ANIMATION_DEPLOYED = "Deployed";
  5. float m_ConstructionKitHealth; //stored health value for used construction kit
  6. ref Construction m_Construction;
  7. bool m_HasBase;
  8. //variables for synchronization of base building parts (2x31 is the current limit)
  9. int m_SyncParts01; //synchronization for already built parts (31 parts)
  10. int m_SyncParts02; //synchronization for already built parts (+31 parts)
  11. int m_SyncParts03; //synchronization for already built parts (+31 parts)
  12. int m_InteractedPartId; //construction part id that an action was performed on
  13. int m_PerformedActionId; //action id that was performed on a construction part
  14. //Sounds
  15. //build
  16. const string SOUND_BUILD_WOOD_LOG = "putDown_WoodLog_SoundSet";
  17. const string SOUND_BUILD_WOOD_PLANK = "putDown_WoodPlank_SoundSet";
  18. const string SOUND_BUILD_WOOD_STAIRS = "putDown_WoodStairs_SoundSet";
  19. const string SOUND_BUILD_METAL = "putDown_MetalPlank_SoundSet";
  20. const string SOUND_BUILD_WIRE = "putDown_BarbedWire_SoundSet";
  21. //dismantle
  22. const string SOUND_DISMANTLE_WOOD_LOG = "Crash_WoodPlank_SoundSet";
  23. const string SOUND_DISMANTLE_WOOD_PLANK = "Crash_WoodPlank_SoundSet";
  24. const string SOUND_DISMANTLE_WOOD_STAIRS = "Crash_WoodPlank_SoundSet";
  25. const string SOUND_DISMANTLE_METAL = "Crash_MetalPlank_SoundSet";
  26. const string SOUND_DISMANTLE_WIRE = "putDown_BarbedWire_SoundSet";
  27. protected EffectSound m_Sound;
  28. ref map<string, ref AreaDamageManager> m_DamageTriggers;
  29. ref array<string> m_HybridAttachments;
  30. ref array<string> m_Mountables;
  31. // Constructor
  32. void BaseBuildingBase()
  33. {
  34. m_DamageTriggers = new ref map<string, ref AreaDamageManager>;
  35. //synchronized variables
  36. RegisterNetSyncVariableInt( "m_SyncParts01" );
  37. RegisterNetSyncVariableInt( "m_SyncParts02" );
  38. RegisterNetSyncVariableInt( "m_SyncParts03" );
  39. RegisterNetSyncVariableInt( "m_InteractedPartId" );
  40. RegisterNetSyncVariableInt( "m_PerformedActionId" );
  41. RegisterNetSyncVariableBool( "m_HasBase" );
  42. //Construction init
  43. ConstructionInit();
  44. if (ConfigIsExisting("hybridAttachments"))
  45. {
  46. m_HybridAttachments = new array<string>;
  47. ConfigGetTextArray("hybridAttachments", m_HybridAttachments);
  48. }
  49. if (ConfigIsExisting("mountables"))
  50. {
  51. m_Mountables = new array<string>;
  52. ConfigGetTextArray("mountables", m_Mountables);
  53. }
  54. ProcessInvulnerabilityCheck(GetInvulnerabilityTypeString());
  55. }
  56. override void EEDelete(EntityAI parent)
  57. {
  58. super.EEDelete(parent);
  59. foreach (AreaDamageManager areaDamage : m_DamageTriggers)
  60. {
  61. areaDamage.Destroy();
  62. }
  63. }
  64. override string GetInvulnerabilityTypeString()
  65. {
  66. return "disableBaseDamage";
  67. }
  68. override bool CanObstruct()
  69. {
  70. return true;
  71. }
  72. override int GetHideIconMask()
  73. {
  74. return EInventoryIconVisibility.HIDE_VICINITY;
  75. }
  76. // --- SYNCHRONIZATION
  77. void SynchronizeBaseState()
  78. {
  79. if ( GetGame().IsServer() )
  80. {
  81. SetSynchDirty();
  82. }
  83. }
  84. override void OnVariablesSynchronized()
  85. {
  86. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " OnVariablesSynchronized");
  87. super.OnVariablesSynchronized();
  88. GetGame().GetCallQueue( CALL_CATEGORY_GAMEPLAY ).CallLater( OnSynchronizedClient, 100, false );
  89. }
  90. protected void OnSynchronizedClient()
  91. {
  92. //update parts
  93. SetPartsFromSyncData();
  94. //update action on part
  95. SetActionFromSyncData();
  96. //update visuals (client)
  97. UpdateVisuals();
  98. }
  99. //parts synchronization
  100. void RegisterPartForSync( int part_id )
  101. {
  102. //part_id must starts from index = 1
  103. int offset;
  104. int mask;
  105. if ( part_id >= 1 && part_id <= 31 ) //<1,31> (31 parts)
  106. {
  107. offset = part_id - 1;
  108. mask = 1 << offset;
  109. m_SyncParts01 = m_SyncParts01 | mask;
  110. }
  111. else if ( part_id >= 32 && part_id <= 62 ) //<32,62> (31 parts)
  112. {
  113. offset = ( part_id % 32 );
  114. mask = 1 << offset;
  115. m_SyncParts02 = m_SyncParts02 | mask;
  116. }
  117. else if ( part_id >= 63 && part_id <= 93 ) //<63,93> (31 parts)
  118. {
  119. offset = ( part_id % 63 );
  120. mask = 1 << offset;
  121. m_SyncParts03 = m_SyncParts03 | mask;
  122. }
  123. }
  124. void UnregisterPartForSync( int part_id )
  125. {
  126. //part_id must starts from index = 1
  127. int offset;
  128. int mask;
  129. if ( part_id >= 1 && part_id <= 31 ) //<1,31> (31 parts)
  130. {
  131. offset = part_id - 1;
  132. mask = 1 << offset;
  133. m_SyncParts01 = m_SyncParts01 & ~mask;
  134. }
  135. else if ( part_id >= 32 && part_id <= 62 ) //<32,62> (31 parts)
  136. {
  137. offset = ( part_id % 32 );
  138. mask = 1 << offset;
  139. m_SyncParts02 = m_SyncParts02 & ~mask;
  140. }
  141. else if ( part_id >= 63 && part_id <= 93 ) //<63,93> (31 parts)
  142. {
  143. offset = ( part_id % 63 );
  144. mask = 1 << offset;
  145. m_SyncParts03 = m_SyncParts03 & ~mask;
  146. }
  147. }
  148. bool IsPartBuildInSyncData( int part_id )
  149. {
  150. //part_id must starts from index = 1
  151. int offset;
  152. int mask;
  153. if ( part_id >= 1 && part_id <= 31 ) //<1,31> (31 parts)
  154. {
  155. offset = part_id - 1;
  156. mask = 1 << offset;
  157. if ( ( m_SyncParts01 & mask ) > 0 )
  158. {
  159. return true;
  160. }
  161. }
  162. else if ( part_id >= 32 && part_id <= 62 ) //<32,62> (31 parts)
  163. {
  164. offset = ( part_id % 32 );
  165. mask = 1 << offset;
  166. if ( ( m_SyncParts02 & mask ) > 0 )
  167. {
  168. return true;
  169. }
  170. }
  171. else if ( part_id >= 63 && part_id <= 93 ) //<63,93> (31 parts)
  172. {
  173. offset = ( part_id % 63 );
  174. mask = 1 << offset;
  175. if ( ( m_SyncParts03 & mask ) > 0 )
  176. {
  177. return true;
  178. }
  179. }
  180. return false;
  181. }
  182. protected void RegisterActionForSync( int part_id, int action_id )
  183. {
  184. m_InteractedPartId = part_id;
  185. m_PerformedActionId = action_id;
  186. }
  187. protected void ResetActionSyncData()
  188. {
  189. //reset data
  190. m_InteractedPartId = -1;
  191. m_PerformedActionId = -1;
  192. }
  193. protected void SetActionFromSyncData()
  194. {
  195. if ( m_InteractedPartId > -1 && m_PerformedActionId > -1 )
  196. {
  197. ConstructionPart constrution_part = GetConstructionPartById( m_InteractedPartId );
  198. int build_action_id = m_PerformedActionId;
  199. switch( build_action_id )
  200. {
  201. case AT_BUILD_PART : OnPartBuiltClient( constrution_part.GetPartName(), build_action_id ); break;
  202. case AT_DISMANTLE_PART : OnPartDismantledClient( constrution_part.GetPartName(), build_action_id ); break;
  203. case AT_DESTROY_PART : OnPartDestroyedClient( constrution_part.GetPartName(), build_action_id ); break;
  204. }
  205. }
  206. }
  207. //------
  208. void SetPartFromSyncData( ConstructionPart part )
  209. {
  210. string key = part.m_PartName;
  211. bool is_base = part.IsBase();
  212. bool is_part_built_sync = IsPartBuildInSyncData( part.GetId() );
  213. bsbDebugSpam("[bsb] " + GetDebugName(this) + " SetPartFromSyncData try to sync: built=" + is_part_built_sync + " key=" + key + " part=" + part.GetPartName() + " part_built=" + part.IsBuilt());
  214. if ( is_part_built_sync )
  215. {
  216. if ( !part.IsBuilt() )
  217. {
  218. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " SetPartsFromSyncData +++ " + key);
  219. GetConstruction().AddToConstructedParts( key );
  220. GetConstruction().ShowConstructionPartPhysics(part.GetPartName());
  221. if (is_base)
  222. {
  223. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " RM");
  224. RemoveProxyPhysics( ANIMATION_DEPLOYED );
  225. }
  226. }
  227. }
  228. else
  229. {
  230. if ( part.IsBuilt() )
  231. {
  232. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " SetPartsFromSyncData --- " + key);
  233. GetConstruction().RemoveFromConstructedParts( key );
  234. GetConstruction().HideConstructionPartPhysics(part.GetPartName());
  235. if (is_base)
  236. {
  237. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " ADD");
  238. AddProxyPhysics( ANIMATION_DEPLOYED );
  239. }
  240. }
  241. }
  242. //check slot lock for material attachments
  243. GetConstruction().SetLockOnAttachedMaterials( part.GetPartName(), part.IsBuilt() ); //failsafe for corrupted sync/storage data
  244. }
  245. //set construction parts based on synchronized data
  246. void SetPartsFromSyncData()
  247. {
  248. Construction construction = GetConstruction();
  249. map<string, ref ConstructionPart> construction_parts = construction.GetConstructionParts();
  250. for ( int i = 0; i < construction_parts.Count(); ++i )
  251. {
  252. string key = construction_parts.GetKey( i );
  253. ConstructionPart value = construction_parts.Get( key );
  254. SetPartFromSyncData(value);
  255. }
  256. //regenerate navmesh
  257. UpdateNavmesh();
  258. }
  259. protected ConstructionPart GetConstructionPartById( int id )
  260. {
  261. Construction construction = GetConstruction();
  262. map<string, ref ConstructionPart> construction_parts = construction.GetConstructionParts();
  263. for ( int i = 0; i < construction_parts.Count(); ++i )
  264. {
  265. string key = construction_parts.GetKey( i );
  266. ConstructionPart value = construction_parts.Get( key );
  267. if ( value.GetId() == id )
  268. {
  269. return value;
  270. }
  271. }
  272. return NULL;
  273. }
  274. //
  275. //Base
  276. bool HasBase()
  277. {
  278. return m_HasBase;
  279. }
  280. void SetBaseState( bool has_base )
  281. {
  282. m_HasBase = has_base;
  283. }
  284. override bool IsDeployable()
  285. {
  286. return true;
  287. }
  288. bool IsOpened()
  289. {
  290. return false;
  291. }
  292. //--- CONSTRUCTION KIT
  293. ItemBase CreateConstructionKit()
  294. {
  295. ItemBase construction_kit = ItemBase.Cast( GetGame().CreateObjectEx( GetConstructionKitType(), GetKitSpawnPosition(), ECE_PLACE_ON_SURFACE ) );
  296. if ( m_ConstructionKitHealth > 0 )
  297. {
  298. construction_kit.SetHealth( m_ConstructionKitHealth );
  299. }
  300. return construction_kit;
  301. }
  302. void CreateConstructionKitInHands(notnull PlayerBase player)
  303. {
  304. ItemBase construction_kit = ItemBase.Cast(player.GetHumanInventory().CreateInHands(GetConstructionKitType()));
  305. if ( m_ConstructionKitHealth > 0 )
  306. {
  307. construction_kit.SetHealth( m_ConstructionKitHealth );
  308. }
  309. }
  310. protected vector GetKitSpawnPosition()
  311. {
  312. return GetPosition();
  313. }
  314. protected string GetConstructionKitType()
  315. {
  316. return "";
  317. }
  318. void DestroyConstructionKit( ItemBase construction_kit )
  319. {
  320. m_ConstructionKitHealth = construction_kit.GetHealth();
  321. GetGame().ObjectDelete( construction_kit );
  322. }
  323. //--- CONSTRUCTION
  324. void DestroyConstruction()
  325. {
  326. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " DestroyConstruction");
  327. GetGame().ObjectDelete( this );
  328. }
  329. // --- EVENTS
  330. override void OnStoreSave( ParamsWriteContext ctx )
  331. {
  332. super.OnStoreSave( ctx );
  333. //sync parts 01
  334. ctx.Write( m_SyncParts01 );
  335. ctx.Write( m_SyncParts02 );
  336. ctx.Write( m_SyncParts03 );
  337. ctx.Write( m_HasBase );
  338. }
  339. override bool OnStoreLoad( ParamsReadContext ctx, int version )
  340. {
  341. if ( !super.OnStoreLoad( ctx, version ) )
  342. return false;
  343. //--- Base building data ---
  344. //Restore synced parts data
  345. if ( !ctx.Read( m_SyncParts01 ) )
  346. {
  347. m_SyncParts01 = 0; //set default
  348. return false;
  349. }
  350. if ( !ctx.Read( m_SyncParts02 ) )
  351. {
  352. m_SyncParts02 = 0; //set default
  353. return false;
  354. }
  355. if ( !ctx.Read( m_SyncParts03 ) )
  356. {
  357. m_SyncParts03 = 0; //set default
  358. return false;
  359. }
  360. //has base
  361. if ( !ctx.Read( m_HasBase ) )
  362. {
  363. m_HasBase = false;
  364. return false;
  365. }
  366. //---
  367. return true;
  368. }
  369. override void AfterStoreLoad()
  370. {
  371. super.AfterStoreLoad();
  372. if (!m_FixDamageSystemInit)
  373. {
  374. SetPartsAfterStoreLoad();
  375. }
  376. }
  377. void SetPartsAfterStoreLoad()
  378. {
  379. //update server data
  380. SetPartsFromSyncData();
  381. //set base state
  382. ConstructionPart construction_part = GetConstruction().GetBaseConstructionPart();
  383. SetBaseState( construction_part.IsBuilt() ) ;
  384. //synchronize after load
  385. SynchronizeBaseState();
  386. }
  387. override void OnCreatePhysics()
  388. {
  389. super.OnCreatePhysics();
  390. ConstructionInit();
  391. SetPartsAfterStoreLoad();
  392. }
  393. override void EEHealthLevelChanged(int oldLevel, int newLevel, string zone)
  394. {
  395. if (m_FixDamageSystemInit)
  396. return;
  397. super.EEHealthLevelChanged(oldLevel,newLevel,zone);
  398. if (GetGame().IsMultiplayer() && !GetGame().IsServer())
  399. return;
  400. Construction construction = GetConstruction();
  401. string part_name = zone;
  402. part_name.ToLower();
  403. if ( newLevel == GameConstants.STATE_RUINED )
  404. {
  405. ConstructionPart construction_part = construction.GetConstructionPart( part_name );
  406. if ( construction_part && construction.IsPartConstructed( part_name ) )
  407. {
  408. construction.DestroyPartServer( null, part_name, AT_DESTROY_PART );
  409. construction.DestroyConnectedParts(part_name);
  410. }
  411. //barbed wire handling (hack-ish)
  412. if ( part_name.Contains("barbed") )
  413. {
  414. BarbedWire barbed_wire = BarbedWire.Cast( FindAttachmentBySlotName( zone ) );
  415. if (barbed_wire)
  416. barbed_wire.SetMountedState( false );
  417. }
  418. }
  419. }
  420. override void EEOnAfterLoad()
  421. {
  422. if (m_FixDamageSystemInit)
  423. {
  424. GetGame().GetCallQueue( CALL_CATEGORY_GAMEPLAY ).CallLater( SetPartsAfterStoreLoad, 500, false, this );
  425. }
  426. super.EEOnAfterLoad();
  427. }
  428. override void EEInit()
  429. {
  430. super.EEInit();
  431. // init visuals and physics
  432. InitBaseState();
  433. //debug
  434. #ifdef DEVELOPER
  435. DebugCustomState();
  436. #endif
  437. }
  438. override void EEItemAttached( EntityAI item, string slot_name )
  439. {
  440. super.EEItemAttached( item, slot_name );
  441. CheckForHybridAttachments( item, slot_name );
  442. UpdateVisuals();
  443. UpdateAttachmentPhysics( slot_name, false );
  444. }
  445. override void EEItemDetached( EntityAI item, string slot_name )
  446. {
  447. super.EEItemDetached( item, slot_name );
  448. UpdateVisuals();
  449. UpdateAttachmentPhysics( slot_name, false );
  450. }
  451. protected void OnSetSlotLock( int slotId, bool locked, bool was_locked )
  452. {
  453. string slot_name = InventorySlots.GetSlotName( slotId );
  454. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint( "inv: OnSetSlotLock " + GetDebugName( this ) + " slot=" + slot_name + " locked=" + locked + " was_locked=" + was_locked );
  455. UpdateAttachmentVisuals( slot_name, locked );
  456. UpdateAttachmentPhysics( slot_name, locked );
  457. }
  458. //ignore out of reach condition
  459. override bool IgnoreOutOfReachCondition()
  460. {
  461. return true;
  462. }
  463. //CONSTRUCTION EVENTS
  464. //Build
  465. void OnPartBuiltServer(notnull Man player, string part_name, int action_id)
  466. {
  467. ConstructionPart construtionPart = GetConstruction().GetConstructionPart(part_name);
  468. //check base state
  469. if (construtionPart.IsBase())
  470. {
  471. SetBaseState(true);
  472. //spawn kit
  473. CreateConstructionKit();
  474. }
  475. //register constructed parts for synchronization
  476. RegisterPartForSync(construtionPart.GetId());
  477. //register action that was performed on part
  478. RegisterActionForSync(construtionPart.GetId(), action_id);
  479. //synchronize
  480. SynchronizeBaseState();
  481. SetPartFromSyncData(construtionPart); // server part of sync, client will be synced from SetPartsFromSyncData
  482. UpdateNavmesh();
  483. //update visuals
  484. UpdateVisuals();
  485. //reset action sync data
  486. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ResetActionSyncData, 100, false, this);
  487. }
  488. void OnPartBuiltClient(string part_name, int action_id)
  489. {
  490. //play sound
  491. SoundBuildStart( part_name );
  492. }
  493. //Dismantle
  494. void OnPartDismantledServer(notnull Man player, string part_name, int action_id)
  495. {
  496. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " OnPartDismantledServer " + part_name);
  497. ConstructionPart construtionPart = GetConstruction().GetConstructionPart(part_name);
  498. //register constructed parts for synchronization
  499. UnregisterPartForSync(construtionPart.GetId());
  500. //register action that was performed on part
  501. RegisterActionForSync(construtionPart.GetId(), action_id);
  502. //synchronize
  503. SynchronizeBaseState();
  504. // server part of sync, client will be synced from SetPartsFromSyncData
  505. SetPartFromSyncData(construtionPart);
  506. UpdateNavmesh();
  507. //update visuals
  508. UpdateVisuals();
  509. //reset action sync data
  510. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ResetActionSyncData, 100, false, this);
  511. //check base state
  512. if (construtionPart.IsBase())
  513. {
  514. //Destroy construction
  515. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(DestroyConstruction, 200, false, this);
  516. }
  517. }
  518. void OnPartDismantledClient( string part_name, int action_id )
  519. {
  520. //play sound
  521. SoundDismantleStart( part_name );
  522. }
  523. //Destroy
  524. void OnPartDestroyedServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part = false)
  525. {
  526. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " OnPartDestroyedServer " + part_name);
  527. ConstructionPart construtionPart = GetConstruction().GetConstructionPart(part_name);
  528. //register constructed parts for synchronization
  529. UnregisterPartForSync(construtionPart.GetId());
  530. //register action that was performed on part
  531. RegisterActionForSync(construtionPart.GetId(), action_id);
  532. //synchronize
  533. SynchronizeBaseState();
  534. // server part of sync, client will be synced from SetPartsFromSyncData
  535. SetPartFromSyncData(construtionPart);
  536. UpdateNavmesh();
  537. //update visuals
  538. UpdateVisuals();
  539. //reset action sync data
  540. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ResetActionSyncData, 100, false, this);
  541. //check base state
  542. if (construtionPart.IsBase())
  543. {
  544. //Destroy construction
  545. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(DestroyConstruction, 200, false, this);
  546. }
  547. }
  548. void OnPartDestroyedClient( string part_name, int action_id )
  549. {
  550. //play sound
  551. SoundDestroyStart( part_name );
  552. }
  553. // --- UPDATE
  554. void InitBaseState()
  555. {
  556. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " BaseBuildingBase::InitBaseState ");
  557. InitVisuals();
  558. UpdateNavmesh(); //regenerate navmesh
  559. GetConstruction().InitBaseState();
  560. }
  561. void InitVisuals()
  562. {
  563. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " InitVisuals");
  564. //check base
  565. if ( !HasBase() )
  566. {
  567. SetAnimationPhase( ANIMATION_DEPLOYED, 0 );
  568. }
  569. else
  570. {
  571. SetAnimationPhase( ANIMATION_DEPLOYED, 1 );
  572. }
  573. GetConstruction().UpdateVisuals();
  574. }
  575. void UpdateVisuals()
  576. {
  577. array<string> attachmentSlots = new array<string>;
  578. GetAttachmentSlots(this, attachmentSlots);
  579. foreach (string slotName : attachmentSlots)
  580. {
  581. UpdateAttachmentVisuals(slotName, IsAttachmentSlotLocked(slotName));
  582. }
  583. //check base
  584. if (!HasBase())
  585. SetAnimationPhase(ANIMATION_DEPLOYED, 0);
  586. else
  587. SetAnimationPhase(ANIMATION_DEPLOYED, 1);
  588. GetConstruction().UpdateVisuals();
  589. }
  590. void UpdateAttachmentVisuals(string slot_name, bool is_locked)
  591. {
  592. string slotNameMounted = slot_name + "_Mounted";
  593. EntityAI attachment = FindAttachmentBySlotName(slot_name);
  594. if (attachment)
  595. {
  596. BarbedWire barbedWire = BarbedWire.Cast(attachment);
  597. if (barbedWire && barbedWire.IsMounted())
  598. CreateAreaDamage(slotNameMounted);
  599. else
  600. DestroyAreaDamage(slotNameMounted);
  601. if (is_locked)
  602. {
  603. SetAnimationPhase(slotNameMounted, 0);
  604. SetAnimationPhase(slot_name, 1);
  605. }
  606. else
  607. {
  608. SetAnimationPhase(slotNameMounted, 1);
  609. SetAnimationPhase(slot_name, 0);
  610. }
  611. }
  612. else
  613. {
  614. SetAnimationPhase(slotNameMounted, 1);
  615. SetAnimationPhase(slot_name, 1);
  616. DestroyAreaDamage(slotNameMounted);
  617. }
  618. }
  619. // avoid calling this function on frequent occasions, it's a massive performance hit
  620. void UpdatePhysics()
  621. {
  622. if (LogManager.IsBaseBuildingLogEnable())
  623. bsbDebugPrint("[bsb] " + GetDebugName(this) + " BaseBuildingBase::UpdatePhysics");
  624. array<string> attachmentSlots = new array<string>;
  625. GetAttachmentSlots(this, attachmentSlots);
  626. if (LogManager.IsBaseBuildingLogEnable())
  627. bsbDebugPrint("[bsb] " + GetDebugName(this) + " att_cnt=" + attachmentSlots.Count());
  628. foreach (string slotName : attachmentSlots)
  629. {
  630. UpdateAttachmentPhysics(slotName, IsAttachmentSlotLocked(slotName));
  631. }
  632. //check base
  633. if (!HasBase())
  634. {
  635. if (LogManager.IsBaseBuildingLogEnable())
  636. bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " ADD");
  637. AddProxyPhysics(ANIMATION_DEPLOYED);
  638. }
  639. else
  640. {
  641. if (LogManager.IsBaseBuildingLogEnable())
  642. bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " RM");
  643. RemoveProxyPhysics(ANIMATION_DEPLOYED);
  644. }
  645. GetConstruction().UpdatePhysics();
  646. UpdateNavmesh();
  647. }
  648. void UpdateAttachmentPhysics( string slot_name, bool is_locked )
  649. {
  650. //checks for invalid appends; hotfix
  651. if ( !m_Mountables || m_Mountables.Find(slot_name) == -1 )
  652. return;
  653. //----------------------------------
  654. string slot_name_mounted = slot_name + "_Mounted";
  655. EntityAI attachment = FindAttachmentBySlotName( slot_name );
  656. //remove proxy physics
  657. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " Removing ATT SLOT=" + slot_name + " RM / RM");
  658. RemoveProxyPhysics( slot_name_mounted );
  659. RemoveProxyPhysics( slot_name );
  660. if ( attachment )
  661. {
  662. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " Adding ATT=" + Object.GetDebugName(attachment));
  663. if ( is_locked )
  664. {
  665. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " RM / RM");
  666. AddProxyPhysics( slot_name_mounted );
  667. }
  668. else
  669. {
  670. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " ADD");
  671. AddProxyPhysics( slot_name );
  672. }
  673. }
  674. }
  675. protected void UpdateNavmesh()
  676. {
  677. SetAffectPathgraph( true, false );
  678. GetGame().GetCallQueue( CALL_CATEGORY_SYSTEM ).CallLater( GetGame().UpdatePathgraphRegionByObject, 100, false, this );
  679. }
  680. override bool CanUseConstruction()
  681. {
  682. return true;
  683. }
  684. override bool CanUseConstructionBuild()
  685. {
  686. return true;
  687. }
  688. protected bool IsAttachmentSlotLocked( EntityAI attachment )
  689. {
  690. if ( attachment )
  691. {
  692. InventoryLocation inventory_location = new InventoryLocation;
  693. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  694. return GetInventory().GetSlotLock( inventory_location.GetSlot() );
  695. }
  696. return false;
  697. }
  698. protected bool IsAttachmentSlotLocked( string slot_name )
  699. {
  700. return GetInventory().GetSlotLock( InventorySlots.GetSlotIdFromString( slot_name ) );
  701. }
  702. //--- ATTACHMENT SLOTS
  703. void GetAttachmentSlots( EntityAI entity, out array<string> attachment_slots )
  704. {
  705. string config_path = "CfgVehicles" + " " + entity.GetType() + " " + "attachments";
  706. if ( GetGame().ConfigIsExisting( config_path ) )
  707. {
  708. GetGame().ConfigGetTextArray( config_path, attachment_slots );
  709. }
  710. }
  711. bool CheckSlotVerticalDistance( int slot_id, PlayerBase player )
  712. {
  713. return true;
  714. }
  715. protected bool CheckMemoryPointVerticalDistance( float max_dist, string selection, PlayerBase player )
  716. {
  717. return true;
  718. }
  719. protected bool CheckLevelVerticalDistance( float max_dist, string selection, PlayerBase player )
  720. {
  721. return true;
  722. }
  723. // --- INIT
  724. void ConstructionInit()
  725. {
  726. if ( !m_Construction )
  727. {
  728. m_Construction = new Construction( this );
  729. }
  730. GetConstruction().Init();
  731. }
  732. Construction GetConstruction()
  733. {
  734. return m_Construction;
  735. }
  736. //--- INVENTORY/ATTACHMENTS CONDITIONS
  737. //attachments
  738. override bool CanReceiveAttachment( EntityAI attachment, int slotId )
  739. {
  740. return super.CanReceiveAttachment(attachment, slotId);
  741. }
  742. bool HasAttachmentsBesidesBase()
  743. {
  744. int attachment_count = GetInventory().AttachmentCount();
  745. if ( attachment_count > 0 )
  746. {
  747. if ( HasBase() && attachment_count == 1 )
  748. {
  749. return false;
  750. }
  751. return true;
  752. }
  753. return false;
  754. }
  755. override bool ShowZonesHealth()
  756. {
  757. return true;
  758. }
  759. override bool IsTakeable()
  760. {
  761. return false;
  762. }
  763. //this into/outo parent.Cargo
  764. override bool CanPutInCargo( EntityAI parent )
  765. {
  766. return false;
  767. }
  768. override bool CanRemoveFromCargo( EntityAI parent )
  769. {
  770. return false;
  771. }
  772. //hands
  773. override bool CanPutIntoHands( EntityAI parent )
  774. {
  775. return false;
  776. }
  777. //--- ACTION CONDITIONS
  778. //direction
  779. override bool IsFacingPlayer( PlayerBase player, string selection )
  780. {
  781. return true;
  782. }
  783. override bool IsPlayerInside( PlayerBase player, string selection )
  784. {
  785. return true;
  786. }
  787. //! Some buildings can only be built from outside
  788. bool MustBeBuiltFromOutside()
  789. {
  790. return false;
  791. }
  792. //camera direction check
  793. bool IsFacingCamera( string selection )
  794. {
  795. return true;
  796. }
  797. //roof check
  798. bool PerformRoofCheckForBase( string partName, PlayerBase player, out bool result )
  799. {
  800. return false;
  801. }
  802. //selection->player distance check
  803. bool HasProperDistance( string selection, PlayerBase player )
  804. {
  805. return true;
  806. }
  807. //folding
  808. bool CanFoldBaseBuildingObject()
  809. {
  810. if ( HasBase() || GetInventory().AttachmentCount() > 0 )
  811. {
  812. return false;
  813. }
  814. return true;
  815. }
  816. ItemBase FoldBaseBuildingObject()
  817. {
  818. ItemBase item = CreateConstructionKit();
  819. DestroyConstruction();
  820. return item;
  821. }
  822. //Damage triggers (barbed wire)
  823. void CreateAreaDamage( string slot_name, float rotation_angle = 0 )
  824. {
  825. if ( GetGame() && GetGame().IsServer() )
  826. {
  827. //destroy area damage if some already exists
  828. DestroyAreaDamage( slot_name );
  829. //create new area damage
  830. AreaDamageLoopedDeferred_NoVehicle areaDamage = new AreaDamageLoopedDeferred_NoVehicle( this );
  831. areaDamage.SetDamageComponentType(AreaDamageComponentTypes.HITZONE);
  832. vector min_max[2];
  833. if ( MemoryPointExists( slot_name + "_min" ) )
  834. {
  835. min_max[0] = GetMemoryPointPos( slot_name + "_min" );
  836. }
  837. if ( MemoryPointExists( slot_name + "_max" ) )
  838. {
  839. min_max[1] = GetMemoryPointPos( slot_name + "_max" );
  840. }
  841. //get proper trigger extents (min<max)
  842. vector extents[2];
  843. GetConstruction().GetTriggerExtents( min_max, extents );
  844. //get box center
  845. vector center;
  846. center = GetConstruction().GetBoxCenter( min_max );
  847. center = ModelToWorld( center );
  848. //rotate center if needed
  849. vector orientation = GetOrientation();;
  850. CalcDamageAreaRotation( rotation_angle, center, orientation );
  851. areaDamage.SetExtents( extents[0], extents[1] );
  852. areaDamage.SetAreaPosition( center );
  853. areaDamage.SetAreaOrientation( orientation );
  854. areaDamage.SetLoopInterval( 1.0 );
  855. areaDamage.SetDeferDuration( 0.2 );
  856. areaDamage.SetHitZones( { "Torso","LeftHand","LeftLeg","LeftFoot","RightHand","RightLeg","RightFoot" } );
  857. areaDamage.SetAmmoName( "BarbedWireHit" );
  858. areaDamage.Spawn();
  859. m_DamageTriggers.Insert( slot_name, areaDamage );
  860. }
  861. }
  862. void CalcDamageAreaRotation( float angle_deg, out vector center, out vector orientation )
  863. {
  864. if ( angle_deg != 0 )
  865. {
  866. //orientation
  867. orientation[0] = orientation[0] - angle_deg;
  868. //center
  869. vector rotate_axis;
  870. if ( MemoryPointExists( "rotate_axis" ) )
  871. {
  872. rotate_axis = ModelToWorld( GetMemoryPointPos( "rotate_axis" ) );
  873. }
  874. float r_center_x = ( Math.Cos( angle_deg * Math.DEG2RAD ) * ( center[0] - rotate_axis[0] ) ) - ( Math.Sin( angle_deg * Math.DEG2RAD ) * ( center[2] - rotate_axis[2] ) ) + rotate_axis[0];
  875. float r_center_z = ( Math.Sin( angle_deg * Math.DEG2RAD ) * ( center[0] - rotate_axis[0] ) ) + ( Math.Cos( angle_deg * Math.DEG2RAD ) * ( center[2] - rotate_axis[2] ) ) + rotate_axis[2];
  876. center[0] = r_center_x;
  877. center[2] = r_center_z;
  878. }
  879. }
  880. void DestroyAreaDamage( string slot_name )
  881. {
  882. if (GetGame() && GetGame().IsServer())
  883. {
  884. AreaDamageLoopedDeferred_NoVehicle areaDamage;
  885. if (m_DamageTriggers.Find(slot_name, areaDamage))
  886. {
  887. if (areaDamage)
  888. {
  889. areaDamage.Destroy();
  890. }
  891. m_DamageTriggers.Remove( slot_name );
  892. }
  893. }
  894. }
  895. override bool IsIgnoredByConstruction()
  896. {
  897. return true;
  898. }
  899. //================================================================
  900. // SOUNDS
  901. //================================================================
  902. protected void SoundBuildStart( string part_name )
  903. {
  904. PlaySoundSet( m_Sound, GetBuildSoundByMaterial( part_name ), 0.1, 0.1 );
  905. }
  906. protected void SoundDismantleStart( string part_name )
  907. {
  908. PlaySoundSet( m_Sound, GetDismantleSoundByMaterial( part_name ), 0.1, 0.1 );
  909. }
  910. protected void SoundDestroyStart( string part_name )
  911. {
  912. PlaySoundSet( m_Sound, GetDismantleSoundByMaterial( part_name ), 0.1, 0.1 );
  913. }
  914. protected string GetBuildSoundByMaterial( string part_name )
  915. {
  916. ConstructionMaterialType material_type = GetConstruction().GetMaterialType( part_name );
  917. switch ( material_type )
  918. {
  919. case ConstructionMaterialType.MATERIAL_LOG: return SOUND_BUILD_WOOD_LOG;
  920. case ConstructionMaterialType.MATERIAL_WOOD: return SOUND_BUILD_WOOD_PLANK;
  921. case ConstructionMaterialType.MATERIAL_STAIRS: return SOUND_BUILD_WOOD_STAIRS;
  922. case ConstructionMaterialType.MATERIAL_METAL: return SOUND_BUILD_METAL;
  923. case ConstructionMaterialType.MATERIAL_WIRE: return SOUND_BUILD_WIRE;
  924. }
  925. return "";
  926. }
  927. protected string GetDismantleSoundByMaterial( string part_name )
  928. {
  929. ConstructionMaterialType material_type = GetConstruction().GetMaterialType( part_name );
  930. switch ( material_type )
  931. {
  932. case ConstructionMaterialType.MATERIAL_LOG: return SOUND_DISMANTLE_WOOD_LOG;
  933. case ConstructionMaterialType.MATERIAL_WOOD: return SOUND_DISMANTLE_WOOD_PLANK;
  934. case ConstructionMaterialType.MATERIAL_STAIRS: return SOUND_DISMANTLE_WOOD_STAIRS;
  935. case ConstructionMaterialType.MATERIAL_METAL: return SOUND_DISMANTLE_METAL;
  936. case ConstructionMaterialType.MATERIAL_WIRE: return SOUND_DISMANTLE_WIRE;
  937. }
  938. return "";
  939. }
  940. //misc
  941. void CheckForHybridAttachments( EntityAI item, string slot_name )
  942. {
  943. if (!GetGame().IsMultiplayer() || GetGame().IsServer())
  944. {
  945. //if this is a hybrid attachment, set damage of appropriate damage zone. Zone name must match slot name...WIP
  946. if (m_HybridAttachments && m_HybridAttachments.Find(slot_name) != -1)
  947. {
  948. SetHealth(slot_name,"Health",item.GetHealth());
  949. }
  950. }
  951. }
  952. override int GetDamageSystemVersionChange()
  953. {
  954. return 111;
  955. }
  956. override void SetActions()
  957. {
  958. super.SetActions();
  959. AddAction(ActionDetachFromTarget);
  960. RemoveAction(ActionTakeItem);
  961. RemoveAction(ActionTakeItemToHands);
  962. }
  963. //================================================================
  964. // DEBUG
  965. //================================================================
  966. protected void DebugCustomState()
  967. {
  968. }
  969. //! Excludes certain parts from being built by OnDebugSpawn, uses Contains to compare
  970. array<string> OnDebugSpawnBuildExcludes()
  971. {
  972. return null;
  973. }
  974. override void OnDebugSpawn()
  975. {
  976. FullyBuild();
  977. }
  978. void FullyBuild()
  979. {
  980. array<string> excludes = OnDebugSpawnBuildExcludes();
  981. array<ConstructionPart> parts = GetConstruction().GetConstructionParts().GetValueArray();
  982. Man p;
  983. #ifdef SERVER
  984. array<Man> players = new array<Man>;
  985. GetGame().GetWorld().GetPlayerList(players);
  986. if (players.Count())
  987. p = players[0];
  988. #else
  989. p = GetGame().GetPlayer();
  990. #endif
  991. foreach (ConstructionPart part : parts)
  992. {
  993. bool excluded = false;
  994. string partName = part.GetPartName();
  995. if (excludes)
  996. {
  997. foreach (string exclude : excludes)
  998. {
  999. if (partName.Contains(exclude))
  1000. {
  1001. excluded = true;
  1002. break;
  1003. }
  1004. }
  1005. }
  1006. if (!excluded)
  1007. {
  1008. OnPartBuiltServer(p, partName, AT_BUILD_PART);
  1009. }
  1010. }
  1011. GetConstruction().UpdateVisuals();
  1012. }
  1013. }
  1014. void bsbDebugPrint (string s)
  1015. {
  1016. #ifdef BSB_DEBUG
  1017. PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
  1018. #else
  1019. //Print("" + s); // comment/uncomment to hide/see debug logs
  1020. #endif
  1021. }
  1022. void bsbDebugSpam (string s)
  1023. {
  1024. #ifdef BSB_DEBUG_SPAM
  1025. PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
  1026. #else
  1027. //Print("" + s); // comment/uncomment to hide/see debug logs
  1028. #endif
  1029. }