entityai.c 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659
  1. enum EWetnessLevel
  2. {
  3. DRY,
  4. DAMP,
  5. WET,
  6. SOAKING,
  7. DRENCHED
  8. }
  9. enum SurfaceAnimationBone
  10. {
  11. LeftFrontLimb = 0,
  12. RightFrontLimb,
  13. LeftBackLimb,
  14. RightBackLimb
  15. }
  16. enum PlantType
  17. {
  18. TREE_HARD = 1000,
  19. TREE_SOFT = 1001,
  20. BUSH_HARD = 1002,
  21. BUSH_SOFT = 1003,
  22. }
  23. enum WeightUpdateType
  24. {
  25. FULL = 0,
  26. ADD,
  27. REMOVE,
  28. RECURSIVE_ADD,
  29. RECURSIVE_REMOVE
  30. }
  31. enum EItemManipulationContext
  32. {
  33. UPDATE, //generic operation
  34. ATTACHING,
  35. DETACHING,
  36. }
  37. //! icon visibility, meant to be used in a bitmask
  38. enum EInventoryIconVisibility
  39. {
  40. ALWAYS = 0,
  41. HIDE_VICINITY = 1,
  42. //further values yet unused, but nice to have anyway
  43. HIDE_PLAYER_CONTAINER = 2,
  44. HIDE_HANDS_SLOT = 4
  45. }
  46. //!EXCLUSIVITY values, restrict attachment combinations
  47. enum EAttExclusions
  48. {
  49. OCCUPANCY_INVALID = -1,
  50. //Legacy relations
  51. LEGACY_EYEWEAR_HEADGEAR,
  52. LEGACY_EYEWEAR_MASK,
  53. LEGACY_HEADSTRAP_HEADGEAR,
  54. LEGACY_HEADSTRAP_MASK,
  55. LEGACY_HEADGEAR_MASK,
  56. LEGACY_HEADGEAR_EYEWEWEAR,
  57. LEGACY_HEADGEAR_HEADSTRAP,
  58. LEGACY_MASK_HEADGEAR,
  59. LEGACY_MASK_EYEWEWEAR,
  60. LEGACY_MASK_HEADSTRAP,
  61. //
  62. EXCLUSION_HEADGEAR_HELMET_0, //full helmet
  63. //EXCLUSION_HEADGEAR_HELMET_0_A, //example of another 'vector' of potential conflict, like between helmet and eyewear..otherwise the other non-helmet entities would collide through the 'EXCLUSION_HEADSTRAP_0' value.
  64. EXCLUSION_HEADSTRAP_0,
  65. EXCLUSION_MASK_0,
  66. EXCLUSION_MASK_1,
  67. EXCLUSION_MASK_2, //Mostly Gasmasks
  68. EXCLUSION_MASK_3, //bandana mask special behavior
  69. EXCLUSION_GLASSES_REGULAR_0,
  70. EXCLUSION_GLASSES_TIGHT_0,
  71. //values to solve the edge-cases with shaving action
  72. SHAVING_MASK_ATT_0,
  73. SHAVING_HEADGEAR_ATT_0,
  74. SHAVING_EYEWEAR_ATT_0,
  75. }
  76. class DebugSpawnParams
  77. {
  78. Man m_Player;
  79. static DebugSpawnParams WithPlayer(Man player)
  80. {
  81. DebugSpawnParams params = new DebugSpawnParams();
  82. params.m_Player = player;
  83. return params;
  84. }
  85. };
  86. class TSelectableActionInfoArrayEx extends array<ref Param> {}
  87. typedef Param3<int, int, string> TSelectableActionInfo;
  88. typedef Param4<int, int, string, int> TSelectableActionInfoWithColor;
  89. class EntityAI extends Entity
  90. {
  91. bool m_DeathSyncSent;
  92. bool m_KilledByHeadshot;
  93. bool m_PreparedToDelete = false;
  94. bool m_RefresherViable = false;
  95. bool m_WeightDirty = 1;
  96. protected bool m_RoofAbove = false;
  97. private ref map<int,ref set<int>> m_AttachmentExclusionSlotMap; //own masks for different slots <slot,mask>. Kept on instance to better respond to various state changes
  98. private ref set<int> m_AttachmentExclusionMaskGlobal; //additional mask values and simple item values. Independent of slot-specific behavior!
  99. private ref set<int> m_AttachmentExclusionMaskChildren; //additional mask values and simple item values
  100. ref DestructionEffectBase m_DestructionBehaviourObj;
  101. ref KillerData m_KillerData;
  102. private ref HiddenSelectionsData m_HiddenSelectionsData;
  103. const int DEAD_REPLACE_DELAY = 250;
  104. const int DELETE_CHECK_DELAY = 100;
  105. ref array<EntityAI> m_AttachmentsWithCargo;
  106. ref array<EntityAI> m_AttachmentsWithAttachments;
  107. ref InventoryLocation m_OldLocation;
  108. protected ref DamageZoneMap m_DamageZoneMap;
  109. private ref map<int, string> m_DamageDisplayNameMap = new map<int, string>; //values are localization keys as strings, use 'Widget.TranslateString' method to get the localized one
  110. float m_Weight;
  111. float m_WeightEx;
  112. float m_ConfigWeight = ConfigGetInt("weight");
  113. protected bool m_CanDisplayWeight;
  114. private float m_LastUpdatedTime; //CE update time
  115. protected float m_ElapsedSinceLastUpdate; //CE update time
  116. protected float m_PreviousRoofTestTime = 0;
  117. protected UTemperatureSource m_UniversalTemperatureSource;
  118. bool m_PendingDelete = false;
  119. bool m_Initialized = false;
  120. bool m_TransportHitRegistered = false;
  121. vector m_TransportHitVelocity;
  122. // ============================================
  123. // Variable Manipulation System
  124. // ============================================
  125. int m_VariablesMask;//this holds information about which vars have been changed from their default values
  126. // Temperature
  127. float m_VarTemperature;
  128. float m_VarTemperatureInit;
  129. float m_VarTemperatureMin;
  130. float m_VarTemperatureMax;
  131. float m_VarTemperatureFreezeThreshold;
  132. float m_VarTemperatureThawThreshold;
  133. float m_VarTemperatureFreezeTime;
  134. float m_VarTemperatureThawTime;
  135. float m_VarTemperatureOverheatTime;
  136. float m_VarHeatPermeabilityCoef;
  137. protected ref TemperatureAccessComponent m_TAC;
  138. protected bool m_IsFrozen;
  139. protected bool m_IsFrozenLocal;
  140. protected float m_FreezeThawProgress;
  141. protected float m_OverheatProgress;
  142. //---------------------------------------------
  143. //Called on item attached to this item (EntityAI item, string slot, EntityAI parent)
  144. protected ref ScriptInvoker m_OnItemAttached;
  145. //Called on item detached from this item (EntityAI item, string slot, EntityAI parent)
  146. protected ref ScriptInvoker m_OnItemDetached;
  147. //Called when an item is added to the cargo of this item (EntityAI item, EntityAI parent)
  148. protected ref ScriptInvoker m_OnItemAddedIntoCargo;
  149. //Called when an item is removed from the cargo of this item (EntityAI item, EntityAI parent)
  150. protected ref ScriptInvoker m_OnItemRemovedFromCargo;
  151. //Called when an item is moved around in the cargo of this item (EntityAI item, EntityAI parent)
  152. protected ref ScriptInvoker m_OnItemMovedInCargo;
  153. //Called when an item is flipped around in cargo (bool flip)
  154. protected ref ScriptInvoker m_OnItemFlipped;
  155. //Called when an items view index is changed
  156. protected ref ScriptInvoker m_OnViewIndexChanged;
  157. //Called when an location in this item is reserved (EntityAI item) - cargo
  158. protected ref ScriptInvoker m_OnSetLock;
  159. //Called when this item is unreserved (EntityAI item) - cargo
  160. protected ref ScriptInvoker m_OnReleaseLock;
  161. //Called when an location in this item is reserved (EntityAI item) - attachment
  162. protected ref ScriptInvoker m_OnAttachmentSetLock;
  163. //Called when this item is unreserved (EntityAI item) - attachment
  164. protected ref ScriptInvoker m_OnAttachmentReleaseLock;
  165. //Called when this entity is hit
  166. protected ref ScriptInvoker m_OnHitByInvoker;
  167. //Called when this entity is killed
  168. protected ref ScriptInvoker m_OnKilledInvoker;
  169. private ref map<eAgents, float> m_BloodInfectionChanceCached; //! cache blood infection chance (cfgVehicles-><entity>->Skinning->BloodInfectionSettings)
  170. #ifdef DEVELOPER
  171. float m_LastFTChangeTime;;
  172. float m_PresumedTimeRemaining;
  173. #endif
  174. void EntityAI()
  175. {
  176. // Set up the Energy Manager
  177. string type = GetType();
  178. string param_access_energy_sys = "CfgVehicles " + type + " EnergyManager ";
  179. bool is_electic_device = GetGame().ConfigIsExisting(param_access_energy_sys);
  180. if (is_electic_device) // TO DO: Check if this instance is a hologram (advanced placement). If Yes, then do not create Energy Manager component.
  181. {
  182. CreateComponent(COMP_TYPE_ENERGY_MANAGER);
  183. RegisterNetSyncVariableBool("m_EM.m_IsSwichedOn");
  184. RegisterNetSyncVariableBool("m_EM.m_CanWork");
  185. RegisterNetSyncVariableBool("m_EM.m_IsPlugged");
  186. RegisterNetSyncVariableInt("m_EM.m_EnergySourceNetworkIDLow");
  187. RegisterNetSyncVariableInt("m_EM.m_EnergySourceNetworkIDHigh");
  188. RegisterNetSyncVariableFloat("m_EM.m_Energy");
  189. }
  190. // Item preview index
  191. RegisterNetSyncVariableInt( "m_ViewIndex", 0, 99 );
  192. // Refresher signalization
  193. RegisterNetSyncVariableBool("m_RefresherViable");
  194. m_AttachmentsWithCargo = new array<EntityAI>();
  195. m_AttachmentsWithAttachments = new array<EntityAI>();
  196. m_LastUpdatedTime = 0.0;
  197. m_ElapsedSinceLastUpdate = 0.0;
  198. m_CanDisplayWeight = ConfigGetBool("displayWeight");
  199. InitDamageZoneMapping();
  200. InitDamageZoneDisplayNameMapping();
  201. InitItemVariables();
  202. m_HiddenSelectionsData = new HiddenSelectionsData( GetType() );
  203. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(DeferredInit,34);
  204. m_BloodInfectionChanceCached = new map<eAgents, float>();
  205. }
  206. void ~EntityAI()
  207. {
  208. }
  209. void InitItemVariables()
  210. {
  211. m_VarTemperatureInit = ConfigGetFloat("varTemperatureInit");
  212. m_VarTemperatureMin = ConfigGetFloat("varTemperatureMin");
  213. m_VarTemperatureMax = ConfigGetFloat("varTemperatureMax");
  214. if (ConfigIsExisting("varTemperatureFreezePoint"))
  215. m_VarTemperatureFreezeThreshold = ConfigGetFloat("varTemperatureFreezePoint");
  216. else
  217. m_VarTemperatureFreezeThreshold = float.LOWEST;
  218. if (ConfigIsExisting("varTemperatureThawPoint"))
  219. m_VarTemperatureThawThreshold = ConfigGetFloat("varTemperatureThawPoint");
  220. else
  221. m_VarTemperatureThawThreshold = float.LOWEST;
  222. m_VarTemperatureFreezeTime = Math.Clamp(ConfigGetFloat("varTemperatureFreezeTime"),1,float.MAX);
  223. m_VarTemperatureThawTime = Math.Clamp(ConfigGetFloat("varTemperatureThawTime"),1,float.MAX);
  224. if (ConfigIsExisting("varTemperatureOverheatTime"))
  225. m_VarTemperatureOverheatTime = ConfigGetFloat("varTemperatureOverheatTime");
  226. else
  227. m_VarTemperatureOverheatTime = -1;
  228. if (ConfigIsExisting("varHeatPermeabilityCoef"))
  229. m_VarHeatPermeabilityCoef = ConfigGetFloat("varHeatPermeabilityCoef");
  230. else
  231. m_VarHeatPermeabilityCoef = 1;
  232. if (CanHaveTemperature())
  233. {
  234. RegisterNetSyncVariableFloat("m_VarTemperature", GetTemperatureMin(),GetTemperatureMax());
  235. RegisterNetSyncVariableBool("m_IsFrozen");
  236. if (GetGame().IsServer())
  237. m_TAC = new TemperatureAccessComponent(this);
  238. if (!GetGame().IsMultiplayer() || GetGame().IsClient())
  239. m_FreezeThawProgress = -1;
  240. }
  241. }
  242. void DeferredInit()
  243. {
  244. m_Initialized = true;
  245. }
  246. bool IsInitialized()
  247. {
  248. return m_Initialized;
  249. }
  250. //! should the item's icon be hidden in any part of the inventory?
  251. int GetHideIconMask()
  252. {
  253. return EInventoryIconVisibility.ALWAYS;
  254. }
  255. private ref ComponentsBank m_ComponentsBank;
  256. ComponentEnergyManager m_EM; // This reference is necesarry due to synchronization, since it's impossible to synchronize values from a component :(
  257. //! CreateComponent
  258. Component CreateComponent(int comp_type, string extended_class_name="")
  259. {
  260. return GetComponent(comp_type, extended_class_name);
  261. }
  262. //! GetComponent
  263. Component GetComponent(int comp_type, string extended_class_name="")
  264. {
  265. if ( m_ComponentsBank == NULL )
  266. m_ComponentsBank = new ComponentsBank(this);
  267. return m_ComponentsBank.GetComponent(comp_type, extended_class_name);
  268. }
  269. //! DeleteComponent
  270. bool DeleteComponent(int comp_type)
  271. {
  272. return m_ComponentsBank.DeleteComponent(comp_type);
  273. }
  274. string GetDestructionBehaviour()
  275. {
  276. return "";
  277. }
  278. bool IsDestructionBehaviour()
  279. {
  280. return false;
  281. }
  282. //! IsComponentExist
  283. bool HasComponent(int comp_type)
  284. {
  285. if ( m_ComponentsBank )
  286. return m_ComponentsBank.IsComponentAlreadyExist(comp_type);
  287. return false;
  288. }
  289. //! Calculates if the max lifetime is higher than refresher frequency (i.e. gets kept alive by refresher)
  290. void MaxLifetimeRefreshCalc()
  291. {
  292. if ( (!GetGame().IsMultiplayer() || GetGame().IsServer()) && GetEconomyProfile() )
  293. {
  294. float lifetime = GetEconomyProfile().GetLifetime();
  295. int frequency = GetCEApi().GetCEGlobalInt("FlagRefreshFrequency");
  296. if ( frequency <= 0 )
  297. {
  298. frequency = GameConstants.REFRESHER_FREQUENCY_DEFAULT;
  299. }
  300. if ( frequency <= lifetime )
  301. {
  302. m_RefresherViable = true;
  303. SetSynchDirty();
  304. }
  305. }
  306. }
  307. bool IsRefresherSignalingViable()
  308. {
  309. if (IsRuined())
  310. {
  311. return false;
  312. }
  313. return m_RefresherViable;
  314. }
  315. #ifdef DEVELOPER
  316. override void SetDebugItem()
  317. {
  318. super.SetDebugItem();
  319. _item = this;
  320. }
  321. #endif
  322. //! Initializes script-side map of damage zones and their components (named selections in models)
  323. void InitDamageZoneMapping()
  324. {
  325. m_DamageZoneMap = new DamageZoneMap;
  326. DamageSystem.GetDamageZoneMap(this,m_DamageZoneMap);
  327. }
  328. //! Initialize map of damage zone display names for more optimized retrieval
  329. void InitDamageZoneDisplayNameMapping()
  330. {
  331. string path_base;
  332. string path;
  333. string component_name;
  334. if ( IsWeapon() )
  335. {
  336. path_base = CFG_WEAPONSPATH;
  337. }
  338. else if ( IsMagazine() )
  339. {
  340. path_base = CFG_MAGAZINESPATH;
  341. }
  342. else
  343. {
  344. path_base = CFG_VEHICLESPATH;
  345. }
  346. path_base = string.Format( "%1 %2 DamageSystem DamageZones", path_base, GetType() );
  347. if ( !GetGame().ConfigIsExisting(path_base) )
  348. {
  349. component_name = GetDisplayName();
  350. GetGame().FormatRawConfigStringKeys(component_name);
  351. m_DamageDisplayNameMap.Insert( "".Hash(), component_name );
  352. }
  353. else
  354. {
  355. TStringArray zone_names = new TStringArray;
  356. GetDamageZones( zone_names );
  357. for ( int i = 0; i < zone_names.Count(); i++ )
  358. {
  359. path = string.Format( "%1 %2 displayName", path_base, zone_names[i] );
  360. if (GetGame().ConfigIsExisting(path) && GetGame().ConfigGetTextRaw(path,component_name))
  361. {
  362. GetGame().FormatRawConfigStringKeys(component_name);
  363. m_DamageDisplayNameMap.Insert( zone_names[i].Hash(), component_name );
  364. }
  365. }
  366. }
  367. }
  368. protected float ConvertNonlethalDamage(float damage, DamageType damageType)
  369. {
  370. return 0.0;
  371. }
  372. //! DEPRECATED - for legacy purposes
  373. float ConvertNonlethalDamage(float damage)
  374. {
  375. return 0.0;
  376. }
  377. DamageZoneMap GetEntityDamageZoneMap()
  378. {
  379. return m_DamageZoneMap;
  380. }
  381. map<int, string> GetEntityDamageDisplayNameMap()
  382. {
  383. return m_DamageDisplayNameMap;
  384. }
  385. //! 'displayWeight' in item config
  386. bool CanDisplayWeight()
  387. {
  388. return m_CanDisplayWeight;
  389. }
  390. //! Log
  391. void Log(string msg, string fnc_name = "n/a")
  392. {
  393. Debug.Log(msg, "Object", "n/a", fnc_name, this.GetType());
  394. }
  395. //! LogWarning
  396. void LogWarning(string msg, string fnc_name = "n/a")
  397. {
  398. Debug.LogWarning(msg, "Object", "n/a", fnc_name, this.GetType());
  399. }
  400. //! LogError
  401. void LogError(string msg, string fnc_name = "n/a")
  402. {
  403. Debug.LogError(msg, "Object", "n/a", fnc_name, this.GetType());
  404. }
  405. ///@{ Skinning
  406. bool IsSkinned()
  407. {
  408. return GetCompBS() && GetCompBS().IsSkinned();
  409. }
  410. void SetAsSkinned()
  411. {
  412. if (GetCompBS())
  413. GetCompBS().SetAsSkinned();
  414. }
  415. bool CanBeSkinnedWith(EntityAI tool)
  416. {
  417. if ( !IsSkinned() && tool )
  418. if ( !IsAlive() )
  419. return true;
  420. return false;
  421. }
  422. float GetSkinningBloodInfectionChance(eAgents type)
  423. {
  424. float value = 0.0;
  425. if (m_BloodInfectionChanceCached.Find(type, value))
  426. return value;
  427. return value;
  428. }
  429. protected void CacheSkinningBloodInfectionChance(eAgents type)
  430. {
  431. string basePath = string.Format("cfgVehicles %1 Skinning BloodInfectionSettings", GetType());
  432. if (g_Game.ConfigIsExisting(basePath))
  433. {
  434. string agentName = EnumTools.EnumToString(eAgents, type);
  435. agentName.ToLower();
  436. float value = g_Game.ConfigGetFloat(string.Format("%1 %2 chance", basePath, agentName));
  437. m_BloodInfectionChanceCached.Set(type, value);
  438. }
  439. }
  440. ///@} Skinning
  441. // ITEM TO ITEM FIRE DISTRIBUTION
  442. //! Override this method to return TRUE when this item has or can provide fire. Evaluated on server and client.
  443. bool HasFlammableMaterial()
  444. {
  445. return false;
  446. }
  447. //! Override this method so it checks whenever this item can be ignited right now or not. Evaluated on Server and Client.
  448. bool CanBeIgnitedBy(EntityAI igniter = NULL)
  449. {
  450. return false;
  451. }
  452. //! Override this method and check if the given item can be ignited right now by this one. Evaluated on Server and Client.
  453. bool CanIgniteItem(EntityAI ignite_target = NULL)
  454. {
  455. return false;
  456. }
  457. //! Override this method and make it so it returns whenever this item is on fire right now or not. Evaluated on Server and Client.
  458. bool IsIgnited()
  459. {
  460. if (m_EM)
  461. return m_EM.IsWorking();
  462. return false;
  463. }
  464. // Change return value to true if last detached item cause disassemble of item - different handlig some inventory operations
  465. bool DisassembleOnLastDetach()
  466. {
  467. return false;
  468. }
  469. bool IsBasebuildingKit()
  470. {
  471. return false;
  472. }
  473. bool IsCookware()
  474. {
  475. return false;
  476. }
  477. //! Should return false if you want to disable hologram rotation
  478. bool PlacementCanBeRotated()
  479. {
  480. return true;
  481. }
  482. //! Executed on Server when this item ignites some target item
  483. void OnIgnitedTarget( EntityAI target_item)
  484. {
  485. }
  486. //! Executed on Server when some item ignited this one
  487. void OnIgnitedThis( EntityAI fire_source)
  488. {
  489. }
  490. //! Executed on Server when this item failed to ignite target item
  491. void OnIgnitedTargetFailed( EntityAI target_item)
  492. {
  493. }
  494. //! Executed on Server when some item failed to ignite this one
  495. void OnIgnitedThisFailed( EntityAI fire_source)
  496. {
  497. }
  498. //! Final evaluation just before the target item is actually ignited. Evaluated on Server.
  499. bool IsTargetIgnitionSuccessful(EntityAI item_target)
  500. {
  501. return true;
  502. }
  503. //! Final evaluation just before this item is actually ignited from fire source. Evaluated on Server.
  504. bool IsThisIgnitionSuccessful(EntityAI item_source = NULL)
  505. {
  506. return true;
  507. }
  508. // End of fire distribution ^
  509. // ADVANCED PLACEMENT EVENTS
  510. void OnPlacementStarted(Man player);
  511. void OnHologramBeingPlaced(Man player);
  512. void OnPlacementComplete(Man player, vector position = "0 0 0", vector orientation = "0 0 0");
  513. void OnPlacementCancelled(Man player);
  514. bool CanBePlaced(Man player, vector position)
  515. {
  516. return true;
  517. }
  518. //! Method which returns message why object can't be placed at given position
  519. string CanBePlacedFailMessage( Man player, vector position )
  520. {
  521. return "";
  522. }
  523. //! Do the roof check when placing this?
  524. bool DoPlacingHeightCheck()
  525. {
  526. return false;
  527. }
  528. //! used as script-side override of distance for specific height checks
  529. float HeightCheckOverride()
  530. {
  531. return 0.0;
  532. }
  533. //! used as script-side override of start pos for specific height checks
  534. float HeightStartCheckOverride()
  535. {
  536. return 0.0;
  537. }
  538. //! is this container empty or not, checks both cargo and attachments
  539. bool IsEmpty()
  540. {
  541. return (!HasAnyCargo() && GetInventory().AttachmentCount() == 0);
  542. }
  543. //! returns just the configured 'canBeSplit' bool
  544. bool IsSplitable()
  545. {
  546. return false;
  547. }
  548. //! returns current splitability
  549. bool CanBeSplit()
  550. {
  551. return false;
  552. }
  553. //! is this container empty or not, checks only cargo
  554. bool HasAnyCargo()
  555. {
  556. CargoBase cargo = GetInventory().GetCargo();
  557. if(!cargo) return false;//this is not a cargo container
  558. if( cargo.GetItemCount() > 0 )
  559. {
  560. return true;
  561. }
  562. else
  563. {
  564. return false;
  565. }
  566. }
  567. array<EntityAI> GetAttachmentsWithCargo()
  568. {
  569. return m_AttachmentsWithCargo;
  570. }
  571. array<EntityAI> GetAttachmentsWithAttachments()
  572. {
  573. return m_AttachmentsWithAttachments;
  574. }
  575. //is there any roof above
  576. bool IsRoofAbove()
  577. {
  578. return m_RoofAbove;
  579. }
  580. void SetRoofAbove(bool state)
  581. {
  582. m_RoofAbove = state;
  583. }
  584. //! Roof check for entity, limited by time (anti-spam solution)
  585. void CheckForRoofLimited(float timeTresholdMS = 3000);
  586. int GetAgents() { return 0; }
  587. void RemoveAgent(int agent_id);
  588. void RemoveAllAgents();
  589. void RemoveAllAgentsExcept(int agent_to_keep);
  590. void InsertAgent(int agent, float count = 1);
  591. override bool IsEntityAI() { return true; }
  592. bool IsInventoryVisible()
  593. {
  594. return !( GetParent() || GetHierarchyParent() );
  595. }
  596. bool IsPlayer()
  597. {
  598. return false;
  599. }
  600. bool IsAnimal()
  601. {
  602. return false;
  603. }
  604. bool IsZombie()
  605. {
  606. return false;
  607. }
  608. bool IsZombieMilitary()
  609. {
  610. return false;
  611. }
  612. bool IsIgnoredByConstruction()
  613. {
  614. return IsDamageDestroyed();
  615. }
  616. bool CanBeTargetedByAI(EntityAI ai)
  617. {
  618. if (ai && ai.IsBeingBackstabbed())
  619. {
  620. return false;
  621. }
  622. if ( !dBodyIsActive( this ) && !IsMan() )
  623. return false;
  624. return !IsDamageDestroyed();
  625. }
  626. bool CanBeBackstabbed()
  627. {
  628. return false;
  629. }
  630. /**@brief Delete this object in next frame
  631. * @return \p void
  632. *
  633. * @code
  634. * ItemBase item = GetGame().GetPlayer().CreateInInventory("GrenadeRGD5");
  635. * item.Delete();
  636. * @endcode
  637. **/
  638. override void Delete()
  639. {
  640. m_PendingDelete = true;
  641. super.Delete();
  642. }
  643. void DeleteOnClient()
  644. {
  645. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).Call(GetGame().ObjectDeleteOnClient, this);
  646. }
  647. // delete synchronized between server and client
  648. void DeleteSafe()
  649. {
  650. if (GetHierarchyRootPlayer() == null || (GetHierarchyRootPlayer() && !GetHierarchyRootPlayer().IsAlive()))
  651. {
  652. Delete();
  653. }
  654. else
  655. {
  656. if (GetGame().IsServer() && GetGame().IsMultiplayer())
  657. GetHierarchyRootPlayer().JunctureDeleteItem(this);
  658. else
  659. GetHierarchyRootPlayer().AddItemToDelete(this);
  660. }
  661. }
  662. //legacy, wrong name, use 'DeleteSafe()' instead
  663. void DeleteSave()
  664. {
  665. DeleteSafe();
  666. }
  667. bool IsSetForDeletion()
  668. {
  669. return IsPreparedToDelete() || m_PendingDelete || ToDelete() || IsPendingDeletion();
  670. }
  671. override bool CanBeActionTarget()
  672. {
  673. if (super.CanBeActionTarget())
  674. {
  675. return !IsSetForDeletion();
  676. }
  677. else
  678. {
  679. return false;
  680. }
  681. }
  682. void SetPrepareToDelete()
  683. {
  684. m_PreparedToDelete = true;
  685. }
  686. bool IsPreparedToDelete()
  687. {
  688. return m_PreparedToDelete;
  689. }
  690. void CheckForDestroy()
  691. {
  692. if (IsPrepareToDelete())
  693. {
  694. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(TryDelete, DELETE_CHECK_DELAY, false);
  695. }
  696. }
  697. bool IsPrepareToDelete()
  698. {
  699. return false;
  700. }
  701. bool TryDelete()
  702. {
  703. if (!IsPrepareToDelete())
  704. {
  705. Debug.Log("TryDelete - not ready for deletion");
  706. return false;
  707. }
  708. if (GetGame().HasInventoryJunctureItem(this))
  709. {
  710. Debug.Log("TryDelete - deferred call");
  711. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(TryDelete, DELETE_CHECK_DELAY, false);
  712. return false;
  713. }
  714. OnBeforeTryDelete();
  715. Debug.Log("TryDelete - OnBeforeTryDelete end");
  716. DeleteSafe();
  717. Debug.Log("TryDelete - DeleteSafe end");
  718. return true;
  719. }
  720. void OnBeforeTryDelete();
  721. //! Returns root of current hierarchy (for example: if this entity is in Backpack on gnd, returns Backpack)
  722. proto native EntityAI GetHierarchyRoot();
  723. //! Returns root of current hierarchy cast to Man
  724. proto native Man GetHierarchyRootPlayer();
  725. //! Returns direct parent of current entity
  726. proto native EntityAI GetHierarchyParent();
  727. //! Get economy item profile (if assigned, otherwise null)
  728. proto native CEItemProfile GetEconomyProfile();
  729. // !returns the number of levels bellow the hierarchy root this entity is at
  730. int GetHierarchyLevel(int lvl = 0)
  731. {
  732. if (!GetHierarchyParent())
  733. return lvl;
  734. return GetHierarchyParent().GetHierarchyLevel(lvl+1);
  735. }
  736. void OnInventoryInit()
  737. {
  738. InitAttachmentExclusionValues();
  739. }
  740. //! Called upon object creation
  741. void EEInit()
  742. {
  743. if (GetInventory())
  744. {
  745. GetInventory().EEInit();
  746. m_AttachmentsWithCargo.Clear();
  747. m_AttachmentsWithAttachments.Clear();
  748. for ( int i = 0; i < GetInventory().AttachmentCount(); i++ )
  749. {
  750. EntityAI attachment = GetInventory().GetAttachmentFromIndex( i );
  751. if ( attachment )
  752. {
  753. if ( attachment.GetInventory().GetCargo() )
  754. {
  755. m_AttachmentsWithCargo.Insert( attachment );
  756. }
  757. if ( attachment.GetInventory().GetAttachmentSlotsCount() > 0 )
  758. {
  759. m_AttachmentsWithAttachments.Insert( attachment );
  760. }
  761. }
  762. }
  763. }
  764. MaxLifetimeRefreshCalc();
  765. if (CanHaveTemperature() && GetGame().IsServer())
  766. InitTemperature();
  767. }
  768. //! Called right before object deleting
  769. void EEDelete(EntityAI parent)
  770. {
  771. m_PendingDelete = true;
  772. GetInventory().EEDelete(parent);
  773. if (m_EM)
  774. m_EM.OnDeviceDestroyed();
  775. }
  776. override void OnExplosionEffects(Object source, Object directHit, int componentIndex, string surface, vector pos, vector surfNormal, float energyFactor, float explosionFactor, bool isWater, string ammoType)
  777. {
  778. super.OnExplosionEffects(source, directHit, componentIndex, surface, pos, surfNormal, energyFactor, explosionFactor, isWater, ammoType);
  779. #ifndef SERVER
  780. g_Game.GetWorld().AddEnvShootingSource(pos, 1.0);
  781. #endif
  782. if (m_DestructionBehaviourObj && m_DestructionBehaviourObj.HasExplosionDamage())
  783. {
  784. m_DestructionBehaviourObj.OnExplosionEffects(source, directHit, componentIndex, surface, pos, surfNormal, energyFactor, explosionFactor, isWater, ammoType);
  785. }
  786. }
  787. void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner) { }
  788. void OnChildItemRemoved(InventoryItem item) { }
  789. void OnChildItemReceived(InventoryItem item) { }
  790. void OnItemAttachmentSlotChanged (notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc) {}
  791. void EEItemLocationChanged (notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
  792. {
  793. EntityAI old_owner = oldLoc.GetParent();
  794. EntityAI new_owner = newLoc.GetParent();
  795. OnItemLocationChanged(old_owner, new_owner);
  796. if (oldLoc.GetType() == InventoryLocationType.ATTACHMENT && newLoc.GetType() == InventoryLocationType.ATTACHMENT)
  797. {
  798. OnItemAttachmentSlotChanged(oldLoc,newLoc);
  799. }
  800. if (oldLoc.GetType() == InventoryLocationType.ATTACHMENT)
  801. {
  802. if (old_owner)
  803. OnWasDetached(old_owner, oldLoc.GetSlot());
  804. else
  805. Error("EntityAI::EEItemLocationChanged - detached, but old_owner is null");
  806. }
  807. if (newLoc.GetType() == InventoryLocationType.ATTACHMENT)
  808. {
  809. if (new_owner)
  810. OnWasAttached(newLoc.GetParent(), newLoc.GetSlot());
  811. else
  812. Error("EntityAI::EEItemLocationChanged - attached, but new_owner is null");
  813. }
  814. if (oldLoc.GetType() == InventoryLocationType.HANDS)
  815. {
  816. Man.Cast(oldLoc.GetParent()).OnItemInHandsChanged();
  817. }
  818. if (newLoc.GetType() == InventoryLocationType.HANDS)
  819. {
  820. Man.Cast(newLoc.GetParent()).OnItemInHandsChanged();
  821. }
  822. }
  823. //! Called from 'IEntity.AddChild'
  824. void EEParentedTo(EntityAI parent)
  825. {
  826. }
  827. //! Called from 'IEntity.RemoveChild' or 'IEntity.AddChild' when hierarchy changes
  828. void EEParentedFrom(EntityAI parent)
  829. {
  830. }
  831. void EEInventoryIn (Man newParentMan, EntityAI diz, EntityAI newParent)
  832. {
  833. }
  834. void EEInventoryOut (Man oldParentMan, EntityAI diz, EntityAI newParent)
  835. {
  836. m_LastUpdatedTime = GetGame().GetTickTime();
  837. if (GetInventory() && newParent == null)
  838. {
  839. GetInventory().ResetFlipCargo();
  840. }
  841. }
  842. void EEAmmoChanged()
  843. {
  844. SetWeightDirty();
  845. }
  846. void EEHealthLevelChanged(int oldLevel, int newLevel, string zone)
  847. {
  848. // Notify potential parent that this item was ruined
  849. EntityAI parent = GetHierarchyParent();
  850. if (newLevel == GameConstants.STATE_RUINED)
  851. {
  852. if (parent)
  853. {
  854. parent.OnAttachmentRuined(this);
  855. }
  856. if (!zone)
  857. {
  858. OnDamageDestroyed(oldLevel);
  859. }
  860. AttemptDestructionBehaviour(oldLevel,newLevel, zone);
  861. }
  862. }
  863. //! Called when the health gets to the min value, 'oldLevel' is previous health level, 'oldLevel' -1 means this entity was just spawned
  864. void OnDamageDestroyed(int oldLevel);
  865. void AttemptDestructionBehaviour(int oldLevel, int newLevel, string zone)
  866. {
  867. if (IsDestructionBehaviour() && GetDestructionBehaviour())
  868. {
  869. typename destType = GetDestructionBehaviour().ToType();
  870. if (destType)
  871. {
  872. if (!m_DestructionBehaviourObj)
  873. {
  874. m_DestructionBehaviourObj = DestructionEffectBase.Cast(destType.Spawn());
  875. }
  876. if (m_DestructionBehaviourObj)
  877. {
  878. m_DestructionBehaviourObj.OnHealthLevelChanged(this, oldLevel, newLevel, zone);
  879. }
  880. }
  881. else
  882. {
  883. ErrorEx("Incorrect destruction behaviour type, make sure the class returned in 'GetDestructionBehaviour()' is a valid type inheriting from 'DestructionEffectBase'");
  884. }
  885. }
  886. }
  887. void SetTakeable(bool pState);
  888. //! called on server when the entity is killed
  889. void EEKilled(Object killer)
  890. {
  891. if (m_OnKilledInvoker)
  892. m_OnKilledInvoker.Invoke(this, killer);
  893. GetGame().GetAnalyticsServer().OnEntityKilled(killer, this);
  894. if (ReplaceOnDeath())
  895. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(DeathUpdate, DEAD_REPLACE_DELAY, false);
  896. }
  897. bool ReplaceOnDeath()
  898. {
  899. return false;
  900. }
  901. string GetDeadItemName()
  902. {
  903. return "";
  904. }
  905. bool KeepHealthOnReplace()
  906. {
  907. return false;
  908. }
  909. void DeathUpdate()
  910. {
  911. EntityAI dead_entity = EntityAI.Cast( GetGame().CreateObjectEx( GetDeadItemName(), GetPosition(), ECE_OBJECT_SWAP, RF_ORIGINAL ) );
  912. dead_entity.SetOrientation(GetOrientation());
  913. if (KeepHealthOnReplace())
  914. dead_entity.SetHealth(GetHealth());
  915. DeleteSafe();
  916. }
  917. //! Called when some attachment of this parent is ruined. Called on server and client side.
  918. void OnAttachmentRuined(EntityAI attachment);
  919. void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
  920. {
  921. if (m_OnHitByInvoker)
  922. m_OnHitByInvoker.Invoke(this, damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
  923. #ifdef DEVELOPER
  924. //Print("EEHitBy: " + this + "; damageResult:"+ damageResult.GetDamage("","") +"; damageType: "+ damageType +"; source: "+ source +"; component: "+ component +"; dmgZone: "+ dmgZone +"; ammo: "+ ammo +"; modelPos: "+ modelPos);
  925. #endif
  926. }
  927. // called only on the client who caused the hit
  928. void EEHitByRemote(int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos)
  929. {
  930. }
  931. // !Called on PARENT when a child is attached to it.
  932. void EEItemAttached(EntityAI item, string slot_name)
  933. {
  934. int slotId = InventorySlots.GetSlotIdFromString(slot_name);
  935. PropagateExclusionValueRecursive(item.GetAttachmentExclusionMaskAll(slotId),slotId); //Performed from parent to avoid event order issues on swap
  936. SetWeightDirty();
  937. if ( m_ComponentsBank != NULL )
  938. {
  939. for ( int comp_key = 0; comp_key < COMP_TYPE_COUNT; ++comp_key )
  940. {
  941. if ( m_ComponentsBank.IsComponentAlreadyExist(comp_key) )
  942. {
  943. m_ComponentsBank.GetComponent(comp_key).Event_OnItemAttached(item, slot_name);
  944. }
  945. }
  946. }
  947. // Energy Manager
  948. if ( m_EM && item.GetCompEM())
  949. m_EM.OnAttachmentAdded(item);
  950. if ( item.GetInventory().GetCargo() )
  951. m_AttachmentsWithCargo.Insert( item );
  952. if ( item.GetInventory().GetAttachmentSlotsCount() > 0 )
  953. m_AttachmentsWithAttachments.Insert( item );
  954. if ( m_OnItemAttached )
  955. m_OnItemAttached.Invoke( item, slot_name, this );
  956. }
  957. void SwitchItemSelectionTexture(EntityAI item, string slot_name);
  958. void SwitchItemSelectionTextureEx(EItemManipulationContext context, Param par = null);
  959. // !Called on PARENT when a child is detached from it.
  960. void EEItemDetached(EntityAI item, string slot_name)
  961. {
  962. int slotId = InventorySlots.GetSlotIdFromString(slot_name);
  963. ClearExclusionValueRecursive(item.GetAttachmentExclusionMaskAll(slotId),slotId); //Performed from parent to avoid event order issues on swap
  964. SetWeightDirty();
  965. if ( m_ComponentsBank != NULL )
  966. {
  967. for ( int comp_key = 0; comp_key < COMP_TYPE_COUNT; ++comp_key )
  968. {
  969. if ( m_ComponentsBank.IsComponentAlreadyExist(comp_key) )
  970. {
  971. m_ComponentsBank.GetComponent(comp_key).Event_OnItemDetached(item, slot_name);
  972. }
  973. }
  974. }
  975. // Energy Manager
  976. if (m_EM && item.GetCompEM())
  977. m_EM.OnAttachmentRemoved(item);
  978. if ( m_AttachmentsWithCargo.Find( item ) > -1 )
  979. m_AttachmentsWithCargo.RemoveItem( item );
  980. if ( m_AttachmentsWithAttachments.Find( item ) > -1 )
  981. m_AttachmentsWithAttachments.RemoveItem( item );
  982. if ( m_OnItemDetached )
  983. m_OnItemDetached.Invoke( item, slot_name, this );
  984. }
  985. void EECargoIn(EntityAI item)
  986. {
  987. SetWeightDirty();
  988. if( m_OnItemAddedIntoCargo )
  989. m_OnItemAddedIntoCargo.Invoke( item, this );
  990. item.OnMovedInsideCargo(this);
  991. }
  992. void EECargoOut(EntityAI item)
  993. {
  994. SetWeightDirty();
  995. if( m_OnItemRemovedFromCargo )
  996. m_OnItemRemovedFromCargo.Invoke( item, this );
  997. item.OnRemovedFromCargo(this);
  998. }
  999. void EECargoMove(EntityAI item)
  1000. {
  1001. if( m_OnItemMovedInCargo )
  1002. m_OnItemMovedInCargo.Invoke( item, this );
  1003. item.OnMovedWithinCargo(this);
  1004. }
  1005. ScriptInvoker GetOnItemAttached()
  1006. {
  1007. if( !m_OnItemAttached )
  1008. m_OnItemAttached = new ScriptInvoker;
  1009. return m_OnItemAttached;
  1010. }
  1011. ScriptInvoker GetOnItemDetached()
  1012. {
  1013. if( !m_OnItemDetached )
  1014. m_OnItemDetached = new ScriptInvoker;
  1015. return m_OnItemDetached;
  1016. }
  1017. ScriptInvoker GetOnItemAddedIntoCargo()
  1018. {
  1019. if( !m_OnItemAddedIntoCargo )
  1020. m_OnItemAddedIntoCargo = new ScriptInvoker;
  1021. return m_OnItemAddedIntoCargo;
  1022. }
  1023. ScriptInvoker GetOnItemRemovedFromCargo()
  1024. {
  1025. if( !m_OnItemRemovedFromCargo )
  1026. m_OnItemRemovedFromCargo = new ScriptInvoker;
  1027. return m_OnItemRemovedFromCargo;
  1028. }
  1029. ScriptInvoker GetOnItemMovedInCargo()
  1030. {
  1031. if( !m_OnItemMovedInCargo )
  1032. m_OnItemMovedInCargo = new ScriptInvoker;
  1033. return m_OnItemMovedInCargo;
  1034. }
  1035. ScriptInvoker GetOnItemFlipped()
  1036. {
  1037. if( !m_OnItemFlipped )
  1038. m_OnItemFlipped = new ScriptInvoker;
  1039. return m_OnItemFlipped;
  1040. }
  1041. ScriptInvoker GetOnViewIndexChanged()
  1042. {
  1043. if( !m_OnViewIndexChanged )
  1044. m_OnViewIndexChanged = new ScriptInvoker;
  1045. return m_OnViewIndexChanged;
  1046. }
  1047. ScriptInvoker GetOnSetLock()
  1048. {
  1049. if( !m_OnSetLock )
  1050. m_OnSetLock = new ScriptInvoker;
  1051. return m_OnSetLock;
  1052. }
  1053. ScriptInvoker GetOnReleaseLock()
  1054. {
  1055. if( !m_OnReleaseLock )
  1056. m_OnReleaseLock = new ScriptInvoker;
  1057. return m_OnReleaseLock;
  1058. }
  1059. ScriptInvoker GetOnAttachmentSetLock()
  1060. {
  1061. if( !m_OnAttachmentSetLock )
  1062. m_OnAttachmentSetLock = new ScriptInvoker;
  1063. return m_OnAttachmentSetLock;
  1064. }
  1065. ScriptInvoker GetOnAttachmentReleaseLock()
  1066. {
  1067. if( !m_OnAttachmentReleaseLock )
  1068. m_OnAttachmentReleaseLock = new ScriptInvoker;
  1069. return m_OnAttachmentReleaseLock;
  1070. }
  1071. ScriptInvoker GetOnHitByInvoker()
  1072. {
  1073. if ( !m_OnHitByInvoker )
  1074. m_OnHitByInvoker = new ScriptInvoker;
  1075. return m_OnHitByInvoker;
  1076. }
  1077. ScriptInvoker GetOnKilledInvoker()
  1078. {
  1079. if ( !m_OnKilledInvoker )
  1080. m_OnKilledInvoker = new ScriptInvoker;
  1081. return m_OnKilledInvoker;
  1082. }
  1083. //! Called when this item enters cargo of some container
  1084. void OnMovedInsideCargo(EntityAI container)
  1085. {
  1086. if (m_EM)
  1087. m_EM.HandleMoveInsideCargo(container);
  1088. }
  1089. //! Called when this item exits cargo of some container
  1090. void OnRemovedFromCargo(EntityAI container)
  1091. {
  1092. }
  1093. //! Called when this item moves within cargo of some container
  1094. void OnMovedWithinCargo(EntityAI container)
  1095. {
  1096. }
  1097. //! Called when entity is part of "connected system" and being restored after load
  1098. void EEOnAfterLoad()
  1099. {
  1100. // ENERGY MANAGER
  1101. // Restore connections between devices which were connected before server restart
  1102. if ( m_EM && m_EM.GetRestorePlugState() )
  1103. {
  1104. int b1 = m_EM.GetEnergySourceStorageIDb1();
  1105. int b2 = m_EM.GetEnergySourceStorageIDb2();
  1106. int b3 = m_EM.GetEnergySourceStorageIDb3();
  1107. int b4 = m_EM.GetEnergySourceStorageIDb4();
  1108. // get pointer to EntityAI based on this ID
  1109. EntityAI potential_energy_source = GetGame().GetEntityByPersitentID(b1, b2, b3, b4); // This function is available only in this event!
  1110. // IMPORTANT!
  1111. // Object IDs acquired here become INVALID when electric devices are transfered to another server while in plugged state (like Flashlight plugged into its attachment 9V battery)
  1112. // To avoid issues, these items must be excluded from this system of restoring plug state so they don't unintentionally plug to incorrect devices through these invalid IDs.
  1113. // Therefore their plug state is being restored withing the EEItemAttached() event while being excluded by the following 'if' conditions...
  1114. bool is_attachment = false;
  1115. if (potential_energy_source)
  1116. is_attachment = GetInventory().HasAttachment(potential_energy_source);
  1117. if ( !is_attachment && potential_energy_source )
  1118. is_attachment = potential_energy_source.GetInventory().HasAttachment(this);
  1119. if ( potential_energy_source && potential_energy_source.GetCompEM() /*&& potential_energy_source.HasEnergyManager()*/ && !is_attachment )
  1120. m_EM.PlugThisInto(potential_energy_source); // restore connection
  1121. }
  1122. }
  1123. //! Called when entity is being created as new by CE/ Debug
  1124. void EEOnCECreate()
  1125. {
  1126. }
  1127. //! Called when entity is being loaded from DB or Storage (after all children loaded)
  1128. void AfterStoreLoad()
  1129. {
  1130. }
  1131. //! Called when an item fails to get loaded into the inventory of an entity and gets dropped
  1132. void OnBinLoadItemsDropped()
  1133. {
  1134. if (GetHierarchyRootPlayer())
  1135. GetHierarchyRootPlayer().SetProcessUIWarning(true);
  1136. }
  1137. //! Sets all animation values to 1, making them INVISIBLE if they are configured in models.cfg in such way. These selections must also be defined in the entity's config class in 'AnimationSources'.
  1138. void HideAllSelections()
  1139. {
  1140. string cfg_path = "cfgVehicles " + GetType() + " AnimationSources";
  1141. if ( GetGame().ConfigIsExisting(cfg_path) )
  1142. {
  1143. int selections = GetGame().ConfigGetChildrenCount(cfg_path);
  1144. for (int i = 0; i < selections; i++)
  1145. {
  1146. string selection_name;
  1147. GetGame().ConfigGetChildName(cfg_path, i, selection_name);
  1148. HideSelection(selection_name);
  1149. }
  1150. }
  1151. }
  1152. //! Sets all animation values to 0, making them VISIBLE if they are configured in models.cfg in such way. These selections must also be defined in the entity's config class in 'AnimationSources'.
  1153. void ShowAllSelections()
  1154. {
  1155. string cfg_path = "cfgVehicles " + GetType() + " AnimationSources";
  1156. if ( GetGame().ConfigIsExisting(cfg_path) )
  1157. {
  1158. int selections = GetGame().ConfigGetChildrenCount(cfg_path);
  1159. for (int i = 0; i < selections; i++)
  1160. {
  1161. string selection_name;
  1162. GetGame().ConfigGetChildName(cfg_path, i, selection_name);
  1163. ShowSelection(selection_name);
  1164. }
  1165. }
  1166. }
  1167. /**@fn CanReceiveAttachment
  1168. * @brief calls this->CanReceiveAttachment(attachment)
  1169. * @return true if action allowed
  1170. *
  1171. * @note: return scriptConditionExecute(this, attachment, "CanReceiveAttachment");
  1172. **/
  1173. bool CanReceiveAttachment (EntityAI attachment, int slotId)
  1174. {
  1175. //generic occupancy check
  1176. return CheckAttachmentReceiveExclusion(attachment,slotId);
  1177. }
  1178. /**@fn CanLoadAsAttachment
  1179. * @brief calls this->CanLoadAsAttachment(attachment), is called on server start when loading in the storage
  1180. * @return true if action allowed
  1181. *
  1182. * @note: return scriptConditionExecute(this, attachment, "CanLoadAsAttachment");
  1183. **/
  1184. bool CanLoadAttachment(EntityAI attachment)
  1185. {
  1186. return true;
  1187. }
  1188. /**@fn CanPutAsAttachment
  1189. * @brief calls this->CanPutAsAttachment(parent)
  1190. * @param[in] parent \p target entity this is trying to attach to
  1191. * @return true if action allowed
  1192. *
  1193. * @note: engine code is scriptConditionExecute(this, parent, "CanPutAsAttachment")
  1194. **/
  1195. bool CanPutAsAttachment (EntityAI parent)
  1196. {
  1197. return !IsHologram();
  1198. }
  1199. //If return true, item can be attached even from parent to this. Item will be switched during proccess. (only hands)
  1200. bool CanSwitchDuringAttach(EntityAI parent)
  1201. {
  1202. return false;
  1203. }
  1204. /**@fn CanReleaseAttachment
  1205. * @brief calls this->CanReleaseAttachment(attachment)
  1206. * @return true if action allowed
  1207. *
  1208. * @note: return scriptConditionExecute(this, attachment, "CanReleaseAttachment");
  1209. **/
  1210. bool CanReleaseAttachment (EntityAI attachment)
  1211. {
  1212. if( attachment && attachment.GetInventory() && GetInventory() )
  1213. {
  1214. InventoryLocation il = new InventoryLocation();
  1215. attachment.GetInventory().GetCurrentInventoryLocation( il );
  1216. if( il.IsValid() )
  1217. {
  1218. int slot = il.GetSlot();
  1219. return !GetInventory().GetSlotLock( slot );
  1220. }
  1221. }
  1222. return true;
  1223. }
  1224. /**@fn CanDetachAttachment
  1225. * @brief calls this->CanDetachAttachment(parent)
  1226. * @return true if action allowed
  1227. *
  1228. * @note: return scriptConditionExecute(this, parent, "CanDetachAttachment");
  1229. **/
  1230. bool CanDetachAttachment (EntityAI parent)
  1231. {
  1232. return true;
  1233. }
  1234. bool CanBeFSwaped()
  1235. {
  1236. return true;
  1237. }
  1238. bool CanCombineAttachment(notnull EntityAI e, int slot, bool stack_max_limit = false)
  1239. {
  1240. EntityAI att = GetInventory().FindAttachment(slot);
  1241. if(att)
  1242. return att.CanBeCombined(e, true, stack_max_limit);
  1243. return false;
  1244. }
  1245. bool CanBeCombined(EntityAI other_item, bool reservation_check = true, bool stack_max_limit = false )
  1246. {
  1247. return false;
  1248. }
  1249. void CombineItemsEx(EntityAI entity2, bool use_stack_max = false );
  1250. void SplitIntoStackMaxEx(EntityAI destination_entity, int slot_id);
  1251. void CombineItemsClient(EntityAI entity2, bool use_stack_max = false )
  1252. {}
  1253. void SplitIntoStackMaxClient(EntityAI destination_entity, int slot_id);
  1254. /**@fn CanReceiveItemIntoCargo
  1255. * @brief calls this->CanReceiveItemIntoCargo(item)
  1256. * @return true if action allowed
  1257. *
  1258. * @note: return scriptConditionExecute(this, item, "CanReceiveItemIntoCargo");
  1259. **/
  1260. bool CanReceiveItemIntoCargo(EntityAI item)
  1261. {
  1262. if (GetInventory() && GetInventory().GetCargo())
  1263. return GetInventory().GetCargo().CanReceiveItemIntoCargo(item));
  1264. return true;
  1265. }
  1266. /**@fn CanLoadItemIntoCargo
  1267. * @brief calls this->CanLoadItemIntoCargo(item), is called on server start when loading in the storage
  1268. * @return true if action allowed
  1269. *
  1270. * @note: return scriptConditionExecute(this, item, "CanLoadItemIntoCargo");
  1271. **/
  1272. bool CanLoadItemIntoCargo(EntityAI item)
  1273. {
  1274. return true;
  1275. }
  1276. /**@fn CanPutInCargo
  1277. * @brief calls this->CanPutInCargo(parent)
  1278. * @return true if action allowed
  1279. *
  1280. * @note: return scriptConditionExecute(this, parent, "CanPutInCargo");
  1281. **/
  1282. bool CanPutInCargo (EntityAI parent)
  1283. {
  1284. return !IsHologram();
  1285. }
  1286. /**@fn CanSwapItemInCargo
  1287. * @brief calls this->CanSwapItemInCargo(child_entity, new_entity)
  1288. * @return true if action allowed
  1289. *
  1290. * @note: return ScriptConditionExecute(GetOwner(), child_entity, "CanSwapItemInCargo", new_entity);
  1291. **/
  1292. bool CanSwapItemInCargo (EntityAI child_entity, EntityAI new_entity)
  1293. {
  1294. if (GetInventory() && GetInventory().GetCargo())
  1295. return GetInventory().GetCargo().CanSwapItemInCargo(child_entity, new_entity));
  1296. return true;
  1297. }
  1298. /**@fn CanReleaseCargo
  1299. * @brief calls this->CanReleaseCargo(cargo)
  1300. * @return true if action allowed
  1301. *
  1302. * @note: return scriptConditionExecute(this, cargo, "CanReleaseCargo");
  1303. **/
  1304. bool CanReleaseCargo (EntityAI cargo)
  1305. {
  1306. return true;
  1307. }
  1308. /**@fn CanRemoveFromCargo
  1309. * @brief calls this->CanRemoveFromCargo(parent)
  1310. * @return true if action allowed
  1311. *
  1312. * @note: return scriptConditionExecute(this, parent, "CanRemoveFromCargo");
  1313. **/
  1314. bool CanRemoveFromCargo (EntityAI parent)
  1315. {
  1316. return true;
  1317. }
  1318. /**@fn CanReceiveItemIntoInventory
  1319. * @brief calls this->CanReceiveItemIntoInventory(item)
  1320. * @return true if action allowed
  1321. *
  1322. * @note: return scriptConditionExecute(this, , "CanReceiveItemIntoInventory");
  1323. **/
  1324. /*bool CanReceiveItemIntoInventory (EntityAI entity_ai)
  1325. {
  1326. return true;
  1327. }*/
  1328. /**@fn CanPutInInventory
  1329. * @brief calls this->CanPutInInventory(parent)
  1330. * @return true if action allowed
  1331. *
  1332. * @note: return scriptConditionExecute(this, parent, "ConditionIntoInventory");
  1333. **/
  1334. /*bool CanPutInInventory (EntityAI parent)
  1335. {
  1336. return true;
  1337. }*/
  1338. /**@fn CanReceiveItemIntoHands
  1339. * @brief calls this->CanReceiveItemIntoHands(item_to_hands)
  1340. * @return true if action allowed
  1341. *
  1342. * @note: scriptConditionExecute(this, item_to_hands, "CanReceiveItemIntoHands");
  1343. **/
  1344. bool CanReceiveItemIntoHands (EntityAI item_to_hands)
  1345. {
  1346. return true;
  1347. }
  1348. bool AreChildrenAccessible()
  1349. {
  1350. InventoryLocation lcn = new InventoryLocation();
  1351. EntityAI ent = this;
  1352. int attachmentDepth = 0;
  1353. while (ent)
  1354. {
  1355. if (ent.GetInventory().GetCurrentInventoryLocation(lcn) && lcn.IsValid())
  1356. {
  1357. if (lcn.GetType() == InventoryLocationType.CARGO || lcn.GetType() == InventoryLocationType.PROXYCARGO)
  1358. {
  1359. return false;
  1360. }
  1361. //hands treated as regular attachment here
  1362. if (lcn.GetType() == InventoryLocationType.ATTACHMENT || lcn.GetType() == InventoryLocationType.HANDS)
  1363. {
  1364. attachmentDepth++;
  1365. }
  1366. }
  1367. ent = ent.GetHierarchyParent();
  1368. }
  1369. return attachmentDepth <= GameConstants.INVENTORY_MAX_REACHABLE_DEPTH_ATT;
  1370. }
  1371. bool IsBeingPlaced()
  1372. {
  1373. return false;
  1374. }
  1375. override bool IsHologram()
  1376. {
  1377. return false;
  1378. }
  1379. bool CanSaveItemInHands (EntityAI item_in_hands)
  1380. {
  1381. return true;
  1382. }
  1383. /**@fn CanPutIntoHands
  1384. * @brief calls this->CanPutIntoHands(parent)
  1385. * @return true if action allowed
  1386. *
  1387. * @note: return scriptConditionExecute(this, parent, "CanPutIntoHands");
  1388. **/
  1389. bool CanPutIntoHands (EntityAI parent)
  1390. {
  1391. return !IsHologram();
  1392. }
  1393. /**@fn CanReleaseFromHands
  1394. * @brief calls this->CanReleaseFromHands(handheld)
  1395. * @return true if action allowed
  1396. *
  1397. * @note: scriptConditionExecute(this, handheld, "CanReleaseFromHands");
  1398. **/
  1399. bool CanReleaseFromHands (EntityAI handheld)
  1400. {
  1401. return true;
  1402. }
  1403. /**@fn CanRemoveFromHands
  1404. * @brief calls this->CanRemoveFromHands(parent)
  1405. * @return true if action allowed
  1406. *
  1407. * @note: return scriptConditionExecute(this, parent, "CanRemoveFromHands");
  1408. **/
  1409. bool CanRemoveFromHands (EntityAI parent)
  1410. {
  1411. return true;
  1412. }
  1413. /**@fn CanDisplayAttachmentSlot
  1414. * @param slot_name->name of the attachment slot that will or won't be displayed
  1415. * @return true if attachment icon can be displayed in UI (inventory)
  1416. **/
  1417. bool CanDisplayAttachmentSlot( string slot_name )
  1418. {
  1419. Debug.LogWarning("Obsolete function - use CanDisplayAttachmentSlot with slot id parameter");
  1420. return InventorySlots.GetShowForSlotId(InventorySlots.GetSlotIdFromString(slot_name));
  1421. }
  1422. /**@fn CanDisplayAttachmentSlot
  1423. * @param slot_id->id of the attachment slot that will or won't be displayed
  1424. * @return true if attachment icon can be displayed in UI (inventory)
  1425. **/
  1426. bool CanDisplayAttachmentSlot( int slot_id )
  1427. {
  1428. return InventorySlots.GetShowForSlotId(slot_id);
  1429. }
  1430. /**@fn CanDisplayAnyAttachmentSlot
  1431. * @return true if any attachment slot can be shown
  1432. **/
  1433. bool CanDisplayAnyAttachmentSlot()
  1434. {
  1435. int count = GetInventory().GetAttachmentSlotsCount();
  1436. int slotID;
  1437. for (int i = 0; i < count; i++)
  1438. {
  1439. slotID = GetInventory().GetAttachmentSlotId(i);
  1440. if (CanDisplayAttachmentSlot(slotID))
  1441. {
  1442. return true;
  1443. }
  1444. }
  1445. return false;
  1446. }
  1447. /**@fn CanDisplayAttachmentCategory
  1448. * @param category_name->name of the attachment category that will or won't be displayed
  1449. * @return true if attachment icon can be displayed in UI (inventory)
  1450. **/
  1451. bool CanDisplayAttachmentCategory( string category_name )
  1452. {
  1453. return true;
  1454. }
  1455. /**@fn CanDisplayCargo
  1456. * @return true if cargo can be displayed in UI (inventory)
  1457. **/
  1458. bool CanDisplayCargo()
  1459. {
  1460. return GetInventory().GetCargo() != null;
  1461. }
  1462. /**@fn CanAssignToQuickbar
  1463. * @return true if item can be assigned to quickbar safely
  1464. **/
  1465. bool CanAssignToQuickbar()
  1466. {
  1467. return true;
  1468. }
  1469. /**@fn CanAssignAttachmentsToQuickbar
  1470. * @return true if attached item can be assigned to quickbar safely
  1471. **/
  1472. bool CanAssignAttachmentsToQuickbar()
  1473. {
  1474. return true;
  1475. }
  1476. /**@fn IgnoreOutOfReachCondition
  1477. * @return if true, attachment condition for out of reach (inventory) will be ignored
  1478. **/
  1479. bool IgnoreOutOfReachCondition()
  1480. {
  1481. return GetHierarchyRootPlayer() == GetGame().GetPlayer();
  1482. }
  1483. // !Called on CHILD when it's attached to parent.
  1484. void OnWasAttached( EntityAI parent, int slot_id );
  1485. // !Called on CHILD when it's detached from parent.
  1486. void OnWasDetached( EntityAI parent, int slot_id )
  1487. {
  1488. if (!IsFlagSet(EntityFlags.VISIBLE))
  1489. {
  1490. SetInvisible(false);
  1491. OnInvisibleSet(false);
  1492. SetInvisibleRecursive(false,parent);
  1493. }
  1494. }
  1495. void OnCargoChanged() { }
  1496. bool IsTakeable()
  1497. {
  1498. return false;
  1499. }
  1500. proto native GameInventory GetInventory();
  1501. proto native void CreateAndInitInventory();
  1502. proto native void DestroyInventory();
  1503. int GetSlotsCountCorrect()
  1504. {
  1505. if (GetInventory())
  1506. return GetInventory().GetAttachmentSlotsCount();
  1507. else
  1508. return -1;
  1509. }
  1510. EntityAI FindAttachmentBySlotName(string slot_name)
  1511. {
  1512. if ( GetGame() )
  1513. {
  1514. int slot_id = InventorySlots.GetSlotIdFromString(slot_name);
  1515. if (slot_id != InventorySlots.INVALID)
  1516. return GetInventory().FindAttachment(slot_id);
  1517. }
  1518. return null;
  1519. }
  1520. // Check whether attachmnent slot is reserved
  1521. bool IsSlotReserved(int slotID)
  1522. {
  1523. Man player = GetHierarchyRootPlayer();
  1524. if (!player)
  1525. return false;
  1526. HumanInventory inv = player.GetHumanInventory();
  1527. if (!inv || inv.GetUserReservedLocationCount() == 0)
  1528. return false;
  1529. int id = inv.FindFirstUserReservedLocationIndexForContainer(this);
  1530. InventoryLocation loc = new InventoryLocation();
  1531. if (id == -1)
  1532. return false;
  1533. inv.GetUserReservedLocation(id, loc);
  1534. if (loc.GetSlot() != slotID)
  1535. return false;
  1536. return true;
  1537. }
  1538. /**@fn IsLockedInSlot
  1539. * @return true if entity is locked in attachment slot
  1540. **/
  1541. bool IsLockedInSlot()
  1542. {
  1543. EntityAI parent = GetHierarchyParent();
  1544. if ( parent )
  1545. {
  1546. InventoryLocation inventory_location = new InventoryLocation();
  1547. GetInventory().GetCurrentInventoryLocation( inventory_location );
  1548. return parent.GetInventory().GetSlotLock( inventory_location.GetSlot() );
  1549. }
  1550. return false;
  1551. }
  1552. /**
  1553. \brief Put item anywhere into this entity (as attachment or into cargo, recursively)
  1554. */
  1555. bool PredictiveTakeEntityToInventory (FindInventoryLocationType flags, notnull EntityAI item)
  1556. {
  1557. if ( GetGame().IsMultiplayer() )
  1558. return GetInventory().TakeEntityToInventory(InventoryMode.JUNCTURE, flags, item);
  1559. else
  1560. return GetInventory().TakeEntityToInventory(InventoryMode.PREDICTIVE, flags, item);
  1561. }
  1562. bool LocalTakeEntityToInventory (FindInventoryLocationType flags, notnull EntityAI item)
  1563. {
  1564. return GetInventory().TakeEntityToInventory(InventoryMode.LOCAL, flags, item);
  1565. }
  1566. bool ServerTakeEntityToInventory (FindInventoryLocationType flags, notnull EntityAI item)
  1567. {
  1568. return GetInventory().TakeEntityToInventory(InventoryMode.SERVER, flags, item);
  1569. }
  1570. bool PredictiveTakeEntityToTargetInventory (notnull EntityAI target, FindInventoryLocationType flags, notnull EntityAI item)
  1571. {
  1572. if ( GetGame().IsMultiplayer() )
  1573. return GetInventory().TakeEntityToTargetInventory(InventoryMode.JUNCTURE, target, flags, item);
  1574. else
  1575. return GetInventory().TakeEntityToTargetInventory(InventoryMode.PREDICTIVE, target, flags, item);
  1576. }
  1577. bool LocalTakeEntityToTargetInventory (notnull EntityAI target, FindInventoryLocationType flags, notnull EntityAI item)
  1578. {
  1579. return GetInventory().TakeEntityToTargetInventory(InventoryMode.LOCAL, target, flags, item);
  1580. }
  1581. bool ServerTakeEntityToTargetInventory (notnull EntityAI target, FindInventoryLocationType flags, notnull EntityAI item)
  1582. {
  1583. return GetInventory().TakeEntityToTargetInventory(InventoryMode.SERVER, target, flags, item);
  1584. }
  1585. /**
  1586. \brief Put item into into cargo
  1587. */
  1588. bool PredictiveTakeEntityToCargo (notnull EntityAI item)
  1589. {
  1590. if ( GetGame().IsMultiplayer() )
  1591. return GetInventory().TakeEntityToCargo(InventoryMode.JUNCTURE, item);
  1592. else
  1593. return GetInventory().TakeEntityToCargo(InventoryMode.PREDICTIVE, item);
  1594. }
  1595. bool LocalTakeEntityToCargo (notnull EntityAI item)
  1596. {
  1597. return GetInventory().TakeEntityToCargo(InventoryMode.LOCAL, item);
  1598. }
  1599. bool ServerTakeEntityToCargo (notnull EntityAI item)
  1600. {
  1601. return GetInventory().TakeEntityToCargo(InventoryMode.SERVER, item);
  1602. }
  1603. bool PredictiveTakeEntityToTargetCargo (notnull EntityAI target, notnull EntityAI item)
  1604. {
  1605. if ( GetGame().IsMultiplayer() )
  1606. return GetInventory().TakeEntityToTargetCargo(InventoryMode.JUNCTURE, target, item);
  1607. else
  1608. return GetInventory().TakeEntityToTargetCargo(InventoryMode.PREDICTIVE, target, item);
  1609. }
  1610. bool LocalTakeEntityToTargetCargo (notnull EntityAI target, notnull EntityAI item)
  1611. {
  1612. return GetInventory().TakeEntityToTargetCargo(InventoryMode.LOCAL, target, item);
  1613. }
  1614. bool ServerTakeEntityToTargetCargo (notnull EntityAI target, notnull EntityAI item)
  1615. {
  1616. return GetInventory().TakeEntityToTargetCargo(InventoryMode.SERVER, target, item);
  1617. }
  1618. /**
  1619. \brief Put item into into cargo on specific cargo location
  1620. */
  1621. bool PredictiveTakeEntityToCargoEx (notnull EntityAI item, int idx, int row, int col)
  1622. {
  1623. if ( GetGame().IsMultiplayer() )
  1624. return GetInventory().TakeEntityToCargoEx(InventoryMode.JUNCTURE, item, idx, row, col);
  1625. else
  1626. return GetInventory().TakeEntityToCargoEx(InventoryMode.PREDICTIVE, item, idx, row, col);
  1627. }
  1628. bool LocalTakeEntityToCargoEx (notnull EntityAI item, int idx, int row, int col)
  1629. {
  1630. return GetInventory().TakeEntityToCargoEx(InventoryMode.LOCAL, item, idx, row, col);
  1631. }
  1632. bool PredictiveTakeEntityToTargetCargoEx (notnull CargoBase cargo, notnull EntityAI item, int row, int col)
  1633. {
  1634. if ( GetGame().IsMultiplayer() )
  1635. return GetInventory().TakeEntityToTargetCargoEx(InventoryMode.JUNCTURE, cargo, item, row, col);
  1636. else
  1637. return GetInventory().TakeEntityToTargetCargoEx(InventoryMode.PREDICTIVE, cargo, item, row, col);
  1638. }
  1639. bool LocalTakeEntityToTargetCargoEx (notnull CargoBase cargo, notnull EntityAI item, int row, int col)
  1640. {
  1641. return GetInventory().TakeEntityToTargetCargoEx(InventoryMode.LOCAL, cargo, item, row, col);
  1642. }
  1643. bool ServerTakeEntityToTargetCargoEx (notnull CargoBase cargo, notnull EntityAI item, int row, int col)
  1644. {
  1645. return GetInventory().TakeEntityToTargetCargoEx(InventoryMode.SERVER, cargo, item, row, col);
  1646. }
  1647. /**
  1648. \brief Returns if item can be added as attachment on specific slot. Note that slot index IS NOT slot ID! Slot ID is defined in DZ/data/config.cpp
  1649. */
  1650. bool PredictiveTakeEntityAsAttachmentEx (notnull EntityAI item, int slot)
  1651. {
  1652. if ( GetGame().IsMultiplayer() )
  1653. return GetInventory().TakeEntityAsAttachmentEx(InventoryMode.JUNCTURE, item, slot);
  1654. else
  1655. return GetInventory().TakeEntityAsAttachmentEx(InventoryMode.PREDICTIVE, item, slot);
  1656. }
  1657. bool LocalTakeEntityAsAttachmentEx (notnull EntityAI item, int slot)
  1658. {
  1659. return GetInventory().TakeEntityAsAttachmentEx(InventoryMode.LOCAL, item, slot);
  1660. }
  1661. bool ServerTakeEntityAsAttachmentEx (notnull EntityAI item, int slot)
  1662. {
  1663. return GetInventory().TakeEntityAsAttachmentEx(InventoryMode.SERVER, item, slot);
  1664. }
  1665. bool PredictiveTakeEntityToTargetAttachmentEx (notnull EntityAI target, notnull EntityAI item, int slot)
  1666. {
  1667. if ( GetGame().IsMultiplayer() )
  1668. return GetInventory().TakeEntityAsTargetAttachmentEx(InventoryMode.JUNCTURE, target, item, slot);
  1669. else
  1670. return GetInventory().TakeEntityAsTargetAttachmentEx(InventoryMode.PREDICTIVE, target, item, slot);
  1671. }
  1672. bool LocalTakeEntityToTargetAttachmentEx (notnull EntityAI target, notnull EntityAI item, int slot)
  1673. {
  1674. return GetInventory().TakeEntityAsTargetAttachmentEx(InventoryMode.LOCAL, target, item, slot);
  1675. }
  1676. bool ServerTakeEntityToTargetAttachmentEx (notnull EntityAI target, notnull EntityAI item, int slot)
  1677. {
  1678. return GetInventory().TakeEntityAsTargetAttachmentEx(InventoryMode.SERVER, target, item, slot);
  1679. }
  1680. bool PredictiveTakeEntityToTargetAttachment (notnull EntityAI target, notnull EntityAI item)
  1681. {
  1682. if ( GetGame().IsMultiplayer() )
  1683. return GetInventory().TakeEntityAsTargetAttachment(InventoryMode.JUNCTURE, target, item);
  1684. else
  1685. return GetInventory().TakeEntityAsTargetAttachment(InventoryMode.PREDICTIVE, target, item);
  1686. }
  1687. bool LocalTakeEntityToTargetAttachment (notnull EntityAI target, notnull EntityAI item)
  1688. {
  1689. return GetInventory().TakeEntityAsTargetAttachment(InventoryMode.LOCAL, target, item);
  1690. }
  1691. bool ServerTakeEntityToTargetAttachment (notnull EntityAI target, notnull EntityAI item)
  1692. {
  1693. return GetInventory().TakeEntityAsTargetAttachment(InventoryMode.SERVER, target, item);
  1694. }
  1695. bool PredictiveTakeToDst (notnull InventoryLocation src, notnull InventoryLocation dst)
  1696. {
  1697. if ( GetGame().IsMultiplayer() )
  1698. return GetInventory().TakeToDst(InventoryMode.JUNCTURE, src, dst);
  1699. else
  1700. return GetInventory().TakeToDst(InventoryMode.PREDICTIVE, src, dst);
  1701. }
  1702. bool LocalTakeToDst (notnull InventoryLocation src, notnull InventoryLocation dst)
  1703. {
  1704. return GetInventory().TakeToDst(InventoryMode.LOCAL, src, dst);
  1705. }
  1706. bool ServerTakeToDst (notnull InventoryLocation src, notnull InventoryLocation dst)
  1707. {
  1708. return GetInventory().TakeToDst(InventoryMode.SERVER, src, dst);
  1709. }
  1710. /**
  1711. \brief Put item into as attachment
  1712. */
  1713. bool PredictiveTakeEntityAsAttachment(notnull EntityAI item)
  1714. {
  1715. if (GetGame().IsMultiplayer())
  1716. return GetInventory().TakeEntityAsAttachment(InventoryMode.JUNCTURE, item);
  1717. else
  1718. return GetInventory().TakeEntityAsAttachment(InventoryMode.PREDICTIVE, item);
  1719. }
  1720. bool LocalTakeEntityAsAttachment (notnull EntityAI item)
  1721. {
  1722. return GetInventory().TakeEntityAsAttachment(InventoryMode.LOCAL, item);
  1723. }
  1724. bool ServerTakeEntityAsAttachment (notnull EntityAI item)
  1725. {
  1726. return GetInventory().TakeEntityAsAttachment(InventoryMode.SERVER, item);
  1727. }
  1728. bool PredictiveDropEntity(notnull EntityAI item)
  1729. {
  1730. return false;
  1731. }
  1732. bool LocalDropEntity(notnull EntityAI item)
  1733. {
  1734. return false;
  1735. }
  1736. bool ServerDropEntity(notnull EntityAI item)
  1737. {
  1738. return false;
  1739. }
  1740. /**
  1741. \brief Get attached entity by type
  1742. */
  1743. EntityAI GetAttachmentByType(typename type)
  1744. {
  1745. for ( int i = 0; i < GetInventory().AttachmentCount(); i++ )
  1746. {
  1747. EntityAI attachment = GetInventory().GetAttachmentFromIndex( i );
  1748. if ( attachment && attachment.IsInherited( type ) )
  1749. return attachment;
  1750. }
  1751. return NULL;
  1752. }
  1753. /**
  1754. \brief Get attached entity by config type name
  1755. */
  1756. EntityAI GetAttachmentByConfigTypeName(string type)
  1757. {
  1758. for ( int i = 0; i < GetInventory().AttachmentCount(); i++ )
  1759. {
  1760. EntityAI attachment = GetInventory().GetAttachmentFromIndex ( i );
  1761. if ( attachment.IsKindOf ( type ) )
  1762. return attachment;
  1763. }
  1764. return NULL;
  1765. }
  1766. /**
  1767. \brief Returns if item can be dropped out from this entity
  1768. */
  1769. bool CanDropEntity(notnull EntityAI item)
  1770. {
  1771. return true;
  1772. }
  1773. EntityAI SpawnInInventoryOrGroundPos(string object_name, GameInventory inv, vector pos)
  1774. {
  1775. if (inv)
  1776. {
  1777. EntityAI res = inv.CreateInInventory(object_name);
  1778. if (res)
  1779. {
  1780. return res;
  1781. }
  1782. }
  1783. return SpawnEntityOnGroundPos(object_name, pos);
  1784. }
  1785. /**
  1786. **/
  1787. EntityAI SpawnEntityOnGroundPos(string object_name, vector pos)
  1788. {
  1789. InventoryLocation il = new InventoryLocation();
  1790. vector mat[4];
  1791. Math3D.MatrixIdentity4(mat);
  1792. mat[3] = pos;
  1793. il.SetGround(NULL, mat);
  1794. return SpawnEntity(object_name, il,ECE_PLACE_ON_SURFACE,RF_DEFAULT);
  1795. }
  1796. /**
  1797. **/
  1798. EntityAI SpawnEntityOnGround(string object_name, vector mat[4])
  1799. {
  1800. InventoryLocation il = new InventoryLocation();
  1801. il.SetGround(NULL, mat);
  1802. return SpawnEntity(object_name, il,ECE_PLACE_ON_SURFACE,RF_DEFAULT);
  1803. }
  1804. //----------------------------------------------------------------
  1805. bool CanSwapEntities(EntityAI otherItem, InventoryLocation otherDestination, InventoryLocation destination)
  1806. {
  1807. return true;
  1808. }
  1809. // Forward declarations to allow lower modules to access properties that are modified from higher modules
  1810. // These are mainly used within the ItemBase
  1811. void SetWet(float value, bool allow_client = false);
  1812. void AddWet(float value);
  1813. void SetWetMax();
  1814. float GetWet()
  1815. {
  1816. return 0;
  1817. }
  1818. float GetWetMax()
  1819. {
  1820. return 0;
  1821. }
  1822. float GetWetMin()
  1823. {
  1824. return 0;
  1825. }
  1826. float GetWetInit()
  1827. {
  1828. return 0;
  1829. }
  1830. bool HasWetness()
  1831. {
  1832. return GetWetMax() - GetWetMin() != 0;
  1833. }
  1834. void OnWetChanged(float newVal, float oldVal);
  1835. void OnWetLevelChanged(EWetnessLevel newLevel, EWetnessLevel oldLevel);
  1836. // ! Returns current wet level of the entity
  1837. EWetnessLevel GetWetLevel();
  1838. // ! Calculates wet level from a given wetness, to get level of an entity, use 'GetWetLevel()' instead
  1839. static EWetnessLevel GetWetLevelInternal(float wetness)
  1840. {
  1841. if (wetness < GameConstants.STATE_DAMP)
  1842. {
  1843. return EWetnessLevel.DRY;
  1844. }
  1845. else if (wetness < GameConstants.STATE_WET)
  1846. {
  1847. return EWetnessLevel.DAMP;
  1848. }
  1849. else if (wetness < GameConstants.STATE_SOAKING_WET)
  1850. {
  1851. return EWetnessLevel.WET;
  1852. }
  1853. else if (wetness < GameConstants.STATE_DRENCHED)
  1854. {
  1855. return EWetnessLevel.SOAKING;
  1856. }
  1857. return EWetnessLevel.DRENCHED;
  1858. }
  1859. //----------------------------------------------------------------
  1860. bool HasQuantity()
  1861. {
  1862. return false;
  1863. }
  1864. bool SetQuantity(float value, bool destroy_config = true, bool destroy_forced = false, bool allow_client = false, bool clamp_to_stack_max = true);
  1865. float GetQuantity()
  1866. {
  1867. return 0;
  1868. }
  1869. float GetQuantityNormalized()
  1870. {
  1871. return 0;
  1872. }
  1873. int GetQuantityMax()
  1874. {
  1875. return 0;
  1876. }
  1877. int GetQuantityMin()
  1878. {
  1879. return 0;
  1880. }
  1881. void SetQuantityToMinimum();
  1882. int GetTargetQuantityMax(int attSlotID = -1)
  1883. {
  1884. return 0;
  1885. }
  1886. int GetQuickBarBonus()
  1887. {
  1888. return 0;
  1889. }
  1890. //----------------------------------------------------------------
  1891. bool UseConfigInitTemperature()
  1892. {
  1893. return (IsMan() || IsAnimal() || IsZombie()) && IsAlive() || IsCorpse();
  1894. }
  1895. protected void InitTemperature()
  1896. {
  1897. EntityAI rootParent = GetHierarchyRoot();
  1898. bool isParentAliveOrganism = false;
  1899. if (rootParent && rootParent != this)
  1900. isParentAliveOrganism = (rootParent.IsMan() || rootParent.IsAnimal() || rootParent.IsZombie()) && rootParent.IsAlive();
  1901. if (UseConfigInitTemperature())
  1902. {
  1903. SetTemperatureDirect(m_VarTemperatureInit);
  1904. }
  1905. else if (isParentAliveOrganism) //living player's inventory etc.
  1906. {
  1907. SetTemperatureDirect(rootParent.GetTemperature());
  1908. }
  1909. else
  1910. {
  1911. SetTemperatureDirect(g_Game.GetMission().GetWorldData().GetBaseEnvTemperatureAtObject(this));
  1912. }
  1913. SetFrozen(GetTemperature() < GetTemperatureFreezeThreshold());
  1914. }
  1915. void SetTemperatureDirect(float value, bool allow_client = false)
  1916. {
  1917. if (!IsServerCheck(allow_client))
  1918. return;
  1919. float min = GetTemperatureMin();
  1920. float max = GetTemperatureMax();
  1921. float previousValue = m_VarTemperature;
  1922. m_VarTemperature = Math.Clamp(value, min, max);
  1923. if (previousValue != m_VarTemperature)
  1924. SetVariableMask(VARIABLE_TEMPERATURE);
  1925. }
  1926. //! not really deprecated, but missing context info from TemperatureData. Default values used instead.
  1927. void SetTemperature(float value, bool allow_client = false)
  1928. {
  1929. /*#ifdef DEVELOPER
  1930. ErrorEx("Obsolete 'SetTemperature' called! Metadata will be extrapolated from base values.");
  1931. #endif*/
  1932. if (!IsServerCheck(allow_client))
  1933. return;
  1934. SetTemperatureEx(new TemperatureData(value));
  1935. }
  1936. void AddTemperature(float value)
  1937. {
  1938. SetTemperature(value + GetTemperature());
  1939. }
  1940. ////////////////////////////////////////////
  1941. //! sets temperature, handles base overheating and freezing state progression logics
  1942. void SetTemperatureEx(TemperatureData data)
  1943. {
  1944. #ifdef DEVELOPER
  1945. m_LastFTChangeTime = -1;
  1946. m_PresumedTimeRemaining = -1;
  1947. #endif
  1948. if (!CanHaveTemperature())
  1949. {
  1950. Debug.Log("SetTemperatureEx | entity " + this + " does not have temperature range defined!");
  1951. return;
  1952. }
  1953. if (!m_TAC.TryAccessSource(data))
  1954. return;
  1955. if (!IsServerCheck(false))
  1956. return;
  1957. InterpolateTempData(TemperatureDataInterpolated.Cast(data));
  1958. float target = Math.Clamp(data.m_AdjustedTarget, GetTemperatureMin(), GetTemperatureMax());
  1959. float delta;
  1960. //overheating
  1961. if (CanItemOverheat())
  1962. {
  1963. if (GetTemperature() > GetItemOverheatThreshold())
  1964. delta = data.m_AdjustedTarget - GetTemperature();
  1965. else
  1966. delta = data.m_AdjustedTarget - GetItemOverheatThreshold();
  1967. HandleItemOverheating(delta,data);
  1968. }
  1969. //freezing, can obstruct temperature change
  1970. if (CanFreeze())
  1971. {
  1972. if (!m_IsFrozen)
  1973. {
  1974. delta = target - GetTemperatureFreezeThreshold();
  1975. if (target < GetTemperatureFreezeThreshold())
  1976. {
  1977. //first crossing the threshold
  1978. if (m_VarTemperature >= GetTemperatureFreezeThreshold()) //going DOWN or STAYING AT THRESHOLD, FREEZING;
  1979. {
  1980. SetTemperatureDirect(GetTemperatureFreezeThreshold());
  1981. }
  1982. else //going UP, still FREEZING
  1983. {
  1984. SetTemperatureDirect(target);
  1985. }
  1986. HandleFreezingProgression(delta,data);
  1987. }
  1988. else
  1989. {
  1990. SetTemperatureDirect(target);
  1991. if (target > GetTemperatureFreezeThreshold())
  1992. HandleFreezingProgression(delta,data);
  1993. }
  1994. }
  1995. else
  1996. {
  1997. delta = target - GetTemperatureThawThreshold();
  1998. if (target > GetTemperatureThawThreshold())
  1999. {
  2000. //first crossing the threshold
  2001. if (m_VarTemperature <= GetTemperatureThawThreshold()) //going UP, THAWING
  2002. {
  2003. SetTemperatureDirect(GetTemperatureThawThreshold());
  2004. }
  2005. else //going DOWN, still THAWING
  2006. {
  2007. SetTemperatureDirect(target);
  2008. }
  2009. HandleFreezingProgression(delta,data);
  2010. }
  2011. else
  2012. {
  2013. SetTemperatureDirect(target);
  2014. if (target < GetTemperatureThawThreshold())
  2015. HandleFreezingProgression(delta,data);
  2016. }
  2017. }
  2018. }
  2019. else //!CanFreeze
  2020. {
  2021. SetTemperatureDirect(target);
  2022. }
  2023. }
  2024. //! refreshes access without setting temperature, keeps the source locked in
  2025. void RefreshTemperatureAccess(TemperatureData data)
  2026. {
  2027. if (!CanHaveTemperature())
  2028. {
  2029. Debug.Log("RefreshTemperatureAccess | entity " + this + " does not have temperature range defined!");
  2030. return;
  2031. }
  2032. m_TAC.TryAccessSource(data);
  2033. }
  2034. void InterpolateTempData(TemperatureDataInterpolated data)
  2035. {
  2036. if (data)
  2037. data.InterpolateTemperatureDelta(GetTemperature());
  2038. }
  2039. ////////////////////////////////////////////
  2040. //! presumably for debug purposes?
  2041. void SetTemperatureMax()
  2042. {
  2043. SetTemperatureDirect(GetTemperatureMax());
  2044. SetFrozen(GetTemperature() < GetTemperatureFreezeThreshold());
  2045. }
  2046. float GetTemperature()
  2047. {
  2048. return m_VarTemperature;
  2049. }
  2050. float GetTemperatureInit()
  2051. {
  2052. return m_VarTemperatureInit;
  2053. }
  2054. float GetTemperatureMin()
  2055. {
  2056. return m_VarTemperatureMin;
  2057. }
  2058. float GetTemperatureMax()
  2059. {
  2060. return m_VarTemperatureMax;
  2061. }
  2062. //! specifically for cooking system, to get heat source target temperatures
  2063. bool GetCookingTargetTemperature(out float temperature)
  2064. {
  2065. return false;
  2066. }
  2067. /**
  2068. \brief Returns temperature change speed multiplier for this item and all its children (multiplicative interaction)
  2069. \note Values > 1 accelerate, values in <0,1) interval decelerate. Values < 0 should not be used here, but I'm not your mom.
  2070. */
  2071. float GetHeatPermeabilityCoef()
  2072. {
  2073. return m_VarHeatPermeabilityCoef;
  2074. }
  2075. float GetTemperatureFreezeThreshold()
  2076. {
  2077. return m_VarTemperatureFreezeThreshold;
  2078. }
  2079. float GetTemperatureThawThreshold()
  2080. {
  2081. return m_VarTemperatureThawThreshold;
  2082. }
  2083. float GetTemperatureFreezeTime()
  2084. {
  2085. return m_VarTemperatureFreezeTime;
  2086. }
  2087. float GetTemperatureThawTime()
  2088. {
  2089. return m_VarTemperatureThawTime;
  2090. }
  2091. //! on server only
  2092. float GetFreezeThawProgress()
  2093. {
  2094. return m_FreezeThawProgress;
  2095. }
  2096. //! on server only
  2097. bool IsFreezeThawProgressFinished()
  2098. {
  2099. return m_FreezeThawProgress <= 0.0 || m_FreezeThawProgress >= 1.0;
  2100. }
  2101. //! 0->1 when freezing, 1->0 when thawing
  2102. protected void SetFreezeThawProgress(float val)
  2103. {
  2104. m_FreezeThawProgress = val;
  2105. }
  2106. bool CanFreeze()
  2107. {
  2108. return CanHaveTemperature() && GetTemperatureFreezeThreshold() > GetTemperatureMin() && GetTemperatureThawThreshold() < GetTemperatureMax();
  2109. }
  2110. bool GetIsFrozen()
  2111. {
  2112. return m_IsFrozen;
  2113. }
  2114. void SetFrozen(bool frozen)
  2115. {
  2116. if (!CanFreeze() && frozen)
  2117. return;
  2118. bool previous = m_IsFrozen;
  2119. m_IsFrozen = frozen;
  2120. SetFreezeThawProgress(frozen);
  2121. if (previous != frozen)
  2122. {
  2123. SetSynchDirty();
  2124. OnFreezeStateChangeServer();
  2125. }
  2126. }
  2127. protected void HandleFreezingProgression(float deltaHeat, TemperatureData data)
  2128. {
  2129. float progressVal = m_FreezeThawProgress;
  2130. float progressDelta = 1;
  2131. if (deltaHeat > 0)
  2132. progressDelta = -1;
  2133. if (data.m_UpdateTimeInfo == -1)
  2134. progressDelta = (-deltaHeat / GameConstants.TEMPERATURE_RATE_AVERAGE_ABS) * GameConstants.TEMPERATURE_FREEZETHAW_LEGACY_COEF; //reverse-calculate the progress if actual time is not available
  2135. else
  2136. progressDelta *= data.m_UpdateTimeInfo;
  2137. if (progressDelta == 0)
  2138. return;
  2139. float changeTimeDefault;
  2140. float changeTimeMin;
  2141. float changeTime;
  2142. if (!m_IsFrozen)
  2143. {
  2144. changeTimeDefault = GetTemperatureFreezeTime();
  2145. changeTimeMin = GameConstants.TEMPERATURE_TIME_FREEZE_MIN;
  2146. }
  2147. else
  2148. {
  2149. changeTimeDefault = GetTemperatureThawTime();
  2150. changeTimeMin = GameConstants.TEMPERATURE_TIME_THAW_MIN;
  2151. }
  2152. float coef = data.m_UpdateTimeCoef;
  2153. if (deltaHeat < 0) //use cooling coef when freezing (mostly just to make sure)
  2154. coef = GameConstants.TEMP_COEF_COOLING_GLOBAL;
  2155. if (coef != 0)
  2156. changeTimeDefault *= 1/coef;
  2157. changeTime = Math.Lerp(Math.Max(changeTimeDefault,changeTimeMin),changeTimeMin,data.m_InterpolatedFraction);
  2158. progressVal = progressVal + progressDelta / changeTime;
  2159. float remnantTemp = 0;
  2160. if (!m_IsFrozen && progressVal >= 1)
  2161. {
  2162. SetFrozen(true);
  2163. if (progressVal > 1.0)
  2164. {
  2165. if (data.m_UpdateTimeInfo == -1)
  2166. remnantTemp = (progressVal - 1) * changeTime * GameConstants.TEMPERATURE_RATE_AVERAGE_ABS * -1;
  2167. else
  2168. remnantTemp = (((progressVal - 1) * changeTime) / progressDelta) * deltaHeat;
  2169. }
  2170. }
  2171. else if (m_IsFrozen && progressVal <= 0)
  2172. {
  2173. SetFrozen(false);
  2174. if (progressVal < 0.0)
  2175. {
  2176. if (data.m_UpdateTimeInfo == -1)
  2177. remnantTemp = -progressVal * changeTime * GameConstants.TEMPERATURE_RATE_AVERAGE_ABS;
  2178. else
  2179. remnantTemp = ((-progressVal * changeTime) / progressDelta) * deltaHeat;
  2180. }
  2181. }
  2182. else
  2183. {
  2184. if ((progressDelta < 0 && !m_IsFrozen) || (progressDelta > 0 && m_IsFrozen))
  2185. progressVal = (progressDelta * GameConstants.TEMPERATURE_FREEZETHAW_ACCELERATION_COEF) / changeTime + m_FreezeThawProgress;
  2186. SetFreezeThawProgress(Math.Clamp(progressVal,0,1));
  2187. }
  2188. if (remnantTemp >= GameConstants.TEMPERATURE_SENSITIVITY_THRESHOLD)//discards tiny values
  2189. SetTemperatureDirect(GetTemperature() + remnantTemp);
  2190. #ifdef DEVELOPER
  2191. if (progressVal > 0 && progressVal < 1)
  2192. {
  2193. m_LastFTChangeTime = changeTime;
  2194. if (!m_IsFrozen)
  2195. m_PresumedTimeRemaining = (1 - progressVal) * changeTime;
  2196. else
  2197. m_PresumedTimeRemaining = progressVal * changeTime;
  2198. }
  2199. #endif
  2200. }
  2201. void OnFreezeStateChangeClient();
  2202. void OnFreezeStateChangeServer();
  2203. //----------------------------------------------------------------
  2204. //! Overheat time CAN be 0, GameConstants.TEMPERATURE_TIME_OVERHEAT_MIN is ignored if so
  2205. bool CanItemOverheat()
  2206. {
  2207. return GetItemOverheatTime() >= 0;
  2208. }
  2209. //! if undefined, max temperature used as default
  2210. float GetItemOverheatThreshold()
  2211. {
  2212. return GetTemperatureMax();
  2213. }
  2214. //! any configured value >= 0 will simulate overheating
  2215. float GetItemOverheatTime()
  2216. {
  2217. return m_VarTemperatureOverheatTime;
  2218. }
  2219. bool IsItemOverheated()
  2220. {
  2221. return m_OverheatProgress >= 1;
  2222. }
  2223. float GetItemOverheatProgress()
  2224. {
  2225. return m_OverheatProgress;
  2226. }
  2227. void SetItemOverheatProgress(float val, float deltaTime = 0)
  2228. {
  2229. float previous = m_OverheatProgress;
  2230. m_OverheatProgress = Math.Clamp(val,0,1);
  2231. if (m_OverheatProgress >= 1)
  2232. {
  2233. if (previous < 1)
  2234. OnItemOverheatStart();
  2235. OnItemOverheat(deltaTime);
  2236. }
  2237. else if (previous >= 1)
  2238. {
  2239. OnItemOverheatEnd();
  2240. }
  2241. }
  2242. //! override to implement desired overheat behavior on entity
  2243. protected void OnItemOverheatStart();
  2244. protected void OnItemOverheat(float deltaTime); //! note, that the deltaTime could be reverse-calculated and not totally accurate
  2245. protected void OnItemOverheatEnd();
  2246. protected void HandleItemOverheating(float deltaHeat, TemperatureData data)
  2247. {
  2248. float deltaTime = 1;
  2249. float progressVal = m_OverheatProgress;
  2250. if (deltaHeat < 0)
  2251. deltaTime = -1;
  2252. if (data.m_UpdateTimeInfo == -1)
  2253. deltaTime = deltaHeat / GameConstants.TEMPERATURE_RATE_AVERAGE_ABS; //reverse-calculate the progress if actual time is not available
  2254. else
  2255. deltaTime *= data.m_UpdateTimeInfo;
  2256. if (GetItemOverheatTime() > 0)
  2257. {
  2258. float changeTime = Math.Lerp(Math.Max(GameConstants.TEMPERATURE_TIME_OVERHEAT_MIN,GetItemOverheatTime()),GameConstants.TEMPERATURE_TIME_OVERHEAT_MIN,Math.Clamp(data.m_InterpolatedFraction,0,1));
  2259. progressVal += deltaTime / changeTime;
  2260. }
  2261. else
  2262. {
  2263. if (deltaHeat < 0)
  2264. progressVal = 0;
  2265. else if (deltaHeat > 0)
  2266. progressVal = 1;
  2267. }
  2268. SetItemOverheatProgress(Math.Clamp(progressVal,0,1),deltaTime);
  2269. }
  2270. //----------------------------------------------------------------
  2271. void SetLiquidType(int value, bool allow_client = false);
  2272. int GetLiquidType()
  2273. {
  2274. return 0;
  2275. }
  2276. //----------------------------------------------------------------
  2277. void SetColor(int r, int g, int b, int a);
  2278. void GetColor(out int r,out int g,out int b,out int a)
  2279. {
  2280. r = -1;
  2281. g = -1;
  2282. b = -1;
  2283. a = -1;
  2284. }
  2285. //----------------------------------------------------------------
  2286. void SetStoreLoad(bool value);
  2287. bool IsStoreLoad()
  2288. {
  2289. return false;
  2290. }
  2291. void SetStoreLoadedQuantity(float value);
  2292. float GetStoreLoadedQuantity()
  2293. {
  2294. return 0.0;
  2295. }
  2296. //----------------------------------------------------------------
  2297. void SetCleanness(int value, bool allow_client = false);
  2298. int GetCleanness()
  2299. {
  2300. return 0;
  2301. }
  2302. //----------------------------------------------------------------
  2303. bool IsServerCheck(bool allow_client)
  2304. {
  2305. if (g_Game.IsServer())
  2306. return true;
  2307. if (allow_client)
  2308. return true;
  2309. if (GetGame().IsClient() && GetGame().IsMultiplayer())
  2310. {
  2311. Error("Attempting to change variable client side, variables are supposed to be changed on server only !!");
  2312. return false;
  2313. }
  2314. return true;
  2315. }
  2316. //----------------------------------------------------------------
  2317. HiddenSelectionsData GetHiddenSelectionsData()
  2318. {
  2319. return m_HiddenSelectionsData;
  2320. }
  2321. //! Returns index of the string found in cfg array 'hiddenSelections'. If it's not found then it returns -1.
  2322. int GetHiddenSelectionIndex( string selection )
  2323. {
  2324. if (m_HiddenSelectionsData)
  2325. return m_HiddenSelectionsData.GetHiddenSelectionIndex( selection );
  2326. return -1;
  2327. }
  2328. //! Returns the hiddenSelectionsTextures array from the object's config
  2329. override TStringArray GetHiddenSelections()
  2330. {
  2331. if (m_HiddenSelectionsData)
  2332. return m_HiddenSelectionsData.m_HiddenSelections;
  2333. else
  2334. return super.GetHiddenSelections();
  2335. }
  2336. //! Returns the hiddenSelectionsTextures array from the object's config
  2337. override TStringArray GetHiddenSelectionsTextures()
  2338. {
  2339. if (m_HiddenSelectionsData)
  2340. return m_HiddenSelectionsData.m_HiddenSelectionsTextures;
  2341. else
  2342. return super.GetHiddenSelectionsTextures();
  2343. }
  2344. //! Returns the hiddenSelectionsMaterials array from the object's config
  2345. override TStringArray GetHiddenSelectionsMaterials()
  2346. {
  2347. if (m_HiddenSelectionsData)
  2348. return m_HiddenSelectionsData.m_HiddenSelectionsMaterials;
  2349. else
  2350. return super.GetHiddenSelectionsMaterials();
  2351. }
  2352. /**
  2353. * @fn EntityPlaceOnSurfacePointWithRotation
  2354. * @brief applies correct rotation according to WRUtils::EntityPlacementRotation(type->GetRotationFlags())
  2355. *
  2356. * @param[out] trans \p the transform to apply the correct rotation on
  2357. * @param[in] pos \p position to check
  2358. * @param[in] dx \p up vector x to align to
  2359. * @param[in] dz \p up vector z to align to
  2360. * @param[in] fAngle \p angle to position
  2361. * @param[in] align \p align to surface
  2362. **/
  2363. proto native void PlaceOnSurfaceRotated(out vector trans[4], vector pos, float dx = 0, float dz = 0, float fAngle = 0, bool align = false);
  2364. /**
  2365. * @fn RegisterNetSyncVariableBool
  2366. * @brief registers bool variable synchronized over network
  2367. *
  2368. * @param[in] variableName \p which variable should be synchronized
  2369. **/
  2370. proto native void RegisterNetSyncVariableBool(string variableName);
  2371. /**
  2372. * @fn RegisterNetSyncVariableBoolSignal
  2373. * @brief when bool variable is true, it's sent to clients and become false again
  2374. *
  2375. * @param[in] variableName \p which variable should be synchronized
  2376. **/
  2377. proto native void RegisterNetSyncVariableBoolSignal(string variableName);
  2378. /**
  2379. * @fn RegisterNetSyncVariableInt
  2380. * @brief registers int variable synchronized over network
  2381. *
  2382. * @param[in] variableName \p which variable should be synchronized
  2383. * @param[in] minValue \p minimal value used for quantization (when minValue == maxValue, no quatization is done)
  2384. * @param[in] maxValue \p maximal value used for quantization (when minValue == maxValue, no quatization is done)
  2385. **/
  2386. proto native void RegisterNetSyncVariableInt(string variableName, int minValue = 0, int maxValue = 0);
  2387. /**
  2388. * @fn RegisterNetSyncVariableFloat
  2389. * @brief registers float variable synchronized over network
  2390. *
  2391. * @param[in] variableName \p which variable should be synchronized
  2392. * @param[in] minValue \p minimal value used for quantization (when minValue == maxValue, no quatization is done)
  2393. * @param[in] maxValue \p maximal value used for quantization (when minValue == maxValue, no quatization is done)
  2394. * @param[in] precision \p precision in number of digits after decimal point
  2395. **/
  2396. proto native void RegisterNetSyncVariableFloat(string variableName, float minValue = 0, float maxValue = 0, int precision = 1);
  2397. /**
  2398. * @fn RegisterNetSyncVariableObject
  2399. * @brief registers object variable synchronized over network, only synchronizes if network id is assigned. Doesn't handle object despawn on client
  2400. *
  2401. * @param[in] variableName \p which variable should be synchronized
  2402. **/
  2403. proto native void RegisterNetSyncVariableObject(string variableName);
  2404. proto native void UpdateNetSyncVariableInt(string variableName, float minValue = 0, float maxValue = 0);
  2405. proto native void UpdateNetSyncVariableFloat(string variableName, float minValue = 0, float maxValue = 0, int precision = 1);
  2406. proto native void SwitchLight(bool isOn);
  2407. //! Simple hidden selection state; 0 == hidden
  2408. proto native void SetSimpleHiddenSelectionState(int index, bool state);
  2409. proto native bool IsSimpleHiddenSelectionVisible(int index);
  2410. //! Change texture in hiddenSelections
  2411. proto native void SetObjectTexture(int index, string texture_name);
  2412. proto native owned string GetObjectTexture(int index);
  2413. //! Change material in hiddenSelections
  2414. proto native void SetObjectMaterial(int index, string mat_name);
  2415. proto native owned string GetObjectMaterial(int index);
  2416. proto native bool IsPilotLight();
  2417. proto native void SetPilotLight(bool isOn);
  2418. /**
  2419. \brief Engine calls this function to collect data from entity to store for persistence (on server side).
  2420. @code
  2421. void OnStoreSave(ParamsWriteContext ctx)
  2422. {
  2423. // dont forget to propagate this call trough class hierarchy!
  2424. super.OnStoreSave(ctx);
  2425. // write any data (using params) you want to store
  2426. int a = 5;
  2427. float b = 6.0;
  2428. ctx.Write(a);
  2429. ctx.Write(b);
  2430. }
  2431. @endcode
  2432. */
  2433. void OnStoreSave(ParamsWriteContext ctx)
  2434. {
  2435. // Saving of energy related states
  2436. if ( m_EM )
  2437. {
  2438. // Save energy amount
  2439. ctx.Write( m_EM.GetEnergy() );
  2440. // Save passive/active state
  2441. ctx.Write( m_EM.IsPassive() );
  2442. // Save ON/OFF state
  2443. ctx.Write( m_EM.IsSwitchedOn() );
  2444. // Save plugged/unplugged state
  2445. ctx.Write( m_EM.IsPlugged() );
  2446. // ENERGY SOURCE
  2447. // Save energy source IDs
  2448. EntityAI energy_source = m_EM.GetEnergySource();
  2449. int b1 = 0;
  2450. int b2 = 0;
  2451. int b3 = 0;
  2452. int b4 = 0;
  2453. if (energy_source)
  2454. {
  2455. energy_source.GetPersistentID(b1, b2, b3, b4);
  2456. }
  2457. ctx.Write( b1 ); // Save energy source block 1
  2458. ctx.Write( b2 ); // Save energy source block 2
  2459. ctx.Write( b3 ); // Save energy source block 3
  2460. ctx.Write( b4 ); // Save energy source block 4
  2461. }
  2462. // variable management system
  2463. SaveVariables(ctx);
  2464. }
  2465. /**
  2466. \brief Called when data is loaded from persistence (on server side).
  2467. @code
  2468. void OnStoreLoad(ParamsReadContext ctx, int version)
  2469. {
  2470. // dont forget to propagate this call trough class hierarchy!
  2471. if ( !super.OnStoreLoad(ctx, version) )
  2472. return false;
  2473. // read data loaded from game database (format and order of reading must be the same as writing!)
  2474. int a;
  2475. if ( !ctx.Read(a) )
  2476. return false;
  2477. float b;
  2478. if ( !ctx.Read(b) )
  2479. return false;
  2480. return true;
  2481. }
  2482. @endcode
  2483. */
  2484. bool OnStoreLoad (ParamsReadContext ctx, int version)
  2485. {
  2486. // Restoring of energy related states
  2487. if ( m_EM )
  2488. {
  2489. // Load energy amount
  2490. float f_energy = 0;
  2491. if ( !ctx.Read( f_energy ) )
  2492. f_energy = 0;
  2493. m_EM.SetEnergy(f_energy);
  2494. // Load passive/active state
  2495. bool b_is_passive = false;
  2496. if ( !ctx.Read( b_is_passive ) )
  2497. return false;
  2498. m_EM.SetPassiveState(b_is_passive);
  2499. // Load ON/OFF state
  2500. bool b_is_on = false;
  2501. if ( !ctx.Read( b_is_on ) )
  2502. {
  2503. m_EM.SwitchOn();
  2504. return false;
  2505. }
  2506. // Load plugged/unplugged state
  2507. bool b_is_plugged = false;
  2508. if ( !ctx.Read( b_is_plugged ) )
  2509. return false;
  2510. // ENERGY SOURCE
  2511. if ( version <= 103 )
  2512. {
  2513. // Load energy source ID low
  2514. int i_energy_source_ID_low = 0; // Even 0 can be valid ID!
  2515. if ( !ctx.Read( i_energy_source_ID_low ) )
  2516. return false;
  2517. // Load energy source ID high
  2518. int i_energy_source_ID_high = 0; // Even 0 can be valid ID!
  2519. if ( !ctx.Read( i_energy_source_ID_high ) )
  2520. return false;
  2521. }
  2522. else
  2523. {
  2524. int b1 = 0;
  2525. int b2 = 0;
  2526. int b3 = 0;
  2527. int b4 = 0;
  2528. if ( !ctx.Read(b1) ) return false;
  2529. if ( !ctx.Read(b2) ) return false;
  2530. if ( !ctx.Read(b3) ) return false;
  2531. if ( !ctx.Read(b4) ) return false;
  2532. if ( b_is_plugged )
  2533. {
  2534. // Because function GetEntityByPersitentID() cannot be called here, ID values must be stored and used later.
  2535. m_EM.StoreEnergySourceIDs( b1, b2, b3, b4 );
  2536. m_EM.RestorePlugState(true);
  2537. }
  2538. }
  2539. if (b_is_on)
  2540. {
  2541. m_EM.SwitchOn();
  2542. }
  2543. }
  2544. if (version >= 140)
  2545. {
  2546. // variable management system
  2547. if (!LoadVariables(ctx, version))
  2548. return false;
  2549. }
  2550. return true;
  2551. }
  2552. //! Sets object synchronization dirty flag, which signalize that object wants to be synchronized (take effect only in MP on server side)
  2553. proto native void SetSynchDirty();
  2554. /**
  2555. \brief Called on clients after receiving synchronization data from server.
  2556. */
  2557. void OnVariablesSynchronized()
  2558. {
  2559. if ( m_EM )
  2560. {
  2561. if ( GetGame().IsMultiplayer() )
  2562. {
  2563. bool is_on = m_EM.IsSwitchedOn();
  2564. if (is_on != m_EM.GetPreviousSwitchState())
  2565. {
  2566. if (is_on)
  2567. m_EM.SwitchOn();
  2568. else
  2569. m_EM.SwitchOff();
  2570. }
  2571. int id_low = m_EM.GetEnergySourceNetworkIDLow();
  2572. int id_High = m_EM.GetEnergySourceNetworkIDHigh();
  2573. EntityAI energy_source = EntityAI.Cast( GetGame().GetObjectByNetworkId(id_low, id_High) );
  2574. if (energy_source)
  2575. {
  2576. ComponentEnergyManager esem = energy_source.GetCompEM();
  2577. if ( !esem )
  2578. {
  2579. string object = energy_source.GetType();
  2580. Error("Synchronization error! Object " + object + " has no instance of the Energy Manager component!");
  2581. }
  2582. m_EM.PlugThisInto(energy_source);
  2583. }
  2584. else
  2585. {
  2586. m_EM.UnplugThis();
  2587. }
  2588. m_EM.DeviceUpdate();
  2589. m_EM.StartUpdates();
  2590. }
  2591. }
  2592. if (m_IsFrozen != m_IsFrozenLocal && !GetGame().IsDedicatedServer())
  2593. {
  2594. m_IsFrozenLocal = m_IsFrozen;
  2595. OnFreezeStateChangeClient();
  2596. }
  2597. }
  2598. //-----------------------------
  2599. // VARIABLE MANIPULATION SYSTEM
  2600. //-----------------------------
  2601. //!'true' if this variable has ever been changed from default
  2602. bool IsVariableSet(int variable)
  2603. {
  2604. return (variable & m_VariablesMask);
  2605. }
  2606. void SetVariableMask(int variable)
  2607. {
  2608. m_VariablesMask = variable | m_VariablesMask;
  2609. if (GetGame().IsServer())
  2610. {
  2611. SetSynchDirty();
  2612. }
  2613. }
  2614. //!Removes variable from variable mask, making it appear as though the variable has never been changed from default
  2615. void RemoveItemVariable(int variable)
  2616. {
  2617. m_VariablesMask = ~variable & m_VariablesMask;
  2618. }
  2619. void TransferVariablesFloat(array<float> float_vars)
  2620. {
  2621. DeSerializeNumericalVars(float_vars);
  2622. }
  2623. array<float> GetVariablesFloat()
  2624. {
  2625. CachedObjectsArrays.ARRAY_FLOAT.Clear();
  2626. SerializeNumericalVars(CachedObjectsArrays.ARRAY_FLOAT);
  2627. return CachedObjectsArrays.ARRAY_FLOAT;
  2628. }
  2629. void SaveVariables(ParamsWriteContext ctx)
  2630. {
  2631. //first set the flags
  2632. int varFlags = 0;
  2633. if (m_VariablesMask)
  2634. varFlags = ItemVariableFlags.FLOAT;
  2635. ctx.Write(varFlags);
  2636. //-------------------
  2637. //now serialize the variables
  2638. //floats
  2639. if (m_VariablesMask)
  2640. WriteVarsToCTX(ctx);
  2641. }
  2642. //----------------------------------------------------------------
  2643. bool LoadVariables(ParamsReadContext ctx, int version = -1)
  2644. {
  2645. int varFlags;
  2646. //read the flags
  2647. if (!ctx.Read(varFlags))
  2648. {
  2649. return false;
  2650. }
  2651. //--------------
  2652. if (varFlags & ItemVariableFlags.FLOAT)
  2653. {
  2654. if (!ReadVarsFromCTX(ctx, version))
  2655. return false;
  2656. }
  2657. return true;
  2658. }
  2659. //! Writes to storage CTX
  2660. void WriteVarsToCTX(ParamsWriteContext ctx)
  2661. {
  2662. ctx.Write(m_VariablesMask);
  2663. //--------------------------------------------
  2664. if (IsVariableSet(VARIABLE_TEMPERATURE))
  2665. {
  2666. ctx.Write(GetTemperature());
  2667. ctx.Write((int)GetIsFrozen());
  2668. }
  2669. }
  2670. //! Reads from storage CTX
  2671. bool ReadVarsFromCTX(ParamsReadContext ctx, int version = -1)//with ID optimization
  2672. {
  2673. if (version < 140)
  2674. return true;
  2675. int intValue;
  2676. float value;
  2677. if (!ctx.Read(intValue))
  2678. return false;
  2679. m_VariablesMask = intValue; //necessary for higher implement overrides. Hope it does not bork some init somewhere.
  2680. //--------------------------------------------
  2681. if (m_VariablesMask & VARIABLE_TEMPERATURE)
  2682. {
  2683. if (!ctx.Read(value))
  2684. return false;
  2685. SetTemperatureDirect(value);
  2686. if (!ctx.Read(intValue))
  2687. return false;
  2688. SetFrozen(intValue);
  2689. }
  2690. return true;
  2691. }
  2692. void SerializeNumericalVars(array<float> floats_out)
  2693. {
  2694. // the order of serialization must be the same as the order of de-serialization
  2695. floats_out.Insert(m_VariablesMask);
  2696. //--------------------------------------------
  2697. if (IsVariableSet(VARIABLE_TEMPERATURE))
  2698. {
  2699. floats_out.Insert(m_VarTemperature);
  2700. floats_out.Insert((float)GetIsFrozen());
  2701. floats_out.Insert((float)GetFreezeThawProgress());
  2702. }
  2703. }
  2704. void DeSerializeNumericalVars(array<float> floats)
  2705. {
  2706. // the order of serialization must be the same as the order of de-serialization
  2707. int index = 0;
  2708. int mask = Math.Round(floats.Get(index));
  2709. index++;
  2710. //--------------------------------------------
  2711. if (mask & VARIABLE_TEMPERATURE)
  2712. {
  2713. float temperature = floats.Get(index);
  2714. SetTemperatureDirect(temperature);
  2715. floats.RemoveOrdered(index);
  2716. bool frozen = Math.Round(floats.Get(index));
  2717. SetFrozen(frozen);
  2718. floats.RemoveOrdered(index);
  2719. float FTProgress = floats.Get(index);
  2720. SetFreezeThawProgress(FTProgress);
  2721. floats.RemoveOrdered(index);
  2722. }
  2723. }
  2724. //----------------------------------------------------------------
  2725. proto native void SetAITargetCallbacks(AbstractAITargetCallbacks callbacks);
  2726. override void EOnFrame(IEntity other, float timeSlice)
  2727. {
  2728. if ( m_ComponentsBank != NULL )
  2729. {
  2730. for ( int comp_key = 0; comp_key < COMP_TYPE_COUNT; ++comp_key )
  2731. {
  2732. if ( m_ComponentsBank.IsComponentAlreadyExist(comp_key) )
  2733. {
  2734. m_ComponentsBank.GetComponent(comp_key).Event_OnFrame(other, timeSlice);
  2735. }
  2736. }
  2737. }
  2738. }
  2739. string GetDebugText()
  2740. {
  2741. string text = string.Empty;
  2742. text += "Weight: " + GetWeightEx() + "\n";
  2743. text += "Disabled: " + GetIsSimulationDisabled() + "\n";
  2744. #ifdef SERVER
  2745. if (GetEconomyProfile())
  2746. text += "CE Lifetime default: " + (int)GetEconomyProfile().GetLifetime() + "\n";
  2747. text += "CE Lifetime remaining: " + (int)GetLifetime() + "\n";
  2748. #endif
  2749. ComponentEnergyManager compEM = GetCompEM();
  2750. if (compEM)
  2751. {
  2752. text += "Energy Source: " + Object.GetDebugName(compEM.GetEnergySource()) + "\n";
  2753. text += "Switched On: " + compEM.IsSwitchedOn() + "\n";
  2754. text += "Is Working: " + compEM.IsWorking() + "\n";
  2755. }
  2756. return text;
  2757. }
  2758. void GetDebugButtonNames(out string button1, out string button2, out string button3, out string button4){}//DEPRICATED, USE GetDebugActions / OnAction
  2759. void OnDebugButtonPressClient(int button_index){}//DEPRICATED, USE GetDebugActions / OnAction
  2760. void OnDebugButtonPressServer(int button_index){}//DEPRICATED, USE GetDebugActions / OnAction
  2761. Shape DebugBBoxDraw()
  2762. {
  2763. return GetComponent(COMP_TYPE_ETITY_DEBUG).DebugBBoxDraw();
  2764. }
  2765. void DebugBBoxSetColor(int color)
  2766. {
  2767. GetComponent(COMP_TYPE_ETITY_DEBUG).DebugBBoxSetColor(color);
  2768. }
  2769. void DebugBBoxDelete()
  2770. {
  2771. GetComponent(COMP_TYPE_ETITY_DEBUG).DebugBBoxDelete();
  2772. }
  2773. Shape DebugDirectionDraw(float distance = 1)
  2774. {
  2775. return GetComponent(COMP_TYPE_ETITY_DEBUG).DebugDirectionDraw(distance);
  2776. }
  2777. void DebugDirectionSetColor(int color)
  2778. {
  2779. GetComponent(COMP_TYPE_ETITY_DEBUG).DebugDirectionSetColor(color);
  2780. }
  2781. void DebugDirectionDelete()
  2782. {
  2783. GetComponent(COMP_TYPE_ETITY_DEBUG).DebugDirectionDelete();
  2784. }
  2785. //! Hides selection of the given name. Must be configed in config.cpp and models.cfg
  2786. void HideSelection( string selection_name )
  2787. {
  2788. if ( !ToDelete() )
  2789. {
  2790. SetAnimationPhase ( selection_name, 1 ); // 1 = hide, 0 = unhide!
  2791. }
  2792. }
  2793. //! Shows selection of the given name. Must be configed in config.hpp and models.cfg
  2794. void ShowSelection( string selection_name )
  2795. {
  2796. if ( !ToDelete() )
  2797. {
  2798. SetAnimationPhase ( selection_name, 0 ); // 1 = hide, 0 = unhide!
  2799. }
  2800. }
  2801. //! Returns blocks of bits of persistence id of this entity.
  2802. //! This id stays the same even after server restart.
  2803. proto void GetPersistentID( out int b1, out int b2, out int b3, out int b4 );
  2804. //! Set (override) remaining economy lifetime (seconds)
  2805. proto native void SetLifetime( float fLifeTime );
  2806. //! Get remaining economy lifetime (seconds)
  2807. proto native float GetLifetime();
  2808. //! Reset economy lifetime to default (seconds)
  2809. proto native void IncreaseLifetime();
  2810. //! Set (override) max economy lifetime per entity instance (seconds)
  2811. proto native void SetLifetimeMax( float fLifeTime );
  2812. //! Get max economy lifetime per instance - default is from DB (seconds)
  2813. proto native float GetLifetimeMax();
  2814. //! Reset economy lifetime to default across entity hierarchy all the way to the topmost entity
  2815. void IncreaseLifetimeUp()
  2816. {
  2817. IncreaseLifetime();
  2818. if (GetHierarchyParent())
  2819. GetHierarchyParent().IncreaseLifetimeUp();
  2820. }
  2821. // BODY STAGING
  2822. //! Use this to access Body Staging component on dead character. Returns NULL if the given object lacks such component.
  2823. ComponentBodyStaging GetCompBS()
  2824. {
  2825. if ( HasComponent(COMP_TYPE_BODY_STAGING) )
  2826. return ComponentBodyStaging.Cast( GetComponent(COMP_TYPE_BODY_STAGING) );
  2827. return NULL;
  2828. }
  2829. ///@{ energy manager
  2830. //! ENERGY MANAGER:Documentation: Confluence >> Camping & Squatting >> Electricity >> Energy Manager functionalities
  2831. //! Use this to access Energy Manager component on your device. Returns NULL if the given object lacks such component.
  2832. ComponentEnergyManager GetCompEM()
  2833. {
  2834. if (m_EM)
  2835. return m_EM;
  2836. if ( HasComponent(COMP_TYPE_ENERGY_MANAGER) )
  2837. return ComponentEnergyManager.Cast( GetComponent(COMP_TYPE_ENERGY_MANAGER) );
  2838. return NULL;
  2839. }
  2840. //! If this item has class EnergyManager in its config then it returns true. Otherwise returns false.
  2841. bool HasEnergyManager()
  2842. {
  2843. return HasComponent(COMP_TYPE_ENERGY_MANAGER);
  2844. }
  2845. // ------ Public Events for Energy manager component. Overwrite these and put your own functionality into them. ------
  2846. //! Energy manager event: Called only once when this device starts doing its work
  2847. void OnWorkStart() {}
  2848. //! Energy manager event: Called every device update if its supposed to do some work. The update can be every second or at random, depending on its manipulation.
  2849. void OnWork( float consumed_energy ) {}
  2850. //! Energy manager event: Called when the device stops working (was switched OFF or ran out of energy)
  2851. void OnWorkStop() {}
  2852. //! Energy manager event: Called when the device is switched on
  2853. void OnSwitchOn() {}
  2854. //! Energy manager event: Called when the device is switched OFF
  2855. void OnSwitchOff() {}
  2856. //! Energy manager event: Called when this device is plugged into some energy source
  2857. void OnIsPlugged(EntityAI source_device) {}
  2858. //! Energy manager event: Called when this device is UNPLUGGED from the energy source
  2859. void OnIsUnplugged( EntityAI last_energy_source ) {}
  2860. //! Energy manager event: When something is plugged into this device
  2861. void OnOwnSocketTaken( EntityAI device ) {}
  2862. //! Energy manager event: When something is UNPLUGGED from this device
  2863. void OnOwnSocketReleased( EntityAI device ) {}
  2864. //! Energy manager event: Object's initialization. Energy Manager is fully initialized by this point.
  2865. void OnInitEnergy() {}
  2866. //! Energy manager event: Called when energy was consumed on this device. ALWAYS CALL super.OnEnergyConsumed() !!!
  2867. void OnEnergyConsumed() {}
  2868. //! Energy manager event: Called when energy was added on this device. ALWAYS CALL super.OnEnergyAdded() !!!
  2869. void OnEnergyAdded() {}
  2870. ///@} energy manager
  2871. override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx)
  2872. {
  2873. super.OnRPC(sender, rpc_type, ctx);
  2874. if ( GetGame().IsClient() )
  2875. {
  2876. switch (rpc_type)
  2877. {
  2878. // BODY STAGING - server => client synchronization of skinned state.
  2879. case ERPCs.RPC_BS_SKINNED_STATE:
  2880. {
  2881. Param1<bool> p_skinned_state= new Param1<bool>(false);
  2882. if (ctx.Read(p_skinned_state))
  2883. {
  2884. float state = p_skinned_state.param1;
  2885. if (state && GetCompBS())
  2886. GetCompBS().SetAsSkinnedClient();
  2887. }
  2888. break;
  2889. }
  2890. case ERPCs.RPC_EXPLODE_EVENT:
  2891. {
  2892. OnExplodeClient();
  2893. break;
  2894. }
  2895. }
  2896. }
  2897. }
  2898. #ifdef DIAG_DEVELOPER
  2899. void FixEntity()
  2900. {
  2901. if (!(GetGame().IsServer()))
  2902. return;
  2903. SetFullHealth();
  2904. if (GetInventory())
  2905. {
  2906. int i = 0;
  2907. int AttachmentsCount = GetInventory().AttachmentCount();
  2908. if (AttachmentsCount > 0)
  2909. {
  2910. for (i = 0; i < AttachmentsCount; i++)
  2911. {
  2912. GetInventory().GetAttachmentFromIndex(i).FixEntity();
  2913. }
  2914. }
  2915. CargoBase cargo = GetInventory().GetCargo();
  2916. if (cargo)
  2917. {
  2918. int cargoCount = cargo.GetItemCount();
  2919. for (i = 0; i < cargoCount; i++)
  2920. {
  2921. cargo.GetItem(i).FixEntity();
  2922. }
  2923. }
  2924. }
  2925. }
  2926. #endif
  2927. float GetWetWeightModifier()
  2928. {
  2929. return CfgGameplayHandler.GetWetnessWeightModifiers()[GetWetLevel()];
  2930. }
  2931. float GetConfigWeightModified()
  2932. {
  2933. return m_ConfigWeight * GetWetWeightModifier();
  2934. }
  2935. #ifdef DEVELOPER
  2936. string GetConfigWeightModifiedDebugText()
  2937. {
  2938. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
  2939. {
  2940. return "(" + m_ConfigWeight + "(config weight) * " + GetWetWeightModifier() + "(Wetness Modifier))";
  2941. }
  2942. return string.Empty;
  2943. }
  2944. #endif
  2945. //Obsolete, use GetWeightEx()
  2946. int GetWeight()
  2947. {
  2948. return GetWeightEx();
  2949. }
  2950. void ClearWeightDirty()
  2951. {
  2952. //Print("ent:" + this + " - ClearWeightDirty");
  2953. m_WeightDirty = 0;
  2954. }
  2955. void SetWeightDirty()
  2956. {
  2957. #ifdef DEVELOPER
  2958. if (WeightDebug.m_VerbosityFlags & WeightDebugType.SET_DIRTY_FLAG)
  2959. {
  2960. Print("---------------------------------------");
  2961. Print("ent:" + this + " - SetWeightDirty");
  2962. if (WeightDebug.m_VerbosityFlags & WeightDebugType.DUMP_STACK)
  2963. {
  2964. DumpStack();
  2965. }
  2966. Print("---------------------------------------");
  2967. }
  2968. #endif
  2969. m_WeightDirty = 1;
  2970. if (GetHierarchyParent())
  2971. {
  2972. GetHierarchyParent().SetWeightDirty();
  2973. }
  2974. }
  2975. // returns weight of all cargo and attachments
  2976. float GetInventoryAndCargoWeight(bool forceRecalc = false)
  2977. {
  2978. float totalWeight;
  2979. if (GetInventory())
  2980. {
  2981. int i = 0;
  2982. int AttachmentsCount = GetInventory().AttachmentCount();
  2983. if (AttachmentsCount > 0)
  2984. {
  2985. for (i = 0; i < AttachmentsCount; i++)
  2986. {
  2987. totalWeight += GetInventory().GetAttachmentFromIndex(i).GetWeightEx(forceRecalc);
  2988. }
  2989. }
  2990. CargoBase cargo = GetInventory().GetCargo();
  2991. if (cargo)
  2992. {
  2993. int cargoCount = cargo.GetItemCount();
  2994. for (i = 0; i < cargoCount; i++)
  2995. {
  2996. totalWeight += cargo.GetItem(i).GetWeightEx(forceRecalc);
  2997. }
  2998. }
  2999. }
  3000. return totalWeight;
  3001. }
  3002. //! returns weight of the entity in a way that's specific to the entity type and is internal to the weight system calculation, to obtain entity's weight, use the 'GetWeightEx' method instead
  3003. protected float GetWeightSpecialized(bool forceRecalc = false)
  3004. {
  3005. return GetInventoryAndCargoWeight(forceRecalc);
  3006. }
  3007. //! returns overall weight of the entity, 'forceRecalc = true' is meant to be used only when debugging, using it in gameplay code is higly inadvisable as it bypasses the weight caching and has adverse effect on performance
  3008. //this method is not meant to be overriden, to adjust weight calculation for specific item type, override 'GetWeightSpecialized(bool forceRecalc = false)' instead
  3009. float GetWeightEx(bool forceRecalc = false)
  3010. {
  3011. if (m_WeightDirty || forceRecalc)//recalculate
  3012. {
  3013. m_WeightEx = GetWeightSpecialized(forceRecalc);
  3014. ClearWeightDirty();
  3015. #ifdef DEVELOPER
  3016. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
  3017. {
  3018. WeightDebug.GetWeightDebug(this).SetWeight(m_WeightEx);
  3019. }
  3020. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_DIRTY)
  3021. {
  3022. Print("ent:" + this + " - Dirty Recalc");
  3023. if (WeightDebug.m_VerbosityFlags & WeightDebugType.DUMP_STACK)
  3024. {
  3025. DumpStack();
  3026. }
  3027. }
  3028. #endif
  3029. }
  3030. return m_WeightEx;
  3031. }
  3032. void UpdateWeight(WeightUpdateType updateType = WeightUpdateType.FULL, float weightAdjustment = 0);
  3033. float GetSingleInventoryItemWeightEx(){}
  3034. void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
  3035. {
  3036. //fix entity
  3037. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FIX_ENTITY, "Fix Entity", FadeColors.LIGHT_GREY));
  3038. //weight
  3039. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GET_TOTAL_WEIGHT, "Print Weight", FadeColors.LIGHT_GREY));
  3040. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GET_TOTAL_WEIGHT_RECALC, "Print Weight Verbose", FadeColors.LIGHT_GREY));
  3041. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GET_PLAYER_WEIGHT, "Print Player Weight", FadeColors.LIGHT_GREY));
  3042. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GET_PLAYER_WEIGHT_RECALC, "Print Player Weight Verbose", FadeColors.LIGHT_GREY));
  3043. }
  3044. bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  3045. {
  3046. if (action_id == EActions.FIX_ENTITY)
  3047. {
  3048. #ifdef DIAG_DEVELOPER
  3049. FixEntity();
  3050. #endif
  3051. }
  3052. else if (action_id == EActions.GET_TOTAL_WEIGHT) //Prints total weight of item + its contents
  3053. {
  3054. WeightDebug.ClearWeightDebug();
  3055. #ifndef SERVER
  3056. Debug.Log("======================== "+ GetType() +" =================================");
  3057. #endif
  3058. Debug.Log("Weight:" + GetWeightEx().ToString());
  3059. Debug.Log("Weight excluding cargo and attachments:" + GetSingleInventoryItemWeightEx());
  3060. Debug.Log("----------------------------------------------------------------------------------------------");
  3061. }
  3062. else if (action_id == EActions.GET_TOTAL_WEIGHT_RECALC) //Prints total weight of item + its contents
  3063. {
  3064. WeightDebug.ClearWeightDebug();
  3065. WeightDebug.SetVerbosityFlags(WeightDebugType.RECALC_FORCED);
  3066. #ifndef SERVER
  3067. Debug.Log("======================== "+ GetType() +" RECALC ===========================");
  3068. #endif
  3069. Debug.Log("Weight:" + GetWeightEx(true).ToString());
  3070. Debug.Log("Weight excluding cargo and attachments:" + GetSingleInventoryItemWeightEx());
  3071. WeightDebug.PrintAll(this);
  3072. Debug.Log("----------------------------------------------------------------------------------------------");
  3073. WeightDebug.SetVerbosityFlags(0);
  3074. }
  3075. else if (action_id == EActions.GET_PLAYER_WEIGHT) //Prints total weight of item + its contents
  3076. {
  3077. WeightDebug.ClearWeightDebug();
  3078. #ifndef SERVER
  3079. Debug.Log("======================== PLAYER: "+player+" ===========================");
  3080. #endif
  3081. Debug.Log("New overall weight Player:"+player.GetWeightEx().ToString());
  3082. Debug.Log("----------------------------------------------------------------------------------------------");
  3083. }
  3084. else if (action_id == EActions.GET_PLAYER_WEIGHT_RECALC) //Prints total weight of item + its contents
  3085. {
  3086. WeightDebug.ClearWeightDebug();
  3087. WeightDebug.SetVerbosityFlags(WeightDebugType.RECALC_FORCED);
  3088. #ifndef SERVER
  3089. Debug.Log("======================== PLAYER RECALC: "+player+" ===========================");
  3090. #endif
  3091. Debug.Log("New overall weight Player:"+player.GetWeightEx(true).ToString());
  3092. WeightDebug.PrintAll(player);
  3093. Debug.Log("----------------------------------------------------------------------------------------------");
  3094. WeightDebug.SetVerbosityFlags(0);
  3095. }
  3096. return false;
  3097. }
  3098. ///@{ view index
  3099. //! Item view index is used to setup which camera will be used in item view widget in inventory.
  3100. //! With this index you can setup various camera angles for different item states (e.g. fireplace, weapons).
  3101. int m_ViewIndex = 0;
  3102. //! Sets item preview index
  3103. void SetViewIndex( int index )
  3104. {
  3105. m_ViewIndex = index;
  3106. if( GetGame().IsServer() )
  3107. {
  3108. SetSynchDirty();
  3109. }
  3110. }
  3111. //! Returns item preview index !!!! IF OVERRIDING with more dynamic events call GetOnViewIndexChanged() in constructor on client !!!!
  3112. int GetViewIndex()
  3113. {
  3114. if ( MemoryPointExists( "invView2" ) )
  3115. {
  3116. #ifdef PLATFORM_WINDOWS
  3117. InventoryLocation il = new InventoryLocation();
  3118. GetInventory().GetCurrentInventoryLocation( il );
  3119. InventoryLocationType type = il.GetType();
  3120. switch ( type )
  3121. {
  3122. case InventoryLocationType.CARGO:
  3123. {
  3124. return 0;
  3125. }
  3126. case InventoryLocationType.ATTACHMENT:
  3127. {
  3128. return 1;
  3129. }
  3130. case InventoryLocationType.HANDS:
  3131. {
  3132. return 0;
  3133. }
  3134. case InventoryLocationType.GROUND:
  3135. {
  3136. return 1;
  3137. }
  3138. case InventoryLocationType.PROXYCARGO:
  3139. {
  3140. return 0;
  3141. }
  3142. default:
  3143. {
  3144. return 0;
  3145. }
  3146. }
  3147. #endif
  3148. #ifdef PLATFORM_CONSOLE
  3149. return 1;
  3150. #endif
  3151. }
  3152. return 0;
  3153. }
  3154. ///@} view index
  3155. //! Returns hit component for the Entity (overriden for each Type - PlayerBase, DayZInfected, DayZAnimal, etc.)
  3156. string GetHitComponentForAI()
  3157. {
  3158. Debug.LogError("EntityAI: HitComponentForAI not set properly for that entity (" + GetType() + ")");
  3159. //! returns Global so it is obvious you need to configure that properly on entity
  3160. return "";
  3161. }
  3162. //! returns default hit component for the Entity (overriden for each Type - PlayerBase, DayZInfected, DayZAnimal, etc.)
  3163. string GetDefaultHitComponent()
  3164. {
  3165. Debug.LogError("EntityAI: DefaultHitComponent not set properly for that entity (" + GetType() + ")");
  3166. //! returns Global so it is obvious you need to configure that properly on entity
  3167. return "";
  3168. }
  3169. //! returns default hit position component name for the Entity (overriden by type if needed - used mainly as support for impact particles)
  3170. string GetDefaultHitPositionComponent()
  3171. {
  3172. Debug.LogError("EntityAI: DefaultHitPositionComponent not set for that entity (" + GetType() + ")");
  3173. return "";
  3174. }
  3175. array<string> GetSuitableFinisherHitComponents()
  3176. {
  3177. Debug.LogError("EntityAI: SuitableFinisherHitComponents not set for that entity (" + GetType() + ")");
  3178. return null;
  3179. }
  3180. vector GetDefaultHitPosition()
  3181. {
  3182. Debug.LogError("EntityAI: DefaultHitPosition not set for that entity (" + GetType() + ")");
  3183. return vector.Zero;
  3184. }
  3185. //! value is related to EMeleeTargetType
  3186. int GetMeleeTargetType()
  3187. {
  3188. return EMeleeTargetType.ALIGNABLE;
  3189. }
  3190. //! returns sound type of attachment (used for clothing and weapons on DayZPlayerImplement, paired with Anim*Type enum from DayZAnimEvents)
  3191. string GetAttachmentSoundType()
  3192. {
  3193. return "None";
  3194. }
  3195. //! returns item behaviour of item (more in ItemBase)
  3196. bool IsHeavyBehaviour()
  3197. {
  3198. return false;
  3199. }
  3200. //! returns item behaviour of item (more in ItemBase)
  3201. bool IsOneHandedBehaviour()
  3202. {
  3203. return false;
  3204. }
  3205. //! returns item behaviour of item (more in ItemBase)
  3206. bool IsTwoHandedBehaviour()
  3207. {
  3208. return false;
  3209. }
  3210. string ChangeIntoOnAttach(string slot) {}
  3211. string ChangeIntoOnDetach() {}
  3212. //! returns true used on selected items that have a temperature effect and can processes temperature changes
  3213. bool CanHaveTemperature()
  3214. {
  3215. return GetTemperatureMin() < GetTemperatureMax();
  3216. }
  3217. bool IsSelfAdjustingTemperature()
  3218. {
  3219. return false;
  3220. }
  3221. /**
  3222. \brief Central economy calls this function whenever going over all the entities
  3223. @code
  3224. void OnCEUpdate()
  3225. {
  3226. // dont forget to propagate this call trough class hierarchy! - always at the start of the function
  3227. super.OnCEUpdate();
  3228. // use m_ElapsedSinceLastUpdate for time-related purposes
  3229. }
  3230. @endcode
  3231. */
  3232. void OnCEUpdate()
  3233. {
  3234. float currentTime = GetGame().GetTickTime();
  3235. if (m_LastUpdatedTime == 0)
  3236. m_LastUpdatedTime = currentTime;
  3237. m_ElapsedSinceLastUpdate = currentTime - m_LastUpdatedTime;
  3238. m_LastUpdatedTime = currentTime;
  3239. ProcessVariables();
  3240. }
  3241. void ProcessVariables()
  3242. {
  3243. //currently only temperature on EntityAI
  3244. if (g_Game.IsWorldWetTempUpdateEnabled())
  3245. {
  3246. if (CanHaveTemperature() && !IsSelfAdjustingTemperature() && !GetHierarchyRoot().IsSelfAdjustingTemperature())
  3247. {
  3248. float target = g_Game.GetMission().GetWorldData().GetBaseEnvTemperatureAtObject(this);
  3249. if (GetTemperature() != target || !IsFreezeThawProgressFinished())
  3250. {
  3251. float heatPermCoef = 1.0;
  3252. EntityAI ent = this;
  3253. while (ent)
  3254. {
  3255. heatPermCoef *= ent.GetHeatPermeabilityCoef();
  3256. ent = ent.GetHierarchyParent();
  3257. }
  3258. SetTemperatureEx(new TemperatureDataInterpolated(target,ETemperatureAccessTypes.ACCESS_WORLD,m_ElapsedSinceLastUpdate,GameConstants.TEMP_COEF_WORLD,heatPermCoef));
  3259. }
  3260. }
  3261. }
  3262. }
  3263. void OnDebugSpawnEx(DebugSpawnParams params)
  3264. {
  3265. OnDebugSpawn();
  3266. }
  3267. void OnDebugSpawn()
  3268. {
  3269. array<string> slots = new array<string>;
  3270. ConfigGetTextArray("Attachments", slots);
  3271. array<string> mags = new array<string>;
  3272. ConfigGetTextArray("magazines", mags);
  3273. //-------
  3274. TStringArray all_paths = new TStringArray;
  3275. all_paths.Insert(CFG_VEHICLESPATH);
  3276. all_paths.Insert(CFG_MAGAZINESPATH);
  3277. all_paths.Insert(CFG_WEAPONSPATH);
  3278. string config_path;
  3279. string child_name;
  3280. int scope;
  3281. string path;
  3282. int consumable_count;
  3283. for (int i = 0; i < all_paths.Count(); i++)
  3284. {
  3285. config_path = all_paths.Get(i);
  3286. int children_count = GetGame().ConfigGetChildrenCount(config_path);
  3287. for (int x = 0; x < children_count; x++)
  3288. {
  3289. GetGame().ConfigGetChildName(config_path, x, child_name);
  3290. path = config_path + " " + child_name;
  3291. scope = GetGame().ConfigGetInt( config_path + " " + child_name + " scope" );
  3292. bool should_check = 1;
  3293. if ( config_path == "CfgVehicles" && scope == 0)
  3294. {
  3295. should_check = 0;
  3296. }
  3297. if ( should_check )
  3298. {
  3299. string inv_slot;
  3300. GetGame().ConfigGetText( config_path + " " + child_name + " inventorySlot",inv_slot );
  3301. for (int z = 0; z < slots.Count(); z++)
  3302. {
  3303. if (slots.Get(z) == inv_slot)
  3304. {
  3305. this.GetInventory().CreateInInventory( child_name );
  3306. continue;
  3307. //Print("matching attachment: " + child_name + " for inv. slot name:" +inv_slot);
  3308. }
  3309. }
  3310. }
  3311. }
  3312. }
  3313. };
  3314. override EntityAI ProcessMeleeItemDamage(int mode = 0)
  3315. {
  3316. if (GetGame().IsServer())
  3317. AddHealth("","Health",-MELEE_ITEM_DAMAGE);
  3318. return this;
  3319. }
  3320. //! Returns liquid throughput coeficient
  3321. float GetLiquidThroughputCoef()
  3322. {
  3323. return LIQUID_THROUGHPUT_DEFAULT;
  3324. }
  3325. string GetInvulnerabilityTypeString()
  3326. {
  3327. return "";
  3328. }
  3329. void ProcessInvulnerabilityCheck(string servercfg_param)
  3330. {
  3331. if ( GetGame() && GetGame().IsMultiplayer() && GetGame().IsServer() )
  3332. {
  3333. int invulnerability;
  3334. switch (servercfg_param)
  3335. {
  3336. case "disableContainerDamage":
  3337. invulnerability = CfgGameplayHandler.GetDisableContainerDamage();
  3338. break;
  3339. case "disableBaseDamage":
  3340. invulnerability = CfgGameplayHandler.GetDisableBaseDamage();
  3341. break;
  3342. }
  3343. if (invulnerability > 0)
  3344. {
  3345. SetAllowDamage(false);
  3346. }
  3347. }
  3348. }
  3349. void SetBayonetAttached(bool pState, int slot_idx = -1) {};
  3350. bool HasBayonetAttached() {};
  3351. int GetBayonetAttachmentIdx() {};
  3352. void SetButtstockAttached(bool pState, int slot_idx = -1) {};
  3353. bool HasButtstockAttached() {};
  3354. int GetButtstockAttachmentIdx() {};
  3355. void SetInvisibleRecursive(bool invisible, EntityAI parent = null, array<int> attachments = null)
  3356. {
  3357. array<int> childrenAtt = new array<int>;
  3358. array<int> attachmentsArray = new array<int>;
  3359. if (attachments)
  3360. attachmentsArray.Copy(attachments);
  3361. else
  3362. {
  3363. for (int i = 0; i < GetInventory().GetAttachmentSlotsCount(); i++)
  3364. {
  3365. attachmentsArray.Insert(GetInventory().GetAttachmentSlotId(i));
  3366. }
  3367. }
  3368. EntityAI item;
  3369. foreach( int slot : attachmentsArray )
  3370. {
  3371. if( parent )
  3372. item = parent.GetInventory().FindAttachment(slot);
  3373. else
  3374. item = this;//GetInventory().FindAttachment(slot);
  3375. if( item )
  3376. {
  3377. if( item.GetInventory().AttachmentCount() > 0 )
  3378. {
  3379. for(i = 0; i < item.GetInventory().GetAttachmentSlotsCount(); i++)
  3380. {
  3381. childrenAtt.Insert(item.GetInventory().GetAttachmentSlotId(i));
  3382. }
  3383. SetInvisibleRecursive(invisible,item,childrenAtt);
  3384. }
  3385. item.SetInvisible(invisible);
  3386. item.OnInvisibleSet(invisible);
  3387. }
  3388. }
  3389. }
  3390. void SoundHardTreeFallingPlay()
  3391. {
  3392. EffectSound sound = SEffectManager.PlaySound( "hardTreeFall_SoundSet", GetPosition() );
  3393. sound.SetAutodestroy( true );
  3394. }
  3395. void SoundSoftTreeFallingPlay()
  3396. {
  3397. EffectSound sound = SEffectManager.PlaySound( "softTreeFall_SoundSet", GetPosition() );
  3398. sound.SetAutodestroy( true );
  3399. }
  3400. void SoundHardBushFallingPlay()
  3401. {
  3402. EffectSound sound = SEffectManager.PlaySound( "hardBushFall_SoundSet", GetPosition() );
  3403. sound.SetAutodestroy( true );
  3404. }
  3405. void SoundSoftBushFallingPlay()
  3406. {
  3407. EffectSound sound = SEffectManager.PlaySound( "softBushFall_SoundSet", GetPosition() );
  3408. sound.SetAutodestroy( true );
  3409. }
  3410. void RegisterTransportHit(Transport transport)
  3411. {
  3412. if (!m_TransportHitRegistered)
  3413. {
  3414. m_TransportHitRegistered = true;
  3415. m_TransportHitVelocity = GetVelocity(transport);
  3416. Car car;
  3417. Boat boat;
  3418. float damage;
  3419. vector impulse;
  3420. // a different attempt to solve hits from "standing" car to the players
  3421. if (Car.CastTo(car, transport))
  3422. {
  3423. if (car.GetSpeedometerAbsolute() > 2 )
  3424. {
  3425. damage = m_TransportHitVelocity.Length();
  3426. ProcessDirectDamage(DT_CUSTOM, transport, "", "TransportHit", "0 0 0", damage);
  3427. }
  3428. else
  3429. {
  3430. m_TransportHitRegistered = false;
  3431. }
  3432. // compute impulse and apply only if the body dies
  3433. if (IsDamageDestroyed() && car.GetSpeedometerAbsolute() > 3)
  3434. {
  3435. impulse = 40 * m_TransportHitVelocity;
  3436. impulse[1] = 40 * 1.5;
  3437. dBodyApplyImpulse(this, impulse);
  3438. }
  3439. }
  3440. else if (Boat.CastTo(boat, transport))
  3441. {
  3442. Human player = Human.Cast(this);
  3443. if (player && player.PhysicsGetLinkedEntity() == boat) // standing on boat
  3444. {
  3445. m_TransportHitRegistered = false;
  3446. return;
  3447. }
  3448. if (m_TransportHitVelocity.Normalize() > 5) // 5 m/s
  3449. {
  3450. damage = m_TransportHitVelocity.Length() * 0.5;
  3451. ProcessDirectDamage(DT_CUSTOM, transport, "", "TransportHit", "0 0 0", damage);
  3452. }
  3453. else
  3454. m_TransportHitRegistered = false;
  3455. }
  3456. else //old solution just in case if somebody use it
  3457. {
  3458. // avoid damage because of small movements
  3459. if (m_TransportHitVelocity.Length() > 0.1)
  3460. {
  3461. damage = m_TransportHitVelocity.Length();
  3462. ProcessDirectDamage(DT_CUSTOM, transport, "", "TransportHit", "0 0 0", damage);
  3463. }
  3464. else
  3465. {
  3466. m_TransportHitRegistered = false;
  3467. }
  3468. // compute impulse and apply only if the body dies
  3469. if (IsDamageDestroyed() && m_TransportHitVelocity.Length() > 0.3)
  3470. {
  3471. impulse = 40 * m_TransportHitVelocity;
  3472. impulse[1] = 40 * 1.5;
  3473. dBodyApplyImpulse(this, impulse);
  3474. }
  3475. }
  3476. }
  3477. }
  3478. bool GetInventoryHandAnimation(notnull InventoryLocation loc, out int value)
  3479. {
  3480. value = -1;
  3481. return false;
  3482. }
  3483. bool TranslateSlotFromSelection(string selection_name, out int slot_id)
  3484. {
  3485. return false;
  3486. }
  3487. //! Universal Temperature Sources Helpers
  3488. bool IsUniversalTemperatureSource()
  3489. {
  3490. return GetUniversalTemperatureSource() != null && GetUniversalTemperatureSource().IsActive();
  3491. }
  3492. UTemperatureSource GetUniversalTemperatureSource()
  3493. {
  3494. return m_UniversalTemperatureSource;
  3495. }
  3496. void SetUniversalTemperatureSource(UTemperatureSource uts)
  3497. {
  3498. m_UniversalTemperatureSource = uts;
  3499. }
  3500. vector GetUniversalTemperatureSourcePosition()
  3501. {
  3502. return GetPosition();
  3503. }
  3504. //! Remotely controlled devices helpers
  3505. RemotelyActivatedItemBehaviour GetRemotelyActivatedItemBehaviour();
  3506. void PairRemote(notnull EntityAI trigger);
  3507. void UnpairRemote();
  3508. EntityAI GetPairDevice();
  3509. void SetPersistentPairID(int id)
  3510. {
  3511. RemotelyActivatedItemBehaviour raib = GetRemotelyActivatedItemBehaviour();
  3512. if (raib)
  3513. {
  3514. raib.SetPersistentPairID(id);
  3515. }
  3516. }
  3517. //! Turnable Valve behaviour
  3518. bool HasTurnableValveBehavior();
  3519. bool IsValveTurnable(int pValveIndex);
  3520. int GetTurnableValveIndex(int pComponentIndex);
  3521. void ExecuteActionsConnectedToValve(int pValveIndex);
  3522. //////////////////////////////////
  3523. // attachment exclusion section //
  3524. //////////////////////////////////
  3525. private void InitAttachmentExclusionValues()
  3526. {
  3527. m_AttachmentExclusionSlotMap = new map<int,ref set<int>>();
  3528. m_AttachmentExclusionMaskGlobal = new set<int>;
  3529. m_AttachmentExclusionMaskChildren = new set<int>();
  3530. int count = GetInventory().GetSlotIdCount();
  3531. //no sense in performing inits for something that cannot be attached anywhere (hand/lefthand and some other 'special' slots are the reason for creating 'new' sets above)
  3532. if (count == 0)
  3533. return;
  3534. InitInherentSlotExclusionMap();
  3535. InitGlobalExclusionValues();
  3536. InitLegacyConfigExclusionValues();
  3537. }
  3538. //! map stored on instance to better respond to various state changes
  3539. private void InitInherentSlotExclusionMap()
  3540. {
  3541. int count = GetInventory().GetSlotIdCount();
  3542. //starting with the INVALID slot, so it is always in the map of attachable items
  3543. SetAttachmentExclusionMaskSlot(InventorySlots.INVALID,GetAttachmentExclusionInitSlotValue(InventorySlots.INVALID));
  3544. int slotId;
  3545. for (int i = 0; i < count; i++)
  3546. {
  3547. slotId = GetInventory().GetSlotId(i);
  3548. SetAttachmentExclusionMaskSlot(slotId,GetAttachmentExclusionInitSlotValue(slotId));
  3549. }
  3550. }
  3551. //! override this to modify slot behavior for specific items, or just set 'm_AttachmentExclusionMaskGlobal' value for simple items
  3552. protected set<int> GetAttachmentExclusionInitSlotValue(int slotId)
  3553. {
  3554. set<int> dflt = new set<int>;
  3555. return dflt;
  3556. }
  3557. //Initiated last, and only for items that do not have others defined already
  3558. protected void InitLegacyConfigExclusionValues()
  3559. {
  3560. bool performLegacyInit = InitLegacyExclusionCheck();
  3561. //adding implicit slot info AFTER the check is performed
  3562. InitLegacySlotExclusionValuesImplicit();
  3563. if (performLegacyInit)
  3564. InitLegacySlotExclusionValuesDerived();
  3565. }
  3566. //returns 'false' if the script initialization
  3567. protected bool InitLegacyExclusionCheck()
  3568. {
  3569. //first check the globals
  3570. if (m_AttachmentExclusionMaskGlobal.Count() > 0)
  3571. return false;
  3572. //now the map
  3573. int count = m_AttachmentExclusionSlotMap.Count();
  3574. if (count > 1) //more than InventorySlots.INVALID
  3575. {
  3576. for (int i = 0; i < count; i++)
  3577. {
  3578. int countSet = m_AttachmentExclusionSlotMap.GetElement(i).Count();
  3579. if (countSet > 0) //SOMETHING is defined
  3580. {
  3581. return false;
  3582. }
  3583. }
  3584. }
  3585. return true;
  3586. }
  3587. /**@fn InitLegacySlotExclusionValuesImplicit
  3588. * @brief adding base one-directional relations between headgear, masks, eyewear, and headstraps (exception)
  3589. *
  3590. * @note: 'InitLegacyConfigExclusionValues' adds them the other way if the item does not have any script-side exclusions AND has some legacy config parameter.
  3591. **/
  3592. protected void InitLegacySlotExclusionValuesImplicit()
  3593. {
  3594. int slotId;
  3595. int slotCount = GetInventory().GetSlotIdCount();
  3596. for (int i = 0; i < slotCount; i++)
  3597. {
  3598. slotId = GetInventory().GetSlotId(i);
  3599. set<int> tmp;
  3600. switch (slotId)
  3601. {
  3602. case InventorySlots.HEADGEAR:
  3603. {
  3604. tmp = new set<int>;
  3605. tmp.Copy(GetAttachmentExclusionInitSlotValue(slotId));
  3606. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_MASK);
  3607. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_HEADSTRAP);
  3608. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_EYEWEWEAR);
  3609. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3610. break;
  3611. }
  3612. case InventorySlots.MASK:
  3613. {
  3614. tmp = new set<int>;
  3615. tmp.Copy(GetAttachmentExclusionInitSlotValue(slotId));
  3616. tmp.Insert(EAttExclusions.LEGACY_MASK_HEADGEAR);
  3617. tmp.Insert(EAttExclusions.LEGACY_MASK_HEADSTRAP);
  3618. tmp.Insert(EAttExclusions.LEGACY_MASK_EYEWEWEAR);
  3619. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3620. break;
  3621. }
  3622. case InventorySlots.EYEWEAR:
  3623. {
  3624. tmp = new set<int>;
  3625. tmp.Copy(GetAttachmentExclusionInitSlotValue(slotId));
  3626. if (ConfigGetBool("isStrap"))
  3627. {
  3628. tmp.Insert(EAttExclusions.LEGACY_HEADSTRAP_HEADGEAR);
  3629. tmp.Insert(EAttExclusions.LEGACY_HEADSTRAP_MASK);
  3630. }
  3631. else
  3632. {
  3633. tmp.Insert(EAttExclusions.LEGACY_EYEWEAR_HEADGEAR);
  3634. tmp.Insert(EAttExclusions.LEGACY_EYEWEAR_MASK);
  3635. }
  3636. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3637. break;
  3638. }
  3639. }
  3640. }
  3641. }
  3642. protected void InitLegacySlotExclusionValuesDerived()
  3643. {
  3644. int slotId;
  3645. int slotCount = GetInventory().GetSlotIdCount();
  3646. for (int i = 0; i < slotCount; i++)
  3647. {
  3648. slotId = GetInventory().GetSlotId(i);
  3649. set<int> tmp;
  3650. switch (slotId)
  3651. {
  3652. case InventorySlots.HEADGEAR:
  3653. {
  3654. tmp = new set<int>;
  3655. tmp.Copy(GetAttachmentExclusionMaskSlot(slotId));
  3656. if (ConfigGetBool("noNVStrap"))
  3657. {
  3658. tmp.Insert(EAttExclusions.LEGACY_HEADSTRAP_HEADGEAR);
  3659. }
  3660. if (ConfigGetBool("noMask"))
  3661. {
  3662. tmp.Insert(EAttExclusions.LEGACY_MASK_HEADGEAR);
  3663. }
  3664. if (ConfigGetBool("noEyewear"))
  3665. {
  3666. tmp.Insert(EAttExclusions.LEGACY_EYEWEAR_HEADGEAR);
  3667. }
  3668. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3669. break;
  3670. }
  3671. case InventorySlots.MASK:
  3672. {
  3673. tmp = new set<int>;
  3674. tmp.Copy(GetAttachmentExclusionMaskSlot(slotId));
  3675. if (ConfigGetBool("noNVStrap"))
  3676. {
  3677. tmp.Insert(EAttExclusions.LEGACY_HEADSTRAP_MASK);
  3678. }
  3679. if (ConfigGetBool("noHelmet"))
  3680. {
  3681. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_MASK);
  3682. }
  3683. if (ConfigGetBool("noEyewear"))
  3684. {
  3685. tmp.Insert(EAttExclusions.LEGACY_EYEWEAR_MASK);
  3686. }
  3687. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3688. break;
  3689. }
  3690. case InventorySlots.EYEWEAR:
  3691. {
  3692. tmp = new set<int>;
  3693. tmp.Copy(GetAttachmentExclusionMaskSlot(slotId));
  3694. if (ConfigGetBool("isStrap"))
  3695. {
  3696. if (ConfigGetBool("noHelmet"))
  3697. {
  3698. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_HEADSTRAP);
  3699. }
  3700. if (ConfigGetBool("noMask"))
  3701. {
  3702. tmp.Insert(EAttExclusions.LEGACY_MASK_HEADSTRAP);
  3703. }
  3704. }
  3705. else
  3706. {
  3707. if (ConfigGetBool("noHelmet"))
  3708. {
  3709. tmp.Insert(EAttExclusions.LEGACY_HEADGEAR_EYEWEWEAR);
  3710. }
  3711. if (ConfigGetBool("noMask"))
  3712. {
  3713. tmp.Insert(EAttExclusions.LEGACY_MASK_EYEWEWEAR);
  3714. }
  3715. }
  3716. SetAttachmentExclusionMaskSlot(slotId,tmp);
  3717. break;
  3718. }
  3719. }
  3720. }
  3721. }
  3722. //! override to init part of the mask, independent of slot-specific behavior
  3723. protected void InitGlobalExclusionValues();
  3724. //! to help with item staging exclusions
  3725. protected void AddSingleExclusionValueGlobal(EAttExclusions value)
  3726. {
  3727. if (m_AttachmentExclusionMaskGlobal.Find(value) == -1)
  3728. m_AttachmentExclusionMaskGlobal.Insert(value);
  3729. }
  3730. //! to help with item staging exclusions
  3731. protected void ClearSingleExclusionValueGlobal(EAttExclusions value)
  3732. {
  3733. int idx = m_AttachmentExclusionMaskGlobal.Find(value);
  3734. if (idx != -1)
  3735. m_AttachmentExclusionMaskGlobal.Remove(idx);
  3736. }
  3737. protected void SetAttachmentExclusionMaskGlobal(set<int> values)
  3738. {
  3739. m_AttachmentExclusionMaskGlobal.Clear();
  3740. m_AttachmentExclusionMaskGlobal.Copy(values);
  3741. }
  3742. //! sets values for specific slot
  3743. protected void SetAttachmentExclusionMaskSlot(int slotId, set<int> values)
  3744. {
  3745. if (m_AttachmentExclusionSlotMap)
  3746. {
  3747. m_AttachmentExclusionSlotMap.Set(slotId,values);
  3748. }
  3749. else
  3750. ErrorEx("m_AttachmentExclusionSlotMap not available! Fill the 'inventorySlot[]' in the " + this + " config file.");
  3751. }
  3752. private void PropagateExclusionValueRecursive(set<int> values, int slotId)
  3753. {
  3754. if (values && values.Count() != 0)
  3755. {
  3756. set<int> passThis;
  3757. InventoryLocation lcn = new InventoryLocation();
  3758. GetInventory().GetCurrentInventoryLocation(lcn);
  3759. if (CheckExclusionAccessPropagation(lcn.GetSlot(), slotId, values, passThis))
  3760. {
  3761. m_AttachmentExclusionMaskChildren.InsertSet(passThis);
  3762. EntityAI parent = GetHierarchyParent();
  3763. if (parent)
  3764. parent.PropagateExclusionValueRecursive(passThis,lcn.GetSlot());
  3765. }
  3766. }
  3767. }
  3768. private void ClearExclusionValueRecursive(set<int> values, int slotId)
  3769. {
  3770. if (values && values.Count() != 0)
  3771. {
  3772. set<int> passThis;
  3773. InventoryLocation lcn = new InventoryLocation();
  3774. GetInventory().GetCurrentInventoryLocation(lcn);
  3775. if (CheckExclusionAccessPropagation(lcn.GetSlot(), slotId, values, passThis))
  3776. {
  3777. int count = passThis.Count();
  3778. for (int i = 0; i < count; i++)
  3779. {
  3780. m_AttachmentExclusionMaskChildren.RemoveItem(passThis[i]);
  3781. }
  3782. EntityAI parent = GetHierarchyParent();
  3783. if (parent)
  3784. parent.ClearExclusionValueRecursive(passThis,lcn.GetSlot());
  3785. }
  3786. }
  3787. }
  3788. //! Slot-specific, children (attachments), and additional (state etc.) masks combined
  3789. set<int> GetAttachmentExclusionMaskAll(int slotId)
  3790. {
  3791. set<int> values = new set<int>();
  3792. set<int> slotValues = GetAttachmentExclusionMaskSlot(slotId);
  3793. if (slotValues)
  3794. values.InsertSet(slotValues);
  3795. values.InsertSet(m_AttachmentExclusionMaskGlobal);
  3796. values.InsertSet(m_AttachmentExclusionMaskChildren);
  3797. return values;
  3798. }
  3799. //! Specific slot behavior
  3800. set<int> GetAttachmentExclusionMaskSlot(int slotId)
  3801. {
  3802. return m_AttachmentExclusionSlotMap.Get(slotId);
  3803. }
  3804. //! Global mask value, independent of slot-specific behavior!
  3805. set<int> GetAttachmentExclusionMaskGlobal()
  3806. {
  3807. return m_AttachmentExclusionMaskGlobal;
  3808. }
  3809. //! Mask value coming from the item's attachments
  3810. set<int> GetAttachmentExclusionMaskChildren()
  3811. {
  3812. return m_AttachmentExclusionMaskChildren;
  3813. }
  3814. //! checks if any attachment or item state would interfere with this being attached into a different slot (Headgear -> Mask)
  3815. private bool HasInternalExclusionConflicts(int targetSlot)
  3816. {
  3817. set<int> targetSlotValues = GetAttachmentExclusionMaskSlot(targetSlot);
  3818. if (targetSlotValues) //can be null, if so, no conflict
  3819. {
  3820. set<int> additionalValues = new set<int>(); //NOT slot values
  3821. additionalValues.InsertSet(GetAttachmentExclusionMaskGlobal());
  3822. additionalValues.InsertSet(GetAttachmentExclusionMaskChildren());
  3823. if (additionalValues.Count() > 0)
  3824. {
  3825. int countTarget = targetSlotValues.Count();
  3826. for (int i = 0; i < countTarget; i++)
  3827. {
  3828. if (additionalValues.Find(targetSlotValues[i]) != -1)
  3829. {
  3830. return true;
  3831. }
  3832. }
  3833. }
  3834. }
  3835. return false;
  3836. }
  3837. //! checks 'this' if the incoming flag is present for the current state (slot behavior and others)
  3838. protected bool IsExclusionFlagPresent(set<int> values)
  3839. {
  3840. int slotId;
  3841. string slotName;
  3842. GetInventory().GetCurrentAttachmentSlotInfo(slotId,slotName); //if currently attached, treat it accordingly
  3843. set<int> currentSlotValuesAll = GetAttachmentExclusionMaskAll(slotId);
  3844. int count = values.Count();
  3845. for (int i = 0; i < count; i++)
  3846. {
  3847. if (currentSlotValuesAll.Find(values[i]) != -1)
  3848. return true;
  3849. }
  3850. return false;
  3851. }
  3852. //! Gets flag from what is effectively an owner
  3853. protected bool IsExclusionFlagPresentRecursive(set<int> values, int targetSlot)
  3854. {
  3855. if (values && values.Count() != 0)
  3856. {
  3857. InventoryLocation lcn = new InventoryLocation();
  3858. GetInventory().GetCurrentInventoryLocation(lcn);
  3859. EntityAI parent = GetHierarchyParent();
  3860. set<int> passThis;
  3861. if (CheckExclusionAccessCondition(lcn.GetSlot(),targetSlot, values, passThis))
  3862. {
  3863. if (parent && parent != this) //we reached root if false
  3864. {
  3865. return parent.IsExclusionFlagPresentRecursive(passThis,lcn.GetSlot());
  3866. }
  3867. }
  3868. return IsExclusionFlagPresent(passThis);
  3869. }
  3870. return false;
  3871. }
  3872. //!
  3873. protected bool CheckExclusionAccessCondition(int occupiedSlot, int targetSlot, set<int> value, inout set<int> adjustedValue)
  3874. {
  3875. bool occupiedException = occupiedSlot == InventorySlots.HANDS || occupiedSlot == InventorySlots.SHOULDER || occupiedSlot == InventorySlots.MELEE || occupiedSlot == InventorySlots.LEFTHAND;
  3876. bool targetException = targetSlot == InventorySlots.HANDS || targetSlot == InventorySlots.SHOULDER || targetSlot == InventorySlots.MELEE || targetSlot == InventorySlots.LEFTHAND;
  3877. if (occupiedException)
  3878. {
  3879. adjustedValue = value;
  3880. return false;
  3881. }
  3882. if (targetException)
  3883. {
  3884. adjustedValue = null;
  3885. return false;
  3886. }
  3887. AdjustExclusionAccessCondition(occupiedSlot,targetSlot,value,adjustedValue);
  3888. return adjustedValue.Count() != 0;
  3889. }
  3890. //!if we want to filter
  3891. protected void AdjustExclusionAccessCondition(int occupiedSlot, int testedSlot, set<int> value, inout set<int> adjustedValue)
  3892. {
  3893. adjustedValue = value;
  3894. }
  3895. //! special propagation contition
  3896. protected bool CheckExclusionAccessPropagation(int occupiedSlot, int targetSlot, set<int> value, inout set<int> adjustedValue)
  3897. {
  3898. bool occupiedException = occupiedSlot == InventorySlots.HANDS || occupiedSlot == InventorySlots.SHOULDER || occupiedSlot == InventorySlots.MELEE || occupiedSlot == InventorySlots.LEFTHAND;
  3899. bool targetException = targetSlot == InventorySlots.HANDS || targetSlot == InventorySlots.SHOULDER || targetSlot == InventorySlots.MELEE || targetSlot == InventorySlots.LEFTHAND || targetSlot == InventorySlots.INVALID;
  3900. if (targetException)
  3901. {
  3902. adjustedValue = null;
  3903. return false;
  3904. }
  3905. AdjustExclusionAccessPropagation(occupiedSlot,targetSlot,value,adjustedValue);
  3906. return adjustedValue.Count() != 0;
  3907. }
  3908. //!if we want to filter propagation specifically; DO NOT override unless you know what you are doing.
  3909. protected void AdjustExclusionAccessPropagation(int occupiedSlot, int testedSlot, set<int> value, inout set<int> adjustedValue)
  3910. {
  3911. AdjustExclusionAccessCondition(occupiedSlot,testedSlot,value,adjustedValue);
  3912. }
  3913. //! checks specifically for att. exclusion conflicts before att. receive
  3914. bool CheckAttachmentReceiveExclusion(EntityAI attachment, int slotId)
  3915. {
  3916. EntityAI currentAtt = GetInventory().FindAttachment(slotId);
  3917. bool hasInternalConflict = attachment.HasInternalExclusionConflicts(slotId);
  3918. set<int> diff;
  3919. InventoryLocation curLoc = new InventoryLocation();
  3920. if (currentAtt) //probably a swap or same-type swap
  3921. {
  3922. diff = attachment.GetAttachmentExclusionMaskAll(slotId);
  3923. diff.RemoveItems(currentAtt.GetAttachmentExclusionMaskAll(slotId));
  3924. if (diff.Count() == 0)
  3925. {
  3926. return !hasInternalConflict;
  3927. }
  3928. else
  3929. {
  3930. return !hasInternalConflict && !IsExclusionFlagPresentRecursive(diff,slotId);
  3931. }
  3932. }
  3933. else if (attachment.GetInventory().GetCurrentInventoryLocation(curLoc) && curLoc.GetType() == InventoryLocationType.ATTACHMENT)
  3934. {
  3935. EntityAI rootOwner = attachment.GetHierarchyRoot();
  3936. if (rootOwner && rootOwner == this.GetHierarchyRoot()) //attachment within the same exclusion hierarchy context
  3937. {
  3938. diff = attachment.GetAttachmentExclusionMaskAll(slotId);
  3939. diff.RemoveItems(attachment.GetAttachmentExclusionMaskAll(curLoc.GetSlot()));
  3940. if (diff.Count() == 0)
  3941. {
  3942. return !hasInternalConflict;
  3943. }
  3944. else
  3945. {
  3946. return !hasInternalConflict && !IsExclusionFlagPresentRecursive(diff,slotId);
  3947. }
  3948. }
  3949. }
  3950. return !hasInternalConflict && !IsExclusionFlagPresentRecursive(attachment.GetAttachmentExclusionMaskAll(slotId),slotId);
  3951. }
  3952. bool IsManagingArrows()
  3953. {
  3954. return false;
  3955. }
  3956. ArrowManagerBase GetArrowManager()
  3957. {
  3958. return null;
  3959. }
  3960. void SetFromProjectile(ProjectileStoppedInfo info)
  3961. {
  3962. }
  3963. void ClearInventory();
  3964. };
  3965. #ifdef DEVELOPER
  3966. void SetDebugDeveloper_item(Object entity)//without a setter,the place where the setting happens is near impossible to find as way too many hits for "_item" exist
  3967. {
  3968. if (entity)
  3969. entity.SetDebugItem();
  3970. }
  3971. Object _item;//watched item goes here(LCTRL+RMB->Watch)
  3972. #endif