DamageDetector.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. //===========================================================================================================================
  2. // Spirenkov Maxim, 2003
  3. //===========================================================================================================================//
  4. // Mission objects
  5. //===========================================================================================================================
  6. // DamageDetector
  7. //============================================================================================
  8. #include "DamageDetector.h"
  9. #define MissionDamageDetectorRadius 0.2f
  10. //============================================================================================
  11. DamageDetector::DamageDetector()
  12. {
  13. immuneCount = 0;
  14. immuneTimerIsActive = false;
  15. }
  16. DamageDetector::~DamageDetector()
  17. {
  18. }
  19. //============================================================================================
  20. //Инициализировать объект
  21. bool DamageDetector::Create(MOPReader & reader)
  22. {
  23. immuneCount = 0;
  24. immuneTimerIsActive = false;
  25. if(!DamageObject::Create(reader)) return false;
  26. //Получим идентификатор объекта
  27. SetTarget(reader.String());
  28. //Получить позицию и размеры
  29. detector.pos = reader.Position();
  30. detector.r = reader.Float();
  31. Matrix mtx;
  32. mtx.pos = detector.pos;
  33. Assert(finder);
  34. finder->SetMatrix(mtx);
  35. finder->SetBoxSize(Vector(detector.r*2.0f));
  36. //Количество жизней у детектора
  37. InitHP(reader.Float());
  38. //От кого принимать демедж
  39. multipliers.Init(reader);
  40. //Активация
  41. Activate(reader.Bool());
  42. autoReset = reader.Bool();
  43. registerEventEverytime = reader.Bool();
  44. collide = reader.Bool();
  45. immuneTime = reader.Float();
  46. //Триггеры
  47. eventDamage.Init(reader);
  48. eventActivate.Init(reader);
  49. return true;
  50. }
  51. //Инициализировать объект
  52. bool DamageDetector::EditMode_Create(MOPReader & reader)
  53. {
  54. SetUpdate(&DamageDetector::EditModeWork, ML_ALPHA5);
  55. EditMode_Update(reader);
  56. return true;
  57. }
  58. //Обновить параметры
  59. bool DamageDetector::EditMode_Update(MOPReader & reader)
  60. {
  61. Create(reader);
  62. return true;
  63. }
  64. //Получить размеры описывающего ящика
  65. void DamageDetector::EditMode_GetSelectBox(Vector & min, Vector & max)
  66. {
  67. min = -detector.r - 0.1f;
  68. max = detector.r + 0.1f;
  69. }
  70. //============================================================================================
  71. //Воздействовать на объект сферой
  72. bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector & center, float radius)
  73. {
  74. //Отсекаем воздействие
  75. if(!IsCanAttack(obj, source, hp))
  76. {
  77. return false;
  78. }
  79. //Проверяем геометрию
  80. float d2 = ~(center - detector.pos);
  81. float r = radius + detector.radius;
  82. if(d2 > r*r)
  83. {
  84. return false;
  85. }
  86. //Поподание
  87. return HitProcess(source, obj, hp);
  88. }
  89. //Воздействовать на объект линией
  90. bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector & from, const Vector & to)
  91. {
  92. //Отсекаем воздействие
  93. if(!IsCanAttack(obj, source, hp))
  94. {
  95. return false;
  96. }
  97. //Проверяем геометрию
  98. if(!detector.Intersection(from, to))
  99. {
  100. return false;
  101. }
  102. //Поподание
  103. return HitProcess(source, obj, hp);
  104. }
  105. //Воздействовать на объект выпуклым чехырёхугольником
  106. bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector vrt[4])
  107. {
  108. //Отсекаем воздействие
  109. if(!IsCanAttack(obj, source, hp))
  110. {
  111. return false;
  112. }
  113. //Проверяем геометрию
  114. Plane plane;
  115. plane.N = (vrt[1] - vrt[0]) ^ (vrt[2] - vrt[0]);
  116. if(plane.N.Normalize() > 1e-20f)
  117. {
  118. plane.Move(vrt[0]);
  119. //Проверим дистанцию до плоскости
  120. float dist = plane.Dist(detector.pos);
  121. if(fabsf(dist) > detector.r)
  122. {
  123. return false;
  124. }
  125. //Найдём круг на плоскости
  126. Vector center = detector.pos - plane.N*dist;
  127. float r = sqrtf(detector.r*detector.r - dist*dist);
  128. //Проверим на пересечение круг и четырёхугольник
  129. Plane pln;
  130. for(long n = 0; n < 4; n++)
  131. {
  132. //Строим плоскость, ортоганальную плоскости четырёхугольника и прохлдящую через грань
  133. Vector v = vrt[n] - vrt[n - 1 >= 0 ? n - 1 : 3];
  134. if(v.Normalize() < 1e-20) continue;
  135. pln.N = v ^ plane.N;
  136. pln.Move(vrt[n]);
  137. //Проверяем дистанцию до центра круга
  138. float d = pln.Dist(center);
  139. if(d > r) break;
  140. }
  141. if(n < 4) return false;
  142. }else{
  143. //Это точка или линия
  144. if(~(vrt[1] - vrt[0]) > 0.0f)
  145. {
  146. if(!detector.Intersection(vrt[0], vrt[1]))
  147. {
  148. return false;
  149. }
  150. }else
  151. if(~(vrt[2] - vrt[1]) > 0.0f)
  152. {
  153. if(!detector.Intersection(vrt[1], vrt[2]))
  154. {
  155. return false;
  156. }
  157. }else{
  158. if(!detector.Intersection(vrt[0]))
  159. {
  160. return false;
  161. }
  162. }
  163. }
  164. //Поподание
  165. return HitProcess(source, obj, hp);
  166. }
  167. //Логическая проверка на возможность аттаки
  168. inline bool DamageDetector::IsCanAttack(MissionObject * obj, dword source, float & hp)
  169. {
  170. //Отсекаем воздействие по цели
  171. if(targetID.NotEmpty())
  172. {
  173. if(target.Ptr() != obj)
  174. {
  175. return false;
  176. }
  177. }
  178. if(source != ds_check)
  179. {
  180. //Отсекаем по источнику демеджа
  181. hp *= multipliers.Multiplier(source);
  182. if(fabsf(hp) < 1e-10f)
  183. {
  184. return false;
  185. }
  186. }else{
  187. return true;
  188. }
  189. //Если режим без коллижена то делаемся имунными на время
  190. if(!collide)
  191. {
  192. //Смотрим список иммуна
  193. for(dword i = 0; i < immuneCount; i++)
  194. {
  195. if(immune[i].obj == obj)
  196. {
  197. return false;
  198. }
  199. }
  200. }
  201. return true;
  202. }
  203. //Отработка попадания
  204. bool DamageDetector::HitProcess(dword source, MissionObject * obj, float hp)
  205. {
  206. if(source != ds_check)
  207. {
  208. SetImmune(obj);
  209. ApplyDamage(hp);
  210. return (collide != 0);
  211. }
  212. return true;
  213. }
  214. //Сделать объект имунным
  215. inline void DamageDetector::SetImmune(MissionObject * obj)
  216. {
  217. if(collide)
  218. {
  219. return;
  220. }
  221. if(immuneCount >= ARRSIZE(immune))
  222. {
  223. const dword last = - 1;
  224. for(dword i = 1; i < ARRSIZE(immune); i++)
  225. {
  226. immune[i - 1] = immune[i];
  227. }
  228. immuneCount--;
  229. }
  230. immune[immuneCount].obj = obj;
  231. immune[immuneCount].time = immuneTime;
  232. immuneCount++;
  233. immuneTimerWorkTime = 5.0f;
  234. if(!immuneTimerIsActive)
  235. {
  236. immuneTimerIsActive = true;
  237. SetUpdate(&DamageDetector::ImmuneTimer, ML_ALPHA5);
  238. }
  239. }
  240. //Таймер невосприимчевости
  241. void _cdecl DamageDetector::ImmuneTimer(float dltTime, long level)
  242. {
  243. for(dword i = 0; i < immuneCount; i++)
  244. {
  245. immune[i].time -= dltTime;
  246. if(immune[i].time <= 0.0f)
  247. {
  248. for(dword j = i + 1; j < immuneCount; j++)
  249. {
  250. immune[j - 1] = immune[j];
  251. }
  252. immuneCount--;
  253. }
  254. }
  255. if(!immuneCount && immuneTimerWorkTime < 0.0f)
  256. {
  257. DelUpdate(&DamageDetector::ImmuneTimer);
  258. immuneTimerIsActive = false;
  259. }else{
  260. immuneTimerWorkTime -= dltTime;
  261. }
  262. }
  263. //============================================================================================
  264. void DamageDetector::Command(const char * id, dword numParams, const char ** params)
  265. {
  266. if(string::IsEqual(id, "reset"))
  267. {
  268. Reset();
  269. LogicDebug("Command <reset> HP now is %f", HP);
  270. }
  271. }
  272. //Работа детектора в режиме редактирования
  273. void _cdecl DamageDetector::EditModeWork(float dltTime, long level)
  274. {
  275. if(!Mission().EditMode_IsAdditionalDraw()) return;
  276. if(!EditMode_IsVisible()) return;
  277. //Обновляем состояние
  278. dword clr;
  279. UpdateTarget();
  280. if(!target.Validate())
  281. {
  282. FindObject(targetID, target);
  283. }
  284. if(target.Validate())
  285. {
  286. if(IsActive())
  287. {
  288. clr = 0xff00ffcc;
  289. }else{
  290. clr = 0xcccccc80;
  291. }
  292. }else{
  293. clr = 0xffff508c;
  294. }
  295. //Рисуем
  296. Render().DrawSphere(detector.pos, detector.r, clr, "ShowDetector");
  297. if(EditMode_IsSelect())
  298. {
  299. Render().Print(detector.pos, -1.0f, -1.0f, 0xffffffff, "Object id: %s", GetObjectID().c_str());
  300. Render().Print(detector.pos, -1.0f, 0.0f, 0xffffffff, "Target: %s", targetID.c_str());
  301. Render().Print(detector.pos, -1.0f, 1.0f, 0xffffffff, IsActive() ? "State: on" : "State: off");
  302. }
  303. }
  304. //============================================================================================
  305. //Параметры инициализации
  306. //============================================================================================
  307. MOP_BEGINLISTCG(DamageDetector, "Damage detector", '1.00', 0x0fffffff, "Damage detector triggering when mission object attack it.", "Logic")
  308. MOP_STRINGC("Object id", "Player", "Is set object, then apply damage only from this object")
  309. MOP_POSITIONC("Position", Vector(0.0f), "Detector sphere position")
  310. MOP_FLOATEXC("Radius", 0.7f, 0.0001f, 1000000.0f, "Detector sphere radius")
  311. MOP_FLOATEXC("HP", 1.0f, 0.0001f, 1000000.0f, "Hit points of this object")
  312. MOP_DR_MULTIPLIERSG
  313. MOP_BOOLC("Active", true, "Active object in start mission time")
  314. MOP_BOOLC("Autoreset", true, "When trigger is done, reset it")
  315. MOP_BOOLC("Anytime damage", true, "Activate damage event when detector is done too")
  316. MOP_BOOLC("Collision", true, "Dont collide with damage source")
  317. MOP_FLOATEXC("Immune time", 0.2f, 0.001f, 1000000.0f, "Use in non collision mode.\nTime when detector dont take damage from attak object.")
  318. MOP_MISSIONTRIGGERG("Damage", "Damage.")
  319. MOP_MISSIONTRIGGERG("Done", "Activate.")
  320. MOP_ENDLIST(DamageDetector)