Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_GadgetManagerComponent.c
Go to the documentation of this file.
2class SCR_GadgetInvokersInitState
3{
4 SCR_GadgetManagerComponent m_GadgetManager;
6
7 bool m_bIsControlledInit = false; // init flag for controlled entity invokers
8 bool m_bIsDefaultInit = false; // init flag for default invokers
9 bool m_bIsControlledEnt = false; // controlled entity flag
10
11 //------------------------------------------------------------------------------------------------
13 bool IsInit()
14 {
15 if (m_bIsControlledEnt)
16 return m_bIsDefaultInit && m_bIsControlledInit;
17
18 return m_bIsDefaultInit;
19 }
20
21 //------------------------------------------------------------------------------------------------
25 void InitInvokers(IEntity character, SCR_CharacterControllerComponent controller)
26 {
27 if (m_bIsDefaultInit)
28 return;
29
30 m_Controller = controller;
31
32 SCR_InventoryStorageManagerComponent invManager = SCR_InventoryStorageManagerComponent.Cast(m_Controller.GetInventoryStorageManager());
33 if (invManager)
34 {
35 m_Controller.m_OnGadgetStateChangedInvoker.Insert(m_GadgetManager.OnGadgetStateChanged);
36 m_Controller.m_OnControlledByPlayer.Insert(m_GadgetManager.OnControlledByPlayer);
37 invManager.m_OnItemAddedInvoker.Insert(m_GadgetManager.OnItemAdded);
38 invManager.m_OnItemRemovedInvoker.Insert(m_GadgetManager.OnItemRemoved);
39
40 m_bIsDefaultInit = true;
41 }
42 }
43
44 //------------------------------------------------------------------------------------------------
48 void InitControlledInvokers(IEntity character, SCR_CharacterControllerComponent controller)
49 {
50 if (m_bIsControlledInit)
51 return;
52
53 m_Controller = controller;
54 m_Controller.GetOnPlayerDeathWithParam().Insert(m_GadgetManager.OnPlayerDeath);
55 m_Controller.m_OnGadgetFocusStateChangedInvoker.Insert(m_GadgetManager.OnGadgetFocusStateChanged);
56
57 SCR_EditorManagerEntity editorManager = SCR_EditorManagerEntity.GetInstance();
58 if (editorManager)
59 editorManager.GetOnOpened().Insert(m_GadgetManager.OnEditorOpened);
60
61 m_bIsControlledEnt = true;
62 m_bIsControlledInit = true;
63 }
64
65 //------------------------------------------------------------------------------------------------
68 void CleanupInvokers(GenericEntity character)
69 {
70 if (m_Controller)
71 {
72 m_Controller.m_OnGadgetStateChangedInvoker.Remove(m_GadgetManager.OnGadgetStateChanged);
73 m_Controller.m_OnControlledByPlayer.Remove(m_GadgetManager.OnControlledByPlayer);
74 }
75
76 SCR_InventoryStorageManagerComponent invManager = SCR_InventoryStorageManagerComponent.Cast(character.FindComponent(SCR_InventoryStorageManagerComponent));
77 if (invManager)
78 {
79 invManager.m_OnItemAddedInvoker.Remove(m_GadgetManager.OnItemAdded);
80 invManager.m_OnItemRemovedInvoker.Remove(m_GadgetManager.OnItemRemoved);
81 }
82
83 m_bIsDefaultInit = false;
84 }
85
86 //------------------------------------------------------------------------------------------------
89 void CleanupLocalInvokers(GenericEntity character)
90 {
91 if (m_Controller)
92 {
93 m_Controller.GetOnPlayerDeathWithParam().Remove(m_GadgetManager.OnPlayerDeath);
94 m_Controller.m_OnGadgetFocusStateChangedInvoker.Remove(m_GadgetManager.OnGadgetFocusStateChanged);
95 }
96
97 SCR_EditorManagerEntity editorManager = SCR_EditorManagerEntity.GetInstance();
98 if (editorManager)
99 editorManager.GetOnOpened().Remove(m_GadgetManager.OnEditorOpened);
100
101 m_bIsControlledInit = false;
102 m_bIsControlledEnt = false;
103 }
104
105 //------------------------------------------------------------------------------------------------
108 void Clear(GenericEntity entity)
109 {
110 if (!entity)
111 return;
112
113 CleanupLocalInvokers(entity);
114 CleanupInvokers(entity);
115 }
116
117 //------------------------------------------------------------------------------------------------
118 // constructor
120 void SCR_GadgetInvokersInitState(notnull SCR_GadgetManagerComponent gadgetManager)
121 {
122 m_GadgetManager = gadgetManager;
123 }
124}
125
126[EntityEditorProps(category: "GameScripted/Gadgets", description: "Gadget manager", color: "0 0 255 255")]
127class SCR_GadgetManagerComponentClass : ScriptGameComponentClass
129 //------------------------------------------------------------------------------------------------
130 static override bool DependsOn(string className)
132 if (className == "SCR_CharacterInventoryStorageComponent") // enforce load order here to be able to access storage
133 return true;
134
135 return false;
137}
138
139class SCR_GadgetManagerComponent : ScriptGameComponent
140{
141 int m_iRadiosFlags = EGadgetType.RADIO | EGadgetType.RADIO_BACKPACK;
142
143 ref ScriptInvoker<SCR_GadgetComponent> m_OnGadgetAdded = new ScriptInvoker(); // called when gadget is added to inventory
144 ref ScriptInvoker<SCR_GadgetComponent> m_OnGadgetRemoved = new ScriptInvoker(); // called when gadget is removed from inventory
145 protected static ref ScriptInvoker<IEntity, SCR_GadgetManagerComponent> s_OnGadgetInitDone = new ScriptInvoker(); // invoked after gadget init is done on a newly spawned character
146
147 protected bool m_bIsGadgetADS; // is gadget currently in raised state
149 protected SCR_GadgetComponent m_HeldGadgetComponent;
150 protected SCR_GadgetComponent m_HiddenGadgetComponent;
152 protected SCR_InventoryStorageManagerComponent m_InventoryStorageMgr;
154 protected SCR_VONController m_VONController;
156
157 protected ref array<ref array<SCR_GadgetComponent>> m_aInventoryGadgetTypes = {}; // array of gadget types > array of gadget components
158 protected ref map<EGadgetType, int> m_aGadgetArrayMap = new map<EGadgetType, int>(); // map of gadget types -> gadget type array ID
159
160 //TODO
161 protected SCR_GadgetComponent m_LastHeldGadgetComponent; // hack to make thingy work, unhack me
162
163 //------------------------------------------------------------------------------------------------
164 // GET/SET METHODS
165 //------------------------------------------------------------------------------------------------
166
167 //------------------------------------------------------------------------------------------------
170 {
172 }
173
174 //------------------------------------------------------------------------------------------------
178 {
179 GenericEntity player = GenericEntity.Cast(entity);
180 if (!player)
181 return null;
182
184
185 return gadgetManager;
186 }
187
188 //------------------------------------------------------------------------------------------------
192 {
193 if (m_HeldGadget)
194 return m_HeldGadget;
196 return m_HiddenGadgetComponent.GetOwner();
197 else
198 return null;
199 }
200
201 //------------------------------------------------------------------------------------------------
205 {
206 return m_bIsGadgetADS;
207 }
208
209 //------------------------------------------------------------------------------------------------
212 SCR_GadgetComponent GetHeldGadgetComponent()
213 {
216
218 }
219
220 //------------------------------------------------------------------------------------------------
221 static bool ValidController(IEntity owner)
222 {
223 if (owner && GetGadgetManager(owner).m_Controller)
224 return true;
225
226 return false;
227 }
228
229 //------------------------------------------------------------------------------------------------
231 //! When changing mode FROM EGadgetMode.IN_HAND to inventory, target should be EGadgetMode.IN_STORAGE -> it will do EGadgetMode.IN_SLOT automatically if it is slotted
232 //! \param[in] gadget is the subject
233 //! \param[in] targetMode is the mode being switched into
234 //! \param[in] doFocus determines whether the gadget will becomes focused straight away
235 void SetGadgetMode(IEntity gadget, EGadgetMode targetMode, bool doFocus = false)
236 {
237 if (!gadget)
238 return;
239
240 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(gadget.FindComponent(SCR_GadgetComponent));
241 if (!gadgetComp)
242 return;
244 if (targetMode == EGadgetMode.IN_HAND && !gadgetComp.CanBeHeld())
245 return;
246
247 // switch mode rules
248 if (!CanChangeGadgetMode(gadget, gadgetComp, targetMode))
249 return;
250
251 if (targetMode == EGadgetMode.IN_HAND || gadgetComp.GetMode() == EGadgetMode.IN_HAND || gadgetComp == m_HiddenGadgetComponent) // If going TO or FROM mode1 -> anims need to happen first. Mode is synched from finish events instead of here
252 {
253 if (!m_Controller)
254 return;
255
256 if (targetMode == EGadgetMode.IN_HAND) // Gadget to hand
257 {
259
260 if (gadgetComp.CanBeRaised())
261 m_Controller.TakeGadgetInLeftHand(gadget, gadgetComp.GetAnimVariable(), doFocus);
262 else
263 m_Controller.TakeGadgetInLeftHand(gadget, gadgetComp.GetAnimVariable());
264 }
265 else // Gadget from hand
266 {
267 if (targetMode == EGadgetMode.ON_GROUND) // if moving from hand to storage, SetGadgetMode will call hand->ground ground->slot , so we cannot wait for anim to finish to switch mode
268 m_Controller.RemoveGadgetFromHand(true);
269 else
270 m_Controller.RemoveGadgetFromHand(gadgetComp == m_HiddenGadgetComponent);
271
272 if (gadgetComp.GetType() == EGadgetType.MAP) // TODO hotfix against incorrect toggle set when spamming input, will be solved when map has unfocused & focused mode
273 return;
274
275 if (gadgetComp.m_bFocused) // close focus state
276 gadgetComp.ToggleFocused(false);
277 }
278 }
279 else // If switching between NONE and MODE0
280 gadgetComp.OnModeChanged(targetMode, GetOwner());
281 }
282
283 //------------------------------------------------------------------------------------------------
287 static void SetGadgetModeStashed(SCR_GadgetComponent gadgetComp, EGadgetMode targetMode)
288 {
289 if (targetMode != EGadgetMode.ON_GROUND && targetMode != EGadgetMode.IN_STORAGE)
290 return;
291
292 gadgetComp.OnModeChanged(targetMode, null);
293 }
294
295 //------------------------------------------------------------------------------------------------
298 {
299 if (m_HeldGadget)
300 SetGadgetMode(m_HeldGadget, EGadgetMode.IN_SLOT); // whether the gadget is actually slotted or put to storage is handled in OnGadgetStateChanged
302 SetGadgetMode(m_HiddenGadgetComponent.GetOwner(), EGadgetMode.IN_SLOT);
303 }
304
305 //------------------------------------------------------------------------------------------------
307 protected void OnActivateHeldGadget()
308 {
310 m_HeldGadgetComponent.ActivateAction();
312 m_HiddenGadgetComponent.ActivateAction();
313 }
314
315 //------------------------------------------------------------------------------------------------
318 void ToggleHeldGadget(bool state)
319 {
321 m_HeldGadgetComponent.ToggleActive(state, SCR_EUseContext.FROM_ACTION);
323 m_HiddenGadgetComponent.ToggleActive(state, SCR_EUseContext.FROM_ACTION);
324 }
325
326 //------------------------------------------------------------------------------------------------
330 array<SCR_GadgetComponent> GetGadgetsByType(EGadgetType type)
331 {
332 int gadgetArrayID = m_aGadgetArrayMap.Get(type);
333 if (gadgetArrayID != -1)
334 {
335 array<SCR_GadgetComponent> arr = {};
336 arr.Copy(m_aInventoryGadgetTypes[gadgetArrayID]);
337
338 return arr;
339 }
340
341 return null;
342 }
343
344 //------------------------------------------------------------------------------------------------
349 {
350 array<SCR_GadgetComponent> gadgets = GetGadgetsByType(type);
351 if (!gadgets || gadgets.IsEmpty())
352 return null;
353
354 foreach (SCR_GadgetComponent comp : gadgets)
355 {
356 if (comp)
357 return comp.GetOwner();
358 else
359 Print(GetOwner().ToString() + " SCR_GadgetManager::GetGadgetsByType returned null entry in an array of " + typename.EnumToString(EGadgetType, type) + " gadgets", LogLevel.ERROR); // this should not happen
360 }
361
362 return null;
363 }
364
365 //------------------------------------------------------------------------------------------------
370 {
371 SCR_InventoryStorageManagerComponent storageManager = SCR_InventoryStorageManagerComponent.Cast(m_Controller.GetInventoryStorageManager());
372 if (!storageManager)
373 return null;
374
375 SCR_CharacterInventoryStorageComponent charStorage = storageManager.GetCharacterStorage();
376 array<ref SCR_QuickslotBaseContainer> quickSlotsContainers = charStorage.GetQuickSlotItems();
377
378 SCR_QuickslotEntityContainer entityContainer;
379 SCR_GadgetComponent gadgetComp;
380 foreach (SCR_QuickslotBaseContainer container : quickSlotsContainers)
381 {
382 entityContainer = SCR_QuickslotEntityContainer.Cast(container);
383 if (!entityContainer || !entityContainer.GetEntity()) // empty slots will be null
384 continue;
385
386 gadgetComp = SCR_GadgetComponent.Cast(entityContainer.GetEntity().FindComponent(SCR_GadgetComponent));
387 if (gadgetComp)
388 {
389 if (gadgetComp.GetType() == type)
390 return entityContainer.GetEntity();
391 }
392 }
393
394 return null;
395 }
396
397 //------------------------------------------------------------------------------------------------
401 bool IsGadgetOwned(SCR_GadgetComponent gadgetComp)
402 {
403 int gadgetArrayID = m_aGadgetArrayMap.Get(gadgetComp.GetType());
404 if (gadgetArrayID != 1)
405 {
406 return m_aInventoryGadgetTypes[gadgetArrayID].Contains(gadgetComp);
407 }
408
409 return false;
410 }
411
412 //------------------------------------------------------------------------------------------------
413 // MANAGER METHODS
414 //------------------------------------------------------------------------------------------------
415
416 //------------------------------------------------------------------------------------------------
421 protected bool CanChangeGadgetMode(IEntity gadget, SCR_GadgetComponent gadgetComp, EGadgetMode targetMode)
422 {
423 if (targetMode == EGadgetMode.IN_HAND || gadgetComp.GetMode() == EGadgetMode.IN_HAND) // If going TO or FROM mode1 -> anims need to happen first. Mode is synched from finish events instead of here
424 {
425 ChimeraCharacter character = ChimeraCharacter.Cast(GetOwner());
426 if (!character)
427 return false;
428
429 CompartmentAccessComponent compAccess = character.GetCompartmentAccessComponent(); // if in vehicle
430 if (compAccess && compAccess.IsInCompartment())
431 {
433 if (!invItemComponent)
434 return false;
435
436 CharacterModifierAttributes charModifData = CharacterModifierAttributes.Cast(invItemComponent.FindAttribute(CharacterModifierAttributes));
437 if (!charModifData)
438 return false;
439
440 if (targetMode == EGadgetMode.IN_HAND && !charModifData.CanBeEquippedInVehicle())
441 return false;
442 }
443 }
444
445 return true;
446 }
447
448 //------------------------------------------------------------------------------------------------
451 protected void UpdateHeldGadget(IEntity gadget)
452 {
453 // no need ot update
454 if (gadget && gadget == m_HeldGadget)
455 return;
456
457 m_bIsGadgetADS = false;
458
459 // clear
460 if (!gadget)
461 {
464
465 m_HeldGadget = null;
468
469 CharacterInputContext inputCtx = m_Controller.GetInputContext();
470 IEntity hiddenGadget = inputCtx.GetWantedLefHandGadgetEntity();
471 if (hiddenGadget)
472 {
473 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(hiddenGadget.FindComponent(SCR_GadgetComponent));
474 if (!gadgetComp)
475 return;
476
477 m_HiddenGadgetComponent = gadgetComp;
478
480 }
481 else
482 {
484 }
485 }
486 else
487 {
488 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(gadget.FindComponent(SCR_GadgetComponent));
489 if (!gadgetComp)
490 return;
491
492 m_HeldGadget = gadget;
493 m_HeldGadgetComponent = gadgetComp;
496 }
497 }
498
499 //------------------------------------------------------------------------------------------------
503 void HandleInput(IEntity gadget, float inputVal)
504 {
505 EGadgetMode targetMode = EGadgetMode.IN_HAND;
506 bool doFocus = inputVal != 1; // input modifier from config
507
508 if (m_HeldGadget == gadget) // already holding this gadget
509 targetMode = EGadgetMode.IN_STORAGE;
510
511 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(gadget.FindComponent(SCR_GadgetComponent));
512 if (!gadgetComp)
513 return;
514
515 if (inputVal != 1 && (gadgetComp.GetUseMask() & SCR_EUseContext.FROM_ACTION) != 0)
516 {
517 gadgetComp.ToggleActive(!gadgetComp.IsToggledOn(), SCR_EUseContext.FROM_ACTION);
518 }
519 else
520 {
521 if (m_HeldGadgetComponent && m_HeldGadgetComponent.GetType() == gadgetComp.GetType())
522 SetGadgetMode(m_HeldGadget, EGadgetMode.IN_STORAGE);
523 else
524 SetGadgetMode(gadget, targetMode, doFocus);
525 }
526 }
527
528 //------------------------------------------------------------------------------------------------
530 protected void ClearToggleState()
531 {
532 m_bIsGadgetADS = false;
534 {
535 m_HeldGadgetComponent.ToggleFocused(false);
536 m_Controller.SetGadgetRaisedModeWanted(false);
537 }
538 }
539
540 //------------------------------------------------------------------------------------------------
541 // EVENTS
542 //------------------------------------------------------------------------------------------------
543
544 //------------------------------------------------------------------------------------------------
548 void OnItemAdded(IEntity item, BaseInventoryStorageComponent storageOwner)
549 {
550 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(item.FindComponent(SCR_GadgetComponent));
551 if (!gadgetComp)
552 return;
553
555 if (!invComp)
556 return;
557
558 EGadgetType type = gadgetComp.GetType();
559
560 int gadgetArrayID = m_aGadgetArrayMap.Get(type);
561 if (gadgetArrayID == -1)
562 return;
563
564 m_aInventoryGadgetTypes[gadgetArrayID].Insert(gadgetComp);
565
566 // Check whether the gadget is in equipment slot (OnAddedToSlot will happen before this)
567 EquipmentStorageComponent equipmentComp = EquipmentStorageComponent.Cast(storageOwner);
568 if (equipmentComp)
569 {
570 InventoryStorageSlot storageSlot = equipmentComp.FindItemSlot(item);
571 if (storageSlot)
572 SetGadgetMode(item, EGadgetMode.IN_SLOT);
573 }
574 else if (type == EGadgetType.RADIO_BACKPACK) // special case for backpack radios, always in (character) slot
575 SetGadgetMode(item, EGadgetMode.IN_SLOT);
576 else
577 SetGadgetMode(item, EGadgetMode.IN_STORAGE);
578
579 m_OnGadgetAdded.Invoke(gadgetComp);
580
581 if (m_VONController && (type & m_iRadiosFlags)) // add entries to VONController
582 {
583 SCR_RadioComponent radioGadget = SCR_RadioComponent.Cast(gadgetComp);
584 if (!radioGadget)
585 return;
586
587 BaseRadioComponent radioComp = radioGadget.GetRadioComponent();
588 if (!radioComp)
589 return;
590
591 // Put all transceivers (AKA) channels in the VoN menu
592 int count = radioComp.TransceiversCount();
593 for (int i = 0; i < count; i++)
594 {
595 SCR_VONEntryRadio radioEntry = new SCR_VONEntryRadio();
596 radioEntry.SetRadioEntry(radioComp.GetTransceiver(i), i + 1, gadgetComp);
597 m_VONController.AddEntry(radioEntry);
598 }
599 }
600 }
601
602 //------------------------------------------------------------------------------------------------
606 void OnItemRemoved(IEntity item, BaseInventoryStorageComponent storageOwner)
607 {
608 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(item.FindComponent(SCR_GadgetComponent));
609 if (!gadgetComp)
610 return;
611
613 if (!invComp)
614 return;
615
616 EGadgetType type = gadgetComp.GetType();
617
618 int gadgetArrayID = m_aGadgetArrayMap.Get(gadgetComp.GetType());
619 if (gadgetArrayID == -1)
620 return;
621
622 int gadgetPos = m_aInventoryGadgetTypes[gadgetArrayID].Find(gadgetComp);
623 if (gadgetPos != -1)
624 m_aInventoryGadgetTypes[gadgetArrayID].Remove(gadgetPos);
625
626 m_OnGadgetRemoved.Invoke(gadgetComp);
627
628 if (m_VONController && (type == EGadgetType.RADIO || type == EGadgetType.RADIO_BACKPACK)) // remove entries from VONController
629 {
630 array<ref SCR_VONEntry> entries = {};
631 m_VONController.GetVONEntries(entries);
632
633 for (int i = entries.Count() - 1; i >= 0; --i)
634 {
635 SCR_VONEntryRadio entry = SCR_VONEntryRadio.Cast(entries[i]);
636 if (entry && entry.GetGadget() == gadgetComp)
637 m_VONController.RemoveEntry(entries[i]); // multiple entries per gadget possible
638 }
639 }
640
641 if (item && item == m_HeldGadget)
642 UpdateHeldGadget(null);
643 }
644
645 //------------------------------------------------------------------------------------------------
650 void OnPlayerDeath(SCR_CharacterControllerComponent charController, IEntity instigatorEntity, notnull Instigator instigator)
651 {
652 if (!charController || charController != m_Controller)
653 return;
654
656 m_pInvokersState.Clear(GetOwner());
660 }
661
662 //------------------------------------------------------------------------------------------------
666 void OnControlledByPlayer(IEntity owner, bool controlled)
667 {
668 if (System.IsConsoleApp()) // hotfix for this being called on DS when other players control their characters
669 return;
670
671 if (controlled && owner != SCR_PlayerController.GetLocalControlledEntity()) // same as hotfix above but for hosted server, if we get controlled=true for entity which isnt ours, discard
672 controlled = false;
673
674 if (!controlled)
675 {
676 m_pInvokersState.CleanupLocalInvokers(GetOwner());
680 }
681 else if (owner)
682 {
683 m_pInvokersState.InitControlledInvokers(owner, m_Controller);
687 }
688 }
689
690 //------------------------------------------------------------------------------------------------
695 void OnGadgetStateChanged(IEntity gadget, bool isInHand, bool isOnGround)
696 {
697 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(gadget.FindComponent(SCR_GadgetComponent));
698 if (!gadgetComp)
699 return;
700
701 if (isInHand)
702 {
703 UpdateHeldGadget(gadget);
704 gadgetComp.OnModeChanged(EGadgetMode.IN_HAND, GetOwner());
705 }
706 else
707 {
708 UpdateHeldGadget(null);
709
710 if (isOnGround) // this means it has been moved directly to ground from hand
711 {
712 gadgetComp.OnModeChanged(EGadgetMode.ON_GROUND, GetOwner());
713 return;
714 }
715
716 // Check whether this gadget is slotted in a parent's equipment storage in order to set correct mode
717 IEntity parent = gadget.GetParent();
718 if (parent)
719 {
721 if (item)
722 {
723 EquipmentStorageSlot storageSlot = EquipmentStorageSlot.Cast(item.GetParentSlot());
724 if (storageSlot && storageSlot.GetOwner() == parent)
725 {
726 gadgetComp.OnModeChanged(EGadgetMode.IN_SLOT, GetOwner());
727 return;
728 }
729 }
730 }
731
732 gadgetComp.OnModeChanged(EGadgetMode.IN_STORAGE, GetOwner());
733 }
734 }
735
736 //------------------------------------------------------------------------------------------------
740 void OnGadgetFocusStateChanged(IEntity gadget, bool isFocused)
741 {
742 SCR_GadgetComponent gadgetComponent;
743 if (gadget)
744 {
745 gadgetComponent = m_HeldGadgetComponent;
746 }
747 else
748 {
749 // when gadget is switched, this gets called after gadget state change with null TODO preferably this shouldnt happen :(
750 gadgetComponent = m_LastHeldGadgetComponent;
751 isFocused = false;
752 }
753
754 m_bIsGadgetADS = isFocused;
755
756 // TODO hotfix against incorrect toggle set when spamming input, will be solved when map has unfocused & focused mode
757 if (!gadgetComponent
758 || (!isFocused && gadgetComponent.GetType() == EGadgetType.MAP && gadgetComponent.GetMode() == EGadgetMode.IN_HAND))
759 return;
760
761 gadgetComponent.ToggleFocused(isFocused);
762 }
763
764 //------------------------------------------------------------------------------------------------
767 {
769 }
770
771 //------------------------------------------------------------------------------------------------
772 // INPUTS & INIT
773 //------------------------------------------------------------------------------------------------
774
775 //------------------------------------------------------------------------------------------------
779 protected void OnGadgetInput(float value, EActionTrigger reason)
780 {
781 EGadgetType input = GetGadgetInputAction();
782 if (input == 0)
783 return;
784
785 // Search quickslots first, then inventory
786 IEntity gadget = GetQuickslotGadgetByType(input);
787 if (!gadget)
788 gadget = GetGadgetByType(input);
789
790 if (!gadget)
791 return;
792
793 HandleInput(gadget, value);
794 }
795
796 //------------------------------------------------------------------------------------------------
800 protected void ActionFlashlightToggle(float value, EActionTrigger reason)
801 {
802 // Search quickslots first, then inventory
803 IEntity flashlight = GetQuickslotGadgetByType(EGadgetType.FLASHLIGHT);
804 if (!flashlight)
805 flashlight = GetGadgetByType(EGadgetType.FLASHLIGHT);
806
807 if (!flashlight)
808 return;
809
810 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(flashlight.FindComponent(SCR_GadgetComponent));
811 if (gadgetComp)
812 gadgetComp.ActivateAction();
813 }
814
815 //------------------------------------------------------------------------------------------------
817 protected void OnPauseMenu()
818 {
819 if (SCR_MapGadgetComponent.Cast(m_HeldGadgetComponent))
820 SetGadgetMode(m_HeldGadget, EGadgetMode.IN_STORAGE); // TODO update state transition
821 }
822
823 //------------------------------------------------------------------------------------------------
825 protected void OnGadgetADS()
826 {
828 }
829
830 //------------------------------------------------------------------------------------------------
834 protected void OnGadgetADSHold(float value, EActionTrigger reason)
835 {
837 }
838
839 //------------------------------------------------------------------------------------------------
842 void SetGadgetADS(bool gadgetADS)
843 {
844 if (!m_Controller)
845 return;
846
847 // Cancel character and turret ADS
848 if (gadgetADS)
850
851 if (m_HeldGadgetComponent && m_HeldGadgetComponent.CanBeRaised())
852 {
853 m_Controller.SetGadgetRaisedModeWanted(gadgetADS);
854 }
855 else if (m_HiddenGadgetComponent && m_HiddenGadgetComponent.CanBeRaised())
856 {
857 if (gadgetADS)
858 m_Controller.RecoverHiddenGadget(false, false);
859
860 m_Controller.SetGadgetRaisedModeWanted(gadgetADS);
861 }
862 }
863
864 //------------------------------------------------------------------------------------------------
867 {
868 if (!m_Controller)
869 return;
870
871 m_Controller.SetWeaponADSInput(false);
872
873 ChimeraCharacter character = m_Controller.GetCharacter();
874 if (!character)
875 return;
876
877 CompartmentAccessComponent access = character.GetCompartmentAccessComponent();
878 if (!access || !access.IsInCompartment())
879 return;
880
881 BaseCompartmentSlot compartment = access.GetCompartment();
882 if (!compartment)
883 return;
884
885 TurretControllerComponent turretController = TurretControllerComponent.Cast(compartment.GetController());
886 if (!turretController)
887 return;
888
889 turretController.SetWeaponADSInput(false);
890 }
891
892 //------------------------------------------------------------------------------------------------
895 protected void RegisterInitialGadgets(IEntity character)
896 {
897 array<IEntity> foundItems = {};
898 array<typename> componentsQuery = {SCR_GadgetComponent};
899
900 m_InventoryStorageMgr = SCR_InventoryStorageManagerComponent.Cast(m_Controller.GetInventoryStorageManager());
902 m_InventoryStorageMgr.FindItemsWithComponents(foundItems, componentsQuery, EStoragePurpose.PURPOSE_ANY);
903
904 int count = foundItems.Count();
905 for (int i = 0; i < count; i++)
906 {
907 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(foundItems[i].FindComponent(SCR_GadgetComponent));
908 int gadgetArrayID = m_aGadgetArrayMap.Get(gadgetComp.GetType());
909 if (gadgetArrayID == -1)
910 continue;
911
912 m_aInventoryGadgetTypes[gadgetArrayID].Insert(gadgetComp);
913
914 if (gadgetComp.GetMode() != EGadgetMode.ON_GROUND) // initial gadget for client can/will already have set mode members by replication, set the entire mode process properly here
915 {
916 SetGadgetMode(foundItems[i], gadgetComp.GetMode());
917 continue;
918 }
919
920 // initial gadgets for host will likely be added to storage before manager starts catching OnAdded events and will default to ground
921 InventoryItemComponent invItemComp = InventoryItemComponent.Cast(foundItems[i].FindComponent(InventoryItemComponent));
922 if (invItemComp)
923 {
924 EquipmentStorageSlot storageSlot = EquipmentStorageSlot.Cast(invItemComp.GetParentSlot()); // Check whether the gadget is in equipment slot (OnAddedToSlot will happen before this)
925 if (storageSlot || gadgetComp.GetType() == EGadgetType.RADIO_BACKPACK) // backpack slot is not EquipmentStorageSlot but we consider it as such
926 {
927 SetGadgetMode(foundItems[i], EGadgetMode.IN_SLOT);
928 continue;
929 }
930 }
931
932 SetGadgetMode(foundItems[i], EGadgetMode.IN_STORAGE);
933 }
934
935 s_OnGadgetInitDone.Invoke(character, this);
936 }
937
938 //------------------------------------------------------------------------------------------------
940 protected void RegisterVONEntries()
941 {
943 return;
944
945 m_VONController = SCR_VONController.Cast(GetGame().GetPlayerController().FindComponent(SCR_VONController));
946 if (!m_VONController)
947 return;
948
949 array<SCR_GadgetComponent> radiosArray = {};
950 radiosArray.Copy(GetGadgetsByType(EGadgetType.RADIO)); // squad radios
951 radiosArray.InsertAll(GetGadgetsByType(EGadgetType.RADIO_BACKPACK)); // backpack radio
952
953 SCR_RadioComponent radioGadget;
954 BaseRadioComponent radioComp;
955 foreach (SCR_GadgetComponent radio : radiosArray)
956 {
957 radioGadget = SCR_RadioComponent.Cast(radio);
958 if (!radioGadget)
959 continue;
960
961 radioComp = radioGadget.GetRadioComponent();
962 if (!radioComp)
963 continue;
964
965 int count = radioComp.TransceiversCount();
966 for (int i = 0; i < count; ++i) // Get all individual transceivers (AKA channels) from the radio
967 {
968 SCR_VONEntryRadio radioEntry = new SCR_VONEntryRadio();
969 radioEntry.SetRadioEntry(radioComp.GetTransceiver(i), i + 1, radio);
970
971 m_VONController.AddEntry(radioEntry);
972 }
973 }
974 }
975
976 //------------------------------------------------------------------------------------------------
977 protected void UnregisterVONEntries()
978 {
979 if (!m_VONController)
980 return;
981
982 array<SCR_GadgetComponent> radiosArray = {};
983 radiosArray.Copy(GetGadgetsByType(EGadgetType.RADIO)); // squad radios
984 radiosArray.InsertAll(GetGadgetsByType(EGadgetType.RADIO_BACKPACK)); // backpack radio
985
986 array<ref SCR_VONEntry> entries = {};
987 m_VONController.GetVONEntries(entries);
988
989 foreach (SCR_GadgetComponent radio : radiosArray)
990 {
991 for (int i = entries.Count() - 1; i >= 0; --i)
992 {
993 SCR_VONEntryRadio entry = SCR_VONEntryRadio.Cast(entries[i]);
994 if (entry && entry.GetGadget() == radio)
995 m_VONController.RemoveEntry(entries[i]); // multiple entries per gadget possible
996 }
997 }
998 }
999
1000 //------------------------------------------------------------------------------------------------
1002 protected void RegisterInputs()
1003 {
1004 m_InputManager = GetGame().GetInputManager();
1005 if (!m_InputManager)
1006 return;
1007
1008 // Gadgets
1009 m_InputManager.AddActionListener("GadgetMap", EActionTrigger.DOWN, OnGadgetInput);
1010 m_InputManager.AddActionListener("MapEscape", EActionTrigger.DOWN, OnPauseMenu);
1011 m_InputManager.AddActionListener("GadgetCompass", EActionTrigger.DOWN, OnGadgetInput);
1012 m_InputManager.AddActionListener("GadgetBinoculars", EActionTrigger.DOWN, OnGadgetInput);
1013 m_InputManager.AddActionListener("GadgetFlashlight", EActionTrigger.DOWN, OnGadgetInput);
1014 m_InputManager.AddActionListener("GadgetFlashlightToggle", EActionTrigger.DOWN, ActionFlashlightToggle);
1015 m_InputManager.AddActionListener("GadgetWatch", EActionTrigger.DOWN, OnGadgetInput);
1016 m_InputManager.AddActionListener("GadgetADS", EActionTrigger.DOWN, OnGadgetADS);
1017 m_InputManager.AddActionListener("GadgetADSHold", EActionTrigger.DOWN, OnGadgetADSHold);
1018 m_InputManager.AddActionListener("GadgetADSHold", EActionTrigger.UP, OnGadgetADSHold);
1019 m_InputManager.AddActionListener("GadgetCancel", EActionTrigger.DOWN, RemoveHeldGadget);
1020 m_InputManager.AddActionListener("GadgetActivate", EActionTrigger.DOWN, OnActivateHeldGadget);
1021 }
1022
1023 //------------------------------------------------------------------------------------------------
1025 protected void UnregisterInputs()
1026 {
1027 m_InputManager = GetGame().GetInputManager();
1028 if (!m_InputManager)
1029 return;
1030
1031 m_InputManager.RemoveActionListener("GadgetMap", EActionTrigger.DOWN, OnGadgetInput);
1032 m_InputManager.RemoveActionListener("MapEscape", EActionTrigger.DOWN, OnPauseMenu);
1033 m_InputManager.RemoveActionListener("GadgetCompass", EActionTrigger.DOWN, OnGadgetInput);
1034 m_InputManager.RemoveActionListener("GadgetBinoculars", EActionTrigger.DOWN, OnGadgetInput);
1035 m_InputManager.RemoveActionListener("GadgetFlashlight", EActionTrigger.DOWN, OnGadgetInput);
1036 m_InputManager.RemoveActionListener("GadgetFlashlightToggle", EActionTrigger.DOWN, ActionFlashlightToggle);
1037 m_InputManager.RemoveActionListener("GadgetWatch", EActionTrigger.DOWN, OnGadgetInput);
1038 m_InputManager.RemoveActionListener("GadgetADS", EActionTrigger.DOWN, OnGadgetADS);
1039 m_InputManager.RemoveActionListener("GadgetADSHold", EActionTrigger.DOWN, OnGadgetADSHold);
1040 m_InputManager.RemoveActionListener("GadgetADSHold", EActionTrigger.UP, OnGadgetADSHold);
1041 m_InputManager.RemoveActionListener("GadgetCancel", EActionTrigger.DOWN, RemoveHeldGadget);
1042 m_InputManager.RemoveActionListener("GadgetActivate", EActionTrigger.DOWN, OnActivateHeldGadget);
1043 }
1044
1045 //------------------------------------------------------------------------------------------------
1048 protected EGadgetType GetGadgetInputAction()
1049 {
1050 if (m_InputManager.GetActionTriggered("GadgetMap"))
1051 return EGadgetType.MAP;
1052
1053 if (m_InputManager.GetActionTriggered("GadgetCompass"))
1054 return EGadgetType.COMPASS;
1055
1056 if (m_InputManager.GetActionTriggered("GadgetBinoculars"))
1057 return EGadgetType.BINOCULARS;
1058
1059 if (m_InputManager.GetActionTriggered("GadgetFlashlight"))
1060 return EGadgetType.FLASHLIGHT;
1061
1062 if (m_InputManager.GetActionTriggered("GadgetWatch"))
1063 return EGadgetType.WRISTWATCH;
1064
1065 return 0;
1066 }
1067
1068 //------------------------------------------------------------------------------------------------
1071 protected void InitComponent(IEntity owner)
1072 {
1073 ChimeraCharacter character = ChimeraCharacter.Cast(owner);
1074 if (!character)
1075 return;
1076
1077 SCR_CharacterControllerComponent controller = SCR_CharacterControllerComponent.Cast(character.GetCharacterController());
1078 if (!controller)
1079 return;
1080
1081 m_Controller = controller;
1082
1083 m_pInvokersState.InitInvokers(owner, m_Controller); // default (all entities with gadget manager) invokers
1084
1086 m_pInvokersState.InitControlledInvokers(owner, m_Controller); // local (controlled entity) invokers, ignore owned non controlled characters
1087
1088 // Owner specific behavior
1089 if (m_pInvokersState.IsInit())
1090 {
1092
1093 if (m_pInvokersState.m_bIsControlledEnt)
1094 {
1097 }
1098 else
1099 DisconnectFromGadgetsManagerSystem(); // if not controlled entity, clear frame
1100 }
1101 }
1102
1103 //------------------------------------------------------------------------------------------------
1104 // RPC
1105 //------------------------------------------------------------------------------------------------
1106
1107 //------------------------------------------------------------------------------------------------
1111 void AskToggleGadget(SCR_GadgetComponent gadgetComp, bool state)
1112 {
1113 RplId id = Replication.FindItemId(gadgetComp);
1114
1115 if (id && id.IsValid())
1116 Rpc(RPC_AskToggleGadget, id, state);
1117 }
1118
1119 //------------------------------------------------------------------------------------------------
1123 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
1124 protected void RPC_AskToggleGadget(RplId id, bool state)
1125 {
1126 // TODO sanity check
1127
1128 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(Replication.FindItem(id));
1129 if (!gadgetComp)
1130 return;
1131
1132 gadgetComp.OnToggleActive(state);
1133 Rpc(RPC_DoToggleGadget, id, state);
1134 }
1135
1136 //------------------------------------------------------------------------------------------------
1140 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast, RplCondition.NoOwner)]
1141 protected void RPC_DoToggleGadget(RplId id, bool state)
1142 {
1143 // TODO sanity check
1144
1145 SCR_GadgetComponent gadgetComp = SCR_GadgetComponent.Cast(Replication.FindItem(id));
1146 if (!gadgetComp)
1147 return;
1148
1149 gadgetComp.OnToggleActive(state);
1150 }
1151
1152 //------------------------------------------------------------------------------------------------
1154 {
1155 IEntity owner = GetOwner();
1156 if (!owner || owner != SCR_PlayerController.GetLocalControlledEntity())
1157 return;
1158
1159 World world = owner.GetWorld();
1160 GadgetManagersSystem gadgetManagersSystem = GadgetManagersSystem.Cast(world.FindSystem(GadgetManagersSystem));
1161 if (!gadgetManagersSystem)
1162 return;
1163
1164 gadgetManagersSystem.Register(this);
1165 }
1166
1167 //------------------------------------------------------------------------------------------------
1169 {
1170 World world = GetOwner().GetWorld();
1171 GadgetManagersSystem gadgetManagersSystem = GadgetManagersSystem.Cast(world.FindSystem(GadgetManagersSystem));
1172 if (!gadgetManagersSystem)
1173 return;
1174
1175 gadgetManagersSystem.Unregister(this);
1176 }
1177
1178 //------------------------------------------------------------------------------------------------
1179 override void OnDelete(IEntity owner)
1180 {
1182
1183 super.OnDelete(owner);
1184 }
1185
1186 #ifndef DISABLE_GADGETS
1187 //------------------------------------------------------------------------------------------------
1190 void Update(float timeSlice)
1191 {
1192 if (!m_pInvokersState.IsInit())
1194
1195 // context
1197 {
1199 return;
1200 }
1201
1202 SCR_GadgetComponent gadgetComp;
1204 gadgetComp = m_HeldGadgetComponent;
1205 else
1206 gadgetComp = m_HiddenGadgetComponent;
1207
1208 // Limit weapon fire for short time after gadget is unequipped
1209 if (m_Controller)
1210 m_Controller.SetWeaponNoFireTime(gadgetComp.GetWeaponNoFireTime());
1211
1212 m_InputManager.ActivateContext("GadgetContext");
1213
1214 if ((gadgetComp.GetUseMask() & SCR_EUseContext.FROM_ACTION) != 0)
1215 m_InputManager.ActivateContext("GadgetContextToggleable");
1216
1217 if (gadgetComp.IsUsingADSControls())
1218 {
1219 // Cancel gadget ADS while actively driving vehicle
1220 SCR_ChimeraCharacter character = SCR_ChimeraCharacter.Cast(GetOwner());
1221 if (character && character.IsDriving(1))
1222 {
1223 if (m_bIsGadgetADS)
1224 SetGadgetADS(false);
1225 }
1226 else
1227 {
1228 m_InputManager.ActivateContext("GadgetContextRaisable");
1229 }
1230 }
1231
1232 if (gadgetComp.GetType() == EGadgetType.MAP)
1233 m_InputManager.ActivateContext("GadgetMapContext");
1234 }
1235
1236 //------------------------------------------------------------------------------------------------
1237 override void OnPostInit(IEntity owner)
1238 {
1239 SetEventMask(owner, EntityEvent.INIT);
1240 }
1241 #endif
1242
1243 protected override void EOnInit(IEntity owner)
1244 {
1245 // init arrays
1246 typename gadgetTypes = EGadgetType;
1247 int count = gadgetTypes.GetVariableCount();
1248 array<SCR_GadgetComponent> gadgets;
1249 for (int i = 0; i < count; i++)
1250 {
1251 gadgets = {};
1252 m_aInventoryGadgetTypes.Insert(gadgets);
1253 m_aGadgetArrayMap.Insert(Math.Pow(2, i), i); // EGadgetType flag + array ID
1254 }
1255
1257 }
1258}
ArmaReforgerScripted GetGame()
Definition game.c:1398
EDamageType type
SCR_EUseContext
void SCR_EditorManagerEntity(IEntitySource src, IEntity parent)
void SCR_GadgetInvokersInitState(notnull SCR_GadgetManagerComponent gadgetManager)
class SCR_GadgetInvokersInitState EntityEditorProps(category:"GameScripted/Gadgets", description:"Gadget manager", color:"0 0 255 255")
void SCR_QuickslotEntityContainer(IEntity entity)
CompartmentControllerComponent m_Controller
void Register(SCR_GadgetManagerComponent component)
void Unregister(SCR_GadgetManagerComponent component)
proto external Managed FindComponent(typename typeName)
proto external BaseWorld GetWorld()
proto external IEntity GetParent()
Input management system for user interactions.
Definition Math.c:13
Main replication API.
Definition Replication.c:14
Replication item identifier.
Definition RplId.c:14
OnPlayerDeathWithParamInvoker GetOnPlayerDeathWithParam()
array< ref SCR_QuickslotBaseContainer > GetQuickSlotItems()
Controls invoker resgistration for gadget manager.
void ActionFlashlightToggle(float value, EActionTrigger reason)
static ScriptInvoker GetOnGadgetInitDoneInvoker()
void RegisterVONEntries()
Register radio gadgets into the VON system as entries.
void OnActivateHeldGadget()
Activate held gadget.
void OnGadgetADS()
Input action callback.
void OnControlledByPlayer(IEntity owner, bool controlled)
ref SCR_GadgetInvokersInitState m_pInvokersState
void OnItemRemoved(IEntity item, BaseInventoryStorageComponent storageOwner)
static ref ScriptInvoker< IEntity, SCR_GadgetManagerComponent > s_OnGadgetInitDone
void RPC_DoToggleGadget(RplId id, bool state)
void OnPauseMenu()
Input action callback.
void SetGadgetMode(IEntity gadget, EGadgetMode targetMode, bool doFocus=false)
void AskToggleGadget(SCR_GadgetComponent gadgetComp, bool state)
IEntity GetGadgetByType(EGadgetType type)
override void OnPostInit(IEntity owner)
bool IsGadgetOwned(SCR_GadgetComponent gadgetComp)
void OnGadgetInput(float value, EActionTrigger reason)
void RegisterInitialGadgets(IEntity character)
array< SCR_GadgetComponent > GetGadgetsByType(EGadgetType type)
bool CanChangeGadgetMode(IEntity gadget, SCR_GadgetComponent gadgetComp, EGadgetMode targetMode)
void HandleInput(IEntity gadget, float inputVal)
void OnEditorOpened()
SCR_EditorManagerEntity event //TODO we shouldnt need this, probably needs to be dependent on camera ...
static SCR_GadgetManagerComponent GetGadgetManager(IEntity entity)
void RegisterInputs()
Register input actions.
void RemoveHeldGadget()
Remove gadget held in hand.
override void EOnInit(IEntity owner)
void OnGadgetFocusStateChanged(IEntity gadget, bool isFocused)
void RPC_AskToggleGadget(RplId id, bool state)
void UnregisterInputs()
Register input actions.
void OnPlayerDeath(SCR_CharacterControllerComponent charController, IEntity instigatorEntity, notnull Instigator instigator)
SCR_CharacterControllerComponent m_Controller
ref array< ref array< SCR_GadgetComponent > > m_aInventoryGadgetTypes
SCR_GadgetComponent GetHeldGadgetComponent()
void ClearToggleState()
Clear toggle state for cases where it needs to be done without waiting for animation.
static void SetGadgetModeStashed(SCR_GadgetComponent gadgetComp, EGadgetMode targetMode)
void OnGadgetStateChanged(IEntity gadget, bool isInHand, bool isOnGround)
override void OnDelete(IEntity owner)
void OnGadgetADSHold(float value, EActionTrigger reason)
void OnItemAdded(IEntity item, BaseInventoryStorageComponent storageOwner)
IEntity GetQuickslotGadgetByType(EGadgetType type)
static bool ValidController(IEntity owner)
void CancelADSInput()
Cancel weapon and turret ADS input state.
SCR_InventoryStorageManagerComponent m_InventoryStorageMgr
ref map< EGadgetType, int > m_aGadgetArrayMap
static IEntity GetLocalControlledEntity()
SCR_QuickslotBaseContainer is intended to be used for quickslots, to allow quickslotting of non-item ...
VONEntry class for radio entries.
SCR_GadgetComponent GetGadget()
Gadget component associated with this entry.
void SetRadioEntry(notnull BaseTransceiver transceiver, int number, SCR_GadgetComponent gadgetComp)
Definition World.c:16
Definition Types.c:486
IEntity GetOwner()
Owner entity of the fuel tank.
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
EntityEvent
Various entity events.
Definition EntityEvent.c:14
proto external PlayerController GetPlayerController()
EActionTrigger
EStoragePurpose
void RplRpc(RplChannel channel, RplRcver rcver, RplCondition condition=RplCondition.None, string customConditionName="")
Definition EnNetwork.c:95
RplCondition
Conditional replication rule. Fine grained selection of receivers.
RplRcver
Definition RplRcver.c:59
RplChannel
Communication channel. Reliable is guaranteed to be delivered. Unreliable not.
Definition RplChannel.c:14
proto external string ToString()
Plain C++ pointer, no weak pointers, no memory management.
proto native void Clear()
Remove all calls from list.
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134