effect.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. //! Enum to determine what type of effect the Effect is
  2. enum EffectType
  3. {
  4. //! Plain Effect base
  5. NONE,
  6. //! EffectSound
  7. SOUND,
  8. //! EffectParticle
  9. PARTICLE,
  10. }
  11. /**
  12. \brief Base wrapper class for managing effects (Particles, Sound) through SEffectManager
  13. \note This is just a base class, not intended for direct usage
  14. */
  15. class Effect : Managed
  16. {
  17. /** \name Event invokers
  18. * ScriptInvonkers for certain events
  19. */
  20. //@{
  21. ref ScriptInvoker Event_OnStarted = new ScriptInvoker();
  22. ref ScriptInvoker Event_OnStopped = new ScriptInvoker();
  23. ref ScriptInvoker Event_OnEffectStarted = new ScriptInvoker();
  24. ref ScriptInvoker Event_OnEffectEnded = new ScriptInvoker();
  25. //@}
  26. /** \name Generic data
  27. * Generic data for the Effect
  28. */
  29. //@{
  30. //! Whether the Effect cleans up after itself when stopped
  31. protected bool m_IsAutodestroy;
  32. //! Whether the Destroy process has already been called
  33. protected bool m_IsPendingDeletion;
  34. //! Whether the Effect is currently playing
  35. protected bool m_IsPlaying;
  36. //! Cached parent
  37. protected Object m_ParentObject;
  38. //! Cached parent pivot id
  39. protected int m_PivotIndex = -1;
  40. //! Cached world position
  41. protected vector m_Position;
  42. //@}
  43. /** \name SEffectManager data
  44. * Data filled in by SEffectManager to identify it when it is registered
  45. */
  46. //@{
  47. //! ID of effect, given by SEffectManager when registered (automatically done when playing through it)
  48. protected int m_ID;
  49. //! Whether the effect is registered in SEffectManager
  50. protected bool m_IsRegistered;
  51. //@}
  52. /** \name Attachment data
  53. * Cached settings set through 'SetAttachment...' methods
  54. * Does not necessarily reflect the current state when EffectParticle
  55. */
  56. //@{
  57. //! Cached local pos
  58. protected vector m_LocalPos;
  59. //! Local orientation set by SetAttachedLocalOri, only used by EffectParticle
  60. protected vector m_LocalOri;
  61. //@}
  62. /**
  63. \brief ctor
  64. */
  65. void Effect()
  66. {
  67. if (GetGame().IsDedicatedServer())
  68. {
  69. ErrorEx("Created Effect on server.", ErrorExSeverity.WARNING);
  70. }
  71. m_IsPlaying = false;
  72. InitEffect();
  73. }
  74. /**
  75. \brief dtor
  76. */
  77. void ~Effect()
  78. {
  79. // Safety
  80. if ( IsRegistered() )
  81. SEffectManager.EffectUnregister(GetID());
  82. // Certain effects need to be stopped to clean up properly
  83. Stop();
  84. // Another safety
  85. SetEnableEventFrame(false);
  86. }
  87. /**
  88. \brief init
  89. */
  90. void InitEffect()
  91. {
  92. Event_OnStarted.Insert(Event_OnEffectStarted);
  93. Event_OnStarted.Insert(ValidateStart);
  94. Event_OnStopped.Insert(Event_OnEffectEnded);
  95. }
  96. /** \name EffectType
  97. Information about what type of effect the Effect is, without the need for casting
  98. */
  99. //@{
  100. /**
  101. \brief Get what type of effect the Effect is
  102. \return \p EffectType What type of effect the Effect is
  103. */
  104. EffectType GetEffectType()
  105. {
  106. return EffectType.NONE;
  107. }
  108. /**
  109. \brief Check whether the Effect is EffectSound without casting
  110. \return \p bool Whether the Effect is EffectSound
  111. */
  112. bool IsSound()
  113. {
  114. return false;
  115. }
  116. /**
  117. \brief Check whether the Effect is EffectParticle without casting
  118. \return \p bool Whether the Effect is EffectParticle
  119. */
  120. bool IsParticle()
  121. {
  122. return false;
  123. }
  124. //@}
  125. /** \name Playback
  126. * Methods to Play/Stop Effect
  127. * Generally, SEffectManager.Play methods are used instead of Start
  128. */
  129. //@{
  130. /**
  131. \brief Plays all elements this effects consists of
  132. \note Is called by SEffectManager.Play methods
  133. */
  134. void Start()
  135. {
  136. // It is already playing!
  137. if (IsPlaying())
  138. return;
  139. Event_OnStarted();
  140. // I can't call this from inside the method with same name
  141. // because that method is often overriden without super......
  142. Event_OnStarted.Invoke(this);
  143. }
  144. /**
  145. \brief Validation whether an effect truly started playing or if the Effect should stop as none is present
  146. \note Override this when inheriting to create own validation check
  147. \note Is called from Event_OnStarted invoker after Event_OnStarted has been performed
  148. */
  149. void ValidateStart()
  150. {
  151. }
  152. /**
  153. \brief Stops all elements this effect consists of
  154. \note Alternatively use SEffectManager.Stop( effect_id )
  155. */
  156. void Stop()
  157. {
  158. // It is not playing!
  159. if (!IsPlaying())
  160. return;
  161. Event_OnStopped();
  162. // Yes, that event is new, but let's keep up some consistency
  163. Event_OnStopped.Invoke(this);
  164. }
  165. /**
  166. \brief Returns true when the Effect is playing, false otherwise
  167. */
  168. bool IsPlaying()
  169. {
  170. return m_IsPlaying;
  171. }
  172. //@}
  173. /** \name Destroy
  174. Methods regarding automatic cleanup
  175. */
  176. //@{
  177. /**
  178. \brief Cleans up the Effect, including unregistering if needed
  179. \note Will stop the Effect and queue up the deletion in the callqueue
  180. \note Is intended for usage from within the Effect itself, use SEffectManager.DestroyEffect when working from a pointer
  181. */
  182. protected void Destroy()
  183. {
  184. // Already queued
  185. if (IsPendingDeletion())
  186. return;
  187. // Mark it to prevent queuing it up multiple times or get stuck in a call loop
  188. m_IsPendingDeletion = true;
  189. // Stop it, so that the effects can clean up themselves
  190. // Since if for example this is EffectParticle and the particle is looping
  191. // It NEEDS to be stopped to clean up the Particle
  192. Stop();
  193. // Queue up the destroying, as we should not do it while we are accessing it here
  194. if (GetGame())
  195. {
  196. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(SEffectManager.DestroyEffect, this);
  197. }
  198. }
  199. /**
  200. \brief Sets whether Effect automatically cleans up when it stops
  201. \note This means that it will be unregistered from SEffectManager as well
  202. \param auto_destroy \p bool Whether Effect automatically cleans up when it stops
  203. */
  204. void SetAutodestroy(bool auto_destroy)
  205. {
  206. m_IsAutodestroy = auto_destroy;
  207. }
  208. /**
  209. \brief Get whether Effect automatically cleans up when it stops
  210. \return \p bool Whether Effect automatically cleans up when it stops
  211. */
  212. bool IsAutodestroy()
  213. {
  214. return m_IsAutodestroy;
  215. }
  216. /**
  217. \brief Get whether the Effect is queued up for being cleaned up
  218. \return \p bool Whether the Effect is queued up for being cleaned up
  219. */
  220. bool IsPendingDeletion()
  221. {
  222. return m_IsPendingDeletion;
  223. }
  224. /**
  225. \brief Get whether the Effect can be destroyed right now
  226. \return \p bool Whether the Effect can be destroyed right now
  227. */
  228. bool CanDestroy()
  229. {
  230. return true;
  231. }
  232. //@}
  233. /**
  234. \brief Enable Event_OnFrameUpdate for the effect
  235. \note Read SEffectManager.Event_OnFrameUpdate for more info
  236. */
  237. void SetEnableEventFrame(bool enable)
  238. {
  239. if ( enable )
  240. {
  241. SEffectManager.Event_OnFrameUpdate.Insert(Event_OnFrameUpdate);
  242. }
  243. else
  244. {
  245. SEffectManager.Event_OnFrameUpdate.Remove(Event_OnFrameUpdate);
  246. }
  247. }
  248. /** \name Events
  249. Various events that can be overriden for custom behaviour
  250. */
  251. //@{
  252. /**
  253. \brief Event used when Start was called
  254. */
  255. void Event_OnStarted()
  256. {
  257. // Override this method for own use
  258. }
  259. /**
  260. \brief Event used when Stop was called
  261. */
  262. void Event_OnStopped()
  263. {
  264. // Override this method for own use
  265. }
  266. /**
  267. \brief Event used when the actual effect started playing
  268. */
  269. void Event_OnEffectStarted()
  270. {
  271. m_IsPlaying = true;
  272. Event_OnEffectStarted.Invoke(this);
  273. }
  274. /**
  275. \brief Event used when the actual effect stopped playing
  276. */
  277. void Event_OnEffectEnded()
  278. {
  279. m_IsPlaying = false;
  280. Event_OnEffectEnded.Invoke(this);
  281. if ( IsAutodestroy() )
  282. {
  283. Destroy();
  284. }
  285. }
  286. /**
  287. \brief Event called on frame when enabled by SetEnableEventFrame(true)
  288. \note Called from SEffectManager.Event_OnFrameUpdate in MissionGameplay.OnUpdate
  289. \param time_delta \p float Time passed since the previous frame
  290. */
  291. void Event_OnFrameUpdate(float time_delta)
  292. {
  293. // Override this method for own use
  294. }
  295. /**
  296. \brief Event called from SEffectManager when the Effect is registered
  297. \note Should only ever be called by SEffectManager!
  298. \param id \p int ID registered in SEffectManager
  299. */
  300. void Event_OnRegistered(int id)
  301. {
  302. SetID(id);
  303. m_IsRegistered = true;
  304. }
  305. /**
  306. \brief Event called from SEffectManager when the Effect is unregistered
  307. \note Should only ever be called by SEffectManager!
  308. */
  309. void Event_OnUnregistered()
  310. {
  311. SetID(SEffectManager.INVALID_ID);
  312. m_IsRegistered = false;
  313. }
  314. /**
  315. \brief Event used when EffectParticle.CheckLifeSpan was called (DEPRECATED)
  316. \note So this is EffectParticle specific...
  317. \note EffectParticle.CheckLifeSpan is currently not in use
  318. */
  319. void OnCheckUpdate()
  320. {
  321. }
  322. //@}
  323. /** \name Generic API
  324. Setters and getters for generic data and properties
  325. */
  326. //@{
  327. /**
  328. \brief Set parent of the Effect
  329. \note Same as SetAttachmentParent, but more generic name
  330. \warning Only sets the cached variable, for immediate effect use SetCurrent variant
  331. \param parent_obj \p Object The parent
  332. \param pivot \p int The pivot index
  333. */
  334. void SetParent(Object parent_obj, int pivot)
  335. {
  336. m_ParentObject = parent_obj;
  337. m_PivotIndex = pivot;
  338. }
  339. /**
  340. \brief Set parent of the Effect
  341. \note Same as SetAttachmentParent, but more generic name
  342. \warning Only sets the cached variable, for immediate effect use SetCurrent variant
  343. \param parent_obj \p Object The parent for the Effect
  344. */
  345. void SetParent(Object parent_obj)
  346. {
  347. SetParent(parent_obj, -1);
  348. }
  349. /**
  350. \brief Get parent of the Effect
  351. \note Same as GetAttachmentParent, but more generic name
  352. \warning Only gets the cached variable, for immediate effect use GetCurrent variant
  353. \return \p Object The parent of the Effect
  354. */
  355. Object GetParent()
  356. {
  357. return m_ParentObject;
  358. }
  359. /**
  360. \brief Get parent pivot of the Effect, only valid when there is some GetParent
  361. \warning Only gets the cached variable
  362. \return \p int The parent pivot of the Effect
  363. */
  364. int GetPivotIndex()
  365. {
  366. return m_PivotIndex;
  367. }
  368. /**
  369. \brief Set current parent of the managed effect
  370. \note Same as SetAttachmentParent, but more generic name
  371. \param parent_obj \p Object The parent for the Effect
  372. \param updateCached \p bool Whether to update the cached variable
  373. */
  374. void SetCurrentParent( Object parent_obj, bool updateCached = true )
  375. {
  376. if (updateCached)
  377. SetParent(parent_obj);
  378. }
  379. /**
  380. \brief Get the current parent of the managed Effect
  381. \return \p Object The current parent of the managed Effect
  382. */
  383. Object GetCurrentParent()
  384. {
  385. return null;
  386. }
  387. /**
  388. \brief Set the world position of the Effect
  389. \warning Only sets the cached variable, for immediate effect use SetCurrent variant
  390. \param pos \p vector The world position for the Effect
  391. */
  392. void SetPosition( vector pos )
  393. {
  394. m_Position = pos;
  395. }
  396. /**
  397. \brief Get the world position of the Effect
  398. \warning Only gets the cached variable, for immediate effect use GetCurrent variant
  399. \return \p vector The world position of the Effect
  400. */
  401. vector GetPosition()
  402. {
  403. return m_Position;
  404. }
  405. /**
  406. \brief Set the current world position of the managed effect
  407. \param pos \p vector The current world position for the Effect
  408. \param updateCached \p bool Whether to update the cached variable
  409. */
  410. void SetCurrentPosition( vector pos, bool updateCached = true )
  411. {
  412. if (updateCached)
  413. SetPosition(pos);
  414. }
  415. /**
  416. \brief Get the current world position of the managed effect
  417. \return \p vector The current world position of the managed effect
  418. */
  419. vector GetCurrentPosition()
  420. {
  421. return vector.Zero;
  422. }
  423. /**
  424. \brief Set the local position of the Effect
  425. \warning Only sets the cached variable, for immediate effect use SetCurrent variant
  426. \param pos \p vector The local position for the Effect
  427. */
  428. void SetLocalPosition( vector pos )
  429. {
  430. m_LocalPos = pos;
  431. }
  432. /**
  433. \brief Get the local position of the Effect
  434. \warning Only gets the cached variable, for immediate effect use GetCurrent variant
  435. \return \p vector The lcoal position of the Effect
  436. */
  437. vector GetLocalPosition()
  438. {
  439. return m_LocalPos;
  440. }
  441. /**
  442. \brief Set the current local position of the managed effect
  443. \param pos \p vector The current local position for the managed effect
  444. \param updateCached \p bool Whether to update the cached variable
  445. */
  446. void SetCurrentLocalPosition( vector pos, bool updateCached = true )
  447. {
  448. if (updateCached)
  449. SetLocalPosition(pos);
  450. }
  451. /**
  452. \brief Get the current local position of the managed effect
  453. \return \p vector The current local position of the managed effect
  454. */
  455. vector GetCurrentLocalPosition()
  456. {
  457. return vector.Zero;
  458. }
  459. //@}
  460. /** \name Effect ID
  461. The ID of the effect when registered in SEffectManager
  462. */
  463. //@{
  464. /**
  465. \brief Set the ID registered in SEffectManager
  466. \note Should only ever be called by Event_OnRegistered!
  467. \param id \p int ID registered in SEffectManager
  468. */
  469. protected void SetID(int id)
  470. {
  471. m_ID = id;
  472. }
  473. /**
  474. \brief Get the ID registered in SEffectManager
  475. \return \p int ID registered in SEffectManager, or 0 (SEffectManager.INVALID_ID) when not registered
  476. */
  477. int GetID()
  478. {
  479. return m_ID;
  480. }
  481. /**
  482. \brief Get whether this Effect is registered in SEffectManager
  483. \return \p bool Whether this Effect is registered in SEffectManager
  484. */
  485. bool IsRegistered()
  486. {
  487. return m_IsRegistered;
  488. }
  489. //@}
  490. /** \name Attachment API
  491. * Data to attach an Effect to a parent
  492. * Mostly replaced by equivalents without 'Attachment' in name
  493. * Mildly deprecated, exist for backwards compatibility
  494. */
  495. //@{
  496. /**
  497. \brief Set parent for the Effect
  498. \param obj \p Object The parent for the Effect
  499. */
  500. void SetAttachmentParent(Object obj)
  501. {
  502. SetParent(obj);
  503. }
  504. /**
  505. \brief Get the parent set by SetAttachmentParent
  506. \return \p Object The parent set by SetAttachmentParent
  507. */
  508. Object GetAttachmentParent()
  509. {
  510. return GetParent();
  511. }
  512. /**
  513. \brief Set local pos for the Effect relative to the parent
  514. \param pos \p vector The local pos relative to the parent
  515. */
  516. void SetAttachedLocalPos(vector pos)
  517. {
  518. SetLocalPosition(pos);
  519. }
  520. /**
  521. \brief Get the local pos set by SetAttachedLocalPos
  522. \return \p vector The local pos set by SetAttachedLocalPos
  523. */
  524. vector GetAttachedLocalPos()
  525. {
  526. return GetLocalPosition();
  527. }
  528. /**
  529. \brief Set local orientation for the Effectparticle to attach to when the Effect is started
  530. \warning Only caches it into a variable to be used by Start, does not live update when called afterwards
  531. \note Overrides the orientation set by EffectParticle.SetOrientation
  532. \param ori \p vector The local orientation to use on Start
  533. */
  534. void SetAttachedLocalOri(vector ori)
  535. {
  536. m_LocalOri = ori;
  537. }
  538. /**
  539. \brief Get the local orientation set by SetAttachedLocalOri
  540. \warning Is not necessarily the current local orientation
  541. \return \p vector The local orientation set by SetAttachedLocalOri
  542. */
  543. vector GetAttachedLocalOri()
  544. {
  545. return m_LocalOri;
  546. }
  547. //@}
  548. }