weaponparticles.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. Author: Boris Vacula
  3. For documentation go to: DayZ Confluence -> How-to articles -> Weapon muzzle flash particle system configuration
  4. This system plays effect(s) on any weapon that is fired/jammed/ruined/...
  5. */
  6. class WeaponParticlesBase // This class represents every particle effect you see in config within OnFire or OnOverheating events
  7. {
  8. bool m_IlluminateWorld;
  9. bool m_IgnoreIfSuppressed;
  10. bool m_OnlyIfBoltIsOpen;
  11. int m_MuzzleIndex;
  12. int m_OverrideParticle;
  13. int m_OnlyWithinHealthLabelMin;
  14. int m_OnlyWithinHealthLabelMax;
  15. float m_OnlyWithinOverheatLimitsMin;
  16. float m_OnlyWithinOverheatLimitsMax;
  17. float m_OnlyWithinRainLimitsMin;
  18. float m_OnlyWithinRainLimitsMax;
  19. string m_OverrideDirectionPoint;
  20. string m_OnlyIfBulletIs;
  21. string m_OnlyIfWeaponIs;
  22. string m_OverridePoint;
  23. vector m_OverrideDirectionVector;
  24. vector m_PositionOffset;
  25. string m_Name;
  26. //======================================
  27. // PRELOAD EVERYTHING
  28. //======================================
  29. void WeaponParticlesBase(ItemBase muzzle_owner, string config_OnFire_entry)
  30. {
  31. m_Name = config_OnFire_entry;
  32. // ignoreIfSuppressed
  33. m_IgnoreIfSuppressed = GetGame().ConfigGetFloat(string.Format("%1 ignoreIfSuppressed", m_Name));
  34. // onlyIfBoltIsOpen
  35. m_OnlyIfBoltIsOpen = GetGame().ConfigGetFloat(string.Format("%1 onlyIfBoltIsOpen", m_Name));
  36. // illuminateWorld
  37. m_IlluminateWorld = GetGame().ConfigGetFloat(string.Format("%1 illuminateWorld", m_Name));
  38. m_MuzzleIndex = -1;
  39. if (GetGame().ConfigIsExisting(string.Format("%1 muzzleIndex", m_Name)))
  40. {
  41. m_MuzzleIndex = GetGame().ConfigGetInt(string.Format("%1 muzzleIndex", m_Name));
  42. }
  43. // onlyIfWeaponIs
  44. m_OnlyIfWeaponIs = "";
  45. GetGame().ConfigGetText(string.Format("%1 onlyIfWeaponIs", m_Name), m_OnlyIfWeaponIs);
  46. // onlyIfBulletIs
  47. m_OnlyIfBulletIs = "";
  48. GetGame().ConfigGetText(string.Format("%1 onlyIfBulletIs", m_Name), m_OnlyIfBulletIs);
  49. // onlyWithinHealthLabel[]
  50. array<float> health_limit = new array<float>;
  51. GetGame().ConfigGetFloatArray(string.Format("%1 onlyWithinHealthLabel", m_Name), health_limit);
  52. if (health_limit.Count() == 2)
  53. {
  54. m_OnlyWithinHealthLabelMin = health_limit.Get(0);
  55. m_OnlyWithinHealthLabelMax = health_limit.Get(1);
  56. }
  57. else
  58. {
  59. // Disable this filter
  60. m_OnlyWithinHealthLabelMin = -1;
  61. m_OnlyWithinHealthLabelMax = 99;
  62. }
  63. // onlyWithinOverheatLimits[]
  64. array<float> overheat_limit = new array<float>;
  65. GetGame().ConfigGetFloatArray(string.Format("%1 onlyWithinOverheatLimits", m_Name), overheat_limit);
  66. if (overheat_limit.Count() == 2)
  67. {
  68. m_OnlyWithinOverheatLimitsMin = overheat_limit.Get(0);
  69. m_OnlyWithinOverheatLimitsMax = overheat_limit.Get(1);
  70. }
  71. else
  72. {
  73. // Disable this filter
  74. m_OnlyWithinOverheatLimitsMin = -1;
  75. m_OnlyWithinOverheatLimitsMax = 2;
  76. }
  77. // onlyWithinRainLimits[]
  78. array<float> rain_limit = new array<float>;
  79. GetGame().ConfigGetFloatArray(string.Format("%1 onlyWithinRainLimits", m_Name), rain_limit);
  80. if (rain_limit.Count() == 2)
  81. {
  82. m_OnlyWithinRainLimitsMin = rain_limit.Get(0);
  83. m_OnlyWithinRainLimitsMax = rain_limit.Get(1);
  84. }
  85. else
  86. {
  87. // Disable this filter
  88. m_OnlyWithinRainLimitsMin = -1;
  89. m_OnlyWithinRainLimitsMax = 2;
  90. }
  91. // overridePoint
  92. m_OverridePoint = "";
  93. GetGame().ConfigGetText(string.Format("%1 overridePoint", m_Name), m_OverridePoint);
  94. if (m_OverridePoint == "")
  95. m_OverridePoint = "Usti hlavne"; // default memory point name
  96. // overrideParticle
  97. string particle_name = "";
  98. GetGame().ConfigGetText( string.Format("%1 overrideParticle", m_Name), particle_name);
  99. if (particle_name != "")
  100. {
  101. m_OverrideParticle = ParticleList.GetParticleIDByName(particle_name);
  102. }
  103. else
  104. {
  105. m_OverrideParticle = -1;
  106. ErrorEx(string.Format("'%1' does not contain a definition for 'overrideparticle'",
  107. config_OnFire_entry), ErrorExSeverity.INFO);
  108. }
  109. // overrideDirectionPoint
  110. m_OverrideDirectionPoint = "";
  111. GetGame().ConfigGetText(string.Format("%1 overrideDirectionPoint", m_Name), m_OverrideDirectionPoint);
  112. if (m_OverrideDirectionPoint == "")
  113. {
  114. // overrideDirectionVector
  115. vector test_ori = GetGame().ConfigGetVector(string.Format("%1 overrideDirectionVector", m_Name));
  116. if (test_ori != vector.Zero)
  117. {
  118. m_OverrideDirectionVector = test_ori;
  119. }
  120. }
  121. // positionOffset[]
  122. array<float> v = new array<float>;
  123. GetGame().ConfigGetFloatArray(string.Format("%1 positionOffset", m_Name), v);
  124. if (v.Count() == 3)
  125. {
  126. float v1 = v.Get(0);
  127. float v2 = v.Get(1);
  128. float v3 = v.Get(2);
  129. m_PositionOffset = Vector(v1, v2, v3);
  130. }
  131. }
  132. //======================================
  133. // PLAY PARTICLES
  134. //======================================
  135. // It is important to know that this block of script is called for weapons and muzzle attachments alike.
  136. // Thus weapon == muzzle_owner when this is called for a weapon, and weapon != muzzle_owner when this is called for a suppressor.
  137. void OnActivate(ItemBase weapon, int muzzle_index, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  138. {
  139. if ( !GetGame().IsServer() || !GetGame().IsMultiplayer() )
  140. {
  141. // Handle effect's parameters
  142. if ( PrtTest.m_GunParticlesState ) // Check if particles are enabled by debug
  143. {
  144. if ( m_MuzzleIndex == -1 || m_MuzzleIndex == muzzle_index )
  145. {
  146. if ( CheckBoltStateCondition(weapon) ) // onlyIfBoltIsOpen
  147. {
  148. if ( !suppressor || suppressor.IsRuined() || !(m_IgnoreIfSuppressed) ) // ignoreIfSuppressed
  149. {
  150. if ( CheckHealthCondition( muzzle_owner.GetHealthLevel() ) ) // onlyWithinHealthLabel
  151. {
  152. if ( CheckOverheatingCondition( muzzle_owner.GetOverheatingCoef() ) ) // onlyWithinOverheatLimits
  153. {
  154. if ( CheckRainCondition( GetGame().GetWeather().GetRain().GetActual() ) ) // onlyWithinRainLimits
  155. {
  156. if ( m_OnlyIfBulletIs == "" || m_OnlyIfBulletIs == ammoType ) // onlyIfBulletIs
  157. {
  158. if ( m_OnlyIfWeaponIs == "" || m_OnlyIfWeaponIs == weapon.GetType() ) // onlyIfWeaponIs
  159. {
  160. // Get particle ID
  161. int particle_id = CheckParticleOverride(ammoType);
  162. if (ParticleList.IsValidId(particle_id))
  163. {
  164. // Get position of the particle
  165. vector local_pos = muzzle_owner.GetSelectionPositionLS(m_OverridePoint);
  166. local_pos += m_PositionOffset;
  167. // Set orientation of the particle
  168. vector particle_ori = CheckOrientationOverride(local_pos, muzzle_owner);
  169. // Create particle
  170. Particle p = ParticleManager.GetInstance().PlayOnObject( particle_id, muzzle_owner, local_pos, particle_ori );
  171. OnParticleCreated(weapon, ammoType, muzzle_owner, suppressor, config_to_search, p);
  172. }
  173. else
  174. {
  175. ErrorEx(string.Format("No valid particle found for: '%1'", m_Name));
  176. }
  177. // Create light
  178. if (m_IlluminateWorld)
  179. {
  180. vector global_pos = muzzle_owner.ModelToWorld(local_pos + Vector(-0.2, 0, 0));
  181. int randX = Math.RandomInt( 0,10 );
  182. if ( randX > 8 )
  183. ScriptedLightBase.CreateLight( MuzzleFlashLight_2, global_pos );
  184. else if ( randX > 4 )
  185. ScriptedLightBase.CreateLight( MuzzleFlashLight_1, global_pos );
  186. else
  187. ScriptedLightBase.CreateLight(MuzzleFlashLight, global_pos);
  188. }
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }
  195. }
  196. }
  197. }
  198. }
  199. }
  200. void OnParticleCreated(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search, Particle p)
  201. {
  202. }
  203. void OnDeactivate(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  204. {
  205. }
  206. void OnUpdate(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  207. {
  208. }
  209. //==============================================
  210. // HANDLE CONFIG PARAMETERS
  211. //==============================================
  212. // OnlyWithinHealthLabelMin & OnlyWithinHealthLabelMax
  213. bool CheckBoltStateCondition(ItemBase weapon)
  214. {
  215. if ( m_OnlyIfBoltIsOpen )
  216. {
  217. Weapon_Base wb = Weapon_Base.Cast( weapon );
  218. WeaponStateBase current_state = wb.GetCurrentState();
  219. return current_state.IsBoltOpen();
  220. }
  221. return true;
  222. }
  223. // OnlyWithinHealthLabelMin & OnlyWithinHealthLabelMax
  224. bool CheckHealthCondition(int health_label)
  225. {
  226. return ( (health_label >= m_OnlyWithinHealthLabelMin) && (health_label <= m_OnlyWithinHealthLabelMax) );
  227. }
  228. // OnlyWithinOverheatLimitsMin & OnlyWithinOverheatLimitsMax
  229. bool CheckOverheatingCondition(float overheating_coef)
  230. {
  231. return ( (overheating_coef >= m_OnlyWithinOverheatLimitsMin) && (overheating_coef <= m_OnlyWithinOverheatLimitsMax) );
  232. }
  233. // OnlyWithinRainLimitsMin & OnlyWithinRainLimitsMax
  234. bool CheckRainCondition(float rain_coef)
  235. {
  236. return ( (rain_coef >= m_OnlyWithinRainLimitsMin) && (rain_coef <= m_OnlyWithinRainLimitsMax) );
  237. }
  238. // muzzleFlashParticle
  239. int CheckParticleOverride(string ammoType)
  240. {
  241. int particle_id = -1;
  242. string particle_file = "";
  243. string cfg_path = "CfgAmmo " + ammoType + " muzzleFlashParticle";
  244. if (GetGame().ConfigGetText( cfg_path, particle_file))
  245. particle_id = ParticleList.GetParticleIDByName(particle_file);
  246. // Config is accessed only once because the data is saved into a map for repeated access.
  247. if ( particle_id > 0 || m_OverrideParticle == -1)
  248. {
  249. if (particle_file == "")
  250. {
  251. ErrorEx(string.Format("Cannot spawn particle effect because item %1 is missing config parameter muzzleFlashParticle!", ammoType), ErrorExSeverity.INFO);
  252. }
  253. else
  254. {
  255. particle_id = ParticleList.GetParticleIDByName(particle_file);
  256. if (particle_id == 0)
  257. {
  258. string devStr;
  259. #ifdef DEVELOPER
  260. devStr = " Make sure it's registered there and then rebuild Scripts and Graphics PBOs.";
  261. #endif
  262. ErrorEx(string.Format("Cannot play particle effect with name %1 because no such file is registered in ParticleList.c!%2", particle_file, devStr));
  263. m_OverrideParticle = particle_id; // Prevents another appearence of the above error.
  264. }
  265. }
  266. }
  267. else
  268. {
  269. particle_id = m_OverrideParticle;
  270. }
  271. return particle_id;
  272. }
  273. // OverrideDirectionPoint & OverrideDirectionVector
  274. vector CheckOrientationOverride(vector local_pos, ItemBase muzzle_owner)
  275. {
  276. vector particle_ori = "0 0 0";
  277. if (m_OverrideDirectionPoint != "")
  278. {
  279. vector target_pos = muzzle_owner.GetSelectionPositionLS(m_OverrideDirectionPoint);
  280. target_pos = vector.Direction(local_pos, target_pos);
  281. particle_ori = target_pos.VectorToAngles();
  282. }
  283. else
  284. {
  285. if (m_OverrideDirectionVector != Vector(0, 0, 0))
  286. {
  287. particle_ori = m_OverrideDirectionVector;
  288. }
  289. if (muzzle_owner.IsInherited(ItemSuppressor))
  290. {
  291. particle_ori = particle_ori + Vector(0,0,270); // This rotation is necesarry due to suppressors being rotated into ground in their p3d files
  292. }
  293. }
  294. return particle_ori;
  295. }
  296. }
  297. // FIRE particles
  298. class WeaponParticlesOnFire : WeaponParticlesBase {}
  299. // BULLET EJECT particles
  300. class WeaponParticlesOnBulletCasingEject : WeaponParticlesBase {}
  301. // OVERHEATING particles
  302. class WeaponParticlesOnOverheating: WeaponParticlesBase
  303. {
  304. override void OnParticleCreated(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search, Particle p)
  305. {
  306. muzzle_owner.RegisterOverheatingParticle(p, m_OnlyWithinOverheatLimitsMin, m_OnlyWithinOverheatLimitsMax, p.GetParticleID(), muzzle_owner, p.m_DefaultPos, p.m_DefaultOri );
  307. }
  308. override void OnDeactivate(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  309. {
  310. if ( !GetGame().IsServer() || !GetGame().IsMultiplayer() )
  311. {
  312. weapon.KillAllOverheatingParticles();
  313. }
  314. }
  315. override void OnUpdate(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  316. {
  317. OnActivate(weapon, 0, ammoType, muzzle_owner, suppressor, config_to_search);
  318. }
  319. }
  320. class OverheatingParticle
  321. {
  322. Particle m_Particle;
  323. int m_ParticleID;
  324. Object m_Parent;
  325. vector m_LocalPos;
  326. vector m_LocalOri;
  327. float m_OverheatingLimitMin;
  328. float m_OverheatingLimitMax;
  329. void RegisterParticle( Particle p)
  330. {
  331. m_Particle = p;
  332. }
  333. Particle GetParticle()
  334. {
  335. return m_Particle;
  336. }
  337. void SetOverheatingLimitMin(float min)
  338. {
  339. m_OverheatingLimitMin = min;
  340. }
  341. void SetOverheatingLimitMax(float max)
  342. {
  343. m_OverheatingLimitMax = max;
  344. }
  345. float GetOverheatingLimitMin()
  346. {
  347. return m_OverheatingLimitMin;
  348. }
  349. float GetOverheatingLimitMax()
  350. {
  351. return m_OverheatingLimitMax;
  352. }
  353. void SetParticleParams(int particle_id, Object parent, vector local_pos, vector local_ori)
  354. {
  355. m_ParticleID = particle_id;
  356. m_Parent = parent;
  357. m_LocalPos = local_pos;
  358. m_LocalOri = local_ori;
  359. }
  360. int GetParticleID()
  361. {
  362. return m_ParticleID;
  363. }
  364. Object GetParticleParent()
  365. {
  366. return m_Parent;
  367. }
  368. vector GetParticlePos()
  369. {
  370. return m_LocalPos;
  371. }
  372. vector GetParticleOri()
  373. {
  374. return m_LocalOri;
  375. }
  376. }