DayZ 1.28
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 (GetGame().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 (GetGame().IsServer())
127 {
129 }
131 }
132
134
135 override void EEInit()
136 {
137 super.EEInit();
138
139 if (GetGame().IsServer())
140 {
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: " + 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 void EEFired(int muzzleType, int mode, string ammoType)
342 {
343 if ( !GetGame().IsDedicatedServer() )
344 {
345 ItemBase suppressor = GetAttachedSuppressor();
346
347 // Muzzle flash & overheating effects
348 ItemBase.PlayFireParticles(this, muzzleType, ammoType, this, suppressor, "CfgWeapons" );
349 IncreaseOverheating(this, ammoType, this, suppressor, "CfgWeapons");
350
351 if (suppressor)
352 {
353 ItemBase.PlayFireParticles(this, muzzleType, ammoType, suppressor, NULL, "CfgVehicles" );
354 suppressor.IncreaseOverheating(this, ammoType, this, suppressor, "CfgVehicles");
355 }
356 }
357
358 //obsolete, replaced by C++ solution!
359/*
360 if (GetGame().IsServer())
361 {
362 AddHealth("","Health",-m_DmgPerShot); //damages weapon
363 if (suppressor)
364 suppressor.AddHealth("","Health",-m_DmgPerShot); //damages suppressor; TODO add suppressor damage coeficient/parameter (?) to suppressors/weapons (?)
365 }
366*/
367 //JamCheck(muzzleType);
368
369 #ifdef DIAG_DEVELOPER
370 MiscGameplayFunctions.UnlimitedAmmoDebugCheck(this);
371 #endif
372 }
373
374 bool JamCheck(int muzzleIndex )
375 {
376 PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
377 if ( player )
378 {
379 float rnd = player.GetRandomGeneratorSyncManager().GetRandom01(RandomGeneratorSyncUsage.RGSJam);
380 //Print("Random Jam - " + rnd);
381 if (rnd < GetSyncChanceToJam())
382 return true;
383 }
384 return false;
385 }
386
387 void ShowBullet(int muzzleIndex)
388 {
389 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
390 {
391 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],1);
392 }
393 else
394 SelectionBulletShow();
395 }
396
397 void HideBullet(int muzzleIndex)
398 {
399 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
400 {
401 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],0);
402 }
403 else
404 SelectionBulletHide();
405 }
406
407 bool IsJammed() { return m_isJammed; }
408 bool CanEjectBullet() {return true;}
409 void SetJammed(bool value) { m_isJammed = value; }
412 {
413 int level = GetHealthLevel();
414
415 if (level >= 0 && level < m_ChanceToJam.Count())
416 return m_ChanceToJam[level];
417 else
418 return 0.0;
419 }
420
421 void SyncSelectionState(bool has_bullet, bool has_mag)
422 {
423 if (has_bullet)
424 {
425 string chamberedAmmoTypeName;
426 float chamberedAmmoDmg;
427
428 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
429 {
430 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
431 }
432 //ShowBullet(0);
433 SelectionBulletShow();
434 }
435 else
436 {
437 //HideBullet(0);
438 SelectionBulletHide();
439 EffectBulletHide(0);
440 }
441
442 if (has_mag)
443 ShowMagazine();
444 else
445 HideMagazine();
446 }
447
448 /*override void EEOnAfterLoad()
449 {
450 super.EEOnAfterLoad();
451
452 string chamberedAmmoTypeName;
453 float chamberedAmmoDmg;
454
455 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
456 {
457 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
458 }
459
460 }*/
461
463 {
464 int nMuzzles = GetMuzzleCount();
465 for (int i = 0; i < nMuzzles; ++i)
466 {
467 if (IsChamberFull(i))
468 {
469 ShowBullet(i);
470 float damage;
471 string ammoTypeName;
472 GetCartridgeInfo(i, damage, ammoTypeName);
473 EffectBulletShow(i, damage, ammoTypeName);
474 }
475 else
476 {
477 HideBullet(i);
478 EffectBulletHide(i);
479 }
480
481 Magazine mag = GetMagazine(i);
482 if (mag)
483 ShowMagazine();
484 else
485 HideMagazine();
486 }
487 }
488
489 override bool OnStoreLoad(ParamsReadContext ctx, int version)
490 {
491 if ( !super.OnStoreLoad(ctx, version) )
492 return false;
493
494
495 if (version >= 113)
496 {
497 int current_muzzle = 0;
498 if (!ctx.Read(current_muzzle))
499 {
500 Error("Weapon.OnStoreLoad " + this + " cannot read current muzzle!");
501 return false;
502 }
503
504 if (current_muzzle >= GetMuzzleCount() || current_muzzle < 0)
505 Error("Weapon.OnStoreLoad " + this + " trying to set muzzle index " + current_muzzle + " while it only has " + GetMuzzleCount() + " muzzles!");
506 else
507 SetCurrentMuzzle(current_muzzle);
508 }
509
510 if (version >= 105)
511 {
512 int mode_count = 0;
513 if (!ctx.Read(mode_count))
514 {
515 Error("Weapon.OnStoreLoad " + this + " cannot read mode count!");
516 return false;
517 }
518
519 for (int m = 0; m < mode_count; ++m)
520 {
521 int mode = 0;
522 if (!ctx.Read(mode))
523 {
524 Error("Weapon.OnStoreLoad " + this + " cannot read mode[" + m + "]");
525 return false;
526 }
527
528 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " OnStoreLoad - loaded muzzle[" + m + "].mode = " + mode); }
529 SetCurrentMode(m, mode);
530 }
531 }
532
533 if ( version >= 106 )
534 {
535 if ( !ctx.Read(m_isJammed) )
536 {
537 Error("Weapon.OnStoreLoad cannot load jamming state");
538 return false;
539 }
540 }
541
542 if (m_fsm)
543 {
544 if (!m_fsm.OnStoreLoad(ctx, version))
545 return false;
546
547 WeaponStableState wss = WeaponStableState.Cast(m_fsm.GetCurrentState());
548 if (wss)
549 {
550 SetGroundAnimFrameIndex(wss.m_animState);
551 }
552
553 }
554 else
555 {
556 int dummy = 0;
557 if (!ctx.Read(dummy))
558 return false;
559 }
560
561 return true;
562 }
563
565 {
566 if (m_fsm && m_fsm.IsRunning())
567 {
568 if (m_fsm.SaveCurrentFSMState(ctx))
569 {
570 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state saved."); }
571 }
572 else
573 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state NOT saved.");
574 }
575 else
576 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.SaveCurrentFSMState: trying to save weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
577 }
578
580 {
581 if (m_fsm)
582 {
583 if (m_fsm.LoadCurrentFSMState(ctx, version))
584 {
586 if (state)
587 {
588 SyncSelectionState(state.HasBullet(), state.HasMagazine());
589 state.SyncAnimState();
590 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " stable state loaded and synced."); }
591 return true;
592 }
593 else
594 {
595 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " unstable/error state loaded."); }
596 return false;
597 }
598 }
599 else
600 {
601 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " did not load.");
602 return false;
603 }
604 }
605 else
606 {
607 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.LoadCurrentFSMState: trying to load weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
608 return false;
609 }
610 }
611
612 override void AfterStoreLoad()
613 {
614 if (m_fsm)
615 {
616 int mi = GetCurrentMuzzle();
617 Magazine mag = GetMagazine(mi);
618 bool has_mag = mag != null;
619 bool has_bullet = !IsChamberEmpty(mi);
620 SyncSelectionState(has_bullet, has_mag);
621 }
622 }
623
625 {
626 super.OnStoreSave(ctx);
627
628 // current muzzle added in version 113
629 int current_muzzle = GetCurrentMuzzle();
630 ctx.Write(current_muzzle);
631
632 // fire mode added in version 105
633 int mode_count = GetMuzzleCount();
634 ctx.Write(mode_count);
635 for (int m = 0; m < mode_count; ++m)
636 ctx.Write(GetCurrentMode(m));
637
638 ctx.Write(m_isJammed);
639
640 if (m_fsm)
641 m_fsm.OnStoreSave(ctx);
642 else
643 {
644 int dummy = 0;
645 ctx.Write(dummy);
646 }
647 }
648
653 {
654 if (m_fsm)
655 return m_fsm.GetInternalStateID();
656 return 0;
657 }
658
663 {
664 if (m_fsm)
665 {
666 return m_fsm.GetCurrentStableStateID();
667 }
668 return 0;
669 }
670
676 {
677 if (m_fsm)
678 {
679 int mi = GetCurrentMuzzle();
680 Magazine mag = GetMagazine(mi);
681 bool has_mag = mag != null;
682 bool has_bullet = !IsChamberEmpty(mi);
683 bool has_jam = IsJammed();
684 array<MuzzleState> muzzleStates = GetMuzzleStates();
685 m_fsm.RandomizeFSMStateEx(muzzleStates, has_mag, has_jam);
687 }
688 }
689
692 {
693 array<MuzzleState> muzzleStates = new array<MuzzleState>;
694
695 int nMuzzles = GetMuzzleCount();
696 for (int i = 0; i < nMuzzles; ++i)
697 {
698 MuzzleState state = MuzzleState.U;
699 if (IsChamberFiredOut(i))
700 state = MuzzleState.F;
701 else if (IsChamberFull(i))
702 state = MuzzleState.L;
703 else if (IsChamberEmpty(i))
704 state = MuzzleState.E;
705 else
706 ErrorEx(string.Format("Unable to identify chamber state of muzzle %1", i));
707
708 muzzleStates.Insert(state);
709 }
710
711 return muzzleStates;
712 }
713
720
728 static Weapon_Base CreateWeaponWithAmmo( string weaponType, string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
729 {
730 Weapon_Base wpn = Weapon_Base.Cast(GetGame().CreateObjectEx( weaponType, vector.Zero, ECE_PLACE_ON_SURFACE ));
731
732 if ( !wpn )
733 {
734 ErrorEx(string.Format("%1 does not exist or is not a weapon.", weaponType));
735 return null;
736 }
737
738 wpn.SpawnAmmo(magazineType, flags);
739 return wpn;
740 }
741
748 bool SpawnAmmo( string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
749 {
750 // Attempt internal mag
751 if ( HasInternalMagazine(-1) && FillInnerMagazine(magazineType, flags) )
752 return true;
753
754 // Attempt mag attachment
755 if ( GetMagazineTypeCount(0) > 0 && SpawnAttachedMagazine(magazineType, flags) )
756 return true;
757
758 // Attempt chamber
759 if ( FillChamber(magazineType, flags) )
760 return true;
761
762 return false;
763 }
764
771 Magazine SpawnAttachedMagazine( string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
772 {
773 // Check if the gun has any magazines registered in config
774 if ( GetMagazineTypeCount(0) == 0 )
775 {
776 ErrorEx(string.Format("No 'magazines' config entry for %1.", this));
777 return null;
778 }
779
780 // Randomize when no specific one is given
781 if ( magazineType == "" )
782 {
783 if ( flags & WeaponWithAmmoFlags.MAX_CAPACITY_MAG)
784 magazineType = GetMaxMagazineTypeName(0);
785 else
786 magazineType = GetRandomMagazineTypeName(0);
787 }
788
789 EntityAI magAI = GetInventory().CreateAttachment(magazineType);
790 if (!magAI)
791 {
792 ErrorEx(string.Format("Failed to create and attach %1 to %2", GetDebugName(magAI), this));
793 return null;
794 }
795
796 Magazine mag;
797 if (!CastTo(mag, magAI))
798 {
799 ErrorEx(string.Format("Expected magazine, created: %1", GetDebugName(magAI)));
800 return null;
801 }
802
803 // Decide random quantity when enabled
804 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
805 mag.ServerSetAmmoCount(Math.RandomIntInclusive(0, mag.GetAmmoMax()));
806
807 if(MustBeChambered(0))
808 {
809 string bulletType;
810 float dmg;
811 if(mag.ServerAcquireCartridge(dmg,bulletType))
812 {
813 FillChamber(bulletType, flags);
814 }
815 }
816
817 // Fill chamber when flagged
818 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
819 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || chamberRng;
820 if (chamber || chamberRng)
821 {
822 FillChamber(magazineType, flags);
823 }
824
825 // FSM cares about magazine state
827 Synchronize();
828
829 return mag;
830 }
831
839 bool FillInnerMagazine( string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
840 {
841 // Don't try to fill it when there are none
842 if (!HasInternalMagazine(-1))
843 return false;
844
845 // Make sure the given ammoType is actually useable
846 if (ammoType != "")
847 {
848 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
849 return false;
850 }
851
852
853 bool didSomething = false;
854 bool needUpdateStateMachine = false;
855 int muzzCount = GetMuzzleCount();
856
857 bool ammoRng = ammoType == "";
858 bool ammoFullRng = ammoRng && (flags & WeaponWithAmmoFlags.AMMO_MAG_RNG);
859
860 // No full RNG flag, so pick one random and use only this one
861 if (ammoRng && !ammoFullRng)
862 ammoType = GetRandomChamberableAmmoTypeName(0);
863
864 // Fill the internal magazine
865 for (int i = 0; i < muzzCount; ++i)
866 {
867 bool loadAnyBullet = false;
868 int ammoCount = GetInternalMagazineMaxCartridgeCount(i);
869
870 // Decide random quantity when enabled
871 if ( flags & WeaponWithAmmoFlags.QUANTITY_RNG )
872 ammoCount = Math.RandomIntInclusive(0, ammoCount);
873
874 // Only do the things when there is actually ammo to fill
875 if (ammoCount > 0)
876 {
877 // Push in the cartridges
878 for (int j = 0; j < ammoCount; ++j)
879 {
880 // Full random, decide a new one for every cartridge
881 if ( ammoFullRng )
882 ammoType = GetRandomChamberableAmmoTypeName(i);
883
884 PushCartridgeToInternalMagazine(i, 0, ammoType);
885 loadAnyBullet = true;
886 didSomething = true;
887 }
888
889 if (loadAnyBullet && MustBeChambered(i))
890 {
891 if ( ammoFullRng )
892 ammoType = GetRandomChamberableAmmoTypeName(i);
893
894 if (FillSpecificChamber(i, 0, ammoType))
895 needUpdateStateMachine = true;
896
897 }
898 }
899 }
900
901 // Call the chamber method if asked for
902 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
903 if (chamber && FillChamber(ammoType, flags))
904 {
905 didSomething = true;
906 }
907
908 // Only fix the FSM and Synchronize when absolutely needed
909 if (!didSomething)
910 return false;
911
912 if( needUpdateStateMachine )
913 {
914 // FSM cares about chamber state
916 Synchronize();
917 }
918
919 return true;
920 }
921
929 bool FillChamber( string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER )
930 {
931 bool didSomething = false;
932 bool chamberFullRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG_SPORADIC);
933 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
934 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER);
935
936
937 if (chamber || chamberFullRng)
938 {
939 // Make sure the given ammoType is actually useable
940 if (ammoType != "")
941 {
942 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
943 return false;
944 }
945 else if (!(flags & WeaponWithAmmoFlags.AMMO_CHAMBER_RNG))
946 {
947 ammoType = GetRandomChamberableAmmoTypeName(0);
948 }
949
950 // fill chambers
951 int muzzCount = GetMuzzleCount();
952 int amountToChamber = muzzCount;
953
954 if (chamberRng)
955 amountToChamber = Math.RandomIntInclusive(0, muzzCount);
956
957
958 for (int m = 0; m < muzzCount; ++m)
959 {
960 if (chamberFullRng)
961 chamber = Math.RandomIntInclusive(0, 1);
962
963 if (chamber)
964 {
965 if (FillSpecificChamber(m))
966 {
967 didSomething = true;
968 amountToChamber--;
969 if (amountToChamber <= 0)
970 break;
971 }
972 }
973 }
974 }
975
976 if (!didSomething)
977 return false;
978
979 // FSM cares about chamber state
981 Synchronize();
982
983 return true;
984 }
985
986 bool FillSpecificChamber(int muzzleIndex, float dmg = 0, string ammoType = "")
987 {
988 if(!IsChamberEmpty(muzzleIndex))
989 return false;
990
991 if (ammoType == "")
992 {
993 ammoType = GetRandomChamberableAmmoTypeName(muzzleIndex);
994 }
995 else
996 {
997 if (!AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
998 return false;
999 }
1000
1001 return PushCartridgeToChamber(muzzleIndex, dmg, ammoType);
1002 }
1003
1005
1006
1007
1012 {
1013 int ac = GetInventory().AttachmentCount();
1014 int sc = GetInventory().GetAttachmentSlotsCount() + GetMuzzleCount();
1015 if (ac > sc) sc = ac; // fix of some weapons which has 1 attachments but 0 slots...
1016 return sc;
1017 };
1018
1027
1028 void OnFire(int muzzle_index)
1029 {
1030/*
1031 array<Man> players();
1032 GetGame().GetPlayers(players);
1033
1034 Man root = GetHierarchyRootPlayer();
1035
1036 if (!root)
1037 {
1038 return;
1039 }
1040
1041 vector safePosition = root.GetPosition() + (root.GetDirection() * "0 1 0" * 3.0);
1042
1043 Man other = null;
1044 foreach (auto player : players)
1045 {
1046 if (player != GetHierarchyRootPlayer())
1047 {
1048 player.SetPosition(safePosition);
1049 }
1050 }
1051*/
1052
1053 m_BurstCount++;
1054 }
1055
1056 void OnFireModeChange(int fireMode)
1057 {
1058 if ( !GetGame().IsDedicatedServer() )
1059 {
1060 EffectSound eff;
1061
1062 if ( fireMode == 0 )
1063 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Marked_Click_SoundSet", GetPosition());
1064 else
1065 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Simple_Click_SoundSet", GetPosition());
1066
1067 eff.SetAutodestroy(true);
1068 }
1069
1071 }
1072
1074 {
1076 {
1077 m_DelayedValidationTimer.Run(VALIDATE_DELAY , this, "ValidateAndRepair");
1078 }
1079 else
1080 {
1081 Error("[wpn] Weapon_Base::DelayedValidateAndRepair m_DelayedValidationTimer not initialized.");
1083 }
1084 }
1085
1087 {
1088 if ( m_fsm )
1089 m_fsm.ValidateAndRepair();
1090 }
1091
1092 override void OnInventoryEnter(Man player)
1093 {
1095
1096 if (GetGame().IsServer())
1097 {
1098 // The server knows about all of its attachments
1100 }
1101 else
1102 {
1103 // The client doesn't know it has attachments yet... give it a moment
1105 }
1106
1107 super.OnInventoryEnter(player);
1108 }
1109
1110 override void OnInventoryExit(Man player)
1111 {
1113 super.OnInventoryExit(player);
1114 }
1115
1116 override void EEItemAttached(EntityAI item, string slot_name)
1117 {
1118 super.EEItemAttached(item, slot_name);
1119
1120 GetPropertyModifierObject().UpdateModifiers();
1121 }
1122
1123 override void EEItemDetached(EntityAI item, string slot_name)
1124 {
1125 super.EEItemDetached(item, slot_name);
1126
1127 GetPropertyModifierObject().UpdateModifiers();
1128 }
1129
1130 override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
1131 {
1132 super.EEItemLocationChanged(oldLoc, newLoc);
1133
1134 if (newLoc.GetType() == InventoryLocationType.HANDS)
1135 {
1136 PlayerBase player;
1137 if (newLoc.GetParent() && PlayerBase.CastTo(player, newLoc.GetParent()))
1138 {
1139 HumanCommandMove cm = player.GetCommand_Move();
1140 if (cm)
1141 {
1142 cm.SetMeleeBlock(false);
1143 }
1144 }
1145 }
1146 }
1147
1148 override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
1149 {
1150 /*
1151 // TODO(kumarjac): Solve this in code instead, OnItemLocationChanged is called too late.
1152 // Maybe extend an option for items to specify what attachments they must
1153 // be synchronized with? Moving to 'DelayedValidateAndRepair' works for now.
1154 int muzzles = GetMuzzleCount();
1155 for (int muzzleIdx = 0; muzzleIdx < muzzles; muzzleIdx++)
1156 {
1157 Magazine mag = GetMagazine(muzzleIdx);
1158 Print(mag);
1159 if (!mag)
1160 continue;
1161
1162 Print(mag.GetInventory());
1163 if (!mag.GetInventory())
1164 continue;
1165
1166 InventoryLocation invLoc = new InventoryLocation();
1167 mag.GetInventory().GetCurrentInventoryLocation(invLoc);
1168
1169 GetGame().AddInventoryJunctureEx(null, this, invLoc, true, 1000);
1170 }
1171 */
1172
1173 super.OnItemLocationChanged(old_owner,new_owner);
1174
1175 // "resets" optics memory on optics
1176 PlayerBase player;
1177 if (PlayerBase.CastTo(player,old_owner))
1178 {
1179 player.SetReturnToOptics(false);
1180
1181 //optics item state reset
1182 ItemOptics optics;
1183 if (Class.CastTo(optics,GetAttachedOptics()))
1184 {
1185 player.SwitchOptics(optics,false);
1186 }
1187 }
1188
1189 if (old_owner != new_owner && PlayerBase.Cast(new_owner))
1190 SetWasIronSight(true); // reset ironsight/optic default
1191
1192 HideWeaponBarrel(false);
1193 }
1194
1195 override bool CanReleaseAttachment(EntityAI attachment)
1196 {
1197 if ( !super.CanReleaseAttachment( attachment ) )
1198 return false;
1199 Magazine mag = Magazine.Cast(attachment);
1200 if (mag)
1201 {
1202 PlayerBase player = PlayerBase.Cast( GetHierarchyRootPlayer() );
1203 if ( player )
1204 {
1205 if ( player.GetItemInHands() == this )
1206 return true;
1207 }
1208 return false;
1209 }
1210
1211 return true;
1212 }
1213
1214 override bool CanRemoveFromHands(EntityAI parent)
1215 {
1216 if (IsIdle())
1217 {
1218 return true;
1219 }
1220 if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " not in stable state=" + GetCurrentState().Type()); }
1221 return false; // do not allow removal of weapon while weapon is busy
1222 }
1223
1225 {
1227 if (GetInventory().GetCurrentInventoryLocation(il))
1228 {
1229 EntityAI parent = il.GetParent();
1230 DayZPlayer dayzp = DayZPlayer.Cast(parent);
1231 if (il.GetType() == InventoryLocationType.HANDS && dayzp)
1232 {
1233 bool remote = dayzp.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_REMOTE;
1234 return remote;
1235 }
1236 }
1237 return true;
1238 }
1239
1241 {
1242 DayZPlayer p = DayZPlayer.Cast(GetHierarchyParent());
1243 if (p && p.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_SERVER)
1244 {
1246
1248 e.WriteToContext(ctx);
1249
1251 wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " send 2 remote: sending e=" + e + " id=" + e.GetEventID() + " p=" + e.m_player + " m=" + e.m_magazine);
1252
1253 p.StoreInputForRemotes(ctx);
1254 }
1255 }
1256
1257
1259 {
1260 return new DefaultRecoil(this);
1261 }
1262
1263 int GetWeaponSpecificCommand(int weaponAction, int subCommand)
1264 {
1265 return subCommand;
1266 }
1267
1268 bool CanFire()
1269 {
1270 if (!IsChamberEmpty(GetCurrentMuzzle()) && !IsChamberFiredOut(GetCurrentMuzzle()) && !IsJammed() && !m_LiftWeapon && !IsDamageDestroyed())
1271 return true;
1272 return false;
1273 }
1274
1276 {
1277 ItemOptics optic = GetAttachedOptics();
1278 if (!optic)
1279 return true;
1280
1281 return optic.HasWeaponIronsightsOverride();
1282 }
1283
1285 bool InitDOFProperties(out array<float> temp_array)
1286 {
1287 if (GetGame().ConfigIsExisting("cfgWeapons " + GetType() + " PPDOFProperties"))
1288 {
1289 GetGame().ConfigGetFloatArray("cfgWeapons " + GetType() + " PPDOFProperties", temp_array);
1290 return true;
1291 }
1292 return false;
1293 }
1294
1295 bool InitReliability(out array<float> reliability_array)
1296 {
1297 if (GetGame().ConfigIsExisting("cfgWeapons " + GetType() + " Reliability ChanceToJam"))
1298 {
1299 GetGame().ConfigGetFloatArray("cfgWeapons " + GetType() + " Reliability ChanceToJam", reliability_array);
1300 return true;
1301 }
1302 return false;
1303 }
1304
1307 {
1308 if (ConfigIsExisting("WeaponLength"))
1309 {
1310 m_WeaponLength = ConfigGetFloat("WeaponLength");
1311 return true;
1312 }
1313 m_WeaponLength = 0.8; //default value if not set in config; should not be zero
1314 return false;
1315 }
1316
1319 {
1320 if (ConfigIsExisting("WeaponLiftCheckVerticalOffset"))
1321 {
1322 m_WeaponLiftCheckVerticalOffset = ConfigGetFloat("WeaponLiftCheckVerticalOffset");
1323 return true;
1324 }
1325 m_WeaponLiftCheckVerticalOffset = 0.0; //no offset by default
1326 return false;
1327 }
1328
1330 protected bool InitShoulderDistance()
1331 {
1332 if (ConfigIsExisting("ShoulderDistance"))
1333 {
1334 m_ShoulderDistance = ConfigGetFloat("ShoulderDistance");
1335 return true;
1336 }
1337
1339 return false;
1340 }
1341
1344 {
1345 if (ConfigIsExisting("ObstructionDistance"))
1346 {
1347 m_ObstructionDistance = ConfigGetFloat("ObstructionDistance");
1348 return true;
1349 }
1350
1352 return false;
1353 }
1354
1356 {
1357 return m_DOFProperties;
1358 }
1359
1361 {
1362 return m_WasIronSight;
1363 }
1364
1365 // used to remember last used ironsight/optic state
1366 void SetWasIronSight(bool state)
1367 {
1368 m_WasIronSight = state;
1369 }
1370
1371 // lifting weapon on obstcles
1373 {
1374 Object object;
1375 float obstruction;
1376 return LiftWeaponCheckEx(player, obstruction, object);
1377 }
1378
1385 bool UseWeaponObstruction(PlayerBase player, float obstructionValue, Object hitObject)
1386 {
1388 player.GetMovementState(ms);
1389
1390 #ifdef DIAG_DEVELOPER
1391 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 2) // allow always
1392 return true;
1393 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 6) // neverEver
1394 return false;
1395 #endif
1396
1397 // Obstruction in prone does not really work well, the weapon has no physical room
1398 // to move, so we instead always lift in such stance
1399 if (ms.IsInProne() || ms.IsInRaisedProne())
1400 {
1401 return false;
1402 }
1403
1404 // if ( m_ObstructionDistance != 0 && m_ObstructionDistance < 0.7 && ZombieBase.Cast( hitObject ) ) return true;
1405
1406 bool isDynamic;
1407 bool isStatic;
1408 if (hitObject)
1409 {
1410 isDynamic = dBodyIsDynamic(hitObject);
1411 isStatic = !isDynamic;
1412 }
1413
1414 #ifdef DIAG_DEVELOPER
1415 // alwaysDynamic || alwaysDynamicNeverStatic
1416 bool diagAlwaysDynamic = DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 3 || DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 5;
1417 if (diagAlwaysDynamic && isDynamic) // alwaysDynamic
1418 return true;
1419
1420 // neverStatic || alwaysDynamicNeverStatic
1421 bool diagNeverStatic = DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 4 || DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 5;
1422 if (diagNeverStatic && isStatic) // neverStatic
1423 return false;
1424 #endif
1425
1426 //CFGGAMEPLAY
1429 if (hitObject) // Can determine logic reliably
1430 {
1431 if ((isStatic && staticMode == EWeaponObstructionMode.DISABLED) || (isDynamic && dynamicMode == EWeaponObstructionMode.DISABLED))
1432 {
1433 return false;
1434 }
1435 else if ((isStatic && staticMode == EWeaponObstructionMode.ALWAYS) || (isDynamic && dynamicMode == EWeaponObstructionMode.ALWAYS))
1436 {
1437 return true;
1438 }
1439 }
1440 else if (obstructionValue > 0) // With no hit we have to guess whether object was dynamic or static
1441 {
1442 // Allow obstruction if it was already going on (and it is allowed in either mode)
1443 return staticMode != EWeaponObstructionMode.DISABLED && dynamicMode != EWeaponObstructionMode.DISABLED;
1444 }
1446
1447
1448 // Create a buffer between entering and leaving the lift to prevent
1449 // continuous state changes while the value is near the edge. (hysteresis)
1450 bool isLift = player.IsLiftWeapon();
1451
1452 if (isLift && obstructionValue > 0.9) // Retain lift while already lifted
1453 {
1454 return false;
1455 }
1456
1457 if (!isLift && obstructionValue >= 1.0) // Enter lift while not lifted and obstructed enough
1458 {
1459 return false;
1460 }
1461
1462 #ifdef DIAG_DEVELOPER // Keep this diag below all state conditions but above weapon type checks
1463 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_FORCEALLOW_OBSTRUCTION) == 1) // allow conditionally
1464 return true;
1465 #endif
1466
1467 // Allow obstruction with weapons that have their distance defined, otherwise don't
1468 return m_ObstructionDistance != 0;
1469 }
1470
1471 //----------------------------------------------------------------------------------------
1472 /*
1473 Computes/fills the provided `dst` with aim offsets relevant for the provided `characterStance`.
1474 Aiming angles are sampled as the normalized < -1.0, +1.0 > range.
1475 */
1476 protected void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
1477 {
1478 if (characterStance >= DayZPlayerConstants.STANCEIDX_RAISED)
1479 characterStance -= DayZPlayerConstants.STANCEIDX_RAISED;
1480
1481 // All following values were set by inspecting the character with
1482 // a weapon in-game and adjusting the offsets as such that with
1483 // the weapon lift diagnostic enabled, the shapes would nearly
1484 // perfectly overlap an equipped RIFLE.
1485 if (characterStance == DayZPlayerConstants.STANCEIDX_CROUCH)
1486 {
1487 dst.Insert( 0.0, -1.0, " 0.16 0.22 -0.04"); // fully down
1488 dst.Insert( 0.0, -0.5, " 0.14 0.13 0.00"); // halway down
1489 dst.Insert( 0.0, 0.0, " 0.13 0.04 -0.02"); // forward
1490 dst.Insert( 0.0, 0.5, " 0.13 0.01 -0.03"); // halfway up
1491 dst.Insert( 0.0, 1.0, " 0.14 -0.01 -0.04"); // fully up
1492 }
1493 else if (characterStance == DayZPlayerConstants.STANCEIDX_PRONE)
1494 {
1495 dst.Insert( 0.0, -1.0, " 0.120 -0.080 -0.030"); // fully down
1496 dst.Insert( 0.0, -0.5, " 0.120 -0.040 -0.040"); // halfway down
1497 dst.Insert( 0.0, 0.0, " 0.120 0.010 -0.022");// forward
1498 dst.Insert( 0.0, 0.5, " 0.120 -0.080 -0.050"); // halfway up
1499 dst.Insert( 0.0, 1.0, " 0.120 -0.160 -0.130"); // fully up
1500
1501 // prone is very special, so there are some points mapped
1502 // when aiming right and left (and up), to at least somewhat
1503 // correspond with the actual character animation
1504 dst.Insert( 0.3, 0.0, " 0.110 0.008 0.010");
1505 dst.Insert( 0.5, 0.0, " 0.000 0.100 0.025");
1506 dst.Insert( 0.8, 0.0, " 0.070 0.150 -0.014");
1507 dst.Insert( 1.0, 0.0, " 0.140 -0.050 0.020");
1508
1509 dst.Insert(-0.3, 0.0, " 0.090 -0.100 -0.025");
1510 dst.Insert(-0.5, 0.0, " 0.072 -0.064 -0.002");
1511 dst.Insert(-0.9, 0.0, " 0.129 -0.080 0.015");
1512 dst.Insert(-1.0, 0.0, " 0.140 -0.050 0.020");
1513
1514 dst.Insert( 0.5, 1.0, "-0.050 0.150 0.120");
1515 dst.Insert( 1.0, 1.0, " 0.150 -0.035 0.030");
1516 dst.Insert(-0.5, 1.0, " 0.050 -0.124 -0.040");
1517 dst.Insert(-1.0, 1.0, " 0.150 -0.035 0.030");
1518 }
1519 else
1520 {
1521 dst.Insert( 0.0, -1.0, "0.13 0.14 0.082"); // fully down
1522 dst.Insert( 0.0, -0.5, "0.13 0.05 0.048"); // halfway down
1523 dst.Insert( 0.0, 0.0, "0.13 0.01 -0.008"); // forward
1524 dst.Insert( 0.0, 0.5, "0.13 0.00 -0.015"); // halfway up
1525 dst.Insert( 0.0, 1.0, "0.13 -0.04 -0.016"); // fully up
1526 }
1527 }
1528
1529 //----------------------------------------------------------------------------------------
1530 /*
1531 Computes approximate offset during movement for this weapon.
1532 */
1533 protected vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
1534 {
1535 vector offset;
1536 if (lean != 0)
1537 {
1538 const float LEAN_VERT_OFFSET = -0.1;
1539 const float LEAN_HORIZ_OFFSET_L = 0;
1540 const float LEAN_HORIZ_OFFSET_R = 0.01;
1541 float aimStraightWeight = 1.0 - Math.AbsFloat(ud11); // 1 when aiming forward
1542 float leanOffset = lean * aimStraightWeight;
1543 offset += Vector( leanOffset * Math.Lerp(LEAN_HORIZ_OFFSET_L, LEAN_HORIZ_OFFSET_R, lean * 0.5 + 0.5), leanOffset * LEAN_VERT_OFFSET, 0);
1544 }
1545
1546
1547 float maxVelocity = Math.Max( Math.AbsFloat(localVelocity[0]), Math.AbsFloat(localVelocity[2]) );
1548 float peakVelocity = 0.5;
1549 float moveAmount01 = Math.Clamp(maxVelocity / peakVelocity, 0.0, 1.0);
1550 if (moveAmount01 != 0.0)
1551 {
1552 vector moveOffset = "0 -0.2 -0.1";
1553 float ud01 = (ud11 * 0.5) + 0.5;
1554 float aimWeight = Math.Clamp(1.0 - (ud01 * 2), 0, 1);
1555 // The issue is only apparent when looking down and the 2nd power seems
1556 // to follow the actual visual relatively accurately
1557 float moveWeight = moveAmount01 * Math.Pow(aimWeight, 2.0);
1558 offset = offset + (moveWeight * moveOffset);
1559 }
1560
1561 return offset;
1562 }
1563
1564 //----------------------------------------------------------------------------------------
1570 protected void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity = "0 0 0")
1571 {
1572 // Construct stable trasformation matrix that somewhat aligns with the weapon transform,
1573 // without actually using the weapon as reference - the weapon will move during the lift/obstruction
1574 // in more than 1 axis and is therefore not realiable source of truth.
1575 vector resTM[4];
1576 resTM[0] = Vector(direction[0], 0, direction[2]).Normalized();
1577 resTM[0] = vector.RotateAroundZeroDeg(resTM[0], vector.Up, 90);
1578 resTM[2] = direction;
1579 resTM[1] = resTM[2] * resTM[0];
1580 resTM[3] = start;
1581
1582 // Approximate the roll angle of leaning
1583 float leanAngle = hms.m_fLeaning * 35;
1584 vector rotTM[3];
1585 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1586 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1587 Math3D.YawPitchRollMatrix( Vector(xAimHandsOffset , yAimHandsOffset, leanAngle), rotTM );
1588 Math3D.MatrixMultiply3(resTM, rotTM, resTM);
1589
1590 // Draw relative transformation matrix diagnostic
1591 #ifndef SERVER
1592 #ifdef DIAG_DEVELOPER
1593 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetTransform(resTM);
1594 #endif
1595 #endif
1596
1597 // Compute normalized aiming angles
1598 float udAngle = hcw.GetBaseAimingAngleUD();
1599 float lrAngle = hcw.GetBaseAimingAngleLR();
1600
1601 float ud01 = Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX, udAngle); // 0-1
1602 float ud11 = Math.Clamp((ud01 * 2) - 1, -1, 1); // -1, 1
1603 float lr01 = Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_LR_MIN, DayZPlayerCamera1stPerson.CONST_LR_MAX, lrAngle); // 0-1
1604 float lr11 = Math.Clamp((lr01 * 2) - 1, -1, 1);
1605
1606 #ifndef SERVER
1607 #ifdef DIAG_DEVELOPER
1608 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetAimAngles(udAngle, lrAngle, ud11, lr11);
1609 #endif
1610 #endif
1611
1612 // Fetch approximate aim offset position based on current state
1613 Blend2DVector aimOffsets = new Blend2DVector();
1614 GetApproximateAimOffsets(aimOffsets, hms.m_iStanceIdx);
1615 vector offset = aimOffsets.Blend(lr11, ud11);
1616
1617 // Apply height offset if any is defined
1619 {
1620 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1621 }
1622
1623 // Approximate the shift caused by movement. There is an enormous shift when aiming
1624 // downwards, creating insane shift that we will compensate by shifting the offset
1625 // based on the movement and aiming angle:
1626 vector moveOffset = GetApproximateMovementOffset(localVelocity, hms.m_iStanceIdx, hms.m_fLeaning, ud11, lr11);
1627 offset += moveOffset;
1628
1629 // While changing stances the weapon moves slightly forward and although this may
1630 // cause some unwanted lifts ocasionally, it should prevent some unwanted clipping
1631 if (hcm.IsChangingStance())
1632 {
1633 offset[2] = offset[2] + 0.05;
1634 }
1635
1636 offset = offset.InvMultiply3(rotTM);
1637
1638 // Finally use the computed offset as the start position.
1639 start = offset.Multiply4(resTM);
1640 }
1641 //----------------------------------------------------------------------------------------
1644 {
1645 float approximateLength = Math.Max(0, m_WeaponLength / 1.5) * m_WeaponLength;
1646 return m_ShoulderDistance + approximateLength;
1647 }
1648
1649 //----------------------------------------------------------------------------------------
1657 bool LiftWeaponCheckEx(PlayerBase player, out float outObstruction, out Object outHitObject)
1658 {
1659 bool wasLift = m_LiftWeapon;
1660 vector lastLiftPosition = m_LastLiftPosition;
1661
1662 m_LiftWeapon = false;
1663
1664 // [14.2.2025]
1665 // The following selection check should be *unused* for some time now.
1666 // Leaving commented out for future reference, should the removal have unforseen consequences.
1667 // if ( HasSelection("Usti hlavne") )
1668 // return false;
1669
1670 if (!player)
1671 {
1672 #ifndef SERVER
1673 #ifdef DIAG_DEVELOPER
1674 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1675 #endif
1676 #endif
1677 Print("Error: No weapon owner for LiftWeaponCheckEx, returning.");
1678 return false;
1679 }
1680
1681 // Obstruction can only occur if the weapon is rasied
1682 HumanMovementState movementState = new HumanMovementState();
1683 player.GetMovementState(movementState);
1684 if (!movementState.IsRaised())
1685 return false;
1686
1687 // Suppress weapon obstruction during melee attack preventing state inconsistency
1688 if (movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE || movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE2)
1689 {
1690 #ifndef SERVER
1691 #ifdef DIAG_DEVELOPER
1692 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1693 #endif
1694 #endif
1695 return false;
1696 }
1697
1698
1699 // If possible use aiming angles instead as these will work consistently
1700 // and independently of any cameras, etc.
1701 vector direction;
1702 HumanInputController hic = player.GetInputController();
1703 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1704 HumanCommandMove hcm = player.GetCommand_Move();
1705 if (hcw)
1706 {
1707 vector yawPitchRoll = Vector(
1708 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1710 0.0);
1711
1712 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1713 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1714
1715 yawPitchRoll[0] = yawPitchRoll[0] + xAimHandsOffset;
1716 yawPitchRoll[1] = Math.Clamp( yawPitchRoll[1] + yAimHandsOffset, DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX );
1717
1718 direction = yawPitchRoll.AnglesToVector();
1719 }
1720 else // Fallback to previously implemented logic
1721 {
1722 // freelook raycast
1723 if (hic.CameraIsFreeLook())
1724 {
1725 if (player.m_DirectionToCursor != vector.Zero)
1726 {
1727 direction = player.m_DirectionToCursor;
1728 }
1729 // if player raises weapon in freelook
1730 else
1731 {
1732 direction = MiscGameplayFunctions.GetHeadingVector(player);
1733 }
1734 }
1735 else
1736 {
1737 direction = GetGame().GetCurrentCameraDirection(); // exception for freelook. Much better this way!
1738 }
1739 }
1740
1741 // Reference bone to perform checks from
1742 vector start;
1743 int boneIdx = player.GetBoneIndexByName("Neck");
1744 if (boneIdx == -1)
1745 {
1746 start = player.GetPosition()[1] + 1.5;
1747 }
1748 else
1749 {
1750 start = player.GetBonePositionWS(boneIdx);
1751 }
1752
1753 // Update the ray origin and direction with approximations of character state
1754 vector velocity = GetVelocity(player);
1755 velocity = player.VectorToLocal(velocity);
1756 ApproximateWeaponLiftTransform(start, direction, movementState, hic, hcw, hcm, velocity);
1757
1758 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1759
1760 // weapon length including effective attachments
1761 float weaponLength = m_WeaponLength + effectiveAttachmentLength;
1762 // distance of point from 'shoulder' (start) from which the weapon length should be computed,
1763 // pistols have the start point further, near the character wrist whereas longer rifles, typically
1764 // the ones with buttstocks have the start point at 0 distance, ie. directly at shoulder
1765 float weaponStartDist = m_ShoulderDistance;
1766 float weaponEndDist = weaponStartDist + weaponLength;
1767
1768 // Weapon start and end positions as an offset from the character shoulder
1769 vector weaponStart = start + (weaponStartDist * direction);
1770 vector weaponEnd = start + (weaponEndDist * direction);
1771
1772 // distance of point from 'shoulder' (start) at which the weapon is "fully obstructed", i.e.
1773 // needs to be lifted to be able to be physically fit wherever it is. Shifted by effective
1774 // attachment length to account for e.g. suppressors that make the weapon "longer".
1775 // Defaults to FLT_MAX if no value is configured, effectivelly always lifting weapon instead of obstructing.
1776 float baseObstructionLength = m_ObstructionDistance;
1777 if (baseObstructionLength==0)
1778 {
1779 baseObstructionLength = ApproximateBaseObstructionLength();
1780 }
1781
1782 float weaponObstructionDist = baseObstructionLength + effectiveAttachmentLength;
1783 float rayRadius = 0.02;
1784
1785 #ifndef SERVER
1786 #ifdef DIAG_DEVELOPER // Retrieve possible override
1787 float overrideObstDist = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_ObstructionDistance;
1788 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetWeaponRayParams(start, direction, weaponStartDist, weaponEndDist, effectiveAttachmentLength, m_ObstructionDistance, weaponObstructionDist, rayRadius);
1789 weaponObstructionDist = overrideObstDist;
1790 rayRadius = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_RayRadiusOverride;
1791 #endif
1792 #endif
1793
1794 // Extend the raycast range by 30 cm to allow checking for intersections even
1795 // under shallow angles and other odd cases
1796 float rayEndDist = weaponEndDist + 0.30;
1797 vector rayEnd = start + rayEndDist * direction;
1798
1799 // Prepare raycast params and perform the cast in fire geo
1800 RaycastRVParams rayParm = new RaycastRVParams(start, rayEnd, player, rayRadius);
1801 rayParm.flags = CollisionFlags.ALLOBJECTS;
1802 rayParm.type = ObjIntersect.Fire;
1803
1804 RaycastRVResult hitResult;
1805 float hitFraction;
1806 float hitDist;
1807
1808 array<ref RaycastRVResult> results = {};
1809 if (!DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1810 {
1811 hitFraction = 0;
1812 }
1813 else
1814 {
1815 // In case of multiple results, find the best (nearest) match, RaycastRVProxy doesn't guarantee any sensible order
1816 int numRes = results.Count();
1817 if (numRes == 1)
1818 {
1819 hitResult = results[0];
1820 }
1821 else
1822 {
1823 int bi = -1;
1824 float maxDist = float.MAX;
1825 for (int i = 0, nr = results.Count(); i < nr; ++i)
1826 {
1827 float sqDist = vector.DistanceSq(results[i].pos, weaponStart);
1828 if (sqDist < maxDist)
1829 {
1830 maxDist = sqDist;
1831 bi = i;
1832 }
1833 }
1834 hitResult = results[bi];
1835 }
1836
1837 if (LiftWeaponRaycastResultCheck(hitResult))
1838 {
1839 float len0 = (hitResult.pos - start).Length();
1840 float len1 = (weaponEnd - start).Length(); // Do not include 'rayEnd' - pretend as if the computation happened in <start, weaponEnd>
1841
1842 if (len0 <= 0 || len1 <= 0)
1843 {
1844 hitFraction = 1;
1845 }
1846 else
1847 {
1848 hitFraction = len0 / len1;
1849 }
1850 hitDist = hitFraction * weaponEndDist;
1851 }
1852 else
1853 {
1854 hitFraction = 0;
1855 hitDist = 0;
1856 }
1857 }
1858
1859 #ifndef SERVER
1860 #ifdef DIAG_DEVELOPER // isect diag
1861 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetIntersectionParams(hitResult, hitFraction, hitDist);
1862 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetLastPosition(lastLiftPosition);
1863 #endif // !isect diag
1864 #endif
1865
1866 // Start by assuming that we want to retain state
1867 bool wantsLift = wasLift;
1868
1869 // Sq. distance of weapon movement required to trigger lift (in)
1870 const float inThreshold = 0.002;
1871 // Sq. distance of weapon movement required to trigger lift (out)
1872 const float outThreshold = 0.003;
1873 const float noIsctOutThreshold = 0.01;
1874 // Max num of ticks with no hit for which hysteresis will persist
1875 // value chosen by iteration, should be approx 0.333s
1876 const int maxNumMissedTicks = 10;
1877
1878 // Min angle in degrees change from last lift to stop lifting
1879 // Base threshold of 0.75 degrees + 0.6 degrees per meter of weapon length
1880 float angleThreshold = 0.75 + Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1881
1882 // Update state when a hit is registered
1883 if (hitFraction != 0)
1884 {
1885 vector v1 = hitResult.pos - weaponEnd;
1886 vector v2 = hitResult.pos - rayEnd;
1887 float d = vector.Dot(v1, v2);
1888 // But leave some threshold where previous state is kept
1889 // to prevent excessive switches from occuring
1890 if (!wasLift && d > inThreshold)
1891 {
1892 wantsLift = true;
1893 }
1894 else if (wasLift && d < -outThreshold)
1895 {
1896 wantsLift = false;
1897 }
1898
1899 m_LastLiftPosition = hitResult.pos;
1900 m_LastLiftHit = player.GetSimulationTimeStamp();
1901 }
1902 else
1903 {
1904 // With no hit and no previous lift
1905 if (lastLiftPosition == vector.Zero)
1906 {
1907 wantsLift = false;
1909 }
1910 // See if previous hit wasn't very close to our current position,
1911 // in which case simply don't lift the weapon
1912 else
1913 {
1914 vector v3 = (lastLiftPosition - start).Normalized();
1915 vector v4 = (weaponEnd-start).Normalized();
1916 float d2 = vector.Dot(v3, v4);
1917 // no isect, angle delta check
1918 if (Math.Acos(d2) > (angleThreshold * Math.DEG2RAD)) // if relative angle is > x degree, stop lifting
1919 {
1920 wantsLift = false;
1922 }
1923 // no isect, distance check
1924 else
1925 {
1926 float d3 = vector.Dot( lastLiftPosition - weaponEnd, (start-weaponEnd).Normalized() );
1927 if (d3 < -noIsctOutThreshold)
1928 {
1929 wantsLift = false;
1931 }
1932 float lastObstruction = hcw.GetWeaponObstruction();
1933 // fallback in case offending object disappears or moves
1934 int timeSinceHit = player.GetSimulationTimeStamp() - m_LastLiftHit;
1935 if (timeSinceHit > maxNumMissedTicks)
1936 {
1937 wantsLift = false;
1939 }
1940 else if (wantsLift && m_LastLiftPosition != vector.Zero) // pretended hit to retain obstruction in this very tight edge case
1941 {
1942 float l0 = (m_LastLiftPosition - start).Length();
1943 float l1 = (weaponEnd - start).Length();
1944 if (l0 <= 0 || l1 <= 0)
1945 {
1946 hitFraction = 1;
1947 }
1948 else
1949 {
1950 hitFraction = l0 / l1;
1951 }
1952 hitDist = hitFraction * weaponEndDist;
1953 }
1954 }
1955 }
1956 }
1957
1958 // lift is desired
1959 if (wantsLift)
1960 {
1961 // Remap the hit distance into the <obstruction, weaponWithAttachmentLength> range as 0..1 (and beyond)
1962 float begDist = weaponObstructionDist;
1963 float endDist = weaponStartDist + weaponLength;
1964
1965 float obstFraction;
1966 if (begDist < endDist)
1967 obstFraction = Math.InverseLerp( begDist, endDist, hitDist );
1968
1969 if (hitResult)
1970 outHitObject = hitResult.obj;
1971
1972 outObstruction = 1.0 - obstFraction;
1973 m_LiftWeapon = true;
1974 return true;
1975 }
1976
1977 return false;
1978 }
1979
1986 float GetObstructionPenetrationDistance(float obstruction01)
1987 {
1988 float baseObstructionLength = m_ObstructionDistance;
1989 if (baseObstructionLength==0)
1990 {
1991 baseObstructionLength = ApproximateBaseObstructionLength();
1992 }
1993
1994 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1995 float weaponEnd = m_ShoulderDistance + m_WeaponLength + effectiveAttachmentLength;
1996 return weaponEnd - Math.Lerp(weaponEnd, baseObstructionLength + effectiveAttachmentLength, obstruction01);
1997 }
1998
2001 {
2002 return res.surface.IsSolid();
2003 }
2004
2007 {
2008 ItemBase attachment;
2009 if (HasBayonetAttached())
2010 {
2011 int bayonetIndex = GetBayonetAttachmentIdx();
2012 attachment = ItemBase.Cast(GetInventory().FindAttachment(bayonetIndex));
2013 }
2014 else
2015 {
2016 attachment = GetAttachedSuppressor();
2017 }
2018
2019 if (attachment)
2020 {
2021 return Math.Max(attachment.m_ItemModelLength + attachment.m_ItemAttachOffset, 0);
2022 }
2023 else
2024 {
2025 return 0;
2026 }
2027 }
2028
2029 void SetSyncJammingChance( float jamming_chance )
2030 {
2031 m_ChanceToJamSync = jamming_chance;
2032 }
2033
2044 bool EjectCartridge(int muzzleIndex, out float ammoDamage, out string ammoTypeName)
2045 {
2046 if (IsChamberEjectable(muzzleIndex))
2047 {
2048 if (PopCartridgeFromChamber(muzzleIndex, ammoDamage, ammoTypeName))
2049 return true;
2050 }
2051 else if (GetInternalMagazineCartridgeCount(muzzleIndex) > 0)
2052 {
2053 if (PopCartridgeFromInternalMagazine(muzzleIndex, ammoDamage, ammoTypeName))
2054 return true;
2055 }
2056 return false;
2057 }
2058
2060 {
2061 float damage = 0.0;
2062 string type;
2063
2064 for (int mi = 0; mi < src.GetMuzzleCount(); ++mi)
2065 {
2066 if (!src.IsChamberEmpty(mi))
2067 {
2068 if (src.GetCartridgeInfo(mi, damage, type))
2069 {
2070 PushCartridgeToChamber(mi, damage, type);
2071 }
2072 }
2073
2074 for (int ci = 0; ci < src.GetInternalMagazineCartridgeCount(mi); ++ci)
2075 {
2076 if (src.GetInternalMagazineCartridgeInfo(mi, ci, damage, type))
2077 {
2078 PushCartridgeToInternalMagazine(mi, damage, type);
2079 }
2080 }
2081 }
2082
2083 int dummy_version = int.MAX;
2084 PlayerBase parentPlayer = PlayerBase.Cast(src.GetHierarchyRootPlayer());
2085 if (!parentPlayer)
2086 dummy_version -= 1;
2088 src.OnStoreSave(ctx.GetWriteContext());
2089 OnStoreLoad(ctx.GetReadContext(), dummy_version);
2090 return true;
2091 }
2092
2094 override void SetBayonetAttached(bool pState, int slot_idx = -1)
2095 {
2096 m_BayonetAttached = pState;
2097 m_BayonetAttachmentIdx = slot_idx;
2098 }
2099
2100 override bool HasBayonetAttached()
2101 {
2102 return m_BayonetAttached;
2103 }
2104
2106 {
2108 }
2109
2110 override void SetButtstockAttached(bool pState, int slot_idx = -1)
2111 {
2112 m_ButtstockAttached = pState;
2113 m_ButtstockAttachmentIdx = slot_idx;
2114 }
2115
2116 override bool HasButtstockAttached()
2117 {
2118 return m_ButtstockAttached;
2119 }
2120
2122 {
2124 }
2125
2126 void HideWeaponBarrel(bool state)
2127 {
2128 if ( !GetGame().IsDedicatedServer() )//hidden for client only
2129 {
2130 ItemOptics optics = GetAttachedOptics();
2131 if ( optics && !optics.AllowsDOF() && m_weaponHideBarrelIdx != -1 )
2132 {
2133 SetSimpleHiddenSelectionState(m_weaponHideBarrelIdx,!state);
2134 }
2135 }
2136 }
2137
2139 {
2141 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,1);
2142 else
2143 SelectionMagazineShow();
2144 }
2145
2147 {
2149 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,0);
2150 else
2151 SelectionMagazineHide();
2152 }
2153
2154 override EntityAI ProcessMeleeItemDamage(int mode = 0)
2155 {
2156 EntityAI attachment;
2157
2158 switch (mode)
2159 {
2160 case 0:
2161 super.ProcessMeleeItemDamage();
2162 break;
2163
2164 case 1:
2165 attachment = GetInventory().FindAttachment(m_ButtstockAttachmentIdx);
2166 break;
2167
2168 case 2:
2169 attachment = GetInventory().FindAttachment(m_BayonetAttachmentIdx);
2170 break;
2171
2172 default:
2173 super.ProcessMeleeItemDamage();
2174 break;
2175 }
2176
2177 if (attachment)
2178 {
2179 attachment.ProcessMeleeItemDamage();
2180 return attachment;
2181 }
2182
2183 return this;
2184 }
2185
2187 {
2188 return true;
2189 }
2190
2192 {
2193 return m_BurstCount;
2194 }
2195
2197 {
2198 m_BurstCount = 0;
2199 }
2200
2214
2215 override bool CanBeUsedForSuicide()
2216 {
2217 if (!ConfigGetBool("isSuicideWeapon"))
2218 return false;
2219
2220 return super.CanBeUsedForSuicide();
2221 }
2222
2223 //Debug menu Spawn Ground Special
2224 override void OnDebugSpawn()
2225 {
2227 }
2228
2229 bool AddJunctureToAttachedMagazine(PlayerBase player, int timeoutMS)
2230 {
2231 Magazine mag = GetMagazine(GetCurrentMuzzle());
2233 if (mag)
2234 {
2235 return GetGame().AddInventoryJunctureEx(player, mag, il, false, timeoutMS);
2236 }
2237
2238 return true;
2239 }
2240
2242 {
2243 Magazine mag = GetMagazine(GetCurrentMuzzle());
2244 if (mag)
2245 {
2246 GetGame().ClearJunctureEx(player, mag);
2247 }
2248 }
2249
2250 void SetNextWeaponMode(int muzzleIndex)
2251 {
2252 SetNextMuzzleMode(muzzleIndex);
2253 }
2254
2255 // CoolDown
2256 void SetCoolDown( float coolDownTime )
2257 {
2258 m_coolDownTime = coolDownTime;
2259 }
2260 void UpdateCoolDown( float dt ) { m_coolDownTime -= dt; }
2262 {
2263 return m_coolDownTime > 0;
2264 }
2265
2266 // If there are bullet in attached / internal magazine then bullet must be in chamber also
2267 bool MustBeChambered(int muzzleIndex)
2268 {
2269 return false;
2270 }
2271
2272#ifdef TEST_WEAPON_SYSNC_REPAIR
2273 void SetSyncStable(bool value)
2274 {
2275 m_SyncStable = value;
2276 if (!value)
2277 {
2278 m_SyncStableTime = GetGame().GetTickTime();
2279 }
2280 }
2281
2282 bool IsSyncStable()
2283 {
2284 return m_SyncStable;
2285 }
2286#endif
2287};
2288
const int INPUT_UDT_WEAPON_REMOTE_EVENT
eBleedingSourceType GetType()
void wpnDebugPrint(string s)
void AddAction(typename actionName)
Определения AdvancedCommunication.c:220
class Blend2D< Class T > Blend2DVector
const int ECE_PLACE_ON_SURFACE
Определения CentralEconomy.c:37
EWeaponObstructionMode
Определения CfgGameplayDataJson.c:365
EWeaponObstructionMode staticMode
!! all member variables must correspond with the cfggameplay.json file contents !!...
Определения CfgGameplayDataJson.c:384
EWeaponObstructionMode dynamicMode
Определения CfgGameplayDataJson.c:385
void Synchronize()
Определения CombinationLock.c:151
override bool IsJammed()
Определения Crossbow.c:22
DayZGame g_Game
Определения DayZGame.c:3868
PhxInteractionLayers
Определения DayZPhysics.c:2
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:5364
string Type
Определения JsonDataContaminatedArea.c:11
bool OnStoreLoad(ParamsReadContext ctx, int version)
Определения ModifiersManager.c:265
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 bool MagazineTypeToAmmoType(string magazineType, out string ammoType)
Helper method.
Определения AmmoTypes.c:14
Определения AmmoTypes.c:2
static float GetAmmoWeightByBulletType(string bulletType)
Определения AmmunitionPiles.c:6
ammo pile base
Определения AmmunitionPiles.c:3
proto native float GetTickTime()
Returns current time from start of the game.
override ScriptCallQueue GetCallQueue(int call_category)
Определения DayZGame.c:1187
bool ClearJunctureEx(Man player, notnull EntityAI item)
Определения Global/game.c:762
bool AddInventoryJunctureEx(Man player, notnull EntityAI item, InventoryLocation dst, bool test_dst_occupancy, int timeout_ms)
Определения Global/game.c:741
proto native vector GetCurrentCameraDirection()
proto native void ConfigGetFloatArray(string path, out TFloatArray values)
Get array of floats from config on path.
static EWeaponObstructionMode GetWeaponObstructionModeStatic()
Определения CfgGameplayHandler.c:262
static EWeaponObstructionMode GetWeaponObstructionModeDynamic()
Определения CfgGameplayHandler.c:267
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
Определения DefaultRecoil.c:2
Определения EnDebug.c:241
override void SetAutodestroy(bool auto_destroy)
Sets whether Effect automatically cleans up when it stops.
Определения EffectSound.c:603
Wrapper class for managing sound through SEffectManager.
Определения EffectSound.c:5
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:434
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:998
proto native bool CameraIsFreeLook()
returns true if freelook is active
Определения human.c:18
int m_iStanceIdx
current command's id
Определения human.c:1154
int m_CommandTypeId
Определения human.c:1153
float m_fLeaning
current movement (0 idle, 1 walk, 2-run, 3-sprint), only if the command has a movement
Определения human.c:1156
bool IsInProne()
Определения human.c:1173
bool IsInRaisedProne()
Определения human.c:1179
bool IsRaised()
Определения human.c:1161
Определения human.c:1152
proto native EntityAI GetParent()
returns parent of current inventory location
proto native int GetType()
returns type of InventoryLocation
InventoryLocation.
Определения InventoryLocation.c:29
bool AllowsDOF()
returns 'true' for non-magnifying optics
Определения ItemOptics.c:482
proto native bool HasWeaponIronsightsOverride()
is weapon in optics mode or not
Определения ItemOptics.c:2
static bool IsWeaponLogEnable()
Определения 3_Game/tools/Debug.c:718
Определения 3_Game/tools/Debug.c:594
Определения 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:169
Manager class for managing Effect (EffectParticle, EffectSound)
Определения EffectManager.c:6
proto void Call(func fn, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL)
adds call into the queue with given parameters and arguments (arguments are held in memory until the ...
proto native ParamsReadContext GetReadContext()
proto native ParamsWriteContext GetWriteContext()
proto bool Write(void value_out)
proto bool Read(void value_in)
Определения DayZPlayerImplement.c:63
override void InitStateMachine()
Определения Magnum.c:85
override void HideBullet(int muzzleIndex)
Определения Magnum.c:323
override void ShowBullet(int muzzleIndex)
Определения Magnum.c:300
override void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
Определения Pistol_Base.c:636
override vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
Определения Pistol_Base.c:684
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:2105
override int GetButtstockAttachmentIdx()
Определения Weapon_Base.c:2121
void HideMagazine()
Определения Weapon_Base.c:2146
ref array< float > GetWeaponDOF()
Определения Weapon_Base.c:1355
int GetBurstCount()
Определения Weapon_Base.c:2191
bool CopyWeaponStateFrom(notnull Weapon_Base src)
Определения Weapon_Base.c:2059
bool IsShowingChamberedBullet()
Определения Weapon_Base.c:2186
Magazine SpawnAttachedMagazine(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to spawn and attach a magazine.
Определения Weapon_Base.c:771
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:1366
bool IsRemoteWeapon()
Определения Weapon_Base.c:1224
bool JamCheck(int muzzleIndex)
Определения Weapon_Base.c:374
float m_coolDownTime
Определения Weapon_Base.c:77
void SyncEventToRemote(WeaponEventBase e)
Определения Weapon_Base.c:1240
void DelayedValidateAndRepair()
Определения Weapon_Base.c:1073
override bool HasBayonetAttached()
Определения Weapon_Base.c:2100
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:986
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:1533
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:421
float GetEffectiveAttachmentLength()
Returns effective length of attachments that influence total weapon length.
Определения Weapon_Base.c:2006
bool m_isJammed
weapon state machine
Определения Weapon_Base.c:50
void EEFired(int muzzleType, int mode, string ammoType)
Определения Weapon_Base.c:341
void ShowMagazine()
Определения Weapon_Base.c:2138
static Weapon_Base CreateWeaponWithAmmo(string weaponType, string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Create weapon with ammo.
Определения Weapon_Base.c:728
float m_ShoulderDistance
Определения Weapon_Base.c:66
int GetWeaponSpecificCommand(int weaponAction, int subCommand)
Определения Weapon_Base.c:1263
bool FillInnerMagazine(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the inner magazine.
Определения Weapon_Base.c:839
int m_weaponHideBarrelIdx
Определения Weapon_Base.c:62
bool InitWeaponLiftCheckVerticalOffset()
gets weapon vertical offset from config for weaponlift raycast
Определения Weapon_Base.c:1318
float GetObstructionPenetrationDistance(float obstruction01)
Определения Weapon_Base.c:1986
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:2044
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:1011
void HideWeaponBarrel(bool state)
Определения Weapon_Base.c:2126
bool InitShoulderDistance()
gets approximate weapon distance from shoulder from config
Определения Weapon_Base.c:1330
override bool CanReleaseAttachment(EntityAI attachment)
Определения Weapon_Base.c:1195
void ShowBullet(int muzzleIndex)
Определения Weapon_Base.c:387
void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity="0 0 0")
Определения Weapon_Base.c:1570
bool CanProcessAction(int action, int actionType)
Определения Weapon_Base.c:236
void HideBullet(int muzzleIndex)
Определения Weapon_Base.c:397
array< MuzzleState > GetMuzzleStates()
Helper method for RandomizeFSMState.
Определения Weapon_Base.c:691
void SetCharged(bool value)
Определения Weapon_Base.c:158
void ResetBurstCount()
Определения Weapon_Base.c:2196
bool InitDOFProperties(out array< float > temp_array)
Initializes DOF properties for weapon's ironsight/optics cameras.
Определения Weapon_Base.c:1285
override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
Определения Weapon_Base.c:1130
void SetNextWeaponMode(int muzzleIndex)
Определения Weapon_Base.c:2250
bool AddJunctureToAttachedMagazine(PlayerBase player, int timeoutMS)
Определения Weapon_Base.c:2229
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:1110
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:1360
bool m_BayonetAttached
Определения Weapon_Base.c:52
bool CanFire()
Определения Weapon_Base.c:1268
void RandomizeFSMState()
With the parameters given, selects a random suitable state for the FSM of the weapon @WARNING: Weapon...
Определения Weapon_Base.c:675
bool LiftWeaponCheckEx(PlayerBase player, out float outObstruction, out Object outHitObject)
Определения Weapon_Base.c:1657
bool InitObstructionDistance()
gets weapon obstruction distance from shoulder at which the weapon is fully obstructed
Определения Weapon_Base.c:1343
bool m_WeaponOpen
Определения Weapon_Base.c:55
float GetSyncChanceToJam()
Определения Weapon_Base.c:410
bool m_Charged
Определения Weapon_Base.c:54
int m_weaponAnimState
Определения Weapon_Base.c:60
void SetSyncJammingChance(float jamming_chance)
Определения Weapon_Base.c:2029
override void OnDebugSpawn()
Определения Weapon_Base.c:2224
bool FillChamber(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the chamber.
Определения Weapon_Base.c:929
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:2000
float GetChanceToJam()
Определения Weapon_Base.c:411
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:462
bool LiftWeaponCheck(PlayerBase player)
Определения Weapon_Base.c:1372
override void AfterStoreLoad()
Определения Weapon_Base.c:612
bool CanEjectBullet()
Определения Weapon_Base.c:408
bool ProcessWeaponAbortEvent(WeaponEventBase e)
Определения Weapon_Base.c:315
override bool CanRemoveFromHands(EntityAI parent)
Определения Weapon_Base.c:1214
override void EEInit()
Определения Weapon_Base.c:135
override void SetButtstockAttached(bool pState, int slot_idx=-1)
Определения Weapon_Base.c:2110
PropertyModifiers GetPropertyModifierObject()
Определения Weapon_Base.c:1019
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:2215
void ClearJunctureToAttachedMagazine(PlayerBase player)
Определения Weapon_Base.c:2241
RecoilBase SpawnRecoilObject()
Определения Weapon_Base.c:1258
override void EEItemDetached(EntityAI item, string slot_name)
Определения Weapon_Base.c:1123
int GetCurrentStableStateID()
tries to return identifier of current stable state (or nearest stable state if unstable state is curr...
Определения Weapon_Base.c:662
void InitStateMachine()
Определения Weapon_Base.c:133
ref PropertyModifiers m_PropertyModifierObject
Определения Weapon_Base.c:74
bool IsJammed()
Определения Weapon_Base.c:407
void ValidateAndRepair()
Определения Weapon_Base.c:1086
const int SAMF_DEFAULT
Full highest capacity magazine + chambered round.
Определения Weapon_Base.c:41
void OnFire(int muzzle_index)
Определения Weapon_Base.c:1028
bool m_LiftWeapon
Определения Weapon_Base.c:51
override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
Определения Weapon_Base.c:1148
int m_ButtstockAttachmentIdx
Определения Weapon_Base.c:59
override void SetActions()
Определения Weapon_Base.c:2201
void ResetWeaponAnimState()
Определения Weapon_Base.c:334
void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
Определения Weapon_Base.c:1476
bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
Определения Weapon_Base.c:579
void SetCoolDown(float coolDownTime)
Определения Weapon_Base.c:2256
bool CanEnterIronsights()
Определения Weapon_Base.c:1275
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:2154
override bool OnStoreLoad(ParamsReadContext ctx, int version)
Определения Weapon_Base.c:489
bool IsCoolDown()
Определения Weapon_Base.c:2261
bool UseWeaponObstruction(PlayerBase player, float obstructionValue, Object hitObject)
Определения Weapon_Base.c:1385
override void OnStoreSave(ParamsWriteContext ctx)
Определения Weapon_Base.c:624
bool CanChamberBullet(int muzzleIndex, Magazine mag)
Определения Weapon_Base.c:324
bool CanProcessWeaponEvents()
Определения Weapon_Base.c:270
void UpdateCoolDown(float dt)
Определения Weapon_Base.c:2260
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:748
void SaveCurrentFSMState(ParamsWriteContext ctx)
Определения Weapon_Base.c:564
void OnFireModeChange(int fireMode)
Определения Weapon_Base.c:1056
override bool HasButtstockAttached()
Определения Weapon_Base.c:2116
void SetJammed(bool value)
Определения Weapon_Base.c:409
float ApproximateBaseObstructionLength()
Approximate ObstructionDistance for weapons with no configuration. Returned length doesn't account fo...
Определения Weapon_Base.c:1643
const int SAMF_RNG
Random bullet quantity + maybe chambered round.
Определения Weapon_Base.c:43
bool MustBeChambered(int muzzleIndex)
Определения Weapon_Base.c:2267
bool InitReliability(out array< float > reliability_array)
Определения Weapon_Base.c:1295
override void EEItemAttached(EntityAI item, string slot_name)
Определения Weapon_Base.c:1116
bool InitWeaponLength()
gets weapon length from config for weaponlift raycast
Определения Weapon_Base.c:1306
override void OnInventoryEnter(Man player)
Определения Weapon_Base.c:1092
bool IsWeaponOpen()
Определения Weapon_Base.c:163
override void SetBayonetAttached(bool pState, int slot_idx=-1)
attachment helpers (firearm melee)
Определения Weapon_Base.c:2094
int GetInternalStateID()
Определения Weapon_Base.c:652
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/tools/Debug.c:822
void SetCalcDetails(string details)
Определения 3_Game/tools/Debug.c:816
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:450
static float Dot(vector v1, vector v2)
Returns Dot product of vector v1 and vector v2.
Определения EnConvert.c:271
static const vector Zero
Определения EnConvert.c:110
proto vector InvMultiply3(vector mat[3])
Invert-transforms vector.
static const vector Up
Определения EnConvert.c:107
proto vector AnglesToVector()
Converts spherical coordinates (yaw, pitch, roll in degrees) to unit length vector.
Определения EnConvert.c:106
override string GetDebugName()
Определения dayzplayer.c:1170
DayZPlayerInstanceType
defined in C++
Определения dayzplayer.c:1068
DayZPlayerConstants
defined in C++
Определения dayzplayer.c:602
Serializer ParamsReadContext
Определения gameplay.c:15
proto native CGame GetGame()
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.
array< string > TStringArray
Определения EnScript.c:709
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
No flags.
Определения EnProfiler.c:11
proto native vector GetVelocity(notnull IEntity ent)
Returns linear velocity.
proto native bool dBodyIsDynamic(notnull IEntity ent)
class JsonUndergroundAreaTriggerData GetPosition
Определения UndergroundAreaLoader.c:9
const int CALL_CATEGORY_GAMEPLAY
Определения 3_Game/tools/tools.c:10