basebuildingbase.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
  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. if (GetGame().IsServer())
  518. HandleItemFalling(construtionPart);
  519. }
  520. void OnPartDismantledClient( string part_name, int action_id )
  521. {
  522. //play sound
  523. SoundDismantleStart( part_name );
  524. }
  525. //Destroy
  526. void OnPartDestroyedServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part = false)
  527. {
  528. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " OnPartDestroyedServer " + part_name);
  529. ConstructionPart construtionPart = GetConstruction().GetConstructionPart(part_name);
  530. //register constructed parts for synchronization
  531. UnregisterPartForSync(construtionPart.GetId());
  532. //register action that was performed on part
  533. RegisterActionForSync(construtionPart.GetId(), action_id);
  534. //synchronize
  535. SynchronizeBaseState();
  536. // server part of sync, client will be synced from SetPartsFromSyncData
  537. SetPartFromSyncData(construtionPart);
  538. UpdateNavmesh();
  539. //update visuals
  540. UpdateVisuals();
  541. //reset action sync data
  542. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ResetActionSyncData, 100, false, this);
  543. //check base state
  544. if (construtionPart.IsBase())
  545. {
  546. //Destroy construction
  547. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(DestroyConstruction, 200, false, this);
  548. }
  549. if (GetGame().IsServer())
  550. HandleItemFalling(construtionPart);
  551. }
  552. void OnPartDestroyedClient( string part_name, int action_id )
  553. {
  554. //play sound
  555. SoundDestroyStart( part_name );
  556. }
  557. protected void HandleItemFalling(ConstructionPart part)
  558. {
  559. bool process = false;
  560. //TODO: add a parameter to parts' config classes?
  561. process |= part.m_PartName.Contains("_roof");
  562. process |= part.m_PartName.Contains("_platform");
  563. process |= part.m_PartName.Contains("_stair");
  564. if (process)
  565. {
  566. if (!MemoryPointExists(part.m_PartName + "_min") || !MemoryPointExists(part.m_PartName + "_max"))
  567. {
  568. Debug.Log("min/max memory points do not exist for part: " + part.m_PartName);
  569. return;
  570. }
  571. vector mins, maxs;
  572. mins = ModelToWorld(GetMemoryPointPos(part.m_PartName + "_min"));
  573. maxs = ModelToWorld(GetMemoryPointPos(part.m_PartName + "_max"));
  574. //sanitize minmaxs
  575. vector minTmp, maxTmp;
  576. minTmp[0] = Math.Min(mins[0],maxs[0]);
  577. maxTmp[0] = Math.Max(mins[0],maxs[0]);
  578. minTmp[1] = Math.Min(mins[1],maxs[1]);
  579. maxTmp[1] = Math.Max(mins[1],maxs[1]);
  580. minTmp[2] = Math.Min(mins[2],maxs[2]);
  581. maxTmp[2] = Math.Max(mins[2],maxs[2]);
  582. mins = minTmp;
  583. maxs = maxTmp;
  584. maxs[1] = maxs[1] + 0.35; //reach a little above..
  585. ItemFall(mins,maxs);
  586. }
  587. }
  588. protected void ItemFall(vector min, vector max)
  589. {
  590. array<EntityAI> foundEntities = new array<EntityAI>();
  591. DayZPlayerUtils.PhysicsGetEntitiesInBox(min,max,foundEntities);
  592. //filtering
  593. ItemBase item;
  594. foreach (EntityAI entity : foundEntities)
  595. {
  596. if (Class.CastTo(item,entity) && !item.CanUseConstruction()) //BB items?
  597. item.ThrowPhysically(null,vector.Zero);
  598. }
  599. }
  600. // --- UPDATE
  601. void InitBaseState()
  602. {
  603. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " BaseBuildingBase::InitBaseState ");
  604. InitVisuals();
  605. UpdateNavmesh(); //regenerate navmesh
  606. GetConstruction().InitBaseState();
  607. }
  608. void InitVisuals()
  609. {
  610. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " InitVisuals");
  611. //check base
  612. if ( !HasBase() )
  613. {
  614. SetAnimationPhase( ANIMATION_DEPLOYED, 0 );
  615. }
  616. else
  617. {
  618. SetAnimationPhase( ANIMATION_DEPLOYED, 1 );
  619. }
  620. GetConstruction().UpdateVisuals();
  621. }
  622. void UpdateVisuals()
  623. {
  624. array<string> attachmentSlots = new array<string>;
  625. GetAttachmentSlots(this, attachmentSlots);
  626. foreach (string slotName : attachmentSlots)
  627. {
  628. UpdateAttachmentVisuals(slotName, IsAttachmentSlotLocked(slotName));
  629. }
  630. //check base
  631. if (!HasBase())
  632. SetAnimationPhase(ANIMATION_DEPLOYED, 0);
  633. else
  634. SetAnimationPhase(ANIMATION_DEPLOYED, 1);
  635. GetConstruction().UpdateVisuals();
  636. }
  637. void UpdateAttachmentVisuals(string slot_name, bool is_locked)
  638. {
  639. string slotNameMounted = slot_name + "_Mounted";
  640. EntityAI attachment = FindAttachmentBySlotName(slot_name);
  641. if (attachment)
  642. {
  643. BarbedWire barbedWire = BarbedWire.Cast(attachment);
  644. if (barbedWire && barbedWire.IsMounted())
  645. CreateAreaDamage(slotNameMounted);
  646. else
  647. DestroyAreaDamage(slotNameMounted);
  648. if (is_locked)
  649. {
  650. SetAnimationPhase(slotNameMounted, 0);
  651. SetAnimationPhase(slot_name, 1);
  652. }
  653. else
  654. {
  655. SetAnimationPhase(slotNameMounted, 1);
  656. SetAnimationPhase(slot_name, 0);
  657. }
  658. }
  659. else
  660. {
  661. SetAnimationPhase(slotNameMounted, 1);
  662. SetAnimationPhase(slot_name, 1);
  663. DestroyAreaDamage(slotNameMounted);
  664. }
  665. }
  666. // avoid calling this function on frequent occasions, it's a massive performance hit
  667. void UpdatePhysics()
  668. {
  669. if (LogManager.IsBaseBuildingLogEnable())
  670. bsbDebugPrint("[bsb] " + GetDebugName(this) + " BaseBuildingBase::UpdatePhysics");
  671. array<string> attachmentSlots = new array<string>;
  672. GetAttachmentSlots(this, attachmentSlots);
  673. if (LogManager.IsBaseBuildingLogEnable())
  674. bsbDebugPrint("[bsb] " + GetDebugName(this) + " att_cnt=" + attachmentSlots.Count());
  675. foreach (string slotName : attachmentSlots)
  676. {
  677. UpdateAttachmentPhysics(slotName, IsAttachmentSlotLocked(slotName));
  678. }
  679. //check base
  680. if (!HasBase())
  681. {
  682. if (LogManager.IsBaseBuildingLogEnable())
  683. bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " ADD");
  684. AddProxyPhysics(ANIMATION_DEPLOYED);
  685. }
  686. else
  687. {
  688. if (LogManager.IsBaseBuildingLogEnable())
  689. bsbDebugPrint("[bsb] " + GetDebugName(this) + ANIMATION_DEPLOYED + " RM");
  690. RemoveProxyPhysics(ANIMATION_DEPLOYED);
  691. }
  692. GetConstruction().UpdatePhysics();
  693. UpdateNavmesh();
  694. }
  695. void UpdateAttachmentPhysics( string slot_name, bool is_locked )
  696. {
  697. //checks for invalid appends; hotfix
  698. if ( !m_Mountables || m_Mountables.Find(slot_name) == -1 )
  699. return;
  700. //----------------------------------
  701. string slot_name_mounted = slot_name + "_Mounted";
  702. EntityAI attachment = FindAttachmentBySlotName( slot_name );
  703. //remove proxy physics
  704. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " Removing ATT SLOT=" + slot_name + " RM / RM");
  705. RemoveProxyPhysics( slot_name_mounted );
  706. RemoveProxyPhysics( slot_name );
  707. if ( attachment )
  708. {
  709. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " Adding ATT=" + Object.GetDebugName(attachment));
  710. if ( is_locked )
  711. {
  712. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " RM / RM");
  713. AddProxyPhysics( slot_name_mounted );
  714. }
  715. else
  716. {
  717. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + GetDebugName(this) + " ADD");
  718. AddProxyPhysics( slot_name );
  719. }
  720. }
  721. }
  722. protected void UpdateNavmesh()
  723. {
  724. SetAffectPathgraph( true, false );
  725. GetGame().GetCallQueue( CALL_CATEGORY_SYSTEM ).CallLater( GetGame().UpdatePathgraphRegionByObject, 100, false, this );
  726. }
  727. override bool CanUseConstruction()
  728. {
  729. return true;
  730. }
  731. override bool CanUseConstructionBuild()
  732. {
  733. return true;
  734. }
  735. protected bool IsAttachmentSlotLocked( EntityAI attachment )
  736. {
  737. if ( attachment )
  738. {
  739. InventoryLocation inventory_location = new InventoryLocation;
  740. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  741. return GetInventory().GetSlotLock( inventory_location.GetSlot() );
  742. }
  743. return false;
  744. }
  745. protected bool IsAttachmentSlotLocked( string slot_name )
  746. {
  747. return GetInventory().GetSlotLock( InventorySlots.GetSlotIdFromString( slot_name ) );
  748. }
  749. //--- ATTACHMENT SLOTS
  750. void GetAttachmentSlots( EntityAI entity, out array<string> attachment_slots )
  751. {
  752. string config_path = "CfgVehicles" + " " + entity.GetType() + " " + "attachments";
  753. if ( GetGame().ConfigIsExisting( config_path ) )
  754. {
  755. GetGame().ConfigGetTextArray( config_path, attachment_slots );
  756. }
  757. }
  758. bool CheckSlotVerticalDistance( int slot_id, PlayerBase player )
  759. {
  760. return true;
  761. }
  762. protected bool CheckMemoryPointVerticalDistance( float max_dist, string selection, PlayerBase player )
  763. {
  764. return true;
  765. }
  766. protected bool CheckLevelVerticalDistance( float max_dist, string selection, PlayerBase player )
  767. {
  768. return true;
  769. }
  770. // --- INIT
  771. void ConstructionInit()
  772. {
  773. if ( !m_Construction )
  774. {
  775. m_Construction = new Construction( this );
  776. }
  777. GetConstruction().Init();
  778. }
  779. Construction GetConstruction()
  780. {
  781. return m_Construction;
  782. }
  783. //--- INVENTORY/ATTACHMENTS CONDITIONS
  784. //attachments
  785. override bool CanReceiveAttachment( EntityAI attachment, int slotId )
  786. {
  787. return super.CanReceiveAttachment(attachment, slotId);
  788. }
  789. bool HasAttachmentsBesidesBase()
  790. {
  791. int attachment_count = GetInventory().AttachmentCount();
  792. if ( attachment_count > 0 )
  793. {
  794. if ( HasBase() && attachment_count == 1 )
  795. {
  796. return false;
  797. }
  798. return true;
  799. }
  800. return false;
  801. }
  802. override bool ShowZonesHealth()
  803. {
  804. return true;
  805. }
  806. override bool IsTakeable()
  807. {
  808. return false;
  809. }
  810. //this into/outo parent.Cargo
  811. override bool CanPutInCargo( EntityAI parent )
  812. {
  813. return false;
  814. }
  815. override bool CanRemoveFromCargo( EntityAI parent )
  816. {
  817. return false;
  818. }
  819. //hands
  820. override bool CanPutIntoHands( EntityAI parent )
  821. {
  822. return false;
  823. }
  824. //--- ACTION CONDITIONS
  825. //direction
  826. override bool IsFacingPlayer( PlayerBase player, string selection )
  827. {
  828. return true;
  829. }
  830. override bool IsPlayerInside( PlayerBase player, string selection )
  831. {
  832. return true;
  833. }
  834. //! Some buildings can only be built from outside
  835. bool MustBeBuiltFromOutside()
  836. {
  837. return false;
  838. }
  839. //camera direction check
  840. bool IsFacingCamera( string selection )
  841. {
  842. return true;
  843. }
  844. //roof check
  845. bool PerformRoofCheckForBase( string partName, PlayerBase player, out bool result )
  846. {
  847. return false;
  848. }
  849. //selection->player distance check
  850. bool HasProperDistance( string selection, PlayerBase player )
  851. {
  852. return true;
  853. }
  854. //folding
  855. bool CanFoldBaseBuildingObject()
  856. {
  857. if ( HasBase() || GetInventory().AttachmentCount() > 0 )
  858. {
  859. return false;
  860. }
  861. return true;
  862. }
  863. ItemBase FoldBaseBuildingObject()
  864. {
  865. ItemBase item = CreateConstructionKit();
  866. DestroyConstruction();
  867. return item;
  868. }
  869. //Damage triggers (barbed wire)
  870. void CreateAreaDamage( string slot_name, float rotation_angle = 0 )
  871. {
  872. if ( GetGame() && GetGame().IsServer() )
  873. {
  874. //destroy area damage if some already exists
  875. DestroyAreaDamage( slot_name );
  876. //create new area damage
  877. AreaDamageLoopedDeferred_NoVehicle areaDamage = new AreaDamageLoopedDeferred_NoVehicle( this );
  878. areaDamage.SetDamageComponentType(AreaDamageComponentTypes.HITZONE);
  879. vector min_max[2];
  880. if ( MemoryPointExists( slot_name + "_min" ) )
  881. {
  882. min_max[0] = GetMemoryPointPos( slot_name + "_min" );
  883. }
  884. if ( MemoryPointExists( slot_name + "_max" ) )
  885. {
  886. min_max[1] = GetMemoryPointPos( slot_name + "_max" );
  887. }
  888. //get proper trigger extents (min<max)
  889. vector extents[2];
  890. GetConstruction().GetTriggerExtents( min_max, extents );
  891. //get box center
  892. vector center;
  893. center = GetConstruction().GetBoxCenter( min_max );
  894. center = ModelToWorld( center );
  895. //rotate center if needed
  896. vector orientation = GetOrientation();;
  897. CalcDamageAreaRotation( rotation_angle, center, orientation );
  898. areaDamage.SetExtents( extents[0], extents[1] );
  899. areaDamage.SetAreaPosition( center );
  900. areaDamage.SetAreaOrientation( orientation );
  901. areaDamage.SetLoopInterval( 1.0 );
  902. areaDamage.SetDeferDuration( 0.2 );
  903. areaDamage.SetHitZones( { "Torso","LeftHand","LeftLeg","LeftFoot","RightHand","RightLeg","RightFoot" } );
  904. areaDamage.SetAmmoName( "BarbedWireHit" );
  905. areaDamage.Spawn();
  906. m_DamageTriggers.Insert( slot_name, areaDamage );
  907. }
  908. }
  909. void CalcDamageAreaRotation( float angle_deg, out vector center, out vector orientation )
  910. {
  911. if ( angle_deg != 0 )
  912. {
  913. //orientation
  914. orientation[0] = orientation[0] - angle_deg;
  915. //center
  916. vector rotate_axis;
  917. if ( MemoryPointExists( "rotate_axis" ) )
  918. {
  919. rotate_axis = ModelToWorld( GetMemoryPointPos( "rotate_axis" ) );
  920. }
  921. 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];
  922. 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];
  923. center[0] = r_center_x;
  924. center[2] = r_center_z;
  925. }
  926. }
  927. void DestroyAreaDamage( string slot_name )
  928. {
  929. if (GetGame() && GetGame().IsServer())
  930. {
  931. AreaDamageLoopedDeferred_NoVehicle areaDamage;
  932. if (m_DamageTriggers.Find(slot_name, areaDamage))
  933. {
  934. if (areaDamage)
  935. {
  936. areaDamage.Destroy();
  937. }
  938. m_DamageTriggers.Remove( slot_name );
  939. }
  940. }
  941. }
  942. override bool IsIgnoredByConstruction()
  943. {
  944. return true;
  945. }
  946. //================================================================
  947. // SOUNDS
  948. //================================================================
  949. protected void SoundBuildStart( string part_name )
  950. {
  951. PlaySoundSet( m_Sound, GetBuildSoundByMaterial( part_name ), 0.1, 0.1 );
  952. }
  953. protected void SoundDismantleStart( string part_name )
  954. {
  955. PlaySoundSet( m_Sound, GetDismantleSoundByMaterial( part_name ), 0.1, 0.1 );
  956. }
  957. protected void SoundDestroyStart( string part_name )
  958. {
  959. PlaySoundSet( m_Sound, GetDismantleSoundByMaterial( part_name ), 0.1, 0.1 );
  960. }
  961. protected string GetBuildSoundByMaterial( string part_name )
  962. {
  963. ConstructionMaterialType material_type = GetConstruction().GetMaterialType( part_name );
  964. switch ( material_type )
  965. {
  966. case ConstructionMaterialType.MATERIAL_LOG: return SOUND_BUILD_WOOD_LOG;
  967. case ConstructionMaterialType.MATERIAL_WOOD: return SOUND_BUILD_WOOD_PLANK;
  968. case ConstructionMaterialType.MATERIAL_STAIRS: return SOUND_BUILD_WOOD_STAIRS;
  969. case ConstructionMaterialType.MATERIAL_METAL: return SOUND_BUILD_METAL;
  970. case ConstructionMaterialType.MATERIAL_WIRE: return SOUND_BUILD_WIRE;
  971. }
  972. return "";
  973. }
  974. protected string GetDismantleSoundByMaterial( string part_name )
  975. {
  976. ConstructionMaterialType material_type = GetConstruction().GetMaterialType( part_name );
  977. switch ( material_type )
  978. {
  979. case ConstructionMaterialType.MATERIAL_LOG: return SOUND_DISMANTLE_WOOD_LOG;
  980. case ConstructionMaterialType.MATERIAL_WOOD: return SOUND_DISMANTLE_WOOD_PLANK;
  981. case ConstructionMaterialType.MATERIAL_STAIRS: return SOUND_DISMANTLE_WOOD_STAIRS;
  982. case ConstructionMaterialType.MATERIAL_METAL: return SOUND_DISMANTLE_METAL;
  983. case ConstructionMaterialType.MATERIAL_WIRE: return SOUND_DISMANTLE_WIRE;
  984. }
  985. return "";
  986. }
  987. //misc
  988. void CheckForHybridAttachments( EntityAI item, string slot_name )
  989. {
  990. if (!GetGame().IsMultiplayer() || GetGame().IsServer())
  991. {
  992. //if this is a hybrid attachment, set damage of appropriate damage zone. Zone name must match slot name...WIP
  993. if (m_HybridAttachments && m_HybridAttachments.Find(slot_name) != -1)
  994. {
  995. SetHealth(slot_name,"Health",item.GetHealth());
  996. }
  997. }
  998. }
  999. override int GetDamageSystemVersionChange()
  1000. {
  1001. return 111;
  1002. }
  1003. override void SetActions()
  1004. {
  1005. super.SetActions();
  1006. AddAction(ActionDetachFromTarget);
  1007. RemoveAction(ActionTakeItem);
  1008. RemoveAction(ActionTakeItemToHands);
  1009. }
  1010. //================================================================
  1011. // DEBUG
  1012. //================================================================
  1013. protected void DebugCustomState()
  1014. {
  1015. }
  1016. //! Excludes certain parts from being built by OnDebugSpawn, uses Contains to compare
  1017. array<string> OnDebugSpawnBuildExcludes()
  1018. {
  1019. return null;
  1020. }
  1021. override void OnDebugSpawn()
  1022. {
  1023. FullyBuild();
  1024. }
  1025. void FullyBuild()
  1026. {
  1027. array<string> excludes = OnDebugSpawnBuildExcludes();
  1028. array<ConstructionPart> parts = GetConstruction().GetConstructionParts().GetValueArray();
  1029. Man p;
  1030. #ifdef SERVER
  1031. array<Man> players = new array<Man>;
  1032. GetGame().GetWorld().GetPlayerList(players);
  1033. if (players.Count())
  1034. p = players[0];
  1035. #else
  1036. p = GetGame().GetPlayer();
  1037. #endif
  1038. foreach (ConstructionPart part : parts)
  1039. {
  1040. bool excluded = false;
  1041. string partName = part.GetPartName();
  1042. if (excludes)
  1043. {
  1044. foreach (string exclude : excludes)
  1045. {
  1046. if (partName.Contains(exclude))
  1047. {
  1048. excluded = true;
  1049. break;
  1050. }
  1051. }
  1052. }
  1053. if (!excluded)
  1054. {
  1055. OnPartBuiltServer(p, partName, AT_BUILD_PART);
  1056. }
  1057. }
  1058. GetConstruction().UpdateVisuals();
  1059. }
  1060. }
  1061. void bsbDebugPrint (string s)
  1062. {
  1063. #ifdef BSB_DEBUG
  1064. PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
  1065. #else
  1066. //Print("" + s); // comment/uncomment to hide/see debug logs
  1067. #endif
  1068. }
  1069. void bsbDebugSpam (string s)
  1070. {
  1071. #ifdef BSB_DEBUG_SPAM
  1072. PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
  1073. #else
  1074. //Print("" + s); // comment/uncomment to hide/see debug logs
  1075. #endif
  1076. }