shapeImage.cpp

Engine/source/T3D/shapeImage.cpp

More...

Public Functions

ConsoleDocClass(ShapeBaseImageData , "@brief Represents geometry <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classshapebase/">ShapeBase</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
IMPLEMENT_CALLBACK(ShapeBaseImageData , onMount , void , (SceneObject *obj, S32 slot, F32 dt) , (obj, slot, dt) , "@brief Called when the Image is first mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param obj object that this Image has been mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param slot Image mount slot on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param dt time remaining in this Image <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update\n</a>" )
IMPLEMENT_CALLBACK(ShapeBaseImageData , onUnmount , void , (SceneObject *obj, S32 slot, F32 dt) , (obj, slot, dt) , "@brief Called when the Image is unmounted from the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param obj object that this Image has been unmounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from\n</a>" "@param slot Image mount slot on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param dt time remaining in this Image <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update\n</a>" )
ImplementEnumType(ShapeBaseImageLightType , "@brief The type of light <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> attach <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseImage.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )
ImplementEnumType(ShapeBaseImageLoadedState , "@brief The loaded state of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseImage.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )
ImplementEnumType(ShapeBaseImageRecoilState , "@brief What kind of recoil this ShapeBaseImage should emit when <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fired.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )
ImplementEnumType(ShapeBaseImageSpinState , "@brief How the spin animation should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">played.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )

Detailed Description

Public Variables

 EndImplementEnumType 
ShapeBaseImageData::StateData gDefaultStateData 
ShapeBaseImageData * InvalidImagePtr 

Public Functions

ConsoleDocClass(ShapeBaseImageData , "@brief Represents geometry <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classshapebase/">ShapeBase</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )

IMPLEMENT_CALLBACK(ShapeBaseImageData , onMount , void , (SceneObject *obj, S32 slot, F32 dt) , (obj, slot, dt) , "@brief Called when the Image is first mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param obj object that this Image has been mounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to\n</a>" "@param slot Image mount slot on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param dt time remaining in this Image <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update\n</a>" )

IMPLEMENT_CALLBACK(ShapeBaseImageData , onUnmount , void , (SceneObject *obj, S32 slot, F32 dt) , (obj, slot, dt) , "@brief Called when the Image is unmounted from the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@param obj object that this Image has been unmounted <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from\n</a>" "@param slot Image mount slot on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param dt time remaining in this Image <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">update\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseImageData )

ImplementEnumType(ShapeBaseImageLightType , "@brief The type of light <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> attach <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseImage.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )

ImplementEnumType(ShapeBaseImageLoadedState , "@brief The loaded state of this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ShapeBaseImage.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )

ImplementEnumType(ShapeBaseImageRecoilState , "@brief What kind of recoil this ShapeBaseImage should emit when <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">fired.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )

ImplementEnumType(ShapeBaseImageSpinState , "@brief How the spin animation should be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">played.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )

   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
  26#include "T3D/shapeBase.h"
  27#include "core/resourceManager.h"
  28#include "core/stream/bitStream.h"
  29#include "ts/tsShapeInstance.h"
  30#include "console/consoleInternal.h"
  31#include "console/consoleTypes.h"
  32#include "console/engineAPI.h"
  33#include "lighting/lightInfo.h"
  34#include "lighting/lightManager.h"
  35#include "T3D/fx/particleEmitter.h"
  36#include "T3D/projectile.h"
  37#include "T3D/gameBase/gameConnection.h"
  38#include "math/mathIO.h"
  39#include "T3D/debris.h"
  40#include "math/mathUtils.h"
  41#include "sim/netObject.h"
  42#include "sfx/sfxTrack.h"
  43#include "sfx/sfxSource.h"
  44#include "sfx/sfxSystem.h"
  45#include "sfx/sfxTypes.h"
  46#include "scene/sceneManager.h"
  47#include "core/stream/fileStream.h"
  48#include "T3D/fx/cameraFXMgr.h"
  49
  50//----------------------------------------------------------------------------
  51
  52ShapeBaseImageData* InvalidImagePtr = (ShapeBaseImageData*) 1;
  53
  54ImplementEnumType( ShapeBaseImageLoadedState,
  55   "@brief The loaded state of this ShapeBaseImage.\n\n"
  56   "@ingroup gameObjects\n\n")
  57   { ShapeBaseImageData::StateData::IgnoreLoaded, "Ignore", "Ignore the loaded state.\n" },
  58   { ShapeBaseImageData::StateData::Loaded,       "Loaded", "ShapeBaseImage is loaded.\n" },
  59   { ShapeBaseImageData::StateData::NotLoaded,    "Empty", "ShapeBaseImage is not loaded.\n" },
  60EndImplementEnumType;
  61
  62ImplementEnumType( ShapeBaseImageSpinState,
  63   "@brief How the spin animation should be played.\n\n"
  64   "@ingroup gameObjects\n\n")
  65   { ShapeBaseImageData::StateData::IgnoreSpin,"Ignore", "No changes to the spin sequence.\n" },
  66   { ShapeBaseImageData::StateData::NoSpin,    "Stop", "Stops the spin sequence at its current position\n" },
  67   { ShapeBaseImageData::StateData::SpinUp,    "SpinUp", "Increase spin sequence timeScale from 0 (on state entry) to 1 (after stateTimeoutValue seconds).\n" },
  68   { ShapeBaseImageData::StateData::SpinDown,  "SpinDown", "Decrease spin sequence timeScale from 1 (on state entry) to 0 (after stateTimeoutValue seconds).\n" },
  69   { ShapeBaseImageData::StateData::FullSpin,  "FullSpeed", "Resume the spin sequence playback at its current position with timeScale = 1.\n"},
  70EndImplementEnumType;
  71
  72ImplementEnumType( ShapeBaseImageRecoilState,
  73   "@brief What kind of recoil this ShapeBaseImage should emit when fired.\n\n"
  74   "@ingroup gameObjects\n\n")
  75   { ShapeBaseImageData::StateData::NoRecoil,     "NoRecoil", "No recoil occurs.\n" },
  76   { ShapeBaseImageData::StateData::LightRecoil,  "LightRecoil", "A light recoil occurs.\n" },
  77   { ShapeBaseImageData::StateData::MediumRecoil, "MediumRecoil", "A medium recoil occurs.\n" },
  78   { ShapeBaseImageData::StateData::HeavyRecoil,  "HeavyRecoil", "A heavy recoil occurs.\n" },
  79EndImplementEnumType;
  80
  81ImplementEnumType( ShapeBaseImageLightType,
  82   "@brief The type of light to attach to this ShapeBaseImage.\n\n"
  83   "@ingroup gameObjects\n\n")
  84   { ShapeBaseImageData::NoLight,           "NoLight", "No light is attached.\n" },
  85   { ShapeBaseImageData::ConstantLight,     "ConstantLight", "A constant emitting light is attached.\n" },
  86   { ShapeBaseImageData::SpotLight,         "SpotLight", "A spotlight is attached.\n" },
  87   { ShapeBaseImageData::PulsingLight,      "PulsingLight", "A pusling light is attached.\n" },
  88   { ShapeBaseImageData::WeaponFireLight,   "WeaponFireLight", "Light emits when the weapon is fired, then dissipates.\n" }
  89EndImplementEnumType;
  90
  91//----------------------------------------------------------------------------
  92//----------------------------------------------------------------------------
  93
  94IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseImageData);
  95
  96ConsoleDocClass( ShapeBaseImageData,
  97   "@brief Represents geometry to be mounted to a ShapeBase object.\n\n"
  98   "@ingroup gameObjects\n"
  99);
 100
 101IMPLEMENT_CALLBACK( ShapeBaseImageData, onMount, void, ( SceneObject* obj, S32 slot, F32 dt ), ( obj, slot, dt ),
 102   "@brief Called when the Image is first mounted to the object.\n\n"
 103
 104   "@param obj object that this Image has been mounted to\n"
 105   "@param slot Image mount slot on the object\n"
 106   "@param dt time remaining in this Image update\n" );
 107
 108IMPLEMENT_CALLBACK( ShapeBaseImageData, onUnmount, void, ( SceneObject* obj, S32 slot, F32 dt ), ( obj, slot, dt ),
 109   "@brief Called when the Image is unmounted from the object.\n\n"
 110
 111   "@param obj object that this Image has been unmounted from\n"
 112   "@param slot Image mount slot on the object\n"
 113   "@param dt time remaining in this Image update\n" );
 114
 115ShapeBaseImageData::StateData::StateData()
 116{
 117   name = 0;
 118   transition.loaded[0] = transition.loaded[1] = -1;
 119   transition.ammo[0] = transition.ammo[1] = -1;
 120   transition.target[0] = transition.target[1] = -1;
 121   transition.trigger[0] = transition.trigger[1] = -1;
 122   transition.altTrigger[0] = transition.altTrigger[1] = -1;
 123   transition.wet[0] = transition.wet[1] = -1;
 124   transition.motion[0] = transition.motion[1] = -1;
 125   transition.timeout = -1;
 126   waitForTimeout = true;
 127   timeoutValue = 0;
 128   fire = false;
 129   altFire = false;
 130   reload = false;
 131   energyDrain = 0;
 132   allowImageChange = true;
 133   loaded = IgnoreLoaded;
 134   spin = IgnoreSpin;
 135   recoil = NoRecoil;
 136   sound = 0;
 137   emitter = NULL;
 138   shapeSequence = NULL;
 139   shapeSequenceScale = true;
 140   script = 0;
 141   ignoreLoadedForReady = false;
 142   
 143   ejectShell = false;
 144   scaleAnimation = false;
 145   scaleAnimationFP = false;
 146   sequenceTransitionIn = false;
 147   sequenceTransitionOut = false;
 148   sequenceNeverTransition = false;
 149   sequenceTransitionTime = 0;
 150   direction = false;
 151   emitterTime = 0.0f;
 152
 153   for( U32 i=0; i<MaxShapes; ++i)
 154   {
 155      sequence[i] = -1;
 156      sequenceVis[i] = -1;
 157      flashSequence[i] = false;
 158      emitterNode[i] = -1;
 159   }
 160}
 161
 162static ShapeBaseImageData::StateData gDefaultStateData;
 163
 164//----------------------------------------------------------------------------
 165
 166ShapeBaseImageData::ShapeBaseImageData()
 167{
 168   emap = false;
 169
 170   mountPoint = 0;
 171   mountOffset.identity();
 172   eyeOffset.identity();
 173   correctMuzzleVector = true;
 174   correctMuzzleVectorTP = true;
 175   firstPerson = true;
 176   useFirstPersonShape = false;
 177   useEyeOffset = false;
 178   useEyeNode = false;
 179   mass = 0;
 180
 181   usesEnergy = false;
 182   minEnergy = 2;
 183   accuFire = false;
 184
 185   projectile = NULL;
 186
 187   cloakable = true;
 188
 189   lightType = ShapeBaseImageData::NoLight;
 190   lightColor.set(1.f,1.f,1.f,1.f);
 191   lightDuration = 1000;
 192   lightRadius = 10.f;
 193   lightBrightness = 1.0f;
 194
 195   shapeName = "core/rendering/shapes/noshape.dts";
 196   shapeNameFP = "";
 197   imageAnimPrefix = "";
 198   imageAnimPrefixFP = "";
 199   fireState = -1;
 200   altFireState = -1;
 201   reloadState = -1;
 202   computeCRC = false;
 203
 204   animateAllShapes = true;
 205   animateOnServer = false;
 206
 207   scriptAnimTransitionTime = 0.25f;
 208
 209   //
 210   for (S32 i = 0; i < MaxStates; i++) {
 211      stateName[i] = 0;
 212
 213      stateTransitionLoaded[i] = 0;
 214      stateTransitionNotLoaded[i] = 0;
 215      stateTransitionAmmo[i] = 0;
 216      stateTransitionNoAmmo[i] = 0;
 217      stateTransitionTarget[i] = 0;
 218      stateTransitionNoTarget[i] = 0;
 219      stateTransitionWet[i] = 0;
 220      stateTransitionNotWet[i] = 0;
 221      stateTransitionMotion[i] = 0;
 222      stateTransitionNoMotion[i] = 0;
 223      stateTransitionTriggerUp[i] = 0;
 224      stateTransitionTriggerDown[i] = 0;
 225      stateTransitionAltTriggerUp[i] = 0;
 226      stateTransitionAltTriggerDown[i] = 0;
 227      stateTransitionTimeout[i] = 0;
 228
 229      stateTransitionGeneric0In[i] = 0;
 230      stateTransitionGeneric0Out[i] = 0;
 231      stateTransitionGeneric1In[i] = 0;
 232      stateTransitionGeneric1Out[i] = 0;
 233      stateTransitionGeneric2In[i] = 0;
 234      stateTransitionGeneric2Out[i] = 0;
 235      stateTransitionGeneric3In[i] = 0;
 236      stateTransitionGeneric3Out[i] = 0;
 237
 238      stateWaitForTimeout[i] = true;
 239      stateTimeoutValue[i] = 0;
 240      stateFire[i] = false;
 241      stateAlternateFire[i] = false;
 242      stateReload[i] = false;
 243      stateEjectShell[i] = false;
 244      stateEnergyDrain[i] = 0;
 245      stateAllowImageChange[i] = true;
 246      stateScaleAnimation[i] = true;
 247      stateScaleAnimationFP[i] = true;
 248      stateSequenceTransitionIn[i] = false;
 249      stateSequenceTransitionOut[i] = false;
 250      stateSequenceNeverTransition[i] = false;
 251      stateSequenceTransitionTime[i] = 0.25f;
 252      stateDirection[i] = true;
 253      stateLoaded[i] = StateData::IgnoreLoaded;
 254      stateSpin[i] = StateData::IgnoreSpin;
 255      stateRecoil[i] = StateData::NoRecoil;
 256      stateSequence[i] = 0;
 257      stateSequenceRandomFlash[i] = false;
 258
 259      stateShapeSequence[i] = 0;
 260      stateScaleShapeSequence[i] = false;
 261
 262      stateSound[i] = 0;
 263      stateScript[i] = 0;
 264      stateEmitter[i] = 0;
 265      stateEmitterTime[i] = 0;
 266      stateEmitterNode[i] = 0;
 267      stateIgnoreLoadedForReady[i] = false;
 268   }
 269   statesLoaded = false;
 270
 271   maxConcurrentSounds = 0;
 272
 273   useRemainderDT = false;
 274
 275   casing = NULL;
 276   casingID = 0;
 277   shellExitDir.set( 1.0, 0.0, 1.0 );
 278   shellExitDir.normalize();
 279   shellExitVariance = 20.0;
 280   shellVelocity = 1.0;
 281   
 282   fireStateName = NULL;
 283
 284   for(U32 i=0; i<MaxShapes; ++i)
 285   {
 286      mCRC[i] = U32_MAX;
 287      mountTransform[i].identity();
 288      retractNode[i] = -1;
 289      muzzleNode[i] = -1;
 290      ejectNode[i] = -1;
 291      emitterNode[i] = -1;
 292      eyeMountNode[i] = -1;
 293      eyeNode[i] = -1;
 294      spinSequence[i] = -1;
 295      ambientSequence[i] = -1;
 296      isAnimated[i] = false;
 297      hasFlash[i] = false;
 298      shapeIsValid[i] = false;
 299   }
 300
 301   shakeCamera = false;
 302   camShakeFreq = Point3F::Zero;
 303   camShakeAmp = Point3F::Zero;
 304   camShakeDuration = 1.5f;
 305   camShakeRadius = 3.0f;
 306   camShakeFalloff = 10.0f;
 307}
 308
 309ShapeBaseImageData::~ShapeBaseImageData()
 310{
 311}
 312
 313bool ShapeBaseImageData::onAdd()
 314{
 315   if (!Parent::onAdd())
 316      return false;
 317
 318   // Copy state data from the scripting arrays into the
 319   // state structure array. If we have state data already,
 320   // we are on the client and need to leave it alone.
 321   for (U32 i = 0; i < MaxStates; i++) {
 322      StateData& s = state[i];
 323      if (statesLoaded == false) {
 324         s.name = stateName[i];
 325         s.transition.loaded[0] = lookupState(stateTransitionNotLoaded[i]);
 326         s.transition.loaded[1] = lookupState(stateTransitionLoaded[i]);
 327         s.transition.ammo[0] = lookupState(stateTransitionNoAmmo[i]);
 328         s.transition.ammo[1] = lookupState(stateTransitionAmmo[i]);
 329         s.transition.target[0] = lookupState(stateTransitionNoTarget[i]);
 330         s.transition.target[1] = lookupState(stateTransitionTarget[i]);
 331         s.transition.wet[0] = lookupState(stateTransitionNotWet[i]);
 332         s.transition.wet[1] = lookupState(stateTransitionWet[i]);
 333         s.transition.motion[0] = lookupState(stateTransitionNoMotion[i]);
 334         s.transition.motion[1] = lookupState(stateTransitionMotion[i]);
 335         s.transition.trigger[0] = lookupState(stateTransitionTriggerUp[i]);
 336         s.transition.trigger[1] = lookupState(stateTransitionTriggerDown[i]);
 337         s.transition.altTrigger[0] = lookupState(stateTransitionAltTriggerUp[i]);
 338         s.transition.altTrigger[1] = lookupState(stateTransitionAltTriggerDown[i]);
 339         s.transition.timeout = lookupState(stateTransitionTimeout[i]);
 340
 341         s.transition.genericTrigger[0][0] = lookupState(stateTransitionGeneric0Out[i]);
 342         s.transition.genericTrigger[0][1] = lookupState(stateTransitionGeneric0In[i]);
 343         s.transition.genericTrigger[1][0] = lookupState(stateTransitionGeneric1Out[i]);
 344         s.transition.genericTrigger[1][1] = lookupState(stateTransitionGeneric1In[i]);
 345         s.transition.genericTrigger[2][0] = lookupState(stateTransitionGeneric2Out[i]);
 346         s.transition.genericTrigger[2][1] = lookupState(stateTransitionGeneric2In[i]);
 347         s.transition.genericTrigger[3][0] = lookupState(stateTransitionGeneric3Out[i]);
 348         s.transition.genericTrigger[3][1] = lookupState(stateTransitionGeneric3In[i]);
 349
 350         s.waitForTimeout = stateWaitForTimeout[i];
 351         s.timeoutValue = stateTimeoutValue[i];
 352         s.fire = stateFire[i];
 353         s.altFire = stateAlternateFire[i];
 354         s.reload = stateReload[i];
 355         s.ejectShell = stateEjectShell[i];
 356         s.energyDrain = stateEnergyDrain[i];
 357         s.allowImageChange = stateAllowImageChange[i];
 358         s.scaleAnimation = stateScaleAnimation[i];
 359         s.scaleAnimationFP = stateScaleAnimationFP[i];
 360         s.sequenceTransitionIn = stateSequenceTransitionIn[i];
 361         s.sequenceTransitionOut = stateSequenceTransitionOut[i];
 362         s.sequenceNeverTransition = stateSequenceNeverTransition[i];
 363         s.sequenceTransitionTime = stateSequenceTransitionTime[i];
 364         s.direction = stateDirection[i];
 365         s.loaded = stateLoaded[i];
 366         s.spin = stateSpin[i];
 367         s.recoil = stateRecoil[i];
 368
 369         s.shapeSequence = stateShapeSequence[i];
 370         s.shapeSequenceScale = stateScaleShapeSequence[i];
 371
 372         s.sound = stateSound[i];
 373         s.script = stateScript[i];
 374         s.emitter = stateEmitter[i];
 375         s.emitterTime = stateEmitterTime[i];
 376
 377         // Resolved at load time
 378         for( U32 j=0; j<MaxShapes; ++j)
 379         {
 380            s.sequence[j]     = -1;    // Sequence is resolved in load
 381            s.sequenceVis[j]  = -1;    // Vis Sequence is resolved in load
 382            s.emitterNode[j]  = -1;    // Sequnce is resolved in load
 383         }
 384      }
 385
 386      // The first state marked as "fire" is the state entered on the
 387      // client when it recieves a fire event.
 388      if (s.fire && fireState == -1)
 389         fireState = i;
 390
 391      // The first state marked as "alternateFire" is the state entered on the
 392      // client when it recieves an alternate fire event.
 393      if (s.altFire && altFireState == -1)
 394         altFireState = i;
 395
 396      // The first state marked as "reload" is the state entered on the
 397      // client when it recieves a reload event.
 398      if (s.reload && reloadState == -1)
 399         reloadState = i;
 400   }
 401
 402   // Always preload images, this is needed to avoid problems with
 403   // resolving sequences before transmission to a client.
 404   return true;
 405}
 406
 407bool ShapeBaseImageData::preload(bool server, String &errorStr)
 408{
 409   if (!Parent::preload(server, errorStr))
 410      return false;
 411
 412   // Resolve objects transmitted from server
 413   if (!server) {
 414      if (projectile)
 415         if (Sim::findObject(SimObjectId((uintptr_t)projectile), projectile) == false)
 416            Con::errorf(ConsoleLogEntry::General, "Error, unable to load projectile for shapebaseimagedata");
 417
 418      for (U32 i = 0; i < MaxStates; i++) {
 419         if (state[i].emitter)
 420            if (!Sim::findObject(SimObjectId((uintptr_t)state[i].emitter), state[i].emitter))
 421               Con::errorf(ConsoleLogEntry::General, "Error, unable to load emitter for image datablock");
 422               
 423         String str;
 424         if( !sfxResolve( &state[ i ].sound, str ) )
 425            Con::errorf( ConsoleLogEntry::General, str.c_str() );
 426      }
 427   }
 428
 429   // Use the first person eye offset if it's set.
 430   useEyeOffset = !eyeOffset.isIdentity();
 431
 432   // Go through each of the shapes
 433   for (U32 i=0; i<MaxShapes; ++i)
 434   {
 435      // Shape 0: Standard image shape
 436      // Shape 1: Optional first person image shape
 437
 438      StringTableEntry name;
 439      if (i == FirstPersonImageShape)
 440      {
 441         if ((useEyeOffset || useEyeNode) && shapeNameFP && shapeNameFP[0])
 442         {
 443            // Make use of the first person shape
 444            useFirstPersonShape = true;
 445            name = shapeNameFP;
 446         }
 447         else
 448         {
 449            // Skip the first person shape
 450            continue;
 451         }
 452      }
 453      else
 454      {
 455         name = shapeName;
 456      }
 457
 458      if (name && name[0]) {
 459         // Resolve shapename
 460         shape[i] = ResourceManager::get().load(name);
 461         if (!bool(shape[i])) {
 462            errorStr = String::ToString("Unable to load shape: %s", name);
 463            return false;
 464         }
 465         if(computeCRC)
 466         {
 467            Con::printf("Validation required for shape: %s", name);
 468
 469            Torque::FS::FileNodeRef    fileRef = Torque::FS::GetFileNode(shape[i].getPath());
 470
 471            if (!fileRef)
 472            {
 473               errorStr = String::ToString("ShapeBaseImageData: Couldn't load shape \"%s\"",name);
 474               return false;
 475            }
 476
 477            if(server)
 478            {
 479               mCRC[i] = fileRef->getChecksum();
 480            }
 481            else if(mCRC[i] != fileRef->getChecksum())
 482            {
 483               errorStr = String::ToString("Shape \"%s\" does not match version on server.",name);
 484               return false;
 485            }
 486         }
 487
 488         // Resolve nodes & build mount transform
 489         eyeMountNode[i] = shape[i]->findNode("eyeMount");
 490         eyeNode[i] = shape[i]->findNode("eye");
 491         if (eyeNode[i] == -1)
 492            eyeNode[i] = eyeMountNode[i];
 493         ejectNode[i] = shape[i]->findNode("ejectPoint");
 494         muzzleNode[i] = shape[i]->findNode("muzzlePoint");
 495         retractNode[i] = shape[i]->findNode("retractionPoint");
 496         mountTransform[i] = mountOffset;
 497         S32 node = shape[i]->findNode("mountPoint");
 498         if (node != -1) {
 499            MatrixF total(1);
 500            do {
 501               MatrixF nmat;
 502               QuatF q;
 503               TSTransform::setMatrix(shape[i]->defaultRotations[node].getQuatF(&q),shape[i]->defaultTranslations[node],&nmat);
 504               total.mul(nmat);
 505               node = shape[i]->nodes[node].parentIndex;
 506            }
 507            while(node != -1);
 508            total.inverse();
 509            mountTransform[i].mul(total);
 510         }
 511
 512         // Resolve state sequence names & emitter nodes
 513         isAnimated[i] = false;
 514         hasFlash[i] = false;
 515         for (U32 j = 0; j < MaxStates; j++) {
 516            StateData& s = state[j];
 517            if (stateSequence[j] && stateSequence[j][0])
 518               s.sequence[i] = shape[i]->findSequence(stateSequence[j]);
 519            if (s.sequence[i] != -1)
 520            {
 521               // This state has an animation sequence
 522               isAnimated[i] = true;
 523            }
 524
 525            if (stateSequence[j] && stateSequence[j][0] && stateSequenceRandomFlash[j]) {
 526               char bufferVis[128];
 527               dStrncpy(bufferVis, stateSequence[j], 100);
 528               dStrcat(bufferVis, "_vis", 128);
 529               s.sequenceVis[i] = shape[i]->findSequence(bufferVis);
 530            }
 531            if (s.sequenceVis[i] != -1)
 532            {
 533               // This state has a flash animation sequence
 534               s.flashSequence[i] = true;
 535               hasFlash[i] = true;
 536            }
 537
 538            s.ignoreLoadedForReady = stateIgnoreLoadedForReady[j];
 539
 540            if (stateEmitterNode[j] && stateEmitterNode[j][0])
 541               s.emitterNode[i] = shape[i]->findNode(stateEmitterNode[j]);
 542            if (s.emitterNode[i] == -1)
 543               s.emitterNode[i] = muzzleNode[i];
 544         }
 545
 546         ambientSequence[i] = shape[i]->findSequence("ambient");
 547         spinSequence[i] = shape[i]->findSequence("spin");
 548
 549         shapeIsValid[i] = true;
 550      }
 551      else {
 552         errorStr = "Bad Datablock from server";
 553         return false;
 554      }
 555   }
 556
 557   if( !casing && casingID != 0 )
 558   {
 559      if( !Sim::findObject( SimObjectId( casingID ), casing ) )
 560      {
 561         Con::errorf( ConsoleLogEntry::General, "ShapeBaseImageData::preload: Invalid packet, bad datablockId(casing): 0x%x", casingID );
 562      }
 563   }
 564
 565
 566   // Preload the shapes
 567   for( U32 i=0; i<MaxShapes; ++i)
 568   {
 569      if( shapeIsValid[i] )
 570      {
 571         TSShapeInstance* pDummy = new TSShapeInstance(shape[i], !server);
 572         delete pDummy;
 573      }
 574   }
 575   return true;
 576}
 577
 578S32 ShapeBaseImageData::lookupState(const char* name)
 579{
 580   if (!name || !name[0])
 581      return -1;
 582   for (U32 i = 0; i < MaxStates; i++)
 583      if (stateName[i] && !dStricmp(name,stateName[i]))
 584         return i;
 585   Con::errorf(ConsoleLogEntry::General,"ShapeBaseImageData:: Could not resolve state \"%s\" for image \"%s\"",name,getName());
 586   return 0;
 587}
 588
 589void ShapeBaseImageData::initPersistFields()
 590{
 591   addField( "emap", TypeBool, Offset(emap, ShapeBaseImageData),
 592      "@brief Whether to enable environment mapping on this Image.\n\n" );
 593
 594   addField( "shapeFile", TypeShapeFilename, Offset(shapeName, ShapeBaseImageData),
 595      "@brief The DTS or DAE model to use for this Image.\n\n" );
 596
 597   addField( "shapeFileFP", TypeShapeFilename, Offset(shapeNameFP, ShapeBaseImageData),
 598      "@brief The DTS or DAE model to use for this Image when in first person.\n\n"
 599      "This is an optional parameter that also requires either eyeOffset or useEyeNode "
 600      "to be set.  If none of these conditions is met then shapeFile will be used "
 601      "for all cases.\n\n"
 602      "Typically you set a first person image for a weapon that "
 603      "includes the player's arms attached to it for animating while firing, "
 604      "reloading, etc.  This is typical of many FPS games."
 605      "@see eyeOffset\n"
 606      "@see useEyeNode\n");
 607
 608   addField( "imageAnimPrefix", TypeCaseString, Offset(imageAnimPrefix, ShapeBaseImageData),
 609      "@brief Passed along to the mounting shape to modify animation sequences played in third person. [optional]\n\n" );
 610   addField( "imageAnimPrefixFP", TypeCaseString, Offset(imageAnimPrefixFP, ShapeBaseImageData),
 611      "@brief Passed along to the mounting shape to modify animation sequences played in first person. [optional]\n\n" );
 612
 613   addField( "animateAllShapes", TypeBool, Offset(animateAllShapes, ShapeBaseImageData),
 614      "@brief Indicates that all shapes should be animated in sync.\n\n"
 615      "When multiple shapes are defined for this image datablock, each of them are automatically "
 616      "animated in step with each other.  This allows for easy switching between between shapes "
 617      "when some other condition changes, such as going from first person to third person, and "
 618      "keeping their look consistent.  If you know that you'll never switch between shapes on the "
 619      "fly, such as players only being allowed in a first person view, then you could set this to "
 620      "false to save some calculations.\n\n"
 621      "There are other circumstances internal to the engine that determine that only the current shape "
 622      "should be animated rather than all defined shapes.  In those cases, this property is ignored.\n\n"
 623      "@note This property is only important if you have more than one shape defined, such as shapeFileFP.\n\n"
 624      "@see shapeFileFP\n");
 625
 626   addField( "animateOnServer", TypeBool, Offset(animateOnServer, ShapeBaseImageData),
 627      "@brief Indicates that the image should be animated on the server.\n\n"
 628      "In most cases you'll want this set if you're using useEyeNode.  You may also want to "
 629      "set this if the muzzlePoint is animated while it shoots.  You can set this "
 630      "to false even if these previous cases are true if the image's shape is set "
 631      "up in the correct position and orientation in the 'root' pose and none of "
 632      "the nodes are animated at key times, such as the muzzlePoint essentially "
 633      "remaining at the same position at the start of the fire state (it could "
 634      "animate just fine after the projectile is away as the muzzle vector is only "
 635      "calculated at the start of the state).\n\n"
 636      "You'll also want to set this to true if you're animating the camera using the "
 637      "image's 'eye' node -- unless the movement is very subtle and doesn't need to "
 638      "be reflected on the server.\n\n"
 639      "@note Setting this to true causes up to four animation threads to be advanced on the server "
 640      "for each instance in use, although for most images only one or two are actually defined.\n\n"
 641      "@see useEyeNode\n");
 642
 643   addField( "scriptAnimTransitionTime", TypeF32, Offset(scriptAnimTransitionTime, ShapeBaseImageData),
 644      "@brief The amount of time to transition between the previous sequence and new sequence when the script prefix has changed.\n\n"
 645      "When setImageScriptAnimPrefix() is used on a ShapeBase that has this image mounted, the image "
 646      "will attempt to switch to the new animation sequence based on the given script prefix.  This is "
 647      "the amount of time it takes to transition from the previously playing animation sequence to"
 648      "the new script prefix-based animation sequence.\n"
 649      "@see ShapeBase::setImageScriptAnimPrefix()");
 650
 651   addField( "projectile", TYPEID< ProjectileData >(), Offset(projectile, ShapeBaseImageData),
 652      "@brief The projectile fired by this Image\n\n" );
 653
 654   addField( "cloakable", TypeBool, Offset(cloakable, ShapeBaseImageData),
 655      "@brief Whether this Image can be cloaked.\n\n"
 656      "Currently unused." );
 657
 658   addField( "mountPoint", TypeS32, Offset(mountPoint, ShapeBaseImageData),
 659      "@brief Mount node # to mount this Image to.\n\n"
 660      "This should correspond to a mount# node on the ShapeBase derived object we are mounting to." );
 661
 662   addField( "offset", TypeMatrixPosition, Offset(mountOffset, ShapeBaseImageData),
 663      "@brief \"X Y Z\" translation offset from this Image's <i>mountPoint</i> node to "
 664      "attach to.\n\n"
 665      "Defaults to \"0 0 0\". ie. attach this Image's "
 666      "<i>mountPoint</i> node to the ShapeBase model's mount# node without any offset.\n"
 667      "@see rotation");
 668
 669   addField( "rotation", TypeMatrixRotation, Offset(mountOffset, ShapeBaseImageData),
 670      "@brief \"X Y Z ANGLE\" rotation offset from this Image's <i>mountPoint</i> node "
 671      "to attach to.\n\n"
 672      "Defaults to \"0 0 0\". ie. attach this Image's "
 673      "<i>mountPoint</i> node to the ShapeBase model's mount# node without any additional rotation.\n"
 674      "@see offset");
 675
 676   addField( "eyeOffset", TypeMatrixPosition, Offset(eyeOffset, ShapeBaseImageData),
 677      "@brief \"X Y Z\" translation offset from the ShapeBase model's eye node.\n\n"
 678      "When in first person view, this is the offset from the eye node to place the gun.  This "
 679      "gives the gun a fixed point in space, typical of a lot of FPS games.\n"
 680      "@see eyeRotation");
 681
 682   addField( "eyeRotation", TypeMatrixRotation, Offset(eyeOffset, ShapeBaseImageData),
 683      "@brief \"X Y Z ANGLE\" rotation offset from the ShapeBase model's eye node.\n\n"
 684      "When in first person view, this is the rotation from the eye node to place the gun.\n"
 685      "@see eyeOffset");
 686
 687   addField( "useEyeNode", TypeBool, Offset(useEyeNode, ShapeBaseImageData),
 688      "@brief Mount image using image's eyeMount node and place the camera at the image's eye node (or "
 689      "at the eyeMount node if the eye node is missing).\n\n"
 690      "When in first person view, if an 'eyeMount' node is present in the image's shape, this indicates "
 691      "that the image should mount eyeMount node to Player eye node for image placement.  The "
 692      "Player's camera should also mount to the image's eye node to inherit any animation (or the eyeMount "
 693      "node if the image doesn't have an eye node).\n\n"
 694      "@note Used instead of eyeOffset.\n\n"
 695      "@note Read about the animateOnServer field as you may want to set it to true if you're using useEyeNode.\n\n"
 696      "@see eyeOffset\n\n"
 697      "@see animateOnServer\n\n");
 698
 699   addField( "correctMuzzleVector", TypeBool,  Offset(correctMuzzleVector, ShapeBaseImageData),
 700      "@brief Flag to adjust the aiming vector to the eye's LOS point when in 1st person view.\n\n"
 701      "@see ShapeBase::getMuzzleVector()" );
 702
 703   addField( "correctMuzzleVectorTP", TypeBool,  Offset(correctMuzzleVectorTP, ShapeBaseImageData),
 704      "@brief Flag to adjust the aiming vector to the camera's LOS point when in 3rd person view.\n\n"
 705      "@see ShapeBase::getMuzzleVector()" );
 706
 707   addField( "firstPerson", TypeBool, Offset(firstPerson, ShapeBaseImageData),
 708      "@brief Set to true to render the image in first person." );
 709
 710   addField( "mass", TypeF32, Offset(mass, ShapeBaseImageData),
 711      "@brief Mass of this Image.\n\n"
 712      "This is added to the total mass of the ShapeBase object." );
 713
 714   addField( "usesEnergy", TypeBool, Offset(usesEnergy,ShapeBaseImageData),
 715      "@brief Flag indicating whether this Image uses energy instead of ammo.  The energy level comes from the ShapeBase object we're mounted to.\n\n"
 716      "@see ShapeBase::setEnergyLevel()");
 717
 718   addField( "minEnergy", TypeF32, Offset(minEnergy, ShapeBaseImageData),
 719      "@brief Minimum Image energy for it to be operable.\n\n"
 720      "@see usesEnergy");
 721
 722   addField( "accuFire", TypeBool, Offset(accuFire, ShapeBaseImageData),
 723      "@brief Flag to control whether the Image's aim is automatically converged with "
 724      "the crosshair.\n\n"
 725      "Currently unused." );
 726
 727   addField( "lightType", TYPEID< ShapeBaseImageData::LightType >(), Offset(lightType, ShapeBaseImageData),
 728      "@brief The type of light this Image emits.\n\n"
 729      "@see ShapeBaseImageLightType");
 730
 731   addField( "lightColor", TypeColorF, Offset(lightColor, ShapeBaseImageData),
 732      "@brief The color of light this Image emits.\n\n"
 733      "@see lightType");
 734
 735   addField( "lightDuration", TypeS32, Offset(lightDuration, ShapeBaseImageData),
 736      "@brief Duration in SimTime of Pulsing and WeaponFire type lights.\n\n"
 737      "@see lightType");
 738
 739   addField( "lightRadius", TypeF32, Offset(lightRadius, ShapeBaseImageData),
 740      "@brief Radius of the light this Image emits.\n\n"
 741      "@see lightType");
 742
 743   addField( "lightBrightness", TypeF32, Offset(lightBrightness, ShapeBaseImageData),
 744      "@brief Brightness of the light this Image emits.\n\n"
 745      "Only valid for WeaponFireLight."
 746      "@see lightType");
 747
 748   addField( "shakeCamera", TypeBool, Offset(shakeCamera, ShapeBaseImageData),
 749      "@brief Flag indicating whether the camera should shake when this Image fires.\n\n" );
 750
 751   addField( "camShakeFreq", TypePoint3F, Offset(camShakeFreq, ShapeBaseImageData),
 752      "@brief Frequency of the camera shaking effect.\n\n"
 753      "@see shakeCamera" );
 754
 755   addField( "camShakeAmp", TypePoint3F, Offset(camShakeAmp, ShapeBaseImageData),
 756      "@brief Amplitude of the camera shaking effect.\n\n"
 757      "@see shakeCamera" );
 758
 759   addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ShapeBaseImageData),
 760      "Duration (in seconds) to shake the camera." );
 761
 762   addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ShapeBaseImageData),
 763      "Radial distance that a camera's position must be within relative to the "
 764      "center of the explosion to be shaken." );
 765
 766   addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ShapeBaseImageData),
 767      "Falloff value for the camera shake." );
 768
 769   addField( "casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData),
 770      "@brief DebrisData datablock to use for ejected casings.\n\n"
 771      "@see stateEjectShell" );
 772
 773   addField( "shellExitDir", TypePoint3F, Offset(shellExitDir, ShapeBaseImageData),
 774      "@brief Vector direction to eject shell casings.\n\n"
 775      "@see casing");
 776
 777   addField( "shellExitVariance", TypeF32, Offset(shellExitVariance, ShapeBaseImageData),
 778      "@brief Variance (in degrees) from the shellExitDir vector to eject casings.\n\n"
 779      "@see shellExitDir");
 780
 781   addField( "shellVelocity", TypeF32, Offset(shellVelocity, ShapeBaseImageData),
 782      "@brief Speed at which to eject casings.\n\n"
 783      "@see casing");
 784
 785   // State arrays
 786   addArray( "States", MaxStates );
 787
 788      addField( "stateName", TypeCaseString, Offset(stateName, ShapeBaseImageData), MaxStates,
 789         "Name of this state." );
 790
 791      addField( "stateTransitionOnLoaded", TypeString, Offset(stateTransitionLoaded, ShapeBaseImageData), MaxStates,
 792         "Name of the state to transition to when the loaded state of the Image "
 793         "changes to 'Loaded'." );
 794      addField( "stateTransitionOnNotLoaded", TypeString, Offset(stateTransitionNotLoaded, ShapeBaseImageData), MaxStates,
 795         "Name of the state to transition to when the loaded state of the Image "
 796         "changes to 'Empty'." );
 797      addField( "stateTransitionOnAmmo", TypeString, Offset(stateTransitionAmmo, ShapeBaseImageData), MaxStates,
 798         "Name of the state to transition to when the ammo state of the Image "
 799         "changes to true." );
 800      addField( "stateTransitionOnNoAmmo", TypeString, Offset(stateTransitionNoAmmo, ShapeBaseImageData), MaxStates,
 801         "Name of the state to transition to when the ammo state of the Image "
 802         "changes to false." );
 803      addField( "stateTransitionOnTarget", TypeString, Offset(stateTransitionTarget, ShapeBaseImageData), MaxStates,
 804         "Name of the state to transition to when the Image gains a target." );
 805      addField( "stateTransitionOnNoTarget", TypeString, Offset(stateTransitionNoTarget, ShapeBaseImageData), MaxStates,
 806         "Name of the state to transition to when the Image loses a target." );
 807      addField( "stateTransitionOnWet", TypeString, Offset(stateTransitionWet, ShapeBaseImageData), MaxStates,
 808         "Name of the state to transition to when the Image enters the water." );
 809      addField( "stateTransitionOnNotWet", TypeString, Offset(stateTransitionNotWet, ShapeBaseImageData), MaxStates,
 810         "Name of the state to transition to when the Image exits the water." );
 811      addField( "stateTransitionOnMotion", TypeString, Offset(stateTransitionMotion, ShapeBaseImageData), MaxStates,
 812         "Name of the state to transition to when the Player moves." );
 813      addField( "stateTransitionOnNoMotion", TypeString, Offset(stateTransitionNoMotion, ShapeBaseImageData), MaxStates,
 814         "Name of the state to transition to when the Player stops moving." );
 815      addField( "stateTransitionOnTriggerUp", TypeString, Offset(stateTransitionTriggerUp, ShapeBaseImageData), MaxStates,
 816         "Name of the state to transition to when the trigger state of the Image "
 817         "changes to true (fire button down)." );
 818      addField( "stateTransitionOnTriggerDown", TypeString, Offset(stateTransitionTriggerDown, ShapeBaseImageData), MaxStates,
 819         "Name of the state to transition to when the trigger state of the Image "
 820         "changes to false (fire button released)." );
 821      addField( "stateTransitionOnAltTriggerUp", TypeString, Offset(stateTransitionAltTriggerUp, ShapeBaseImageData), MaxStates,
 822         "Name of the state to transition to when the alt trigger state of the "
 823         "Image changes to true (alt fire button down)." );
 824      addField( "stateTransitionOnAltTriggerDown", TypeString, Offset(stateTransitionAltTriggerDown, ShapeBaseImageData), MaxStates,
 825         "Name of the state to transition to when the alt trigger state of the "
 826         "Image changes to false (alt fire button up)." );
 827      addField( "stateTransitionOnTimeout", TypeString, Offset(stateTransitionTimeout, ShapeBaseImageData), MaxStates,
 828         "Name of the state to transition to when we have been in this state "
 829         "for stateTimeoutValue seconds." );
 830
 831      addField( "stateTransitionGeneric0In", TypeString, Offset(stateTransitionGeneric0In, ShapeBaseImageData), MaxStates,
 832         "Name of the state to transition to when the generic trigger 0 state "
 833         "changes to true." );
 834      addField( "stateTransitionGeneric0Out", TypeString, Offset(stateTransitionGeneric0Out, ShapeBaseImageData), MaxStates,
 835         "Name of the state to transition to when the generic trigger 0 state "
 836         "changes to false." );
 837      addField( "stateTransitionGeneric1In", TypeString, Offset(stateTransitionGeneric1In, ShapeBaseImageData), MaxStates,
 838         "Name of the state to transition to when the generic trigger 1 state "
 839         "changes to true." );
 840      addField( "stateTransitionGeneric1Out", TypeString, Offset(stateTransitionGeneric1Out, ShapeBaseImageData), MaxStates,
 841         "Name of the state to transition to when the generic trigger 1 state "
 842         "changes to false." );
 843      addField( "stateTransitionGeneric2In", TypeString, Offset(stateTransitionGeneric2In, ShapeBaseImageData), MaxStates,
 844         "Name of the state to transition to when the generic trigger 2 state "
 845         "changes to true." );
 846      addField( "stateTransitionGeneric2Out", TypeString, Offset(stateTransitionGeneric2Out, ShapeBaseImageData), MaxStates,
 847         "Name of the state to transition to when the generic trigger 2 state "
 848         "changes to false." );
 849      addField( "stateTransitionGeneric3In", TypeString, Offset(stateTransitionGeneric3In, ShapeBaseImageData), MaxStates,
 850         "Name of the state to transition to when the generic trigger 3 state "
 851         "changes to true." );
 852      addField( "stateTransitionGeneric3Out", TypeString, Offset(stateTransitionGeneric3Out, ShapeBaseImageData), MaxStates,
 853         "Name of the state to transition to when the generic trigger 3 state "
 854         "changes to false." );
 855
 856      addField( "stateTimeoutValue", TypeF32, Offset(stateTimeoutValue, ShapeBaseImageData), MaxStates,
 857         "Time in seconds to wait before transitioning to stateTransitionOnTimeout." );
 858      addField( "stateWaitForTimeout", TypeBool, Offset(stateWaitForTimeout, ShapeBaseImageData), MaxStates,
 859         "If false, this state ignores stateTimeoutValue and transitions "
 860         "immediately if other transition conditions are met." );
 861      addField( "stateFire", TypeBool, Offset(stateFire, ShapeBaseImageData), MaxStates,
 862         "The first state with this set to true is the state entered by the "
 863         "client when it receives the 'fire' event." );
 864      addField( "stateAlternateFire", TypeBool, Offset(stateAlternateFire, ShapeBaseImageData), MaxStates,
 865         "The first state with this set to true is the state entered by the "
 866         "client when it receives the 'altFire' event." );
 867      addField( "stateReload", TypeBool, Offset(stateReload, ShapeBaseImageData), MaxStates,
 868         "The first state with this set to true is the state entered by the "
 869         "client when it receives the 'reload' event." );
 870      addField( "stateEjectShell", TypeBool, Offset(stateEjectShell, ShapeBaseImageData), MaxStates,
 871         "If true, a shell casing will be ejected in this state." );
 872      addField( "stateEnergyDrain", TypeF32, Offset(stateEnergyDrain, ShapeBaseImageData), MaxStates,
 873         "@brief Amount of energy to subtract from the Image in this state.\n\n"
 874         "Energy is drained at stateEnergyDrain units/tick as long as we are in "
 875         "this state.\n"
 876         "@see usesEnergy");
 877      addField( "stateAllowImageChange", TypeBool, Offset(stateAllowImageChange, ShapeBaseImageData), MaxStates,
 878         "@brief If false, other Images will temporarily be blocked from mounting "
 879         "while the state machine is executing the tasks in this state.\n\n"
 880         "For instance, if we have a rocket launcher, the player shouldn't "
 881         "be able to switch out <i>while</i> firing. So, you'd set "
 882         "stateAllowImageChange to false in firing states, and true the rest "
 883         "of the time." );
 884      addField( "stateDirection", TypeBool, Offset(stateDirection, ShapeBaseImageData), MaxStates,
 885         "@brief Direction of the animation to play in this state.\n\n"
 886         "True is forward, false is backward." );
 887      addField( "stateLoadedFlag", TYPEID< ShapeBaseImageData::StateData::LoadedState >(), Offset(stateLoaded, ShapeBaseImageData), MaxStates,
 888         "@brief Set the loaded state of the Image.\n\n"
 889         "<ul><li>IgnoreLoaded: Don't change Image loaded state.</li>"
 890         "<li>Loaded: Set Image loaded state to true.</li>"
 891         "<li>NotLoaded: Set Image loaded state to false.</li></ul>\n"
 892         "@see ShapeBaseImageLoadedState");
 893      addField( "stateSpinThread", TYPEID< ShapeBaseImageData::StateData::SpinState >(), Offset(stateSpin, ShapeBaseImageData), MaxStates,
 894         "@brief Controls how fast the 'spin' animation sequence will be played in "
 895         "this state.\n\n"
 896         "<ul><li>Ignore: No change to the spin sequence.</li>"
 897         "<li>Stop: Stops the spin sequence at its current position.</li>"
 898         "<li>SpinUp: Increase spin sequence timeScale from 0 (on state entry) "
 899         "to 1 (after stateTimeoutValue seconds).</li>"
 900         "<li>SpinDown: Decrease spin sequence timeScale from 1 (on state entry) "
 901         "to 0 (after stateTimeoutValue seconds).</li>"
 902         "<li>FullSpeed: Resume the spin sequence playback at its current "
 903         "position with timeScale=1.</li></ul>\n"
 904         "@see ShapeBaseImageSpinState");
 905      addField( "stateRecoil", TYPEID< ShapeBaseImageData::StateData::RecoilState >(), Offset(stateRecoil, ShapeBaseImageData), MaxStates,
 906         "@brief Type of recoil sequence to play on the ShapeBase object on entry to "
 907         "this state.\n\n"
 908         "<ul><li>NoRecoil: Do not play a recoil sequence.</li>"
 909         "<li>LightRecoil: Play the light_recoil sequence.</li>"
 910         "<li>MediumRecoil: Play the medium_recoil sequence.</li>"
 911         "<li>HeavyRecoil: Play the heavy_recoil sequence.</li></ul>\n"
 912         "@see ShapeBaseImageRecoilState");
 913      addField( "stateSequence", TypeString, Offset(stateSequence, ShapeBaseImageData), MaxStates,
 914         "Name of the sequence to play on entry to this state." );
 915      addField( "stateSequenceRandomFlash", TypeBool, Offset(stateSequenceRandomFlash, ShapeBaseImageData), MaxStates,
 916         "@brief If true, the muzzle flash sequence will be played while in this state.\n\n"
 917         "The name of the muzzle flash sequence is the same as stateSequence, "
 918         "with \"_vis\" at the end." );
 919      addField( "stateScaleAnimation", TypeBool, Offset(stateScaleAnimation, ShapeBaseImageData), MaxStates,
 920         "If true, the timeScale of the stateSequence animation will be adjusted "
 921         "such that the sequence plays for stateTimeoutValue seconds. " );
 922      addField( "stateScaleAnimationFP", TypeBool, Offset(stateScaleAnimationFP, ShapeBaseImageData), MaxStates,
 923         "If true, the timeScale of the first person stateSequence animation will be adjusted "
 924         "such that the sequence plays for stateTimeoutValue seconds. " );
 925      addField( "stateSequenceTransitionIn", TypeBool, Offset(stateSequenceTransitionIn, ShapeBaseImageData), MaxStates,
 926         "Do we transition to the state's sequence when we enter the state?" );
 927      addField( "stateSequenceTransitionOut", TypeBool, Offset(stateSequenceTransitionOut, ShapeBaseImageData), MaxStates,
 928         "Do we transition to the new state's sequence when we leave the state?" );
 929      addField( "stateSequenceNeverTransition", TypeBool, Offset(stateSequenceNeverTransition, ShapeBaseImageData), MaxStates,
 930         "Never allow a transition to this sequence.  Often used for a fire sequence." );
 931      addField( "stateSequenceTransitionTime", TypeF32, Offset(stateSequenceTransitionTime, ShapeBaseImageData), MaxStates,
 932         "The time to transition in or out of a sequence." );
 933
 934      addField( "stateShapeSequence", TypeString, Offset(stateShapeSequence, ShapeBaseImageData), MaxStates,
 935         "Name of the sequence that is played on the mounting shape." );
 936      addField( "stateScaleShapeSequence", TypeBool, Offset(stateScaleShapeSequence, ShapeBaseImageData), MaxStates,
 937         "Indicates if the sequence to be played on the mounting shape should be scaled to the length of the state." );
 938
 939      addField( "stateSound", TypeSFXTrackName, Offset(stateSound, ShapeBaseImageData), MaxStates,
 940         "Sound to play on entry to this state." );
 941      addField( "stateScript", TypeCaseString, Offset(stateScript, ShapeBaseImageData), MaxStates,
 942         "@brief Method to execute on entering this state.\n\n"
 943         "Scoped to this image class name, then ShapeBaseImageData. The script "
 944         "callback function takes the same arguments as the onMount callback.\n"
 945         "@see onMount() for the same arguments as this callback.");
 946
 947      addField( "stateEmitter", TYPEID< ParticleEmitterData >(), Offset(stateEmitter, ShapeBaseImageData), MaxStates,
 948         "@brief Emitter to generate particles in this state (from muzzle point or "
 949         "specified node).\n\n"
 950         "@see stateEmitterNode" );
 951      addField( "stateEmitterTime", TypeF32, Offset(stateEmitterTime, ShapeBaseImageData), MaxStates,
 952         "How long (in seconds) to emit particles on entry to this state." );
 953      addField( "stateEmitterNode", TypeString, Offset(stateEmitterNode, ShapeBaseImageData), MaxStates,
 954         "@brief Name of the node to emit particles from.\n\n"
 955         "@see stateEmitter" );
 956      addField( "stateIgnoreLoadedForReady", TypeBool, Offset(stateIgnoreLoadedForReady, ShapeBaseImageData), MaxStates,
 957         "@brief If set to true, and both ready and loaded transitions are true, the "
 958         "ready transition will be taken instead of the loaded transition.\n\n"
 959         "A state is 'ready' if pressing the fire trigger in that state would "
 960         "transition to the fire state." );
 961
 962   endArray( "States" );
 963
 964   addField( "computeCRC", TypeBool, Offset(computeCRC, ShapeBaseImageData),
 965      "If true, verify that the CRC of the client's Image matches the server's "
 966      "CRC for the Image when loaded by the client." );
 967
 968   addField( "maxConcurrentSounds", TypeS32, Offset(maxConcurrentSounds, ShapeBaseImageData),
 969      "@brief Maximum number of sounds this Image can play at a time.\n\n"
 970      "Any value <= 0 indicates that it can play an infinite number of sounds." );
 971
 972   addField( "useRemainderDT", TypeBool, Offset(useRemainderDT, ShapeBaseImageData), 
 973      "@brief If true, allow multiple timeout transitions to occur within a single "
 974      "tick (useful if states have a very small timeout).\n\n" );
 975
 976   Parent::initPersistFields();
 977}
 978
 979void ShapeBaseImageData::packData(BitStream* stream)
 980{
 981   Parent::packData(stream);
 982
 983   if(stream->writeFlag(computeCRC))
 984   {
 985      for( U32 j=0; j<MaxShapes; ++j )
 986      {
 987         stream->write(mCRC[j]);
 988      }
 989   }
 990
 991   stream->writeString(shapeName);        // shape 0 for normal use
 992   stream->writeString(shapeNameFP);      // shape 1 for first person use (optional)
 993
 994   stream->writeString(imageAnimPrefix);
 995   stream->writeString(imageAnimPrefixFP);
 996
 997   stream->write(mountPoint);
 998   if (!stream->writeFlag(mountOffset.isIdentity()))
 999      stream->writeAffineTransform(mountOffset);
1000   if (!stream->writeFlag(eyeOffset.isIdentity()))
1001      stream->writeAffineTransform(eyeOffset);
1002
1003   stream->writeFlag(animateOnServer);
1004
1005   stream->write(scriptAnimTransitionTime);
1006
1007   stream->writeFlag(useEyeNode);
1008
1009   stream->writeFlag(correctMuzzleVector);
1010   stream->writeFlag(correctMuzzleVectorTP);
1011   stream->writeFlag(firstPerson);
1012   stream->write(mass);
1013   stream->writeFlag(usesEnergy);
1014   stream->write(minEnergy);
1015
1016   for( U32 j=0; j<MaxShapes; ++j)
1017   {
1018      stream->writeFlag(hasFlash[j]);
1019   }
1020
1021   // Client doesn't need accuFire
1022
1023   // Write the projectile datablock
1024   if (stream->writeFlag(projectile))
1025      stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)projectile):
1026                             projectile->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
1027
1028   stream->writeFlag(cloakable);
1029   stream->writeRangedU32(lightType, 0, NumLightTypes-1);
1030   if(lightType != NoLight)
1031   {
1032      stream->write(lightRadius);
1033      stream->write(lightDuration);
1034      stream->writeFloat(lightColor.red, 7);
1035      stream->writeFloat(lightColor.green, 7);
1036      stream->writeFloat(lightColor.blue, 7);
1037      stream->writeFloat(lightColor.alpha, 7);
1038      stream->write(lightBrightness);
1039   }
1040
1041   if ( stream->writeFlag( shakeCamera ) )
1042   {      
1043      mathWrite( *stream, camShakeFreq );
1044      mathWrite( *stream, camShakeAmp );
1045      stream->write( camShakeDuration );
1046      stream->write( camShakeRadius );
1047      stream->write( camShakeFalloff );
1048   }
1049
1050   mathWrite( *stream, shellExitDir );
1051   stream->write(shellExitVariance);
1052   stream->write(shellVelocity);
1053
1054   if( stream->writeFlag( casing ) )
1055   {
1056      stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)casing):
1057         casing->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
1058   }
1059
1060   for (U32 i = 0; i < MaxStates; i++)
1061      if (stream->writeFlag(state[i].name && state[i].name[0])) {
1062         StateData& s = state[i];
1063         // States info not needed on the client:
1064         //    s.allowImageChange
1065         //    s.scriptNames
1066         // Transitions are inc. one to account for -1 values
1067         stream->writeString(state[i].name);
1068
1069         stream->writeInt(s.transition.loaded[0]+1,NumStateBits);
1070         stream->writeInt(s.transition.loaded[1]+1,NumStateBits);
1071         stream->writeInt(s.transition.ammo[0]+1,NumStateBits);
1072         stream->writeInt(s.transition.ammo[1]+1,NumStateBits);
1073         stream->writeInt(s.transition.target[0]+1,NumStateBits);
1074         stream->writeInt(s.transition.target[1]+1,NumStateBits);
1075         stream->writeInt(s.transition.wet[0]+1,NumStateBits);
1076         stream->writeInt(s.transition.wet[1]+1,NumStateBits);
1077         stream->writeInt(s.transition.trigger[0]+1,NumStateBits);
1078         stream->writeInt(s.transition.trigger[1]+1,NumStateBits);
1079         stream->writeInt(s.transition.altTrigger[0]+1,NumStateBits);
1080         stream->writeInt(s.transition.altTrigger[1]+1,NumStateBits);
1081         stream->writeInt(s.transition.timeout+1,NumStateBits);
1082
1083         // Most states don't make use of the motion transition.
1084         if (stream->writeFlag(s.transition.motion[0] != -1 || s.transition.motion[1] != -1))
1085         {
1086            // This state does
1087            stream->writeInt(s.transition.motion[0]+1,NumStateBits);
1088            stream->writeInt(s.transition.motion[1]+1,NumStateBits);
1089         }
1090
1091         // Most states don't make use of the generic trigger transitions.  Don't transmit
1092         // if that is the case here.
1093         for (U32 j=0; j<MaxGenericTriggers; ++j)
1094         {
1095            if (stream->writeFlag(s.transition.genericTrigger[j][0] != -1 || s.transition.genericTrigger[j][1] != -1))
1096            {
1097               stream->writeInt(s.transition.genericTrigger[j][0]+1,NumStateBits);
1098               stream->writeInt(s.transition.genericTrigger[j][1]+1,NumStateBits);
1099            }
1100         }
1101
1102         if(stream->writeFlag(s.timeoutValue != gDefaultStateData.timeoutValue))
1103            stream->write(s.timeoutValue);
1104
1105         stream->writeFlag(s.waitForTimeout);
1106         stream->writeFlag(s.fire);
1107         stream->writeFlag(s.altFire);
1108         stream->writeFlag(s.reload);
1109         stream->writeFlag(s.ejectShell);
1110         stream->writeFlag(s.scaleAnimation);
1111         stream->writeFlag(s.scaleAnimationFP);
1112         stream->writeFlag(s.direction);
1113
1114         stream->writeFlag(s.sequenceTransitionIn);
1115         stream->writeFlag(s.sequenceTransitionOut);
1116         stream->writeFlag(s.sequenceNeverTransition);
1117         if(stream->writeFlag(s.sequenceTransitionTime != gDefaultStateData.sequenceTransitionTime))
1118            stream->write(s.sequenceTransitionTime);
1119
1120         stream->writeString(s.shapeSequence);
1121         stream->writeFlag(s.shapeSequenceScale);
1122
1123         if(stream->writeFlag(s.energyDrain != gDefaultStateData.energyDrain))
1124            stream->write(s.energyDrain);
1125
1126         stream->writeInt(s.loaded,StateData::NumLoadedBits);
1127         stream->writeInt(s.spin,StateData::NumSpinBits);
1128         stream->writeInt(s.recoil,StateData::NumRecoilBits);
1129
1130         for( U32 j=0; j<MaxShapes; ++j )
1131         {
1132            if(stream->writeFlag(s.sequence[j] != gDefaultStateData.sequence[j]))
1133               stream->writeSignedInt(s.sequence[j], 16);
1134
1135            if(stream->writeFlag(s.sequenceVis[j] != gDefaultStateData.sequenceVis[j]))
1136               stream->writeSignedInt(s.sequenceVis[j],16);
1137
1138            stream->writeFlag(s.flashSequence[j]);
1139         }
1140
1141         stream->writeFlag(s.ignoreLoadedForReady);
1142
1143         if (stream->writeFlag(s.emitter))
1144         {
1145            stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)s.emitter):
1146                                   s.emitter->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
1147            stream->write(s.emitterTime);
1148
1149            for( U32 j=0; j<MaxShapes; ++j )
1150            {
1151               stream->write(s.emitterNode[j]);
1152            }
1153         }
1154
1155         sfxWrite( stream, s.sound );
1156      }
1157   stream->write(maxConcurrentSounds);
1158   stream->writeFlag(useRemainderDT);
1159}
1160
1161void ShapeBaseImageData::unpackData(BitStream* stream)
1162{
1163   Parent::unpackData(stream);
1164   computeCRC = stream->readFlag();
1165   if(computeCRC)
1166   {
1167      for( U32 j=0; j<MaxShapes; ++j )
1168      {
1169         stream->read(&mCRC[j]);
1170      }
1171   }
1172
1173   shapeName = stream->readSTString();       // shape 0 for normal use
1174   shapeNameFP = stream->readSTString();     // shape 1 for first person use (optional)
1175
1176   imageAnimPrefix = stream->readSTString();
1177   imageAnimPrefixFP = stream->readSTString();
1178
1179   stream->read(&mountPoint);
1180   if (stream->readFlag())
1181      mountOffset.identity();
1182   else
1183      stream->readAffineTransform(&mountOffset);
1184   if (stream->readFlag())
1185      eyeOffset.identity();
1186   else
1187      stream->readAffineTransform(&eyeOffset);
1188
1189   animateOnServer = stream->readFlag();
1190
1191   stream->read(&scriptAnimTransitionTime);
1192
1193   useEyeNode = stream->readFlag();
1194
1195   correctMuzzleVector = stream->readFlag();
1196   correctMuzzleVectorTP = stream->readFlag();
1197   firstPerson = stream->readFlag();
1198   stream->read(&mass);
1199   usesEnergy = stream->readFlag();
1200   stream->read(&minEnergy);
1201
1202   for( U32 j=0; j<MaxShapes; ++j )
1203   {
1204      hasFlash[j] = stream->readFlag();
1205   }
1206
1207   projectile = (stream->readFlag() ?
1208                 (ProjectileData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
1209                                                        DataBlockObjectIdLast) : 0);
1210
1211   cloakable = stream->readFlag();
1212   lightType = stream->readRangedU32(0, NumLightTypes-1);
1213   if(lightType != NoLight)
1214   {
1215      stream->read(&lightRadius);
1216      stream->read(&lightDuration);
1217      lightColor.red = stream->readFloat(7);
1218      lightColor.green = stream->readFloat(7);
1219      lightColor.blue = stream->readFloat(7);
1220      lightColor.alpha = stream->readFloat(7);
1221      stream->read( &lightBrightness );
1222   }
1223
1224   shakeCamera = stream->readFlag();
1225   if ( shakeCamera )
1226   {
1227      mathRead( *stream, &camShakeFreq );
1228      mathRead( *stream, &camShakeAmp );
1229      stream->read( &camShakeDuration );
1230      stream->read( &camShakeRadius );
1231      stream->read( &camShakeFalloff );
1232   }
1233
1234   mathRead( *stream, &shellExitDir );
1235   stream->read(&shellExitVariance);
1236   stream->read(&shellVelocity);
1237
1238   if(stream->readFlag())
1239   {
1240      casingID = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
1241   }
1242
1243   for (U32 i = 0; i < MaxStates; i++) {
1244      if (stream->readFlag()) {
1245         StateData& s = state[i];
1246         // States info not needed on the client:
1247         //    s.allowImageChange
1248         //    s.scriptNames
1249         // Transitions are dec. one to restore -1 values
1250         s.name = stream->readSTString();
1251
1252         s.transition.loaded[0] = stream->readInt(NumStateBits) - 1;
1253         s.transition.loaded[1] = stream->readInt(NumStateBits) - 1;
1254         s.transition.ammo[0] = stream->readInt(NumStateBits) - 1;
1255         s.transition.ammo[1] = stream->readInt(NumStateBits) - 1;
1256         s.transition.target[0] = stream->readInt(NumStateBits) - 1;
1257         s.transition.target[1] = stream->readInt(NumStateBits) - 1;
1258         s.transition.wet[0] = stream->readInt(NumStateBits) - 1;
1259         s.transition.wet[1] = stream->readInt(NumStateBits) - 1;
1260         s.transition.trigger[0] = stream->readInt(NumStateBits) - 1;
1261         s.transition.trigger[1] = stream->readInt(NumStateBits) - 1;
1262         s.transition.altTrigger[0] = stream->readInt(NumStateBits) - 1;
1263         s.transition.altTrigger[1] = stream->readInt(NumStateBits) - 1;
1264         s.transition.timeout = stream->readInt(NumStateBits) - 1;
1265
1266         // Motion trigger
1267         if (stream->readFlag())
1268         {
1269            s.transition.motion[0] = stream->readInt(NumStateBits) - 1;
1270            s.transition.motion[1] = stream->readInt(NumStateBits) - 1;
1271         }
1272         else
1273         {
1274            s.transition.motion[0] = -1;
1275            s.transition.motion[1] = -1;
1276         }
1277
1278         // Generic triggers
1279         for (U32 j=0; j<MaxGenericTriggers; ++j)
1280         {
1281            if (stream->readFlag())
1282            {
1283               s.transition.genericTrigger[j][0] = stream->readInt(NumStateBits) - 1;
1284               s.transition.genericTrigger[j][1] = stream->readInt(NumStateBits) - 1;
1285            }
1286            else
1287            {
1288               s.transition.genericTrigger[j][0] = -1;
1289               s.transition.genericTrigger[j][1] = -1;
1290            }
1291         }
1292
1293         if(stream->readFlag())
1294            stream->read(&s.timeoutValue);
1295         else
1296            s.timeoutValue = gDefaultStateData.timeoutValue;
1297
1298         s.waitForTimeout = stream->readFlag();
1299         s.fire = stream->readFlag();
1300         s.altFire = stream->readFlag();
1301         s.reload = stream->readFlag();
1302         s.ejectShell = stream->readFlag();
1303         s.scaleAnimation = stream->readFlag();
1304         s.scaleAnimationFP = stream->readFlag();
1305         s.direction = stream->readFlag();
1306
1307         s.sequenceTransitionIn = stream->readFlag();
1308         s.sequenceTransitionOut = stream->readFlag();
1309         s.sequenceNeverTransition = stream->readFlag();
1310         if (stream->readFlag())
1311            stream->read(&s.sequenceTransitionTime);
1312         else
1313            s.sequenceTransitionTime = gDefaultStateData.sequenceTransitionTime;
1314
1315         s.shapeSequence = stream->readSTString();
1316         s.shapeSequenceScale = stream->readFlag();
1317
1318         if(stream->readFlag())
1319            stream->read(&s.energyDrain);
1320         else
1321            s.energyDrain = gDefaultStateData.energyDrain;
1322
1323         s.loaded = (StateData::LoadedState)stream->readInt(StateData::NumLoadedBits);
1324         s.spin = (StateData::SpinState)stream->readInt(StateData::NumSpinBits);
1325         s.recoil = (StateData::RecoilState)stream->readInt(StateData::NumRecoilBits);
1326
1327         for( U32 j=0; j<MaxShapes; ++j )
1328         {
1329            if(stream->readFlag())
1330               s.sequence[j] = stream->readSignedInt(16);
1331            else
1332               s.sequence[j] = gDefaultStateData.sequence[j];
1333
1334            if(stream->readFlag())
1335               s.sequenceVis[j] = stream->readSignedInt(16);
1336            else
1337               s.sequenceVis[j] = gDefaultStateData.sequenceVis[j];
1338
1339            s.flashSequence[j] = stream->readFlag();
1340         }
1341
1342         s.ignoreLoadedForReady = stream->readFlag();
1343
1344         if (stream->readFlag())
1345         {
1346            s.emitter = (ParticleEmitterData*)(uintptr_t)stream->readRangedU32(DataBlockObjectIdFirst,
1347                                                                     DataBlockObjectIdLast);
1348            stream->read(&s.emitterTime);
1349
1350            for( U32 j=0; j<MaxShapes; ++j )
1351            {
1352               stream->read(&(s.emitterNode[j]));
1353            }
1354         }
1355         else
1356            s.emitter = 0;
1357            
1358         sfxRead( stream, &s.sound );
1359      }
1360   }
1361   
1362   stream->read(&maxConcurrentSounds);
1363   useRemainderDT = stream->readFlag();
1364
1365   statesLoaded = true;
1366}
1367
1368void ShapeBaseImageData::inspectPostApply()
1369{
1370   Parent::inspectPostApply();
1371
1372   // This does not do a very good job of applying changes to states
1373   // which may have occured in the editor, but at least we can do this...
1374   useEyeOffset = !eyeOffset.isIdentity();   
1375}
1376
1377//----------------------------------------------------------------------------
1378//----------------------------------------------------------------------------
1379
1380//----------------------------------------------------------------------------
1381
1382ShapeBase::MountedImage::MountedImage()
1383{
1384   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
1385   {
1386      shapeInstance[i] = 0;
1387      ambientThread[i] = NULL;
1388      visThread[i] = NULL;
1389      animThread[i] = NULL;
1390      flashThread[i] = NULL;
1391      spinThread[i] = NULL;
1392   }
1393
1394   doAnimateAllShapes = false;
1395   forceAnimateAllShapes = false;
1396   lastShapeIndex = 0;
1397
1398   state = 0;
1399   dataBlock = 0;
1400   nextImage = InvalidImagePtr;
1401   delayTime = 0;
1402   rDT = 0.0f;
1403   ammo = false;
1404   target = false;
1405   triggerDown = false;
1406   altTriggerDown = false;
1407   loaded = false;
1408   fireCount = 0;
1409   altFireCount = 0;
1410   reloadCount = 0;
1411   wet = false;
1412   motion = false;
1413   lightStart = 0;
1414   lightInfo = NULL;
1415   dMemset(emitter, 0, sizeof(emitter));
1416
1417   for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
1418   {
1419      genericTrigger[i] = false;
1420   }
1421
1422   nextLoaded = false;
1423}
1424
1425ShapeBase::MountedImage::~MountedImage()
1426{
1427   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
1428   {
1429      delete shapeInstance[i];
1430      shapeInstance[i] = 0;
1431   }
1432
1433   // stop sound
1434   for(Vector<SFXSource*>::iterator i = mSoundSources.begin(); i != mSoundSources.end(); i++)  
1435   {  
1436      SFX_DELETE((*i));  
1437   }  
1438   mSoundSources.clear(); 
1439
1440   for (S32 i = 0; i < MaxImageEmitters; i++)
1441      if (bool(emitter[i].emitter))
1442         emitter[i].emitter->deleteWhenEmpty();
1443
1444   if ( lightInfo != NULL )
1445      delete lightInfo;
1446}
1447
1448void ShapeBase::MountedImage::addSoundSource(SFXSource* source)
1449{
1450   if(source != NULL)
1451   {
1452      if(dataBlock->maxConcurrentSounds > 0 && mSoundSources.size() > dataBlock->maxConcurrentSounds)
1453      {
1454         SFX_DELETE(mSoundSources.first());
1455         mSoundSources.pop_front();
1456      }
1457      source->play();
1458      mSoundSources.push_back(source);
1459   }
1460}
1461
1462void ShapeBase::MountedImage::updateSoundSources( const MatrixF &renderTransform )
1463{
1464   // Update all the sounds removing any ones that have stopped.
1465   for ( U32 i=0; i < mSoundSources.size(); )
1466   {
1467      SFXSource *source = mSoundSources[i];
1468
1469      if ( source->isStopped() )
1470      {
1471         SFX_DELETE( source );
1472         mSoundSources.erase_fast( i );
1473         continue;
1474      }
1475
1476      source->setTransform(renderTransform);
1477      i++;
1478   }
1479}
1480
1481void ShapeBase::MountedImage::updateDoAnimateAllShapes(const ShapeBase* owner)
1482{
1483   doAnimateAllShapes = false;
1484   if (!dataBlock)
1485      return;
1486
1487   // According to ShapeBase::isFirstPerson() the server is always in first person mode.
1488   // Therefore we don't need to animate any other shapes but the one that will be
1489   // used for first person.
1490
1491   // Sometimes this is forced externally, so honour it.
1492   if (forceAnimateAllShapes)
1493   {
1494      doAnimateAllShapes = true;
1495      return;
1496   }
1497
1498   if (owner->isClientObject())
1499   {
1500      // If this client object doesn't have a controlling client, then according to 
1501      // ShapeBase::isFirstPerson() it cannot ever be in first person mode.  So no need 
1502      // to animate any shapes beyond the current one. 
1503      if (!owner->getControllingClient()) 
1504      { 
1505         return; 
1506      }
1507
1508      doAnimateAllShapes = dataBlock->animateAllShapes;
1509   }
1510}
1511
1512//----------------------------------------------------------------------------
1513//----------------------------------------------------------------------------
1514
1515//----------------------------------------------------------------------------
1516// Any item with an item image is selectable
1517
1518bool ShapeBase::mountImage(ShapeBaseImageData* imageData,U32 imageSlot,bool loaded,NetStringHandle &skinNameHandle)
1519{
1520   AssertFatal(imageSlot<MaxMountedImages,"Out of range image slot");
1521
1522   MountedImage& image = mMountedImageList[imageSlot];
1523   if (image.dataBlock) {
1524      if ((image.dataBlock == imageData) && (image.skinNameHandle == skinNameHandle)) {
1525         // Image already loaded
1526         image.nextImage = InvalidImagePtr;
1527         return true;
1528      }
1529   }
1530   //
1531   setImage(imageSlot,imageData,skinNameHandle,loaded);
1532
1533   return true;
1534}
1535
1536bool ShapeBase::unmountImage(U32 imageSlot)
1537{
1538   AssertFatal(imageSlot<MaxMountedImages,"Out of range image slot");
1539
1540   bool returnValue = false;
1541   MountedImage& image = mMountedImageList[imageSlot];
1542   if (image.dataBlock)
1543   {
1544      NetStringHandle temp;
1545      setImage(imageSlot,0, temp);
1546      returnValue = true;
1547   }
1548
1549   return returnValue;
1550}
1551
1552
1553//----------------------------------------------------------------------------
1554
1555ShapeBaseImageData* ShapeBase::getMountedImage(U32 imageSlot)
1556{
1557   AssertFatal(imageSlot<MaxMountedImages,"Out of range image slot");
1558
1559   return mMountedImageList[imageSlot].dataBlock;
1560}
1561
1562
1563ShapeBase::MountedImage* ShapeBase::getImageStruct(U32 imageSlot)
1564{
1565   return &mMountedImageList[imageSlot];
1566}
1567
1568
1569ShapeBaseImageData* ShapeBase::getPendingImage(U32 imageSlot)
1570{
1571   ShapeBaseImageData* data = mMountedImageList[imageSlot].nextImage;
1572   return (data == InvalidImagePtr)? 0: data;
1573}
1574
1575bool ShapeBase::isImageFiring(U32 imageSlot)
1576{
1577   MountedImage& image = mMountedImageList[imageSlot];
1578   return image.dataBlock && image.state->fire;
1579}
1580
1581bool ShapeBase::isImageAltFiring(U32 imageSlot)
1582{
1583   MountedImage& image = mMountedImageList[imageSlot];
1584   return image.dataBlock && image.state->altFire;
1585}
1586
1587bool ShapeBase::isImageReloading(U32 imageSlot)
1588{
1589   MountedImage& image = mMountedImageList[imageSlot];
1590   return image.dataBlock && image.state->reload;
1591}
1592
1593bool ShapeBase::isImageReady(U32 imageSlot,U32 ns,U32 depth)
1594{
1595   // Will pressing the trigger lead to a fire state?
1596   MountedImage& image = mMountedImageList[imageSlot];
1597   if (depth++ > 5 || !image.dataBlock)
1598      return false;
1599   ShapeBaseImageData::StateData& stateData = (ns == -1) ?
1600      *image.state : image.dataBlock->state[ns];
1601   if (stateData.fire)
1602      return true;
1603
1604   // Try the transitions...
1605   if (stateData.ignoreLoadedForReady == true) {
1606      if ((ns = stateData.transition.loaded[true]) != -1)
1607         if (isImageReady(imageSlot,ns,depth))
1608            return true;
1609   } else {
1610      if ((ns = stateData.transition.loaded[image.loaded]) != -1)
1611         if (isImageReady(imageSlot,ns,depth))
1612            return true;
1613   }
1614   for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
1615   {
1616      if ((ns = stateData.transition.genericTrigger[i][image.genericTrigger[i]]) != -1)
1617         if (isImageReady(imageSlot,ns,depth))
1618            return true;
1619   }
1620   if ((ns = stateData.transition.ammo[image.ammo]) != -1)
1621      if (isImageReady(imageSlot,ns,depth))
1622         return true;
1623   if ((ns = stateData.transition.target[image.target]) != -1)
1624      if (isImageReady(imageSlot,ns,depth))
1625         return true;
1626   if ((ns = stateData.transition.wet[image.wet]) != -1)
1627      if (isImageReady(imageSlot,ns,depth))
1628         return true;
1629   if ((ns = stateData.transition.motion[image.motion]) != -1)
1630      if (isImageReady(imageSlot,ns,depth))
1631         return true;
1632   if ((ns = stateData.transition.trigger[1]) != -1)
1633      if (isImageReady(imageSlot,ns,depth))
1634         return true;
1635   if ((ns = stateData.transition.altTrigger[1]) != -1)
1636      if (isImageReady(imageSlot,ns,depth))
1637         return true;
1638   if ((ns = stateData.transition.timeout) != -1)
1639      if (isImageReady(imageSlot,ns,depth))
1640         return true;
1641   return false;
1642}
1643
1644bool ShapeBase::isImageMounted(ShapeBaseImageData* imageData)
1645{
1646   for (U32 i = 0; i < MaxMountedImages; i++)
1647      if (imageData == mMountedImageList[i].dataBlock)
1648         return true;
1649   return false;
1650}
1651
1652S32 ShapeBase::getMountSlot(ShapeBaseImageData* imageData)
1653{
1654   for (U32 i = 0; i < MaxMountedImages; i++)
1655      if (imageData == mMountedImageList[i].dataBlock)
1656         return i;
1657   return -1;
1658}
1659
1660NetStringHandle ShapeBase::getImageSkinTag(U32 imageSlot)
1661{
1662   MountedImage& image = mMountedImageList[imageSlot];
1663   return image.dataBlock? image.skinNameHandle : NetStringHandle();
1664}
1665
1666const char* ShapeBase::getImageState(U32 imageSlot)
1667{
1668   MountedImage& image = mMountedImageList[imageSlot];
1669   return image.dataBlock? image.state->name: 0;
1670}
1671
1672void ShapeBase::setImageGenericTriggerState(U32 imageSlot, U32 trigger, bool state)
1673{
1674   MountedImage& image = mMountedImageList[imageSlot];
1675   if (image.dataBlock && image.genericTrigger[trigger] != state) {
1676      setMaskBits(ImageMaskN << imageSlot);
1677      image.genericTrigger[trigger] = state;
1678   }
1679}
1680
1681bool ShapeBase::getImageGenericTriggerState(U32 imageSlot, U32 trigger)
1682{
1683   MountedImage& image = mMountedImageList[imageSlot];
1684   if (!image.dataBlock)
1685      return false;
1686   return image.genericTrigger[trigger];
1687}
1688
1689void ShapeBase::setImageAmmoState(U32 imageSlot,bool ammo)
1690{
1691   MountedImage& image = mMountedImageList[imageSlot];
1692   if (image.dataBlock && !image.dataBlock->usesEnergy && image.ammo != ammo) {
1693      setMaskBits(ImageMaskN << imageSlot);
1694      image.ammo = ammo;
1695   }
1696}
1697
1698bool ShapeBase::getImageAmmoState(U32 imageSlot)
1699{
1700   MountedImage& image = mMountedImageList[imageSlot];
1701   if (!image.dataBlock)
1702      return false;
1703   return image.ammo;
1704}
1705
1706void ShapeBase::setImageWetState(U32 imageSlot,bool wet)
1707{
1708   MountedImage& image = mMountedImageList[imageSlot];
1709   if (image.dataBlock && image.wet != wet) {
1710      setMaskBits(ImageMaskN << imageSlot);
1711      image.wet = wet;
1712   }
1713}
1714
1715bool ShapeBase::getImageWetState(U32 imageSlot)
1716{
1717   MountedImage& image = mMountedImageList[imageSlot];
1718   if (!image.dataBlock)
1719      return false;
1720   return image.wet;
1721}
1722
1723void ShapeBase::setImageMotionState(U32 imageSlot,bool motion)
1724{
1725   MountedImage& image = mMountedImageList[imageSlot];
1726   if (image.dataBlock && image.motion != motion) {
1727      setMaskBits(ImageMaskN << imageSlot);
1728      image.motion = motion;
1729   }
1730}
1731
1732bool ShapeBase::getImageMotionState(U32 imageSlot)
1733{
1734   MountedImage& image = mMountedImageList[imageSlot];
1735   if (!image.dataBlock)
1736      return false;
1737   return image.motion;
1738}
1739
1740void ShapeBase::setImageTargetState(U32 imageSlot,bool target)
1741{
1742   MountedImage& image = mMountedImageList[imageSlot];
1743   if (image.dataBlock && image.target != target) {
1744      setMaskBits(ImageMaskN << imageSlot);
1745      image.target = target;
1746   }
1747}
1748
1749bool ShapeBase::getImageTargetState(U32 imageSlot)
1750{
1751   MountedImage& image = mMountedImageList[imageSlot];
1752   if (!image.dataBlock)
1753      return false;
1754   return image.target;
1755}
1756
1757void ShapeBase::setImageLoadedState(U32 imageSlot,bool loaded)
1758{
1759   MountedImage& image = mMountedImageList[imageSlot];
1760   if (image.dataBlock && image.loaded != loaded) {
1761      setMaskBits(ImageMaskN << imageSlot);
1762      image.loaded = loaded;
1763   }
1764}
1765
1766bool ShapeBase::getImageLoadedState(U32 imageSlot)
1767{
1768   MountedImage& image = mMountedImageList[imageSlot];
1769   if (!image.dataBlock)
1770      return false;
1771   return image.loaded;
1772}
1773
1774void ShapeBase::getMuzzleVector(U32 imageSlot,VectorF* vec)
1775{
1776   MatrixF mat;
1777   getMuzzleTransform(imageSlot,&mat);
1778
1779   GameConnection * gc = getControllingClient();
1780   if (gc && !gc->isAIControlled())
1781   {
1782      MountedImage& image = mMountedImageList[imageSlot];
1783
1784      bool fp = gc->isFirstPerson();
1785      if ((fp && image.dataBlock->correctMuzzleVector) ||
1786         (!fp && image.dataBlock->correctMuzzleVectorTP))
1787         if (getCorrectedAim(mat, vec))
1788            return;
1789   }
1790
1791   mat.getColumn(1,vec);
1792}
1793
1794void ShapeBase::getMuzzlePoint(U32 imageSlot,Point3F* pos)
1795{
1796   MatrixF mat;
1797   getMuzzleTransform(imageSlot,&mat);
1798   mat.getColumn(3,pos);
1799}
1800
1801
1802void ShapeBase::getRenderMuzzleVector(U32 imageSlot,VectorF* vec)
1803{
1804   MatrixF mat;
1805   getRenderMuzzleTransform(imageSlot,&mat);
1806
1807   GameConnection * gc = getControllingClient();
1808   if (gc && !gc->isAIControlled())
1809   {
1810      MountedImage& image = mMountedImageList[imageSlot];
1811
1812      bool fp = gc->isFirstPerson();
1813      if ((fp && image.dataBlock->correctMuzzleVector) ||
1814         (!fp && image.dataBlock->correctMuzzleVectorTP))
1815         if (getCorrectedAim(mat, vec))
1816            return;
1817   }
1818
1819   mat.getColumn(1,vec);
1820}
1821
1822void ShapeBase::getRenderMuzzlePoint(U32 imageSlot,Point3F* pos)
1823{
1824   MatrixF mat;
1825   getRenderMuzzleTransform(imageSlot,&mat);
1826   mat.getColumn(3,pos);
1827}
1828
1829//----------------------------------------------------------------------------
1830
1831void ShapeBase::scriptCallback(U32 imageSlot,const char* function)
1832{
1833   MountedImage &image = mMountedImageList[imageSlot];
1834
1835   char buff1[32];
1836   dSprintf( buff1, 32, "%d", imageSlot );
1837
1838   char buff2[32];
1839   dSprintf( buff2, 32, "%f", image.dataBlock->useRemainderDT ? image.rDT : 0.0f );
1840
1841   Con::executef( image.dataBlock, function, getIdString(), buff1, buff2 );
1842}
1843
1844
1845//----------------------------------------------------------------------------
1846
1847void ShapeBase::getMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat )
1848{
1849   // Returns mount point to world space transform
1850   if ( index >= 0 && index < SceneObject::NumMountPoints) {
1851      S32 ni = mDataBlock->mountPointNode[index];
1852      if (ni != -1) {
1853         MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];
1854         mountTransform.mul( xfm );
1855         const Point3F& scale = getScale();
1856
1857         // The position of the mount point needs to be scaled.
1858         Point3F position = mountTransform.getPosition();
1859         position.convolve( scale );
1860         mountTransform.setPosition( position );
1861
1862         // Also we would like the object to be scaled to the model.
1863         outMat->mul(mObjToWorld, mountTransform);
1864         return;
1865      }
1866   }
1867
1868   // Then let SceneObject handle it.
1869   Parent::getMountTransform( index, xfm, outMat );      
1870}
1871
1872void ShapeBase::getImageTransform(U32 imageSlot,MatrixF* mat)
1873{
1874   // Image transform in world space
1875   MountedImage& image = mMountedImageList[imageSlot];
1876   if (image.dataBlock) {
1877      ShapeBaseImageData& data = *image.dataBlock;
1878      U32 shapeIndex = getImageShapeIndex(image);
1879
1880      MatrixF nmat;
1881      if (data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1) {
1882         // We need to animate, even on the server, to make sure the nodes are in the correct location.
1883         image.shapeInstance[shapeIndex]->animate();
1884
1885         getEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
1886
1887         MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
1888
1889         mat->mul(nmat, mountTransform);
1890      }
1891      else if (data.useEyeOffset && isFirstPerson()) {
1892         getEyeTransform(&nmat);
1893         mat->mul(nmat,data.eyeOffset);
1894      }
1895      else {
1896         getMountTransform( image.dataBlock->mountPoint, MatrixF::Identity, &nmat );
1897         mat->mul(nmat,data.mountTransform[shapeIndex]);
1898      }
1899   }
1900   else
1901      *mat = mObjToWorld;
1902}
1903
1904void ShapeBase::getImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
1905{
1906   // Image transform in world space
1907   MountedImage& image = mMountedImageList[imageSlot];
1908   if (image.dataBlock)
1909   {
1910      if (node != -1)
1911      {
1912         ShapeBaseImageData& data = *image.dataBlock;
1913         U32 shapeIndex = getImageShapeIndex(image);
1914
1915         MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node];
1916         MatrixF mmat;
1917
1918         if (data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1)
1919         {
1920            // We need to animate, even on the server, to make sure the nodes are in the correct location.
1921            image.shapeInstance[shapeIndex]->animate();
1922
1923            MatrixF emat;
1924            getEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
1925
1926            MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
1927            mountTransform.affineInverse();
1928
1929            mmat.mul(emat, mountTransform);
1930         }
1931         else if (data.useEyeOffset && isFirstPerson())
1932         {
1933            MatrixF emat;
1934            getEyeTransform(&emat);
1935            mmat.mul(emat,data.eyeOffset);
1936         }
1937         else
1938         {
1939            MatrixF emat;
1940            getMountTransform( image.dataBlock->mountPoint, MatrixF::Identity, &emat );
1941            mmat.mul(emat,data.mountTransform[shapeIndex]);
1942         }
1943
1944         mat->mul(mmat, nmat);
1945      }
1946      else
1947         getImageTransform(imageSlot,mat);
1948   }
1949   else
1950      *mat = mObjToWorld;
1951}
1952
1953void ShapeBase::getImageTransform(U32 imageSlot,StringTableEntry nodeName,MatrixF* mat)
1954{
1955   getImageTransform( imageSlot, getNodeIndex( imageSlot, nodeName ), mat );
1956}
1957
1958void ShapeBase::getMuzzleTransform(U32 imageSlot,MatrixF* mat)
1959{
1960   // Muzzle transform in world space
1961   MountedImage& image = mMountedImageList[imageSlot];
1962   if (image.dataBlock)
1963      getImageTransform(imageSlot,image.dataBlock->muzzleNode[getImageShapeIndex(image)],mat);
1964   else
1965      *mat = mObjToWorld;
1966}
1967
1968
1969//----------------------------------------------------------------------------
1970
1971void ShapeBase::getRenderMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat )
1972{
1973   // Returns mount point to world space transform
1974   if ( mountPoint >= 0 && mountPoint < SceneObject::NumMountPoints) {
1975      S32 ni = mDataBlock->mountPointNode[mountPoint];
1976      if (ni != -1) {
1977         MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];
1978         mountTransform.mul( xfm );
1979         const Point3F& scale = getScale();
1980
1981         // The position of the mount point needs to be scaled.
1982         Point3F position = mountTransform.getPosition();
1983         position.convolve( scale );
1984         mountTransform.setPosition( position );
1985
1986         // Also we would like the object to be scaled to the model.
1987         mountTransform.scale( scale );
1988         outMat->mul(getRenderTransform(), mountTransform);
1989         return;
1990      }
1991   }
1992
1993   // Then let SceneObject handle it.
1994   Parent::getRenderMountTransform( delta, mountPoint, xfm, outMat );   
1995}
1996
1997
1998void ShapeBase::getRenderImageTransform( U32 imageSlot, MatrixF* mat, bool noEyeOffset )
1999{
2000   // Image transform in world space
2001   MountedImage& image = mMountedImageList[imageSlot];
2002   if (image.dataBlock) 
2003   {
2004      ShapeBaseImageData& data = *image.dataBlock;
2005      U32 shapeIndex = getImageShapeIndex(image);
2006
2007      MatrixF nmat;
2008      if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 ) {
2009         getRenderEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
2010
2011         MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
2012
2013         mat->mul(nmat, mountTransform);
2014      }
2015      else if ( !noEyeOffset && data.useEyeOffset && isFirstPerson() ) 
2016      {
2017         getRenderEyeTransform(&nmat);
2018         mat->mul(nmat,data.eyeOffset);
2019      }
2020      else 
2021      {
2022         getRenderMountTransform( 0.0f, data.mountPoint, MatrixF::Identity, &nmat );
2023         mat->mul(nmat,data.mountTransform[shapeIndex]);
2024      }
2025   }
2026   else
2027      *mat = getRenderTransform();
2028}
2029
2030void ShapeBase::getRenderImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
2031{
2032   // Image transform in world space
2033   MountedImage& image = mMountedImageList[imageSlot];
2034   if (image.dataBlock)
2035   {
2036      if (node != -1)
2037      {
2038         ShapeBaseImageData& data = *image.dataBlock;
2039         U32 shapeIndex = getImageShapeIndex(image);
2040
2041         MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node];
2042         MatrixF mmat;
2043
2044         if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 )
2045         {
2046            MatrixF emat;
2047            getRenderEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
2048
2049            MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
2050            mountTransform.affineInverse();
2051
2052            mmat.mul(emat, mountTransform);
2053         }
2054         else if ( data.useEyeOffset && isFirstPerson() ) 
2055         {
2056            MatrixF emat;
2057            getRenderEyeTransform(&emat);
2058            mmat.mul(emat,data.eyeOffset);
2059         }
2060         else 
2061         {
2062            MatrixF emat;
2063            getRenderMountTransform( 0.0f, data.mountPoint, MatrixF::Identity, &emat );
2064            mmat.mul(emat,data.mountTransform[shapeIndex]);
2065         }
2066
2067         mat->mul(mmat, nmat);
2068      }
2069      else
2070         getRenderImageTransform(imageSlot,mat);
2071   }
2072   else
2073      *mat = getRenderTransform();
2074}
2075
2076void ShapeBase::getRenderImageTransform(U32 imageSlot,StringTableEntry nodeName,MatrixF* mat)
2077{
2078   getRenderImageTransform( imageSlot, getNodeIndex( imageSlot, nodeName ), mat );
2079}
2080
2081void ShapeBase::getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat)
2082{
2083   // Muzzle transform in world space
2084   MountedImage& image = mMountedImageList[imageSlot];
2085   if (image.dataBlock)
2086      getRenderImageTransform(imageSlot,image.dataBlock->muzzleNode[getImageShapeIndex(image)],mat);
2087   else
2088      *mat = getRenderTransform();
2089}
2090
2091
2092void ShapeBase::getRetractionTransform(U32 imageSlot,MatrixF* mat)
2093{
2094   // Muzzle transform in world space
2095   MountedImage& image = mMountedImageList[imageSlot];
2096   if (image.dataBlock) {
2097      ShapeBaseImageData& data = *image.dataBlock;
2098      U32 imageShapeIndex = getImageShapeIndex(image);
2099      if (data.retractNode[imageShapeIndex] != -1)
2100         getImageTransform(imageSlot,data.retractNode[imageShapeIndex],mat);
2101      else
2102         getImageTransform(imageSlot,data.muzzleNode[imageShapeIndex],mat);
2103   } else {
2104      *mat = getTransform();
2105   }
2106}
2107
2108
2109void ShapeBase::getRenderRetractionTransform(U32 imageSlot,MatrixF* mat)
2110{
2111   // Muzzle transform in world space
2112   MountedImage& image = mMountedImageList[imageSlot];
2113   if (image.dataBlock) {
2114      ShapeBaseImageData& data = *image.dataBlock;
2115      U32 imageShapeIndex = getImageShapeIndex(image);
2116      if (data.retractNode[imageShapeIndex] != -1)
2117         getRenderImageTransform(imageSlot,data.retractNode[imageShapeIndex],mat);
2118      else
2119         getRenderImageTransform(imageSlot,data.muzzleNode[imageShapeIndex],mat);
2120   } else {
2121      *mat = getRenderTransform();
2122   }
2123}
2124
2125
2126//----------------------------------------------------------------------------
2127
2128S32 ShapeBase::getNodeIndex(U32 imageSlot,StringTableEntry nodeName)
2129{
2130   MountedImage& image = mMountedImageList[imageSlot];
2131   if (image.dataBlock)
2132      return image.dataBlock->shape[getImageShapeIndex(image)]->findNode(nodeName);
2133   else
2134      return -1;
2135}
2136
2137// Modify muzzle if needed to aim at whatever is straight in front of the camera.  Let the
2138// caller know if we actually modified the result.
2139bool ShapeBase::getCorrectedAim(const MatrixF& muzzleMat, VectorF* result)
2140{
2141   F32 pullInD = sFullCorrectionDistance;
2142   const F32 maxAdjD = 500;
2143
2144   VectorF  aheadVec(0, maxAdjD, 0);
2145
2146   MatrixF  camMat;
2147   Point3F  camPos;
2148
2149   F32 pos = 0;
2150   GameConnection * gc = getControllingClient();
2151   if (gc && !gc->isFirstPerson())
2152      pos = 1.0f;
2153
2154   getCameraTransform(&pos, &camMat);
2155
2156   camMat.getColumn(3, &camPos);
2157   camMat.mulV(aheadVec);
2158   Point3F  aheadPoint = (camPos + aheadVec);
2159
2160   // Should we check if muzzle point is really close to camera?  Does that happen?
2161   Point3F  muzzlePos;
2162   muzzleMat.getColumn(3, &muzzlePos);
2163
2164   Point3F  collidePoint;
2165   VectorF  collideVector;
2166   disableCollision();
2167      RayInfo rinfo;
2168      if (getContainer()->castRay(camPos, aheadPoint, STATIC_COLLISION_TYPEMASK</a>|<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1a96ad067ae761cdb0978acf1983f7990da37d67fb4e997b0b39ee39023bdde80ab">DAMAGEABLE_TYPEMASK, &rinfo) &&
2169         (mDot(rinfo.point - mObjToWorld.getPosition(), mObjToWorld.getForwardVector()) > 0)) // Check if point is behind us (could happen in 3rd person view)
2170         collideVector = ((collidePoint = rinfo.point) - camPos);
2171      else
2172         collideVector = ((collidePoint = aheadPoint) - camPos);
2173   enableCollision();
2174
2175   // For close collision we want to NOT aim at ground since we're bending
2176   // the ray here as it is.  But we don't want to pop, so adjust continuously.
2177   F32   lenSq = collideVector.lenSquared();
2178   if (lenSq < (pullInD * pullInD) && lenSq > 0.04)
2179   {
2180      F32   len = mSqrt(lenSq);
2181      F32   mid = pullInD;    // (pullInD + len) / 2.0;
2182      // This gives us point beyond to focus on-
2183      collideVector *= (mid / len);
2184      collidePoint = (camPos + collideVector);
2185   }
2186
2187   VectorF  muzzleToCollide = (collidePoint - muzzlePos);
2188   lenSq = muzzleToCollide.lenSquared();
2189   if (lenSq > 0.04)
2190   {
2191      muzzleToCollide *= (1 / mSqrt(lenSq));
2192      * result = muzzleToCollide;
2193      return true;
2194   }
2195   return false;
2196}
2197
2198//----------------------------------------------------------------------------
2199
2200void ShapeBase::updateMass()
2201{
2202   if (mDataBlock) {
2203      F32 imass = 0;
2204      for (U32 i = 0; i < MaxMountedImages; i++) {
2205         MountedImage& image = mMountedImageList[i];
2206         if (image.dataBlock)
2207            imass += image.dataBlock->mass;
2208      }
2209      //
2210      mMass = mDataBlock->mass + imass;
2211      mOneOverMass = 1 / mMass;
2212   }
2213}
2214
2215void ShapeBase::onImage(U32 imageSlot, bool unmount)
2216{
2217}
2218
2219void ShapeBase::onImageRecoil(U32,ShapeBaseImageData::StateData::RecoilState)
2220{
2221}
2222
2223void ShapeBase::onImageStateAnimation(U32 imageSlot, const char* seqName, bool direction, bool scaleToState, F32 stateTimeOutValue)
2224{
2225}
2226
2227void ShapeBase::onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState, const char* anim, F32 pos, F32 timeScale, bool reset)
2228{
2229}
2230
2231void ShapeBase::onImageAnimThreadUpdate(U32 imageSlot, S32 imageShapeIndex, F32 dt)
2232{
2233}
2234
2235
2236//----------------------------------------------------------------------------
2237
2238void ShapeBase::setImage(  U32 imageSlot, 
2239                           ShapeBaseImageData* imageData, 
2240                           NetStringHandle& skinNameHandle, 
2241                           bool loaded, 
2242                           bool ammo, 
2243                           bool triggerDown,
2244                           bool altTriggerDown,
2245                           bool motion,
2246                           bool genericTrigger0,
2247                           bool genericTrigger1,
2248                           bool genericTrigger2,
2249                           bool genericTrigger3,
2250                           bool target)
2251{
2252   AssertFatal(imageSlot<MaxMountedImages,"Out of range image slot");
2253
2254   MountedImage& image = mMountedImageList[imageSlot];
2255
2256   // If we already have this datablock...
2257   if (image.dataBlock == imageData) {
2258      // Mark that there is not a datablock change pending.
2259      image.nextImage = InvalidImagePtr;
2260      // Change the skin handle if necessary.
2261      if (image.skinNameHandle != skinNameHandle) {
2262         if (!isGhost()) {
2263            // Serverside, note the skin handle and tell the client.
2264            image.skinNameHandle = skinNameHandle;
2265            setMaskBits(ImageMaskN << imageSlot);
2266         }
2267         else {
2268            // Clientside, do the reskin.
2269            image.skinNameHandle = skinNameHandle;
2270            for( U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2271            {
2272               if (image.shapeInstance[i])
2273               {
2274                  String newSkin = skinNameHandle.getString();
2275                  image.shapeInstance[i]->reSkin(newSkin, image.appliedSkinName);
2276                  image.appliedSkinName = newSkin;
2277               }
2278            }
2279         }
2280      }
2281      return;
2282   }
2283
2284   // Check to see if we need to delay image changes until state change.
2285   if (!isGhost()) {
2286      if (imageData && image.dataBlock && !image.state->allowImageChange) {
2287         image.nextImage = imageData;
2288         image.nextSkinNameHandle = skinNameHandle;
2289         image.nextLoaded = loaded;
2290         return;
2291      }
2292   }
2293
2294   // Mark that updates are happenin'.
2295   setMaskBits(ImageMaskN << imageSlot);
2296
2297   // Notify script unmount since we're swapping datablocks.
2298   if (image.dataBlock && !isGhost()) {
2299      F32 dt = image.dataBlock->useRemainderDT ? image.rDT : 0.0f;
2300      image.dataBlock->onUnmount_callback( this, imageSlot, dt );
2301   }
2302
2303   // Stop anything currently going on with the image.
2304   resetImageSlot(imageSlot);
2305
2306   // If we're just unselecting the current shape without swapping
2307   // in a new one, then bail.
2308   if (!imageData) {
2309      onImage( imageSlot, true);
2310      return;
2311   }
2312
2313   // Otherwise, init the new shape.
2314   image.dataBlock = imageData;
2315   image.state = &image.dataBlock->state[0];
2316   image.skinNameHandle = skinNameHandle;
2317   image.updateDoAnimateAllShapes(this);
2318
2319   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2320   {
2321      if (image.dataBlock->shapeIsValid[i])
2322         image.shapeInstance[i] = new TSShapeInstance(image.dataBlock->shape[i], isClientObject());
2323   }
2324
2325   if (isClientObject())
2326   {
2327      for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2328      {
2329         if (image.shapeInstance[i])
2330         {
2331            image.shapeInstance[i]->cloneMaterialList();
2332            String newSkin = skinNameHandle.getString();
2333            image.shapeInstance[i]->reSkin(newSkin, image.appliedSkinName);
2334            image.appliedSkinName = newSkin;
2335         }
2336      }
2337   }
2338   image.loaded = loaded;
2339   image.ammo = ammo;
2340   image.triggerDown = triggerDown;
2341   image.altTriggerDown = altTriggerDown;
2342   image.target = target;
2343   image.motion = motion;
2344   image.genericTrigger[0] = genericTrigger0;
2345   image.genericTrigger[1] = genericTrigger1;
2346   image.genericTrigger[2] = genericTrigger2;
2347   image.genericTrigger[3] = genericTrigger3;
2348
2349   // The server needs the shape loaded for muzzle mount nodes
2350   // but it doesn't need to run any of the animations, unless the image
2351   // has animateOnServer set.  Then the server needs to animate as well.
2352   // This is often set when using useEyeNode.
2353   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2354   {
2355      image.ambientThread[i] = 0;
2356      image.animThread[i] = 0;
2357      image.flashThread[i] = 0;
2358      image.spinThread[i] = 0;
2359   }
2360
2361   if (imageData->animateOnServer || isGhost())
2362   {
2363      for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2364      {
2365         if (!image.shapeInstance[i])
2366            continue;
2367
2368         if (image.dataBlock->isAnimated[i]) {
2369            image.animThread[i] = image.shapeInstance[i]->addThread();
2370            image.shapeInstance[i]->setTimeScale(image.animThread[i],0);
2371         }
2372         if (image.dataBlock->hasFlash[i]) {
2373            image.flashThread[i] = image.shapeInstance[i]->addThread();
2374            image.shapeInstance[i]->setTimeScale(image.flashThread[i],0);
2375         }
2376         if (image.dataBlock->ambientSequence[i] != -1) {
2377            image.ambientThread[i] = image.shapeInstance[i]->addThread();
2378            image.shapeInstance[i]->setTimeScale(image.ambientThread[i],1);
2379            image.shapeInstance[i]->setSequence(image.ambientThread[i],
2380                                             image.dataBlock->ambientSequence[i],0);
2381         }
2382         if (image.dataBlock->spinSequence[i] != -1) {
2383            image.spinThread[i] = image.shapeInstance[i]->addThread();
2384            image.shapeInstance[i]->setTimeScale(image.spinThread[i],1);
2385            image.shapeInstance[i]->setSequence(image.spinThread[i],
2386                                             image.dataBlock->spinSequence[i],0);
2387         }
2388      }
2389   }
2390
2391   // Set the image to its starting state.
2392   setImageState(imageSlot, (U32)0, true);
2393
2394   // Update the mass for the mount object.
2395   updateMass();
2396
2397   // Notify script mount.
2398   if ( !isGhost() )
2399   {
2400      F32 dt = image.dataBlock->useRemainderDT ? image.rDT : 0.0f;
2401      image.dataBlock->onMount_callback( this, imageSlot, dt );
2402   }
2403   else
2404   {
2405      if ( imageData->lightType == ShapeBaseImageData::PulsingLight )
2406         image.lightStart = Sim::getCurrentTime();
2407   }
2408
2409   onImage(imageSlot, false);
2410
2411   // Done.
2412}
2413
2414
2415//----------------------------------------------------------------------------
2416
2417void ShapeBase::resetImageSlot(U32 imageSlot)
2418{
2419   AssertFatal(imageSlot<MaxMountedImages,"Out of range image slot");
2420
2421   // Clear out current image
2422   MountedImage& image = mMountedImageList[imageSlot];
2423   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2424   {
2425      delete image.shapeInstance[i];
2426      image.shapeInstance[i] = 0;
2427   }
2428
2429   // stop sound
2430   for(Vector<SFXSource*>::iterator i = image.mSoundSources.begin(); i != image.mSoundSources.end(); i++)  
2431   {  
2432      SFX_DELETE((*i));  
2433   }  
2434   image.mSoundSources.clear(); 
2435
2436   for (S32 i = 0; i < MaxImageEmitters; i++) {
2437      MountedImage::ImageEmitter& em = image.emitter[i];
2438      if (bool(em.emitter)) {
2439         em.emitter->deleteWhenEmpty();
2440         em.emitter = 0;
2441      }
2442   }
2443
2444   image.dataBlock = 0;
2445   image.nextImage = InvalidImagePtr;
2446   image.skinNameHandle = NetStringHandle();
2447   image.nextSkinNameHandle  = NetStringHandle();
2448   image.state = 0;
2449   image.delayTime = 0;
2450   image.rDT = 0;
2451   image.ammo = false;
2452   image.triggerDown = false;
2453   image.altTriggerDown = false;
2454   image.loaded = false;
2455   image.motion = false;
2456
2457   for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
2458   {
2459      image.genericTrigger[i] = false;
2460   }
2461
2462   image.lightStart = 0;
2463   if ( image.lightInfo != NULL )
2464      SAFE_DELETE( image.lightInfo );
2465
2466   updateMass();
2467}
2468
2469
2470//----------------------------------------------------------------------------
2471
2472bool ShapeBase::getImageTriggerState(U32 imageSlot)
2473{
2474   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
2475      return false;
2476   return mMountedImageList[imageSlot].triggerDown;
2477}
2478
2479void ShapeBase::setImageTriggerState(U32 imageSlot,bool trigger)
2480{
2481   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
2482      return;
2483   MountedImage& image = mMountedImageList[imageSlot];
2484
2485   if (trigger) {
2486      if (!image.triggerDown && image.dataBlock) {
2487         image.triggerDown = true;
2488         if (!isGhost()) {
2489            setMaskBits(ImageMaskN << imageSlot);
2490            updateImageState(imageSlot,0);
2491         }
2492      }
2493   }
2494   else
2495      if (image.triggerDown) {
2496         image.triggerDown = false;
2497         if (!isGhost()) {
2498            setMaskBits(ImageMaskN << imageSlot);
2499            updateImageState(imageSlot,0);
2500         }
2501      }
2502}
2503
2504bool ShapeBase::getImageAltTriggerState(U32 imageSlot)
2505{
2506   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
2507      return false;
2508   return mMountedImageList[imageSlot].altTriggerDown;
2509}
2510
2511void ShapeBase::setImageAltTriggerState(U32 imageSlot,bool trigger)
2512{
2513   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
2514      return;
2515   MountedImage& image = mMountedImageList[imageSlot];
2516
2517   if (trigger) {
2518      if (!image.altTriggerDown && image.dataBlock) {
2519         image.altTriggerDown = true;
2520         if (!isGhost()) {
2521            setMaskBits(ImageMaskN << imageSlot);
2522            updateImageState(imageSlot,0);
2523         }
2524      }
2525   }
2526   else
2527      if (image.altTriggerDown) {
2528         image.altTriggerDown = false;
2529         if (!isGhost()) {
2530            setMaskBits(ImageMaskN << imageSlot);
2531            updateImageState(imageSlot,0);
2532         }
2533      }
2534}
2535
2536//----------------------------------------------------------------------------
2537
2538U32 ShapeBase::getImageFireState(U32 imageSlot)
2539{
2540   MountedImage& image = mMountedImageList[imageSlot];
2541   // If there is no fire state, then try state 0
2542   if (image.dataBlock && image.dataBlock->fireState != -1)
2543      return image.dataBlock->fireState;
2544   return 0;
2545}
2546
2547U32 ShapeBase::getImageAltFireState(U32 imageSlot)
2548{
2549   MountedImage& image = mMountedImageList[imageSlot];
2550   // If there is no alternate fire state, then try state 0
2551   if (image.dataBlock && image.dataBlock->altFireState != -1)
2552      return image.dataBlock->altFireState;
2553   return 0;
2554}
2555
2556U32  ShapeBase::getImageReloadState(U32 imageSlot)
2557{
2558   MountedImage& image = mMountedImageList[imageSlot];
2559   // If there is no reload state, then try state 0
2560   if (image.dataBlock && image.dataBlock->reloadState != -1)
2561      return image.dataBlock->reloadState;
2562   return 0;
2563}
2564
2565
2566//----------------------------------------------------------------------------
2567
2568bool ShapeBase::hasImageState(U32 imageSlot, const char* state)
2569{
2570   if (!state || !state[0])
2571      return false;
2572
2573   MountedImage& image = mMountedImageList[imageSlot];
2574   if (image.dataBlock)
2575   {
2576      for (U32 i = 0; i < ShapeBaseImageData::MaxStates; i++)
2577      {
2578         ShapeBaseImageData::StateData& sd = image.dataBlock->state[i];
2579         if (sd.name && !dStricmp(state, sd.name))
2580            return true;
2581      }
2582   }
2583
2584   return false;
2585}
2586
2587void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
2588{
2589   if (!mMountedImageList[imageSlot].dataBlock)
2590      return;
2591   MountedImage& image = mMountedImageList[imageSlot];
2592
2593
2594   // The client never enters the initial fire state on its own, but it
2595   //  will continue to set that state...
2596   if (isGhost() && !force && newState == image.dataBlock->fireState) {
2597      if (image.state != &image.dataBlock->state[newState])
2598         return;
2599   }
2600
2601   // The client never enters the initial alternate fire state on its own, but it
2602   //  will continue to set that state...
2603   if (isGhost() && !force && newState == image.dataBlock->altFireState) {
2604      if (image.state != &image.dataBlock->state[newState])
2605         return;
2606   }
2607
2608   // The client never enters the initial reload state on its own, but it
2609   //  will continue to set that state...
2610   if (isGhost() && !force && newState == image.dataBlock->reloadState) {
2611      if (image.state != &image.dataBlock->state[newState])
2612         return;
2613   }
2614
2615   // Eject shell casing on every state change (client side only)
2616   ShapeBaseImageData::StateData& nextStateData = image.dataBlock->state[newState];
2617   if (isGhost() && nextStateData.ejectShell) {
2618      ejectShellCasing( imageSlot );
2619   }
2620
2621   // Shake camera on client.
2622   if (isGhost() && nextStateData.fire && image.dataBlock->shakeCamera) {
2623      shakeCamera( imageSlot );
2624   }
2625
2626   // Server must animate the shape if it is a firestate...
2627   if (isServerObject() && (image.dataBlock->state[newState].fire || image.dataBlock->state[newState].altFire))
2628      mShapeInstance->animate();
2629
2630   // Obtain the image's shape index for future use.
2631   U32 imageShapeIndex = getImageShapeIndex(image);
2632   image.lastShapeIndex = imageShapeIndex;
2633
2634   // If going back into the same state, just reset the timer
2635   // and invoke the script callback
2636   if (!force && image.state == &image.dataBlock->state[newState]) {
2637      image.delayTime = image.state->timeoutValue;
2638      if (image.state->script && !isGhost())
2639         scriptCallback(imageSlot,image.state->script);
2640
2641      // If this is a flash sequence, we need to select a new position for the
2642      //  animation if we're returning to that state...
2643      F32 randomPos = Platform::getRandom();
2644      for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2645      {
2646         if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
2647            continue;
2648
2649         if (image.animThread[i] && image.state->sequence[i] != -1 && image.state->flashSequence[i]) {
2650            image.shapeInstance[i]->setPos(image.animThread[i], randomPos);
2651            image.shapeInstance[i]->setTimeScale(image.animThread[i], 0);
2652            if (image.flashThread[i])
2653               image.shapeInstance[i]->setPos(image.flashThread[i], 0);
2654         }
2655      }
2656
2657      return;
2658   }
2659
2660   F32 lastDelay = image.delayTime;
2661   ShapeBaseImageData::StateData* lastState = image.state;
2662   image.state = &image.dataBlock->state[newState];
2663
2664   //
2665   // Do state cleanup first...
2666   //
2667   ShapeBaseImageData::StateData& stateData = *image.state;
2668   image.delayTime = stateData.timeoutValue;
2669
2670   // Mount pending images
2671   if (image.nextImage != InvalidImagePtr && stateData.allowImageChange) {
2672      setImage(imageSlot,image.nextImage,image.nextSkinNameHandle,image.nextLoaded);
2673      return;
2674   }
2675
2676   // Reset cyclic sequences back to the first frame to turn it off
2677   // (the first key frame should be it's off state).
2678   // We need to do this across all image shapes to make sure we have no hold overs when switching
2679   // rendering shapes while in the middle of a state change.
2680   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2681   {
2682      // If we are to do a sequence transition then we need to keep the previous animThread active
2683      if (image.animThread[i] && image.animThread[i]->getSequence()->isCyclic() && (stateData.sequenceNeverTransition || !(stateData.sequenceTransitionIn || lastState->sequenceTransitionOut))) {
2684         image.shapeInstance[i]->setPos(image.animThread[i],0);
2685         image.shapeInstance[i]->setTimeScale(image.animThread[i],0);
2686      }
2687      if (image.flashThread[i]) {
2688         image.shapeInstance[i]->setPos(image.flashThread[i],0);
2689         image.shapeInstance[i]->setTimeScale(image.flashThread[i],0);
2690      }
2691   }
2692
2693   // Broadcast the reset
2694   onImageAnimThreadChange(imageSlot, imageShapeIndex, lastState, NULL, 0, 0, true);
2695
2696   // Check for immediate transitions, but only if we don't need to wait for
2697   // a time out.  Only perform this wait if we're not forced to change.
2698   S32 ns;
2699   if (image.delayTime <= 0 || !stateData.waitForTimeout) 
2700   {
2701      if ((ns = stateData.transition.loaded[image.loaded]) != -1) {
2702         setImageState(imageSlot,ns);
2703         return;
2704      }
2705      for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
2706      {
2707         if ((ns = stateData.transition.genericTrigger[i][image.genericTrigger[i]]) != -1) {
2708            setImageState(imageSlot, ns);
2709            return;
2710         }
2711      }
2712      //if (!imageData.usesEnergy)
2713         if ((ns = stateData.transition.ammo[image.ammo]) != -1) {
2714            setImageState(imageSlot,ns);
2715            return;
2716         }
2717      if ((ns = stateData.transition.target[image.target]) != -1) {
2718         setImageState(imageSlot, ns);
2719         return;
2720      }
2721      if ((ns = stateData.transition.wet[image.wet]) != -1) {
2722         setImageState(imageSlot, ns);
2723         return;
2724      }
2725      if ((ns = stateData.transition.motion[image.motion]) != -1) {
2726         setImageState(imageSlot, ns);
2727         return;
2728      }
2729      if ((ns = stateData.transition.trigger[image.triggerDown]) != -1) {
2730         setImageState(imageSlot,ns);
2731         return;
2732      }
2733      if ((ns = stateData.transition.altTrigger[image.altTriggerDown]) != -1) {
2734         setImageState(imageSlot,ns);
2735         return;
2736      }
2737   }
2738
2739   //
2740   // Initialize the new state...
2741   //
2742   if (stateData.loaded != ShapeBaseImageData::StateData::IgnoreLoaded)
2743      image.loaded = stateData.loaded == ShapeBaseImageData::StateData::Loaded;
2744   if (!isGhost() && image.dataBlock->state[newState].fire) {
2745      setMaskBits(ImageMaskN << imageSlot);
2746      image.fireCount = (image.fireCount + 1) & 0x7;
2747   }
2748   if (!isGhost() && image.dataBlock->state[newState].altFire) {
2749      setMaskBits(ImageMaskN << imageSlot);
2750      image.altFireCount = (image.altFireCount + 1) & 0x7;
2751   }
2752   if (!isGhost() && image.dataBlock->state[newState].reload) {
2753      setMaskBits(ImageMaskN << imageSlot);
2754      image.reloadCount = (image.reloadCount + 1) & 0x7;
2755   }
2756
2757   // Apply recoil
2758   if (stateData.recoil != ShapeBaseImageData::StateData::NoRecoil)
2759      onImageRecoil(imageSlot,stateData.recoil);
2760
2761   // Apply image state animation on mounting shape
2762   if (stateData.shapeSequence && stateData.shapeSequence[0])
2763   {
2764      onImageStateAnimation(imageSlot, stateData.shapeSequence, stateData.direction, stateData.shapeSequenceScale, stateData.timeoutValue);
2765   }
2766
2767   // Delete any loooping sounds that were in the previous state.
2768   if (lastState->sound && lastState->sound->getDescription()->mIsLooping)  
2769   {  
2770      for(Vector<SFXSource*>::iterator i = image.mSoundSources.begin(); i != image.mSoundSources.end(); i++)      
2771         SFX_DELETE((*i));    
2772
2773      image.mSoundSources.clear();  
2774   }  
2775
2776   // Play sound
2777   if( stateData.sound && isGhost() )
2778   {
2779      const Point3F& velocity         = getVelocity();
2780      image.addSoundSource(SFX->createSource( stateData.sound, &getRenderTransform(), &velocity )); 
2781   }
2782
2783   // Play animation
2784   updateAnimThread(imageSlot, imageShapeIndex, lastState);
2785   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2786   {
2787      if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
2788         continue;
2789
2790      // Start spin thread
2791      if (image.spinThread[i]) {
2792         switch (stateData.spin) {
2793          case ShapeBaseImageData::StateData::IgnoreSpin:
2794            image.shapeInstance[i]->setTimeScale(image.spinThread[i], image.shapeInstance[i]->getTimeScale(image.spinThread[i]));
2795            break;
2796          case ShapeBaseImageData::StateData::NoSpin:
2797            image.shapeInstance[i]->setTimeScale(image.spinThread[i],0);
2798            break;
2799          case ShapeBaseImageData::StateData::SpinUp:
2800            if (lastState->spin == ShapeBaseImageData::StateData::SpinDown)
2801               image.delayTime *= 1.0f - (lastDelay / stateData.timeoutValue);
2802            break;
2803          case ShapeBaseImageData::StateData::SpinDown:
2804            if (lastState->spin == ShapeBaseImageData::StateData::SpinUp)
2805               image.delayTime *= 1.0f - (lastDelay / stateData.timeoutValue);
2806            break;
2807          case ShapeBaseImageData::StateData::FullSpin:
2808            image.shapeInstance[i]->setTimeScale(image.spinThread[i],1);
2809            break;
2810         }
2811      }
2812   }
2813
2814   // Start particle emitter on the client (client side only)
2815   if (isGhost() && stateData.emitter)
2816      startImageEmitter(image,stateData);
2817
2818   // Script callback on server
2819   if (stateData.script && stateData.script[0] && !isGhost())
2820      scriptCallback(imageSlot,stateData.script);
2821
2822   // If there is a zero timeout, and a timeout transition, then
2823   // go ahead and transition imediately.
2824   if (!image.delayTime)
2825   {
2826      if ((ns = stateData.transition.timeout) != -1)
2827      {
2828         setImageState(imageSlot,ns);
2829         return;
2830      }
2831   }
2832}
2833
2834void ShapeBase::updateAnimThread(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState)
2835{
2836   MountedImage& image = mMountedImageList[imageSlot];
2837   ShapeBaseImageData::StateData& stateData = *image.state;
2838
2839   F32 randomPos = Platform::getRandom();
2840   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
2841   {
2842      if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
2843         continue;
2844
2845      if (image.animThread[i] && stateData.sequence[i] != -1) 
2846      {
2847         S32 seqIndex = stateData.sequence[i];  // Standard index without any prefix
2848         bool scaleAnim = stateData.scaleAnimation;
2849         if (i == ShapeBaseImageData::FirstPersonImageShape)
2850            scaleAnim = stateData.scaleAnimationFP;
2851
2852         // We're going to apply various prefixes to determine the final sequence to use.
2853         // Here is the order:
2854         // shapeBasePrefix_scriptPrefix_baseAnimName
2855         // shapeBasePrefix_baseAnimName
2856         // scriptPrefix_baseAnimName
2857         // baseAnimName
2858
2859         // Collect the prefixes
2860         const char* shapeBasePrefix = getImageAnimPrefix(imageSlot, i);
2861         bool hasShapeBasePrefix = shapeBasePrefix && shapeBasePrefix[0];
2862         const char* scriptPrefix = getImageScriptAnimPrefix(imageSlot).getString();
2863         bool hasScriptPrefix = scriptPrefix && scriptPrefix[0];
2864
2865         // Find the final sequence based on the prefix combinations
2866         if (hasShapeBasePrefix || hasScriptPrefix)
2867         {
2868            bool found = false;
2869            String baseSeqName(image.shapeInstance[i]->getShape()->getSequenceName(stateData.sequence[i]));
2870
2871            if (!found && hasShapeBasePrefix && hasScriptPrefix)
2872            {
2873               String seqName = String(shapeBasePrefix) + String("_") + String(scriptPrefix) + String("_") + baseSeqName;
2874               S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2875               if (index != -1)
2876               {
2877                  seqIndex = index;
2878                  found = true;
2879               }
2880            }
2881
2882            if (!found && hasShapeBasePrefix)
2883            {
2884               String seqName = String(shapeBasePrefix) + String("_") + baseSeqName;
2885               S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2886               if (index != -1)
2887               {
2888                  seqIndex = index;
2889                  found = true;
2890               }
2891            }
2892
2893            if (!found && hasScriptPrefix)
2894            {
2895               String seqName = String(scriptPrefix) + String("_") + baseSeqName;
2896               S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2897               if (index != -1)
2898               {
2899                  seqIndex = index;
2900                  found = true;
2901               }
2902            }
2903         }
2904
2905         if (seqIndex != -1)
2906         {
2907            if (!lastState)
2908            {
2909               // No lastState indicates that we are just switching animation sequences, not states.  Transition into this new sequence, but only
2910               // if it is different than what we're currently playing.
2911               S32 prevSeq = -1;
2912               if (image.animThread[i]->hasSequence())
2913               {
2914                  prevSeq = image.shapeInstance[i]->getSequence(image.animThread[i]);
2915               }
2916               if (seqIndex != prevSeq)
2917               {
2918                  image.shapeInstance[i]->transitionToSequence(image.animThread[i], seqIndex, stateData.direction ? 0.0f : 1.0f, image.dataBlock->scriptAnimTransitionTime, true);
2919               }
2920            }
2921            else if (!stateData.sequenceNeverTransition && stateData.sequenceTransitionTime && (stateData.sequenceTransitionIn || lastState->sequenceTransitionOut))
2922            {
2923               image.shapeInstance[i]->transitionToSequence(image.animThread[i], seqIndex, stateData.direction ? 0.0f : 1.0f, stateData.sequenceTransitionTime, true);
2924            }
2925            else
2926            {
2927               image.shapeInstance[i]->setSequence(image.animThread[i], seqIndex, stateData.direction ? 0.0f : 1.0f);
2928            }
2929
2930            if (stateData.flashSequence[i] == false) 
2931            {
2932               F32 timeScale = (scaleAnim && stateData.timeoutValue) ?
2933                  image.shapeInstance[i]->getDuration(image.animThread[i]) / stateData.timeoutValue : 1.0f;
2934               image.shapeInstance[i]->setTimeScale(image.animThread[i], stateData.direction ? timeScale : -timeScale);
2935
2936               // Broadcast the sequence change
2937               String seqName = image.shapeInstance[i]->getShape()->getSequenceName(stateData.sequence[i]);
2938               onImageAnimThreadChange(imageSlot, imageShapeIndex, lastState, seqName, stateData.direction ? 0.0f : 1.0f, stateData.direction ? timeScale : -timeScale);
2939            }
2940            else
2941            {
2942               image.shapeInstance[i]->setPos(image.animThread[i], randomPos);
2943               image.shapeInstance[i]->setTimeScale(image.animThread[i], 0);
2944
2945               S32 seqVisIndex = stateData.sequenceVis[i];
2946
2947               // Go through the same process as the animThread sequence to find the flashThread sequence
2948               if (hasShapeBasePrefix || hasScriptPrefix)
2949               {
2950                  bool found = false;
2951                  String baseVisSeqName(image.shapeInstance[i]->getShape()->getSequenceName(stateData.sequenceVis[i]));
2952
2953                  if (!found && hasShapeBasePrefix && hasScriptPrefix)
2954                  {
2955                     String seqName = String(shapeBasePrefix) + String("_") + String(scriptPrefix) + String("_") + baseVisSeqName;
2956                     S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2957                     if (index != -1)
2958                     {
2959                        seqVisIndex = index;
2960                        found = true;
2961                     }
2962                  }
2963
2964                  if (!found && hasShapeBasePrefix)
2965                  {
2966                     String seqName = String(shapeBasePrefix) + String("_") + baseVisSeqName;
2967                     S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2968                     if (index != -1)
2969                     {
2970                        seqVisIndex = index;
2971                        found = true;
2972                     }
2973                  }
2974
2975                  if (!found && hasScriptPrefix)
2976                  {
2977                     String seqName = String(scriptPrefix) + String("_") + baseVisSeqName;
2978                     S32 index = image.shapeInstance[i]->getShape()->findSequence(seqName);
2979                     if (index != -1)
2980                     {
2981                        seqVisIndex = index;
2982                        found = true;
2983                     }
2984                  }
2985               }
2986
2987               image.shapeInstance[i]->setSequence(image.flashThread[i], seqVisIndex, 0);
2988               image.shapeInstance[i]->setPos(image.flashThread[i], 0);
2989               F32 timeScale = (scaleAnim && stateData.timeoutValue) ?
2990                  image.shapeInstance[i]->getDuration(image.flashThread[i]) / stateData.timeoutValue : 1.0f;
2991               image.shapeInstance[i]->setTimeScale(image.flashThread[i], timeScale);
2992
2993               // Broadcast the sequence change
2994               String seqName = image.shapeInstance[i]->getShape()->getSequenceName(stateData.sequenceVis[i]);
2995               onImageAnimThreadChange(imageSlot, imageShapeIndex, lastState, seqName, stateData.direction ? 0.0f : 1.0f, stateData.direction ? timeScale : -timeScale);
2996            }
2997         }
2998      }
2999   }
3000}
3001
3002
3003//----------------------------------------------------------------------------
3004
3005void ShapeBase::updateImageState(U32 imageSlot,F32 dt)
3006{
3007   if (!mMountedImageList[imageSlot].dataBlock)
3008      return;
3009   MountedImage& image = mMountedImageList[imageSlot];
3010   ShapeBaseImageData& imageData = *image.dataBlock;
3011
3012   image.rDT = dt;
3013   F32 elapsed;
3014
3015TICKAGAIN:
3016
3017   ShapeBaseImageData::StateData& stateData = *image.state;
3018
3019   if ( image.delayTime > dt )
3020      elapsed = dt;
3021   else
3022      elapsed = image.delayTime;
3023
3024   dt = elapsed;
3025   image.rDT -= elapsed;
3026
3027   image.delayTime -= dt;
3028
3029   // Energy management
3030   if (imageData.usesEnergy) 
3031   {
3032      F32 newEnergy = getEnergyLevel() - stateData.energyDrain * dt;
3033      if (newEnergy < 0)
3034         newEnergy = 0;
3035      setEnergyLevel(newEnergy);
3036
3037      if (!isGhost()) 
3038      {
3039         bool ammo = newEnergy > imageData.minEnergy;
3040         if (ammo != image.ammo) 
3041         {
3042            setMaskBits(ImageMaskN << imageSlot);
3043            image.ammo = ammo;
3044         }
3045      }
3046   }
3047
3048   // Check for transitions. On some states we must wait for the
3049   // full timeout value before moving on.
3050   if (image.delayTime <= 0 || !stateData.waitForTimeout) 
3051   {
3052      S32 ns;
3053
3054      if ((ns = stateData.transition.loaded[image.loaded]) != -1) 
3055         setImageState(imageSlot,ns);
3056      else if ((ns = stateData.transition.genericTrigger[0][image.genericTrigger[0]]) != -1)
3057         setImageState(imageSlot,ns);
3058      else if ((ns = stateData.transition.genericTrigger[1][image.genericTrigger[1]]) != -1)
3059         setImageState(imageSlot,ns);
3060      else if ((ns = stateData.transition.genericTrigger[2][image.genericTrigger[2]]) != -1)
3061         setImageState(imageSlot,ns);
3062      else if ((ns = stateData.transition.genericTrigger[3][image.genericTrigger[3]]) != -1)
3063         setImageState(imageSlot,ns);
3064      else if ((ns = stateData.transition.ammo[image.ammo]) != -1) 
3065         setImageState(imageSlot,ns);
3066      else if ((ns = stateData.transition.target[image.target]) != -1) 
3067         setImageState(imageSlot,ns);
3068      else if ((ns = stateData.transition.wet[image.wet]) != -1)
3069         setImageState(imageSlot,ns);
3070      else if ((ns = stateData.transition.motion[image.motion]) != -1)
3071         setImageState(imageSlot,ns);
3072      else if ((ns = stateData.transition.trigger[image.triggerDown]) != -1)
3073         setImageState(imageSlot,ns);
3074      else if ((ns = stateData.transition.altTrigger[image.altTriggerDown]) != -1) 
3075         setImageState(imageSlot,ns);
3076      else if (image.delayTime <= 0 && (ns = stateData.transition.timeout) != -1) 
3077         setImageState(imageSlot,ns);
3078   }
3079
3080   // Update the spinning thread timeScale
3081   U32 imageShapeIndex = getImageShapeIndex(image);
3082   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
3083   {
3084      if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
3085         continue;
3086
3087      if (image.spinThread[i])
3088      {
3089         F32 timeScale;
3090
3091         switch (stateData.spin) 
3092         {
3093            case ShapeBaseImageData::StateData::IgnoreSpin:
3094            case ShapeBaseImageData::StateData::NoSpin:
3095            case ShapeBaseImageData::StateData::FullSpin: 
3096            {
3097               timeScale = 0;
3098               image.shapeInstance[i]->setTimeScale(image.spinThread[i], image.shapeInstance[i]->getTimeScale(image.spinThread[i]));
3099               break;
3100            }
3101
3102            case ShapeBaseImageData::StateData::SpinUp: 
3103            {
3104               timeScale = 1.0f - image.delayTime / stateData.timeoutValue;
3105               image.shapeInstance[i]->setTimeScale(image.spinThread[i],timeScale);
3106               break;
3107            }
3108
3109            case ShapeBaseImageData::StateData::SpinDown: 
3110            {
3111               timeScale = image.delayTime / stateData.timeoutValue;
3112               image.shapeInstance[i]->setTimeScale(image.spinThread[i],timeScale);
3113               break;
3114            }
3115         }
3116      }
3117   }
3118
3119   if ( image.rDT > 0.0f && image.delayTime > 0.0f && imageData.useRemainderDT && dt != 0.0f )
3120   {
3121      dt = image.rDT;
3122      goto TICKAGAIN;
3123   }
3124}
3125
3126
3127//----------------------------------------------------------------------------
3128
3129void ShapeBase::updateImageAnimation(U32 imageSlot, F32 dt)
3130{
3131   if (!mMountedImageList[imageSlot].dataBlock)
3132      return;
3133   MountedImage& image = mMountedImageList[imageSlot];
3134   U32 imageShapeIndex = getImageShapeIndex(image);
3135
3136   // Advance animation threads
3137   for (U32 i=0; i<ShapeBaseImageData::MaxShapes; ++i)
3138   {
3139      if (!image.dataBlock->shapeIsValid[i] || (i != imageShapeIndex && !image.doAnimateAllShapes))
3140         continue;
3141
3142      if (image.ambientThread[i])
3143         image.shapeInstance[i]->advanceTime(dt,image.ambientThread[i]);
3144      if (image.animThread[i])
3145         image.shapeInstance[i]->advanceTime(dt,image.animThread[i]);
3146      if (image.spinThread[i])
3147         image.shapeInstance[i]->advanceTime(dt,image.spinThread[i]);
3148      if (image.flashThread[i])
3149         image.shapeInstance[i]->advanceTime(dt,image.flashThread[i]);
3150   }
3151
3152   // Broadcast the update
3153   onImageAnimThreadUpdate(imageSlot, imageShapeIndex, dt);
3154
3155   image.updateSoundSources(getRenderTransform());
3156
3157   // Particle emission
3158   for (S32 i = 0; i < MaxImageEmitters; i++) {
3159      MountedImage::ImageEmitter& em = image.emitter[i];
3160      if (bool(em.emitter)) {
3161         if (em.time > 0) {
3162            em.time -= dt;
3163
3164            // Do we need to update the emitter's node due to the current shape changing?
3165            if (imageShapeIndex != image.lastShapeIndex)
3166            {
3167               em.node = image.state->emitterNode[imageShapeIndex];
3168            }
3169
3170            MatrixF mat;
3171            getRenderImageTransform(imageSlot,em.node,&mat);
3172            Point3F pos,axis;
3173            mat.getColumn(3,&pos);
3174            mat.getColumn(1,&axis);
3175            em.emitter->emitParticles(pos,true,axis,getVelocity(),(U32) (dt * 1000));
3176         }
3177         else {
3178            em.emitter->deleteWhenEmpty();
3179            em.emitter = 0;
3180         }
3181      }
3182   }
3183
3184   image.lastShapeIndex = imageShapeIndex;
3185}
3186
3187
3188//----------------------------------------------------------------------------
3189
3190void ShapeBase::setImageScriptAnimPrefix(U32 imageSlot, NetStringHandle prefix)
3191{
3192   MountedImage& image = mMountedImageList[imageSlot];
3193   if (image.dataBlock) {
3194      setMaskBits(ImageMaskN << imageSlot);
3195      image.scriptAnimPrefix = prefix;
3196   }
3197}
3198
3199NetStringHandle ShapeBase::getImageScriptAnimPrefix(U32 imageSlot)
3200{
3201   MountedImage& image = mMountedImageList[imageSlot];
3202   return image.dataBlock? image.scriptAnimPrefix : NetStringHandle();
3203}
3204
3205
3206//----------------------------------------------------------------------------
3207
3208U32 ShapeBase::getImageShapeIndex(const MountedImage& image) const
3209{
3210   U32 shapeIndex = ShapeBaseImageData::StandardImageShape;
3211
3212   const ShapeBaseImageData* data = image.dataBlock;
3213   if (data && data->useFirstPersonShape && isFirstPerson())
3214      shapeIndex = ShapeBaseImageData::FirstPersonImageShape;
3215
3216   return shapeIndex;
3217}
3218
3219
3220//----------------------------------------------------------------------------
3221
3222void ShapeBase::startImageEmitter(MountedImage& image,ShapeBaseImageData::StateData& state)
3223{
3224   MountedImage::ImageEmitter* bem = 0;
3225   MountedImage::ImageEmitter* em = image.emitter;
3226   MountedImage::ImageEmitter* ee = &image.emitter[MaxImageEmitters];
3227
3228   U32 imageShapeIndex = getImageShapeIndex(image);
3229
3230   // If we are already emitting the same particles from the same
3231   // node, then simply extend the time.  Otherwise, find an empty
3232   // emitter slot, or grab the one with the least amount of time left.
3233   for (; em != ee; em++) {
3234      if (bool(em->emitter)) {
3235         if (state.emitter == em->emitter->getDataBlock() && state.emitterNode[imageShapeIndex] == em->node) {
3236            if (state.emitterTime > em->time)
3237               em->time = state.emitterTime;
3238            return;
3239         }
3240         if (!bem || (bool(bem->emitter) && bem->time > em->time))
3241            bem = em;
3242      }
3243      else
3244         bem = em;
3245   }
3246
3247   bem->time = state.emitterTime;
3248   bem->node = state.emitterNode[imageShapeIndex];
3249   bem->emitter = new ParticleEmitter;
3250   bem->emitter->onNewDataBlock(state.emitter,false);
3251   if( !bem->emitter->registerObject() )
3252   {
3253      bem->emitter.getPointer()->destroySelf();
3254      bem->emitter = NULL;
3255   }
3256}
3257
3258void ShapeBase::submitLights( LightManager *lm, bool staticLighting )
3259{
3260   if ( staticLighting )
3261      return;
3262
3263   // Submit lights for MountedImage(s)
3264   for ( S32 i = 0; i < MaxMountedImages; i++ )
3265   {
3266      ShapeBaseImageData *imageData = getMountedImage( i );
3267
3268      if ( imageData != NULL && imageData->lightType != ShapeBaseImageData::NoLight )
3269      {                  
3270         MountedImage &image = mMountedImageList[i];         
3271         
3272         F32 intensity;
3273
3274         switch ( imageData->lightType )
3275         {
3276         case ShapeBaseImageData::ConstantLight:
3277         case ShapeBaseImageData::SpotLight:
3278            intensity = 1.0f;
3279            break;
3280
3281         case ShapeBaseImageData::PulsingLight:
3282            intensity = 0.5f + 0.5f * mSin( M_PI_F * (F32)Sim::getCurrentTime() / (F32)imageData->lightDuration + image.lightStart );
3283            intensity = 0.15f + intensity * 0.85f;
3284            break;
3285
3286         case ShapeBaseImageData::WeaponFireLight:
3287            {
3288            S32 elapsed = Sim::getCurrentTime() - image.lightStart;
3289            if ( elapsed > imageData->lightDuration )
3290               continue;
3291            intensity = ( 1.0 - (F32)elapsed / (F32)imageData->lightDuration ) * imageData->lightBrightness;
3292            break;
3293            }
3294         default:
3295            intensity = 1.0f;
3296            return;
3297         }
3298
3299         if ( !image.lightInfo )
3300            image.lightInfo = LightManager::createLightInfo();
3301
3302         image.lightInfo->setColor( imageData->lightColor );
3303         image.lightInfo->setBrightness( intensity );   
3304         image.lightInfo->setRange( imageData->lightRadius );  
3305
3306         if ( imageData->lightType == ShapeBaseImageData::SpotLight )
3307         {
3308            image.lightInfo->setType( LightInfo::Spot );
3309            // Do we want to expose these or not?
3310            image.lightInfo->setInnerConeAngle( 15 );
3311            image.lightInfo->setOuterConeAngle( 40 );      
3312         }
3313         else
3314            image.lightInfo->setType( LightInfo::Point );
3315
3316         MatrixF imageMat;
3317         getRenderImageTransform( i, &imageMat );
3318
3319         image.lightInfo->setTransform( imageMat );
3320
3321         lm->registerGlobalLight( image.lightInfo, NULL );         
3322      }
3323   }
3324}
3325
3326
3327//----------------------------------------------------------------------------
3328
3329void ShapeBase::ejectShellCasing( U32 imageSlot )
3330{
3331   MountedImage& image = mMountedImageList[imageSlot];
3332   ShapeBaseImageData* imageData = image.dataBlock;
3333
3334   if (!imageData->casing)
3335      return;
3336
3337   // Shell casings are client-side only, so use the render transform.
3338   MatrixF ejectTrans;
3339   getRenderImageTransform( imageSlot, imageData->ejectNode[getImageShapeIndex(image)], &ejectTrans );
3340
3341   Point3F ejectDir = imageData->shellExitDir;
3342   ejectDir.normalize();
3343
3344   F32 ejectSpread = mDegToRad( imageData->shellExitVariance );
3345   MatrixF ejectOrient = MathUtils::createOrientFromDir( ejectDir );
3346
3347   Point3F randomDir;
3348   randomDir.x = mSin( gRandGen.randF( -ejectSpread, ejectSpread ) );
3349   randomDir.y = 1.0;
3350   randomDir.z = mSin( gRandGen.randF( -ejectSpread, ejectSpread ) );
3351   randomDir.normalizeSafe();
3352
3353   ejectOrient.mulV( randomDir );
3354
3355   MatrixF imageTrans = getRenderTransform();
3356   imageTrans.mulV( randomDir );
3357
3358   Point3F shellVel = randomDir * imageData->shellVelocity;
3359   Point3F shellPos = ejectTrans.getPosition();
3360
3361
3362   Debris *casing = new Debris;
3363   casing->onNewDataBlock( imageData->casing, false );
3364   casing->setTransform( imageTrans );
3365
3366   if (!casing->registerObject())
3367      delete casing;
3368   else
3369      casing->init( shellPos, shellVel );
3370}
3371
3372void ShapeBase::shakeCamera( U32 imageSlot )
3373{
3374   MountedImage& image = mMountedImageList[imageSlot];
3375   ShapeBaseImageData* imageData = image.dataBlock;
3376
3377   if (!imageData->shakeCamera)
3378      return;
3379
3380   // Warning: this logic was duplicated from Explosion.
3381
3382   // first check if explosion is near camera
3383   GameConnection* connection = GameConnection::getConnectionToServer();
3384   ShapeBase *obj = dynamic_cast<ShapeBase*>(connection->getControlObject());
3385
3386   bool applyShake = true;
3387
3388   if (obj)
3389   {
3390      ShapeBase* cObj = obj;
3391      while ((cObj = cObj->getControlObject()) != 0)
3392      {
3393         if (cObj->useObjsEyePoint())
3394         {
3395            applyShake = false;
3396            break;
3397         }
3398      }
3399   }
3400
3401   if (applyShake && obj)
3402   {
3403      VectorF diff;
3404      getMuzzlePoint(imageSlot, &diff);
3405      diff = obj->getPosition() - diff;
3406      F32 dist = diff.len();
3407      if (dist < imageData->camShakeRadius)
3408      {
3409         CameraShake *camShake = new CameraShake;
3410         camShake->setDuration(imageData->camShakeDuration);
3411         camShake->setFrequency(imageData->camShakeFreq);
3412
3413         F32 falloff =  dist / imageData->camShakeRadius;
3414         falloff = 1.0f + falloff * 10.0f;
3415         falloff = 1.0f / (falloff * falloff);
3416
3417         VectorF shakeAmp = imageData->camShakeAmp * falloff;
3418         camShake->setAmplitude(shakeAmp);
3419         camShake->setFalloff(imageData->camShakeFalloff);
3420         camShake->init();
3421         gCamFXMgr.addFX(camShake);
3422      }
3423   }
3424}
3425