DayZ 1.24
Loading...
Searching...
No Matches
Weapon_Base.c
Go to the documentation of this file.
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;
44
45 protected const float DEFAULT_DAMAGE_ON_SHOT = 0.05;
47 protected ref WeaponFSM m_fsm;
48 protected bool m_isJammed = false;
49 protected bool m_LiftWeapon = false;
50 protected bool m_BayonetAttached;
51 protected bool m_ButtstockAttached;
52 protected bool m_Charged = false;
53 protected bool m_WeaponOpen = false;
54 protected int m_BurstCount;
57 protected int m_weaponAnimState = -1;
58 protected int m_magazineSimpleSelectionIndex = -1;
59 protected int m_weaponHideBarrelIdx = -1; //index in simpleHiddenSelections cfg array
60 protected float m_DmgPerShot = 0; //default is set to zero, since C++ solution has been implemented. See 'damageBarrel' and 'barrelArmor' in configs.
61 protected float m_WeaponLength;
63 protected float m_ShoulderDistance;
65 ref array<int> m_bulletSelectionIndex = new array<int>;
67 ref array<float> m_ChanceToJam = new array<float>;
68 protected float m_ChanceToJamSync = 0;
71
73 {
74 //m_DmgPerShot = ConfigGetFloat("damagePerShot");
75 m_BayonetAttached = false;
76 m_ButtstockAttached = false;
77 m_BayonetAttachmentIdx = -1;
78 m_ButtstockAttachmentIdx = -1;
79 m_BurstCount = 0;
80 m_DOFProperties = new array<float>;
81
82 if (ConfigIsExisting("simpleHiddenSelections"))
83 {
85 ConfigGetTextArray("simpleHiddenSelections", selectionNames);
86 m_weaponHideBarrelIdx = selectionNames.Find("hide_barrel");
87 m_magazineSimpleSelectionIndex = selectionNames.Find("magazine");
88
89 int bulletIndex = selectionNames.Find("bullet");
90 if (bulletIndex != -1)
91 {
92 m_bulletSelectionIndex.Insert(bulletIndex);
93
94 for (int i = 2; i < 100; i++)
95 {
96 bulletIndex = selectionNames.Find(string.Format("bullet%1", i));
97 if (bulletIndex != -1)
98 m_bulletSelectionIndex.Insert(bulletIndex);
99 else
100 break;
101 }
102 }
103 }
104
105 InitWeaponLength();
106 InitWeaponLiftCheckVerticalOffset();
107 InitShoulderDistance();
108 InitDOFProperties(m_DOFProperties);
109 if (GetGame().IsServer())
110 InitReliability(m_ChanceToJam);
112 }
113
115
116 override void EEInit()
117 {
118 super.EEInit();
119
120 if (GetGame().IsServer())
121 GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(AssembleGun);
122 }
123
125 {
126 m_fsm.SetInitialState(initState);
127 SetCharged(!initState.IsDischarged());
128 SetWeaponOpen(!initState.IsWeaponOpen());
129 SetGroundAnimFrameIndex(initState.m_animState);
130 }
131
133 {
134 return m_Charged;
135 }
136
137 void SetCharged(bool value)
138 {
139 m_Charged = value;
140 }
141
143 {
144 return m_WeaponOpen;
145 }
146
148 {
149 m_WeaponOpen = value;
150 }
151
152 override protected float GetWeightSpecialized(bool forceRecalc = false)
153 {
154 float baseWeight = GetInventoryAndCargoWeight(forceRecalc);
155 float ammoWeight;
156 float ammoDamage;
158
159 int muzzleCount = GetMuzzleCount();
160#ifdef DEVELOPER
161 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
162 {
163 WeightDebugData data1 = WeightDebug.GetWeightDebug(this);
164 data1.SetCalcDetails("TWPN: " + m_ConfigWeight + "(item weight) + " + baseWeight + "(contents weight)");
165 }
166#endif
168 {
169 //chamber weight
170 if (!IsChamberEmpty(muzzleIndex))
171 {
172 ammoTypeName = GetChamberAmmoTypeName(muzzleIndex);
173 ammoWeight += g_Game.ConfigGetFloat(string.Format("CfgMagazines %1 weight", ammoTypeName));
174
175#ifdef DEVELOPER
176 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
177 {
178 WeightDebugData data2 = WeightDebug.GetWeightDebug(this);
179 data2.AddCalcDetails(g_Game.ConfigGetFloat("CfgMagazines " + ammoTypeName + " weight").ToString() + "(chamber weight)");
180 }
181#endif
182 }
183
184 //correctly calculates internal magazine weight based on the ammo type of each bullet
185 if (HasInternalMagazine(muzzleIndex))
186 {
187#ifdef DEVELOPER
189#endif
190 int cartridgeCount = GetInternalMagazineCartridgeCount(muzzleIndex);
192 {
193 GetInternalMagazineCartridgeInfo(muzzleIndex, cartridgeIndex, ammoDamage, bulletTypeName);
195#ifdef DEVELOPER
196 debugInternalMagWeight += g_Game.ConfigGetFloat("CfgMagazines " + ammoTypeName + " weight");
197#endif
198 }
199#ifdef DEVELOPER
200
201 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
202 {
203 WeightDebugData data3 = WeightDebug.GetWeightDebug(this);
204 data3.AddCalcDetails(debugInternalMagWeight.ToString() + "(internal mag weight)");
205 }
206#endif
207 }
208
209 }
210 return ammoWeight + baseWeight + GetConfigWeightModified();
211 }
214
216 {
217 return false; // @TODO
218 }
226 {
227 int count = GetAbilityCount();
228 for (int i = 0; i < count; ++i)
229 {
230 AbilityRecord rec = GetAbility(i);
231 if (rec.m_action == action && rec.m_actionType == actionType)
232 return true;
233 }
234 return false;
235 }
239 int GetAbilityCount() { return m_abilities.Count(); }
244 AbilityRecord GetAbility(int index) { return m_abilities.Get(index); }
245
249 bool CanProcessWeaponEvents() { return m_fsm && m_fsm.IsRunning(); }
250
255 WeaponStateBase GetCurrentState() { return m_fsm.GetCurrentState(); }
256
261 {
262 return CanProcessWeaponEvents() && GetCurrentState().IsWaitingForActionFinish();
263 }
264
265 bool IsIdle()
266 {
267 return CanProcessWeaponEvents() && GetCurrentState().IsIdle();
268 }
269
275 {
276 SyncEventToRemote(e);
277
278 // @NOTE: synchronous events not handled by fsm
279 if (e.GetEventID() == WeaponEventID.SET_NEXT_MUZZLE_MODE)
280 {
281 SetNextMuzzleMode(GetCurrentMuzzle());
282 return true;
283 }
284
285 if (m_fsm.ProcessEvent(e) == ProcessEventResult.FSM_OK)
286 return true;
287
288 //if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("FSM refused to process event (no transition): src=" + GetCurrentState().ToString() + " event=" + e.ToString()); }
289 return false;
290 }
295 {
296 SyncEventToRemote(e);
297
299 m_fsm.ProcessAbortEvent(e, aa);
300 return aa == ProcessEventResult.FSM_OK;
301 }
302
304 {
305 return CanChamberFromMag(muzzleIndex, mag) && (!IsChamberFull(muzzleIndex) || IsChamberFiredOut(muzzleIndex) || !IsInternalMagazineFull(muzzleIndex));
306 }
307
309 {
310 m_weaponAnimState = state;
311 SetGroundAnimFrameIndex(state);
312 }
314 {
315 if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[wpnfsm] " + Object.GetDebugName(this) + " resetting anim state: " + typename.EnumToString(PistolAnimState, m_weaponAnimState) + " --> " + typename.EnumToString(PistolAnimState, -1));
316 m_weaponAnimState = -1;
317 }
318 int GetWeaponAnimState() { return m_weaponAnimState; }
319
320 void EEFired(int muzzleType, int mode, string ammoType)
321 {
322 if (!GetGame().IsDedicatedServer())
323 {
324 ItemBase suppressor = GetAttachedSuppressor();
325
326 // Muzzle flash & overheating effects
327 ItemBase.PlayFireParticles(this, muzzleType, ammoType, this, suppressor, "CfgWeapons");
328 IncreaseOverheating(this, ammoType, this, suppressor, "CfgWeapons");
329
330 if (suppressor)
331 {
332 ItemBase.PlayFireParticles(this, muzzleType, ammoType, suppressor, NULL, "CfgVehicles");
333 suppressor.IncreaseOverheating(this, ammoType, this, suppressor, "CfgVehicles");
334 }
335 }
336
337 //obsolete, replaced by C++ solution!
338 /*
339 if (GetGame().IsServer())
340 {
341 AddHealth("","Health",-m_DmgPerShot); //damages weapon
342 if (suppressor)
343 suppressor.AddHealth("","Health",-m_DmgPerShot); //damages suppressor; TODO add suppressor damage coeficient/parameter (?) to suppressors/weapons (?)
344 }
345 */
346 //JamCheck(muzzleType);
347
348#ifdef DIAG_DEVELOPER
349 MiscGameplayFunctions.UnlimitedAmmoDebugCheck(this);
350#endif
351 }
352
354 {
355 PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
356 if (player)
357 {
358 float rnd = player.GetRandomGeneratorSyncManager().GetRandom01(RandomGeneratorSyncUsage.RGSJam);
359 //Print("Random Jam - " + rnd);
360 if (rnd < GetSyncChanceToJam())
361 return true;
362 }
363 return false;
364 }
365
367 {
368 if (m_bulletSelectionIndex.Count() > muzzleIndex)
369 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex], 1);
370 else
371 SelectionBulletShow();
372 }
373
375 {
376 if (m_bulletSelectionIndex.Count() > muzzleIndex)
377 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex], 0);
378 else
379 SelectionBulletHide();
380 }
381
382 bool IsJammed() { return m_isJammed; }
383 bool CanEjectBullet() {return true;}
384 void SetJammed(bool value) { m_isJammed = value; }
385 float GetSyncChanceToJam() { return m_ChanceToJamSync; }
387 {
388 int level = GetHealthLevel();
389
390 if (level >= 0 && level < m_ChanceToJam.Count())
391 return m_ChanceToJam[level];
392 else
393 return 0.0;
394 }
395
397 {
398 if (has_bullet)
399 {
401 float chamberedAmmoDmg;
402
403 if (GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName))
404 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
405 //ShowBullet(0);
406 SelectionBulletShow();
407 }
408 else
409 {
410 //HideBullet(0);
411 SelectionBulletHide();
412 EffectBulletHide(0);
413 }
414
415 if (has_mag)
416 ShowMagazine();
417 else
418 HideMagazine();
419 }
420
421 /*override void EEOnAfterLoad()
422 {
423 super.EEOnAfterLoad();
424
425 string chamberedAmmoTypeName;
426 float chamberedAmmoDmg;
427
428 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
429 {
430 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
431 }
432
433 }*/
434
436 {
437 int nMuzzles = GetMuzzleCount();
438 for (int i = 0; i < nMuzzles; ++i)
439 {
440 if (IsChamberFull(i))
441 {
442 ShowBullet(i);
443 float damage;
444 string ammoTypeName;
445 GetCartridgeInfo(i, damage, ammoTypeName);
446 EffectBulletShow(i, damage, ammoTypeName);
447 }
448 else
449 {
450 HideBullet(i);
451 EffectBulletHide(i);
452 }
453
454 Magazine mag = GetMagazine(i);
455 if (mag)
456 ShowMagazine();
457 else
458 HideMagazine();
459 }
460 }
461
462 override bool OnStoreLoad(ParamsReadContext ctx, int version)
463 {
464 if (!super.OnStoreLoad(ctx, version))
465 return false;
466
467
468 if (version >= 113)
469 {
470 int current_muzzle = 0;
471 if (!ctx.Read(current_muzzle))
472 {
473 Error("Weapon.OnStoreLoad " + this + " cannot read current muzzle!");
474 return false;
475 }
476
477 if (current_muzzle >= GetMuzzleCount() || current_muzzle < 0)
478 Error("Weapon.OnStoreLoad " + this + " trying to set muzzle index " + current_muzzle + " while it only has " + GetMuzzleCount() + " muzzles!");
479 else
480 SetCurrentMuzzle(current_muzzle);
481 }
482
483 if (version >= 105)
484 {
485 int mode_count = 0;
486 if (!ctx.Read(mode_count))
487 {
488 Error("Weapon.OnStoreLoad " + this + " cannot read mode count!");
489 return false;
490 }
491
492 for (int m = 0; m < mode_count; ++m)
493 {
494 int mode = 0;
495 if (!ctx.Read(mode))
496 {
497 Error("Weapon.OnStoreLoad " + this + " cannot read mode[" + m + "]");
498 return false;
499 }
500
501 if (LogManager.IsWeaponLogEnable()) wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " OnStoreLoad - loaded muzzle[" + m + "].mode = " + mode);
502 SetCurrentMode(m, mode);
503 }
504 }
505
506 if (version >= 106)
507 {
508 if (!ctx.Read(m_isJammed))
509 {
510 Error("Weapon.OnStoreLoad cannot load jamming state");
511 return false;
512 }
513 }
514
515 if (m_fsm)
516 {
517 if (!m_fsm.OnStoreLoad(ctx, version))
518 return false;
519
520 WeaponStableState wss = WeaponStableState.Cast(m_fsm.GetCurrentState());
521 if (wss)
522 SetGroundAnimFrameIndex(wss.m_animState);
523
524 }
525 else
526 {
527 int dummy = 0;
528 if (!ctx.Read(dummy))
529 return false;
530 }
531
532 return true;
533 }
534
536 {
537 if (m_fsm && m_fsm.IsRunning())
538 {
539 if (m_fsm.SaveCurrentFSMState(ctx))
540 {
541 if (LogManager.IsWeaponLogEnable()) wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state saved.");
542 }
543 else
544 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " state NOT saved.");
545 }
546 else
547 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.SaveCurrentFSMState: trying to save weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
548 }
549
551 {
552 if (m_fsm)
553 {
554 if (m_fsm.LoadCurrentFSMState(ctx, version))
555 {
556 WeaponStableState state = WeaponStableState.Cast(GetCurrentState());
557 if (state)
558 {
559 SyncSelectionState(state.HasBullet(), state.HasMagazine());
560 state.SyncAnimState();
561 if (LogManager.IsWeaponLogEnable()) wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " stable state loaded and synced.");
562 return true;
563 }
564 else
565 {
566 if (LogManager.IsWeaponLogEnable()) wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " unstable/error state loaded.");
567 return false;
568 }
569 }
570 else
571 {
572 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " did not load.");
573 return false;
574 }
575 }
576 else
577 {
578 Error("[wpnfsm] " + Object.GetDebugName(this) + " Weapon.LoadCurrentFSMState: trying to load weapon without FSM (or uninitialized weapon) this=" + this + " type=" + GetType());
579 return false;
580 }
581 }
582
583 override void AfterStoreLoad()
584 {
585 if (m_fsm)
586 {
587 int mi = GetCurrentMuzzle();
588 Magazine mag = GetMagazine(mi);
589 bool has_mag = mag != null;
590 bool has_bullet = !IsChamberEmpty(mi);
591 SyncSelectionState(has_bullet, has_mag);
592 }
593 }
594
596 {
597 super.OnStoreSave(ctx);
598
599 // current muzzle added in version 113
600 int current_muzzle = GetCurrentMuzzle();
601 ctx.Write(current_muzzle);
602
603 // fire mode added in version 105
604 int mode_count = GetMuzzleCount();
605 ctx.Write(mode_count);
606 for (int m = 0; m < mode_count; ++m)
607 ctx.Write(GetCurrentMode(m));
608
609 ctx.Write(m_isJammed);
610
611 if (m_fsm)
612 m_fsm.OnStoreSave(ctx);
613 else
614 {
615 int dummy = 0;
616 ctx.Write(dummy);
617 }
618 }
619
624 {
625 if (m_fsm)
626 return m_fsm.GetInternalStateID();
627 return 0;
628 }
629
634 {
635 if (m_fsm)
636 return m_fsm.GetCurrentStableStateID();
637 return 0;
638 }
639
645 {
646 if (m_fsm)
647 {
648 int mi = GetCurrentMuzzle();
649 Magazine mag = GetMagazine(mi);
650 bool has_mag = mag != null;
651 bool has_bullet = !IsChamberEmpty(mi);
652 bool has_jam = IsJammed();
653 array<MuzzleState> muzzleStates = GetMuzzleStates();
654 m_fsm.RandomizeFSMStateEx(muzzleStates, has_mag, has_jam);
655 ForceSyncSelectionState();
656 }
657 }
658
661 {
663
664 int nMuzzles = GetMuzzleCount();
665 for (int i = 0; i < nMuzzles; ++i)
666 {
668 if (IsChamberFiredOut(i))
669 state = MuzzleState.F;
670 else if (IsChamberFull(i))
671 state = MuzzleState.L;
672 else if (IsChamberEmpty(i))
673 state = MuzzleState.E;
674 else
675 ErrorEx(string.Format("Unable to identify chamber state of muzzle %1", i));
676
677 muzzleStates.Insert(state);
678 }
679
680 return muzzleStates;
681 }
682
689
697 static Weapon_Base CreateWeaponWithAmmo(string weaponType, string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER)
698 {
700
701 if (!wpn)
702 {
703 ErrorEx(string.Format("%1 does not exist or is not a weapon.", weaponType));
704 return null;
705 }
706
707 wpn.SpawnAmmo(magazineType, flags);
708 return wpn;
709 }
710
717 bool SpawnAmmo(string magazineType = "", int flags = WeaponWithAmmoFlags.CHAMBER)
718 {
719 // Attempt internal mag
720 if (HasInternalMagazine(-1) && FillInnerMagazine(magazineType, flags))
721 return true;
722
723 // Attempt mag attachment
724 if (GetMagazineTypeCount(0) > 0 && SpawnAttachedMagazine(magazineType, flags))
725 return true;
726
727 // Attempt chamber
728 if (FillChamber(magazineType, flags))
729 return true;
730
731 return false;
732 }
733
741 {
742 // Check if the gun has any magazines registered in config
743 if (GetMagazineTypeCount(0) == 0)
744 {
745 ErrorEx(string.Format("No 'magazines' config entry for %1.", this));
746 return null;
747 }
748
749 // Randomize when no specific one is given
750 if (magazineType == "")
751 {
752 if (flags & WeaponWithAmmoFlags.MAX_CAPACITY_MAG)
753 magazineType = GetMaxMagazineTypeName(0);
754 else
755 magazineType = GetRandomMagazineTypeName(0);
756 }
757
758 EntityAI magAI = GetInventory().CreateAttachment(magazineType);
759 if (!magAI)
760 {
761 ErrorEx(string.Format("Failed to create and attach %1 to %2", GetDebugName(magAI), this));
762 return null;
763 }
764
766 if (!CastTo(mag, magAI))
767 {
768 ErrorEx(string.Format("Expected magazine, created: %1", GetDebugName(magAI)));
769 return null;
770 }
771
772 // Decide random quantity when enabled
773 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
774 mag.ServerSetAmmoCount(Math.RandomIntInclusive(0, mag.GetAmmoMax()));
775
776 // Fill chamber when flagged
777 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
778 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || chamberRng;
779 if (chamber || chamberRng)
780 FillChamber(magazineType, flags);
781
782 // FSM cares about magazine state
783 RandomizeFSMState();
784 Synchronize();
785
786 return mag;
787 }
788
796 bool FillInnerMagazine(string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER)
797 {
798 // Don't try to fill it when there are none
799 if (!HasInternalMagazine(-1))
800 return false;
801
802 // Make sure the given ammoType is actually useable
803 if (ammoType != "")
804 {
806 return false;
807 }
808
809
810 bool didSomething = false;
811 int muzzCount = GetMuzzleCount();
812
813 bool ammoRng = ammoType == "";
814 bool ammoFullRng = ammoRng && (flags & WeaponWithAmmoFlags.AMMO_MAG_RNG);
815
816 // No full RNG flag, so pick one random and use only this one
817 if (ammoRng && !ammoFullRng)
818 ammoType = GetRandomChamberableAmmoTypeName(0);
819
820 // Fill the internal magazine
821 for (int i = 0; i < muzzCount; ++i)
822 {
823 int ammoCount = GetInternalMagazineMaxCartridgeCount(i);
824
825 // Decide random quantity when enabled
826 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
828
829 // Only do the things when there is actually ammo to fill
830 if (ammoCount > 0)
831 {
832 // Push in the cartridges
833 for (int j = 0; j < ammoCount; ++j)
834 {
835 // Full random, decide a new one for every cartridge
836 if (ammoFullRng)
837 ammoType = GetRandomChamberableAmmoTypeName(i);
838
839 PushCartridgeToInternalMagazine(i, 0, ammoType);
840 didSomething = true;
841 }
842 }
843 }
844
845 // Call the chamber method if asked for
846 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
847 if (chamber && FillChamber(ammoType, flags))
848 didSomething = true;
849
850 // Does not need any FSM fixing, FSM does not care about inner magazines
851
852 return didSomething;
853 }
854
862 bool FillChamber(string ammoType = "", int flags = WeaponWithAmmoFlags.CHAMBER)
863 {
864 // Quickly check if there are any chambers we can fill
865 int muzzCount = GetMuzzleCount();
866 bool anyEmpty = false;
867
868 for (int m = 0; m < muzzCount; ++m)
869 {
870 if (IsChamberEmpty(m))
871 {
872 anyEmpty = true;
873 break;
874 }
875 }
876
877 if (!anyEmpty)
878 return false;
879
880 // Make sure the given ammoType is actually useable
881 if (ammoType != "")
883 return false;
884
885 // Just so we don't '&' wastefully in a loop
886 bool didSomething = false;
887 bool chamberFullRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG_SPORADIC);
888 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
889 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER);
890
892 {
894
895 // No need to do this for full rng, as that will roll for every muzzle
896 if (chamberRng)
898
899 bool chamberAmmoRng = (ammoType == "");
900 bool chamberAmmoFullRng = chamberAmmoRng && (flags & WeaponWithAmmoFlags.AMMO_CHAMBER_RNG);
901
902 // No full RNG flag, so pick one random and use only this one
904 ammoType = GetRandomChamberableAmmoTypeName(0);
905
906 for (int i = 0; i < muzzCount; ++i)
907 {
908 // Skip when there's already something in the chamber
909 if (!IsChamberEmpty(i))
910 continue;
911
912 // Roll the rng when enabled
913 if (chamberFullRng)
915
916 // We chambering
917 if (chamber)
918 {
919 // Full random, decide a new one for every muzzle
921 ammoType = GetRandomChamberableAmmoTypeName(i);
922
923 // Push it
924 PushCartridgeToChamber(i, 0, ammoType);
925 didSomething = true;
926
927 // Stop chambering when we hit the desired amount
929 if (amountToChamber <= 0)
930 break;
931 }
932 }
933 }
934
935 // Only fix the FSM and Synchronize when absolutely needed
936 if (!didSomething)
937 return false;
938
939 // FSM cares about chamber state
940 RandomizeFSMState();
941 Synchronize();
942
943 return true;
944 }
945
947
948
952 override int GetSlotsCountCorrect()
953 {
954 int ac = GetInventory().AttachmentCount();
955 int sc = GetInventory().GetAttachmentSlotsCount() + GetMuzzleCount();
956 if (ac > sc) sc = ac; // fix of some weapons which has 1 attachments but 0 slots...
957 return sc;
958 };
959
961 {
962 if (!m_PropertyModifierObject)
963 m_PropertyModifierObject = new PropertyModifiers(this);
964 return m_PropertyModifierObject;
965 }
966
968 {
969 /*
970 array<Man> players();
971 GetGame().GetPlayers(players);
972
973 Man root = GetHierarchyRootPlayer();
974
975 if (!root)
976 {
977 return;
978 }
979
980 vector safePosition = root.GetPosition() + (root.GetDirection() * "0 1 0" * 3.0);
981
982 Man other = null;
983 foreach (auto player : players)
984 {
985 if (player != GetHierarchyRootPlayer())
986 {
987 player.SetPosition(safePosition);
988 }
989 }
990 */
991
992 m_BurstCount++;
993 }
994
996 {
997 if (!GetGame().IsDedicatedServer())
998 {
1000
1001 if (fireMode == 0)
1002 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Marked_Click_SoundSet", GetPosition());
1003 else
1004 eff = SEffectManager.PlaySound("Fire_Mode_Switch_Simple_Click_SoundSet", GetPosition());
1005
1006 eff.SetAutodestroy(true);
1007 }
1008
1009 ResetBurstCount();
1010 }
1011
1013 {
1014 if (m_fsm)
1015 m_fsm.ValidateAndRepair();
1016 }
1017
1018 override void OnInventoryEnter(Man player)
1019 {
1020 m_PropertyModifierObject = null;
1021
1022 ValidateAndRepair();
1023
1024 super.OnInventoryEnter(player);
1025 }
1026
1027 override void OnInventoryExit(Man player)
1028 {
1029 m_PropertyModifierObject = null;
1030 super.OnInventoryExit(player);
1031 }
1032
1033 override void EEItemAttached(EntityAI item, string slot_name)
1034 {
1035 super.EEItemAttached(item, slot_name);
1036
1037 GetPropertyModifierObject().UpdateModifiers();
1038 }
1039
1040 override void EEItemDetached(EntityAI item, string slot_name)
1041 {
1042 super.EEItemDetached(item, slot_name);
1043
1044 GetPropertyModifierObject().UpdateModifiers();
1045 }
1046
1048 {
1049 super.EEItemLocationChanged(oldLoc, newLoc);
1050
1051 if (newLoc.GetType() == InventoryLocationType.HANDS)
1052 {
1054 if (newLoc.GetParent() && PlayerBase.CastTo(player, newLoc.GetParent()))
1055 {
1056 HumanCommandMove cm = player.GetCommand_Move();
1057 if (cm)
1058 cm.SetMeleeBlock(false);
1059 }
1060 }
1061 }
1062
1064 {
1065 super.OnItemLocationChanged(old_owner, new_owner);
1066
1067 // "resets" optics memory on optics
1069 if (PlayerBase.CastTo(player, old_owner))
1070 {
1071 player.SetReturnToOptics(false);
1072
1073 //optics item state reset
1075 if (Class.CastTo(optics, GetAttachedOptics()))
1076 player.SwitchOptics(optics, false);
1077 }
1078
1079 HideWeaponBarrel(false);
1080 }
1081
1083 {
1084 if (!super.CanReleaseAttachment(attachment))
1085 return false;
1087 if (mag)
1088 {
1089 PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
1090 if (player)
1091 {
1092 if (player.GetItemInHands() == this)
1093 return true;
1094 }
1095 return false;
1096 }
1097
1098 return true;
1099 }
1100
1101 override bool CanRemoveFromHands(EntityAI parent)
1102 {
1103 if (IsIdle())
1104 return true;
1105 if (LogManager.IsWeaponLogEnable()) wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " Weapon=" + this + " not in stable state=" + GetCurrentState().Type());
1106 return false; // do not allow removal of weapon while weapon is busy
1107 }
1108
1110 {
1112 if (GetInventory().GetCurrentInventoryLocation(il))
1113 {
1114 EntityAI parent = il.GetParent();
1115 DayZPlayer dayzp = DayZPlayer.Cast(parent);
1116 if (il.GetType() == InventoryLocationType.HANDS && dayzp)
1117 {
1118 bool remote = dayzp.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_REMOTE;
1119 return remote;
1120 }
1121 }
1122 return true;
1123 }
1124
1126 {
1127 DayZPlayer p = DayZPlayer.Cast(GetHierarchyParent());
1128 if (p && p.GetInstanceType() == DayZPlayerInstanceType.INSTANCETYPE_SERVER)
1129 {
1131
1133 e.WriteToContext(ctx);
1134
1136 wpnDebugPrint("[wpnfsm] " + Object.GetDebugName(this) + " send 2 remote: sending e=" + e + " id=" + e.GetEventID() + " p=" + e.m_player + " m=" + e.m_magazine);
1137
1138 p.StoreInputForRemotes(ctx);
1139 }
1140 }
1141
1142
1144 {
1145 return new DefaultRecoil(this);
1146 }
1147
1149 {
1150 return subCommand;
1151 }
1152
1153 bool CanFire()
1154 {
1155 if (!IsChamberEmpty(GetCurrentMuzzle()) && !IsChamberFiredOut(GetCurrentMuzzle()) && !IsJammed() && !m_LiftWeapon && !IsDamageDestroyed())
1156 return true;
1157 return false;
1158 }
1159
1161 {
1162 ItemOptics optic = GetAttachedOptics();
1163 if (!optic)
1164 return true;
1165
1166 return optic.HasWeaponIronsightsOverride();
1167 }
1168
1171 {
1172 if (GetGame().ConfigIsExisting("cfgWeapons " + GetType() + " PPDOFProperties"))
1173 {
1174 GetGame().ConfigGetFloatArray("cfgWeapons " + GetType() + " PPDOFProperties", temp_array);
1175 return true;
1176 }
1177 return false;
1178 }
1179
1181 {
1182 if (GetGame().ConfigIsExisting("cfgWeapons " + GetType() + " Reliability ChanceToJam"))
1183 {
1184 GetGame().ConfigGetFloatArray("cfgWeapons " + GetType() + " Reliability ChanceToJam", reliability_array);
1185 return true;
1186 }
1187 return false;
1188 }
1189
1192 {
1193 if (ConfigIsExisting("WeaponLength"))
1194 {
1195 m_WeaponLength = ConfigGetFloat("WeaponLength");
1196 return true;
1197 }
1198 m_WeaponLength = 0.8; //default value if not set in config; should not be zero
1199 return false;
1200 }
1201
1204 {
1205 if (ConfigIsExisting("WeaponLiftCheckVerticalOffset"))
1206 {
1207 m_WeaponLiftCheckVerticalOffset = ConfigGetFloat("WeaponLiftCheckVerticalOffset");
1208 return true;
1209 }
1210 m_WeaponLiftCheckVerticalOffset = 0.0; //no offset by default
1211 return false;
1212 }
1213
1215 protected bool InitShoulderDistance()
1216 {
1217 if (ConfigIsExisting("ShoulderDistance"))
1218 {
1219 m_ShoulderDistance = ConfigGetFloat("ShoulderDistance");
1220 return true;
1221 }
1222
1223 m_ShoulderDistance = 0;
1224 return false;
1225 }
1226
1228 {
1229 return m_DOFProperties;
1230 }
1231
1232 // lifting weapon on obstcles
1234 {
1235 int idx;
1236 float distance;
1237 float hit_fraction; //junk
1238 vector start, end;
1242 vector hit_pos, hit_normal; //junk
1243 Object obj;
1246
1247 bool wasLift = m_LiftWeapon;
1248 vector lastLiftPosition = m_LastLiftPosition;
1249
1250 m_LiftWeapon = false;
1251 // not a gun, no weap.raise for now
1252 if (HasSelection("Usti hlavne"))
1253 return false;
1254
1255 if (!player)
1256 {
1257 Print("Error: No weapon owner, returning");
1258 return false;
1259 }
1260
1261 // weapon not raised
1262 player.GetMovementState(movementState);
1263 if (!movementState.IsRaised())
1264 return false;
1265
1266 // suppress raising of weapon during melee attack preventing state inconsistency
1267 if (movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE || movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE2)
1268 return false;
1269
1270 usti_hlavne_position = GetSelectionPositionLS("Usti hlavne"); // Usti hlavne
1271 trigger_axis_position = GetSelectionPositionLS("trigger_axis");
1272
1273 // If possible use aiming angles instead as these will work consistently
1274 // and independently of any cameras, etc.
1275 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1276 if (hcw)
1277 {
1279 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1280 hcw.GetBaseAimingAngleUD(),
1281 0.0);
1282 direction = yawPitchRoll.AnglesToVector();
1283 }
1284 else // Fallback to previously implemented logic
1285 {
1286 // freelook raycast
1287 if (player.GetInputController().CameraIsFreeLook())
1288 {
1289 if (player.m_DirectionToCursor != vector.Zero)
1290 direction = player.m_DirectionToCursor;
1291 // if player raises weapon in freelook
1292 else
1293 direction = MiscGameplayFunctions.GetHeadingVector(player);
1294 }
1295 else
1296 {
1297 direction = GetGame().GetCurrentCameraDirection(); // exception for freelook. Much better this way!
1298 }
1299 }
1300
1301 idx = player.GetBoneIndexByName("Neck"); //RightHandIndex1
1302 if (idx == -1)
1303 start = player.GetPosition()[1] + 1.5;
1304 else
1305 start = player.GetBonePositionWS(idx);
1306
1307
1308 // Updated weapon lift detection code prototype
1309 {
1310 // 0: construct stable trasformation matrix that
1311 // approximately aligns with the weapon transform
1312 // without actually using the weapon as reference
1313 // (as the weapon can be moved unpredictably by anims)
1314 vector resTM[4];
1315 resTM[0] = Vector(direction[0], 0, direction[2]).Normalized();
1317 resTM[2] = direction;
1318 resTM[1] = resTM[2] * resTM[0];
1319 resTM[3] = start;
1320
1321 // Approximate the roll of leaning
1323 player.GetMovementState(hms);
1324 float leanAngle = hms.m_fLeaning * 35;
1325 vector rotTM[3];
1328
1329 // Draw relative TM diagnostic
1330#ifdef DIAG_DEVELOPER
1331 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1332 {
1333 Shape.CreateArrow(resTM[3], resTM[3] + resTM[0], 0.05, COLOR_RED, ShapeFlags.ONCE);
1334 Shape.CreateArrow(resTM[3], resTM[3] + resTM[1], 0.05, COLOR_GREEN, ShapeFlags.ONCE);
1335 Shape.CreateArrow(resTM[3], resTM[3] + resTM[2], 0.05, COLOR_BLUE, ShapeFlags.ONCE);
1336 }
1337#endif
1338
1339 // 1: pick from predefined offset relative to
1340 // the previously constructed transform
1341 float udAngle = Math.Asin(direction[1]) * Math.RAD2DEG;
1342
1343 // offsets are [right, up, forward]
1344 // values are based on what felt right after iterating
1345 vector offsets[] = {
1346 "0.11 0.17 0.0", // offset while aiming down
1347 "0.12 0.05 0.0", // offset while aiming forward
1348 "0.112 0.03 0.0" // offset while aiming up
1349 };
1350 const int lastIndex = 2; // length of offsets - 1
1351
1352 // <0,1> range of aiming
1353 float a = Math.Clamp(Math.InverseLerp(DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX, udAngle), 0, 0.9999);
1354 int lo = a * lastIndex;
1355 int hi = Math.Clamp(lo + 1, 0, lastIndex);
1356
1357 // remap to current lo-hi range
1358 float t = Math.Clamp(a * lastIndex - lo, 0, 1);
1360
1361 // offsets are [right, up forward]
1362 // additional offsets added to previous offsets per stance
1363 vector stanceOffsets[] = {
1364 "0 -0.015 0", // erect
1365 "0 0.03 0", // crouch
1366 "0 -0.04 0",// prone
1367 };
1368
1369 // 2. pick from predefined offsets based on stance,
1370 // allows to even further approximate the alignment
1371 int stanceOffsetIndex = hms.m_iStanceIdx;
1372 if (stanceOffsetIndex >= DayZPlayerConstants.STANCEIDX_PRONE)
1373 stanceOffsetIndex -= DayZPlayerConstants.STANCEIDX_RAISED;
1374
1375 stanceOffsetIndex -= DayZPlayerConstants.STANCEIDX_ERECT;
1377
1378 // if any additional height offset is defined, apply it
1379 if (m_WeaponLiftCheckVerticalOffset != 0)
1380 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1381
1382 // 3. use the offset as the start position.
1383 // it will not be perfect, but it should reflect
1384 // the actual weapon transform more accurately
1385 start = offset.Multiply4(resTM);
1386 }
1387
1389 /*usti_hlavne_position = ModelToWorld(usti_hlavne_position);
1390 distance = vector.Distance(start,usti_hlavne_position);*/
1391 distance = m_WeaponLength + GetEffectiveAttachmentLength();
1392
1393 vector weaponStart = start + (m_ShoulderDistance * direction);
1395
1396 // Draw diagnostics: Script -> Weapon -> Weapon Lift
1397#ifdef DIAG_DEVELOPER
1398 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1399 {
1400 vector diagNoAttachEnd = weaponStart + (m_WeaponLength * direction);
1401 int diagPtsShpFlgs = ShapeFlags.ONCE | ShapeFlags.NOOUTLINE;
1402 float diagPtsRadius = 0.025;
1406 }
1407#endif
1408
1409 // For the physical cast, extend the distance by x%
1410 // to allow for smoother transition handling in some cases
1411 end = weaponEnd + ((0.1 * distance) * direction);
1412
1413 // Prepare raycast params and perform the cast in fire geo
1415 rayParm.flags = CollisionFlags.ALLOBJECTS;
1416 rayParm.type = ObjIntersect.Fire;
1417
1420 if (!DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1421 {
1423 hit_fraction = 0;
1424 }
1425 else
1426 {
1428
1429#ifdef DIAG_DEVELOPER // isect diag
1430 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG) == 2)
1431 {
1432 DbgUI.Begin("Weapon Lift Diag");
1433 {
1434 if (res.surface)
1435 {
1436 DbgUI.Text("Intersection data:");
1437 DbgUI.Text(" Name: " + res.surface.GetName());
1438 DbgUI.Text(" EntryName: " + res.surface.GetEntryName());
1439 DbgUI.Text(" SurfaceType: " + res.surface.GetSurfaceType());
1440
1441 DbgUI.Text(" IsPassThrough: " + res.surface.IsPassthrough());
1442 DbgUI.Text(" IsSolid: " + res.surface.IsSolid());
1443 }
1444 else
1445 DbgUI.Text("Intersection with no surface");
1446 }
1447 DbgUI.End();
1448 }
1449#endif // !isect diag
1450
1451 if (LiftWeaponRaycastResultCheck(res))
1452 {
1453 hit_pos = res.pos;
1454 float len0 = (hit_pos - start).Length();
1455 float len1 = (end - start).Length();
1456 if (len0 <= 0 || len1 <= 0)
1457 hit_fraction = 1;
1458 else
1460 }
1461 else
1462 {
1464 hit_fraction = 0;
1465 }
1466 }
1467
1469
1470 // Draw diagnostics: Script -> Weapon -> Weapon Lift
1471#ifdef DIAG_DEVELOPER
1472 if (DiagMenu.GetValue(DiagMenuIDs.WEAPON_LIFT_DEBUG))
1473 {
1474 const vector epsilon = "0 0.0002 0"; // to overcome excessive z-fighting for diag
1476 Shape.CreateArrow(start - epsilon, lastLiftPosition - epsilon, 0.05, COLOR_YELLOW, ShapeFlags.ONCE);
1477
1478 Shape.CreateArrow(start, weaponEnd, 0.05, COLOR_WHITE, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER);
1479
1480 if (hit_fraction != 0)
1481 Shape.CreateArrow(start + epsilon, hit_pos + epsilon, 0.05, COLOR_RED, ShapeFlags.ONCE);
1482 }
1483#endif
1484
1485 // Start by assuming that we want to retain state
1486 bool wantsLift = wasLift;
1487
1488 // Sq. distance of weapon movement required to trigger lift (in)
1489 const float inThreshold = 0.002;
1490 // Sq. distance of weapon movement required to trigger lift (out)
1491 const float outThreshold = 0.003;
1492 const float noIsctOutThreshold = 0.01;
1493
1494 // Min angle in degrees change from last lift to stop lifting
1495 // Base threshold of 0.75 degrees + 0.6 degrees per meter of weapon length
1496 float angleThreshold = 0.75 + Math.Clamp(m_WeaponLength * 0.6, 0, 1.5);
1497
1498 // Update state when a hit is registered
1499 if (hit_fraction != 0)
1500 {
1502 vector v2 = hit_pos - end;
1503 float d = vector.Dot(v1, v2);
1504 // But leave some threshold where previous state is kept
1505 // to prevent excessive switches from occuring
1506 if (!wasLift && d > inThreshold)
1507 wantsLift = true;
1508 else if (wasLift && d < -outThreshold)
1509 wantsLift = false;
1510
1511 m_LastLiftPosition = hit_pos;
1512 }
1513 else
1514 {
1515 // With no hit and no previous lift
1517 {
1518 wantsLift = false;
1519 m_LastLiftPosition = vector.Zero;
1520 }
1521 // See if previous hit wasn't very close to our current position,
1522 // in which case simply don't lift the weapon
1523 else
1524 {
1525 vector v3 = (lastLiftPosition - start).Normalized();
1526 vector v4 = (end - start).Normalized();
1527 float d2 = vector.Dot(v3, v4);
1528 // no isect, angle delta check
1529 if (Math.Acos(d2) > (angleThreshold * Math.DEG2RAD)) // if relative angle is > x degree, stop lifting
1530 {
1531 wantsLift = false;
1532 m_LastLiftPosition = vector.Zero;
1533 }
1534 // no isect, distance check
1535 else
1536 {
1537 float d3 = vector.Dot(lastLiftPosition - weaponEnd, (start - end).Normalized());
1538 if (d3 < -noIsctOutThreshold)
1539 {
1540 wantsLift = false;
1541 m_LastLiftPosition = vector.Zero;
1542 }
1543 }
1544 }
1545 }
1546
1547 // lift is desired
1548 if (wantsLift)
1549 {
1550 //Print(distance);
1551 m_LiftWeapon = true;
1552 return true;
1553 }
1554 return false;
1555 }
1556
1559 {
1560 return res.surface.IsSolid();
1561 }
1562
1565 {
1567 if (HasBayonetAttached())
1568 {
1569 int bayonetIndex = GetBayonetAttachmentIdx();
1570 attachment = ItemBase.Cast(GetInventory().FindAttachment(bayonetIndex));
1571 }
1572 else
1573 attachment = GetAttachedSuppressor();
1574
1575 if (attachment)
1576 return Math.Max(attachment.m_ItemModelLength + attachment.m_ItemAttachOffset, 0);
1577 else
1578 return 0;
1579 }
1580
1582 {
1583 m_ChanceToJamSync = jamming_chance;
1584 }
1585
1597 {
1598 if (IsChamberEjectable(muzzleIndex))
1599 {
1600 if (PopCartridgeFromChamber(muzzleIndex, ammoDamage, ammoTypeName))
1601 return true;
1602 }
1603 else if (GetInternalMagazineCartridgeCount(muzzleIndex) > 0)
1604 {
1605 if (PopCartridgeFromInternalMagazine(muzzleIndex, ammoDamage, ammoTypeName))
1606 return true;
1607 }
1608 return false;
1609 }
1610
1612 {
1613 float damage = 0.0;
1614 string type;
1615
1616 for (int mi = 0; mi < src.GetMuzzleCount(); ++mi)
1617 {
1618 if (!src.IsChamberEmpty(mi))
1619 {
1620 if (src.GetCartridgeInfo(mi, damage, type))
1621 PushCartridgeToChamber(mi, damage, type);
1622 }
1623
1624 for (int ci = 0; ci < src.GetInternalMagazineCartridgeCount(mi); ++ci)
1625 {
1626 if (src.GetInternalMagazineCartridgeInfo(mi, ci, damage, type))
1627 PushCartridgeToInternalMagazine(mi, damage, type);
1628 }
1629 }
1630
1631 int dummy_version = int.MAX;
1632 PlayerBase parentPlayer = PlayerBase.Cast(src.GetHierarchyRootPlayer());
1633 if (!parentPlayer)
1634 dummy_version -= 1;
1636 src.OnStoreSave(ctx.GetWriteContext());
1637 OnStoreLoad(ctx.GetReadContext(), dummy_version);
1638 return true;
1639 }
1640
1642 override void SetBayonetAttached(bool pState, int slot_idx = -1)
1643 {
1644 m_BayonetAttached = pState;
1645 m_BayonetAttachmentIdx = slot_idx;
1646 }
1647
1648 override bool HasBayonetAttached()
1649 {
1650 return m_BayonetAttached;
1651 }
1652
1654 {
1655 return m_BayonetAttachmentIdx;
1656 }
1657
1658 override void SetButtstockAttached(bool pState, int slot_idx = -1)
1659 {
1660 m_ButtstockAttached = pState;
1661 m_ButtstockAttachmentIdx = slot_idx;
1662 }
1663
1664 override bool HasButtstockAttached()
1665 {
1666 return m_ButtstockAttached;
1667 }
1668
1670 {
1671 return m_ButtstockAttachmentIdx;
1672 }
1673
1675 {
1676 if (!GetGame().IsDedicatedServer()) //hidden for client only
1677 {
1678 ItemOptics optics = GetAttachedOptics();
1679 if (optics && !optics.AllowsDOF() && m_weaponHideBarrelIdx != -1)
1680 SetSimpleHiddenSelectionState(m_weaponHideBarrelIdx, !state);
1681 }
1682 }
1683
1685 {
1686 if (m_magazineSimpleSelectionIndex > -1)
1687 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex, 1);
1688 else
1689 SelectionMagazineShow();
1690 }
1691
1693 {
1694 if (m_magazineSimpleSelectionIndex > -1)
1695 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex, 0);
1696 else
1697 SelectionMagazineHide();
1698 }
1699
1701 {
1703
1704 switch (mode)
1705 {
1706 case 0:
1707 super.ProcessMeleeItemDamage();
1708 break;
1709
1710 case 1:
1711 attachment = GetInventory().FindAttachment(m_ButtstockAttachmentIdx);
1712 break;
1713
1714 case 2:
1715 attachment = GetInventory().FindAttachment(m_BayonetAttachmentIdx);
1716 break;
1717
1718 default:
1719 super.ProcessMeleeItemDamage();
1720 break;
1721 }
1722
1723 if (attachment)
1724 {
1725 attachment.ProcessMeleeItemDamage();
1726 return attachment;
1727 }
1728
1729 return this;
1730 }
1731
1733 {
1734 return true;
1735 }
1736
1738 {
1739 return m_BurstCount;
1740 }
1741
1743 {
1744 m_BurstCount = 0;
1745 }
1746
1760
1761 override bool CanBeUsedForSuicide()
1762 {
1763 if (!ConfigGetBool("isSuicideWeapon"))
1764 return false;
1765
1766 return super.CanBeUsedForSuicide();
1767 }
1768
1769 //Debug menu Spawn Ground Special
1770 override void OnDebugSpawn()
1771 {
1772 SpawnAmmo("", SAMF_DEFAULT);
1773 }
1774};
1775
const int INPUT_UDT_WEAPON_REMOTE_EVENT
Definition _constants.c:12
eBleedingSourceType GetType()
void wpnDebugPrint(string s)
Definition Debug.c:9
bool IsDamageDestroyed(ActionTarget target)
Definition ActionBase.c:841
void AddAction(typename actionName)
const int ECE_PLACE_ON_SURFACE
void Synchronize()
override bool IsJammed()
Definition Crossbow.c:22
DayZGame g_Game
Definition DayZGame.c:3528
PhxInteractionLayers
Definition DayZPhysics.c:2
DiagMenuIDs
Definition EDiagMenuIDs.c:2
WeaponEventID
identifier for events. mainly for rpc purposes
Definition Events.c:6
ProcessEventResult
Definition FSMBase.c:41
FirearmActionLoadBullet FirearmActionBase FirearmActionLoadBulletQuick()
void fsmDebugSpam(string s)
Definition HFSMBase.c:9
InventoryLocationType
types of Inventory Location
void IncreaseOverheating(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
Definition ItemBase.c:5176
string Type
bool OnStoreLoad(ParamsReadContext ctx, int version)
PistolAnimState
Definition Pistol_Base.c:3
class JsonUndergroundAreaTriggerData GetPosition
@ AMMO_CHAMBER_RNG
Fully randomizes the ammo type instead of picking one random for all chambers (needs to have type as ...
Definition Weapon_Base.c:26
@ CHAMBER
Chambers bullets.
Definition Weapon_Base.c:16
@ CHAMBER_RNG_SPORADIC
Maybe chambers bullets (full random) example: 0 1 0 0 1 1.
Definition Weapon_Base.c:20
@ MAX_CAPACITY_MAG
Instead of randomizing when type is empty, it looks for the one which has the highest capacity.
Definition Weapon_Base.c:28
@ QUANTITY_RNG
Randomizes the quantity of the bullets in the spawned magazine.
Definition Weapon_Base.c:22
@ CHAMBER_RNG
Maybe chambers bullets (sequential rng) example: 1 1 1 0 0 0.
Definition Weapon_Base.c:18
@ NONE
Attached magazine will be full and no round will be chambered.
Definition Weapon_Base.c:14
@ AMMO_MAG_RNG
Fully randomizes the ammo type instead of picking one random for the entire mag (needs to have type a...
Definition Weapon_Base.c:24
enum FSMTransition WeaponTransition
MuzzleState
override bool IsIdle()
bool IsChamberFiredOut(int idx)
bool IsChamberFull(int idx)
pair ( action, actionType )
Definition Weapon_Base.c:5
void AbilityRecord(int a, int at)
corresponds to Human::actionTypes == CHAMBERING_ONEBULLET_CLOSED, MECHANISM_CLOSED....
Definition Weapon_Base.c:8
int m_actionType
corresponds to Human::actions == RELOAD, MECHANISM, ...
Definition Weapon_Base.c:7
static bool MagazineTypeToAmmoType(string magazineType, out string ammoType)
Helper method.
Definition AmmoTypes.c:12
ammo pile base
static float GetAmmoWeightByBulletType(string bulletType)
Super root of all classes in Enforce script.
Definition EnScript.c:11
static proto bool RaycastRVProxy(notnull RaycastRVParams in, out notnull array< ref RaycastRVResult > results, array< Object > excluded=null)
Definition DbgUI.c:60
Wrapper class for managing sound through SEffectManager.
Definition EffectSound.c:5
InventoryLocation.
static bool IsWeaponLogEnable()
Definition Debug.c:799
Definition EnMath.c:7
Manager class for managing Effect (EffectParticle, EffectSound)
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.
Serialization general interface. Serializer API works with:
Definition Serializer.c:56
override void InitStateMachine()
Definition Magnum.c:87
override void HideBullet(int muzzleIndex)
Definition Magnum.c:320
override void ShowBullet(int muzzleIndex)
Definition Magnum.c:297
override void AssembleGun()
Definition Magnum.c:178
signalize mechanism manipulation
Definition Events.c:35
weapon finite state machine
script counterpart to engine's class Weapon
bool m_ButtstockAttached
Definition Weapon_Base.c:51
int m_BurstCount
Definition Weapon_Base.c:54
override int GetBayonetAttachmentIdx()
override int GetButtstockAttachmentIdx()
void HideMagazine()
ref array< float > GetWeaponDOF()
int GetCurrentStableStateID()
tries to return identifier of current stable state (or nearest stable state if unstable state is curr...
int GetBurstCount()
bool CopyWeaponStateFrom(notnull Weapon_Base src)
bool EjectCartridge(int muzzleIndex, out float ammoDamage, out string ammoTypeName)
unload bullet from chamber or internal magazine
bool IsShowingChamberedBullet()
bool IsRemoteWeapon()
bool JamCheck(int muzzleIndex)
void SyncEventToRemote(WeaponEventBase e)
override bool HasBayonetAttached()
void SetInitialState(WeaponStableState initState)
bool IsCharged()
float m_WeaponLiftCheckVerticalOffset
Definition Weapon_Base.c:62
void SyncSelectionState(bool has_bullet, bool has_mag)
float GetEffectiveAttachmentLength()
Returns effective length of attachments that influence total weapon length.
void EEFired(int muzzleType, int mode, string ammoType)
void ShowMagazine()
float m_ShoulderDistance
Definition Weapon_Base.c:63
int GetWeaponSpecificCommand(int weaponAction, int subCommand)
int GetAbilityCount()
bool InitWeaponLiftCheckVerticalOffset()
gets weapon vertical offset from config for weaponlift raycast
int m_BayonetAttachmentIdx
Definition Weapon_Base.c:55
ref array< float > m_DOFProperties
Definition Weapon_Base.c:66
bool FillInnerMagazine(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the inner magazine.
bool IsIdle()
float GetWeightSpecialized(bool forceRecalc=false)
override int GetSlotsCountCorrect()
Returns number of slots for attachments corrected for weapons.
void HideWeaponBarrel(bool state)
bool InitShoulderDistance()
gets approximate weapon distance from shoulder from config
override bool CanReleaseAttachment(EntityAI attachment)
void ShowBullet(int muzzleIndex)
bool CanProcessAction(int action, int actionType)
void HideBullet(int muzzleIndex)
array< MuzzleState > GetMuzzleStates()
Helper method for RandomizeFSMState.
void SetCharged(bool value)
void ResetBurstCount()
bool InitDOFProperties(out array< float > temp_array)
Initializes DOF properties for weapon's ironsight/optics cameras.
override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
vector m_LastLiftPosition
Definition Weapon_Base.c:64
void Weapon_Base()
Definition Weapon_Base.c:72
override void OnInventoryExit(Man player)
ref WeaponFSM m_fsm
weapon abilities
Definition Weapon_Base.c:47
bool m_BayonetAttached
Definition Weapon_Base.c:50
bool CanFire()
float GetSyncChanceToJam()
void SetSyncJammingChance(float jamming_chance)
override void OnDebugSpawn()
void SetWeaponAnimState(int state)
bool LiftWeaponRaycastResultCheck(notnull RaycastRVResult res)
Return whether provided material triggers weapon lift (true) or not (false).
float GetChanceToJam()
void SetWeaponOpen(bool value)
bool HasActionAbility(int action, int actionType)
query if weapon supports action and actionType
void ForceSyncSelectionState()
bool LiftWeaponCheck(PlayerBase player)
override void AfterStoreLoad()
bool ProcessWeaponEvent(WeaponEventBase e)
weapon's fsm handling of events @NOTE: warning: ProcessWeaponEvent can be called only within DayZPlay...
bool CanEjectBullet()
AbilityRecord GetAbility(int index)
override bool CanRemoveFromHands(EntityAI parent)
bool CanProcessWeaponEvents()
override void EEInit()
override void SetButtstockAttached(bool pState, int slot_idx=-1)
Magazine SpawnAttachedMagazine(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to spawn and attach a magazine.
PropertyModifiers GetPropertyModifierObject()
bool SpawnAmmo(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
General method trying to attch magazine, fill inner magazine and fill chamber.
WeaponStateBase GetCurrentState()
returns currently active state
void AssembleGun()
override on weapons with some assembly required
override bool CanBeUsedForSuicide()
RecoilBase SpawnRecoilObject()
bool FillChamber(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the chamber.
override void EEItemDetached(EntityAI item, string slot_name)
void InitStateMachine()
bool ProcessWeaponAbortEvent(WeaponEventBase e)
ref PropertyModifiers m_PropertyModifierObject
Definition Weapon_Base.c:69
bool IsJammed()
void ValidateAndRepair()
void OnFire(int muzzle_index)
override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
int m_ButtstockAttachmentIdx
Definition Weapon_Base.c:56
override void SetActions()
void ResetWeaponAnimState()
bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
bool CanEnterIronsights()
void RandomizeFSMState()
With the parameters given, selects a random suitable state for the FSM of the weapon @WARNING: Weapon...
float m_WeaponLength
Definition Weapon_Base.c:61
int GetWeaponAnimState()
override EntityAI ProcessMeleeItemDamage(int mode=0)
override bool OnStoreLoad(ParamsReadContext ctx, int version)
override void OnStoreSave(ParamsWriteContext ctx)
bool IsWaitingForActionFinish()
returns true if state machine started playing action/actionType and waits for finish
bool CanChamberBullet(int muzzleIndex, Magazine mag)
static Weapon_Base CreateWeaponWithAmmo(string weaponType, string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Create weapon with ammo.
void SaveCurrentFSMState(ParamsWriteContext ctx)
void OnFireModeChange(int fireMode)
override bool HasButtstockAttached()
void SetJammed(bool value)
bool InitReliability(out array< float > reliability_array)
override void EEItemAttached(EntityAI item, string slot_name)
bool InitWeaponLength()
gets weapon length from config for weaponlift raycast
override void OnInventoryEnter(Man player)
bool IsWeaponOpen()
override void SetBayonetAttached(bool pState, int slot_idx=-1)
attachment helpers (firearm melee)
int GetInternalStateID()
represents weapon's stable state (i.e. the basic states that the weapon will spend the most time in)
Definition Crossbow.c:27
represent weapon state base
Definition BulletHide.c:2
static vector RotateAroundZeroDeg(vector vec, vector axis, float angle)
Rotate a vector around 0,0,0 by an angle in degrees.
Definition EnConvert.c:451
static float Dot(vector v1, vector v2)
Returns Dot product of vector v1 and vector v2.
Definition EnConvert.c:271
static const vector Zero
Definition EnConvert.c:110
static const vector Up
Definition EnConvert.c:107
static proto native vector Lerp(vector v1, vector v2, float t)
Lerp between two vectors.
override string GetDebugName()
DayZPlayerInstanceType
defined in C++
DayZPlayerConstants
defined in C++
Definition dayzplayer.c:597
proto native CGame GetGame()
const int COLOR_BLUE
Definition constants.c:66
const int COLOR_RED
Definition constants.c:64
const int COLOR_GREEN
Definition constants.c:65
const int COLOR_WHITE
Definition constants.c:63
const int COLOR_YELLOW
Definition constants.c:67
void Error(string err)
Messagebox with error message.
Definition EnDebug.c:90
proto void Print(void var)
Prints content of variable to console/log.
enum ShapeType ErrorEx
CollisionFlags
Definition EnDebug.c:141
ShapeFlags
Definition EnDebug.c:126
static proto native void End()
static proto native void Begin(string windowTitle, float x=0, float y=0)
static proto native void Text(string label)
static proto void BeginCleanupScope()
static proto native void EndCleanupScope()
class DiagMenu Shape
don't call destructor directly. Use Destroy() instead
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
Definition EnScript.c:666
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 Asin(float s)
Returns angle in radians from sinus.
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 const float RAD2DEG
Definition EnMath.c:16
static const float DEG2RAD
Definition EnMath.c:17
static int RandomIntInclusive(int min, int max)
Returns a random int number between and min [inclusive] and max [inclusive].
Definition EnMath.c:54
const int CALL_CATEGORY_GAMEPLAY
Definition tools.c:10