11 enum WeaponWithAmmoFlags
41 const int SAMF_DEFAULT = WeaponWithAmmoFlags.CHAMBER | WeaponWithAmmoFlags.MAX_CAPACITY_MAG;
43 const int SAMF_RNG = WeaponWithAmmoFlags.CHAMBER_RNG | WeaponWithAmmoFlags.QUANTITY_RNG;
45 protected const float DEFAULT_DAMAGE_ON_SHOT = 0.05;
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;
55 protected int m_BayonetAttachmentIdx;
56 protected int m_ButtstockAttachmentIdx;
57 protected int m_weaponAnimState = -1;
58 protected int m_magazineSimpleSelectionIndex = -1;
59 protected int m_weaponHideBarrelIdx = -1;
60 protected float m_DmgPerShot = 0;
61 protected float m_WeaponLength;
62 protected float m_WeaponLiftCheckVerticalOffset;
63 protected float m_ShoulderDistance;
64 protected vector m_LastLiftPosition;
68 protected float m_ChanceToJamSync = 0;
75 m_BayonetAttached =
false;
76 m_ButtstockAttached =
false;
77 m_BayonetAttachmentIdx = -1;
78 m_ButtstockAttachmentIdx = -1;
82 if ( ConfigIsExisting(
"simpleHiddenSelections") )
85 ConfigGetTextArray(
"simpleHiddenSelections",selectionNames);
86 m_weaponHideBarrelIdx = selectionNames.Find(
"hide_barrel");
87 m_magazineSimpleSelectionIndex = selectionNames.Find(
"magazine");
89 int bulletIndex = selectionNames.Find(
"bullet");
90 if ( bulletIndex != -1 )
92 m_bulletSelectionIndex.Insert(bulletIndex);
94 for (
int i = 2; i < 100; i++)
96 bulletIndex = selectionNames.Find(
string.Format(
"bullet%1",i));
97 if (bulletIndex != -1)
99 m_bulletSelectionIndex.Insert(bulletIndex);
110 InitWeaponLiftCheckVerticalOffset();
111 InitShoulderDistance();
112 InitDOFProperties(m_DOFProperties);
115 InitReliability(m_ChanceToJam);
120 void InitStateMachine() { }
134 m_fsm.SetInitialState(initState);
135 SetCharged(!initState.IsDischarged());
136 SetWeaponOpen(!initState.IsWeaponOpen());
137 SetGroundAnimFrameIndex(initState.m_animState);
145 void SetCharged(
bool value)
155 void SetWeaponOpen(
bool value)
157 m_WeaponOpen = value;
162 float baseWeight = GetInventoryAndCargoWeight(forceRecalc);
165 string bulletTypeName, ammoTypeName;
167 int muzzleCount = GetMuzzleCount();
169 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
172 data1.SetCalcDetails(
"TWPN: " + m_ConfigWeight+
"(item weight) + " + baseWeight +
"(contents weight)" );
175 for (
int muzzleIndex = 0; muzzleIndex < muzzleCount; muzzleIndex++)
178 if (!IsChamberEmpty(muzzleIndex))
180 ammoTypeName = GetChamberAmmoTypeName(muzzleIndex);
181 ammoWeight +=
g_Game.ConfigGetFloat(
string.Format(
"CfgMagazines %1 weight", ammoTypeName));
184 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
187 data2.AddCalcDetails(
g_Game.ConfigGetFloat(
"CfgMagazines " + ammoTypeName +
" weight").ToString() +
"(chamber weight)");
193 if (HasInternalMagazine(muzzleIndex))
196 float debugInternalMagWeight;
198 int cartridgeCount = GetInternalMagazineCartridgeCount(muzzleIndex);
199 for (
int cartridgeIndex = 0; cartridgeIndex < cartridgeCount; cartridgeIndex++)
201 GetInternalMagazineCartridgeInfo(muzzleIndex, cartridgeIndex, ammoDamage, bulletTypeName);
202 ammoWeight +=
Ammunition_Base.GetAmmoWeightByBulletType(bulletTypeName);
204 debugInternalMagWeight +=
g_Game.ConfigGetFloat(
"CfgMagazines " + ammoTypeName +
" weight");
209 if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
212 data3.AddCalcDetails(debugInternalMagWeight.ToString()+
"(internal mag weight)");
218 return ammoWeight + baseWeight + GetConfigWeightModified();
223 bool CanProcessAction(
int action,
int actionType)
233 bool HasActionAbility(
int action,
int actionType)
235 int count = GetAbilityCount();
236 for (
int i = 0; i < count; ++i)
239 if (rec.m_action == action && rec.m_actionType == actionType)
247 int GetAbilityCount() {
return m_abilities.Count(); }
252 AbilityRecord GetAbility(
int index) {
return m_abilities.Get(index); }
257 bool CanProcessWeaponEvents() {
return m_fsm && m_fsm.IsRunning(); }
270 return CanProcessWeaponEvents() && GetCurrentState().IsWaitingForActionFinish();
275 return CanProcessWeaponEvents() && GetCurrentState().IsIdle();
284 SyncEventToRemote(e);
289 SetNextMuzzleMode(GetCurrentMuzzle());
304 SyncEventToRemote(e);
307 m_fsm.ProcessAbortEvent(e, aa);
311 bool CanChamberBullet(
int muzzleIndex, Magazine mag)
313 return CanChamberFromMag(muzzleIndex, mag) && (!
IsChamberFull(muzzleIndex) ||
IsChamberFiredOut(muzzleIndex) || !IsInternalMagazineFull(muzzleIndex));
316 void SetWeaponAnimState(
int state)
318 m_weaponAnimState = state;
319 SetGroundAnimFrameIndex(state);
321 void ResetWeaponAnimState()
324 m_weaponAnimState = -1;
326 int GetWeaponAnimState() {
return m_weaponAnimState; }
328 void EEFired(
int muzzleType,
int mode,
string ammoType)
330 if ( !
GetGame().IsDedicatedServer() )
332 ItemBase suppressor = GetAttachedSuppressor();
335 ItemBase.PlayFireParticles(
this, muzzleType, ammoType,
this, suppressor,
"CfgWeapons" );
340 ItemBase.PlayFireParticles(
this, muzzleType, ammoType, suppressor, NULL,
"CfgVehicles" );
341 suppressor.IncreaseOverheating(
this, ammoType,
this, suppressor,
"CfgVehicles");
356 #ifdef DIAG_DEVELOPER
357 MiscGameplayFunctions.UnlimitedAmmoDebugCheck(
this);
361 bool JamCheck(
int muzzleIndex )
368 if (rnd < GetSyncChanceToJam())
374 void ShowBullet(
int muzzleIndex)
376 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
378 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],1);
381 SelectionBulletShow();
384 void HideBullet(
int muzzleIndex)
386 if ( m_bulletSelectionIndex.Count() > muzzleIndex )
388 SetSimpleHiddenSelectionState(m_bulletSelectionIndex[muzzleIndex],0);
391 SelectionBulletHide();
394 bool IsJammed() {
return m_isJammed; }
395 bool CanEjectBullet() {
return true;}
396 void SetJammed(
bool value) { m_isJammed = value; }
397 float GetSyncChanceToJam() {
return m_ChanceToJamSync; }
398 float GetChanceToJam()
400 int level = GetHealthLevel();
402 if (level >= 0 && level < m_ChanceToJam.Count())
403 return m_ChanceToJam[level];
408 void SyncSelectionState(
bool has_bullet,
bool has_mag)
412 string chamberedAmmoTypeName;
413 float chamberedAmmoDmg;
415 if ( GetCartridgeInfo(0, chamberedAmmoDmg, chamberedAmmoTypeName) )
417 EffectBulletShow(0, chamberedAmmoDmg, chamberedAmmoTypeName);
420 SelectionBulletShow();
425 SelectionBulletHide();
449 void ForceSyncSelectionState()
451 int nMuzzles = GetMuzzleCount();
452 for (
int i = 0; i < nMuzzles; ++i)
459 GetCartridgeInfo(i, damage, ammoTypeName);
460 EffectBulletShow(i, damage, ammoTypeName);
468 Magazine mag = GetMagazine(i);
478 if ( !super.OnStoreLoad(ctx, version) )
484 int current_muzzle = 0;
485 if (!ctx.Read(current_muzzle))
487 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read current muzzle!");
491 if (current_muzzle >= GetMuzzleCount() || current_muzzle < 0)
492 Error(
"Weapon.OnStoreLoad " +
this +
" trying to set muzzle index " + current_muzzle +
" while it only has " + GetMuzzleCount() +
" muzzles!");
494 SetCurrentMuzzle(current_muzzle);
500 if (!ctx.Read(mode_count))
502 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read mode count!");
506 for (
int m = 0; m < mode_count; ++m)
511 Error(
"Weapon.OnStoreLoad " +
this +
" cannot read mode[" + m +
"]");
515 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" OnStoreLoad - loaded muzzle[" + m +
"].mode = " + mode); }
516 SetCurrentMode(m, mode);
520 if ( version >= 106 )
522 if ( !ctx.Read(m_isJammed) )
524 Error(
"Weapon.OnStoreLoad cannot load jamming state");
531 if (!m_fsm.OnStoreLoad(ctx, version))
537 SetGroundAnimFrameIndex(wss.m_animState);
544 if (!ctx.Read(dummy))
553 if (m_fsm && m_fsm.IsRunning())
555 if (m_fsm.SaveCurrentFSMState(ctx))
560 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" state NOT saved.");
563 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon.SaveCurrentFSMState: trying to save weapon without FSM (or uninitialized weapon) this=" +
this +
" type=" +
GetType());
570 if (m_fsm.LoadCurrentFSMState(ctx, version))
575 SyncSelectionState(state.HasBullet(), state.HasMagazine());
576 state.SyncAnimState();
577 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" stable state loaded and synced."); }
582 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" unstable/error state loaded."); }
588 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" did not load.");
594 Error(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon.LoadCurrentFSMState: trying to load weapon without FSM (or uninitialized weapon) this=" +
this +
" type=" +
GetType());
603 int mi = GetCurrentMuzzle();
604 Magazine mag = GetMagazine(mi);
605 bool has_mag = mag !=
null;
606 bool has_bullet = !IsChamberEmpty(mi);
607 SyncSelectionState(has_bullet, has_mag);
613 super.OnStoreSave(ctx);
616 int current_muzzle = GetCurrentMuzzle();
617 ctx.Write(current_muzzle);
620 int mode_count = GetMuzzleCount();
621 ctx.Write(mode_count);
622 for (
int m = 0; m < mode_count; ++m)
623 ctx.Write(GetCurrentMode(m));
625 ctx.Write(m_isJammed);
628 m_fsm.OnStoreSave(ctx);
639 int GetInternalStateID()
642 return m_fsm.GetInternalStateID();
649 int GetCurrentStableStateID()
653 return m_fsm.GetCurrentStableStateID();
662 void RandomizeFSMState()
666 int mi = GetCurrentMuzzle();
667 Magazine mag = GetMagazine(mi);
668 bool has_mag = mag !=
null;
669 bool has_bullet = !IsChamberEmpty(mi);
672 m_fsm.RandomizeFSMStateEx(muzzleStates, has_mag, has_jam);
673 ForceSyncSelectionState();
682 int nMuzzles = GetMuzzleCount();
683 for (
int i = 0; i < nMuzzles; ++i)
690 else if (IsChamberEmpty(i))
693 ErrorEx(
string.Format(
"Unable to identify chamber state of muzzle %1", i));
695 muzzleStates.Insert(state);
715 static Weapon_Base CreateWeaponWithAmmo(
string weaponType,
string magazineType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
721 ErrorEx(
string.Format(
"%1 does not exist or is not a weapon.", weaponType));
725 wpn.SpawnAmmo(magazineType, flags);
735 bool SpawnAmmo(
string magazineType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
738 if ( HasInternalMagazine(-1) && FillInnerMagazine(magazineType, flags) )
742 if ( GetMagazineTypeCount(0) > 0 && SpawnAttachedMagazine(magazineType, flags) )
746 if ( FillChamber(magazineType, flags) )
758 Magazine SpawnAttachedMagazine(
string magazineType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
761 if ( GetMagazineTypeCount(0) == 0 )
763 ErrorEx(
string.Format(
"No 'magazines' config entry for %1.",
this));
768 if ( magazineType ==
"" )
770 if ( flags & WeaponWithAmmoFlags.MAX_CAPACITY_MAG)
771 magazineType = GetMaxMagazineTypeName(0);
773 magazineType = GetRandomMagazineTypeName(0);
776 EntityAI magAI = GetInventory().CreateAttachment(magazineType);
784 if (!CastTo(mag, magAI))
791 if (flags & WeaponWithAmmoFlags.QUANTITY_RNG)
792 mag.ServerSetAmmoCount(
Math.RandomIntInclusive(0, mag.GetAmmoMax()));
795 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
796 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || chamberRng;
797 if (chamber || chamberRng)
799 FillChamber(magazineType, flags);
816 bool FillInnerMagazine(
string ammoType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
819 if (!HasInternalMagazine(-1))
825 if (!
AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
830 bool didSomething =
false;
831 int muzzCount = GetMuzzleCount();
833 bool ammoRng = ammoType ==
"";
834 bool ammoFullRng = ammoRng && (flags & WeaponWithAmmoFlags.AMMO_MAG_RNG);
837 if (ammoRng && !ammoFullRng)
838 ammoType = GetRandomChamberableAmmoTypeName(0);
841 for (
int i = 0; i < muzzCount; ++i)
843 int ammoCount = GetInternalMagazineMaxCartridgeCount(i);
846 if ( flags & WeaponWithAmmoFlags.QUANTITY_RNG )
847 ammoCount =
Math.RandomIntInclusive(0, ammoCount);
853 for (
int j = 0; j < ammoCount; ++j)
857 ammoType = GetRandomChamberableAmmoTypeName(i);
859 PushCartridgeToInternalMagazine(i, 0, ammoType);
866 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER) || (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
867 if (chamber && FillChamber(ammoType, flags))
884 bool FillChamber(
string ammoType =
"",
int flags = WeaponWithAmmoFlags.CHAMBER )
887 int muzzCount = GetMuzzleCount();
888 bool anyEmpty =
false;
890 for (
int m = 0; m < muzzCount; ++m)
892 if (IsChamberEmpty(m))
904 if (!
AmmoTypesAPI.MagazineTypeToAmmoType(ammoType, ammoType))
908 bool didSomething =
false;
909 bool chamberFullRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG_SPORADIC);
910 bool chamberRng = (flags & WeaponWithAmmoFlags.CHAMBER_RNG);
911 bool chamber = (flags & WeaponWithAmmoFlags.CHAMBER);
913 if (chamber || chamberRng || chamberFullRng)
915 int amountToChamber = muzzCount;
919 amountToChamber =
Math.RandomIntInclusive(0, muzzCount);
921 bool chamberAmmoRng = (ammoType ==
"");
922 bool chamberAmmoFullRng = chamberAmmoRng && (flags & WeaponWithAmmoFlags.AMMO_CHAMBER_RNG);
925 if (chamberAmmoRng && !chamberAmmoFullRng)
926 ammoType = GetRandomChamberableAmmoTypeName(0);
928 for (
int i = 0; i < muzzCount; ++i)
931 if (!IsChamberEmpty(i))
936 chamber =
Math.RandomIntInclusive(0, 1);
942 if ( chamberAmmoFullRng )
943 ammoType = GetRandomChamberableAmmoTypeName(i);
946 PushCartridgeToChamber(i, 0, ammoType);
951 if (amountToChamber <= 0)
975 override int GetSlotsCountCorrect()
977 int ac = GetInventory().AttachmentCount();
978 int sc = GetInventory().GetAttachmentSlotsCount() + GetMuzzleCount();
979 if (ac > sc) sc = ac;
985 if (!m_PropertyModifierObject)
989 return m_PropertyModifierObject;
992 void OnFire(
int muzzle_index)
1020 void OnFireModeChange(
int fireMode)
1022 if ( !
GetGame().IsDedicatedServer() )
1026 if ( fireMode == 0 )
1031 eff.SetAutodestroy(
true);
1037 void ValidateAndRepair()
1040 m_fsm.ValidateAndRepair();
1045 m_PropertyModifierObject =
null;
1047 ValidateAndRepair();
1049 super.OnInventoryEnter(player);
1054 m_PropertyModifierObject =
null;
1055 super.OnInventoryExit(player);
1060 super.EEItemAttached(item, slot_name);
1062 GetPropertyModifierObject().UpdateModifiers();
1067 super.EEItemDetached(item, slot_name);
1069 GetPropertyModifierObject().UpdateModifiers();
1074 super.EEItemLocationChanged(oldLoc, newLoc);
1079 if (newLoc.GetParent() &&
PlayerBase.CastTo(player, newLoc.GetParent()))
1084 cm.SetMeleeBlock(
false);
1092 super.OnItemLocationChanged(old_owner,new_owner);
1098 player.SetReturnToOptics(
false);
1102 if (
Class.CastTo(optics,GetAttachedOptics()))
1104 player.SwitchOptics(optics,
false);
1108 HideWeaponBarrel(
false);
1113 if ( !super.CanReleaseAttachment( attachment ) )
1115 Magazine mag = Magazine.Cast(attachment);
1121 if ( player.GetItemInHands() ==
this )
1136 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" Weapon=" +
this +
" not in stable state=" + GetCurrentState().
Type()); }
1140 bool IsRemoteWeapon()
1143 if (GetInventory().GetCurrentInventoryLocation(il))
1164 e.WriteToContext(ctx);
1167 wpnDebugPrint(
"[wpnfsm] " +
Object.GetDebugName(
this) +
" send 2 remote: sending e=" + e +
" id=" + e.GetEventID() +
" p=" + e.m_player +
" m=" + e.m_magazine);
1169 p.StoreInputForRemotes(ctx);
1179 int GetWeaponSpecificCommand(
int weaponAction,
int subCommand)
1197 return optic.HasWeaponIronsightsOverride();
1203 if (
GetGame().ConfigIsExisting(
"cfgWeapons " +
GetType() +
" PPDOFProperties"))
1205 GetGame().ConfigGetFloatArray(
"cfgWeapons " +
GetType() +
" PPDOFProperties", temp_array);
1211 bool InitReliability(out
array<float> reliability_array)
1213 if (
GetGame().ConfigIsExisting(
"cfgWeapons " +
GetType() +
" Reliability ChanceToJam"))
1215 GetGame().ConfigGetFloatArray(
"cfgWeapons " +
GetType() +
" Reliability ChanceToJam", reliability_array);
1222 bool InitWeaponLength()
1224 if (ConfigIsExisting(
"WeaponLength"))
1226 m_WeaponLength = ConfigGetFloat(
"WeaponLength");
1229 m_WeaponLength = 0.8;
1234 bool InitWeaponLiftCheckVerticalOffset()
1236 if (ConfigIsExisting(
"WeaponLiftCheckVerticalOffset"))
1238 m_WeaponLiftCheckVerticalOffset = ConfigGetFloat(
"WeaponLiftCheckVerticalOffset");
1241 m_WeaponLiftCheckVerticalOffset = 0.0;
1246 protected bool InitShoulderDistance()
1248 if (ConfigIsExisting(
"ShoulderDistance"))
1250 m_ShoulderDistance = ConfigGetFloat(
"ShoulderDistance");
1254 m_ShoulderDistance = 0;
1260 return m_DOFProperties;
1271 vector usti_hlavne_position;
1272 vector trigger_axis_position;
1273 vector hit_pos, hit_normal;
1278 bool wasLift = m_LiftWeapon;
1279 vector lastLiftPosition = m_LastLiftPosition;
1281 m_LiftWeapon =
false;
1283 if ( HasSelection(
"Usti hlavne") )
1288 Print(
"Error: No weapon owner, returning");
1293 player.GetMovementState(movementState);
1294 if (!movementState.IsRaised())
1303 usti_hlavne_position = GetSelectionPositionLS(
"Usti hlavne" );
1304 trigger_axis_position = GetSelectionPositionLS(
"trigger_axis");
1312 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1313 hcw.GetBaseAimingAngleUD(),
1315 direction = yawPitchRoll.AnglesToVector();
1320 if (player.GetInputController().CameraIsFreeLook())
1322 if (player.m_DirectionToCursor !=
vector.Zero)
1324 direction = player.m_DirectionToCursor;
1329 direction = MiscGameplayFunctions.GetHeadingVector(player);
1334 direction =
GetGame().GetCurrentCameraDirection();
1338 idx = player.GetBoneIndexByName(
"Neck");
1340 { start = player.GetPosition()[1] + 1.5; }
1342 { start = player.GetBonePositionWS(idx); }
1352 resTM[0] =
Vector(direction[0], 0, direction[2]).Normalized();
1353 resTM[0] =
vector.RotateAroundZeroDeg(resTM[0],
vector.Up, 90);
1354 resTM[2] = direction;
1355 resTM[1] = resTM[2] * resTM[0];
1360 player.GetMovementState(hms);
1361 float leanAngle = hms.m_fLeaning * 35;
1363 Math3D.YawPitchRollMatrix(
Vector(0, 0, leanAngle), rotTM );
1364 Math3D.MatrixMultiply3(resTM, rotTM, resTM);
1367 #ifdef DIAG_DEVELOPER
1378 float udAngle =
Math.Asin(direction[1]) *
Math.RAD2DEG;
1388 const int lastIndex = 2;
1392 int lo = a * lastIndex;
1393 int hi =
Math.Clamp(lo+1, 0, lastIndex);
1396 float t =
Math.Clamp(a * lastIndex - lo, 0, 1);
1397 vector offset =
vector.Lerp(offsets[lo], offsets[hi], t);
1410 int stanceOffsetIndex = hms.m_iStanceIdx;
1415 offset += stanceOffsets[stanceOffsetIndex];
1418 if (m_WeaponLiftCheckVerticalOffset != 0)
1420 offset[1] = offset[1] + m_WeaponLiftCheckVerticalOffset;
1426 start = offset.Multiply4(resTM);
1432 distance = m_WeaponLength + GetEffectiveAttachmentLength();
1434 vector weaponStart = start + (m_ShoulderDistance * direction);
1435 vector weaponEnd = weaponStart + (distance * direction);
1438 #ifdef DIAG_DEVELOPER
1441 vector diagNoAttachEnd = weaponStart + (m_WeaponLength * direction);
1443 float diagPtsRadius = 0.025;
1444 Shape.CreateSphere(
COLOR_GREEN, diagPtsShpFlgs, weaponStart, diagPtsRadius);
1445 Shape.CreateSphere(
COLOR_YELLOW, diagPtsShpFlgs, diagNoAttachEnd, diagPtsRadius);
1446 Shape.CreateSphere(
COLOR_BLUE, diagPtsShpFlgs, weaponEnd, diagPtsRadius);
1452 end = weaponEnd + ((0.1 * distance) * direction);
1457 rayParm.type = ObjIntersect.Fire;
1459 DbgUI.BeginCleanupScope();
1461 if (!
DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1470 #ifdef DIAG_DEVELOPER // isect diag
1473 DbgUI.Begin(
"Weapon Lift Diag");
1477 DbgUI.Text(
"Intersection data:");
1478 DbgUI.Text(
" Name: " + res.surface.GetName());
1479 DbgUI.Text(
" EntryName: " + res.surface.GetEntryName());
1480 DbgUI.Text(
" SurfaceType: " + res.surface.GetSurfaceType());
1482 DbgUI.Text(
" IsPassThrough: " + res.surface.IsPassthrough());
1483 DbgUI.Text(
" IsSolid: " + res.surface.IsSolid());
1487 DbgUI.Text(
"Intersection with no surface");
1492 #endif // !isect diag
1494 if (LiftWeaponRaycastResultCheck(res))
1497 float len0 = (hit_pos - start).Length();
1498 float len1 = (end - start).Length();
1499 if (len0 <= 0 || len1 <= 0)
1505 hit_fraction = len0 / len1;
1515 DbgUI.EndCleanupScope();
1518 #ifdef DIAG_DEVELOPER
1521 const vector epsilon =
"0 0.0002 0";
1522 if (lastLiftPosition!=
vector.Zero)
1529 if (hit_fraction != 0)
1537 bool wantsLift = wasLift;
1540 const float inThreshold = 0.002;
1542 const float outThreshold = 0.003;
1543 const float noIsctOutThreshold = 0.01;
1547 float angleThreshold = 0.75 +
Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1550 if (hit_fraction != 0)
1552 vector v1 = hit_pos - weaponEnd;
1553 vector v2 = hit_pos - end;
1554 float d =
vector.Dot(v1, v2);
1557 if (!wasLift && d > inThreshold)
1561 else if (wasLift && d < -outThreshold)
1566 m_LastLiftPosition = hit_pos;
1571 if (lastLiftPosition ==
vector.Zero)
1574 m_LastLiftPosition =
vector.Zero;
1580 vector v3 = (lastLiftPosition - start).Normalized();
1581 vector v4 = (end-start).Normalized();
1582 float d2 =
vector.Dot(v3, v4);
1584 if (
Math.Acos(d2) > (angleThreshold *
Math.DEG2RAD))
1587 m_LastLiftPosition =
vector.Zero;
1592 float d3 =
vector.Dot( lastLiftPosition - weaponEnd, (start-end).Normalized() );
1593 if (d3 < -noIsctOutThreshold)
1596 m_LastLiftPosition =
vector.Zero;
1606 m_LiftWeapon =
true;
1615 return res.surface.IsSolid();
1619 float GetEffectiveAttachmentLength()
1622 if (HasBayonetAttached())
1624 int bayonetIndex = GetBayonetAttachmentIdx();
1625 attachment =
ItemBase.Cast(GetInventory().FindAttachment(bayonetIndex));
1629 attachment = GetAttachedSuppressor();
1634 return Math.Max(attachment.m_ItemModelLength + attachment.m_ItemAttachOffset, 0);
1642 void SetSyncJammingChance(
float jamming_chance )
1644 m_ChanceToJamSync = jamming_chance;
1657 bool EjectCartridge(
int muzzleIndex, out
float ammoDamage, out
string ammoTypeName)
1659 if (IsChamberEjectable(muzzleIndex))
1661 if (PopCartridgeFromChamber(muzzleIndex, ammoDamage, ammoTypeName))
1664 else if (GetInternalMagazineCartridgeCount(muzzleIndex) > 0)
1666 if (PopCartridgeFromInternalMagazine(muzzleIndex, ammoDamage, ammoTypeName))
1677 for (
int mi = 0; mi < src.GetMuzzleCount(); ++mi)
1679 if (!src.IsChamberEmpty(mi))
1681 if (src.GetCartridgeInfo(mi, damage, type))
1683 PushCartridgeToChamber(mi, damage, type);
1687 for (
int ci = 0; ci < src.GetInternalMagazineCartridgeCount(mi); ++ci)
1689 if (src.GetInternalMagazineCartridgeInfo(mi, ci, damage, type))
1691 PushCartridgeToInternalMagazine(mi, damage, type);
1696 int dummy_version =
int.MAX;
1701 src.OnStoreSave(ctx.GetWriteContext());
1707 override void SetBayonetAttached(
bool pState,
int slot_idx = -1)
1709 m_BayonetAttached = pState;
1710 m_BayonetAttachmentIdx = slot_idx;
1713 override bool HasBayonetAttached()
1715 return m_BayonetAttached;
1718 override int GetBayonetAttachmentIdx()
1720 return m_BayonetAttachmentIdx;
1723 override void SetButtstockAttached(
bool pState,
int slot_idx = -1)
1725 m_ButtstockAttached = pState;
1726 m_ButtstockAttachmentIdx = slot_idx;
1729 override bool HasButtstockAttached()
1731 return m_ButtstockAttached;
1734 override int GetButtstockAttachmentIdx()
1736 return m_ButtstockAttachmentIdx;
1739 void HideWeaponBarrel(
bool state)
1741 if ( !
GetGame().IsDedicatedServer() )
1744 if ( optics && !optics.AllowsDOF() && m_weaponHideBarrelIdx != -1 )
1746 SetSimpleHiddenSelectionState(m_weaponHideBarrelIdx,!state);
1753 if (m_magazineSimpleSelectionIndex > -1)
1754 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,1);
1756 SelectionMagazineShow();
1761 if (m_magazineSimpleSelectionIndex > -1)
1762 SetSimpleHiddenSelectionState(m_magazineSimpleSelectionIndex,0);
1764 SelectionMagazineHide();
1767 override EntityAI ProcessMeleeItemDamage(
int mode = 0)
1774 super.ProcessMeleeItemDamage();
1778 attachment = GetInventory().FindAttachment(m_ButtstockAttachmentIdx);
1782 attachment = GetInventory().FindAttachment(m_BayonetAttachmentIdx);
1786 super.ProcessMeleeItemDamage();
1792 attachment.ProcessMeleeItemDamage();
1799 bool IsShowingChamberedBullet()
1806 return m_BurstCount;
1809 void ResetBurstCount()
1814 override void SetActions()
1830 if (!ConfigGetBool(
"isSuicideWeapon"))
1833 return super.CanBeUsedForSuicide();
1837 override void OnDebugSpawn()
1839 SpawnAmmo(
"", SAMF_DEFAULT);