construction.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366
  1. enum ConstructionMaterialType
  2. {
  3. MATERIAL_NONE = 0,
  4. MATERIAL_LOG = 1,
  5. MATERIAL_WOOD = 2,
  6. MATERIAL_STAIRS = 3,
  7. MATERIAL_METAL = 4,
  8. MATERIAL_WIRE = 5
  9. }
  10. class Construction
  11. {
  12. static const float REPAIR_MATERIAL_PERCENTAGE = 0.15;
  13. static const float DECONSTURCT_MATERIAL_LOSS = 0.2;
  14. protected ref map<string, ref ConstructionPart> m_ConstructionParts; //string - part name; int - 0-not constructed, 1-constructed
  15. protected BaseBuildingBase m_Parent;
  16. //Debug
  17. protected Shape m_CollisionBox;
  18. //Collision detectection
  19. protected ConstructionBoxTrigger m_ConstructionBoxTrigger;
  20. //============================================
  21. // Construction
  22. //============================================
  23. void Construction( BaseBuildingBase parent )
  24. {
  25. m_ConstructionParts = new ref map<string, ref ConstructionPart>;
  26. //set parent object
  27. SetParent( parent );
  28. }
  29. void Init()
  30. {
  31. UpdateConstructionParts();
  32. }
  33. //parent
  34. protected BaseBuildingBase GetParent()
  35. {
  36. return m_Parent;
  37. }
  38. protected void SetParent( BaseBuildingBase parent )
  39. {
  40. m_Parent = parent;
  41. }
  42. //============================================
  43. // Construction process
  44. //============================================
  45. //constructed parts
  46. void AddToConstructedParts( string part_name )
  47. {
  48. ConstructionPart constrution_part = GetConstructionPart( part_name );
  49. if ( constrution_part )
  50. {
  51. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " AddToConstructedParts part=" + constrution_part.GetPartName());
  52. constrution_part.SetBuiltState( true );
  53. }
  54. }
  55. void RemoveFromConstructedParts( string part_name )
  56. {
  57. ConstructionPart constrution_part = GetConstructionPart( part_name );
  58. if ( constrution_part )
  59. {
  60. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " RemoveFromConstructedParts part=" + constrution_part.GetPartName());
  61. constrution_part.SetBuiltState( false );
  62. }
  63. }
  64. //BuildPart
  65. void BuildPartServer( notnull Man player, string part_name, int action_id )
  66. {
  67. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction BuildPartServer | " + part_name);
  68. //reset DamageZone health
  69. string damage_zone;
  70. if (DamageSystem.GetDamageZoneFromComponentName(GetParent(),part_name,damage_zone))
  71. {
  72. GetParent().SetAllowDamage(true);
  73. GetParent().SetHealthMax(damage_zone);
  74. GetParent().ProcessInvulnerabilityCheck(GetParent().GetInvulnerabilityTypeString());
  75. }
  76. //on action
  77. TakeMaterialsServer( part_name );
  78. //destroy build collision check trigger
  79. DestroyCollisionTrigger();
  80. //call event
  81. GetParent().OnPartBuiltServer( player, part_name, action_id );
  82. }
  83. //DismantlePart
  84. void DismantlePartServer( notnull Man player, string part_name, int action_id )
  85. {
  86. string damage_zone;
  87. DamageSystem.GetDamageZoneFromComponentName( GetParent(),part_name,damage_zone );
  88. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DismantlePartServer | " + part_name);
  89. //receive materials
  90. ReceiveMaterialsServer( player, part_name, damage_zone );
  91. //drop non-usable materials
  92. DropNonUsableMaterialsServer( player, part_name );
  93. //call event
  94. GetParent().OnPartDismantledServer( player, part_name, action_id );
  95. //set DamageZone health to zero (redundant?)
  96. /*if ( GetParent().GetHealth(damage_zone,"Health") > 0 )
  97. {
  98. GetParent().SetHealth(damage_zone,"Health",0);
  99. }*/
  100. }
  101. //DestroyPart
  102. void DestroyPartServer( Man player, string part_name, int action_id, bool destroyed_by_connected_part = false )
  103. {
  104. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DestroyPartServer | " + part_name);
  105. //destroy attached materials (if locked)
  106. DestroyMaterialsServer( player, part_name );
  107. //drop non-usable materials
  108. DropNonUsableMaterialsServer( player, part_name );
  109. //call event
  110. GetParent().OnPartDestroyedServer( player, part_name, action_id, destroyed_by_connected_part );
  111. //set DamageZone health to zero (redundant?)
  112. string damage_zone;
  113. if ( DamageSystem.GetDamageZoneFromComponentName(GetParent(),part_name,damage_zone) && GetParent().GetHealth(damage_zone,"Health") > 0 )
  114. {
  115. GetParent().SetHealth(damage_zone,"Health",0);
  116. }
  117. }
  118. void DestroyConnectedParts(string part_name)
  119. {
  120. array<string> parts;// = new array<string>;
  121. parts = GetValidDepenentPartsArray(part_name);
  122. if (parts)
  123. {
  124. for (int i = 0; i < parts.Count(); i++)
  125. {
  126. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DestroyConnectedParts | " + parts.Get(i));
  127. if (!ExceptionCheck(parts.Get(i)))
  128. DestroyPartServer(null,parts.Get(i),AT_DESTROY_PART,true);
  129. }
  130. }
  131. }
  132. //!Exceptions from 'dependent parts' hierarchy are handled here
  133. bool ExceptionCheck(string part_name)
  134. {
  135. //gate hack
  136. ConstructionPart part = GetConstructionPart(part_name);
  137. if( /*Fence.Cast(m_Parent) && */part.IsGate() )
  138. {
  139. if( GetConstructionPart("wall_base_down").IsBuilt() || GetConstructionPart("wall_base_up").IsBuilt() )
  140. return true;
  141. }
  142. return false;
  143. }
  144. //============================================
  145. // Update construction
  146. //============================================
  147. //update visual
  148. void InitVisuals()
  149. {
  150. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " InitVisuals");
  151. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  152. {
  153. string key = m_ConstructionParts.GetKey( i );
  154. ConstructionPart value = m_ConstructionParts.Get( key );
  155. if ( value.IsBuilt() )
  156. {
  157. ShowConstructionPart( value.GetPartName() );
  158. }
  159. }
  160. }
  161. void UpdateVisuals()
  162. {
  163. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " UpdateVisuals");
  164. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  165. {
  166. string key = m_ConstructionParts.GetKey( i );
  167. ConstructionPart value = m_ConstructionParts.Get( key );
  168. if ( value.IsBuilt() )
  169. {
  170. ShowConstructionPart( value.GetPartName() );
  171. }
  172. else
  173. {
  174. HideConstructionPart( value.GetPartName() );
  175. }
  176. }
  177. }
  178. //update physics (only)
  179. void UpdatePhysics()
  180. {
  181. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " UpdatePhysics m_ConstructionParts=" + m_ConstructionParts.Count());
  182. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  183. {
  184. string key = m_ConstructionParts.GetKey( i );
  185. ConstructionPart value = m_ConstructionParts.Get( key );
  186. if ( value.IsBuilt() )
  187. {
  188. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] GetType=" + m_Parent.GetType() + " i=" + i + " ADD");
  189. ShowConstructionPartPhysics( value.GetPartName() );
  190. }
  191. else
  192. {
  193. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] GetType=" + m_Parent.GetType() + " i=" + i + " RM");
  194. HideConstructionPartPhysics( value.GetPartName() );
  195. }
  196. }
  197. }
  198. void InitBaseState ()
  199. {
  200. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_Parent) + " InitBaseState");
  201. InitVisuals();
  202. }
  203. //update construction parts
  204. protected void UpdateConstructionParts()
  205. {
  206. m_ConstructionParts.Clear();
  207. string construction_path = "cfgVehicles" + " " + GetParent().GetType() + " " + "Construction";
  208. if ( GetGame().ConfigIsExisting( construction_path ) )
  209. {
  210. //main parts
  211. for ( int i = 0; i < GetGame().ConfigGetChildrenCount( construction_path ); ++i )
  212. {
  213. string main_part_name;
  214. GetGame().ConfigGetChildName( construction_path, i, main_part_name );
  215. string part_path = construction_path + " " + main_part_name;
  216. //parts
  217. for ( int j = 0; j < GetGame().ConfigGetChildrenCount( part_path ); ++j )
  218. {
  219. string part_name;
  220. GetGame().ConfigGetChildName( part_path, j, part_name );
  221. string name;
  222. GetGame().ConfigGetTextRaw( part_path + " " + part_name + " " + "name", name ); //name
  223. GetGame().FormatRawConfigStringKeys(name);
  224. bool show_on_init = GetGame().ConfigGetInt( part_path + " " + part_name + " " + "show_on_init" ); //show on init
  225. int id = GetGame().ConfigGetInt( part_path + " " + part_name + " " + "id" ); //part id
  226. bool is_base = GetGame().ConfigGetInt( part_path + " " + part_name + " " + "is_base" ); //is base (part)
  227. bool is_gate = GetGame().ConfigGetInt( part_path + " " + part_name + " " + "is_gate" ); //is gate (part)
  228. m_ConstructionParts.Insert( part_name, new ConstructionPart( name, part_name, main_part_name, id, show_on_init, is_base, is_gate, GetRequiredParts(part_name,main_part_name) ) );
  229. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction name=" + name + " part_name=" + part_name + " show=" + show_on_init + " base=" + is_base + " gate=" + is_gate);
  230. }
  231. }
  232. }
  233. }
  234. //============================================
  235. // Parts
  236. //============================================
  237. map<string, ref ConstructionPart> GetConstructionParts()
  238. {
  239. return m_ConstructionParts;
  240. }
  241. ConstructionPart GetConstructionPart( string part_name )
  242. {
  243. return m_ConstructionParts.Get( part_name );
  244. }
  245. //CONSTRUCTION
  246. /*ConstructionPart GetConstructionPartToBuild( string part_name, ItemBase tool )
  247. {
  248. if ( CanBuildPart( part_name, tool ) )
  249. {
  250. return GetConstructionPart( part_name );
  251. }
  252. return NULL;
  253. }*/
  254. bool CanBuildPart( string part_name, ItemBase tool, bool use_tool )
  255. {
  256. if ( !IsPartConstructed( part_name ) && HasRequiredPart( part_name ) && !HasConflictPart( part_name ) && HasMaterials( part_name ) && (!use_tool || CanUseToolToBuildPart( part_name, tool )) && !MaterialIsRuined(part_name) )
  257. {
  258. return true;
  259. }
  260. return false;
  261. }
  262. bool MaterialIsRuined(string part_name)
  263. {
  264. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  265. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  266. if ( GetGame().ConfigIsExisting( cfg_path ) )
  267. {
  268. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  269. for ( int i = 0; i < child_count; i++ )
  270. {
  271. string child_name;
  272. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  273. //get type, quantity from material
  274. string config_path;
  275. string slot_name;
  276. config_path = cfg_path + " " + child_name + " " + "slot_name";
  277. GetGame().ConfigGetText( config_path, slot_name );
  278. config_path = cfg_path + " " + child_name + " " + "quantity";
  279. float quantity = GetGame().ConfigGetFloat( config_path );
  280. config_path = cfg_path + " " + child_name + " " + "lockable";
  281. bool lockable = GetGame().ConfigGetInt( config_path );
  282. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( slot_name ) );
  283. if (attachment.IsRuined())
  284. return true;
  285. }
  286. }
  287. return false;
  288. }
  289. //Get all construction parts that can be build (at that current time)
  290. void GetConstructionPartsToBuild( string main_part_name, out array<ConstructionPart> construction_parts, ItemBase tool, out string real_constructionTarget, bool use_tool )
  291. {
  292. construction_parts.Clear();
  293. string part_name;
  294. ConstructionPart value;
  295. string key;
  296. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  297. {
  298. key = m_ConstructionParts.GetKey( i );
  299. value = m_ConstructionParts.Get( key );
  300. if ( main_part_name == value.GetMainPartName() && CanBuildPart( value.GetPartName(), tool, use_tool ) )
  301. {
  302. construction_parts.Insert( value );
  303. }
  304. if ( main_part_name == value.GetPartName() )
  305. {
  306. part_name = value.GetMainPartName();
  307. }
  308. }
  309. if( construction_parts.Count() == 0 && part_name )
  310. {
  311. for ( i = 0; i < m_ConstructionParts.Count(); ++i )
  312. {
  313. key = m_ConstructionParts.GetKey( i );
  314. value = m_ConstructionParts.Get( key );
  315. if ( part_name == value.GetMainPartName() && CanBuildPart( value.GetPartName(), tool, use_tool ) )
  316. {
  317. construction_parts.Insert( value );
  318. }
  319. }
  320. }
  321. }
  322. //Returns (first found) base construction part
  323. ConstructionPart GetBaseConstructionPart()
  324. {
  325. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  326. {
  327. string key = m_ConstructionParts.GetKey( i );
  328. ConstructionPart value = m_ConstructionParts.Get( key );
  329. if ( value.IsBase() )
  330. {
  331. return value;
  332. }
  333. }
  334. return NULL;
  335. }
  336. //Returns (first found) gate construction part
  337. ConstructionPart GetGateConstructionPart()
  338. {
  339. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  340. {
  341. string key = m_ConstructionParts.GetKey( i );
  342. ConstructionPart value = m_ConstructionParts.Get( key );
  343. if ( value.IsGate() )
  344. {
  345. return value;
  346. }
  347. }
  348. return NULL;
  349. }
  350. //checks if construction part has required part already built
  351. protected bool HasRequiredPart( string part_name )
  352. {
  353. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  354. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "required_parts";
  355. ref array<string> required_parts = new array<string>;
  356. GetGame().ConfigGetTextArray( cfg_path, required_parts );
  357. //check if parts are already built
  358. for ( int i = 0; i < required_parts.Count(); ++i )
  359. {
  360. if ( !IsPartConstructed( required_parts.Get( i ) ) )
  361. {
  362. return false;
  363. }
  364. //hack - gate
  365. /*else if (part_name == "wall_gate" && (IsPartConstructed("wall_base_down") || IsPartConstructed("wall_base_up")))
  366. {
  367. return true;
  368. }*/
  369. }
  370. return true;
  371. }
  372. //checks if there are conflict parts already built
  373. protected bool HasConflictPart( string part_name )
  374. {
  375. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  376. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "conflicted_parts";
  377. ref array<string> conflict_parts = new array<string>;
  378. GetGame().ConfigGetTextArray( cfg_path, conflict_parts );
  379. //check if parts are already built
  380. for ( int i = 0; i < conflict_parts.Count(); i++ )
  381. {
  382. if ( IsPartConstructed( conflict_parts.Get( i ) ) )
  383. {
  384. return true;
  385. }
  386. }
  387. return false;
  388. }
  389. //DECONSTRUCTION
  390. ConstructionPart GetConstructionPartToDismantle( string part_name, ItemBase tool )
  391. {
  392. if ( CanDismantlePart( part_name, tool ) )
  393. {
  394. return GetConstructionPart( part_name );
  395. }
  396. return NULL;
  397. }
  398. bool CanDismantlePart( string part_name, ItemBase tool )
  399. {
  400. if ( IsPartConstructed( part_name ) && !HasDependentPart( part_name ) && CanUseToolToDismantlePart( part_name, tool ) )
  401. {
  402. return true;
  403. }
  404. return false;
  405. }
  406. //checks if construction part has dependent part (that is already built) because of which it cannot be deconstruct
  407. bool HasDependentPart( string part_name )
  408. {
  409. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  410. {
  411. string key = m_ConstructionParts.GetKey( i );
  412. ConstructionPart construction_part = m_ConstructionParts.Get( key );
  413. if ( construction_part.IsBuilt() )
  414. {
  415. if ( construction_part.GetRequiredParts().Find( part_name ) > -1 )
  416. {
  417. return true;
  418. }
  419. }
  420. }
  421. return false;
  422. }
  423. //returns array of BUILT parts that directly depend on 'part_name'
  424. protected array<string> GetValidDepenentPartsArray( string part_name, array<string> recurs = null )
  425. {
  426. string name;
  427. string cfg_path;
  428. ref array<string> dependent_parts;
  429. for ( int i = 0; i < m_ConstructionParts.Count(); ++i )
  430. {
  431. name = m_ConstructionParts.GetKey( i );
  432. ConstructionPart construction_part = m_ConstructionParts.Get( name );
  433. if ( construction_part.IsBuilt() && construction_part.GetRequiredParts() && construction_part.GetRequiredParts().Find( part_name ) > -1 ) //does the construction part need 'part_name' to exist?
  434. {
  435. if ( !dependent_parts )
  436. {
  437. dependent_parts = new array<string>;
  438. }
  439. if ( !recurs || (recurs.Find(name) == -1 ) )
  440. {
  441. dependent_parts.Insert(name);
  442. }
  443. // Print("part #" + i + ": " + name);
  444. }
  445. }
  446. //fully recursive search, disconnected (unnescessary)
  447. /*if (dependent_parts)
  448. {
  449. if ( dependent_parts.Count() > 0 )
  450. {
  451. ref array<string> temp = new array<string>;
  452. for ( i = 0; i < dependent_parts.Count(); i++ )
  453. {
  454. temp = GetValidDepenentPartsArray(dependent_parts.Get(i),dependent_parts);
  455. if (temp.Count() > 0)
  456. {
  457. dependent_parts.InsertAll(temp);
  458. }
  459. }
  460. }
  461. Print("dependent_parts.Count(): " + dependent_parts.Count());
  462. }*/
  463. return dependent_parts;
  464. }
  465. //gets all required parts of a construction part; fills into ConstructionPart on init
  466. array<string> GetRequiredParts( string part_name, string main_part_name )
  467. {
  468. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " " + "Construction" + " " + main_part_name + " " + part_name + " " + "required_parts";
  469. ref array<string> required_parts = new array<string>;
  470. GetGame().ConfigGetTextArray( cfg_path, required_parts );
  471. return required_parts;
  472. }
  473. //DESTROY
  474. ConstructionPart GetConstructionPartToDestroy( string part_name )
  475. {
  476. if ( CanDestroyPart( part_name ) )
  477. {
  478. return GetConstructionPart( part_name );
  479. }
  480. return NULL;
  481. }
  482. bool CanDestroyPart( string part_name )
  483. {
  484. if ( IsPartConstructed( part_name ) && !HasDependentPart( part_name ) )
  485. {
  486. return true;
  487. }
  488. return false;
  489. }
  490. //CONSTRUCTION PART STATE
  491. //show/hide construction part
  492. protected void ShowConstructionPart( string part_name )
  493. {
  494. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction ShowConstructionPart - " + part_name);
  495. GetParent().SetAnimationPhase( part_name, 0 );
  496. }
  497. protected void HideConstructionPart( string part_name )
  498. {
  499. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction HideConstructionPart - " + part_name);
  500. GetParent().SetAnimationPhase( part_name, 1 );
  501. }
  502. //show/hide physics
  503. void ShowConstructionPartPhysics( string part_name )
  504. {
  505. GetParent().AddProxyPhysics( part_name );
  506. }
  507. void HideConstructionPartPhysics( string part_name )
  508. {
  509. GetParent().RemoveProxyPhysics( part_name );
  510. }
  511. //is part constructed
  512. bool IsPartConstructed( string part_name )
  513. {
  514. ConstructionPart construction_part = GetConstructionPart( part_name );
  515. if ( construction_part && construction_part.IsBuilt() )
  516. {
  517. return true;
  518. }
  519. return false;
  520. }
  521. //============================================
  522. // Materials for construction
  523. //============================================
  524. //has materials
  525. bool HasMaterials( string part_name, bool repairing = false )
  526. {
  527. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  528. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  529. if ( GetGame().ConfigIsExisting( cfg_path ) )
  530. {
  531. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  532. for ( int i = 0; i < child_count; i++ )
  533. {
  534. string child_name;
  535. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  536. //get type, quantity from material
  537. string material_path;
  538. string slot_name;
  539. float quantity;
  540. material_path = cfg_path + " " + child_name + " " + "slot_name";
  541. GetGame().ConfigGetText( material_path, slot_name );
  542. material_path = cfg_path + " " + child_name + " " + "quantity";
  543. quantity = GetGame().ConfigGetFloat( material_path );
  544. if (repairing)
  545. {
  546. quantity *= REPAIR_MATERIAL_PERCENTAGE;
  547. quantity = Math.Max(Math.Floor(quantity),1);
  548. }
  549. //if the selected material (or its quantity) is not available
  550. if ( !HasMaterialWithQuantityAttached( slot_name, quantity ) )
  551. {
  552. return false;
  553. }
  554. }
  555. }
  556. return true; //return true even if no material required
  557. }
  558. //check if parent object has attachment of required quantity attached to it
  559. protected bool HasMaterialWithQuantityAttached( string slot_name, float quantity )
  560. {
  561. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( slot_name ) );
  562. if ( attachment && attachment.GetQuantity() >= quantity )
  563. {
  564. return true;
  565. }
  566. return false;
  567. }
  568. //take materials when building
  569. void TakeMaterialsServer( string part_name, bool repairing = false )
  570. {
  571. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  572. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  573. if ( GetGame().ConfigIsExisting( cfg_path ) )
  574. {
  575. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  576. for ( int i = 0; i < child_count; i++ )
  577. {
  578. string child_name;
  579. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  580. //get type, quantity from material
  581. string config_path;
  582. string slot_name;
  583. config_path = cfg_path + " " + child_name + " " + "slot_name";
  584. GetGame().ConfigGetText( config_path, slot_name );
  585. config_path = cfg_path + " " + child_name + " " + "quantity";
  586. float quantity = GetGame().ConfigGetFloat( config_path );
  587. config_path = cfg_path + " " + child_name + " " + "lockable";
  588. bool lockable = GetGame().ConfigGetInt( config_path );
  589. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( slot_name ) );
  590. if ( lockable )
  591. {
  592. //lock attachment
  593. InventoryLocation inventory_location = new InventoryLocation;
  594. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  595. GetParent().GetInventory().SetSlotLock( inventory_location.GetSlot(), true );
  596. }
  597. else
  598. {
  599. if ( quantity > -1 ) //0 - ignores quantity
  600. {
  601. if (repairing)
  602. {
  603. quantity *= REPAIR_MATERIAL_PERCENTAGE;
  604. quantity = Math.Max(Math.Floor(quantity),1);
  605. }
  606. //subtract quantity
  607. attachment.AddQuantity( -quantity );
  608. }
  609. else //-1 - deletes the object
  610. {
  611. GetGame().ObjectDelete( attachment );
  612. }
  613. }
  614. }
  615. }
  616. }
  617. //receive materials when dismantling
  618. protected void ReceiveMaterialsServer( notnull Man player, string part_name, string damagezone_name )
  619. {
  620. ConstructionPart construction_part = GetConstructionPart( part_name );
  621. bool is_base = construction_part.IsBase();
  622. string main_part_name = construction_part.GetMainPartName();
  623. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  624. if ( GetGame().ConfigIsExisting( cfg_path ) )
  625. {
  626. StaticConstructionMethods.SpawnConstructionMaterialPiles(GetParent(),player,cfg_path,part_name,damagezone_name,is_base);
  627. }
  628. }
  629. //destroy lockable materials when destroying
  630. protected void DestroyMaterialsServer( Man player, string part_name )
  631. {
  632. ConstructionPart cPart = GetConstructionPart( part_name );
  633. string main_part_name = cPart.GetMainPartName();
  634. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  635. if ( GetGame().ConfigIsExisting( cfg_path ) )
  636. {
  637. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  638. for ( int i = 0; i < child_count; i++ )
  639. {
  640. string child_name;
  641. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  642. //get type, quantity from material
  643. string config_path;
  644. string type;
  645. string slot_name;
  646. config_path = cfg_path + " " + child_name + " " + "type";
  647. GetGame().ConfigGetText( config_path, type );
  648. config_path = cfg_path + " " + child_name + " " + "slot_name";
  649. GetGame().ConfigGetText( config_path, slot_name );
  650. config_path = cfg_path + " " + child_name + " " + "quantity";
  651. float quantity = GetGame().ConfigGetFloat( config_path );
  652. config_path = cfg_path + " " + child_name + " " + "lockable";
  653. bool lockable = GetGame().ConfigGetInt( config_path );
  654. //get material
  655. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( slot_name ) );
  656. //material still attached
  657. if ( lockable ) //if lockable
  658. {
  659. if ( attachment )
  660. {
  661. InventoryLocation inventory_location = new InventoryLocation;
  662. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  663. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(GetParent()) + " DestroyMaterialsServer unlock slot=" + inventory_location.GetSlot());
  664. GetParent().GetInventory().SetSlotLock( inventory_location.GetSlot() , false );
  665. GetGame().ObjectDelete( attachment ); //delete object
  666. }
  667. }
  668. }
  669. }
  670. }
  671. void DropNonUsableMaterialsServer( Man player, string part_name )
  672. {
  673. ConstructionPart construction_part = GetConstructionPart( part_name );
  674. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " " + "Construction" + " " + construction_part.GetMainPartName() + " " + construction_part.GetPartName() + " " + "platform_support";
  675. string platform_support;
  676. if ( GetGame().ConfigIsExisting( cfg_path ) )
  677. {
  678. GetGame().ConfigGetText( cfg_path, platform_support );
  679. }
  680. if ( platform_support.Length() > 0 || construction_part.IsBase() )
  681. {
  682. string at_cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "GUIInventoryAttachmentsProps";
  683. if ( GetGame().ConfigIsExisting( at_cfg_path ) )
  684. {
  685. int child_count = GetGame().ConfigGetChildrenCount( at_cfg_path );
  686. for ( int i = 0; i < child_count; i++ )
  687. {
  688. string child_name;
  689. GetGame().ConfigGetChildName( at_cfg_path, i, child_name );
  690. child_name.ToLower();
  691. if ( child_name.Contains( platform_support ) )
  692. {
  693. ref array<string> attachment_slots = new array<string>;
  694. GetGame().ConfigGetTextArray( at_cfg_path + " " + child_name + " " + "attachmentSlots", attachment_slots );
  695. for ( int j = 0; j < attachment_slots.Count(); ++j )
  696. {
  697. //get material
  698. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( attachment_slots.Get( j ) ) );
  699. //material still attached
  700. if ( attachment )
  701. {
  702. InventoryLocation inventory_location = new InventoryLocation;
  703. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  704. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(GetParent()) + " DropNonUsableMaterials UNlocking slot=" + inventory_location.GetSlot());
  705. //unlock slot
  706. GetParent().GetInventory().SetSlotLock( inventory_location.GetSlot() , false );
  707. EntityAI parent = GetParent();
  708. if (!parent)
  709. parent = player;
  710. int quantity_max = attachment.GetTargetQuantityMax(-1);
  711. InventoryLocation dst = new InventoryLocation;
  712. vector mat[4];
  713. attachment.GetTransform(mat);
  714. //TODO: why are we spawning and deleting here, instead of moving to location??
  715. if ( parent.MemoryPointExists("" + part_name + "_materials") )
  716. {
  717. vector destination = parent.GetMemoryPointPos("" + part_name + "_materials");
  718. destination = GetGame().ObjectModelToWorld(parent,destination);
  719. float health = attachment.GetHealth("","Health");
  720. float quantity = attachment.GetQuantity() - 1;
  721. if (quantity < 1.0)
  722. quantity = 1.0;
  723. float dir[4];
  724. inventory_location.GetDir(dir);
  725. dst.SetGroundEx(attachment,destination,dir);
  726. if (player)
  727. {
  728. vector posHead;
  729. MiscGameplayFunctions.GetHeadBonePos(PlayerBase.Cast(player),posHead);
  730. MiscGameplayFunctions.CreateItemBasePilesDispersed(attachment.GetType(),posHead,destination,UAItemsSpreadRadius.NARROW,quantity,health,player);
  731. }
  732. else
  733. {
  734. MiscGameplayFunctions.CreateItemBasePiles(attachment.GetType(),destination,quantity,health,true);
  735. }
  736. attachment.AddQuantity( -quantity );
  737. }
  738. else
  739. {
  740. dst.SetGround(attachment,mat);
  741. for ( int k = attachment.GetQuantity(); k > quantity_max; )
  742. {
  743. Object o = parent.GetInventory().LocationCreateEntity( dst, attachment.GetType(), ECE_PLACE_ON_SURFACE, RF_DEFAULT );
  744. ItemBase new_item = ItemBase.Cast( o );
  745. if( new_item )
  746. {
  747. MiscGameplayFunctions.TransferItemProperties( attachment, new_item );
  748. attachment.AddQuantity( -quantity_max );
  749. new_item.SetQuantity( quantity_max );
  750. }
  751. k -= quantity_max;
  752. }
  753. }
  754. //drop
  755. if (attachment.GetQuantity() > 0)
  756. {
  757. if ( GetGame().IsMultiplayer() )
  758. {
  759. parent.ServerTakeToDst( inventory_location, dst );
  760. }
  761. else
  762. {
  763. parent.LocalTakeToDst( inventory_location, dst );
  764. }
  765. }
  766. else
  767. {
  768. attachment.Delete();
  769. }
  770. }
  771. }
  772. }
  773. }
  774. }
  775. }
  776. }
  777. //set lock on materials that are attached and cannot be locked/unlocked
  778. void SetLockOnAttachedMaterials( string part_name, bool lock_slot )
  779. {
  780. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  781. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "Materials";
  782. if ( GetGame().ConfigIsExisting( cfg_path ) )
  783. {
  784. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  785. for ( int i = 0; i < child_count; i++ )
  786. {
  787. string child_name;
  788. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  789. //get type, quantity from material
  790. string config_path;
  791. string type;
  792. string slot_name;
  793. config_path = cfg_path + " " + child_name + " " + "type";
  794. GetGame().ConfigGetText( config_path, type );
  795. config_path = cfg_path + " " + child_name + " " + "slot_name";
  796. GetGame().ConfigGetText( config_path, slot_name );
  797. config_path = cfg_path + " " + child_name + " " + "quantity";
  798. float quantity = GetGame().ConfigGetFloat( config_path );
  799. config_path = cfg_path + " " + child_name + " " + "lockable";
  800. bool lockable = GetGame().ConfigGetInt( config_path );
  801. //get material
  802. ItemBase attachment = ItemBase.Cast( GetParent().FindAttachmentBySlotName( slot_name ) );
  803. //material still attached
  804. if ( lockable ) //if lockable
  805. {
  806. if ( attachment )
  807. {
  808. InventoryLocation inventory_location = new InventoryLocation;
  809. attachment.GetInventory().GetCurrentInventoryLocation( inventory_location );
  810. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(GetParent()) + " SetLockOnAttachedMaterials lock=" + lock_slot +" slot=" + inventory_location.GetSlot());
  811. GetParent().GetInventory().SetSlotLock( inventory_location.GetSlot(), lock_slot );
  812. }
  813. }
  814. }
  815. }
  816. }
  817. //============================================
  818. // Construction tools
  819. //============================================
  820. bool CanUseToolToBuildPart( string part_name, ItemBase tool )
  821. {
  822. ConstructionPart construction_part = GetConstructionPart( part_name );
  823. string part_cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + construction_part.GetMainPartName() + " " + construction_part.GetPartName() + " " + "build_action_type";
  824. if ( GetGame().ConfigIsExisting( part_cfg_path ) )
  825. {
  826. int part_build_action_type = GetGame().ConfigGetInt( part_cfg_path );
  827. string tool_cfg_path = "cfgVehicles" + " " + tool.GetType() + " " + "build_action_type";
  828. if ( GetGame().ConfigIsExisting( tool_cfg_path ) )
  829. {
  830. int tool_build_action_type = GetGame().ConfigGetInt( tool_cfg_path );
  831. if ( ( part_build_action_type & tool_build_action_type ) > 0 )
  832. {
  833. return true;
  834. }
  835. }
  836. }
  837. return false;
  838. }
  839. bool CanUseToolToDismantlePart( string part_name, ItemBase tool )
  840. {
  841. ConstructionPart construction_part = GetConstructionPart( part_name );
  842. string part_cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + construction_part.GetMainPartName() + " " + construction_part.GetPartName() + " " + "dismantle_action_type";
  843. if ( GetGame().ConfigIsExisting( part_cfg_path ) )
  844. {
  845. int part_dismantle_action_type = GetGame().ConfigGetInt( part_cfg_path );
  846. string tool_cfg_path = "cfgVehicles" + " " + tool.GetType() + " " + "dismantle_action_type";
  847. if ( GetGame().ConfigIsExisting( tool_cfg_path ) )
  848. {
  849. int tool_dismantle_action_type = GetGame().ConfigGetInt( tool_cfg_path );
  850. if ( ( part_dismantle_action_type & tool_dismantle_action_type ) > 0 )
  851. {
  852. return true;
  853. }
  854. }
  855. }
  856. return false;
  857. }
  858. ConstructionMaterialType GetMaterialType( string part_name )
  859. {
  860. ConstructionPart construction_part = GetConstructionPart( part_name );
  861. string part_cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + construction_part.GetMainPartName() + " " + construction_part.GetPartName() + " " + "material_type";
  862. if ( GetGame().ConfigIsExisting( part_cfg_path ) )
  863. {
  864. return GetGame().ConfigGetInt( part_cfg_path );
  865. }
  866. return ConstructionMaterialType.MATERIAL_NONE;
  867. }
  868. //============================================
  869. // Collision check
  870. //============================================
  871. //Collisions (BBox and Trigger); deprecated
  872. bool IsColliding( string part_name )
  873. {
  874. if (CfgGameplayHandler.GetDisableIsCollidingCheck())
  875. return false;
  876. ConstructionPart construction_part = GetConstructionPart( part_name );
  877. if ( construction_part )
  878. {
  879. vector center;
  880. float absolute_ofset = 0.05; //we need to lift BBox even more, because it colliddes with house floors due to various reasons (probably geometry or float imperfections)
  881. vector edge_length;
  882. vector min_max[2]; //data used for creating trigger
  883. ref array<Object> excluded_objects = new array<Object>;
  884. ref array<Object> collided_objects = new array<Object>;
  885. excluded_objects.Insert( GetParent() );
  886. //get min_max and center from config and memory points
  887. GetCollisionBoxData( part_name, min_max );
  888. center = GetBoxCenter( min_max );
  889. center = GetParent().ModelToWorld( center ); //convert to world coordinates
  890. edge_length = GetCollisionBoxSize( min_max );
  891. //Create trigger
  892. //CreateCollisionTrigger( part_name, min_max, center );
  893. //check collision on box trigger and collision box
  894. //IsTrigger colliding was turned off (for now) for easier way to build something with other players around
  895. if ( /* IsTriggerColliding() || */ GetGame().IsBoxCollidingGeometry( Vector( center[0], center[1] + absolute_ofset, center[2] ), GetParent().GetOrientation(), edge_length, ObjIntersectView, ObjIntersectGeom, excluded_objects, collided_objects ) )
  896. {
  897. //Debug
  898. // DrawDebugCollisionBox( min_max, ARGB( 150, 255, 0, 0 ) );
  899. //
  900. for (int i = 0; i < collided_objects.Count(); i++)
  901. {
  902. //Print(collided_objects.Get(i).GetType());
  903. EntityAI entity = EntityAI.Cast(collided_objects.Get(i));
  904. if ( entity && !entity.IsIgnoredByConstruction() )
  905. return true;
  906. }
  907. }
  908. //Debug
  909. // DrawDebugCollisionBox( min_max, ARGB( 150, 255, 255, 255 ) );
  910. }
  911. return false;
  912. }
  913. //! Collision check for building part
  914. bool IsCollidingEx( CollisionCheckData check_data )
  915. {
  916. if (CfgGameplayHandler.GetDisableIsCollidingCheck())
  917. return false;
  918. ConstructionPart construction_part = GetConstructionPart( check_data.m_PartName );
  919. if ( construction_part )
  920. {
  921. vector center;
  922. float absolute_ofset = 0.05; //we need to lift BBox even more, because it colliddes with house floors due to various reasons (probably geometry or float imperfections)
  923. vector edge_length;
  924. vector min_max[2]; //data used for creating trigger
  925. ref array<Object> excluded_objects = new array<Object>;
  926. ref array<Object> collided_objects = new array<Object>;
  927. excluded_objects.Insert( GetParent() );
  928. if (check_data.m_AdditionalExcludes.Count() > 0)
  929. {
  930. excluded_objects.InsertAll(check_data.m_AdditionalExcludes);
  931. }
  932. GetCollisionBoxData( check_data.m_PartName, min_max );
  933. center = GetBoxCenter( min_max );
  934. center = GetParent().ModelToWorld( center ); //convert to world coordinates
  935. edge_length = GetCollisionBoxSize( min_max );
  936. if ( GetGame().IsBoxCollidingGeometry( Vector( center[0], center[1] + absolute_ofset, center[2] ), GetParent().GetOrientation(), edge_length, check_data.m_PrimaryGeometry, check_data.m_SecondaryGeometry, excluded_objects, collided_objects ) )
  937. {
  938. //Debug
  939. //DrawDebugCollisionBox( min_max, ARGB( 150, 255, 0, 0 ) );
  940. for (int i = 0; i < collided_objects.Count(); i++)
  941. {
  942. EntityAI entity = EntityAI.Cast(collided_objects.Get(i));
  943. if ( entity && !entity.IsIgnoredByConstruction() )
  944. return true;
  945. }
  946. }
  947. //Debug
  948. //DrawDebugCollisionBox( min_max, ARGB( 150, 255, 255, 255 ) );
  949. }
  950. return false;
  951. }
  952. vector GetCollisionBoxSize( vector min_max[2] )
  953. {
  954. vector box_size = Vector( 0, 0, 0 );
  955. box_size[0] = Math.AbsFloat( min_max[1][0] - min_max[0][0] );
  956. box_size[1] = Math.AbsFloat( min_max[1][1] - min_max[0][1] );
  957. box_size[2] = Math.AbsFloat( min_max[1][2] - min_max[0][2] );
  958. return box_size;
  959. }
  960. //returns collision box data from construction config and model p3d
  961. protected void GetCollisionBoxData( string part_name, out vector min_max[2] )
  962. {
  963. string main_part_name = GetConstructionPart( part_name ).GetMainPartName();
  964. string cfg_path = "cfgVehicles" + " " + GetParent().GetType() + " "+ "Construction" + " " + main_part_name + " " + part_name + " " + "collision_data";
  965. ref array<string> collision_data = new array<string>;
  966. GetGame().ConfigGetTextArray( cfg_path, collision_data );
  967. if ( collision_data.Count() > 0 )
  968. {
  969. if ( GetParent().MemoryPointExists( collision_data[0] ) )
  970. {
  971. min_max[0] = GetParent().GetMemoryPointPos( collision_data[0] );
  972. }
  973. if ( GetParent().MemoryPointExists( collision_data[1] ) )
  974. {
  975. min_max[1] = GetParent().GetMemoryPointPos( collision_data[1] );
  976. }
  977. }
  978. }
  979. //returns center point of box defined by min/max values
  980. vector GetBoxCenter( vector min_max[2] )
  981. {
  982. vector center;
  983. center[0] = ( min_max[1][0] - min_max[0][0] ) / 2;
  984. center[1] = ( min_max[1][1] - min_max[0][1] ) / 2;
  985. center[2] = ( min_max[1][2] - min_max[0][2] ) / 2;
  986. center = Vector( min_max[1][0] - center[0], min_max[1][1] - center[1], min_max[1][2] - center[2] ); //offset to box center
  987. return center;
  988. }
  989. void GetTriggerExtents( vector min_max[2], out vector extents[2] )
  990. {
  991. vector egde_length = GetCollisionBoxSize( min_max );
  992. extents[0][0] = -egde_length[0] / 2; //min
  993. extents[0][1] = -egde_length[1] / 2;
  994. extents[0][2] = -egde_length[2] / 2;
  995. extents[1][0] = egde_length[0] / 2; //max
  996. extents[1][1] = egde_length[1] / 2;
  997. extents[1][2] = egde_length[2] / 2;
  998. }
  999. //Debug
  1000. protected void DrawDebugCollisionBox( vector min_max[2], int color )
  1001. {
  1002. DestroyDebugCollisionBox();
  1003. vector mat[4];
  1004. GetParent().GetTransform( mat );
  1005. m_CollisionBox = Debug.DrawBox( min_max[0], min_max[1], color );
  1006. m_CollisionBox.SetMatrix( mat );
  1007. }
  1008. protected void DestroyDebugCollisionBox()
  1009. {
  1010. if ( m_CollisionBox )
  1011. {
  1012. m_CollisionBox.Destroy();
  1013. m_CollisionBox = NULL;
  1014. }
  1015. }
  1016. void CreateCollisionTrigger( string part_name, vector min_max[2], vector center )
  1017. {
  1018. if ( m_ConstructionBoxTrigger )
  1019. {
  1020. if ( m_ConstructionBoxTrigger.GetPartName() == part_name ) //already created
  1021. {
  1022. return;
  1023. }
  1024. else
  1025. {
  1026. DestroyCollisionTrigger();
  1027. }
  1028. }
  1029. //get proper trigger extents (min<max)
  1030. vector extents[2];
  1031. GetTriggerExtents( min_max, extents );
  1032. //create trigger
  1033. m_ConstructionBoxTrigger = ConstructionBoxTrigger.Cast( GetGame().CreateObject( "ConstructionBoxTrigger", center, false, false, false ) );
  1034. m_ConstructionBoxTrigger.SetPosition( center );
  1035. m_ConstructionBoxTrigger.SetOrientation( GetParent().GetOrientation() );
  1036. m_ConstructionBoxTrigger.SetExtents( extents[0], extents[1] );
  1037. m_ConstructionBoxTrigger.SetPartName( part_name );
  1038. }
  1039. //
  1040. void DestroyCollisionTrigger()
  1041. {
  1042. GetGame().ObjectDelete( m_ConstructionBoxTrigger );
  1043. m_ConstructionBoxTrigger = NULL;
  1044. }
  1045. bool IsTriggerColliding()
  1046. {
  1047. return m_ConstructionBoxTrigger.IsColliding();
  1048. }
  1049. }
  1050. class StaticConstructionMethods
  1051. {
  1052. //! spawns material from any construction; 'player' parameter optional
  1053. static void SpawnConstructionMaterialPiles(notnull EntityAI entity, Man player, string cfg_path, string main_part_name, string damagezone_name = "", bool is_base = false )
  1054. {
  1055. int child_count = GetGame().ConfigGetChildrenCount( cfg_path );
  1056. for ( int i = 0; i < child_count; i++ )
  1057. {
  1058. string child_name;
  1059. GetGame().ConfigGetChildName( cfg_path, i, child_name );
  1060. //get type, quantity from material
  1061. string config_path;
  1062. string type;
  1063. string slot_name;
  1064. config_path = cfg_path + " " + child_name + " " + "type";
  1065. GetGame().ConfigGetText( config_path, type );
  1066. config_path = cfg_path + " " + child_name + " " + "slot_name";
  1067. GetGame().ConfigGetText( config_path, slot_name );
  1068. config_path = cfg_path + " " + child_name + " " + "quantity";
  1069. float quantity = GetGame().ConfigGetFloat( config_path );
  1070. config_path = cfg_path + " " + child_name + " " + "lockable";
  1071. bool lockable = GetGame().ConfigGetInt( config_path );
  1072. //receive material quantity
  1073. ItemBase attachment = ItemBase.Cast( entity.FindAttachmentBySlotName( slot_name ) );
  1074. int slot_id;
  1075. //material still attached
  1076. if ( lockable ) //if lockable
  1077. {
  1078. if ( attachment )
  1079. {
  1080. InventoryLocation src = new InventoryLocation;
  1081. attachment.GetInventory().GetCurrentInventoryLocation( src );
  1082. if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName( entity) + " DropNonUsableMaterials UNlocking slot=" + src.GetSlot() );
  1083. entity.GetInventory().SetSlotLock( src.GetSlot() , false );
  1084. //detach if base
  1085. if ( is_base )
  1086. {
  1087. if ( GetGame().IsMultiplayer() && player )
  1088. {
  1089. InventoryLocation dst = new InventoryLocation;
  1090. GameInventory.SetGroundPosByOwner( player, src.GetItem(), dst );
  1091. player.ServerTakeToDst( src, dst );
  1092. }
  1093. else
  1094. {
  1095. entity.GetInventory().DropEntity( InventoryMode.PREDICTIVE, entity, attachment );
  1096. }
  1097. }
  1098. }
  1099. }
  1100. else
  1101. {
  1102. float pile_health;
  1103. float qty_coef;
  1104. vector destination = entity.GetPosition();
  1105. //placed on helper memory point, if available
  1106. if ( entity.MemoryPointExists("" + main_part_name + "_materials") )
  1107. {
  1108. destination = entity.GetMemoryPointPos("" + main_part_name + "_materials");
  1109. destination = GetGame().ObjectModelToWorld(entity,destination);
  1110. }
  1111. else if ( entity.MemoryPointExists(main_part_name) )
  1112. {
  1113. destination = entity.GetMemoryPointPos(main_part_name);
  1114. destination = GetGame().ObjectModelToWorld(entity,destination);
  1115. }
  1116. pile_health = entity.GetHealth01(damagezone_name,"Health") * MiscGameplayFunctions.GetTypeMaxGlobalHealth(type);
  1117. qty_coef = 1 - (entity.GetHealthLevel(damagezone_name) * Construction.DECONSTURCT_MATERIAL_LOSS) - Construction.DECONSTURCT_MATERIAL_LOSS;
  1118. quantity *= qty_coef;
  1119. quantity = Math.Max(Math.Floor(quantity),1);
  1120. if (player)
  1121. {
  1122. vector posHead;
  1123. MiscGameplayFunctions.GetHeadBonePos(PlayerBase.Cast(player),posHead);
  1124. MiscGameplayFunctions.CreateItemBasePilesDispersed(type,posHead,destination,UAItemsSpreadRadius.NARROW,quantity,pile_health,player);
  1125. }
  1126. else
  1127. {
  1128. MiscGameplayFunctions.CreateItemBasePiles(type,destination,quantity,pile_health,true);
  1129. }
  1130. }
  1131. }
  1132. }
  1133. }
  1134. //! Data structure for passing parameters (extendable, modable)
  1135. class CollisionCheckData
  1136. {
  1137. ref array<Object> m_AdditionalExcludes;
  1138. string m_PartName;
  1139. int m_PrimaryGeometry;
  1140. int m_SecondaryGeometry;
  1141. void CollisionCheckData()
  1142. {
  1143. m_AdditionalExcludes = new array<Object>;
  1144. m_PartName = "";
  1145. m_PrimaryGeometry = ObjIntersectGeom;
  1146. m_SecondaryGeometry = ObjIntersectView;
  1147. }
  1148. }
  1149. class ConstructionBoxTrigger : ManTrigger
  1150. {
  1151. string m_PartName;
  1152. void SetPartName( string part_name )
  1153. {
  1154. m_PartName = part_name;
  1155. }
  1156. string GetPartName()
  1157. {
  1158. return m_PartName;
  1159. }
  1160. override protected void UpdateInsiders( int timeout )
  1161. {
  1162. super.UpdateInsiders( 20 );
  1163. }
  1164. bool IsColliding()
  1165. {
  1166. if ( GetInsiders().Count() > 0 )
  1167. {
  1168. return true;
  1169. }
  1170. return false;
  1171. }
  1172. }