turretShape.cpp
Engine/source/T3D/turret/turretShape.cpp
Public Variables
Public Functions
ConsoleDocClass(TurretShape , "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
ConsoleDocClass(TurretShapeData , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShape\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShapeData\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(TurretShape , doRespawn , bool , () , "@brief Does the turret respawn after it has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" "@returns True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">respawns.\n</a>" )
DefineEngineMethod(TurretShape , getAllowManualFire , bool , () , "@brief Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , getAllowManualRotation , bool , () , "@brief Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , getState , const char * , () , "@brief Get the name of the turret's current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n\n</a>" "The state is one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n\n</a><ul>" "<li>Dead - The <a href="/coding/class/classturretshape/">TurretShape</a> is destroyed.</li>" "<li>Mounted - The <a href="/coding/class/classturretshape/">TurretShape</a> is mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an object such as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vehicle.</li>" "<li>Ready - The <a href="/coding/class/classturretshape/">TurretShape</a> is free <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move. The usual state.</li></ul>\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return The current state; one of: \"Dead\" , \"Mounted\" , \"Ready\"\n" )
DefineEngineMethod(TurretShape , getTurretEulerRotation , Point3F , () , "@brief Get Euler rotation of this turret's heading and pitch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n\n</a>" "@return the orientation of the turret's heading and pitch nodes in the " "form of rotations around the X, Y and Z axes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n</a>" )
DefineEngineMethod(TurretShape , setAllowManualFire , void , (bool allow) , "@brief Set <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@param allow If true then the turret may be fired through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , setAllowManualRotation , void , (bool allow) , "@brief Set <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@param allow If true then the turret may be rotated through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , setTurretEulerRotation , void , (Point3F rot) , "@brief Set Euler rotation of this turret's heading and pitch nodes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n\n</a>" "@param rot The rotation in degrees. The pitch is the X component and the " "heading is the Z component. The Y component is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ignored.\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onMountObject , void , (SceneObject *turret, SceneObject *obj, S32 node) , (turret, obj, node) , "@brief Informs the <a href="/coding/class/classturretshapedata/">TurretShapeData</a> object that <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> player is mounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" "@param turret The <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param obj The player that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mounting.\n</a>" "@param node The node the player is mounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onStickyCollision , void , (TurretShape *obj) , (obj) , "@brief Informs the TurretData object that it is now sticking <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "This callback is only called <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the TurretData::sticky property <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this Turret is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n</a>" "@param obj The Turret object that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">colliding.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" "@see TurretShape, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretData\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onUnmountObject , void , (SceneObject *turret, SceneObject *obj) , (turret, obj) , "@brief Informs the <a href="/coding/class/classturretshapedata/">TurretShapeData</a> object that <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> player is unmounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" "@param turret The <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param obj The player that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unmounting.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" )
ImplementEnumType(TurretShapeFireLinkType , "@brief How the weapons are linked <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> triggers <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShape.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n\n</a>" )
Detailed Description
Public Variables
EndImplementEnumType
U32 sTriggerMask
Public Functions
ConsoleDocClass(TurretShape , "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
ConsoleDocClass(TurretShapeData , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShape\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShapeData\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(TurretShape , doRespawn , bool , () , "@brief Does the turret respawn after it has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" "@returns True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">respawns.\n</a>" )
DefineEngineMethod(TurretShape , getAllowManualFire , bool , () , "@brief Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , getAllowManualRotation , bool , () , "@brief Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@return True <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , getState , const char * , () , "@brief Get the name of the turret's current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">state.\n\n</a>" "The state is one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n\n</a><ul>" "<li>Dead - The <a href="/coding/class/classturretshape/">TurretShape</a> is destroyed.</li>" "<li>Mounted - The <a href="/coding/class/classturretshape/">TurretShape</a> is mounted <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> an object such as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> vehicle.</li>" "<li>Ready - The <a href="/coding/class/classturretshape/">TurretShape</a> is free <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move. The usual state.</li></ul>\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return The current state; one of: \"Dead\" , \"Mounted\" , \"Ready\"\n" )
DefineEngineMethod(TurretShape , getTurretEulerRotation , Point3F , () , "@brief Get Euler rotation of this turret's heading and pitch <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n\n</a>" "@return the orientation of the turret's heading and pitch nodes in the " "form of rotations around the X, Y and Z axes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n</a>" )
DefineEngineMethod(TurretShape , setAllowManualFire , void , (bool allow) , "@brief Set <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> fire through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@param allow If true then the turret may be fired through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , setAllowManualRotation , void , (bool allow) , "@brief Set <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the turret is allowed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> rotate through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n\n</a>" "@param allow If true then the turret may be rotated through <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moves.\n</a>" )
DefineEngineMethod(TurretShape , setTurretEulerRotation , void , (Point3F rot) , "@brief Set Euler rotation of this turret's heading and pitch nodes in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">degrees.\n\n</a>" "@param rot The rotation in degrees. The pitch is the X component and the " "heading is the Z component. The Y component is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ignored.\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onMountObject , void , (SceneObject *turret, SceneObject *obj, S32 node) , (turret, obj, node) , "@brief Informs the <a href="/coding/class/classturretshapedata/">TurretShapeData</a> object that <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> player is mounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" "@param turret The <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param obj The player that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mounting.\n</a>" "@param node The node the player is mounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onStickyCollision , void , (TurretShape *obj) , (obj) , "@brief Informs the TurretData object that it is now sticking <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "This callback is only called <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the TurretData::sticky property <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this Turret is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n</a>" "@param obj The Turret object that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">colliding.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" "@see TurretShape, <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretData\n</a>" )
IMPLEMENT_CALLBACK(TurretShapeData , onUnmountObject , void , (SceneObject *turret, SceneObject *obj) , (turret, obj) , "@brief Informs the <a href="/coding/class/classturretshapedata/">TurretShapeData</a> object that <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> player is unmounting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">it.\n\n</a>" "@param turret The <a href="/coding/class/classturretshape/">TurretShape</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param obj The player that is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">unmounting.\n</a>" "@note Server side <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only.\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(TurretShapeData )
IMPLEMENT_CO_NETOBJECT_V1(TurretShape )
ImplementEnumType(TurretShapeFireLinkType , "@brief How the weapons are linked <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> triggers <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">TurretShape.\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 "T3D/turret/turretShape.h" 25 26#include "console/console.h" 27#include "console/consoleTypes.h" 28#include "console/engineAPI.h" 29#include "core/stream/bitStream.h" 30#include "math/mMath.h" 31#include "math/mathIO.h" 32#include "ts/tsShapeInstance.h" 33#include "T3D/fx/cameraFXMgr.h" 34#include "T3D/gameBase/gameConnection.h" 35#include "T3D/physics/physicsBody.h" 36 37//---------------------------------------------------------------------------- 38 39// Client prediction 40// Trigger objects that are not normally collided with. 41static U32 sTriggerMask = ItemObjectType | 42 TriggerObjectType | 43 CorpseObjectType; 44 45//---------------------------------------------------------------------------- 46 47ImplementEnumType( TurretShapeFireLinkType, 48 "@brief How the weapons are linked to triggers for this TurretShape.\n\n" 49 "@ingroup gameObjects\n\n") 50 { TurretShapeData::FireTogether, "FireTogether", "All weapons fire under trigger 0.\n" }, 51 { TurretShapeData::GroupedFire, "GroupedFire", "Weapon mounts 0,2 fire under trigger 0, mounts 1,3 fire under trigger 1.\n" }, 52 { TurretShapeData::IndividualFire, "IndividualFire", "Each weapon mount fires under its own trigger 0-3.\n" }, 53EndImplementEnumType; 54 55IMPLEMENT_CO_DATABLOCK_V1(TurretShapeData); 56 57ConsoleDocClass( TurretShapeData, 58 "@brief Defines properties for a TurretShape object.\n\n" 59 "@see TurretShape\n" 60 "@see TurretShapeData\n" 61 "@ingroup gameObjects\n" 62); 63 64IMPLEMENT_CALLBACK( TurretShapeData, onMountObject, void, ( SceneObject* turret, SceneObject* obj, S32 node ),( turret, obj, node ), 65 "@brief Informs the TurretShapeData object that a player is mounting it.\n\n" 66 "@param turret The TurretShape object.\n" 67 "@param obj The player that is mounting.\n" 68 "@param node The node the player is mounting to.\n" 69 "@note Server side only.\n" 70); 71 72IMPLEMENT_CALLBACK( TurretShapeData, onUnmountObject, void, ( SceneObject* turret, SceneObject* obj ),( turret, obj ), 73 "@brief Informs the TurretShapeData object that a player is unmounting it.\n\n" 74 "@param turret The TurretShape object.\n" 75 "@param obj The player that is unmounting.\n" 76 "@note Server side only.\n" 77); 78 79IMPLEMENT_CALLBACK( TurretShapeData, onStickyCollision, void, ( TurretShape* obj ),( obj ), 80 "@brief Informs the TurretData object that it is now sticking to another object.\n\n" 81 "This callback is only called if the TurretData::sticky property for this Turret is true.\n" 82 "@param obj The Turret object that is colliding.\n" 83 "@note Server side only.\n" 84 "@see TurretShape, TurretData\n" 85); 86 87TurretShapeData::TurretShapeData() 88{ 89 weaponLinkType = FireTogether; 90 91 shadowEnable = true; 92 93 zRotOnly = false; 94 95 startLoaded = true; 96 97 friction = 0; 98 elasticity = 0; 99 100 sticky = false; 101 gravityMod = 1.0; 102 maxVelocity = 25.0f; 103 104 density = 2; 105 drag = 0.5; 106 107 cameraOffset = 0; 108 109 maxHeading = 180.0f; 110 minPitch = 90.0f; 111 maxPitch = 90.0f; 112 113 headingRate = -1; 114 pitchRate = -1; 115 116 headingNode = -1; 117 pitchNode = -1; 118 U32 i = 0; 119 for (i=0; i<NumMirrorDirectionNodes; ++i) 120 { 121 pitchNodes[i] = -1; 122 headingNodes[i] = -1; 123 } 124 125 for (i=0; i<ShapeBase::MaxMountedImages; ++i) 126 { 127 weaponMountNode[i] = -1; 128 } 129 for (i = 0; i < NumRecoilSequences;i++) 130 recoilSequence[i] = -1; 131 pitchSequence = -1; 132 headingSequence = -1; 133} 134 135void TurretShapeData::initPersistFields() 136{ 137 addField("zRotOnly", TypeBool, Offset(zRotOnly, TurretShapeData), 138 "@brief Should the turret allow only z rotations.\n\n" 139 "True indicates that the turret may only be rotated on its z axis, just like the Item class. " 140 "This keeps the turret always upright regardless of the surface it lands on.\n"); 141 142 addField( "weaponLinkType", TYPEID< TurretShapeData::FireLinkType >(), Offset(weaponLinkType, TurretShapeData), 143 "@brief Set how the mounted weapons are linked and triggered.\n\n" 144 "<ul><li>FireTogether: All weapons fire under trigger 0.</li>" 145 "<li>GroupedFire: Weapon mounts 0,2 fire under trigger 0, mounts 1,3 fire under trigger 1.</li>" 146 "<li>IndividualFire: Each weapon mount fires under its own trigger 0-3.</li></ul>\n" 147 "@see TurretShapeFireLinkType"); 148 149 addField("startLoaded", TypeBool, Offset(startLoaded, TurretShapeData), 150 "@brief Does the turret's mounted weapon(s) start in a loaded state.\n\n" 151 "True indicates that all mounted weapons start in a loaded state.\n" 152 "@see ShapeBase::setImageLoaded()"); 153 154 addField("cameraOffset", TypeF32, Offset(cameraOffset, TurretShapeData), 155 "Vertical (Z axis) height of the camera above the turret." ); 156 157 addField("maxHeading", TypeF32, Offset(maxHeading, TurretShapeData), 158 "@brief Maximum number of degrees to rotate from center.\n\n" 159 "A value of 180 or more degrees indicates the turret may rotate completely around.\n"); 160 addField("minPitch", TypeF32, Offset(minPitch, TurretShapeData), 161 "@brief Minimum number of degrees to rotate down from straight ahead.\n\n"); 162 addField("maxPitch", TypeF32, Offset(maxPitch, TurretShapeData), 163 "@brief Maximum number of degrees to rotate up from straight ahead.\n\n"); 164 165 addField("headingRate", TypeF32, Offset(headingRate, TurretShapeData), 166 "@brief Degrees per second rotation.\n\n" 167 "A value of 0 means no rotation is allowed. A value less than 0 means the rotation is instantaneous.\n"); 168 addField("pitchRate", TypeF32, Offset(pitchRate, TurretShapeData), 169 "@brief Degrees per second rotation.\n\n" 170 "A value of 0 means no rotation is allowed. A value less than 0 means the rotation is instantaneous.\n"); 171 172 Parent::initPersistFields(); 173} 174 175void TurretShapeData::packData(BitStream* stream) 176{ 177 Parent::packData(stream); 178 179 stream->writeFlag(zRotOnly); 180 181 stream->writeInt(weaponLinkType,NumFireLinkTypeBits); 182 183 stream->write(cameraOffset); 184 185 stream->write(maxHeading); 186 stream->write(minPitch); 187 stream->write(maxPitch); 188 189 stream->write(headingRate); 190 stream->write(pitchRate); 191} 192 193void TurretShapeData::unpackData(BitStream* stream) 194{ 195 Parent::unpackData(stream); 196 197 zRotOnly = stream->readFlag(); 198 199 weaponLinkType = (FireLinkType)stream->readInt(NumFireLinkTypeBits); 200 201 stream->read(&cameraOffset); 202 203 stream->read(&maxHeading); 204 stream->read(&minPitch); 205 stream->read(&maxPitch); 206 207 stream->read(&headingRate); 208 stream->read(&pitchRate); 209} 210 211bool TurretShapeData::preload(bool server, String &errorStr) 212{ 213 if (!Parent::preload(server, errorStr)) 214 return false; 215 216 // We have mShape at this point. Resolve nodes. 217 headingNode = mShape->findNode("heading"); 218 pitchNode = mShape->findNode("pitch"); 219 220 // Find any mirror pitch nodes 221 for (U32 i = 0; i < NumMirrorDirectionNodes; ++i) 222 { 223 char name[32]; 224 dSprintf(name, 31, "pitch%d", i+1); 225 pitchNodes[i] = mShape->findNode(name); 226 227 dSprintf(name, 31, "heading%d", i+1); 228 headingNodes[i] = mShape->findNode(name); 229 } 230 231 // Resolve weapon mount point node indexes 232 for (U32 i = 0; i < ShapeBase::MaxMountedImages; i++) { 233 char fullName[256]; 234 dSprintf(fullName,sizeof(fullName),"weaponMount%d",i); 235 weaponMountNode[i] = mShape->findNode(fullName); 236 } 237 238 // Recoil animations 239 recoilSequence[0] = mShape->findSequence("light_recoil"); 240 recoilSequence[1] = mShape->findSequence("medium_recoil"); 241 recoilSequence[2] = mShape->findSequence("heavy_recoil"); 242 243 // Optional sequences used when the turret rotates 244 pitchSequence = mShape->findSequence("pitch"); 245 headingSequence = mShape->findSequence("heading"); 246 247 return true; 248} 249 250 251//---------------------------------------------------------------------------- 252 253IMPLEMENT_CO_NETOBJECT_V1(TurretShape); 254 255ConsoleDocClass( TurretShape, 256 "@ingroup gameObjects\n" 257); 258 259TurretShape::TurretShape() 260{ 261 mTypeMask |= VehicleObjectType | DynamicShapeObjectType; 262 mDataBlock = 0; 263 264 allowManualRotation = true; 265 allowManualFire = true; 266 267 mTurretDelta.rot = Point3F(0.0f, 0.0f, 0.0f); 268 mTurretDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f); 269 mTurretDelta.dt = 1; 270 271 mRot = mTurretDelta.rot; 272 273 mPitchAllowed = true; 274 mHeadingAllowed = true; 275 276 mPitchRate = -1; 277 mHeadingRate = -1; 278 279 mPitchUp = 0; 280 mPitchDown = 0; 281 mHeadingMax = mDegToRad(180.0f); 282 283 mRespawn = false; 284 285 mPitchThread = 0; 286 mHeadingThread = 0; 287 288 mSubclassTurretShapeHandlesScene = false; 289 290 // For the Item class 291 mSubclassItemHandlesScene = true; 292 mRecoilThread = NULL; 293 mImageStateThread = NULL; 294} 295 296TurretShape::~TurretShape() 297{ 298} 299 300//---------------------------------------------------------------------------- 301 302void TurretShape::initPersistFields() 303{ 304 addField("respawn", TypeBool, Offset(mRespawn, TurretShape), 305 "@brief Respawn the turret after it has been destroyed.\n\n" 306 "If true, the turret will respawn after it is destroyed.\n"); 307 308 Parent::initPersistFields(); 309} 310 311bool TurretShape::onAdd() 312{ 313 if( !Parent::onAdd() ) 314 return false; 315 316 // Add this object to the scene 317 if (!mSubclassTurretShapeHandlesScene) 318 { 319 addToScene(); 320 } 321 322 if (isServerObject() && !mSubclassTurretShapeHandlesScene) 323 { 324 scriptOnAdd(); 325 } 326 327 return true; 328} 329 330void TurretShape::onRemove() 331{ 332 Parent::onRemove(); 333 334 if (!mSubclassTurretShapeHandlesScene) 335 { 336 scriptOnRemove(); 337 338 // Remove this object from the scene 339 removeFromScene(); 340 } 341} 342 343bool TurretShape::onNewDataBlock(GameBaseData* dptr, bool reload) 344{ 345 mDataBlock = dynamic_cast<TurretShapeData*>(dptr); 346 if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) 347 return false; 348 349 // Mark these nodes for control by code only (will not animate in a sequence) 350 if (mDataBlock->headingNode != -1) 351 mShapeInstance->setNodeAnimationState(mDataBlock->headingNode, TSShapeInstance::MaskNodeHandsOff); 352 if (mDataBlock->pitchNode != -1) 353 mShapeInstance->setNodeAnimationState(mDataBlock->pitchNode, TSShapeInstance::MaskNodeHandsOff); 354 for (U32 i=0; i<TurretShapeData::NumMirrorDirectionNodes; ++i) 355 { 356 if (mDataBlock->pitchNodes[i] != -1) 357 { 358 mShapeInstance->setNodeAnimationState(mDataBlock->pitchNodes[i], TSShapeInstance::MaskNodeHandsOff); 359 } 360 361 if (mDataBlock->headingNodes[i] != -1) 362 { 363 mShapeInstance->setNodeAnimationState(mDataBlock->headingNodes[i], TSShapeInstance::MaskNodeHandsOff); 364 } 365 } 366 367 if (mIsZero(mDataBlock->pitchRate)) 368 { 369 mPitchAllowed = false; 370 } 371 else 372 { 373 mPitchAllowed = true; 374 if (mDataBlock->pitchRate > 0) 375 { 376 mPitchRate = mDegToRad(mDataBlock->pitchRate); 377 } 378 else 379 { 380 mPitchRate = -1; 381 } 382 } 383 384 if (mIsZero(mDataBlock->headingRate)) 385 { 386 mHeadingAllowed = false; 387 } 388 else 389 { 390 mHeadingAllowed = true; 391 if (mDataBlock->headingRate > 0) 392 { 393 mHeadingRate = mDegToRad(mDataBlock->headingRate); 394 } 395 else 396 { 397 mHeadingRate = -1; 398 } 399 } 400 401 mPitchUp = -mDegToRad(mDataBlock->maxPitch); 402 mPitchDown = mDegToRad(mDataBlock->minPitch); 403 mHeadingMax = mDegToRad(mDataBlock->maxHeading); 404 405 // Create Recoil thread if any recoil sequences are specified. 406 // Note that the server player does not play this animation. 407 mRecoilThread = 0; 408 if (isGhost()) 409 for (U32 s = 0; s < TurretShapeData::NumRecoilSequences; s++) 410 if (mDataBlock->recoilSequence[s] != -1) { 411 mRecoilThread = mShapeInstance->addThread(); 412 mShapeInstance->setSequence(mRecoilThread, mDataBlock->recoilSequence[s], 0); 413 mShapeInstance->setTimeScale(mRecoilThread, 0); 414 break; 415 } 416 417 // Reset the image state driven animation thread. This will be properly built 418 // in onImageStateAnimation() when needed. 419 mImageStateThread = 0; 420 421 // Optional rotation threads. These only play on the client. 422 mPitchThread = 0; 423 mHeadingThread = 0; 424 if (isGhost()) 425 { 426 if (mDataBlock->pitchSequence != -1) 427 { 428 mPitchThread = mShapeInstance->addThread(); 429 mShapeInstance->setSequence(mPitchThread, mDataBlock->pitchSequence, 0); 430 mShapeInstance->setTimeScale(mPitchThread, 0); 431 } 432 if (mDataBlock->headingSequence != -1) 433 { 434 mHeadingThread = mShapeInstance->addThread(); 435 mShapeInstance->setSequence(mHeadingThread, mDataBlock->headingSequence, 0); 436 mShapeInstance->setTimeScale(mHeadingThread, 0); 437 } 438 } 439 440 if (!mSubclassTurretShapeHandlesScene) 441 { 442 scriptOnNewDataBlock(); 443 } 444 445 return true; 446} 447 448//---------------------------------------------------------------------------- 449 450void TurretShape::updateAnimation(F32 dt) 451{ 452 if (mRecoilThread) 453 mShapeInstance->advanceTime(dt,mRecoilThread); 454 if (mImageStateThread) 455 mShapeInstance->advanceTime(dt,mImageStateThread); 456 457 // Update any pitch and heading threads 458 if (mPitchThread) 459 { 460 F32 d = mPitchDown - mPitchUp; 461 if (!mIsZero(d)) 462 { 463 F32 pos = (mRot.x - mPitchUp) / d; 464 mShapeInstance->setPos(mPitchThread, mClampF(pos, 0.0f, 1.0f)); 465 } 466 } 467 if (mHeadingThread) 468 { 469 F32 pos = 0.0f; 470 if (mHeadingMax < mDegToRad(180.0f)) 471 { 472 F32 d = mHeadingMax * 2.0f; 473 if (!mIsZero(d)) 474 { 475 pos = (mRot.z + mHeadingMax) / d; 476 } 477 } 478 else 479 { 480 pos = mRot.z / M_2PI; 481 if (pos < 0.0f) 482 { 483 // We don't want negative rotations to simply mirror the 484 // positive rotations but to animate into them as if -0.0 485 // is equivalent to 1.0. 486 pos = mFmod(pos, 1.0f) + 1.0f; 487 } 488 if (pos > 1.0f) 489 { 490 pos = mFmod(pos, 1.0f); 491 } 492 } 493 mShapeInstance->setPos(mHeadingThread, mClampF(pos, 0.0f, 1.0f)); 494 } 495} 496 497//---------------------------------------------------------------------------- 498 499void TurretShape::onImage(U32 imageSlot, bool unmount) 500{ 501 // Clear out any previous image state animation 502 if (mImageStateThread) 503 { 504 mShapeInstance->destroyThread(mImageStateThread); 505 mImageStateThread = 0; 506 } 507} 508 509void TurretShape::onImageRecoil( U32, ShapeBaseImageData::StateData::RecoilState state ) 510{ 511 if ( mRecoilThread ) 512 { 513 if ( state != ShapeBaseImageData::StateData::NoRecoil ) 514 { 515 S32 stateIndex = state - ShapeBaseImageData::StateData::LightRecoil; 516 if ( mDataBlock->recoilSequence[stateIndex] != -1 ) 517 { 518 mShapeInstance->setSequence( mRecoilThread, mDataBlock->recoilSequence[stateIndex], 0 ); 519 mShapeInstance->setTimeScale( mRecoilThread, 1 ); 520 } 521 } 522 } 523} 524 525void TurretShape::onImageStateAnimation(U32 imageSlot, const char* seqName, bool direction, bool scaleToState, F32 stateTimeOutValue) 526{ 527 if (isGhost()) 528 { 529 S32 seqIndex = mShapeInstance->getShape()->findSequence(seqName); 530 531 if (seqIndex != -1) 532 { 533 if (!mImageStateThread) 534 { 535 mImageStateThread = mShapeInstance->addThread(); 536 } 537 538 mShapeInstance->setSequence( mImageStateThread, seqIndex, 0 ); 539 540 F32 timeScale = (scaleToState && stateTimeOutValue) ? 541 mShapeInstance->getDuration(mImageStateThread) / stateTimeOutValue : 1.0f; 542 543 mShapeInstance->setTimeScale( mImageStateThread, direction ? timeScale : -timeScale ); 544 } 545 } 546} 547 548//---------------------------------------------------------------------------- 549 550const char* TurretShape::getStateName() 551{ 552 if (mDamageState != Enabled) 553 return "Dead"; 554 if (isMounted()) 555 return "Mounted"; 556 return "Ready"; 557} 558 559void TurretShape::updateDamageLevel() 560{ 561 if (!isGhost()) 562 setDamageState((mDamage >= mDataBlock->maxDamage)? Destroyed: Enabled); 563 if (mDamageThread) 564 mShapeInstance->setPos(mDamageThread, mDamage / mDataBlock->destroyedLevel); 565} 566 567//---------------------------------------------------------------------------- 568 569void TurretShape::processTick(const Move* move) 570{ 571 // Image Triggers 572 if (getAllowManualFire() && move && mDamageState == Enabled) 573 { 574 switch(mDataBlock->weaponLinkType) 575 { 576 case TurretShapeData::FireTogether: 577 { 578 setImageTriggerState(0,move->trigger[0]); 579 setImageTriggerState(1,move->trigger[0]); 580 setImageTriggerState(2,move->trigger[0]); 581 setImageTriggerState(3,move->trigger[0]); 582 583 setImageAltTriggerState(0,move->trigger[1]); 584 setImageAltTriggerState(1,move->trigger[1]); 585 setImageAltTriggerState(2,move->trigger[1]); 586 setImageAltTriggerState(3,move->trigger[1]); 587 588 break; 589 } 590 591 case TurretShapeData::GroupedFire: 592 { 593 setImageTriggerState(0,move->trigger[0]); 594 setImageTriggerState(1,move->trigger[1]); 595 setImageTriggerState(2,move->trigger[0]); 596 setImageTriggerState(3,move->trigger[1]); 597 598 break; 599 } 600 601 case TurretShapeData::IndividualFire: 602 { 603 setImageTriggerState(0,move->trigger[0]); 604 setImageTriggerState(1,move->trigger[1]); 605 setImageTriggerState(2,move->trigger[2]); 606 setImageTriggerState(3,move->trigger[3]); 607 608 break; 609 } 610 } 611 } 612 613 Parent::processTick(move); 614 615 // Change our type based on our rest state 616 if (mAtRest) 617 { 618 // At rest so we're static 619 mTypeMask &= ~<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084aae78d764ab9171d8c9d82b09cb376192">DynamicShapeObjectType</a>; 620 mTypeMask |= StaticObjectType | StaticShapeObjectType; 621 } 622 else 623 { 624 // Not at rest so we're dynamic 625 mTypeMask &= ~<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084a38f2a997e7e1d6c416cf1a761979a690">StaticObjectType</a>; 626 mTypeMask &= ~<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084ac4dfaa39d1def366730d03f409c0fd98">StaticShapeObjectType</a>; 627 mTypeMask |= DynamicShapeObjectType; 628 } 629 630 if (!isGhost()) 631 updateAnimation(TickSec); 632 633 updateMove(move); 634} 635 636void TurretShape::interpolateTick(F32 dt) 637{ 638 Parent::interpolateTick(dt); 639 640 if (isMounted()) { 641 MatrixF mat; 642 mMount.object->getRenderMountTransform( dt, mMount.node, mMount.xfm, &mat ); 643 ShapeBase::setRenderTransform(mat); 644 } 645 646 // Orientation 647 Point3F rot = mTurretDelta.rot + mTurretDelta.rotVec * dt; 648 649 // Make sure we don't interpolate past the limits 650 _applyLimits(rot); 651 652 _setRotation(rot); 653} 654 655void TurretShape::advanceTime(F32 dt) 656{ 657 // If there were any ShapeBase script threads that 658 // have played, then we need to update all code 659 // controlled nodes. This is done before the Parent 660 // call as script threads may play and be destroyed 661 // before our code is called. 662 bool updateNodes = false; 663 for (U32 i = 0; i < MaxScriptThreads; i++) 664 { 665 Thread& st = mScriptThread[i]; 666 if (st.thread) 667 { 668 updateNodes = true; 669 break; 670 } 671 } 672 673 Parent::advanceTime(dt); 674 675 updateAnimation(dt); 676 677 _setRotation(mRot); 678} 679 680void TurretShape::setTransform( const MatrixF& mat ) 681{ 682 if (mDataBlock && mDataBlock->zRotOnly) 683 { 684 // Allow Item::setTransform() to do the work 685 Parent::setTransform( mat ); 686 } 687 else 688 { 689 // Do the transform work here to avoid Item's restriction on rotation 690 ShapeBase::setTransform( mat ); 691 692 if ( !mStatic ) 693 { 694 mAtRest = false; 695 mAtRestCounter = 0; 696 } 697 698 if ( mPhysicsRep ) 699 mPhysicsRep->setTransform( getTransform() ); 700 701 setMaskBits( Item::RotationMask | Item::PositionMask | Item::NoWarpMask ); 702 } 703} 704 705void TurretShape::updateMove(const Move* move) 706{ 707 PROFILE_SCOPE( TurretShape_UpdateMove ); 708 709 if (!move) 710 return; 711 712 Point3F vec, pos; 713 714 // Update orientation 715 mTurretDelta.rotVec = mRot; 716 717 VectorF rotVec(0, 0, 0); 718 if (getAllowManualRotation()) 719 { 720 if (mPitchAllowed) 721 { 722 rotVec.x = move->pitch * 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script; 723 if (mPitchRate > 0) 724 { 725 rotVec.x *= mPitchRate * TickSec; 726 } 727 } 728 if (mHeadingAllowed) 729 { 730 rotVec.z = move->yaw * 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script 731 if (mHeadingRate > 0) 732 { 733 rotVec.z *= mHeadingRate * TickSec; 734 } 735 } 736 } 737 738 mRot.x += rotVec.x; 739 mRot.z += rotVec.z; 740 _applyLimits(mRot); 741 742 if (isServerObject()) 743 { 744 // As this ends up animating shape nodes, we have no sense of a transform and 745 // render transform. Therefore we treat this as the true transform and leave the 746 // client shape node changes to interpolateTick() as the render transform. Otherwise 747 // on the client we'll have this node change from processTick() and then backstepping 748 // and catching up to the true node change in interpolateTick(), which causes the 749 // turret to stutter. 750 _setRotation( mRot ); 751 } 752 else 753 { 754 // If on the client, calc delta for backstepping 755 mTurretDelta.rot = mRot; 756 mTurretDelta.rotVec = mTurretDelta.rotVec - mTurretDelta.rot; 757 } 758 759 setMaskBits(TurretUpdateMask); 760} 761 762bool TurretShape::getNodeTransform(S32 node, MatrixF& mat) 763{ 764 if (node == -1) 765 return false; 766 767 MatrixF nodeTransform = mShapeInstance->mNodeTransforms[node]; 768 const Point3F& scale = getScale(); 769 770 // The position of the node needs to be scaled. 771 Point3F position = nodeTransform.getPosition(); 772 position.convolve( scale ); 773 nodeTransform.setPosition( position ); 774 775 mat.mul(mObjToWorld, nodeTransform); 776 return true; 777} 778 779bool TurretShape::getWorldNodeTransform(S32 node, MatrixF& mat) 780{ 781 MatrixF nodeMat; 782 if (!getNodeTransform(node, nodeMat)) 783 return false; 784 785 nodeMat.affineInverse(); 786 mat = nodeMat; 787 return true; 788} 789 790void TurretShape::_setRotation(const Point3F& rot) 791{ 792 _updateNodes(rot); 793 794 mShapeInstance->animate(); 795 796 mRot = rot; 797} 798 799void TurretShape::_updateNodes(const Point3F& rot) 800{ 801 EulerF xRot(rot.x, 0.0f, 0.0f); 802 EulerF zRot(0.0f, 0.0f, rot.z); 803 804 // Set heading 805 S32 node = mDataBlock->headingNode; 806 if (node != -1) 807 { 808 MatrixF* mat = &mShapeInstance->mNodeTransforms[node]; 809 Point3F defaultPos = mShapeInstance->getShape()->defaultTranslations[node]; 810 Quat16 defaultRot = mShapeInstance->getShape()->defaultRotations[node]; 811 812 QuatF qrot(zRot); 813 qrot *= defaultRot.getQuatF(); 814 qrot.setMatrix( mat ); 815 mat->setColumn(3, defaultPos); 816 } 817 818 // Set pitch 819 node = mDataBlock->pitchNode; 820 if (node != -1) 821 { 822 MatrixF* mat = &mShapeInstance->mNodeTransforms[node]; 823 Point3F defaultPos = mShapeInstance->getShape()->defaultTranslations[node]; 824 Quat16 defaultRot = mShapeInstance->getShape()->defaultRotations[node]; 825 826 QuatF qrot(xRot); 827 qrot *= defaultRot.getQuatF(); 828 qrot.setMatrix( mat ); 829 mat->setColumn(3, defaultPos); 830 } 831 832 // Now the mirror direction nodes, if any 833 for (U32 i=0; i<TurretShapeData::NumMirrorDirectionNodes; ++i) 834 { 835 node = mDataBlock->pitchNodes[i]; 836 if (node != -1) 837 { 838 MatrixF* mat = &mShapeInstance->mNodeTransforms[node]; 839 Point3F defaultPos = mShapeInstance->getShape()->defaultTranslations[node]; 840 Quat16 defaultRot = mShapeInstance->getShape()->defaultRotations[node]; 841 842 QuatF qrot(xRot); 843 qrot *= defaultRot.getQuatF(); 844 qrot.setMatrix( mat ); 845 mat->setColumn(3, defaultPos); 846 } 847 848 node = mDataBlock->headingNodes[i]; 849 if (node != -1) 850 { 851 MatrixF* mat = &mShapeInstance->mNodeTransforms[node]; 852 Point3F defaultPos = mShapeInstance->getShape()->defaultTranslations[node]; 853 Quat16 defaultRot = mShapeInstance->getShape()->defaultRotations[node]; 854 855 QuatF qrot(zRot); 856 qrot *= defaultRot.getQuatF(); 857 qrot.setMatrix( mat ); 858 mat->setColumn(3, defaultPos); 859 } 860 } 861 862 mShapeInstance->setDirty(TSShapeInstance::TransformDirty); 863} 864 865void TurretShape::_applyLimits(Point3F& rot) 866{ 867 rot.x = mClampF(rot.x, mPitchUp, mPitchDown); 868 if (mHeadingMax < mDegToRad(180.0f)) 869 { 870 rot.z = mClampF(rot.z, -mHeadingMax, mHeadingMax); 871 } 872} 873 874bool TurretShape::_outsideLimits(Point3F& rot) 875{ 876 if (rot.x < mPitchUp || rot.x > mPitchDown) 877 return true; 878 879 if (mHeadingMax < mDegToRad(180.0f)) 880 { 881 if (rot.z < -mHeadingMax || rot.z > mHeadingMax) 882 return true; 883 } 884 885 return false; 886} 887 888//---------------------------------------------------------------------------- 889 890void TurretShape::mountObject( SceneObject *obj, S32 node, const MatrixF &xfm ) 891{ 892 Parent::mountObject(obj, node, xfm); 893 894 if (isClientObject()) 895 { 896 if (obj) 897 { 898 GameConnection* conn = obj->getControllingClient(); 899 if (conn) 900 { 901 // Allow the client to set up any action maps, HUD, etc. 902 Con::executef("turretMountCallback", Con::getIntArg(getId()), Con::getIntArg(obj->getId()), Con::getIntArg(true)); 903 } 904 } 905 } 906 else 907 { 908 mDataBlock->onMountObject_callback( this, obj, node ); 909 } 910} 911 912void TurretShape::unmountObject( SceneObject *obj ) 913{ 914 Parent::unmountObject(obj); 915 916 if (isClientObject()) 917 { 918 if (obj) 919 { 920 GameConnection* conn = obj->getControllingClient(); 921 if (conn) 922 { 923 // Allow the client to set up any action maps, HUD, etc. 924 Con::executef("turretMountCallback", Con::getIntArg(getId()), Con::getIntArg(obj->getId()), Con::getIntArg(false)); 925 } 926 } 927 } 928 else 929 { 930 mDataBlock->onUnmountObject_callback( this, obj ); 931 } 932} 933 934void TurretShape::onUnmount(SceneObject*,S32) 935{ 936 // Make sure the client get's the final server pos of this turret. 937 setMaskBits(PositionMask); 938} 939 940//---------------------------------------------------------------------------- 941 942void TurretShape::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot) 943{ 944 *min = mDataBlock->cameraMinDist; 945 *max = mDataBlock->cameraMaxDist; 946 947 off->set(0,0,mDataBlock->cameraOffset); 948 rot->identity(); 949} 950 951void TurretShape::getCameraTransform(F32* pos,MatrixF* mat) 952{ 953 // Returns camera to world space transform 954 // Handles first person / third person camera position 955 if (isServerObject() && mShapeInstance) 956 mShapeInstance->animateNodeSubtrees(true); 957 958 if (*pos == 0) { 959 getRenderEyeTransform(mat); 960 return; 961 } 962 963 // Get the shape's camera parameters. 964 F32 min,max; 965 MatrixF rot; 966 Point3F offset; 967 getCameraParameters(&min,&max,&offset,&rot); 968 969 // Start with the current eye position 970 MatrixF eye; 971 getRenderEyeTransform(&eye); 972 973 // Build a transform that points along the eye axis 974 // but where the Z axis is always up. 975 { 976 MatrixF cam(1); 977 VectorF x,y,z(0,0,1); 978 eye.getColumn(1, &y); 979 mCross(y, z, &x); 980 x.normalize(); 981 mCross(x, y, &z); 982 z.normalize(); 983 cam.setColumn(0,x); 984 cam.setColumn(1,y); 985 cam.setColumn(2,z); 986 mat->mul(cam,rot); 987 } 988 989 // Camera is positioned straight back along the eye's -Y axis. 990 // A ray is cast to make sure the camera doesn't go through 991 // anything solid. 992 VectorF vp,vec; 993 vp.x = vp.z = 0; 994 vp.y = -(max - min) * *pos; 995 eye.mulV(vp,&vec); 996 997 // Use the camera node as the starting position if it exists. 998 Point3F osp,sp; 999 if (mDataBlock->cameraNode != -1) 1000 { 1001 mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp); 1002 getRenderTransform().mulP(osp,&sp); 1003 } 1004 else 1005 eye.getColumn(3,&sp); 1006 1007 // Make sure we don't hit ourself... 1008 disableCollision(); 1009 if (isMounted()) 1010 getObjectMount()->disableCollision(); 1011 1012 // Cast the ray into the container database to see if we're going 1013 // to hit anything. 1014 RayInfo collision; 1015 Point3F ep = sp + vec + offset; 1016 if (mContainer->castRay(sp, ep, 1017 ~(WaterObjectType | GameBaseObjectType | DefaultObjectType | sTriggerMask), 1018 &collision) == true) { 1019 1020 // Shift the collision point back a little to try and 1021 // avoid clipping against the front camera plane. 1022 F32 t = collision.t - (-mDot(vec, collision.normal) / vec.len()) * 0.1; 1023 if (t > 0.0f) 1024 ep = sp + offset + (vec * t); 1025 else 1026 eye.getColumn(3,&ep); 1027 } 1028 mat->setColumn(3,ep); 1029 1030 // Re-enable our collision. 1031 if (isMounted()) 1032 getObjectMount()->enableCollision(); 1033 enableCollision(); 1034 1035 // Apply Camera FX. 1036 mat->mul( gCamFXMgr.getTrans() ); 1037} 1038 1039//---------------------------------------------------------------------------- 1040 1041void TurretShape::writePacketData(GameConnection *connection, BitStream *stream) 1042{ 1043 // Update client regardless of status flags. 1044 Parent::writePacketData(connection, stream); 1045 1046 stream->writeSignedFloat(mRot.x / M_2PI_F, 7); 1047 stream->writeSignedFloat(mRot.z / M_2PI_F, 7); 1048} 1049 1050void TurretShape::readPacketData(GameConnection *connection, BitStream *stream) 1051{ 1052 Parent::readPacketData(connection, stream); 1053 1054 Point3F rot(0.0f, 0.0f, 0.0f); 1055 rot.x = stream->readSignedFloat(7) * M_2PI_F; 1056 rot.z = stream->readSignedFloat(7) * M_2PI_F; 1057 _setRotation(rot); 1058 1059 mTurretDelta.rot = rot; 1060 mTurretDelta.rotVec.set(0.0f, 0.0f, 0.0f); 1061} 1062 1063U32 TurretShape::packUpdate(NetConnection *connection, U32 mask, BitStream *stream) 1064{ 1065 // Handle rotation ourselves (so it is not locked to the Z axis like for Items) 1066 U32 retMask = Parent::packUpdate( connection, mask & (~<a href="/coding/class/classitem/#classitem_1aaacac713d02fa2d54fcca2662866de3fa5f0360bea9b5df7a11abb6ab328e4a92">Item::RotationMask</a>), stream ); 1067 1068 if (stream->writeFlag(mask & InitialUpdateMask)) { 1069 stream->writeFlag(mRespawn); 1070 } 1071 1072 if ( stream->writeFlag( mask & Item::RotationMask ) ) 1073 { 1074 QuatF rot( mObjToWorld ); 1075 mathWrite( *stream, rot ); 1076 } 1077 1078 // The rest of the data is part of the control object packet update. 1079 // If we're controlled by this client, we don't need to send it. 1080 if(stream->writeFlag((NetConnection*)getControllingClient() == connection && !(mask & InitialUpdateMask))) 1081 return 0; 1082 1083 if (stream->writeFlag(mask & TurretUpdateMask)) 1084 { 1085 stream->writeSignedFloat(mRot.x / M_2PI_F, 7); 1086 stream->writeSignedFloat(mRot.z / M_2PI_F, 7); 1087 stream->write(allowManualRotation); 1088 stream->write(allowManualFire); 1089 } 1090 1091 return retMask; 1092} 1093 1094void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream) 1095{ 1096 Parent::unpackUpdate(connection,stream); 1097 1098 // InitialUpdateMask 1099 if (stream->readFlag()) { 1100 mRespawn = stream->readFlag(); 1101 } 1102 1103 // Item::RotationMask 1104 if ( stream->readFlag() ) 1105 { 1106 QuatF rot; 1107 mathRead( *stream, &rot ); 1108 1109 Point3F pos = mObjToWorld.getPosition(); 1110 rot.setMatrix( &mObjToWorld ); 1111 mObjToWorld.setPosition( pos ); 1112 } 1113 1114 // controlled by the client? 1115 if(stream->readFlag()) 1116 return; 1117 1118 // TurretUpdateMask 1119 if (stream->readFlag()) 1120 { 1121 Point3F rot(0.0f, 0.0f, 0.0f); 1122 rot.x = stream->readSignedFloat(7) * M_2PI_F; 1123 rot.z = stream->readSignedFloat(7) * M_2PI_F; 1124 _setRotation(rot); 1125 1126 // New delta for client side interpolation 1127 mTurretDelta.rot = rot; 1128 mTurretDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f); 1129 1130 stream->read(&allowManualRotation); 1131 stream->read(&allowManualFire); 1132 } 1133} 1134 1135//---------------------------------------------------------------------------- 1136 1137void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat ) 1138{ 1139 // Returns mount point to world space transform 1140 if ( index >= 0 && index < ShapeBase::MaxMountedImages) { 1141 S32 ni = mDataBlock->weaponMountNode[index]; 1142 if (ni != -1) { 1143 MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; 1144 mountTransform.mul( xfm ); 1145 const Point3F& scale = getScale(); 1146 1147 // The position of the mount point needs to be scaled. 1148 Point3F position = mountTransform.getPosition(); 1149 position.convolve( scale ); 1150 mountTransform.setPosition( position ); 1151 1152 // Also we would like the object to be scaled to the model. 1153 outMat->mul(mObjToWorld, mountTransform); 1154 return; 1155 } 1156 } 1157 1158 // Then let SceneObject handle it. 1159 GrandParent::getMountTransform( index, xfm, outMat ); 1160} 1161 1162void TurretShape::getRenderWeaponMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat ) 1163{ 1164 // Returns mount point to world space transform 1165 if ( mountPoint >= 0 && mountPoint < ShapeBase::MaxMountedImages) { 1166 S32 ni = mDataBlock->weaponMountNode[mountPoint]; 1167 if (ni != -1) { 1168 MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; 1169 mountTransform.mul( xfm ); 1170 const Point3F& scale = getScale(); 1171 1172 // The position of the mount point needs to be scaled. 1173 Point3F position = mountTransform.getPosition(); 1174 position.convolve( scale ); 1175 mountTransform.setPosition( position ); 1176 1177 // Also we would like the object to be scaled to the model. 1178 mountTransform.scale( scale ); 1179 outMat->mul(getRenderTransform(), mountTransform); 1180 return; 1181 } 1182 } 1183 1184 // Then let SceneObject handle it. 1185 GrandParent::getRenderMountTransform( delta, mountPoint, xfm, outMat ); 1186} 1187 1188void TurretShape::getImageTransform(U32 imageSlot,MatrixF* mat) 1189{ 1190 // Image transform in world space 1191 MountedImage& image = mMountedImageList[imageSlot]; 1192 if (image.dataBlock) { 1193 ShapeBaseImageData& data = *image.dataBlock; 1194 1195 MatrixF nmat; 1196 if (data.useEyeOffset && isFirstPerson()) { 1197 getEyeTransform(&nmat); 1198 mat->mul(nmat,data.eyeOffset); 1199 } 1200 else { 1201 getWeaponMountTransform( imageSlot, MatrixF::Identity, &nmat ); 1202 mat->mul(nmat,data.mountTransform[getImageShapeIndex(image)]); 1203 } 1204 } 1205 else 1206 *mat = mObjToWorld; 1207} 1208 1209void TurretShape::getRenderImageTransform( U32 imageSlot, MatrixF* mat, bool noEyeOffset ) 1210{ 1211 // Image transform in world space 1212 MountedImage& image = mMountedImageList[imageSlot]; 1213 if (image.dataBlock) 1214 { 1215 ShapeBaseImageData& data = *image.dataBlock; 1216 1217 MatrixF nmat; 1218 if ( !noEyeOffset && data.useEyeOffset && isFirstPerson() ) 1219 { 1220 getRenderEyeTransform(&nmat); 1221 mat->mul(nmat,data.eyeOffset); 1222 } 1223 else 1224 { 1225 getRenderWeaponMountTransform( 0.0f, imageSlot, MatrixF::Identity, &nmat ); 1226 mat->mul(nmat,data.mountTransform[getImageShapeIndex(image)]); 1227 } 1228 } 1229 else 1230 *mat = getRenderTransform(); 1231} 1232 1233void TurretShape::getImageTransform(U32 imageSlot,S32 node,MatrixF* mat) 1234{ 1235 // Same as ShapeBase::getImageTransform() other than getRenderWeaponMountTransform() below 1236 1237 // Image transform in world space 1238 MountedImage& image = mMountedImageList[imageSlot]; 1239 if (image.dataBlock) 1240 { 1241 if (node != -1) 1242 { 1243 ShapeBaseImageData& data = *image.dataBlock; 1244 U32 shapeIndex = getImageShapeIndex(image); 1245 1246 MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node]; 1247 MatrixF mmat; 1248 1249 if (data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1) 1250 { 1251 // We need to animate, even on the server, to make sure the nodes are in the correct location. 1252 image.shapeInstance[shapeIndex]->animate(); 1253 1254 MatrixF emat; 1255 getEyeBaseTransform(&emat, mDataBlock->mountedImagesBank); 1256 1257 MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]]; 1258 mountTransform.affineInverse(); 1259 1260 mmat.mul(emat, mountTransform); 1261 } 1262 else if (data.useEyeOffset && isFirstPerson()) 1263 { 1264 MatrixF emat; 1265 getEyeTransform(&emat); 1266 mmat.mul(emat,data.eyeOffset); 1267 } 1268 else 1269 { 1270 MatrixF emat; 1271 getWeaponMountTransform( imageSlot, MatrixF::Identity, &emat ); 1272 mmat.mul(emat,data.mountTransform[shapeIndex]); 1273 } 1274 1275 mat->mul(mmat, nmat); 1276 } 1277 else 1278 getImageTransform(imageSlot,mat); 1279 } 1280 else 1281 *mat = mObjToWorld; 1282} 1283 1284void TurretShape::getRenderImageTransform(U32 imageSlot,S32 node,MatrixF* mat) 1285{ 1286 // Same as ShapeBase::getRenderImageTransform() other than getRenderWeaponMountTransform() below 1287 1288 // Image transform in world space 1289 MountedImage& image = mMountedImageList[imageSlot]; 1290 if (image.dataBlock) 1291 { 1292 if (node != -1) 1293 { 1294 ShapeBaseImageData& data = *image.dataBlock; 1295 U32 shapeIndex = getImageShapeIndex(image); 1296 1297 MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node]; 1298 MatrixF mmat; 1299 1300 if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 ) 1301 { 1302 MatrixF emat; 1303 getRenderEyeBaseTransform(&emat, mDataBlock->mountedImagesBank); 1304 1305 MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]]; 1306 mountTransform.affineInverse(); 1307 1308 mmat.mul(emat, mountTransform); 1309 } 1310 else if ( data.useEyeOffset && isFirstPerson() ) 1311 { 1312 MatrixF emat; 1313 getRenderEyeTransform(&emat); 1314 mmat.mul(emat,data.eyeOffset); 1315 } 1316 else 1317 { 1318 MatrixF emat; 1319 getRenderWeaponMountTransform( 0.0f, imageSlot, MatrixF::Identity, &emat ); 1320 mmat.mul(emat,data.mountTransform[shapeIndex]); 1321 } 1322 1323 mat->mul(mmat, nmat); 1324 } 1325 else 1326 getRenderImageTransform(imageSlot,mat); 1327 } 1328 else 1329 *mat = getRenderTransform(); 1330} 1331 1332//---------------------------------------------------------------------------- 1333 1334void TurretShape::prepRenderImage( SceneRenderState *state ) 1335{ 1336 // Skip the Item class rendering 1337 _prepRenderImage( state, true, true ); 1338} 1339 1340void TurretShape::prepBatchRender( SceneRenderState *state, S32 mountedImageIndex ) 1341{ 1342 Parent::prepBatchRender( state, mountedImageIndex ); 1343 1344 if ( !gShowBoundingBox ) 1345 return; 1346 1347 //if ( mountedImageIndex != -1 ) 1348 //{ 1349 // ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1350 // ri->renderDelegate.bind( this, &Vehicle::_renderMuzzleVector ); 1351 // ri->objectIndex = mountedImageIndex; 1352 // ri->type = RenderPassManager::RIT_Editor; 1353 // state->getRenderPass()->addInst( ri ); 1354 // return; 1355 //} 1356 1357 //ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1358 //ri->renderDelegate.bind( this, &Vehicle::_renderMassAndContacts ); 1359 //ri->type = RenderPassManager::RIT_Editor; 1360 //state->getRenderPass()->addInst( ri ); 1361} 1362 1363//---------------------------------------------------------------------------- 1364 1365DefineEngineMethod( TurretShape, getAllowManualRotation, bool, (),, 1366 "@brief Get if the turret is allowed to rotate through moves.\n\n" 1367 "@return True if the turret is allowed to rotate through moves.\n" ) 1368{ 1369 return object->getAllowManualRotation(); 1370} 1371 1372DefineEngineMethod( TurretShape, setAllowManualRotation, void, (bool allow),, 1373 "@brief Set if the turret is allowed to rotate through moves.\n\n" 1374 "@param allow If true then the turret may be rotated through moves.\n") 1375{ 1376 return object->setAllowManualRotation(allow); 1377} 1378 1379DefineEngineMethod( TurretShape, getAllowManualFire, bool, (),, 1380 "@brief Get if the turret is allowed to fire through moves.\n\n" 1381 "@return True if the turret is allowed to fire through moves.\n" ) 1382{ 1383 return object->getAllowManualFire(); 1384} 1385 1386DefineEngineMethod( TurretShape, setAllowManualFire, void, (bool allow),, 1387 "@brief Set if the turret is allowed to fire through moves.\n\n" 1388 "@param allow If true then the turret may be fired through moves.\n") 1389{ 1390 return object->setAllowManualFire(allow); 1391} 1392 1393DefineEngineMethod( TurretShape, getState, const char*, (),, 1394 "@brief Get the name of the turret's current state.\n\n" 1395 1396 "The state is one of the following:\n\n<ul>" 1397 "<li>Dead - The TurretShape is destroyed.</li>" 1398 "<li>Mounted - The TurretShape is mounted to an object such as a vehicle.</li>" 1399 "<li>Ready - The TurretShape is free to move. The usual state.</li></ul>\n" 1400 1401 "@return The current state; one of: \"Dead\", \"Mounted\", \"Ready\"\n" ) 1402{ 1403 return object->getStateName(); 1404} 1405 1406DefineEngineMethod( TurretShape, getTurretEulerRotation, Point3F, (),, 1407 "@brief Get Euler rotation of this turret's heading and pitch nodes.\n\n" 1408 "@return the orientation of the turret's heading and pitch nodes in the " 1409 "form of rotations around the X, Y and Z axes in degrees.\n" ) 1410{ 1411 Point3F euler = object->getTurretRotation(); 1412 1413 // Convert to degrees. 1414 euler.x = mRadToDeg( euler.x ); 1415 euler.y = mRadToDeg( euler.y ); 1416 euler.z = mRadToDeg( euler.z ); 1417 1418 return euler; 1419} 1420 1421DefineEngineMethod( TurretShape, setTurretEulerRotation, void, ( Point3F rot ),, 1422 "@brief Set Euler rotation of this turret's heading and pitch nodes in degrees.\n\n" 1423 "@param rot The rotation in degrees. The pitch is the X component and the " 1424 "heading is the Z component. The Y component is ignored.\n") 1425{ 1426 object->setTurretRotation( rot ); 1427} 1428 1429DefineEngineMethod( TurretShape, doRespawn, bool, (),, 1430 "@brief Does the turret respawn after it has been destroyed.\n\n" 1431 "@returns True if the turret respawns.\n") 1432{ 1433 return object->doRespawn(); 1434} 1435