afxMagicSpell.cpp 76 KB

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