Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_CharacterControllerComponent.c
Go to the documentation of this file.
1[ComponentEditorProps(category: "GameScripted/Character", description: "Scripted character controller", icon: HYBRID_COMPONENT_ICON)]
5
6//------------------------------------------------------------------------------------------------
7void OnPlayerDeathWithParam(SCR_CharacterControllerComponent characterController, IEntity killerEntity, notnull Instigator killer);
9typedef ScriptInvokerBase<OnPlayerDeathWithParam> OnPlayerDeathWithParamInvoker;
10
11//------------------------------------------------------------------------------------------------
12void OnControlledByPlayer(IEntity ownerEntity, bool controlled);
14typedef ScriptInvokerBase<OnControlledByPlayer> OnControlledByPlayerInvoker;
15
16//------------------------------------------------------------------------------------------------
18typedef ScriptInvokerBase<OnLifeStateChanged> OnLifeStateChangedInvoker;
19
20//------------------------------------------------------------------------------------------------
23typedef ScriptInvokerBase<OnItemUseBegan> OnItemUseBeganInvoker;
24
25//------------------------------------------------------------------------------------------------
26void OnItemUseEnded(IEntity item, bool successful, ItemUseParameters animParams);
28typedef ScriptInvokerBase<OnItemUseEnded> OnItemUseEndedInvoker;
29
30//------------------------------------------------------------------------------------------------
31void OnItemUseFinished(IEntity item, bool successful, ItemUseParameters animParams);
33typedef ScriptInvokerBase<OnItemUseFinished> OnItemUseFinishedInvoker;
34
35class SCR_CharacterControllerComponent : CharacterControllerComponent
36{
37 [Attribute(defvalue: "10", uiwidget: UIWidgets.EditBox, params:"1 inf 0.1", desc: "Maximum duration it takes for character to drown\n[s]")]
38 protected float m_fDrowningDuration;
39
40 [Attribute(defvalue: "4", uiwidget: UIWidgets.EditBox, params:"0 inf 0.1", desc: "Amount of raw damage needed for character to play an animated hitreaction")]
42
43 protected static ref array<EDamageType> s_aHitReactionDamageTypes = {
44 EDamageType.COLLISION,
45 EDamageType.MELEE,
46 EDamageType.KINETIC,
47 EDamageType.FRAGMENTATION,
48 EDamageType.EXPLOSIVE
49 };
50
51 // Private members
52 protected SCR_CharacterCameraHandlerComponent m_CameraHandler; // Set from the camera handler itself
54 protected bool m_bOverrideActions = true;
55 protected bool m_bInspectionFocus;
56 protected bool m_bCharacterIsDrowning;
57 protected float m_fDrowningTime;
60
62 protected ref array<ref SCR_ShellConfig> m_aSavedShellConfigs;
63
64 // Character event invokers
71
72 // Gadget event invokers
75
76 // Item event invokers
79 // called when all listeners reacted on ItemUseEnded invoker - may delete the item now thus listerners to ItemUseFinished may get first parameter null!
82
83 // Weapon raising/lowering event invokers
88
89 // Diagnostics, debugging
90 #ifdef ENABLE_DIAG
91 private static bool s_bDiagRegistered;
92 private static bool m_bEnableDebugUI;
93 private Widget m_wDebugRootWidget;
94 private ECharacterStance m_bDebugLastStance = ECharacterStance.STAND;
95 #endif
96
97 //------------------------------------------------------------------------------------------------
102 {
103 if (GetLifeState() != ECharacterLifeState.ALIVE)
104 return false;
105
106 if (IsUsingItem())
107 return false;
108
109 if (IsClimbing())
110 return false;
111
112 ChimeraCharacter character = GetCharacter();
113 if (!character || character.IsInVehicleADS())
114 return false;
115
116 // Disable in vehicle 3pp
117 if (character.IsInVehicle() && IsInThirdPersonView())
118 return false;
119
121 return false;
122
123 return true;
124 }
125
126 //------------------------------------------------------------------------------------------------
127 override void OnConsciousnessChanged(bool conscious)
128 {
129 if (GetLifeState() != ECharacterLifeState.INCAPACITATED)
130 return;
131
132 AIControlComponent aiControl = AIControlComponent.Cast(GetOwner().FindComponent(AIControlComponent));
133 if (!aiControl || !aiControl.IsAIActivated())
134 return;
135
136 IEntity currentWeapon;
137 BaseWeaponManagerComponent wpnMan = GetWeaponManagerComponent();
138 if (wpnMan && wpnMan.GetCurrentWeapon())
139 currentWeapon = wpnMan.GetCurrentWeapon().GetOwner();
140
141 if (currentWeapon)
142 {
143 bool dropGrenade = false;
144
145 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
146
147 EWeaponType wt = wpnMan.GetCurrentWeapon().GetWeaponType();
148 if (currentWeapon.FindComponent(GrenadeMoveComponent))
149 {
151
152 if ((triggerComp && triggerComp.WasTriggered()) || (handler && handler.IsThrowingAction()))
153 {
154 dropGrenade = true;
155 }
156 }
157
158 if (dropGrenade)
159 handler.DropLiveGrenadeFromHand(false);
160 else
161 TryEquipRightHandItem(null, EEquipItemType.EEquipTypeUnarmedContextual, true);
162 }
163 }
164
165 //------------------------------------------------------------------------------------------------
166 override bool CanJumpClimb()
167 {
168 SCR_ExtendedDamageManagerComponent damageMan = SCR_ExtendedDamageManagerComponent.Cast(GetCharacter().GetDamageManager());
169 if (!damageMan)
170 return true;
171
172 array<ref SCR_PersistentDamageEffect> effects = damageMan.GetAllPersistentEffectsOfType(SCR_SpecialCollisionDamageEffect, true);
173 foreach (SCR_PersistentDamageEffect effect : effects)
174 {
176 if (!collisionEffect.GetJumpingAndClimbingAllowed())
177 return false;
178 }
179
180 return true;
181 }
182
183 //------------------------------------------------------------------------------------------------
192
193 //------------------------------------------------------------------------------------------------
194 override void OnGadgetStateChanged(IEntity gadget, bool isInHand, bool isOnGround)
195 {
196 m_OnGadgetStateChangedInvoker.Invoke(gadget, isInHand, isOnGround);
197 }
198
199 //------------------------------------------------------------------------------------------------
200 override void OnGadgetFocusStateChanged(IEntity gadget, bool isFocused)
201 {
202 m_OnGadgetFocusStateChangedInvoker.Invoke(gadget, isFocused);
203 }
204
205 //------------------------------------------------------------------------------------------------
211
212 //------------------------------------------------------------------------------------------------
218
219 //------------------------------------------------------------------------------------------------
225
226 //------------------------------------------------------------------------------------------------
232
233 //------------------------------------------------------------------------------------------------
235 {
237 }
238
239 //------------------------------------------------------------------------------------------------
241 {
243 }
244
245 //------------------------------------------------------------------------------------------------
247 {
249 }
250
251 //------------------------------------------------------------------------------------------------
253 {
255 }
256
257 //------------------------------------------------------------------------------------------------
258 override void OnItemUseBegan(ItemUseParameters itemUseParams)
259 {
260 m_OnItemUseBeganInvoker.Invoke(itemUseParams.GetEntity(), itemUseParams);
261 }
262
263 //------------------------------------------------------------------------------------------------
264 override void OnItemUseEnded(ItemUseParameters itemUseParams, bool successful)
265 {
266 m_OnItemUseEndedInvoker.Invoke(itemUseParams.GetEntity(), successful, itemUseParams);
267 // now all interested in non-null item have listened, we can call Finished to delete the item
268 m_OnItemUseFinishedInvoker.Invoke(itemUseParams.GetEntity(), successful, itemUseParams);
269
270 IEntity gadget = GetItemInHandSlot();
271 if (!gadget)
272 return;
273
275 if (!characterInventory)
276 return;
277
278 characterInventory.UseItem(gadget);
279 }
280
281 //------------------------------------------------------------------------------------------------
282 protected override void OnAnimationEvent(AnimationEventID animEventType, AnimationEventID animUserString, int intParam, float timeFromStart, float timeToEnd)
283 {
285 m_OnAnimationEvent.Invoke(animEventType, animUserString, intParam, timeFromStart, timeToEnd, this);
286 }
287
288 //------------------------------------------------------------------------------------------------
289 // handling of melee events. Sends true if melee started, false, when melee ends
290 override void OnMeleeDamage(bool started)
291 {
292 m_MeleeComponent.SetMeleeAttackStarted(started);
293 }
294
295 //------------------------------------------------------------------------------------------------
296 // play hitreaction when taking momentary physical damage
297 protected override EHitReactionType ComputeHitReaction(float damageValue, EDamageType damageType)
298 {
299 if (damageValue < m_fAnimatedHitReactionThreshold)
300 return EHitReactionType.HIT_REACTION_NONE;
301
302 if (!s_aHitReactionDamageTypes.Contains(damageType))
303 return EHitReactionType.HIT_REACTION_NONE;
304
305 return EHitReactionType.HIT_REACTION_LIGHT;
306 }
307
308 //------------------------------------------------------------------------------------------------
314
315 //------------------------------------------------------------------------------------------------
321
322 //------------------------------------------------------------------------------------------------
323 override void OnDeath(IEntity instigatorEntity, notnull Instigator instigator)
324 {
325 m_OnPlayerDeath.Invoke();
326 m_OnPlayerDeathWithParam.Invoke(this, instigatorEntity, instigator);
327
329 if (pc && m_CameraHandler && m_CameraHandler.IsInThirdPerson())
330 pc.m_bRetain3PV = true;
331
332 IEntity character = GetCharacter();
333 auto garbageSystem = SCR_GarbageSystem.GetByEntityWorld(character);
334 if (garbageSystem)
335 garbageSystem.Insert(character);
336 }
337
338 //------------------------------------------------------------------------------------------------
339 override void OnLifeStateChanged(ECharacterLifeState previousLifeState, ECharacterLifeState newLifeState, bool isJIP)
340 {
341 m_OnLifeStateChanged.Invoke(previousLifeState, newLifeState, isJIP);
342
343 IEntity vehicle = CompartmentAccessComponent.GetVehicleIn(GetCharacter());
344 if (!vehicle)
345 return;
346
348 if (!vehicleFactionAff)
349 return;
350
351 vehicleFactionAff.UpdateOccupantsCount();
352 }
353
354 //------------------------------------------------------------------------------------------------
355 override bool ShouldGadgetBeDropped(IEntity gadget)
356 {
357 if (!gadget)
358 return false;
359
360 if (GetItemInHandSlot() != gadget)
361 return false;
362
363 SCR_InventoryStorageManagerComponent inventoryManager = SCR_InventoryStorageManagerComponent.Cast(GetOwner().FindComponent(SCR_InventoryStorageManagerComponent));
364 if (!inventoryManager)
365 return true;
366
367 BaseInventoryStorageComponent storage = inventoryManager.FindStorageForItem(gadget, EStoragePurpose.PURPOSE_DEPOSIT);
368 if (storage && inventoryManager.TryMoveItemToStorage(gadget, storage))
369 {
371 SCR_NotificationsComponent.SendLocal(ENotification.PLAYER_HAND_ITEM_PUT_IN_INVENTORY);
372
373 return false;
374 }
375
377 SCR_NotificationsComponent.SendLocal(ENotification.PLAYER_HAND_ITEM_DROPPED);
378
379 return true;
380 }
381
382 //------------------------------------------------------------------------------------------------
385 {
386 SCR_HandSlotStorageComponent handSlot = SCR_HandSlotStorageComponent.Cast(GetOwner().FindComponent(SCR_HandSlotStorageComponent));
387 if (!handSlot)
388 return null;
389
390 InventoryStorageSlot slot = handSlot.GetSlot(0);
391 if (!slot)
392 return null;
393
394 return slot.GetAttachedEntity();
395 }
396
397 //------------------------------------------------------------------------------------------------
400 void SetShellConfig(notnull SCR_ShellConfig config)
401 {
402 SCR_ShellConfig oldShellConfig = GetSavedShellConfig(config.GetPrefabData());
403 if (!oldShellConfig)
404 {
407
408 m_aSavedShellConfigs.Insert(config);
409 return;
410 }
411
412 oldShellConfig.SetSavedTime(config.GetSavedTime());
413 oldShellConfig.SetManualTimeUsage(config.IsUsingManualTime());
414 oldShellConfig.SetChargeRingConfigId(config.GetChargeRingConfigId());
415 }
416
417 //------------------------------------------------------------------------------------------------
419 {
421 return null;
422
423 foreach (SCR_ShellConfig savedConfig : m_aSavedShellConfigs)
424 {
425 if (!savedConfig)
426 continue;
427
428 if (shellPrefab != savedConfig.GetPrefabData())
429 continue;
430
431 return savedConfig;
432 }
433
434 return null;
435 }
436
437 //------------------------------------------------------------------------------------------------
441 void SyncShellChargeRingConfig(notnull SCR_MortarShellGadgetComponent shellComp, int configId)
442 {
443 RplComponent rplComp = SCR_EntityHelper.GetEntityRplComponent(shellComp.GetOwner());
444 if (!rplComp)
445 return;
446
447 Rpc(RPC_AskSetShellChargeRing, rplComp.Id(), configId);
448 }
449
450 //------------------------------------------------------------------------------------------------
451 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
452 protected void RPC_AskSetShellChargeRing(RplId replicationId, int configId)
453 {
454 if (!replicationId.IsValid())
455 return;
456
457 Rpc(RPC_DoSetShellChargeRing, replicationId, configId);
458 RPC_DoSetShellChargeRing(replicationId, configId);
459 }
460
461 //------------------------------------------------------------------------------------------------
462 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]
463 protected void RPC_DoSetShellChargeRing(RplId replicationId, int configId)
464 {
465 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(replicationId));
466 if (!rplComp)
467 return;
468
469 SCR_MortarShellGadgetComponent shellComp = SCR_MortarShellGadgetComponent.Cast(rplComp.GetEntity().FindComponent(SCR_MortarShellGadgetComponent));
470 if (!shellComp)
471 return;
472
473 shellComp.SetChargeRingConfig(configId, true, false);
474 }
475
476 //------------------------------------------------------------------------------------------------
480 void ReplicateHelicopterSightState(bool newState, RplId sightId)
481 {
482 if (!sightId.IsValid())
483 return;
484
485 Rpc(RPC_AskSyncSightState, newState, sightId);
486 }
487
488 //------------------------------------------------------------------------------------------------
489 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
490 protected void RPC_AskSyncSightState(bool newState, RplId sightId)
491 {
492 RplComponent rplComp = RplComponent.Cast(Replication.FindItem(sightId));
493 if (!rplComp)
494 return;
495
496 IEntity owner = rplComp.GetEntity();
497 if (!owner)
498 return;
499
500 SCR_HelicopterCollimatorSightComponent collimator = SCR_HelicopterCollimatorSightComponent.Cast(owner.FindComponent(SCR_HelicopterCollimatorSightComponent));
501 if (!collimator)
502 return;
503
504 collimator.OwnerSyncSightState(newState);
505 }
506
507 //------------------------------------------------------------------------------------------------
508 override bool GetCanMeleeAttack()
509 {
510 if (!m_MeleeComponent)
511 return false;
512
513 if (IsFalling())
514 return false;
515
516 if (GetStance() == ECharacterStance.PRONE)
517 return false;
518
519 // TODO: Gadget melee weapon properties in case we want to be able to have melee component, like a shovel?
520 if (IsGadgetInHands())
521 return false;
522
524 BaseWeaponManagerComponent weaponManager = GetWeaponManagerComponent();
525 if (weaponManager && !SCR_WeaponLib.CurrentWeaponHasComponent(weaponManager, SCR_MeleeWeaponProperties))
526 return false;
527
528 return true;
529 }
530
531 override bool GetCanEquipGadget(IEntity gadget)
532 {
533 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
534 if (handler.IsLoitering() || GetScrInputContext().m_iLoiteringType != -1)
535 return false;
536
537 return true;
538 }
539
540 //------------------------------------------------------------------------------------------------
543 override bool OnPerformAction()
544 {
545 return m_bOverrideActions;
546 }
547
548 //------------------------------------------------------------------------------------------------
549 override void OnInit(IEntity owner)
550 {
551 ChimeraCharacter character = GetCharacter();
552
553 if (!m_MeleeComponent)
554 m_MeleeComponent = SCR_MeleeComponent.Cast(character.FindComponent(SCR_MeleeComponent));
555 if (!m_CameraHandler)
556 m_CameraHandler = SCR_CharacterCameraHandlerComponent.Cast(character.FindComponent(SCR_CharacterCameraHandlerComponent));
557
559
561 }
562
563 //------------------------------------------------------------------------------------------------
564 protected override void OnApplyControls(IEntity owner, float timeSlice)
565 {
566 if (GetScrInputContext().m_iLoiteringType >= 0)
567 {
568 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
569 if (!handler.IsLoitering())
570 {
572 return;
573 }
574 }
575 }
576
577 //------------------------------------------------------------------------------------------------
578 override bool IsUsingBinoculars()
579 {
580 return SCR_PlayerController.s_pLocalPlayerController.GetIsBinocularsZoomed();
581 }
582
583 //------------------------------------------------------------------------------------------------
584 protected override void UpdateDrowning(float timeSlice, vector waterLevel)
585 {
586 if (GetLifeState() == ECharacterLifeState.DEAD)
587 return;
588
590
591 CompartmentAccessComponent accesComp = char.GetCompartmentAccessComponent();
592 bool isInWatertightCompartment = accesComp && accesComp.GetCompartment() && accesComp.GetCompartment().GetIsWaterTight();
593
594 const float drowningTimeStartFX = 4;
595 if (waterLevel[2] > 0 && !isInWatertightCompartment)
596 {
597 if (m_fDrowningTime < drowningTimeStartFX && (m_fDrowningTime + timeSlice) > drowningTimeStartFX)
598 {
599 m_OnPlayerDrowning.Invoke(m_fDrowningDuration, drowningTimeStartFX);
601 }
602
603 m_fDrowningTime += timeSlice;
604 }
605 else
606 {
607 if (m_fDrowningTime != 0)
608 {
609 m_OnPlayerStopDrowning.Invoke();
611 }
612
613 m_fDrowningTime = 0;
614 return;
615 }
616
618 if (!damageMan)
619 return;
620
622 {
623 HitZone targetHitZone;
624 if (IsUnconscious())
625 targetHitZone = damageMan.GetHeadHitZone();
626 else
627 targetHitZone = damageMan.GetResilienceHitZone();
628
629 if (!targetHitZone)
630 return;
631
632 vector hitPosDirNorm[3];
633 SCR_DamageContext context = new SCR_DamageContext(EDamageType.TRUE, 1000, hitPosDirNorm, char, targetHitZone, null, null, -1, -1);
634 context.damageEffect = new SCR_DrowningDamageEffect();
635 damageMan.HandleDamage(context);
636 }
637 }
638
639 //------------------------------------------------------------------------------------------------
642 {
643 return m_fDrowningTime;
644 }
645
646 //------------------------------------------------------------------------------------------------
649 {
651 }
652
653 //------------------------------------------------------------------------------------------------
655 {
656 return IsAligningBeforeLoiter();
657 }
658
659 //------------------------------------------------------------------------------------------------
662 {
663 return GetScrInputContext().m_iLoiteringType != -1 && GetScrInputContext().m_bLoiteringShouldAlignCharacter && GetAnimationComponent().GetHeadingComponent().IsAligning();
664 }
665
666 //------------------------------------------------------------------------------------------------
667 // why the SCR_ prefix?
669 {
670 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
671 if (!handler)
672 return false;
673
674 if (GetScrInputContext().m_iLoiteringType > 0)
675 {
676 bool isAligningBeforeLoiter = IsAligningBeforeLoiter();
677 bool isHolsteringBeforeLoiter = GetScrInputContext().m_bLoiteringShouldHolsterWeapon && IsChangingItem();
678
679 if (isAligningBeforeLoiter || isHolsteringBeforeLoiter)
680 return true;
681 }
682
683 return handler.IsLoitering();
684 }
685
686 //------------------------------------------------------------------------------------------------
688 {
689 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
690 if (!handler)
691 return;
692
693 if (handler.IsLoitering())
694 {
695 if (m_pScrInputContext.m_bLoiteringDisablePlayerInput)
696 return;
697
698 StopLoitering(false);
699 }
700
702 {
703 CharacterHeadingAnimComponent headingComponent = GetAnimationComponent().GetHeadingComponent();
704 if (headingComponent)
705 {
706 headingComponent.ResetAligning();
707 GetScrInputContext().m_iLoiteringType = -1;
708 }
709 }
710 }
711
712 //------------------------------------------------------------------------------------------------
713 // #ifdef ENABLE_DIAG
714 //------------------------------------------------------------------------------------------------
715 #ifdef ENABLE_DIAG
716 //------------------------------------------------------------------------------------------------
717 override void OnDiag(IEntity owner, float timeslice)
718 {
719 ChimeraCharacter character = GetCharacter();
720 if (IsDead())
721 return;
722
723 if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_NOBANKING))
724 SetBanking(0);
725
726 bool diagTransform = DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_TRANSFORMATION);
727 bool bIsLocalCharacter = SCR_PlayerController.GetLocalControlledEntity() == character;
728
729 // Character Transformation Diag
730 if (bIsLocalCharacter && diagTransform)
731 {
732 DbgUI.Begin("Character Transformation");
733 const string CHAR_POS = "X:\t%1\nY:\t%2\nZ:\t%3";
734 const string CHAR_ROT = "PITCH:\t%1\nYAW:\t%2\nROLL:\t%3";
735 const string CHAR_SCALE = "%1";
736 const string CHAR_AIM = "X:\t%1\nY:\t%2\nZ:\t%3";
737 vector pos = character.GetOrigin();
738 vector rot = character.GetYawPitchRoll();
739 float scale = character.GetScale();
740 vector aimRot = GetInputContext().GetAimingAngles();
741 string strPosition = string.Format(CHAR_POS, pos[0].ToString(), pos[1].ToString(), pos[2].ToString());
742 string strRotation = string.Format(CHAR_ROT, rot[1].ToString(), rot[0].ToString(), rot[2].ToString());
743 string strScale = string.Format(CHAR_SCALE, scale.ToString());
744 string strAiming = string.Format(CHAR_AIM, aimRot[0].ToString(), aimRot[1].ToString(), aimRot[2].ToString());
745 DbgUI.Text("POSITION:\n" + strPosition);
746 DbgUI.Text("ROTATION:\n" + strRotation);
747 DbgUI.Text("SCALE:" + strScale);
748 DbgUI.Text("AIMING ANGLES:\n" + strAiming);
749
750 if (DbgUI.Button("Print plaintext to console"))
751 Print("TransformInfo:\nPOSITION:\n" + strPosition + "\nROTATION:\n" + strRotation + "\nSCALE:" + strScale + "\nAIMING ANGLES:\n" + strAiming, LogLevel.NORMAL);
752
753 DbgUI.End();
754 }
755
756 // Character Controller diag (inputs...)
757 m_bEnableDebugUI = bIsLocalCharacter && DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_MENU);
758 if (m_bEnableDebugUI && !m_wDebugRootWidget) // Currently controlled player
759 CreateDebugUI();
760 else if (!m_bEnableDebugUI && m_wDebugRootWidget)
761 DeleteDebugUI();
762
763 if (m_bEnableDebugUI)
764 UpdateDebugUI();
765 }
766
767 //------------------------------------------------------------------------------------------------
768 private void ReloadDebugUI()
769 {
770 if (m_wDebugRootWidget)
771 DeleteDebugUI();
772
773 CreateDebugUI();
774 }
775
776 //------------------------------------------------------------------------------------------------
777 private void DeleteDebugUI()
778 {
779 m_wDebugRootWidget.RemoveFromHierarchy();
780 m_wDebugRootWidget = null;
781 }
782
783 //------------------------------------------------------------------------------------------------
784 private void UpdateInputCircles()
785 {
786 if (!m_wDebugRootWidget)
787 return;
788
789 CharacterAnimationComponent animComponent = GetAnimationComponent();
790 if (!animComponent)
791 return;
792
793 Widget wInput = m_wDebugRootWidget.FindAnyWidget("Input");
794 if (!wInput)
795 return;
796
797 WorkspaceWidget workspaceWidget = GetGame().GetWorkspace();
798
799 float topSpeed = animComponent.GetTopSpeed(-1, false);
800
801 TextWidget wMaxSpeed = TextWidget.Cast(wInput.FindAnyWidget("MaxSpeed"));
802 if (wMaxSpeed)
803 {
804 float speed = Math.Ceil(topSpeed * 10) * 0.1;
805 wMaxSpeed.SetText(speed.ToString() + "m/s");
806 }
807
808 float ringSize = FrameSlot.GetSizeX(wInput);
809 float degSizeDivider = topSpeed * ringSize;
810 if (degSizeDivider > 0)
811 for (int spd = 0; spd < 3; spd++)
812 {
813 int spdType;
814 if (spd == 0)
815 spdType = EMovementType.WALK;
816 else
817 if (spd == 1)
818 spdType = EMovementType.RUN;
819 else
820 if (spd == 2)
821 spdType = EMovementType.SPRINT;
822
823 int color;
824 if (spd == 0)
825 color = ARGB(255, 150, 255, 150);
826 else
827 if (spd == 1)
828 color = ARGB(255, 200, 200, 150);
829 else
830 if (spd == 2)
831 color = ARGB(255, 255, 150, 150);
832
833 for (int deg = 0; deg < 360; deg++)
834 {
835 vector velInput = GetMovementVelocity();
836 float inputForward = velInput[2];
837 float inputRight = velInput[0];
838
839 float degSize = animComponent.GetMaxSpeed(inputForward, inputRight, spdType) / degSizeDivider;
840 if (spdType == EMovementType.SPRINT && !IsSprinting())
841 degSize = 0;
842
843 float degOff = (ringSize - degSize) * 0.5;
844
845 string iRingname = "iRing_" + spd.ToString() + "_" + deg.ToString();
846
847 ImageWidget wImg = ImageWidget.Cast(wInput.FindAnyWidget(iRingname));
848 if (!wImg)
849 {
850 wImg = ImageWidget.Cast(workspaceWidget.CreateWidget(WidgetType.ImageWidgetTypeID, WidgetFlags.BLEND | WidgetFlags.VISIBLE | WidgetFlags.STRETCH | WidgetFlags.NOWRAP, Color.FromInt(color), spd + 2, wInput));
851 wImg.LoadImageTexture(0, "{90DF4F065D08EF4E}UI/Textures/HUD_obsolete/character/input_360ringslice.edds");
852 wImg.SetRotation(deg);
853 wImg.SetName(iRingname);
854 }
855
856 FrameSlot.SetAnchorMax(wImg, 0, 0);
857 FrameSlot.SetAnchorMin(wImg, 0, 0);
858 FrameSlot.SetSize(wImg, degSize, degSize);
859 FrameSlot.SetPos(wImg, degOff, degOff);
860 }
861 }
862 }
863
864 //------------------------------------------------------------------------------------------------
865 private void CreateDebugUI()
866 {
867 m_wDebugRootWidget = GetGame().GetWorkspace().CreateWidgets("{C70DA11469BBAF67}UI/layouts/Debug/HUD_Debug_Character.layout", null);
868 UpdateInputCircles();
869 }
870
871 //------------------------------------------------------------------------------------------------
872 private void UpdateDebugBoolWidget(string textWidgetName, bool isTrue, float time = 0)
873 {
874 TextWidget wTxt = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget(textWidgetName));
875 if (!wTxt)
876 return;
877
878 time = Math.Ceil(time * 10) * 0.1;
879 if (isTrue)
880 {
881 wTxt.SetColorInt(ARGB(255, 160, 210, 255));
882 if (time != 0)
883 wTxt.SetText("YES (" + time.ToString() + ")");
884 else
885 wTxt.SetText("YES");
886 }
887 else
888 {
889 wTxt.SetColorInt(ARGB(255, 255, 160, 160));
890 if (time != 0)
891 wTxt.SetText("NO (" + time.ToString() + ")");
892 else
893 wTxt.SetText("NO");
894 }
895 }
896
897 //------------------------------------------------------------------------------------------------
898 private void UpdateDebugUI()
899 {
900 ChimeraCharacter character = GetCharacter();
901
902 // Reload debug UI for stance change
903 if (m_bDebugLastStance != GetStance())
904 {
905 m_bDebugLastStance = GetStance();
906 UpdateInputCircles();
907 }
908
909 float topSpeed = 0;
910 CharacterAnimationComponent animComponent = GetAnimationComponent();
911 topSpeed = animComponent.GetTopSpeed(-1, false);
912
913 Widget wCenter = m_wDebugRootWidget.FindAnyWidget("Center");
914 Widget wCenter2 = m_wDebugRootWidget.FindAnyWidget("Center2");
915 Widget wCenter3 = m_wDebugRootWidget.FindAnyWidget("Center3");
916
917 vector movementInput = GetMovementInput();
918 if (movementInput != vector.Zero)
919 {
920 float inputLength = movementInput.Length();
921 if (inputLength > 1)
922 movementInput *= 1 / inputLength;
923 }
924
925 if (wCenter && wCenter2 && wCenter3 && topSpeed > 0)
926 {
927 float inputForward = movementInput[0];
928 float inputRight = movementInput[2];
929 float maxSpeed = animComponent.GetMaxSpeed(inputForward, inputRight, GetCurrentMovementPhase());
930 float moveScale = maxSpeed / topSpeed;
931 float x = movementInput[0] * moveScale * 0.5 + 0.5;
932 float y = -movementInput[2] * moveScale * 0.5 + 0.5;
933 FrameSlot.SetAnchorMin(wCenter, x, y);
934 FrameSlot.SetAnchorMax(wCenter, x, y);
935
936 vector moveLocal = animComponent.GetInertiaSpeed();
937 x = (moveLocal[0] / topSpeed) * 0.5 + 0.5;
938 y = (-moveLocal[2] / topSpeed) * 0.5 + 0.5;
939 FrameSlot.SetAnchorMin(wCenter2, x, y);
940 FrameSlot.SetAnchorMax(wCenter2, x, y);
941
942 moveLocal = character.VectorToLocal(GetVelocity());
943 x = (moveLocal[0] / topSpeed) * 0.5 + 0.5;
944 y = (-moveLocal[2] / topSpeed) * 0.5 + 0.5;
945 FrameSlot.SetAnchorMin(wCenter3, x, y);
946 FrameSlot.SetAnchorMax(wCenter3, x, y);
947 }
948
949 TextWidget wSpeed = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget("Speed"));
950 TextWidget wSpeed2 = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget("Speed2"));
951 if (wSpeed && wSpeed2)
952 {
953 float speed = Math.Ceil(animComponent.GetInertiaSpeed().Length() * 10) * 0.1;
954 wSpeed.SetText(speed.ToString() + "m/s");
955
956 speed = Math.Ceil(GetVelocity().Length() * 10) * 0.1;
957 wSpeed2.SetText(speed.ToString() + "m/s");
958 }
959
960 TextWidget wAdjustedSpeed = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget("AdjustedSpeed"));
961 if (wAdjustedSpeed)
962 wAdjustedSpeed.SetText(GetDynamicSpeed().ToString());
963
964 TextWidget wAdjustedStance = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget("AdjustedStance"));
965 if (wAdjustedStance)
966 wAdjustedStance.SetText(GetDynamicStance().ToString());
967
968 UpdateDebugBoolWidget("ToggleSprint", GetIsSprintingToggle());
969 UpdateDebugBoolWidget("IsInADS", IsWeaponADS());
970 UpdateDebugBoolWidget("IsWeaponHolstered", !IsWeaponRaised());
971 UpdateDebugBoolWidget("CanFireWeapon", GetCanFireWeapon());
972 UpdateDebugBoolWidget("CanThrow", GetCanThrow());
973 UpdateDebugBoolWidget("InFreeLook", IsFreeLookEnabled());
974
975 TextWidget wMovementAngle = TextWidget.Cast(m_wDebugRootWidget.FindAnyWidget("MovementAngle"));
976 CharacterCommandHandlerComponent handler = animComponent.GetCommandHandler();
977 if (!wMovementAngle || !handler)
978 return;
979
980 CharacterCommandMove moveCmd = handler.GetCommandMove();
981 if (moveCmd)
982 {
983 float currAngle = moveCmd.GetMovementSlopeAngle();
984 wMovementAngle.SetText(currAngle.ToString() + "deg");
985 }
986 }
987
988 //------------------------------------------------------------------------------------------------
989 // #endif ENABLE_DIAG
990 //------------------------------------------------------------------------------------------------
991 #endif
992
993 //------------------------------------------------------------------------------------------------
994 override void OnPrepareControls(IEntity owner, ActionManager am, float dt, bool player)
995 {
996 if (am.GetActionTriggered("JumpOut") && CanJumpOutVehicleScript())
997 {
998 ChimeraCharacter character = ChimeraCharacter.Cast(owner);
999 CompartmentAccessComponent compAccess = character.GetCompartmentAccessComponent();
1000
1001 BaseCompartmentSlot compartment = compAccess.GetCompartment();
1002 if (compartment)
1003 {
1004 CompartmentUserAction action = compartment.GetJumpOutAction();
1005 if (action && action.CanBePerformed(GetOwner()))
1006 {
1007 action.PerformAction(compartment.GetOwner(), GetOwner());
1008 return;
1009 }
1010
1011 // Add the following once the correct action exists
1012 //if (!action && compAccess.CanGetOutVehicle())
1013 //{
1014 // compAccess.GetOutVehicle(-1);
1015 //}
1016 }
1017 }
1018
1019 if (am.GetActionTriggered("GetOut") && CanGetOutVehicleScript())
1020 {
1021 ChimeraCharacter character = ChimeraCharacter.Cast(owner);
1022 CompartmentAccessComponent compAccess = character.GetCompartmentAccessComponent();
1023
1024 BaseCompartmentSlot compartment = compAccess.GetCompartment();
1025 if (compartment)
1026 {
1027 CompartmentUserAction action = compartment.GetGetOutAction();
1028 if (action && action.CanBePerformed(GetOwner()))
1029 {
1030 action.PerformAction(compartment.GetOwner(), GetOwner());
1031 return;
1032 }
1033
1034 if (!action && compAccess.CanGetOutVehicle())
1035 {
1036 compAccess.GetOutVehicle(EGetOutType.ANIMATED, -1, ECloseDoorAfterActions.INVALID, false);
1037 }
1038 }
1039 }
1040
1041 if (GetStance() == ECharacterStance.PRONE)
1042 {
1043 float value = am.GetActionValue("CharacterRoll");
1044 int rollValue = 0;
1045 if (value < -0.5)
1046 rollValue = 1;
1047 else if (value > 0.5)
1048 rollValue = 2;
1049
1050 // If one wants to use hold action - it needs too be allowed on CharacterControllerComponent at character prefab or by calling EnableHoldInputForRoll(true) during construction/initialization
1052 SetRoll(rollValue);
1053 else if (rollValue != 0)
1054 SetRoll(rollValue);
1055 }
1056
1057 if (player && GetAnimationComponent().IsWeaponADSTag())
1058 {
1059 SightsComponent sights = GetWeaponManagerComponent().GetCurrentSights();
1060 if (sights)
1061 {
1062 SCR_SightsZoomFOVInfo fovInfo = SCR_SightsZoomFOVInfo.Cast(sights.GetFOVInfo());
1063 if (fovInfo && fovInfo.GetStepsCount() > 1)
1064 am.ActivateContext("CharacterWeaponMagnificationContext");
1065 }
1066 }
1067 }
1068
1069 //------------------------------------------------------------------------------------------------
1070 // constructor
1075 {
1076 #ifdef ENABLE_DIAG
1077 if (System.IsCLIParam("CharacterDebugUI")) // If the startup parameter is set, enable the debug UI
1078 m_bEnableDebugUI = true;
1079
1080 if (!s_bDiagRegistered)
1081 {
1082 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_MENU, "", "Enable Debug UI", "Character");
1083 DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_CHARACTER_MENU, m_bEnableDebugUI);
1084 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_NOBANKING, "", "Disable Banking", "Character");
1085 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_TRANSFORMATION, "", "Enable transform info", "Character");
1086 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_RECOIL_CAMERASHAKE_DISABLE, "", "Disable recoil cam shake", "Character");
1087 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_ADDITIONAL_CAMERASHAKE_DISABLE, "", "Disable additional cam shake", "Character");
1088 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_CHARACTER_CAMERASHAKE_TEST_WINDOW, "", "Show shake diag", "Character");
1089 DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_WEAPONS_ALLOW_INSPECTION_LOOKAT, "", "Inspection LookAt", "Character");
1090 s_bDiagRegistered = true;
1091 }
1092 #endif
1093 }
1094
1095 //------------------------------------------------------------------------------------------------
1096 // destructor
1098 {
1099 #ifdef ENABLE_DIAG
1100 if (m_wDebugRootWidget)
1101 DeleteDebugUI();
1102 #endif
1103 }
1104
1105 //------------------------------------------------------------------------------------------------
1109 void SetNextSightsFOVInfo(int direction = 1, bool allowCycling = false)
1110 {
1111 if (direction == 0)
1112 return;
1113
1114 SightsFOVInfo fovInfo = GetSightsFOVInfo();
1115 if (!fovInfo)
1116 return;
1117
1118 SCR_BaseVariableSightsFOVInfo variableFovInfo = SCR_BaseVariableSightsFOVInfo.Cast(fovInfo);
1119 if (!variableFovInfo)
1120 return;
1121
1122 if (direction > 0)
1123 variableFovInfo.SetNext(allowCycling);
1124 else
1125 variableFovInfo.SetPrevious(allowCycling);
1126 }
1127
1128 //------------------------------------------------------------------------------------------------
1132 {
1133 // Check if we are in a turret and switch the turret's optics instead
1134 SCR_ChimeraCharacter character = SCR_ChimeraCharacter.Cast(GetOwner());
1135 CompartmentAccessComponent compartmentAccess = character.GetCompartmentAccessComponent();
1136 if (compartmentAccess)
1137 {
1138 BaseCompartmentSlot compartment = compartmentAccess.GetCompartment();
1139 if (compartment)
1140 {
1141 TurretControllerComponent turretController = TurretControllerComponent.Cast(compartment.GetController());
1142 if (!turretController)
1143 turretController = compartment.GetAttachedTurret();
1144 if (turretController)
1145 {
1146 TurretComponent turretComponent = turretController.GetTurretComponent();
1147 if (turretComponent)
1148 {
1149 if (direction > 0)
1150 turretComponent.SwitchNextSights();
1151 else
1152 turretComponent.SwitchPrevSights();
1153
1154 return;
1155 }
1156 }
1157 }
1158 }
1159
1160 BaseWeaponManagerComponent weaponManager = GetWeaponManagerComponent();
1161 if (!weaponManager)
1162 return;
1163
1164 BaseWeaponComponent weaponComponent = weaponManager.GetCurrentWeapon();
1165 if (!weaponComponent)
1166 return;
1167
1168 if (direction > 0)
1169 weaponComponent.SwitchNextSights();
1170 else
1171 weaponComponent.SwitchPrevSights();
1172
1174 m_CharacterSoundComponent.SoundEvent(SCR_SoundEvent.SOUND_CHAR_MOVEMENT_WEAPON_SIGHT_TOGGLE);
1175 }
1176
1177 //------------------------------------------------------------------------------------------------
1180 {
1181 BaseWeaponManagerComponent weaponManager = GetWeaponManagerComponent();
1182 if (!weaponManager)
1183 return null;
1184
1185 BaseWeaponComponent weaponComponent = weaponManager.GetCurrentWeapon();
1186 if (!weaponComponent)
1187 return null;
1188
1189 BaseSightsComponent sightsComponent = weaponComponent.GetSights();
1190 if (!sightsComponent)
1191 return null;
1192
1193 return sightsComponent.GetFOVInfo();
1194 }
1195
1196 //------------------------------------------------------------------------------------------------
1197 protected override void OnControlledByPlayer(IEntity owner, bool controlled)
1198 {
1199 // Do initialisation/deinitialisation of character that was given/lost control by plyer here
1200 if (controlled && owner == SCR_PlayerController.GetLocalControlledEntity())
1201 {
1202 GetGame().GetInputManager().AddActionListener("CharacterNextWeapon", EActionTrigger.DOWN, ActionNextWeapon);
1203 GetGame().GetInputManager().AddActionListener("CharacterUnequipItem", EActionTrigger.DOWN, ActionUnequipItem);
1204 GetGame().GetInputManager().AddActionListener("CharacterDropItem", EActionTrigger.DOWN, ActionDropItem);
1205 GetGame().GetInputManager().AddActionListener("CharacterWeaponLowReady", EActionTrigger.DOWN, ActionWeaponLowReady);
1206 GetGame().GetInputManager().AddActionListener("CharacterWeaponRaised", EActionTrigger.DOWN, ActionWeaponRaised);
1207 GetGame().GetInputManager().AddActionListener("CharacterWeaponBipod", EActionTrigger.DOWN, ActionWeaponBipod);
1208
1209 // TODO: This should be handled by camera handler itself
1210 if (m_CameraHandler)
1211 GetGame().GetInputManager().AddActionListener("SwitchCameraType", EActionTrigger.DOWN, m_CameraHandler.OnCameraSwitchPressed);
1212 }
1213 else
1214 {
1215 GetGame().GetInputManager().RemoveActionListener("CharacterNextWeapon", EActionTrigger.DOWN, ActionNextWeapon);
1216 GetGame().GetInputManager().RemoveActionListener("CharacterUnequipItem", EActionTrigger.DOWN, ActionUnequipItem);
1217 GetGame().GetInputManager().RemoveActionListener("CharacterDropItem", EActionTrigger.DOWN, ActionDropItem);
1218 GetGame().GetInputManager().RemoveActionListener("CharacterWeaponLowReady", EActionTrigger.DOWN, ActionWeaponLowReady);
1219 GetGame().GetInputManager().RemoveActionListener("CharacterWeaponRaised", EActionTrigger.DOWN, ActionWeaponRaised);
1220 GetGame().GetInputManager().RemoveActionListener("CharacterWeaponBipod", EActionTrigger.DOWN, ActionWeaponBipod);
1221
1222 // TODO: This should be handled by camera handler itself
1223 if (m_CameraHandler)
1224 GetGame().GetInputManager().RemoveActionListener("SwitchCameraType", EActionTrigger.DOWN, m_CameraHandler.OnCameraSwitchPressed);
1225 }
1226
1227 m_OnControlledByPlayer.Invoke(owner, controlled);
1228
1229 // diiferentiate the inventory setup for player and AI
1231 if (pCharInvComponent)
1232 pCharInvComponent.InitAsPlayer(owner, controlled);
1233 }
1234
1235 //------------------------------------------------------------------------------------------------
1239 void ActionNextWeapon(float value = 0.0, EActionTrigger trigger = 0)
1240 {
1241 CharacterInputContext inputContext = GetInputContext();
1242 if (inputContext && inputContext.IsThrowCanceled())
1243 {
1244 inputContext.SetThrow(false);
1245 return;
1246 }
1247
1248 SCR_InventoryStorageManagerComponent storageManager = SCR_InventoryStorageManagerComponent.Cast(GetInventoryStorageManager());
1249 if (!storageManager)
1250 return;
1251
1252 SCR_CharacterInventoryStorageComponent storage = storageManager.GetCharacterStorage();
1253 if (storage)
1254 storage.SelectNextWeapon();
1255 }
1256
1257 //------------------------------------------------------------------------------------------------
1261 void ActionUnequipItem(float value = 0.0, EActionTrigger trigger = 0)
1262 {
1263 SCR_InventoryStorageManagerComponent storageManager = SCR_InventoryStorageManagerComponent.Cast(GetInventoryStorageManager());
1264 if (!storageManager)
1265 return;
1266
1267 SCR_CharacterInventoryStorageComponent storage = storageManager.GetCharacterStorage();
1268 if (storage)
1269 storage.UnequipCurrentItem();
1270 }
1271
1272 //------------------------------------------------------------------------------------------------
1276 void ActionDropItem(float value = 0.0, EActionTrigger trigger = 0)
1277 {
1278 SCR_InventoryStorageManagerComponent storageManager = SCR_InventoryStorageManagerComponent.Cast(GetInventoryStorageManager());
1279 if (!storageManager)
1280 return;
1281
1282 SCR_CharacterInventoryStorageComponent storage = storageManager.GetCharacterStorage();
1283 if (storage)
1284 storage.DropCurrentItem();
1285 }
1286
1287 //------------------------------------------------------------------------------------------------
1291 void ActionWeaponLowReady(float value = 0.0, EActionTrigger trigger = 0)
1292 {
1293 if (GetIsWeaponDeployed())
1294 return;
1295
1297 return;
1298
1300 SetPartialLower(true);
1301 }
1302
1303 //------------------------------------------------------------------------------------------------
1307 void ActionWeaponRaised(float value = 0.0, EActionTrigger trigger = 0)
1308 {
1309 if (!IsWeaponRaised())
1310 SetWeaponRaised(true);
1311
1312 if (IsPartiallyLowered())
1313 SetPartialLower(false);
1314 }
1315
1316 //------------------------------------------------------------------------------------------------
1320 void ActionWeaponBipod(float value = 0.0, EActionTrigger trigger = 0)
1321 {
1322 BaseWeaponManagerComponent weaponManager = GetWeaponManagerComponent();
1323 if (!weaponManager)
1324 return;
1325
1326 BaseWeaponComponent weapon = weaponManager.GetCurrentWeapon();
1327 if (!weapon || !weapon.HasBipod())
1328 return;
1329
1332
1333 weapon.SetBipod(!weapon.GetBipod());
1334 }
1335
1336 //------------------------------------------------------------------------------------------------
1337 protected override void OnInspectionModeChanged(bool newState)
1338 {
1339 m_bInspectionFocus = newState;
1340 }
1341
1342 protected int m_iTargetContext;
1343
1344 //------------------------------------------------------------------------------------------------
1345 protected override float GetInspectTargetLookAt(out vector targetAngles)
1346 {
1347 #ifdef ENABLE_DIAG
1348 if (!DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_WEAPONS_ALLOW_INSPECTION_LOOKAT))
1349 return 0;
1350 #else
1351 return 0; // Disabled for now
1352 #endif
1353
1354 // Just for testing
1355 if (Debug.KeyState(KeyCode.KC_ADD))
1356 {
1358 Debug.ClearKey(KeyCode.KC_ADD);
1359 m_bInspectionFocus = true;
1360 }
1361
1362 if (Debug.KeyState(KeyCode.KC_SUBTRACT))
1363 {
1365 Debug.ClearKey(KeyCode.KC_SUBTRACT);
1366 m_bInspectionFocus = true;
1367 }
1368
1369 if (!m_bInspectionFocus)
1370 return 0;
1371
1372 vector aimChange = GetInputContext().GetAimChange();
1373 const float threshold = 0.001;
1374 if (Math.AbsFloat(aimChange[0]) > threshold || Math.AbsFloat(aimChange[1]) > threshold)
1375 {
1376 m_bInspectionFocus = false;
1377 return 0;
1378 } // not now
1379
1380 IEntity ent = GetInspectEntity();
1381 if (!ent)
1382 return 0;
1383
1384 SCR_InteractionHandlerComponent handler = SCR_InteractionHandlerComponent.Cast(GetGame().GetPlayerController().FindComponent(SCR_InteractionHandlerComponent));
1385 if (!handler)
1386 return 0;
1387
1388 ChimeraCharacter character = GetCharacter();
1389
1390 // Update target
1391 array<UserActionContext> contexts = {};
1392 vector tmp;
1393 array<IEntity> ents = handler.GetManualOverrideList(null, tmp);
1395 array<UserActionContext> buff;
1397 array<BaseUserAction> actions;
1398 foreach (IEntity e : ents)
1399 {
1400 ac = ActionsManagerComponent.Cast(e.FindComponent(ActionsManagerComponent));
1401 if (!ac)
1402 continue;
1403
1404 buff = {};
1405 int bc = ac.GetContextList(buff);
1406 for (int i = 0; i < bc; ++i)
1407 {
1408 ctx = buff[i];
1409 if (ctx.GetActionsCount() == 0)
1410 continue;
1411
1412 actions = {};
1413 int actionsCount = ctx.GetActionsList(actions);
1414 foreach (BaseUserAction action : actions)
1415 {
1416 if (action.CanBeShown(character))
1417 {
1418 contexts.Insert(ctx);
1419 break;
1420 }
1421 }
1422 }
1423 }
1424
1425 int nonEmptyCount = contexts.Count();
1426 m_iTargetContext = Math.Repeat(m_iTargetContext, nonEmptyCount);
1427
1428 if (nonEmptyCount == 0)
1429 return 0.0;
1430
1431 ctx = contexts[m_iTargetContext];
1432 vector contextPos = ctx.GetOrigin();
1433
1434 vector localAimDirection = GetHeadAimingComponent().GetAimingDirection();
1435 vector targetDirection = contextPos - character.EyePosition();
1436 vector localTargetDirection = character.VectorToLocal( targetDirection );
1437 localTargetDirection.Normalize();
1438
1439 float lookYaw = Math.Sin(localTargetDirection[0]) * Math.RAD2DEG;
1440 float lookPitch = Math.Sin(localTargetDirection[1]) * Math.RAD2DEG;
1441
1442 //Shape shape = Shape.CreateSphere(COLOR_RED, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER, contextPos, 0.01);
1443
1444 lookPitch -= GetAimingComponent().GetAimingDirection()[1];
1445 targetAngles = Vector(lookYaw, lookPitch, 0) * Math.DEG2RAD;
1446
1447 return 4.30 * Math.RAD2DEG ; // speed, approx deg/s
1448 }
1449
1450 //------------------------------------------------------------------------------------------------
1456
1461
1462 //------------------------------------------------------------------------------------------------
1472 void StartLoitering(IEntity loiterEntity, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4] = { "1 0 0", "0 1 0", "0 0 1", "0 0 0" }, bool disableInput = false,
1473 SCR_LoiterCustomAnimData customAnimData = SCR_LoiterCustomAnimData.Default)
1474 {
1475 if (loiteringType == ELoiteringType.NONE)
1476 {
1477 Print("SCR_CharacterControllerComponent::StartLoitering is called with loiteringType=0.", LogLevel.WARNING);
1478 return;
1479 }
1480
1481 ChimeraCharacter character = GetCharacter();
1482 RplComponent rplComp = character.GetRplComponent();
1483 if (rplComp && !rplComp.IsOwner())
1484 return;
1485
1486 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(character.GetAnimationComponent().GetCommandHandler());
1487 if (!scrCmdHandler)
1488 return;
1489
1490 if (!scrCmdHandler.GetCommandMove())
1491 return;
1492
1493 m_pScrInputContext.SetLoiteringEntity(loiterEntity);
1494 m_pScrInputContext.m_iLoiteringType = loiteringType;
1495 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon = holsterWeapon;
1496 m_pScrInputContext.m_bLoiteringShouldAlignCharacter = alignToPosition;
1497 m_pScrInputContext.m_bLoiteringDisablePlayerInput = disableInput;
1498 m_pScrInputContext.m_mLoiteringPosition = targetPosition;
1499 m_pScrInputContext.m_bLoiteringRootMotion = allowRootMotion;
1500 m_pScrInputContext.m_CustomAnimData = customAnimData;
1501
1502 if (IsGadgetInHands())
1504
1505 if (alignToPosition)
1506 AlignToPositionFromCurrentPosition(targetPosition);
1507
1509 }
1510
1511 //------------------------------------------------------------------------------------------------
1512 protected bool AlignToPositionFromCurrentPosition(vector targetPosition[4], float toleranceXZ = 0.01, float toleranceY = 0.01)
1513 {
1514 ChimeraCharacter character = GetCharacter();
1515 RplComponent rplComponent = character.GetRplComponent();
1516 if (rplComponent && !rplComponent.IsOwner())
1517 return false;
1518
1519 vector currentTransform[4];
1520 character.GetWorldTransform(currentTransform);
1521 CharacterHeadingAnimComponent headingComponent = GetAnimationComponent().GetHeadingComponent();
1522 if (headingComponent)
1523 headingComponent.AlignPosDirWS(currentTransform[3], currentTransform[2], targetPosition[3], targetPosition[2]);
1524
1525 return vector.DistanceSqXZ(currentTransform[3], targetPosition[3]) < (toleranceXZ * toleranceXZ)
1526 && Math.AbsFloat(currentTransform[3][2] - targetPosition[3][2]) < toleranceY;
1527 }
1528
1529 //------------------------------------------------------------------------------------------------
1530 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
1531 protected void Rpc_StartLoitering_S(RplId entityRplId, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4], SCR_LoiterCustomAnimData customAnimData)
1532 {
1533 m_pScrInputContext.SetLoiteringEntityId(entityRplId);
1534 m_pScrInputContext.m_iLoiteringType = loiteringType;
1535 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon = holsterWeapon;
1536 m_pScrInputContext.m_bLoiteringShouldAlignCharacter = alignToPosition;
1537 m_pScrInputContext.m_mLoiteringPosition = targetPosition;
1538 m_pScrInputContext.m_bLoiteringRootMotion = allowRootMotion;
1539 m_pScrInputContext.m_CustomAnimData = customAnimData;
1540
1541 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(GetCharacter().GetAnimationComponent().GetCommandHandler());
1542 scrCmdHandler.StartCommandLoitering(customAnimData);
1543
1545 entityRplId,
1546 m_pScrInputContext.m_iLoiteringType,
1547 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon,
1548 m_pScrInputContext.m_bLoiteringRootMotion,
1549 m_pScrInputContext.m_bLoiteringShouldAlignCharacter,
1550 m_pScrInputContext.m_mLoiteringPosition,
1551 m_pScrInputContext.m_CustomAnimData);
1552 }
1553
1554 //------------------------------------------------------------------------------------------------
1555 [RplRpc(RplChannel.Reliable, RplRcver.Broadcast, RplCondition.NoOwner)]
1556 protected void Rpc_StartLoitering_BCNO(RplId entityRplId, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4], SCR_LoiterCustomAnimData customAnimData)
1557 {
1558 m_pScrInputContext.SetLoiteringEntityId(entityRplId);
1559 m_pScrInputContext.m_iLoiteringType = loiteringType;
1560 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon = holsterWeapon;
1561 m_pScrInputContext.m_bLoiteringShouldAlignCharacter = alignToPosition;
1562 m_pScrInputContext.m_mLoiteringPosition = targetPosition;
1563 m_pScrInputContext.m_bLoiteringRootMotion = allowRootMotion;
1564 m_pScrInputContext.m_CustomAnimData = customAnimData;
1565
1566 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(GetCharacter().GetAnimationComponent().GetCommandHandler());
1567 scrCmdHandler.StartCommandLoitering(customAnimData);
1568 }
1569
1570 //------------------------------------------------------------------------------------------------
1572 {
1573 if (IsChangingItem())
1574 return false;
1575
1576 if (GetScrInputContext().m_bLoiteringShouldHolsterWeapon && GetCurrentItemInHands() != null)
1577 {
1578 TryEquipRightHandItem(null, EEquipItemType.EEquipTypeUnarmedContextual);
1579 return false;
1580 }
1581
1582 if(m_pScrInputContext.m_bLoiteringShouldAlignCharacter)
1583 {
1584 CharacterHeadingAnimComponent headingComponent = GetAnimationComponent().GetHeadingComponent();
1585 if (headingComponent && headingComponent.IsAligning())
1586 {
1587 if (AlignToPositionFromCurrentPosition(GetScrInputContext().m_mLoiteringPosition, 0.02, 0.3)) // distance smaller than 2cm
1588 return false;
1589 }
1590 }
1591
1592 ChimeraCharacter character = GetCharacter();
1593 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(character.GetAnimationComponent().GetCommandHandler());
1594 scrCmdHandler.StartCommandLoitering(m_pScrInputContext.m_CustomAnimData);
1595
1596 RplComponent rplComponent = character.GetRplComponent();
1597
1598 if (rplComponent && rplComponent.IsProxy())
1600 m_pScrInputContext.m_loiterEntityRplId,
1601 m_pScrInputContext.m_iLoiteringType,
1602 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon,
1603 m_pScrInputContext.m_bLoiteringRootMotion,
1604 m_pScrInputContext.m_bLoiteringShouldAlignCharacter,
1605 m_pScrInputContext.m_mLoiteringPosition,
1606 m_pScrInputContext.m_CustomAnimData);
1607 else
1609 m_pScrInputContext.m_loiterEntityRplId,
1610 m_pScrInputContext.m_iLoiteringType,
1611 m_pScrInputContext.m_bLoiteringShouldHolsterWeapon,
1612 m_pScrInputContext.m_bLoiteringRootMotion,
1613 m_pScrInputContext.m_bLoiteringShouldAlignCharacter,
1614 m_pScrInputContext.m_mLoiteringPosition,
1615 m_pScrInputContext.m_CustomAnimData);
1616
1617 return true;
1618 }
1619
1620 //------------------------------------------------------------------------------------------------
1623 [RplRpc(RplChannel.Reliable, RplRcver.Server)]
1624 void RPC_StopLoitering_S(bool terminateFast)
1625 {
1626 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
1627 scrCmdHandler.StopLoitering(terminateFast);
1628 }
1629
1630 //------------------------------------------------------------------------------------------------
1633 //terminateFast should be true when we are going into alerted or combat state.
1634 void StopLoitering(bool terminateFast)
1635 {
1636 ChimeraCharacter character = GetCharacter();
1637 RplComponent rplComponent = character.GetRplComponent();
1638 if (rplComponent && !rplComponent.IsOwner())
1639 return;
1640
1641 SCR_CharacterCommandHandlerComponent scrCmdHandler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
1642 scrCmdHandler.StopLoitering(terminateFast);
1643
1644 if (rplComponent && rplComponent.IsProxy())
1645 Rpc(RPC_StopLoitering_S, terminateFast);
1646 }
1647
1648 //------------------------------------------------------------------------------------------------
1650 {
1651 SCR_CharacterCommandHandlerComponent handler = SCR_CharacterCommandHandlerComponent.Cast(GetAnimationComponent().GetCommandHandler());
1652 if (!handler)
1653 return false;
1654 else
1655 return handler.IsLoitering();
1656 }
1657
1658 //------------------------------------------------------------------------------------------------
1660 {
1661 return m_pScrInputContext && IsLoitering() && m_pScrInputContext.GetLoiterEntity() == entity;
1662 }
1663}
1664
1665enum ECharacterGestures // TODO: SCR_
1666{
1667 NONE = 0,
1674 SALUTE = 15
1675}
int AnimationEventID
vector scale
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition DebugMenuID.c:4
ENotification
ArmaReforgerScripted GetGame()
Definition game.c:1398
enum EAIGroupCombatMode ComponentEditorProps(category:"GameScripted/AI", description:"Component for utility AI system for groups")
ScriptInvokerBase< OnItemUseBegan > OnItemUseBeganInvoker
SCR_CharacterControllerComponent COMMAND_FOLLOW
ScriptInvokerBase< OnControlledByPlayer > OnControlledByPlayerInvoker
ScriptInvokerBase< OnPlayerDeathWithParam > OnPlayerDeathWithParamInvoker
SCR_CharacterControllerComponent COMMAND_GET_IN_THAT_VEHICLE
SCR_CharacterControllerComponent COMMAND_STOP
SCR_CharacterControllerComponent COMMAND_GET_IN
SCR_CharacterControllerComponent POINT_WITH_FINGER
ScriptInvokerBase< OnItemUseEnded > OnItemUseEndedInvoker
ScriptInvokerBase< OnLifeStateChanged > OnLifeStateChangedInvoker
ScriptInvokerBase< OnItemUseFinished > OnItemUseFinishedInvoker
SCR_CharacterControllerComponent COMMAND_MOVE
vector direction
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
ScriptInvokerBase< ScriptInvokerVoidMethod > ScriptInvokerVoid
ScriptInvokerBase< ScriptInvokerFloat2Method > ScriptInvokerFloat2
SCR_VehicleDamageManagerComponent GetDamageManager()
ActionManager holds information about states of registered Contexts and Actions.
proto external bool CanBePerformed(IEntity user)
Can this action be performed by the user?
Definition DbgUI.c:66
Definition Debug.c:13
Diagnostic and developer menu system.
Definition DiagMenu.c:18
proto external Managed FindComponent(typename typeName)
Definition Math.c:13
Main replication API.
Definition Replication.c:14
Replication item identifier.
Definition RplId.c:14
bool SetPrevious(bool allowUnderflow=true)
bool SetNext(bool allowOverflow=true)
void RPC_DoSetShellChargeRing(RplId replicationId, int configId)
static ref array< EDamageType > s_aHitReactionDamageTypes
ref ScriptInvokerFloat2< float > m_OnPlayerDrowning
void RPC_AskSetShellChargeRing(RplId replicationId, int configId)
SCR_ScriptedCharacterInputContext GetScrInputContext()
IEntity GetItemInHandSlot()
Return item currently stored in the hand slot.
void ActionDropItem(float value=0.0, EActionTrigger trigger=0)
override void OnDeath(IEntity instigatorEntity, notnull Instigator instigator)
void StartLoitering(IEntity loiterEntity, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4]={ "1 0 0", "0 1 0", "0 0 1", "0 0 0" }, bool disableInput=false, SCR_LoiterCustomAnimData customAnimData=SCR_LoiterCustomAnimData.Default)
void RPC_AskSyncSightState(bool newState, RplId sightId)
override void OnItemUseBegan(ItemUseParameters itemUseParams)
bool AlignToPositionFromCurrentPosition(vector targetPosition[4], float toleranceXZ=0.01, float toleranceY=0.01)
override void OnControlledByPlayer(IEntity owner, bool controlled)
override void OnLifeStateChanged(ECharacterLifeState previousLifeState, ECharacterLifeState newLifeState, bool isJIP)
override void OnApplyControls(IEntity owner, float timeSlice)
override void OnGadgetFocusStateChanged(IEntity gadget, bool isFocused)
void Rpc_StartLoitering_BCNO(RplId entityRplId, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4], SCR_LoiterCustomAnimData customAnimData)
override void OnAnimationEvent(AnimationEventID animEventType, AnimationEventID animUserString, int intParam, float timeFromStart, float timeToEnd)
void ActionWeaponRaised(float value=0.0, EActionTrigger trigger=0)
void SetNextSightsFOVInfo(int direction=1, bool allowCycling=false)
void Rpc_StartLoitering_S(RplId entityRplId, int loiteringType, bool holsterWeapon, bool allowRootMotion, bool alignToPosition, vector targetPosition[4], SCR_LoiterCustomAnimData customAnimData)
ref ScriptInvoker< IEntity, bool, bool > m_OnGadgetStateChangedInvoker
ref ScriptInvoker< IEntity, bool > m_OnGadgetFocusStateChangedInvoker
ref OnPlayerDeathWithParamInvoker m_OnPlayerDeathWithParam
SCR_ShellConfig GetSavedShellConfig(notnull EntityPrefabData shellPrefab)
void ReplicateHelicopterSightState(bool newState, RplId sightId)
override EHitReactionType ComputeHitReaction(float damageValue, EDamageType damageType)
ref ScriptInvoker< AnimationEventID, AnimationEventID, int, float, float, SCR_CharacterControllerComponent > m_OnAnimationEvent
ref OnControlledByPlayerInvoker m_OnControlledByPlayer
void SyncShellChargeRingConfig(notnull SCR_MortarShellGadgetComponent shellComp, int configId)
void SetScrInputContext(SCR_ScriptedCharacterInputContext ctx)
override bool ShouldGadgetBeDropped(IEntity gadget)
void ActionWeaponLowReady(float value=0.0, EActionTrigger trigger=0)
void SCR_CharacterControllerComponent(IEntityComponentSource src, IEntity ent, IEntity parent)
void ActionUnequipItem(float value=0.0, EActionTrigger trigger=0)
override void OnConsciousnessChanged(bool conscious)
override void OnPrepareControls(IEntity owner, ActionManager am, float dt, bool player)
ref array< ref SCR_ShellConfig > m_aSavedShellConfigs
Contains information about for which shell player saved some information for future use.
ref OnItemUseFinishedInvoker m_OnItemUseFinishedInvoker
ref SCR_ScriptedCharacterInputContext m_pScrInputContext
void SetShellConfig(notnull SCR_ShellConfig config)
void ActionNextWeapon(float value=0.0, EActionTrigger trigger=0)
OnPlayerDeathWithParamInvoker GetOnPlayerDeathWithParam()
void ActionWeaponBipod(float value=0.0, EActionTrigger trigger=0)
override void UpdateDrowning(float timeSlice, vector waterLevel)
SCR_CharacterCameraHandlerComponent m_CameraHandler
ref OnLifeStateChangedInvoker m_OnLifeStateChanged
override void OnItemUseEnded(ItemUseParameters itemUseParams, bool successful)
override void OnGadgetStateChanged(IEntity gadget, bool isInHand, bool isOnGround)
override float GetInspectTargetLookAt(out vector targetAngles)
bool UseItem(notnull IEntity item, ESlotFunction slotFunction=ESlotFunction.TYPE_GENERIC, SCR_EUseContext context=SCR_EUseContext.FROM_QUICKSLOT)
IEntity SelectNextWeapon(int maxSlot=-1)
Select next weapon.
void UnequipCurrentItem()
Unequip currently held item. Not allowed while switching to another item.
void DropCurrentItem()
Drop currently held item. Not allowed while switching to another item.
static RplComponent GetEntityRplComponent(notnull IEntity entity)
Script entry for garbage system modding.
static SCR_GarbageSystem GetByEntityWorld(IEntity entity)
static IEntity GetLocalControlledEntity()
void SetChargeRingConfigId(int configId)
void SetManualTimeUsage(bool shouldUse)
void SetSavedTime(float newTime)
proto external AIBaseAimingComponent GetAimingComponent()
IEntity GetOwner()
Owner entity of the fuel tank.
proto external bool IsDead()
HYBRID_COMPONENT_ICON
Default icon for all components written in script that don't inherit ScriptComponent.
EHitReactionType
ECharacterStance
EEquipItemType
EMovementType
ECharacterLifeState
proto external ECharacterLifeState GetLifeState()
proto external InventoryStorageManagerComponent GetInventoryStorageManager()
proto external void RemoveGadgetFromHand(bool skipAnimations=false)
Remove held gadget.
proto external bool IsChangingItem()
proto external bool IsUnconscious()
proto external bool ShouldHoldInputForRoll()
proto external int GetCurrentMovementPhase()
proto external void SetPartialLower(bool state)
Sets desired partial lower state, if allowed.
proto external bool IsFreeLookEnabled()
event bool CanJumpOutVehicleScript()
Override to handle whether character can eject from vehicle via JumpOut input action.
proto external ECharacterStance GetStance()
Returns the current stance of the character.
proto external bool GetIsWeaponDeployed()
proto external bool IsUsingItem()
proto external bool IsFalling()
proto external bool GetIsWeaponDeployedBipod()
proto external IEntity GetCurrentItemInHands()
proto external bool IsSprinting()
proto external bool IsClimbing()
proto external void SetBanking(float val)
proto external CharacterAnimationComponent GetAnimationComponent()
proto external IEntity GetInspectEntity()
proto external bool GetCanThrow()
proto external CharacterHeadAimingComponent GetHeadAimingComponent()
event bool CanGetOutVehicleScript()
Override to handle whether character can get out of vehicle via GetOut input action.
proto external void SetWeaponRaised(bool val)
Set the current weapon-raised state.
proto external bool GetIsSprintingToggle()
proto external vector GetMovementInput()
proto external CharacterInputContext GetInputContext()
void OnDiag(IEntity owner, float timeslice)
proto external bool IsGadgetInHands()
Returns true if there is a gadget in hands.
proto external bool GetCanFireWeapon()
proto external bool CanPartialLower()
Returns true if the character can partially lower (weapon).
proto external bool IsWeaponRaised()
proto external vector GetVelocity()
proto external float GetDynamicSpeed()
proto external bool IsPartiallyLowered()
Returns true if the character is partially lowered.
proto external bool TryEquipRightHandItem(IEntity item, EEquipItemType type, bool swap=false, BaseUserAction callbackAction=null)
proto external SCR_ChimeraCharacter GetCharacter()
Returns the current controlled character.
proto external vector GetMovementVelocity()
proto external BaseWeaponManagerComponent GetWeaponManagerComponent()
proto external bool IsInThirdPersonView()
proto external float GetDynamicStance()
proto external void SetRoll(int val)
2 - right, 1 - left
proto external bool IsWeaponADS()
proto external void StopDeployment()
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
SCR_FieldOfViewSettings Attribute
proto external PlayerController GetPlayerController()
EDamageType
Definition EDamageType.c:13
EActionTrigger
KeyCode
Definition KeyCode.c:13
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 vector Vector(float x, float y, float z)
WidgetFlags
Widget flags. See enf::Widget::SetFlags().
Definition WidgetFlags.c:14
ECloseDoorAfterActions
EGetOutType
Definition EGetOutType.c:13
EWeaponType
Definition EWeaponType.c:13
TypeID WidgetType
Definition EnWidgets.c:6
proto int ARGB(int a, int r, int g, int b)
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134