| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- //===========================================================================================================================
- // Spirenkov Maxim, 2003
- //===========================================================================================================================//
- // Mission objects
- //===========================================================================================================================
- // DamageDetector
- //============================================================================================
-
- #include "DamageDetector.h"
- #define MissionDamageDetectorRadius 0.2f
- //============================================================================================
- DamageDetector::DamageDetector()
- {
- immuneCount = 0;
- immuneTimerIsActive = false;
- }
- DamageDetector::~DamageDetector()
- {
- }
- //============================================================================================
- //Инициализировать объект
- bool DamageDetector::Create(MOPReader & reader)
- {
- immuneCount = 0;
- immuneTimerIsActive = false;
- if(!DamageObject::Create(reader)) return false;
- //Получим идентификатор объекта
- SetTarget(reader.String());
- //Получить позицию и размеры
- detector.pos = reader.Position();
- detector.r = reader.Float();
- Matrix mtx;
- mtx.pos = detector.pos;
- Assert(finder);
- finder->SetMatrix(mtx);
- finder->SetBoxSize(Vector(detector.r*2.0f));
- //Количество жизней у детектора
- InitHP(reader.Float());
- //От кого принимать демедж
- multipliers.Init(reader);
- //Активация
- Activate(reader.Bool());
- autoReset = reader.Bool();
- registerEventEverytime = reader.Bool();
- collide = reader.Bool();
- immuneTime = reader.Float();
- //Триггеры
- eventDamage.Init(reader);
- eventActivate.Init(reader);
- return true;
- }
- //Инициализировать объект
- bool DamageDetector::EditMode_Create(MOPReader & reader)
- {
- SetUpdate(&DamageDetector::EditModeWork, ML_ALPHA5);
- EditMode_Update(reader);
- return true;
- }
- //Обновить параметры
- bool DamageDetector::EditMode_Update(MOPReader & reader)
- {
- Create(reader);
- return true;
- }
- //Получить размеры описывающего ящика
- void DamageDetector::EditMode_GetSelectBox(Vector & min, Vector & max)
- {
- min = -detector.r - 0.1f;
- max = detector.r + 0.1f;
- }
- //============================================================================================
- //Воздействовать на объект сферой
- bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector & center, float radius)
- {
- //Отсекаем воздействие
- if(!IsCanAttack(obj, source, hp))
- {
- return false;
- }
- //Проверяем геометрию
- float d2 = ~(center - detector.pos);
- float r = radius + detector.radius;
- if(d2 > r*r)
- {
- return false;
- }
- //Поподание
- return HitProcess(source, obj, hp);
- }
- //Воздействовать на объект линией
- bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector & from, const Vector & to)
- {
- //Отсекаем воздействие
- if(!IsCanAttack(obj, source, hp))
- {
- return false;
- }
- //Проверяем геометрию
- if(!detector.Intersection(from, to))
- {
- return false;
- }
- //Поподание
- return HitProcess(source, obj, hp);
- }
- //Воздействовать на объект выпуклым чехырёхугольником
- bool DamageDetector::Attack(MissionObject * obj, dword source, float hp, const Vector vrt[4])
- {
- //Отсекаем воздействие
- if(!IsCanAttack(obj, source, hp))
- {
- return false;
- }
- //Проверяем геометрию
- Plane plane;
- plane.N = (vrt[1] - vrt[0]) ^ (vrt[2] - vrt[0]);
- if(plane.N.Normalize() > 1e-20f)
- {
- plane.Move(vrt[0]);
- //Проверим дистанцию до плоскости
- float dist = plane.Dist(detector.pos);
- if(fabsf(dist) > detector.r)
- {
- return false;
- }
- //Найдём круг на плоскости
- Vector center = detector.pos - plane.N*dist;
- float r = sqrtf(detector.r*detector.r - dist*dist);
- //Проверим на пересечение круг и четырёхугольник
- Plane pln;
- for(long n = 0; n < 4; n++)
- {
- //Строим плоскость, ортоганальную плоскости четырёхугольника и прохлдящую через грань
- Vector v = vrt[n] - vrt[n - 1 >= 0 ? n - 1 : 3];
- if(v.Normalize() < 1e-20) continue;
- pln.N = v ^ plane.N;
- pln.Move(vrt[n]);
- //Проверяем дистанцию до центра круга
- float d = pln.Dist(center);
- if(d > r) break;
- }
- if(n < 4) return false;
- }else{
- //Это точка или линия
- if(~(vrt[1] - vrt[0]) > 0.0f)
- {
- if(!detector.Intersection(vrt[0], vrt[1]))
- {
- return false;
- }
- }else
- if(~(vrt[2] - vrt[1]) > 0.0f)
- {
- if(!detector.Intersection(vrt[1], vrt[2]))
- {
- return false;
- }
- }else{
- if(!detector.Intersection(vrt[0]))
- {
- return false;
- }
- }
- }
- //Поподание
- return HitProcess(source, obj, hp);
- }
- //Логическая проверка на возможность аттаки
- inline bool DamageDetector::IsCanAttack(MissionObject * obj, dword source, float & hp)
- {
- //Отсекаем воздействие по цели
- if(targetID.NotEmpty())
- {
- if(target.Ptr() != obj)
- {
- return false;
- }
- }
- if(source != ds_check)
- {
- //Отсекаем по источнику демеджа
- hp *= multipliers.Multiplier(source);
- if(fabsf(hp) < 1e-10f)
- {
- return false;
- }
- }else{
- return true;
- }
- //Если режим без коллижена то делаемся имунными на время
- if(!collide)
- {
- //Смотрим список иммуна
- for(dword i = 0; i < immuneCount; i++)
- {
- if(immune[i].obj == obj)
- {
- return false;
- }
- }
- }
- return true;
- }
- //Отработка попадания
- bool DamageDetector::HitProcess(dword source, MissionObject * obj, float hp)
- {
- if(source != ds_check)
- {
- SetImmune(obj);
- ApplyDamage(hp);
- return (collide != 0);
- }
- return true;
- }
- //Сделать объект имунным
- inline void DamageDetector::SetImmune(MissionObject * obj)
- {
- if(collide)
- {
- return;
- }
- if(immuneCount >= ARRSIZE(immune))
- {
- const dword last = - 1;
- for(dword i = 1; i < ARRSIZE(immune); i++)
- {
- immune[i - 1] = immune[i];
- }
- immuneCount--;
- }
- immune[immuneCount].obj = obj;
- immune[immuneCount].time = immuneTime;
- immuneCount++;
- immuneTimerWorkTime = 5.0f;
- if(!immuneTimerIsActive)
- {
- immuneTimerIsActive = true;
- SetUpdate(&DamageDetector::ImmuneTimer, ML_ALPHA5);
- }
- }
- //Таймер невосприимчевости
- void _cdecl DamageDetector::ImmuneTimer(float dltTime, long level)
- {
- for(dword i = 0; i < immuneCount; i++)
- {
- immune[i].time -= dltTime;
- if(immune[i].time <= 0.0f)
- {
- for(dword j = i + 1; j < immuneCount; j++)
- {
- immune[j - 1] = immune[j];
- }
- immuneCount--;
- }
- }
- if(!immuneCount && immuneTimerWorkTime < 0.0f)
- {
- DelUpdate(&DamageDetector::ImmuneTimer);
- immuneTimerIsActive = false;
- }else{
- immuneTimerWorkTime -= dltTime;
- }
- }
- //============================================================================================
- void DamageDetector::Command(const char * id, dword numParams, const char ** params)
- {
- if(string::IsEqual(id, "reset"))
- {
- Reset();
- LogicDebug("Command <reset> HP now is %f", HP);
- }
- }
- //Работа детектора в режиме редактирования
- void _cdecl DamageDetector::EditModeWork(float dltTime, long level)
- {
- if(!Mission().EditMode_IsAdditionalDraw()) return;
- if(!EditMode_IsVisible()) return;
- //Обновляем состояние
- dword clr;
- UpdateTarget();
- if(!target.Validate())
- {
- FindObject(targetID, target);
- }
- if(target.Validate())
- {
- if(IsActive())
- {
- clr = 0xff00ffcc;
- }else{
- clr = 0xcccccc80;
- }
- }else{
- clr = 0xffff508c;
- }
- //Рисуем
- Render().DrawSphere(detector.pos, detector.r, clr, "ShowDetector");
- if(EditMode_IsSelect())
- {
- Render().Print(detector.pos, -1.0f, -1.0f, 0xffffffff, "Object id: %s", GetObjectID().c_str());
- Render().Print(detector.pos, -1.0f, 0.0f, 0xffffffff, "Target: %s", targetID.c_str());
- Render().Print(detector.pos, -1.0f, 1.0f, 0xffffffff, IsActive() ? "State: on" : "State: off");
- }
- }
- //============================================================================================
- //Параметры инициализации
- //============================================================================================
- MOP_BEGINLISTCG(DamageDetector, "Damage detector", '1.00', 0x0fffffff, "Damage detector triggering when mission object attack it.", "Logic")
- MOP_STRINGC("Object id", "Player", "Is set object, then apply damage only from this object")
- MOP_POSITIONC("Position", Vector(0.0f), "Detector sphere position")
- MOP_FLOATEXC("Radius", 0.7f, 0.0001f, 1000000.0f, "Detector sphere radius")
- MOP_FLOATEXC("HP", 1.0f, 0.0001f, 1000000.0f, "Hit points of this object")
- MOP_DR_MULTIPLIERSG
- MOP_BOOLC("Active", true, "Active object in start mission time")
- MOP_BOOLC("Autoreset", true, "When trigger is done, reset it")
- MOP_BOOLC("Anytime damage", true, "Activate damage event when detector is done too")
- MOP_BOOLC("Collision", true, "Dont collide with damage source")
- MOP_FLOATEXC("Immune time", 0.2f, 0.001f, 1000000.0f, "Use in non collision mode.\nTime when detector dont take damage from attak object.")
- MOP_MISSIONTRIGGERG("Damage", "Damage.")
- MOP_MISSIONTRIGGERG("Done", "Activate.")
- MOP_ENDLIST(DamageDetector)
|