proximityMine.cpp
Engine/source/T3D/proximityMine.cpp
Public Variables
Public Functions
ConsoleDocClass(ProximityMine , "@brief A simple proximity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mine.\n\n</a>" "Proximity mines can be deployed using the world editor or thrown by an " "in-game object. Once armed, any <a href="/coding/class/classplayer/">Player</a> or <a href="/coding/class/classvehicle/">Vehicle</a> object that moves within " "the mine 's trigger area will cause it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" " Internally, the <a href="/coding/class/classproximitymine/">ProximityMine</a> object transitions through the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">states:\n</a>" "< ol >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Thrown</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has been thrown, but has not yet attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> surface</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Deployed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> surface but is not yet armed. Start " "playing the #armingSound and< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> >armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> > sequence.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine is armed and will trigger <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classvehicle/">Vehicle</a> or <a href="/coding/class/classplayer/">Player</a> object moves " "within the trigger area.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Triggered</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has been triggered and will explode soon. Invoke the " "onTriggered callback, and start playing the #triggerSound and< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> >triggered</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> > " "sequence.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Exploded</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has exploded and will be deleted on the server shortly. " "Invoke the onExplode callback on the server and generate the explosion effects " "on the client.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "</ol >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @note Proximity mines with the #static field set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true will start in the " "< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> > state. Use this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> mines placed with the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor.\n\n</a>" "The shape used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the mine may optionally define the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sequences:\n</a>" "< dl >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< dt >armed</dt >< dd >Sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the mine is deployed, but before " "it becomes active and triggerable(#armingDelay should be set appropriately).</dd >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< dt >triggered</dt >< dd >Sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the mine is triggered)
ConsoleDocClass(ProximityMineData , "@brief Stores common 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/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(ProximityMine , explode , void , () , "@brief Manually cause the mine <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" )
IMPLEMENT_CALLBACK(ProximityMineData , onExplode , void , (ProximityMine *obj, Point3F pos) , (obj, pos) , "Callback invoked when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classproximitymine/">ProximityMine</a> is about <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" "@param obj The <a href="/coding/class/classproximitymine/">ProximityMine</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param pos The position of the mine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion\n</a>" "@note This callback is only invoked on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" )
IMPLEMENT_CALLBACK(ProximityMineData , onTriggered , void , (ProximityMine *obj, SceneObject *target) , (obj, target) , "Callback invoked when an object triggers the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine.\n\n</a>" "@param obj The <a href="/coding/class/classproximitymine/">ProximityMine</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param target The object that triggered the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mine\n</a>" "@note This callback is only invoked on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" )
Detailed Description
Public Variables
S32 gAutoDeleteTicks
const U32 sTriggerCollisionMask
Public Functions
ConsoleDocClass(ProximityMine , "@brief A simple proximity <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mine.\n\n</a>" "Proximity mines can be deployed using the world editor or thrown by an " "in-game object. Once armed, any <a href="/coding/class/classplayer/">Player</a> or <a href="/coding/class/classvehicle/">Vehicle</a> object that moves within " "the mine 's trigger area will cause it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" " Internally, the <a href="/coding/class/classproximitymine/">ProximityMine</a> object transitions through the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">states:\n</a>" "< ol >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Thrown</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has been thrown, but has not yet attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> surface</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Deployed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> surface but is not yet armed. Start " "playing the #armingSound and< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> >armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> > sequence.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine is armed and will trigger <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classvehicle/">Vehicle</a> or <a href="/coding/class/classplayer/">Player</a> object moves " "within the trigger area.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Triggered</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has been triggered and will explode soon. Invoke the " "onTriggered callback, and start playing the #triggerSound and< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> >triggered</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1acb559820d9ca11295b4500f179ef6392">i</a> > " "sequence.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< li >< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Exploded</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >:Mine has exploded and will be deleted on the server shortly. " "Invoke the onExplode callback on the server and generate the explosion effects " "on the client.</li >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "</ol >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" " @note Proximity mines with the #static field set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true will start in the " "< <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> >Armed</<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a> > state. Use this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> mines placed with the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Editor.\n\n</a>" "The shape used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the mine may optionally define the following <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sequences:\n</a>" "< dl >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< dt >armed</dt >< dd >Sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the mine is deployed, but before " "it becomes active and triggerable(#armingDelay should be set appropriately).</dd >\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "< dt >triggered</dt >< dd >Sequence <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> play when the mine is triggered)
ConsoleDocClass(ProximityMineData , "@brief Stores common 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/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">gameObjects\n</a>" )
DefineEngineMethod(ProximityMine , explode , void , () , "@brief Manually cause the mine <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" )
IMPLEMENT_CALLBACK(ProximityMineData , onExplode , void , (ProximityMine *obj, Point3F pos) , (obj, pos) , "Callback invoked when <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classproximitymine/">ProximityMine</a> is about <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explode.\n\n</a>" "@param obj The <a href="/coding/class/classproximitymine/">ProximityMine</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param pos The position of the mine <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">explosion\n</a>" "@note This callback is only invoked on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" )
IMPLEMENT_CALLBACK(ProximityMineData , onTriggered , void , (ProximityMine *obj, SceneObject *target) , (obj, target) , "Callback invoked when an object triggers the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine.\n\n</a>" "@param obj The <a href="/coding/class/classproximitymine/">ProximityMine</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n</a>" "@param target The object that triggered the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">mine\n</a>" "@note This callback is only invoked on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ProximityMine\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(ProximityMineData )
IMPLEMENT_CO_NETOBJECT_V1(ProximityMine )
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 "core/stream/bitStream.h" 27#include "console/console.h" 28#include "console/consoleTypes.h" 29#include "console/engineAPI.h" 30#include "sim/netConnection.h" 31#include "math/mMath.h" 32#include "math/mathIO.h" 33#include "math/mathUtils.h" 34#include "gfx/gfxTransformSaver.h" 35#include "gfx/gfxDrawUtil.h" 36#include "sfx/sfxTrack.h" 37#include "sfx/sfxTypes.h" 38#include "sfx/sfxSystem.h" 39#include "ts/tsShapeInstance.h" 40#include "T3D/fx/explosion.h" 41#include "T3D/proximityMine.h" 42#include "T3D/physics/physicsBody.h" 43 44const U32 sTriggerCollisionMask = ( VehicleObjectType | PlayerObjectType ); 45 46static S32 gAutoDeleteTicks = 16; // Provides about half a second for all clients to be updated 47 // before a mine is deleted on the server. 48 49//---------------------------------------------------------------------------- 50 51IMPLEMENT_CO_DATABLOCK_V1( ProximityMineData ); 52 53ConsoleDocClass( ProximityMineData, 54 "@brief Stores common properties for a ProximityMine.\n\n" 55 "@see ProximityMine\n" 56 "@ingroup gameObjects\n" 57); 58 59IMPLEMENT_CALLBACK( ProximityMineData, onTriggered, void, ( ProximityMine* obj, SceneObject *target ),( obj, target ), 60 "Callback invoked when an object triggers the ProximityMine.\n\n" 61 "@param obj The ProximityMine object\n" 62 "@param target The object that triggered the mine\n" 63 "@note This callback is only invoked on the server.\n" 64 "@see ProximityMine\n" 65); 66 67IMPLEMENT_CALLBACK( ProximityMineData, onExplode, void, ( ProximityMine* obj, Point3F pos ),( obj, pos ), 68 "Callback invoked when a ProximityMine is about to explode.\n\n" 69 "@param obj The ProximityMine object\n" 70 "@param pos The position of the mine explosion\n" 71 "@note This callback is only invoked on the server.\n" 72 "@see ProximityMine\n" 73); 74 75ProximityMineData::ProximityMineData() 76 : armingDelay( 0 ), 77 armingSequence( -1 ), 78 armingSound( NULL ), 79 triggerRadius( 5.0f ), 80 triggerSpeed( 1.0f ), 81 autoTriggerDelay( 0 ), 82 triggerOnOwner( false ), 83 triggerDelay( 0 ), 84 triggerSequence( -1 ), 85 triggerSound( NULL ), 86 explosionOffset( 0.05f ) 87{ 88} 89 90void ProximityMineData::initPersistFields() 91{ 92 addGroup( "Arming" ); 93 addField( "armingDelay", TypeF32, Offset(armingDelay, ProximityMineData), 94 "Delay (in seconds) from when the mine is placed to when it becomes active." ); 95 addField( "armingSound", TypeSFXTrackName, Offset(armingSound, ProximityMineData), 96 "Sound to play when the mine is armed (starts at the same time as " 97 "the <i>armed</i> sequence if defined)." ); 98 endGroup( "Arming" ); 99 100 addGroup( "Triggering" ); 101 addField( "autoTriggerDelay", TypeF32, Offset(autoTriggerDelay, ProximityMineData), 102 "@brief Delay (in seconds) from arming until the mine automatically " 103 "triggers and explodes, even if no object has entered the trigger area.\n\n" 104 "Set to 0 to disable." ); 105 addField( "triggerOnOwner", TypeBool, Offset(triggerOnOwner, ProximityMineData), 106 "@brief Controls whether the mine can be triggered by the object that owns it.\n\n" 107 "For example, a player could deploy mines that are only dangerous to other " 108 "players and not himself." ); 109 addField( "triggerRadius", TypeF32, Offset(triggerRadius, ProximityMineData), 110 "Distance at which an activated mine will detect other objects and explode." ); 111 addField( "triggerSpeed", TypeF32, Offset(triggerSpeed, ProximityMineData), 112 "Speed above which moving objects within the trigger radius will trigger the mine" ); 113 addField( "triggerDelay", TypeF32, Offset(triggerDelay, ProximityMineData), 114 "Delay (in seconds) from when the mine is triggered until it explodes." ); 115 addField( "triggerSound", TypeSFXTrackName, Offset(triggerSound, ProximityMineData), 116 "Sound to play when the mine is triggered (starts at the same time as " 117 "the <i>triggered</i> sequence if defined)." ); 118 endGroup( "Triggering" ); 119 120 addGroup( "Explosion" ); 121 addField( "explosionOffset", TypeF32, Offset(explosionOffset, ProximityMineData), 122 "@brief Offset from the mine's origin where the explosion emanates from." 123 "Sometimes a thrown mine may be slightly sunk into the ground. This can be just " 124 "enough to cause the explosion to occur under the ground, especially on flat " 125 "ground, which can end up blocking the explosion. This offset along the mine's " 126 "'up' normal allows you to raise the explosion origin to a better height."); 127 endGroup( "Explosion" ); 128 129 Parent::initPersistFields(); 130} 131 132bool ProximityMineData::preload( bool server, String& errorStr ) 133{ 134 if ( Parent::preload( server, errorStr ) == false ) 135 return false; 136 137 if ( !server ) 138 { 139 // Resolve sounds 140 String sfxErrorStr; 141 if( !sfxResolve( &armingSound, sfxErrorStr ) ) 142 Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() ); 143 if( !sfxResolve( &triggerSound, sfxErrorStr ) ) 144 Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() ); 145 } 146 147 if ( mShape ) 148 { 149 // Lookup animation sequences 150 armingSequence = mShape->findSequence( "armed" ); 151 triggerSequence = mShape->findSequence( "triggered" ); 152 } 153 154 return true; 155} 156 157void ProximityMineData::packData( BitStream* stream ) 158{ 159 Parent::packData( stream ); 160 161 stream->write( armingDelay ); 162 sfxWrite( stream, armingSound ); 163 164 stream->write( autoTriggerDelay ); 165 stream->writeFlag( triggerOnOwner ); 166 stream->write( triggerRadius ); 167 stream->write( triggerSpeed ); 168 stream->write( triggerDelay ); 169 sfxWrite( stream, triggerSound ); 170} 171 172void ProximityMineData::unpackData( BitStream* stream ) 173{ 174 Parent::unpackData(stream); 175 176 stream->read( &armingDelay ); 177 sfxRead( stream, &armingSound ); 178 179 stream->read( &autoTriggerDelay ); 180 triggerOnOwner = stream->readFlag(); 181 stream->read( &triggerRadius ); 182 stream->read( &triggerSpeed ); 183 stream->read( &triggerDelay ); 184 sfxRead( stream, &triggerSound ); 185} 186 187//---------------------------------------------------------------------------- 188 189IMPLEMENT_CO_NETOBJECT_V1( ProximityMine ); 190 191ConsoleDocClass( ProximityMine, 192 "@brief A simple proximity mine.\n\n" 193 194 "Proximity mines can be deployed using the world editor or thrown by an " 195 "in-game object. Once armed, any Player or Vehicle object that moves within " 196 "the mine's trigger area will cause it to explode.\n\n" 197 198 "Internally, the ProximityMine object transitions through the following states:\n" 199 "<ol>\n" 200 " <li><b>Thrown</b>: Mine has been thrown, but has not yet attached to a surface</li>\n" 201 " <li><b>Deployed</b>: Mine has attached to a surface but is not yet armed. Start " 202 "playing the #armingSound and <i>armed</i> sequence.</li>\n" 203 " <li><b>Armed</b>: Mine is armed and will trigger if a Vehicle or Player object moves " 204 "within the trigger area.</li>\n" 205 " <li><b>Triggered</b>: Mine has been triggered and will explode soon. Invoke the " 206 "onTriggered callback, and start playing the #triggerSound and <i>triggered</i> " 207 "sequence.</li>\n" 208 " <li><b>Exploded</b>: Mine has exploded and will be deleted on the server shortly. " 209 "Invoke the onExplode callback on the server and generate the explosion effects " 210 "on the client.</li>\n" 211 "</ol>\n\n" 212 213 "@note Proximity mines with the #static field set to true will start in the " 214 "<b>Armed</b> state. Use this for mines placed with the World Editor.\n\n" 215 216 "The shape used for the mine may optionally define the following sequences:\n" 217 "<dl>\n" 218 " <dt>armed</dt><dd>Sequence to play when the mine is deployed, but before " 219 "it becomes active and triggerable (#armingDelay should be set appropriately).</dd>\n" 220 " <dt>triggered</dt><dd>Sequence to play when the mine is triggered, just " 221 "before it explodes (#triggerDelay should be set appropriately).<dd>\n" 222 "</dl>\n\n" 223 224 "@tsexample\n" 225 "datablock ProximityMineData( SimpleMine )\n" 226 "{\n" 227 " // ShapeBaseData fields\n" 228 " category = \"Weapon\";\n" 229 " shapeFile = \"art/shapes/weapons/misc/proximityMine.dts\";\n\n" 230 231 " // ItemData fields\n" 232 " sticky = true;\n\n" 233 234 " // ProximityMineData fields\n" 235 " armingDelay = 0.5;\n" 236 " armingSound = MineArmedSound;\n\n" 237 238 " autoTriggerDelay = 0;\n" 239 " triggerOnOwner = true;\n" 240 " triggerRadius = 5.0;\n" 241 " triggerSpeed = 1.0;\n" 242 " triggerDelay = 0.5;\n" 243 " triggerSound = MineTriggeredSound;\n" 244 " explosion = RocketLauncherExplosion;\n\n" 245 246 " // dynamic fields\n" 247 " pickUpName = \"Proximity Mines\";\n" 248 " maxInventory = 20;\n\n" 249 250 " damageType = \"MineDamage\"; // type of damage applied to objects in radius\n" 251 " radiusDamage = 30; // amount of damage to apply to objects in radius\n" 252 " damageRadius = 8; // search radius to damage objects when exploding\n" 253 " areaImpulse = 2000; // magnitude of impulse to apply to objects in radius\n" 254 "};\n\n" 255 256 "function ProximityMineData::onTriggered( %this, %obj, %target )\n" 257 "{\n" 258 " echo( %this.name SPC \"triggered by \" @ %target.getClassName() );\n" 259 "}\n\n" 260 261 "function ProximityMineData::onExplode( %this, %obj, %position )\n" 262 "{\n" 263 " // Damage objects within the mine's damage radius\n" 264 " if ( %this.damageRadius > 0 )\n" 265 " radiusDamage( %obj.sourceObject, %position, %this.damageRadius, %this.radiusDamage, %this.damageType, %this.areaImpulse );\n" 266 "}\n\n" 267 268 "function ProximityMineData::damage( %this, %obj, %position, %source, %amount, %damageType )\n" 269 "{\n" 270 " // Explode if any damage is applied to the mine\n" 271 " %obj.schedule(50 + getRandom(50), explode);\n" 272 "}\n\n" 273 274 "%obj = new ProximityMine()\n" 275 "{\n" 276 " dataBlock = SimpleMine;\n" 277 "};\n" 278 "@endtsexample\n\n" 279 280 "@see ProximityMineData\n" 281 282 "@ingroup gameObjects\n" 283); 284 285ProximityMine::ProximityMine() 286{ 287 mTypeMask |= StaticShapeObjectType; 288 mDataBlock = 0; 289 290 mStickyCollisionPos.zero(); 291 292 mOwner = NULL; 293 294 mState = Thrown; 295 mStateTimeout = 0; 296 297 mAnimThread = NULL; 298 299 // For the Item class 300 mSubclassItemHandlesScene = true; 301} 302 303ProximityMine::~ProximityMine() 304{ 305} 306 307//---------------------------------------------------------------------------- 308 309void ProximityMine::consoleInit() 310{ 311 Parent::consoleInit(); 312 313 Con::addVariable("$ProxMine::autoDeleteTicks", TypeS32, &gAutoDeleteTicks, 314 "@brief Number of ticks until an exploded mine is deleted on the server.\n\n" 315 316 "After a mine has exploded it remains in the server's scene graph for a time " 317 "to allow its exploded state to be passed along to each client. This variable " 318 "controls how long a mine remains before it is deleted. Any client that has not " 319 "received the exploded state by then (perhaps due to lag) will not see any " 320 "explosion produced by the mine.\n\n" 321 322 "@ingroup GameObjects"); 323} 324 325//---------------------------------------------------------------------------- 326 327bool ProximityMine::onAdd() 328{ 329 if ( !Parent::onAdd() || !mDataBlock ) 330 return false; 331 332 addToScene(); 333 334 if (isServerObject()) 335 scriptOnAdd(); 336 337 if ( mStatic ) 338 { 339 // static mines are armed immediately 340 mState = Deployed; 341 mStateTimeout = 0; 342 } 343 344 return true; 345} 346 347bool ProximityMine::onNewDataBlock( GameBaseData* dptr, bool reload ) 348{ 349 mDataBlock = dynamic_cast<ProximityMineData*>( dptr ); 350 if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) ) 351 return false; 352 353 scriptOnNewDataBlock(); 354 return true; 355} 356 357void ProximityMine::onRemove() 358{ 359 scriptOnRemove(); 360 removeFromScene(); 361 362 Parent::onRemove(); 363} 364 365//---------------------------------------------------------------------------- 366 367void ProximityMine::setTransform( const MatrixF& mat ) 368{ 369 ShapeBase::setTransform( mat ); // Skip Item::setTransform as it restricts rotation to the Z axis 370 371 if ( !mStatic ) 372 { 373 mAtRest = false; 374 mAtRestCounter = 0; 375 } 376 377 if ( mPhysicsRep ) 378 mPhysicsRep->setTransform( getTransform() ); 379 380 setMaskBits( Item::RotationMask | Item::PositionMask | Item::NoWarpMask ); 381} 382 383void ProximityMine::setDeployedPos( const Point3F& pos, const Point3F& normal ) 384{ 385 // Align to deployed surface normal 386 MatrixF mat( true ); 387 MathUtils::getMatrixFromUpVector( normal, &mat ); 388 mat.setPosition( pos + normal * mObjBox.minExtents.z ); 389 390 mDelta.pos = pos; 391 mDelta.posVec.set(0, 0, 0); 392 393 ShapeBase::setTransform( mat ); 394 if ( mPhysicsRep ) 395 mPhysicsRep->setTransform( getTransform() ); 396 397 setMaskBits( DeployedMask ); 398} 399 400void ProximityMine::processTick( const Move* move ) 401{ 402 Parent::processTick( move ); 403 404 // Process state machine 405 mStateTimeout -= TickSec; 406 407 State lastState = NumStates;; 408 while ( mState != lastState ) 409 { 410 lastState = mState; 411 switch ( mState ) 412 { 413 case Thrown: 414 if ( mAtRest ) 415 { 416 mState = Deployed; 417 mStateTimeout = mDataBlock->armingDelay; 418 419 // Get deployed position if mine was not stuck to another surface 420 if ( mStickyCollisionPos.isZero() ) 421 { 422 mObjToWorld.getColumn( 2, &mStickyCollisionNormal ); 423 mObjToWorld.getColumn( 3, &mStickyCollisionPos ); 424 } 425 setDeployedPos( mStickyCollisionPos, mStickyCollisionNormal ); 426 427 if ( mDataBlock->armingSequence != -1 ) 428 { 429 mAnimThread = mShapeInstance->addThread(); 430 mShapeInstance->setSequence( mAnimThread, mDataBlock->armingSequence, 0.0f ); 431 } 432 if ( mDataBlock->armingSound ) 433 SFX->playOnce( mDataBlock->armingSound, &getRenderTransform() ); 434 } 435 break; 436 437 case Deployed: 438 // Timeout into Armed state 439 if ( mStateTimeout <= 0 ) 440 { 441 mState = Armed; 442 mStateTimeout = mDataBlock->autoTriggerDelay ? mDataBlock->autoTriggerDelay : F32_MAX; 443 } 444 break; 445 446 case Armed: 447 { 448 // Check for objects within the trigger area 449 Box3F triggerBox( mDataBlock->triggerRadius * 2 ); 450 triggerBox.setCenter( getTransform().getPosition() ); 451 452 SimpleQueryList sql; 453 getContainer()->findObjects( triggerBox, sTriggerCollisionMask, 454 SimpleQueryList::insertionCallback, &sql ); 455 for ( S32 i = 0; i < sql.mList.size(); i++ ) 456 { 457 // Detect movement in the trigger area 458 if ( ( sql.mList[i] == mOwner && !mDataBlock->triggerOnOwner ) || 459 sql.mList[i]->getVelocity().len() < mDataBlock->triggerSpeed ) 460 continue; 461 462 // Mine has been triggered 463 mShapeInstance->destroyThread( mAnimThread ); 464 mAnimThread = NULL; 465 466 mState = Triggered; 467 mStateTimeout = mDataBlock->triggerDelay; 468 if ( mDataBlock->triggerSequence != -1 ) 469 { 470 mAnimThread = mShapeInstance->addThread(); 471 mShapeInstance->setSequence( mAnimThread, mDataBlock->triggerSequence, 0.0f ); 472 } 473 if ( mDataBlock->triggerSound ) 474 SFX->playOnce( mDataBlock->triggerSound, &getRenderTransform() ); 475 476 if ( isServerObject() ) 477 mDataBlock->onTriggered_callback( this, sql.mList[0] ); 478 } 479 break; 480 } 481 482 case Triggered: 483 // Timeout into exploded state 484 if ( mStateTimeout <= 0 ) 485 { 486 explode(); 487 } 488 break; 489 490 case Exploded: 491 // Mine's delete themselves on the server after exploding 492 if ( isServerObject() && ( mStateTimeout <= 0 ) ) 493 { 494 deleteObject(); 495 return; 496 } 497 break; 498 } 499 } 500} 501 502//---------------------------------------------------------------------------- 503 504void ProximityMine::explode() 505{ 506 // Make sure we don't explode twice 507 if ( mState == Exploded ) 508 { 509 return; 510 } 511 512 mState = Exploded; 513 mStateTimeout = TickSec * gAutoDeleteTicks; // auto-delete on server N ticks after exploding 514 515 // Move the explosion point slightly off the surface to avoid problems with radius damage 516 Point3F normal = getTransform().getUpVector(); 517 Point3F explodePos = getTransform().getPosition() + normal * mDataBlock->explosionOffset; 518 519 if ( isServerObject() ) 520 { 521 // Do what the server needs to do, damage the surrounding objects, etc. 522 mDataBlock->onExplode_callback( this, explodePos ); 523 setMaskBits( ExplosionMask ); 524 525 // Wait till the timeout to self delete. This gives the server object time 526 // to get ghosted to the client 527 } 528 else 529 { 530 // Client just plays the explosion effect at the right place 531 if ( mDataBlock->explosion ) 532 { 533 Explosion *pExplosion = new Explosion; 534 pExplosion->onNewDataBlock( mDataBlock->explosion, false ); 535 536 MatrixF xform( true ); 537 xform.setPosition( explodePos ); 538 pExplosion->setTransform( xform ); 539 pExplosion->setInitialState( explodePos, normal ); 540 pExplosion->setCollideType( sTriggerCollisionMask ); 541 if ( pExplosion->registerObject() == false ) 542 { 543 Con::errorf( ConsoleLogEntry::General, "ProximityMine(%s)::explode: couldn't register explosion", 544 mDataBlock->getName() ); 545 delete pExplosion; 546 } 547 } 548 } 549} 550 551void ProximityMine::advanceTime( F32 dt ) 552{ 553 Parent::advanceTime( dt ); 554 555 if ( mAnimThread ) 556 mShapeInstance->advancePos( dt, mAnimThread ); 557} 558 559//---------------------------------------------------------------------------- 560 561U32 ProximityMine::packUpdate( NetConnection* connection, U32 mask, BitStream* stream ) 562{ 563 // Handle rotation ourselves (so it is not locked to the Z axis like for Items) 564 U32 retMask = Parent::packUpdate( connection, mask & (~<a href="/coding/class/classitem/#classitem_1aaacac713d02fa2d54fcca2662866de3fa5f0360bea9b5df7a11abb6ab328e4a92">Item::RotationMask</a>), stream ); 565 566 if ( stream->writeFlag( mask & Item::RotationMask ) ) 567 { 568 QuatF rot( mObjToWorld ); 569 mathWrite( *stream, rot ); 570 } 571 572 if ( stream->writeFlag( !mStatic && ( mask & DeployedMask ) && ( mState > Thrown ) ) ) 573 { 574 mathWrite( *stream, mStickyCollisionPos ); 575 mathWrite( *stream, mStickyCollisionNormal ); 576 } 577 578 stream->writeFlag( ( mask & ExplosionMask ) && ( mState == Exploded ) ); 579 580 return retMask; 581} 582 583void ProximityMine::unpackUpdate( NetConnection* connection, BitStream* stream ) 584{ 585 Parent::unpackUpdate( connection, stream ); 586 587 // Item::RotationMask 588 if ( stream->readFlag() ) 589 { 590 QuatF rot; 591 mathRead( *stream, &rot ); 592 593 Point3F pos = mObjToWorld.getPosition(); 594 rot.setMatrix( &mObjToWorld ); 595 mObjToWorld.setPosition( pos ); 596 } 597 598 // !mStatic && ( mask & DeployedMask ) && ( mState > Thrown ) 599 if ( stream->readFlag() ) 600 { 601 mathRead( *stream, &mStickyCollisionPos ); 602 mathRead( *stream, &mStickyCollisionNormal ); 603 604 mAtRest = true; 605 606 setDeployedPos( mStickyCollisionPos, mStickyCollisionNormal ); 607 } 608 609 // ( mask & ExplosionMask ) && ( mState == Exploded ) 610 if ( stream->readFlag() ) 611 { 612 // start the explosion visuals on the client 613 explode(); 614 } 615 616 if ( mStatic && mState <= Deployed ) 617 { 618 // static mines are armed immediately 619 mState = Deployed; 620 mStateTimeout = 0; 621 } 622} 623 624//---------------------------------------------------------------------------- 625 626void ProximityMine::prepRenderImage( SceneRenderState* state ) 627{ 628 // Don't render the mine if exploded 629 if ( mState == Exploded ) 630 return; 631 632 // Use ShapeBase to render the 3D shape 633 Parent::prepRenderImage( state ); 634 635 // Add a custom render instance to draw the trigger area 636 if ( !state->isShadowPass() ) 637 { 638 ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 639 ri->renderDelegate.bind( this, &ProximityMine::renderObject ); 640 ri->type = RenderPassManager::RIT_ObjectTranslucent; 641 ri->translucentSort = true; 642 ri->defaultKey = 1; 643 state->getRenderPass()->addInst( ri ); 644 } 645} 646 647void ProximityMine::renderObject( ObjectRenderInst* ri, 648 SceneRenderState* state, 649 BaseMatInstance* overrideMat ) 650{ 651 if ( overrideMat ) 652 return; 653/* 654 // Render the trigger area 655 if ( mState == Armed || mState == Triggered ) 656 { 657 const LinearColorF drawColor(1, 0, 0, 0.05f); 658 if ( drawColor.alpha > 0 ) 659 { 660 GFXStateBlockDesc desc; 661 desc.setZReadWrite( true, false ); 662 desc.setBlend( true ); 663 664 GFXTransformSaver saver; 665 666 MatrixF mat = getRenderTransform(); 667 mat.scale( getScale() ); 668 669 GFX->getDrawUtil()->drawSphere( desc, mDataBlock->triggerRadius, mat.getPosition(), 670 drawColor, true, false, &mat ); 671 } 672 } 673*/ 674} 675 676//---------------------------------------------------------------------------- 677 678DefineEngineMethod( ProximityMine, explode, void, (),, 679 "@brief Manually cause the mine to explode.\n\n") 680{ 681 object->explode(); 682} 683