DayZ 1.30
DayZ Explorer by KGB
 
Загрузка...
Поиск...
Не найдено
ConstructionBase.c
См. документацию.
1
13
14enum EConstructionDirCheckType
15{
18 MISC
19}
20
21#ifdef DIAG_DEVELOPER
22enum EConstructionDebugModes
23{
25 FAST,
26 INSTANT
27}
28#endif
29
31{
32 protected static const int MAX_MATERIAL_PILES = 64; //safety cap for material pile spawning
33
34 static const float REPAIR_MATERIAL_PERCENTAGE = 0.15;
35 static const float DECONSTURCT_MATERIAL_LOSS = 0.2;
36 static const float DEFAULT_DECAY_RATE = -1.0;
37 static const float DEFAULT_DECAY_THRESHOLD = 0.3;
38 static const float DEFAULT_DECAY_RATE_COEF = 1.0;
39 static const float SANDSTORM_DECAY_RATE_COEF = 1.5;
40
42 protected ref map<string, ref ConstructionPart> m_ConstructionParts
43 protected ref array<ConstructionPart> m_ConstructionPartArray; //ordered array for easier access
44 protected ref array<ConstructionPart> m_BuiltConstructionPartArray; //built parts array
47
48 #ifdef DIAG_DEVELOPER
49 //Debug
50 protected Shape m_CollisionBox;
51 protected Shape m_PlayerInsideTestCylinder;
52 protected ref array<Shape> m_InsideTestBoxes;
53 #endif
54
55 //============================================
56 // Construction
57 //============================================
59 {
61 m_ConstructionParts = new map<string, ref ConstructionPart>();
64
65 #ifdef DIAG_DEVELOPER
66 m_InsideTestBoxes = new array<Shape>();
67 #endif
68
69 //set parent object
70 SetParent(parent);
71 EntityAIType entityType;
72 if (!Class.CastTo(entityType, m_EntityParent.GetEntityType()) || !Class.CastTo(m_TypeLevelHolder, entityType.GetConstructionDataHolderBasic()))
73 {
74 ErrorEx("invalid EntityType or ConstructionDataTypeHolder for entity instance: " + parent);
75 }
76 }
77
83
84 override void Init()
85 {
87 //InitBaseState(); //called from EEInit instead (physics updates require physics to be initialized)
88 }
89
90 override void EEInitConstruction()
91 {
92 if (m_EntityParent.IsPendingDeletion())
93 return;
94
96 {
97 part.PartInstanceDeferredInit(m_EntityParent);
98 }
99
100 #ifdef DIAG_DEVELOPER
101 if ((g_Game.IsServer() || !g_Game.IsMultiplayer()) && IsCLIParam("RBLDRebuildEverythingWithLocks"))
102 {
103 RebuildingSpawner.RebuildAllWoodenPartsFiltered(this, m_EntityParent);
104 }
105 #endif
106 }
107
108 protected void Cleanup()
109 {
110 m_ConstructionParts = null;
113
114 #ifdef DIAG_DEVELOPER
115 m_InsideTestBoxes = null;
116 #endif
117 }
118
119 protected void SetParent(EntityAI parent)
120 {
121 m_EntityParent = parent;
122 }
123
124 //============================================
125 // Syncing
126 //============================================
132 {
133 return false;
134 }
135
136 //============================================
137 // Construction process
138 //============================================
139 //constructed parts
140 void AddToConstructedParts(string part_name)
141 {
142 ConstructionPart part = GetConstructionPart(part_name);
143 if (part)
144 {
145 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_EntityParent) + " AddToConstructedParts part=" + part.GetPartName());
146 part.SetBuiltState(true);
148 if (m_BuiltConstructionPartArray.Find(part) == -1)
149 m_BuiltConstructionPartArray.Insert(part);
150
151 #ifndef SERVER
152 if (m_EntityParent.IsInitialized())
154 #endif
155 }
156 }
157
158 void RemoveFromConstructedParts(string part_name)
159 {
160 ConstructionPart part = GetConstructionPart(part_name);
161 if (part)
162 {
163 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_EntityParent) + " RemoveFromConstructedParts part=" + part.GetPartName());
164 part.SetBuiltState(false);
166 m_BuiltConstructionPartArray.RemoveItem(part);
167
168 #ifndef SERVER
169 if (m_EntityParent.IsInitialized())
171 #endif
172 }
173 }
174
179 void BuildPartServerEx(Man player, string part_name, int action_id)
180 {
181 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction BuildPartServerEx | " + part_name);
182 //on action
183 TakeMaterialsServer(part_name);
184 }
185
190 void DismantlePartServerEx(Man player, string part_name, int action_id)
191 {
192 string damageZone;
193 DamageSystem.GetDamageZoneFromComponentName(m_EntityParent,part_name,damageZone);
194
195 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DismantlePartServerEx | " + part_name);
196 //receive materials
197 if (player)
198 ReceiveMaterialsServer(player, part_name, damageZone);
199
200 //drop non-usable materials
201 DropNonUsableMaterialsServer(player, part_name);
202 DropEssentialAttachments(player, part_name);
203
205 HandleEntityFalling(part_name);
206 }
207
209 void DestroyPartServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part = false)
210 {
211 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DestroyPartServer | " + part_name);
212 //destroy attached materials (if locked)
213 DestroyMaterialsServer(player, part_name);
214
215 //drop non-usable materials
216 DropNonUsableMaterialsServer(player, part_name);
217 DropEssentialAttachments(player, part_name);
218
220 HandleEntityFalling(part_name);
221 }
222
223 void DestroyConnectedParts(string part_name)
224 {
225 array<string> partNames;
226 partNames = GetValidDepenentPartsArray(part_name);
227 if (partNames && partNames.Count() > 0)
228 {
229 foreach (string partName : partNames)
230 {
231 if (!ExceptionCheck(partName))
232 {
233 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DestroyConnectedParts | " + partName);
234 DestroyPartServer(null,partName,AT_DESTROY_PART,true);
235 }
236 }
237 }
238 }
239
241 void HandleEntityFalling(string partName)
242 {
243 ConstructionPart part = GetConstructionPart(partName);
244 if (part.CanSimulateItemFalling())
245 {
246 g_Game.GetCallQueue(CALL_CATEGORY_SYSTEM).Call(ItemFall, partName); //deferred call to allow for material spawning/part's phx adjustment
247 }
248 }
249
250 protected void ItemFall(string partName)
251 {
252 vector minMax[2];
253 if (!GetItemFallDetectionBoxData(partName, minMax))
254 {
255 ErrorEx(string.Format("Wrong collision_data configuration of %1 for object %2; valid collision_data must contain exactly 2 strings (min/max) or must be a base building object for auto evaluation for boundings!", partName, m_EntityParent), ErrorExSeverity.INFO);
256 return;
257 }
258
259 vector center = GetBoxCenter(minMax);
260 center = m_EntityParent.ModelToWorld(center); //convert to world coordinates
261 vector edgeLength = GetCollisionBoxSize(minMax);
262 vector orientation = m_EntityParent.GetOrientation();
264 params.SetParams(center, orientation, edgeLength, ObjIntersect.View, ObjIntersect.Geom, false);
265
266 array<Object> excludes; //null by default
268
269 if (g_Game.IsBoxCollidingGeometryProxy(params, excludes, results))
270 {
271 foreach (BoxCollidingResult res : results)
272 {
273 if (res.obj == m_EntityParent) //skip parent
274 continue;
275
276 Physics objPhysics = res.obj.GetPhysics();
277 SimulationState simState = objPhysics.GetSimulationState();
278 if (simState != SimulationState.NONE && simState != SimulationState.COLLISION)
279 continue;
280
281 Transport vehicle;
282 if (Class.CastTo(vehicle, res.obj)) //special treatment for transports
283 {
284 dBodyActive(vehicle, ActiveState.ACTIVE);
285 continue;
286 }
287
288 PlayerBase player;
289 if (Class.CastTo(player, res.obj)) //special treatment for characters
290 {
291 objPhysics.ApplyImpulse(-vector.Up * 0.01);
292 continue;
293 }
294
295 InventoryItem item;
296 if (Class.CastTo(item, res.obj))
297 {
298 item.OnItemFallRebuilding();
299 if (item)
300 item.ThrowPhysically(null, vector.Zero);
301 }
302 }
303 }
304 }
305
307 override void ProcessConstructionDecay(float dTime)
308 {
309 float healthTarget;
310 float currentHP;
311 float threshold;
312
313 foreach (ConstructionPart part : m_ConstructionParts)
314 {
315 if (part.IsBuilt() && part.CanPartDecay())
316 {
317 string damageZone;
318 DamageSystem.GetDamageZoneFromComponentName(m_EntityParent,part.GetPartName(),damageZone);
319 if (damageZone != "")
320 {
321 currentHP = m_EntityParent.GetHealth(damageZone,"Health");
322 threshold = part.GetPartDecayThreshold() * m_EntityParent.GetMaxHealth(damageZone,"Health");
323 if (currentHP > threshold)
324 {
325 healthTarget = m_EntityParent.GetHealth(damageZone,"Health") + (dTime * part.GetPartDecayRate() * GetCurrentDecayCoef());
326 healthTarget = Math.Clamp(healthTarget,threshold,m_EntityParent.GetMaxHealth(damageZone,"Health"));
327 m_EntityParent.SetHealth(damageZone,"Health",healthTarget);
328 }
329 }
330 }
331 }
332 }
333
334 protected float GetCurrentDecayCoef()
335 {
336 if (g_Game.GetWeather().GetSandstorm().IsActive())
338
340 }
341
346
348 {
349 return m_AnyPartBuildableByHands != 0;
350 }
351
352 override void OnHealthLevelChanged(int oldLevel, int newLevel, string zone)
353 {
354 super.OnHealthLevelChanged(oldLevel, newLevel, zone);
355
356 string partName = zone;
357 partName.ToLower();
358
359 if (newLevel == GameConstants.STATE_RUINED)
360 {
361 ConstructionPart constructionPart = GetConstructionPart(partName);
362
363 if (constructionPart && IsPartConstructed(partName))
364 {
365 DestroyPartServer(null, partName, AT_DESTROY_PART);
366 }
367 }
368 }
369
371 bool ExceptionCheck(string part_name)
372 {
373 return false;
374 }
375
376 //============================================
377 // Construction-based event processing, not for BBB
378 //============================================
379 void ProcessOnPartBuiltServer(Man player, string part_name, int action_id)
380 {
381 ConstructionPart part = GetConstructionPart(part_name);
382 if (part.IsUtilityPart())
383 return;
384
385 string damageZone;
386 if (DamageSystem.GetDamageZoneFromComponentName(m_EntityParent,part_name,damageZone))
387 {
388 m_EntityParent.SetAllowDamage(true);
389 m_EntityParent.SetHealthMax(damageZone);
390 m_EntityParent.ProcessInvulnerabilityCheck(m_EntityParent.GetInvulnerabilityTypeString());
391 }
392
393 part.OnBeforeBuildServer(m_EntityParent, player); //performs any checks specific part type may need
395
397
399
400 part.OnBuiltServer(m_EntityParent, player);
401
402 m_EntityParent.SetSynchDirty();
403 }
404
405 void ProcessOnPartDismantledServer(Man player, string part_name, int action_id)
406 {
407 ConstructionPart part = GetConstructionPart(part_name);
408 part.OnBeforeDismantleServer(m_EntityParent, player); //performs any checks specific part type may need
410
412
414
416 m_EntityParent.SetSynchDirty();
417 }
418
419 void ProcessOnPartDestroyedServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part = false)
420 {
421 ConstructionPart part = GetConstructionPart(part_name);
422 part.OnBeforeDestroyServer(m_EntityParent, player); //performs any checks specific part type may need
424
426
428
429 part.OnDestroyedServer(m_EntityParent, player);
430 m_EntityParent.SetSynchDirty();
431
432 DestroyConnectedParts(part_name);
433 }
434
435 //============================================
436 // Update construction
437 //============================================
440 {
441 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_EntityParent) + " InitVisuals");
443 }
444
447 {
448 if (part.IsBuilt())
449 {
451 }
452 else
453 {
455 }
456 }
457
460 {
461 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_EntityParent) + " UpdateVisuals");
462
464 {
465 if (part.IsBuilt())
466 {
467 ShowConstructionPart(part.GetPartName());
468 }
469 else
470 {
471 HideConstructionPart(part.GetPartName());
472 }
473 }
474 }
475
478 {
479 if (part.IsBuilt())
480 {
482 }
483 else
484 {
486 }
487 }
488
491 {
492 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction " + Object.GetDebugName(m_EntityParent));
493
495 foreach (ConstructionPart anyPart : m_ConstructionPartArray)
496 {
497 if (anyPart.IsBuilt())
498 builtArray.Insert(anyPart);
499 else
501 }
502
503 foreach (ConstructionPart builtPart : builtArray)
504 {
505 UpdateSpecificPartPhysics(builtPart);
506 }
507
508 builtArray = null;
509 }
510
512 {
513 g_Game.GetWorld().UpdatePathgraphEntityState(m_EntityParent);
514 }
515
517 protected void UpdateConstructionParts()
518 {
519 m_ConstructionParts.Clear();
522
523 EntityAIType entityType;
525 if (Class.CastTo(entityType, m_EntityParent.GetEntityType()) && Class.CastTo(holder, entityType.GetConstructionDataHolderBasic()))
526 {
528 foreach (ConstructionPartTypeData typeData : partTypesArray)
529 {
530 ConstructionPart part;
531 typename customInstanceTypename = typeData.GetCustomInstanceType();
532 if (!customInstanceTypename || !Class.CastTo(part, CreatePartInstanceObject(customInstanceTypename)))
533 {
534 //parameters are purely optional at this point, all config data is cached on entity type level
536 }
537
538 part.SetPartTypeData(typeData);
540 initData.m_ParentEnt = m_EntityParent;
541 part.InitAdditionalPartInstanceInfo(initData);
542
543 m_ConstructionParts.Insert(typeData.GetPartName(), part);
544 m_ConstructionPartArray.Insert(part);
545 m_AnyPartBuildableByHands |= part.GetBuildIndicationTypeMask() & EConstructionTools.TOOL_HANDS;
546 }
547 }
548 }
549
550 protected ConstructionPart CreatePartInstanceObject(typename partTypename)
551 {
552 return ConstructionPart.Cast(partTypename.Spawn());
553 }
554
557 {
558 ErrorEx("missing valid override!");
559 return typename;
560 }
561
563 {
564 foreach (ConstructionPart part : changedParts)
565 {
567 }
568 }
569
570 //============================================
571 // Parts
572 //============================================
574 {
575 return m_ConstructionParts;
576 }
577
579 {
580 return m_ConstructionParts.Get(part_name);
581 }
582
583 bool CanBuildPart(string part_name, ItemBase tool, bool use_tool)
584 {
585 int dump;
586 return CanBuildPartEx(part_name, tool, dump);
587 }
588
590 bool CanBuildPartEx(string partName, ItemBase tool, out EConstructionInfoCategories failureReasonsMask)
591 {
592 failureReasonsMask = EConstructionInfoCategories.NONE;
593
594 if (IsPartConstructed(partName))
595 failureReasonsMask |= EConstructionInfoCategories.PART_CONSTRUCTED;
596 if (!HasRequiredPart(partName))
597 failureReasonsMask |= EConstructionInfoCategories.PART_MISSING_REQUIREMENT;
598 if (!PartHasAnySupportFulfilled(partName))
599 failureReasonsMask |= EConstructionInfoCategories.PART_MISSING_SUPPORT;
600 if (HasConflictPart(partName))
601 failureReasonsMask |= EConstructionInfoCategories.PART_CONFLICTED;
602 if (!HasMaterials(partName))
603 failureReasonsMask |= EConstructionInfoCategories.MATERIALS_PRESENCE;
604 if (MaterialIsRuined(partName))
605 failureReasonsMask |= EConstructionInfoCategories.MATERIALS_DAMAGE;
606 if (!CanUseToolToBuildPart(partName, tool))
607 failureReasonsMask |= EConstructionInfoCategories.TOOL_PRESENCE;
608
609 return failureReasonsMask == EConstructionInfoCategories.NONE;
610 }
611
613 bool CanBuildUtilityPart(string partName)
614 {
615 if (IsPartConstructed(partName))
616 return false;
617 if (!HasRequiredPart(partName))
618 return false;
619 if (!PartHasAnySupportFulfilled(partName))
620 return false;
621 if (HasConflictPart(partName))
622 return false;
623
624 return true;
625 }
626
627 bool MaterialIsRuined(string part_name)
628 {
629 ConstructionPart part = GetConstructionPart(part_name);
631 foreach (ConstructionMaterialData dta : materials)
632 {
633 ItemBase attachment = ItemBase.Cast(m_EntityParent.FindAttachmentBySlotName(dta.m_MaterialSlotName));
634 if (attachment && attachment.IsRuined())
635 return true;
636 }
637
638 return false;
639 }
640
641 //Get all construction parts that can currently be built
642 void GetConstructionPartsToBuild(string main_part_name, out array<ConstructionPart> construction_parts, ItemBase tool, out string real_constructionTarget, bool use_tool)
643 {
644 construction_parts.Clear();
645
647 {
648 if ((main_part_name == part.GetMainPartName() || main_part_name == part.GetPartName()) && CanBuildPart(part.GetPartName(), tool, use_tool))
649 {
650 construction_parts.Insert(part);
651 }
652 }
653 }
654
655 //Get all construction parts from the targeted actionComponentName, that currently CANNOT be built
656 void GetConstructionPartsUnableToBuild(string actionComponentName, out array<ConstructionPart> constructionParts, ItemBase tool, out string realConstructionTarget, bool useTool)
657 {
658 constructionParts.Clear();
659
661 {
662 if (actionComponentName == part.GetMainPartName() && !CanBuildPart(part.GetPartName(), tool, useTool))
663 {
664 constructionParts.Insert(part);
665 }
666 }
667 }
668
669 //Returns (first found) base construction part
671 {
673 {
674 if (part.IsBase())
675 return part;
676 }
677
678 return NULL;
679 }
680
682 bool HasRequiredPart(string part_name)
683 {
684 ConstructionPart part = m_ConstructionParts.Get(part_name);
685
686 //check if simple required parts are already built
687 array<string> requiredParts = part.GetRequiredParts();
688 foreach (string partName : requiredParts)
689 {
690 if (!IsPartConstructed(partName))
691 return false;
692 }
693
694 return true;
695 }
696
698 bool PartHasAnySupportFulfilled(string part_name)
699 {
700 return true;
701 }
702
703 //checks if there are conflict parts already built. Simple variant, still in use
704 bool HasConflictPart(string part_name)
705 {
706 string conflictingPartName = "";
707 return HasConflictPart(part_name, conflictingPartName);
708 }
709
710 //checks if there are conflict parts already built. Outputs the conflicting part name.
711 bool HasConflictPart(string partName, out string conflictingPartName)
712 {
713 conflictingPartName = "";
714 ConstructionPart part = GetConstructionPart(partName);
715 array<string> conflictedParts = part.GetConflictedParts();
716 foreach (string partNameTest : conflictedParts)
717 {
718 if (IsPartConstructed(partNameTest))
719 {
720 conflictingPartName = partNameTest;
721 return true;
722 }
723 }
724
725 return false;
726 }
727
728 //DECONSTRUCTION
730 {
731 if (CanDismantlePart(part_name, tool))
732 {
733 return GetConstructionPart(part_name);
734 }
735
736 return NULL;
737 }
738
739 bool CanDismantlePart(string part_name, ItemBase tool)
740 {
741 if (IsPartConstructed(part_name) && !HasDependentPart(part_name) && SupportRemovalCheck(part_name) && CanUseToolToDismantlePart(part_name, tool))
742 {
743 #ifdef DIAG_DEVELOPER
744 if (DiagMenu.GetBool(DiagMenuIDs.BASEBUILDING_FULLDEBUG))
745 {
746 ConstructionDebug.ResetDismantlePartData();
747 }
748 #endif
749 return true;
750 }
751
752 #ifdef DIAG_DEVELOPER
753 if (GetConstructionPart(part_name))
754 {
755 if (DiagMenu.GetBool(DiagMenuIDs.BASEBUILDING_FULLDEBUG))
756 {
757 ConstructionDismantleDebugData data = new ConstructionDismantleDebugData();
758 data.partName = part_name;
759 data.constructed = IsPartConstructed(part_name);
760 data.hasDependents = HasDependentPart(part_name);
761 data.supportState = SupportRemovalCheck(part_name);
762
763 ConstructionDebug.SetCanDismantlePartData(data);
764 }
765 }
766 #endif
767
768 return false;
769 }
770
772 bool HasDependentPart(string part_name)
773 {
775 {
776 if (!part.IsUtilityPart() && part.GetRequiredParts().Find(part_name) > -1)
777 {
778 return true;
779 }
780 }
781
782 return false;
783 }
784
786 bool SupportRemovalCheck(string part_name)
787 {
788 return true;
789 }
790
791 bool CanRepairPart(string partName, ItemBase tool = null, PlayerBase player = null, bool facingCheck = false)
792 {
793 ConstructionPart constructionPart = GetConstructionPart(partName);
794 if (constructionPart)
795 {
796 //damage check
797 string zoneName;
798 if (!DamageSystem.GetDamageZoneFromComponentName(m_EntityParent, partName, zoneName)) //no zone, no repair
799 return false;
800
801 float currentZoneHealthLevel = m_EntityParent.GetHealthLevel(zoneName);
802 if (currentZoneHealthLevel == GameConstants.STATE_PRISTINE || currentZoneHealthLevel == GameConstants.STATE_RUINED)
803 return false;
804
805 ConstructionPart part = GetConstructionPart(partName);
806 if (!part.CanBeRepaired(currentZoneHealthLevel, tool, player))
807 return false;
808
809 if (!player) //for debug purposes, I guess?
810 return true;
811
812 //materials check
813 if (!HasMaterials(partName,true))
814 return false;
815
816 //facing and position checks
817 if (!ConstructionDirectionCheck(player, constructionPart, EConstructionDirCheckType.INDOORS) || !ConstructionDirectionCheck(player, constructionPart, EConstructionDirCheckType.REFERENCE_DIRECTION))
818 return false;
819
820 if (!m_EntityParent.IsFacingPlayerEx(player, partName) && !player.GetInputController().CameraIsFreeLook())
821 {
822 //Camera check (client-only)
823 if (!g_Game.IsDedicatedServer())
824 {
825 if (facingCheck)
826 {
827 if (m_EntityParent.IsFacingCamera(partName))
828 return false;
829 }
830 }
831
832 ConstructionActionData cad = player.GetConstructionActionData();
833 cad.SetTargetPart(constructionPart);
834 return true;
835 }
836 }
837
838 return false;
839 }
840
843 {
844 const float CYLINDER_HEIGHT = 0.01;
845 const float CYLINDER_RADIUS = 0.01;
846
847 #ifdef DIAG_DEVELOPER
848 bool fullDebugEnabled = DiagMenu.GetBool(DiagMenuIDs.BASEBUILDING_COLLISIONDEBUG);
849 if (fullDebugEnabled || (!fullDebugEnabled && m_InsideTestBoxes.Count() > 0))
850 DestroyDebugInsideTestBoxes();
851 #endif
852
854 if (!modelMinMaxs)
855 return true;
856
857 vector matPlayer[4];
858 Math3D.MatrixIdentity4(matPlayer);
859 vector adjustedPos = player.GetPosition();
860 adjustedPos[1] = adjustedPos[1] + CYLINDER_HEIGHT / 2;
861 matPlayer[3] = adjustedPos;
862
863 #ifdef DIAG_DEVELOPER
864 if (fullDebugEnabled)
865 {
866 if (m_PlayerInsideTestCylinder)
867 m_PlayerInsideTestCylinder.Destroy();
868 m_PlayerInsideTestCylinder = Debug.DrawCylinder("0 0 0", CYLINDER_RADIUS * 5, CYLINDER_HEIGHT, COLOR_YELLOW_A);
869 m_PlayerInsideTestCylinder.SetMatrix(matPlayer);
870 }
871 #endif
872
873 vector matParent[4];
874 m_EntityParent.GetTransform(matParent);
875 bool success = false;
876
877 foreach (array<vector> minMaxPair : modelMinMaxs)
878 {
879 vector min = minMaxPair[0];
880 vector max = minMaxPair[1];
881
882 bool playerInside = false;
883
884 //temporary test solution
885 playerInside = Math3D.IntersectCylinderOBB(min, max, matParent, matPlayer, CYLINDER_RADIUS, CYLINDER_HEIGHT);
886
887 if (playerInside)
888 {
889 success = true;
890 #ifdef DIAG_DEVELOPER
891 if (fullDebugEnabled)
892 {
893 DrawDebugInsideTestBox(min, max, ARGB(90, 128, 128, 128));
894 }
895 else
896 #else
897 return true;
898 #endif
899 }
900 #ifdef DIAG_DEVELOPER
901 else
902 {
903 if (fullDebugEnabled)
904 {
905 DrawDebugInsideTestBox(min, max, ARGB(90, 128, 0, 128));
906 }
907 }
908 #endif
909 }
910
911 #ifdef DIAG_DEVELOPER
912 if (fullDebugEnabled)
913 {
914 if (!success)
915 ConstructionDebug.SetInsideboxCheckDebugData(part.GetPartName());
916 else
917 ConstructionDebug.SetInsideboxCheckDebugData("");
918 }
919 #endif
920
921 return success;
922 }
923
924 bool ConstructionDirectionCheck(PlayerBase player, ConstructionPart part, EConstructionDirCheckType type)
925 {
926 string name = part.GetPartName();
927 //first we check actual part names in case of individual handling
928 string memStart = "" + name + "_pos";
929 string memEnd;
930
931 if (m_EntityParent.MemoryPointExists(memStart))
932 {
933 switch (type)
934 {
935 case EConstructionDirCheckType.INDOORS:
936 memEnd = "" + name + "_inside";
937 break;
938
939 case EConstructionDirCheckType.REFERENCE_DIRECTION:
940 memEnd = "" + name + "_ref";
941 break;
942
943 default:
944 memEnd = "";
945 break;
946 }
947 }
948
949 //next we check main part name for mass handling
950 name = part.GetMainPartName();
951 memStart = "" + name + "_pos";
952
953 if (m_EntityParent.MemoryPointExists(memStart))
954 {
955 switch (type)
956 {
957 case EConstructionDirCheckType.INDOORS:
958 memEnd = "" + name + "_inside";
959 break;
960
961 case EConstructionDirCheckType.REFERENCE_DIRECTION:
962 memEnd = "" + name + "_ref";
963 break;
964
965 default:
966 memEnd = "";
967 break;
968 }
969 }
970
971 if (memEnd != "" && m_EntityParent.MemoryPointExists(memEnd))
972 {
973 return MiscGameplayFunctions.MemPointDirectionalCheck(player, m_EntityParent, memStart, memEnd);
974 }
975
976 return true;
977 }
978
979 //returns array of BUILT parts that directly depend on 'part_name' in some fashion
980 protected array<string> GetValidDepenentPartsArray(string part_name, array<string> recurs = null)
981 {
982 string name = "";
983 array<string> dependentParts;
984
986 {
987 name = part.GetPartName();
988
989 array<string> reqPartsArray = part.GetRequiredParts();
990 if (part.IsBuilt() && reqPartsArray && reqPartsArray.Find(part_name) > -1)
991 {
992 if (!dependentParts)
993 dependentParts = new array<string>();
994
995 if (!recurs || (recurs.Find(name) == -1))
996 dependentParts.Insert(name);
997 }
998 }
999
1000 return dependentParts;
1001 }
1002
1003 //gets simple required parts of a construction part; caches into ConstructionPartTypeData array on init
1004 array<string> GetRequiredParts(string part_name, string main_part_name)
1005 {
1006 string cfgPath = "cfgVehicles" + " " + m_EntityParent.GetType() + " " + "Construction" + " " + main_part_name + " " + part_name + " " + "required_parts";
1007 array<string> requiredParts = new array<string>();
1008 g_Game.ConfigGetTextArray(cfgPath, requiredParts);
1009
1010 return requiredParts;
1011 }
1012
1013 //DESTROY
1015 {
1016 if (CanDestroyPart(part_name))
1017 return GetConstructionPart(part_name);
1018
1019 return NULL;
1020 }
1021
1022 bool CanDestroyPart(string part_name)
1023 {
1024 if (IsPartConstructed(part_name) && !HasDependentPart(part_name) && SupportRemovalCheck(part_name))
1025 return true;
1026
1027 return false;
1028 }
1029
1030 //CONSTRUCTION PART STATE
1032 protected void ShowConstructionPart(string part_name)
1033 {
1034 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction ShowConstructionPart " + m_EntityParent.GetType() + " | part = " + part_name);
1035
1036 ConstructionPart part = m_ConstructionParts.Get(part_name);
1038 }
1039
1041 protected void HideConstructionPart(string part_name)
1042 {
1043 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction HideConstructionPart " + m_EntityParent.GetType() + " | part = " + part_name);
1044
1045 ConstructionPart part = m_ConstructionParts.Get(part_name);
1047 }
1048
1050 void ShowConstructionPartPhysics(string part_name)
1051 {
1052 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] ShowConstructionPartPhysics " + m_EntityParent.GetType() + " | part = " + part_name);
1053
1054 ConstructionPart part = m_ConstructionParts.Get(part_name);
1056 }
1057
1059 void HideConstructionPartPhysics(string part_name)
1060 {
1061 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] HideConstructionPartPhysics " + m_EntityParent.GetType() + " | part = " + part_name);
1062
1063 ConstructionPart part = m_ConstructionParts.Get(part_name);
1065 }
1066
1068 bool IsPartConstructed(string part_name)
1069 {
1070 ConstructionPart part = GetConstructionPart(part_name);
1071 if (part)
1072 return part.IsBuilt();
1073
1074 return false;
1075 }
1076
1077 //============================================
1078 // Materials for construction
1079 //============================================
1081 bool HasMaterialsEx(string part_name, bool repairing = false, out string slotName = "", out float requiredQuantity = 0.0)
1082 {
1083 #ifdef DIAG_DEVELOPER
1084 if (g_Game.IsClient() || !g_Game.IsMultiplayer()) //weird, I know, but this is just used for initial filtering purposes. Action conditions take care of the rest for both sides
1085 {
1086 PlayerBase player = PlayerBase.Cast(g_Game.GetPlayer());
1087 if (player)
1088 {
1089 if (player.GetConstructionActionData().GetFastConstructionMode())
1090 return true;
1091 }
1092 }
1093 #endif
1094
1095 ConstructionPart part = GetConstructionPart(part_name);
1097 foreach (ConstructionMaterialData dta : materials)
1098 {
1099 float quantity = dta.m_MaterialQuantity;
1100 if (quantity == 0.0) //0 - ignores quantity
1101 continue;
1102
1103 if (repairing)
1104 {
1105 quantity *= REPAIR_MATERIAL_PERCENTAGE;
1106 quantity = Math.Max(Math.Floor(quantity),1);
1107 }
1108
1109 //if the selected material (or its quantity) is not available
1110 if (!HasMaterialWithQuantityAttached(dta.m_MaterialSlotName, quantity))
1111 {
1112 slotName = dta.m_MaterialSlotName;
1113 requiredQuantity = quantity;
1114 return false;
1115 }
1116 }
1117
1118 return true; //return true even if no material required
1119 }
1120
1121 //simplified variant of the above (legacy)
1122 bool HasMaterials(string part_name, bool repairing = false)
1123 {
1124 string dumpSlotName;
1125 float dumpQty;
1126 return HasMaterialsEx(part_name, repairing, dumpSlotName, dumpQty);
1127 }
1128 //check if parent object has attachment of required quantity attached to it
1129 protected bool HasMaterialWithQuantityAttached(string slot_name, float quantity)
1130 {
1131 ItemBase attachment = ItemBase.Cast(m_EntityParent.FindAttachmentBySlotName(slot_name));
1132 if (attachment && ((int)quantity == -1 || attachment.GetQuantity() >= quantity)) //-1 - deletes the object
1133 return true;
1134
1135 return false;
1136 }
1137
1138 //take materials when building
1139 void TakeMaterialsServer(string part_name, bool repairing = false)
1140 {
1141 ConstructionPart part = GetConstructionPart(part_name);
1143 foreach (ConstructionMaterialData dta : materials)
1144 {
1145 ItemBase attachment = ItemBase.Cast(m_EntityParent.FindAttachmentBySlotName(dta.m_MaterialSlotName));
1146 if (!attachment)
1147 continue;
1148
1149 if (repairing && dta.m_SkipOnRepair)
1150 continue;
1151
1152 if (dta.m_MaterialLockable)
1153 {
1154 //lock attachment
1155 InventoryLocation invloc = new InventoryLocation();
1156 attachment.GetInventory().GetCurrentInventoryLocation(invloc);
1157
1158 m_EntityParent.GetInventory().SetSlotLock(invloc.GetSlot(), true);
1159 }
1160 else
1161 {
1162 if (dta.m_MaterialQuantity > 0.0) //0 - ignores quantity
1163 {
1164 float quantity = dta.m_MaterialQuantity;
1165 if (repairing)
1166 {
1167 quantity *= REPAIR_MATERIAL_PERCENTAGE;
1168 quantity = Math.Max(Math.Floor(quantity),1);
1169 }
1170 //subtract quantity
1171 attachment.AddQuantity(-quantity);
1172 }
1173 else if (dta.m_MaterialQuantity == -1.0) //-1 - deletes the object
1174 {
1175 g_Game.ObjectDelete(attachment);
1176 }
1177 }
1178 }
1179 }
1180
1181 // Receive materials when dismantling
1182 // ToDo: Use cached materials data from part
1183 protected void ReceiveMaterialsServer(notnull Man player, string part_name, string damagezone_name)
1184 {
1185 ConstructionPart part = GetConstructionPart(part_name);
1186 bool isBase = part.IsBase();
1187 string mainPartName = part.GetMainPartName();
1188 string cfgPath = "cfgVehicles" + " " + m_EntityParent.GetType() + " "+ "Construction" + " " + mainPartName + " " + part_name + " " + "Materials";
1189
1190 if (g_Game.ConfigIsExisting(cfgPath))
1191 {
1192 StaticConstructionMethods.SpawnConstructionMaterialPilesEx(m_EntityParent,player,cfgPath,part_name,damagezone_name,isBase);
1193 }
1194 }
1195
1196 //destroy lockable materials when destroying
1197 protected void DestroyMaterialsServer(Man player, string part_name)
1198 {
1199 ConstructionPart part = GetConstructionPart(part_name);
1201 foreach (ConstructionMaterialData dta : materials)
1202 {
1203 //get material
1204 ItemBase attachment = ItemBase.Cast(m_EntityParent.FindAttachmentBySlotName(dta.m_MaterialSlotName));
1205 if (!attachment)
1206 continue;
1207
1208 //material still attached
1209 if (dta.m_MaterialLockable)
1210 {
1211 InventoryLocation invloc = new InventoryLocation();
1212 attachment.GetInventory().GetCurrentInventoryLocation(invloc);
1213 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(m_EntityParent) + " DestroyMaterialsServer unlock slot=" + invloc.GetSlot());
1214
1215 m_EntityParent.GetInventory().SetSlotLock(invloc.GetSlot() , false);
1216 g_Game.ObjectDelete(attachment);
1217 }
1218 }
1219 }
1220
1221 void DropNonUsableMaterialsServer(Man player, string part_name)
1222 {
1223 ConstructionPart part = GetConstructionPart(part_name);
1224
1227 if (!part.IsBase())
1228 return;
1229
1231 if (!materials)
1232 return;
1233
1234 GameInventory parentInv = m_EntityParent.GetInventory();
1235 foreach (ConstructionMaterialData dta : materials)
1236 {
1237 if (dta.m_SkipOnDismantle)
1238 continue;
1239
1240 int slotId = dta.m_MaterialSlotID;
1241 if (slotId == InventorySlots.INVALID)
1242 {
1243 ErrorEx(string.Format("DropNonUsableMaterialsServer: invalid cached slot id for '%1' on part %2", dta.m_MaterialSlotName, part_name));
1244 continue;
1245 }
1246
1247 ItemBase attachment = ItemBase.Cast(parentInv.FindAttachment(slotId));
1248 if (!attachment)
1249 {
1250 ErrorEx(string.Format("Attachment is not present for material type '%1' on part %2", dta.m_MaterialType, part_name));
1251 continue;
1252 }
1253
1255 bsbDebugPrint("[bsb] " + Object.GetDebugName(m_EntityParent) + " DropNonUsableMaterials UNlocking slot=" + slotId + " (" + dta.m_MaterialSlotName + ")");
1256
1257 parentInv.SetSlotLock(slotId, false);
1258
1259 //-1 => consumed by construction. Lockable materials are NEVER consumed
1260 //(TakeMaterialsServer locks them instead) so they must be returned.
1261 //Example: Fence wall_gate: MetalWire quantity=-1 lockable=1
1262 if (dta.m_MaterialQuantity == -1.0 && !dta.m_MaterialLockable)
1263 {
1265 bsbDebugPrint("[bsb] " + Object.GetDebugName(m_EntityParent) + " DropNonUsableMaterials DELETING (qty==-1, non-lockable) slot=" + slotId);
1266
1267 g_Game.ObjectDelete(attachment);
1268 continue;
1269 }
1270
1271 InventoryLocation invloc = new InventoryLocation();
1272 attachment.GetInventory().GetCurrentInventoryLocation(invloc);
1273
1274 MoveMaterialAttachmentToGround(m_EntityParent, player, attachment, invloc, part_name);
1275 }
1276 }
1277
1280 protected void MoveMaterialAttachmentToGround(notnull EntityAI parent, Man player, notnull ItemBase attachment, notnull InventoryLocation invloc, string partName)
1281 {
1282 // 1) base drop position
1283 vector basePos;
1284 bool hasMemPoint = parent.MemoryPointExists(partName + "_materials");
1285 if (hasMemPoint)
1286 basePos = g_Game.ObjectModelToWorld(parent, parent.GetMemoryPointPos(partName + "_materials"));
1287 else if (player)
1288 basePos = player.GetPosition();
1289 else
1290 basePos = attachment.GetPosition();
1291
1292 // 2) capture everything we need BEFORE touching the entity
1293 string itemType = attachment.GetType();
1294 float health = attachment.GetHealth("", "Health");
1295 int total = attachment.GetQuantity();
1296 int stackMax = attachment.GetTargetQuantityMax(-1);
1297 if (stackMax <= 0)
1298 stackMax = 1;
1299
1300 // number of fresh entities needed to carry total at stackMax each
1301 int pileCount = Math.Ceil((float)total / stackMax);
1302 if (pileCount > MAX_MATERIAL_PILES)
1303 {
1304 ErrorEx(string.Format("MoveMaterialAttachmentToGround: pile count %1 exceeds cap %2 for %3 on part %4, truncating!", pileCount, MAX_MATERIAL_PILES, itemType, partName), ErrorExSeverity.INFO);
1305 pileCount = MAX_MATERIAL_PILES;
1306 }
1307
1308 // 3) spawn ALL units as fresh, cleanly-networked ground entities
1309 int remaining = total;
1310 for (int i = 0; i < pileCount; ++i)
1311 {
1312 int thisQty = stackMax;
1313 if (remaining < stackMax)
1314 thisQty = remaining;
1315
1316 float ang = i * 90 * Math.DEG2RAD;
1317 vector dropPos = basePos + Vector(Math.Cos(ang) * 0.45, 0, Math.Sin(ang) * 0.45);
1318
1319 ItemBase newItem = ItemBase.Cast(g_Game.CreateObjectEx(itemType, dropPos, ECE_PLACE_ON_SURFACE));
1320 if (!newItem)
1321 {
1322 ErrorEx("MoveMaterialAttachmentToGround: failed to create '" + itemType + "' on part " + partName + ", aborting drop!");
1323 return; //bail BEFORE deleting the original, so materials aren't lost
1324 }
1325
1326 newItem.SetQuantity(thisQty);
1327 newItem.SetHealth("", "Health", health);
1328 newItem.PlaceOnSurface();
1329
1330 remaining -= thisQty;
1331 }
1332
1333 // 4) remove the original - it never becomes a ground item, so it can never be a stale one
1334 attachment.Delete();
1335 }
1336
1338 protected void DropEssentialAttachments(Man player, string partName)
1339 {
1340 ConstructionPart part = GetConstructionPart(partName);
1341 if (part.HasEssentialAttachmentSlots())
1342 {
1344 ItemBase attachment;
1345 GameInventory parentInventory = m_EntityParent.GetInventory();
1346 vector groundPos;
1347 foreach (string slotName: slots)
1348 {
1349 if (Class.CastTo(attachment, m_EntityParent.FindAttachmentBySlotName(slotName)))
1350 {
1351 //first get rid of any possible locks preventing the drop
1352 parentInventory.SetSlotLock(InventorySlots.GetSlotIdFromString(slotName), false);
1353
1354 //now drop
1355 int mode = InventoryMode.LOCAL;
1356 if (g_Game.IsMultiplayer())
1357 mode = InventoryMode.SERVER;
1358
1359 if (m_EntityParent.MemoryPointExists(slotName))
1360 {
1361 groundPos = m_EntityParent.ModelToWorld(m_EntityParent.GetMemoryPointPos(slotName));
1362 }
1363 else if (player)
1364 {
1365 groundPos = player.GetPosition();
1366 }
1367 else
1368 {
1369 groundPos = attachment.GetPosition();
1370 }
1371
1372 vector m4[4];
1374 m4[3] = groundPos;
1375
1376 parentInventory.DropEntityWithTransform(mode, m_EntityParent, attachment, m4);
1377 }
1378 }
1379 }
1380 }
1381
1382 //set lock on materials that are attached and cannot be locked/unlocked
1383 void SetLockOnAttachedMaterials(string part_name, bool lock_slot)
1384 {
1385 ConstructionPart part = GetConstructionPart(part_name);
1387 foreach (ConstructionMaterialData dta : materials)
1388 {
1389 ItemBase attachment = ItemBase.Cast(m_EntityParent.FindAttachmentBySlotName(dta.m_MaterialSlotName));
1390 if (attachment && dta.m_MaterialLockable)
1391 {
1392 InventoryLocation inventoryLocation = new InventoryLocation();
1393 attachment.GetInventory().GetCurrentInventoryLocation(inventoryLocation);
1394 m_EntityParent.GetInventory().SetSlotLock(inventoryLocation.GetSlot(), lock_slot);
1395
1396 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(m_EntityParent) + " SetLockOnAttachedMaterials lock=" + lock_slot +" slot=" + inventoryLocation.GetSlot());
1397 }
1398 }
1399 }
1400
1401 //============================================
1402 // Construction tools
1403 //============================================
1404 bool CanUseToolToBuildPart(string part_name, ItemBase tool)
1405 {
1406 #ifdef DIAG_DEVELOPER
1407 if (g_Game.IsClient() || !g_Game.IsMultiplayer())
1408 {
1409 PlayerBase player = PlayerBase.Cast(g_Game.GetPlayer());
1410 if (player)
1411 {
1412 if (player.GetConstructionActionData().GetFastConstructionMode())
1413 return true;
1414 }
1415 }
1416 #endif
1417
1418 ConstructionPart part = GetConstructionPart(part_name);
1419 int actionMask = part.GetBuildActionTypeMask();
1420 if (actionMask != EConstructionTools.TOOL_NO_ACTION)
1421 {
1422 if (tool)
1423 {
1424 string toolCfgPath = "cfgVehicles" + " " + tool.GetType() + " " + "build_action_type";
1425 if (g_Game.ConfigIsExisting(toolCfgPath))
1426 {
1427 int toolActionType = g_Game.ConfigGetInt(toolCfgPath);
1428 if ((actionMask & toolActionType) > 0)
1429 {
1430 return true;
1431 }
1432 }
1433 }
1434 else if (actionMask & EConstructionTools.TOOL_HANDS)
1435 {
1436 return true;
1437 }
1438 }
1439
1440 return false;
1441 }
1442
1443 bool CanUseToolToDismantlePart(string part_name, ItemBase tool)
1444 {
1445 ConstructionPart part = GetConstructionPart(part_name);
1446 int actionMask = part.GetDismantleActionTypeMask();
1447 if (actionMask != EConstructionTools.TOOL_NO_ACTION)
1448 {
1449 if (tool)
1450 {
1451 string toolCfgPath = "cfgVehicles" + " " + tool.GetType() + " " + "dismantle_action_type";
1452
1453 if (g_Game.ConfigIsExisting(toolCfgPath))
1454 {
1455 int toolActionType = g_Game.ConfigGetInt(toolCfgPath);
1456 if ((actionMask & toolActionType) > 0)
1457 {
1458 return true;
1459 }
1460 }
1461 }
1462 else if (actionMask & EConstructionTools.TOOL_HANDS)
1463 {
1464 return true;
1465 }
1466 }
1467
1468 return false;
1469 }
1470
1472 {
1473 ConstructionPart part = GetConstructionPart(part_name);
1474 return part.GetMaterialType();
1475 }
1476
1477 //============================================
1478 // Collision check
1479 //============================================
1482 {
1484 return false;
1485
1486 ConstructionPart part = GetConstructionPart(check_data.m_PartName);
1487 if (part && part.GetCollisionData().Count() == 2)
1488 {
1489 vector center;
1490 float absoluteOfset = 0.05; //we need to lift BBox even more, because it colliddes with house floors due to various reasons (probably geometry or float imperfections)
1491 vector edgeLength;
1492 vector minMax[2]; //data used for creating trigger
1493 array<Object> excludedObjects = new array<Object>();
1494 array<Object> collidedObjects = new array<Object>();
1495
1496 excludedObjects.Insert(m_EntityParent);
1497 if (check_data.m_AdditionalExcludes.Count() > 0)
1498 {
1499 excludedObjects.InsertAll(check_data.m_AdditionalExcludes);
1500 }
1501
1502 GetCollisionBoxData(check_data.m_PartName, minMax);
1503 center = GetBoxCenter(minMax);
1504 center = m_EntityParent.ModelToWorld(center); //convert to world coordinates
1505 edgeLength = GetCollisionBoxSize(minMax);
1506
1507 #ifdef DIAG_DEVELOPER
1508 bool collisionDebugEnabled = DiagMenu.GetBool(DiagMenuIDs.BASEBUILDING_COLLISIONDEBUG);
1509 #endif
1510 if (g_Game.IsBoxCollidingGeometry(Vector(center[0], center[1] + absoluteOfset, center[2]), m_EntityParent.GetOrientation(), edgeLength, check_data.m_PrimaryGeometry, check_data.m_SecondaryGeometry, excludedObjects, collidedObjects))
1511 {
1512 bool validCollision = false;
1513 #ifdef DIAG_DEVELOPER
1514 array<string> validEntityCollisions = new array<string>();
1515 #endif
1516
1517 for (int i = 0; i < collidedObjects.Count(); ++i)
1518 {
1519 EntityAI entity = EntityAI.Cast(collidedObjects.Get(i));
1520 if (entity && !entity.IsIgnoredByConstruction())
1521 {
1522 validCollision = true;
1523 #ifdef DIAG_DEVELOPER
1524 if (collisionDebugEnabled)
1525 {
1526 validEntityCollisions.Insert(entity.GetType());
1527 }
1528 #else
1529 break;
1530 #endif
1531 }
1532 }
1533
1534 #ifdef DIAG_DEVELOPER
1535 if (collisionDebugEnabled)
1536 {
1537 if (validCollision)
1538 {
1539 ConstructionDebug.SetCollisionPrintoutData(check_data.m_PartName, validEntityCollisions);
1540 DrawDebugCollisionBox(minMax, ARGB(150, 0, 0, 255));
1541 }
1542 else
1543 {
1544 ConstructionDebug.ResetCollisionPrintoutData();
1545 DrawDebugCollisionBox(minMax, ARGB(150, 255, 255, 255));
1546 }
1547 }
1548 else if (m_CollisionBox)
1549 {
1550 DestroyDebugCollisionBox();
1551 }
1552 #endif
1553
1554 return validCollision;
1555 }
1556 #ifdef DIAG_DEVELOPER
1557 else //Debug
1558 {
1559 if (collisionDebugEnabled)
1560 {
1561 ConstructionDebug.ResetCollisionPrintoutData();
1562 DrawDebugCollisionBox(minMax, ARGB(150, 255, 255, 255));
1563 }
1564 else if (m_CollisionBox)
1565 {
1566 DestroyDebugCollisionBox();
1567 }
1568 }
1569 #endif
1570 }
1571 return false;
1572 }
1573
1575 {
1576 vector boxSize = Vector(0, 0, 0);
1577
1578 boxSize[0] = Math.AbsFloat(min_max[1][0] - min_max[0][0]);
1579 boxSize[1] = Math.AbsFloat(min_max[1][1] - min_max[0][1]);
1580 boxSize[2] = Math.AbsFloat(min_max[1][2] - min_max[0][2]);
1581
1582 return boxSize;
1583 }
1584
1585 //outputs collision box minMax from construction config and model p3d, in MODELSPACE coordinates
1586 protected void GetCollisionBoxData(string part_name, out vector min_max[2])
1587 {
1589 array<string> dta = path.GetCollisionData();
1590 if (dta.Count() == 2)
1591 {
1592 if (m_EntityParent.MemoryPointExists(dta[0]))
1593 {
1594 min_max[0] = m_EntityParent.GetMemoryPointPos(dta[0]);
1595 }
1596 if (m_EntityParent.MemoryPointExists(dta[1]))
1597 {
1598 min_max[1] = m_EntityParent.GetMemoryPointPos(dta[1]);
1599 }
1600 }
1601 else if (dta.Count() > 0)
1602 {
1603 ErrorEx(string.Format("Wrong collision_data configuration of %1 for object %2; valid collision_data must contain exactly 2 strings (min/max)!", part_name, m_EntityParent), ErrorExSeverity.INFO);
1604 }
1605 }
1606
1607 //outputs item fall detection box minMax from construction config and model p3d, in MODELSPACE coordinates
1608 protected bool GetItemFallDetectionBoxData(string partName, out vector minMax[2])
1609 {
1611 array<string> dta = path.GetItemFallingData();
1612 if (dta.Count() == 2)
1613 {
1614 if (m_EntityParent.MemoryPointExists(dta[0]))
1615 {
1616 minMax[0] = m_EntityParent.GetMemoryPointPos(dta[0]);
1617 }
1618 if (m_EntityParent.MemoryPointExists(dta[1]))
1619 {
1620 minMax[1] = m_EntityParent.GetMemoryPointPos(dta[1]);
1621 }
1622
1623 return true;
1624 }
1625 else if (dta.Count() > 0)
1626 {
1627 ErrorEx(string.Format("Wrong collision_data configuration of %1 for object %2; valid item_falling_data must contain exactly 2 strings (min/max)!", partName, m_EntityParent), ErrorExSeverity.INFO);
1628 }
1629
1630 return false;
1631 }
1632
1633 //returns center point of box defined by min/max values
1635 {
1636 vector center;
1637
1638 center[0] = (min_max[1][0] - min_max[0][0]) / 2;
1639 center[1] = (min_max[1][1] - min_max[0][1]) / 2;
1640 center[2] = (min_max[1][2] - min_max[0][2]) / 2;
1641 center = Vector(min_max[1][0] - center[0], min_max[1][1] - center[1], min_max[1][2] - center[2]); //offset to box center
1642
1643 return center;
1644 }
1645
1646 void GetTriggerExtents(vector min_max[2], out vector extents[2])
1647 {
1648 vector egdeLength = GetCollisionBoxSize(min_max);
1649 extents[0][0] = -egdeLength[0] / 2; //min
1650 extents[0][1] = -egdeLength[1] / 2;
1651 extents[0][2] = -egdeLength[2] / 2;
1652 extents[1][0] = egdeLength[0] / 2; //max
1653 extents[1][1] = egdeLength[1] / 2;
1654 extents[1][2] = egdeLength[2] / 2;
1655 }
1656
1657 #ifdef DIAG_DEVELOPER
1658 //Debug
1659 protected void DrawDebugCollisionBox(vector min_max[2], int color)
1660 {
1661 DestroyDebugCollisionBox();
1662
1663 vector mat[4];
1664 m_EntityParent.GetTransform(mat);
1665
1666 m_CollisionBox = Debug.DrawBox(min_max[0], min_max[1], color);
1667 m_CollisionBox.SetMatrix(mat);
1668 }
1669
1670 protected void DestroyDebugCollisionBox()
1671 {
1672 if (m_CollisionBox)
1673 {
1674 m_CollisionBox.Destroy();
1675 m_CollisionBox = NULL;
1676 }
1677 }
1678
1679 protected void DrawDebugInsideTestBox(vector min, vector max, int color)
1680 {
1681 vector mat[4];
1682 m_EntityParent.GetTransform(mat);
1683
1684 Shape box = Debug.DrawBox(min, max, color);
1685 box.SetMatrix(mat);
1686 m_InsideTestBoxes.Insert(box);
1687 }
1688
1689 protected void DestroyDebugInsideTestBoxes()
1690 {
1691 foreach (Shape box : m_InsideTestBoxes)
1692 {
1693 box.Destroy();
1694 box = NULL;
1695 }
1696 m_InsideTestBoxes.Clear();
1697 }
1698 #endif
1700 //Deprecated Code
1702 [Obsolete("call BuildPartServerEx instead")]
1703 void BuildPartServer(notnull Man player, string part_name, int action_id)
1704 {
1705 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction BuildPartServer | " + part_name);
1706
1707 BuildPartServerEx(player,part_name,action_id);
1708 }
1709
1710 [Obsolete("call DismantlePartServerEx instead")]
1711 void DismantlePartServer(notnull Man player, string part_name, int action_id)
1712 {
1713 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] Construction DismantlePartServer | " + part_name);
1714
1715 DismantlePartServerEx(player,part_name,action_id);
1716 }
1717
1718 [Obsolete("call IsCollidingEx instead")]
1719 bool IsColliding(string part_name)
1720 {
1722 return false;
1723
1724 ConstructionPart part = GetConstructionPart(part_name);
1725 if (part && part.GetCollisionData().Count() == 2)
1726 {
1727 vector center;
1728 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)
1729 vector edge_length;
1730 vector min_max[2]; //data used for creating trigger
1731 array<Object> excludedObjects = new array<Object>();
1732 array<Object> collidedObjects = new array<Object>();
1733
1734 excludedObjects.Insert(m_EntityParent);
1735
1736 //get min_max and center from config and memory points
1737 GetCollisionBoxData(part_name, min_max);
1738
1739 center = GetBoxCenter(min_max);
1740 center = m_EntityParent.ModelToWorld(center); //convert to world coordinates
1741 edge_length = GetCollisionBoxSize(min_max);
1742
1743 if (g_Game.IsBoxCollidingGeometry(Vector(center[0], center[1] + absolute_ofset, center[2]), m_EntityParent.GetOrientation(), edge_length, ObjIntersectView, ObjIntersectGeom, excludedObjects, collidedObjects))
1744 {
1745 for (int i = 0; i < collidedObjects.Count(); ++i)
1746 {
1747 EntityAI entity = EntityAI.Cast(collidedObjects.Get(i));
1748 if (entity && !entity.IsIgnoredByConstruction())
1749 return true;
1750 }
1751 }
1752 }
1753 return false;
1754 }
1755
1756 [Obsolete("no replacement")]
1757 void CreateCollisionTrigger(string part_name, vector min_max[2], vector center)
1758 {
1760 {
1761 if (m_ConstructionBoxTrigger.GetPartName() == part_name) //already created
1762 {
1763 return;
1764 }
1765 else
1766 {
1768 }
1769 }
1770
1771 //get proper trigger extents (min<max)
1772 vector extents[2];
1773 GetTriggerExtents(min_max, extents);
1774
1775 //create trigger
1776 m_ConstructionBoxTrigger = ConstructionBoxTrigger.Cast(g_Game.CreateObject("ConstructionBoxTrigger", center, false, false, false));
1777 m_ConstructionBoxTrigger.SetPosition(center);
1778 m_ConstructionBoxTrigger.SetOrientation(m_EntityParent.GetOrientation());
1779 m_ConstructionBoxTrigger.SetExtents(extents[0], extents[1]);
1780
1781 m_ConstructionBoxTrigger.SetPartName(part_name);
1782 }
1783
1784 [Obsolete("no replacement")]
1786 {
1788 return;
1789
1790 g_Game.ObjectDelete(m_ConstructionBoxTrigger);
1792 }
1793
1794 [Obsolete("no replacement")]
1796 {
1798 return false;
1799
1800 return m_ConstructionBoxTrigger.IsColliding();
1801 }
1802
1804}
1805
1807{
1809 static void SpawnConstructionMaterialPilesEx(notnull EntityAI entity, Man player, string cfgPath, string mainPartName, string damagezoneName = "", bool isBase = false, bool throwPiles = false)
1810 {
1811 string partName = mainPartName; //'mainPartName' is actually a PART_NAME, using this to avoid further confustion
1812 int childCount = g_Game.ConfigGetChildrenCount(cfgPath);
1813
1814 for (int i = 0; i < childCount; ++i)
1815 {
1816 string child_name;
1817 g_Game.ConfigGetChildName(cfgPath, i, child_name);
1818
1819 //get type, quantity from material
1820 string configPath;
1821 string type;
1822 string slot_name;
1823 configPath = cfgPath + " " + child_name + " " + "type";
1824 g_Game.ConfigGetText(configPath, type);
1825 configPath = cfgPath + " " + child_name + " " + "slot_name";
1826 g_Game.ConfigGetText(configPath, slot_name);
1827 configPath = cfgPath + " " + child_name + " " + "quantity";
1828 float quantity = g_Game.ConfigGetFloat(configPath);
1829 configPath = cfgPath + " " + child_name + " " + "lockable";
1830 bool lockable = g_Game.ConfigGetInt(configPath);
1831 configPath = cfgPath + " " + child_name + " " + "skipOnDismantle";
1832 bool skipOnDismantle = g_Game.ConfigGetInt(configPath);
1833
1834 if (skipOnDismantle)
1835 continue;
1836
1837 //receive material quantity
1838 ItemBase attachment = ItemBase.Cast(entity.FindAttachmentBySlotName(slot_name));
1839 int slot_id;
1840
1841 //material still attached
1842 if (lockable) //if lockable
1843 {
1844 if (attachment)
1845 {
1847 attachment.GetInventory().GetCurrentInventoryLocation(src);
1848 if (LogManager.IsBaseBuildingLogEnable()) bsbDebugPrint("[bsb] " + Object.GetDebugName(entity) + " DropNonUsableMaterials UNlocking slot=" + src.GetSlot());
1849 entity.GetInventory().SetSlotLock(src.GetSlot() , false);
1850
1851 //detach if base
1852 if (isBase)
1853 {
1854 if (g_Game.IsMultiplayer() && player)
1855 {
1857 GameInventory.SetGroundPosByOwner(player, src.GetItem(), dst);
1858 player.ServerTakeToDst(src, dst);
1859 }
1860 else
1861 {
1862 entity.GetInventory().DropEntity(InventoryMode.PREDICTIVE, entity, attachment);
1863 }
1864 }
1865 }
1866 }
1867 else
1868 {
1869 float pileHealth;
1870 float qtyCoef;
1871 vector destination = entity.GetPosition();
1872 vector playerPosition;
1873 //placed on helper memory point, if available, or on player pos, if available, or on entity pos otherwise
1874 if (player)
1875 {
1876 playerPosition = player.GetPosition();
1877 destination = playerPosition;
1878 }
1879
1880 if (entity.MemoryPointExists("" + partName + "_materials"))
1881 {
1882 destination = entity.GetMemoryPointPos("" + partName + "_materials");
1883 destination = g_Game.ObjectModelToWorld(entity, destination);
1884 }
1885 else if (entity.MemoryPointExists(partName))
1886 {
1887 destination = entity.GetMemoryPointPos(partName);
1888 destination = g_Game.ObjectModelToWorld(entity, destination);
1889 }
1890 pileHealth = entity.GetHealth01(damagezoneName, "Health") * MiscGameplayFunctions.GetTypeMaxGlobalHealth(type);
1891 qtyCoef = 1 - (entity.GetHealthLevel(damagezoneName) * Construction.DECONSTURCT_MATERIAL_LOSS) - Construction.DECONSTURCT_MATERIAL_LOSS;
1892 quantity *= qtyCoef;
1893 quantity = Math.Max(Math.Floor(quantity),1);
1894
1895 if (player)
1896 {
1897 vector posHead = MiscGameplayFunctions.GetPlayerHeadPosition(PlayerBase.Cast(player));
1898 MiscGameplayFunctions.CreateItemBasePilesDispersed(type, posHead, destination, UAItemsSpreadRadius.NARROW, quantity, pileHealth, player);
1899 }
1900 else
1901 {
1902 MiscGameplayFunctions.CreateItemBasePilesEx(type, destination, quantity, pileHealth, true, throwPiles);
1903 }
1904 }
1905 }
1906 }
1907
1908 [Obsolete("1.30: Use SpawnConstructionMaterialPilesEx instead")]
1909 static void SpawnConstructionMaterialPiles(notnull EntityAI entity, Man player, string cfg_path, string main_part_name, string damagezone_name = "", bool is_base = false)
1910 {
1911 SpawnConstructionMaterialPilesEx(entity, player, cfg_path, main_part_name, damagezone_name, is_base);
1912 }
1913}
1914
1917{
1922
1924 {
1926 m_PartName = "";
1927 m_PrimaryGeometry = ObjIntersectGeom;
1928 m_SecondaryGeometry = ObjIntersectView;
1929 }
1930}
1931
1933{
1935
1936 void SetPartName(string part_name)
1937 {
1938 m_PartName = part_name;
1939 }
1940
1942 {
1943 return m_PartName;
1944 }
1945
1946 override protected void UpdateInsiders(int timeout)
1947 {
1948 super.UpdateInsiders(20);
1949 }
1950
1952 {
1953 if (GetInsiders().Count() > 0)
1954 {
1955 return true;
1956 }
1957
1958 return false;
1959 }
1960}
InventoryMode
NOTE: PREDICTIVE is not to be used at all in multiplayer.
const int AT_DESTROY_PART
ConstructionPart GetConstructionPart()
Определения ActionPartInfo.c:235
static void Cleanup()
Определения AmmoTypes.c:134
class BaseBuildingBase extends ItemBase bsbDebugPrint(string s)
Определения BaseBuildingBase.c:1291
@ FAST
Определения BoatWaterEffects.c:7
string Debug()
Определения CachedEquipmentStorageBase.c:26
const int ECE_PLACE_ON_SURFACE
Определения CentralEconomy.c:38
PlayerSpawnPresetDiscreteItemSetSlotData name
one set for cargo
PlayerSpawnPreset slotName
void UpdateVisuals()
Определения CodeLockVisualManager.c:91
void DropNonUsableMaterialsServer(Man player, string part_name)
Определения ConstructionBase.c:1221
void HideConstructionPartPhysics(string part_name)
sets physics LOCALLY
Определения ConstructionBase.c:1059
bool CanDestroyPart(string part_name)
Определения ConstructionBase.c:1022
void ConstructionBase(EntityAI parent)
Определения ConstructionBase.c:58
vector GetBoxCenter(vector min_max[2])
Определения ConstructionBase.c:1634
bool CanBuildPart(string part_name, ItemBase tool, bool use_tool)
Определения ConstructionBase.c:583
bool UpdatePartSyncStateLocal(ConstructionPart part)
Returns 'true' if part state was locally changed.
Определения ConstructionBase.c:131
bool m_AnyPartBuildableByHands
Определения ConstructionBase.c:46
static const float DECONSTURCT_MATERIAL_LOSS
Определения ConstructionBase.c:35
void ProcessOnPartDestroyedServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part=false)
Определения ConstructionBase.c:419
void BuildPartServer(notnull Man player, string part_name, int action_id)
Определения ConstructionBase.c:1703
override bool CanUseHandConstruction()
Определения ConstructionBase.c:347
static const float SANDSTORM_DECAY_RATE_COEF
Default decay speed coef.
Определения ConstructionBase.c:39
bool IsCollidingEx(CollisionCheckData check_data)
Collision check for building part.
Определения ConstructionBase.c:1481
ConstructionDataTypeHolder m_TypeLevelHolder
Sandstorm decay speed coef.
Определения ConstructionBase.c:41
ConstructionPart GetBaseConstructionPart()
Определения ConstructionBase.c:670
ConstructionPart GetConstructionPartToDestroy(string part_name)
Определения ConstructionBase.c:1014
enum ConstructionMaterialType MAX_MATERIAL_PILES
void HandleEntityFalling(string partName)
when supporting part is removed, entities on top of it should transform to surface Y height
Определения ConstructionBase.c:241
void UpdateSpecificPartVisuals(ConstructionPart part)
update SPECIFIC ConstructionPart visuals
Определения ConstructionBase.c:446
bool HasMaterials(string part_name, bool repairing=false)
Определения ConstructionBase.c:1122
vector GetCollisionBoxSize(vector min_max[2])
Определения ConstructionBase.c:1574
bool ConstructionInsiderBoxCheck(PlayerBase player, ConstructionPart part)
Check character positioning with a box check (character must be inside at least one of the defined bo...
Определения ConstructionBase.c:842
void GetCollisionBoxData(string part_name, out vector min_max[2])
Определения ConstructionBase.c:1586
class StaticConstructionMethods m_AdditionalExcludes
Data structure for passing parameters (extendable, modable)
bool MaterialIsRuined(string part_name)
Определения ConstructionBase.c:627
bool HasConflictPart(string part_name)
Определения ConstructionBase.c:704
ConstructionPart GetConstructionPartToDismantle(string part_name, ItemBase tool)
Определения ConstructionBase.c:729
void DropEssentialAttachments(Man player, string partName)
Drop other, non-material attachments tied to the construction part.
Определения ConstructionBase.c:1338
void UpdateSpecificPartPhysics(ConstructionPart part)
update SPECIFIC part's physics
Определения ConstructionBase.c:477
void GetTriggerExtents(vector min_max[2], out vector extents[2])
Определения ConstructionBase.c:1646
static const float REPAIR_MATERIAL_PERCENTAGE
Определения ConstructionBase.c:34
void ProcessOnPartDismantledServer(Man player, string part_name, int action_id)
Определения ConstructionBase.c:405
void ProcessOnPartBuiltServer(Man player, string part_name, int action_id)
Определения ConstructionBase.c:379
void ReceiveMaterialsServer(notnull Man player, string part_name, string damagezone_name)
Определения ConstructionBase.c:1183
void GetConstructionPartsToBuild(string main_part_name, out array< ConstructionPart > construction_parts, ItemBase tool, out string real_constructionTarget, bool use_tool)
Определения ConstructionBase.c:642
bool GetItemFallDetectionBoxData(string partName, out vector minMax[2])
Определения ConstructionBase.c:1608
int m_PrimaryGeometry
Определения ConstructionBase.c:1920
int m_SecondaryGeometry
Определения ConstructionBase.c:1921
void ShowConstructionPart(string part_name)
Animates AnimationSource. Use on server only, AUTO-SYNCED.
Определения ConstructionBase.c:1032
ref array< ConstructionPart > m_ConstructionPartArray
INSTANCED construction part data;.
Определения ConstructionBase.c:43
bool IsTriggerColliding()
Определения ConstructionBase.c:1795
static const float DEFAULT_DECAY_RATE
Определения ConstructionBase.c:36
enum ConstructionMaterialType INDOORS
void HandleSyncDataDismantle(ConstructionPart part)
void UpdateConstructionParts()
Parse type data and create part instance data objects.
Определения ConstructionBase.c:517
bool IsPartConstructed(string part_name)
returns true if part constructed
Определения ConstructionBase.c:1068
void BuildPartServerEx(Man player, string part_name, int action_id)
new build part method
Определения ConstructionBase.c:179
ref array< ConstructionPart > m_BuiltConstructionPartArray
Определения ConstructionBase.c:44
void UpdateNavmesh()
Определения ConstructionBase.c:511
void DestroyConnectedParts(string part_name)
Определения ConstructionBase.c:223
float GetCurrentDecayCoef()
Определения ConstructionBase.c:334
void QueueFullUpdateParts(array< ConstructionPart > changedParts)
Определения ConstructionBase.c:562
bool CanUseToolToBuildPart(string part_name, ItemBase tool)
Определения ConstructionBase.c:1404
ConstructionPart CreatePartInstanceObject(typename partTypename)
Определения ConstructionBase.c:550
map< string, ref ConstructionPart > GetConstructionParts()
Определения ConstructionBase.c:573
static const float DEFAULT_DECAY_RATE_COEF
Percentage of max health where the decay stops.
Определения ConstructionBase.c:38
bool CanBuildPartEx(string partName, ItemBase tool, out EConstructionInfoCategories failureReasonsMask)
not meant to replace, but rather extend the functionality for specific use
Определения ConstructionBase.c:590
void HandleSyncDataBuild(ConstructionPart part)
override void OnHealthLevelChanged(int oldLevel, int newLevel, string zone)
Определения ConstructionBase.c:352
GetDefaultPartInstanceTypename()
Override on lower implements to create desired part types.
Определения ConstructionBase.c:556
ConstructionBoxTrigger m_ConstructionBoxTrigger
Определения ConstructionBase.c:1803
bool HasDependentPart(string part_name)
checks if construction part has dependent part (that is already built) because of which it cannot be ...
Определения ConstructionBase.c:772
void CollisionCheckData()
Определения ConstructionBase.c:1923
bool HasRequiredPart(string part_name)
checks if construction part has all the required parts built
Определения ConstructionBase.c:682
static const float DEFAULT_DECAY_THRESHOLD
HP/s change.
Определения ConstructionBase.c:37
void DestroyPartServer(Man player, string part_name, int action_id, bool destroyed_by_connected_part=false)
destroy part method
Определения ConstructionBase.c:209
void InitVisuals()
init ConstructionPart visuals
Определения ConstructionBase.c:439
array< ConstructionPart > GetConstructionPartArray()
Определения ConstructionBase.c:342
bool SupportRemovalCheck(string part_name)
Checks if all supports would hold on part removal. Returns 'false' if some would fail.
Определения ConstructionBase.c:786
void DismantlePartServer(notnull Man player, string part_name, int action_id)
Определения ConstructionBase.c:1711
ConstructionMaterialType
used to guide action sound selection, mostly. Could be also used for particles and stuff,...
Определения ConstructionBase.c:3
@ MATERIAL_RUBBLE
Определения ConstructionBase.c:11
@ MATERIAL_STAIRS
Определения ConstructionBase.c:7
@ MATERIAL_BRICK
Определения ConstructionBase.c:10
@ MATERIAL_NONE
Определения ConstructionBase.c:4
@ MATERIAL_LOG
Определения ConstructionBase.c:5
@ MATERIAL_WIRE
Определения ConstructionBase.c:9
void MoveMaterialAttachmentToGround(notnull EntityAI parent, Man player, notnull ItemBase attachment, notnull InventoryLocation invloc, string partName)
Определения ConstructionBase.c:1280
void CreateCollisionTrigger(string part_name, vector min_max[2], vector center)
Определения ConstructionBase.c:1757
void AddToConstructedParts(string part_name)
Определения ConstructionBase.c:140
array< string > GetValidDepenentPartsArray(string part_name, array< string > recurs=null)
Определения ConstructionBase.c:980
bool PartHasAnySupportFulfilled(string part_name)
checks if construction part has all the required support
Определения ConstructionBase.c:698
void HandleSyncDataDestroy(ConstructionPart part)
enum ConstructionMaterialType REFERENCE_DIRECTION
void DismantlePartServerEx(Man player, string part_name, int action_id)
new dismantle part method
Определения ConstructionBase.c:190
void ~ConstructionBase()
Определения ConstructionBase.c:78
void RemoveFromConstructedParts(string part_name)
Определения ConstructionBase.c:158
bool CanRepairPart(string partName, ItemBase tool=null, PlayerBase player=null, bool facingCheck=false)
Определения ConstructionBase.c:791
void UpdatePhysics()
update ALL parts physics. Sets hide first, then shows the rest. Use only if the update queue system w...
Определения ConstructionBase.c:490
void TakeMaterialsServer(string part_name, bool repairing=false)
Определения ConstructionBase.c:1139
bool HasMaterialsEx(string part_name, bool repairing=false, out string slotName="", out float requiredQuantity=0.0)
returns true if materials to build the part are available
Определения ConstructionBase.c:1081
void GetConstructionPartsUnableToBuild(string actionComponentName, out array< ConstructionPart > constructionParts, ItemBase tool, out string realConstructionTarget, bool useTool)
Определения ConstructionBase.c:656
bool CanUseToolToDismantlePart(string part_name, ItemBase tool)
Определения ConstructionBase.c:1443
bool ExceptionCheck(string part_name)
Exceptions from 'dependent parts' hierarchy are handled here.
Определения ConstructionBase.c:371
override void EEInitConstruction()
Определения ConstructionBase.c:90
bool ConstructionDirectionCheck(PlayerBase player, ConstructionPart part, EConstructionDirCheckType type)
Определения ConstructionBase.c:924
bool IsColliding(string part_name)
Определения ConstructionBase.c:1719
bool CanBuildUtilityPart(string partName)
Simplified condition for utility (non-)parts.
Определения ConstructionBase.c:613
void DestroyMaterialsServer(Man player, string part_name)
Определения ConstructionBase.c:1197
bool HasMaterialWithQuantityAttached(string slot_name, float quantity)
Определения ConstructionBase.c:1129
EntityAI m_EntityParent
Определения ConstructionBase.c:45
void ItemFall(string partName)
Определения ConstructionBase.c:250
void SetLockOnAttachedMaterials(string part_name, bool lock_slot)
Определения ConstructionBase.c:1383
void DestroyCollisionTrigger()
Определения ConstructionBase.c:1785
void ShowConstructionPartPhysics(string part_name)
sets physics LOCALLY
Определения ConstructionBase.c:1050
void HideConstructionPart(string part_name)
Animates AnimationSource. Use on server only, AUTO-SYNCED.
Определения ConstructionBase.c:1041
override void ProcessConstructionDecay(float dTime)
Handles decay for constructed parts, if enabled.
Определения ConstructionBase.c:307
bool CanDismantlePart(string part_name, ItemBase tool)
Определения ConstructionBase.c:739
EConstructionInfoCategories
Определения ConstructionConstants.c:2
string m_PartName
Определения ConstructionInitData.c:10
int GetMaterialType()
rough material type, used for effect playback
Определения ConstructionPart.c:843
array< string > GetRequiredParts()
Определения ConstructionPart.c:800
array< ref array< vector > > TConstructionPartInsiderBoxData
Определения ConstructionPart.c:1159
map
Определения ControlsXboxNew.c:4
DayZGame g_Game
Определения DayZGame.c:4074
override Widget Init()
Определения DayZGame.c:127
vector orientation
Определения DustKickupEffects.c:21
DiagMenuIDs
Определения EDiagMenuIDs.c:2
void SetParent(Object parent_obj, int pivot)
Set parent of the Effect.
Определения Effect.c:399
string path
Определения OptionSelectorMultistate.c:142
@ Count
Определения RandomGeneratorSyncManager.c:8
proto native void SetParams(vector center, vector orientation, vector edgeLength, ObjIntersect primaryType, ObjIntersect secondaryType, bool fullComponentInfo)
Set the parameters.
Class that holds parameters to feed into CGame.IsBoxCollidingGeometryProxy.
static bool GetDisableItemFalling()
Определения CfgGameplayHandler.c:352
static bool GetDisableIsCollidingCheck()
Определения CfgGameplayHandler.c:337
Super root of all classes in Enforce script.
Определения EnScript.c:11
void SetTargetPart(ConstructionPart target_part)
Определения ConstructionActionData.c:121
just declared for module 3 use
Определения Construction_Basic.c:3
string m_PartName
Определения ConstructionBase.c:1934
void UpdateInsiders(int timeout)
Определения ConstructionBase.c:1946
bool IsColliding()
Определения ConstructionBase.c:1951
string GetPartName()
Определения ConstructionBase.c:1941
void SetPartName(string part_name)
Определения ConstructionBase.c:1936
array< ConstructionPartTypeData > GetConstructionPartTypeDataArray()
Определения ConstructionPartTypedHolder.c:115
holder object for entity type-level parts info
Определения ConstructionPartTypedHolder.c:3
Used in BBB objects.
Определения Construction.c:3
static void AddPartToProcess(ConstructionBase con, ConstructionPart part)
Определения ConstructionManagerStatic.c:32
static void RemoveFromProcessing(ConstructionBase con)
Unremoved objects can become NULL.
Определения ConstructionManagerStatic.c:51
Static part of the construction system, for global handling mostly.
Определения ConstructionManagerStatic.c:4
instanced data holder for single construction material
Определения ConstructionMaterials.c:3
void OnBuiltServer(EntityAI parent, Man builder)
void HandleShowConstructionPart(EntityAI parent)
Определения ConstructionPart.c:412
void HandleHideConstructionPart(EntityAI parent)
Определения ConstructionPart.c:417
void OnBeforeDismantleServer(EntityAI parent, Man dismantler)
void InitAdditionalPartInstanceInfo(PartInstanceInitData initData)
intended to fill in additional INSTANCE info AFTER basic info is filled (which is tied to constructor...
void OnBeforeBuildServer(EntityAI parent, Man builder)
bool HasEssentialAttachmentSlots()
Определения ConstructionPart.c:263
void TryHandleUtilityParts(EntityAI parent)
int GetBuildIndicationTypeMask()
Определения ConstructionPart.c:336
string GetPartName()
Определения ConstructionPart.c:198
int GetMaterialType()
rough material type, used for effect playback
Определения ConstructionPart.c:326
array< string > GetEssentialAttachmentSlots()
Определения ConstructionPart.c:305
void OnDestroyedServer(EntityAI parent, Man destroyer)
Определения ConstructionPart.c:442
array< string > GetConflictedParts()
Определения ConstructionPart.c:288
bool IsBase()
Определения ConstructionPart.c:273
int GetDismantleActionTypeMask()
Определения ConstructionPart.c:341
void SetBuiltState(bool is_built)
Определения ConstructionPart.c:389
array< string > GetCollisionData()
strings of min/max selections (should be single points in memory LOD)
Определения ConstructionPart.c:294
bool IsBuilt()
Определения ConstructionPart.c:160
void HandleAddPhysics(EntityAI parent)
Определения ConstructionPart.c:422
bool CanBeRepaired(int zoneHealthLevel, ItemBase tool=null, PlayerBase player=null)
Определения ConstructionPart.c:177
bool CanSimulateItemFalling()
Определения ConstructionPart.c:258
void PlayConstructionEffects(EntityAI parent)
void SetPartTypeData(ConstructionPartTypeData ptd)
Определения ConstructionPart.c:395
TConstructionPartInsiderBoxData GetInsiderBoxData()
translated MODELSPACE positions of min/max memory points (should be single points in memory LOD)
Определения ConstructionPart.c:172
int GetBuildActionTypeMask()
Определения ConstructionPart.c:331
void OnDismantledServer(EntityAI parent, Man dismantler)
Определения ConstructionPart.c:437
bool IsUtilityPart()
Определения ConstructionPart.c:233
void OnBeforeDestroyServer(EntityAI parent, Man destroyer)
array< string > GetRequiredParts()
Определения ConstructionPart.c:283
void HandleRemovePhysics(EntityAI parent)
Определения ConstructionPart.c:427
string GetMainPartName()
Определения ConstructionPart.c:203
array< ref ConstructionMaterialData > GetMaterialsData()
Определения ConstructionPart.c:346
Instanced construction part data classes for dynamic data, statics now stored on EntityType level in ...
Определения ConstructionPart.c:4
static parts info, lives on EntityType level. Instanced data in 'ConstructionPart' class
Определения ConstructionPartTyped.c:3
static Shape DrawCylinder(vector pos, float radius, float height=1, int color=0x1fff7f7f, ShapeFlags flags=ShapeFlags.TRANSP|ShapeFlags.NOOUTLINE)
Определения 3_Game/DayZ/tools/Debug.c:411
Определения 3_Game/DayZ/tools/Debug.c:2
Определения EnDebug.c:241
ConstructionDataTypeHolderBasic GetConstructionDataHolderBasic()
Cast to 'ConstructionDataTypeHolder' before using in higher modules.
Определения EntityAIType.c:82
Определения EntityAIType.c:2
bool DropEntityWithTransform(InventoryMode mode, EntityAI owner, notnull EntityAI item, vector transform[4])
static bool SetGroundPosByOwner(EntityAI owner, notnull EntityAI item, out InventoryLocation ground)
proto native bool SetSlotLock(int slot, bool locked)
proto native EntityAI FindAttachment(int slot)
Returns attached entity in slot (you can use InventorySlots.GetSlotIdFromString(name) to get slot id)
script counterpart to engine's class Inventory
Определения Feet.c:1
proto native int GetSlot()
returns slot id if current type is Attachment
proto native EntityAI GetItem()
returns item of current inventory location
InventoryLocation.
Определения InventoryLocation.c:30
const int INVALID
Invalid slot (-1)
Определения InventorySlots.c:17
static proto native int GetSlotIdFromString(string slot_name)
converts string to slot_id
provides access to slot configuration
Определения InventorySlots.c:6
override bool SetQuantity(float value, bool destroy_config=true, bool destroy_forced=false, bool allow_client=false, bool clamp_to_stack_max=true)
Определения PileOfBricks.c:64
static bool IsBaseBuildingLogEnable()
Определения 3_Game/DayZ/tools/Debug.c:809
Trigger only accepting Object which IsMan()
Определения ManTrigger.c:3
Определения EnMath3D.c:28
Определения EnMath.c:7
Определения ObjectTyped.c:2
EntityAI m_ParentEnt
Определения ConstructionInitData.c:4
proto external SimulationState GetSimulationState()
Returns simulation state of the physics body.
proto external void ApplyImpulse(vector impulse)
Applies impulse on the physics body.
Определения Physics.c:17
Определения PlayerBaseClient.c:2
static void SpawnConstructionMaterialPiles(notnull EntityAI entity, Man player, string cfg_path, string main_part_name, string damagezone_name="", bool is_base=false)
Определения ConstructionBase.c:1909
static void SpawnConstructionMaterialPilesEx(notnull EntityAI entity, Man player, string cfgPath, string mainPartName, string damagezoneName="", bool isBase=false, bool throwPiles=false)
spawns material from any construction; 'player' parameter optional; 'main_part_name' is actually a PA...
Определения ConstructionBase.c:1809
Deprecated.
Определения ConstructionBase.c:1807
Native class for boats - handles physics simulation.
Определения Boat.c:29
array< ref TriggerInsider > GetInsiders()
Get the current TriggerInsider array, left for backwards compatibility, moved down from ManTrigger.
Определения Trigger.c:128
const float NARROW
Определения ActionConstants.c:130
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
Определения Transport.c:70
static const vector Zero
Определения EnConvert.c:123
static const vector Up
Определения EnConvert.c:120
Определения EnConvert.c:119
const int COLOR_YELLOW_A
Определения 1_Core/DayZ/constants.c:74
ErrorExSeverity
Определения EnDebug.c:62
enum ShapeType ErrorEx
static proto bool GetBool(int id, bool reverse=false)
Get value as bool from the given script id.
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
static proto bool CastTo(out Class to, Class from)
Try to safely down-cast base class to child class.
void Obsolete(string msg="")
Определения EnScript.c:371
const int STATE_RUINED
Определения 3_Game/DayZ/constants.c:909
const int STATE_PRISTINE
Определения 3_Game/DayZ/constants.c:913
const int MATERIAL_METAL
Определения 1_Core/DayZ/constants.c:91
const int MATERIAL_WOOD
Определения 1_Core/DayZ/constants.c:101
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
static proto bool IntersectCylinderOBB(vector mins, vector maxs, vector obbMat[4], vector cylMat[4], float cylinderRadius, float cylinderHeight)
Tests whether cylinder is intersecting oriented box.
static void MatrixIdentity4(out vector mat[4])
Creates identity matrix.
Определения EnMath3D.c:256
static proto float Max(float x, float y)
Returns bigger of two given values.
static proto float Floor(float f)
Returns floor of value.
static proto float Cos(float angle)
Returns cosinus of angle in radians.
static proto float Clamp(float value, float min, float max)
Clamps 'value' to 'min' if it is lower than 'min', or to 'max' if it is higher than 'max'.
static proto float Sin(float angle)
Returns sinus of angle in radians.
static proto float Ceil(float f)
Returns ceil of value.
static const float DEG2RAD
Определения EnMath.c:17
static proto float AbsFloat(float f)
Returns absolute value.
SimulationState
Определения SimulationState.c:13
ActiveState
Определения ActiveState.c:10
proto native void dBodyActive(notnull IEntity ent, ActiveState activeState)
proto void Insert(int index, string input)
Inserts a string into the n-th index, increasing the string length by the size of the input.
proto int ToLower()
Changes string to lowercase. Returns length.
proto native bool IsCLIParam(string param)
Returns if command line argument is present.
const int CALL_CATEGORY_SYSTEM
Определения 3_Game/DayZ/tools/tools.c:8
@ DISABLED
Определения EnWidgets.c:79
int ARGB(int a, int r, int g, int b)
Определения proto.c:322