| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821 |
- #include "MissionPhysObject.h"
- #define FADEOUT_TIME 1.0f
- MissionPhysObject::MissionPhysObject() : solid(_FL_),
- broken(_FL_)
- // ,lines(_FL_)
- {
- HP = 0.0f;
- flags = f_needCalcBox | f_isShowTips;
- hideTime = 3.0f;
- chacheIndex = -1;
- visAbb.min = visAbb.max = 0.0f;
- colAbb.min = colAbb.max = 0.0f;
- aiColider = null;
- }
- MissionPhysObject::~MissionPhysObject()
- {
- Release();
- if(EditMode_IsOn() && pattern.Validate())
- {
- pattern.Ptr()->regObjects.Del(this);
- }
- if(aiColider)
- {
- aiColider->Release();
- }
- }
- //Инициализировать объект
- bool MissionPhysObject::Create(MOPReader & reader)
- {
- DamageReceiver::Create(reader);
- if(!aiColider)
- {
- aiColider = QTCreateObject(MG_AI_COLLISION, _FL_);
- }
- aiColider->Activate(false);
- ResetFlag(flags, f_isFadeProcess | f_isShock);
- ReadParameters(reader);
- brokeEvent.Init(reader);
- if(reader.Bool())
- {
- SetFlag(flags, f_drawDebugBoxes);
- }else{
- ResetFlag(flags, f_drawDebugBoxes);
- }
- if(!pattern.Validate()) return false;
- UpdatePatternData();
- FindVisibleABB(solid, visAbb);
- Show(IsShow());
- return true;
- }
- //Пересоздать объект
- void MissionPhysObject::Restart()
- {
- Activate(false);
- SetShow(false);
- DelUpdate(&MissionPhysObject::HideTimer);
- DelUpdate(&MissionPhysObject::Fader);
- Release();
- if(pattern.Validate())
- {
- pattern.Ptr()->regObjects.Del(this);
- }
- HP = 0.0f;
- flags = f_needCalcBox;
- hideTime = 3.0f;
- pattern.Reset();
- chacheIndex = -1;
- visAbb.min = visAbb.max = 0.0f;
- colAbb.min = colAbb.max = 0.0f;
- waterLevel.Reset();
- ReCreate();
- }
- //Инициализировать объект
- bool MissionPhysObject::EditMode_Create(MOPReader & reader)
- {
- SetUpdate(&MissionPhysObject::EditMode_Draw, ML_GEOMETRY2);
- return EditMode_Update(reader);
- }
- //Обновить параметры
- bool MissionPhysObject::EditMode_Update(MOPReader & reader)
- {
- //Удаляем всё
- Release();
- pattern.Reset();
- //Читаем и заводим заново
- ReadParameters(reader);
- UpdatePatternPointer();
- UpdatePatternData();
- return true;
- }
- //Получить размеры описывающего ящика
- void MissionPhysObject::EditMode_GetSelectBox(Vector & min, Vector & max)
- {
- ABB abb; abb.min = abb.max = 0.0f;
- bool isAdd = false;
- for(long i = 0; i < solid; i++)
- {
- Part & part = solid[i];
- if(part.model)
- {
- const GMXBoundBox & bbx = part.model->GetBound();
- if(isAdd)
- {
- min.Min(min, bbx.vMin);
- max.Min(max, bbx.vMax);
- }else{
- min = bbx.vMin;
- max = bbx.vMax;
- isAdd = true;
- }
- /*
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- const GMXBoundBox & bbx = part.model->GetLocalBound();
- Box::FindABBforOBB(po.mtx, bbx.vMin, bbx.vMax, abb.min, abb.max, isAdd);
- isAdd = true;
- */
- }
- }
- /*
- min = abb.min;
- max = abb.max;
- */
- }
- //Получить бокс, описывающий объект в локальных координатах
- void MissionPhysObject::GetBox(Vector & min, Vector & max)
- {
- min = visAbb.min;
- max = visAbb.max;
- }
- //Показать/скрыть объект
- void MissionPhysObject::Show(bool isShow)
- {
- if(EditMode_IsOn())
- {
- MissionObject::Show(isShow);
- return;
- }
- MissionObject::Show(isShow);
- SetShow(isShow);
- LogicDebug(isShow ? "Show" : "Hide");
- Activate(IsActive());
- ShowTips();
- }
- //Устоновить состояние подписки
- void MissionPhysObject::SetShow(bool isShow)
- {
- if(!pattern.Validate()) return;
- if(isShow)
- {
- DelUpdate(&MissionPhysObject::Draw);
- SetUpdate(&MissionPhysObject::Draw, pattern.Ptr()->level);
- if(CheckFlag(flags, f_isFadeProcess | f_isCheckLod))
- {
- SetUpdate(&MissionPhysObject::Draw, pattern.Ptr()->level + (ML_ALPHA1 + 1) - ML_GEOMETRY1);
- }
- if(pattern.Ptr()->shadowCast)
- {
- Registry(MG_SHADOWCAST, (MOF_EVENT)&MissionPhysObject::ShadowInfo, pattern.Ptr()->level);
- }else{
- Unregistry(MG_SHADOWCAST);
- }
- if(pattern.Ptr()->shadowReceive)
- {
- Unregistry(MG_SHADOWDONTRECEIVE);
- Registry(MG_SHADOWRECEIVE, (MOF_EVENT)&MissionPhysObject::ShadowDraw, pattern.Ptr()->level);
- }else{
- Registry(MG_SHADOWDONTRECEIVE, (MOF_EVENT)&MissionPhysObject::ShadowDraw, pattern.Ptr()->level);
- Unregistry(MG_SHADOWRECEIVE);
- }
- if(pattern.Ptr()->seaReflection)
- {
- Registry(MG_SEAREFLECTION, (MOF_EVENT)&MissionPhysObject::SeaReflection, pattern.Ptr()->level);
- }else{
- Unregistry(MG_SEAREFLECTION);
- }
- }else{
- DelUpdate(&MissionPhysObject::Draw);
- Unregistry(MG_SHADOWCAST);
- Unregistry(MG_SHADOWRECEIVE);
- Unregistry(MG_SEAREFLECTION);
- Unregistry(MG_SHADOWDONTRECEIVE);
- }
- }
- //Обновить состояние типсов
- void MissionPhysObject::ShowTips()
- {
- bool currentShow = IsShow() && CheckFlag(flags, f_isShowTips);
- SetTipsState(solid, currentShow && !CheckFlag(flags, f_isBroken));
- SetTipsState(broken, currentShow && CheckFlag(flags, f_isBroken));
- }
- //Установить состояние подсказки
- void MissionPhysObject::SetTipsState(array<Part> & obj, bool isActive)
- {
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- if(part.tip)
- {
- if(isActive)
- {
- part.tip->Activate(true);
- }else{
- part.tip->Activate(false);
- }
-
- }
- }
- }
- //Активировать/деактивировать объект
- void MissionPhysObject::Activate(bool isActive)
- {
- if(EditMode_IsOn())
- {
- MissionObject::Activate(isActive);
- return;
- }
- MissionObject::Activate(isActive);
- if(!IsShow())
- {
- isActive = false;
- }
- finder->Activate(isActive);
- if(isActive && !CheckFlag(flags, f_isBroken) && (solid > 0) && pattern.Validate() && !EditMode_IsOn())
- {
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[solid[0].descIndex];
- aiColider->SetBox(po.min, po.max);
- aiColider->SetMatrix(solid[0].mtx);
- aiColider->Activate(true);
- }else{
- aiColider->Activate(false);
- }
-
- if(isActive)
- {
- SetUpdate(&MissionPhysObject::Update, ML_EXECUTE1);
- ApplyDamage(0.0f, dt_unknown);
- if(!CheckFlag(flags, f_isBroken))
- {
- MakePhysics(solid);
- }else{
- MakePhysics(broken);
- if(!CheckFlag(flags, f_isFadeProcess))
- {
- SetUpdate(&MissionPhysObject::HideTimer, ML_EXECUTE1);
- }else{
- if(!CheckFlag(flags, f_isDead))
- {
- SetUpdate(&MissionPhysObject::Fader, ML_EXECUTE1);
- }else{
- hideTime = 1.0f;
- Fader(0.0f, 0);
- }
- }
- }
- LogicDebug("Activate");
- }else{
- DelUpdate(&MissionPhysObject::Update);
- DelUpdate(&MissionPhysObject::HideTimer);
- DelUpdate(&MissionPhysObject::Fader);
- ReleasePhysics(solid);
- ReleasePhysics(broken);
- LogicDebug("Deactivate");
- }
- }
- //Получить матрицу объекта
- Matrix & MissionPhysObject::GetMatrix(Matrix & mtx)
- {
- return mtx.SetIdentity();
- }
- //Обработчик команд для объекта
- void MissionPhysObject::Command(const char * id, dword numParams, const char ** params)
- {
- if(string::IsEqual(id, "broke"))
- {
- if(!CheckFlag(flags, f_isBroken))
- {
- Broke();
- if(numParams >= 2)
- {
- MOSafePointer mo;
- if(FindObject(ConstString(params[0]), mo))
- {
- Matrix mtx;
- mo.SPtr()->GetMatrix(mtx);
- char * endPtr = null;
- float forceMin = (float)strtod(params[1], &endPtr);
- float forceMax = forceMin*1.2f;
- if(numParams >= 3)
- {
- forceMax = (float)strtod(params[2], &endPtr);;
- }
- for(long i = 0; i < broken; i++)
- {
- Part & part = broken[i];
- Vector dir = part.mtx.pos - mtx.pos;
- dir.Normalize();
- Vector vforce(RRnd(forceMin, forceMax), RRnd(forceMin, forceMax), RRnd(forceMin, forceMax));
- part.impDir += dir*vforce;
- part.count++;
- }
- LogicDebug("Command: broke, take force [%f, %f] from object %s", forceMin, forceMax, params[0]);
- }else{
- LogicDebugError("Command: broke, object %s not found", params[0]);
- }
- }else{
- LogicDebug("Command: broke, without parameters");
- }
- ApplyImpulses(dt_unknown);
- }
- }else
- if(string::IsEqual(id, "shock"))
- {
- if(numParams >= 3)
- {
- char * endPtr = null;
- float time = (float)strtod(params[0], &endPtr);
- float force = (float)strtod(params[1], &endPtr);
- float period = (float)strtod(params[1], &endPtr);
- shockTime = Clampf(time, 0.0f, 10.0f);
- shockForce = Clampf(force, 0.0f, 100.0f);
- shockWaitTimeMid = Clampf(period, 0.0f, 10.0f);
- LogicDebug("Command: shock (set:%f, def:%f) (set:%f, def:%f) (set:%f, def:%f)", shockTime, time, shockForce, force, shockWaitTimeMid, period);
- if(shockTime > 1e-5f)
- {
- kShockTime = 1.0f/shockTime;
- }else{
- kShockTime = 0.0f;
- }
- shockTime = 0.0f;
- shockWaitTime = 0.0f;
- SetFlag(flags, f_isShock);
- }else{
- LogicDebugError("Command: shock, not enough parameters: shock 1:time 2:force");
- }
- }else
- if(string::IsEqual(id, "hackhideon"))
- {
- LogicDebug("Command: hackhideon !!!");
- SetFlag(flags, f_hackHide);
- }else
- if(string::IsEqual(id, "hackhideoff"))
- {
- LogicDebug("Command: hackhideoff");
- ResetFlag(flags, f_hackHide);
- }else{
- LogicDebugError("Unknown command: %s", id);
- }
- }
- //Обновление позиций
- void _cdecl MissionPhysObject::Update(float dltTime, long level)
- {
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- if(CheckFlag(flags, f_isShock) && dltTime > 0.0f)
- {
- if(shockWaitTime <= 1e-10f)
- {
- float force = shockForce*RRnd(1.0f - shockTime, 1.0f);
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(part.physObject)
- {
- part.physObject->ApplyImpulse(Vector(0.0f, force, 0.0f), Vector(0.0f));
- }
- }
- shockWaitTime = shockWaitTimeMid*RRnd(0.8f, 1.2f);
- }else{
- shockWaitTime -= dltTime;
- }
- shockTime -= dltTime;
- if(shockTime <= 0.0f)
- {
- ResetFlag(flags, f_isShock);
- }
- }
- float wlevel = IWaterLevel::GetWaterLevel(Mission(), waterLevel);
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(part.sndMatMask)
- {
- part.sndCooldown -= dltTime;
- if(part.sndCooldown <= 0.0f)
- {
- part.sndMatMask = 0;
- }
- }
- if(part.physObject)
- {
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- const Vector & com = po.centerOfMass;
- Vector curPos = part.mtx*com;
- part.physObject->GetTransform(part.mtx);
- if(part.model)
- {
- part.model->SetTransform(part.mtx);
- long mtlId = (long)part.physObject->GetContactReport();
- if(mtlId > pmtlid_air && mtlId <= pmtlid_fabrics)
- {
- //Попали в звучащий материал
- dword mask = 1 << mtlId;
- if((part.sndMatMask & mask) == 0)
- {
- part.sndCooldown = 0.8f;
- part.sndMatMask |= mask;
- Vector pos = part.physObject->GetContactPoint();
- float force = part.physObject->GetContactForce().GetLength2();
- pattern.Ptr()->PlayCollisionEffect(mtlId, pos, force);
- }
- }
- }
- if(part.tip)
- {
- part.tip->SetPos(part.mtx*po.tipPosition);
- }
- Vector newPos = part.mtx*com;
- if(newPos.y <= wlevel && curPos.y > wlevel)
- {
- WaterDrop(part, curPos, newPos, wlevel);
- }
- if(part.mtx.pos.y < -800.0f)
- {
- if(part.physObject)
- {
- part.physObject->Release();
- part.physObject = null;
- }
- if(part.model)
- {
- part.model->Release();
- part.model = null;
- }
- ResetFlag(part.flags, f_part_isCollision);
- }
- }
- }
- FindCollidersABB(parts, colAbb);
- finder->SetBox(colAbb.min, colAbb.max);
- FindVisibleABB(parts, visAbb);
- if(!CheckFlag(flags, f_isBroken) && solid > 0)
- {
- aiColider->SetMatrix(solid[0].mtx);
- }
- }
- //Отиграть эффект падения в воду
- void MissionPhysObject::WaterDrop(Part & part, Vector & pos1, Vector & pos2, float level)
- {
- const ConstString & prtName = pattern.Ptr()->objects[part.descIndex].waterParticle;
- const ConstString & sndName = pattern.Ptr()->objects[part.descIndex].waterSound;
- float k = (pos1.y - pos2.y);
- if(k > 0.0f)
- {
- k = (level - pos2.y)/k;
- }else{
- k = 0.0f;
- }
- Matrix mtx(0.0f, Rnd(2.0f*PI), 0.0f, pos2.x + (pos1.x - pos2.x)*k, level, pos2.z + (pos1.z - pos2.z)*k);
- if(prtName.NotEmpty())
- {
- Particles().CreateParticleSystemEx2(prtName.c_str(), mtx, true, _FL_);
- }
- if(sndName.NotEmpty())
- {
- Sound().Create3D(sndName, mtx.pos, _FL_);
- }
- }
- //Нарисовать модельку
- void _cdecl MissionPhysObject::Draw(float dltTime, long level)
- {
- Assert(pattern.Validate());
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- bool haveSomeModels = false;
- Vector cam = Render().GetView().GetCamPos();
- Color userColor(0.0f, 0.0f, 0.0f, 1.0f);
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(part.model)
- {
- haveSomeModels = true;
- if(level == pattern.Ptr()->level)
- {
- if(CheckFlag(flags, f_isCheckLod))
- {
- const GMXBoundBox & gbb = part.model->GetBound();
- Vector center = (gbb.vMin + gbb.vMax)*0.5f;
- float k = (center - cam).GetAttenuation2(pattern.Ptr()->hideDistanceMin2, pattern.Ptr()->hideDistanceK2);
- if(k < 1.0f)
- {
- k *= part.alpha;
- if(k < 1e-5f)
- {
- continue;
- }
- userColor.a = k;
- part.model->SetUserColor(userColor);
- }else{
- userColor.a = part.alpha;
- part.model->SetUserColor(userColor);
- }
- }
- if(part.model->GetUserColor().a > 0.9999f)
- {
- if(!CheckFlag(flags, f_hackHide))
- {
- part.model->Draw();
- }
- ResetFlag(part.flags, f_part_isDrawInAlphaLevel);
- }else{
- SetFlag(part.flags, f_part_isDrawInAlphaLevel);
- }
- }else{
- if(CheckFlag(part.flags, f_part_isDrawInAlphaLevel))
- {
- if(!CheckFlag(flags, f_hackHide))
- {
- part.model->Draw();
- }
- }
- }
- }
- }
- if(level == pattern.Ptr()->level)
- {
- if(CheckFlag(flags, f_drawDebugBoxes))
- {
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Matrix mtx(box.mtx, part.mtx);
- Render().DrawBox(-box.size05, box.size05, mtx);
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Matrix mtx(cap.mtx, part.mtx);
- Render().DrawBox(-cap.size05, cap.size05, mtx);
- }
- }
- }
- if(!haveSomeModels && !CheckFlag(flags, f_drawDebugBoxes))
- {
- SetShow(false);
- }
- }
- /*
- // Render().DrawBox(visAbb.min, visAbb.max);
- Render().DrawBox(colAbb.min, colAbb.max);
- static Vector poly[4] =
- {
- Vector(-1.0f, 0.0f, 0.5f),
- Vector(1.2f, 0.0f, 1.0f),
- Vector(0.7f, 0.0f, -1.0f),
- Vector(-1.0f, 0.0f, -1.0f)
- };
- static Vector p[4];
- static float cnt = 0.0f;
- cnt += dltTime;
- //#define CAMERA
- #ifndef CAMERA
- if(api->DebugKeyState(VK_SPACE)) cnt = 0.0f;
- if(cnt > 0.5f)
- {
- cnt = 0.0f;
- Matrix mtx(Vector().Rand(Vector(-PI), Vector(PI)), Vector().Rand(Vector(-4.0f), Vector(4.0f)));
- #else
- if(api->DebugKeyState(VK_SPACE))
- {
- Matrix mtx = Render().GetView();
- mtx.Inverse();
- #endif
- for(long i = 0; i < 4; i++)
- {
- p[i] = poly[i]*mtx;
- }
- }
- Vector size05(1.0f, 0.6f, 0.4f);
-
- bool bs = OverlapsBoxSphere(Matrix(), size05, p[0], 1.0f);
- bool bl = OverlapsBoxLine(Matrix(), size05, p[0], p[1]);
- bool bp = OverlapsBoxPoly(Matrix(), size05, p);
-
- //Render().DrawSphere(p[0], 1.0f, bs ? 0xffff0000 : 0xff0000ff);
- Render().DrawLine(p[0], bl ? 0xffff0000 : 0xff0000ff, p[1], bl ? 0xffff0000 : 0xff0000ff);
- // Render().DrawPolygon(p, 4, bp ? 0xffff0000 : 0xff0000ff);
- Render().DrawBox(-size05, size05);
- //*/
- /* Render().FlushBufferedLines();
- for(dword i = 0; i < lines.Size(); i++)
- {
- DLine & dl = lines[i];
- //Render().DrawBufferedLine(dl.from, dl.cf, dl.to, dl.ct);
- Render().DrawLine(dl.from, dl.cf, dl.to, dl.ct);
- }
- Render().FlushBufferedLines();
- */
- // Render().DrawBox(aiColider.GetBoxCenter() - aiColider.GetBoxSize05(), aiColider.GetBoxCenter() + aiColider.GetBoxSize05(), aiColider.GetMatrix());
- }
- //Нарисовать модельку
- void _cdecl MissionPhysObject::EditMode_Draw(float dltTime, long level)
- {
- /*
- Vector vmin, vmax;
- EditMode_GetSelectBox(vmin, vmax);
- Render().DrawBox(vmin, vmax, Matrix(), 0xffff0000);
- */
- if(!EditMode_IsVisible())
- {
- return;
- }
- if(!IsShow())
- {
- return;
- }
- if(!pattern.Validate())
- {
- UpdatePatternPointer();
- if(!pattern.Validate())
- {
- return;
- }
- UpdatePatternData();
- }
- for(long i = 0; i < solid; i++)
- {
- if(solid[i].model)
- {
- solid[i].model->Draw();
- }
- }
- }
- //Нарисовать модельку для тени
- void _cdecl MissionPhysObject::ShadowInfo(const char * group, MissionObject * sender)
- {
- if(CheckFlag(flags, f_hackHide))
- {
- return;
- }
- ((MissionShadowCaster *)sender)->AddObject(this, &MissionPhysObject::ShadowDraw, visAbb.min, visAbb.max);
- }
- //Нарисовать модельку для тени
- void _cdecl MissionPhysObject::ShadowDraw(const char * group, MissionObject * sender)
- {
- if(CheckFlag(flags, f_hackHide))
- {
- return;
- }
- Assert(pattern.Validate());
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(part.model)
- {
- part.model->Draw();
- }
- }
- }
- //Нарисовать отражёную модельку
- void _cdecl MissionPhysObject::SeaReflection(const char * group, MissionObject * sender)
- {
- ShadowDraw(null, null);
- }
- //Отсчёт исчезновения
- void _cdecl MissionPhysObject::HideTimer(float dltTime, long level)
- {
- brokeEvent.Activate(Mission());
- hideTime -= dltTime;
- if(hideTime > 0.0f) return;
- hideTime = 0.0f;
- DelUpdate(&MissionPhysObject::HideTimer);
- SetUpdate(&MissionPhysObject::Fader, ML_EXECUTE1);
- SetFlag(flags, f_isFadeProcess);
- LogicDebug("Start fade process");
- SetShow(IsShow());
- }
- //Процесс исчезновения, или другого окончания объекта
- void _cdecl MissionPhysObject::Fader(float dltTime, long level)
- {
- hideTime += dltTime*(1.0f/FADEOUT_TIME);
- if(hideTime > 1.0f)
- {
- SetFlag(flags, f_isDead);
- hideTime = 1.0f;
- DelUpdate(&MissionPhysObject::Fader);
- }
- bool isSomeVisible = false;
- Color userColor(0.0f, 0.0f, 0.0f, 1.0f - hideTime);
- for(long i = 0; i < broken; i++)
- {
- Part & part = broken[i];
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- if(po.fe == MissionPhysObjPattern::fe_hide)
- {
- if(!CheckFlag(flags, f_isDead))
- {
- if(part.model)
- {
- part.model->SetUserColor(userColor);
- part.alpha = userColor.a;
- isSomeVisible = true;
- }
- }else{
- LogicDebug("Object's part %i is faded", i);
- if(part.model)
- {
- part.model->Release();
- part.model = null;
- }
- if(part.physObject)
- {
- part.physObject->Release();
- part.physObject = null;
- }
- ResetFlag(part.flags, f_part_isCollision);
- }
- }else
- if(po.fe == MissionPhysObjPattern::fe_static)
- {
- isSomeVisible = true;
- if(CheckFlag(flags, f_isDead))
- {
- LogicDebug("Object's part %i is modify to static", i);
- if(part.physObject)
- {
- part.physObject->Release();
- part.physObject = null;
- }
- }
- }else{
- isSomeVisible = true;
- }
- }
- if(!isSomeVisible)
- {
- LogicDebug("No more visible parts, object off");
- Show(false);
- }
- }
- //Воздействовать на объект сферой
- bool MissionPhysObject::Attack(MissionObject * obj, dword source, float hp, const Vector & center, float radius)
- {
- if(!pattern.Validate()) return false;
- if(!IsActive()) return false;
- DamageType dtype = DetectType(source);
- if(dtype == dt_pickup)
- {
- if(!pattern.Ptr()->isPickup || CheckFlag(flags, f_isBroken) || solid > 1)
- {
- return false;
- }
- }
- hp = ModifyHp(dtype, hp);
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- bool isHit = false;
- float dmg = 0.0f;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- part.impPos = 0.0f;
- part.impDir = 0.0f;
- part.count = 0;
- part.effectsPos = 0.0f;
- part.effectsCount = 0;
- if(!CheckFlag(part.flags, f_part_isCollision))
- {
- continue;
- }
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- bool isApplyDmg = false;
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Matrix mtx(box.mtx, part.mtx);
- if(Box::OverlapsBoxSphere(mtx, box.size05, center, radius))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, center, radius, hp, dtype);
- }
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Matrix mtx(cap.mtx, part.mtx);
- if(Box::OverlapsBoxSphere(mtx, cap.size05, center, radius))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, center, radius, hp, dtype);
- }
- }
- if(isApplyDmg)
- {
- dmg += hp;
- isHit = true;
- }
- }
- ApplyDamage(dmg, dtype);
- ApplyImpulses(dtype);
- return isHit;
- }
- __forceinline void MissionPhysObject::ApplyImpulse(Part & p, const Matrix & boxTransform, const Vector & spherePos, float sphereRadius, float hp, DamageType dtype)
- {
- //Вычисляем направление импульса
- Vector dir = boxTransform.pos - spherePos;
- float dist = dir.Normalize();
- if(dist < 0.01f)
- {
- dir.Rand();
- }
- //Слегка подбросим вверх
- dir.y += RRnd(0.1f, 0.2f);
- dir.Normalize();
- //Считаем коэфициент затухания в зависимости от удалённости от центра
- float k;
- if(sphereRadius > 1e-10f)
- {
- k = 1.0f - Clampf(dist/sphereRadius);
- k = powf(k, 0.3f);
- }else{
- k = 0.0f;
- }
- //Прикладываем импульс к части
- ApplyImpulseResult(p, boxTransform.MulVertexByInverse(spherePos), dir, k, hp, dtype, spherePos);
- }
- //Воздействовать на объект линией
- bool MissionPhysObject::Attack(MissionObject * obj, dword source, float hp, const Vector & from, const Vector & to)
- {
- // lines.Add(DLine(from, 0xff00ffff, to, 0xff0000ff));
- if(!pattern.Validate()) return false;
- if(!IsActive()) return false;
- DamageType dtype = DetectType(source);
- hp = ModifyHp(dtype, hp);
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- bool isHit = false;
- float dmg = 0.0f;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- part.impPos = 0.0f;
- part.impDir = 0.0f;
- part.count = 0;
- part.effectsPos = 0.0f;
- part.effectsCount = 0;
- if(!CheckFlag(part.flags, f_part_isCollision))
- {
- continue;
- }
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- bool isApplyDmg = false;
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Matrix mtx(box.mtx, part.mtx);
- if(Box::OverlapsBoxLine(mtx, box.size05, from, to))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, from, to , hp, dtype);
- }
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Matrix mtx(cap.mtx, part.mtx);
- if(Box::OverlapsBoxLine(mtx, cap.size05, from, to))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, from, to , hp, dtype);
- }
- }
- if(isApplyDmg)
- {
- dmg += hp;
- isHit = true;
- }
- }
- ApplyDamage(dmg, dtype);
- ApplyImpulses(dtype);
- return isHit;
- }
- void MissionPhysObject::ApplyImpulse(Part & p, const Matrix & boxTransform, const Vector & from, const Vector & to, float hp, DamageType dtype)
- {
- if(dtype == dt_sword)
- {
- Vector middle = (from + to)*0.5f;
- Vector dir = boxTransform.pos - middle;
- float dist = dir.Normalize();
- float k;
- if(dist < 1e-10f)
- {
- dir.Rand();
- k = 1.0f;
- }else{
- k = 1.0f/(1.0f + dist);
- }
- ApplyImpulseResult(p, boxTransform.MulVertexByInverse(middle), dir, k, hp, dtype, middle);
- return;
- }
- Vector dir = to - from;
- float distDir = dir.Normalize();
- ApplyImpulseResult(p, boxTransform.MulVertexByInverse(from), dir, 1.0f, hp, dtype, from);
- }
- //Воздействовать на объект выпуклым чехырёхугольником
- bool MissionPhysObject::Attack(MissionObject * obj, dword source, float hp, const Vector vrt[4])
- {
- if(!pattern.Validate()) return false;
- if(!IsActive()) return false;
- DamageType dtype = DetectType(source);
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- bool isHit = false;
- float dmg = 0.0f;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- part.impPos = 0.0f;
- part.impDir = 0.0f;
- part.count = 0;
- part.effectsPos = 0.0f;
- part.effectsCount = 0;
- if(!CheckFlag(part.flags, f_part_isCollision))
- {
- continue;
- }
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- bool isApplyDmg = false;
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Matrix mtx(box.mtx, part.mtx);
- if(Box::OverlapsBoxPoly(mtx, box.size05, vrt))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, vrt, hp, dtype);
- }
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Matrix mtx(cap.mtx, part.mtx);
- if(Box::OverlapsBoxPoly(mtx, cap.size05, vrt))
- {
- isApplyDmg = true;
- ApplyImpulse(part, mtx, vrt, hp, dtype);
- }
- }
- if(isApplyDmg)
- {
- dmg += ModifyHp(dtype, hp);
- isHit = true;
- }
- }
- ApplyDamage(dmg, dtype);
- ApplyImpulses(dtype);
- return isHit;
- }
- __forceinline void MissionPhysObject::ApplyImpulse(Part & p, const Matrix & boxTransform, const Vector vrt[4], float hp, DamageType dtype)
- {
- //Направление силы в направлении тьраектории движения
- Vector dir = vrt[1] - vrt[2] + vrt[0] - vrt[3];
- dir.Normalize();
- //Позиция определяется серединой оружия на передней кромке
- Vector pos = (vrt[0] + vrt[1])*0.5f;
- //На силу влияет только наносимые повреждения
- ApplyImpulseResult(p, boxTransform.MulVertexByInverse(pos), dir, 1.0f, hp, dtype, pos);
- }
- //Применить импульс к части зная параметры импульса
- __forceinline void MissionPhysObject::ApplyImpulseResult(Part & p, const Vector & impulsePos, const Vector & impulseDir, float kAttenuation, float hp, DamageType dtype, const Vector & effectsPos)
- {
- //Добавляем эффект
- p.effectsPos += effectsPos;
- p.effectsCount++;
- //Модификатор импульса в зависимости от источника демеджа
- /*
- if(hp <= 1e-10f || kAttenuation <= 1e-10f)
- {
- return;
- }*/
- float force = 1.0f;
- switch(dtype)
- {
- case dt_sword:
- force = 1.0f;
- break;
- case dt_bomb:
- //force = 6.0f;
- force = 0.1f*Clampf(fabsf(hp)*RRnd(0.9f, 1.1f), 1.0f, 500.0f);
- break;
- case dt_bullet:
- force = 5.0f;
- break;
- case dt_cannon:
- //force = 6.0f;
- force = 0.1f*Clampf(fabsf(hp)*RRnd(0.9f, 1.1f), 1.0f, 500.0f);
- break;
- case dt_flame:
- force = 1.0f;
- break;
- case dt_shooter:
- force = 6.0f;
- break;
- case dt_unknown:
- force = 1.0f;
- break;
- case dt_pickup:
- force = 0.0f;
- break;
- default:
- force = 0.0f;
- }
- /* //Вычислим силу в зависимости от наносимого повреждения
- force = Clampf(fabsf(hp)*RRnd(0.9f, 1.1f), 1.0f, 500.0f);
- //Добавляем импульс к объекту
- p.impPos += impulsePos;
- p.impDir += impulseDir*(force*modifier*kAttenuation); //Уберём ослабление
- */
-
- //Вычислим силу в зависимости от наносимого повреждения
- p.impPos += impulsePos;
- if (dtype == dt_bullet)
- {
- Vector dir;
- dir.Rand(0.0f,1.0f);
- dir.y = fabs(dir.y);
- p.impDir += dir*(force*RRnd(0.9f, 1.1f));
- }
- else
- {
- p.impDir += impulseDir*(force*RRnd(0.9f, 1.1f));
- }
- p.count++;
- // lines.Add(DLine(p.effectsPos, 0xff00ffff, p.effectsPos + impulseDir, 0xffff00ff));
- }
- //Применить импульсы
- __forceinline void MissionPhysObject::ApplyImpulses(DamageType type)
- {
- if(type == dt_check)
- {
- return;
- }
- array<Part> & parts = CheckFlag(flags, f_isBroken) ? broken : solid;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(part.count && part.physObject)
- {
- float kNorm = 1.0f/float(part.count);
- //Усредняем позицию и импульс по количеству приложенных
- part.impPos *= kNorm;
- part.impDir *= kNorm;
- //Ограничиваем приложенный импульс предельным значением
- float impulseScalar = part.impDir.Normalize();
- static const float velocityMax = 100.0f; // m/s
- const float impulseMax = velocityMax;
- if(impulseScalar > impulseMax)
- {
- impulseScalar = impulseMax;
- }
- if(type != dt_unknown)
- {
- float mass = part.physObject->GetMass();
- part.impDir *= impulseScalar/Clampf(mass, 0.5f, 10.0f);
- }else{
- part.impDir *= impulseScalar;
- }
- //Прикладываем полученный сумарный импульс к физическому объекту
- part.physObject->ApplyImpulse(part.impDir, part.impPos);
- }
- //Проигрываем спецэффект в точки приложения импульса
- if(part.effectsCount)
- {
- ConstString particlesName;
- ConstString soundName;
- switch(type)
- {
- case dt_sword:
- particlesName = pattern.Ptr()->hitSword.particles;
- soundName = pattern.Ptr()->hitSword.sound;
- break;
- case dt_bomb:
- particlesName = pattern.Ptr()->hitBomb.particles;
- soundName = pattern.Ptr()->hitBomb.sound;
- break;
- case dt_bullet:
- particlesName = pattern.Ptr()->hitBullet.particles;
- soundName = pattern.Ptr()->hitBullet.sound;
- break;
- case dt_cannon:
- particlesName = pattern.Ptr()->hitCannon.particles;
- soundName = pattern.Ptr()->hitCannon.sound;
- break;
- case dt_flame:
- particlesName = pattern.Ptr()->hitFlame.particles;
- soundName = pattern.Ptr()->hitFlame.sound;
- break;
- case dt_shooter:
- particlesName = pattern.Ptr()->hitShooter.particles;
- soundName = pattern.Ptr()->hitShooter.sound;
- break;
- }
- part.effectsPos *= 1.0f/part.effectsCount;
- // lines.Add(DLine(part.effectsPos, 0xffffffff, part.effectsPos - part.impDir, 0xffff0000));
- if(particlesName.NotEmpty())
- {
- Matrix mtx;
- if(!mtx.BuildOrient(-part.impDir, Vector(0.0f, 1.0f, 0.0f)))
- {
- mtx.SetIdentity();
- }
- mtx.pos = part.effectsPos;
- Particles().CreateParticleSystemEx2(particlesName.c_str(), mtx, true, _FL_);
- }
- if(soundName.NotEmpty())
- {
- Sound().Create3D(soundName, part.effectsPos, _FL_);
- }
- }
- part.impPos = 0.0f;
- part.impDir = 0.0f;
- part.effectsPos = 0.0f;
- part.count = 0;
- }
- }
- //Умирает
- bool MissionPhysObject::IsDie()
- {
- return HP <= 0.0f;
- }
- //Мёртв
- bool MissionPhysObject::IsDead()
- {
- return CheckFlag(flags, f_isDead);
- }
- //Проверить на пересечение отрезка и ящиков описывающих объекты
- bool MissionPhysObject::OverlapLine(const Vector & v1, const Vector & v2, float skin)
- {
- array<Part> & parts = !CheckFlag(flags, f_isBroken) ? solid : broken;
- for(long i = 0; i < parts; i++)
- {
- Part & part = parts[i];
- if(!part.physObject || !CheckFlag(part.flags, f_part_isCollision))
- {
- continue;
- }
- Vector abbMin, abbMax;
- bool isAdd = false;
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Box::FindABBforOBB(box.mtx, -box.size05, box.size05, abbMin, abbMax, isAdd);
- isAdd = true;
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Box::FindABBforOBB(cap.mtx, -cap.size05, cap.size05, abbMin, abbMax, isAdd);
- isAdd = true;
- }
- if(isAdd)
- {
- Vector size05 = (abbMax - abbMin)*0.5f;
- Vector center = (abbMin + abbMax)*0.5f;
- Matrix mtx(part.mtx);
- mtx.pos = mtx*center;
- if(Box::OverlapsBoxLine(mtx, size05 + Vector(skin), v1, v2))
- {
- return true;
- }
- }
- }
- return false;
- };
- //Патерн удаляется
- void MissionPhysObject::DeletePattern()
- {
- Release();
- pattern.Reset();
- }
- //Прочитать параметры
- void MissionPhysObject::ReadParameters(MOPReader & reader)
- {
- Vector pos = reader.Position();
- Vector ang = reader.Angles();
- initMtx.Build(ang, pos);
- patternName = reader.String();
- pattern.Reset();
- MissionObject::Show(reader.Bool());
- MissionObject::Activate(reader.Bool());
- UpdatePatternPointer();
- if(reader.Bool())
- {
- reader.Float();
- if(pattern.Validate())
- {
- HP = pattern.Ptr()->hp;
- }else{
- HP = 1.0f;
- }
- }else{
- HP = reader.Float();
- }
- if(pattern.Validate())
- {
- hideTime = pattern.Ptr()->activeTime;
- }
- }
- //Получить поинтер на патерн
- void MissionPhysObject::UpdatePatternPointer()
- {
- if(patternName.IsEmpty())
- {
- pattern.Reset();
- return;
- }
- FindObject(patternName, pattern.GetSPObject());
- if(pattern.Validate())
- {
- MO_IS_IF_NOT(id_MissionPhysObjPattern, "MissionPhysObjPattern", pattern.Ptr())
- {
- pattern.Reset();
- if(!EditMode_IsOn())
- {
- LogicDebug("Incorrect physic object pattern type (object: \"%s\", type: \"%s\")", patternName.c_str(), pattern.Ptr()->GetObjectType());
- }
- }
- }else{
- if(!EditMode_IsOn())
- {
- LogicDebug("Physic object pattern \"%s\" not found", patternName.c_str());
- }
- }
- if(pattern.Validate())
- {
- if(!EditMode_IsOn())
- {
- pattern.Ptr()->CacheModels();
- }else{
- for(long i = 0; i < pattern.Ptr()->regObjects; i++)
- {
- if(pattern.Ptr()->regObjects[i] == this)
- {
- return;
- }
- }
- pattern.Ptr()->regObjects.Add(this);
- }
- }
- }
- //Перестроить данные с паттерна
- void MissionPhysObject::UpdatePatternData()
- {
- Release();
- if(!pattern.Validate()) return;
- if(pattern.Ptr()->hideDistanceMin2 > 1e-10f)
- {
- SetFlag(flags, f_isCheckLod);
- }else{
- ResetFlag(flags, f_isCheckLod);
- }
- bool isDynamicLighting = pattern.Ptr()->dynamicLighting;
- bool isShadowReceive = pattern.Ptr()->shadowReceive;
- ITipsManager * tmanager = ITipsManager::GetManager(&Mission());
- solid.AddElements(pattern.Ptr()->soldObjectsCount);
- for(long i = 0; i < solid; i++)
- {
- Part & psolid = solid[i];
- psolid.mtx.EqMultiplyFast(pattern.Ptr()->objects[i].mtx, initMtx);
- psolid.model = Geometry().CreateScene(pattern.Ptr()->objects[i].modelName.c_str(), &Animation(), &Particles(), &Sound(), _FL_);
- if(psolid.model)
- {
- psolid.model->SetTransform(psolid.mtx);
- psolid.model->SetDynamicLightState(isDynamicLighting);
- psolid.model->SetShadowReceiveState(isShadowReceive);
- }
- psolid.physObject = null;
- psolid.impPos = 0.0f;
- psolid.impDir = 0.0f;
- psolid.count = 0;
- psolid.effectsPos = 0.0f;
- psolid.effectsCount = 0;
- psolid.alpha = 1.0f;
- psolid.curAlpha = 1.0f;
- psolid.descIndex = i;
- psolid.tip = null;
- psolid.flags = f_part_isCollision;
- psolid.sndMatMask = -1;
- psolid.sndCooldown = 3.0f;
- if(!EditMode_IsOn())
- {
- if(tmanager && pattern.Ptr()->objects[i].tipId.NotEmpty())
- {
- psolid.tip = tmanager->CreateTip(pattern.Ptr()->objects[i].tipId, psolid.mtx.pos, this);
- if(psolid.tip)
- {
- psolid.tip->Activate(false);
- }
- }
- }
- }
- broken.AddElements(pattern.Ptr()->objects - pattern.Ptr()->soldObjectsCount);
- for(long i = 0; i < broken; i++)
- {
- Part & pbroken = broken[i];
- long index = pattern.Ptr()->soldObjectsCount + i;
- pbroken.mtx.EqMultiplyFast(pattern.Ptr()->objects[index].mtx, initMtx);
- pbroken.model = Geometry().CreateScene(pattern.Ptr()->objects[index].modelName.c_str(), &Animation(), &Particles(), &Sound(), _FL_);
- if(pbroken.model)
- {
- pbroken.model->SetTransform(pbroken.mtx);
- pbroken.model->SetDynamicLightState(isDynamicLighting);
- pbroken.model->SetShadowReceiveState(isShadowReceive);
- }
- pbroken.physObject = null;
- pbroken.impPos = 0.0f;
- pbroken.impDir = 0.0f;
- pbroken.count = 0;
- pbroken.effectsPos = 0.0f;
- pbroken.effectsCount = 0;
- pbroken.alpha = 1.0f;
- pbroken.curAlpha = 1.0f;
- pbroken.descIndex = index;
- pbroken.tip = null;
- pbroken.flags = 0;
- pbroken.sndMatMask = -1;
- pbroken.sndCooldown = 3.0f;
- if(!EditMode_IsOn())
- {
- if(tmanager && pattern.Ptr()->objects[index].tipId.NotEmpty())
- {
- pbroken.tip = tmanager->CreateTip(pattern.Ptr()->objects[index].tipId, pbroken.mtx.pos, this);
- if(pbroken.tip)
- {
- pbroken.tip->Activate(false);
- }
- }
- }
- }
- }
- //Создать физические объекты
- void MissionPhysObject::MakePhysics(array<Part> & obj)
- {
- if(EditMode_IsOn()) return;
- if(!pattern.Validate()) return;
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- if(part.physObject) continue;
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- if((po.boxes || po.capsules) && !po.isStatic)
- {
- IPhysCombined * cb = Physics().CreateCombined(_FL_, part.mtx, true);
- part.physObject = cb;
- for(long j = 0; j < po.boxes; j++)
- {
- cb->AddBox(po.boxes[j].size05*2.0f, po.boxes[j].mtx);
- }
- for(long j = 0; j < po.capsules; j++)
- {
- cb->AddCapsule(po.capsules[j].radius, po.capsules[j].height - po.capsules[j].radius*2.0f, po.capsules[j].mtx);
- }
- cb->Build();
- cb->SetGroup(phys_physobjects);
- cb->SetMaterial(pattern.Ptr()->materialId);
- }
- }
- }
- //Удалить физические объекты
- void MissionPhysObject::ReleasePhysics(array<Part> & obj)
- {
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- if(part.physObject)
- {
- part.physObject->Release();
- part.physObject = null;
- }
- }
- }
- //Удалить модельки
- void MissionPhysObject::ReleaseModels(array<Part> & obj)
- {
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- if(part.model)
- {
- part.model->Release();
- part.model = null;
- }
- if(part.tip)
- {
- part.tip->Release();
- part.tip = null;
- }
- }
- }
- //Удалить данные
- void MissionPhysObject::Release()
- {
- ReleasePhysics(solid);
- ReleasePhysics(broken);
- ReleaseModels(solid);
- ReleaseModels(broken);
- solid.DelAll();
- broken.DelAll();
- }
- //Сломать
- void MissionPhysObject::Broke()
- {
- LogicDebug("Broke");
- //Обновляем состояние подписки
- SetShow(IsShow());
- //Ломаем
- SetFlag(flags, f_isBroken);
- //Больше нет препятствий для АИ
- aiColider->Activate(false);
- //Проигрываем звуки и партиклы
- for(long i = 0; i < solid; i++)
- {
- Part & sld = solid[i];
- ResetFlag(sld.flags, f_part_isCollision);
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[sld.descIndex];
- //Запускаем эффекты
- for(long j = 0; j < po.particles; j++)
- {
- IParticleSystem * ps = Particles().CreateParticleSystemEx(po.particles[j].name.c_str(), _FL_);
- if(ps)
- {
- ps->SetTransform(sld.mtx*po.particles[j].mtx);
- ps->AutoDelete(true);
- }
- }
- for(long j = 0; j < po.sounds; j++)
- {
- Sound().Create3D(po.sounds[j].name, sld.mtx*po.sounds[j].mtx.pos, _FL_);
- }
- //Взрываем если есть что
- if(po.receiveBoom.NotEmpty())
- {
- MOSafePointer mo;
- if(FindObject(po.receiveBoom, mo))
- {
- Vector p = sld.mtx*po.centerOfMass;
- const char * params[3];
- char pos[3][32];
- for(long i = 0; i < 3; i++)
- {
- crt_snprintf(pos[i], sizeof(pos[i]), "%f", p.v[i]);
- params[i] = pos[i];
- }
- mo.Ptr()->Command("boom", 3, params);
- }
- }
- //Бросаем бонусы
- if(po.bonusesTable.NotEmpty())
- {
- BonusesManager::CreateBonus(Mission(), sld.mtx.pos, po.bonusesTable);
- }
- }
- //Удаляем физические объекты
- ReleasePhysics(solid);
- for(long i = 0; i < broken; i++)
- {
- //Проставляем матрицу для будующего сломаного объекта
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[broken[i].descIndex];
- long j = 0;
- Part & brn = broken[i];
- SetFlag(brn.flags, f_part_isCollision);
- if(j < solid)
- {
- brn.mtx = solid[j].mtx;
- brn.impPos = solid[j].impPos;
- brn.impDir = solid[j].impDir;
- brn.count = solid[j].count;
- brn.effectsPos = 0.0f;
- brn.effectsCount = 0;
- }else{
- brn.impPos = 0.0f;
- brn.impDir = 0.0f;
- brn.count = 1;
- brn.effectsPos = 0.0f;
- brn.effectsCount = 0;
- }
- if(po.isAddImpulse)
- {
- brn.impPos += brn.mtx*po.impulsePosition;
- brn.impDir += brn.mtx.MulNormal(po.impulse)*10.0f;
- brn.count += 1;
- }
- }
- if(broken > 0)
- {
- broken[0].effectsPos = solid[0].effectsPos;
- broken[0].effectsCount = solid[0].effectsCount;
- }
- //Создаём физические объекты
- MakePhysics(broken);
- //Установим таймер на исчезновение
- SetUpdate(&MissionPhysObject::HideTimer, ML_EXECUTE1);
- //Обновляем состояние типсов
- ShowTips();
- //
- Update(0.0f, 0);
- }
- //Модифицировать наносимое повреждение с учётом коэфициентов демеджа
- float MissionPhysObject::ModifyHp(DamageType type, float hp)
- {
- float modifier = pattern.Ptr()->damageModifier.Multiplier(type, 0.0f);
- return hp*modifier;
- }
- //Нанести повреждение
- bool MissionPhysObject::ApplyDamage(float damage, DamageType type)
- {
- if(!pattern.Validate()) return false;
- if(type == dt_check) return false;
- if(CheckFlag(flags, f_isBroken)) return false;
- HP -= damage;
- if(HP > 0.0f) return false;
- Broke();
- return true;
- }
- //Найти видимый ABB
- void MissionPhysObject::FindVisibleABB(array<Part> & obj, ABB & abb)
- {
- abb.min = abb.max = 0.0f;
- bool isAdd = false;
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- if(part.model)
- {
- const GMXBoundBox & bbx = part.model->GetLocalBound();
- Box::FindABBforOBB(part.model->GetTransform(), bbx.vMin, bbx.vMax, abb.min, abb.max, isAdd);
- isAdd = true;
- }
- }
- }
- //Найти для физики ABB
- void MissionPhysObject::FindCollidersABB(array<Part> & obj, ABB & abb)
- {
- abb.min = abb.max = 0.0f;
- bool isAdd = false;
- for(long i = 0; i < obj; i++)
- {
- Part & part = obj[i];
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- for(long j = 0; j < po.boxes; j++)
- {
- MissionPhysObjPattern::CollisionBox & box = po.boxes[j];
- Box::FindABBforOBB(box.mtx*part.mtx, -box.size05, box.size05, abb.min, abb.max, isAdd);
- isAdd = true;
- }
- for(long j = 0; j < po.capsules; j++)
- {
- MissionPhysObjPattern::CollisionCapsule & cap = po.capsules[j];
- Box::FindABBforOBB(cap.mtx*part.mtx, -cap.size05, cap.size05, abb.min, abb.max, isAdd);
- isAdd = true;
- }
- }
- }
- __forceinline MissionPhysObject::DamageType MissionPhysObject::DetectType(dword source)
- {
- switch(source)
- {
- case DamageReceiver::ds_sword:
- return dt_sword;
- case DamageReceiver::ds_bomb:
- return dt_bomb;
- case DamageReceiver::ds_bullet:
- return dt_bullet;
- case DamageReceiver::ds_cannon:
- return dt_cannon;
- case DamageReceiver::ds_flame:
- return dt_flame;
- case DamageReceiver::ds_shooter:
- return dt_shooter;
- case DamageReceiver::ds_unknown:
- return dt_unknown;
- case DamageReceiver::ds_check:
- return dt_check;
- case ds_pickup:
- return dt_pickup;
- }
- return dt_unknown;
- }
- //Переместить целую часть в новую позицию
- bool MissionPhysObject::SetPartMatrix(long partIndex, const Matrix & mtx)
- {
- if(IsActive() || CheckFlag(flags, f_isBroken)) return false;
- if(partIndex >= solid || partIndex < 0) return false;
- Part & part = solid[partIndex];
- part.mtx = mtx;
- if(part.model)
- {
- part.model->SetTransform(part.mtx);
- }
- if(part.tip)
- {
- part.tip->SetPos(part.mtx.pos);
- }
- float wlevel = IWaterLevel::GetWaterLevel(Mission(), waterLevel);
- if(part.mtx.pos.y < wlevel)
- {
- const Vector & com = pattern.Ptr()->objects[part.descIndex].centerOfMass;
- Vector newPos = part.mtx*com;
- Vector curPos = Vector(newPos.x, wlevel - 1.0f, newPos.z);
- WaterDrop(part, curPos, newPos, wlevel);
- }
- Update(0.0f, 0);
- return true;
- }
- //Получить текущую матрицу целой части объекта
- bool MissionPhysObject::GetPartMatrix(long partIndex, Matrix & mtx)
- {
- if(CheckFlag(flags, f_isBroken)) return false;
- if(partIndex >= solid || partIndex < 0) return false;
- Part & part = solid[partIndex];
- mtx = part.mtx;
- return true;
- }
- //Получить пивот целой части
- bool MissionPhysObject::GetPartPivot(long partIndex, Matrix & mtx)
- {
- if(CheckFlag(flags, f_isBroken)) return false;
- if(partIndex >= solid || partIndex < 0) return false;
- Part & part = solid[partIndex];
- MissionPhysObjPattern::PatternObject & po = pattern.Ptr()->objects[part.descIndex];
- mtx = po.mtx;
- return true;
- }
- //Применить импульс в мировых координатах
- void MissionPhysObject::Impulse(const Vector & dir)
- {
- array<Part> & part = CheckFlag(flags, f_isBroken) ? broken : solid;
- for(long i = 0; i < part; i++)
- {
- part[i].impDir = dir;
- part[i].impPos = 0.0f;
- part[i].count = 1;
- }
- ApplyImpulses(dt_unknown);
- }
- //Сломать объект
- void MissionPhysObject::BrokeObject()
- {
- if(!CheckFlag(flags, f_isBroken))
- {
- Broke();
- }
- }
- //Показать-скрыть подсказки
- void MissionPhysObject::ShowTips(bool isShow)
- {
- if(CheckFlag(flags, f_isShowTips) != isShow)
- {
- if(isShow)
- {
- SetFlag(flags, f_isShowTips);
- }else{
- ResetFlag(flags, f_isShowTips);
- }
- ShowTips();
- }
- }
- //Найти индекс локатора по имени, -1 если нет такого
- long MissionPhysObject::GetLocatorIndexByName(const ConstString & name)
- {
- if(!pattern.Validate() || name.IsEmpty())
- {
- return -1;
- }
- MissionPhysObjPattern::Locator * locs = pattern.Ptr()->locators.GetBuffer();
- long size = pattern.Ptr()->locators;
- for(long i = 0; i < size; i++)
- {
- if(locs[i].name == name)
- {
- return i;
- }
- }
- return -1;
- }
- //Получить позицию локатора по индексу
- bool MissionPhysObject::GetLocator(long index, Matrix & mtx)
- {
- if(!pattern.Validate() || index < 0 || index >= pattern.Ptr()->locators)
- {
- return false;
- }
- MissionPhysObjPattern::Locator & loc = pattern.Ptr()->locators[index];
- Part & part = (loc.objectIndex < pattern.Ptr()->soldObjectsCount) ? solid[loc.objectIndex] : broken[loc.objectIndex - pattern.Ptr()->soldObjectsCount];
- mtx.EqMultiply(loc.mtx, part.mtx);
- return true;
- }
- __forceinline void MissionPhysObject::ResetFlag(dword & f, dword value)
- {
- f &= ~value;
- }
- __forceinline void MissionPhysObject::SetFlag(dword & f, dword value)
- {
- f |= value;
- }
- __forceinline bool MissionPhysObject::CheckFlag(dword f, dword value)
- {
- return (f & value) != 0;
- }
- //============================================================================================
- //Параметры инициализации
- //============================================================================================
- MOP_BEGINLISTCG(MissionPhysObject, "Physic object", '1.00', 1, "Patterned physic object\n Commands:\n broke [objectId impulseForce [impulseForceMax]]\n shock time[0..10] force[0..100] period[0..10]\n hackhideon\n hackhideoff", "Physics")
- MOP_POSITIONC("Position", Vector(0.0f), "Model position in world")
- MOP_ANGLESC("Angles", Vector(0.0f), "Model orientation in world")
- MOP_STRINGC("Pattern", "", "Name of physics object pattern")
- MOP_BOOLC("Show", true, "Show or hide geometry in start mission time")
- MOP_BOOLC("Active", true, "Show or hide geometry in start mission time")
- MOP_BOOLC("Use pattern HP", true, "Object HP")
- MOP_FLOATEXC("HP", 0.0f, 0.0f, 100000.0f, "Physic objects HP")
- MOP_MISSIONTRIGGERG("Broke trigger", "")
- MOP_BOOLC("Draw collision", false, "Draw collision primitives")
- MOP_ENDLIST(MissionPhysObject)
|