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