11enum WeaponWithAmmoFlags
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;
47 protected const float DEFAULT_DAMAGE_ON_SHOT = 0.05;
50 protected bool m_isJammed =
false;
51 protected bool m_LiftWeapon =
false;
54 protected bool m_Charged =
false;
55 protected bool m_WeaponOpen =
false;
60 protected int m_weaponAnimState = -1;
61 protected int m_magazineSimpleSelectionIndex = -1;
62 protected int m_weaponHideBarrelIdx = -1;
63 protected float m_DmgPerShot = 0;
73 protected float m_ChanceToJamSync = 0;
77 private float m_coolDownTime = 0;
82 m_BayonetAttached =
false;
83 m_ButtstockAttached =
false;
84 m_WasIronSight =
true;
85 m_BayonetAttachmentIdx = -1;
86 m_ButtstockAttachmentIdx = -1;
91 m_DelayedValidationTimer =
new Timer();
94 if ( ConfigIsExisting(
"simpleHiddenSelections") )
97 ConfigGetTextArray(
"simpleHiddenSelections",selectionNames);
98 m_weaponHideBarrelIdx = selectionNames.Find(
"hide_barrel");
99 m_magazineSimpleSelectionIndex = selectionNames.Find(
"magazine");
101 int bulletIndex = selectionNames.Find(
"bullet");
102 if ( bulletIndex != -1 )
104 m_bulletSelectionIndex.Insert(bulletIndex);
106 for (
int i = 2; i < 100; i++)
108 bulletIndex = selectionNames.Find(
string.Format(
"bullet%1",i));
109 if (bulletIndex != -1)
111 m_bulletSelectionIndex.Insert(bulletIndex);
122 InitWeaponLiftCheckVerticalOffset();
123 InitShoulderDistance();
124 InitObstructionDistance();
125 InitDOFProperties(m_DOFProperties);
128 InitReliability(m_ChanceToJam);
133 void InitStateMachine() { }
147 m_fsm.SetInitialState(initState);
148 SetCharged(!initState.IsDischarged());
149 SetWeaponOpen(initState.IsWeaponOpen());
150 SetGroundAnimFrameIndex(initState.m_animState);
158 void SetCharged(
bool value)
168 void SetWeaponOpen(
bool value)
170 m_WeaponOpen = value;
175 float baseWeight = GetInventoryAndCargoWeight(forceRecalc);
178 string bulletTypeName, ammoTypeName;
180 int muzzleCount = GetMuzzleCount();
182 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
185 data1.SetCalcDetails(
"TWPN: " + m_ConfigWeight+
"(item weight) + " + baseWeight +
"(contents weight)" );
188 for (
int muzzleIndex = 0; muzzleIndex < muzzleCount; muzzleIndex++)
191 if (!IsChamberEmpty(muzzleIndex))
193 ammoTypeName = GetChamberAmmoTypeName(muzzleIndex);
194 ammoWeight +=
g_Game.ConfigGetFloat(
string.Format(
"CfgMagazines %1 weight", ammoTypeName));
197 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
200 data2.AddCalcDetails(
g_Game.ConfigGetFloat(
"CfgMagazines " + ammoTypeName +
" weight").ToString() +
"(chamber weight)");
206 if (HasInternalMagazine(muzzleIndex))
209 float debugInternalMagWeight;
211 int cartridgeCount = GetInternalMagazineCartridgeCount(muzzleIndex);
212 for (
int cartridgeIndex = 0; cartridgeIndex < cartridgeCount; cartridgeIndex++)
214 GetInternalMagazineCartridgeInfo(muzzleIndex, cartridgeIndex, ammoDamage, bulletTypeName);
215 ammoWeight +=
Ammunition_Base.GetAmmoWeightByBulletType(bulletTypeName);
217 debugInternalMagWeight +=
g_Game.ConfigGetFloat(
"CfgMagazines " + ammoTypeName +
" weight");
222 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
225 data3.AddCalcDetails(debugInternalMagWeight.ToString()+
"(internal mag weight)");
231 return ammoWeight + baseWeight + GetConfigWeightModified();
248 int count = GetAbilityCount();
249 for (
int i = 0; i < count; ++i)
252 if (rec.m_action == action && rec.m_actionType == actionType)
283 return CanProcessWeaponEvents() && GetCurrentState().IsWaitingForActionFinish();
288 return CanProcessWeaponEvents() && GetCurrentState().IsIdle();
297 SyncEventToRemote(e);
302 SetNextWeaponMode(GetCurrentMuzzle());
317 SyncEventToRemote(e);
320 m_fsm.ProcessAbortEvent(e, aa);
326 return CanChamberFromMag(muzzleIndex, mag) && (!
IsChamberFull(muzzleIndex) ||
IsChamberFiredOut(muzzleIndex) || !IsInternalMagazineFull(muzzleIndex));
331 m_weaponAnimState = state;
332 SetGroundAnimFrameIndex(state);
337 m_weaponAnimState = -1;
341 void EEFired(
int muzzleType,
int mode,
string ammoType)
343 if ( !
GetGame().IsDedicatedServer() )
345 ItemBase suppressor = GetAttachedSuppressor();
348 ItemBase.PlayFireParticles(
this, muzzleType, ammoType,
this, suppressor,
"CfgWeapons" );
349 IncreaseOverheating(
this, ammoType,
this, suppressor,
"CfgWeapons");
353 ItemBase.PlayFireParticles(
this, muzzleType, ammoType, suppressor, NULL,
"CfgVehicles" );
354 suppressor.IncreaseOverheating(
this, ammoType,
this, suppressor,
"CfgVehicles");
369 #ifdef DIAG_DEVELOPER
370 MiscGameplayFunctions.UnlimitedAmmoDebugCheck(
this);
381 if (rnd < GetSyncChanceToJam())
389 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
391 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],1);
394 SelectionBulletShow();
399 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
401 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],0);
404 SelectionBulletHide();
413 int level = GetHealthLevel();
415 if (level >= 0 && level < m_ChanceToJam.Count())
416 return m_ChanceToJam[level];
425 string chamberedAmmoTypeName;
426 float chamberedAmmoDmg;
428 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
430 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
433 SelectionBulletShow();
438 SelectionBulletHide();
464 int nMuzzles = GetMuzzleCount();
465 for (
int i = 0; i < nMuzzles; ++i)
472 GetCartridgeInfo(i, damage, ammoTypeName);
473 EffectBulletShow(i, damage, ammoTypeName);
481 Magazine mag = GetMagazine(i);
491 if ( !super.OnStoreLoad(ctx, version) )
497 int current_muzzle = 0;
498 if (!ctx.Read(current_muzzle))
500 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read current muzzle!");
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!");
507 SetCurrentMuzzle(current_muzzle);
513 if (!ctx.Read(mode_count))
515 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read mode count!");
519 for (
int m = 0; m < mode_count; ++m)
524 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read mode[" + m +
"]");
528 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" OnStoreLoad - loaded muzzle[" + m +
"].mode = " + mode); }
529 SetCurrentMode(m, mode);
533 if ( version >= 106 )
535 if ( !ctx.Read(m_isJammed) )
537 Error(
"Weapon.OnStoreLoad cannot load jamming state");
544 if (!m_fsm.OnStoreLoad(ctx, version))
550 SetGroundAnimFrameIndex(wss.m_animState);
557 if (!ctx.Read(dummy))
566 if (m_fsm && m_fsm.IsRunning())
568 if (m_fsm.SaveCurrentFSMState(ctx))
573 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" state NOT saved.");
576 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon.SaveCurrentFSMState: trying to save weapon without FSM (or uninitialized weapon) this=" +
this +
" type=" +
GetType());
583 if (m_fsm.LoadCurrentFSMState(ctx, version))
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."); }
595 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" unstable/error state loaded."); }
601 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" did not load.");
607 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon.LoadCurrentFSMState: trying to load weapon without FSM (or uninitialized weapon) this=" +
this +
" type=" +
GetType());
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);
626 super.OnStoreSave(ctx);
629 int current_muzzle = GetCurrentMuzzle();
630 ctx.Write(current_muzzle);
633 int mode_count = GetMuzzleCount();
634 ctx.Write(mode_count);
635 for (
int m = 0; m < mode_count; ++m)
636 ctx.Write(GetCurrentMode(m));
638 ctx.Write(m_isJammed);
641 m_fsm.OnStoreSave(ctx);
655 return m_fsm.GetInternalStateID();
666 return m_fsm.GetCurrentStableStateID();
679 int mi = GetCurrentMuzzle();
680 Magazine mag = GetMagazine(mi);
681 bool has_mag = mag != null;
682 bool has_bullet = !IsChamberEmpty(mi);
685 m_fsm.RandomizeFSMStateEx(muzzleStates, has_mag, has_jam);
686 ForceSyncSelectionState();
695 int nMuzzles = GetMuzzleCount();
696 for (
int i = 0; i < nMuzzles; ++i)
703 else if (IsChamberEmpty(i))
706 ErrorEx(
string.Format(
"Unable to identify chamber state of muzzle %1", i));
708 muzzleStates.Insert(state);
734 ErrorEx(
string.Format(
"%1 does not exist or is not a weapon.", weaponType));
738 wpn.SpawnAmmo(magazineType, flags);
748 bool SpawnAmmo(
string magazineType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
751 if ( HasInternalMagazine(-1) && FillInnerMagazine(magazineType, flags) )
755 if ( GetMagazineTypeCount(0) > 0 && SpawnAttachedMagazine(magazineType, flags) )
759 if ( FillChamber(magazineType, flags) )
774 if ( GetMagazineTypeCount(0) == 0 )
776 ErrorEx(
string.Format(
"No 'magazines' config entry for %1.",
this));
781 if ( magazineType ==
"" )
783 if ( flags & WeaponWithAmmoFlags.MAX_CAPACITY_MAG)
784 magazineType = GetMaxMagazineTypeName(0);
786 magazineType = GetRandomMagazineTypeName(0);
789 EntityAI magAI = GetInventory().CreateAttachment(magazineType);
797 if (!CastTo(mag, magAI))
804 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
805 mag.ServerSetAmmoCount(
Math.RandomIntInclusive(0, mag.GetAmmoMax()));
807 if(MustBeChambered(0))
811 if(mag.ServerAcquireCartridge(dmg,bulletType))
813 FillChamber(bulletType, flags);
818 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
819 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || chamberRng;
820 if (chamber || chamberRng)
822 FillChamber(magazineType, flags);
842 if (!HasInternalMagazine(-1))
848 if (!
AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
853 bool didSomething =
false;
854 bool needUpdateStateMachine =
false;
855 int muzzCount = GetMuzzleCount();
857 bool ammoRng = ammoType ==
"";
858 bool ammoFullRng = ammoRng && (flags & WeaponWithAmmoFlags.AMMO_MAG_RNG);
861 if (ammoRng && !ammoFullRng)
862 ammoType = GetRandomChamberableAmmoTypeName(0);
865 for (
int i = 0; i < muzzCount; ++i)
867 bool loadAnyBullet =
false;
868 int ammoCount = GetInternalMagazineMaxCartridgeCount(i);
871 if ( flags & WeaponWithAmmoFlags.QUANTITY_RNG )
872 ammoCount =
Math.RandomIntInclusive(0, ammoCount);
878 for (
int j = 0; j < ammoCount; ++j)
882 ammoType = GetRandomChamberableAmmoTypeName(i);
884 PushCartridgeToInternalMagazine(i, 0, ammoType);
885 loadAnyBullet =
true;
889 if (loadAnyBullet && MustBeChambered(i))
892 ammoType = GetRandomChamberableAmmoTypeName(i);
894 if (FillSpecificChamber(i, 0, ammoType))
895 needUpdateStateMachine =
true;
902 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
903 if (chamber && FillChamber(ammoType, flags))
912 if( needUpdateStateMachine )
929 bool FillChamber(
string ammoType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
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);
937 if (chamber || chamberFullRng)
942 if (!
AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
945 else if (!(flags & WeaponWithAmmoFlags.AMMO_CHAMBER_RNG))
947 ammoType = GetRandomChamberableAmmoTypeName(0);
951 int muzzCount = GetMuzzleCount();
952 int amountToChamber = muzzCount;
955 amountToChamber =
Math.RandomIntInclusive(0, muzzCount);
958 for (
int m = 0; m < muzzCount; ++m)
961 chamber =
Math.RandomIntInclusive(0, 1);
965 if (FillSpecificChamber(m))
969 if (amountToChamber <= 0)
988 if(!IsChamberEmpty(muzzleIndex))
993 ammoType = GetRandomChamberableAmmoTypeName(muzzleIndex);
997 if (!
AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
1001 return PushCartridgeToChamber(muzzleIndex, dmg, ammoType);
1013 int ac = GetInventory().AttachmentCount();
1014 int sc = GetInventory().GetAttachmentSlotsCount() + GetMuzzleCount();
1015 if (ac > sc) sc = ac;
1021 if (!m_PropertyModifierObject)
1025 return m_PropertyModifierObject;
1058 if ( !
GetGame().IsDedicatedServer() )
1062 if ( fireMode == 0 )
1075 if (m_DelayedValidationTimer)
1077 m_DelayedValidationTimer.Run(VALIDATE_DELAY ,
this,
"ValidateAndRepair");
1081 Error(
"[wpn] Weapon_Base::DelayedValidateAndRepair m_DelayedValidationTimer not initialized.");
1082 ValidateAndRepair();
1089 m_fsm.ValidateAndRepair();
1094 m_PropertyModifierObject = null;
1099 ValidateAndRepair();
1104 DelayedValidateAndRepair();
1107 super.OnInventoryEnter(player);
1112 m_PropertyModifierObject = null;
1113 super.OnInventoryExit(player);
1118 super.EEItemAttached(item, slot_name);
1120 GetPropertyModifierObject().UpdateModifiers();
1125 super.EEItemDetached(item, slot_name);
1127 GetPropertyModifierObject().UpdateModifiers();
1132 super.EEItemLocationChanged(oldLoc, newLoc);
1137 if (newLoc.GetParent() &&
PlayerBase.CastTo(player, newLoc.GetParent()))
1139 HumanCommandMove cm = player.GetCommand_Move();
1142 cm.SetMeleeBlock(
false);
1173 super.OnItemLocationChanged(old_owner,new_owner);
1179 player.SetReturnToOptics(
false);
1183 if (
Class.CastTo(optics,GetAttachedOptics()))
1185 player.SwitchOptics(optics,
false);
1189 if (old_owner != new_owner &&
PlayerBase.Cast(new_owner))
1190 SetWasIronSight(
true);
1192 HideWeaponBarrel(
false);
1197 if ( !super.CanReleaseAttachment( attachment ) )
1199 Magazine mag = Magazine.Cast(attachment);
1205 if ( player.GetItemInHands() ==
this )
1220 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" not in stable state=" + GetCurrentState().
Type()); }
1227 if (GetInventory().GetCurrentInventoryLocation(il))
1248 e.WriteToContext(ctx);
1251 wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" send 2 remote: sending e=" + e +
" id=" + e.GetEventID() +
" p=" + e.m_player +
" m=" + e.m_magazine);
1253 p.StoreInputForRemotes(ctx);
1270 if (!IsChamberEmpty(GetCurrentMuzzle()) && !
IsChamberFiredOut(GetCurrentMuzzle()) && !
IsJammed() && !m_LiftWeapon && !IsDamageDestroyed())
1281 return optic.HasWeaponIronsightsOverride();
1287 if (
GetGame().ConfigIsExisting(
"cfgWeapons " +
GetType() +
" PPDOFProperties"))
1289 GetGame().ConfigGetFloatArray(
"cfgWeapons " +
GetType() +
" PPDOFProperties", temp_array);
1297 if (
GetGame().ConfigIsExisting(
"cfgWeapons " +
GetType() +
" Reliability ChanceToJam"))
1299 GetGame().ConfigGetFloatArray(
"cfgWeapons " +
GetType() +
" Reliability ChanceToJam", reliability_array);
1308 if (ConfigIsExisting(
"WeaponLength"))
1310 m_WeaponLength = ConfigGetFloat(
"WeaponLength");
1313 m_WeaponLength = 0.8;
1320 if (ConfigIsExisting(
"WeaponLiftCheckVerticalOffset"))
1322 m_WeaponLiftCheckVerticalOffset = ConfigGetFloat(
"WeaponLiftCheckVerticalOffset");
1325 m_WeaponLiftCheckVerticalOffset = 0.0;
1332 if (ConfigIsExisting(
"ShoulderDistance"))
1334 m_ShoulderDistance = ConfigGetFloat(
"ShoulderDistance");
1338 m_ShoulderDistance = 0;
1345 if (ConfigIsExisting(
"ObstructionDistance"))
1347 m_ObstructionDistance = ConfigGetFloat(
"ObstructionDistance");
1351 m_ObstructionDistance = 0;
1357 return m_DOFProperties;
1362 return m_WasIronSight;
1368 m_WasIronSight = state;
1376 return LiftWeaponCheckEx(player, obstruction,
object);
1387 HumanMovementState ms =
new HumanMovementState();
1388 player.GetMovementState(ms);
1390 #ifdef DIAG_DEVELOPER
1399 if (ms.IsInProne() || ms.IsInRaisedProne())
1411 isStatic = !isDynamic;
1414 #ifdef DIAG_DEVELOPER
1417 if (diagAlwaysDynamic && isDynamic)
1422 if (diagNeverStatic && isStatic)
1440 else if (obstructionValue > 0)
1450 bool isLift = player.IsLiftWeapon();
1452 if (isLift && obstructionValue > 0.9)
1457 if (!isLift && obstructionValue >= 1.0)
1462 #ifdef DIAG_DEVELOPER
1468 return m_ObstructionDistance != 0;
1487 dst.Insert( 0.0, -1.0,
" 0.16 0.22 -0.04");
1488 dst.Insert( 0.0, -0.5,
" 0.14 0.13 0.00");
1489 dst.Insert( 0.0, 0.0,
" 0.13 0.04 -0.02");
1490 dst.Insert( 0.0, 0.5,
" 0.13 0.01 -0.03");
1491 dst.Insert( 0.0, 1.0,
" 0.14 -0.01 -0.04");
1495 dst.Insert( 0.0, -1.0,
" 0.120 -0.080 -0.030");
1496 dst.Insert( 0.0, -0.5,
" 0.120 -0.040 -0.040");
1497 dst.Insert( 0.0, 0.0,
" 0.120 0.010 -0.022");
1498 dst.Insert( 0.0, 0.5,
" 0.120 -0.080 -0.050");
1499 dst.Insert( 0.0, 1.0,
" 0.120 -0.160 -0.130");
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");
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");
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");
1521 dst.Insert( 0.0, -1.0,
"0.13 0.14 0.082");
1522 dst.Insert( 0.0, -0.5,
"0.13 0.05 0.048");
1523 dst.Insert( 0.0, 0.0,
"0.13 0.01 -0.008");
1524 dst.Insert( 0.0, 0.5,
"0.13 0.00 -0.015");
1525 dst.Insert( 0.0, 1.0,
"0.13 -0.04 -0.016");
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);
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);
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)
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);
1557 float moveWeight = moveAmount01 *
Math.Pow(aimWeight, 2.0);
1558 offset = offset + (moveWeight * moveOffset);
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];
1583 float leanAngle = hms.m_fLeaning * 35;
1585 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1586 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1587 Math3D.YawPitchRollMatrix(
Vector(xAimHandsOffset , yAimHandsOffset, leanAngle), rotTM );
1588 Math3D.MatrixMultiply3(resTM, rotTM, resTM);
1592 #ifdef DIAG_DEVELOPER
1598 float udAngle = hcw.GetBaseAimingAngleUD();
1599 float lrAngle = hcw.GetBaseAimingAngleLR();
1602 float ud11 =
Math.Clamp((ud01 * 2) - 1, -1, 1);
1604 float lr11 =
Math.Clamp((lr01 * 2) - 1, -1, 1);
1607 #ifdef DIAG_DEVELOPER
1615 vector offset = aimOffsets.Blend(lr11, ud11);
1618 if (m_WeaponLiftCheckVerticalOffset != 0)
1620 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1627 offset += moveOffset;
1631 if (hcm.IsChangingStance())
1633 offset[2] = offset[2] + 0.05;
1636 offset = offset.InvMultiply3(rotTM);
1639 start = offset.Multiply4(resTM);
1643 private float ApproximateBaseObstructionLength()
1645 float approximateLength =
Math.Max(0, m_WeaponLength / 1.5) * m_WeaponLength;
1646 return m_ShoulderDistance + approximateLength;
1657 bool LiftWeaponCheckEx(
PlayerBase player, out
float outObstruction, out
Object outHitObject)
1659 bool wasLift = m_LiftWeapon;
1660 vector lastLiftPosition = m_LastLiftPosition;
1662 m_LiftWeapon =
false;
1673 #ifdef DIAG_DEVELOPER
1677 Print(
"Error: No weapon owner for LiftWeaponCheckEx, returning.");
1682 HumanMovementState movementState =
new HumanMovementState();
1683 player.GetMovementState(movementState);
1684 if (!movementState.IsRaised())
1691 #ifdef DIAG_DEVELOPER
1703 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1704 HumanCommandMove hcm = player.GetCommand_Move();
1708 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1709 hcw.GetBaseAimingAngleUD(),
1712 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1713 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1715 yawPitchRoll[0] = yawPitchRoll[0] + xAimHandsOffset;
1718 direction = yawPitchRoll.AnglesToVector();
1723 if (hic.CameraIsFreeLook())
1725 if (player.m_DirectionToCursor !=
vector.Zero)
1727 direction = player.m_DirectionToCursor;
1732 direction = MiscGameplayFunctions.GetHeadingVector(player);
1737 direction =
GetGame().GetCurrentCameraDirection();
1743 int boneIdx = player.GetBoneIndexByName(
"Neck");
1746 start = player.GetPosition()[1] + 1.5;
1750 start = player.GetBonePositionWS(boneIdx);
1755 velocity = player.VectorToLocal(velocity);
1756 ApproximateWeaponLiftTransform(start, direction, movementState, hic, hcw, hcm, velocity);
1758 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1761 float weaponLength = m_WeaponLength + effectiveAttachmentLength;
1765 float weaponStartDist = m_ShoulderDistance;
1766 float weaponEndDist = weaponStartDist + weaponLength;
1769 vector weaponStart = start + (weaponStartDist * direction);
1770 vector weaponEnd = start + (weaponEndDist * direction);
1776 float baseObstructionLength = m_ObstructionDistance;
1777 if (baseObstructionLength==0)
1779 baseObstructionLength = ApproximateBaseObstructionLength();
1782 float weaponObstructionDist = baseObstructionLength + effectiveAttachmentLength;
1783 float rayRadius = 0.02;
1786 #ifdef DIAG_DEVELOPER
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;
1796 float rayEndDist = weaponEndDist + 0.30;
1797 vector rayEnd = start + rayEndDist * direction;
1802 rayParm.type = ObjIntersect.Fire;
1809 if (!
DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1816 int numRes = results.Count();
1819 hitResult = results[0];
1824 float maxDist =
float.MAX;
1825 for (
int i = 0, nr = results.Count(); i < nr; ++i)
1827 float sqDist =
vector.DistanceSq(results[i].pos, weaponStart);
1828 if (sqDist < maxDist)
1834 hitResult = results[bi];
1837 if (LiftWeaponRaycastResultCheck(hitResult))
1839 float len0 = (hitResult.pos - start).Length();
1840 float len1 = (weaponEnd - start).Length();
1842 if (len0 <= 0 || len1 <= 0)
1848 hitFraction = len0 / len1;
1850 hitDist = hitFraction * weaponEndDist;
1860 #ifdef DIAG_DEVELOPER
1861 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetIntersectionParams(hitResult, hitFraction, hitDist);
1867 bool wantsLift = wasLift;
1870 const float inThreshold = 0.002;
1872 const float outThreshold = 0.003;
1873 const float noIsctOutThreshold = 0.01;
1876 const int maxNumMissedTicks = 10;
1880 float angleThreshold = 0.75 +
Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1883 if (hitFraction != 0)
1885 vector v1 = hitResult.pos - weaponEnd;
1886 vector v2 = hitResult.pos - rayEnd;
1887 float d =
vector.Dot(v1, v2);
1890 if (!wasLift && d > inThreshold)
1894 else if (wasLift && d < -outThreshold)
1899 m_LastLiftPosition = hitResult.pos;
1900 m_LastLiftHit = player.GetSimulationTimeStamp();
1905 if (lastLiftPosition ==
vector.Zero)
1908 m_LastLiftPosition =
vector.Zero;
1914 vector v3 = (lastLiftPosition - start).Normalized();
1915 vector v4 = (weaponEnd-start).Normalized();
1916 float d2 =
vector.Dot(v3, v4);
1918 if (
Math.Acos(d2) > (angleThreshold *
Math.DEG2RAD))
1921 m_LastLiftPosition =
vector.Zero;
1926 float d3 =
vector.Dot( lastLiftPosition - weaponEnd, (start-weaponEnd).Normalized() );
1927 if (d3 < -noIsctOutThreshold)
1930 m_LastLiftPosition =
vector.Zero;
1932 float lastObstruction = hcw.GetWeaponObstruction();
1934 int timeSinceHit = player.GetSimulationTimeStamp() - m_LastLiftHit;
1935 if (timeSinceHit > maxNumMissedTicks)
1938 m_LastLiftPosition =
vector.Zero;
1940 else if (wantsLift && m_LastLiftPosition !=
vector.Zero)
1942 float l0 = (m_LastLiftPosition - start).Length();
1943 float l1 = (weaponEnd - start).Length();
1944 if (l0 <= 0 || l1 <= 0)
1950 hitFraction = l0 / l1;
1952 hitDist = hitFraction * weaponEndDist;
1962 float begDist = weaponObstructionDist;
1963 float endDist = weaponStartDist + weaponLength;
1966 if (begDist < endDist)
1967 obstFraction =
Math.InverseLerp( begDist, endDist, hitDist );
1970 outHitObject = hitResult.obj;
1972 outObstruction = 1.0 - obstFraction;
1973 m_LiftWeapon =
true;
1986 float GetObstructionPenetrationDistance(
float obstruction01)
1988 float baseObstructionLength = m_ObstructionDistance;
1989 if (baseObstructionLength==0)
1991 baseObstructionLength = ApproximateBaseObstructionLength();
1994 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1995 float weaponEnd = m_ShoulderDistance + m_WeaponLength + effectiveAttachmentLength;
1996 return weaponEnd -
Math.Lerp(weaponEnd, baseObstructionLength + effectiveAttachmentLength, obstruction01);
2002 return res.surface.IsSolid();
2006 float GetEffectiveAttachmentLength()
2009 if (HasBayonetAttached())
2011 int bayonetIndex = GetBayonetAttachmentIdx();
2012 attachment =
ItemBase.Cast(GetInventory().FindAttachment(bayonetIndex));
2016 attachment = GetAttachedSuppressor();
2021 return Math.Max(attachment.m_ItemModelLength + attachment.m_ItemAttachOffset, 0);
2029 void SetSyncJammingChance(
float jamming_chance )
2031 m_ChanceToJamSync = jamming_chance;
2044 bool EjectCartridge(
int muzzleIndex, out
float ammoDamage, out
string ammoTypeName)
2046 if (IsChamberEjectable(muzzleIndex))
2048 if (PopCartridgeFromChamber(muzzleIndex, ammoDamage, ammoTypeName))
2051 else if (GetInternalMagazineCartridgeCount(muzzleIndex) > 0)
2053 if (PopCartridgeFromInternalMagazine(muzzleIndex, ammoDamage, ammoTypeName))
2064 for (
int mi = 0; mi < src.GetMuzzleCount(); ++mi)
2066 if (!src.IsChamberEmpty(mi))
2068 if (src.GetCartridgeInfo(mi, damage, type))
2070 PushCartridgeToChamber(mi, damage, type);
2074 for (
int ci = 0; ci < src.GetInternalMagazineCartridgeCount(mi); ++ci)
2076 if (src.GetInternalMagazineCartridgeInfo(mi, ci, damage, type))
2078 PushCartridgeToInternalMagazine(mi, damage, type);
2083 int dummy_version =
int.MAX;
2088 src.OnStoreSave(ctx.GetWriteContext());
2094 override void SetBayonetAttached(
bool pState,
int slot_idx = -1)
2096 m_BayonetAttached = pState;
2097 m_BayonetAttachmentIdx = slot_idx;
2100 override bool HasBayonetAttached()
2102 return m_BayonetAttached;
2105 override int GetBayonetAttachmentIdx()
2107 return m_BayonetAttachmentIdx;
2110 override void SetButtstockAttached(
bool pState,
int slot_idx = -1)
2112 m_ButtstockAttached = pState;
2113 m_ButtstockAttachmentIdx = slot_idx;
2116 override bool HasButtstockAttached()
2118 return m_ButtstockAttached;
2121 override int GetButtstockAttachmentIdx()
2123 return m_ButtstockAttachmentIdx;
2126 void HideWeaponBarrel(
bool state)
2128 if ( !
GetGame().IsDedicatedServer() )
2131 if ( optics && !optics.
AllowsDOF() && m_weaponHideBarrelIdx != -1 )
2133 SetSimpleHiddenSelectionState(m_weaponHideBarrelIdx,!state);
2140 if (m_magazineSimpleSelectionIndex > -1)
2141 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,1);
2143 SelectionMagazineShow();
2148 if (m_magazineSimpleSelectionIndex > -1)
2149 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,0);
2151 SelectionMagazineHide();
2154 override EntityAI ProcessMeleeItemDamage(
int mode = 0)
2161 super.ProcessMeleeItemDamage();
2165 attachment = GetInventory().FindAttachment(m_ButtstockAttachmentIdx);
2169 attachment = GetInventory().FindAttachment(m_BayonetAttachmentIdx);
2173 super.ProcessMeleeItemDamage();
2179 attachment.ProcessMeleeItemDamage();
2186 bool IsShowingChamberedBullet()
2193 return m_BurstCount;
2196 void ResetBurstCount()
2201 override void SetActions()
2217 if (!ConfigGetBool(
"isSuicideWeapon"))
2220 return super.CanBeUsedForSuicide();
2224 override void OnDebugSpawn()
2226 SpawnAmmo(
"", SAMF_DEFAULT);
2229 bool AddJunctureToAttachedMagazine(
PlayerBase player,
int timeoutMS)
2231 Magazine mag = GetMagazine(GetCurrentMuzzle());
2235 return GetGame().AddInventoryJunctureEx(player, mag, il,
false, timeoutMS);
2241 void ClearJunctureToAttachedMagazine(
PlayerBase player)
2243 Magazine mag = GetMagazine(GetCurrentMuzzle());
2246 GetGame().ClearJunctureEx(player, mag);
2250 void SetNextWeaponMode(
int muzzleIndex)
2252 SetNextMuzzleMode(muzzleIndex);
2256 void SetCoolDown(
float coolDownTime )
2258 m_coolDownTime = coolDownTime;
2260 void UpdateCoolDown(
float dt ) { m_coolDownTime -= dt; }
2263 return m_coolDownTime > 0;
2267 bool MustBeChambered(
int muzzleIndex)
2272#ifdef TEST_WEAPON_SYSNC_REPAIR
2273 void SetSyncStable(
bool value)
2275 m_SyncStable = value;
2278 m_SyncStableTime =
GetGame().GetTickTime();
2284 return m_SyncStable;
eBleedingSourceType GetType()
void wpnDebugPrint(string s)
void AddAction(typename actionName)
class Blend2D< Class T > Blend2DVector
const int ECE_PLACE_ON_SURFACE
EWeaponObstructionMode staticMode
!! all member variables must correspond with the cfggameplay.json file contents !!...
EWeaponObstructionMode dynamicMode
pair ( action, actionType )
Super root of all classes in Enforce script.
Wrapper class for managing sound through SEffectManager.
override void SetAutodestroy(bool auto_destroy)
Sets whether Effect automatically cleans up when it stops.
represents transition src -— event[guard]/action -—|> dst
bool AllowsDOF()
returns 'true' for non-magnifying optics
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:
override void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
override vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
signalize mechanism manipulation
weapon finite state machine
script counterpart to engine's class Weapon
ref array< float > GetWeaponDOF()
Magazine SpawnAttachedMagazine(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to spawn and attach a magazine.
bool IsWaitingForActionFinish()
returns true if state machine started playing action/actionType and waits for finish
void SetWasIronSight(bool state)
bool JamCheck(int muzzleIndex)
void SyncEventToRemote(WeaponEventBase e)
void DelayedValidateAndRepair()
float m_ObstructionDistance
bool FillSpecificChamber(int muzzleIndex, float dmg=0, string ammoType="")
ref Timer m_DelayedValidationTimer
vector GetApproximateMovementOffset(vector localVelocity, int characterStance, float lean, float ud11, float lr11)
float m_WeaponLiftCheckVerticalOffset
void SyncSelectionState(bool has_bullet, bool has_mag)
void EEFired(int muzzleType, int mode, string ammoType)
static Weapon_Base CreateWeaponWithAmmo(string weaponType, string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Create weapon with ammo.
int GetWeaponSpecificCommand(int weaponAction, int subCommand)
bool FillInnerMagazine(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the inner magazine.
bool InitWeaponLiftCheckVerticalOffset()
gets weapon vertical offset from config for weaponlift raycast
int m_BayonetAttachmentIdx
ref array< float > m_DOFProperties
float GetWeightSpecialized(bool forceRecalc=false)
override int GetSlotsCountCorrect()
Returns number of slots for attachments corrected for weapons.
bool InitShoulderDistance()
gets approximate weapon distance from shoulder from config
override bool CanReleaseAttachment(EntityAI attachment)
void ShowBullet(int muzzleIndex)
void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity="0 0 0")
bool CanProcessAction(int action, int actionType)
void HideBullet(int muzzleIndex)
array< MuzzleState > GetMuzzleStates()
Helper method for RandomizeFSMState.
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
override void OnInventoryExit(Man player)
ref WeaponFSM m_fsm
weapon abilities
void RandomizeFSMState()
With the parameters given, selects a random suitable state for the FSM of the weapon @WARNING: Weapon...
bool InitObstructionDistance()
gets weapon obstruction distance from shoulder at which the weapon is fully obstructed
float GetSyncChanceToJam()
bool FillChamber(string ammoType="", int flags=WeaponWithAmmoFlags.CHAMBER)
Try to fill the chamber.
void SetWeaponAnimState(int state)
bool HasActionAbility(int action, int actionType)
query if weapon supports action and actionType
void ForceSyncSelectionState()
bool LiftWeaponCheck(PlayerBase player)
override void AfterStoreLoad()
bool ProcessWeaponAbortEvent(WeaponEventBase e)
override bool CanRemoveFromHands(EntityAI parent)
PropertyModifiers GetPropertyModifierObject()
bool ProcessWeaponEvent(WeaponEventBase e)
weapon's fsm handling of events @NOTE: warning: ProcessWeaponEvent can be called only within DayZPlay...
WeaponStateBase GetCurrentState()
returns currently active state
void AssembleGun()
override on weapons with some assembly required
AbilityRecord GetAbility(int index)
RecoilBase SpawnRecoilObject()
override void EEItemDetached(EntityAI item, string slot_name)
int GetCurrentStableStateID()
tries to return identifier of current stable state (or nearest stable state if unstable state is curr...
ref PropertyModifiers m_PropertyModifierObject
void OnFire(int muzzle_index)
override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
int m_ButtstockAttachmentIdx
void ResetWeaponAnimState()
void GetApproximateAimOffsets(Blend2DVector dst, int characterStance)
bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
bool CanEnterIronsights()
override bool OnStoreLoad(ParamsReadContext ctx, int version)
bool UseWeaponObstruction(PlayerBase player, float obstructionValue, Object hitObject)
override void OnStoreSave(ParamsWriteContext ctx)
bool CanChamberBullet(int muzzleIndex, Magazine mag)
bool CanProcessWeaponEvents()
bool SpawnAmmo(string magazineType="", int flags=WeaponWithAmmoFlags.CHAMBER)
General method trying to attch magazine, fill inner magazine and fill chamber.
void SaveCurrentFSMState(ParamsWriteContext ctx)
void OnFireModeChange(int fireMode)
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)
represents weapon's stable state (i.e. the basic states that the weapon will spend the most time in)
represent weapon state base
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
ContaminatedArea_Base EffectArea EEInit()
override string GetDebugName()
DayZPlayerInstanceType
defined in C++
DayZPlayerConstants
defined in C++
WeaponEventID
identifier for events. mainly for rpc purposes
FirearmActionLoadBullet FirearmActionBase FirearmActionLoadBulletQuick()
proto native CGame GetGame()
void Error(string err)
Messagebox with error message.
proto void Print(void var)
Prints content of variable to console/log.
array< string > TStringArray
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
proto native vector GetVelocity(notnull IEntity ent)
Returns linear velocity.
proto native bool dBodyIsDynamic(notnull IEntity ent)
class JsonUndergroundAreaTriggerData GetPosition
void fsmDebugSpam(string s)
InventoryLocationType
types of Inventory Location
bool CanBeUsedForSuicide()
bool OnStoreLoad(ParamsReadContext ctx, int version)
@ AMMO_CHAMBER_RNG
Fully randomizes the ammo type instead of picking one random for all chambers (needs to have type as ...
@ CHAMBER
Chambers bullets.
@ CHAMBER_RNG_SPORADIC
Maybe chambers bullets (full random) example: 0 1 0 0 1 1.
@ MAX_CAPACITY_MAG
Instead of randomizing when type is empty, it looks for the one which has the highest capacity.
@ QUANTITY_RNG
Randomizes the quantity of the bullets in the spawned magazine.
@ CHAMBER_RNG
Maybe chambers bullets (sequential rng) example: 1 1 1 0 0 0.
@ NONE
Attached magazine will be full and no round will be chambered.
@ AMMO_MAG_RNG
Fully randomizes the ammo type instead of picking one random for the entire mag (needs to have type a...
enum FSMTransition WeaponTransition
class WeaponEndAction extends WeaponStartAction m_action
bool IsChamberFiredOut(int idx)
bool IsWeaponOpen()
Whether the gun is open.
bool IsChamberFull(int idx)