afxEA_AreaDamage.cpp
Engine/source/afx/ea/afxEA_AreaDamage.cpp
Classes:
class
class
Detailed Description
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include <typeinfo> 28#include "afx/arcaneFX.h" 29 30#include "afx/afxEffectDefs.h" 31#include "afx/afxEffectWrapper.h" 32#include "afx/afxChoreographer.h" 33#include "afx/ce/afxAreaDamage.h" 34 35//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 36// afxEA_AreaDamage 37 38class afxEA_AreaDamage : public afxEffectWrapper 39{ 40 typedef afxEffectWrapper Parent; 41 42 afxAreaDamageData* damage_data; 43 Point3F impact_pos; 44 bool damage_is_done; 45 SceneObject* cons_obj; 46 47 void do_runtime_substitutions(); 48 void deal_area_damage(); 49 void apply_damage(ShapeBase*, F32 damage, const char* flavor, Point3F& pos); 50 void apply_impulse(ShapeBase*, F32 impulse, Point3F& pos); 51 void notify_damage_source(ShapeBase* damaged, F32 damage, const char* flavor, Point3F& pos); 52 53public: 54 /*C*/ afxEA_AreaDamage(); 55 /*C*/ ~afxEA_AreaDamage(); 56 57 virtual bool isDone(); 58 59 virtual void ea_set_datablock(SimDataBlock*); 60 virtual bool ea_start(); 61 virtual bool ea_update(F32 dt); 62 virtual void ea_finish(bool was_stopped); 63}; 64 65//~~~~~~~~~~~~~~~~~~~~// 66 67afxEA_AreaDamage::afxEA_AreaDamage() 68{ 69 damage_data = 0; 70 impact_pos.zero(); 71 damage_is_done = false; 72 cons_obj = 0; 73} 74 75afxEA_AreaDamage::~afxEA_AreaDamage() 76{ 77 if (damage_data && damage_data->isTempClone()) 78 delete damage_data; 79 damage_data = 0; 80} 81 82bool afxEA_AreaDamage::isDone() 83{ 84 return damage_is_done; 85} 86 87void afxEA_AreaDamage::ea_set_datablock(SimDataBlock* db) 88{ 89 damage_data = dynamic_cast<afxAreaDamageData*>(db); 90} 91 92bool afxEA_AreaDamage::ea_start() 93{ 94 if (!damage_data) 95 { 96 Con::errorf("afxEA_AreaDamage::ea_start() -- missing or incompatible datablock."); 97 return false; 98 } 99 100 do_runtime_substitutions(); 101 102 return true; 103} 104 105bool afxEA_AreaDamage::ea_update(F32 dt) 106{ 107 if (!damage_is_done) 108 { 109 afxConstraint* pos_cons = getPosConstraint(); 110 if (pos_cons) 111 { 112 pos_cons->getPosition(impact_pos); 113 cons_obj = pos_cons->getSceneObject(); 114 } 115 116 deal_area_damage(); 117 118 damage_is_done = true; 119 } 120 121 return true; 122} 123 124void afxEA_AreaDamage::ea_finish(bool was_stopped) 125{ 126 damage_is_done = false; 127} 128 129void afxEA_AreaDamage::do_runtime_substitutions() 130{ 131 // only clone the datablock if there are substitutions 132 if (damage_data->getSubstitutionCount() > 0) 133 { 134 // clone the datablock and perform substitutions 135 afxAreaDamageData* orig_db = damage_data; 136 damage_data = new afxAreaDamageData(*orig_db, true); 137 orig_db->performSubstitutions(damage_data, mChoreographer, mGroup_index); 138 } 139} 140 141// radiusDamage(%sourceObject, %position, %radius, %damage, %damageType, %impulse, %excluded) 142 143void afxEA_AreaDamage::deal_area_damage() 144{ 145 // initContainerRadiusSearch -- afterwards Container::mSearchList contains objects within radius sorted by distance 146 gServerContainer.initRadiusSearch(impact_pos, damage_data->radius, ShapeBaseObjectType); 147 148 F32 halfradius = damage_data->radius*0.5f; 149 150 const Vector<SimObjectPtr<SceneObject>*>& list = gServerContainer.getRadiusSearchList(); 151 for (S32 i = 0; i < list.size(); i++) 152 { 153 if (!list[i]->isNull()) 154 { 155 ShapeBase* shape = dynamic_cast<ShapeBase*>((SceneObject*)(*list[i])); 156 if (!shape || (shape->getTypeMask() & CameraObjectType)) 157 continue; 158 159 if (damage_data->exclude_cons_obj && cons_obj == *list[i]) 160 continue; 161 162#if 0 // AFX_T3D_DISABLED -- calcExplosionCoverage() is a script function 163 // so we currently assign a coverage value of 1.0. 164 165 VehicleObjectType; 166 F32 coverage = calcExplosionCoverage(impact_pos, shape, mask); 167 if (coverage == 0.0f) 168 continue; 169#else 170 F32 coverage = 1.0f; 171#endif 172 173 // calulate distance 174 Point3F pos; 175 shape->getWorldBox().getCenter(&pos); 176 F32 dist = (pos - impact_pos).len(); 177 178 F32 min_dist = shape->getWorldBox().len_x(); 179 if (shape->getWorldBox().len_y() < min_dist) 180 min_dist = shape->getWorldBox().len_y(); 181 if (shape->getWorldBox().len_z() < min_dist) 182 min_dist = shape->getWorldBox().len_z(); 183 184 dist -= min_dist; 185 if (dist < 0) 186 dist = 0; 187 188 F32 dist_scale = (dist < halfradius) ? 1.0f : 1.0f - ((dist - halfradius)/halfradius); 189 190 F32 damage = damage_data->amount*coverage*dist_scale; 191 apply_damage(shape, damage, damage_data->flavor, impact_pos); 192 apply_impulse(shape, damage_data->impulse*dist_scale, impact_pos); 193 194 if (damage_data->notify_damage_src) 195 notify_damage_source(shape, damage, damage_data->flavor, impact_pos); 196 } 197 } 198} 199 200void afxEA_AreaDamage::notify_damage_source(ShapeBase* damaged, F32 damage, const char* flavor, Point3F& pos) 201{ 202 if (mIsZero(damage)) 203 return; 204 205 char *posArg = Con::getArgBuffer(64); 206 dSprintf(posArg, 64, "%f %f %f", pos.x, pos.y, pos.z); 207 208 Con::executef(mChoreographer->getDataBlock(), "onInflictedAreaDamage", 209 mChoreographer->getIdString(), 210 damaged->getIdString(), 211 Con::getFloatArg(damage), 212 flavor, 213 posArg); 214} 215 216void afxEA_AreaDamage::apply_damage(ShapeBase* shape, F32 damage, const char* flavor, Point3F& pos) 217{ 218 if (mIsZero(damage)) 219 return; 220 221 char *posArg = Con::getArgBuffer(64); 222 dSprintf(posArg, 64, "%f %f %f", pos.x, pos.y, pos.z); 223 224 Con::executef(shape, "damage", 225 mChoreographer->getIdString(), 226 posArg, 227 Con::getFloatArg(damage), 228 flavor); 229} 230 231void afxEA_AreaDamage::apply_impulse(ShapeBase* shape, F32 impulse, Point3F& pos) 232{ 233 if (impulse <= 0.0f) 234 return; 235 236 Point3F center; shape->getWorldBox().getCenter(¢er); 237 VectorF impulse_vec = center - pos; 238 impulse_vec.normalizeSafe(); 239 impulse_vec *= impulse; 240 shape->applyImpulse(pos, impulse_vec); 241} 242 243//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 244 245class afxEA_AreaDamageDesc : public afxEffectAdapterDesc, public afxEffectDefs 246{ 247 static afxEA_AreaDamageDesc desc; 248 249public: 250 virtual bool testEffectType(const SimDataBlock*) const; 251 virtual bool requiresStop(const afxEffectWrapperData*, const afxEffectTimingData&) const { return false; } 252 virtual bool runsOnServer(const afxEffectWrapperData*) const { return true; } 253 virtual bool runsOnClient(const afxEffectWrapperData*) const { return false; } 254 255 virtual afxEffectWrapper* create() const { return new afxEA_AreaDamage; } 256}; 257 258afxEA_AreaDamageDesc afxEA_AreaDamageDesc::desc; 259 260bool afxEA_AreaDamageDesc::testEffectType(const SimDataBlock* db) const 261{ 262 return (typeid(afxAreaDamageData) == typeid(*db)); 263} 264 265//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 266