Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
miscgameplayfunctions.c
Go to the documentation of this file.
2 {
3  bool m_TransferAgents;
4  bool m_TransferVariables;
5  bool m_TransferHealth;
6  bool m_ExcludeQuantity;
7  float m_quantity_override;
8 
9  void TurnItemIntoItemLambda (EntityAI old_item, string new_item_type, PlayerBase player)
10  {
11  SetTransferParams();
12  }
13 
14  void SetTransferParams (bool transfer_agents = true, bool transfer_variables = true, bool transfer_health = true, bool exclude_quantity = false, float quantity_override = -1)
15  {
16  m_TransferAgents = transfer_agents;
17  m_TransferVariables = transfer_variables;
18  m_TransferHealth = transfer_health;
19  m_ExcludeQuantity = exclude_quantity;
20  m_quantity_override = quantity_override;
21  }
22 
23  override void CopyOldPropertiesToNew (notnull EntityAI old_item, EntityAI new_item)
24  {
25  super.CopyOldPropertiesToNew(old_item, new_item);
26 
27  if (new_item)
28  {
29  MiscGameplayFunctions.TransferItemProperties(old_item, new_item, m_TransferAgents, m_TransferVariables, m_TransferHealth, m_ExcludeQuantity);
30  MiscGameplayFunctions.TransferInventory(old_item, new_item, m_Player);
31 
32  //quantity override
33  if (ItemBase.Cast(new_item) && m_quantity_override != -1)
34  {
35  m_quantity_override = Math.Max(m_quantity_override,0);
36  ItemBase.Cast(new_item).SetQuantity(m_quantity_override);
37  }
38  }
39  else
40  {
41  Debug.LogError("TurnItemIntoItemLambda: failed to create new item","static");
42  }
43  }
44 
46  override void VerifyItemTypeBySlotType ()
47  {
48  if (m_NewLocation.GetType() == InventoryLocationType.ATTACHMENT && m_OldItem.ConfigIsExisting("ChangeIntoOnAttach"))
49  {
50  string str;
51  int idx = -1;
52  TStringArray inventory_slots = new TStringArray;
53  TIntArray inventory_slots_idx = new TIntArray;
54  TStringArray attach_types = new TStringArray;
55 
56  m_OldItem.ConfigGetTextArray("ChangeInventorySlot",inventory_slots);
57  if (inventory_slots.Count() < 1) //is string
58  {
59  inventory_slots_idx.Insert(InventorySlots.GetSlotIdFromString(m_OldItem.ConfigGetString("ChangeInventorySlot")));
60  attach_types.Insert(m_OldItem.ConfigGetString("ChangeIntoOnAttach"));
61  }
62  else //is array
63  {
64  inventory_slots_idx.Clear();
65  for (int i = 0; i < inventory_slots.Count(); i++)
66  {
67  inventory_slots_idx.Insert(InventorySlots.GetSlotIdFromString(inventory_slots.Get(i)));
68  }
69  m_OldItem.ConfigGetTextArray("ChangeIntoOnAttach",attach_types);
70  }
71 
72  idx = m_NewLocation.GetSlot();
73  str = attach_types.Get(inventory_slots_idx.Find(idx));
74  if (str != "")
75  {
76  m_NewItemType = str;
77  }
78  }
79  }
80 
81  override void OnSuccess (EntityAI new_item)
82  {
83  super.OnSuccess(new_item);
84  if( m_Player )
85  {
86  m_Player.GetItemAccessor().OnItemInHandsChanged();
87  }
88  }
89 };
90 
91 class TurnItemIntoItemLambdaAnimSysNotifyLambda extends TurnItemIntoItemLambda
92 {
93  override void OnSuccess (EntityAI new_item)
94  {
95  super.OnSuccess(new_item);
96  if( m_Player )
97  {
98  m_Player.GetItemAccessor().OnItemInHandsChanged();
99  }
100  }
101 }
102 
103 class TurnItemIntoItemLambdaRestrainLambda extends TurnItemIntoItemLambdaAnimSysNotifyLambda
104 {
105  override void OnSuccess (EntityAI new_item)
106  {
107  super.OnSuccess(new_item);
108  m_Player.SetRestrained(true);
109  }
110 }
111 
116 {
117  PlayerBase m_Player;
118 
119  void DropEquipAndDestroyRootLambda (EntityAI old_item, string new_item_type, PlayerBase player)
120  {
121  m_Player = player;
122  }
123 
124  override void CopyOldPropertiesToNew (notnull EntityAI old_item, EntityAI new_item)
125  {
126  super.CopyOldPropertiesToNew(old_item, new_item);
127 
128  InventoryLocation understash_src = m_NewLocation; // m_NewLocation is a backup of original old_item's src before the operation started
129 
130  array<EntityAI> children = new array<EntityAI>;
131  old_item.GetInventory().EnumerateInventory(InventoryTraversalType.LEVELORDER, children);
132  int count = children.Count();
133  for (int i = 0; i < count; i++)
134  {
135  EntityAI child = children.Get(i);
136  if (child)
137  {
138  InventoryLocation child_src = new InventoryLocation;
139  child.GetInventory().GetCurrentInventoryLocation(child_src);
140 
141  InventoryLocation child_dst = new InventoryLocation;
142  //@TODO: modify _dst with place on gnd?
143 
144  vector m4[4];
145  Math3D.MatrixIdentity4(m4);
146 
148  GameInventory.PrepareDropEntityPos(old_item, child, m4, false, -1);
149 
150  child_dst.SetGround(child,m4);
151 
152  m_Player.LocalTakeToDst(child_src, child_dst);
153 
154  GetGame().RemoteObjectTreeCreate(child); // this forces server to send CreateVehicle Message to client. This is needed for preserving the appearance of network operations on client (so that DeleteObject(old) arrives before CreateVehicle(new)). @NOTE: this does not delete the object on server, only it's network representation.
155  }
156  }
157  }
158 }
159 
164 {
167 
168  void MoveEquipToExistingItemAndDestroyOldRootLambda (EntityAI old_item, string new_item_type, PlayerBase player, EntityAI new_item)
169  {
170  m_Player = player;
171  m_NewItem = new_item;
172  if (new_item_type != string.Empty)
173  Error("MoveEquipAndDestroyRootLambda expects new_item_type to be empty");
174  }
175 
176  override protected void RemoveNetworkObjectInfo ()
177  {
178  super.RemoveNetworkObjectInfo();
179  GetGame().RemoteObjectTreeDelete(m_NewItem);
180  }
181  override protected void UndoRemoveNetworkObjectInfo ()
182  {
183  super.UndoRemoveNetworkObjectInfo();
184  GetGame().RemoteObjectTreeCreate(m_NewItem);
185  }
186 
187  override void CopyOldPropertiesToNew (notnull EntityAI old_item, EntityAI new_item)
188  {
189  // @NOTE: new_item is NULL, this lambda does not create new entity
190  super.CopyOldPropertiesToNew(old_item, new_item);
191 
192  MiscGameplayFunctions.TransferInventory(old_item, m_NewItem, m_Player);
193  }
194 
195  override protected void CreateNetworkObjectInfo (EntityAI new_item)
196  {
197  super.CreateNetworkObjectInfo(new_item);
198  GetGame().RemoteObjectTreeCreate(m_NewItem);
199  }
200 };
201 
203 {
205 };
206 
208 {
209  NONE = 0,
210  SPLIT = 1, //< Splits the item when it has quantity, recommended to use when called on an attachment
211 }
212 
213 class MiscGameplayFunctions
214 {
216  static float Truncate(float value, int decimals = 2)
217  {
218  int multiplier = Math.Pow(10,decimals);
219  return Math.Clamp(Math.Floor(value * multiplier),float.LOWEST, float.MAX) / multiplier;
220  }
222  static string TruncateToS(float value, int decimals = 2)
223  {
224  return Truncate(value, decimals).ToString();
225  }
227  static vector TruncateVec(vector value, int decimals = 2)
228  {
229  int multiplier = Math.Pow(10,decimals);
230  float v1 = Math.Clamp(Math.Floor(value[0] * multiplier),float.LOWEST, float.MAX) / multiplier;
231  float v2 = Math.Clamp(Math.Floor(value[1] * multiplier),float.LOWEST, float.MAX) / multiplier;
232  float v3 = Math.Clamp(Math.Floor(value[2] * multiplier),float.LOWEST, float.MAX) / multiplier;
233  return Vector(v1,v2,v3);
234  }
235 
236  static string TruncateVecToS(vector value,int decimals = 2, string delimiter = " ")
237  {
238  return MiscGameplayFunctions.TruncateToS(value[0],decimals) + delimiter + MiscGameplayFunctions.TruncateToS(value[1],decimals) +delimiter + MiscGameplayFunctions.TruncateToS(value[2],decimals));
239  }
240 
241  static string GetColorString(float r, float g, float b, float a)
242  {
243  return string.Format("#(argb,8,8,3)color(%1,CO)", string.Format("%1,%2,%3,%4", r, g, b, a));
244  }
245 
247  static string ValueToBar(float value, string bar = "[----------]", string mark = "x")
248  {
249  int length = bar.Length() - 2;
250  float index = Math.Lerp(0,length, value);
251  index = Math.Round(index);
252  index = Math.Clamp(index,0,length);
253 
254  return InsertAtPos(bar,mark,index);
255  }
256 
258  static string InsertAtPos(string base, string insert, int pos)
259  {
260  int length_first = pos+1;
261  int length_base = base.Length();
262  int length_second = length_base - length_first;
263  string first = base.Substring(0,length_first);
264  string second = base.Substring(pos+1,length_second);
265  return first + insert + second;
266  }
267 
269  static void TransferItemProperties(EntityAI source, notnull EntityAI target, bool transfer_agents = true, bool transfer_variables = true, bool transfer_health = true, bool exclude_quantity = false)
270  {
271  ItemBase target_ib = ItemBase.Cast(target);
272  ItemBase source_ib = ItemBase.Cast(source);
273 
274  if( transfer_agents ) target_ib.TransferAgents( source.GetAgents() );
275 
276  if( transfer_variables )
277  {
278  MiscGameplayFunctions.TransferItemVariables(source_ib, target_ib, exclude_quantity);
279  }
280 
281  if (GetGame().IsServer() || !GetGame().IsMultiplayer())
282  {
283  if( transfer_health )
284  target_ib.SetHealth01("", "", source.GetHealth01("",""));
285  }
286  }
287 
288  static void TransferItemVariables(ItemBase source, ItemBase target, bool exclude_quantity = false)
289  {
290  target.TransferVariablesFloat( source.GetVariablesFloat() );
291  //target.TransferVariablesString( source.GetVariablesString() );
292  if ( exclude_quantity )
293  {
294  target.RemoveItemVariable(VARIABLE_QUANTITY);
295  }
296  else if ( source.IsMagazine() && target.IsMagazine() )
297  {
298  Magazine source_mag = Magazine.Cast(source);
299  Magazine target_mag = Magazine.Cast(target);
300 
301  target_mag.ServerSetAmmoCount( source_mag.GetAmmoCount() );
302  }
303 
304  if ( source.IsWeapon() && target.IsWeapon() )
305  {
306  Weapon_Base source_wpn = Weapon_Base.Cast(source);
307  Weapon_Base target_wpn = Weapon_Base.Cast(target);
308 
309  target_wpn.CopyWeaponStateFrom(source_wpn);
310  }
311  else if ( source.HasEnergyManager() && target.HasEnergyManager() )
312  {
313  ComponentEnergyManager ems = source.GetCompEM();
314  ComponentEnergyManager emt = target.GetCompEM();
315 
316  emt.SetEnergy(ems.GetEnergy());
317 
318  if (ems.IsSwitchedOn())
319  emt.SwitchOn();
320  }
321  else if ( source.CanDecay() && target.CanDecay() )
322  {
323  Edible_Base source_edb = Edible_Base.Cast(source);
324  Edible_Base target_edb = Edible_Base.Cast(target);
325 
326  target_edb.TransferFoodStage(source_edb);
327  }
328  }
329 
330  static TransferInventoryResult TransferInventory( EntityAI sourceItem, EntityAI targetItem, PlayerBase player)
331  {
333 
334  array<EntityAI> children = new array<EntityAI>;
335  sourceItem.GetInventory().EnumerateInventory(InventoryTraversalType.LEVELORDER, children);
336  int count = children.Count();
337  for (int i = 0; i < count; i++)
338  {
339  EntityAI child = children.Get(i);
340  if (child)
341  {
342  InventoryLocation child_src = new InventoryLocation;
343  child.GetInventory().GetCurrentInventoryLocation( child_src );
344 
345  InventoryLocation child_dst = new InventoryLocation;
346  child_dst.Copy( child_src );
347  child_dst.SetParent( targetItem );
348 
349  bool drop = false;
350 
351  if (GameInventory.LocationCanAddEntity(child_dst))
352  {
353  // try to move it to the same exact place in dst
354  targetItem.GetInventory().TakeToDst(InventoryMode.LOCAL, child_src, child_dst);
355  }
356  else
357  {
358  drop = true; // or drop otherwise
359  }
360 
361  if (drop)
362  {
363  player.LocalDropEntity(child);
364  GetGame().RemoteObjectTreeCreate(child);
365  result = TransferInventoryResult.DroppedSome;
366  }
367  }
368  }
369  return result;
370  }
371 
372  static void UnlimitedAmmoDebugCheck(Weapon_Base weapon)
373  {
374  if ( ItemBase.GetDebugActionsMask() & DebugActionType.UNLIMITED_AMMO )
375  {
376  Magazine magazine;
377  if ( GetGame().IsServer() )
378  {
379  magazine = weapon.GetMagazine(weapon.GetCurrentMuzzle());
380 
381  if (magazine)
382  {
383  if (magazine.GetAmmoCount() <= 5)
384  {
385  magazine.ServerSetAmmoMax();
386  }
387  }
388  }
389  else
390  {
391  magazine = weapon.GetMagazine(weapon.GetCurrentMuzzle());
392 
393  if (magazine)
394  {
395  if (magazine.GetAmmoCount() <= 5)
396  {
397  magazine.LocalSetAmmoMax();
398  }
399  }
400 
401  }
402  }
403  }
404 
405 
406 
407  static void TurnItemIntoItem (notnull ItemBase old_item, string new_item_type, notnull PlayerBase player)
408  {
409  TurnItemIntoItemEx(player, new TurnItemIntoItemLambda(old_item, new_item_type, player));
410  }
411 
412  static void TurnItemIntoItemEx (notnull PlayerBase player, ReplaceItemWithNewLambdaBase lambda)
413  {
414  player.ServerReplaceItemWithNew(lambda);
415  }
416 
417  static void TurnItemInHandsIntoItem (notnull ItemBase old_item, string new_item_type, notnull PlayerBase player)
418  {
419  TurnItemInHandsIntoItemEx(player, new TurnItemIntoItemLambda(old_item, new_item_type, player));
420  }
421 
422  static void TurnItemInHandsIntoItemEx (notnull PlayerBase player, ReplaceItemWithNewLambdaBase lambda)
423  {
424  player.ServerReplaceItemInHandsWithNew(lambda);
425  }
426 
428  static array<ItemBase> CreateItemBasePiles(string item_name, vector ground_position, float quantity, float health, bool floaty_spawn = false)
429  {
430  array<ItemBase> item_piles;
431  float max_stack_size;
432  ItemBase pile;
433 
434  item_piles = new array<ItemBase>;
435  max_stack_size = g_Game.ConfigGetInt("cfgVehicles " + item_name + " varStackMax");
436  if( max_stack_size < 1)
437  max_stack_size = g_Game.ConfigGetInt("cfgVehicles " + item_name + " varQuantityMax");
438  if( max_stack_size < 1)
439  max_stack_size = 1;
440 
441  int full_piles_count = Math.Floor(quantity/max_stack_size);
442  int rest = quantity - (full_piles_count*max_stack_size);
443 
444  for ( int i = 0; i < full_piles_count; i++ )
445  {
446  if (floaty_spawn)
447  pile = ItemBase.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_CREATEPHYSICS|ECE_UPDATEPATHGRAPH));
448  else
449  pile = ItemBase.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
450  pile.SetQuantity(max_stack_size);
451  pile.SetHealth(health);
452  item_piles.Insert(pile);
453  }
454  if ( rest > 0 )
455  {
456  if (floaty_spawn)
457  pile = ItemBase.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_CREATEPHYSICS|ECE_UPDATEPATHGRAPH));
458  else
459  pile = ItemBase.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
460  pile.SetQuantity(rest);
461  pile.SetHealth(health);
462  item_piles.Insert(pile);
463  }
464  return item_piles;
465  }
466 
467  static array<Magazine> CreateMagazinePiles(string item_name, vector ground_position, float quantity, float health )
468  {
469  array<Magazine> items;
470  float stack_size;
471  Magazine pile;
472 
473  items = new array<Magazine>;
474  stack_size = g_Game.ConfigGetInt("cfgMagazines " + item_name + " count");
475 
476  int piles_count = Math.Floor(quantity/stack_size);
477  int rest = quantity - (piles_count*stack_size);
478 
479  for ( int i = 0; i < piles_count; i++ )
480  {
481  pile = Magazine.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
482  pile.ServerSetAmmoCount(stack_size);
483  items.Insert(pile);
484  }
485  if ( rest > 0)
486  {
487  pile = Magazine.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
488  pile.ServerSetAmmoCount(rest);
489  items.Insert(pile);
490  }
491  return items;
492  }
493 
494  static array<Magazine> CreateMagazinePilesFromBullet(string bullet_type, vector ground_position, float quantity, float health )
495  {
496  array<Magazine> items;
497  items = new array<Magazine>;
498  float stack_size;
499  Magazine pile;
500  string item_name;
501  if( !g_Game.ConfigGetText("cfgAmmo " + bullet_type + " spawnPileType", item_name) )
502  return items;
503 
504  stack_size = g_Game.ConfigGetInt("cfgMagazines " + item_name + " count");
505 
506  if(stack_size > 0)
507  {
508  int piles_count = Math.Floor(quantity/stack_size);
509  int rest = quantity - (piles_count*stack_size);
510 
511  for ( int i = 0; i < piles_count; i++ )
512  {
513  pile = Magazine.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
514  pile.ServerSetAmmoCount(stack_size);
515  items.Insert(pile);
516  }
517  if ( rest > 0)
518  {
519  pile = Magazine.Cast(GetGame().CreateObjectEx(item_name, ground_position, ECE_PLACE_ON_SURFACE));
520  pile.ServerSetAmmoCount(rest);
521  items.Insert(pile);
522  }
523  }
524  return items;
525  }
526 
527  static int GetHealthLevelForAmmo(string class_name, float health)
528  {
529  float health_normalized = health / 100;
530  string config_path = CFG_WEAPONSPATH + " " + class_name + " DamageSystem" + " GlobalHealth" + " healthLabels";
531  CachedObjectsArrays.ARRAY_FLOAT.Clear();
532  GetGame().ConfigGetFloatArray(config_path, CachedObjectsArrays.ARRAY_FLOAT);
533  for(int i = 0; i < CachedObjectsArrays.ARRAY_FLOAT.Count(); i++)
534  {
535  if( health_normalized >= CachedObjectsArrays.ARRAY_FLOAT.Get(i) )
536  {
537  return i;
538  }
539  }
540  return -1;
541  }
542 
543  static float GetTypeMaxGlobalHealth(string class_name, string health_type = "Health")
544  {
545  float max_health;
546  string cfg_path;
547 
548  if ( GetGame().ConfigIsExisting(CFG_VEHICLESPATH+" "+class_name) )
549  {
550  cfg_path = CFG_VEHICLESPATH;
551  }
552  else if ( GetGame().ConfigIsExisting(CFG_WEAPONSPATH+" "+class_name) )
553  {
554  cfg_path = CFG_WEAPONSPATH;
555  }
556  else if ( GetGame().ConfigIsExisting(CFG_MAGAZINESPATH+" "+class_name) )
557  {
558  cfg_path = CFG_MAGAZINESPATH;
559  }
560  cfg_path = cfg_path + " "+class_name+" DamageSystem GlobalHealth " + health_type + " hitpoints";
561  max_health = GetGame().ConfigGetFloat(cfg_path);
562 
563  return max_health;
564  }
565 
566  static bool GetProjectedCursorPos3d (out vector position, Weapon_Base weapon)
567  {
568  vector usti_hlavne_position = weapon.GetSelectionPositionMS( "usti hlavne" );
569  vector konec_hlavne_position = weapon.GetSelectionPositionMS( "konec hlavne" );
570  vector end_point = weapon.ModelToWorld(usti_hlavne_position);
571  vector begin_point = weapon.ModelToWorld(konec_hlavne_position);
572  vector contact_dir;
573  int contact_component;
574 
575  vector aim_point = end_point - begin_point;
576  aim_point = aim_point.Normalized() * PROJECTED_CURSOR_DISTANCE;
577  aim_point = aim_point + end_point;
578 
579  if (DayZPhysics.RaycastRV(begin_point, aim_point, position, contact_dir, contact_component, null, null, null, false, false, ObjIntersectFire))
580  return true;
581  return false;
582  }
583 
584  static void GetHeadBonePos(notnull PlayerBase player, out vector pos)
585  {
586  // Get position of head for starting trace pos, otherwise use sane default
587  int headBoneIdx = player.GetBoneIndexByName("Head");
588  if ( headBoneIdx == -1 )
589  { pos = player.GetPosition()[1] + 1.6; }
590  else
591  { pos = player.GetBonePositionWS(headBoneIdx); }
592  }
593 
594  static vector GetHeadingVector(notnull PlayerBase player)
595  {
596  vector dir = vector.Zero;
597  float headingAngle = GetHeadingAngle(player);
598  dir[0] = Math.Cos(headingAngle + Math.PI_HALF);
599  dir[2] = Math.Sin(headingAngle + Math.PI_HALF);
600 
601  return dir.Normalized();
602  }
603 
604  static float GetHeadingAngle(notnull DayZPlayerImplement player)
605  {
606  HumanInputController hic = player.GetInputController();
607  float headingAngle = hic.GetHeadingAngle();
608 
609  return headingAngle;
610  }
611 
612  static float GetEnergyMetabolicSpeed(int movement_speed)
613  {
614  float speed;
615  switch (movement_speed)
616  {
617  case DayZPlayerConstants.MOVEMENTIDX_WALK:
618  speed = PlayerConstants.METABOLIC_SPEED_ENERGY_WALK;
619  break;
620  case DayZPlayerConstants.MOVEMENTIDX_RUN:
621  speed = PlayerConstants.METABOLIC_SPEED_ENERGY_JOG;
622  break;
623  case DayZPlayerConstants.MOVEMENTIDX_SPRINT:
624  speed = PlayerConstants.METABOLIC_SPEED_ENERGY_SPRINT;
625  break;
626  default:
627  speed = 0;
628  break;
629  }
630 
631  speed += PlayerConstants.METABOLIC_SPEED_ENERGY_BASAL;
632  return speed;
633  }
634 
635  static float GetWaterMetabolicSpeed(int movement_speed)
636  {
637  float speed;
638  switch (movement_speed)
639  {
640  case DayZPlayerConstants.MOVEMENTIDX_WALK:
641  speed = PlayerConstants.METABOLIC_SPEED_WATER_WALK;
642  break;
643  case DayZPlayerConstants.MOVEMENTIDX_RUN:
644  speed = PlayerConstants.METABOLIC_SPEED_WATER_JOG;
645  break;
646  case DayZPlayerConstants.MOVEMENTIDX_SPRINT:
647  speed = PlayerConstants.METABOLIC_SPEED_WATER_SPRINT;
648  break;
649  default:
650  speed = 0;
651  break;
652  }
653 
654  speed += PlayerConstants.METABOLIC_SPEED_WATER_BASAL;
655  return speed;
656  }
657 
658  static string ObtainRestrainItemTargetClassname(notnull EntityAI entity)
659  {
660  return entity.ConfigGetString( "OnRestrainChange");
661  }
662 
663  static void TransformRestrainItem(EntityAI current_item, EntityAI tool, PlayerBase player_source, PlayerBase player_target, bool destroy = false)
664  {
665  bool type;
666 
667  if ( tool )
668  {
669  //is unrestrain and not struggle
670  type = tool.ConfigGetBool("RestrainUnlockType");
671  }
672  string new_item_name = current_item.ConfigGetString( "OnRestrainChange");
673 
674  if ( new_item_name != "" )
675  {
676  if ( player_target )
677  {
678  if (player_target.IsAlive())
679  MiscGameplayFunctions.TurnItemIntoItemEx(player_target, new ReplaceAndDestroyLambdaEx(current_item, new_item_name, player_target, type));
680  else
681  MiscGameplayFunctions.TurnItemIntoItemEx(player_source, new DestroyItemInCorpsesHandsAndCreateNewOnGndLambda(current_item, new_item_name, player_target, type));
682  }
683  else
684  {
685  MiscGameplayFunctions.TurnItemIntoItemEx(player_target, new ReplaceAndDestroyLambdaEx(current_item, new_item_name, player_target, type));
686  }
687  }
688  else
689  {
690  Error("current_item:" +current_item+ ", tool:" +tool +". No value for 'OnRestrainChange' config parameter");
691  }
692  }
693 
694  static bool IsValueInRange(float value, float from, float to)
695  {
696  return (value >= from) && (value <= to);
697  }
698 
700  static bool IsPlayerOrientedTowardPos(notnull DayZPlayerImplement player, vector target_pos, float cone_angle)
701  {
702  if (player)
703  {
704  vector player_dir = player.GetDirection();
705  vector to_target_dir = target_pos - player.GetPosition();
706 
707  player_dir[1] = 0;
708  to_target_dir[1] = 0;
709 
710  player_dir.Normalize();
711  to_target_dir.Normalize();
712 
713  float cos_fi = vector.Dot(player_dir, to_target_dir);
714  vector cross = player_dir * to_target_dir;
715 
716  int dir = Math.Acos(cos_fi) * Math.RAD2DEG;
717 
718  if( cross[1] < 0 )
719  dir = -dir;
720 
722  if( (dir <= cone_angle && dir >= -cone_angle) || Math.AbsFloat(dir) == 90 )
723  {
724  return true;
725  }
726  }
727 
728  return false;
729  }
730 
731  //TODO
732  static string SanitizeString(string input)
733  {
734  int max_length = 512;
735  string output = input;
736 
737  output = output.Substring(0,Math.Clamp(max_length,0,output.Length()));
738  return output;
739  }
740 
741  // deprecated - dont use
742  static bool ComplexBuildCollideCheckClient( PlayerBase player, ActionTarget target, ItemBase item, string partName = "" )
743  {
744  return true;
745  }
746 
747  static bool ComplexBuildCollideCheckClient( PlayerBase player, ActionTarget target, ItemBase item, int constraction_index )
748  {
749  BaseBuildingBase base_building = BaseBuildingBase.Cast( target.GetObject() );
750  if (base_building)
751  {
752  Construction construction = base_building.GetConstruction();
753  if (construction && BuildCondition( player, target, item, false, constraction_index ))
754  {
755  ConstructionActionData construction_action_data = player.GetConstructionActionData();
756  string partName;
757  if ( item )
758  {
759  partName = construction_action_data.GetBuildPartAtIndex(constraction_index).GetPartName();
760  }
761  else
762  {
763  partName = construction_action_data.GetBuildPartNoToolAtIndex(constraction_index).GetPartName();
764  }
765  bool boo;
766  if (base_building.PerformRoofCheckForBase(partName,player,boo) && boo)
767  return false;
768  if ( player.IsPlacingLocal() || player.IsPlacingServer() )
769  return false;
770 
771  /*float distance_root = vector.DistanceSq(target.GetCursorHitPos(), player.GetPosition());
772 
773  if (!CfgGameplayHandler.GetDisableDistanceCheck() && distance_root < UAMaxDistances.BASEBUILDING_SHORT)
774  {
775  return false;
776  } */
777  return !construction.IsColliding( partName );
778  }
779  }
780  return false;
781  }
782 
783  // deprecated - dont use
784  static bool BuildCondition( PlayerBase player, ActionTarget target, ItemBase item, bool camera_check )
785  {
786  return true;
787  }
788 
789  static bool BuildCondition( PlayerBase player, ActionTarget target, ItemBase item, bool camera_check, int constraction_index )
790  {
791  Object targetObject = target.GetObject();
792  if ( targetObject && targetObject.CanUseConstruction() )
793  {
794  BaseBuildingBase base_building = BaseBuildingBase.Cast( targetObject );
795  ConstructionActionData construction_action_data = player.GetConstructionActionData();
796  construction_action_data.SetTarget( targetObject );
797 
798  ConstructionPart constrution_part;
799  if ( item )
800  {
801  constrution_part = construction_action_data.GetBuildPartAtIndex(constraction_index);
802  }
803  else
804  {
805  constrution_part = construction_action_data.GetBuildPartNoToolAtIndex(constraction_index);
806  }
807 
808  //Debug
809  /*
810  if ( constrution_part )
811  {
812  Construction construction = base_building.GetConstruction();
813  construction.IsColliding( constrution_part.GetPartName() );
814  }
815  */
816 
817  if ( constrution_part )
818  {
819  //camera and position checks
820  bool position_check = ( base_building.MustBeBuiltFromOutside() && !base_building.IsPlayerInside(player, constrution_part.GetMainPartName()) ) || ( !base_building.MustBeBuiltFromOutside() && base_building.IsPlayerInside(player, constrution_part.GetMainPartName()) );
821  if ( position_check && !player.GetInputController().CameraIsFreeLook() )
822  {
823  //Camera check (client-only)
824  if ( camera_check )
825  {
826  if ( GetGame() && ( !GetGame().IsDedicatedServer() ) )
827  {
828  return !base_building.IsFacingCamera( constrution_part.GetMainPartName() );
829  }
830  }
831 
832  return true;
833  }
834  }
835  }
836 
837  return false;
838  }
839 
840  static void IsUnderRoofFromToCalculation(EntityAI entity, out vector from, out vector to, float height = GameConstants.ROOF_CHECK_RAYCAST_DIST)
841  {
842  vector minMax[2];
843  entity.GetCollisionBox(minMax);
844 
845  vector size = Vector(0,0,0);
846  //size[1] = minMax[1][1] - minMax[0][1];
847  float from_override = entity.HeightStartCheckOverride();
848  if (from_override > 0.0)
849  {
850  size[1] = from_override;
851  }
852  else
853  {
854  size[1] = minMax[1][1] - minMax[0][1];
855  }
856 
857  from = entity.GetPosition() + size;
858  if ( entity.HeightCheckOverride() > 0 )
859  {
860  to = entity.GetPosition() + Vector(0, entity.HeightCheckOverride(), 0);
861  }
862  else
863  {
864  vector ceiling = "0 0 0";
865  ceiling[1] = height;
866  to = from + ceiling; //+size ??? offset to cast same distance
867  }
868  }
869 
870  static bool IsUnderRoof(EntityAI entity, float height = GameConstants.ROOF_CHECK_RAYCAST_DIST)
871  {
872  return IsUnderRoofEx(entity, height, ObjIntersectView);
873  }
874 
875  static bool IsUnderRoofEx(EntityAI entity, float height = GameConstants.ROOF_CHECK_RAYCAST_DIST, int geometry = ObjIntersectView)
876  {
877  vector from;
878  vector to;
879 
880  IsUnderRoofFromToCalculation(entity, from, to, height);
881 
882  vector contact_pos;
883  vector contact_dir;
884 
885  int contact_component;
886  //set<Object> hit_object = new set<Object>;
887  bool boo = DayZPhysics.RaycastRV( from, to, contact_pos, contact_dir, contact_component, /*hit_object*/NULL, NULL, entity, false, false, geometry,0.25 );
888 
889  /*if (boo)
890  {
891  Debug.DrawSphere(from , 0.8,Colors.YELLOW, ShapeFlags.ONCE);
892  Debug.DrawSphere(to , 0.8,Colors.RED, ShapeFlags.ONCE);
893  }
894  else
895  {
896  Debug.DrawSphere(from , 0.8,Colors.GREEN, ShapeFlags.ONCE);
897  Debug.DrawSphere(to , 0.8,Colors.RED, ShapeFlags.ONCE);
898  }*/
899 
900  return boo;
901  }
902 
903  // cooking equipment effects (get position for steam particle)
904  static vector GetSteamPosition( EntityAI parent )
905  {
906  vector particle_pos;
907  float steam_offset = 0;
908 
909  if ( parent )
910  {
911  particle_pos = parent.GetPosition();
912 
913  if ( parent.IsInherited( PortableGasStove ) )
914  {
915  steam_offset = 0.2;
916  }
917  else if ( parent.IsInherited( FireplaceBase ) )
918  {
919  FireplaceBase fireplace = FireplaceBase.Cast( parent );
920 
921  if ( fireplace.IsBaseFireplace() )
922  {
923  steam_offset = 0.8;
924  }
925  else if ( fireplace.IsBarrelWithHoles() )
926  {
927  steam_offset = 1.1;
928  }
929  else if ( fireplace.IsFireplaceIndoor() )
930  {
931  steam_offset = 0.45;
932  }
933  else if ( fireplace.IsIndoorOven() )
934  {
935  steam_offset = 0.9;
936  }
937  }
938  }
939 
940  particle_pos[1] = particle_pos[1] + steam_offset;
941 
942  return particle_pos;
943  }
944 
945  static void DropAllItemsInInventoryInBounds(ItemBase ib, vector halfExtents)
946  {
947  if (!GetGame().IsServer())
948  return;
949  array<EntityAI> items = new array<EntityAI>;
950  ib.GetInventory().EnumerateInventory(InventoryTraversalType.LEVELORDER, items);
951 
952  vector direction = ib.GetDirection();
953  float dot = vector.Dot(direction, vector.Forward);
954 
955  float angle = Math.Acos(dot);
956  if (direction[0] < 0)
957  angle = -angle;
958 
959  float cos = Math.Cos(angle);
960  float sin = Math.Sin(angle);
961 
962  EntityAI item;
963  int count = items.Count();
964  for ( int i = 0; i < count; ++i )
965  {
966  item = items.Get(i);
967  if ( item )
968  ib.GetInventory().DropEntityInBounds(InventoryMode.SERVER, ib, item, halfExtents, angle, cos, sin);
969  }
970  }
971 
972  static void ThrowAllItemsInInventory(notnull EntityAI parent, int flags)
973  {
974  vector position = parent.GetPosition();
975  vector orientation = parent.GetOrientation();
976  vector rotation_matrix[3];
977  float direction[4];
978 
979  vector minmax[2];
980  parent.GetCollisionBox(minmax);
981 
982  Math3D.YawPitchRollMatrix( orientation, rotation_matrix );
983  Math3D.MatrixToQuat( rotation_matrix, direction );
984 
985  vector randomPos;
986  for ( int i = 0; i < parent.GetInventory().AttachmentCount(); ++i )
987  {
988  randomPos = Vector(position[0] + Math.RandomFloat(minmax[0][0], minmax[1][0]),
989  position[1] + Math.RandomFloat(minmax[0][1], minmax[1][1]),
990  position[2] + Math.RandomFloat(minmax[0][2], minmax[1][2]));
991 
992  ThrowEntityFromInventory(parent.GetInventory().GetAttachmentFromIndex( i ), randomPos, direction, -GetVelocity(parent), ThrowEntityFlags.NONE);
993  }
994 
995  for ( int j = 0; j < parent.GetInventory().GetCargo().GetItemCount(); ++j )
996  {
997  randomPos = Vector(position[0] + Math.RandomFloat(minmax[0][0], minmax[1][0]),
998  position[1] + Math.RandomFloat(minmax[0][1], minmax[1][1]),
999  position[2] + Math.RandomFloat(minmax[0][2], minmax[1][2]));
1000 
1001  ThrowEntityFromInventory(parent.GetInventory().GetCargo().GetItem( j ), randomPos, direction, -GetVelocity(parent), ThrowEntityFlags.NONE);
1002  }
1003  }
1004 
1005  static void ThrowEntityFromInventory(notnull EntityAI entity, vector position, float direction[4], vector force, int flags)
1006  {
1007  InventoryMode invMode = InventoryMode.SERVER;
1008  if ( !GetGame().IsMultiplayer() )
1009  invMode = InventoryMode.LOCAL;
1010 
1011  ItemBase entityIB;
1012  if (CastTo(entityIB, entity))
1013  {
1015  dst.SetGroundEx(entity, position, direction);
1016 
1017  if ( (flags & ThrowEntityFlags.SPLIT) && entityIB.CanBeSplit() )
1018  {
1019  for (int l = 0; l < entityIB.GetQuantity(); ++l)
1020  {
1021  ItemBase new_item = ItemBase.Cast( GameInventory.LocationCreateEntity( dst, entityIB.GetType(), ECE_NONE, RF_DEFAULT ) );
1022 
1023  if ( new_item )
1024  {
1025  MiscGameplayFunctions.TransferItemProperties(entityIB, new_item);
1026  entityIB.AddQuantity( -1 );
1027  new_item.SetQuantity( 1 );
1028  new_item.ThrowPhysically(null, force, false);
1029  }
1030  }
1031  }
1032  else
1033  {
1034  float stackable = entityIB.GetTargetQuantityMax();
1035  if ( !(stackable == 0 || stackable >= entityIB.GetQuantity()) )
1036  {
1037  while (entityIB.GetQuantity() > stackable)
1038  {
1039  InventoryLocation spltDst = new InventoryLocation;
1040  position[1] = position[1] + 0.1;
1041  spltDst.SetGroundEx(entity, position, direction);
1042 
1043  ItemBase splitItem = entityIB.SplitIntoStackMaxToInventoryLocationEx( spltDst );
1044  splitItem.ThrowPhysically(null, force, false);
1045  }
1046  }
1047 
1049  entity.GetInventory().GetCurrentInventoryLocation(src);
1050 
1051  entity.GetInventory().TakeToDst(invMode, src, dst);
1052  entityIB.ThrowPhysically(null, force, false);
1053  }
1054  }
1055  else
1056  {
1057  entity.GetInventory().DropEntity(invMode, entity.GetHierarchyRoot(), entity);
1058  dBodyApplyImpulse(entity, force);
1059  }
1060  }
1061 
1062  static float GetCurrentItemHeatIsolation( ItemBase pItem )
1063  {
1064  float wetFactor;
1065  float healthFactor;
1066 
1067  float heatIsolation = pItem.GetHeatIsolation();
1068  float itemHealthLabel = pItem.GetHealthLevel();
1069  float itemWetness = pItem.GetWet();
1070 
1072  if ( itemWetness >= GameConstants.STATE_DRY && itemWetness < GameConstants.STATE_DAMP )
1073  {
1074  wetFactor = GameConstants.ENVIRO_ISOLATION_WETFACTOR_DRY;
1075  }
1076  else if ( itemWetness >= GameConstants.STATE_DAMP && itemWetness < GameConstants.STATE_WET )
1077  {
1078  wetFactor = GameConstants.ENVIRO_ISOLATION_WETFACTOR_DAMP;
1079  }
1080  else if ( itemWetness >= GameConstants.STATE_WET && itemWetness < GameConstants.STATE_SOAKING_WET )
1081  {
1082  wetFactor = GameConstants.ENVIRO_ISOLATION_WETFACTOR_WET;
1083  }
1084  else if ( itemWetness >= GameConstants.STATE_SOAKING_WET && itemWetness < GameConstants.STATE_DRENCHED )
1085  {
1086  wetFactor = GameConstants.ENVIRO_ISOLATION_WETFACTOR_SOAKED;
1087  }
1088  else if ( itemWetness >= GameConstants.STATE_DRENCHED )
1089  {
1090  wetFactor = GameConstants.ENVIRO_ISOLATION_WETFACTOR_DRENCHED;
1091  }
1092 
1094  switch (itemHealthLabel)
1095  {
1096  case GameConstants.STATE_PRISTINE:
1097  healthFactor = GameConstants.ENVIRO_ISOLATION_HEALTHFACTOR_PRISTINE;
1098  break;
1099 
1100  case GameConstants.STATE_WORN:
1101  healthFactor = GameConstants.ENVIRO_ISOLATION_HEALTHFACTOR_WORN;
1102  break;
1103 
1104  case GameConstants.STATE_DAMAGED:
1105  healthFactor = GameConstants.ENVIRO_ISOLATION_HEALTHFACTOR_DAMAGED;
1106  break;
1107 
1108  case GameConstants.STATE_BADLY_DAMAGED:
1109  healthFactor = GameConstants.ENVIRO_ISOLATION_HEALTHFACTOR_B_DAMAGED;
1110  break;
1111 
1112  case GameConstants.STATE_RUINED:
1113  healthFactor = GameConstants.ENVIRO_ISOLATION_HEALTHFACTOR_RUINED;
1114  break;
1115  }
1116 
1118  heatIsolation *= healthFactor;
1119  heatIsolation *= wetFactor;
1120 
1121  return heatIsolation;
1122  }
1123 
1124  static void FilterObstructingObjects(array<Object> potentiallyObstructingObjects, out array<Object> obstructingObjects)
1125  {
1126  if (!obstructingObjects)
1127  obstructingObjects = new array<Object>;
1128 
1129  for ( int i = 0; i < potentiallyObstructingObjects.Count(); ++i )
1130  {
1131  Object obj = potentiallyObstructingObjects[i];
1132  if ( obj && ( obj.CanObstruct() || obj.CanProxyObstruct() ) )
1133  obstructingObjects.Insert(obj);
1134  }
1135  }
1136 
1137  static bool CanIgnoreDistanceCheck(Object obj)
1138  {
1139  return obj.IsTransport() || obj.CanUseConstruction();
1140  }
1141 
1143  static void FilterObstructedObjectsByGrouping(vector origin, float range, float distanceDelta, array<Object> objects, array<Object> obstructingObjects, out array<Object> filteredObjects, bool doDistanceCheck = false, bool checkIfDistanceCanBeIgnored = false, float maxDist = 0)
1144  {
1145  array<Object> vicinityObjects= new array<Object>;
1146  vicinityObjects.Copy(objects);
1147 
1148  int i = 0;
1149  int j = 0;
1150  int k = 0;
1151  int mCount = vicinityObjects.Count();
1152 
1153  if (!filteredObjects)
1154  filteredObjects = new array<Object>;
1155 
1156  // Remove objects that are too far from the player anyways
1157  if ( doDistanceCheck )
1158  {
1159  for ( i = vicinityObjects.Count() - 1; i >= 0; --i )
1160  {
1161  Object obj = vicinityObjects[i];
1162  if ( obj && !CanIgnoreDistanceCheck( obj ) && vector.DistanceSq(origin, obj.GetPosition()) > maxDist * maxDist )
1163  vicinityObjects.Remove(i);
1164  }
1165  }
1166 
1167  // Sort obstructingObjects to have the furthest one first
1168  array<Object> sortedObstructingObjects = new array<Object>;
1169  array<float> distanceHelper = new array<float>;
1170  array<float> distanceHelperUnsorted = new array<float>;
1171  float distance, dist1, dist2;
1172 
1173  for ( i = 0; i < obstructingObjects.Count(); ++i )
1174  {
1175  distance = vector.DistanceSq(obstructingObjects[i].GetWorldPosition(), origin);
1176  distanceHelper.Insert(distance);
1177  }
1178 
1179  distanceHelperUnsorted.Copy(distanceHelper);
1180  distanceHelper.Sort();
1181 
1182  for ( i = distanceHelper.Count() - 1; i >= 0; --i )
1183  sortedObstructingObjects.Insert(obstructingObjects[distanceHelperUnsorted.Find(distanceHelper[i])]);
1184 
1186  array<ref array<Object>> objectGroups = new array<ref array<Object>>;
1187  array<Object> group;
1188 
1189  float cos = Math.Cos(90);
1190  float sin = Math.Sin(90);
1191 
1192  // Iterate through sorted obstructingObjects
1193  for ( i = 0; i < sortedObstructingObjects.Count(); ++i )
1194  {
1195  Object obstrObj = sortedObstructingObjects[i];
1196  vector worldPos = obstrObj.GetWorldPosition();
1197  vector min, max;
1198  vector minMax[2];
1199  if ( obstrObj.GetCollisionBox(minMax) )
1200  {
1201  min = minMax[0];
1202  max = minMax[1];
1203  max = max * (obstrObj.GetOrientation() * range);
1204 
1205  vector center, dx, dy, dz, half;
1206  center = (min + max) * 0.5;
1207  dz = obstrObj.GetOrientation();
1208  dx = vector.RotateAroundZero(dz, vector.Up, cos, sin);
1209  dy = vector.RotateAroundZero(dz, vector.Aside, cos, sin);
1210  half = (max - min) * 0.5;
1211  half = Vector(Math.AbsFloat(half[0]), Math.AbsFloat(half[1]), Math.AbsFloat(half[2]));
1212 
1213  group = new array<Object>;
1214 
1215  // Group objects within the above box
1216  for ( j = vicinityObjects.Count() - 1; j >= 0; --j )
1217  {
1218  Object vicObj = vicinityObjects[j];
1219  if ( vicObj )
1220  {
1221  vector d = vicObj.GetWorldPosition() - worldPos + center;
1222  if ( Math.AbsFloat(vector.Dot(d, dx)) <= half[0] && Math.AbsFloat(vector.Dot(d, dy)) <= half[1] && Math.AbsFloat(vector.Dot(d, dz)) <= half[2] )
1223  {
1224  group.Insert(vicObj);
1225  vicinityObjects.Remove(j);
1226  }
1227  }
1228  }
1229 
1230  if ( group.Count() > 0 )
1231  tempGroups.Insert(group);
1232  }
1233  }
1234 
1235  // Go through the objects grouped by obstruction to split them by distance too
1236  for ( i = 0; i < tempGroups.Count(); ++i )
1237  SplitArrayIntoGroupsByDistance(tempGroups[i], objectGroups, distanceDelta);
1238 
1239  // Split initial groups by distance
1240  SplitArrayIntoGroupsByDistance(vicinityObjects, objectGroups, distanceDelta);
1241 
1242  // Raycast accordingly to groups
1243  IsObjectObstructedCache cache = new IsObjectObstructedCache(origin, mCount);
1244  for ( i = 0; i < objectGroups.Count(); ++i )
1245  {
1246  array<Object> objectGroup = objectGroups[i];
1247  Object sampleObject = objectGroup[0];
1248 
1249  if ( !IsObjectObstructedEx(sampleObject, cache) )
1250  filteredObjects.InsertAll(objectGroup);
1251 
1252  cache.ClearCache();
1253  }
1254  }
1255 
1256  static void SplitArrayIntoGroupsByDistance(array<Object> objects, array<ref array<Object>> objectGroups, float squaredDistanceDelta)
1257  {
1258  array<Object> group;
1259  for ( int i = 0; i < objects.Count(); )
1260  {
1261  Object obj1 = objects[i];
1262  if ( obj1 )
1263  {
1264  group = new array<Object>;
1265  group.Insert(obj1);
1266  for ( int j = objects.Count() - 1; j > i; --j )
1267  {
1268  Object obj2 = objects[j];
1269  if ( obj1 && obj2 )
1270  {
1271  vector start = obj1.GetWorldPosition();
1272  vector end = obj2.GetWorldPosition();
1273 
1274  float distance = vector.DistanceSq(start, end);
1275  if ( distance < squaredDistanceDelta )
1276  {
1277  group.Insert(obj2);
1278  objects.Remove(j);
1279  }
1280  }
1281  }
1282  objectGroups.Insert(group);
1283  objects.Remove(i);
1284  continue;
1285  }
1286  ++i;
1287  }
1288  }
1289 
1290  static bool IsObjectObstructed(Object object, bool doDistanceCheck = false, vector distanceCheckPos = "0 0 0", float maxDist = 0)
1291  {
1292  vector rayStart;
1293  MiscGameplayFunctions.GetHeadBonePos(PlayerBase.Cast(GetGame().GetPlayer()), rayStart);
1294  IsObjectObstructedCache cache = new IsObjectObstructedCache(rayStart, 1);
1295 
1296  return IsObjectObstructedEx(object, cache, doDistanceCheck, distanceCheckPos, maxDist);
1297  }
1298 
1299  static bool IsObjectObstructedEx(Object object, IsObjectObstructedCache cache, bool doDistanceCheck = false, vector distanceCheckPos = "0 0 0", float maxDist = 0)
1300  {
1301  if (!object)
1302  return true;
1303 
1304  PlayerBase player = PlayerBase.Cast(g_Game.GetPlayer());
1305  if (doDistanceCheck && vector.DistanceSq(player.GetPosition(), distanceCheckPos) > maxDist * maxDist)
1306  return true;
1307 
1308  cache.ObjectCenterPos = object.GetCenter();
1309 
1310  return IsObjectObstructedFilterEx(object, cache, player);
1311  }
1312 
1313  static bool IsObjectObstructedProxy(Object object, IsObjectObstructedCache cache, PlayerBase player)
1314  {
1315  if (object.CanProxyObstruct())
1316  {
1317  RaycastRVParams rayInput = new RaycastRVParams(cache.RaycastStart, cache.ObjectCenterPos, player);
1318  DayZPhysics.RaycastRVProxy(rayInput, cache.HitProxyObjects);
1319  if (cache.HitProxyObjects)
1320  {
1321  if (cache.HitProxyObjects.Count() > 0)
1322  {
1323  if (cache.HitProxyObjects[0].hierLevel > 0)
1324  {
1325  // ignores attachments on player
1326  if (!cache.HitProxyObjects[0].parent.IsMan())
1327  {
1328  if (cache.HitProxyObjects[0].parent)
1329  {
1330  EntityAI proxyParent = EntityAI.Cast(cache.HitProxyObjects[0].parent);
1331  if (proxyParent.GetInventory() && proxyParent.GetInventory().GetCargo())
1332  return true;
1333  }
1334  }
1335  }
1336  }
1337  }
1338  }
1339  return false;
1340  }
1341 
1342  static bool IsObjectObstructedFilter(Object object, IsObjectObstructedCache cache, PlayerBase player)
1343  {
1344  for ( int m = 0; m < cache.HitObjects.Count(); m++ )
1345  {
1346  Object hit_object = cache.HitObjects.Get(m);
1347 
1348  if ( hit_object.CanObstruct() )
1349  return true;
1350 
1351  //4.3. ignore item if items are big and heavy >= OBJECT_OBSTRUCTION_WEIGHT
1352  //EntityAI eai;
1353  //if ( Class.CastTo( eai, hit_object ) )
1354  //{
1355  // if ( eai.GetWeight() >= OBJECT_OBSTRUCTION_WEIGHT )
1356  // {
1357  // if ( eai != filtered_object && eai.GetHierarchyRoot() != filtered_object )
1358  // {
1359  // //Print("!!!!!obstacle vaha: " + hit_object);
1360  // is_obstructed = true;
1361  // }
1362  // }
1363  //}
1364  }
1365 
1366  return false;
1367  }
1368 
1370  static bool IsObjectObstructedFilterEx(Object object, IsObjectObstructedCache cache, PlayerBase player, int geometryTypeOverride = -1)
1371  {
1372  //first proxy geometries
1373  RaycastRVParams rayInput = new RaycastRVParams(cache.RaycastStart, cache.ObjectCenterPos, player);
1374  rayInput.flags = CollisionFlags.ALLOBJECTS;
1375  if (geometryTypeOverride != -1)
1376  rayInput.type = geometryTypeOverride; //default 'ObjIntersectView'
1377  DayZPhysics.RaycastRVProxy(rayInput, cache.HitProxyObjects);
1378  int count;
1379  int i;
1380 
1381  if (cache.HitProxyObjects)
1382  {
1383  count = cache.HitProxyObjects.Count();
1384  Object parent;
1385  for (i = 0; i < count; i++)
1386  {
1387  if (cache.HitProxyObjects[i].hierLevel > 0) //parent has to exist, skipping nullcheck
1388  {
1389  parent = cache.HitProxyObjects[i].parent;
1390  if (parent && !parent.IsMan() && parent.CanProxyObstruct())
1391  {
1392  if (parent != object || (parent == object && object.CanProxyObstructSelf()))
1393  return true;
1394  }
1395  }
1396  }
1397  }
1398 
1399  //second, regular raycast
1400  int geometry = ObjIntersectFire; //default for the RV raycast
1401  if (geometryTypeOverride != -1)
1402  geometry = geometryTypeOverride;
1403  DayZPhysics.RaycastRV(cache.RaycastStart, cache.ObjectCenterPos, cache.ObjectContactPos, cache.ObjectContactDir, cache.ContactComponent, cache.HitObjects, object, GetGame().GetPlayer(), false, false, geometry, 0.0, CollisionFlags.ALLOBJECTS);
1404  count = cache.HitObjects.Count();
1405  for (i = 0; i < count; i++ )
1406  {
1407  if (cache.HitObjects[i].CanObstruct())
1408  return true;
1409  }
1410 
1411  return false;
1412  }
1413 
1414  //Inflict absolute damage to item (used on tools when completing actions)
1415  static void DealAbsoluteDmg(ItemBase item, float dmg)
1416  {
1417  item.DecreaseHealth(dmg, false);
1418  }
1419 
1420  //Function used to normailze values, enter the used value and the max value (max will become 1)
1421  static float Normalize(int val, int maxVal)
1422  {
1423  if (maxVal == 0)
1424  {
1425  Debug.LogError("Division by 0 is not allowed");
1426  return 0;
1427  }
1428 
1429  return val / maxVal;
1430  }
1431 
1432  static float Bobbing(float period, float amplitude, float elapsedTime)
1433  {
1434  //Prevent division by 0
1435  if ( period == 0 )
1436  period = 1;
1437 
1438  elapsedTime /= period;
1439 
1440  float cycle;
1441  cycle += elapsedTime;
1442  cycle = FModulus(cycle, 360);
1443  cycle = Math.Sin(cycle) * amplitude;
1444 
1445  return cycle;
1446  }
1447 
1448  // DEPRECATED, use Math.ModFloat directly instead
1449  static float FModulus(float x, float y)
1450  {
1451  return Math.ModFloat(x, y);
1452  }
1453 
1454  static void RemoveSplint( PlayerBase player )
1455  {
1456  EntityAI entity = player.GetInventory().CreateInInventory("Splint");
1457  if (!entity)
1458  entity = player.SpawnEntityOnGroundOnCursorDir("Splint", 0.5);
1459 
1460  EntityAI attachment;
1461  ItemBase new_item = ItemBase.Cast(entity);
1462  Class.CastTo(attachment, player.GetItemOnSlot("Splint_Right"));
1463  if ( attachment && attachment.GetType() == "Splint_Applied" )
1464  {
1465  if (new_item)
1466  {
1467  MiscGameplayFunctions.TransferItemProperties(attachment,new_item);
1468 
1469  if (GetGame().IsServer())
1470  {
1471  //Lower health level of splint after use
1472  if (new_item.GetHealthLevel() < 4)
1473  {
1474  int newDmgLevel = new_item.GetHealthLevel() + 1;
1475 
1476  float max = new_item.GetMaxHealth("","");
1477 
1478  switch ( newDmgLevel )
1479  {
1480  case GameConstants.STATE_BADLY_DAMAGED:
1481  new_item.SetHealth( "", "", max * GameConstants.DAMAGE_BADLY_DAMAGED_VALUE );
1482  break;
1483 
1484  case GameConstants.STATE_DAMAGED:
1485  new_item.SetHealth( "", "", max * GameConstants.DAMAGE_DAMAGED_VALUE );
1486  break;
1487 
1488  case GameConstants.STATE_WORN:
1489  new_item.SetHealth( "", "", max * GameConstants.DAMAGE_WORN_VALUE );
1490  break;
1491 
1492  case GameConstants.STATE_RUINED:
1493  new_item.SetHealth( "", "", max * GameConstants.DAMAGE_RUINED_VALUE );
1494  break;
1495 
1496  default:
1497  break;
1498  }
1499  }
1500  }
1501  }
1502 
1503  attachment.Delete();
1504  }
1505  }
1506 
1508  static void TeleportCheck(notnull PlayerBase player, notnull array<ref array<float>> safe_positions)
1509  {
1510  if( player.GetSimulationTimeStamp() < 20 && !player.IsPersistentFlag(PersistentFlag.AREA_PRESENCE) )
1511  {
1512  //simulation time is bellow a threshold, which means the player has recently connected,
1513  //the player does not have the AREA_PRESENCE flag set, which means they were not inside the area when they disconnected,
1514  //that means they just spawned into a contaminated area, lets move them somewhere safe
1515  vector player_pos = player.GetPosition();
1516  vector closest_safe_pos = MiscGameplayFunctions.GetClosestSafePos(player_pos, safe_positions);
1517 
1518  if (player_pos!=closest_safe_pos)
1519  {
1520  closest_safe_pos[1] = GetGame().SurfaceY(closest_safe_pos[0], closest_safe_pos[2]);
1521 
1522  player.SetPosition( closest_safe_pos );//...so lets teleport them somewhere safe
1523  //DeveloperTeleport.SetPlayerPosition(player, closest_safe_pos);
1524  GetGame().RPCSingleParam(player, ERPCs.RPC_WARNING_TELEPORT, null, true, player.GetIdentity());
1525  }
1526 
1527  player.SetPersistentFlag(PersistentFlag.AREA_PRESENCE, false);
1528  }
1529  }
1530 
1531 
1532  static vector GetClosestSafePos(vector to_pos, notnull array<ref array<float>> positions)
1533  {
1534  vector closest_pos = to_pos;
1535  float smallest_dist = float.MAX;
1536  foreach( array<float> pos:positions)
1537  {
1538  vector vpos = "0 0 0";
1539  vpos[0] = pos[0];
1540  vpos[2] = pos[1];
1541 
1542  to_pos[1] = 0;
1543  float dist = vector.DistanceSq(to_pos, vpos);//2d dist sq
1544  if ( dist < smallest_dist)
1545  {
1546  smallest_dist = dist;
1547  closest_pos = vpos;
1548  }
1549  }
1550  return closest_pos;
1551  }
1552 
1553  static void GenerateAINoiseAtPosition(vector position, float lifeTime, NoiseParams noiseParams)
1554  {
1555  if (GetGame().IsServer())
1556  {
1557  NoiseSystem noise = GetGame().GetNoiseSystem();
1558  if (noise)
1559  {
1560  noise.AddNoiseTarget(position, lifeTime, noiseParams);
1561  }
1562  }
1563  }
1564 
1565  static float GetMinValue(array<float> pArray)
1566  {
1567  float minValue = 0.0;
1568  for (int i = 0; i < pArray.Count(); i++)
1569  {
1570  if (minValue == 0 || pArray.Get(i) < minValue)
1571  {
1572  minValue = pArray.Get(i);
1573  }
1574  }
1575 
1576  return minValue;
1577  }
1578 
1579  static float GetMaxValue(array<float> pArray)
1580  {
1581  float maxValue = 0.0;
1582  for (int i = 0; i < pArray.Count(); i++)
1583  {
1584  if (maxValue == 0 || pArray.Get(i) > maxValue)
1585  {
1586  maxValue = pArray.Get(i);
1587  }
1588  }
1589 
1590  return maxValue;
1591  }
1592 
1593  static string GetItemDisplayName(string type)
1594  {
1595  return GetGame().ConfigGetTextOut("CfgVehicles " + type + " displayName");
1596  }
1597 
1598  static bool IsComponentInSelection(array<Selection> pSelection, string pCompName)
1599  {
1600  if (pSelection.Count() == 0 || pCompName.Length() == 0)
1601  {
1602  return false;
1603  }
1604 
1605  for (int i = 0; i < pSelection.Count(); ++i)
1606  {
1607  pCompName.ToLower();
1608  if (pSelection[i] && pSelection[i].GetName() == pCompName)
1609  {
1610  return true;
1611  }
1612  }
1613 
1614  return false;
1615  }
1616 
1617  static int GetComponentIndex(array<Selection> pSelection, string pCompName)
1618  {
1619  if (!MiscGameplayFunctions.IsComponentInSelection(pSelection, pCompName))
1620  {
1621  return INDEX_NOT_FOUND;
1622  }
1623 
1624  for (int i = 0; i < pSelection.Count(); ++i)
1625  {
1626  pCompName.ToLower();
1627  if (pSelection[i] && pSelection[i].GetName() == pCompName)
1628  {
1629  return i;
1630  }
1631  }
1632 
1633  return INDEX_NOT_FOUND;
1634  }
1635 
1636  static void RemoveAllAttachedChildrenByTypename(notnull EntityAI parent, array<typename> listOfTypenames)
1637  {
1638  if (listOfTypenames.Count() > 0)
1639  {
1640  Object child = Object.Cast(parent.GetChildren());
1641  while (child)
1642  {
1643  Object childToRemove = child;
1644  child = Object.Cast(child.GetSibling());
1645 
1646  if (childToRemove.IsAnyInherited(listOfTypenames))
1647  {
1648  vector pos = childToRemove.GetPosition();
1649  parent.RemoveChild(childToRemove, false);
1650 
1651  vector m4[4];
1652  Math3D.MatrixIdentity4(m4);
1653  m4[3] = pos;
1654  childToRemove.SetTransform(m4);
1655  childToRemove.PlaceOnSurface();
1656  }
1657  }
1658  }
1659  }
1661  static void GetAttachedChildren(IEntity parent, array<IEntity> outputObjects)
1662  {
1663  IEntity child = parent.GetChildren();
1664  while (child)
1665  {
1666  outputObjects.Insert(child);
1667  child = child.GetSibling();
1668  }
1669  }
1670 
1671  static void SoakItemInsideParentContainingLiquidAboveThreshold(notnull ItemBase item, notnull ItemBase parent, float liquidQuantityThresholdPercentage = 0.05)
1672  {
1673  if (g_Game.IsServer())
1674  {
1675  if (parent.GetLiquidType() != 0 && parent.GetQuantityNormalized() > liquidQuantityThresholdPercentage)
1676  item.SetWetMax();
1677  }
1678  }
1679 }
1680 
1682 {
1683  // @NOTE m_Player == target player - i.e. restrained one
1684  void DestroyItemInCorpsesHandsAndCreateNewOnGndLambda(EntityAI old_item, string new_item_type, PlayerBase player, bool destroy = false)
1685  {
1687  vector mtx[4];
1688  if (old_item)
1689  old_item.GetTransform(mtx);
1690  else
1691  player.GetTransform(mtx);
1692  gnd.SetGround(NULL, mtx);
1693  OverrideNewLocation(gnd);
1694  }
1695 
1696  protected override void RemoveOldItemFromLocation()
1697  {
1698  super.RemoveOldItemFromLocation();
1699  m_Player.GetHumanInventory().OnEntityInHandsDestroyed(m_OldLocation);
1700  }
1701 }
1702 
1703 // This was created since IsObjectObstructed is often called multiple times in one frame
1704 // And apparently it seems that keeping this data in one struct seems to be more efficient than creating the variables dozens of times per frame
1705 class IsObjectObstructedCache // Pretending this is a struct
1706 {
1707  // Outside data
1708  vector RaycastStart = "0 0 0";
1709  int TotalObjects = 0;
1710 
1711  // Inside data
1717  ref set<Object> HitObjects = new set<Object>;
1718 
1719  void IsObjectObstructedCache(vector rayCastStart, int totalObjects)
1720  {
1721  RaycastStart = rayCastStart;
1722  TotalObjects = totalObjects;
1723  }
1724 
1725  // Only inside data
1726  void ClearCache()
1727  {
1728  ObjectCenterPos = "0 0 0";
1729  ObjectContactPos = "0 0 0";
1730  ObjectContactDir = "0 0 0";
1731  ContactComponent = -1;
1732  HitProxyObjects.Clear();
1733  HitObjects.Clear();
1734  }
1735 }
ItemBase
Definition: inventoryitem.c:730
RF_DEFAULT
const int RF_DEFAULT
Definition: centraleconomy.c:65
GetGame
proto native CGame GetGame()
CopyOldPropertiesToNew
override void CopyOldPropertiesToNew(notnull EntityAI old_item, EntityAI new_item)
Definition: actiontakefireplacefrombarrel.c:69
MoveEquipToExistingItemAndDestroyOldRootLambda
void MoveEquipToExistingItemAndDestroyOldRootLambda(EntityAI old_item, string new_item_type, PlayerBase player, EntityAI new_item)
Definition: miscgameplayfunctions.c:168
ComponentEnergyManager
Definition: componentenergymanager.c:18
ConstructionActionData
Definition: constructionactiondata.c:1
Error
void Error(string err)
Messagebox with error message.
Definition: endebug.c:90
RaycastStart
DestroyItemInCorpsesHandsAndCreateNewOnGndLambda RaycastStart
ClearCache
void ClearCache()
Definition: miscgameplayfunctions.c:1726
InventorySlots
provides access to slot configuration
Definition: inventoryslots.c:5
ThrowEntityFlags
ThrowEntityFlags
Definition: miscgameplayfunctions.c:207
INDEX_NOT_FOUND
const int INDEX_NOT_FOUND
Definition: gameplay.c:13
DestroyItemInCorpsesHandsAndCreateNewOnGndLambda
Definition: miscgameplayfunctions.c:1681
TStringArray
array< string > TStringArray
Definition: enscript.c:685
Construction
void Construction(BaseBuildingBase parent)
Definition: construction.c:26
m_NewItem
EntityAI m_NewItem
Definition: miscgameplayfunctions.c:166
ContactComponent
int ContactComponent
Definition: miscgameplayfunctions.c:1715
NONE
NONE
Definition: miscgameplayfunctions.c:196
GetMinValue
float GetMinValue()
Definition: staminahandler.c:154
GetName
proto native owned string GetName()
Definition: syncedvalue.c:117
dBodyApplyImpulse
proto void dBodyApplyImpulse(notnull IEntity body, vector impulse)
Applies impuls on a rigidbody (origin)
OnSuccess
class TurnItemIntoItemLambdaAnimSysNotifyLambda extends TurnItemIntoItemLambda OnSuccess(EntityAI new_item)
Definition: miscgameplayfunctions.c:105
y
Icon y
InventoryLocation
InventoryLocation.
Definition: inventorylocation.c:27
HitProxyObjects
ref array< ref RaycastRVResult > HitProxyObjects
Definition: miscgameplayfunctions.c:1716
ECE_PLACE_ON_SURFACE
const int ECE_PLACE_ON_SURFACE
Definition: centraleconomy.c:37
GetMaxValue
float GetMaxValue()
Definition: staminahandler.c:157
FireplaceBase
Definition: barrelholes_colorbase.c:1
m_Player
PlayerBase m_Player
Definition: miscgameplayfunctions.c:161
ObjectContactDir
vector ObjectContactDir
Definition: miscgameplayfunctions.c:1714
IEntity
Definition: enentity.c:164
DebugActionType
DebugActionType
Definition: plugindiagmenu.c:6
ReplaceItemWithNewLambda
adds automatic QuickBar handling
Definition: miscgameplayfunctions.c:1
TotalObjects
int TotalObjects
Definition: miscgameplayfunctions.c:1709
CollisionFlags
CollisionFlags
Definition: endebug.c:140
TIntArray
array< int > TIntArray
Definition: enscript.c:687
Truncate
enum ThrowEntityFlags Truncate(float value, int decimals=2)
truncate float to specified precision
Definition: miscgameplayfunctions.c:216
PersistentFlag
PersistentFlag
Definition: persistentflag.c:5
PlayerBase
Definition: playerbaseclient.c:1
RaycastRVParams
Definition: dayzphysics.c:49
PlayerConstants
Definition: playerconstants.c:1
vector
Definition: enconvert.c:105
NoiseParams
class ObjectSpawnerHandler NoiseParams
ECE_NONE
const int ECE_NONE
Definition: centraleconomy.c:7
ActionTarget
class ActionTargets ActionTarget
InventoryMode
InventoryMode
NOTE: PREDICTIVE is not to be used at all in multiplayer.
Definition: inventory.c:21
CFG_VEHICLESPATH
const string CFG_VEHICLESPATH
Definition: constants.c:209
DayZPlayerConstants
DayZPlayerConstants
defined in C++
Definition: dayzplayer.c:601
BaseBuildingBase
Definition: fence.c:1
InventoryLocationType
InventoryLocationType
types of Inventory Location
Definition: inventorylocation.c:3
GetColorString
string GetColorString()
Returns item's PROCEDURAL color as formated string, i.e. "#(argb,8,8,3)color(0.15,...
Definition: itembase.c:3736
g_Game
DayZGame g_Game
Definition: dayzgame.c:3727
ObjectCenterPos
vector ObjectCenterPos
Definition: miscgameplayfunctions.c:1712
Object
Definition: objecttyped.c:1
m_Player
DayZPlayer m_Player
Definition: hand_events.c:42
class_name
class OptionSelectorMultistate extends OptionSelector class_name
DropEquipAndDestroyRootLambda
this one is a bit special: it drops all items and destroys the ex-root of the hierarchy
Definition: miscgameplayfunctions.c:115
CFG_MAGAZINESPATH
const string CFG_MAGAZINESPATH
Definition: constants.c:211
DayZPlayerImplement
Definition: manbase.c:1
CFG_WEAPONSPATH
const string CFG_WEAPONSPATH
Definition: constants.c:210
CopyOldPropertiesToNew
override void CopyOldPropertiesToNew(notnull EntityAI old_item, EntityAI new_item)
Definition: miscgameplayfunctions.c:168
HumanInputController
Definition: human.c:17
array< string >
CreateNetworkObjectInfo
override protected void CreateNetworkObjectInfo(EntityAI new_item)
Definition: actiontakefireplacefrombarrel.c:81
Empty
Empty
Definition: hand_states.c:3
NoiseSystem
Definition: noise.c:1
HitObjects
ref set< Object > HitObjects
Definition: miscgameplayfunctions.c:1717
x
Icon x
VARIABLE_QUANTITY
const int VARIABLE_QUANTITY
Definition: constants.c:580
GetPlayer
protected void GetPlayer()
Definition: crosshairselector.c:127
GameConstants
Definition: constants.c:612
Debug
Definition: debug.c:13
ConstructionPart
Definition: constructionpart.c:1
InventoryTraversalType
InventoryTraversalType
tree traversal type, for more see http://en.wikipedia.org/wiki/Tree_traversal
Definition: gameplay.c:5
Weapon_Base
shorthand
Definition: boltactionrifle_base.c:5
DayZPhysics
Definition: dayzphysics.c:123
RemoveNetworkObjectInfo
override protected void RemoveNetworkObjectInfo()
Definition: miscgameplayfunctions.c:176
ECE_UPDATEPATHGRAPH
const int ECE_UPDATEPATHGRAPH
Definition: centraleconomy.c:13
ERPCs
ERPCs
Definition: erpcs.c:1
ObjectContactPos
vector ObjectContactPos
Definition: miscgameplayfunctions.c:1713
ECE_CREATEPHYSICS
const int ECE_CREATEPHYSICS
Definition: centraleconomy.c:16
GetComponentIndex
proto native int GetComponentIndex()
Definition: actiontargets.c:135
DroppedSome
@ DroppedSome
Definition: miscgameplayfunctions.c:204
ReplaceItemWithNewLambdaBase
base class for transformation operations (creating one item from another)
Definition: replaceitemwithnewlambdabase.c:4
IsObjectObstructedCache
void IsObjectObstructedCache(vector rayCastStart, int totalObjects)
Definition: miscgameplayfunctions.c:1719
Ok
@ Ok
Definition: miscgameplayfunctions.c:204
SPLIT
SPLIT
Definition: miscgameplayfunctions.c:197
Math
Definition: enmath.c:6
GetVelocity
proto native vector GetVelocity(notnull IEntity ent)
Returns linear velocity.
ReplaceAndDestroyLambda
Definition: actionunrestraintarget.c:149
Class
Super root of all classes in Enforce script.
Definition: enscript.c:10
Vector
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
PROJECTED_CURSOR_DISTANCE
const float PROJECTED_CURSOR_DISTANCE
Definition: constants.c:592
TurnItemIntoItemLambda
Definition: miscgameplayfunctions.c:91
EntityAI
Definition: building.c:5
MoveEquipToExistingItemAndDestroyOldRootLambda
this one is a also bit special: it moves all items to already existing item and destroys the ex-root ...
Definition: miscgameplayfunctions.c:115
Math3D
Definition: enmath3d.c:27
TransferInventoryResult
TransferInventoryResult
Definition: miscgameplayfunctions.c:202
CachedObjectsArrays
Definition: utilityclasses.c:40
Edible_Base
Definition: bearsteakmeat.c:1
ReplaceAndDestroyLambdaEx
Definition: actionunrestraintarget.c:173
GameInventory
script counterpart to engine's class Inventory
Definition: inventory.c:78
UndoRemoveNetworkObjectInfo
override protected void UndoRemoveNetworkObjectInfo()
Definition: miscgameplayfunctions.c:181