weaponmanager.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  1. class WeaponManager
  2. {
  3. const float MAX_DROP_MAGAZINE_DISTANCE_SQ = 4;
  4. protected PlayerBase m_player;
  5. protected int m_LastAcknowledgmentID;
  6. protected int m_PendingWeaponActionAcknowledgmentID;
  7. protected Magazine m_PendingTargetMagazine;
  8. protected ref InventoryLocation m_TargetInventoryLocation;
  9. protected int m_PendingWeaponAction;
  10. protected ref InventoryLocation m_PendingInventoryLocation;
  11. protected bool m_canEnd;
  12. protected bool m_justStart;
  13. protected bool m_InProgress;
  14. protected bool m_IsEventSended;
  15. protected bool m_WantContinue;
  16. protected bool m_InIronSight;
  17. protected bool m_InOptic;
  18. protected bool m_readyToStart;
  19. protected Weapon_Base m_WeaponInHand;
  20. protected MagazineStorage m_MagazineInHand;
  21. protected ActionBase m_ControlAction;
  22. protected int m_ForceEjectBulletTimestamp;
  23. protected const int FORCE_EJECT_BULLET_TIMEOUT = 2000;
  24. #ifdef DIAG_DEVELOPER
  25. protected int m_BurstOption;
  26. #endif
  27. //Reload
  28. protected ref array<Magazine> m_MagazinePilesInInventory;
  29. protected ref array<MagazineStorage> m_MagazineStorageInInventory;
  30. protected ref array<Magazine> m_SuitableMagazines;
  31. protected Magazine m_PreparedMagazine;
  32. //Jamming
  33. protected float m_NewJamChance;
  34. protected bool m_WaitToSyncJamChance;
  35. protected int m_AnimationRefreshCooldown;
  36. void WeaponManager(PlayerBase player)
  37. {
  38. m_ForceEjectBulletTimestamp = -1;
  39. m_player = player;
  40. m_PendingWeaponActionAcknowledgmentID = -1;
  41. m_PendingTargetMagazine = NULL;
  42. m_PendingInventoryLocation = NULL;
  43. m_WeaponInHand = NULL;
  44. m_MagazineInHand = NULL;
  45. m_ControlAction = NULL;
  46. m_PendingWeaponAction = -1;
  47. m_LastAcknowledgmentID = 1;
  48. m_InProgress = false;
  49. m_WantContinue = true;
  50. m_IsEventSended = false;
  51. m_canEnd = false;
  52. m_readyToStart = false;
  53. m_AnimationRefreshCooldown = 0;
  54. m_NewJamChance = -1;
  55. m_WaitToSyncJamChance = false;
  56. m_MagazinePilesInInventory = new array<Magazine>;
  57. m_MagazineStorageInInventory = new array<MagazineStorage>;
  58. m_SuitableMagazines = new array<Magazine>;
  59. m_PreparedMagazine = null;
  60. #ifdef DEVELOPER
  61. m_BurstOption = 0;
  62. #endif
  63. }
  64. //----------------------------------------------------------------------------
  65. // Weapon Action conditions
  66. //----------------------------------------------------------------------------
  67. bool CanFire(Weapon_Base wpn)
  68. {
  69. if( m_player.GetHumanInventory().GetEntityInHands() != wpn )
  70. return false;
  71. if( m_player.IsLiftWeapon() || !m_player.IsRaised() || wpn.IsDamageDestroyed() || m_player.GetDayZPlayerInventory().IsProcessing() || !m_player.IsWeaponRaiseCompleted() || m_player.IsFighting() )
  72. return false;
  73. return !wpn.IsCoolDown();
  74. }
  75. bool CanAttachMagazine(Weapon_Base wpn, Magazine mag, bool reservationCheck = true )
  76. {
  77. if ( !wpn || !mag )
  78. return false;
  79. if ( m_player.GetHumanInventory().GetEntityInHands() != wpn )
  80. return false;
  81. if ( wpn.IsDamageDestroyed())
  82. return false;
  83. //if ( mag.GetHierarchyRootPlayer() && mag.GetHierarchyRootPlayer() != m_player )
  84. //return false;
  85. if( m_player.IsItemsToDelete())
  86. return false;
  87. if ( reservationCheck && (m_player.GetInventory().HasInventoryReservation(wpn, null) || m_player.GetInventory().HasInventoryReservation(mag, null)))
  88. return false;
  89. InventoryLocation invLoc;
  90. invLoc = new InventoryLocation();
  91. mag.GetInventory().GetCurrentInventoryLocation(invLoc);
  92. Weapon_Base wnp2;
  93. //magazine is already in weapon
  94. if ( Class.CastTo(wnp2, invLoc.GetParent()) )
  95. return false;
  96. int muzzleIndex = wpn.GetCurrentMuzzle();
  97. if (wpn.CanAttachMagazine(muzzleIndex, mag))
  98. return true;
  99. return false;
  100. }
  101. //---------------------------------------------------------------------------
  102. bool CanSwapMagazine(Weapon_Base wpn, Magazine mag, bool reservationCheck = true)
  103. {
  104. if ( !wpn || !mag )
  105. return false;
  106. if ( m_player.GetHumanInventory().GetEntityInHands() != wpn )
  107. return false;
  108. if ( mag.IsDamageDestroyed() || wpn.IsDamageDestroyed())
  109. return false;
  110. //if ( mag.GetHierarchyRootPlayer() && mag.GetHierarchyRootPlayer() != m_player )
  111. //return false;
  112. if( m_player.IsItemsToDelete())
  113. return false;
  114. if ( reservationCheck && (m_player.GetInventory().HasInventoryReservation(wpn, null) || m_player.GetInventory().HasInventoryReservation(mag, null)))
  115. return false;
  116. InventoryLocation invLoc;
  117. invLoc = new InventoryLocation();
  118. mag.GetInventory().GetCurrentInventoryLocation(invLoc);
  119. Weapon_Base wnp2;
  120. //second magazine is already in weapon
  121. if( Class.CastTo(wnp2, invLoc.GetParent()) )
  122. return false;
  123. int muzzleIndex = wpn.GetCurrentMuzzle();
  124. Magazine mag2;
  125. if( !Class.CastTo(mag2, wpn.GetMagazine(muzzleIndex)) )
  126. return false;
  127. if( GameInventory.CanSwapEntitiesEx( mag, mag2 ) )
  128. return true;
  129. InventoryLocation il = new InventoryLocation();
  130. if( GameInventory.CanForceSwapEntitiesEx( mag, null, mag2, il ) )
  131. return true;
  132. return false;
  133. }
  134. //----------------------------------------------------------------------------
  135. bool CanDetachMagazine(Weapon_Base wpn, Magazine mag, bool reservationCheck = true)
  136. {
  137. if ( !wpn || !mag )
  138. return false;
  139. if ( m_player.GetHumanInventory().GetEntityInHands() != wpn )
  140. return false;
  141. if ( mag.GetHierarchyParent() != wpn )
  142. return false;
  143. if( m_player.IsItemsToDelete())
  144. return false;
  145. if ( reservationCheck && (m_player.GetInventory().HasInventoryReservation(wpn, null) || m_player.GetInventory().HasInventoryReservation(mag, null)))
  146. return false;
  147. return true;
  148. }
  149. //---------------------------------------------------------------------------
  150. bool CanLoadBullet(Weapon_Base wpn, Magazine mag, bool reservationCheck = true)
  151. {
  152. if (!wpn || !mag)
  153. return false;
  154. if (m_player.GetHumanInventory().GetEntityInHands() != wpn)
  155. return false;
  156. if (mag.IsDamageDestroyed() || wpn.IsDamageDestroyed())
  157. return false;
  158. if (wpn.IsJammed())
  159. return false;
  160. if (m_player.IsItemsToDelete())
  161. return false;
  162. if (reservationCheck && (m_player.GetInventory().HasInventoryReservation(wpn, null) || m_player.GetInventory().HasInventoryReservation(mag, null)))
  163. return false;
  164. for (int i = 0; i < wpn.GetMuzzleCount(); i++)
  165. {
  166. if (wpn.CanChamberBullet(i, mag))
  167. return true;
  168. }
  169. return false;
  170. }
  171. //---------------------------------------------------------------------------
  172. bool CanUnjam(Weapon_Base wpn, bool reservationCheck = true)
  173. {
  174. if( !wpn )
  175. return false;
  176. if( m_player.GetHumanInventory().GetEntityInHands() != wpn)
  177. return false;
  178. if( wpn.IsDamageDestroyed())
  179. return false;
  180. if( m_player.IsItemsToDelete())
  181. return false;
  182. if ( reservationCheck && m_player.GetInventory().HasInventoryReservation(wpn, null))
  183. return false;
  184. if( !wpn.IsJammed(/*wpn.GetCurrentMuzzle()*/) )
  185. return false;
  186. return true;
  187. }
  188. bool CanEjectBullet(Weapon_Base wpn, bool reservationCheck = true)
  189. {
  190. if( !wpn )
  191. return false;
  192. if( m_player.GetHumanInventory().GetEntityInHands() != wpn)
  193. return false;
  194. if( m_player.IsItemsToDelete())
  195. return false;
  196. if( reservationCheck && m_player.GetInventory().HasInventoryReservation(wpn, null))
  197. return false;
  198. if( !wpn.CanEjectBullet() )
  199. return false;
  200. if( wpn.IsJammed(/*wpn.GetCurrentMuzzle()*/) )
  201. return false;
  202. return true;
  203. }
  204. void SetEjectBulletTryTimestamp()
  205. {
  206. m_ForceEjectBulletTimestamp = GetGame().GetTime();
  207. }
  208. //----------------------------------------------------------------------------
  209. bool InventoryReservation( Magazine mag, InventoryLocation invLoc)
  210. {
  211. Weapon_Base weapon;
  212. InventoryLocation ilWeapon = new InventoryLocation();
  213. if (Weapon_Base.CastTo(weapon, m_player.GetItemInHands()) )
  214. {
  215. weapon.GetInventory().GetCurrentInventoryLocation(ilWeapon);
  216. if ( m_player.GetInventory().HasInventoryReservation(weapon, ilWeapon) )
  217. {
  218. return false;
  219. }
  220. else
  221. {
  222. m_player.GetInventory().AddInventoryReservationEx(weapon,ilWeapon,GameInventory.c_InventoryReservationTimeoutMS);
  223. }
  224. }
  225. if( invLoc )
  226. {
  227. if ( m_player.GetInventory().HasInventoryReservation(invLoc.GetItem(),invLoc) )
  228. {
  229. m_player.GetInventory().ClearInventoryReservationEx(weapon, ilWeapon);
  230. return false;
  231. }
  232. else
  233. {
  234. m_player.GetInventory().AddInventoryReservationEx(invLoc.GetItem(),invLoc,GameInventory.c_InventoryReservationTimeoutMS);
  235. }
  236. }
  237. if( mag )
  238. {
  239. m_TargetInventoryLocation = new InventoryLocation();
  240. m_TargetInventoryLocation.SetAttachment( m_WeaponInHand, mag, InventorySlots.MAGAZINE);
  241. if ( m_player.GetInventory().HasInventoryReservation(mag, m_TargetInventoryLocation) )
  242. //if ( !m_player.GetInventory().AddInventoryReservationEx( mag, m_TargetInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS) )
  243. {
  244. m_player.GetInventory().ClearInventoryReservationEx(weapon, ilWeapon);
  245. if (invLoc)
  246. {
  247. m_player.GetInventory().ClearInventoryReservationEx(invLoc.GetItem(), invLoc);
  248. }
  249. return false;
  250. }
  251. else
  252. {
  253. m_player.GetInventory().AddInventoryReservationEx(mag, m_TargetInventoryLocation, GameInventory.c_InventoryReservationTimeoutMS);
  254. }
  255. }
  256. m_PendingTargetMagazine = mag;
  257. m_PendingInventoryLocation = invLoc;
  258. return true;
  259. }
  260. //----------------------------------------------------------------------------
  261. // Weapon Actions
  262. //----------------------------------------------------------------------------
  263. bool AttachMagazine( Magazine mag , ActionBase control_action = NULL )
  264. {
  265. return StartAction(AT_WPN_ATTACH_MAGAZINE, mag, NULL, control_action);
  266. }
  267. bool DetachMagazine( InventoryLocation invLoc, ActionBase control_action = NULL)
  268. {
  269. return StartAction(AT_WPN_DETACH_MAGAZINE, NULL, invLoc, control_action);
  270. }
  271. bool SwapMagazine( Magazine mag, ActionBase control_action = NULL )
  272. {
  273. InventoryLocation il = new InventoryLocation();
  274. if (PrepareInventoryLocationForMagazineSwap(m_WeaponInHand, mag, il) )
  275. {
  276. return StartAction(AT_WPN_SWAP_MAGAZINE, mag, il, control_action);
  277. }
  278. return false;
  279. }
  280. bool SwapMagazineEx( Magazine mag, InventoryLocation invLoc, ActionBase control_action = NULL )
  281. {
  282. return StartAction(AT_WPN_SWAP_MAGAZINE, mag, invLoc, control_action);
  283. }
  284. bool LoadBullet( Magazine mag, ActionBase control_action = NULL )
  285. {
  286. return StartAction(AT_WPN_LOAD_BULLET, mag, NULL, control_action);
  287. }
  288. bool LoadMultiBullet( Magazine mag, ActionBase control_action = NULL )
  289. {
  290. return StartAction(AT_WPN_LOAD_MULTI_BULLETS_START, mag, NULL, control_action);
  291. }
  292. void LoadMultiBulletStop( )
  293. {
  294. if(m_InProgress) m_WantContinue = false;
  295. }
  296. bool Unjam( ActionBase control_action = NULL )
  297. {
  298. return StartAction(AT_WPN_UNJAM, NULL, NULL, control_action);
  299. }
  300. bool EjectBullet( ActionBase control_action = NULL )
  301. {
  302. return StartAction(AT_WPN_EJECT_BULLET, NULL, NULL, control_action);
  303. }
  304. bool CanEjectBulletVerified()
  305. {
  306. int mi = m_WeaponInHand.GetCurrentMuzzle();
  307. if( !m_WeaponInHand.IsChamberFiredOut(mi) && !m_WeaponInHand.IsChamberEmpty(mi) )
  308. {
  309. int actual_time = GetGame().GetTime();
  310. if ( actual_time - m_ForceEjectBulletTimestamp > FORCE_EJECT_BULLET_TIMEOUT )
  311. {
  312. return false;
  313. }
  314. }
  315. return true;
  316. }
  317. bool EjectBulletVerified( ActionBase control_action = NULL )
  318. {
  319. if ( m_WeaponInHand )
  320. {
  321. int mi = m_WeaponInHand.GetCurrentMuzzle();
  322. if ( !m_WeaponInHand.IsChamberFiredOut(mi) && !m_WeaponInHand.IsChamberEmpty(mi) )
  323. {
  324. m_ForceEjectBulletTimestamp = GetGame().GetTime();
  325. return StartAction(AT_WPN_EJECT_BULLET, NULL, NULL, control_action);
  326. }
  327. else
  328. {
  329. return StartAction(AT_WPN_EJECT_BULLET, NULL, NULL, control_action);
  330. }
  331. }
  332. return false;
  333. }
  334. bool SetNextMuzzleMode ()
  335. {
  336. return StartAction(AT_WPN_SET_NEXT_MUZZLE_MODE, NULL, NULL, NULL);
  337. }
  338. void Fire(Weapon_Base wpn)
  339. {
  340. int mi = wpn.GetCurrentMuzzle();
  341. if ( wpn.IsChamberFiredOut(mi) || wpn.IsJammed() || wpn.IsChamberEmpty(mi) )
  342. {
  343. wpn.ProcessWeaponEvent(new WeaponEventTrigger(m_player));
  344. return;
  345. }
  346. if (wpn.JamCheck(0))
  347. {
  348. wpn.ProcessWeaponEvent(new WeaponEventTriggerToJam(m_player));
  349. }
  350. else
  351. {
  352. wpn.ProcessWeaponEvent(new WeaponEventTrigger(m_player));
  353. }
  354. }
  355. #ifdef DIAG_DEVELOPER
  356. int GetBurstOption()
  357. {
  358. return m_BurstOption;
  359. }
  360. void SetBurstOption(int value)
  361. {
  362. m_BurstOption = value;
  363. }
  364. #endif
  365. //-------------------------------------------------------------------------------------
  366. // Synchronize - initialize from client side
  367. //-------------------------------------------------------------------------------------
  368. //Client
  369. private void Synchronize( )
  370. {
  371. if ( GetGame().IsClient() )
  372. {
  373. m_PendingWeaponActionAcknowledgmentID = ++m_LastAcknowledgmentID;
  374. ScriptInputUserData ctx = new ScriptInputUserData;
  375. ctx.Write(INPUT_UDT_WEAPON_ACTION);
  376. ctx.Write(m_PendingWeaponAction);
  377. ctx.Write(m_PendingWeaponActionAcknowledgmentID);
  378. switch (m_PendingWeaponAction)
  379. {
  380. case AT_WPN_ATTACH_MAGAZINE:
  381. {
  382. ctx.Write(m_PendingTargetMagazine);
  383. break;
  384. }
  385. case AT_WPN_SWAP_MAGAZINE:
  386. {
  387. ctx.Write(m_PendingTargetMagazine);
  388. m_PendingInventoryLocation.WriteToContext(ctx);
  389. break;
  390. }
  391. case AT_WPN_DETACH_MAGAZINE:
  392. {
  393. m_PendingInventoryLocation.WriteToContext(ctx);
  394. break;
  395. }
  396. case AT_WPN_LOAD_BULLET:
  397. {
  398. ctx.Write(m_PendingTargetMagazine);
  399. break;
  400. }
  401. case AT_WPN_LOAD_MULTI_BULLETS_START:
  402. {
  403. ctx.Write(m_PendingTargetMagazine);
  404. break;
  405. }
  406. case AT_WPN_UNJAM:
  407. {
  408. break;
  409. }
  410. case AT_WPN_EJECT_BULLET:
  411. {
  412. break;
  413. }
  414. default:
  415. break;
  416. }
  417. ctx.Send();
  418. //if( !m_player.GetDayZPlayerInventory().HasLockedHands() )
  419. // m_player.GetDayZPlayerInventory().LockHands();
  420. }
  421. }
  422. void OnSyncJuncture(int pJunctureID, ParamsReadContext pCtx)
  423. {
  424. if (pJunctureID == DayZPlayerSyncJunctures.SJ_WEAPON_SET_JAMMING_CHANCE )
  425. {
  426. pCtx.Read(m_NewJamChance);
  427. }
  428. else
  429. {
  430. int AcknowledgmentID;
  431. pCtx.Read(AcknowledgmentID);
  432. if ( AcknowledgmentID == m_PendingWeaponActionAcknowledgmentID)
  433. {
  434. if (pJunctureID == DayZPlayerSyncJunctures.SJ_WEAPON_ACTION_ACK_ACCEPT)
  435. {
  436. m_readyToStart = true;
  437. }
  438. else if (pJunctureID == DayZPlayerSyncJunctures.SJ_WEAPON_ACTION_ACK_REJECT)
  439. {
  440. if(m_PendingWeaponAction >= 0 )
  441. {
  442. if(!(GetGame().IsServer() && GetGame().IsMultiplayer()))
  443. {
  444. InventoryLocation ilWeapon = new InventoryLocation();
  445. ItemBase weapon = m_player.GetItemInHands();
  446. weapon.GetInventory().GetCurrentInventoryLocation(ilWeapon);
  447. m_player.GetInventory().ClearInventoryReservationEx(m_player.GetItemInHands(),ilWeapon);
  448. if( m_PendingTargetMagazine )
  449. {
  450. m_PendingTargetMagazine.GetInventory().ClearInventoryReservationEx(m_PendingTargetMagazine, m_TargetInventoryLocation );
  451. }
  452. if( m_PendingInventoryLocation )
  453. {
  454. m_player.GetInventory().ClearInventoryReservationEx( NULL, m_PendingInventoryLocation );
  455. }
  456. }
  457. m_PendingWeaponActionAcknowledgmentID = -1;
  458. m_PendingTargetMagazine = NULL;
  459. m_PendingWeaponAction = -1;
  460. m_PendingInventoryLocation = NULL;
  461. m_InProgress = false;
  462. }
  463. }
  464. }
  465. }
  466. }
  467. //Server
  468. bool OnInputUserDataProcess(int userDataType, ParamsReadContext ctx)
  469. {
  470. Weapon_Base wpn;
  471. int mi;
  472. InventoryLocation il;
  473. int slotID;
  474. bool accepted = false;
  475. if( userDataType == INPUT_UDT_WEAPON_ACTION)
  476. {
  477. if (!ctx.Read(m_PendingWeaponAction))
  478. return false;
  479. if (!ctx.Read(m_PendingWeaponActionAcknowledgmentID))
  480. return false;
  481. if(m_PendingTargetMagazine)
  482. {
  483. GetGame().ClearJuncture(m_player, m_PendingTargetMagazine);
  484. m_PendingTargetMagazine = NULL;
  485. }
  486. m_InProgress = true;
  487. m_IsEventSended = false;
  488. Magazine mag = NULL;
  489. Weapon_Base.CastTo( wpn, m_player.GetItemInHands() );
  490. if ( wpn )
  491. mi = wpn.GetCurrentMuzzle();
  492. switch (m_PendingWeaponAction)
  493. {
  494. case AT_WPN_ATTACH_MAGAZINE:
  495. {
  496. if ( !ctx.Read(mag) )
  497. break;
  498. if ( !mag || !wpn )
  499. break;
  500. slotID = wpn.GetSlotFromMuzzleIndex(mi);
  501. il = new InventoryLocation();
  502. il.SetAttachment(wpn,mag,slotID);
  503. if( GetGame().AddInventoryJunctureEx(m_player, mag, il, false, 10000) )
  504. accepted = true;
  505. m_PendingTargetMagazine = mag;
  506. break;
  507. }
  508. case AT_WPN_SWAP_MAGAZINE:
  509. {
  510. if ( !ctx.Read(mag) )
  511. break;
  512. il = new InventoryLocation();
  513. if (!il.ReadFromContext(ctx))
  514. break;
  515. if ( !mag || !wpn )
  516. break;
  517. if ( !wpn.GetMagazine(mi) )
  518. break;
  519. if ( GetGame().AddActionJuncture(m_player,mag,10000) )
  520. accepted = true;
  521. m_PendingInventoryLocation = il;
  522. m_PendingTargetMagazine = mag;
  523. break;
  524. }
  525. case AT_WPN_DETACH_MAGAZINE:
  526. {
  527. il = new InventoryLocation();
  528. if ( !il.ReadFromContext(ctx) )
  529. break;
  530. if ( !il.IsValid() )
  531. break;
  532. if ( !wpn )
  533. break;
  534. Magazine det_mag = wpn.GetMagazine(mi);
  535. mag = Magazine.Cast(il.GetItem());
  536. if ( !det_mag || ( mag != det_mag) )
  537. break;
  538. if (GetGame().AddInventoryJunctureEx(m_player, il.GetItem(), il, true, 10000))
  539. accepted = true;
  540. m_PendingInventoryLocation = il;
  541. m_PendingTargetMagazine = mag;
  542. break;
  543. }
  544. case AT_WPN_LOAD_BULLET:
  545. {
  546. ctx.Read(mag);
  547. if ( !mag )
  548. break;
  549. if( GetGame().AddActionJuncture(m_player,mag,10000) )
  550. accepted = true;
  551. m_PendingTargetMagazine = mag;
  552. break;
  553. }
  554. case AT_WPN_LOAD_MULTI_BULLETS_START:
  555. {
  556. ctx.Read(mag);
  557. if ( !mag )
  558. break;
  559. if( GetGame().AddActionJuncture(m_player,mag,10000) )
  560. accepted = true;
  561. m_PendingTargetMagazine = mag;
  562. break;
  563. }
  564. case AT_WPN_UNJAM:
  565. {
  566. accepted = true;
  567. //Unjam();
  568. break;
  569. }
  570. case AT_WPN_EJECT_BULLET:
  571. {
  572. accepted = true;
  573. break;
  574. }
  575. case AT_WPN_SET_NEXT_MUZZLE_MODE:
  576. {
  577. accepted = true;
  578. break;
  579. }
  580. default:
  581. Error("unknown actionID=" + m_PendingWeaponAction);
  582. break;
  583. }
  584. DayZPlayerSyncJunctures.SendWeaponActionAcknowledgment(m_player, m_PendingWeaponActionAcknowledgmentID, accepted);
  585. }
  586. return accepted;
  587. }
  588. bool StartAction(int action, Magazine mag, InventoryLocation il, ActionBase control_action = NULL)
  589. {
  590. //if it is controled by action inventory reservation and synchronization provide action itself
  591. if(control_action)
  592. {
  593. m_ControlAction = ActionBase.Cast(control_action);
  594. m_PendingWeaponAction = action;
  595. m_InProgress = true;
  596. m_IsEventSended = false;
  597. m_PendingTargetMagazine = mag;
  598. m_PendingInventoryLocation = il;
  599. StartPendingAction();
  600. return true;
  601. }
  602. if (GetGame().IsMultiplayer() && GetGame().IsServer())
  603. return false;
  604. if ( !ScriptInputUserData.CanStoreInputUserData() )
  605. return false;
  606. if ( !InventoryReservation(mag, il) )
  607. return false;
  608. m_PendingWeaponAction = action;
  609. m_InProgress = true;
  610. m_IsEventSended = false;
  611. if ( !GetGame().IsMultiplayer() )
  612. m_readyToStart = true;
  613. else
  614. Synchronize();
  615. return true;
  616. }
  617. void StartPendingAction()
  618. {
  619. m_WeaponInHand = Weapon_Base.Cast(m_player.GetItemInHands());
  620. if(!m_WeaponInHand)
  621. {
  622. OnWeaponActionEnd();
  623. return;
  624. }
  625. switch (m_PendingWeaponAction)
  626. {
  627. case AT_WPN_ATTACH_MAGAZINE:
  628. {
  629. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventAttachMagazine(m_player, m_PendingTargetMagazine) );
  630. break;
  631. }
  632. case AT_WPN_SWAP_MAGAZINE:
  633. {
  634. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventSwapMagazine(m_player, m_PendingTargetMagazine, m_PendingInventoryLocation) );
  635. break;
  636. }
  637. case AT_WPN_DETACH_MAGAZINE:
  638. {
  639. Magazine mag = Magazine.Cast(m_PendingInventoryLocation.GetItem());
  640. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventDetachMagazine(m_player, mag, m_PendingInventoryLocation) );
  641. break;
  642. }
  643. case AT_WPN_LOAD_BULLET:
  644. {
  645. m_WantContinue = false;
  646. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventLoad1Bullet(m_player, m_PendingTargetMagazine) );
  647. break;
  648. }
  649. case AT_WPN_LOAD_MULTI_BULLETS_START:
  650. {
  651. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventLoad1Bullet(m_player, m_PendingTargetMagazine) );
  652. break;
  653. }
  654. case AT_WPN_LOAD_MULTI_BULLETS_END:
  655. {
  656. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventContinuousLoadBulletEnd(m_player) );
  657. break;
  658. }
  659. case AT_WPN_UNJAM:
  660. {
  661. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventUnjam(m_player, NULL) );
  662. break;
  663. }
  664. case AT_WPN_EJECT_BULLET:
  665. {
  666. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventMechanism(m_player, NULL) );
  667. break;
  668. }
  669. case AT_WPN_SET_NEXT_MUZZLE_MODE:
  670. {
  671. m_player.GetDayZPlayerInventory().PostWeaponEvent( new WeaponEventSetNextMuzzleMode(m_player, NULL) );
  672. break;
  673. }
  674. default:
  675. m_InProgress = false;
  676. Error("unknown actionID=" + m_PendingWeaponAction);
  677. }
  678. m_IsEventSended = true;
  679. m_canEnd = false;
  680. }
  681. bool IsRunning()
  682. {
  683. return m_InProgress;
  684. }
  685. void SetRunning( bool value)
  686. {
  687. m_InProgress = value;
  688. }
  689. void Refresh()
  690. {
  691. OnWeaponActionEnd();
  692. }
  693. void Update( float deltaT )
  694. {
  695. if (m_WeaponInHand != m_player.GetItemInHands())
  696. {
  697. if( m_WeaponInHand )
  698. {
  699. m_SuitableMagazines.Clear();
  700. OnWeaponActionEnd();
  701. }
  702. m_WeaponInHand = Weapon_Base.Cast(m_player.GetItemInHands());
  703. if ( m_WeaponInHand )
  704. {
  705. m_MagazineInHand = null;
  706. //SET new magazine
  707. SetSutableMagazines();
  708. m_WeaponInHand.SetSyncJammingChance(0);
  709. }
  710. m_AnimationRefreshCooldown = 0;
  711. }
  712. if (m_WeaponInHand)
  713. {
  714. if(m_AnimationRefreshCooldown)
  715. {
  716. m_AnimationRefreshCooldown--;
  717. if( m_AnimationRefreshCooldown == 0)
  718. {
  719. RefreshAnimationState();
  720. }
  721. }
  722. if (!GetGame().IsMultiplayer())
  723. {
  724. m_WeaponInHand.SetSyncJammingChance(m_WeaponInHand.GetChanceToJam());
  725. }
  726. else
  727. {
  728. if ( m_NewJamChance >= 0)
  729. {
  730. m_WeaponInHand.SetSyncJammingChance(m_NewJamChance);
  731. m_NewJamChance = -1;
  732. m_WaitToSyncJamChance = false;
  733. }
  734. if (GetGame().IsServer() && !m_WaitToSyncJamChance )
  735. {
  736. float actual_chance_to_jam;
  737. actual_chance_to_jam = m_WeaponInHand.GetChanceToJam();
  738. if ( Math.AbsFloat(m_WeaponInHand.GetSyncChanceToJam() - m_WeaponInHand.GetChanceToJam()) > 0.001 )
  739. {
  740. DayZPlayerSyncJunctures.SendWeaponJamChance(m_player, m_WeaponInHand.GetChanceToJam());
  741. m_WaitToSyncJamChance = true;
  742. }
  743. }
  744. }
  745. if(m_readyToStart)
  746. {
  747. StartPendingAction();
  748. m_readyToStart = false;
  749. return;
  750. }
  751. if( !m_InProgress || !m_IsEventSended )
  752. return;
  753. if(m_canEnd)
  754. {
  755. if(m_WeaponInHand.IsIdle())
  756. {
  757. OnWeaponActionEnd();
  758. }
  759. else if(m_justStart)
  760. {
  761. m_InIronSight = m_player.IsInIronsights();
  762. m_InOptic = m_player.IsInOptics();
  763. if(m_InIronSight || m_InOptic)
  764. {
  765. //'RequestResetADSSync' can be called here, if ADS reset is desired
  766. m_player.ExitSights();
  767. }
  768. m_justStart = false;
  769. }
  770. }
  771. else
  772. {
  773. m_canEnd = true;
  774. m_justStart = true;
  775. }
  776. }
  777. else
  778. {
  779. if ( m_MagazineInHand != m_player.GetItemInHands() )
  780. {
  781. m_MagazineInHand = MagazineStorage.Cast(m_player.GetItemInHands());
  782. if ( m_MagazineInHand )
  783. {
  784. SetSutableMagazines();
  785. }
  786. }
  787. }
  788. }
  789. void OnWeaponActionEnd()
  790. {
  791. if ( !m_InProgress )
  792. return;
  793. if (!m_ControlAction)
  794. {
  795. if (GetGame().IsServer() && GetGame().IsMultiplayer())
  796. {
  797. if(m_PendingTargetMagazine)
  798. {
  799. GetGame().ClearJuncture(m_player,m_PendingTargetMagazine);
  800. }
  801. }
  802. else
  803. {
  804. InventoryLocation il = new InventoryLocation();
  805. il.SetHands(m_player,m_player.GetItemInHands());
  806. m_player.GetInventory().ClearInventoryReservationEx(m_player.GetItemInHands(),il);
  807. if( m_PendingTargetMagazine )
  808. {
  809. m_player.GetInventory().ClearInventoryReservationEx(m_PendingTargetMagazine, m_TargetInventoryLocation );
  810. }
  811. if( m_PendingInventoryLocation )
  812. {
  813. m_player.GetInventory().ClearInventoryReservationEx( m_PendingInventoryLocation.GetItem(), m_PendingInventoryLocation );
  814. }
  815. }
  816. }
  817. m_ControlAction = NULL;
  818. m_PendingWeaponAction = -1;
  819. m_PendingTargetMagazine = NULL;
  820. m_PendingInventoryLocation = NULL;
  821. m_TargetInventoryLocation = NULL;
  822. m_PendingWeaponActionAcknowledgmentID = -1;
  823. //m_WeaponInHand = NULL;
  824. m_InProgress = false;
  825. m_readyToStart = false;
  826. m_WantContinue = true;
  827. }
  828. void DelayedRefreshAnimationState(int delay)
  829. {
  830. if(m_WeaponInHand)
  831. {
  832. if(delay == 0)
  833. {
  834. RefreshAnimationState();
  835. }
  836. m_AnimationRefreshCooldown = delay;
  837. }
  838. }
  839. void RefreshAnimationState()
  840. {
  841. if(m_WeaponInHand)
  842. {
  843. WeaponStableState state = WeaponStableState.Cast( m_WeaponInHand.GetCurrentState() );
  844. if (state)
  845. {
  846. HumanCommandWeapons hcw = m_player.GetCommandModifier_Weapons();
  847. if (hcw)
  848. {
  849. hcw.SetInitState(state.m_animState);
  850. }
  851. }
  852. }
  853. }
  854. bool WantContinue()
  855. {
  856. return m_WantContinue;
  857. }
  858. Magazine GetPreparedMagazine()
  859. {
  860. Magazine mag;
  861. for (int i = 0; i < m_SuitableMagazines.Count(); i++)
  862. {
  863. mag = m_SuitableMagazines[i];
  864. if (!mag || mag.IsRuined() || (mag.GetHierarchyParent() && mag.GetHierarchyParent().IsWeapon()) )
  865. {
  866. m_SuitableMagazines.Remove(i);
  867. i--;
  868. continue;
  869. }
  870. if(!mag.GetHierarchyParent() || mag.GetHierarchyParent().GetInventory().AreChildrenAccessible())
  871. {
  872. if (mag.GetAmmoCount() > 0)
  873. return mag;
  874. }
  875. }
  876. return null;
  877. }
  878. Magazine GetNextPreparedMagazine( out int startIdx )
  879. {
  880. int count = m_SuitableMagazines.Count();
  881. Magazine mag;
  882. for (int i = startIdx; i < count; i++)
  883. {
  884. mag = m_SuitableMagazines[i];
  885. if (mag && mag.GetAmmoCount() > 0 && (!mag.GetHierarchyParent() || mag.GetHierarchyParent().GetInventory().AreChildrenAccessible()))
  886. {
  887. startIdx = i;
  888. return m_SuitableMagazines.Get(i);
  889. }
  890. }
  891. return null;
  892. }
  893. void OnMagazineInventoryEnter(Magazine mag)
  894. {
  895. if (mag)
  896. {
  897. Weapon_Base weapon = Weapon_Base.Cast(mag.GetHierarchyParent());
  898. if (weapon)
  899. return;
  900. }
  901. int i;
  902. MagazineStorage sMag = MagazineStorage.Cast(mag);
  903. if(sMag)
  904. {
  905. for(i = 0; i < m_MagazineStorageInInventory.Count(); i++ )
  906. {
  907. MagazineStorage s_mag_i = m_MagazineStorageInInventory[i];
  908. if(!s_mag_i)
  909. {
  910. m_MagazineStorageInInventory.RemoveOrdered(i);
  911. i--;
  912. continue;
  913. }
  914. if(CompareMagazinesSuitability(s_mag_i,sMag)<0)
  915. break;
  916. }
  917. m_MagazineStorageInInventory.InsertAt(sMag,i);
  918. SetSutableMagazines(); //TODO optimalize
  919. return;
  920. }
  921. if(mag)
  922. {
  923. for(i = 0; i < m_MagazinePilesInInventory.Count(); i++ )
  924. {
  925. Magazine mag_i = m_MagazinePilesInInventory[i];
  926. if(!mag_i)
  927. {
  928. m_MagazinePilesInInventory.RemoveOrdered(i);
  929. i--;
  930. continue;
  931. }
  932. if(CompareMagazinesSuitability(mag_i,mag)<0)
  933. {
  934. break;
  935. }
  936. }
  937. m_MagazinePilesInInventory.InsertAt(mag,i);
  938. SetSutableMagazines(); //TODO optimalize
  939. }
  940. }
  941. void OnMagazineInventoryExit(Magazine mag)
  942. {
  943. m_SuitableMagazines.RemoveItem(mag);
  944. MagazineStorage sMag = MagazineStorage.Cast(mag);
  945. if(sMag)
  946. {
  947. m_MagazineStorageInInventory.RemoveItem(sMag);
  948. return;
  949. }
  950. if(mag)
  951. {
  952. m_MagazinePilesInInventory.RemoveItem(mag);
  953. }
  954. }
  955. void OnMagazineAttach(Magazine mag)
  956. {
  957. OnMagazineInventoryExit(mag);
  958. }
  959. void OnMagazineDetach(Magazine mag)
  960. {
  961. OnMagazineInventoryEnter(mag);
  962. }
  963. int CompareMagazinesSuitability( Magazine mag1, Magazine mag2 )
  964. {
  965. return mag1.GetAmmoCount() - mag2.GetAmmoCount();
  966. }
  967. void SortMagazineAfterLoad()
  968. {
  969. array<MagazineStorage> magazines = new array<MagazineStorage>;
  970. array<Magazine> magazines_piles = new array<Magazine>;
  971. int low_mag1, high_mag1;
  972. int low_mag2, high_mag2;
  973. int i, j;
  974. for(i = 0; i < m_MagazineStorageInInventory.Count(); i++ )
  975. {
  976. MagazineStorage mag = m_MagazineStorageInInventory.Get(i);
  977. mag.GetNetworkID(low_mag1,high_mag1);
  978. for( j = 0; j < magazines.Count(); j++)
  979. {
  980. magazines.Get(j).GetNetworkID(low_mag2,high_mag2);
  981. if(low_mag1 > low_mag2)
  982. {
  983. break;
  984. }
  985. else if (low_mag1 == low_mag2)
  986. {
  987. if( high_mag1 > high_mag2 )
  988. {
  989. break;
  990. }
  991. }
  992. }
  993. magazines.InsertAt(mag,j);
  994. }
  995. m_MagazineStorageInInventory.Clear();
  996. m_MagazineStorageInInventory.Copy(magazines);
  997. for(i = 0; i < m_MagazinePilesInInventory.Count(); i++ )
  998. {
  999. Magazine pile = m_MagazinePilesInInventory.Get(i);
  1000. pile.GetNetworkID(low_mag1,high_mag1);
  1001. for( j = 0; j < magazines_piles.Count(); j++)
  1002. {
  1003. magazines_piles.Get(j).GetNetworkID(low_mag2,high_mag2);
  1004. if(low_mag1 > low_mag2)
  1005. {
  1006. break;
  1007. }
  1008. else if (low_mag1 == low_mag2)
  1009. {
  1010. if( high_mag1 > high_mag2 )
  1011. {
  1012. break;
  1013. }
  1014. }
  1015. }
  1016. magazines_piles.InsertAt(pile,j);
  1017. }
  1018. m_MagazinePilesInInventory.Clear();
  1019. m_MagazinePilesInInventory.Copy(magazines_piles);
  1020. SetSutableMagazines();
  1021. }
  1022. void SetSutableMagazines()
  1023. {
  1024. m_SuitableMagazines.Clear();
  1025. int i;
  1026. if (m_WeaponInHand)
  1027. {
  1028. int mi = m_WeaponInHand.GetCurrentMuzzle();
  1029. for (i = 0; i < m_MagazineStorageInInventory.Count(); i++ )
  1030. {
  1031. MagazineStorage s_mag = m_MagazineStorageInInventory[i];
  1032. if (!s_mag)
  1033. {
  1034. m_MagazineStorageInInventory.RemoveOrdered(i);
  1035. i--;
  1036. continue;
  1037. }
  1038. if ( m_WeaponInHand.TestAttachMagazine(mi, s_mag, false, true))
  1039. m_SuitableMagazines.Insert(s_mag);
  1040. }
  1041. for (i = 0; i < m_MagazinePilesInInventory.Count(); i++ )
  1042. {
  1043. Magazine mag = m_MagazinePilesInInventory[i];
  1044. if (!mag)
  1045. {
  1046. m_MagazinePilesInInventory.RemoveOrdered(i);
  1047. i--;
  1048. continue;
  1049. }
  1050. if (m_WeaponInHand.CanChamberFromMag(mi, mag))
  1051. m_SuitableMagazines.Insert(mag);
  1052. }
  1053. //TODO m_MagazineStorageInInventory and m_MagazinePilesInInventory always sort
  1054. }
  1055. else if (m_MagazineInHand)
  1056. {
  1057. for (i = 0; i < m_MagazinePilesInInventory.Count(); i++ )
  1058. {
  1059. Magazine m_mag = m_MagazinePilesInInventory[i];
  1060. if (!m_mag)
  1061. {
  1062. m_MagazinePilesInInventory.RemoveOrdered(i);
  1063. i--;
  1064. continue;
  1065. }
  1066. if (m_MagazineInHand.IsCompatiableAmmo( m_mag ))
  1067. m_SuitableMagazines.Insert(m_mag);
  1068. }
  1069. }
  1070. else
  1071. {
  1072. m_PreparedMagazine = null;
  1073. }
  1074. }
  1075. void OnLiftWeapon()
  1076. {
  1077. if( m_WeaponInHand )
  1078. m_WeaponInHand.ResetBurstCount();
  1079. }
  1080. string GetCurrentModeName()
  1081. {
  1082. if( m_WeaponInHand )
  1083. {
  1084. int mi = m_WeaponInHand.GetCurrentMuzzle();
  1085. return m_WeaponInHand.GetCurrentModeName(mi);
  1086. }
  1087. return "";
  1088. }
  1089. bool PrepareInventoryLocationForMagazineSwap( notnull Weapon_Base wpn, notnull Magazine new_mag, out InventoryLocation new_il )
  1090. {
  1091. int muzzleIndex = wpn.GetCurrentMuzzle();
  1092. Magazine old_mag = Magazine.Cast(wpn.GetMagazine(muzzleIndex));
  1093. InventoryLocation temp = new InventoryLocation();
  1094. if (old_mag)
  1095. {
  1096. bool result = GameInventory.CanSwapEntitiesEx(new_mag, old_mag);
  1097. if ( result )
  1098. {
  1099. new_mag.GetInventory().GetCurrentInventoryLocation(new_il);
  1100. new_il.SetItem(old_mag);
  1101. }
  1102. else
  1103. {
  1104. result = GameInventory.CanForceSwapEntitiesEx(new_mag, null, old_mag, new_il);
  1105. float dir[4];
  1106. if ( !result )
  1107. {
  1108. new_il.SetGroundEx( old_mag, m_player.GetPosition(), dir);
  1109. }
  1110. }
  1111. }
  1112. return true;
  1113. }
  1114. }