MissionPhysObjPattern.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. #include "MissionPhysObjPattern.h"
  2. #include "MissionPhysObject.h"
  3. #ifdef _DEBUG
  4. #ifndef STOP_DEBUG
  5. //#define ENABLE_FX_DEBUG
  6. #endif
  7. #endif
  8. #ifdef ENABLE_FX_DEBUG
  9. //После отладки переменные надо будет перенести в PlayCollisionEffect и тут всё вычистить
  10. float minImpulseThreshold = 1.0f;
  11. float minImpulseParticlesThreshold = 10.0f;
  12. float maxImpulseValue = 1000.0f;
  13. float impulseParticlesPow = 0.2f;
  14. float impulseSoundsPow = 0.7f;
  15. float minParticlesScale = 0.2f;
  16. float minSoundVolume = 0.1f;
  17. #endif
  18. void SaveFX()
  19. {
  20. #ifdef ENABLE_FX_DEBUG
  21. #ifndef STOP_DEBUG
  22. IFileService * fs = (IFileService *)api->GetService("FileService");
  23. Assert(fs);
  24. IEditableIniFile * ini = fs->OpenEditableIniFile("debugFxParams.delme", file_create_always, _FL_);
  25. if(ini)
  26. {
  27. ini->SetFloat(null, "minImpulseThreshold", minImpulseThreshold);
  28. ini->SetFloat(null, "minImpulseParticlesThreshold", minImpulseParticlesThreshold);
  29. ini->SetFloat(null, "maxImpulseValue", maxImpulseValue);
  30. ini->SetFloat(null, "impulseParticlesPow", impulseParticlesPow);
  31. ini->SetFloat(null, "impulseSoundsPow", impulseSoundsPow);
  32. ini->SetFloat(null, "minParticlesScale", minParticlesScale);
  33. ini->SetFloat(null, "minSoundVolume", minSoundVolume);
  34. ini->Release();
  35. }
  36. #endif
  37. #endif
  38. }
  39. void _cdecl ReadFX()
  40. {
  41. #ifdef ENABLE_FX_DEBUG
  42. #ifndef STOP_DEBUG
  43. IFileService * fs = (IFileService *)api->GetService("FileService");
  44. Assert(fs);
  45. IIniFile * ini = fs->OpenIniFile("debugFxParams.delme", _FL_);
  46. if(ini)
  47. {
  48. minImpulseThreshold = ini->GetFloat(null, "minImpulseThreshold", minImpulseThreshold);
  49. minImpulseParticlesThreshold = ini->GetFloat(null, "minImpulseParticlesThreshold", minImpulseParticlesThreshold);
  50. maxImpulseValue = ini->GetFloat(null, "maxImpulseValue", maxImpulseValue);
  51. impulseParticlesPow = ini->GetFloat(null, "impulseParticlesPow", impulseParticlesPow);
  52. impulseSoundsPow = ini->GetFloat(null, "impulseSoundsPow", impulseSoundsPow);
  53. minParticlesScale = ini->GetFloat(null, "minParticlesScale", minParticlesScale);
  54. minSoundVolume = ini->GetFloat(null, "minSoundVolume", minSoundVolume);
  55. ini->Release();
  56. }
  57. #endif
  58. #endif
  59. }
  60. void _cdecl Console_UpdateFXParams(const ConsoleStack & params)
  61. {
  62. #ifdef ENABLE_FX_DEBUG
  63. #pragma message("MissionPhysObjPattern::PlayCollisionEffect not complette!!!")
  64. #ifndef STOP_DEBUG
  65. ReadFX();
  66. bool isSave = false;
  67. for(dword i = 0; i < params.GetSize()/2; i++)
  68. {
  69. const char * name = params.GetParam(i*2 + 0);
  70. float param = (float)atof(params.GetParam(i*2 + 1));
  71. switch(name[0])
  72. {
  73. case '1':
  74. isSave = true;
  75. minImpulseThreshold = Clampf(param, 0.001f, 100000.0f);
  76. break;
  77. case '2':
  78. isSave = true;
  79. minImpulseParticlesThreshold = Clampf(param, 0.001f, 100000.0f);
  80. break;
  81. case '3':
  82. isSave = true;
  83. maxImpulseValue = Clampf(param, 0.001f, 100000.0f);
  84. break;
  85. case '4':
  86. isSave = true;
  87. impulseParticlesPow = Clampf(param, 0.001f, 1000.0f);
  88. break;
  89. case '5':
  90. isSave = true;
  91. impulseSoundsPow = Clampf(param, 0.001f, 1000.0f);
  92. break;
  93. case '6':
  94. isSave = true;
  95. minParticlesScale = Clampf(param);
  96. break;
  97. case '7':
  98. isSave = true;
  99. minSoundVolume = Clampf(param);
  100. break;
  101. }
  102. }
  103. if(isSave)
  104. {
  105. SaveFX();
  106. }
  107. #else
  108. #pragma message("Fix MissionPhysObjPattern::PlayCollisionEffect before release!!!")
  109. #endif
  110. #endif
  111. }
  112. MissionPhysObjPattern::FadeoutElement MissionPhysObjPattern::fadeoutElements[] =
  113. {
  114. {ConstString("Hide"), fe_hide},
  115. {ConstString("Set static"), fe_static},
  116. {ConstString("No change"), fe_none}
  117. };
  118. MissionPhysObjPattern::MaterialDescription MissionPhysObjPattern::materialDescs[] =
  119. {
  120. {ConstString("Wood"), pmtlid_wood},
  121. {ConstString("Stone"), pmtlid_stone},
  122. {ConstString("Iron"), pmtlid_iron},
  123. {ConstString("Fabrics"), pmtlid_fabrics}
  124. };
  125. MissionPhysObjPattern::PatternObject::PatternObject() : boxes(_FL_, 1),
  126. capsules(_FL_, 1),
  127. sounds(_FL_, 1),
  128. particles(_FL_, 1)
  129. {
  130. Assert(pmtlid_ground == 1);
  131. Assert(pmtlid_stone == 2);
  132. Assert(pmtlid_sand == 3);
  133. Assert(pmtlid_wood == 4);
  134. Assert(pmtlid_grass == 5);
  135. Assert(pmtlid_water == 6);
  136. Assert(pmtlid_iron == 7);
  137. Assert(pmtlid_fabrics == 8);
  138. dencity = 5.0f;
  139. centerOfMass = 0.0f;
  140. isStatic = true;
  141. isShow = true;
  142. isSoloDraw = false;
  143. fe = fe_none;
  144. impulsePosition = 0.0f;
  145. impulse = 0.0f;
  146. isAddImpulse = false;
  147. min = 0.0f;
  148. max = 0.0f;
  149. tipPosition = 0.0f;
  150. model = null;
  151. }
  152. MissionPhysObjPattern::Effect::Effect()
  153. {
  154. #ifdef ENABLE_FX_DEBUG
  155. SaveFX();
  156. #endif
  157. }
  158. MissionPhysObjPattern::MissionPhysObjPattern() : objects(_FL_),
  159. locators(_FL_),
  160. regObjects(_FL_),
  161. scenes(_FL_)
  162. {
  163. dynamicLighting = true;
  164. shadowCast = true;
  165. shadowReceive = true;
  166. seaReflection = false;
  167. level = 0;
  168. hideDistanceMin2 = hideDistanceK2 = 0.0f;
  169. }
  170. MissionPhysObjPattern::~MissionPhysObjPattern()
  171. {
  172. for(long i = 0; i < regObjects; i++)
  173. {
  174. regObjects[i]->DeletePattern();
  175. }
  176. objects.DelAll();
  177. for(long i = 0; i < scenes; i++)
  178. {
  179. if(scenes[i].model)
  180. {
  181. scenes[i].model->Release();
  182. }
  183. }
  184. scenes.DelAll();
  185. }
  186. //Инициализировать объект
  187. bool MissionPhysObjPattern::Create(MOPReader & reader)
  188. {
  189. #ifdef ENABLE_FX_DEBUG
  190. #ifndef STOP_DEBUG
  191. Console().Register_PureC_Command("ufx", "Скажи Максу удалить это!!!", Console_UpdateFXParams);
  192. ReadFX();
  193. #endif
  194. #endif
  195. haveSoloDraw = false;
  196. objects.DelAll();
  197. locators.DelAll();
  198. buildPosition = reader.Position();
  199. Show(reader.Bool());
  200. showOnlySelected = reader.Bool();
  201. showSolid = reader.Bool();
  202. showBroken = reader.Bool();
  203. showObjectCenter = reader.Bool();
  204. showSoundsPoints = reader.Bool();
  205. showParticlesPoints = reader.Bool();
  206. showBrokeImpulses = reader.Bool();
  207. showCenterOfMass = reader.Bool();
  208. showTipsPosition = reader.Bool();
  209. showLocators = reader.Bool();
  210. isPickup = reader.Bool();
  211. hp = reader.Float();
  212. activeTime = reader.Float();
  213. ConstString matDesc = reader.Enum();
  214. materialId = pmtlid_wood;
  215. for(dword i = 0; i < ARRSIZE(materialDescs); i++)
  216. {
  217. if(materialDescs[i].name == matDesc)
  218. {
  219. materialId = materialDescs[i].id;
  220. break;
  221. }
  222. }
  223. hitSword.particles = reader.String();
  224. hitSword.sound = reader.String();
  225. hitBullet.particles = reader.String();
  226. hitBullet.sound = reader.String();
  227. hitBomb.particles = reader.String();
  228. hitBomb.sound = reader.String();
  229. hitShooter.particles = reader.String();
  230. hitShooter.sound = reader.String();
  231. hitCannon.particles = reader.String();
  232. hitCannon.sound = reader.String();
  233. hitFlame.particles = reader.String();
  234. hitFlame.sound = reader.String();
  235. for(dword i = 0; i < ARRSIZE(hitToMaterial); i++)
  236. {
  237. hitToMaterial[i].particles = reader.String();
  238. hitToMaterial[i].sound = reader.String();
  239. }
  240. soldObjectsCount = reader.Array();
  241. objects.AddElements(soldObjectsCount);
  242. for(long i = 0; i < objects; i++)
  243. {
  244. PatternObject & obj = objects[i];
  245. ReadModelParams(i, reader);
  246. obj.particles.AddElements(reader.Array());
  247. for(long j = 0; j < obj.particles; j++)
  248. {
  249. obj.particles[j].name = reader.String();
  250. Vector pos = reader.Position();
  251. Vector ang = reader.Angles();
  252. obj.particles[j].mtx = Matrix(ang, pos);
  253. }
  254. obj.sounds.AddElements(reader.Array());
  255. for(long j = 0; j < obj.sounds; j++)
  256. {
  257. obj.sounds[j].name = reader.String();
  258. obj.sounds[j].mtx.pos = reader.Position();
  259. }
  260. obj.receiveBoom = reader.String();
  261. obj.waterParticle = reader.String();
  262. obj.waterSound = reader.String();
  263. obj.dencity = reader.Float();
  264. obj.centerOfMass = reader.Position();
  265. obj.isStatic = reader.Bool();
  266. obj.isShow = reader.Bool();
  267. obj.isSoloDraw = reader.Bool();
  268. obj.tipId = reader.String();
  269. obj.tipPosition = reader.Position();
  270. obj.bonusesTable = reader.String();
  271. haveSoloDraw |= obj.isSoloDraw;
  272. }
  273. objects.AddElements(reader.Array());
  274. for(; i < objects; i++)
  275. {
  276. PatternObject & obj = objects[i];
  277. ReadModelParams(i, reader);
  278. obj.waterParticle = reader.String();
  279. obj.waterSound = reader.String();
  280. ConstString fe = reader.Enum();
  281. for(dword i = 0; i < ARRSIZE(fadeoutElements); i++)
  282. {
  283. if(fe == fadeoutElements[i].name)
  284. {
  285. obj.fe = fadeoutElements[i].id;
  286. break;
  287. }
  288. }
  289. Assert(i < ARRSIZE(fadeoutElements));
  290. Vector pos = reader.Position();
  291. Vector ang = reader.Angles();
  292. Matrix mtx(ang, pos);
  293. obj.impulsePosition = mtx.pos;
  294. obj.impulse = mtx.vz;
  295. obj.impulse *= reader.Float();
  296. obj.isAddImpulse = reader.Bool();
  297. obj.dencity = reader.Float();
  298. obj.centerOfMass = reader.Position();
  299. obj.isStatic = reader.Bool();
  300. obj.isShow = reader.Bool();
  301. obj.isSoloDraw = reader.Bool();
  302. haveSoloDraw |= obj.isSoloDraw;
  303. }
  304. damageModifier.Init(reader);
  305. if(EditMode_IsOn())
  306. {
  307. Matrix toWorld(Vector(0.0f), buildPosition);
  308. for(long j = 0; j < scenes; j++)
  309. {
  310. scenes[j].use = false;
  311. }
  312. for(long i = 0; i < objects; i++)
  313. {
  314. PatternObject & obj = objects[i];
  315. obj.model = null;
  316. for(long j = 0; j < scenes; j++)
  317. {
  318. if(!scenes[j].model) continue;
  319. if(scenes[j].use == false && obj.modelName.c_str() == scenes[j].model->GetFileName())
  320. {
  321. obj.model = scenes[j].model;
  322. obj.model->SetTransform(obj.mtx*toWorld);
  323. scenes[j].use = true;
  324. break;
  325. }
  326. }
  327. if(!obj.model)
  328. {
  329. CacheScene cs;
  330. cs.model = obj.model = Geometry().CreateScene(obj.modelName.c_str(), &Animation(), &Particles(), &Sound(), _FL_);
  331. if(obj.model)
  332. {
  333. obj.model->SetTransform(obj.mtx*toWorld);
  334. }
  335. cs.use = true;
  336. if(cs.model)
  337. {
  338. scenes.Add(cs);
  339. }
  340. }
  341. }
  342. for(long j = 0; j < scenes; )
  343. {
  344. if(scenes[j].use == false)
  345. {
  346. scenes[j].model->Release();
  347. scenes.DelIndex(j);
  348. }else{
  349. j++;
  350. }
  351. }
  352. bool isAddBound = false;
  353. viewMinBox = viewMaxBox = 0.0f;
  354. for(long i = 0; i < objects; i++)
  355. {
  356. PatternObject & obj = objects[i];
  357. if(!obj.model) continue;
  358. if(isAddBound)
  359. {
  360. viewMinBox.Min(obj.model->GetBound().vMin);
  361. viewMinBox.Min(obj.model->GetBound().vMax);
  362. viewMaxBox.Max(obj.model->GetBound().vMin);
  363. viewMaxBox.Max(obj.model->GetBound().vMax);
  364. }else{
  365. viewMinBox = obj.model->GetBound().vMin;
  366. viewMaxBox = obj.model->GetBound().vMax;
  367. isAddBound = true;
  368. }
  369. }
  370. }
  371. dynamicLighting = reader.Bool();
  372. shadowCast = reader.Bool();
  373. shadowReceive = reader.Bool();
  374. seaReflection = reader.Bool();
  375. if(reader.Bool())
  376. {
  377. level = reader.Long() + ML_ALPHA1;
  378. }else{
  379. level = reader.Long() + ML_GEOMETRY1;
  380. }
  381. float hideDistanceMin = reader.Float();
  382. if(hideDistanceMin > 1e-5f)
  383. {
  384. float hideDistanceMax = hideDistanceMin + 5.0f;
  385. hideDistanceMin2 = hideDistanceMin*hideDistanceMin;
  386. hideDistanceK2 = 1.0f/(hideDistanceMax*hideDistanceMax - hideDistanceMin*hideDistanceMin);
  387. }else{
  388. hideDistanceMin2 = 0.0f;
  389. hideDistanceK2 = 0.0f;
  390. }
  391. for(long i = 0; i < regObjects; i++)
  392. {
  393. regObjects[i]->UpdatePatternData();
  394. }
  395. return true;
  396. }
  397. void MissionPhysObjPattern::ReadModelParams(long index, MOPReader & reader)
  398. {
  399. PatternObject & obj = objects[index];
  400. Vector pos = reader.Position();
  401. Vector ang = reader.Angles();
  402. obj.mtx.Build(ang, pos);
  403. obj.modelName = reader.String();
  404. bool isAdd = false;
  405. obj.boxes.AddElements(reader.Array());
  406. for(long i = 0; i < obj.boxes; i++)
  407. {
  408. CollisionBox & box = obj.boxes[i];
  409. pos = reader.Position();
  410. ang = reader.Angles();
  411. box.mtx.Build(ang, pos);
  412. box.size05.x = reader.Float()*0.5f;
  413. box.size05.y = reader.Float()*0.5f;
  414. box.size05.z = reader.Float()*0.5f;
  415. Box::FindABBforOBB(box.mtx, -box.size05, box.size05, obj.min, obj.max, isAdd);
  416. isAdd = true;
  417. }
  418. obj.capsules.AddElements(reader.Array());
  419. for(long i = 0; i < obj.capsules; i++)
  420. {
  421. CollisionCapsule & capsule = obj.capsules[i];
  422. pos = reader.Position();
  423. ang = reader.Angles();
  424. capsule.mtx.Build(ang, pos);
  425. capsule.height = reader.Float();
  426. capsule.radius = reader.Float();
  427. if(capsule.height < 0.001f) capsule.height = 0.001f;
  428. capsule.height += capsule.radius*2.0f;
  429. capsule.size05.x = capsule.radius;
  430. capsule.size05.y = capsule.height*0.5f;
  431. capsule.size05.z = capsule.radius;
  432. Box::FindABBforOBB(capsule.mtx, -capsule.size05, capsule.size05, obj.min, obj.max, isAdd);
  433. isAdd = true;
  434. }
  435. long locatorsCount = reader.Array();
  436. for(long i = 0; i < locatorsCount; i++)
  437. {
  438. Locator & loc = locators[locators.Add()];
  439. loc.name = reader.String();
  440. pos = reader.Position();
  441. ang = reader.Angles();
  442. loc.mtx.Build(ang, pos);
  443. //loc.mtx.EqMultiplyFast(Matrix(ang, pos), obj.mtx);
  444. loc.objectIndex = index;
  445. }
  446. }
  447. //Инициализировать объект
  448. bool MissionPhysObjPattern::EditMode_Create(MOPReader & reader)
  449. {
  450. EditMode_Update(reader);
  451. return true;
  452. }
  453. //Обновить параметры
  454. bool MissionPhysObjPattern::EditMode_Update(MOPReader & reader)
  455. {
  456. Create(reader);
  457. if(IsShow())
  458. {
  459. SetUpdate(&MissionPhysObjPattern::Draw, ML_GEOMETRY1);
  460. }
  461. return true;
  462. }
  463. //Получить размеры описывающего ящика
  464. void MissionPhysObjPattern::EditMode_GetSelectBox(Vector & min, Vector & max)
  465. {
  466. min = viewMinBox;
  467. max = viewMaxBox;
  468. }
  469. //Получить матрицу объекта
  470. Matrix & MissionPhysObjPattern::GetMatrix(Matrix & mtx)
  471. {
  472. mtx.SetIdentity();
  473. return mtx;
  474. }
  475. //Нарисовать модельку
  476. void _cdecl MissionPhysObjPattern::Draw(float dltTime, long level)
  477. {
  478. if(!IsShow())
  479. {
  480. DelUpdate(&MissionPhysObjPattern::Draw);
  481. return;
  482. }
  483. if(showOnlySelected && !EditMode_IsSelect()) return;
  484. if(!EditMode_IsVisible()) return;
  485. Matrix toWorld(Vector(0.0f), buildPosition);
  486. if(showObjectCenter)
  487. {
  488. Render().DrawMatrix(toWorld, 1.0f);
  489. }
  490. for(long i = 0; i < objects; i++)
  491. {
  492. PatternObject & obj = objects[i];
  493. //Пропускаем невидимые объекты
  494. if(!haveSoloDraw)
  495. {
  496. if(!obj.isShow) continue;
  497. if(i < soldObjectsCount)
  498. {
  499. if(!showSolid) continue;
  500. }else{
  501. if(!showBroken) continue;
  502. }
  503. }else{
  504. if(!obj.isSoloDraw) continue;
  505. }
  506. //Позиция
  507. Matrix toWorld(obj.mtx);
  508. toWorld.pos += buildPosition;
  509. //Звуки-партиклы отдельно
  510. if(showSoundsPoints)
  511. {
  512. for(long j = 0; j < obj.sounds; j++)
  513. {
  514. Render().DrawSphere(obj.sounds[j].mtx.pos*toWorld, 0.05f, 0xff0000ff);
  515. Render().Print(obj.sounds[j].mtx.pos*toWorld, 20.0f, -1.0f, 0xffc0c0ff, "Sound");
  516. Render().Print(obj.sounds[j].mtx.pos*toWorld, 20.0f, 0.0f, 0xffc0c0ff, obj.sounds[j].name.c_str());
  517. }
  518. }
  519. if(showParticlesPoints)
  520. {
  521. for(long j = 0; j < obj.particles; j++)
  522. {
  523. Render().DrawSphere(obj.particles[j].mtx.pos*toWorld, 0.05f, 0xffff0000);
  524. Render().DrawMatrix(obj.particles[j].mtx*toWorld, 0.4f);
  525. Render().Print(obj.particles[j].mtx.pos*toWorld, 20.0f, -1.0f, 0xffc0c0ff, "Particles");
  526. Render().Print(obj.particles[j].mtx.pos*toWorld, 20.0f, 0.0f, 0xffc0c0ff, obj.particles[j].name.c_str());
  527. }
  528. }
  529. if(showCenterOfMass)
  530. {
  531. Render().DrawSphere(obj.centerOfMass*toWorld, 0.08f, 0xffcfcf00);
  532. }
  533. if(showTipsPosition)
  534. {
  535. Render().DrawSphere(obj.tipPosition*toWorld, 0.08f, 0xffff00ff);
  536. }
  537. //Рисуем
  538. if(obj.model)
  539. {
  540. obj.model->Draw();
  541. }
  542. for(long j = 0; j < obj.boxes; j++)
  543. {
  544. CollisionBox & box = obj.boxes[j];
  545. Render().DrawBox(-box.size05, box.size05, box.mtx*toWorld, 0xffffff80);
  546. }
  547. for(long j = 0; j < obj.capsules; j++)
  548. {
  549. CollisionCapsule & cps = obj.capsules[j];
  550. Render().DrawCapsule(cps.radius, cps.height-(cps.radius*2.0f), 0xffffff00, cps.mtx*toWorld);
  551. Render().DrawBox(-cps.size05, cps.size05, cps.mtx*toWorld, 0x5fff0000);
  552. }
  553. if(showBrokeImpulses)
  554. {
  555. if(i >= soldObjectsCount)
  556. {
  557. Vector impulsePos = toWorld*obj.impulsePosition;
  558. Render().DrawVector(impulsePos, impulsePos + toWorld.MulNormal(obj.impulse), 0xffff0000);
  559. }
  560. }
  561. }
  562. for(long i = 0; i < locators; i++)
  563. {
  564. Locator & loc = locators[i];
  565. PatternObject & obj = objects[loc.objectIndex];
  566. Matrix mtx(loc.mtx, obj.mtx);
  567. mtx.pos += buildPosition;
  568. Render().DrawMatrix(mtx, 0.2f);
  569. }
  570. }
  571. //Прекешировать модельки заданные в патерне
  572. void MissionPhysObjPattern::CacheModels()
  573. {
  574. if(scenes > 0)
  575. {
  576. return;
  577. }
  578. scenes.AddElements(objects);
  579. for(long i = 0; i < objects; i++)
  580. {
  581. PatternObject & po = objects[i];
  582. if(po.modelName.NotEmpty())
  583. {
  584. scenes[i].model = Geometry().CreateScene(po.modelName.c_str(), &Animation(), null, null, _FL_);
  585. }else{
  586. scenes[i].model = null;
  587. }
  588. }
  589. }
  590. //Проиграть звук столкновения с данным материалом
  591. void MissionPhysObjPattern::PlayCollisionEffect(long mtlId, const Vector & pos, float impulse2)
  592. {
  593. #ifdef ENABLE_FX_DEBUG
  594. api->Trace("))))))))))))) Material: %i, impulse: %f", mtlId, powf(impulse2, 0.5f));
  595. #else
  596. static const float minImpulseThreshold = 1.0f;
  597. static const float minImpulseParticlesThreshold = 10.0f;
  598. static const float maxImpulseValue = 1000.0f;
  599. static const float impulseParticlesPow = 0.2f;
  600. static const float impulseSoundsPow = 0.7f;
  601. static const float minParticlesScale = 0.2f;
  602. static const float minSoundVolume = 0.1f;
  603. #endif
  604. //Проверяем материалы на возможность реакции
  605. if(mtlId > 8 || mtlId < 1) return;
  606. //Проверить импульс
  607. float maxImpulseValue2 = maxImpulseValue*maxImpulseValue;
  608. if(impulse2 < minImpulseThreshold*minImpulseThreshold) return;
  609. impulse2 = coremin(impulse2, maxImpulseValue2);
  610. //Имена
  611. mtlId--;
  612. Assert(mtlId < ARRSIZE(hitToMaterial));
  613. Sfx & sfx = hitToMaterial[mtlId];
  614. //Если импульс выше порогового для партиклов, то появляем эффект в точке контакта
  615. if(sfx.particles.NotEmpty() && impulse2 > minImpulseParticlesThreshold*minImpulseParticlesThreshold)
  616. {
  617. Matrix mtx;
  618. mtx.pos = pos;
  619. #ifdef ENABLE_FX_DEBUG
  620. //IParticleSystem * ps = Particles().CreateParticleSystemEx2("woodbreak", mtx, false, _FL_);
  621. IParticleSystem * ps = Particles().CreateParticleSystemEx2("shiphitlarge", mtx, false, _FL_);
  622. #else
  623. IParticleSystem * ps = Particles().CreateParticleSystemEx2(sfx.particles.c_str(), mtx, true, _FL_);
  624. #endif
  625. if(ps)
  626. {
  627. float scale = powf(impulse2/maxImpulseValue2, impulseParticlesPow)*(1.0f - minParticlesScale) + minParticlesScale;
  628. ps->SetScale(scale);
  629. ps->AutoDelete(true);
  630. #ifdef ENABLE_FX_DEBUG
  631. api->Trace(")))))))))))))> Show particles with scale: %f", scale);
  632. #endif
  633. }
  634. }
  635. if(sfx.sound.NotEmpty())
  636. {
  637. float volume = powf((impulse2/maxImpulseValue2), impulseSoundsPow)*(1.0f - minSoundVolume) + minSoundVolume;
  638. #ifdef ENABLE_FX_DEBUG
  639. Sound().Create3D(ConstString("gun_hit_wood"), pos, _FL_, true, true, volume);
  640. api->Trace(")))))))))))))> Play sound with volume: %f\n", volume);
  641. #else
  642. Sound().Create3D(sfx.sound, pos, _FL_, true, true, volume);
  643. #endif
  644. }
  645. }
  646. //============================================================================================
  647. //Параметры инициализации
  648. //============================================================================================
  649. MOP_BEGINLISTCG(MissionPhysObjPattern, "Physic object pattern", '1.00', 0, "Pattern for physic objects", "Physics")
  650. MOP_ENUMBEG("Fade effects")
  651. for(dword i = 0; i < ARRSIZE(MissionPhysObjPattern::fadeoutElements); i++)
  652. {
  653. MOP_ENUMELEMENT(MissionPhysObjPattern::fadeoutElements[i].name.c_str())
  654. }
  655. MOP_ENUMEND
  656. MOP_ENUMBEG("Object material")
  657. for(dword i = 0; i < ARRSIZE(MissionPhysObjPattern::materialDescs); i++)
  658. {
  659. MOP_ENUMELEMENT(MissionPhysObjPattern::materialDescs[i].name.c_str())
  660. }
  661. MOP_ENUMEND
  662. MOP_POSITION("Build position", Vector(0.0f))
  663. MOP_BOOL("Show", true)
  664. MOP_BOOL("Show only selected", false)
  665. MOP_BOOL("Show solid part", true)
  666. MOP_BOOL("Show broken part", true)
  667. MOP_BOOL("Show object center", true)
  668. MOP_BOOLC("Show sounds points", true, "Sounds draw as blue spheres")
  669. MOP_BOOLC("Show particles points", true, "Particles draw as red spheres")
  670. MOP_BOOL("Show broke impulses", true)
  671. MOP_BOOL("Show center of mass", true)
  672. MOP_BOOL("Show tips position", true)
  673. MOP_BOOL("Show locators", true)
  674. MOP_BOOL("Is pickup", false);
  675. MOP_FLOATEX("HP", 100.0f, 0.0f, 100000.0f)
  676. MOP_FLOATEXC("Active time", 3.0f, 0.0f, 100000.0f, "Time for change state of broken parts")
  677. MOP_ENUM("Object material", "Material");
  678. MOP_GROUPBEG("Hit effects")
  679. MOP_GROUPBEG("Hit sword")
  680. MOP_STRING("Particles | Hit sword |", "")
  681. MOP_STRING("Sound | Hit sword |", "")
  682. MOP_GROUPEND()
  683. MOP_GROUPBEG("Hit bullet")
  684. MOP_STRING("Particles | Hit bullet |", "")
  685. MOP_STRING("Sound | Hit bullet |", "")
  686. MOP_GROUPEND()
  687. MOP_GROUPBEG("Hit bomb")
  688. MOP_STRING("Particles | Hit bomb |", "")
  689. MOP_STRING("Sound | Hit bomb |", "")
  690. MOP_GROUPEND()
  691. MOP_GROUPBEG("Hit shooter")
  692. MOP_STRING("Particles | Hit shooter |", "")
  693. MOP_STRING("Sound | Hit shooter |", "")
  694. MOP_GROUPEND()
  695. MOP_GROUPBEG("Hit cannon")
  696. MOP_STRING("Particles | Hit cannon |", "")
  697. MOP_STRING("Sound | Hit cannon |", "")
  698. MOP_GROUPEND()
  699. MOP_GROUPBEG("Hit flame")
  700. MOP_STRING("Particles | Hit flame |", "")
  701. MOP_STRING("Sound | Hit flame |", "")
  702. MOP_GROUPEND()
  703. MOP_GROUPBEG("Hit to ground")
  704. MOP_STRING("Particles | Hit to ground |", "hit_wood_to_solid")
  705. MOP_STRING("Sound | Hit to ground |", "h_wood_ground")
  706. MOP_GROUPEND()
  707. MOP_GROUPBEG("Hit to stone")
  708. MOP_STRING("Particles | Hit to stone |", "hit_wood_to_solid")
  709. MOP_STRING("Sound | Hit to stone |", "h_wood_stone")
  710. MOP_GROUPEND()
  711. MOP_GROUPBEG("Hit to sand")
  712. MOP_STRING("Particles | Hit to sand |", "hit_wood_to_sand")
  713. MOP_STRING("Sound | Hit to sand |", "h_wood_sand")
  714. MOP_GROUPEND()
  715. MOP_GROUPBEG("Hit to wood")
  716. MOP_STRING("Particles | Hit to wood |", "hit_wood_to_solid")
  717. MOP_STRING("Sound | Hit to wood |", "h_wood_wood")
  718. MOP_GROUPEND()
  719. MOP_GROUPBEG("Hit to grass")
  720. MOP_STRING("Particles | Hit to grass |", "hit_wood_to_grass")
  721. MOP_STRING("Sound | Hit to grass |", "h_wood_grass")
  722. MOP_GROUPEND()
  723. MOP_GROUPBEG("Hit to water")
  724. MOP_STRING("Particles | Hit to water |", "hit_wood_cloud")
  725. MOP_STRING("Sound | Hit to water |", "h_wood_water")
  726. MOP_GROUPEND()
  727. MOP_GROUPBEG("Hit to iron")
  728. MOP_STRING("Particles | Hit to iron |", "hit_wood_to_solid")
  729. MOP_STRING("Sound | Hit to iron |", "h_wood_iron")
  730. MOP_GROUPEND()
  731. MOP_GROUPBEG("Hit to fabrics")
  732. MOP_STRING("Particles | Hit to fabrics |", "hit_wood_to_fabrics")
  733. MOP_STRING("Sound | Hit to fabrics |", "h_wood_fabrics")
  734. MOP_GROUPEND()
  735. MOP_GROUPEND()
  736. MOP_ARRAYBEG("Solid parts", 1, 1)
  737. MOP_POSITION("Position", Vector(0.0f))
  738. MOP_ANGLES("Orient", Vector(0.0f))
  739. MOP_STRING("Model", "")
  740. MOP_ARRAYBEG("Box", 0, 16)
  741. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  742. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  743. MOP_FLOATEX("Size x", 0.1f, 0.001f, 1000.0f)
  744. MOP_FLOATEX("Size y", 0.1f, 0.001f, 1000.0f)
  745. MOP_FLOATEX("Size z", 0.1f, 0.001f, 1000.0f)
  746. MOP_ARRAYEND
  747. MOP_ARRAYBEG("Capsule", 0, 16)
  748. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  749. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  750. MOP_FLOATEX("Height", 0.3f, 0.001f, 1000.0f)
  751. MOP_FLOATEX("Radius", 0.1f, 0.001f, 1000.0f)
  752. MOP_ARRAYEND
  753. MOP_ARRAYBEG("Locators", 0, 16)
  754. MOP_STRINGC("Name", "", "Locator's name for do access it")
  755. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  756. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  757. MOP_ARRAYEND
  758. MOP_ARRAYBEG("Broke particles", 0, 10)
  759. MOP_STRING("Particles", "")
  760. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  761. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  762. MOP_ARRAYEND
  763. MOP_ARRAYBEG("Broke sounds", 0, 10)
  764. MOP_STRING("Sound", "")
  765. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  766. MOP_ARRAYEND
  767. MOP_STRINGC("Bomb explosion", "", "Object, what receive command |boom x y z|")
  768. MOP_STRING("Water drop particles", "")
  769. MOP_STRING("Water drop sound", "")
  770. MOP_FLOATEX("Density", 5.0f, 0.1f, 100.0f)
  771. MOP_POSITIONC("Center of mass", Vector(0.0f), "Local position center of mass")
  772. MOP_BOOL("Is static", false)
  773. MOP_BOOLC("Is show", true, "Show or hide this object")
  774. MOP_BOOLC("Solo draw", false, "Show only this object (ignore Is show flag)")
  775. MOP_STRINGC("TipID", "Weapon", "Identifier of tip")
  776. MOP_POSITIONC("Tip position", Vector(0.0f), "Local tip pivot, text draw up on this point")
  777. MOP_STRING("Bonus Table", "")
  778. MOP_ARRAYEND
  779. MOP_ARRAYBEG("Broken parts", 0, 100)
  780. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  781. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  782. MOP_STRING("Model", "")
  783. MOP_ARRAYBEG("Box", 0, 16)
  784. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  785. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  786. MOP_FLOATEX("Size x", 0.1f, 0.001f, 1000.0f)
  787. MOP_FLOATEX("Size y", 0.1f, 0.001f, 1000.0f)
  788. MOP_FLOATEX("Size z", 0.1f, 0.001f, 1000.0f)
  789. MOP_ARRAYEND
  790. MOP_ARRAYBEG("Capsule", 0, 16)
  791. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  792. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  793. MOP_FLOATEX("Height", 0.3f, 0.001f, 1000.0f)
  794. MOP_FLOATEX("Radius", 0.1f, 0.001f, 1000.0f)
  795. MOP_ARRAYEND
  796. MOP_ARRAYBEG("Locators", 0, 16)
  797. MOP_STRINGC("Name", "", "Locator's name for do access it")
  798. MOP_POSITIONC("Position", Vector(0.0f), "Local position")
  799. MOP_ANGLESC("Orient", Vector(0.0f), "Local orientation")
  800. MOP_ARRAYEND
  801. MOP_STRING("Water drop particles", "")
  802. MOP_STRING("Water drop sound", "")
  803. MOP_ENUM("Fade effects", "Fadeout effect")
  804. MOP_POSITIONC("Impulse position", Vector(0.0f), "Local impulse position")
  805. MOP_ANGLESC("Impulse orient", Vector(0.0f), "Local orientation")
  806. MOP_FLOATEX("Impulse value", 0.0f, 0.0f, 1000.0f)
  807. MOP_BOOLC("Add impulse", false, "Add impulse to current, else replase current impulse")
  808. MOP_FLOATEX("Dencity", 5.0f, 0.1f, 100.0f)
  809. MOP_POSITIONC("Center of mass", Vector(0.0f), "Local position center of mass")
  810. MOP_BOOL("Is static", false)
  811. MOP_BOOLC("Is show", true, "Show or hide this object")
  812. MOP_BOOLC("Solo draw", false, "Show only this object (ignore Is show flag)")
  813. MOP_ARRAYEND
  814. MOP_DR_MULTIPLIERSG
  815. MOP_GROUPBEG("Render params")
  816. MOP_BOOL("Dynamic lighting", false)
  817. MOP_BOOLC("Shadow cast", false, "Geometry can is shadow cast by some objects")
  818. MOP_BOOLC("Shadow receive", false, "Geometry can is shadow receive from casting objects")
  819. MOP_BOOLC("Sea reflection", false, "Geometry can reflect in sea")
  820. MOP_BOOLC("Transparency", false, "Geometry draw as transparency (i.e. light rays)")
  821. MOP_LONGEXC("Level", 0, 0, 100, "Order of geometry draw")
  822. MOP_FLOATC("Hide distance", -1.0f, "If distance less 0, then ignore this feature")
  823. MOP_GROUPEND()
  824. MOP_ENDLIST(MissionPhysObjPattern)