DayZ 1.30
DayZ Explorer by KGB
 
Загрузка...
Поиск...
Не найдено
Weapon_Base.c
См. документацию.
1
5{
6 int m_action;
8 void AbilityRecord (int a, int at) { m_action = a; m_actionType = at; }
9};
10
32
38class Weapon_Base extends Weapon
39{
41 const int SAMF_DEFAULT = WeaponWithAmmoFlags.CHAMBER | WeaponWithAmmoFlags.MAX_CAPACITY_MAG;
43 const int SAMF_RNG = WeaponWithAmmoFlags.CHAMBER_RNG | WeaponWithAmmoFlags.QUANTITY_RNG;
45 const float VALIDATE_DELAY = 5.0;
46
47 protected const float DEFAULT_DAMAGE_ON_SHOT = 0.05;
49 protected ref WeaponFSM m_fsm;
50 protected bool m_isJammed = false;
51 protected bool m_LiftWeapon = false;
52 protected bool m_BayonetAttached;
53 protected bool m_ButtstockAttached;
54 protected bool m_Charged = false;
55 protected bool m_WeaponOpen = false;
56 protected bool m_WasIronSight;
57 protected int m_BurstCount;
60 protected int m_weaponAnimState = -1;
62 protected int m_weaponHideBarrelIdx = -1; //index in simpleHiddenSelections cfg array
63 protected float m_DmgPerShot = 0; //default is set to zero, since C++ solution has been implemented. See 'damageBarrel' and 'barrelArmor' in configs.
64 protected float m_WeaponLength;
66 protected float m_ShoulderDistance;
67 protected float m_ObstructionDistance;
69 protected int m_LastLiftHit;
73 protected float m_ChanceToJamSync = 0;
77 private float m_coolDownTime = 0;
78
80 {
81 //m_DmgPerShot = ConfigGetFloat("damagePerShot");
82 m_BayonetAttached = false;
83 m_ButtstockAttached = false;
84 m_WasIronSight = true; // initially uses ironsights by default
87 m_BurstCount = 0;
89 if (g_Game.IsClient())
90 {
92 }
93
94 if ( ConfigIsExisting("simpleHiddenSelections") )
95 {
96 TStringArray selectionNames = new TStringArray;
97 ConfigGetTextArray("simpleHiddenSelections",selectionNames);
98 m_weaponHideBarrelIdx = selectionNames.Find("hide_barrel");
99 m_magazineSimpleSelectionIndex = selectionNames.Find("magazine");
100
101 int bulletIndex = selectionNames.Find("bullet");
102 if ( bulletIndex != -1 )
103 {
104 m_bulletSelectionIndex.Insert(bulletIndex);
105
106 for (int i = 2; i < 100; i++)
107 {
108 bulletIndex = selectionNames.Find(string.Format("bullet%1",i));
109 if (bulletIndex != -1)
110 {
111 m_bulletSelectionIndex.Insert(bulletIndex);
112 }
113 else
114 {
115 break;
116 }
117 }
118 }
119 }
120
126 if (g_Game.IsServer())
127 {
129 }
131 }
132
134
135 override void EEInit()
136 {
137 super.EEInit();
138
139 if (g_Game.IsServer())
140 {
141 g_Game.GetCallQueue( CALL_CATEGORY_GAMEPLAY ).Call( AssembleGun );
142 }
143 }
144
146 {
147 m_fsm.SetInitialState(initState);
148 SetCharged(!initState.IsDischarged());
149 SetWeaponOpen(initState.IsWeaponOpen());
150 SetGroundAnimFrameIndex(initState.m_animState);
151 }
152
154 {
155 return m_Charged;
156 }
157
158 void SetCharged(bool value)
159 {
160 m_Charged = value;
161 }
162
164 {
165 return m_WeaponOpen;
166 }
167
168 void SetWeaponOpen(bool value)
169 {
170 m_WeaponOpen = value;
171 }
172
173 override protected float GetWeightSpecialized(bool forceRecalc = false)
174 {
175 float baseWeight = GetInventoryAndCargoWeight(forceRecalc);
176 float ammoWeight;
177 float ammoDamage;
178 string bulletTypeName, ammoTypeName;
179
180 int muzzleCount = GetMuzzleCount();
181 #ifdef DEVELOPER
182 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
183 {
184 WeightDebugData data1 = WeightDebug.GetWeightDebug(this);
185 data1.SetCalcDetails("TWPN: " + EntityAIType.Cast(GetEntityType()).m_ConfigWeight+"(item weight) + " + baseWeight +"(contents weight)" );
186 }
187 #endif
188 for (int muzzleIndex = 0; muzzleIndex < muzzleCount; muzzleIndex++)
189 {
190 //chamber weight
191 if (!IsChamberEmpty(muzzleIndex))
192 {
193 ammoTypeName = GetChamberAmmoTypeName(muzzleIndex);
194 ammoWeight += g_Game.ConfigGetFloat(string.Format("CfgMagazines %1 weight", ammoTypeName));
195
196 #ifdef DEVELOPER
197 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
198 {
199 WeightDebugData data2 = WeightDebug.GetWeightDebug(this);
200 data2.AddCalcDetails( g_Game.ConfigGetFloat("CfgMagazines " + ammoTypeName + " weight").ToString() +"(chamber weight)");
201 }
202 #endif
203 }
204
205 //correctly calculates internal magazine weight based on the ammo type of each bullet
206 if (HasInternalMagazine(muzzleIndex))
207 {
208 #ifdef DEVELOPER
209 float debugInternalMagWeight;
210 #endif
211 int cartridgeCount = GetInternalMagazineCartridgeCount(muzzleIndex);
212 for (int cartridgeIndex = 0; cartridgeIndex < cartridgeCount; cartridgeIndex++)
213 {
214 GetInternalMagazineCartridgeInfo(muzzleIndex, cartridgeIndex, ammoDamage, bulletTypeName);
215 ammoWeight += Ammunition_Base.GetAmmoWeightByBulletType(bulletTypeName);
216 #ifdef DEVELOPER
217 debugInternalMagWeight += g_Game.ConfigGetFloat("CfgMagazines " + ammoTypeName + " weight");
218 #endif
219 }
220 #ifdef DEVELOPER
221
222 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
223 {
224 WeightDebugData data3 = WeightDebug.GetWeightDebug(this);
225 data3.AddCalcDetails(debugInternalMagWeight.ToString()+ "(internal mag weight)");
226 }
227 #endif
228 }
229
230 }
231 return ammoWeight + baseWeight + GetConfigWeightModified();
232 }
233
235
236 bool CanProcessAction(int action, int actionType)
237 {
238 return false; // @TODO
239 }
240
246 bool HasActionAbility(int action, int actionType)
247 {
248 int count = GetAbilityCount();
249 for (int i = 0; i < count; ++i)
250 {
251 AbilityRecord rec = GetAbility(i);
252 if (rec.m_action == action && rec.m_actionType == actionType)
253 return true;
254 }
255 return false;
256 }
257
260 int GetAbilityCount() { return m_abilities.Count(); }
265 AbilityRecord GetAbility(int index) { return m_abilities.Get(index); }
266
270 bool CanProcessWeaponEvents() { return m_fsm && m_fsm.IsRunning(); }
271
276 WeaponStateBase GetCurrentState() { return m_fsm.GetCurrentState(); }
277
282 {
283 return CanProcessWeaponEvents() && GetCurrentState().IsWaitingForActionFinish();
284 }
285
286 bool IsIdle()
287 {
288 return CanProcessWeaponEvents() && GetCurrentState().IsIdle();
289 }
290
296 {
298
299 // @NOTE: synchronous events not handled by fsm
300 if (e.GetEventID() == WeaponEventID.SET_NEXT_MUZZLE_MODE)
301 {
302 SetNextWeaponMode(GetCurrentMuzzle());
303 return true;
304 }
305
306 if (m_fsm.ProcessEvent(e) == ProcessEventResult.FSM_OK)
307 return true;
308
309 //if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("FSM refused to process event (no transition): src=" + GetCurrentState().ToString() + " event=" + e.ToString()); }
310 return false;
311 }
312
316 {
318
320 m_fsm.ProcessAbortEvent(e, aa);
321 return aa == ProcessEventResult.FSM_OK;
322 }
323
324 bool CanChamberBullet(int muzzleIndex, Magazine mag)
325 {
326 return CanChamberFromMag(muzzleIndex, mag) && (!IsChamberFull(muzzleIndex) || IsChamberFiredOut(muzzleIndex) || !IsInternalMagazineFull(muzzleIndex));
327 }
328
329 void SetWeaponAnimState(int state)
330 {
331 m_weaponAnimState = state;
332 SetGroundAnimFrameIndex(state);
333 }
335 {
336 if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[wpnfsm] " + Object.GetDebugName(this) + " resetting anim state: " + typename.EnumToString(PistolAnimState, m_weaponAnimState) + " --> " + typename.EnumToString(PistolAnimState, -1));
338 }
340
341 override void EEFired(int muzzleType, int mode, string ammoType)
342 {
343 auto player = PlayerBase.Cast(GetHierarchyRootPlayer());
344
345 if ( !g_Game.IsHeadlessOrDedicatedServer() )
346 {
347 ItemBase suppressor = GetAttachedSuppressor();
348
349 // Muzzle flash & overheating effects
350 ItemBase.PlayFireParticles(this, muzzleType, ammoType, this, suppressor, "CfgWeapons" );
351 IncreaseOverheating(this, ammoType, this, suppressor, "CfgWeapons");
352
353 if (suppressor)
354 {
355 ItemBase.PlayFireParticles(this, muzzleType, ammoType, suppressor, NULL, "CfgVehicles" );
356 suppressor.IncreaseOverheating(this, ammoType, this, suppressor, "CfgVehicles");
357 }
358 }
359 //JamCheck(muzzleType);
360
361 #ifdef DIAG_DEVELOPER
362 MiscGameplayFunctions.UnlimitedAmmoDebugCheck(this);
363 #endif
364 }
365
366 bool JamCheck(int muzzleIndex )
367 {
368 PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
369 if ( player )
370 {
371 float rnd = player.GetRandomGeneratorSyncManager().GetRandom01(RandomGeneratorSyncUsage.RGSJam);
372 //Print("Random Jam - " + rnd);
373 if (rnd < GetSyncChanceToJam())
374 return true;
375 }
376 return false;
377 }
378
379 void ShowBullet(int muzzleIndex)
380 {
381 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
382 {
383 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],1);
384 }
385 else
386 SelectionBulletShow();
387 }
388
389 void HideBullet(int muzzleIndex)
390 {
391 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
392 {
393 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],0);
394 }
395 else
396 SelectionBulletHide();
397 }
398
399 bool IsJammed() { return m_isJammed; }
400 bool CanEjectBullet() {return true;}
401 void SetJammed(bool value) { m_isJammed = value; }
404 {
405 int level = GetHealthLevel();
406
407 if (level >= 0 && level < m_ChanceToJam.Count())
408 return m_ChanceToJam[level];
409 else
410 return 0.0;
411 }
412
413 void SyncSelectionState(bool has_bullet, bool has_mag)
414 {
415 if (has_bullet)
416 {
417 string chamberedAmmoTypeName;
418 float chamberedAmmoDmg;
419
420 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
421 {
422 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
423 }
424 //ShowBullet(0);
425 SelectionBulletShow();
426 }
427 else
428 {
429 //HideBullet(0);
430 SelectionBulletHide();
431 EffectBulletHide(0);
432 }
433
434 if (has_mag)
435 ShowMagazine();
436 else
437 HideMagazine();
438 }
439
440 /*override void EEOnAfterLoad()
441 {
442 super.EEOnAfterLoad();
443
444 string chamberedAmmoTypeName;
445 float chamberedAmmoDmg;
446
447 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
448 {
449 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
450 }
451
452 }*/
453
455 {
456 int nMuzzles = GetMuzzleCount();
457 for (int i = 0; i < nMuzzles; ++i)
458 {
459 if (IsChamberFull(i))
460 {
461 ShowBullet(i);
462 float damage;
463 string ammoTypeName;
464 GetCartridgeInfo(i, damage, ammoTypeName);
465 EffectBulletShow(i, damage, ammoTypeName);
466 }
467 else
468 {
469 HideBullet(i);
470 EffectBulletHide(i);
471 }
472
473 Magazine mag = GetMagazine(i);
474 if (mag)
475 ShowMagazine();
476 else
477 HideMagazine();
478 }
479 }
480
481 override bool OnStoreLoad(ParamsReadContext ctx, int version)
482 {
483 if ( !super.OnStoreLoad(ctx, version) )
484 return false;
485
486
487 if (version >= 113)
488 {
489 int current_muzzle = 0;
490 if (!ctx.Read(current_muzzle))
491 {
492 Error("Weapon.OnStoreLoad " + this + " cannot read current muzzle!");
493 return false;
494 }
495
496 if (current_muzzle >= GetMuzzleCount() || current_muzzle < 0)
497 Error("Weapon.OnStoreLoad " + this + " trying to set muzzle index " + current_muzzle + " while it only has " + GetMuzzleCount() + " muzzles!");
498 else
499 SetCurrentMuzzle(current_muzzle);
500 }
501
502 if (version >= 105)
503 {
504 int mode_count = 0;
505 if (!ctx.Read(mode_count))
506 {
507 Error("Weapon.OnStoreLoad " + this + " cannot read mode count!");
508 return false;
509 }
510
511 for (int m = 0; m < mode_count; ++m)
512 {
513 int mode = 0;
514 if (!ctx.Read(mode))
515 {
516 Error("Weapon.OnStoreLoad " + this + " cannot read mode[" + m + "]");
517 return false;
518 }
519
520 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " OnStoreLoad - loaded muzzle[" + m + "].mode = " + mode); }
521 SetCurrentMode(m, mode);
522 }
523 }
524
525 if ( version >= 106 )
526 {
527 if ( !ctx.Read(m_isJammed) )
528 {
529 Error("Weapon.OnStoreLoad cannot load jamming state");
530 return false;
531 }
532 }
533
534 if (m_fsm)
535 {
536 if (!m_fsm.OnStoreLoad(ctx, version))
537 return false;
538
539 WeaponStableState wss = WeaponStableState.Cast(m_fsm.GetCurrentState());
540 if (wss)
541 {
542 SetGroundAnimFrameIndex(wss.m_animState);
543 }
544
545 }
546 else
547 {
548 int dummy = 0;
549 if (!ctx.Read(dummy))
550 return false;
551 }
552
553 return true;
554 }
555
557 {
558 if (m_fsm && m_fsm.IsRunning())
559 {
560 if (m_fsm.SaveCurrentFSMState(ctx))
561 {
562 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state saved."); }
563 }
564 else
565 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state NOT saved.");
566 }
567 else
568 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.SaveCurrentFSMState: trying to save weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
569 }
570
572 {
573 if (m_fsm)
574 {
575 if (m_fsm.LoadCurrentFSMState(ctx, version))
576 {
578 if (state)
579 {
580 SyncSelectionState(state.HasBullet(), state.HasMagazine());
581 state.SyncAnimState();
582 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " stable state loaded and synced."); }
583 return true;
584 }
585 else
586 {
587 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " unstable/error state loaded."); }
588 return false;
589 }
590 }
591 else
592 {
593 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " did not load.");
594 return false;
595 }
596 }
597 else
598 {
599 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.LoadCurrentFSMState: trying to load weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
600 return false;
601 }
602 }
603
604 override void AfterStoreLoad()
605 {
606 if (m_fsm)
607 {
608 int mi = GetCurrentMuzzle();
609 Magazine mag = GetMagazine(mi);
610 bool has_mag = mag != null;
611 bool has_bullet = !IsChamberEmpty(mi);
612 SyncSelectionState(has_bullet, has_mag);
613 }
614 }
615
617 {
618 super.OnStoreSave(ctx);
619
620 // current muzzle added in version 113
621 int current_muzzle = GetCurrentMuzzle();
622 ctx.Write(current_muzzle);
623
624 // fire mode added in version 105
625 int mode_count = GetMuzzleCount();
626 ctx.Write(mode_count);
627 for (int m = 0; m < mode_count; ++m)
628 ctx.Write(GetCurrentMode(m));
629
630 ctx.Write(m_isJammed);
631
632 if (m_fsm)
633 m_fsm.OnStoreSave(ctx);
634 else
635 {
636 int dummy = 0;
637 ctx.Write(dummy);
638 }
639 }
640
645 {
646 if (m_fsm)
647 return m_fsm.GetInternalStateID();
648 return 0;
649 }
650
655 {
656 if (m_fsm)
657 {
658 return m_fsm.GetCurrentStableStateID();
659 }
660 return 0;
661 }
662
668 {
669 if (m_fsm)
670 {
671 int mi = GetCurrentMuzzle();
672 Magazine mag = GetMagazine(mi);
673 bool has_mag = mag != null;
674 bool has_bullet = !IsChamberEmpty(mi);
675 bool has_jam = IsJammed();
676 array<MuzzleState> muzzleStates = GetMuzzleStates();
677 m_fsm.RandomizeFSMStateEx(muzzleStates, has_mag, has_jam);
679 }
680 }
681
684 {
685 array<MuzzleState> muzzleStates = new array<MuzzleState>;
686
687 int nMuzzles = GetMuzzleCount();
688 for (int i = 0; i < nMuzzles; ++i)
689 {
690 MuzzleState state = MuzzleState.U;
691 if (IsChamberFiredOut(i))
692 state = MuzzleState.F;
693 else if (IsChamberFull(i))
694 state = MuzzleState.L;
695 else if (IsChamberEmpty(i))
696 state = MuzzleState.E;
697 else
698 ErrorEx(string.Format("Unable to identify chamber state of muzzle %1", i));
699
700 muzzleStates.Insert(state);
701 }
702
703 return muzzleStates;
704 }
705
712
720 static Weapon_Base CreateWeaponWithAmmo( string weaponType, string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
721 {
722 Weapon_Base wpn = Weapon_Base.Cast(g_Game.CreateObjectEx( weaponType, vector.Zero, ECE_PLACE_ON_SURFACE ));
723
724 if ( !wpn )
725 {
726 ErrorEx(string.Format("%1 does not exist or is not a weapon.", weaponType));
727 return null;
728 }
729
730 wpn.SpawnAmmo(magazineType, flags);
731 return wpn;
732 }
733
740 bool SpawnAmmo( string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
741 {
742 // Attempt internal mag
743 if ( HasInternalMagazine(-1) && FillInnerMagazine(magazineType, flags) )
744 return true;
745
746 // Attempt mag attachment
747 if ( GetMagazineTypeCount(0) > 0 && SpawnAttachedMagazine(magazineType, flags) )
748 return true;
749
750 // Attempt chamber
751 if ( FillChamber(magazineType, flags) )
752 return true;
753
754 return false;
755 }
756
763 Magazine SpawnAttachedMagazine( string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
764 {
765 // Check if the gun has any magazines registered in config
766 if ( GetMagazineTypeCount(0) == 0 )
767 {
768 ErrorEx(string.Format("No 'magazines' config entry for %1.", this));
769 return null;
770 }
771
772 // Randomize when no specific one is given
773 if ( magazineType == "" )
774 {
775 if ( flags & WeaponWithAmmoFlags.MAX_CAPACITY_MAG)
776 magazineType = GetMaxMagazineTypeName(0);
777 else
778 magazineType = GetRandomMagazineTypeName(0);
779 }
780
781 EntityAI magAI = GetInventory().CreateAttachment(magazineType);
782 if (!magAI)
783 {
784 ErrorEx(string.Format("Failed to create and attach %1 to %2", GetDebugName(magAI), this));
785 return null;
786 }
787
788 Magazine mag;
789 if (!CastTo(mag, magAI))
790 {
791 ErrorEx(string.Format("Expected magazine, created: %1", GetDebugName(magAI)));
792 return null;
793 }
794
795 // Decide random quantity when enabled
796 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
797 mag.ServerSetAmmoCount(Math.RandomIntInclusive(0, mag.GetAmmoMax()));
798
799 if(MustBeChambered(0))
800 {
801 string bulletType;
802 float dmg;
803 if(mag.ServerAcquireCartridge(dmg,bulletType))
804 {
805 FillChamber(bulletType, flags);
806 }
807 }
808
809 // Fill chamber when flagged
810 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
811 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || chamberRng;
812 if (chamber || chamberRng)
813 {
814 FillChamber(magazineType, flags);
815 }
816
817 // FSM cares about magazine state
819 Synchronize();
820
821 return mag;
822 }
823
831 bool FillInnerMagazine( string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
832 {
833 // Don't try to fill it when there are none
834 if (!HasInternalMagazine(-1))
835 return false;
836
837 // Make sure the given ammoType is actually useable
838 if (ammoType != "")
839 {
840 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
841 return false;
842 }
843
844
845 bool didSomething = false;
846 bool needUpdateStateMachine = false;
847 int muzzCount = GetMuzzleCount();
848
849 bool ammoRng = ammoType == "";
850 bool ammoFullRng = ammoRng && (flags & WeaponWithAmmoFlags.AMMO_MAG_RNG);
851
852 // No full RNG flag, so pick one random and use only this one
853 if (ammoRng && !ammoFullRng)
854 ammoType = GetRandomChamberableAmmoTypeName(0);
855
856 // Fill the internal magazine
857 for (int i = 0; i < muzzCount; ++i)
858 {
859 bool loadAnyBullet = false;
860 int ammoCount = GetInternalMagazineMaxCartridgeCount(i);
861
862 // Decide random quantity when enabled
863 if ( flags & WeaponWithAmmoFlags.QUANTITY_RNG )
864 ammoCount = Math.RandomIntInclusive(0, ammoCount);
865
866 // Only do the things when there is actually ammo to fill
867 if (ammoCount > 0)
868 {
869 // Push in the cartridges
870 for (int j = 0; j < ammoCount; ++j)
871 {
872 // Full random, decide a new one for every cartridge
873 if ( ammoFullRng )
874 ammoType = GetRandomChamberableAmmoTypeName(i);
875
876 PushCartridgeToInternalMagazine(i, 0, ammoType);
877 loadAnyBullet = true;
878 didSomething = true;
879 }
880
881 if (loadAnyBullet && MustBeChambered(i))
882 {
883 if ( ammoFullRng )
884 ammoType = GetRandomChamberableAmmoTypeName(i);
885
886 if (FillSpecificChamber(i, 0, ammoType))
887 needUpdateStateMachine = true;
888
889 }
890 }
891 }
892
893 // Call the chamber method if asked for
894 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
895 if (chamber && FillChamber(ammoType, flags))
896 {
897 didSomething = true;
898 }
899
900 // Only fix the FSM and Synchronize when absolutely needed
901 if (!didSomething)
902 return false;
903
904 if( needUpdateStateMachine )
905 {
906 // FSM cares about chamber state
908 Synchronize();
909 }
910
911 return true;
912 }
913
921 bool FillChamber( string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
922 {
923 bool didSomething = false;
924 bool chamberFullRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG_SPORADIC);
925 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
926 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER);
927
928
929 if (chamber || chamberFullRng)
930 {
931 // Make sure the given ammoType is actually useable
932 if (ammoType != "")
933 {
934 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
935 return false;
936 }
937 else if (!(flags & WeaponWithAmmoFlags.AMMO_CHAMBER_RNG))
938 {
939 ammoType = GetRandomChamberableAmmoTypeName(0);
940 }
941
942 // fill chambers
943 int muzzCount = GetMuzzleCount();
944 int amountToChamber = muzzCount;
945
946 if (chamberRng)
947 amountToChamber = Math.RandomIntInclusive(0, muzzCount);
948
949
950 for (int m = 0; m < muzzCount; ++m)
951 {
952 if (chamberFullRng)
953 chamber = Math.RandomIntInclusive(0, 1);
954
955 if (chamber)
956 {
957 if (FillSpecificChamber(m, 0, ammoType))
958 {
959 didSomething = true;
960 amountToChamber--;
961 if (amountToChamber <= 0)
962 break;
963 }
964 }
965 }
966 }
967
968 if (!didSomething)
969 return false;
970
971 // FSM cares about chamber state
973 Synchronize();
974
975 return true;
976 }
977
978 bool FillSpecificChamber(int muzzleIndex, float dmg = 0, string ammoType = "")
979 {
980 if(!IsChamberEmpty(muzzleIndex))
981 return false;
982
983 if (ammoType == "")
984 {
985 ammoType = GetRandomChamberableAmmoTypeName(muzzleIndex);
986 }
987 else
988 {
989 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
990 return false;
991 }
992
993 return PushCartridgeToChamber(muzzleIndex, dmg, ammoType);
994 }
995
997
998
999
1004 {
1005 int ac = GetInventory().AttachmentCount();
1006 int sc = GetInventory().GetAttachmentSlotsCount() + GetMuzzleCount();
1007 if (ac > sc) sc = ac; // fix of some weapons which has 1 attachments but 0 slots...
1008 return sc;
1009 };
1010
1019
1020 void OnFire(int muzzle_index)
1021 {
1022/*
1023 array<Man> players();
1024 g_Game.GetPlayers(players);
1025
1026 Man root = GetHierarchyRootPlayer();
1027
1028 if (!root)
1029 {
1030 return;
1031 }
1032
1033 vector safePosition = root.GetPosition() + (root.GetDirection() * "0 1 0" * 3.0);
1034
1035 Man other = null;
1036 foreach (auto player : players)
1037 {
1038 if (player != GetHierarchyRootPlayer())
1039 {
1040 player.SetPosition(safePosition);
1041 }
1042 }
1043*/
1044
1045 m_BurstCount++;
1046 }
1047
1048 void OnFireModeChange(int fireMode)
1049 {
1050 if ( !g_Game.IsHeadlessOrDedicatedServer() )
1051 {
1052 EffectSound eff;
1053
1054 if ( fireMode == 0 )
1055 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Marked_Click_SoundSet", GetPosition());
1056 else
1057 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Simple_Click_SoundSet", GetPosition());
1058
1059 eff.SetAutodestroy(true);
1060 }
1061
1063 }
1064
1066 {
1068 {
1069 m_DelayedValidationTimer.Run(VALIDATE_DELAY , this, "ValidateAndRepair");
1070 }
1071 else
1072 {
1073 Error("[wpn] Weapon_Base::DelayedValidateAndRepair m_DelayedValidationTimer not initialized.");
1075 }
1076 }
1077
1079 {
1080 if ( m_fsm )
1081 m_fsm.ValidateAndRepair();
1082 }
1083
1084 override void OnInventoryEnter(Man player)
1085 {
1087
1088 if (g_Game.IsServer())
1089 {
1090 // The server knows about all of its attachments
1092 }
1093 else
1094 {
1095 // The client doesn't know it has attachments yet... give it a moment
1097 }
1098
1099 super.OnInventoryEnter(player);
1100 }
1101
1102 override void OnInventoryExit(Man player)
1103 {
1105 super.OnInventoryExit(player);
1106 }
1107
1108 override void EEItemAttached(EntityAI item, string slot_name)
1109 {
1110 super.EEItemAttached(item, slot_name);
1111
1112 GetPropertyModifierObject().UpdateModifiers();
1113 }
1114
1115 override void EEItemDetached(EntityAI item, string slot_name)
1116 {
1117 super.EEItemDetached(item, slot_name);
1118
1119 GetPropertyModifierObject().UpdateModifiers();
1120
1121 if(item.IsMagazine()) {ValidateAndRepair();}
1122 }
1123
1124 override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
1125 {
1126 super.EEItemLocationChanged(oldLoc, newLoc);
1127
1128 if (newLoc.GetType() == InventoryLocationType.HANDS)
1129 {
1130 PlayerBase player;
1131 if (newLoc.GetParent() && PlayerBase.CastTo(player, newLoc.GetParent()))
1132 {
1133 HumanCommandMove cm = player.GetCommand_Move();
1134 if (cm)
1135 {
1136 cm.SetMeleeBlock(false);
1137 }
1138 }
1139 }
1140 }
1141
1142 override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
1143 {
1144 /*
1145 // TODO(kumarjac): Solve this in code instead, OnItemLocationChanged is called too late.
1146 // Maybe extend an option for items to specify what attachments they must
1147 // be synchronized with? Moving to 'DelayedValidateAndRepair' works for now.
1148 int muzzles = GetMuzzleCount();
1149 for (int muzzleIdx = 0; muzzleIdx < muzzles; muzzleIdx++)
1150 {
1151 Magazine mag = GetMagazine(muzzleIdx);
1152 Print(mag);
1153 if (!mag)
1154 continue;
1155
1156 Print(mag.GetInventory());
1157 if (!mag.GetInventory())
1158 continue;
1159
1160 InventoryLocation invLoc = new InventoryLocation();
1161 mag.GetInventory().GetCurrentInventoryLocation(invLoc);
1162
1163 g_Game.AddInventoryJunctureEx(null, this, invLoc, true, 1000);
1164 }
1165 */
1166
1167 super.OnItemLocationChanged(old_owner,new_owner);
1168
1169 // "resets" optics memory on optics
1170 PlayerBase player;
1171 if (PlayerBase.CastTo(player,old_owner))
1172 {
1173 player.SetReturnToOptics(false);
1174
1175 //optics item state reset
1176 ItemOptics optics;
1177 if (Class.CastTo(optics,GetAttachedOptics()))
1178 {
1179 player.SwitchOptics(optics,false);
1180 }
1181 }
1182
1183 if (old_owner != new_owner && PlayerBase.Cast(new_owner))
1184 SetWasIronSight(true); // reset ironsight/optic default
1185
1186 HideWeaponBarrel(false);
1187 }
1188
1189 override bool CanReleaseAttachment(EntityAI attachment)
1190 {
1191 if ( !super.CanReleaseAttachment( attachment ) )
1192 return false;
1193 Magazine mag = Magazine.Cast(attachment);
1194 if (mag)
1195 {
1196 PlayerBase player = PlayerBase.Cast( GetHierarchyRootPlayer() );
1197 if ( player )
1198 {
1199 if ( player.GetItemInHands() == this )
1200 return true;
1201 }
1202 return false;
1203 }
1204
1205 return true;
1206 }
1207
1208 override bool CanRemoveFromHands(EntityAI parent)
1209 {
1210 if (IsIdle())
1211 {
1212 return true;
1213 }
1214 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " not in stable state=" + GetCurrentState().Type()); }
1215 return false; // do not allow removal of weapon while weapon is busy
1216 }
1217
1219 {
1221 if (GetInventory().GetCurrentInventoryLocation(il))
1222 {
1223 EntityAI parent = il.GetParent();
1224 DayZPlayer dayzp = DayZPlayer.Cast(parent);
1225 if (il.GetType() == InventoryLocationType.HANDS && dayzp)
1226 {
1227 bool remote = dayzp.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_REMOTE;
1228 return remote;
1229 }
1230 }
1231 return true;
1232 }
1233
1235 {
1236 DayZPlayer p = DayZPlayer.Cast(GetHierarchyParent());
1237 if (p && p.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_SERVER)
1238 {
1240
1242 e.WriteToContext(ctx);
1243
1245 wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " send 2 remote: sending e=" + e + " id=" + e.GetEventID() + " p=" + e.m_player + " m=" + e.m_magazine);
1246
1247 p.StoreInputForRemotes(ctx);
1248 }
1249 }
1250
1251
1253 {
1254 return new DefaultRecoil(this);
1255 }
1256
1257 int GetWeaponSpecificCommand(int weaponAction, int subCommand)
1258 {
1259 return subCommand;
1260 }
1261
1262 bool CanFire()
1263 {
1264 if (!IsChamberEmpty(GetCurrentMuzzle()) && !IsChamberFiredOut(GetCurrentMuzzle()) && !IsJammed() && !m_LiftWeapon && !IsDamageDestroyed())
1265 return true;
1266 return false;
1267 }
1268
1270 {
1271 ItemOptics optic = GetAttachedOptics();
1272 if (!optic)
1273 return true;
1274
1275 return optic.HasWeaponIronsightsOverride();
1276 }
1277
1279 bool InitDOFProperties(out array<float> temp_array)
1280 {
1281 if (g_Game.ConfigIsExisting("cfgWeapons " + GetType() + " PPDOFProperties"))
1282 {
1283 g_Game.ConfigGetFloatArray("cfgWeapons " + GetType() + " PPDOFProperties", temp_array);
1284 return true;
1285 }
1286 return false;
1287 }
1288
1289 bool InitReliability(out array<float> reliability_array)
1290 {
1291 if (g_Game.ConfigIsExisting("cfgWeapons " + GetType() + " Reliability ChanceToJam"))
1292 {
1293 g_Game.ConfigGetFloatArray("cfgWeapons " + GetType() + " Reliability ChanceToJam", reliability_array);
1294 return true;
1295 }
1296 return false;
1297 }
1298
1301 {
1302 if (ConfigIsExisting("WeaponLength"))
1303 {
1304 m_WeaponLength = ConfigGetFloat("WeaponLength");
1305 return true;
1306 }
1307 m_WeaponLength = 0.8; //default value if not set in config; should not be zero
1308 return false;
1309 }
1310
1313 {
1314 if (ConfigIsExisting("WeaponLiftCheckVerticalOffset"))
1315 {
1316 m_WeaponLiftCheckVerticalOffset = ConfigGetFloat("WeaponLiftCheckVerticalOffset");
1317 return true;
1318 }
1319 m_WeaponLiftCheckVerticalOffset = 0.0; //no offset by default
1320 return false;
1321 }
1322
1324 protected bool InitShoulderDistance()
1325 {
1326 if (ConfigIsExisting("ShoulderDistance"))
1327 {
1328 m_ShoulderDistance = ConfigGetFloat("ShoulderDistance");
1329 return true;
1330 }
1331
1333 return false;
1334 }
1335
1338 {
1339 if (ConfigIsExisting("ObstructionDistance"))
1340 {
1341 m_ObstructionDistance = ConfigGetFloat("ObstructionDistance");
1342 return true;
1343 }
1344
1346 return false;
1347 }
1348
1350 {
1351 return m_DOFProperties;
1352 }
1353
1355 {
1356 return m_WasIronSight;
1357 }
1358
1359 // used to remember last used ironsight/optic state
1360 void SetWasIronSight(bool state)
1361 {
1362 m_WasIronSight = state;
1363 }
1364
1365 // lifting weapon on obstcles
1367 {
1368 Object object;
1369 float obstruction;
1370 return LiftWeaponCheckEx(player, obstruction, object);
1371 }
1372
1379 bool UseWeaponObstruction(PlayerBase player, float obstructionValue, Object hitObject)
1380 {
1382 player.GetMovementState(ms);
1383
1384 #ifdef DIAG_DEVELOPER
1385 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 2) // allow always
1386 return true;
1387 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 6) // neverEver
1388 return false;
1389 #endif
1390
1391 // Obstruction in prone does not really work well, the weapon has no physical room
1392 // to move, so we instead always lift in such stance
1393 if (ms.IsInProne() || ms.IsInRaisedProne())
1394 {
1395 return false;
1396 }
1397
1398 // if ( m_ObstructionDistance != 0 && m_ObstructionDistance < 0.7 && ZombieBase.Cast( hitObject ) ) return true;
1399
1400 bool isDynamic;
1401 bool isStatic;
1402 if (hitObject)
1403 {
1404 isDynamic = dBodyIsDynamic(hitObject);
1405 isStatic = !isDynamic;
1406 }
1407
1408 #ifdef DIAG_DEVELOPER
1409 // alwaysDynamic || alwaysDynamicNeverStatic
1410 bool diagAlwaysDynamic = DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 3 || DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 5;
1411 if (diagAlwaysDynamic && isDynamic) // alwaysDynamic
1412 return true;
1413
1414 // neverStatic || alwaysDynamicNeverStatic
1415 bool diagNeverStatic = DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 4 || DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 5;
1416 if (diagNeverStatic && isStatic) // neverStatic
1417 return false;
1418 #endif
1419
1420 //CFGGAMEPLAY
1423 if (hitObject) // Can determine logic reliably
1424 {
1425 if ((isStatic && staticMode == EWeaponObstructionMode.DISABLED) || (isDynamic && dynamicMode == EWeaponObstructionMode.DISABLED))
1426 {
1427 return false;
1428 }
1429 else if ((isStatic && staticMode == EWeaponObstructionMode.ALWAYS) || (isDynamic && dynamicMode == EWeaponObstructionMode.ALWAYS))
1430 {
1431 return true;
1432 }
1433 }
1434 else if (obstructionValue > 0) // With no hit we have to guess whether object was dynamic or static
1435 {
1436 // Allow obstruction if it was already going on (and it is allowed in either mode)
1437 return staticMode != EWeaponObstructionMode.DISABLED && dynamicMode != EWeaponObstructionMode.DISABLED;
1438 }
1440
1441
1442 // Create a buffer between entering and leaving the lift to prevent
1443 // continuous state changes while the value is near the edge. (hysteresis)
1444 bool isLift = player.IsLiftWeapon();
1445
1446 if (isLift && obstructionValue > 0.9) // Retain lift while already lifted
1447 {
1448 return false;
1449 }
1450
1451 if (!isLift && obstructionValue >= 1.0) // Enter lift while not lifted and obstructed enough
1452 {
1453 return false;
1454 }
1455
1456 #ifdef DIAG_DEVELOPER // Keep this diag below all state conditions but above weapon type checks
1457 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 1) // allow conditionally
1458 return true;
1459 #endif
1460
1461 // Allow obstruction with weapons that have their distance defined, otherwise don't
1462 return m_ObstructionDistance != 0;
1463 }
1464
1465 //----------------------------------------------------------------------------------------
1466 /*
1467 Computes/fills the provided `dst` with aim offsets relevant for the provided `characterStance`.
1468 Aiming angles are sampled as the normalized < -1.0, +1.0 > range.
1469 */
1470 protected void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
1471 {
1472 if (characterStance >= DayZPlayerConstants.STANCEIDX_RAISED)
1473 characterStance -= DayZPlayerConstants.STANCEIDX_RAISED;
1474
1475 // All following values were set by inspecting the character with
1476 // a weapon in-game and adjusting the offsets as such that with
1477 // the weapon lift diagnostic enabled, the shapes would nearly
1478 // perfectly overlap an equipped RIFLE.
1479 if (characterStance == DayZPlayerConstants.STANCEIDX_CROUCH)
1480 {
1481 dst.Insert( 0.0, -1.0, " 0.16 0.22 -0.04"); // fully down
1482 dst.Insert( 0.0, -0.5, " 0.14 0.13 0.00"); // halway down
1483 dst.Insert( 0.0, 0.0, " 0.13 0.04 -0.02"); // forward
1484 dst.Insert( 0.0, 0.5, " 0.13 0.01 -0.03"); // halfway up
1485 dst.Insert( 0.0, 1.0, " 0.14 -0.01 -0.04"); // fully up
1486 }
1487 else if (characterStance == DayZPlayerConstants.STANCEIDX_PRONE)
1488 {
1489 dst.Insert( 0.0, -1.0, " 0.120 -0.080 -0.030"); // fully down
1490 dst.Insert( 0.0, -0.5, " 0.120 -0.040 -0.040"); // halfway down
1491 dst.Insert( 0.0, 0.0, " 0.120 0.010 -0.022");// forward
1492 dst.Insert( 0.0, 0.5, " 0.120 -0.080 -0.050"); // halfway up
1493 dst.Insert( 0.0, 1.0, " 0.120 -0.160 -0.130"); // fully up
1494
1495 // prone is very special, so there are some points mapped
1496 // when aiming right and left (and up), to at least somewhat
1497 // correspond with the actual character animation
1498 dst.Insert( 0.3, 0.0, " 0.110 0.008 0.010");
1499 dst.Insert( 0.5, 0.0, " 0.000 0.100 0.025");
1500 dst.Insert( 0.8, 0.0, " 0.070 0.150 -0.014");
1501 dst.Insert( 1.0, 0.0, " 0.140 -0.050 0.020");
1502
1503 dst.Insert(-0.3, 0.0, " 0.090 -0.100 -0.025");
1504 dst.Insert(-0.5, 0.0, " 0.072 -0.064 -0.002");
1505 dst.Insert(-0.9, 0.0, " 0.129 -0.080 0.015");
1506 dst.Insert(-1.0, 0.0, " 0.140 -0.050 0.020");
1507
1508 dst.Insert( 0.5, 1.0, "-0.050 0.150 0.120");
1509 dst.Insert( 1.0, 1.0, " 0.150 -0.035 0.030");
1510 dst.Insert(-0.5, 1.0, " 0.050 -0.124 -0.040");
1511 dst.Insert(-1.0, 1.0, " 0.150 -0.035 0.030");
1512 }
1513 else
1514 {
1515 dst.Insert( 0.0, -1.0, "0.13 0.14 0.082"); // fully down
1516 dst.Insert( 0.0, -0.5, "0.13 0.05 0.048"); // halfway down
1517 dst.Insert( 0.0, 0.0, "0.13 0.01 -0.008"); // forward
1518 dst.Insert( 0.0, 0.5, "0.13 0.00 -0.015"); // halfway up
1519 dst.Insert( 0.0, 1.0, "0.13 -0.04 -0.016"); // fully up
1520 }
1521 }
1522
1523 //----------------------------------------------------------------------------------------
1524 /*
1525 Computes approximate offset during movement for this weapon.
1526 */
1527 protected vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
1528 {
1529 vector offset;
1530 if (lean != 0)
1531 {
1532 const float LEAN_VERT_OFFSET = -0.1;
1533 const float LEAN_HORIZ_OFFSET_L = 0;
1534 const float LEAN_HORIZ_OFFSET_R = 0.01;
1535 float aimStraightWeight = 1.0 - Math.AbsFloat(ud11); // 1 when aiming forward
1536 float leanOffset = lean * aimStraightWeight;
1537 offset += Vector( leanOffset * Math.Lerp(LEAN_HORIZ_OFFSET_L, LEAN_HORIZ_OFFSET_R, lean * 0.5 + 0.5), leanOffset * LEAN_VERT_OFFSET, 0);
1538 }
1539
1540
1541 float maxVelocity = Math.Max( Math.AbsFloat(localVelocity[0]), Math.AbsFloat(localVelocity[2]) );
1542 float peakVelocity = 0.5;
1543 float moveAmount01 = Math.Clamp(maxVelocity / peakVelocity, 0.0, 1.0);
1544 if (moveAmount01 != 0.0)
1545 {
1546 vector moveOffset = "0 -0.2 -0.1";
1547 float ud01 = (ud11 * 0.5) + 0.5;
1548 float aimWeight = Math.Clamp(1.0 - (ud01 * 2), 0, 1);
1549 // The issue is only apparent when looking down and the 2nd power seems
1550 // to follow the actual visual relatively accurately
1551 float moveWeight = moveAmount01 * Math.Pow(aimWeight, 2.0);
1552 offset = offset + (moveWeight * moveOffset);
1553 }
1554
1555 return offset;
1556 }
1557
1558 //----------------------------------------------------------------------------------------
1564 protected void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity = "0 0 0")
1565 {
1566 // Construct stable trasformation matrix that somewhat aligns with the weapon transform,
1567 // without actually using the weapon as reference - the weapon will move during the lift/obstruction
1568 // in more than 1 axis and is therefore not realiable source of truth.
1569 vector resTM[4];
1570 resTM[0] = Vector(direction[0], 0, direction[2]).Normalized();
1571 resTM[0] = vector.RotateAroundZeroDeg(resTM[0], vector.Up, 90);
1572 resTM[2] = direction;
1573 resTM[1] = resTM[2] * resTM[0];
1574 resTM[3] = start;
1575
1576 // Approximate the roll angle of leaning
1577 float leanAngle = hms.m_fLeaning * 35;
1578 vector rotTM[3];
1579 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1580 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1581 Math3D.YawPitchRollMatrix( Vector(xAimHandsOffset , yAimHandsOffset, leanAngle), rotTM );
1582 Math3D.MatrixMultiply3(resTM, rotTM, resTM);
1583
1584 // Draw relative transformation matrix diagnostic
1585 #ifndef SERVER
1586 #ifdef DIAG_DEVELOPER
1587 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetTransform(resTM);
1588 #endif
1589 #endif
1590
1591 // Compute normalized aiming angles
1592 float udAngle = hcw.GetBaseAimingAngleUD();
1593 float lrAngle = hcw.GetBaseAimingAngleLR();
1594
1595 float ud01 = Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX, udAngle); // 0-1
1596 float ud11 = Math.Clamp((ud01 * 2) - 1, -1, 1); // -1, 1
1597 float lr01 = Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_LR_MIN, DayZPlayerCamera1stPerson.CONST_LR_MAX, lrAngle); // 0-1
1598 float lr11 = Math.Clamp((lr01 * 2) - 1, -1, 1);
1599
1600 #ifndef SERVER
1601 #ifdef DIAG_DEVELOPER
1602 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetAimAngles(udAngle, lrAngle, ud11, lr11);
1603 #endif
1604 #endif
1605
1606 // Fetch approximate aim offset position based on current state
1607 Blend2DVector aimOffsets = new Blend2DVector();
1608 GetApproximateAimOffsets(aimOffsets, hms.m_iStanceIdx);
1609 vector offset = aimOffsets.Blend(lr11, ud11);
1610
1611 // Apply height offset if any is defined
1613 {
1614 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1615 }
1616
1617 // Approximate the shift caused by movement. There is an enormous shift when aiming
1618 // downwards, creating insane shift that we will compensate by shifting the offset
1619 // based on the movement and aiming angle:
1620 vector moveOffset = GetApproximateMovementOffset(localVelocity, hms.m_iStanceIdx, hms.m_fLeaning, ud11, lr11);
1621 offset += moveOffset;
1622
1623 // While changing stances the weapon moves slightly forward and although this may
1624 // cause some unwanted lifts ocasionally, it should prevent some unwanted clipping
1625 if (hcm.IsChangingStance())
1626 {
1627 offset[2] = offset[2] + 0.05;
1628 }
1629
1630 offset = offset.InvMultiply3(rotTM);
1631
1632 // Finally use the computed offset as the start position.
1633 start = offset.Multiply4(resTM);
1634 }
1635 //----------------------------------------------------------------------------------------
1638 {
1639 float approximateLength = Math.Max(0, m_WeaponLength / 1.5) * m_WeaponLength;
1640 return m_ShoulderDistance + approximateLength;
1641 }
1642
1643 //----------------------------------------------------------------------------------------
1651 bool LiftWeaponCheckEx(PlayerBase player, out float outObstruction, out Object outHitObject)
1652 {
1653 bool wasLift = m_LiftWeapon;
1654 vector lastLiftPosition = m_LastLiftPosition;
1655
1656 m_LiftWeapon = false;
1657
1658 // [14.2.2025]
1659 // The following selection check should be *unused* for some time now.
1660 // Leaving commented out for future reference, should the removal have unforseen consequences.
1661 // if ( HasSelection("Usti hlavne") )
1662 // return false;
1663
1664 if (!player)
1665 {
1666 #ifndef SERVER
1667 #ifdef DIAG_DEVELOPER
1668 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1669 #endif
1670 #endif
1671 Print("Error: No weapon owner for LiftWeaponCheckEx, returning.");
1672 return false;
1673 }
1674
1675 // Obstruction can only occur if the weapon is rasied
1676 HumanMovementState movementState = new HumanMovementState();
1677 player.GetMovementState(movementState);
1678 if (!movementState.IsRaised())
1679 return false;
1680
1681 // Suppress weapon obstruction during melee attack preventing state inconsistency
1682 if (movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE || movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE2)
1683 {
1684 #ifndef SERVER
1685 #ifdef DIAG_DEVELOPER
1686 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1687 #endif
1688 #endif
1689 return false;
1690 }
1691
1692
1693 // If possible use aiming angles instead as these will work consistently
1694 // and independently of any cameras, etc.
1695 vector direction;
1696 HumanInputController hic = player.GetInputController();
1697 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1698 HumanCommandMove hcm = player.GetCommand_Move();
1699 if (hcw)
1700 {
1701 vector yawPitchRoll = Vector(
1702 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1704 0.0);
1705
1706 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1707 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1708
1709 yawPitchRoll[0] = yawPitchRoll[0] + xAimHandsOffset;
1710 yawPitchRoll[1] = Math.Clamp( yawPitchRoll[1] + yAimHandsOffset, DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX );
1711
1712 direction = yawPitchRoll.AnglesToVector();
1713 }
1714 else // Fallback to previously implemented logic
1715 {
1716 // freelook raycast
1717 if (hic.CameraIsFreeLook())
1718 {
1719 if (player.m_DirectionToCursor != vector.Zero)
1720 {
1721 direction = player.m_DirectionToCursor;
1722 }
1723 // if player raises weapon in freelook
1724 else
1725 {
1726 direction = MiscGameplayFunctions.GetHeadingVector(player);
1727 }
1728 }
1729 else
1730 {
1731 direction = g_Game.GetCurrentCameraDirection(); // exception for freelook. Much better this way!
1732 }
1733 }
1734
1735 // Reference bone to perform checks from
1736 vector start;
1737 int boneIdx = player.GetBoneIndexByName("Neck");
1738 if (boneIdx == -1)
1739 {
1740 start = player.GetPosition()[1] + 1.5;
1741 }
1742 else
1743 {
1744 start = player.GetBonePositionWS(boneIdx);
1745 }
1746
1747 // Update the ray origin and direction with approximations of character state
1748 vector velocity = GetVelocity(player);
1749 velocity = player.VectorToLocal(velocity);
1750 ApproximateWeaponLiftTransform(start, direction, movementState, hic, hcw, hcm, velocity);
1751
1752 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1753
1754 // weapon length including effective attachments
1755 float weaponLength = m_WeaponLength + effectiveAttachmentLength;
1756 // distance of point from 'shoulder' (start) from which the weapon length should be computed,
1757 // pistols have the start point further, near the character wrist whereas longer rifles, typically
1758 // the ones with buttstocks have the start point at 0 distance, ie. directly at shoulder
1759 float weaponStartDist = m_ShoulderDistance;
1760 float weaponEndDist = weaponStartDist + weaponLength;
1761
1762 // Weapon start and end positions as an offset from the character shoulder
1763 vector weaponStart = start + (weaponStartDist * direction);
1764 vector weaponEnd = start + (weaponEndDist * direction);
1765
1766 // distance of point from 'shoulder' (start) at which the weapon is "fully obstructed", i.e.
1767 // needs to be lifted to be able to be physically fit wherever it is. Shifted by effective
1768 // attachment length to account for e.g. suppressors that make the weapon "longer".
1769 // Defaults to FLT_MAX if no value is configured, effectivelly always lifting weapon instead of obstructing.
1770 float baseObstructionLength = m_ObstructionDistance;
1771 if (baseObstructionLength==0)
1772 {
1773 baseObstructionLength = ApproximateBaseObstructionLength();
1774 }
1775
1776 float weaponObstructionDist = baseObstructionLength + effectiveAttachmentLength;
1777 float rayRadius = 0.02;
1778
1779 #ifndef SERVER
1780 #ifdef DIAG_DEVELOPER // Retrieve possible override
1781 float overrideObstDist = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_ObstructionDistance;
1782 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetWeaponRayParams(start, direction, weaponStartDist, weaponEndDist, effectiveAttachmentLength, m_ObstructionDistance, weaponObstructionDist, rayRadius);
1783 weaponObstructionDist = overrideObstDist;
1784 rayRadius = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_RayRadiusOverride;
1785 #endif
1786 #endif
1787
1788 // Extend the raycast range by 30 cm to allow checking for intersections even
1789 // under shallow angles and other odd cases
1790 float rayEndDist = weaponEndDist + 0.30;
1791 vector rayEnd = start + rayEndDist * direction;
1792
1793 // Prepare raycast params and perform the cast in fire geo
1794 RaycastRVParams rayParm = new RaycastRVParams(start, rayEnd, player, rayRadius);
1795 rayParm.flags = CollisionFlags.ALLOBJECTS;
1796 rayParm.type = ObjIntersect.Fire;
1797
1798 RaycastRVResult hitResult;
1799 float hitFraction;
1800 float hitDist;
1801
1802 array<ref RaycastRVResult> results = {};
1803 if (!DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1804 {
1805 hitFraction = 0;
1806 }
1807 else
1808 {
1809 // In case of multiple results, find the best (nearest) match, RaycastRVProxy doesn't guarantee any sensible order
1810 int numRes = results.Count();
1811 if (numRes == 1)
1812 {
1813 hitResult = results[0];
1814 }
1815 else
1816 {
1817 int bi = -1;
1818 float maxDist = float.MAX;
1819 for (int i = 0, nr = results.Count(); i < nr; ++i)
1820 {
1821 float sqDist = vector.DistanceSq(results[i].pos, weaponStart);
1822 if (sqDist < maxDist)
1823 {
1824 maxDist = sqDist;
1825 bi = i;
1826 }
1827 }
1828 hitResult = results[bi];
1829 }
1830
1831 if (LiftWeaponRaycastResultCheck(hitResult))
1832 {
1833 float len0 = (hitResult.pos - start).Length();
1834 float len1 = (weaponEnd - start).Length(); // Do not include 'rayEnd' - pretend as if the computation happened in <start, weaponEnd>
1835
1836 if (len0 <= 0 || len1 <= 0)
1837 {
1838 hitFraction = 1;
1839 }
1840 else
1841 {
1842 hitFraction = len0 / len1;
1843 }
1844 hitDist = hitFraction * weaponEndDist;
1845 }
1846 else
1847 {
1848 hitFraction = 0;
1849 hitDist = 0;
1850 }
1851 }
1852
1853 #ifndef SERVER
1854 #ifdef DIAG_DEVELOPER // isect diag
1855 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetIntersectionParams(hitResult, hitFraction, hitDist);
1856 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetLastPosition(lastLiftPosition);
1857 #endif // !isect diag
1858 #endif
1859
1860 // Start by assuming that we want to retain state
1861 bool wantsLift = wasLift;
1862
1863 // Sq. distance of weapon movement required to trigger lift (in)
1864 const float inThreshold = 0.002;
1865 // Sq. distance of weapon movement required to trigger lift (out)
1866 const float outThreshold = 0.003;
1867 const float noIsctOutThreshold = 0.01;
1868 // Max num of ticks with no hit for which hysteresis will persist
1869 // value chosen by iteration, should be approx 0.333s
1870 const int maxNumMissedTicks = 10;
1871
1872 // Min angle in degrees change from last lift to stop lifting
1873 // Base threshold of 0.75 degrees + 0.6 degrees per meter of weapon length
1874 float angleThreshold = 0.75 + Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1875
1876 // Update state when a hit is registered
1877 if (hitFraction != 0)
1878 {
1879 vector v1 = hitResult.pos - weaponEnd;
1880 vector v2 = hitResult.pos - rayEnd;
1881 float d = vector.Dot(v1, v2);
1882 // But leave some threshold where previous state is kept
1883 // to prevent excessive switches from occuring
1884 if (!wasLift && d > inThreshold)
1885 {
1886 wantsLift = true;
1887 }
1888 else if (wasLift && d < -outThreshold)
1889 {
1890 wantsLift = false;
1891 }
1892
1893 m_LastLiftPosition = hitResult.pos;
1894 m_LastLiftHit = player.GetSimulationTimeStamp();
1895 }
1896 else
1897 {
1898 // With no hit and no previous lift
1899 if (lastLiftPosition == vector.Zero)
1900 {
1901 wantsLift = false;
1903 }
1904 // See if previous hit wasn't very close to our current position,
1905 // in which case simply don't lift the weapon
1906 else
1907 {
1908 vector v3 = (lastLiftPosition - start).Normalized();
1909 vector v4 = (weaponEnd-start).Normalized();
1910 float d2 = vector.Dot(v3, v4);
1911 // no isect, angle delta check
1912 if (Math.Acos(d2) > (angleThreshold * Math.DEG2RAD)) // if relative angle is > x degree, stop lifting
1913 {
1914 wantsLift = false;
1916 }
1917 // no isect, distance check
1918 else
1919 {
1920 float d3 = vector.Dot( lastLiftPosition - weaponEnd, (start-weaponEnd).Normalized() );
1921 if (d3 < -noIsctOutThreshold)
1922 {
1923 wantsLift = false;
1925 }
1926 float lastObstruction = hcw.GetWeaponObstruction();
1927 // fallback in case offending object disappears or moves
1928 int timeSinceHit = player.GetSimulationTimeStamp() - m_LastLiftHit;
1929 if (timeSinceHit > maxNumMissedTicks)
1930 {
1931 wantsLift = false;
1933 }
1934 else if (wantsLift && m_LastLiftPosition != vector.Zero) // pretended hit to retain obstruction in this very tight edge case
1935 {
1936 float l0 = (m_LastLiftPosition - start).Length();
1937 float l1 = (weaponEnd - start).Length();
1938 if (l0 <= 0 || l1 <= 0)
1939 {
1940 hitFraction = 1;
1941 }
1942 else
1943 {
1944 hitFraction = l0 / l1;
1945 }
1946 hitDist = hitFraction * weaponEndDist;
1947 }
1948 }
1949 }
1950 }
1951
1952 // lift is desired
1953 if (wantsLift)
1954 {
1955 // Remap the hit distance into the <obstruction, weaponWithAttachmentLength> range as 0..1 (and beyond)
1956 float begDist = weaponObstructionDist;
1957 float endDist = weaponStartDist + weaponLength;
1958
1959 float obstFraction;
1960 if (begDist < endDist)
1961 obstFraction = Math.InverseLerp( begDist, endDist, hitDist );
1962
1963 if (hitResult)
1964 outHitObject = hitResult.obj;
1965
1966 outObstruction = 1.0 - obstFraction;
1967 m_LiftWeapon = true;
1968 return true;
1969 }
1970
1971 return false;
1972 }
1973
1980 float GetObstructionPenetrationDistance(float obstruction01)
1981 {
1982 float baseObstructionLength = m_ObstructionDistance;
1983 if (baseObstructionLength==0)
1984 {
1985 baseObstructionLength = ApproximateBaseObstructionLength();
1986 }
1987
1988 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1989 float weaponEnd = m_ShoulderDistance + m_WeaponLength + effectiveAttachmentLength;
1990 return weaponEnd - Math.Lerp(weaponEnd, baseObstructionLength + effectiveAttachmentLength, obstruction01);
1991 }
1992
1995 {
1996 return res.surface.IsSolid();
1997 }
1998
2001 {
2002 ItemBase attachment;
2003 if (HasBayonetAttached())
2004 {
2005 int bayonetIndex = GetBayonetAttachmentIdx();
2006 attachment = ItemBase.Cast(GetInventory().FindAttachment(bayonetIndex));
2007 }
2008 else
2009 {
2010 attachment = GetAttachedSuppressor();
2011 }
2012
2013 if (attachment)
2014 {
2015 ItemBaseType itemBaseType = ItemBaseType.Cast(attachment.GetEntityType());
2016 return Math.Max(itemBaseType.m_ItemModelLength + itemBaseType.m_ItemAttachOffset, 0);
2017 }
2018 else
2019 {
2020 return 0;
2021 }
2022 }
2023
2024 void SetSyncJammingChance( float jamming_chance )
2025 {
2026 m_ChanceToJamSync = jamming_chance;
2027 }
2028
2039 bool EjectCartridge(int muzzleIndex, out float ammoDamage, out string ammoTypeName)
2040 {
2041 if (IsChamberEjectable(muzzleIndex))
2042 {
2043 if (PopCartridgeFromChamber(muzzleIndex, ammoDamage, ammoTypeName))
2044 return true;
2045 }
2046 else if (GetInternalMagazineCartridgeCount(muzzleIndex) > 0)
2047 {
2048 if (PopCartridgeFromInternalMagazine(muzzleIndex, ammoDamage, ammoTypeName))
2049 return true;
2050 }
2051 return false;
2052 }
2053
2055 {
2056 float damage = 0.0;
2057 string type;
2058
2059 for (int mi = 0; mi < src.GetMuzzleCount(); ++mi)
2060 {
2061 if (!src.IsChamberEmpty(mi))
2062 {
2063 if (src.GetCartridgeInfo(mi, damage, type))
2064 {
2065 PushCartridgeToChamber(mi, damage, type);
2066 }
2067 }
2068
2069 for (int ci = 0; ci < src.GetInternalMagazineCartridgeCount(mi); ++ci)
2070 {
2071 if (src.GetInternalMagazineCartridgeInfo(mi, ci, damage, type))
2072 {
2073 PushCartridgeToInternalMagazine(mi, damage, type);
2074 }
2075 }
2076 }
2077
2078 int dummy_version = int.MAX;
2079 PlayerBase parentPlayer = PlayerBase.Cast(src.GetHierarchyRootPlayer());
2080 if (!parentPlayer)
2081 dummy_version -= 1;
2083 src.OnStoreSave(ctx.GetWriteContext());
2084 OnStoreLoad(ctx.GetReadContext(), dummy_version);
2085 return true;
2086 }
2087
2089 override void SetBayonetAttached(bool pState, int slot_idx = -1)
2090 {
2091 m_BayonetAttached = pState;
2092 m_BayonetAttachmentIdx = slot_idx;
2093 }
2094
2095 override bool HasBayonetAttached()
2096 {
2097 return m_BayonetAttached;
2098 }
2099
2101 {
2103 }
2104
2105 override void SetButtstockAttached(bool pState, int slot_idx = -1)
2106 {
2107 m_ButtstockAttached = pState;
2108 m_ButtstockAttachmentIdx = slot_idx;
2109 }
2110
2111 override bool HasButtstockAttached()
2112 {
2113 return m_ButtstockAttached;
2114 }
2115
2117 {
2119 }
2120
2121 void HideWeaponBarrel(bool state)
2122 {
2123 if ( !g_Game.IsDedicatedServer() )//hidden for client only
2124 {
2125 ItemOptics optics = GetAttachedOptics();
2126 if ( optics && !optics.AllowsDOF() && m_weaponHideBarrelIdx != -1 )
2127 {
2128 SetSimpleHiddenSelectionState(m_weaponHideBarrelIdx,!state);
2129 }
2130 }
2131 }
2132
2134 {
2136 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,1);
2137 else
2138 SelectionMagazineShow();
2139 }
2140
2142 {
2144 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,0);
2145 else
2146 SelectionMagazineHide();
2147 }
2148
2149 override EntityAI ProcessMeleeItemDamage(int mode = 0)
2150 {
2151 EntityAI attachment;
2152
2153 switch (mode)
2154 {
2155 case 0:
2156 super.ProcessMeleeItemDamage();
2157 break;
2158
2159 case 1:
2160 attachment = GetInventory().FindAttachment(m_ButtstockAttachmentIdx);
2161 break;
2162
2163 case 2:
2164 attachment = GetInventory().FindAttachment(m_BayonetAttachmentIdx);
2165 break;
2166
2167 default:
2168 super.ProcessMeleeItemDamage();
2169 break;
2170 }
2171
2172 if (attachment)
2173 {
2174 attachment.ProcessMeleeItemDamage();
2175 return attachment;
2176 }
2177
2178 return this;
2179 }
2180
2182 {
2183 return true;
2184 }
2185
2187 {
2188 return m_BurstCount;
2189 }
2190
2192 {
2193 m_BurstCount = 0;
2194 }
2195
2209
2210 override bool CanBeUsedForSuicide()
2211 {
2212 if (!ConfigGetBool("isSuicideWeapon"))
2213 return false;
2214
2215 return super.CanBeUsedForSuicide();
2216 }
2217
2218 //Debug menu Spawn Ground Special
2219 override void OnDebugSpawn()
2220 {
2222 }
2223
2224 bool AddJunctureToAttachedMagazine(PlayerBase player, int timeoutMS)
2225 {
2226 Magazine mag = GetMagazine(GetCurrentMuzzle());
2228 if (mag)
2229 {
2230 return g_Game.AddInventoryJunctureEx(player, mag, il, false, timeoutMS);
2231 }
2232
2233 return true;
2234 }
2235
2237 {
2238 Magazine mag = GetMagazine(GetCurrentMuzzle());
2239 if (mag)
2240 {
2241 g_Game.ClearJunctureEx(player, mag);
2242 }
2243 }
2244
2245 void SetNextWeaponMode(int muzzleIndex)
2246 {
2247 SetNextMuzzleMode(muzzleIndex);
2248 }
2249
2250 // CoolDown
2251 void SetCoolDown( float coolDownTime )
2252 {
2253 m_coolDownTime = coolDownTime;
2254 }
2255 void UpdateCoolDown( float dt ) { m_coolDownTime -= dt; }
2257 {
2258 return m_coolDownTime > 0;
2259 }
2260
2261 // If there are bullet in attached / internal magazine then bullet must be in chamber also
2262 bool MustBeChambered(int muzzleIndex)
2263 {
2264 return false;
2265 }
2266
2267#ifdef TEST_WEAPON_SYSNC_REPAIR
2268 void SetSyncStable(bool value)
2269 {
2270 m_SyncStable = value;
2271 if (!value)
2272 {
2273 m_SyncStableTime = g_Game.GetTickTime();
2274 }
2275 }
2276
2277 bool IsSyncStable()
2278 {
2279 return m_SyncStable;
2280 }
2281#endif
2282};
2283
const int INPUT_UDT_WEAPON_REMOTE_EVENT
eBleedingSourceType GetType()
void wpnDebugPrint(string s)
bool IsDamageDestroyed(ActionTarget target)
Определения ActionBase.c:1275
void AddAction(typename actionName)
Определения AdvancedCommunication.c:220
void AmmoTypesAPI()
Определения AmmoTypes.c:17
class Blend2D< Class T > Blend2DVector
const int ECE_PLACE_ON_SURFACE
Определения CentralEconomy.c:38
EWeaponObstructionMode
Определения CfgGameplayDataJson.c:376
EWeaponObstructionMode staticMode
!! all member variables must correspond with the cfggameplay.json file contents !!...
Определения CfgGameplayDataJson.c:395
EWeaponObstructionMode dynamicMode
Определения CfgGameplayDataJson.c:396
bool OnStoreLoad(ParamsReadContext ctx, int version)
Определения CodeLockComponent.c:264
void Synchronize()
Определения CombinationLock.c:205
override bool IsJammed()
Определения Crossbow.c:22
DayZGame g_Game
Определения DayZGame.c:4074
PhxInteractionLayers
Определения DayZPhysics.c:2
float hitFraction
Определения DustKickupEffects.c:23
Object object
Определения DustKickupEffects.c:18
string ammoType
Определения DustKickupEffects.c:24
DiagMenuIDs
Определения EDiagMenuIDs.c:2
WeaponEventID
identifier for events. mainly for rpc purposes
Определения Events.c:6
ProcessEventResult
Определения FSMBase.c:41
FirearmActionLoadBullet FirearmActionBase FirearmActionLoadBulletQuick()
void fsmDebugSpam(string s)
Определения HFSMBase.c:9
InventoryLocationType
types of Inventory Location
Определения InventoryLocation.c:4
void IncreaseOverheating(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
Определения ItemBase.c:443
string Type
Определения JsonDataContaminatedArea.c:11
PistolAnimState
Определения Pistol_Base.c:3
RandomGeneratorSyncUsage
Определения RandomGeneratorSyncManager.c:2
@ AMMO_CHAMBER_RNG
Fully randomizes the ammo type instead of picking one random for all chambers (needs to have type as ...
Определения Weapon_Base.c:26
@ CHAMBER
Chambers bullets.
Определения Weapon_Base.c:16
@ CHAMBER_RNG_SPORADIC
Maybe chambers bullets (full random) example: 0 1 0 0 1 1.
Определения Weapon_Base.c:20
@ MAX_CAPACITY_MAG
Instead of randomizing when type is empty, it looks for the one which has the highest capacity.
Определения Weapon_Base.c:28
@ QUANTITY_RNG
Randomizes the quantity of the bullets in the spawned magazine.
Определения Weapon_Base.c:22
@ CHAMBER_RNG
Maybe chambers bullets (sequential rng) example: 1 1 1 0 0 0.
Определения Weapon_Base.c:18
@ AMMO_MAG_RNG
Fully randomizes the ammo type instead of picking one random for the entire mag (needs to have type a...
Определения Weapon_Base.c:24
enum FSMTransition WeaponTransition
MuzzleState
Определения WeaponStableState.c:15
override bool IsIdle()
Определения WeaponStableState.c:95
bool IsChamberFiredOut(int idx)
Определения WeaponStableState.c:157
bool IsChamberFull(int idx)
Определения WeaponStableState.c:158
void AbilityRecord(int a, int at)
corresponds to Human::actionTypes == CHAMBERING_ONEBULLET_CLOSED, MECHANISM_CLOSED....
Определения Weapon_Base.c:8
int m_actionType
corresponds to Human::actions == RELOAD, MECHANISM, ...
Определения Weapon_Base.c:7
int m_action
Определения Weapon_Base.c:6
pair ( action, actionType )
Определения Weapon_Base.c:5
static float GetAmmoWeightByBulletType(string bulletType)
Определения AmmunitionPiles.c:6
ammo pile base
Определения AmmunitionPiles.c:3
static EWeaponObstructionMode GetWeaponObstructionModeStatic()
Определения CfgGameplayHandler.c:272
static EWeaponObstructionMode GetWeaponObstructionModeDynamic()
Определения CfgGameplayHandler.c:277
Super root of all classes in Enforce script.
Определения EnScript.c:11
static proto bool RaycastRVProxy(notnull RaycastRVParams in, out notnull array< ref RaycastRVResult > results, array< Object > excluded=null)
Определения DayZPhysics.c:124
Определения DayZPlayerImplement.c:87
Определения DefaultRecoil.c:2
Определения EnDebug.c:241
override void SetAutodestroy(bool auto_destroy)
Sets whether Effect automatically cleans up when it stops.
Определения EffectSound.c:607
Wrapper class for managing sound through SEffectManager.
Определения EffectSound.c:5
Определения EntityAIType.c:2
represents transition src -— event[guard]/action -—|> dst
proto native void SetMeleeBlock(bool pBlock)
this enables/disables block
proto native bool IsChangingStance()
returns true if character is changing stance
Определения human.c:454
proto native float GetAimingHandsOffsetUD()
returns aiming hands up/down (y) offset angle
proto native float GetWeaponObstruction()
return obstruction value
proto native float GetBaseAimingAngleLR()
returns base aiming angle LR - without sway/offsets/...
proto native float GetAimingHandsOffsetLR()
returns aiming hands left/right (x) offset angle
proto native float GetBaseAimingAngleUD()
returns base aiming angle UD - without sway/offsets/...
Определения human.c:1027
proto native bool CameraIsFreeLook()
returns true if freelook is active
Определения human.c:18
int m_iStanceIdx
current command's id
Определения human.c:1183
int m_CommandTypeId
Определения human.c:1182
float m_fLeaning
current movement (0 idle, 1 walk, 2-run, 3-sprint), only if the command has a movement
Определения human.c:1185
bool IsInProne()
Определения human.c:1202
bool IsInRaisedProne()
Определения human.c:1208
bool IsRaised()
Определения human.c:1190
Определения human.c:1181
proto native EntityAI GetParent()
returns parent of current inventory location
proto native int GetType()
returns type of InventoryLocation
InventoryLocation.
Определения InventoryLocation.c:30
float m_ItemModelLength float m_ItemAttachOffset
Определения ItemBaseType.c:45
Определения ItemBaseType.c:5
bool AllowsDOF()
returns 'true' for non-magnifying optics
Определения ItemOptics.c:516
proto native bool HasWeaponIronsightsOverride()
is weapon in optics mode or not
Определения ItemOptics.c:2
static bool IsWeaponLogEnable()
Определения 3_Game/DayZ/tools/Debug.c:829
Определения EnMath3D.c:28
Определения EnMath.c:7
Определения ObjectTyped.c:2
Определения PlayerBaseClient.c:2
int type
Определения DayZPhysics.c:73
CollisionFlags flags
Определения DayZPhysics.c:63
Определения DayZPhysics.c:50
Object obj
object,that we collide with (NULL if none), If hierLevel > 0 object is the proxy object
Определения DayZPhysics.c:100
vector pos
position of collision (in world coord)
Определения DayZPhysics.c:103
Определения DayZPhysics.c:99
Определения RecoilBase.c:2
static EffectSound PlaySound(string sound_set, vector position, float play_fade_in=0, float stop_fade_out=0, bool loop=false)
Create and play an EffectSound.
Определения EffectManager.c:178
Manager class for managing Effect (EffectParticle, EffectSound)
Определения EffectManager.c:6
proto native ParamsReadContext GetReadContext()
proto native ParamsWriteContext GetWriteContext()
proto bool Write(void value_out)
proto bool Read(void value_in)
Определения DayZPlayerImplement.c:39
override void InitStateMachine()
Определения Magnum.c:85
override void HideBullet(int muzzleIndex)
Определения Magnum.c:326
override void ShowBullet(int muzzleIndex)
Определения Magnum.c:305
override void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
Определения Pistol_Base.c:656
override vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
Определения Pistol_Base.c:704
shorthand
Определения BoltActionRifle_Base.c:6
bool m_ButtstockAttached
Определения Weapon_Base.c:53
int m_BurstCount
Определения Weapon_Base.c:57
float m_ChanceToJamSync
Определения Weapon_Base.c:73
override int GetBayonetAttachmentIdx()
Определения Weapon_Base.c:2100
override int GetButtstockAttachmentIdx()
Определения Weapon_Base.c:2116
void HideMagazine()
Определения Weapon_Base.c:2141
ref array< float > GetWeaponDOF()
Определения Weapon_Base.c:1349
int GetBurstCount()
Определения Weapon_Base.c:2186
bool CopyWeaponStateFrom(notnull Weapon_Base src)
Определения Weapon_Base.c:2054
bool IsShowingChamberedBullet()
Определения Weapon_Base.c:2181
Magazine SpawnAttachedMagazine(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to spawn and attach a magazine.
Определения Weapon_Base.c:763
bool IsWaitingForActionFinish()
returns true if state machine started playing action/actionType and waits for finish
Определения Weapon_Base.c:281
void SetWasIronSight(bool state)
Определения Weapon_Base.c:1360
bool IsRemoteWeapon()
Определения Weapon_Base.c:1218
bool JamCheck(int muzzleIndex)
Определения Weapon_Base.c:366
float m_coolDownTime
Определения Weapon_Base.c:77
void SyncEventToRemote(WeaponEventBase e)
Определения Weapon_Base.c:1234
void DelayedValidateAndRepair()
Определения Weapon_Base.c:1065
override bool HasBayonetAttached()
Определения Weapon_Base.c:2095
float m_ObstructionDistance
Определения Weapon_Base.c:67
void SetInitialState(WeaponStableState initState)
Определения Weapon_Base.c:145
bool IsCharged()
Определения Weapon_Base.c:153
bool FillSpecificChamber(int muzzleIndex, float dmg=0, string ammoType="")
Определения Weapon_Base.c:978
ref array< int > m_bulletSelectionIndex
Определения Weapon_Base.c:70
ref Timer m_DelayedValidationTimer
Определения Weapon_Base.c:76
vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
Определения Weapon_Base.c:1527
int m_LastLiftHit
Определения Weapon_Base.c:69
float m_WeaponLiftCheckVerticalOffset
Определения Weapon_Base.c:65
void SyncSelectionState(bool has_bullet, bool has_mag)
Определения Weapon_Base.c:413
float GetEffectiveAttachmentLength()
Returns effective length of attachments that influence total weapon length.
Определения Weapon_Base.c:2000
bool m_isJammed
weapon state machine
Определения Weapon_Base.c:50
void ShowMagazine()
Определения Weapon_Base.c:2133
static Weapon_Base CreateWeaponWithAmmo(string weaponType, string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Create weapon with ammo.
Определения Weapon_Base.c:720
float m_ShoulderDistance
Определения Weapon_Base.c:66
int GetWeaponSpecificCommand(int weaponAction, int subCommand)
Определения Weapon_Base.c:1257
bool FillInnerMagazine(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the inner magazine.
Определения Weapon_Base.c:831
int m_weaponHideBarrelIdx
Определения Weapon_Base.c:62
bool InitWeaponLiftCheckVerticalOffset()
gets weapon vertical offset from config for weaponlift raycast
Определения Weapon_Base.c:1312
float GetObstructionPenetrationDistance(float obstruction01)
Определения Weapon_Base.c:1980
int m_BayonetAttachmentIdx
Определения Weapon_Base.c:58
bool EjectCartridge(int muzzleIndex, out float ammoDamage, out string ammoTypeName)
unload bullet from chamber or internal magazine
Определения Weapon_Base.c:2039
ref array< float > m_DOFProperties
Определения Weapon_Base.c:71
ref array< ref AbilityRecord > m_abilities
Определения Weapon_Base.c:48
bool IsIdle()
Определения Weapon_Base.c:286
float GetWeightSpecialized(bool forceRecalc=false)
Определения Weapon_Base.c:173
const float VALIDATE_DELAY
Validation on client side delay to have time properly synchronize attachments needed for check.
Определения Weapon_Base.c:45
override int GetSlotsCountCorrect()
Returns number of slots for attachments corrected for weapons.
Определения Weapon_Base.c:1003
void HideWeaponBarrel(bool state)
Определения Weapon_Base.c:2121
bool InitShoulderDistance()
gets approximate weapon distance from shoulder from config
Определения Weapon_Base.c:1324
override bool CanReleaseAttachment(EntityAI attachment)
Определения Weapon_Base.c:1189
override void EEFired(int muzzleType, int mode, string ammoType)
Определения Weapon_Base.c:341
void ShowBullet(int muzzleIndex)
Определения Weapon_Base.c:379
void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity="0 0 0")
Определения Weapon_Base.c:1564
bool CanProcessAction(int action, int actionType)
Определения Weapon_Base.c:236
void HideBullet(int muzzleIndex)
Определения Weapon_Base.c:389
array< MuzzleState > GetMuzzleStates()
Helper method for RandomizeFSMState.
Определения Weapon_Base.c:683
void SetCharged(bool value)
Определения Weapon_Base.c:158
void ResetBurstCount()
Определения Weapon_Base.c:2191
bool InitDOFProperties(out array< float > temp_array)
Initializes DOF properties for weapon's ironsight/optics cameras.
Определения Weapon_Base.c:1279
override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
Определения Weapon_Base.c:1124
void SetNextWeaponMode(int muzzleIndex)
Определения Weapon_Base.c:2245
bool AddJunctureToAttachedMagazine(PlayerBase player, int timeoutMS)
Определения Weapon_Base.c:2224
vector m_LastLiftPosition
Определения Weapon_Base.c:68
const float DEFAULT_DAMAGE_ON_SHOT
Определения Weapon_Base.c:47
void Weapon_Base()
Определения Weapon_Base.c:79
override void OnInventoryExit(Man player)
Определения Weapon_Base.c:1102
int m_magazineSimpleSelectionIndex
animation state the weapon is in, -1 == uninitialized
Определения Weapon_Base.c:61
ref WeaponFSM m_fsm
weapon abilities
Определения Weapon_Base.c:49
bool GetWasIronSight()
Определения Weapon_Base.c:1354
bool m_BayonetAttached
Определения Weapon_Base.c:52
bool CanFire()
Определения Weapon_Base.c:1262
void RandomizeFSMState()
With the parameters given, selects a random suitable state for the FSM of the weapon @WARNING: Weapon...
Определения Weapon_Base.c:667
bool LiftWeaponCheckEx(PlayerBase player, out float outObstruction, out Object outHitObject)
Определения Weapon_Base.c:1651
bool InitObstructionDistance()
gets weapon obstruction distance from shoulder at which the weapon is fully obstructed
Определения Weapon_Base.c:1337
bool m_WeaponOpen
Определения Weapon_Base.c:55
float GetSyncChanceToJam()
Определения Weapon_Base.c:402
bool m_Charged
Определения Weapon_Base.c:54
int m_weaponAnimState
Определения Weapon_Base.c:60
void SetSyncJammingChance(float jamming_chance)
Определения Weapon_Base.c:2024
override void OnDebugSpawn()
Определения Weapon_Base.c:2219
bool FillChamber(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the chamber.
Определения Weapon_Base.c:921
PhxInteractionLayers hit_mask
Определения Weapon_Base.c:75
void SetWeaponAnimState(int state)
Определения Weapon_Base.c:329
bool LiftWeaponRaycastResultCheck(notnull RaycastRVResult res)
Return whether provided material triggers weapon lift (true) or not (false).
Определения Weapon_Base.c:1994
float GetChanceToJam()
Определения Weapon_Base.c:403
bool HasActionAbility(int action, int actionType)
query if weapon supports action and actionType
Определения Weapon_Base.c:246
void SetWeaponOpen(bool value)
Определения Weapon_Base.c:168
void ForceSyncSelectionState()
Определения Weapon_Base.c:454
bool LiftWeaponCheck(PlayerBase player)
Определения Weapon_Base.c:1366
override void AfterStoreLoad()
Определения Weapon_Base.c:604
bool CanEjectBullet()
Определения Weapon_Base.c:400
bool ProcessWeaponAbortEvent(WeaponEventBase e)
Определения Weapon_Base.c:315
override bool CanRemoveFromHands(EntityAI parent)
Определения Weapon_Base.c:1208
override void EEInit()
Определения Weapon_Base.c:135
override void SetButtstockAttached(bool pState, int slot_idx=-1)
Определения Weapon_Base.c:2105
PropertyModifiers GetPropertyModifierObject()
Определения Weapon_Base.c:1011
bool ProcessWeaponEvent(WeaponEventBase e)
weapon's fsm handling of events @NOTE: warning: ProcessWeaponEvent can be called only within DayZPlay...
Определения Weapon_Base.c:295
WeaponStateBase GetCurrentState()
returns currently active state
Определения Weapon_Base.c:276
int GetAbilityCount()
Определения Weapon_Base.c:260
ref array< float > m_ChanceToJam
Определения Weapon_Base.c:72
void AssembleGun()
override on weapons with some assembly required
AbilityRecord GetAbility(int index)
Определения Weapon_Base.c:265
override bool CanBeUsedForSuicide()
Определения Weapon_Base.c:2210
void ClearJunctureToAttachedMagazine(PlayerBase player)
Определения Weapon_Base.c:2236
RecoilBase SpawnRecoilObject()
Определения Weapon_Base.c:1252
override void EEItemDetached(EntityAI item, string slot_name)
Определения Weapon_Base.c:1115
int GetCurrentStableStateID()
tries to return identifier of current stable state (or nearest stable state if unstable state is curr...
Определения Weapon_Base.c:654
void InitStateMachine()
Определения Weapon_Base.c:133
ref PropertyModifiers m_PropertyModifierObject
Определения Weapon_Base.c:74
bool IsJammed()
Определения Weapon_Base.c:399
void ValidateAndRepair()
Определения Weapon_Base.c:1078
const int SAMF_DEFAULT
Full highest capacity magazine + chambered round.
Определения Weapon_Base.c:41
void OnFire(int muzzle_index)
Определения Weapon_Base.c:1020
bool m_LiftWeapon
Определения Weapon_Base.c:51
override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
Определения Weapon_Base.c:1142
int m_ButtstockAttachmentIdx
Определения Weapon_Base.c:59
override void SetActions()
Определения Weapon_Base.c:2196
void ResetWeaponAnimState()
Определения Weapon_Base.c:334
void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
Определения Weapon_Base.c:1470
bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
Определения Weapon_Base.c:571
void SetCoolDown(float coolDownTime)
Определения Weapon_Base.c:2251
bool CanEnterIronsights()
Определения Weapon_Base.c:1269
float m_WeaponLength
Определения Weapon_Base.c:64
float m_DmgPerShot
Определения Weapon_Base.c:63
int GetWeaponAnimState()
Определения Weapon_Base.c:339
override EntityAI ProcessMeleeItemDamage(int mode=0)
Определения Weapon_Base.c:2149
override bool OnStoreLoad(ParamsReadContext ctx, int version)
Определения Weapon_Base.c:481
bool IsCoolDown()
Определения Weapon_Base.c:2256
bool UseWeaponObstruction(PlayerBase player, float obstructionValue, Object hitObject)
Определения Weapon_Base.c:1379
override void OnStoreSave(ParamsWriteContext ctx)
Определения Weapon_Base.c:616
bool CanChamberBullet(int muzzleIndex, Magazine mag)
Определения Weapon_Base.c:324
bool CanProcessWeaponEvents()
Определения Weapon_Base.c:270
void UpdateCoolDown(float dt)
Определения Weapon_Base.c:2255
bool m_WasIronSight
Определения Weapon_Base.c:56
bool SpawnAmmo(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
General method trying to attch magazine, fill inner magazine and fill chamber.
Определения Weapon_Base.c:740
void SaveCurrentFSMState(ParamsWriteContext ctx)
Определения Weapon_Base.c:556
void OnFireModeChange(int fireMode)
Определения Weapon_Base.c:1048
override bool HasButtstockAttached()
Определения Weapon_Base.c:2111
void SetJammed(bool value)
Определения Weapon_Base.c:401
float ApproximateBaseObstructionLength()
Approximate ObstructionDistance for weapons with no configuration. Returned length doesn't account fo...
Определения Weapon_Base.c:1637
const int SAMF_RNG
Random bullet quantity + maybe chambered round.
Определения Weapon_Base.c:43
bool MustBeChambered(int muzzleIndex)
Определения Weapon_Base.c:2262
bool InitReliability(out array< float > reliability_array)
Определения Weapon_Base.c:1289
override void EEItemAttached(EntityAI item, string slot_name)
Определения Weapon_Base.c:1108
bool InitWeaponLength()
gets weapon length from config for weaponlift raycast
Определения Weapon_Base.c:1300
override void OnInventoryEnter(Man player)
Определения Weapon_Base.c:1084
bool IsWeaponOpen()
Определения Weapon_Base.c:163
override void SetBayonetAttached(bool pState, int slot_idx=-1)
attachment helpers (firearm melee)
Определения Weapon_Base.c:2089
int GetInternalStateID()
Определения Weapon_Base.c:644
Magazine m_magazine
Определения Events.c:38
void WriteToContext(ParamsWriteContext ctx)
Определения Events.c:54
DayZPlayer m_player
Определения Events.c:37
WeaponEventID GetEventID()
returns id from enum WeaponEventID
Определения Events.c:42
signalize mechanism manipulation
Определения Events.c:35
weapon finite state machine
script counterpart to engine's class Weapon
override bool IsDischarged()
Определения OpenBolt_Base.c:44
override bool HasBullet()
Определения Crossbow.c:31
override bool HasMagazine()
Определения Crossbow.c:32
represents weapon's stable state (i.e. the basic states that the weapon will spend the most time in)
Определения Crossbow.c:27
represent weapon state base
Определения BulletHide.c:2
void AddCalcDetails(string details)
Определения 3_Game/DayZ/tools/Debug.c:940
void SetCalcDetails(string details)
Определения 3_Game/DayZ/tools/Debug.c:934
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
proto string ToString(bool simple=true)
proto vector Normalized()
return normalized vector (keeps orginal vector untouched)
static proto native float DistanceSq(vector v1, vector v2)
Returns the square distance between tips of two 3D vectors.
proto vector Multiply4(vector mat[4])
Transforms position.
static vector RotateAroundZeroDeg(vector vec, vector axis, float angle)
Rotate a vector around 0,0,0 by an angle in degrees.
Определения EnConvert.c:484
static float Dot(vector v1, vector v2)
Returns Dot product of vector v1 and vector v2.
Определения EnConvert.c:305
static const vector Zero
Определения EnConvert.c:123
proto vector InvMultiply3(vector mat[3])
Invert-transforms vector.
static const vector Up
Определения EnConvert.c:120
proto vector AnglesToVector()
Converts spherical coordinates (yaw, pitch, roll in degrees) to unit length vector.
Определения EnConvert.c:119
override string GetDebugName()
Определения dayzplayer.c:1191
DayZPlayerInstanceType
defined in C++
Определения dayzplayer.c:1084
DayZPlayerConstants
defined in C++
Определения dayzplayer.c:602
Serializer ParamsReadContext
Определения gameplay.c:15
Serializer ParamsWriteContext
Определения gameplay.c:16
void Error(string err)
Messagebox with error message.
Определения EnDebug.c:90
proto void Print(void var)
Prints content of variable to console/log.
enum ShapeType ErrorEx
CollisionFlags
Определения EnDebug.c:141
static proto int GetValue(int id)
Get value as int from the given script id.
static proto bool CastTo(out Class to, Class from)
Try to safely down-cast base class to child class.
class array< Class T > TStringArray
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
static proto void YawPitchRollMatrix(vector ang, out vector mat[3])
Creates rotation matrix from angles.
static proto void MatrixMultiply3(vector mat0[3], vector mat1[3], out vector res[3])
Transforms rotation matrix.
static proto float Max(float x, float y)
Returns bigger of two given values.
static proto float Lerp(float a, float b, float time)
Linearly interpolates between 'a' and 'b' given 'time'.
static proto float Acos(float c)
Returns angle in radians from cosinus.
static proto float Clamp(float value, float min, float max)
Clamps 'value' to 'min' if it is lower than 'min', or to 'max' if it is higher than 'max'.
static proto float InverseLerp(float a, float b, float value)
Calculates the linear value that produces the interpolant value within the range [a,...
static proto float Pow(float v, float power)
Return power of v ^ power.
static const float DEG2RAD
Определения EnMath.c:17
static proto float AbsFloat(float f)
Returns absolute value.
static int RandomIntInclusive(int min, int max)
Returns a random int number between and min [inclusive] and max [inclusive].
Определения EnMath.c:54
@ NONE
body is not in simulation, nor in collision world
Определения SimulationState.c:15
proto native vector GetVelocity(notnull IEntity ent)
Returns linear velocity.
proto native bool dBodyIsDynamic(notnull IEntity ent)
vector GetPosition()
Get the world position of the Effect.
Определения Effect.c:473
const int CALL_CATEGORY_GAMEPLAY
Определения 3_Game/DayZ/tools/tools.c:10