basebuildingbase.c 33 KB

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