effect.c 14 KB

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