explosion.cpp
Engine/source/T3D/fx/explosion.cpp
Public Defines
define
MaxLightRadius() 20
Public Variables
sgRandom (0xdeadbeef)
Public Functions
ConsoleDocClass(Explosion , "@brief The emitter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an explosion effect, with properties defined by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "<a href="/coding/class/classexplosiondata/">ExplosionData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" "The object will initiate the explosion effects automatically after being " "added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>(GrenadeSubExplosion)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " offset=0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[0]=GrenadeExpSparkEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " lightStartRadius=4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndRadius=0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartColor=\"0.9 0.7 0.7\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndColor = \"0.9 0.7 0.7\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartBrightness = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndBrightness = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>( GrenadeLauncherExplosion )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " soundProfile = GrenadeLauncherExplosionSound;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lifeTimeMS = 400; // Quick flash, short burn, and moderate <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dispersal\n\n</a>" " // Volume <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">particles\n</a>" " particleEmitter = GrenadeExpFireEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " particleDensity = 75;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " particleRadius = 2.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Point <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emission\n</a>" " emitter[0] = GrenadeExpDustEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[1] = GrenadeExpSparksEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[2] = GrenadeExpSmokeEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Sub explosion <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects\n</a>" " subExplosion[0] = GrenadeSubExplosion;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // <a href="/coding/class/classcamera/">Camera</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Shaking\n</a>" " shakeCamera = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeFreq = \"10.0 11.0 9.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeAmp = \"15.0 15.0 15.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeDuration = 1.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeRadius = 20;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Exploding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">debris\n</a>" " debris = GrenadeDebris;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMin = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMax = 60;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNum = 4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNumVariance = 2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocity = 25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocityVariance = 5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " lightStartRadius = 4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndRadius = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartColor = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndColor = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartBrightness = 4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndBrightness = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightNormalOffset = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "function ServerPlayExplosion(%position, %datablock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // Play the given explosion on every <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " // The explosion will be transmitted as an event, not attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> any <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a>(%<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a> = 0; %<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a> < ClientGroup.getCount(); %<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a>++)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " %client = ClientGroup.getObject(%<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a>);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " commandToClient(%client, 'PlayExplosion', %position, %datablock.getId());\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "function clientCmdPlayExplosion(%position, %effectDataBlock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // Play an explosion sent by the server. Make sure this function is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">defined\n</a>" " // on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> (isObject(%effectDataBlock))\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classexplosion/">Explosion</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = %position;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dataBlock = %effectDataBlock;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "// schedule an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion\n</a>" "schedule(1000, 0, ServerPlayExplosion, \"0 0 0\", GrenadeLauncherExplosion);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@endtsexample" )
ConsoleDocClass(ExplosionData , "@brief Defines the attributes of an Explosion: particleEmitters, debris , " "lighting and camera shake <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effects.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )
DefineEngineFunction(calcExplosionCoverage , F32 , (Point3F pos, S32 id, U32 covMask) , "@brief Calculates how much an explosion effects <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> specific <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Use this <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine how much damage <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> objects based on their " "distance from the explosion's center point, and whether the explosion is " "blocked by other <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" " @param pos Center position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" " @param <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> Id of the object of which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coverage.\n</a>" " @param covMask Mask of object types that may block the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" " @return Coverage <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> from 0(not affected by the explosion) <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 1(fully affected)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Get the position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" "% position)
Detailed Description
Public Defines
MaxLightRadius() 20
Public Variables
MRandomLCG sgRandom (0xdeadbeef)
Public Functions
ConsoleDocClass(Explosion , "@brief The emitter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an explosion effect, with properties defined by <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> " "<a href="/coding/class/classexplosiondata/">ExplosionData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" "The object will initiate the explosion effects automatically after being " "added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>(GrenadeSubExplosion)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " offset=0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[0]=GrenadeExpSparkEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " lightStartRadius=4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndRadius=0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartColor=\"0.9 0.7 0.7\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndColor = \"0.9 0.7 0.7\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartBrightness = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndBrightness = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>( GrenadeLauncherExplosion )\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " soundProfile = GrenadeLauncherExplosionSound;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lifeTimeMS = 400; // Quick flash, short burn, and moderate <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">dispersal\n\n</a>" " // Volume <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">particles\n</a>" " particleEmitter = GrenadeExpFireEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " particleDensity = 75;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " particleRadius = 2.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Point <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emission\n</a>" " emitter[0] = GrenadeExpDustEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[1] = GrenadeExpSparksEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " emitter[2] = GrenadeExpSmokeEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Sub explosion <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects\n</a>" " subExplosion[0] = GrenadeSubExplosion;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // <a href="/coding/class/classcamera/">Camera</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Shaking\n</a>" " shakeCamera = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeFreq = \"10.0 11.0 9.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeAmp = \"15.0 15.0 15.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeDuration = 1.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " camShakeRadius = 20;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " // Exploding <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">debris\n</a>" " debris = GrenadeDebris;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMin = 10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMax = 60;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNum = 4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNumVariance = 2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocity = 25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocityVariance = 5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " lightStartRadius = 4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndRadius = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartColor = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndColor = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightStartBrightness = 4.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightEndBrightness = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " lightNormalOffset = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "function ServerPlayExplosion(%position, %datablock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // Play the given explosion on every <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " // The explosion will be transmitted as an event, not attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> any <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a>(%<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a> = 0; %<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a> < ClientGroup.getCount(); %<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a>++)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " %client = ClientGroup.getObject(%<a href="/coding/file/mquat_8cpp/#mquat_8cpp_1ad66b7690eb5b70f95cb7cb584e91c9ea">idx</a>);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " commandToClient(%client, 'PlayExplosion', %position, %datablock.getId());\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "function clientCmdPlayExplosion(%position, %effectDataBlock)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " // Play an explosion sent by the server. Make sure this function is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">defined\n</a>" " // on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n</a>" " <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> (isObject(%effectDataBlock))\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classexplosion/">Explosion</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " {\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position = %position;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " dataBlock = %effectDataBlock;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " };\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " }\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "}\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "// schedule an <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion\n</a>" "schedule(1000, 0, ServerPlayExplosion, \"0 0 0\", GrenadeLauncherExplosion);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@endtsexample" )
ConsoleDocClass(ExplosionData , "@brief Defines the attributes of an Explosion: particleEmitters, debris , " "lighting and camera shake <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effects.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )
DefineEngineFunction(calcExplosionCoverage , F32 , (Point3F pos, S32 id, U32 covMask) , "@brief Calculates how much an explosion effects <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> specific <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "Use this <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> determine how much damage <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> objects based on their " "distance from the explosion's center point, and whether the explosion is " "blocked by other <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" " @param pos Center position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" " @param <a href="/coding/file/win32cursorcontroller_8cpp/#win32cursorcontroller_8cpp_1ab38592509822a5f4674447022cc62efe">id</a> Id of the object of which <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> check <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">coverage.\n</a>" " @param covMask Mask of object types that may block the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" " @return Coverage <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> from 0(not affected by the explosion) <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 1(fully affected)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Get the position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion.\n</a>" "% position)
IMPLEMENT_CO_DATABLOCK_V1(ExplosionData )
IMPLEMENT_CONOBJECT(Explosion )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 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//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "T3D/fx/explosion.h" 31 32#include "core/resourceManager.h" 33#include "console/consoleTypes.h" 34#include "console/typeValidators.h" 35#include "sfx/sfxSystem.h" 36#include "sfx/sfxTrack.h" 37#include "sfx/sfxTypes.h" 38#include "scene/sceneManager.h" 39#include "scene/sceneRenderState.h" 40#include "lighting/lightInfo.h" 41#include "lighting/lightManager.h" 42#include "core/stream/bitStream.h" 43#include "sim/netConnection.h" 44#include "ts/tsShape.h" 45#include "ts/tsShapeInstance.h" 46#include "math/mRandom.h" 47#include "math/mathIO.h" 48#include "math/mathUtils.h" 49#include "T3D/debris.h" 50#include "T3D/gameBase/gameConnection.h" 51#include "T3D/fx/particleEmitter.h" 52#include "T3D/fx/cameraFXMgr.h" 53#include "T3D/debris.h" 54#include "T3D/shapeBase.h" 55#include "T3D/gameBase/gameProcess.h" 56#include "renderInstance/renderPassManager.h" 57#include "console/engineAPI.h" 58 59#include "sfx/sfxProfile.h" 60 61IMPLEMENT_CONOBJECT(Explosion); 62 63ConsoleDocClass( Explosion, 64 "@brief The emitter for an explosion effect, with properties defined by a " 65 "ExplosionData object.\n\n" 66 "@ingroup FX\n" 67 "The object will initiate the explosion effects automatically after being " 68 "added to the simulation.\n" 69 "@tsexample\n" 70 "datablock ExplosionData( GrenadeSubExplosion )\n" 71 "{\n" 72 " offset = 0.25;\n" 73 " emitter[0] = GrenadeExpSparkEmitter;\n\n" 74 " lightStartRadius = 4.0;\n" 75 " lightEndRadius = 0.0;\n" 76 " lightStartColor = \"0.9 0.7 0.7\";\n" 77 " lightEndColor = \"0.9 0.7 0.7\";\n" 78 " lightStartBrightness = 2.0;\n" 79 " lightEndBrightness = 0.0;\n" 80 "};\n\n" 81 "datablock ExplosionData( GrenadeLauncherExplosion )\n" 82 "{\n" 83 " soundProfile = GrenadeLauncherExplosionSound;\n" 84 " lifeTimeMS = 400; // Quick flash, short burn, and moderate dispersal\n\n" 85 " // Volume particles\n" 86 " particleEmitter = GrenadeExpFireEmitter;\n" 87 " particleDensity = 75;\n" 88 " particleRadius = 2.25;\n\n" 89 " // Point emission\n" 90 " emitter[0] = GrenadeExpDustEmitter;\n" 91 " emitter[1] = GrenadeExpSparksEmitter;\n" 92 " emitter[2] = GrenadeExpSmokeEmitter;\n\n" 93 " // Sub explosion objects\n" 94 " subExplosion[0] = GrenadeSubExplosion;\n\n" 95 " // Camera Shaking\n" 96 " shakeCamera = true;\n" 97 " camShakeFreq = \"10.0 11.0 9.0\";\n" 98 " camShakeAmp = \"15.0 15.0 15.0\";\n" 99 " camShakeDuration = 1.5;\n" 100 " camShakeRadius = 20;\n\n" 101 " // Exploding debris\n" 102 " debris = GrenadeDebris;\n" 103 " debrisThetaMin = 10;\n" 104 " debrisThetaMax = 60;\n" 105 " debrisNum = 4;\n" 106 " debrisNumVariance = 2;\n" 107 " debrisVelocity = 25;\n" 108 " debrisVelocityVariance = 5;\n\n" 109 " lightStartRadius = 4.0;\n" 110 " lightEndRadius = 0.0;\n" 111 " lightStartColor = \"1.0 1.0 1.0\";\n" 112 " lightEndColor = \"1.0 1.0 1.0\";\n" 113 " lightStartBrightness = 4.0;\n" 114 " lightEndBrightness = 0.0;\n" 115 " lightNormalOffset = 2.0;\n" 116 "};\n\n" 117 "function ServerPlayExplosion(%position, %datablock)\n" 118 "{\n" 119 " // Play the given explosion on every client.\n" 120 " // The explosion will be transmitted as an event, not attached to any object.\n" 121 " for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n" 122 " {\n" 123 " %client = ClientGroup.getObject(%idx);\n" 124 " commandToClient(%client, 'PlayExplosion', %position, %datablock.getId());\n" 125 " }\n" 126 "}\n\n" 127 "function clientCmdPlayExplosion(%position, %effectDataBlock)\n" 128 "{\n" 129 " // Play an explosion sent by the server. Make sure this function is defined\n" 130 " // on the client.\n" 131 " if (isObject(%effectDataBlock))\n" 132 " {\n" 133 " new Explosion()\n" 134 " {\n" 135 " position = %position;\n" 136 " dataBlock = %effectDataBlock;\n" 137 " };\n" 138 " }\n" 139 "}\n\n" 140 "// schedule an explosion\n" 141 "schedule(1000, 0, ServerPlayExplosion, \"0 0 0\", GrenadeLauncherExplosion);\n" 142 "@endtsexample" 143); 144 145#define MaxLightRadius 20 146 147MRandomLCG sgRandom(0xdeadbeef); 148 149//WLE - Vince - The defaults are bad, the whole point of calling this function\ 150//is to determine the explosion coverage on a object. Why would you want them 151//To call this with a null for the ID? In fact, it just returns a 1f if 152//it can't find the object. Seems useless to me. Cause how can I apply 153//damage to a object that doesn't exist? 154 155//I could possible see a use with passing in a null covMask, but even that 156//sounds flaky because it will be 100 percent if your saying not to take 157//any thing in consideration for coverage. So I'm removing these defaults they are just bad. 158 159DefineEngineFunction(calcExplosionCoverage, F32, (Point3F pos, S32 id, U32 covMask),, 160 "@brief Calculates how much an explosion effects a specific object.\n\n" 161 "Use this to determine how much damage to apply to objects based on their " 162 "distance from the explosion's center point, and whether the explosion is " 163 "blocked by other objects.\n\n" 164 "@param pos Center position of the explosion.\n" 165 "@param id Id of the object of which to check coverage.\n" 166 "@param covMask Mask of object types that may block the explosion.\n" 167 "@return Coverage value from 0 (not affected by the explosion) to 1 (fully affected)\n\n" 168 "@tsexample\n" 169 "// Get the position of the explosion.\n" 170 "%position = %explosion.getPosition();\n\n" 171 "// Set a list of TypeMasks (defined in gameFunctioncs.cpp), seperated by the | character.\n" 172 "%TypeMasks = $TypeMasks::StaticObjectType | $TypeMasks::ItemObjectType\n\n" 173 "// Acquire the damage value from 0.0f - 1.0f.\n" 174 "%coverage = calcExplosionCoverage( %position, %sceneObject, %TypeMasks );\n\n" 175 "// Apply damage to object\n" 176 "%sceneObject.applyDamage( %coverage * 20 );\n" 177 "@endtsexample\n" 178 "@ingroup FX") 179{ 180 Point3F center; 181 182 SceneObject* sceneObject = NULL; 183 if (Sim::findObject(id, sceneObject) == false) { 184 Con::warnf(ConsoleLogEntry::General, "calcExplosionCoverage: couldn't find object: %d", id); 185 return 1.0f; 186 } 187 if (sceneObject->isClientObject() || sceneObject->getContainer() == NULL) { 188 Con::warnf(ConsoleLogEntry::General, "calcExplosionCoverage: object is on the client, or not in the container system"); 189 return 1.0f; 190 } 191 192 sceneObject->getObjBox().getCenter(¢er); 193 center.convolve(sceneObject->getScale()); 194 sceneObject->getTransform().mulP(center); 195 196 RayInfo rayInfo; 197 sceneObject->disableCollision(); 198 if (sceneObject->getContainer()->castRay(pos, center, covMask, &rayInfo) == true) { 199 // Try casting up and then out 200 if (sceneObject->getContainer()->castRay(pos, pos + Point3F(0.0f, 0.0f, 1.0f), covMask, &rayInfo) == false) 201 { 202 if (sceneObject->getContainer()->castRay(pos + Point3F(0.0f, 0.0f, 1.0f), center, covMask, &rayInfo) == false) 203 { 204 sceneObject->enableCollision(); 205 return 1.0f; 206 } 207 } 208 209 sceneObject->enableCollision(); 210 return 0.0f; 211 } else { 212 sceneObject->enableCollision(); 213 return 1.0f; 214 } 215} 216 217//---------------------------------------------------------------------------- 218// 219IMPLEMENT_CO_DATABLOCK_V1(ExplosionData); 220 221ConsoleDocClass( ExplosionData, 222 "@brief Defines the attributes of an Explosion: particleEmitters, debris, " 223 "lighting and camera shake effects.\n" 224 "@ingroup FX\n" 225); 226 227ExplosionData::ExplosionData() 228{ 229 dtsFileName = NULL; 230 particleDensity = 10; 231 particleRadius = 1.0f; 232 233 faceViewer = false; 234 235 soundProfile = NULL; 236 particleEmitter = NULL; 237 particleEmitterId = 0; 238 239 explosionScale.set(1.0f, 1.0f, 1.0f); 240 playSpeed = 1.0f; 241 242 explosionShape = NULL; 243 explosionAnimation = -1; 244 245 dMemset( emitterList, 0, sizeof( emitterList ) ); 246 dMemset( emitterIDList, 0, sizeof( emitterIDList ) ); 247 dMemset( debrisList, 0, sizeof( debrisList ) ); 248 dMemset( debrisIDList, 0, sizeof( debrisIDList ) ); 249 250 debrisThetaMin = 0.0f; 251 debrisThetaMax = 90.0f; 252 debrisPhiMin = 0.0f; 253 debrisPhiMax = 360.0f; 254 debrisNum = 1; 255 debrisNumVariance = 0; 256 debrisVelocity = 2.0f; 257 debrisVelocityVariance = 0.0f; 258 259 dMemset( explosionList, 0, sizeof( explosionList ) ); 260 dMemset( explosionIDList, 0, sizeof( explosionIDList ) ); 261 262 delayMS = 0; 263 delayVariance = 0; 264 lifetimeMS = 1000; 265 lifetimeVariance = 0; 266 offset = 0.0f; 267 268 shakeCamera = false; 269 camShakeFreq.set( 10.0f, 10.0f, 10.0f ); 270 camShakeAmp.set( 1.0f, 1.0f, 1.0f ); 271 camShakeDuration = 1.5f; 272 camShakeRadius = 10.0f; 273 camShakeFalloff = 10.0f; 274 275 for( U32 i=0; i<EC_NUM_TIME_KEYS; i++ ) 276 { 277 times[i] = 1.0f; 278 } 279 times[0] = 0.0f; 280 281 for( U32 j=0; j<EC_NUM_TIME_KEYS; j++ ) 282 { 283 sizes[j].set( 1.0f, 1.0f, 1.0f ); 284 } 285 286 // 287 lightStartRadius = lightEndRadius = 0.0f; 288 lightStartColor.set(1.0f,1.0f,1.0f); 289 lightEndColor.set(1.0f,1.0f,1.0f); 290 lightStartBrightness = 1.0f; 291 lightEndBrightness = 1.0f; 292 lightNormalOffset = 0.1f; 293} 294 295//#define TRACK_EXPLOSION_DATA_CLONES 296 297#ifdef TRACK_EXPLOSION_DATA_CLONES 298static int explosion_data_clones = 0; 299#endif 300 301ExplosionData::ExplosionData(const ExplosionData& other, bool temp_clone) : GameBaseData(other, temp_clone) 302{ 303#ifdef TRACK_EXPLOSION_DATA_CLONES 304 explosion_data_clones++; 305 if (explosion_data_clones == 1) 306 Con::errorf("ExplosionData -- Clones are on the loose!"); 307#endif 308 309 dtsFileName = other.dtsFileName; 310 faceViewer = other.faceViewer; 311 particleDensity = other.particleDensity; 312 particleRadius = other.particleRadius; 313 soundProfile = other.soundProfile; 314 particleEmitter = other.particleEmitter; 315 particleEmitterId = other.particleEmitterId; // -- for pack/unpack of particleEmitter ptr 316 explosionScale = other.explosionScale; 317 playSpeed = other.playSpeed; 318 explosionShape = other.explosionShape; // -- TSShape loaded using dtsFileName 319 explosionAnimation = other.explosionAnimation; // -- from explosionShape sequence "ambient" 320 dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) ); 321 dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs 322 dMemcpy( debrisList, other.debrisList, sizeof( debrisList ) ); 323 dMemcpy( debrisIDList, other.debrisIDList, sizeof( debrisIDList ) ); // -- for pack/unpack of debrisList ptrs 324 debrisThetaMin = other.debrisThetaMin; 325 debrisThetaMax = other.debrisThetaMax; 326 debrisPhiMin = other.debrisPhiMin; 327 debrisPhiMax = other.debrisPhiMax; 328 debrisNum = other.debrisNum; 329 debrisNumVariance = other.debrisNumVariance; 330 debrisVelocity = other.debrisVelocity; 331 debrisVelocityVariance = other.debrisVelocityVariance; 332 dMemcpy( explosionList, other.explosionList, sizeof( explosionList ) ); 333 dMemcpy( explosionIDList, other.explosionIDList, sizeof( explosionIDList ) ); // -- for pack/unpack of explosionList ptrs 334 delayMS = other.delayMS; 335 delayVariance = other.delayVariance; 336 lifetimeMS = other.lifetimeMS; 337 lifetimeVariance = other.lifetimeVariance; 338 offset = other.offset; 339 dMemcpy( sizes, other.times, sizeof( sizes ) ); 340 dMemcpy( times, other.times, sizeof( times ) ); 341 shakeCamera = other.shakeCamera; 342 camShakeFreq = other.camShakeFreq; 343 camShakeAmp = other.camShakeAmp; 344 camShakeDuration = other.camShakeDuration; 345 camShakeRadius = other.camShakeRadius; 346 camShakeFalloff = other.camShakeFalloff; 347 lightStartRadius = other.lightStartRadius; 348 lightEndRadius = other.lightEndRadius; 349 lightStartColor = other.lightStartColor; 350 lightEndColor = other.lightEndColor; 351 lightStartBrightness = other.lightStartBrightness; 352 lightEndBrightness = other.lightEndBrightness; 353 lightNormalOffset = other.lightNormalOffset; 354 // Note - Explosion calls mDataBlock->getName() in warning messages but 355 // that should be safe. 356} 357 358ExplosionData::~ExplosionData() 359{ 360 if (!isTempClone()) 361 return; 362 363 if (soundProfile && soundProfile->isTempClone()) 364 { 365 delete soundProfile; 366 soundProfile = 0; 367 } 368 369 // particleEmitter, emitterList[*], debrisList[*], explosionList[*] will delete themselves 370 371#ifdef TRACK_EXPLOSION_DATA_CLONES 372 if (explosion_data_clones > 0) 373 { 374 explosion_data_clones--; 375 if (explosion_data_clones == 0) 376 Con::errorf("ExplosionData -- Clones eliminated!"); 377 } 378 else 379 Con::errorf("ExplosionData -- Too many clones deleted!"); 380#endif 381} 382 383ExplosionData* ExplosionData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index) 384{ 385 if (!owner || getSubstitutionCount() == 0) 386 return this; 387 388 ExplosionData* sub_explosion_db = new ExplosionData(*this, true); 389 performSubstitutions(sub_explosion_db, owner, index); 390 391 return sub_explosion_db; 392} 393 394void ExplosionData::initPersistFields() 395{ 396 addField( "explosionShape", TypeShapeFilename, Offset(dtsFileName, ExplosionData), 397 "@brief Optional DTS or DAE shape to place at the center of the explosion.\n\n" 398 "The <i>ambient</i> animation of this model will be played automatically at " 399 "the start of the explosion." ); 400 addField( "explosionScale", TypePoint3F, Offset(explosionScale, ExplosionData), 401 "\"X Y Z\" scale factor applied to the explosionShape model at the start " 402 "of the explosion." ); 403 addField( "playSpeed", TypeF32, Offset(playSpeed, ExplosionData), 404 "Time scale at which to play the explosionShape <i>ambient</i> sequence." ); 405 addField( "soundProfile", TYPEID< SFXTrack >(), Offset(soundProfile, ExplosionData), 406 "Non-looping sound effect that will be played at the start of the explosion." ); 407 addField( "faceViewer", TypeBool, Offset(faceViewer, ExplosionData), 408 "Controls whether the visual effects of the explosion always face the camera." ); 409 410 addField( "particleEmitter", TYPEID< ParticleEmitterData >(), Offset(particleEmitter, ExplosionData), 411 "@brief Emitter used to generate a cloud of particles at the start of the explosion.\n\n" 412 "Explosions can generate two different particle effects. The first is a " 413 "single burst of particles at the start of the explosion emitted in a " 414 "spherical cloud using particleEmitter.\n\n" 415 "The second effect spawns the list of ParticleEmitters given by the emitter[] " 416 "field. These emitters generate particles in the normal way throughout the " 417 "lifetime of the explosion." ); 418 addField( "particleDensity", TypeS32, Offset(particleDensity, ExplosionData), 419 "@brief Density of the particle cloud created at the start of the explosion.\n\n" 420 "@see particleEmitter" ); 421 addField( "particleRadius", TypeF32, Offset(particleRadius, ExplosionData), 422 "@brief Radial distance from the explosion center at which cloud particles " 423 "are emitted.\n\n" 424 "@see particleEmitter" ); 425 addField( "emitter", TYPEID< ParticleEmitterData >(), Offset(emitterList, ExplosionData), EC_NUM_EMITTERS, 426 "@brief List of additional ParticleEmitterData objects to spawn with this " 427 "explosion.\n\n" 428 "@see particleEmitter" ); 429 430 addField( "debris", TYPEID< DebrisData >(), Offset(debrisList, ExplosionData), EC_NUM_DEBRIS_TYPES, 431 "List of DebrisData objects to spawn with this explosion." ); 432 addField( "debrisThetaMin", TypeF32, Offset(debrisThetaMin, ExplosionData), 433 "Minimum angle, from the horizontal plane, to eject debris from." ); 434 addField( "debrisThetaMax", TypeF32, Offset(debrisThetaMax, ExplosionData), 435 "Maximum angle, from the horizontal plane, to eject debris from." ); 436 addField( "debrisPhiMin", TypeF32, Offset(debrisPhiMin, ExplosionData), 437 "Minimum reference angle, from the vertical plane, to eject debris from." ); 438 addField( "debrisPhiMax", TypeF32, Offset(debrisPhiMax, ExplosionData), 439 "Maximum reference angle, from the vertical plane, to eject debris from." ); 440 addField( "debrisNum", TypeS32, Offset(debrisNum, ExplosionData), 441 "Number of debris objects to create." ); 442 addField( "debrisNumVariance", TypeS32, Offset(debrisNumVariance, ExplosionData), 443 "Variance in the number of debris objects to create (must be from 0 - debrisNum)." ); 444 addField( "debrisVelocity", TypeF32, Offset(debrisVelocity, ExplosionData), 445 "Velocity to toss debris at." ); 446 addField( "debrisVelocityVariance", TypeF32, Offset(debrisVelocityVariance, ExplosionData), 447 "Variance in the debris initial velocity (must be >= 0)." ); 448 449 addField( "subExplosion", TYPEID< ExplosionData >(), Offset(explosionList, ExplosionData), EC_MAX_SUB_EXPLOSIONS, 450 "List of additional ExplosionData objects to create at the start of the " 451 "explosion." ); 452 453 addField( "delayMS", TypeS32, Offset(delayMS, ExplosionData), 454 "Amount of time, in milliseconds, to delay the start of the explosion effect " 455 "from the creation of the Explosion object." ); 456 addField( "delayVariance", TypeS32, Offset(delayVariance, ExplosionData), 457 "Variance, in milliseconds, of delayMS." ); 458 addField( "lifetimeMS", TypeS32, Offset(lifetimeMS, ExplosionData), 459 "@brief Lifetime, in milliseconds, of the Explosion object.\n\n" 460 "@note If explosionShape is defined and contains an <i>ambient</i> animation, " 461 "this field is ignored, and the playSpeed scaled duration of the animation " 462 "is used instead." ); 463 addField( "lifetimeVariance", TypeS32, Offset(lifetimeVariance, ExplosionData), 464 "Variance, in milliseconds, of the lifetimeMS of the Explosion object.\n" ); 465 addField( "offset", TypeF32, Offset(offset, ExplosionData), 466 "@brief Offset distance (in a random direction) of the center of the explosion " 467 "from the Explosion object position.\n\n" 468 "Most often used to create some variance in position for subExplosion effects." ); 469 470 addField( "times", TypeF32, Offset(times, ExplosionData), EC_NUM_TIME_KEYS, 471 "@brief Time keyframes used to scale the explosionShape model.\n\n" 472 "Values should be in increasing order from 0.0 - 1.0, and correspond to " 473 "the life of the Explosion where 0 is the beginning and 1 is the end of " 474 "the explosion lifetime.\n" 475 "@see lifetimeMS" ); 476 addField( "sizes", TypePoint3F, Offset(sizes, ExplosionData), EC_NUM_TIME_KEYS, 477 "@brief \"X Y Z\" size keyframes used to scale the explosionShape model.\n\n" 478 "The explosionShape (if defined) will be scaled using the times/sizes " 479 "keyframes over the lifetime of the explosion.\n" 480 "@see lifetimeMS" ); 481 482 addField( "shakeCamera", TypeBool, Offset(shakeCamera, ExplosionData), 483 "Controls whether the camera shakes during this explosion." ); 484 addField( "camShakeFreq", TypePoint3F, Offset(camShakeFreq, ExplosionData), 485 "Frequency of camera shaking, defined in the \"X Y Z\" axes." ); 486 addField( "camShakeAmp", TypePoint3F, Offset(camShakeAmp, ExplosionData), 487 "@brief Amplitude of camera shaking, defined in the \"X Y Z\" axes.\n\n" 488 "Set any value to 0 to disable shaking in that axis." ); 489 addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ExplosionData), 490 "Duration (in seconds) to shake the camera." ); 491 addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ExplosionData), 492 "Radial distance that a camera's position must be within relative to the " 493 "center of the explosion to be shaken." ); 494 addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ExplosionData), 495 "Falloff value for the camera shake." ); 496 497 addField( "lightStartRadius", TypeF32, Offset(lightStartRadius, ExplosionData), 498 "@brief Initial radius of the PointLight created by this explosion.\n\n" 499 "Radius is linearly interpolated from lightStartRadius to lightEndRadius " 500 "over the lifetime of the explosion.\n" 501 "@see lifetimeMS" ); 502 addField( "lightEndRadius", TypeF32, Offset(lightEndRadius, ExplosionData), 503 "@brief Final radius of the PointLight created by this explosion.\n\n" 504 "@see lightStartRadius" ); 505 addField( "lightStartColor", TypeColorF, Offset(lightStartColor, ExplosionData), 506 "@brief Initial color of the PointLight created by this explosion.\n\n" 507 "Color is linearly interpolated from lightStartColor to lightEndColor " 508 "over the lifetime of the explosion.\n" 509 "@see lifetimeMS" ); 510 addField( "lightEndColor", TypeColorF, Offset(lightEndColor, ExplosionData), 511 "@brief Final color of the PointLight created by this explosion.\n\n" 512 "@see lightStartColor" ); 513 addField( "lightStartBrightness", TypeF32, Offset(lightStartBrightness, ExplosionData), 514 "@brief Initial brightness of the PointLight created by this explosion.\n\n" 515 "Brightness is linearly interpolated from lightStartBrightness to " 516 "lightEndBrightness over the lifetime of the explosion.\n" 517 "@see lifetimeMS" ); 518 addField("lightEndBrightness", TypeF32, Offset(lightEndBrightness, ExplosionData), 519 "@brief Final brightness of the PointLight created by this explosion.\n\n" 520 "@see lightStartBrightness" ); 521 addField( "lightNormalOffset", TypeF32, Offset(lightNormalOffset, ExplosionData), 522 "Distance (in the explosion normal direction) of the PointLight position " 523 "from the explosion center." ); 524 525 // disallow some field substitutions 526 onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK 527 onlyKeepClearSubstitutions("emitter"); 528 onlyKeepClearSubstitutions("particleEmitter"); 529 onlyKeepClearSubstitutions("soundProfile"); 530 onlyKeepClearSubstitutions("subExplosion"); 531 Parent::initPersistFields(); 532} 533 534bool ExplosionData::onAdd() 535{ 536 if (Parent::onAdd() == false) 537 return false; 538 539 if (explosionScale.x < 0.01f || explosionScale.y < 0.01f || explosionScale.z < 0.01f) 540 { 541 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s)::onAdd: ExplosionScale components must be >= 0.01", getName()); 542 explosionScale.x = explosionScale.x < 0.01f ? 0.01f : explosionScale.x; 543 explosionScale.y = explosionScale.y < 0.01f ? 0.01f : explosionScale.y; 544 explosionScale.z = explosionScale.z < 0.01f ? 0.01f : explosionScale.z; 545 } 546 547 if (debrisThetaMin < 0.0f) 548 { 549 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisThetaMin < 0.0", getName()); 550 debrisThetaMin = 0.0f; 551 } 552 if (debrisThetaMax > 180.0f) 553 { 554 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisThetaMax > 180.0", getName()); 555 debrisThetaMax = 180.0f; 556 } 557 if (debrisThetaMin > debrisThetaMax) { 558 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisThetaMin > debrisThetaMax", getName()); 559 debrisThetaMin = debrisThetaMax; 560 } 561 if (debrisPhiMin < 0.0f) 562 { 563 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisPhiMin < 0.0", getName()); 564 debrisPhiMin = 0.0f; 565 } 566 if (debrisPhiMax > 360.0f) 567 { 568 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisPhiMax > 360.0", getName()); 569 debrisPhiMax = 360.0f; 570 } 571 if (debrisPhiMin > debrisPhiMax) { 572 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisPhiMin > debrisPhiMax", getName()); 573 debrisPhiMin = debrisPhiMax; 574 } 575 if (debrisNum > 1000) { 576 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisNum > 1000", getName()); 577 debrisNum = 1000; 578 } 579 if (debrisNumVariance > 1000) { 580 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisNumVariance > 1000", getName()); 581 debrisNumVariance = 1000; 582 } 583 if (debrisVelocity < 0.1f) 584 { 585 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisVelocity < 0.1", getName()); 586 debrisVelocity = 0.1f; 587 } 588 if (debrisVelocityVariance > 1000) { 589 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) debrisVelocityVariance > 1000", getName()); 590 debrisVelocityVariance = 1000; 591 } 592 if (playSpeed < 0.05f) 593 { 594 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) playSpeed < 0.05", getName()); 595 playSpeed = 0.05f; 596 } 597 if (lifetimeMS < 1) { 598 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) lifetimeMS < 1", getName()); 599 lifetimeMS = 1; 600 } 601 if (lifetimeVariance > lifetimeMS) { 602 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) lifetimeVariance > lifetimeMS", getName()); 603 lifetimeVariance = lifetimeMS; 604 } 605 if (delayMS < 0) { 606 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) delayMS < 0", getName()); 607 delayMS = 0; 608 } 609 if (delayVariance > delayMS) { 610 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) delayVariance > delayMS", getName()); 611 delayVariance = delayMS; 612 } 613 if (offset < 0.0f) 614 { 615 Con::warnf(ConsoleLogEntry::General, "ExplosionData(%s) offset < 0.0", getName()); 616 offset = 0.0f; 617 } 618 619 S32 i; 620 for( i=0; i<EC_NUM_DEBRIS_TYPES; i++ ) 621 { 622 if( !debrisList[i] && debrisIDList[i] != 0 ) 623 { 624 if( !Sim::findObject( debrisIDList[i], debrisList[i] ) ) 625 { 626 Con::errorf( ConsoleLogEntry::General, "ExplosionData::onAdd: Invalid packet, bad datablockId(debris): 0x%x", debrisIDList[i] ); 627 } 628 } 629 } 630 631 for( i=0; i<EC_NUM_EMITTERS; i++ ) 632 { 633 if( !emitterList[i] && emitterIDList[i] != 0 ) 634 { 635 if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false) 636 { 637 Con::errorf( ConsoleLogEntry::General, "ExplosionData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", emitterIDList[i] ); 638 } 639 } 640 } 641 642 for( S32 k=0; k<EC_MAX_SUB_EXPLOSIONS; k++ ) 643 { 644 if( !explosionList[k] && explosionIDList[k] != 0 ) 645 { 646 if( Sim::findObject( explosionIDList[k], explosionList[k] ) == false) 647 { 648 Con::errorf( ConsoleLogEntry::General, "ExplosionData::onAdd: Invalid packet, bad datablockId(explosion): 0x%x", explosionIDList[k] ); 649 } 650 } 651 } 652 653 return true; 654} 655 656void ExplosionData::packData(BitStream* stream) 657{ 658 Parent::packData(stream); 659 660 stream->writeString(dtsFileName); 661 662 sfxWrite( stream, soundProfile ); 663 if (stream->writeFlag(particleEmitter)) 664 stream->writeRangedU32(particleEmitter->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast); 665 666 stream->writeInt(particleDensity, 14); 667 stream->write(particleRadius); 668 stream->writeFlag(faceViewer); 669 if(stream->writeFlag(explosionScale.x != 1 || explosionScale.y != 1 || explosionScale.z != 1)) 670 { 671 stream->writeInt((S32)(explosionScale.x * 100), 16); 672 stream->writeInt((S32)(explosionScale.y * 100), 16); 673 stream->writeInt((S32)(explosionScale.z * 100), 16); 674 } 675 stream->writeInt((S32)(playSpeed * 20), 14); 676 stream->writeRangedU32((U32)debrisThetaMin, 0, 180); 677 stream->writeRangedU32((U32)debrisThetaMax, 0, 180); 678 stream->writeRangedU32((U32)debrisPhiMin, 0, 360); 679 stream->writeRangedU32((U32)debrisPhiMax, 0, 360); 680 stream->writeRangedU32((U32)debrisNum, 0, 1000); 681 stream->writeRangedU32(debrisNumVariance, 0, 1000); 682 stream->writeInt((S32)(debrisVelocity * 10), 14); 683 stream->writeRangedU32((U32)(debrisVelocityVariance * 10), 0, 10000); 684 stream->writeInt(delayMS >> 5, 16); 685 stream->writeInt(delayVariance >> 5, 16); 686 stream->writeInt(lifetimeMS >> 5, 16); 687 stream->writeInt(lifetimeVariance >> 5, 16); 688 stream->write(offset); 689 690 stream->writeFlag( shakeCamera ); 691 stream->write(camShakeFreq.x); 692 stream->write(camShakeFreq.y); 693 stream->write(camShakeFreq.z); 694 stream->write(camShakeAmp.x); 695 stream->write(camShakeAmp.y); 696 stream->write(camShakeAmp.z); 697 stream->write(camShakeDuration); 698 stream->write(camShakeRadius); 699 stream->write(camShakeFalloff); 700 701 for( S32 j=0; j<EC_NUM_DEBRIS_TYPES; j++ ) 702 { 703 if( stream->writeFlag( debrisList[j] ) ) 704 { 705 stream->writeRangedU32( debrisList[j]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 706 } 707 } 708 709 S32 i; 710 for( i=0; i<EC_NUM_EMITTERS; i++ ) 711 { 712 if( stream->writeFlag( emitterList[i] != NULL ) ) 713 { 714 stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 715 } 716 } 717 718 for( i=0; i<EC_MAX_SUB_EXPLOSIONS; i++ ) 719 { 720 if( stream->writeFlag( explosionList[i] != NULL ) ) 721 { 722 stream->writeRangedU32( explosionList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); 723 } 724 } 725 U32 count; 726 for(count = 0; count < EC_NUM_TIME_KEYS; count++) 727 if(times[count] >= 1) 728 break; 729 count++; 730 if(count > EC_NUM_TIME_KEYS) 731 count = EC_NUM_TIME_KEYS; 732 733 stream->writeRangedU32(count, 0, EC_NUM_TIME_KEYS); 734 735 for( i=0; i<count; i++ ) 736 stream->writeFloat( times[i], 8 ); 737 738 for( i=0; i<count; i++ ) 739 { 740 stream->writeRangedU32((U32)(sizes[i].x * 100), 0, 16000); 741 stream->writeRangedU32((U32)(sizes[i].y * 100), 0, 16000); 742 stream->writeRangedU32((U32)(sizes[i].z * 100), 0, 16000); 743 } 744 745 // Dynamic light info 746 stream->writeFloat(lightStartRadius/<a href="/coding/file/explosion_8cpp/#explosion_8cpp_1a91285d7c47bf4712b406cb79bf3a6d02">MaxLightRadius</a>, 8); 747 stream->writeFloat(lightEndRadius/<a href="/coding/file/explosion_8cpp/#explosion_8cpp_1a91285d7c47bf4712b406cb79bf3a6d02">MaxLightRadius</a>, 8); 748 stream->writeFloat(lightStartColor.red,7); 749 stream->writeFloat(lightStartColor.green,7); 750 stream->writeFloat(lightStartColor.blue,7); 751 stream->writeFloat(lightEndColor.red,7); 752 stream->writeFloat(lightEndColor.green,7); 753 stream->writeFloat(lightEndColor.blue,7); 754 stream->writeFloat(lightStartBrightness/<a href="/coding/file/explosion_8cpp/#explosion_8cpp_1a91285d7c47bf4712b406cb79bf3a6d02">MaxLightRadius</a>, 8); 755 stream->writeFloat(lightEndBrightness/<a href="/coding/file/explosion_8cpp/#explosion_8cpp_1a91285d7c47bf4712b406cb79bf3a6d02">MaxLightRadius</a>, 8); 756 stream->write(lightNormalOffset); 757} 758 759void ExplosionData::unpackData(BitStream* stream) 760{ 761 Parent::unpackData(stream); 762 763 dtsFileName = stream->readSTString(); 764 765 sfxRead( stream, &soundProfile ); 766 767 if (stream->readFlag()) 768 particleEmitterId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast); 769 else 770 particleEmitterId = 0; 771 772 particleDensity = stream->readInt(14); 773 stream->read(&particleRadius); 774 faceViewer = stream->readFlag(); 775 if(stream->readFlag()) 776 { 777 explosionScale.x = stream->readInt(16) / 100.0f; 778 explosionScale.y = stream->readInt(16) / 100.0f; 779 explosionScale.z = stream->readInt(16) / 100.0f; 780 } 781 else 782 explosionScale.set(1,1,1); 783 playSpeed = stream->readInt(14) / 20.0f; 784 debrisThetaMin = stream->readRangedU32(0, 180); 785 debrisThetaMax = stream->readRangedU32(0, 180); 786 debrisPhiMin = stream->readRangedU32(0, 360); 787 debrisPhiMax = stream->readRangedU32(0, 360); 788 debrisNum = stream->readRangedU32(0, 1000); 789 debrisNumVariance = stream->readRangedU32(0, 1000); 790 791 debrisVelocity = stream->readInt(14) / 10.0f; 792 debrisVelocityVariance = stream->readRangedU32(0, 10000) / 10.0f; 793 delayMS = stream->readInt(16) << 5; 794 delayVariance = stream->readInt(16) << 5; 795 lifetimeMS = stream->readInt(16) << 5; 796 lifetimeVariance = stream->readInt(16) << 5; 797 798 stream->read(&offset); 799 800 shakeCamera = stream->readFlag(); 801 stream->read(&camShakeFreq.x); 802 stream->read(&camShakeFreq.y); 803 stream->read(&camShakeFreq.z); 804 stream->read(&camShakeAmp.x); 805 stream->read(&camShakeAmp.y); 806 stream->read(&camShakeAmp.z); 807 stream->read(&camShakeDuration); 808 stream->read(&camShakeRadius); 809 stream->read(&camShakeFalloff); 810 811 812 for( S32 j=0; j<EC_NUM_DEBRIS_TYPES; j++ ) 813 { 814 if( stream->readFlag() ) 815 { 816 debrisIDList[j] = (S32) stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 817 } 818 } 819 820 U32 i; 821 for( i=0; i<EC_NUM_EMITTERS; i++ ) 822 { 823 if( stream->readFlag() ) 824 { 825 emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 826 } 827 } 828 829 for( S32 k=0; k<EC_MAX_SUB_EXPLOSIONS; k++ ) 830 { 831 if( stream->readFlag() ) 832 { 833 explosionIDList[k] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 834 } 835 } 836 837 U32 count = stream->readRangedU32(0, EC_NUM_TIME_KEYS); 838 839 for( i=0; i<count; i++ ) 840 times[i] = stream->readFloat(8); 841 842 for( i=0; i<count; i++ ) 843 { 844 sizes[i].x = stream->readRangedU32(0, 16000) / 100.0f; 845 sizes[i].y = stream->readRangedU32(0, 16000) / 100.0f; 846 sizes[i].z = stream->readRangedU32(0, 16000) / 100.0f; 847 } 848 849 // 850 lightStartRadius = stream->readFloat(8) * MaxLightRadius; 851 lightEndRadius = stream->readFloat(8) * MaxLightRadius; 852 lightStartColor.red = stream->readFloat(7); 853 lightStartColor.green = stream->readFloat(7); 854 lightStartColor.blue = stream->readFloat(7); 855 lightEndColor.red = stream->readFloat(7); 856 lightEndColor.green = stream->readFloat(7); 857 lightEndColor.blue = stream->readFloat(7); 858 lightStartBrightness = stream->readFloat(8) * MaxLightRadius; 859 lightEndBrightness = stream->readFloat(8) * MaxLightRadius; 860 stream->read( &lightNormalOffset ); 861} 862 863bool ExplosionData::preload(bool server, String &errorStr) 864{ 865 if (Parent::preload(server, errorStr) == false) 866 return false; 867 868 if( !server ) 869 { 870 String sfxErrorStr; 871 if( !sfxResolve( &soundProfile, sfxErrorStr ) ) 872 Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", sfxErrorStr.c_str()); 873 if (!particleEmitter && particleEmitterId != 0) 874 if (Sim::findObject(particleEmitterId, particleEmitter) == false) 875 Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock"); 876 } 877 878 if (dtsFileName && dtsFileName[0]) { 879 explosionShape = ResourceManager::get().load(dtsFileName); 880 if (!bool(explosionShape)) { 881 errorStr = String::ToString("ExplosionData: Couldn't load shape \"%s\"", dtsFileName); 882 return false; 883 } 884 885 // Resolve animations 886 explosionAnimation = explosionShape->findSequence("ambient"); 887 888 // Preload textures with a dummy instance... 889 TSShapeInstance* pDummy = new TSShapeInstance(explosionShape, !server); 890 delete pDummy; 891 892 } else { 893 explosionShape = NULL; 894 explosionAnimation = -1; 895 } 896 897 return true; 898} 899 900 901//-------------------------------------------------------------------------- 902//-------------------------------------- 903// 904Explosion::Explosion() 905 : mDataBlock( NULL ) 906{ 907 mTypeMask |= ExplosionObjectType | LightObjectType; 908 909 mExplosionInstance = NULL; 910 mExplosionThread = NULL; 911 912 dMemset( mEmitterList, 0, sizeof( mEmitterList ) ); 913 mMainEmitter = NULL; 914 915 mFade = 1; 916 mDelayMS = 0; 917 mCurrMS = 0; 918 mEndingMS = 1000; 919 mActive = false; 920 mCollideType = 0; 921 922 mInitialNormal.set( 0.0f, 0.0f, 1.0f ); 923 mRandAngle = sgRandom.randF( 0.0f, 1.0f ) * M_PI_F * 2.0f; 924 mLight = LIGHTMGR->createLightInfo(); 925 926 mNetFlags.set( IsGhost ); 927 ss_object = 0; 928 ss_index = 0; 929 mDataBlock = 0; 930 soundProfile_clone = 0; 931 mRandomVal = 0; 932} 933 934Explosion::~Explosion() 935{ 936 if( mExplosionInstance ) 937 { 938 delete mExplosionInstance; 939 mExplosionInstance = NULL; 940 mExplosionThread = NULL; 941 } 942 943 SAFE_DELETE(mLight); 944 945 if (soundProfile_clone) 946 { 947 delete soundProfile_clone; 948 soundProfile_clone = 0; 949 } 950 951 if (mDataBlock && mDataBlock->isTempClone()) 952 { 953 delete mDataBlock; 954 mDataBlock = 0; 955 } 956} 957 958 959void Explosion::setInitialState(const Point3F& point, const Point3F& normal, const F32 fade) 960{ 961 setPosition(point); 962 mInitialNormal = normal; 963 mFade = fade; 964} 965 966//-------------------------------------------------------------------------- 967void Explosion::initPersistFields() 968{ 969 Parent::initPersistFields(); 970 addField("initialNormal", TypePoint3F, Offset(mInitialNormal, Explosion), "Initial starting Normal."); 971 // 972} 973 974//-------------------------------------------------------------------------- 975bool Explosion::onAdd() 976{ 977 // first check if we have a server connection, if we dont then this is on the server 978 // and we should exit, then check if the parent fails to add the object 979 GameConnection *conn = GameConnection::getConnectionToServer(); 980 if ( !conn || !Parent::onAdd() ) 981 return false; 982 983 if( !mDataBlock ) 984 { 985 Con::errorf("Explosion::onAdd - Fail - No datablok"); 986 return false; 987 } 988 989 mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance ); 990 mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance ); 991 992 if( mFabs( mDataBlock->offset ) > 0.001f ) 993 { 994 MatrixF axisOrient = MathUtils::createOrientFromDir( mInitialNormal ); 995 996 MatrixF trans = getTransform(); 997 Point3F randVec; 998 randVec.x = sgRandom.randF( -1.0f, 1.0f ); 999 randVec.y = sgRandom.randF( 0.0f, 1.0f ); 1000 randVec.z = sgRandom.randF( -1.0f, 1.0f ); 1001 randVec.normalize(); 1002 randVec *= mDataBlock->offset; 1003 axisOrient.mulV( randVec ); 1004 trans.setPosition( trans.getPosition() + randVec ); 1005 setTransform( trans ); 1006 } 1007 1008 // shake camera 1009 if( mDataBlock->shakeCamera ) 1010 { 1011 // first check if explosion is near player 1012 GameConnection* connection = GameConnection::getConnectionToServer(); 1013 ShapeBase *obj = dynamic_cast<ShapeBase*>(connection->getControlObject()); 1014 1015 bool applyShake = true; 1016 1017 if( obj ) 1018 { 1019 ShapeBase* cObj = obj; 1020 while((cObj = cObj->getControlObject()) != 0) 1021 { 1022 if(cObj->useObjsEyePoint()) 1023 { 1024 applyShake = false; 1025 break; 1026 } 1027 } 1028 } 1029 1030 1031 if( applyShake && obj ) 1032 { 1033 VectorF diff = obj->getPosition() - getPosition(); 1034 F32 dist = diff.len(); 1035 if( dist < mDataBlock->camShakeRadius ) 1036 { 1037 CameraShake *camShake = new CameraShake; 1038 camShake->setDuration( mDataBlock->camShakeDuration ); 1039 camShake->setFrequency( mDataBlock->camShakeFreq ); 1040 1041 F32 falloff = dist / mDataBlock->camShakeRadius; 1042 falloff = 1.0f + falloff * 10.0f; 1043 falloff = 1.0f / (falloff * falloff); 1044 1045 VectorF shakeAmp = mDataBlock->camShakeAmp * falloff; 1046 camShake->setAmplitude( shakeAmp ); 1047 camShake->setFalloff( mDataBlock->camShakeFalloff ); 1048 camShake->init(); 1049 gCamFXMgr.addFX( camShake ); 1050 } 1051 } 1052 } 1053 1054 1055 if( mDelayMS == 0 ) 1056 { 1057 if( !explode() ) 1058 { 1059 return false; 1060 } 1061 } 1062 1063 gClientSceneGraph->addObjectToScene(this); 1064 1065 removeFromProcessList(); 1066 ClientProcessList::get()->addObject(this); 1067 1068 mRandomVal = sgRandom.randF(); 1069 1070 NetConnection* pNC = NetConnection::getConnectionToServer(); 1071 AssertFatal(pNC != NULL, "Error, must have a connection to the server!"); 1072 pNC->addObject(this); 1073 1074 // Initialize the light structure and register as a dynamic light 1075 if (mDataBlock->lightStartRadius != 0.0f || mDataBlock->lightEndRadius) 1076 { 1077 mLight->setType( LightInfo::Point ); 1078 mLight->setRange( mDataBlock->lightStartRadius ); 1079 mLight->setColor( mDataBlock->lightStartColor ); 1080 } 1081 1082 return true; 1083} 1084 1085void Explosion::onRemove() 1086{ 1087 for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ ) 1088 { 1089 if( mEmitterList[i] ) 1090 { 1091 mEmitterList[i]->deleteWhenEmpty(); 1092 mEmitterList[i] = NULL; 1093 } 1094 } 1095 1096 if( mMainEmitter ) 1097 { 1098 mMainEmitter->deleteWhenEmpty(); 1099 mMainEmitter = NULL; 1100 } 1101 1102 removeFromScene(); 1103 1104 Parent::onRemove(); 1105} 1106 1107 1108bool Explosion::onNewDataBlock( GameBaseData *dptr, bool reload ) 1109{ 1110 mDataBlock = dynamic_cast<ExplosionData*>( dptr ); 1111 if (!mDataBlock || !Parent::onNewDataBlock( dptr, reload )) 1112 return false; 1113 1114 if (mDataBlock->isTempClone()) 1115 return true; 1116 scriptOnNewDataBlock(); 1117 return true; 1118} 1119 1120 1121//-------------------------------------------------------------------------- 1122void Explosion::prepRenderImage( SceneRenderState* state ) 1123{ 1124 prepBatchRender( state ); 1125} 1126 1127void Explosion::setCurrentScale() 1128{ 1129 F32 t = F32(mCurrMS) / F32(mEndingMS); 1130 1131 for( U32 i = 1; i < ExplosionData::EC_NUM_TIME_KEYS; i++ ) 1132 { 1133 if( mDataBlock->times[i] >= t ) 1134 { 1135 F32 firstPart = t - mDataBlock->times[i-1]; 1136 F32 total = mDataBlock->times[i] - 1137 mDataBlock->times[i-1]; 1138 1139 firstPart /= total; 1140 1141 mObjScale = (mDataBlock->sizes[i-1] * (1.0f - firstPart)) + 1142 (mDataBlock->sizes[i] * firstPart); 1143 1144 return; 1145 } 1146 } 1147 1148} 1149 1150//-------------------------------------------------------------------------- 1151// Make the explosion face the viewer (if desired) 1152//-------------------------------------------------------------------------- 1153void Explosion::prepModelView(SceneRenderState* state) 1154{ 1155 MatrixF rotMatrix( true ); 1156 Point3F targetVector; 1157 1158 if( mDataBlock->faceViewer ) 1159 { 1160 targetVector = getPosition() - state->getCameraPosition(); 1161 targetVector.normalize(); 1162 1163 // rotate explosion each time so it's a little different 1164 rotMatrix.set( EulerF( 0.0f, mRandAngle, 0.0f ) ); 1165 } 1166 else 1167 { 1168 targetVector = mInitialNormal; 1169 } 1170 1171 MatrixF explOrient = MathUtils::createOrientFromDir( targetVector ); 1172 explOrient.mul( rotMatrix ); 1173 explOrient.setPosition( getPosition() ); 1174 1175 setCurrentScale(); 1176 explOrient.scale( mObjScale ); 1177 GFX->setWorldMatrix( explOrient ); 1178} 1179 1180//-------------------------------------------------------------------------- 1181// Render object 1182//-------------------------------------------------------------------------- 1183void Explosion::prepBatchRender(SceneRenderState* state) 1184{ 1185 if ( !mExplosionInstance ) 1186 return; 1187 1188 MatrixF proj = GFX->getProjectionMatrix(); 1189 RectI viewport = GFX->getViewport(); 1190 1191 // Set up our TS render state here. 1192 TSRenderState rdata; 1193 rdata.setSceneState( state ); 1194 1195 // We might have some forward lit materials 1196 // so pass down a query to gather lights. 1197 LightQuery query; 1198 query.init( getWorldSphere() ); 1199 rdata.setLightQuery( &query ); 1200 1201 // render mesh 1202 GFX->pushWorldMatrix(); 1203 1204 prepModelView( state ); 1205 1206 mExplosionInstance->animate(); 1207 mExplosionInstance->render( rdata ); 1208 1209 GFX->popWorldMatrix(); 1210 GFX->setProjectionMatrix( proj ); 1211 GFX->setViewport( viewport ); 1212} 1213 1214void Explosion::submitLights( LightManager *lm, bool staticLighting ) 1215{ 1216 if ( staticLighting ) 1217 return; 1218 1219 // Update the light's info and add it to the scene, the light will 1220 // only be visible for this current frame. 1221 mLight->setPosition( getRenderTransform().getPosition() + mInitialNormal * mDataBlock->lightNormalOffset ); 1222 F32 t = F32(mCurrMS) / F32(mEndingMS); 1223 mLight->setRange( mDataBlock->lightStartRadius + 1224 (mDataBlock->lightEndRadius - mDataBlock->lightStartRadius) * t ); 1225 mLight->setColor( mDataBlock->lightStartColor + 1226 (mDataBlock->lightEndColor - mDataBlock->lightStartColor) * t ); 1227 mLight->setBrightness( mDataBlock->lightStartBrightness + 1228 (mDataBlock->lightEndBrightness - mDataBlock->lightStartBrightness) * t ); 1229 1230 lm->registerGlobalLight( mLight, this ); 1231} 1232 1233 1234//-------------------------------------------------------------------------- 1235void Explosion::processTick(const Move*) 1236{ 1237 mCurrMS += TickMs; 1238 1239 if( mCurrMS >= mEndingMS ) 1240 { 1241 deleteObject(); 1242 return; 1243 } 1244 1245 if( (mCurrMS > mDelayMS) && !mActive ) 1246 explode(); 1247} 1248 1249void Explosion::advanceTime(F32 dt) 1250{ 1251 if (dt == 0.0f) 1252 return; 1253 1254 GameConnection* conn = GameConnection::getConnectionToServer(); 1255 if(!conn) 1256 return; 1257 1258 updateEmitters( dt ); 1259 1260 if( mExplosionInstance ) 1261 mExplosionInstance->advanceTime(dt, mExplosionThread); 1262} 1263 1264//---------------------------------------------------------------------------- 1265// Update emitters 1266//---------------------------------------------------------------------------- 1267void Explosion::updateEmitters( F32 dt ) 1268{ 1269 Point3F pos = getPosition(); 1270 1271 for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ ) 1272 { 1273 if( mEmitterList[i] ) 1274 { 1275 mEmitterList[i]->emitParticles( pos, pos, mInitialNormal, Point3F( 0.0f, 0.0f, 0.0f ), (U32)(dt * 1000)); 1276 } 1277 } 1278 1279} 1280 1281//---------------------------------------------------------------------------- 1282// Launch Debris 1283//---------------------------------------------------------------------------- 1284void Explosion::launchDebris( Point3F &axis ) 1285{ 1286 GameConnection* conn = GameConnection::getConnectionToServer(); 1287 if(!conn) 1288 return; 1289 1290 bool hasDebris = false; 1291 for( S32 j=0; j<ExplosionData::EC_NUM_DEBRIS_TYPES; j++ ) 1292 { 1293 if( mDataBlock->debrisList[j] ) 1294 { 1295 hasDebris = true; 1296 break; 1297 } 1298 } 1299 if( !hasDebris ) 1300 { 1301 return; 1302 } 1303 1304 Point3F axisx; 1305 if (mFabs(axis.z) < 0.999f) 1306 mCross(axis, Point3F(0.0f, 0.0f, 1.0f), &axisx); 1307 else 1308 mCross(axis, Point3F(0.0f, 1.0f, 0.0f), &axisx); 1309 axisx.normalize(); 1310 1311 Point3F pos( 0.0f, 0.0f, 0.5f ); 1312 pos += getPosition(); 1313 1314 1315 U32 numDebris = mDataBlock->debrisNum + sgRandom.randI( -mDataBlock->debrisNumVariance, mDataBlock->debrisNumVariance ); 1316 1317 for( S32 i=0; i<numDebris; i++ ) 1318 { 1319 1320 Point3F launchDir = MathUtils::randomDir( axis, mDataBlock->debrisThetaMin, mDataBlock->debrisThetaMax, 1321 mDataBlock->debrisPhiMin, mDataBlock->debrisPhiMax ); 1322 1323 F32 debrisVel = mDataBlock->debrisVelocity + mDataBlock->debrisVelocityVariance * sgRandom.randF( -1.0f, 1.0f ); 1324 1325 launchDir *= debrisVel; 1326 1327 Debris *debris = new Debris; 1328 debris->setSubstitutionData(ss_object, ss_index); 1329 debris->setDataBlock(mDataBlock->debrisList[0]->cloneAndPerformSubstitutions(ss_object, ss_index)); 1330 debris->setTransform( getTransform() ); 1331 debris->init( pos, launchDir ); 1332 1333 if( !debris->registerObject() ) 1334 { 1335 Con::warnf( ConsoleLogEntry::General, "Could not register debris for class: %s", mDataBlock->getName() ); 1336 delete debris; 1337 debris = NULL; 1338 } 1339 } 1340} 1341 1342//---------------------------------------------------------------------------- 1343// Spawn sub explosions 1344//---------------------------------------------------------------------------- 1345void Explosion::spawnSubExplosions() 1346{ 1347 GameConnection* conn = GameConnection::getConnectionToServer(); 1348 if(!conn) 1349 return; 1350 1351 for( S32 i=0; i<ExplosionData::EC_MAX_SUB_EXPLOSIONS; i++ ) 1352 { 1353 if( mDataBlock->explosionList[i] ) 1354 { 1355 MatrixF trans = getTransform(); 1356 Explosion* pExplosion = new Explosion; 1357 pExplosion->setSubstitutionData(ss_object, ss_index); 1358 pExplosion->setDataBlock(mDataBlock->explosionList[i]->cloneAndPerformSubstitutions(ss_object, ss_index)); 1359 pExplosion->setTransform( trans ); 1360 pExplosion->setInitialState( trans.getPosition(), mInitialNormal, 1); 1361 if (!pExplosion->registerObject()) 1362 delete pExplosion; 1363 } 1364 } 1365} 1366 1367//---------------------------------------------------------------------------- 1368// Explode 1369//---------------------------------------------------------------------------- 1370bool Explosion::explode() 1371{ 1372 mActive = true; 1373 1374 GameConnection* conn = GameConnection::getConnectionToServer(); 1375 if(!conn) 1376 return false; 1377 1378 launchDebris( mInitialNormal ); 1379 spawnSubExplosions(); 1380 1381 if (bool(mDataBlock->explosionShape) && mDataBlock->explosionAnimation != -1) { 1382 mExplosionInstance = new TSShapeInstance(mDataBlock->explosionShape, true); 1383 1384 mExplosionThread = mExplosionInstance->addThread(); 1385 mExplosionInstance->setSequence(mExplosionThread, mDataBlock->explosionAnimation, 0); 1386 mExplosionInstance->setTimeScale(mExplosionThread, mDataBlock->playSpeed); 1387 1388 mCurrMS = 0; 1389 mEndingMS = U32(mExplosionInstance->getScaledDuration(mExplosionThread) * 1000.0f); 1390 1391 mObjScale.convolve(mDataBlock->explosionScale); 1392 mObjBox = mDataBlock->explosionShape->mBounds; 1393 resetWorldBox(); 1394 } 1395 1396 SFXProfile* sound_prof = dynamic_cast<SFXProfile*>(mDataBlock->soundProfile); 1397 if (sound_prof) 1398 { 1399 soundProfile_clone = sound_prof->cloneAndPerformSubstitutions(ss_object, ss_index); 1400 SFX->playOnce( soundProfile_clone, &getTransform() ); 1401 if (!soundProfile_clone->isTempClone()) 1402 soundProfile_clone = 0; 1403 } 1404 1405 if (mDataBlock->particleEmitter) { 1406 mMainEmitter = new ParticleEmitter; 1407 mMainEmitter->setDataBlock(mDataBlock->particleEmitter->cloneAndPerformSubstitutions(ss_object, ss_index)); 1408 mMainEmitter->registerObject(); 1409 1410 mMainEmitter->emitParticles(getPosition(), mInitialNormal, mDataBlock->particleRadius, 1411 Point3F::Zero, U32(mDataBlock->particleDensity * mFade)); 1412 } 1413 1414 for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ ) 1415 { 1416 if( mDataBlock->emitterList[i] != NULL ) 1417 { 1418 ParticleEmitter * pEmitter = new ParticleEmitter; 1419 pEmitter->setDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index)); 1420 if( !pEmitter->registerObject() ) 1421 { 1422 Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() ); 1423 SAFE_DELETE(pEmitter); 1424 } 1425 mEmitterList[i] = pEmitter; 1426 } 1427 } 1428 1429 return true; 1430} 1431 1432