ExplosionPatch.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. #include "ExplosionPatch.h"
  2. #include "..\Common_h\ICharactersArbiter.h"
  3. #include "..\common_h\AnimationStdEvents.h"
  4. //============================================================================================
  5. ExplosionPatchCollider::ExplosionPatchCollider()
  6. {
  7. m_pPatchGMX = NULL;
  8. m_pPatchCollider = NULL;
  9. m_bActivateByCreate = false;
  10. }
  11. ExplosionPatchCollider::~ExplosionPatchCollider()
  12. {
  13. RELEASE(m_pPatchCollider);
  14. RELEASE(m_pPatchGMX);
  15. }
  16. bool ExplosionPatchCollider::Create(MOPReader & reader)
  17. {
  18. ReadMOPs(reader);
  19. if( !EditMode_IsOn() )
  20. Activate(m_bActivateByCreate);
  21. return true;
  22. }
  23. void ExplosionPatchCollider::PostCreate()
  24. {
  25. if( EditMode_IsOn() )
  26. SetUpdate(&ExplosionPatchCollider::WorkEdit, ML_ALPHA1);
  27. }
  28. bool ExplosionPatchCollider::EditMode_Update(MOPReader & reader)
  29. {
  30. ReadMOPs(reader);
  31. return true;
  32. }
  33. void ExplosionPatchCollider::Activate(bool isActive)
  34. {
  35. MissionObject::Activate(isActive);
  36. if( m_pPatchCollider )
  37. m_pPatchCollider->Activate(isActive);
  38. LogicDebug("ExplosionPatchCollider %s is %s now", GetObjectID().c_str(), isActive?"active":"inactive");
  39. }
  40. void ExplosionPatchCollider::ReadMOPs(MOPReader & reader)
  41. {
  42. // patch
  43. ConstString pathName = reader.String();
  44. Vector ang = reader.Angles();
  45. Vector pos = reader.Position();
  46. m_mtxPatchTransform.Build( ang, pos );
  47. // recreate patch
  48. if( !m_pPatchGMX || ConstString(m_pPatchGMX->GetFileName())!=pathName )
  49. {
  50. RELEASE(m_pPatchCollider);
  51. RELEASE(m_pPatchGMX);
  52. m_pPatchGMX = Geometry().CreateScene( pathName.c_str(), &Animation(), &Particles(), &Sound(), _FL_ );
  53. if( m_pPatchGMX )
  54. m_pPatchCollider = m_pPatchGMX->CreatePhysicsActor( Physics(), false );
  55. if( m_pPatchCollider )
  56. {
  57. m_pPatchCollider->SetTransform( m_mtxPatchTransform );
  58. m_pPatchCollider->SetGroup( phys_grp3 );
  59. m_pPatchCollider->EnableCollision(false);
  60. m_pPatchCollider->Activate(false);
  61. }
  62. }
  63. // activate state
  64. m_bActivateByCreate = reader.Bool();
  65. }
  66. void _cdecl ExplosionPatchCollider::WorkEdit(float dltTime, long level)
  67. {
  68. if( Mission().EditMode_IsAdditionalDraw() && EditMode_IsSelect() && m_pPatchGMX )
  69. {
  70. m_pPatchGMX->SetUserColor(Color(1.f, 1.f, 1.f, 1.f));
  71. m_pPatchGMX->SetTransform( m_mtxPatchTransform );
  72. m_pPatchGMX->Draw();
  73. }
  74. }
  75. //============================================================================================
  76. ExplosionPatch::ExplosionPatch() :
  77. m_hitParams(_FL_),
  78. m_models(_FL_),
  79. m_aReadyExplosions(_FL_),
  80. m_aGmxPreload(_FL_)
  81. {
  82. m_arbiter.Reset();
  83. m_bIsShadowCast = false;
  84. m_nExplosionLimit = 0;
  85. m_nExplosionDeleteLimit = 0;
  86. m_fModelFadeTime = 0.f;
  87. m_fModelFadePower = 0.5f;
  88. m_fTraceBottom = -0.3f;
  89. m_fTraceTop = 20.f;
  90. m_bTurnOnDebugTrace = false;
  91. m_nLevelDraw = ML_PARTICLES5+10;
  92. m_bRefraction = false;
  93. }
  94. ExplosionPatch::~ExplosionPatch()
  95. {
  96. // отгружаем модели
  97. ReleaseModels();
  98. ReleasePreloadModels();
  99. }
  100. //============================================================================================
  101. //Инициализировать объект
  102. bool ExplosionPatch::Create(MOPReader & reader)
  103. {
  104. // read mission params
  105. ReadMOPs(reader);
  106. // for edit mode:
  107. if( EditMode_IsOn() )
  108. {
  109. SetUpdate(&ExplosionPatch::WorkEdit, m_nLevelDraw);
  110. }
  111. else
  112. {
  113. long n,q;
  114. // create models buffer for render
  115. ReleaseModels();
  116. m_models.AddElements( m_nExplosionLimit );
  117. for( n=0; n<m_nExplosionLimit; n++ )
  118. {
  119. m_models[n].gmxModel = NULL;
  120. m_models[n].timer = 0.f;
  121. m_models[n].state = est_free;
  122. }
  123. // preload models
  124. ReleasePreloadModels();
  125. for( n=0; n<m_hitParams; n++ )
  126. {
  127. for( q=0; q<m_hitParams[n].hits; q++ )
  128. PreloadModel( m_hitParams[n].hits[q].modelName, m_hitParams[n].hits[q].modelAni );
  129. }
  130. }
  131. return true;
  132. }
  133. void ExplosionPatch::PostCreate()
  134. {
  135. static const ConstString arbiterId("CharactersArbiter");
  136. MissionObject::FindObject(arbiterId, m_arbiter);
  137. Activate( true );
  138. SetUpdate(&ExplosionPatch::WorkGame, m_nLevelDraw);
  139. if( m_bIsShadowCast )
  140. Registry(MG_SHADOWCAST, (MOF_EVENT)&ExplosionPatch::ShadowDraw, ML_GEOMETRY1);
  141. if( m_bRefraction )
  142. Registry(MG_SEAREFRACTION, (MOF_EVENT)&ExplosionPatch::SeaRefraction, ML_GEOMETRY1);
  143. }
  144. // редактировать объект
  145. bool ExplosionPatch::EditMode_Update(MOPReader & reader)
  146. {
  147. ReadMOPs(reader);
  148. return true;
  149. }
  150. void ExplosionPatch::Command(const char * id, dword numParams, const char ** params)
  151. {
  152. if( !id ) return;
  153. if (string::IsEqual(id, "Explosion"))
  154. {
  155. // проверка на параметр: тип попадания
  156. if( numParams < 1 ) {
  157. api->Trace("Error: Command 'Explosion' will be have parameter: <explosion type>");
  158. return;
  159. }
  160. // тип попадания
  161. long nExplosionType = GetHitGroup(params[0]);
  162. if( nExplosionType < 0 ) {
  163. api->Trace("Error: Command 'Explosion' can`t find explosion type: %s", params[0]);
  164. return;
  165. }
  166. // проверка на параметр: объект от которого берется позиция попадания
  167. if( numParams < 2 ) {
  168. api->Trace("Error: Command 'Explosion' will be have parameter: <object id>");
  169. return;
  170. }
  171. // ищем объект для рождения взрыва
  172. ConstString fid(params[1]);
  173. MOSafePointer sptr;
  174. if( !FindObject(fid,sptr) ) {
  175. api->Trace("Error: Command 'Explosion' can`t find object: %s", params[1]);
  176. return;
  177. }
  178. // берем смещение позиции попадания
  179. Vector pos;
  180. if( numParams < 5 )
  181. pos = 0.f;
  182. else
  183. {
  184. pos.x = (float)atof(params[2]);
  185. pos.y = (float)atof(params[3]);
  186. pos.z = (float)atof(params[4]);
  187. }
  188. Matrix mtx(true);
  189. sptr.Ptr()->GetMatrix(mtx);
  190. // собственно рождаем эффект взрыва
  191. MakeExplosion( mtx.MulVertex(pos), nExplosionType );
  192. }
  193. else if (string::IsEqual(id, "ondebug"))
  194. {
  195. m_bTurnOnDebugTrace = !m_bTurnOnDebugTrace;
  196. Console().Trace(COL_CMD_OUTPUT,"Explosion debug mode is turn %s", m_bTurnOnDebugTrace?"on":"off");
  197. }
  198. }
  199. long ExplosionPatch::FindHitParams(const HitGroup& hitGroup, dword dwExplosionMaterial)
  200. {
  201. for( long n=0; n<hitGroup.hits; n++ )
  202. if( hitGroup.hits[n].explosionMaterial == dwExplosionMaterial )
  203. return n;
  204. return -1;
  205. }
  206. dword ExplosionPatch::GetExplodeMaterial( ConstString& matID )
  207. {
  208. if( matID == ConstString("air") )
  209. return pmtlid_air;
  210. if( matID == ConstString("ground") )
  211. return pmtlid_ground;
  212. if( matID == ConstString("stone") )
  213. return pmtlid_stone;
  214. if( matID == ConstString("sand") )
  215. return pmtlid_sand;
  216. if( matID == ConstString("wood") )
  217. return pmtlid_wood;
  218. if( matID == ConstString("grass") )
  219. return pmtlid_grass;
  220. if( matID == ConstString("water") )
  221. return pmtlid_water;
  222. if( matID == ConstString("iron") )
  223. return pmtlid_iron;
  224. if( matID == ConstString("fabrics") )
  225. return pmtlid_fabrics;
  226. if( matID == ConstString("other1") )
  227. return pmtlid_other1;
  228. if( matID == ConstString("other2") )
  229. return pmtlid_other2;
  230. if( matID == ConstString("other3") )
  231. return pmtlid_other3;
  232. if( matID == ConstString("other4") )
  233. return pmtlid_other4;
  234. return 0;
  235. }
  236. long ExplosionPatch::GetHitGroup(const char* groupName)
  237. {
  238. ConstString group( groupName );
  239. for( long n=0; n<m_hitParams; n++ )
  240. if( m_hitParams[n].type == group )
  241. return n;
  242. return -1;
  243. }
  244. void ExplosionPatch::MakeExplosion(const Vector& pos, long nHitGroupIndex)
  245. {
  246. dword dwMaterial = 0xFFFFFFFF;
  247. Vector vPosExplosion = pos;
  248. // проверим попадание в коллидер
  249. IPhysicsScene::RaycastResult HitDetail;
  250. Vector from = pos; from.y += m_fTraceTop;
  251. Vector to = pos; to.y += m_fTraceBottom;
  252. IPhysBase* result = Physics().Raycast(from, to, phys_mask(phys_grp3), &HitDetail);
  253. if( result )
  254. {
  255. dwMaterial = HitDetail.mtl;
  256. vPosExplosion.y = HitDetail.position.y;
  257. }
  258. // промахнулись?
  259. if (m_bTurnOnDebugTrace && !result)
  260. api->Trace("ExplosionPatch: patch raycast failed (%.2f,%.2f,%.2f)-(%.2f,%.2f,%.2f)",
  261. from.x, from.y, from.z, to.x, to.y, to.z );
  262. MakeExplosion(vPosExplosion,nHitGroupIndex,dwMaterial);
  263. }
  264. void ExplosionPatch::MakeExplosion(const Vector& pos, long nHitGroupIndex, dword dwExplosionMaterial)
  265. {
  266. if( nHitGroupIndex<0 ) return;
  267. if( dwExplosionMaterial == 0xFFFFFFFF ) return;
  268. Matrix mPos;
  269. mPos.BuildPosition(pos);
  270. long idxHitParams = FindHitParams( m_hitParams[nHitGroupIndex], dwExplosionMaterial );
  271. // model explosion
  272. if( idxHitParams >= 0 )
  273. {
  274. m_critSection.Enter();
  275. long n = m_aReadyExplosions.Add();
  276. m_aReadyExplosions[n].pos = pos;
  277. m_aReadyExplosions[n].group = nHitGroupIndex;
  278. m_aReadyExplosions[n].material = idxHitParams;
  279. m_critSection.Leave();
  280. }
  281. else
  282. api->Trace("ExplosionPatch: cant find hit parameters for material %d", dwExplosionMaterial);
  283. }
  284. void ExplosionPatch::MakeExplosion(const Vector& pos, const char* groupName)
  285. {
  286. long ngrp = GetHitGroup(groupName);
  287. if( ngrp < 0 )
  288. api->Trace("ExplosionPatch: can`t find explosion type %s", groupName);
  289. else
  290. MakeExplosion(pos,ngrp);
  291. }
  292. void ExplosionPatch::MakeExplosion(const Vector& pos, const ConstString & groupName)
  293. {
  294. for( long n=0; n<m_hitParams; n++ )
  295. if( m_hitParams[n].type == groupName )
  296. MakeExplosion(pos,n);
  297. if( n == m_hitParams )
  298. api->Trace("ExplosionPatch: can`t find explosion type %s", groupName.c_str());
  299. }
  300. void ExplosionPatch::ClearExplosions()
  301. {
  302. for( long n=0; n<m_models; n++ )
  303. if( m_models[n].state != est_free )
  304. FreeModel(n);
  305. }
  306. //============================================================================================
  307. void _cdecl ExplosionPatch::WorkGame(float dltTime, long level)
  308. {
  309. // запросы на рождение взрывов. Могут быть из других потоков/анимация/, поэтому в крит секции
  310. m_critSection.Enter();
  311. for( long n=0; n<m_aReadyExplosions; n++ )
  312. BorrowModel( m_aReadyExplosions[n].pos, m_hitParams[m_aReadyExplosions[n].group].hits[m_aReadyExplosions[n].material] );
  313. m_aReadyExplosions.DelAll();
  314. m_critSection.Leave();
  315. // render geometry
  316. RenderModels(false);
  317. // проверка на удаление
  318. UpdateModels(dltTime);
  319. }
  320. void _cdecl ExplosionPatch::ShadowDraw ()
  321. {
  322. RenderModels(true);
  323. }
  324. void _cdecl ExplosionPatch::SeaRefraction ()
  325. {
  326. RenderModels(false);
  327. }
  328. void _cdecl ExplosionPatch::WorkEdit(float dltTime, long level)
  329. {
  330. }
  331. void ExplosionPatch::PreloadModel( ConstString& gmxName, ConstString& aniName )
  332. {
  333. long n;
  334. // добавляем новую
  335. n = m_aGmxPreload.Add();
  336. m_aGmxPreload[n] = Geometry().CreateScene( gmxName.c_str(), &Animation(), &Particles(), &Sound(), _FL_ );
  337. if( m_aGmxPreload[n] )
  338. {
  339. // загружаем анимацию
  340. m_aGmxPreload[n]->SetAnimationFile( aniName.c_str() );
  341. // ставим анимацию на паузу
  342. IAnimation* pAni = m_aGmxPreload[n]->GetAnimation();
  343. if( pAni )
  344. {
  345. pAni->Pause(true);
  346. pAni->Release();
  347. }
  348. }
  349. }
  350. void ExplosionPatch::ReadMOPs(MOPReader & reader)
  351. {
  352. long n,q;
  353. m_bIsShadowCast = false;
  354. // hit groups
  355. m_hitParams.DelAll();
  356. q = reader.Array();
  357. if( q>0 )
  358. m_hitParams.AddElements(q);
  359. for( n=0; n<q; n++ )
  360. {
  361. // hit type
  362. m_hitParams[n].type = reader.String();
  363. // hit params into group
  364. long q2 = reader.Array();
  365. if( q2>0 )
  366. m_hitParams[n].hits.AddElements(q2);
  367. for( long n2=0; n2<q2; n2++ )
  368. {
  369. m_hitParams[n].hits[n2].explosionMaterial = GetExplodeMaterial( reader.Enum() );
  370. m_hitParams[n].hits[n2].modelName = reader.String();
  371. m_hitParams[n].hits[n2].modelAni = reader.String();
  372. m_hitParams[n].hits[n2].modelTimeout = reader.Float();
  373. m_hitParams[n].hits[n2].modelScale = reader.Float();
  374. m_hitParams[n].hits[n2].isDeletedByTimeout = reader.Bool();
  375. m_hitParams[n].hits[n2].isDynamicLight = reader.Bool();
  376. m_hitParams[n].hits[n2].isShadowReceive = reader.Bool();
  377. m_hitParams[n].hits[n2].isShadowCast = reader.Bool();
  378. if( m_hitParams[n].hits[n2].isShadowCast )
  379. m_bIsShadowCast = true;
  380. }
  381. }
  382. // limit for explosion at one time
  383. m_nExplosionLimit = reader.Long();
  384. Assert(m_nExplosionLimit>0);
  385. m_nExplosionDeleteLimit = reader.Long();
  386. m_fModelFadeTime = reader.Float();
  387. m_fModelFadePower = reader.Float();
  388. m_fTraceBottom = reader.Float();
  389. m_fTraceTop = reader.Float();
  390. m_nLevelDraw = reader.Long();
  391. m_bRefraction = reader.Bool();
  392. }
  393. long ExplosionPatch::BorrowModel(const Vector& pos, const HitParams& hitParams)
  394. {
  395. for( long n=0; n<m_models; n++ )
  396. {
  397. if( m_models[n].state == est_free )
  398. {
  399. // занимаем
  400. m_models[n].state = est_active;
  401. m_models[n].isDeletedByQuantityLimit = !hitParams.isDeletedByTimeout;
  402. // пересоздаем модель
  403. RELEASE( m_models[n].gmxModel );
  404. m_models[n].gmxModel = Geometry().CreateScene( hitParams.modelName.c_str(), &Animation(), &Particles(), &Sound(), _FL_ );
  405. if( !m_models[n].gmxModel )
  406. return -1;
  407. m_models[n].gmxModel->SetAnimationFile (hitParams.modelAni.c_str());
  408. m_models[n].gmxModel->SetDynamicLightState (hitParams.isDynamicLight);
  409. m_models[n].gmxModel->SetShadowReceiveState (hitParams.isShadowReceive);
  410. m_models[n].gmxModel->SetFloatAlphaReference (0.003921f);
  411. m_models[n].gmxModel->SetUserColor(Color(0.f,1.f));
  412. // ставим позицию
  413. m_models[n].mtxPos.BuildRotateY( FRAND(PIm2) );
  414. m_models[n].mtxPos.Mul(hitParams.modelScale);
  415. m_models[n].mtxPos.w = 1.f;
  416. m_models[n].mtxPos.pos = pos;
  417. m_models[n].gmxModel->SetTransform( m_models[n].mtxPos );
  418. // ставим задержку на удаление
  419. m_models[n].timer = hitParams.modelTimeout;
  420. // кастить тень?
  421. m_models[n].isShadowCast = hitParams.isShadowCast;
  422. // стартуем анимацию
  423. IAnimation* pAni = m_models[n].gmxModel->GetAnimation();
  424. if( pAni )
  425. {
  426. pAni->Pause(false);
  427. pAni->Start();
  428. pAni->Release();
  429. }
  430. return n;
  431. }
  432. }
  433. if( m_bTurnOnDebugTrace )
  434. api->Trace("ExplosionPatch: can`t create new explosion because conclude limit = %d", m_nExplosionLimit);
  435. return -1;
  436. }
  437. void ExplosionPatch::FreeModel( long idxModel )
  438. {
  439. if( idxModel>=0 && idxModel<m_models )
  440. {
  441. // освобождаем модель для использования
  442. m_models[idxModel].state = est_free;
  443. // паузим анимацию
  444. if( m_models[idxModel].gmxModel )
  445. {
  446. IAnimation* pAni = m_models[idxModel].gmxModel->GetAnimation();
  447. if( pAni )
  448. {
  449. pAni->Pause(true);
  450. pAni->Release();
  451. }
  452. }
  453. }
  454. }
  455. void ExplosionPatch::GoToNextState( long idxModel )
  456. {
  457. if( idxModel>=0 && idxModel<m_models )
  458. {
  459. switch( m_models[idxModel].state )
  460. {
  461. // из свободного сотсояния никуда не переходим (ибо для перехода надо заводить правильные параметры)
  462. case est_free:
  463. api->Trace("ExplosionPatch::GoToNextState(%d) : Can`t change state 'free', use BorrowModel() for this", idxModel);
  464. break;
  465. // из активного состояния переходим либо в фейд, либо в ожидании удаления по лимиту количества
  466. case est_active:
  467. if( m_models[idxModel].isDeletedByQuantityLimit )
  468. m_models[idxModel].state = est_ready_to_delete;
  469. else
  470. {
  471. m_models[idxModel].state = est_fadeout;
  472. m_models[idxModel].timer = m_fModelFadeTime;
  473. }
  474. break;
  475. // из ожидания удаления переходим к фейду (удалению)
  476. case est_ready_to_delete:
  477. m_models[idxModel].state = est_fadeout;
  478. m_models[idxModel].timer = m_fModelFadeTime;
  479. break;
  480. // по окончанию фейда, освобождаем полностью место для следующего взрыва
  481. case est_fadeout:
  482. FreeModel(idxModel);
  483. break;
  484. }
  485. if( m_bTurnOnDebugTrace )
  486. {
  487. api->Trace("ExplosionPatch: next state for model %d(%s) is %s",
  488. idxModel, m_models[idxModel].gmxModel ? m_models[idxModel].gmxModel->GetFileName() : "null",
  489. m_models[idxModel].state==est_free ? "free" :
  490. m_models[idxModel].state==est_active ? "active" :
  491. m_models[idxModel].state==est_ready_to_delete ? "ready_to_delete" :
  492. m_models[idxModel].state==est_fadeout ? "fade" : "unknown");
  493. }
  494. }
  495. }
  496. void ExplosionPatch::ReleaseModels()
  497. {
  498. for( long n=0; n<m_models; n++ )
  499. {
  500. if( m_models[n].gmxModel )
  501. m_models[n].gmxModel->Release();
  502. }
  503. m_models.DelAll();
  504. }
  505. void ExplosionPatch::ReleasePreloadModels()
  506. {
  507. for( long n=0; n<m_aGmxPreload; n++ )
  508. {
  509. if( m_aGmxPreload[n] )
  510. m_aGmxPreload[n]->Release();
  511. }
  512. m_aGmxPreload.DelAll();
  513. }
  514. void ExplosionPatch::RenderModels(bool shadowCast)
  515. {
  516. for( long n=0; n<m_models; n++ )
  517. {
  518. if( m_models[n].state!=est_free && (!shadowCast || m_models[n].isShadowCast))
  519. {
  520. // расчет альфы при фейде
  521. if( m_models[n].gmxModel && m_models[n].state==est_fadeout )
  522. {
  523. float alpha = 0.f;
  524. if( m_fModelFadeTime > 0.f )
  525. alpha = powf( Clampf( m_models[n].timer / m_fModelFadeTime ), m_fModelFadePower );
  526. if( m_models[n].gmxModel )
  527. m_models[n].gmxModel->SetUserColor(Color(0.f,alpha));
  528. }
  529. // отрисовка
  530. if( m_models[n].gmxModel )
  531. m_models[n].gmxModel->Draw();
  532. }
  533. }
  534. }
  535. void ExplosionPatch::UpdateModels( float dltTime )
  536. {
  537. // идет время
  538. long usedQuantity = 0;
  539. for( long n=0; n<m_models; n++ )
  540. {
  541. if( m_models[n].state==est_free ) continue;
  542. if( m_models[n].state != est_fadeout )
  543. usedQuantity++;
  544. // если модель ждет удаления через лимит количества, то время не учитываем
  545. if( m_models[n].state != est_ready_to_delete )
  546. {
  547. m_models[n].timer -= dltTime;
  548. // доиграли до конца - переходим к следующему состоянию
  549. if( m_models[n].timer <= 0.f )
  550. GoToNextState(n);
  551. }
  552. }
  553. // удалим лишние модели
  554. if( usedQuantity >= m_nExplosionDeleteLimit )
  555. {
  556. long nLimitOverflow = 1 + usedQuantity - m_nExplosionDeleteLimit;
  557. for( n=0; n<m_models && nLimitOverflow>0; n++ )
  558. {
  559. // тех кто ждет удаления удаляем
  560. if( m_models[n].state == est_ready_to_delete )
  561. {
  562. GoToNextState(n);
  563. nLimitOverflow--;
  564. }
  565. }
  566. }
  567. }
  568. //============================================================================================
  569. //Параметры инициализации
  570. //============================================================================================
  571. #define HIT_PARAMS \
  572. MOP_STRING("Explode model","") \
  573. MOP_STRING("Explode animation","") \
  574. MOP_FLOAT("Explode timeout",2.f) \
  575. MOP_FLOAT("Explode model scale",1.f) \
  576. MOP_BOOLC("FreeByTimeout",false,"After timeout do free of explosion model\n(if true then left model till limit of quantity)") \
  577. MOP_BOOL("Dynamic light",true) \
  578. MOP_BOOL("Shadow receive",true) \
  579. MOP_BOOL("Shadow cast",false)
  580. MOP_BEGINLISTCG(ExplosionPatch, "Explosion patch", '1.00', 100, "Object for create explosion by patch", "default")
  581. MOP_ENUMBEG ( "ExplosionMaterial" )
  582. MOP_ENUMELEMENT ( "air" )
  583. MOP_ENUMELEMENT ( "ground" )
  584. MOP_ENUMELEMENT ( "stone" )
  585. MOP_ENUMELEMENT ( "sand" )
  586. MOP_ENUMELEMENT ( "wood" )
  587. MOP_ENUMELEMENT ( "grass" )
  588. MOP_ENUMELEMENT ( "water" )
  589. MOP_ENUMELEMENT ( "iron" )
  590. MOP_ENUMELEMENT ( "fabrics" )
  591. MOP_ENUMELEMENT ( "other1" )
  592. MOP_ENUMELEMENT ( "other2" )
  593. MOP_ENUMELEMENT ( "other3" )
  594. MOP_ENUMELEMENT ( "other4" )
  595. MOP_ENUMEND
  596. MOP_ARRAYBEG( "Hit params", 1, 10 )
  597. MOP_STRINGC("type","bomb","type of damage")
  598. MOP_ARRAYBEG( "Hit params", 1, 15 )
  599. MOP_ENUMC("ExplosionMaterial", "Material", "Material of explosion");
  600. HIT_PARAMS
  601. MOP_ARRAYEND
  602. MOP_ARRAYEND
  603. MOP_LONGEXC("Explosion limit", 10, 1,100, "Limit of explosion at one time")
  604. MOP_LONGEXC("Explosion delete limit", 10, 1,100, "Limit of undeletable explosions")
  605. MOP_FLOATC("Explode fade time",0.8f, "Time for fadeout of explosion")
  606. MOP_FLOATEXC("Explode fade power",0.5f, 0.05f, 5.f, "Power for fadeout of explosion")
  607. MOP_FLOAT("Trace bottom distance",-0.3f)
  608. MOP_FLOAT("Trace top distance",20.f)
  609. MOP_LONGC("DrawLevel", ML_ALPHA5+10, "Draw level for render of explosions")
  610. MOP_BOOLC("Refraction", false, "Use refraction by water")
  611. MOP_ENDLIST(ExplosionPatch)
  612. MOP_BEGINLISTCG(ExplosionPatchCollider, "Explosion collider", '1.00', 100, "Patch for explosion", "default")
  613. MOP_STRINGC("Patch","","Patch with material for explosions")
  614. MOP_ANGLES("Patch angle",Vector(0.f))
  615. MOP_POSITION("Patch pos",Vector(0.f))
  616. MOP_BOOL("Active",true)
  617. MOP_ENDLIST(ExplosionPatchCollider)