afxMagicSpell.cpp 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713
  1. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  3. // Copyright (C) 2015 Faust Logic, Inc.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to
  7. // deal in the Software without restriction, including without limitation the
  8. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9. // sell copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. // IN THE SOFTWARE.
  22. //
  23. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  24. #include "afx/arcaneFX.h"
  25. #include "console/engineAPI.h"
  26. #include "T3D/gameBase/gameConnection.h"
  27. #include "sfx/sfxSystem.h"
  28. #include "math/mathIO.h"
  29. #include "T3D/containerQuery.h"
  30. #include "afx/afxChoreographer.h"
  31. #include "afx/afxPhrase.h"
  32. #include "afx/afxMagicSpell.h"
  33. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  34. // afxMagicSpellData::ewValidator
  35. //
  36. // When any of the effect list fields (addCastingEffect, etc.) are set, this validator
  37. // intercepts the value and adds it to the appropriate effects list. One validator is
  38. // created for each effect list and an id is used to identify which list to add the effect
  39. // to.
  40. //
  41. void afxMagicSpellData::ewValidator::validateType(SimObject* object, void* typePtr)
  42. {
  43. afxMagicSpellData* spelldata = dynamic_cast<afxMagicSpellData*>(object);
  44. afxEffectBaseData** ew = (afxEffectBaseData**)(typePtr);
  45. if (spelldata && ew)
  46. {
  47. switch (id)
  48. {
  49. case CASTING_PHRASE:
  50. spelldata->mCasting_fx_list.push_back(*ew);
  51. break;
  52. case LAUNCH_PHRASE:
  53. spelldata->mLaunch_fx_list.push_back(*ew);
  54. break;
  55. case DELIVERY_PHRASE:
  56. spelldata->mDelivery_fx_list.push_back(*ew);
  57. break;
  58. case IMPACT_PHRASE:
  59. spelldata->mImpact_fx_list.push_back(*ew);
  60. break;
  61. case LINGER_PHRASE:
  62. spelldata->mLinger_fx_list.push_back(*ew);
  63. break;
  64. }
  65. *ew = 0;
  66. }
  67. }
  68. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  69. class SpellFinishStartupEvent : public SimEvent
  70. {
  71. public:
  72. void process(SimObject* obj)
  73. {
  74. afxMagicSpell* spell = dynamic_cast<afxMagicSpell*>(obj);
  75. if (spell)
  76. spell->finish_startup();
  77. }
  78. };
  79. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  80. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  81. // afxMagicSpellData
  82. IMPLEMENT_CO_DATABLOCK_V1(afxMagicSpellData);
  83. ConsoleDocClass( afxMagicSpellData,
  84. "@brief Defines the properties of an afxMagicSpell.\n\n"
  85. "@ingroup afxChoreographers\n"
  86. "@ingroup AFX\n"
  87. "@ingroup Datablocks\n"
  88. );
  89. IMPLEMENT_CALLBACK( afxMagicSpellData, onDamage, void,
  90. (afxMagicSpell* spell, const char* label, const char* flaver, U32 target_id, F32 amount, U8 n, Point3F pos, F32 ad_amount, F32 radius, F32 impulse),
  91. (spell, label, flaver, target_id, amount, n, pos, ad_amount, radius, impulse),
  92. "Called when the spell deals damage.\n"
  93. "@param spell the spell object\n" );
  94. IMPLEMENT_CALLBACK( afxMagicSpellData, onDeactivate, void, (afxMagicSpell* spell), (spell),
  95. "Called when the spell ends naturally.\n"
  96. "@param spell the spell object\n" );
  97. IMPLEMENT_CALLBACK( afxMagicSpellData, onInterrupt, void, (afxMagicSpell* spell, ShapeBase* caster), (spell, caster),
  98. "Called when the spell ends unnaturally due to an interruption.\n"
  99. "@param spell the spell object\n" );
  100. IMPLEMENT_CALLBACK( afxMagicSpellData, onLaunch, void,
  101. (afxMagicSpell* spell, ShapeBase* caster, SceneObject* target, afxMagicMissile* missile),
  102. (spell, caster, target, missile),
  103. "Called when the spell's casting stage ends and the delivery stage begins.\n"
  104. "@param spell the spell object\n" );
  105. IMPLEMENT_CALLBACK( afxMagicSpellData, onImpact, void,
  106. (afxMagicSpell* spell, ShapeBase* caster, SceneObject* impacted, Point3F pos, Point3F normal),
  107. (spell, caster, impacted, pos, normal),
  108. "Called at the spell's missile impact marking the end of the deliver stage and the start of the linger stage.\n"
  109. "@param spell the spell object\n" );
  110. IMPLEMENT_CALLBACK( afxMagicSpellData, onPreactivate, bool,
  111. (SimObject* param_holder, ShapeBase* caster, SceneObject* target, SimObject* extra),
  112. (param_holder, caster, target, extra),
  113. "Called during spell casting before spell instance is fully created.\n");
  114. IMPLEMENT_CALLBACK( afxMagicSpellData, onActivate, void,
  115. (afxMagicSpell* spell, ShapeBase* caster, SceneObject* target),
  116. (spell, caster, target),
  117. "Called when the spell starts.\n"
  118. "@param spell the spell object\n" );
  119. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  120. afxMagicSpellData::afxMagicSpellData()
  121. {
  122. mCasting_dur = 0.0f;
  123. mDelivery_dur = 0.0f;
  124. mLinger_dur = 0.0f;
  125. mNum_casting_loops = 1;
  126. mNum_delivery_loops = 1;
  127. mNum_linger_loops = 1;
  128. mExtra_casting_time = 0.0f;
  129. mExtra_delivery_time = 0.0f;
  130. mExtra_linger_time = 0.0f;
  131. // interrupt flags
  132. mDo_move_interrupts = true;
  133. mMove_interrupt_speed = 2.0f;
  134. // delivers projectile spells
  135. mMissile_db = 0;
  136. mLaunch_on_server_signal = false;
  137. mPrimary_target_types = PlayerObjectType;
  138. // dummy entry holds effect-wrapper pointer while a special validator
  139. // grabs it and adds it to an appropriate effects list
  140. mDummy_fx_entry = NULL;
  141. // marked true if datablock ids need to
  142. // be converted into pointers
  143. mDo_id_convert = false;
  144. }
  145. afxMagicSpellData::afxMagicSpellData(const afxMagicSpellData& other, bool temp_clone) : afxChoreographerData(other, temp_clone)
  146. {
  147. mCasting_dur = other.mCasting_dur;
  148. mDelivery_dur = other.mDelivery_dur;
  149. mLinger_dur = other.mLinger_dur;
  150. mNum_casting_loops = other.mNum_casting_loops;
  151. mNum_delivery_loops = other.mNum_delivery_loops;
  152. mNum_linger_loops = other.mNum_linger_loops;
  153. mExtra_casting_time = other.mExtra_casting_time;
  154. mExtra_delivery_time = other.mExtra_delivery_time;
  155. mExtra_linger_time = other.mExtra_linger_time;
  156. mDo_move_interrupts = other.mDo_move_interrupts;
  157. mMove_interrupt_speed = other.mMove_interrupt_speed;
  158. mMissile_db = other.mMissile_db;
  159. mLaunch_on_server_signal = other.mLaunch_on_server_signal;
  160. mPrimary_target_types = other.mPrimary_target_types;
  161. mDummy_fx_entry = other.mDummy_fx_entry;
  162. mDo_id_convert = other.mDo_id_convert;
  163. mCasting_fx_list = other.mCasting_fx_list;
  164. mLaunch_fx_list = other.mLaunch_fx_list;
  165. mDelivery_fx_list = other.mDelivery_fx_list;
  166. mImpact_fx_list = other.mImpact_fx_list;
  167. mLinger_fx_list = other.mLinger_fx_list;
  168. }
  169. void afxMagicSpellData::reloadReset()
  170. {
  171. mCasting_fx_list.clear();
  172. mLaunch_fx_list.clear();
  173. mDelivery_fx_list.clear();
  174. mImpact_fx_list.clear();
  175. mLinger_fx_list.clear();
  176. }
  177. #define myOffset(field) Offset(field, afxMagicSpellData)
  178. void afxMagicSpellData::initPersistFields()
  179. {
  180. docsURL;
  181. static ewValidator _castingPhrase(CASTING_PHRASE);
  182. static ewValidator _launchPhrase(LAUNCH_PHRASE);
  183. static ewValidator _deliveryPhrase(DELIVERY_PHRASE);
  184. static ewValidator _impactPhrase(IMPACT_PHRASE);
  185. static ewValidator _lingerPhrase(LINGER_PHRASE);
  186. // for each effect list, dummy_fx_entry is set and then a validator adds it to the appropriate effects list
  187. addGroup("Casting Stage");
  188. addField("castingDur", TypeF32, myOffset(mCasting_dur),
  189. "...");
  190. addField("numCastingLoops", TypeS32, myOffset(mNum_casting_loops),
  191. "...");
  192. addField("extraCastingTime", TypeF32, myOffset(mExtra_casting_time),
  193. "...");
  194. addFieldV("addCastingEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_castingPhrase,
  195. "...");
  196. endGroup("Casting Stage");
  197. addGroup("Delivery Stage");
  198. addField("deliveryDur", TypeF32, myOffset(mDelivery_dur),
  199. "...");
  200. addField("numDeliveryLoops", TypeS32, myOffset(mNum_delivery_loops),
  201. "...");
  202. addField("extraDeliveryTime", TypeF32, myOffset(mExtra_delivery_time),
  203. "...");
  204. addFieldV("addLaunchEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_launchPhrase,
  205. "...");
  206. addFieldV("addDeliveryEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_deliveryPhrase,
  207. "...");
  208. endGroup("Delivery Stage");
  209. addGroup("Linger Stage");
  210. addField("lingerDur", TypeF32, myOffset(mLinger_dur),
  211. "...");
  212. addField("numLingerLoops", TypeS32, myOffset(mNum_linger_loops),
  213. "...");
  214. addField("extraLingerTime", TypeF32, myOffset(mExtra_linger_time),
  215. "...");
  216. addFieldV("addImpactEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_impactPhrase,
  217. "...");
  218. addFieldV("addLingerEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_lingerPhrase,
  219. "...");
  220. endGroup("Linger Stage");
  221. // interrupt flags
  222. addField("allowMovementInterrupts", TypeBool, myOffset(mDo_move_interrupts),
  223. "...");
  224. addField("movementInterruptSpeed", TypeF32, myOffset(mMove_interrupt_speed),
  225. "...");
  226. // delivers projectile spells
  227. addField("missile", TYPEID<afxMagicMissileData>(), myOffset(mMissile_db),
  228. "...");
  229. addField("launchOnServerSignal", TypeBool, myOffset(mLaunch_on_server_signal),
  230. "...");
  231. addField("primaryTargetTypes", TypeS32, myOffset(mPrimary_target_types),
  232. "...");
  233. Parent::initPersistFields();
  234. // disallow some field substitutions
  235. onlyKeepClearSubstitutions("missile"); // subs resolving to "~~", or "~0" are OK
  236. disableFieldSubstitutions("addCastingEffect");
  237. disableFieldSubstitutions("addLaunchEffect");
  238. disableFieldSubstitutions("addDeliveryEffect");
  239. disableFieldSubstitutions("addImpactEffect");
  240. disableFieldSubstitutions("addLingerEffect");
  241. }
  242. bool afxMagicSpellData::onAdd()
  243. {
  244. if (Parent::onAdd() == false)
  245. return false;
  246. if (mMissile_db != NULL && mDelivery_dur == 0.0)
  247. mDelivery_dur = -1;
  248. return true;
  249. }
  250. void afxMagicSpellData::pack_fx(BitStream* stream, const afxEffectList& fx, bool packed)
  251. {
  252. stream->writeInt(fx.size(), EFFECTS_PER_PHRASE_BITS);
  253. for (int i = 0; i < fx.size(); i++)
  254. writeDatablockID(stream, fx[i], packed);
  255. }
  256. void afxMagicSpellData::unpack_fx(BitStream* stream, afxEffectList& fx)
  257. {
  258. fx.clear();
  259. S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS);
  260. for (int i = 0; i < n_fx; i++)
  261. fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream));
  262. }
  263. void afxMagicSpellData::packData(BitStream* stream)
  264. {
  265. Parent::packData(stream);
  266. stream->write(mCasting_dur);
  267. stream->write(mDelivery_dur);
  268. stream->write(mLinger_dur);
  269. //
  270. stream->write(mNum_casting_loops);
  271. stream->write(mNum_delivery_loops);
  272. stream->write(mNum_linger_loops);
  273. //
  274. stream->write(mExtra_casting_time);
  275. stream->write(mExtra_delivery_time);
  276. stream->write(mExtra_linger_time);
  277. stream->writeFlag(mDo_move_interrupts);
  278. stream->write(mMove_interrupt_speed);
  279. writeDatablockID(stream, mMissile_db, mPacked);
  280. stream->write(mLaunch_on_server_signal);
  281. stream->write(mPrimary_target_types);
  282. pack_fx(stream, mCasting_fx_list, mPacked);
  283. pack_fx(stream, mLaunch_fx_list, mPacked);
  284. pack_fx(stream, mDelivery_fx_list, mPacked);
  285. pack_fx(stream, mImpact_fx_list, mPacked);
  286. pack_fx(stream, mLinger_fx_list, mPacked);
  287. }
  288. void afxMagicSpellData::unpackData(BitStream* stream)
  289. {
  290. Parent::unpackData(stream);
  291. stream->read(&mCasting_dur);
  292. stream->read(&mDelivery_dur);
  293. stream->read(&mLinger_dur);
  294. //
  295. stream->read(&mNum_casting_loops);
  296. stream->read(&mNum_delivery_loops);
  297. stream->read(&mNum_linger_loops);
  298. //
  299. stream->read(&mExtra_casting_time);
  300. stream->read(&mExtra_delivery_time);
  301. stream->read(&mExtra_linger_time);
  302. mDo_move_interrupts = stream->readFlag();
  303. stream->read(&mMove_interrupt_speed);
  304. mMissile_db = (afxMagicMissileData*)(uintptr_t)readDatablockID(stream);
  305. stream->read(&mLaunch_on_server_signal);
  306. stream->read(&mPrimary_target_types);
  307. mDo_id_convert = true;
  308. unpack_fx(stream, mCasting_fx_list);
  309. unpack_fx(stream, mLaunch_fx_list);
  310. unpack_fx(stream, mDelivery_fx_list);
  311. unpack_fx(stream, mImpact_fx_list);
  312. unpack_fx(stream, mLinger_fx_list);
  313. }
  314. bool afxMagicSpellData::writeField(StringTableEntry fieldname, const char* value)
  315. {
  316. if (!Parent::writeField(fieldname, value))
  317. return false;
  318. // don't write the dynamic array fields
  319. if( fieldname == StringTable->insert("addCastingEffect") )
  320. return false;
  321. if( fieldname == StringTable->insert("addLaunchEffect") )
  322. return false;
  323. if( fieldname == StringTable->insert("addDeliveryEffect") )
  324. return false;
  325. if( fieldname == StringTable->insert("addImpactEffect") )
  326. return false;
  327. if( fieldname == StringTable->insert("addLingerEffect") )
  328. return false;
  329. return true;
  330. }
  331. inline void expand_fx_list(afxEffectList& fx_list, const char* tag)
  332. {
  333. for (S32 i = 0; i < fx_list.size(); i++)
  334. {
  335. SimObjectId db_id = SimObjectId((uintptr_t)fx_list[i]);
  336. if (db_id != 0)
  337. {
  338. // try to convert id to pointer
  339. if (!Sim::findObject(db_id, fx_list[i]))
  340. {
  341. Con::errorf(ConsoleLogEntry::General,
  342. "afxMagicSpellData::preload() -- bad datablockId: 0x%x (%s)",
  343. db_id, tag);
  344. }
  345. }
  346. }
  347. }
  348. bool afxMagicSpellData::preload(bool server, String &errorStr)
  349. {
  350. if (!Parent::preload(server, errorStr))
  351. return false;
  352. // Resolve objects transmitted from server
  353. if (!server)
  354. {
  355. if (mDo_id_convert)
  356. {
  357. SimObjectId missile_id = SimObjectId((uintptr_t)mMissile_db);
  358. if (missile_id != 0)
  359. {
  360. // try to convert id to pointer
  361. if (!Sim::findObject(missile_id, mMissile_db))
  362. {
  363. Con::errorf(ConsoleLogEntry::General,
  364. "afxMagicSpellData::preload() -- bad datablockId: 0x%x (missile)",
  365. missile_id);
  366. }
  367. }
  368. expand_fx_list(mCasting_fx_list, "casting");
  369. expand_fx_list(mLaunch_fx_list, "launch");
  370. expand_fx_list(mDelivery_fx_list, "delivery");
  371. expand_fx_list(mImpact_fx_list, "impact");
  372. expand_fx_list(mLinger_fx_list, "linger");
  373. mDo_id_convert = false;
  374. }
  375. }
  376. return true;
  377. }
  378. void afxMagicSpellData::gatherConstraintDefs(Vector<afxConstraintDef>& defs)
  379. {
  380. afxConstraintDef::gather_cons_defs(defs, mCasting_fx_list);
  381. afxConstraintDef::gather_cons_defs(defs, mLaunch_fx_list);
  382. afxConstraintDef::gather_cons_defs(defs, mDelivery_fx_list);
  383. afxConstraintDef::gather_cons_defs(defs, mImpact_fx_list);
  384. afxConstraintDef::gather_cons_defs(defs, mLinger_fx_list);
  385. if (mMissile_db)
  386. mMissile_db->gather_cons_defs(defs);
  387. }
  388. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
  389. DefineEngineMethod(afxMagicSpellData, reset, void, (),,
  390. "Resets a spell datablock during reload.\n\n"
  391. "@ingroup AFX")
  392. {
  393. object->reloadReset();
  394. }
  395. DefineEngineMethod(afxMagicSpellData, pushCastingEffect, void, (afxEffectBaseData* effect),,
  396. "Adds an effect (wrapper or group) to a spell's casting phase.\n\n"
  397. "@ingroup AFX")
  398. {
  399. if (!effect)
  400. {
  401. Con::errorf(ConsoleLogEntry::General,
  402. "afxMagicSpellData::addCastingEffect() -- "
  403. "missing afxEffectWrapperData.");
  404. return;
  405. }
  406. object->mCasting_fx_list.push_back(effect);
  407. }
  408. DefineEngineMethod(afxMagicSpellData, pushLaunchEffect, void, (afxEffectBaseData* effect),,
  409. "Adds an effect (wrapper or group) to a spell's launch phase.\n\n"
  410. "@ingroup AFX")
  411. {
  412. if (!effect)
  413. {
  414. Con::errorf(ConsoleLogEntry::General,
  415. "afxMagicSpellData::addLaunchEffect() -- "
  416. "failed to find afxEffectWrapperData.");
  417. return;
  418. }
  419. object->mLaunch_fx_list.push_back(effect);
  420. }
  421. DefineEngineMethod(afxMagicSpellData, pushDeliveryEffect, void, (afxEffectBaseData* effect),,
  422. "Adds an effect (wrapper or group) to a spell's delivery phase.\n\n"
  423. "@ingroup AFX")
  424. {
  425. if (!effect)
  426. {
  427. Con::errorf(ConsoleLogEntry::General,
  428. "afxMagicSpellData::addDeliveryEffect() -- "
  429. "missing afxEffectWrapperData.");
  430. return;
  431. }
  432. object->mDelivery_fx_list.push_back(effect);
  433. }
  434. DefineEngineMethod(afxMagicSpellData, pushImpactEffect, void, (afxEffectBaseData* effect),,
  435. "Adds an effect (wrapper or group) to a spell's impact phase.\n\n"
  436. "@ingroup AFX")
  437. {
  438. if (!effect)
  439. {
  440. Con::errorf(ConsoleLogEntry::General,
  441. "afxMagicSpellData::addImpactEffect() -- "
  442. "missing afxEffectWrapperData.");
  443. return;
  444. }
  445. object->mImpact_fx_list.push_back(effect);
  446. }
  447. DefineEngineMethod(afxMagicSpellData, pushLingerEffect, void, (afxEffectBaseData* effect),,
  448. "Adds an effect (wrapper or group) to a spell's linger phase.\n\n"
  449. "@ingroup AFX")
  450. {
  451. if (!effect)
  452. {
  453. Con::errorf(ConsoleLogEntry::General,
  454. "afxMagicSpellData::addLingerEffect() -- "
  455. "missing afxEffectWrapperData.");
  456. return;
  457. }
  458. object->mLinger_fx_list.push_back(effect);
  459. }
  460. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  461. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  462. // afxMagicSpell
  463. IMPLEMENT_GLOBAL_CALLBACK( onCastingStart, void, (), (),
  464. "A callout called on clients by spells when the casting stage begins.\n"
  465. "@ingroup AFX\n" );
  466. IMPLEMENT_GLOBAL_CALLBACK( onCastingProgressUpdate, void, (F32 frac), (frac),
  467. "A callout called periodically on clients by spells to indicate casting progress.\n"
  468. "@ingroup AFX\n" );
  469. IMPLEMENT_GLOBAL_CALLBACK( onCastingEnd, void, (), (),
  470. "A callout called on clients by spells when the casting stage ends.\n"
  471. "@ingroup AFX\n" );
  472. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  473. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  474. // CastingPhrase_C
  475. // Subclass of afxPhrase for the client casting phrase.
  476. // This subclass adds handling of the casting progress
  477. // bar in cases where the caster is the client's control
  478. // object.
  479. //
  480. class CastingPhrase_C : public afxPhrase
  481. {
  482. typedef afxPhrase Parent;
  483. ShapeBase* mCaster;
  484. bool mNotify_castbar;
  485. F32 mCastbar_progress;
  486. public:
  487. /*C*/ CastingPhrase_C(ShapeBase* caster, bool notify_castbar);
  488. virtual void start(F32 startstamp, F32 timestamp);
  489. virtual void update(F32 dt, F32 timestamp);
  490. virtual void stop(F32 timestamp);
  491. virtual void interrupt(F32 timestamp);
  492. };
  493. CastingPhrase_C::CastingPhrase_C(ShapeBase* c, bool notify)
  494. : afxPhrase(false, true)
  495. {
  496. mCaster = c;
  497. mNotify_castbar = notify;
  498. mCastbar_progress = 0.0f;
  499. }
  500. void CastingPhrase_C::start(F32 startstamp, F32 timestamp)
  501. {
  502. Parent::start(startstamp, timestamp); //START
  503. if (mNotify_castbar)
  504. {
  505. mCastbar_progress = 0.0f;
  506. onCastingStart_callback();
  507. }
  508. }
  509. void CastingPhrase_C::update(F32 dt, F32 timestamp)
  510. {
  511. Parent::update(dt, timestamp);
  512. if (!mNotify_castbar)
  513. return;
  514. if (mDur > 0 && mNum_loops > 0)
  515. {
  516. F32 nfrac = (timestamp - mStartTime)/(mDur*mNum_loops);
  517. if (nfrac - mCastbar_progress > 1.0f/200.0f)
  518. {
  519. mCastbar_progress = (nfrac < 1.0f) ? nfrac : 1.0f;
  520. onCastingProgressUpdate_callback(mCastbar_progress);
  521. }
  522. }
  523. }
  524. void CastingPhrase_C::stop(F32 timestamp)
  525. {
  526. Parent::stop(timestamp);
  527. if (mCastbar_progress)
  528. {
  529. onCastingEnd_callback();
  530. mNotify_castbar = false;
  531. }
  532. }
  533. void CastingPhrase_C::interrupt(F32 timestamp)
  534. {
  535. Parent::interrupt(timestamp);
  536. if (mNotify_castbar)
  537. {
  538. onCastingEnd_callback();
  539. mNotify_castbar = false;
  540. }
  541. }
  542. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  543. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  544. // some enum to name converters for debugging purposes
  545. #ifdef USE_FOR_DEBUG_MESSAGES
  546. static char* name_from_state(U8 s)
  547. {
  548. switch (s)
  549. {
  550. case afxMagicSpell::INACTIVE_STATE:
  551. return "inactive";
  552. case afxMagicSpell::CASTING_STATE:
  553. return "casting";
  554. case afxMagicSpell::DELIVERY_STATE:
  555. return "delivery";
  556. case afxMagicSpell::LINGER_STATE:
  557. return "linger";
  558. case afxMagicSpell::CLEANUP_STATE:
  559. return "cleanup";
  560. case afxMagicSpell::DONE_STATE:
  561. return "done";
  562. }
  563. return "unknown";
  564. }
  565. static char* name_from_event(U8 e)
  566. {
  567. switch (e)
  568. {
  569. case afxMagicSpell::NULL_EVENT:
  570. return "null";
  571. case afxMagicSpell::ACTIVATE_EVENT:
  572. return "activate";
  573. case afxMagicSpell::LAUNCH_EVENT:
  574. return "launch";
  575. case afxMagicSpell::IMPACT_EVENT:
  576. return "impact";
  577. case afxMagicSpell::SHUTDOWN_EVENT:
  578. return "shutdown";
  579. case afxMagicSpell::DEACTIVATE_EVENT:
  580. return "deactivate";
  581. case afxMagicSpell::INTERRUPT_PHASE_EVENT:
  582. return "interrupt_phase";
  583. case afxMagicSpell::INTERRUPT_SPELL_EVENT:
  584. return "interrupt_spell";
  585. }
  586. return "unknown";
  587. }
  588. #endif
  589. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  590. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  591. // afxMagicSpell
  592. IMPLEMENT_CO_NETOBJECT_V1(afxMagicSpell);
  593. ConsoleDocClass( afxMagicSpell,
  594. "@brief A magic spell effects choreographer.\n\n"
  595. "@ingroup afxChoreographers\n"
  596. "@ingroup AFX\n"
  597. );
  598. // static
  599. StringTableEntry afxMagicSpell::CASTER_CONS;
  600. StringTableEntry afxMagicSpell::TARGET_CONS;
  601. StringTableEntry afxMagicSpell::MISSILE_CONS;
  602. StringTableEntry afxMagicSpell::CAMERA_CONS;
  603. StringTableEntry afxMagicSpell::LISTENER_CONS;
  604. StringTableEntry afxMagicSpell::IMPACT_POINT_CONS;
  605. StringTableEntry afxMagicSpell::IMPACTED_OBJECT_CONS;
  606. void afxMagicSpell::init()
  607. {
  608. // setup static predefined constraint names
  609. if (CASTER_CONS == 0)
  610. {
  611. CASTER_CONS = StringTable->insert("caster");
  612. TARGET_CONS = StringTable->insert("target");
  613. MISSILE_CONS = StringTable->insert("missile");
  614. CAMERA_CONS = StringTable->insert("camera");
  615. LISTENER_CONS = StringTable->insert("listener");
  616. IMPACT_POINT_CONS = StringTable->insert("impactPoint");
  617. IMPACTED_OBJECT_CONS = StringTable->insert("impactedObject");
  618. }
  619. // afxMagicSpell is always in scope, however effects
  620. // do their own scoping in that they will shut off if
  621. // their position constraint leaves scope.
  622. //
  623. // note -- ghosting is delayed until constraint
  624. // initialization is done.
  625. //
  626. //mNetFlags.set(Ghostable | ScopeAlways);
  627. mNetFlags.clear(Ghostable | ScopeAlways);
  628. mDatablock = NULL;
  629. mExeblock = NULL;
  630. mMissile_db = NULL;
  631. mCaster = NULL;
  632. mTarget = NULL;
  633. mCaster_field = NULL;
  634. mTarget_field = NULL;
  635. mCaster_scope_id = 0;
  636. mTarget_scope_id = 0;
  637. mTarget_is_shape = false;
  638. mConstraints_initialized = false;
  639. mScoping_initialized = false;
  640. mSpell_state = (U8) INACTIVE_STATE;
  641. mSpell_elapsed = 0;
  642. // define named constraints
  643. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, CASTER_CONS);
  644. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, TARGET_CONS);
  645. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, MISSILE_CONS);
  646. constraint_mgr->defineConstraint(CAMERA_CONSTRAINT, CAMERA_CONS);
  647. constraint_mgr->defineConstraint(POINT_CONSTRAINT, LISTENER_CONS);
  648. constraint_mgr->defineConstraint(POINT_CONSTRAINT, IMPACT_POINT_CONS);
  649. constraint_mgr->defineConstraint(OBJECT_CONSTRAINT, IMPACTED_OBJECT_CONS);
  650. for (S32 i = 0; i < NUM_PHRASES; i++)
  651. {
  652. mPhrases[i] = NULL;
  653. mTfactors[i] = 1.0f;
  654. }
  655. mNotify_castbar = false;
  656. mOverall_time_factor = 1.0f;
  657. mCamera_cons_obj = 0;
  658. mMarks_mask = 0;
  659. mMissile = NULL;
  660. mMissile_is_armed = false;
  661. mImpacted_obj = NULL;
  662. mImpact_pos.zero();
  663. mImpact_norm.set(0,0,1);
  664. mImpacted_scope_id = 0;
  665. mImpacted_is_shape = false;
  666. }
  667. afxMagicSpell::afxMagicSpell()
  668. {
  669. started_with_newop = true;
  670. init();
  671. }
  672. afxMagicSpell::afxMagicSpell(ShapeBase* caster, SceneObject* target)
  673. {
  674. started_with_newop = false;
  675. init();
  676. mCaster = caster;
  677. if (caster)
  678. {
  679. mCaster_field = caster;
  680. deleteNotify(caster);
  681. processAfter(caster);
  682. }
  683. mTarget = target;
  684. if (target)
  685. {
  686. mTarget_field = target;
  687. deleteNotify(target);
  688. }
  689. }
  690. afxMagicSpell::~afxMagicSpell()
  691. {
  692. for (S32 i = 0; i < NUM_PHRASES; i++)
  693. {
  694. if (mPhrases[i])
  695. {
  696. mPhrases[i]->interrupt(mSpell_elapsed);
  697. delete mPhrases[i];
  698. }
  699. }
  700. if (mMissile)
  701. mMissile->deleteObject();
  702. if (mMissile_db && mMissile_db->isTempClone())
  703. {
  704. delete mMissile_db;
  705. mMissile_db = 0;
  706. }
  707. if (mDatablock && mDatablock->isTempClone())
  708. {
  709. delete mDatablock;
  710. mDatablock = 0;
  711. }
  712. }
  713. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  714. // STANDARD OVERLOADED METHODS //
  715. bool afxMagicSpell::onNewDataBlock(GameBaseData* dptr, bool reload)
  716. {
  717. mDatablock = dynamic_cast<afxMagicSpellData*>(dptr);
  718. if (!mDatablock || !Parent::onNewDataBlock(dptr, reload))
  719. return false;
  720. if (isServerObject() && started_with_newop)
  721. {
  722. // copy dynamic fields from the datablock but
  723. // don't replace fields with a value
  724. assignDynamicFieldsFrom(dptr, arcaneFX::sParameterFieldPrefix, true);
  725. }
  726. mExeblock = mDatablock;
  727. mMissile_db = mDatablock->mMissile_db;
  728. if (isClientObject())
  729. {
  730. // make a temp datablock clone if there are substitutions
  731. if (mDatablock->getSubstitutionCount() > 0)
  732. {
  733. afxMagicSpellData* orig_db = mDatablock;
  734. mDatablock = new afxMagicSpellData(*orig_db, true);
  735. mExeblock = orig_db;
  736. mMissile_db = mDatablock->mMissile_db;
  737. // Don't perform substitutions yet, the spell's dynamic fields haven't
  738. // arrived yet and the substitutions may refer to them. Hold off and do
  739. // in in the onAdd() method.
  740. }
  741. }
  742. else if (started_with_newop)
  743. {
  744. // make a temp datablock clone if there are substitutions
  745. if (mDatablock->getSubstitutionCount() > 0)
  746. {
  747. afxMagicSpellData* orig_db = mDatablock;
  748. mDatablock = new afxMagicSpellData(*orig_db, true);
  749. mExeblock = orig_db;
  750. orig_db->performSubstitutions(mDatablock, this, ranking);
  751. mMissile_db = mDatablock->mMissile_db;
  752. }
  753. }
  754. return true;
  755. }
  756. void afxMagicSpell::processTick(const Move* m)
  757. {
  758. Parent::processTick(m);
  759. // don't process moves or client ticks
  760. if (m != 0 || isClientObject())
  761. return;
  762. process_server();
  763. }
  764. void afxMagicSpell::advanceTime(F32 dt)
  765. {
  766. Parent::advanceTime(dt);
  767. process_client(dt);
  768. }
  769. bool afxMagicSpell::onAdd()
  770. {
  771. if (!Parent::onAdd())
  772. return false ;
  773. if (isClientObject())
  774. {
  775. if (mDatablock->isTempClone())
  776. {
  777. afxMagicSpellData* orig_db = (afxMagicSpellData*)mExeblock;
  778. orig_db->performSubstitutions(mDatablock, this, ranking);
  779. mMissile_db = mDatablock->mMissile_db;
  780. mNotify_castbar = (mNotify_castbar && (mDatablock->mCasting_dur > 0.0f));
  781. }
  782. }
  783. else if (started_with_newop && !postpone_activation)
  784. {
  785. if (!activationCallInit())
  786. return false;
  787. activate();
  788. }
  789. return true ;
  790. }
  791. void afxMagicSpell::onRemove()
  792. {
  793. Parent::onRemove();
  794. }
  795. void afxMagicSpell::onDeleteNotify(SimObject* obj)
  796. {
  797. // caster deleted?
  798. ShapeBase* shape = dynamic_cast<ShapeBase*>(obj);
  799. if (shape == mCaster)
  800. {
  801. clearProcessAfter();
  802. mCaster = NULL;
  803. mCaster_field = NULL;
  804. mCaster_scope_id = 0;
  805. }
  806. // target deleted?
  807. SceneObject* scene_obj = dynamic_cast<SceneObject*>(obj);
  808. if (scene_obj == mTarget)
  809. {
  810. mTarget = NULL;
  811. mTarget_field = NULL;
  812. mTarget_scope_id = 0;
  813. mTarget_is_shape = false;
  814. }
  815. // impacted_obj deleted?
  816. if (scene_obj == mImpacted_obj)
  817. {
  818. mImpacted_obj = NULL;
  819. mImpacted_scope_id = 0;
  820. mImpacted_is_shape = false;
  821. }
  822. // missile deleted?
  823. afxMagicMissile* missile = dynamic_cast<afxMagicMissile*>(obj);
  824. if (missile != NULL && missile == mMissile)
  825. {
  826. mMissile = NULL;
  827. }
  828. // something else
  829. Parent::onDeleteNotify(obj);
  830. }
  831. // static
  832. void afxMagicSpell::initPersistFields()
  833. {
  834. docsURL;
  835. addField("caster", TYPEID<SimObject>(), Offset(mCaster_field, afxMagicSpell),
  836. "...");
  837. addField("target", TYPEID<SimObject>(), Offset(mTarget_field, afxMagicSpell),
  838. "...");
  839. Parent::initPersistFields();
  840. }
  841. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  842. void afxMagicSpell::pack_constraint_info(NetConnection* conn, BitStream* stream)
  843. {
  844. // pack caster's ghost index or scope id if not yet ghosted
  845. if (stream->writeFlag(mCaster != NULL))
  846. {
  847. S32 ghost_idx = conn->getGhostIndex(mCaster);
  848. if (stream->writeFlag(ghost_idx != -1))
  849. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  850. else
  851. {
  852. bool bit = (mCaster) ? (mCaster->getScopeId() > 0) : false;
  853. if (stream->writeFlag(bit))
  854. stream->writeInt(mCaster->getScopeId(), NetObject::SCOPE_ID_BITS);
  855. }
  856. }
  857. // pack target's ghost index or scope id if not yet ghosted
  858. if (stream->writeFlag(mTarget != NULL))
  859. {
  860. S32 ghost_idx = conn->getGhostIndex(mTarget);
  861. if (stream->writeFlag(ghost_idx != -1))
  862. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  863. else
  864. {
  865. if (stream->writeFlag(mTarget->getScopeId() > 0))
  866. {
  867. stream->writeInt(mTarget->getScopeId(), NetObject::SCOPE_ID_BITS);
  868. stream->writeFlag(dynamic_cast<ShapeBase*>(mTarget) != NULL); // is shape?
  869. }
  870. }
  871. }
  872. Parent::pack_constraint_info(conn, stream);
  873. }
  874. void afxMagicSpell::unpack_constraint_info(NetConnection* conn, BitStream* stream)
  875. {
  876. mCaster = NULL;
  877. mCaster_field = NULL;
  878. mCaster_scope_id = 0;
  879. if (stream->readFlag()) // has caster
  880. {
  881. if (stream->readFlag()) // has ghost_idx
  882. {
  883. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  884. mCaster = dynamic_cast<ShapeBase*>(conn->resolveGhost(ghost_idx));
  885. if (mCaster)
  886. {
  887. mCaster_field = mCaster;
  888. deleteNotify(mCaster);
  889. processAfter(mCaster);
  890. }
  891. }
  892. else
  893. {
  894. if (stream->readFlag()) // has scope_id (is always a shape)
  895. mCaster_scope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  896. }
  897. }
  898. mTarget = NULL;
  899. mTarget_field = NULL;
  900. mTarget_scope_id = 0;
  901. mTarget_is_shape = false;
  902. if (stream->readFlag()) // has target
  903. {
  904. if (stream->readFlag()) // has ghost_idx
  905. {
  906. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  907. mTarget = dynamic_cast<SceneObject*>(conn->resolveGhost(ghost_idx));
  908. if (mTarget)
  909. {
  910. mTarget_field = mTarget;
  911. deleteNotify(mTarget);
  912. }
  913. }
  914. else
  915. {
  916. if (stream->readFlag()) // has scope_id
  917. {
  918. mTarget_scope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  919. mTarget_is_shape = stream->readFlag(); // is shape?
  920. }
  921. }
  922. }
  923. Parent::unpack_constraint_info(conn, stream);
  924. }
  925. U32 afxMagicSpell::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  926. {
  927. S32 mark_stream_pos = stream->getCurPos();
  928. U32 retMask = Parent::packUpdate(conn, mask, stream);
  929. // InitialUpdate
  930. if (stream->writeFlag(mask & InitialUpdateMask))
  931. {
  932. // pack extra object's ghost index or scope id if not yet ghosted
  933. if (stream->writeFlag(dynamic_cast<NetObject*>(mExtra) != 0))
  934. {
  935. NetObject* net_extra = (NetObject*)mExtra;
  936. S32 ghost_idx = conn->getGhostIndex(net_extra);
  937. if (stream->writeFlag(ghost_idx != -1))
  938. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  939. else
  940. {
  941. if (stream->writeFlag(net_extra->getScopeId() > 0))
  942. {
  943. stream->writeInt(net_extra->getScopeId(), NetObject::SCOPE_ID_BITS);
  944. }
  945. }
  946. }
  947. // pack initial exec conditions
  948. stream->write(exec_conds_mask);
  949. // flag if this client owns the spellcaster
  950. bool client_owns_caster = is_caster_client(mCaster, dynamic_cast<GameConnection*>(conn));
  951. stream->writeFlag(client_owns_caster);
  952. // pack per-phrase time-factor values
  953. for (S32 i = 0; i < NUM_PHRASES; i++)
  954. stream->write(mTfactors[i]);
  955. // flag if this conn is zoned-in yet
  956. bool zoned_in = client_owns_caster;
  957. if (!zoned_in)
  958. {
  959. GameConnection* gconn = dynamic_cast<GameConnection*>(conn);
  960. zoned_in = (gconn) ? gconn->isZonedIn() : false;
  961. }
  962. if (stream->writeFlag(zoned_in))
  963. pack_constraint_info(conn, stream);
  964. }
  965. // StateEvent or SyncEvent
  966. if (stream->writeFlag((mask & StateEventMask) || (mask & SyncEventMask)))
  967. {
  968. stream->write(mMarks_mask);
  969. stream->write(mSpell_state);
  970. stream->write(state_elapsed());
  971. stream->write(mSpell_elapsed);
  972. }
  973. // SyncEvent
  974. if (stream->writeFlag((mask & SyncEventMask) && !(mask & InitialUpdateMask)))
  975. {
  976. pack_constraint_info(conn, stream);
  977. }
  978. // LaunchEvent
  979. if (stream->writeFlag((mask & LaunchEventMask) && (mMarks_mask & MARK_LAUNCH) && mMissile))
  980. {
  981. F32 vel; Point3F vel_vec;
  982. mMissile->getStartingVelocityValues(vel, vel_vec);
  983. // pack launch vector and velocity
  984. stream->write(vel);
  985. mathWrite(*stream, vel_vec);
  986. }
  987. // ImpactEvent
  988. if (stream->writeFlag(((mask & ImpactEventMask) || (mask & SyncEventMask)) && (mMarks_mask & MARK_IMPACT)))
  989. {
  990. // pack impact objects's ghost index or scope id if not yet ghosted
  991. if (stream->writeFlag(mImpacted_obj != NULL))
  992. {
  993. S32 ghost_idx = conn->getGhostIndex(mImpacted_obj);
  994. if (stream->writeFlag(ghost_idx != -1))
  995. stream->writeRangedU32(U32(ghost_idx), 0, NetConnection::MaxGhostCount);
  996. else
  997. {
  998. if (stream->writeFlag(mImpacted_obj->getScopeId() > 0))
  999. {
  1000. stream->writeInt(mImpacted_obj->getScopeId(), NetObject::SCOPE_ID_BITS);
  1001. stream->writeFlag(dynamic_cast<ShapeBase*>(mImpacted_obj) != NULL);
  1002. }
  1003. }
  1004. }
  1005. // pack impact position and normal
  1006. mathWrite(*stream, mImpact_pos);
  1007. mathWrite(*stream, mImpact_norm);
  1008. stream->write(exec_conds_mask);
  1009. ShapeBase* temp_shape;
  1010. stream->writeFlag(mCaster != 0 && mCaster->getDamageState() == ShapeBase::Enabled);
  1011. temp_shape = dynamic_cast<ShapeBase*>(mTarget);
  1012. stream->writeFlag(temp_shape != 0 && temp_shape->getDamageState() == ShapeBase::Enabled);
  1013. temp_shape = dynamic_cast<ShapeBase*>(mImpacted_obj);
  1014. stream->writeFlag(temp_shape != 0 && temp_shape->getDamageState() == ShapeBase::Enabled);
  1015. }
  1016. check_packet_usage(conn, stream, mark_stream_pos, "afxMagicSpell:");
  1017. AssertISV(stream->isValid(), "afxMagicSpell::packUpdate(): write failure occurred, possibly caused by packet-size overrun.");
  1018. return retMask;
  1019. }
  1020. //~~~~~~~~~~~~~~~~~~~~//
  1021. // CONSTRAINT REMAPPING <<
  1022. bool afxMagicSpell::remap_builtin_constraint(SceneObject* obj, const char* cons_name)
  1023. {
  1024. StringTableEntry cons_name_ste = StringTable->insert(cons_name);
  1025. if (cons_name_ste == CASTER_CONS)
  1026. return true;
  1027. if (cons_name_ste == TARGET_CONS)
  1028. {
  1029. if (obj && mTarget && obj != mTarget && !mTarget_cons_id.undefined())
  1030. {
  1031. mTarget = obj;
  1032. constraint_mgr->setReferenceObject(mTarget_cons_id, mTarget);
  1033. if (isServerObject())
  1034. {
  1035. if (mTarget->isScopeable())
  1036. constraint_mgr->addScopeableObject(mTarget);
  1037. }
  1038. }
  1039. return true;
  1040. }
  1041. if (cons_name_ste == MISSILE_CONS)
  1042. return true;
  1043. if (cons_name_ste == CAMERA_CONS)
  1044. return true;
  1045. if (cons_name_ste == LISTENER_CONS)
  1046. return true;
  1047. if (cons_name_ste == IMPACT_POINT_CONS)
  1048. return true;
  1049. if (cons_name_ste == IMPACTED_OBJECT_CONS)
  1050. return true;
  1051. return false;
  1052. }
  1053. // CONSTRAINT REMAPPING >>
  1054. void afxMagicSpell::unpackUpdate(NetConnection * conn, BitStream * stream)
  1055. {
  1056. Parent::unpackUpdate(conn, stream);
  1057. bool initial_update = false;
  1058. bool zoned_in = true;
  1059. bool do_sync_event = false;
  1060. U16 new_marks_mask = 0;
  1061. U8 new_spell_state = INACTIVE_STATE;
  1062. F32 new_state_elapsed = 0;
  1063. F32 new_spell_elapsed = 0;;
  1064. // InitialUpdate
  1065. if (stream->readFlag())
  1066. {
  1067. initial_update = true;
  1068. // extra sent
  1069. if (stream->readFlag())
  1070. {
  1071. // cleanup?
  1072. if (stream->readFlag()) // is ghost_idx
  1073. {
  1074. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  1075. mExtra = dynamic_cast<SimObject*>(conn->resolveGhost(ghost_idx));
  1076. }
  1077. else
  1078. {
  1079. if (stream->readFlag()) // has scope_id
  1080. {
  1081. // JTF NOTE: U16 extra_scope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  1082. stream->readInt(NetObject::SCOPE_ID_BITS);
  1083. }
  1084. }
  1085. }
  1086. // unpack initial exec conditions
  1087. stream->read(&exec_conds_mask);
  1088. // if this is controlling client for the caster,
  1089. // enable castbar updates
  1090. bool client_owns_caster = stream->readFlag();
  1091. if (client_owns_caster)
  1092. mNotify_castbar = Con::isFunction("onCastingStart");
  1093. // unpack per-phrase time-factor values
  1094. for (S32 i = 0; i < NUM_PHRASES; i++)
  1095. stream->read(&mTfactors[i]);
  1096. // if client is marked as fully zoned in
  1097. if ((zoned_in = stream->readFlag()) == true)
  1098. {
  1099. unpack_constraint_info(conn, stream);
  1100. init_constraints();
  1101. }
  1102. }
  1103. // StateEvent or SyncEvent
  1104. // this state data is sent for both state-events and
  1105. // sync-events
  1106. if (stream->readFlag())
  1107. {
  1108. stream->read(&new_marks_mask);
  1109. stream->read(&new_spell_state);
  1110. stream->read(&new_state_elapsed);
  1111. stream->read(&new_spell_elapsed);
  1112. mMarks_mask = new_marks_mask;
  1113. }
  1114. // SyncEvent
  1115. if ((do_sync_event = stream->readFlag()) == true)
  1116. {
  1117. unpack_constraint_info(conn, stream);
  1118. init_constraints();
  1119. }
  1120. // LaunchEvent
  1121. if (stream->readFlag())
  1122. {
  1123. F32 vel; Point3F vel_vec;
  1124. stream->read(&vel);
  1125. mathRead(*stream, &vel_vec);
  1126. if (mMissile)
  1127. {
  1128. mMissile->setStartingVelocity(vel);
  1129. mMissile->setStartingVelocityVector(vel_vec);
  1130. }
  1131. }
  1132. // ImpactEvent
  1133. if (stream->readFlag())
  1134. {
  1135. if (mImpacted_obj)
  1136. clearNotify(mImpacted_obj);
  1137. mImpacted_obj = NULL;
  1138. mImpacted_scope_id = 0;
  1139. mImpacted_is_shape = false;
  1140. if (stream->readFlag()) // is impacted_obj
  1141. {
  1142. if (stream->readFlag()) // is ghost_idx
  1143. {
  1144. S32 ghost_idx = stream->readRangedU32(0, NetConnection::MaxGhostCount);
  1145. mImpacted_obj = dynamic_cast<SceneObject*>(conn->resolveGhost(ghost_idx));
  1146. if (mImpacted_obj)
  1147. deleteNotify(mImpacted_obj);
  1148. }
  1149. else
  1150. {
  1151. if (stream->readFlag()) // has scope_id
  1152. {
  1153. mImpacted_scope_id = stream->readInt(NetObject::SCOPE_ID_BITS);
  1154. mImpacted_is_shape = stream->readFlag(); // is shape?
  1155. }
  1156. }
  1157. }
  1158. mathRead(*stream, &mImpact_pos);
  1159. mathRead(*stream, &mImpact_norm);
  1160. stream->read(&exec_conds_mask);
  1161. bool caster_alive = stream->readFlag();
  1162. bool target_alive = stream->readFlag();
  1163. bool impacted_alive = stream->readFlag();
  1164. afxConstraint* cons;
  1165. if ((cons = constraint_mgr->getConstraint(mCaster_cons_id)) != 0)
  1166. cons->setLivingState(caster_alive);
  1167. if ((cons = constraint_mgr->getConstraint(mTarget_cons_id)) != 0)
  1168. cons->setLivingState(target_alive);
  1169. if ((cons = constraint_mgr->getConstraint(mImpacted_cons_id)) != 0)
  1170. cons->setLivingState(impacted_alive);
  1171. }
  1172. //~~~~~~~~~~~~~~~~~~~~//
  1173. if (!zoned_in)
  1174. mSpell_state = LATE_STATE;
  1175. // need to adjust state info to get all synced up with spell on server
  1176. if (do_sync_event && !initial_update)
  1177. sync_client(new_marks_mask, new_spell_state, new_state_elapsed, new_spell_elapsed);
  1178. }
  1179. void afxMagicSpell::sync_with_clients()
  1180. {
  1181. setMaskBits(SyncEventMask);
  1182. }
  1183. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  1184. // private
  1185. bool afxMagicSpell::state_expired()
  1186. {
  1187. afxPhrase* phrase = NULL;
  1188. switch (mSpell_state)
  1189. {
  1190. case CASTING_STATE:
  1191. phrase = mPhrases[CASTING_PHRASE];
  1192. break;
  1193. case DELIVERY_STATE:
  1194. phrase = mPhrases[DELIVERY_PHRASE];
  1195. break;
  1196. case LINGER_STATE:
  1197. phrase = mPhrases[LINGER_PHRASE];
  1198. break;
  1199. }
  1200. if (phrase)
  1201. {
  1202. if (phrase->expired(mSpell_elapsed))
  1203. return (!phrase->recycle(mSpell_elapsed));
  1204. return false;
  1205. }
  1206. return true;
  1207. }
  1208. F32 afxMagicSpell::state_elapsed()
  1209. {
  1210. afxPhrase* phrase = NULL;
  1211. switch (mSpell_state)
  1212. {
  1213. case CASTING_STATE:
  1214. phrase = mPhrases[CASTING_PHRASE];
  1215. break;
  1216. case DELIVERY_STATE:
  1217. phrase = mPhrases[DELIVERY_PHRASE];
  1218. break;
  1219. case LINGER_STATE:
  1220. phrase = mPhrases[LINGER_PHRASE];
  1221. break;
  1222. }
  1223. return (phrase) ? phrase->elapsed(mSpell_elapsed) : 0.0f;
  1224. }
  1225. void afxMagicSpell::init_constraints()
  1226. {
  1227. if (mConstraints_initialized)
  1228. {
  1229. //Con::printf("CONSTRAINTS ALREADY INITIALIZED");
  1230. return;
  1231. }
  1232. Vector<afxConstraintDef> defs;
  1233. mDatablock->gatherConstraintDefs(defs);
  1234. constraint_mgr->initConstraintDefs(defs, isServerObject());
  1235. if (isServerObject())
  1236. {
  1237. mCaster_cons_id = constraint_mgr->setReferenceObject(CASTER_CONS, mCaster);
  1238. mTarget_cons_id = constraint_mgr->setReferenceObject(TARGET_CONS, mTarget);
  1239. #if defined(AFX_CAP_SCOPE_TRACKING)
  1240. if (mCaster && mCaster->isScopeable())
  1241. constraint_mgr->addScopeableObject(mCaster);
  1242. if (mTarget && mTarget->isScopeable())
  1243. constraint_mgr->addScopeableObject(mTarget);
  1244. #endif
  1245. // find local camera
  1246. mCamera_cons_obj = get_camera();
  1247. if (mCamera_cons_obj)
  1248. mCamera_cons_id = constraint_mgr->setReferenceObject(CAMERA_CONS, mCamera_cons_obj);
  1249. }
  1250. else // if (isClientObject())
  1251. {
  1252. if (mCaster)
  1253. mCaster_cons_id = constraint_mgr->setReferenceObject(CASTER_CONS, mCaster);
  1254. else if (mCaster_scope_id > 0)
  1255. mCaster_cons_id = constraint_mgr->setReferenceObjectByScopeId(CASTER_CONS, mCaster_scope_id, true);
  1256. if (mTarget)
  1257. mTarget_cons_id = constraint_mgr->setReferenceObject(TARGET_CONS, mTarget);
  1258. else if (mTarget_scope_id > 0)
  1259. mTarget_cons_id = constraint_mgr->setReferenceObjectByScopeId(TARGET_CONS, mTarget_scope_id, mTarget_is_shape);
  1260. // find local camera
  1261. mCamera_cons_obj = get_camera();
  1262. if (mCamera_cons_obj)
  1263. mCamera_cons_id = constraint_mgr->setReferenceObject(CAMERA_CONS, mCamera_cons_obj);
  1264. // find local listener
  1265. Point3F listener_pos;
  1266. listener_pos = SFX->getListener().getTransform().getPosition();
  1267. mListener_cons_id = constraint_mgr->setReferencePoint(LISTENER_CONS, listener_pos);
  1268. }
  1269. constraint_mgr->adjustProcessOrdering(this);
  1270. mConstraints_initialized = true;
  1271. }
  1272. void afxMagicSpell::init_scoping()
  1273. {
  1274. if (mScoping_initialized)
  1275. {
  1276. //Con::printf("SCOPING ALREADY INITIALIZED");
  1277. return;
  1278. }
  1279. if (isServerObject())
  1280. {
  1281. if (explicit_clients.size() > 0)
  1282. {
  1283. for (U32 i = 0; i < explicit_clients.size(); i++)
  1284. explicit_clients[i]->objectLocalScopeAlways(this);
  1285. }
  1286. else
  1287. {
  1288. mNetFlags.set(Ghostable);
  1289. setScopeAlways();
  1290. }
  1291. mScoping_initialized = true;
  1292. }
  1293. }
  1294. void afxMagicSpell::setup_casting_fx()
  1295. {
  1296. if (isServerObject())
  1297. mPhrases[CASTING_PHRASE] = new afxPhrase(isServerObject(), true);
  1298. else
  1299. mPhrases[CASTING_PHRASE] = new CastingPhrase_C(mCaster, mNotify_castbar);
  1300. if (mPhrases[CASTING_PHRASE])
  1301. mPhrases[CASTING_PHRASE]->init(mDatablock->mCasting_fx_list, mDatablock->mCasting_dur, this,
  1302. mTfactors[CASTING_PHRASE], mDatablock->mNum_casting_loops, 0,
  1303. mDatablock->mExtra_casting_time);
  1304. }
  1305. void afxMagicSpell::setup_launch_fx()
  1306. {
  1307. mPhrases[LAUNCH_PHRASE] = new afxPhrase(isServerObject(), false);
  1308. if (mPhrases[LAUNCH_PHRASE])
  1309. mPhrases[LAUNCH_PHRASE]->init(mDatablock->mLaunch_fx_list, -1, this,
  1310. mTfactors[LAUNCH_PHRASE], 1);
  1311. }
  1312. void afxMagicSpell::setup_delivery_fx()
  1313. {
  1314. mPhrases[DELIVERY_PHRASE] = new afxPhrase(isServerObject(), true);
  1315. if (mPhrases[DELIVERY_PHRASE])
  1316. {
  1317. mPhrases[DELIVERY_PHRASE]->init(mDatablock->mDelivery_fx_list, mDatablock->mDelivery_dur, this,
  1318. mTfactors[DELIVERY_PHRASE], mDatablock->mNum_delivery_loops, 0,
  1319. mDatablock->mExtra_delivery_time);
  1320. }
  1321. }
  1322. void afxMagicSpell::setup_impact_fx()
  1323. {
  1324. mPhrases[IMPACT_PHRASE] = new afxPhrase(isServerObject(), false);
  1325. if (mPhrases[IMPACT_PHRASE])
  1326. {
  1327. mPhrases[IMPACT_PHRASE]->init(mDatablock->mImpact_fx_list, -1, this,
  1328. mTfactors[IMPACT_PHRASE], 1);
  1329. }
  1330. }
  1331. void afxMagicSpell::setup_linger_fx()
  1332. {
  1333. mPhrases[LINGER_PHRASE] = new afxPhrase(isServerObject(), true);
  1334. if (mPhrases[LINGER_PHRASE])
  1335. mPhrases[LINGER_PHRASE]->init(mDatablock->mLinger_fx_list, mDatablock->mLinger_dur, this,
  1336. mTfactors[LINGER_PHRASE], mDatablock->mNum_linger_loops, 0,
  1337. mDatablock->mExtra_linger_time);
  1338. }
  1339. bool afxMagicSpell::cleanup_over()
  1340. {
  1341. for (S32 i = 0; i < NUM_PHRASES; i++)
  1342. if (mPhrases[i] && !mPhrases[i]->isEmpty())
  1343. return false;
  1344. return true;
  1345. }
  1346. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  1347. // private
  1348. //
  1349. // MISSILE STUFF
  1350. //
  1351. void afxMagicSpell::init_missile_s(afxMagicMissileData* mm_db)
  1352. {
  1353. if (mMissile)
  1354. clearNotify(mMissile);
  1355. // create the missile
  1356. mMissile = new afxMagicMissile(true, false);
  1357. mMissile->setSubstitutionData(this, ranking);
  1358. mMissile->setDataBlock(mm_db);
  1359. mMissile->setChoreographer(this);
  1360. if (!mMissile->registerObject())
  1361. {
  1362. Con::errorf("afxMagicSpell: failed to register missile instance.");
  1363. delete mMissile;
  1364. mMissile = NULL;
  1365. }
  1366. if (mMissile)
  1367. {
  1368. deleteNotify(mMissile);
  1369. registerForCleanup(mMissile);
  1370. }
  1371. }
  1372. void afxMagicSpell::launch_missile_s()
  1373. {
  1374. if (mMissile)
  1375. {
  1376. mMissile->launch();
  1377. constraint_mgr->setReferenceObject(MISSILE_CONS, mMissile);
  1378. }
  1379. }
  1380. void afxMagicSpell::init_missile_c(afxMagicMissileData* mm_db)
  1381. {
  1382. if (mMissile)
  1383. clearNotify(mMissile);
  1384. // create the missile
  1385. mMissile = new afxMagicMissile(false, true);
  1386. mMissile->setSubstitutionData(this, ranking);
  1387. mMissile->setDataBlock(mm_db);
  1388. mMissile->setChoreographer(this);
  1389. if (!mMissile->registerObject())
  1390. {
  1391. Con::errorf("afxMagicSpell: failed to register missile instance.");
  1392. delete mMissile;
  1393. mMissile = NULL;
  1394. }
  1395. if (mMissile)
  1396. {
  1397. deleteNotify(mMissile);
  1398. registerForCleanup(mMissile);
  1399. }
  1400. }
  1401. void afxMagicSpell::launch_missile_c()
  1402. {
  1403. if (mMissile)
  1404. {
  1405. mMissile->launch();
  1406. constraint_mgr->setReferenceObject(MISSILE_CONS, mMissile);
  1407. }
  1408. }
  1409. bool afxMagicSpell::is_impact_in_water(SceneObject* obj, const Point3F& p)
  1410. {
  1411. // AFX_T3D_BROKEN -- water impact detection is disabled. Look at projectile.
  1412. return false;
  1413. }
  1414. void afxMagicSpell::impactNotify(const Point3F& p, const Point3F& n, SceneObject* obj)
  1415. {
  1416. if (isClientObject())
  1417. return;
  1418. ///impact_time_ms = spell_elapsed_ms;
  1419. if (mImpacted_obj)
  1420. clearNotify(mImpacted_obj);
  1421. mImpacted_obj = obj;
  1422. mImpact_pos = p;
  1423. mImpact_norm = n;
  1424. if (mImpacted_obj != NULL)
  1425. {
  1426. deleteNotify(mImpacted_obj);
  1427. exec_conds_mask |= IMPACTED_SOMETHING;
  1428. if (mImpacted_obj == mTarget)
  1429. exec_conds_mask |= IMPACTED_TARGET;
  1430. if (mImpacted_obj->getTypeMask() & mDatablock->mPrimary_target_types)
  1431. exec_conds_mask |= IMPACTED_PRIMARY;
  1432. }
  1433. if (is_impact_in_water(obj, p))
  1434. exec_conds_mask |= IMPACT_IN_WATER;
  1435. postSpellEvent(IMPACT_EVENT);
  1436. if (mMissile)
  1437. clearNotify(mMissile);
  1438. mMissile = NULL;
  1439. }
  1440. void afxMagicSpell::executeScriptEvent(const char* method, afxConstraint* cons,
  1441. const MatrixF& xfm, const char* data)
  1442. {
  1443. SceneObject* cons_obj = (cons) ? cons->getSceneObject() : NULL;
  1444. char *arg_buf = Con::getArgBuffer(256);
  1445. Point3F pos;
  1446. xfm.getColumn(3,&pos);
  1447. AngAxisF aa(xfm);
  1448. dSprintf(arg_buf,256,"%g %g %g %g %g %g %g",
  1449. pos.x, pos.y, pos.z,
  1450. aa.axis.x, aa.axis.y, aa.axis.z, aa.angle);
  1451. // CALL SCRIPT afxChoreographerData::method(%spell, %caster, %constraint, %transform, %data)
  1452. Con::executef(mExeblock, method,
  1453. getIdString(),
  1454. (mCaster) ? mCaster->getIdString() : "",
  1455. (cons_obj) ? cons_obj->getIdString() : "",
  1456. arg_buf,
  1457. data);
  1458. }
  1459. void afxMagicSpell::inflictDamage(const char * label, const char* flavor, SimObjectId target_id,
  1460. F32 amount, U8 n, F32 ad_amount, F32 radius, Point3F pos, F32 impulse)
  1461. {
  1462. // Con::printf("INFLICT-DAMAGE label=%s flav=%s id=%d amt=%g n=%d rad=%g pos=(%g %g %g) imp=%g",
  1463. // label, flavor, target_id, amount, n, radius, pos.x, pos.y, pos.z, impulse);
  1464. // CALL SCRIPT afxMagicSpellData::onDamage()
  1465. // onDamage(%spell, %label, %type, %damaged_obj, %amount, %count, %pos, %ad_amount,
  1466. // %radius, %impulse)
  1467. mDatablock->onDamage_callback(this, label, flavor, target_id, amount, n, pos, ad_amount, radius, impulse);
  1468. }
  1469. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  1470. // private
  1471. void afxMagicSpell::process_server()
  1472. {
  1473. if (mSpell_state != INACTIVE_STATE)
  1474. mSpell_elapsed += TickSec;
  1475. U8 pending_state = mSpell_state;
  1476. // check for state changes
  1477. switch (mSpell_state)
  1478. {
  1479. case INACTIVE_STATE:
  1480. if (mMarks_mask & MARK_ACTIVATE)
  1481. pending_state = CASTING_STATE;
  1482. break;
  1483. case CASTING_STATE:
  1484. if (mDatablock->mCasting_dur > 0.0f && mDatablock->mDo_move_interrupts && is_caster_moving())
  1485. {
  1486. displayScreenMessage(mCaster, "SPELL INTERRUPTED.");
  1487. postSpellEvent(INTERRUPT_SPELL_EVENT);
  1488. }
  1489. if (mMarks_mask & MARK_INTERRUPT_CASTING)
  1490. pending_state = CLEANUP_STATE;
  1491. else if (mMarks_mask & MARK_END_CASTING)
  1492. pending_state = DELIVERY_STATE;
  1493. else if (mMarks_mask & MARK_LAUNCH)
  1494. pending_state = DELIVERY_STATE;
  1495. else if (state_expired())
  1496. pending_state = DELIVERY_STATE;
  1497. break;
  1498. case DELIVERY_STATE:
  1499. if (mMarks_mask & MARK_INTERRUPT_DELIVERY)
  1500. pending_state = CLEANUP_STATE;
  1501. else if (mMarks_mask & MARK_END_DELIVERY)
  1502. pending_state = LINGER_STATE;
  1503. else if (mMarks_mask & MARK_IMPACT)
  1504. pending_state = LINGER_STATE;
  1505. else if (state_expired())
  1506. pending_state = LINGER_STATE;
  1507. break;
  1508. case LINGER_STATE:
  1509. if (mMarks_mask & MARK_INTERRUPT_LINGER)
  1510. pending_state = CLEANUP_STATE;
  1511. else if (mMarks_mask & MARK_END_LINGER)
  1512. pending_state = CLEANUP_STATE;
  1513. else if (mMarks_mask & MARK_SHUTDOWN)
  1514. pending_state = CLEANUP_STATE;
  1515. else if (state_expired())
  1516. pending_state = CLEANUP_STATE;
  1517. break;
  1518. case CLEANUP_STATE:
  1519. if ((mMarks_mask & MARK_INTERRUPT_CLEANUP) || cleanup_over())
  1520. pending_state = DONE_STATE;
  1521. break;
  1522. }
  1523. if (mSpell_state != pending_state)
  1524. change_state_s(pending_state);
  1525. if (mSpell_state == INACTIVE_STATE)
  1526. return;
  1527. //--------------------------//
  1528. // sample the constraints
  1529. constraint_mgr->sample(TickSec, Platform::getVirtualMilliseconds());
  1530. for (S32 i = 0; i < NUM_PHRASES; i++)
  1531. if (mPhrases[i])
  1532. mPhrases[i]->update(TickSec, mSpell_elapsed);
  1533. if (mMissile_is_armed)
  1534. {
  1535. launch_missile_s();
  1536. mMissile_is_armed = false;
  1537. }
  1538. }
  1539. void afxMagicSpell::change_state_s(U8 pending_state)
  1540. {
  1541. if (mSpell_state == pending_state)
  1542. return;
  1543. // LEAVING THIS STATE
  1544. switch (mSpell_state)
  1545. {
  1546. case INACTIVE_STATE:
  1547. break;
  1548. case CASTING_STATE:
  1549. leave_casting_state_s();
  1550. break;
  1551. case DELIVERY_STATE:
  1552. leave_delivery_state_s();
  1553. break;
  1554. case LINGER_STATE:
  1555. leave_linger_state_s();
  1556. break;
  1557. case CLEANUP_STATE:
  1558. break;
  1559. case DONE_STATE:
  1560. break;
  1561. }
  1562. mSpell_state = pending_state;
  1563. // ENTERING THIS STATE
  1564. switch (pending_state)
  1565. {
  1566. case INACTIVE_STATE:
  1567. break;
  1568. case CASTING_STATE:
  1569. enter_casting_state_s();
  1570. break;
  1571. case DELIVERY_STATE:
  1572. enter_delivery_state_s();
  1573. break;
  1574. case LINGER_STATE:
  1575. enter_linger_state_s();
  1576. break;
  1577. case CLEANUP_STATE:
  1578. break;
  1579. case DONE_STATE:
  1580. enter_done_state_s();
  1581. break;
  1582. }
  1583. }
  1584. void afxMagicSpell::enter_done_state_s()
  1585. {
  1586. postSpellEvent(DEACTIVATE_EVENT);
  1587. if (mMarks_mask & MARK_INTERRUPTS)
  1588. {
  1589. Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + 500);
  1590. }
  1591. else
  1592. {
  1593. F32 done_time = mSpell_elapsed;
  1594. for (S32 i = 0; i < NUM_PHRASES; i++)
  1595. {
  1596. if (mPhrases[i])
  1597. {
  1598. F32 phrase_done;
  1599. if (mPhrases[i]->willStop() && mPhrases[i]->isInfinite())
  1600. phrase_done = mSpell_elapsed + mPhrases[i]->calcAfterLife();
  1601. else
  1602. phrase_done = mPhrases[i]->calcDoneTime();
  1603. if (phrase_done > done_time)
  1604. done_time = phrase_done;
  1605. }
  1606. }
  1607. F32 time_left = done_time - mSpell_elapsed;
  1608. if (time_left < 0)
  1609. time_left = 0;
  1610. Sim::postEvent(this, new ObjectDeleteEvent, Sim::getCurrentTime() + time_left*1000 + 500);
  1611. }
  1612. // CALL SCRIPT afxMagicSpellData::onDeactivate(%spell)
  1613. mDatablock->onDeactivate_callback(this);
  1614. }
  1615. void afxMagicSpell::enter_casting_state_s()
  1616. {
  1617. // note - onActivate() is called in cast_spell() instead of here to make sure any
  1618. // new time-factor settings resolve before they are sent off to the clients.
  1619. // stamp constraint-mgr starting time and reset spell timer
  1620. constraint_mgr->setStartTime(Platform::getVirtualMilliseconds());
  1621. mSpell_elapsed = 0;
  1622. setup_dynamic_constraints();
  1623. // start casting effects
  1624. setup_casting_fx();
  1625. if (mPhrases[CASTING_PHRASE])
  1626. mPhrases[CASTING_PHRASE]->start(mSpell_elapsed, mSpell_elapsed);
  1627. // initialize missile
  1628. if (mMissile_db)
  1629. {
  1630. mMissile_db = mMissile_db->cloneAndPerformSubstitutions(this, ranking);
  1631. init_missile_s(mMissile_db);
  1632. }
  1633. }
  1634. void afxMagicSpell::leave_casting_state_s()
  1635. {
  1636. if (mPhrases[CASTING_PHRASE])
  1637. {
  1638. if (mMarks_mask & MARK_INTERRUPT_CASTING)
  1639. {
  1640. //Con::printf("INTERRUPT CASTING (S)");
  1641. mPhrases[CASTING_PHRASE]->interrupt(mSpell_elapsed);
  1642. }
  1643. else
  1644. {
  1645. //Con::printf("LEAVING CASTING (S)");
  1646. mPhrases[CASTING_PHRASE]->stop(mSpell_elapsed);
  1647. }
  1648. }
  1649. if (mMarks_mask & MARK_INTERRUPT_CASTING)
  1650. {
  1651. // CALL SCRIPT afxMagicSpellData::onInterrupt(%spell, %caster)
  1652. mDatablock->onInterrupt_callback(this, mCaster);
  1653. }
  1654. }
  1655. void afxMagicSpell::enter_delivery_state_s()
  1656. {
  1657. // CALL SCRIPT afxMagicSpellData::onLaunch(%spell, %caster, %target, %missile)
  1658. mDatablock->onLaunch_callback(this, mCaster, mTarget, mMissile);
  1659. if (mDatablock->mLaunch_on_server_signal)
  1660. postSpellEvent(LAUNCH_EVENT);
  1661. mMissile_is_armed = true;
  1662. // start launch effects
  1663. setup_launch_fx();
  1664. if (mPhrases[LAUNCH_PHRASE])
  1665. mPhrases[LAUNCH_PHRASE]->start(mSpell_elapsed, mSpell_elapsed); //START
  1666. // start delivery effects
  1667. setup_delivery_fx();
  1668. if (mPhrases[DELIVERY_PHRASE])
  1669. mPhrases[DELIVERY_PHRASE]->start(mSpell_elapsed, mSpell_elapsed); //START
  1670. }
  1671. void afxMagicSpell::leave_delivery_state_s()
  1672. {
  1673. if (mPhrases[DELIVERY_PHRASE])
  1674. {
  1675. if (mMarks_mask & MARK_INTERRUPT_DELIVERY)
  1676. {
  1677. //Con::printf("INTERRUPT DELIVERY (S)");
  1678. mPhrases[DELIVERY_PHRASE]->interrupt(mSpell_elapsed);
  1679. }
  1680. else
  1681. {
  1682. //Con::printf("LEAVING DELIVERY (S)");
  1683. mPhrases[DELIVERY_PHRASE]->stop(mSpell_elapsed);
  1684. }
  1685. }
  1686. if (!mMissile && !(mMarks_mask & MARK_IMPACT))
  1687. {
  1688. if (mTarget)
  1689. {
  1690. Point3F p = afxMagicSpell::getShapeImpactPos(mTarget);
  1691. Point3F n = Point3F(0,0,1);
  1692. impactNotify(p, n, mTarget);
  1693. }
  1694. else
  1695. {
  1696. Point3F p = Point3F(0,0,0);
  1697. Point3F n = Point3F(0,0,1);
  1698. impactNotify(p, n, 0);
  1699. }
  1700. }
  1701. }
  1702. void afxMagicSpell::enter_linger_state_s()
  1703. {
  1704. if (mImpacted_obj)
  1705. {
  1706. mImpacted_cons_id = constraint_mgr->setReferenceObject(IMPACTED_OBJECT_CONS, mImpacted_obj);
  1707. #if defined(AFX_CAP_SCOPE_TRACKING)
  1708. if (mImpacted_obj->isScopeable())
  1709. constraint_mgr->addScopeableObject(mImpacted_obj);
  1710. #endif
  1711. }
  1712. else
  1713. constraint_mgr->setReferencePoint(IMPACTED_OBJECT_CONS, mImpact_pos, mImpact_norm);
  1714. constraint_mgr->setReferencePoint(IMPACT_POINT_CONS, mImpact_pos, mImpact_norm);
  1715. constraint_mgr->setReferenceObject(MISSILE_CONS, 0);
  1716. // start impact effects
  1717. setup_impact_fx();
  1718. if (mPhrases[IMPACT_PHRASE])
  1719. mPhrases[IMPACT_PHRASE]->start(mSpell_elapsed, mSpell_elapsed); //START
  1720. // start linger effects
  1721. setup_linger_fx();
  1722. if (mPhrases[LINGER_PHRASE])
  1723. mPhrases[LINGER_PHRASE]->start(mSpell_elapsed, mSpell_elapsed); //START
  1724. #if 0 // code temporarily replaced with old callback technique in order to avoid engine bug.
  1725. // CALL SCRIPT afxMagicSpellData::onImpact(%spell, %caster, %impactedObj, %impactedPos, %impactedNorm)
  1726. mDatablock->onImpact_callback(this, mCaster, mImpacted_obj, mImpact_pos, mImpact_norm);
  1727. #else
  1728. char pos_buf[128];
  1729. dSprintf(pos_buf, sizeof(pos_buf), "%g %g %g", mImpact_pos.x, mImpact_pos.y, mImpact_pos.z);
  1730. char norm_buf[128];
  1731. dSprintf(norm_buf, sizeof(norm_buf), "%g %g %g", mImpact_norm.x, mImpact_norm.y, mImpact_norm.z);
  1732. Con::executef(mExeblock, "onImpact", getIdString(),
  1733. (mCaster) ? mCaster->getIdString(): "",
  1734. (mImpacted_obj) ? mImpacted_obj->getIdString(): "",
  1735. pos_buf, norm_buf);
  1736. #endif
  1737. }
  1738. void afxMagicSpell::leave_linger_state_s()
  1739. {
  1740. if (mPhrases[LINGER_PHRASE])
  1741. {
  1742. if (mMarks_mask & MARK_INTERRUPT_LINGER)
  1743. {
  1744. //Con::printf("INTERRUPT LINGER (S)");
  1745. mPhrases[LINGER_PHRASE]->interrupt(mSpell_elapsed);
  1746. }
  1747. else
  1748. {
  1749. //Con::printf("LEAVING LINGER (S)");
  1750. mPhrases[LINGER_PHRASE]->stop(mSpell_elapsed);
  1751. }
  1752. }
  1753. }
  1754. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  1755. // private
  1756. void afxMagicSpell::process_client(F32 dt)
  1757. {
  1758. mSpell_elapsed += dt; //SPELL_ELAPSED
  1759. U8 pending_state = mSpell_state;
  1760. // check for state changes
  1761. switch (mSpell_state)
  1762. {
  1763. case INACTIVE_STATE:
  1764. if (mMarks_mask & MARK_ACTIVATE)
  1765. pending_state = CASTING_STATE;
  1766. break;
  1767. case CASTING_STATE:
  1768. if (mMarks_mask & MARK_INTERRUPT_CASTING)
  1769. pending_state = CLEANUP_STATE;
  1770. else if (mMarks_mask & MARK_END_CASTING)
  1771. pending_state = DELIVERY_STATE;
  1772. else if (mDatablock->mLaunch_on_server_signal)
  1773. {
  1774. if (mMarks_mask & MARK_LAUNCH)
  1775. pending_state = DELIVERY_STATE;
  1776. }
  1777. else
  1778. {
  1779. if (state_expired())
  1780. pending_state = DELIVERY_STATE;
  1781. }
  1782. break;
  1783. case DELIVERY_STATE:
  1784. if (mMarks_mask & MARK_INTERRUPT_DELIVERY)
  1785. pending_state = CLEANUP_STATE;
  1786. else if (mMarks_mask & MARK_END_DELIVERY)
  1787. pending_state = LINGER_STATE;
  1788. else if (mMarks_mask & MARK_IMPACT)
  1789. pending_state = LINGER_STATE;
  1790. else
  1791. state_expired();
  1792. break;
  1793. case LINGER_STATE:
  1794. if (mMarks_mask & MARK_INTERRUPT_LINGER)
  1795. pending_state = CLEANUP_STATE;
  1796. else if (mMarks_mask & MARK_END_LINGER)
  1797. pending_state = CLEANUP_STATE;
  1798. else if (mMarks_mask & MARK_SHUTDOWN)
  1799. pending_state = CLEANUP_STATE;
  1800. else if (state_expired())
  1801. pending_state = CLEANUP_STATE;
  1802. break;
  1803. case CLEANUP_STATE:
  1804. if ((mMarks_mask & MARK_INTERRUPT_CLEANUP) || cleanup_over())
  1805. pending_state = DONE_STATE;
  1806. break;
  1807. }
  1808. if (mSpell_state != pending_state)
  1809. change_state_c(pending_state);
  1810. if (mSpell_state == INACTIVE_STATE)
  1811. return;
  1812. //--------------------------//
  1813. // update the listener constraint position
  1814. if (!mListener_cons_id.undefined())
  1815. {
  1816. Point3F listener_pos;
  1817. listener_pos = SFX->getListener().getTransform().getPosition();
  1818. constraint_mgr->setReferencePoint(mListener_cons_id, listener_pos);
  1819. }
  1820. // find local camera position
  1821. Point3F cam_pos;
  1822. SceneObject* current_cam = get_camera(&cam_pos);
  1823. // detect camera changes
  1824. if (!mCamera_cons_id.undefined() && current_cam != mCamera_cons_obj)
  1825. {
  1826. constraint_mgr->setReferenceObject(mCamera_cons_id, current_cam);
  1827. mCamera_cons_obj = current_cam;
  1828. }
  1829. // sample the constraints
  1830. constraint_mgr->sample(dt, Platform::getVirtualMilliseconds(), (current_cam) ? &cam_pos : 0);
  1831. // update active effects lists
  1832. for (S32 i = 0; i < NUM_PHRASES; i++)
  1833. if (mPhrases[i])
  1834. mPhrases[i]->update(dt, mSpell_elapsed);
  1835. if (mMissile_is_armed)
  1836. {
  1837. launch_missile_c();
  1838. mMissile_is_armed = false;
  1839. }
  1840. }
  1841. void afxMagicSpell::change_state_c(U8 pending_state)
  1842. {
  1843. if (mSpell_state == pending_state)
  1844. return;
  1845. // LEAVING THIS STATE
  1846. switch (mSpell_state)
  1847. {
  1848. case INACTIVE_STATE:
  1849. break;
  1850. case CASTING_STATE:
  1851. leave_casting_state_c();
  1852. break;
  1853. case DELIVERY_STATE:
  1854. leave_delivery_state_c();
  1855. break;
  1856. case LINGER_STATE:
  1857. leave_linger_state_c();
  1858. break;
  1859. case CLEANUP_STATE:
  1860. break;
  1861. case DONE_STATE:
  1862. break;
  1863. }
  1864. mSpell_state = pending_state;
  1865. // ENTERING THIS STATE
  1866. switch (pending_state)
  1867. {
  1868. case INACTIVE_STATE:
  1869. break;
  1870. case CASTING_STATE:
  1871. enter_casting_state_c(mSpell_elapsed);
  1872. break;
  1873. case DELIVERY_STATE:
  1874. enter_delivery_state_c(mSpell_elapsed);
  1875. break;
  1876. case LINGER_STATE:
  1877. enter_linger_state_c(mSpell_elapsed);
  1878. break;
  1879. case CLEANUP_STATE:
  1880. break;
  1881. case DONE_STATE:
  1882. break;
  1883. }
  1884. }
  1885. void afxMagicSpell::enter_casting_state_c(F32 starttime)
  1886. {
  1887. // stamp constraint-mgr starting time
  1888. constraint_mgr->setStartTime(Platform::getVirtualMilliseconds() - (U32)(mSpell_elapsed *1000));
  1889. //spell_elapsed = 0; //SPELL_ELAPSED
  1890. setup_dynamic_constraints();
  1891. // start casting effects and castbar
  1892. setup_casting_fx();
  1893. if (mPhrases[CASTING_PHRASE])
  1894. mPhrases[CASTING_PHRASE]->start(starttime, mSpell_elapsed); //START
  1895. // initialize missile
  1896. if (mMissile_db)
  1897. {
  1898. mMissile_db = mMissile_db->cloneAndPerformSubstitutions(this, ranking);
  1899. init_missile_c(mMissile_db);
  1900. }
  1901. }
  1902. void afxMagicSpell::leave_casting_state_c()
  1903. {
  1904. if (mPhrases[CASTING_PHRASE])
  1905. {
  1906. if (mMarks_mask & MARK_INTERRUPT_CASTING)
  1907. {
  1908. //Con::printf("INTERRUPT CASTING (C)");
  1909. mPhrases[CASTING_PHRASE]->interrupt(mSpell_elapsed);
  1910. }
  1911. else
  1912. {
  1913. //Con::printf("LEAVING CASTING (C)");
  1914. mPhrases[CASTING_PHRASE]->stop(mSpell_elapsed);
  1915. }
  1916. }
  1917. }
  1918. void afxMagicSpell::enter_delivery_state_c(F32 starttime)
  1919. {
  1920. mMissile_is_armed = true;
  1921. setup_launch_fx();
  1922. if (mPhrases[LAUNCH_PHRASE])
  1923. mPhrases[LAUNCH_PHRASE]->start(starttime, mSpell_elapsed); //START
  1924. setup_delivery_fx();
  1925. if (mPhrases[DELIVERY_PHRASE])
  1926. mPhrases[DELIVERY_PHRASE]->start(starttime, mSpell_elapsed); //START
  1927. }
  1928. void afxMagicSpell::leave_delivery_state_c()
  1929. {
  1930. if (mMissile)
  1931. {
  1932. clearNotify(mMissile);
  1933. mMissile->deleteObject();
  1934. mMissile = NULL;
  1935. }
  1936. if (mPhrases[DELIVERY_PHRASE])
  1937. {
  1938. if (mMarks_mask & MARK_INTERRUPT_DELIVERY)
  1939. {
  1940. //Con::printf("INTERRUPT DELIVERY (C)");
  1941. mPhrases[DELIVERY_PHRASE]->interrupt(mSpell_elapsed);
  1942. }
  1943. else
  1944. {
  1945. //Con::printf("LEAVING DELIVERY (C)");
  1946. mPhrases[DELIVERY_PHRASE]->stop(mSpell_elapsed);
  1947. }
  1948. }
  1949. }
  1950. void afxMagicSpell::enter_linger_state_c(F32 starttime)
  1951. {
  1952. if (mImpacted_obj)
  1953. mImpacted_cons_id = constraint_mgr->setReferenceObject(IMPACTED_OBJECT_CONS, mImpacted_obj);
  1954. else if (mImpacted_scope_id > 0)
  1955. mImpacted_cons_id = constraint_mgr->setReferenceObjectByScopeId(IMPACTED_OBJECT_CONS, mImpacted_scope_id, mImpacted_is_shape);
  1956. else
  1957. constraint_mgr->setReferencePoint(IMPACTED_OBJECT_CONS, mImpact_pos, mImpact_norm);
  1958. constraint_mgr->setReferencePoint(IMPACT_POINT_CONS, mImpact_pos, mImpact_norm);
  1959. constraint_mgr->setReferenceObject(MISSILE_CONS, 0);
  1960. setup_impact_fx();
  1961. if (mPhrases[IMPACT_PHRASE])
  1962. mPhrases[IMPACT_PHRASE]->start(starttime, mSpell_elapsed); //START
  1963. setup_linger_fx();
  1964. if (mPhrases[LINGER_PHRASE])
  1965. {
  1966. mPhrases[LINGER_PHRASE]->start(starttime, mSpell_elapsed); //START
  1967. }
  1968. }
  1969. void afxMagicSpell::leave_linger_state_c()
  1970. {
  1971. if (mPhrases[LINGER_PHRASE])
  1972. {
  1973. if (mMarks_mask & MARK_INTERRUPT_LINGER)
  1974. {
  1975. //Con::printf("INTERRUPT LINGER (C)");
  1976. mPhrases[LINGER_PHRASE]->interrupt(mSpell_elapsed);
  1977. }
  1978. else
  1979. {
  1980. //Con::printf("LEAVING LINGER (C)");
  1981. mPhrases[LINGER_PHRASE]->stop(mSpell_elapsed);
  1982. }
  1983. }
  1984. }
  1985. void afxMagicSpell::sync_client(U16 marks, U8 state, F32 elapsed, F32 spell_elapsed)
  1986. {
  1987. //Con::printf("SYNC marks=%d old_state=%s state=%s elapsed=%g spell_elapsed=%g",
  1988. // marks, name_from_state(spell_state), name_from_state(state), elapsed,
  1989. // spell_elapsed);
  1990. if (mSpell_state != LATE_STATE)
  1991. return;
  1992. mMarks_mask = marks;
  1993. // don't want to be started on late zoning clients
  1994. if (!mDatablock->exec_on_new_clients)
  1995. {
  1996. mSpell_state = DONE_STATE;
  1997. }
  1998. // it looks like we're ghosting pretty late and
  1999. // should just return to the inactive state.
  2000. else if ((marks & (MARK_INTERRUPTS | MARK_DEACTIVATE | MARK_SHUTDOWN)) ||
  2001. (((marks & MARK_IMPACT) || (marks & MARK_END_DELIVERY)) && (marks & MARK_END_LINGER)))
  2002. {
  2003. mSpell_state = DONE_STATE;
  2004. }
  2005. // it looks like we should be in the linger state.
  2006. else if ((marks & MARK_IMPACT) ||
  2007. (((marks & MARK_LAUNCH) || (marks & MARK_END_CASTING)) && (marks & MARK_END_DELIVERY)))
  2008. {
  2009. mSpell_state = LINGER_STATE;
  2010. mSpell_elapsed = spell_elapsed;
  2011. enter_linger_state_c(spell_elapsed-elapsed);
  2012. }
  2013. // it looks like we should be in the delivery state.
  2014. else if ((marks & MARK_LAUNCH) || (marks & MARK_END_CASTING))
  2015. {
  2016. mSpell_state = DELIVERY_STATE;
  2017. mSpell_elapsed = spell_elapsed;
  2018. enter_delivery_state_c(spell_elapsed-elapsed);
  2019. }
  2020. // it looks like we should be in the casting state.
  2021. else if (marks & MARK_ACTIVATE)
  2022. {
  2023. mSpell_state = CASTING_STATE; //SPELL_STATE
  2024. mSpell_elapsed = spell_elapsed;
  2025. enter_casting_state_c(spell_elapsed-elapsed);
  2026. }
  2027. }
  2028. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2029. // public:
  2030. void afxMagicSpell::postSpellEvent(U8 event)
  2031. {
  2032. setMaskBits(StateEventMask);
  2033. switch (event)
  2034. {
  2035. case ACTIVATE_EVENT:
  2036. mMarks_mask |= MARK_ACTIVATE;
  2037. break;
  2038. case LAUNCH_EVENT:
  2039. mMarks_mask |= MARK_LAUNCH;
  2040. setMaskBits(LaunchEventMask);
  2041. break;
  2042. case IMPACT_EVENT:
  2043. mMarks_mask |= MARK_IMPACT;
  2044. setMaskBits(ImpactEventMask);
  2045. break;
  2046. case SHUTDOWN_EVENT:
  2047. mMarks_mask |= MARK_SHUTDOWN;
  2048. break;
  2049. case DEACTIVATE_EVENT:
  2050. mMarks_mask |= MARK_DEACTIVATE;
  2051. break;
  2052. case INTERRUPT_PHASE_EVENT:
  2053. if (mSpell_state == CASTING_STATE)
  2054. mMarks_mask |= MARK_END_CASTING;
  2055. else if (mSpell_state == DELIVERY_STATE)
  2056. mMarks_mask |= MARK_END_DELIVERY;
  2057. else if (mSpell_state == LINGER_STATE)
  2058. mMarks_mask |= MARK_END_LINGER;
  2059. break;
  2060. case INTERRUPT_SPELL_EVENT:
  2061. if (mSpell_state == CASTING_STATE)
  2062. mMarks_mask |= MARK_INTERRUPT_CASTING;
  2063. else if (mSpell_state == DELIVERY_STATE)
  2064. mMarks_mask |= MARK_INTERRUPT_DELIVERY;
  2065. else if (mSpell_state == LINGER_STATE)
  2066. mMarks_mask |= MARK_INTERRUPT_LINGER;
  2067. else if (mSpell_state == CLEANUP_STATE)
  2068. mMarks_mask |= MARK_INTERRUPT_CLEANUP;
  2069. break;
  2070. }
  2071. }
  2072. void afxMagicSpell::resolveTimeFactors()
  2073. {
  2074. for (S32 i = 0; i < NUM_PHRASES; i++)
  2075. mTfactors[i] *= mOverall_time_factor;
  2076. }
  2077. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2078. void afxMagicSpell::finish_startup()
  2079. {
  2080. #if !defined(BROKEN_POINT_IN_WATER)
  2081. // test if caster is in water
  2082. if (mCaster)
  2083. {
  2084. Point3F pos = mCaster->getPosition();
  2085. if (mCaster->pointInWater(pos))
  2086. exec_conds_mask |= CASTER_IN_WATER;
  2087. }
  2088. #endif
  2089. resolveTimeFactors();
  2090. init_constraints();
  2091. init_scoping();
  2092. postSpellEvent(afxMagicSpell::ACTIVATE_EVENT);
  2093. }
  2094. // static
  2095. afxMagicSpell*
  2096. afxMagicSpell::cast_spell(afxMagicSpellData* datablock, ShapeBase* caster, SceneObject* target, SimObject* extra)
  2097. {
  2098. AssertFatal(datablock != NULL, "Datablock is missing.");
  2099. AssertFatal(caster != NULL, "Caster is missing.");
  2100. afxMagicSpellData* exeblock = datablock;
  2101. SimObject* param_holder = new SimObject();
  2102. if (!param_holder->registerObject())
  2103. {
  2104. Con::errorf("afxMagicSpell: failed to register parameter object.");
  2105. delete param_holder;
  2106. return 0;
  2107. }
  2108. param_holder->assignDynamicFieldsFrom(datablock, arcaneFX::sParameterFieldPrefix);
  2109. if (extra)
  2110. {
  2111. // copy dynamic fields from the extra object to the param holder
  2112. param_holder->assignDynamicFieldsFrom(extra, arcaneFX::sParameterFieldPrefix);
  2113. }
  2114. if (datablock->isMethod("onPreactivate"))
  2115. {
  2116. // CALL SCRIPT afxMagicSpellData::onPreactivate(%params, %caster, %target, %extra)
  2117. bool result = datablock->onPreactivate_callback(param_holder, caster, target, extra);
  2118. if (!result)
  2119. {
  2120. #if defined(TORQUE_DEBUG)
  2121. Con::warnf("afxMagicSpell: onPreactivate() returned false, spell aborted.");
  2122. #endif
  2123. Sim::postEvent(param_holder, new ObjectDeleteEvent, Sim::getCurrentTime());
  2124. return 0;
  2125. }
  2126. }
  2127. // make a temp datablock clone if there are substitutions
  2128. if (datablock->getSubstitutionCount() > 0)
  2129. {
  2130. datablock = new afxMagicSpellData(*exeblock, true);
  2131. exeblock->performSubstitutions(datablock, param_holder);
  2132. }
  2133. // create a new spell instance
  2134. afxMagicSpell* spell = new afxMagicSpell(caster, target);
  2135. spell->setDataBlock(datablock);
  2136. spell->mExeblock = exeblock;
  2137. spell->setExtra(extra);
  2138. // copy dynamic fields from the param holder to the spell
  2139. spell->assignDynamicFieldsFrom(param_holder, arcaneFX::sParameterFieldPrefix);
  2140. Sim::postEvent(param_holder, new ObjectDeleteEvent, Sim::getCurrentTime());
  2141. // register
  2142. if (!spell->registerObject())
  2143. {
  2144. Con::errorf("afxMagicSpell: failed to register spell instance.");
  2145. Sim::postEvent(spell, new ObjectDeleteEvent, Sim::getCurrentTime());
  2146. return 0;
  2147. }
  2148. registerForCleanup(spell);
  2149. spell->activate();
  2150. return spell;
  2151. }
  2152. IMPLEMENT_GLOBAL_CALLBACK( DisplayScreenMessage, void, (GameConnection* client, const char* message), (client, message),
  2153. "Called to display a screen message.\n"
  2154. "@ingroup AFX\n" );
  2155. void afxMagicSpell::displayScreenMessage(ShapeBase* caster, const char* msg)
  2156. {
  2157. if (!caster)
  2158. return;
  2159. GameConnection* client = caster->getControllingClient();
  2160. if (client)
  2161. DisplayScreenMessage_callback(client, msg);
  2162. }
  2163. Point3F afxMagicSpell::getShapeImpactPos(SceneObject* obj)
  2164. {
  2165. Point3F pos = obj->getRenderPosition();
  2166. if (obj->getTypeMask() & CorpseObjectType)
  2167. pos.z += 0.5f;
  2168. else
  2169. pos.z += (obj->getObjBox().len_z()/2);
  2170. return pos;
  2171. }
  2172. void afxMagicSpell::restoreObject(SceneObject* obj)
  2173. {
  2174. if (obj->getScopeId() == mCaster_scope_id && dynamic_cast<ShapeBase*>(obj) != NULL)
  2175. {
  2176. mCaster_scope_id = 0;
  2177. mCaster = (ShapeBase*)obj;
  2178. mCaster_field = mCaster;
  2179. deleteNotify(mCaster);
  2180. processAfter(mCaster);
  2181. }
  2182. if (obj->getScopeId() == mTarget_scope_id)
  2183. {
  2184. mTarget_scope_id = 0;
  2185. mTarget = obj;
  2186. mTarget_field = mTarget;
  2187. deleteNotify(mTarget);
  2188. }
  2189. if (obj->getScopeId() == mImpacted_scope_id)
  2190. {
  2191. mImpacted_scope_id = 0;
  2192. mImpacted_obj = obj;
  2193. deleteNotify(mImpacted_obj);
  2194. }
  2195. }
  2196. bool afxMagicSpell::activationCallInit(bool postponed)
  2197. {
  2198. if (postponed && (!started_with_newop || !postpone_activation))
  2199. {
  2200. Con::errorf("afxMagicSpell::activate() -- activate() is only required when creating a spell with the \"new\" operator "
  2201. "and the postponeActivation field is set to \"true\".");
  2202. return false;
  2203. }
  2204. if (!mCaster_field)
  2205. {
  2206. Con::errorf("afxMagicSpell::activate() -- no spellcaster specified.");
  2207. return false;
  2208. }
  2209. mCaster = dynamic_cast<ShapeBase*>(mCaster_field);
  2210. if (!mCaster)
  2211. {
  2212. Con::errorf("afxMagicSpell::activate() -- spellcaster is not a ShapeBase derived object.");
  2213. return false;
  2214. }
  2215. if (mTarget_field)
  2216. {
  2217. mTarget = dynamic_cast<SceneObject*>(mTarget_field);
  2218. if (!mTarget)
  2219. Con::warnf("afxMagicSpell::activate() -- target is not a SceneObject derived object.");
  2220. }
  2221. return true;
  2222. }
  2223. void afxMagicSpell::activate()
  2224. {
  2225. // separating the final part of startup allows the calling script
  2226. // to make certain types of calls on the returned spell that need
  2227. // to happen prior to object registration.
  2228. Sim::postEvent(this, new SpellFinishStartupEvent, Sim::getCurrentTime());
  2229. mCaster_field = mCaster;
  2230. mTarget_field = mTarget;
  2231. // CALL SCRIPT afxMagicSpellData::onActivate(%spell, %caster, %target)
  2232. mDatablock->onActivate_callback(this, mCaster, mTarget);
  2233. }
  2234. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  2235. // console methods/functions
  2236. DefineEngineMethod(afxMagicSpell, getCaster, S32, (),,
  2237. "Returns ID of the spell's caster object.\n\n"
  2238. "@ingroup AFX")
  2239. {
  2240. ShapeBase* caster = object->getCaster();
  2241. return (caster) ? caster->getId() : -1;
  2242. }
  2243. DefineEngineMethod(afxMagicSpell, getTarget, S32, (),,
  2244. "Returns ID of the spell's target object.\n\n"
  2245. "@ingroup AFX")
  2246. {
  2247. SceneObject* target = object->getTarget();
  2248. return (target) ? target->getId() : -1;
  2249. }
  2250. DefineEngineMethod(afxMagicSpell, getMissile, S32, (),,
  2251. "Returns ID of the spell's magic-missile object.\n\n"
  2252. "@ingroup AFX")
  2253. {
  2254. afxMagicMissile* missile = object->getMissile();
  2255. return (missile) ? missile->getId() : -1;
  2256. }
  2257. DefineEngineMethod(afxMagicSpell, getImpactedObject, S32, (),,
  2258. "Returns ID of impacted-object for the spell.\n\n"
  2259. "@ingroup AFX")
  2260. {
  2261. SceneObject* imp_obj = object->getImpactedObject();
  2262. return (imp_obj) ? imp_obj->getId() : -1;
  2263. }
  2264. DefineEngineStringlyVariadicMethod(afxMagicSpell, setTimeFactor, void, 3, 4, "(F32 factor) or (string phase, F32 factor)"
  2265. "Sets the time-factor for the spell, either overall or for a specific phrase.\n\n"
  2266. "@ingroup AFX")
  2267. {
  2268. if (argc == 3)
  2269. object->setTimeFactor(argv[2].getFloat());
  2270. else
  2271. {
  2272. F32 value = argv[3].getFloat();
  2273. if (dStricmp(argv[2], "overall") == 0)
  2274. object->setTimeFactor(dAtof(argv[3]));
  2275. else if (dStricmp(argv[2], "casting") == 0)
  2276. object->setTimeFactor(afxMagicSpell::CASTING_PHRASE, value);
  2277. else if (dStricmp(argv[2], "launch") == 0)
  2278. object->setTimeFactor(afxMagicSpell::LAUNCH_PHRASE, value);
  2279. else if (dStricmp(argv[2], "delivery") == 0)
  2280. object->setTimeFactor(afxMagicSpell::DELIVERY_PHRASE, value);
  2281. else if (dStricmp(argv[2], "impact") == 0)
  2282. object->setTimeFactor(afxMagicSpell::IMPACT_PHRASE, value);
  2283. else if (dStricmp(argv[2], "linger") == 0)
  2284. object->setTimeFactor(afxMagicSpell::LINGER_PHRASE, value);
  2285. else
  2286. Con::errorf("afxMagicSpell::setTimeFactor() -- unknown spell phrase [%s].", argv[2].getString());
  2287. }
  2288. }
  2289. DefineEngineMethod(afxMagicSpell, interruptStage, void, (),,
  2290. "Interrupts the current stage of a magic spell causing it to move onto the next one.\n\n"
  2291. "@ingroup AFX")
  2292. {
  2293. object->postSpellEvent(afxMagicSpell::INTERRUPT_PHASE_EVENT);
  2294. }
  2295. DefineEngineMethod(afxMagicSpell, interrupt, void, (),,
  2296. "Interrupts and deletes a running magic spell.\n\n"
  2297. "@ingroup AFX")
  2298. {
  2299. object->postSpellEvent(afxMagicSpell::INTERRUPT_SPELL_EVENT);
  2300. }
  2301. DefineEngineMethod(afxMagicSpell, activate, void, (),,
  2302. "Activates a magic spell that was started with postponeActivation=true.\n\n"
  2303. "@ingroup AFX")
  2304. {
  2305. if (object->activationCallInit(true))
  2306. object->activate();
  2307. }
  2308. DefineEngineFunction(castSpell, S32, (afxMagicSpellData* datablock, ShapeBase* caster, SceneObject* target, SimObject* extra),
  2309. (nullAsType<afxMagicSpellData*>(), nullAsType<ShapeBase*>(), nullAsType<SceneObject*>(), nullAsType<SimObject*>()),
  2310. "Instantiates the magic spell defined by datablock and cast by caster.\n\n"
  2311. "@ingroup AFX")
  2312. {
  2313. if (!datablock)
  2314. {
  2315. Con::errorf("castSpell() -- missing valid spell datablock.");
  2316. return 0;
  2317. }
  2318. if (!caster)
  2319. {
  2320. Con::errorf("castSpell() -- missing valid spellcaster.");
  2321. return 0;
  2322. }
  2323. // target is optional (depends on spell)
  2324. // note -- we must examine all arguments prior to calling cast_spell because
  2325. // it calls Con::executef() which will overwrite the argument array.
  2326. afxMagicSpell* spell = afxMagicSpell::cast_spell(datablock, caster, target, extra);
  2327. return (spell) ? spell->getId() : 0;
  2328. }
  2329. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//