weaponmanager.c 32 KB

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