Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_InventoryStorageManagerComponent.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/UI/Inventory", description: "[MOD] Inventory Slot UI class")]
5
6enum EInventoryRetCode
7{
11 RETCODE_DEFAULT_STATE = 0xFFFF
12}
13
14enum ECallbackState
15{
16 DROP = 0,
17 INSERT = 1,
18 MOVE = 2,
19 FINAL = 3
20}
21
22enum EResupplyUnavailableReason
23{
24 //~ If multiple reasons for Resupply Unavailable than the Highst enum will be used
25 NONE,
26 NO_VALID_WEAPON = 10,
27 ENOUGH_ITEMS = 20,
28 NOT_IN_GIVEN_STORAGE = 30,
29 INVENTORY_FULL = 40,
30 RANK_TOO_LOW = 50,
32
33 //~ Resupply was valid. Add invalid reasons above
34 RESUPPLY_VALID = 99999,
35}
36
37class SCR_HoldableItemPredicate : InventorySearchPredicate
38{
39 ECommonItemType wanted;
40
41 //------------------------------------------------------------------------------------------------
42 // constructor
43 void SCR_HoldableItemPredicate()
44 {
45 QueryAttributeTypes.Insert(SCR_ItemOfInterestAttribute);
46 }
47
48 //------------------------------------------------------------------------------------------------
49 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
50 {
51 SCR_ItemOfInterestAttribute optionalAttribute = SCR_ItemOfInterestAttribute.Cast(queriedAttributes[0]);
52 return optionalAttribute.GetInterestType() == wanted;
53 }
54}
55
56class SCR_BandagePredicate : InventorySearchPredicate
57{
58 //------------------------------------------------------------------------------------------------
59 // constructor
60 void SCR_BandagePredicate()
61 {
62 QueryComponentTypes.Insert(SCR_ConsumableItemComponent);
63 }
64
65 //------------------------------------------------------------------------------------------------
66 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
67 {
68 return (SCR_ConsumableItemComponent.Cast(queriedComponents[0])).GetConsumableType() == SCR_EConsumableType.BANDAGE;
69 }
70}
71
72class SCR_ApplicableMedicalItemPredicate : InventorySearchPredicate
73{
74 IEntity characterEntity;
75 ECharacterHitZoneGroup hitZoneGroup;
76
77 //------------------------------------------------------------------------------------------------
78 // constructor
79 void SCR_ApplicableMedicalItemPredicate()
80 {
81 QueryComponentTypes.Insert(SCR_ConsumableItemComponent);
82 }
83
84 //------------------------------------------------------------------------------------------------
85 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
86 {
87 SCR_EConsumableType type = SCR_ConsumableItemComponent.Cast(queriedComponents[0]).GetConsumableType();
88 bool isMatch = (type == SCR_EConsumableType.BANDAGE)
89 || (type == SCR_EConsumableType.HEALTH)
90 || (type == SCR_EConsumableType.TOURNIQUET)
91 || (type == SCR_EConsumableType.SALINE)
92 || (type == SCR_EConsumableType.MORPHINE);
93
94 if (!isMatch)
95 return false;
96
97 SCR_ConsumableItemComponent medicalItem = SCR_ConsumableItemComponent.Cast(item.FindComponent(SCR_ConsumableItemComponent));
98 SCR_ConsumableEffectHealthItems effect = SCR_ConsumableEffectHealthItems.Cast(medicalItem.GetConsumableEffect());
99 if (!effect)
100 return false;
101
102 return effect.CanApplyEffectToHZ(characterEntity, characterEntity, hitZoneGroup);
103 }
104}
105
106class SCR_ItemTypeSearchPredicate : InventorySearchPredicate
107{
108 int m_iItemType = -1;
109 IEntity m_iOriginalItem;
110
111 //------------------------------------------------------------------------------------------------
112 // constructor
116 void SCR_ItemTypeSearchPredicate(typename type, int wantedItemType, IEntity originalItem)
117 {
118 QueryComponentTypes.Insert(type);
119 m_iItemType = wantedItemType;
120 }
121
122 //------------------------------------------------------------------------------------------------
123 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
124 {
125 return (item != m_iOriginalItem) && (SCR_CharacterInventoryStorageComponent.GetItemType(item) == m_iItemType);
126 }
127}
128
129class SCR_CommonItemTypeSearchPredicate : InventorySearchPredicate
130{
132 IEntity m_OriginalItem;
133
134 //------------------------------------------------------------------------------------------------
135 // constructor
138 void SCR_CommonItemTypeSearchPredicate(ECommonItemType wantedItemType, IEntity originalItem)
139 {
140 m_eItemType = wantedItemType;
141 m_OriginalItem = originalItem;
142 }
143
144 //------------------------------------------------------------------------------------------------
145 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
146 {
147 InventoryItemComponent iic = InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent));
148 if (!iic || !iic.GetAttributes())
149 return false;
150
151 return (item != m_OriginalItem) && (iic.GetAttributes().GetCommonType() == m_eItemType);
152 }
153}
154
156class SCR_CompatibleAttachmentPredicate : InventorySearchPredicate
157{
158 typename attachmentType;
159
160 //------------------------------------------------------------------------------------------------
161 // constructor
162 void SCR_CompatibleAttachmentPredicate()
163 {
164 QueryComponentTypes.Insert(InventoryItemComponent);
165 }
166
167 //------------------------------------------------------------------------------------------------
168 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
169 {
170 InventoryItemComponent itemComp = InventoryItemComponent.Cast(queriedComponents[0]);
171
172 if (!itemComp)
173 return false;
174
175 ItemAttributeCollection itemAttributes = itemComp.GetAttributes();
176 if (!itemAttributes)
177 return false;
178
179 WeaponAttachmentAttributes itemAttribute = WeaponAttachmentAttributes.Cast(itemAttributes.FindAttribute(WeaponAttachmentAttributes));
180 if (!itemAttribute)
181 return false;
182
183 BaseAttachmentType itemAttachmentType = itemAttribute.GetAttachmentType();
184 if (!itemAttachmentType)
185 return false;
186
187 typename itemAttachmentTypename = itemAttachmentType.Type();
188 if (!itemAttachmentTypename)
189 return false;
190
191 return itemAttachmentTypename.IsInherited(attachmentType); // Check if attachment types match
192 }
193}
194
195class SCR_SalinePredicate : InventorySearchPredicate
196{
197 //------------------------------------------------------------------------------------------------
198 // constructor
199 void SCR_SalinePredicate()
200 {
201 QueryComponentTypes.Insert(SCR_ConsumableItemComponent);
202 }
203
204 //------------------------------------------------------------------------------------------------
205 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
206 {
207 if (storage.Type().IsInherited(EquipmentStorageComponent))
208 return true;
209
210 return false;
211 }
212}
213
215class SCR_MagazinePredicate : InventorySearchPredicate
216{
217 typename magWellType;
218
219 //------------------------------------------------------------------------------------------------
220 // constructor
221 void SCR_MagazinePredicate()
222 {
223 QueryComponentTypes.Insert(BaseMagazineComponent);
224 }
225
226 //------------------------------------------------------------------------------------------------
227 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
228 {
229 BaseMagazineComponent iMag = BaseMagazineComponent.Cast(queriedComponents[0]);
230 if (!iMag)
231 return false;
232
233 BaseMagazineWell iMagWell = iMag.GetMagazineWell();
234 if (!iMagWell)
235 return false;
236
237 return (iMagWell.IsInherited(magWellType)); // Check if magwells match
238 }
239}
240
242class SCR_PrefabNamePredicate : InventorySearchPredicate
243{
244 string prefabName;
245
246 //------------------------------------------------------------------------------------------------
247 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
248 {
249 EntityPrefabData pd = item.GetPrefabData();
250 return pd.GetPrefabName() == this.prefabName;
251 }
252}
253
255class SCR_PrefabDataPredicate : InventorySearchPredicate
256{
257 EntityPrefabData prefabData;
258
259 //------------------------------------------------------------------------------------------------
260 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
261 {
262 return item.GetPrefabData() == this.prefabData;
263 }
264}
265
267class SCR_ResourceNamePredicate : InventorySearchPredicate
268{
270 BaseContainer m_PrefabContainer;
272 IEntity m_ExcludedItem;
273
274 //------------------------------------------------------------------------------------------------
276 void SCR_ResourceNamePredicate(ResourceName rn = string.Empty, IEntity excludedItem = null)
277 {
278 m_ExcludedItem = excludedItem;
279 Resource resource = Resource.Load(rn);
280 if (resource.IsValid())
281 m_PrefabContainer = resource.GetResource().ToBaseContainer();
282 }
283
284 //------------------------------------------------------------------------------------------------
285 override protected bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array<GenericComponent> queriedComponents, array<BaseItemAttributeData> queriedAttributes)
286 {
287 return item != m_ExcludedItem && item.GetPrefabData().GetPrefab() == m_PrefabContainer;
288 }
289}
290
291class DropAndMoveOperationCallback : ScriptedInventoryOperationCallback
292{
293 InventoryItemComponent m_ItemBefore;
294 InventoryItemComponent m_ItemAfter;
295 InventoryStorageSlot m_TargetSlot;
296 SCR_InventoryStorageManagerComponent m_Manager;
297 SCR_InvCallBack m_FinalCB;
298 bool m_bIstakenFromArsenal;
299 ref array<IEntity> m_aItemsToMove = {};
300 ECallbackState m_ECurrentState = 0; // 0 - drop, 1 - insert, 2 - move, 3 - final
301
302 //------------------------------------------------------------------------------------------------
303 override protected void OnComplete()
304 {
305 switch (m_ECurrentState)
306 {
307 case ECallbackState.DROP:
308 {
309 OnDropComplete();
310 }
311 break;
312
313 case ECallbackState.INSERT:
314 {
315 OnInsertComplete();
316 }
317 break;
318
319 case ECallbackState.MOVE:
320 {
321 OnMoveComplete();
322 }
323 break;
324
325 case ECallbackState.FINAL:
326 {
327 OnFinalState();
328 }
329 break;
330 }
331 }
332
333 //------------------------------------------------------------------------------------------------
334 protected void OnDropComplete()
335 {
336 m_ECurrentState++;
337 m_Manager.TryMoveItemToStorage(m_ItemAfter.GetOwner(), m_TargetSlot.GetStorage(), m_TargetSlot.GetID(), this);
338 }
339
340 //------------------------------------------------------------------------------------------------
341 protected void OnInsertComplete()
342 {
343 if (!m_bIstakenFromArsenal)
344 {
345 m_ECurrentState = ECallbackState.FINAL;
346 OnFinalState();
347 return;
348 }
349
350 m_ECurrentState++;
351 //BaseInventoryStorageComponent itemIsStorage = BaseInventoryStorageComponent.Cast(m_ItemBefore);
352 //m_Manager.GetAllItems(m_aItemsToMove, itemIsStorage);
353 OnMoveComplete();
354 }
355
356 //------------------------------------------------------------------------------------------------
357 protected void OnMoveComplete()
358 {
359 // Temporarily disabled for performance reasons. Once it gets fixed the transfer of items can be reenabled.
360// if (m_aItemsToMove.Count() == 0)
361// {
362// m_ECurrentState++;
363// OnDeleteComplete();
364// return;
365// }
366// IEntity item = m_aItemsToMove[m_aItemsToMove.Count() - 1];
367// m_aItemsToMove.Resize(m_aItemsToMove.Count() - 1);
368// BaseInventoryStorageComponent storage = m_Manager.FindStorageForItem(item, EStoragePurpose.PURPOSE_ANY);
369// if (!m_Manager.TryMoveItemToStorage(item, storage, -1, this))
370// OnMoveComplete();
371
372 m_ECurrentState = ECallbackState.FINAL;
373 OnFinalState();
374 return;
375 }
376
377 //------------------------------------------------------------------------------------------------
378 protected void OnFinalState()
379 {
380 if (m_FinalCB)
381 m_FinalCB.InternalComplete();
382 }
383}
384
385class SCR_ResupplyMagazinesCallback : ScriptedInventoryOperationCallback
386{
387 protected SCR_InventoryStorageManagerComponent m_Manager;
388 protected ref map<ResourceName, int> m_MagazinesToSpawn = new map<ResourceName, int>();
389 protected BaseInventoryStorageComponent m_LastTargetStorage;
390
391 //------------------------------------------------------------------------------------------------
395 void Insert(ResourceName prefab, int count)
396 {
397 int currentCount;
398 m_MagazinesToSpawn.Find(prefab, currentCount);
399 m_MagazinesToSpawn.Insert(prefab, currentCount + count);
400 }
401
402 //------------------------------------------------------------------------------------------------
404 void Start()
405 {
406 OnComplete();
407 }
408
409 //------------------------------------------------------------------------------------------------
410 override protected void OnComplete()
411 {
412 if (!m_Manager)
413 return;
414
415 if (m_LastTargetStorage)
416 {//if we spawned something in hand slot then we need to skip the wait for the animation as there is no animation in this case
417 SCR_HandSlotStorageComponent handSlotStorage = SCR_HandSlotStorageComponent.Cast(m_LastTargetStorage);
418 if (handSlotStorage)
419 handSlotStorage.SkipAnimation_S();
420 }
421
422 if (!m_MagazinesToSpawn.IsEmpty())
423 {
424 //--- Next item to process
425 ResourceName prefab = m_MagazinesToSpawn.GetKey(0);
426 int count = m_MagazinesToSpawn.GetElement(0);
427 count--;
428
429 if (count == 0)
430 m_MagazinesToSpawn.Remove(prefab);
431 else
432 m_MagazinesToSpawn.Set(prefab, count);
433
434 m_LastTargetStorage = m_Manager.FindStorageForResource(prefab);
435 m_Manager.TrySpawnPrefabToStorage(prefab, m_LastTargetStorage, cb: this);
436 }
437 else
438 {
439 //--- All processed
440 OnFailed();
441 }
442 }
443
444 //------------------------------------------------------------------------------------------------
445 override protected void OnFailed()
446 {
447 //--- Delete itself (after a delay - can't delete itself at this frame)
448 GetGame().GetCallqueue().CallLater(m_Manager.EndResupplyMagazines, 1, false);
449 }
450
451 //------------------------------------------------------------------------------------------------
452 // constructor
454 void SCR_ResupplyMagazinesCallback(SCR_InventoryStorageManagerComponent manager)
455 {
456 m_Manager = manager;
457 }
458}
459
460class SCR_InventoryStorageManagerComponent : ScriptedInventoryStorageManagerComponent
461{
462 protected ref array<ref SCR_ItemInsertionCallback> m_aQueuedInsertionCallbacks;
463
464 private SCR_CharacterInventoryStorageComponent m_Storage;
465 private SCR_CharacterControllerComponent m_CharacterController;
466 private ref SCR_BandagePredicate m_BandagePredicate = new SCR_BandagePredicate();
467 protected EInventoryRetCode m_ERetCode;
468 protected int m_iHealthEquipment = 0;
469 protected bool m_bIsInventoryLocked = false;
470 protected ref SCR_WeaponSwitchingBaseUI m_pWeaponSwitchingUI;
471 private bool m_bWasRaised;
472 private IEntity m_StorageToOpen;
473 protected ref SCR_ResupplyMagazinesCallback m_ResupplyMagazineCallback;
474 protected bool m_bInventoryAccessAllowed = true;
475
476 ref ScriptInvokerBool m_OnInventoryOpenInvoker = new ScriptInvokerBool();
477 ref ScriptInvokerBool m_OnQuickBarOpenInvoker = new ScriptInvokerBool();
478
480 protected const int ITEM_INSERTION_CALLBACK_CLEANUP_TIME = 1100;
481
482 //------------------------------------------------------------------------------------------------
486 [Obsolete("Use GetItems or a custom predicate with Find instead.")]
487 int GetAllRootItems(out notnull array<IEntity> rootItems)
488 {
489 rootItems.Clear();
490 array<BaseInventoryStorageComponent> storages = {};
491
492 //~ Get deposits like backpacks and jackets as well as any held weapons
493 GetStorages(storages, EStoragePurpose.PURPOSE_DEPOSIT);
494 GetStorages(storages, EStoragePurpose.PURPOSE_WEAPON_PROXY);
495
496 array<IEntity> items = {};
497 foreach (BaseInventoryStorageComponent storage : storages)
498 {
499 //~ If backpack or jacked or any other cloth storage only get what is inside the storage
500 if (ClothNodeStorageComponent.Cast(storage))
501 {
502 if (!storage)
503 continue;
504
505 array<BaseInventoryStorageComponent> clothStorages = {};
506 storage.GetOwnedStorages(clothStorages, 1, false);
507
508 foreach (BaseInventoryStorageComponent clothStorage : clothStorages)
509 {
510 if (!clothStorage)
511 continue;
512
513 clothStorage.GetAll(items);
514 rootItems.Copy(items);
515 items.Clear();
516 }
517
518 continue;
519 }
520
521 storage.GetAll(items);
522 rootItems.Copy(items);
523 items.Clear();
524 }
525
526 return rootItems.Count();
527 }
528
529 //------------------------------------------------------------------------------------------------
530 // Callback when item is added (will be performed locally after server completed the Insert/Move operation)
531 override protected void OnItemAdded(BaseInventoryStorageComponent storageOwner, IEntity item)
532 {
533 super.OnItemAdded(storageOwner, item);
534
535 SCR_ConsumableItemComponent consumable = SCR_ConsumableItemComponent.Cast(item.FindComponent(SCR_ConsumableItemComponent));
536 if ( consumable && consumable.GetConsumableType() == SCR_EConsumableType.BANDAGE )
537 m_iHealthEquipment++; //store count of the health components
538
539 if (storageOwner == m_Storage.GetWeaponStorage())
540 ExecuteItemInsertionCallback(item, storageOwner, true);
541 }
542
543 //------------------------------------------------------------------------------------------------
544 // Callback when item is removed (will be performed locally after server completed the Remove/Move operation)
545 override protected void OnItemRemoved(BaseInventoryStorageComponent storageOwner, IEntity item)
546 {
547 super.OnItemRemoved(storageOwner, item);
548
549 SCR_ConsumableItemComponent consumable = SCR_ConsumableItemComponent.Cast(item.FindComponent(SCR_ConsumableItemComponent));
550 if ( consumable && consumable.GetConsumableType() == SCR_EConsumableType.BANDAGE )
551 m_iHealthEquipment--; //store count of the health components
552 }
553
554 //------------------------------------------------------------------------------------------------
555 override protected bool ShouldForbidRemoveByInstigator(InventoryStorageManagerComponent instigatorManager, BaseInventoryStorageComponent fromStorage, IEntity item)
556 {
557 //in case of health items, permit medics to donate healing items to targets
558 SCR_ConsumableItemComponent consumableItemComp = SCR_ConsumableItemComponent.Cast(item.FindComponent(SCR_ConsumableItemComponent));
559 if (consumableItemComp)
560 return false;
561
563 return true;
564
565 return false;
566 }
567
568 //------------------------------------------------------------------------------------------------
572 void PlayItemSound(IEntity entity, string soundEvent)
573 {
574 if (!entity)
575 return;
576
577 RplComponent rplComp = RplComponent.Cast(entity.FindComponent(RplComponent));
578 if (rplComp)
579 {
580 Rpc(RpcAsk_PlaySound, rplComp.Id(), soundEvent);
581 }
582 else
583 {
584 SoundComponent soundComp = SoundComponent.Cast(entity.FindComponent(SoundComponent));
585 if (soundComp && soundComp.GetEventIndex(soundEvent) != -1)
586 {
587 soundComp.SoundEvent(soundEvent);
588 }
589 else
590 {
591 SCR_SoundManagerModule.CreateAndPlayAudioSource(entity, soundEvent);
592 }
593 }
594 }
595
596 //------------------------------------------------------------------------------------------------
600 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
601 void RpcAsk_PlaySound(RplId targetRplId, string soundAction)
602 {
603 Rpc(RpcDo_PlaySound, targetRplId, soundAction);
604 RpcDo_PlaySound(targetRplId, soundAction);
605 }
606
607 //------------------------------------------------------------------------------------------------
611 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
612 void RpcDo_PlaySound(RplId targetRplId, string soundAction)
613 {
614 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(targetRplId));
615 if (!rplComp)
616 return;
617
618 IEntity entity = rplComp.GetEntity();
619 if (!entity)
620 return;
621
622 SoundComponent soundComp = SoundComponent.Cast(entity.FindComponent(SoundComponent));
623 if (soundComp && soundComp.GetEventIndex(soundAction) != -1)
624 {
625 soundComp.SoundEvent(soundAction);
626 }
627 else
628 {
629 SCR_SoundManagerModule.CreateAndPlayAudioSource(entity, soundAction);
630 }
631 }
632
633#ifndef DISABLE_INVENTORY
634
635 //------------------------------------------------------------------------------------------------
637 SCR_CharacterInventoryStorageComponent GetCharacterStorage()
638 {
639 return m_Storage;
640 }
641
642 //------------------------------------------------------------------------------------------------
648 // TODO: make this method as native (cannot override the proto native CanMoveItemToStorage)
649 bool CanInsertItemInActualStorage(IEntity item, BaseInventoryStorageComponent storage, int slotID = -1)
650 {
651 if (!IsAnimationReady() || IsInventoryLocked())
652 return false;
653
654 array<BaseInventoryStorageComponent> pStorages = {};
655 storage.GetOwnedStorages( pStorages, 1, false );
656 pStorages.Insert( storage );
657
658 foreach ( BaseInventoryStorageComponent pStorage : pStorages )
659 {
660 bool bCanInsert = CanInsertItemInStorage( item, pStorage, -1 ); //split because of debug purposes
661 bool bCanMove = CanMoveItemToStorage( item, pStorage, -1 );
662 if ( bCanInsert || bCanMove )
663 return true;
664 }
665 return false;
666 }
667
668 BaseInventoryStorageComponent FindActualStorageForItemResource(ResourceName itemResource, BaseInventoryStorageComponent storage, int slotID = -1)
669 {
670 array<BaseInventoryStorageComponent> storages = {};
671 storage.GetOwnedStorages(storages, 1, false);
672 storages.Insert(storage);
673
674 foreach (BaseInventoryStorageComponent actualStorage : storages)
675 {
676 if (CanInsertResourceInStorage(itemResource, actualStorage, slotID))
677 return actualStorage;
678 }
679
680 return null;
681 }
682
683 //------------------------------------------------------------------------------------------------
684 // ! The return code informs about the state of the operation ( i.e. cannot insert item, since it is too large )
685 // ! it clear the flag
687 void SetReturnCode( EInventoryRetCode ERetCode )
688 {
689 m_ERetCode &= ~ERetCode;
690 }
691
692 //------------------------------------------------------------------------------------------------
693 // ! The return code informs about the state of the operation ( i.e. cannot insert item, since it is too large )
694 // ! it clear the flag
695 void SetReturnCodeDefault()
696 {
697 m_ERetCode = EInventoryRetCode.RETCODE_DEFAULT_STATE;
698 }
699
700 //------------------------------------------------------------------------------------------------
702 EInventoryRetCode GetReturnCode()
703 {
704 return m_ERetCode;
705 }
706
707 //------------------------------------------------------------------------------------------------
709 float GetTotalWeightOfAllStorages()
710 {
711 array<BaseInventoryStorageComponent> storages = {};
712 float fTotalWeight = 0.0;
713
714 //TODO: actually not a very good way how to get storages, but using the GetStorages() method causes the weight being doubled. We need to get just the "parent" storages
715 //Also if someone ever fixes this let character anim progs know to fix it in CharacterControllerComponent.CalculateSpeedLimits.
716 storages.Insert(m_Storage.GetWeaponStorage());
717 storages.Insert(m_Storage);
718
719 foreach (BaseInventoryStorageComponent storage : storages)
720 {
721 fTotalWeight += storage.GetTotalWeight();
722 }
723
724 return fTotalWeight;
725 }
726
727 //------------------------------------------------------------------------------------------------
729 void SetLootStorage( IEntity pOwner )
730 {
731 if (m_Storage)
732 m_Storage.SetLootStorage(pOwner);
733 }
734
735 //------------------------------------------------------------------------------------------------
741 void InsertItem( IEntity pItem, BaseInventoryStorageComponent pStorageTo = null, BaseInventoryStorageComponent pStorageFrom = null, SCR_InvCallBack cb = null )
742 {
743 if (!pItem || !IsAnimationReady() || IsInventoryLocked())
744 return;
745
746 SetInventoryLocked(true);
747
748 bool canInsert = true;
749 if ( !pStorageTo ) // no storage selected, put it into best fitting storage
750 {
751 string soundEvent = SCR_SoundEvent.SOUND_EQUIP;
752 //TryInsertItem( pItem, EStoragePurpose.PURPOSE_DEPOSIT); // works for the owned storages ( not for the vicinity storages )
753 if ( !TryInsertItem( pItem, EStoragePurpose.PURPOSE_WEAPON_PROXY, cb ) )
754 {
755 if ( !TryInsertItem( pItem, EStoragePurpose.PURPOSE_EQUIPMENT_ATTACHMENT, cb ) )
756 {
757 if ( !TryInsertItem( pItem, EStoragePurpose.PURPOSE_DEPOSIT, cb ) )
758 {
759 if ( !TryMoveItemToStorage( pItem, FindStorageForItem( pItem, EStoragePurpose.PURPOSE_ANY ), -1, cb ) )
760 canInsert = TryMoveItemToStorage(pItem, m_Storage, -1, cb); // clothes from storage in vicinity
761 else
762 soundEvent = SCR_SoundEvent.SOUND_PICK_UP; // play pick up sound for everything else
763
764 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_HOTKEY_CONFIRM);
765 }
766 else
767 soundEvent = SCR_SoundEvent.SOUND_PICK_UP;
768 }
769 }
770
771 if (canInsert)
772 PlayItemSound(pItem, soundEvent);
773 }
774 else
775 {
776 if (pStorageTo == m_Storage)
777 {
778 canInsert = TryReplaceItem( pStorageTo, pItem, 0, cb );
779 if (canInsert)
780 {
781 SetInventoryLocked(false);
782 return;
783 }
784 }
785
786 //~ Find a valid storage to insert item in
787 BaseInventoryStorageComponent validStorage = FindStorageForInsert(pItem, pStorageTo, EStoragePurpose.PURPOSE_EQUIPMENT_ATTACHMENT);
788
789 if (!validStorage)
790 validStorage = FindStorageForInsert(pItem, pStorageTo, EStoragePurpose.PURPOSE_ANY);
791
792 if (validStorage)
793 {
794 pStorageTo = validStorage;
795 }
796 //~ Check if item can be inserted in linked storages
797 else
798 {
799 //~ Find valid storage in linked storages
801 if (universalStorage)
802 {
803 array<BaseInventoryStorageComponent> linkedStorages = {};
804 universalStorage.GetLinkedStorages(linkedStorages);
805
806 foreach(BaseInventoryStorageComponent linkedStorage : linkedStorages)
807 {
808 //~ Valid linked storage found
809 if (FindStorageForInsert(pItem, linkedStorage, EStoragePurpose.PURPOSE_ANY))
810 {
811 pStorageTo = linkedStorage;
812 break;
813 }
814 }
815 }
816 }
817
818 if ( !pStorageFrom )
819 canInsert = TryInsertItemInStorage( pItem, pStorageTo, -1, cb ); // if we move item from ground to opened storage
820 else
821 canInsert = TryMoveItemToStorage( pItem, pStorageTo, -1, cb ); // if we move item between storages
822 }
823
824 if (!canInsert)
825 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_DROP_ERROR);
826 else
827 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_CONTAINER_DIFR_DROP);
828
829 if (m_CharacterController && canInsert && !pStorageFrom)
830 m_CharacterController.TryPlayItemGesture(EItemGesture.EItemGesturePickUp);
831
832 SetInventoryLocked(false);
833 }
834
835 //------------------------------------------------------------------------------------------------
841 bool TryRemoveItemFromInventory(IEntity pItem, BaseInventoryStorageComponent storage = null, InventoryOperationCallback cb = null)
842 {
843 if (!CanMoveItem(pItem))
844 return false;
845
846 if (!storage)
847 {
848 InventoryItemComponent itemComp = InventoryItemComponent.Cast(pItem.FindComponent(InventoryItemComponent));
849 if (!itemComp)
850 return false;
851
852 InventoryStorageSlot parentSlot = itemComp.GetParentSlot();
853 if (parentSlot)
854 storage = parentSlot.GetStorage();
855 }
856
857 SetInventoryLocked(true);
858 bool result = TryRemoveItemFromStorage(pItem, storage, cb);
859 SetInventoryLocked(false);
860
861 return result;
862 }
863
864 //------------------------------------------------------------------------------------------------
868 bool CanMoveItem(IEntity item)
869 {
870 if (!item || item.IsDeleted() || !IsAnimationReady() || IsInventoryLocked())
871 return false;
872
873 return true;
874 }
875
876// //------------------------------------------------------------------------------------------------
877// override bool TryInsertItemInStorageScr( IEntity pItem, BaseInventoryStorageComponent pStorageTo, int slotID = -1, InventoryOperationCallback cb = null )
878// {
879//
880// if ( !pStorageTo )
881// return;
882//
883// array<BaseInventoryStorageComponent> pStorages = {};
884// pStorage.GetOwnedStorages( pStorages, 1, false ); // get all the storages, the storage has attached to it
885// pStorages.Insert( pStorage ); // and put there also the storage
886// foreach ( BaseInventoryStorageComponent tmpStorage : pStorages )
887// {
888// if ( MoveOperation( itemComponent, tmpStorage ) )
889// {
890// bRet = true;
891// break;
892// }
893// }
894// }
895
896 //------------------------------------------------------------------------------------------------
902 bool TrySwapItems( IEntity pOwnerEntity, BaseInventoryStorageComponent pStorageTo, SCR_InvCallBack cb = null )
903 {
904 if (!pStorageTo)
905 return false;
906
907 InventoryStorageSlot slot = pStorageTo.FindSuitableSlotForItem( pOwnerEntity );
908 if (!slot)
909 return false;
910
911 IEntity replacedEntity = slot.GetAttachedEntity();
912 if (replacedEntity)
913 {
914 BaseInventoryStorageComponent weaponStorage = m_Storage.GetWeaponStorage();
915 IEntity currentlyUsedItem = m_CharacterController.GetCurrentItemInHands();
916 if (m_CharacterController && replacedEntity == currentlyUsedItem && pStorageTo == weaponStorage)
917 { // if we are replacing the current weapon then we need to use new API or else it may fail and cause desync
918 if (cb)
919 {
920 if (!cb.m_pStorageToDrop)
921 cb.m_pStorageToDrop = pStorageTo;
922
923 // to ensure that we will add callback on time, we do this before we try to move the item,
924 // just to be ready even in case this is happening in SP
925 AddItemInsertionCallback(pOwnerEntity, cb, pStorageTo);
926 }
927
928 if (!m_CharacterController.ReplaceEquippedItem(pOwnerEntity))
929 return true;
930
931 if (cb)
932 ExecuteItemInsertionCallback(pOwnerEntity, pStorageTo, false);
933
934 return false;
935 }
936
937 if (!TrySwapItemStorages(pOwnerEntity, slot.GetAttachedEntity(), cb))
938 {
939 CharacterHandWeaponSlotComponent handWeaponSlot = CharacterHandWeaponSlotComponent.Cast(slot.GetParentContainer());
940 //Move
941 if (handWeaponSlot)
942 {
943 if (TryRemoveItemFromInventory(slot.GetAttachedEntity()))
944 {
945 TryInsertItem(pOwnerEntity, EStoragePurpose.PURPOSE_ANY, cb);
946 return true;
947 }
948 }
949
950 return false;
951 }
952
953 return true;
954 }
955 else
956 {
957 return TryMoveItemToStorage(pOwnerEntity, pStorageTo, slot.GetID(), cb);
958 }
959
960 return false;
961 }
962
963 //------------------------------------------------------------------------------------------------
968 protected void AddItemInsertionCallback(notnull IEntity item, notnull SCR_InvCallBack cb, notnull BaseInventoryStorageComponent storage)
969 {
970 ChimeraWorld world = ChimeraWorld.CastFrom(GetGame().GetWorld());
971 if (!world)
972 return;
973
974 TimeAndWeatherManagerEntity timeAndWeatherManager = world.GetTimeAndWeatherManager();
975 if (!timeAndWeatherManager)
976 return;
977
978 if (!m_aQueuedInsertionCallbacks)
979 m_aQueuedInsertionCallbacks = {};
980
981 m_aQueuedInsertionCallbacks.Insert(new SCR_ItemInsertionCallback(item, cb, storage, timeAndWeatherManager.GetEngineTime() + 1)); // GetEngineTime() returns time in seconds
982 // since its possible that when using CharacterControllerComponent.ReplaceEquippedItem insertion will fail silently, we have to have a backup plan to remove entries in this array
983 GetGame().GetCallqueue().CallLater(CleanupCallbackQueue, ITEM_INSERTION_CALLBACK_CLEANUP_TIME); // 1100ms should be more than enough to ensure that item insertion has failed
984 }
985
986 //------------------------------------------------------------------------------------------------
991 protected void ExecuteItemInsertionCallback(notnull IEntity item, notnull BaseInventoryStorageComponent storage, bool result)
992 {
993 if (!m_aQueuedInsertionCallbacks || m_aQueuedInsertionCallbacks.IsEmpty())
994 return;
995
996 foreach (SCR_ItemInsertionCallback entry : m_aQueuedInsertionCallbacks)
997 {
998 if (!entry)
999 continue;
1000
1001 if (entry.m_Item != item || entry.m_TargetStorage != storage)
1002 continue;
1003
1004 // ensure that no one manipulated this callback while we were waiting for item to be inserted
1005 if (!entry.m_Callback || entry.m_Callback.m_pStorageToDrop != storage || entry.m_Callback.m_pItem != item)
1006 continue;
1007
1008 if (result)
1009 entry.m_Callback.InternalComplete();
1010 else
1011 entry.m_Callback.InternalFailed();
1012
1013 entry.m_Callback = null;
1014 entry.m_fExpireTime = 0;
1015 return;
1016 }
1017 }
1018
1019 //------------------------------------------------------------------------------------------------
1021 protected void CleanupCallbackQueue()
1022 {
1023 if (!m_aQueuedInsertionCallbacks)
1024 return;
1025
1026 ChimeraWorld world = ChimeraWorld.CastFrom(GetGame().GetWorld());
1027 if (!world)
1028 return;
1029
1030 TimeAndWeatherManagerEntity timeAndWeatherManager = world.GetTimeAndWeatherManager();
1031 if (!timeAndWeatherManager)
1032 return;
1033
1034 const array<int> garbageCollection = {};
1035 float currentTimeInSec = timeAndWeatherManager.GetEngineTime();
1036 foreach (int i, SCR_ItemInsertionCallback entry : m_aQueuedInsertionCallbacks)
1037 {
1038 if (!entry)
1039 {
1040 garbageCollection.InsertAt(i, 0);
1041 continue;
1042 }
1043
1044 if (entry.m_fExpireTime > currentTimeInSec)
1045 continue;
1046
1047 // if no one manipulated this callback while we were waiting, then inform it that item transfer failed
1048 if (entry.m_Callback && entry.m_Callback.m_pStorageToDrop == entry.m_TargetStorage && entry.m_Callback.m_pItem == entry.m_Item)
1049 entry.m_Callback.InternalFailed();
1050
1051 garbageCollection.InsertAt(i, 0); // to not have to read garbage collection from the rear, we can insert at the front so that the content will be reversed
1052 }
1053
1054 foreach (int garbageId : garbageCollection)
1055 {
1056 m_aQueuedInsertionCallbacks.Remove(garbageId);
1057 }
1058
1059 if (m_aQueuedInsertionCallbacks.IsEmpty())
1060 {
1061 GetGame().GetCallqueue().Remove(CleanupCallbackQueue);
1062 m_aQueuedInsertionCallbacks = null;
1063 }
1064 }
1065
1066 //------------------------------------------------------------------------------------------------
1071 bool EquipWeapon( IEntity pOwnerEntity, SCR_InvCallBack cb = null, bool bFromVicinity = true )
1072 {
1073 if ( !bFromVicinity )
1074 {
1075 bool result = TrySwapItems(pOwnerEntity, m_Storage.GetWeaponStorage(), cb);
1076 if (result)
1077 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_CONTAINER_DIFR_DROP);
1078 else
1079 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_DROP_ERROR);
1080
1081 return result;
1082 }
1083
1084 IEntity user = GetOwner();
1085 if (!user)
1086 return false;
1087
1088 BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast(user.FindComponent(BaseWeaponManagerComponent));
1089 if (!weaponManager)
1090 return false;
1091
1092 WeaponSlotComponent slot = weaponManager.GetCurrentSlot();
1093 int preferred = 0;
1094 if ( slot )
1095 preferred = slot.GetWeaponSlotIndex();
1096
1097 bool result = EquipAny(m_Storage.GetWeaponStorage(), pOwnerEntity, preferred, cb);
1098 if (!result)
1099 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_DROP_ERROR);
1100
1101 if (cb && cb.m_pStorageFrom != cb.m_pStorageTo)
1102 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_CONTAINER_DIFR_DROP);
1103 else
1104 SCR_UISoundEntity.SoundEvent(SCR_SoundEvent.SOUND_INV_CONTAINER_SAME_DROP);
1105
1106 // Play sound
1107 PlayItemSound(pOwnerEntity, SCR_SoundEvent.SOUND_EQUIP);
1108 return result;
1109 }
1110
1111 //------------------------------------------------------------------------------------------------
1116 void EquipWeaponAttachment( IEntity pOwnerEntity, IEntity pUserEntity, SCR_InvCallBack cb = null )
1117 {
1118 BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast(pUserEntity.FindComponent(BaseWeaponManagerComponent));
1119 if (!weaponManager)
1120 return;
1121
1122 WeaponSlotComponent slot = weaponManager.GetCurrentSlot();
1123 if (!slot)
1124 return;
1125
1126 IEntity weaponEntity = slot.GetWeaponEntity();
1127 if (!weaponEntity)
1128 return;
1129
1130 BaseInventoryStorageComponent storage = BaseInventoryStorageComponent.Cast(weaponEntity.FindComponent(BaseInventoryStorageComponent));
1131 if (!storage)
1132 return;
1133
1134 EquipAny(storage, pOwnerEntity, -1, cb );
1135
1136 // Play sound
1137 PlayItemSound(pOwnerEntity, SCR_SoundEvent.SOUND_EQUIP);
1138 }
1139
1140 //------------------------------------------------------------------------------------------------
1144 void EquipGadget( IEntity pOwnerEntity, SCR_InvCallBack cb = null )
1145 {
1146 //(kamil) the gadget slots are now present directly on individual clothing items - will have to revise logic here if swapping is wanted
1147 BaseInventoryStorageComponent storageComp = FindStorageForItem(pOwnerEntity, EStoragePurpose.PURPOSE_EQUIPMENT_ATTACHMENT);
1148 if (storageComp)
1149 {
1150 EquipAny( storageComp, pOwnerEntity, -1, cb );
1151
1152 // Play sound
1153 PlayItemSound(pOwnerEntity, SCR_SoundEvent.SOUND_EQUIP);
1154 }
1155 }
1156
1157 //------------------------------------------------------------------------------------------------
1160 void EquipCloth( IEntity pOwnerEntity )
1161 {
1162 // m_pStorage because character storage is inherited from SCR_EquipedLoadoutStorageComponent
1163 EquipAny(m_Storage, pOwnerEntity);
1164
1165 // Play sound
1166 PlayItemSound(pOwnerEntity, SCR_SoundEvent.SOUND_EQUIP);
1167 }
1168
1169 //------------------------------------------------------------------------------------------------
1176 bool EquipAny(BaseInventoryStorageComponent storage, IEntity item, int preferred = -1, SCR_InvCallBack cb = null)
1177 {
1178 if (!storage || !item)
1179 return false;
1180 InventoryItemComponent itemComp = InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent));
1181 if (!itemComp)
1182 return false;
1183
1184 InventoryStorageSlot m_TargetSlot = storage.FindSuitableSlotForItem(item);
1185 // Storage doesn't have suitable slot for item (therefore any future opearation would fail)
1186 if (!m_TargetSlot)
1187 return false;
1188
1189 if (preferred > 0 && preferred < storage.GetSlotsCount())
1190 m_TargetSlot = storage.GetSlot(preferred);
1191 else
1192 preferred = m_TargetSlot.GetID();
1193
1194 InventoryStorageSlot sourceSlot = itemComp.GetParentSlot();
1195 // Item is on the ground as it does not belong to any storage (eg is not in the slot)
1196 if (!sourceSlot || !sourceSlot.GetStorage())
1197 {
1198 // we are picking up item from ground
1199 // if target slot is not empty return the result of replace operation
1200 if (m_TargetSlot.GetAttachedEntity())
1201 return TryReplaceItem(item, storage, preferred, cb);
1202
1203 // we are picking up item from ground into empty slot, simply return result of the insert operation
1204 return TryInsertItemInStorage(item, storage, preferred, cb);
1205 }
1206
1207 // our target slot is empty and we moving item from another storage
1208 // simply return the result of move operation
1209 if (!m_TargetSlot.GetAttachedEntity())
1210 return TryMoveItemToStorage(item, storage, preferred, cb);
1211
1212 BaseInventoryStorageComponent sourceStorage = sourceSlot.GetStorage();
1213 bool isTakenFromArsenal = sourceStorage.GetOwner().FindComponent(SCR_ArsenalComponent);
1214 bool isTakenFromBody = false;
1215
1216 ChimeraCharacter lootedBodyCharacter = ChimeraCharacter.Cast(sourceStorage.GetOwner());
1217 DamageManagerComponent lootedBodyDamageManager;
1218
1219 if (lootedBodyCharacter)
1220 lootedBodyDamageManager = lootedBodyCharacter.GetDamageManager();
1221
1222 if (lootedBodyDamageManager)
1223 isTakenFromBody = lootedBodyDamageManager.GetState() == EDamageState.DESTROYED;
1224
1225 bool performDropOfOriginalItem = isTakenFromBody || isTakenFromArsenal || sourceStorage.GetOwner().FindComponent(SCR_CampaignArmoryStorageComponent) ;
1226
1227 // If we don't want to drop item
1228 if (performDropOfOriginalItem)
1229 {
1230 // if we want to drop originally equipped item
1231 // here sequence would be as follows:
1232 // 1 - drop original item
1233 // 2 - insert item to target storage
1234 // 3 - try move as many items as possible from dropped item back to inventory
1235 // 4 - delete dropped item
1236
1237 // At first - let's validate if this is even possible
1238 if (!CanSwapItemStorages(item, m_TargetSlot.GetAttachedEntity()))
1239 return false;
1240
1241 DropAndMoveOperationCallback chainedCallback = new DropAndMoveOperationCallback();
1242 chainedCallback.m_Manager = this;
1243 chainedCallback.m_ItemAfter = itemComp;
1244 chainedCallback.m_ItemBefore = InventoryItemComponent.Cast(m_TargetSlot.GetAttachedEntity().FindComponent(InventoryItemComponent));
1245 chainedCallback.m_TargetSlot = m_TargetSlot;
1246 chainedCallback.m_FinalCB = cb;
1247 chainedCallback.m_bIstakenFromArsenal = isTakenFromArsenal;
1248
1249 return TryRemoveItemFromStorage(m_TargetSlot.GetAttachedEntity(), m_TargetSlot.GetStorage(), chainedCallback);
1250 }
1251
1252 // we return the result of swap opoeration were item from slotA will be transfered to slotB and item from slotB to slotA
1253 return TrySwapItemStorages(item, m_TargetSlot.GetAttachedEntity(), cb);
1254 }
1255
1256 //------------------------------------------------------------------------------------------------
1264 bool TryAssigningNextItemToQuickSlot(notnull IEntity currentItem, int quickSlotId = -1, bool mustBeSamePrefab = true, out SCR_InvEquipAnyItemCB equipCallback = null, bool equipNewItem = false)
1265 {
1266 if (quickSlotId < 0)
1267 {
1268 quickSlotId = m_Storage.GetEntityIndexInQuickslots(currentItem);
1269 if (quickSlotId < 0)
1270 return false;
1271 }
1272
1273 SCR_ResourceNamePredicate specificItemSearch = new SCR_ResourceNamePredicate(excludedItem: currentItem);
1274 specificItemSearch.m_PrefabContainer = currentItem.GetPrefabData().GetPrefab();
1275 array<IEntity> foundItems = {};
1276 if (FindItems(foundItems, specificItemSearch) <= 0)
1277 {
1278 if (mustBeSamePrefab)
1279 return false;
1280
1281 foundItems.Clear();
1282 InventoryItemComponent iic = InventoryItemComponent.Cast(currentItem.FindComponent(InventoryItemComponent));
1283 if (!iic)
1284 return false;
1285
1286 ItemAttributeCollection attributes = iic.GetAttributes();
1287 if (!attributes)
1288 return false;
1289
1290 ECommonItemType itemType = attributes.GetCommonType();
1291 if (itemType == ECommonItemType.NONE)
1292 return false;
1293
1294 SCR_CommonItemTypeSearchPredicate itemTypeSearch = new SCR_CommonItemTypeSearchPredicate(itemType, currentItem);
1295 if (FindItems(foundItems, itemTypeSearch) <= 0)
1296 return false;
1297 }
1298
1299 IEntity selectedItem = foundItems[0];
1300 if (equipCallback)
1301 {
1302 equipCallback.m_pItem = selectedItem;
1303 equipCallback.m_pStorageToPickUp = m_Storage;
1304 equipCallback.m_iSlotToFocus = quickSlotId;
1305 equipCallback.m_bShouldEquip = equipNewItem;
1306 return true;
1307 }
1308
1309 m_Storage.RemoveItemFromQuickSlotAtIndex(quickSlotId);
1310 m_Storage.StoreItemToQuickSlot(selectedItem, quickSlotId);
1311 SCR_WeaponSwitchingBaseUI.HighlightQuickSlot(quickSlotId);
1312 if (equipNewItem)
1313 m_Storage.UseItem(selectedItem);
1314
1315 return true;
1316 }
1317
1318 //------------------------------------------------------------------------------------------------
1327 bool TryReplaceAndDropItemAtSlot(BaseInventoryStorageComponent storage, IEntity item, int slotID, SCR_InvCallBack cb = null, bool isTakenFromArsenal = false)
1328 {
1329 if (!storage || !item)
1330 return false;
1331 InventoryItemComponent itemComp = InventoryItemComponent.Cast(item.FindComponent(InventoryItemComponent));
1332 if (!itemComp)
1333 return false;
1334
1335 InventoryStorageSlot m_TargetSlot = storage.GetSlot(slotID);
1336 // Storage doesn't have suitable slot for item (therefore any future opearation would fail)
1337 if (!m_TargetSlot)
1338 return false;
1339
1340 InventoryStorageSlot sourceSlot = itemComp.GetParentSlot();
1341 // Item is on the ground as it does not belong to any storage (eg is not in the slot)
1342 if (!sourceSlot || !sourceSlot.GetStorage())
1343 {
1344 // we are picking up item from ground
1345 // if target slot is not empty return the result of replace operation
1346 if (m_TargetSlot.GetAttachedEntity())
1347 return TryReplaceItem(item, storage, slotID, cb);
1348 // we are picking up item from ground into empty slot, simply return result of the insert operation
1349 return TryInsertItemInStorage(item, storage, slotID, cb);
1350 }
1351
1352 // our target slot is empty and we moving item from another storage
1353 // simply return the result of move operation
1354 if (!m_TargetSlot.GetAttachedEntity())
1355 return TryMoveItemToStorage(item, storage, slotID, cb);
1356
1357 // if we want to drop originally equipped item
1358 // here sequence would be as follows:
1359 // 1 - drop original item
1360 // 2 - insert item to target storage
1361 // 3 - try move as many items as possible from dropped item back to inventory
1362 // 4 - delete dropped item
1363
1364 // At first - let's validate if this is even possible
1365 if (!CanSwapItemStorages(item, m_TargetSlot.GetAttachedEntity()))
1366 return false;
1367
1368 DropAndMoveOperationCallback chainedCallback = new DropAndMoveOperationCallback();
1369 chainedCallback.m_Manager = this;
1370 chainedCallback.m_ItemAfter = itemComp;
1371 chainedCallback.m_ItemBefore = InventoryItemComponent.Cast(m_TargetSlot.GetAttachedEntity().FindComponent(InventoryItemComponent));
1372 chainedCallback.m_TargetSlot = m_TargetSlot;
1373 chainedCallback.m_bIstakenFromArsenal = isTakenFromArsenal;
1374 chainedCallback.m_FinalCB = cb;
1375
1376 return TryRemoveItemFromStorage(m_TargetSlot.GetAttachedEntity(), m_TargetSlot.GetStorage(), chainedCallback);
1377 }
1378
1379 //------------------------------------------------------------------------------------------------
1386 bool TryReplaceItem( BaseInventoryStorageComponent storage, IEntity item, int preferred, SCR_InvCallBack cb )
1387 {
1388 int slotCount = storage.GetSlotsCount();
1389
1390 for ( int i = 0; i < slotCount; i++ )
1391 {
1392 int j = ( i + preferred ) % slotCount;
1393 if ( CanReplaceItem( item, storage, j ) )
1394 {
1395 if ( TryReplaceItem( item, storage, j, cb ) )
1396 return true;
1397 }
1398 }
1399
1400 return false;
1401 }
1402
1403 //------------------------------------------------------------------------------------------------
1407 void EquipItem( EquipedWeaponStorageComponent weaponStorage, IEntity weapon )
1408 {
1409 // There are empty suitable slots at weapon storage
1410 if ( CanInsertItemInStorage( weapon, weaponStorage, -1) )
1411 {
1412 TryInsertItemInStorage( weapon, weaponStorage, -1 );
1413 return;
1414 }
1415
1416 // Otherwise try replace weapon at suitable slot
1417 BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast( GetOwner().FindComponent(BaseWeaponManagerComponent) );
1418 if (!weaponManager)
1419 return;
1420
1421 WeaponSlotComponent slot = weaponManager.GetCurrentSlot();
1422 int slotCount = weaponStorage.GetSlotsCount();
1423 int preferred = 0;
1424 if ( slot )
1425 preferred = slot.GetWeaponSlotIndex();
1426
1427 for ( int i = 0; i < slotCount; i++ )
1428 {
1429 int j = ( i + preferred ) % slotCount;
1430 if ( CanReplaceItem( weapon, weaponStorage, j ) )
1431 {
1432 TryReplaceItem( weapon, weaponStorage, j );
1433 return;
1434 }
1435 }
1436 }
1437
1438 //------------------------------------------------------------------------------------------------
1446 bool IsResupplyMagazinesAvailable(int resupplyMagazineCount = 4, out EResupplyUnavailableReason resupplyUnavailableReason = EResupplyUnavailableReason.NONE, EMuzzleType muzzleType = -1, InventoryStorageManagerComponent mustBeInStorage = null)
1447 {
1448 BaseWeaponManagerComponent weaponsManager = BaseWeaponManagerComponent.Cast(GetOwner().FindComponent(BaseWeaponManagerComponent));
1449 if (!weaponsManager)
1450 return false;
1451
1452 array<IEntity> weaponList = {};
1453 weaponsManager.GetWeaponsList(weaponList);
1454
1455 bool foundValidWeapon = false;
1456 ResourceName magazineOrProjectilePrefab;
1457 IEntity spawnedMagazine;
1458
1459 BaseWeaponComponent comp;
1460 array<BaseMuzzleComponent> muzzles;
1461 SCR_MuzzleInMagComponent inMagMuzzle;
1462 SCR_ArsenalInventoryStorageManagerComponent arsenalStorage;
1463 foreach (IEntity weapon : weaponList)
1464 {
1465 comp = BaseWeaponComponent.Cast(weapon.FindComponent(BaseWeaponComponent));
1466 if (!comp)
1467 continue;
1468
1469 string weaponSlotType = comp.GetWeaponSlotType();
1470
1471 // Only refill primary and secondary weapons
1472 if ((weaponSlotType != "primary" && weaponSlotType != "secondary"))
1473 continue;
1474
1475 muzzles = {};
1476
1477 //~ Get base muzzle to only supply magazines
1478 comp.GetMuzzlesList(muzzles);
1479 foreach (BaseMuzzleComponent muzzle : muzzles)
1480 {
1481 if (muzzleType != -1 && muzzle.GetMuzzleType() != muzzleType)
1482 continue;
1483
1484 inMagMuzzle = SCR_MuzzleInMagComponent.Cast(muzzle);
1485 if (inMagMuzzle && !inMagMuzzle.CanBeReloaded())
1486 continue;
1487
1488 magazineOrProjectilePrefab = muzzle.GetDefaultMagazineOrProjectileName();
1489 if (SCR_StringHelper.IsEmptyOrWhiteSpace(magazineOrProjectilePrefab))
1490 continue;
1491
1492 //~ At least one valid weapon was found
1493 foundValidWeapon = true;
1494
1495 //~ If storage is given check if magazine or projectile is in storage and only allow resupply if it is (Does not care for amount and intended use is with Arsenal)
1496 if (mustBeInStorage)
1497 {
1498 arsenalStorage = SCR_ArsenalInventoryStorageManagerComponent.Cast(mustBeInStorage);
1499 if ((arsenalStorage && !arsenalStorage.IsPrefabInArsenalStorage(magazineOrProjectilePrefab)) || (!arsenalStorage && mustBeInStorage.GetDepositItemCountByResource(GetOwner(), magazineOrProjectilePrefab) < 1))
1500 {
1501 if (resupplyUnavailableReason < EResupplyUnavailableReason.NOT_IN_GIVEN_STORAGE)
1502 resupplyUnavailableReason = EResupplyUnavailableReason.NOT_IN_GIVEN_STORAGE;
1503
1504 continue;
1505 }
1506 }
1507
1508 //~ Check if there are already enough magazines
1509 if (resupplyMagazineCount - GetMagazineCountByMuzzle(null,muzzle) <= 0)
1510 {
1511 if (resupplyUnavailableReason < EResupplyUnavailableReason.ENOUGH_ITEMS)
1512 resupplyUnavailableReason = EResupplyUnavailableReason.ENOUGH_ITEMS;
1513
1514 continue;
1515 }
1516
1517 //~ If it can be stored
1518 if (!FindStorageForResourceInsert(magazineOrProjectilePrefab, m_Storage))
1519 {
1520 if (resupplyUnavailableReason < EResupplyUnavailableReason.INVENTORY_FULL)
1521 resupplyUnavailableReason = EResupplyUnavailableReason.INVENTORY_FULL;
1522
1523 continue;
1524 }
1525
1526 //~ Passes all the checks
1527 //~ Set reason none just in case as resupply is available
1528 resupplyUnavailableReason = EResupplyUnavailableReason.NONE;
1529
1530 //~ All checks passed and at least one magazine can be added so function returns true
1531 return true;
1532 }
1533 }
1534
1535 //~ Did not have any valid weapons so set unavailable reason to no valid weapon
1536 if (!foundValidWeapon)
1537 resupplyUnavailableReason = EResupplyUnavailableReason.NO_VALID_WEAPON;
1538
1539 return false;
1540 }
1541
1542 //------------------------------------------------------------------------------------------------
1548 void GetValidResupplyItemsAndCount(out notnull map<ResourceName, int> validResupplyItems, int maxMagazineCount = 4, EMuzzleType muzzleType = -1, InventoryStorageManagerComponent mustBeInStorage = null)
1549 {
1550 validResupplyItems.Clear();
1551
1552 BaseWeaponManagerComponent weaponsManager = BaseWeaponManagerComponent.Cast(GetOwner().FindComponent(BaseWeaponManagerComponent));
1553 if (!weaponsManager)
1554 return;
1555
1556 array<IEntity> weaponList = {};
1557 weaponsManager.GetWeaponsList(weaponList);
1558
1559 BaseWeaponComponent comp;
1560 array<BaseMuzzleComponent> muzzles;
1561 SCR_MuzzleInMagComponent inMagMuzzle;
1562 SCR_ArsenalInventoryStorageManagerComponent arsenalStorage;
1563 foreach (IEntity weapon : weaponList)
1564 {
1565 comp = BaseWeaponComponent.Cast(weapon.FindComponent(BaseWeaponComponent));
1566 string weaponSlotType = comp.GetWeaponSlotType();
1567
1568 // Only refill primary and secondary weapons
1569 if (!(weaponSlotType == "primary" || weaponSlotType == "secondary"))
1570 continue;
1571
1572 muzzles = {};
1573
1574 //~ Get base muzzle to only supply magazines
1575 comp.GetMuzzlesList(muzzles);
1576 foreach (BaseMuzzleComponent muzzle : muzzles)
1577 {
1578 if (muzzleType != -1 && muzzle.GetMuzzleType() != muzzleType)
1579 continue;
1580
1581 inMagMuzzle = SCR_MuzzleInMagComponent.Cast(muzzle);
1582 if (inMagMuzzle && !inMagMuzzle.CanBeReloaded())
1583 continue;
1584
1585 ResourceName magazineOrProjectilePrefab = muzzle.GetDefaultMagazineOrProjectileName();
1586 if (SCR_StringHelper.IsEmptyOrWhiteSpace(magazineOrProjectilePrefab))
1587 continue;
1588
1589 //~ Get current magazine count and see if it needs to be increased
1590 int resupplyCount = maxMagazineCount - GetMagazineCountByMuzzle(null,muzzle);
1591 if (resupplyCount <= 0)
1592 continue;
1593
1594 //~ If storage is given check if magazine or projectile is in storage and only allow resupply if it is (Does not care for amount and intended use is with Arsenal)
1595 if (mustBeInStorage)
1596 {
1597 arsenalStorage = SCR_ArsenalInventoryStorageManagerComponent.Cast(mustBeInStorage);
1598 if ((arsenalStorage && !arsenalStorage.IsPrefabInArsenalStorage(magazineOrProjectilePrefab)) || (!arsenalStorage && mustBeInStorage.GetDepositItemCountByResource(GetOwner(), magazineOrProjectilePrefab) < 1))
1599 continue;
1600 }
1601
1602 //~ Add magazine to be resupplied
1603 if (!validResupplyItems.Contains(magazineOrProjectilePrefab))
1604 validResupplyItems.Insert(magazineOrProjectilePrefab, resupplyCount);
1605 //~ Update count till max
1606 else
1607 validResupplyItems[magazineOrProjectilePrefab] = Math.Clamp(validResupplyItems[magazineOrProjectilePrefab] + resupplyCount, 0, maxMagazineCount);
1608 }
1609 }
1610 }
1611
1612 //------------------------------------------------------------------------------------------------
1615 void ResupplyMagazines(notnull map<ResourceName, int> validResupplyItems)
1616 {
1617 //~ Nothing to resupply
1618 if (validResupplyItems.IsEmpty())
1619 return;
1620
1621 if (!m_ResupplyMagazineCallback)
1622 m_ResupplyMagazineCallback = new SCR_ResupplyMagazinesCallback(this);
1623
1624 //~ Resupply each given entry
1625 foreach (ResourceName itemPrefab, int count : validResupplyItems)
1626 {
1627 m_ResupplyMagazineCallback.Insert(itemPrefab, count);
1628 }
1629
1630 m_ResupplyMagazineCallback.Start();
1631 }
1632
1633 //------------------------------------------------------------------------------------------------
1638 void ResupplyMagazines(int maxMagazineCount = 4, EMuzzleType muzzleType = -1, InventoryStorageManagerComponent mustBeInStorage = null)
1639 {
1640 //~ Get resupply prefabs
1641 map<ResourceName, int> validResupplyItems = new map<ResourceName, int>();
1642 GetValidResupplyItemsAndCount(validResupplyItems, maxMagazineCount, muzzleType, mustBeInStorage);
1643
1644 //~ Resupply
1645 ResupplyMagazines(validResupplyItems);
1646 }
1647
1648 //------------------------------------------------------------------------------------------------
1650 void EndResupplyMagazines()
1651 {
1652 delete m_ResupplyMagazineCallback;
1653 }
1654
1655 //------------------------------------------------------------------------------------------------
1661 static bool IsItemInStorage(notnull InventoryStorageManagerComponent storage, ResourceName item, IEntity player)
1662 {
1663 SCR_ArsenalInventoryStorageManagerComponent arsenalStorage = SCR_ArsenalInventoryStorageManagerComponent.Cast(storage);
1664 return (arsenalStorage && arsenalStorage.IsPrefabInArsenalStorage(item)) || (!arsenalStorage && storage.GetDepositItemCountByResource(player, item) > 0);
1665 }
1666
1667 //------------------------------------------------------------------------------------------------
1674 EResupplyUnavailableReason CanResupplyMuzzle(IEntity user, notnull BaseMuzzleComponent muzzle, int maxMagazineCount = -1, InventoryStorageManagerComponent mustBeInStorage = null, out int currentMagazineAmount = -1)
1675 {
1676 //~ Cannot resupply weapons that cannot be ressupplied like the US rocket Launcer
1677 SCR_MuzzleInMagComponent inMagMuzzle = SCR_MuzzleInMagComponent.Cast(muzzle);
1678 if (inMagMuzzle && !inMagMuzzle.CanBeReloaded())
1679 return EResupplyUnavailableReason.NO_VALID_WEAPON;
1680
1681 //~ Get default magazine to resupply
1682 ResourceName magazineToResupply = muzzle.GetDefaultMagazineOrProjectileName();
1683 if (SCR_StringHelper.IsEmptyOrWhiteSpace(magazineToResupply))
1684 return EResupplyUnavailableReason.NO_VALID_WEAPON;
1685
1686 //~ Check if it is in arsenal or in the storage
1687 if (mustBeInStorage && !IsItemInStorage(mustBeInStorage, magazineToResupply, user))
1688 return EResupplyUnavailableReason.NOT_IN_GIVEN_STORAGE;
1689
1690 //~ Already has enough magazines
1691 currentMagazineAmount = GetMagazineCountByMuzzle(user,muzzle);
1692 if (maxMagazineCount > 0 && currentMagazineAmount >= maxMagazineCount)
1693 return EResupplyUnavailableReason.ENOUGH_ITEMS;
1694
1695 //~ Check if there is space in the inventory
1696 if (!FindStorageForResourceInsert(magazineToResupply, m_Storage))
1697 return EResupplyUnavailableReason.INVENTORY_FULL;
1698
1699 return EResupplyUnavailableReason.RESUPPLY_VALID;
1700 }
1701
1702 //------------------------------------------------------------------------------------------------
1709 EResupplyUnavailableReason CanResupplyItem(IEntity user, ResourceName itemToResupply, int maxItemCount = -1, InventoryStorageManagerComponent mustBeInStorage = null, out int currentItemAmount = -1)
1710 {
1711 //~ Check if it is in arsenal or in the storage
1712 if (mustBeInStorage && !IsItemInStorage(mustBeInStorage, itemToResupply, user))
1713 return EResupplyUnavailableReason.NOT_IN_GIVEN_STORAGE;
1714
1715 //~ Already has enough of the item in storage
1716 currentItemAmount = GetDepositItemCountByResource(user, itemToResupply);
1717 if (maxItemCount > 0 && currentItemAmount >= maxItemCount)
1718 return EResupplyUnavailableReason.ENOUGH_ITEMS;
1719
1720 //~ Check if there is space in the inventory
1721 if (!FindStorageForResourceInsert(itemToResupply, m_Storage))
1722 return EResupplyUnavailableReason.INVENTORY_FULL;
1723
1724 return EResupplyUnavailableReason.RESUPPLY_VALID;
1725 }
1726
1727 //------------------------------------------------------------------------------------------------
1731 void MoveItemToVicinity(IEntity pItem, BaseInventoryStorageComponent pStorageTo = null);
1732
1733 //------------------------------------------------------------------------------------------------
1735 void OpenInventory()
1736 {
1737 if (!m_bInventoryAccessAllowed)
1738 return;
1739
1741 return;
1742
1743 MenuManager menuManager = GetGame().GetMenuManager();
1744 ChimeraMenuPreset menu = ChimeraMenuPreset.Inventory20Menu;
1745
1746 MenuBase inventoryMenu = menuManager.FindMenuByPreset(menu);
1747 if (inventoryMenu)
1748 return;
1749
1750 menuManager.OpenMenu( menu );
1751 m_OnInventoryOpenInvoker.Invoke(true);
1752
1754 return;
1755
1756 // Quit ADS
1757 m_CharacterController.SetWeaponADS(false);
1758 m_CharacterController.SetGadgetRaisedModeWanted(false);
1759
1760 // Pin grenade
1761 if (m_CharacterController.GetInputContext() && m_CharacterController.GetInputContext().GetThrow())
1762 m_CharacterController.SetThrow(false, true);
1763
1764 // Inspection or lowered weapon stance
1765 m_bWasRaised = m_CharacterController.IsWeaponRaised();
1766 m_CharacterController.SetWeaponRaised(false);
1767
1768 //SCR_AnalyticsApplication.GetInstance().OpenInventory(GetTotalWeightOfAllStorages());
1769 }
1770
1771 //------------------------------------------------------------------------------------------------
1773 void CloseInventory()
1774 {
1775 MenuManager menuManager = GetGame().GetMenuManager();
1776 if (!menuManager)
1777 return;
1778
1779 menuManager.CloseMenuByPreset(ChimeraMenuPreset.Inventory20Menu);
1780 }
1781
1782 //------------------------------------------------------------------------------------------------
1784 IEntity GetStorageToOpen()
1785 {
1786 IEntity result = m_StorageToOpen;
1787 m_StorageToOpen = null;
1788
1789 return result;
1790 }
1791
1792 //------------------------------------------------------------------------------------------------
1794 void SetStorageToOpen(IEntity storage)
1795 {
1796 m_StorageToOpen = storage;
1797 }
1798
1799 //------------------------------------------------------------------------------------------------
1801 void Action_OpenInventory()
1802 {
1803 CompartmentAccessComponent cac = m_CharacterController.GetCharacter().GetCompartmentAccessComponent();
1804 if (cac && cac.IsInCompartment())
1805 {
1806 IEntity owner = cac.GetCompartment().GetOwner();
1807 while (owner)
1808 {
1809 UniversalInventoryStorageComponent comp = UniversalInventoryStorageComponent.Cast(owner.FindComponent(UniversalInventoryStorageComponent));
1810 if (comp)
1811 {
1812 SetStorageToOpen(owner);
1813 break;
1814 }
1815
1816 owner = owner.GetParent();
1817 }
1818 }
1819
1820 if (cac && (cac.IsGettingIn() || cac.IsGettingOut()))
1821 return;
1822
1823 OpenInventory();
1824 }
1825
1826 //------------------------------------------------------------------------------------------------
1827 void OnInventoryMenuClosed()
1828 {
1829 m_OnInventoryOpenInvoker.Invoke(false);
1830
1831 // Revert inspection or lowered weapon stance
1833 m_CharacterController.SetWeaponRaised(m_bWasRaised);
1834
1835 //SCR_AnalyticsApplication.GetInstance().CloseInventory(GetTotalWeightOfAllStorages());
1836 }
1837
1838 //------------------------------------------------------------------------------------------------
1839 override void OnStorageAdded(BaseInventoryStorageComponent storage)
1840 {
1841 // do nothing
1842 }
1843
1844// //------------------------------------------------------------------------------------------------
1845// //! Even after physics update
1846// //! \param[in] owner The owner entity
1847// //! \param[in] frameNumber Time passed since last frame
1848// override void EOnPostFrame(IEntity owner, float timeSlice)
1849// {
1850// m_OnPostFrameInvoker.Invoke(timeSlice);
1851// }
1852
1853 //------------------------------------------------------------------------------------------------
1855 void DebugListAllItemsInInventory()
1856 {
1857 array<IEntity> items = {};
1858 GetItems(items);
1859 Print("INV: no item", LogLevel.NORMAL);
1860 InventoryItemComponent pInvComp;
1861 ItemAttributeCollection attribs;
1862 foreach (IEntity item : items)
1863 {
1864 pInvComp = InventoryItemComponent.Cast( item .FindComponent( InventoryItemComponent ) );
1865 if( pInvComp )
1866 {
1867 attribs = pInvComp.GetAttributes();
1868 if( !attribs )
1869 break;
1870
1871 string sName = attribs.GetUIInfo().GetName();
1872 Print("INV: " + sName, LogLevel.NORMAL);
1873
1874 }
1875 }
1876 }
1877
1878 //------------------------------------------------------------------------------------------------
1880 void EnablePostFrame(bool enable)
1881 {
1882 if (enable)
1883 SetEventMask(GetOwner(), EntityEvent.POSTFRAME);
1884 else
1885 ClearEventMask(GetOwner(), EntityEvent.POSTFRAME);
1886 }
1887
1888 //------------------------------------------------------------------------------------------------
1890 int GetHealthComponentCount()
1891 {
1892 return m_iHealthEquipment;
1893 }
1894
1895 //------------------------------------------------------------------------------------------------
1897 IEntity GetBandageItem()
1898 {
1899 return FindItem(m_BandagePredicate, EStoragePurpose.PURPOSE_DEPOSIT);
1900 }
1901
1902 //------------------------------------------------------------------------------------------------
1903 // destructor
1904 void ~SCR_InventoryStorageManagerComponent()
1905 {
1906 m_ERetCode = EInventoryRetCode.RETCODE_DEFAULT_STATE;
1907 }
1908
1909 //------------------------------------------------------------------------------------------------
1911 bool IsAnimationReady()
1912 {
1914 return m_CharacterController.CanPlayItemGesture() || m_CharacterController.IsPlayingItemGesture();
1915 return true;
1916 }
1917
1918 //------------------------------------------------------------------------------------------------
1920 bool IsInventoryLocked()
1921 {
1922 return m_bIsInventoryLocked;
1923 }
1924
1925 //------------------------------------------------------------------------------------------------
1927 void SetInventoryLocked(bool isLocked)
1928 {
1929 m_bIsInventoryLocked = isLocked;
1930 }
1931
1932 //------------------------------------------------------------------------------------------------
1936 int GetAllItems(inout array<IEntity> items, BaseInventoryStorageComponent storage)
1937 {
1938 if (!storage || !items)
1939 return 0;
1940
1941 int count = 0;
1942
1943 if (!ClothNodeStorageComponent.Cast(storage))
1944 count = storage.GetAll(items);
1945
1946 array<BaseInventoryStorageComponent> itemToReplaceAttachedStorages = {};
1947 storage.GetOwnedStorages(itemToReplaceAttachedStorages, 1, false);
1948 foreach (BaseInventoryStorageComponent attachedStorage : itemToReplaceAttachedStorages)
1949 {
1950 if (ClothNodeStorageComponent.Cast(attachedStorage))
1951 attachedStorage.GetOwnedStorages(itemToReplaceAttachedStorages, 1, false);
1952 else
1953 count += attachedStorage.GetAll(items);
1954 }
1955
1956 return count;
1957 }
1958
1959 //------------------------------------------------------------------------------------------------
1964 void GetWeaponPrefabsOfType(notnull array<IEntity> weapons, EWeaponType weaponType, notnull out array<EntityPrefabData> prefabs)
1965 {
1966 BaseWeaponComponent weapon;
1967 EntityPrefabData prefabData;
1968 foreach (IEntity item : weapons)
1969 {
1970 weapon = BaseWeaponComponent.Cast(item.FindComponent(BaseWeaponComponent));
1971 if (weapon.GetWeaponType() != weaponType)
1972 continue;
1973
1974 // Ignore currently selected items
1975 prefabData = item.GetPrefabData();
1976 if (prefabData && !prefabs.Contains(prefabData))
1977 prefabs.Insert(prefabData);
1978 }
1979 }
1980
1981 //------------------------------------------------------------------------------------------------
1987 IEntity FindNextWeaponOfType(EWeaponType weaponType, IEntity currentItem = null, bool allowCurrentPrefab = false)
1988 {
1989 array<EntityPrefabData> prefabs = {};
1990
1991 // Currently selected weapon may be outside of inventory and it has to be considered for sorting
1992 EntityPrefabData currentPrefab;
1993 BaseWeaponComponent currentWeapon;
1994 if (currentItem)
1995 {
1996 currentPrefab = currentItem.GetPrefabData();
1997 currentWeapon = BaseWeaponComponent.Cast(currentItem.FindComponent(BaseWeaponComponent));
1998
1999 if (currentPrefab && currentWeapon.GetWeaponType() == weaponType)
2000 prefabs.Insert(currentPrefab);
2001 }
2002
2003 // Collect all the matching prefabs
2004 array<IEntity> items = {};
2005 FindItemsWithComponents(items, {BaseWeaponComponent});
2006 GetWeaponPrefabsOfType(items, weaponType, prefabs);
2007
2008 // No valid prefabs
2009 if (prefabs.IsEmpty())
2010 return null;
2011
2012 // TODO: better sorting, perhaps by name
2013 prefabs.Sort();
2014
2015// foreach (EntityPrefabData prefab : prefabs)
2016// {
2017// Print(prefab.GetPrefabName(), LogLevel.WARNING);
2018// }
2019
2020 // Select next prefab
2021 int nextPrefabID = (prefabs.Find(currentPrefab) + 1) % prefabs.Count();
2022 EntityPrefabData nextPrefab = prefabs[nextPrefabID];
2023
2024 // Return nothing if prefab is unchanged
2025 if (!allowCurrentPrefab && nextPrefab == currentPrefab)
2026 return null;
2027
2028 // Select the weapon that matches the type to be selected
2029 foreach (IEntity item : items)
2030 {
2031 if (item && item.GetPrefabData() == nextPrefab)
2032 return item;
2033 }
2034
2035 return null;
2036 }
2037
2038 //------------------------------------------------------------------------------------------------
2039 void AllowInventoryAccess(bool allow)
2040 {
2041 m_bInventoryAccessAllowed = allow;
2042 }
2043
2044#else
2045
2046 //------------------------------------------------------------------------------------------------
2048 void SetReturnCode( EInventoryRetCode ERetCode ) ;
2049
2050 //------------------------------------------------------------------------------------------------
2051 void SetReturnCodeDefault() ;
2052
2053 //------------------------------------------------------------------------------------------------
2055 EInventoryRetCode GetReturnCode()
2056 {
2057 return m_ERetCode;
2058 }
2059
2060 //------------------------------------------------------------------------------------------------
2062 float GetTotalWeightOfAllStorages();
2063
2064 //------------------------------------------------------------------------------------------------
2066 void SetLootStorage( IEntity pOwner );
2067
2068 //------------------------------------------------------------------------------------------------
2071 void InsertItem( IEntity pItem );
2072
2073 //------------------------------------------------------------------------------------------------
2078 void EquipWeapon( IEntity pOwnerEntity, SCR_InvCallBack cb = null, bool bFromVicinity = true );
2079
2080 //------------------------------------------------------------------------------------------------
2083 void EquipGadget( IEntity pOwnerEntity );
2084
2085 //------------------------------------------------------------------------------------------------
2088 void EquipCloth( IEntity pOwnerEntity );
2089
2090 //------------------------------------------------------------------------------------------------
2095 void EquipAny(BaseInventoryStorageComponent storage, IEntity item, int preferred = 0);
2096
2097 //------------------------------------------------------------------------------------------------
2101 void EquipItem( EquipedWeaponStorageComponent weaponStorage, IEntity weapon );
2102
2103 //------------------------------------------------------------------------------------------------
2105 void OpenInventory();
2106
2107 //------------------------------------------------------------------------------------------------
2109 void Action_OpenInventory();
2110
2111 //------------------------------------------------------------------------------------------------
2112 override void OnStorageAdded(BaseInventoryStorageComponent storage);
2113
2114 //------------------------------------------------------------------------------------------------
2117 void EnablePostFrame(bool enable);
2118
2119 //------------------------------------------------------------------------------------------------
2121 int GetHealthComponentCount();
2122
2123 //------------------------------------------------------------------------------------------------
2125 IEntity GetBandageItem();
2126
2127#endif
2128
2129 //------------------------------------------------------------------------------------------------
2130 // constructor
2134 void SCR_InventoryStorageManagerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
2135 {
2136 #ifndef DISABLE_INVENTORY
2137
2138 //ChimeraCharacter pChimeraChar = ChimeraCharacter.Cast( ent );
2139 //pChimeraChar.s_OnCharacterCreated.Insert( DebugListAllItemsInInventory );
2140
2141 m_Storage = SCR_CharacterInventoryStorageComponent.Cast(ent.FindComponent(CharacterInventoryStorageComponent));
2142 m_CharacterController = SCR_CharacterControllerComponent.Cast(ent.FindComponent(SCR_CharacterControllerComponent));
2143 #endif
2144 }
2145}
ChimeraMenuPreset
Menu presets.
@ NOT_ENOUGH_AVAILABLE_ALLOCATED_SUPPLIES
If Military Supply Allocation is enabled and player does not have enough Available Allocated Supplies...
@ RANK_TOO_LOW
If player ranks are enabled and player has too low of a rank.
ArmaReforgerScripted GetGame()
Definition game.c:1398
ECommonItemType
void Start()
Start this tracking time in this menu, adds it to previous time if we have not yet sended previous da...
void OnItemAdded(BaseInventoryStorageComponent storageOwner, IEntity item)
void OnItemRemoved(BaseInventoryStorageComponent storageOwner, IEntity item)
SCR_EArsenalItemType m_eItemType
SCR_CharacterPerceivableComponentClass m_CharacterController
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
SCR_EConsumableType
Type of consumable gadget.
EDamageType type
SCR_InventoryStorageManagerComponentClass RETCODE_OK
SCR_InventoryStorageManagerComponentClass RETCODE_ITEM_TOO_HEAVY
SCR_InventoryStorageManagerComponentClass RETCODE_ITEM_TOO_BIG
ScriptInvokerBase< ScriptInvokerBoolMethod > ScriptInvokerBool
BaseInventoryStorageComponent m_Storage
void SCR_UniversalInventoryStorageComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
enum EVehicleType IEntity
bool IsMatch(BaseInventoryStorageComponent storage, IEntity item, array< GenericComponent > queriedComponents, array< BaseItemAttributeData > queriedAttributes)
proto external Managed FindComponent(typename typeName)
proto external EntityPrefabData GetPrefabData()
proto external IEntity GetParent()
proto external bool IsDeleted()
proto external MenuBase FindMenuByPreset(ScriptMenuPresetEnum preset)
Finds first menu/dialog with given preset index, or nullptr when there is no such menu opened.
proto external bool CloseMenuByPreset(ScriptMenuPresetEnum preset)
Put menu with given iPresetId into queue for closing (which is processed during next MenuManeger upda...
proto external MenuBase OpenMenu(ScriptMenuPresetEnum preset, int userId=0, bool unique=false, bool hideParentMenu=true)
bool CanApplyEffectToHZ(notnull IEntity target, notnull IEntity user, ECharacterHitZoneGroup group, out SCR_EConsumableFailReason failReason=SCR_EConsumableFailReason.NONE)
proto external int GetEventIndex(string name)
IEntity GetOwner()
Owner entity of the fuel tank.
EItemGesture
ECharacterLifeState
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
@ NONE
When Shape is created and not initialized yet.
Definition ShapeType.c:15
EntityEvent
Various entity events.
Definition EntityEvent.c:14
EDamageState
ref BaseInventoryTask InsertItem(IEntity item, int slotID, bool justSpawned)
EStoragePurpose
event bool CanReplaceItem(IEntity nextItem, int slotID)
Implemented logics for can replace to nextItem at slotID,.
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
int RplId
Definition EnNetwork.c:33
proto int Insert(T value)
EWeaponType
Definition EWeaponType.c:13
EMuzzleType
Definition EMuzzleType.c:13