itembase.c 132 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930
  1. typedef ItemBase Inventory_Base;
  2. typedef map<typename,ref ActionOverrideData> TActionAnimOverrideMap;
  3. class DummyItem extends ItemBase
  4. {
  5. override bool CanPutAsAttachment(EntityAI parent)
  6. {
  7. return true;
  8. }
  9. };
  10. //const bool QUANTITY_DEBUG_REMOVE_ME = false;
  11. class ItemBase extends InventoryItem
  12. {
  13. static ref map<typename, ref TInputActionMap> m_ItemTypeActionsMap = new map<typename, ref TInputActionMap>;
  14. TInputActionMap m_InputActionMap;
  15. static ref map<typename, ref TActionAnimOverrideMap> m_ItemActionOverrides = new map<typename, ref TActionAnimOverrideMap>;
  16. bool m_ActionsInitialize;
  17. static int m_DebugActionsMask;
  18. bool m_RecipesInitialized;
  19. // ============================================
  20. // Variable Manipulation System
  21. // ============================================
  22. // Quantity
  23. float m_VarQuantity;
  24. float m_VarQuantityPrev;//for client to know quantity changed during synchronization
  25. int m_VarQuantityInit;
  26. int m_VarQuantityMin;
  27. int m_VarQuantityMax;
  28. int m_Count;
  29. float m_VarStackMax;
  30. float m_StoreLoadedQuantity = float.LOWEST;
  31. // Wet
  32. float m_VarWet;
  33. float m_VarWetPrev;//for client to know wetness changed during synchronization
  34. float m_VarWetInit;
  35. float m_VarWetMin;
  36. float m_VarWetMax;
  37. // Cleanness
  38. int m_Cleanness;
  39. int m_CleannessInit;
  40. int m_CleannessMin;
  41. int m_CleannessMax;
  42. // impact sounds
  43. bool m_WantPlayImpactSound;
  44. bool m_CanPlayImpactSound = true;
  45. float m_ImpactSpeed;
  46. int m_ImpactSoundSurfaceHash;
  47. //
  48. float m_HeatIsolation;
  49. float m_ItemModelLength;
  50. float m_ItemAttachOffset; // Offset length for when the item is attached e.g. to weapon
  51. int m_LiquidContainerMask;
  52. int m_VarLiquidType;
  53. int m_ItemBehaviour; // -1 = not specified; 0 = heavy item; 1= onehanded item; 2 = twohanded item
  54. int m_QuickBarBonus;
  55. bool m_IsBeingPlaced;
  56. bool m_IsHologram;
  57. bool m_IsTakeable;
  58. bool m_ThrowItemOnDrop;
  59. bool m_ItemBeingDroppedPhys;
  60. bool m_CanBeMovedOverride;
  61. bool m_FixDamageSystemInit = false; //can be changed on storage version check
  62. bool can_this_be_combined; //Check if item can be combined
  63. bool m_CanThisBeSplit; //Check if item can be split
  64. bool m_IsStoreLoad = false;
  65. bool m_CanShowQuantity;
  66. bool m_HasQuantityBar;
  67. protected bool m_CanBeDigged;
  68. protected bool m_IsResultOfSplit //! distinguish if item has been created as new or it came from splitting (server only flag)
  69. string m_SoundAttType;
  70. // items color variables
  71. int m_ColorComponentR;
  72. int m_ColorComponentG;
  73. int m_ColorComponentB;
  74. int m_ColorComponentA;
  75. //-------------------------------------------------------
  76. // light source managing
  77. ItemBase m_LightSourceItem;
  78. ref TIntArray m_SingleUseActions;
  79. ref TIntArray m_ContinuousActions;
  80. ref TIntArray m_InteractActions;
  81. //==============================================
  82. // agent system
  83. private int m_AttachedAgents;
  84. //! appears to be deprecated, legacy code
  85. void TransferModifiers(PlayerBase reciever);
  86. // Weapons & suppressors particle effects
  87. ref static map<int, ref array<ref WeaponParticlesOnFire>> m_OnFireEffect;
  88. ref static map<int, ref array<ref WeaponParticlesOnBulletCasingEject>> m_OnBulletCasingEjectEffect;
  89. ref map<int, ref array<ref WeaponParticlesOnOverheating>> m_OnOverheatingEffect;
  90. ref static map<string, int> m_WeaponTypeToID;
  91. static int m_LastRegisteredWeaponID = 0;
  92. // Overheating effects
  93. bool m_IsOverheatingEffectActive;
  94. float m_OverheatingShots;
  95. ref Timer m_CheckOverheating;
  96. int m_ShotsToStartOverheating = 0; // After these many shots, the overheating effect begins
  97. int m_MaxOverheatingValue = 0; // Limits the number of shots that will be tracked
  98. float m_OverheatingDecayInterval = 1; // Timer's interval for decrementing overheat effect's lifespan
  99. ref array <ref OverheatingParticle> m_OverheatingParticles;
  100. protected ref TStringArray m_HeadHidingSelections;
  101. protected bool m_HideSelectionsBySlot;
  102. // Admin Log
  103. PluginAdminLog m_AdminLog;
  104. // misc
  105. ref Timer m_PhysDropTimer;
  106. // Attachment Locking variables
  107. ref array<int> m_CompatibleLocks;
  108. protected int m_LockType;
  109. protected ref EffectSound m_LockingSound;
  110. protected string m_LockSoundSet;
  111. // ItemSoundHandler
  112. protected const int ITEM_SOUNDS_MAX = 63; // optimize network synch
  113. protected int m_SoundSyncPlay; // id for sound to play
  114. protected int m_SoundSyncStop; // id for sound to stop
  115. private ref ItemSoundHandler m_ItemSoundHandler;
  116. //temperature
  117. private float m_TemperaturePerQuantityWeight;
  118. // -------------------------------------------------------------------------
  119. void ItemBase()
  120. {
  121. SetEventMask(EntityEvent.INIT); // Enable EOnInit event
  122. m_SingleUseActions = new TIntArray;
  123. m_ContinuousActions = new TIntArray;
  124. m_InteractActions = new TIntArray;
  125. if (!GetGame().IsDedicatedServer())
  126. {
  127. if (HasMuzzle())
  128. {
  129. LoadParticleConfigOnFire(GetMuzzleID());
  130. if (m_ShotsToStartOverheating == 0)
  131. {
  132. LoadParticleConfigOnOverheating(GetMuzzleID());
  133. }
  134. }
  135. PreLoadSoundAttachmentType();
  136. m_ActionsInitialize = false;
  137. }
  138. m_OldLocation = null;
  139. if (GetGame().IsServer())
  140. {
  141. m_AdminLog = PluginAdminLog.Cast(GetPlugin(PluginAdminLog));
  142. }
  143. if (ConfigIsExisting("headSelectionsToHide"))
  144. {
  145. m_HeadHidingSelections = new TStringArray;
  146. ConfigGetTextArray("headSelectionsToHide",m_HeadHidingSelections);
  147. }
  148. m_HideSelectionsBySlot = false;
  149. if (ConfigIsExisting("hideSelectionsByinventorySlot"))
  150. {
  151. m_HideSelectionsBySlot = ConfigGetBool("hideSelectionsByinventorySlot");
  152. }
  153. m_QuickBarBonus = Math.Max(0, ConfigGetInt("quickBarBonus"));
  154. m_IsResultOfSplit = false;
  155. SetActionAnimOverrides();
  156. }
  157. override void InitItemVariables()
  158. {
  159. super.InitItemVariables();
  160. m_VarQuantityInit = ConfigGetInt("varQuantityInit");
  161. m_VarQuantity = m_VarQuantityInit;//should be by the CE, this is just a precaution
  162. m_VarQuantityMin = ConfigGetInt("varQuantityMin");
  163. m_VarQuantityMax = ConfigGetInt("varQuantityMax");
  164. m_VarStackMax = ConfigGetFloat("varStackMax");
  165. m_Count = ConfigGetInt("count");
  166. m_CanShowQuantity = ConfigGetBool("quantityShow");
  167. m_HasQuantityBar = ConfigGetBool("quantityBar");
  168. m_CleannessInit = ConfigGetInt("varCleannessInit");
  169. m_Cleanness = m_CleannessInit;
  170. m_CleannessMin = ConfigGetInt("varCleannessMin");
  171. m_CleannessMax = ConfigGetInt("varCleannessMax");
  172. m_WantPlayImpactSound = false;
  173. m_ImpactSpeed = 0.0;
  174. m_VarWetInit = ConfigGetFloat("varWetInit");
  175. m_VarWet = m_VarWetInit;
  176. m_VarWetMin = ConfigGetFloat("varWetMin");
  177. m_VarWetMax = ConfigGetFloat("varWetMax");
  178. m_LiquidContainerMask = ConfigGetInt("liquidContainerType");
  179. if (IsLiquidContainer() && GetQuantity() != 0)
  180. m_VarLiquidType = GetLiquidTypeInit();
  181. m_IsBeingPlaced = false;
  182. m_IsHologram = false;
  183. m_IsTakeable = true;
  184. m_CanBeMovedOverride = false;
  185. m_HeatIsolation = GetHeatIsolationInit();
  186. m_ItemModelLength = GetItemModelLength();
  187. m_ItemAttachOffset = GetItemAttachOffset();
  188. m_CanBeDigged = ConfigGetBool("canBeDigged");
  189. m_CompatibleLocks = new array<int>();
  190. ConfigGetIntArray("compatibleLocks", m_CompatibleLocks);
  191. m_LockType = ConfigGetInt("lockType");
  192. //Define if item can be split and set ability to be combined accordingly
  193. m_CanThisBeSplit = false;
  194. can_this_be_combined = false;
  195. if (ConfigIsExisting("canBeSplit"))
  196. {
  197. can_this_be_combined = ConfigGetBool("canBeSplit");
  198. m_CanThisBeSplit = can_this_be_combined;
  199. }
  200. m_ItemBehaviour = -1;
  201. if (ConfigIsExisting("itemBehaviour"))
  202. m_ItemBehaviour = ConfigGetInt("itemBehaviour");
  203. //RegisterNetSyncVariableInt("m_VariablesMask");
  204. if (HasQuantity()) RegisterNetSyncVariableFloat("m_VarQuantity", GetQuantityMin(), m_VarQuantityMax);
  205. RegisterNetSyncVariableFloat("m_VarWet", GetWetMin(), GetWetMax(), 2);
  206. RegisterNetSyncVariableInt("m_VarLiquidType");
  207. RegisterNetSyncVariableInt("m_Cleanness",0,1);
  208. RegisterNetSyncVariableBoolSignal("m_WantPlayImpactSound");
  209. RegisterNetSyncVariableFloat("m_ImpactSpeed");
  210. RegisterNetSyncVariableInt("m_ImpactSoundSurfaceHash");
  211. RegisterNetSyncVariableInt("m_ColorComponentR", 0, 255);
  212. RegisterNetSyncVariableInt("m_ColorComponentG", 0, 255);
  213. RegisterNetSyncVariableInt("m_ColorComponentB", 0, 255);
  214. RegisterNetSyncVariableInt("m_ColorComponentA", 0, 255);
  215. RegisterNetSyncVariableBool("m_IsBeingPlaced");
  216. RegisterNetSyncVariableBool("m_IsTakeable");
  217. RegisterNetSyncVariableBool("m_IsHologram");
  218. InitItemSounds();
  219. if (m_ItemSoundHandler)
  220. {
  221. RegisterNetSyncVariableInt("m_SoundSyncPlay", 0, ITEM_SOUNDS_MAX);
  222. RegisterNetSyncVariableInt("m_SoundSyncStop", 0, ITEM_SOUNDS_MAX);
  223. }
  224. m_LockSoundSet = ConfigGetString("lockSoundSet");
  225. m_TemperaturePerQuantityWeight = 1.0;;
  226. if (ConfigIsExisting("temperaturePerQuantityWeight"))
  227. m_TemperaturePerQuantityWeight = ConfigGetFloat("temperaturePerQuantityWeight");
  228. }
  229. override int GetQuickBarBonus()
  230. {
  231. return m_QuickBarBonus;
  232. }
  233. void InitializeActions()
  234. {
  235. m_InputActionMap = m_ItemTypeActionsMap.Get(this.Type());
  236. if (!m_InputActionMap)
  237. {
  238. TInputActionMap iam = new TInputActionMap;
  239. m_InputActionMap = iam;
  240. SetActions();
  241. m_ItemTypeActionsMap.Insert(this.Type(), m_InputActionMap);
  242. }
  243. }
  244. override void GetActions(typename action_input_type, out array<ActionBase_Basic> actions)
  245. {
  246. if (!m_ActionsInitialize)
  247. {
  248. m_ActionsInitialize = true;
  249. InitializeActions();
  250. }
  251. actions = m_InputActionMap.Get(action_input_type);
  252. }
  253. void SetActions()
  254. {
  255. AddAction(ActionTakeItem);
  256. AddAction(ActionTakeItemToHands);
  257. AddAction(ActionWorldCraft);
  258. AddAction(ActionDropItem);
  259. AddAction(ActionAttachWithSwitch);
  260. }
  261. void SetActionAnimOverrides(); // Override action animation for specific item
  262. void AddAction(typename actionName)
  263. {
  264. ActionBase action = ActionManagerBase.GetAction(actionName);
  265. if (!action)
  266. {
  267. Debug.LogError("Action " + actionName + " dosn't exist!");
  268. return;
  269. }
  270. typename ai = action.GetInputType();
  271. if (!ai)
  272. {
  273. m_ActionsInitialize = false;
  274. return;
  275. }
  276. array<ActionBase_Basic> action_array = m_InputActionMap.Get(ai);
  277. if (!action_array)
  278. {
  279. action_array = new array<ActionBase_Basic>;
  280. m_InputActionMap.Insert(ai, action_array);
  281. }
  282. if (LogManager.IsActionLogEnable())
  283. {
  284. Debug.ActionLog(action.ToString() + " -> " + ai, this.ToString() , "n/a", "Add action");
  285. }
  286. if (action_array.Find(action) != -1)
  287. {
  288. Debug.Log("Action " + action.Type() + " already added to " + this + ", skipping!");
  289. }
  290. else
  291. {
  292. action_array.Insert(action);
  293. }
  294. }
  295. void RemoveAction(typename actionName)
  296. {
  297. PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
  298. ActionBase action = player.GetActionManager().GetAction(actionName);
  299. typename ai = action.GetInputType();
  300. array<ActionBase_Basic> action_array = m_InputActionMap.Get(ai);
  301. if (action_array)
  302. {
  303. action_array.RemoveItem(action);
  304. }
  305. }
  306. // Allows override of default action command per item, defined in the SetActionAnimOverrides() of the item's class
  307. // Set -1 for params which should stay in default state
  308. void OverrideActionAnimation(typename action, int commandUID, int stanceMask = -1, int commandUIDProne = -1)
  309. {
  310. ActionOverrideData overrideData = new ActionOverrideData();
  311. overrideData.m_CommandUID = commandUID;
  312. overrideData.m_CommandUIDProne = commandUIDProne;
  313. overrideData.m_StanceMask = stanceMask;
  314. TActionAnimOverrideMap actionMap = m_ItemActionOverrides.Get(action);
  315. if (!actionMap) // create new map of action > overidables map
  316. {
  317. actionMap = new TActionAnimOverrideMap();
  318. m_ItemActionOverrides.Insert(action, actionMap);
  319. }
  320. actionMap.Insert(this.Type(), overrideData); // insert item -> overrides
  321. }
  322. void OnItemInHandsPlayerSwimStart(PlayerBase player);
  323. ScriptedLightBase GetLight();
  324. // Loads muzzle flash particle configuration from config and saves it to a map for faster access
  325. void LoadParticleConfigOnFire(int id)
  326. {
  327. if (!m_OnFireEffect)
  328. m_OnFireEffect = new map<int, ref array<ref WeaponParticlesOnFire>>;
  329. if (!m_OnBulletCasingEjectEffect)
  330. m_OnBulletCasingEjectEffect = new map<int, ref array<ref WeaponParticlesOnBulletCasingEject>>;
  331. string config_to_search = "CfgVehicles";
  332. string muzzle_owner_config;
  333. if (!m_OnFireEffect.Contains(id))
  334. {
  335. if (IsInherited(Weapon))
  336. config_to_search = "CfgWeapons";
  337. muzzle_owner_config = config_to_search + " " + GetType() + " ";
  338. string config_OnFire_class = muzzle_owner_config + "Particles " + "OnFire ";
  339. int config_OnFire_subclass_count = GetGame().ConfigGetChildrenCount(config_OnFire_class);
  340. if (config_OnFire_subclass_count > 0)
  341. {
  342. array<ref WeaponParticlesOnFire> WPOF_array = new array<ref WeaponParticlesOnFire>;
  343. for (int i = 0; i < config_OnFire_subclass_count; i++)
  344. {
  345. string particle_class = "";
  346. GetGame().ConfigGetChildName(config_OnFire_class, i, particle_class);
  347. string config_OnFire_entry = config_OnFire_class + particle_class;
  348. WeaponParticlesOnFire WPOF = new WeaponParticlesOnFire(this, config_OnFire_entry);
  349. WPOF_array.Insert(WPOF);
  350. }
  351. m_OnFireEffect.Insert(id, WPOF_array);
  352. }
  353. }
  354. if (!m_OnBulletCasingEjectEffect.Contains(id))
  355. {
  356. config_to_search = "CfgWeapons"; // Bullet Eject efect is supported on weapons only.
  357. muzzle_owner_config = config_to_search + " " + GetType() + " ";
  358. string config_OnBulletCasingEject_class = muzzle_owner_config + "Particles " + "OnBulletCasingEject ";
  359. int config_OnBulletCasingEject_count = GetGame().ConfigGetChildrenCount(config_OnBulletCasingEject_class);
  360. if (config_OnBulletCasingEject_count > 0 && IsInherited(Weapon))
  361. {
  362. array<ref WeaponParticlesOnBulletCasingEject> WPOBE_array = new array<ref WeaponParticlesOnBulletCasingEject>;
  363. for (i = 0; i < config_OnBulletCasingEject_count; i++)
  364. {
  365. string particle_class2 = "";
  366. GetGame().ConfigGetChildName(config_OnBulletCasingEject_class, i, particle_class2);
  367. string config_OnBulletCasingEject_entry = config_OnBulletCasingEject_class + particle_class2;
  368. WeaponParticlesOnBulletCasingEject WPOBE = new WeaponParticlesOnBulletCasingEject(this, config_OnBulletCasingEject_entry);
  369. WPOBE_array.Insert(WPOBE);
  370. }
  371. m_OnBulletCasingEjectEffect.Insert(id, WPOBE_array);
  372. }
  373. }
  374. }
  375. // Loads muzzle flash particle configuration from config and saves it to a map for faster access
  376. void LoadParticleConfigOnOverheating(int id)
  377. {
  378. if (!m_OnOverheatingEffect)
  379. m_OnOverheatingEffect = new map<int, ref array<ref WeaponParticlesOnOverheating>>;
  380. if (!m_OnOverheatingEffect.Contains(id))
  381. {
  382. string config_to_search = "CfgVehicles";
  383. if (IsInherited(Weapon))
  384. config_to_search = "CfgWeapons";
  385. string muzzle_owner_config = config_to_search + " " + GetType() + " ";
  386. string config_OnOverheating_class = muzzle_owner_config + "Particles " + "OnOverheating ";
  387. if (GetGame().ConfigIsExisting(config_OnOverheating_class))
  388. {
  389. m_ShotsToStartOverheating = GetGame().ConfigGetFloat(config_OnOverheating_class + "shotsToStartOverheating");
  390. if (m_ShotsToStartOverheating == 0)
  391. {
  392. m_ShotsToStartOverheating = -1; // This prevents futher readings from config for future creations of this item
  393. string error = "Error reading config " + GetType() + ">Particles>OnOverheating - Parameter shotsToStartOverheating is configured wrong or is missing! Its value must be 1 or higher!";
  394. Error(error);
  395. return;
  396. }
  397. m_OverheatingDecayInterval = GetGame().ConfigGetFloat(config_OnOverheating_class + "overheatingDecayInterval");
  398. m_MaxOverheatingValue = GetGame().ConfigGetFloat(config_OnOverheating_class + "maxOverheatingValue");
  399. int config_OnOverheating_subclass_count = GetGame().ConfigGetChildrenCount(config_OnOverheating_class);
  400. array<ref WeaponParticlesOnOverheating> WPOOH_array = new array<ref WeaponParticlesOnOverheating>;
  401. for (int i = 0; i < config_OnOverheating_subclass_count; i++)
  402. {
  403. string particle_class = "";
  404. GetGame().ConfigGetChildName(config_OnOverheating_class, i, particle_class);
  405. string config_OnOverheating_entry = config_OnOverheating_class + particle_class;
  406. int entry_type = GetGame().ConfigGetType(config_OnOverheating_entry);
  407. if (entry_type == CT_CLASS)
  408. {
  409. WeaponParticlesOnOverheating WPOF = new WeaponParticlesOnOverheating(this, config_OnOverheating_entry);
  410. WPOOH_array.Insert(WPOF);
  411. }
  412. }
  413. m_OnOverheatingEffect.Insert(id, WPOOH_array);
  414. }
  415. }
  416. }
  417. float GetOverheatingValue()
  418. {
  419. return m_OverheatingShots;
  420. }
  421. void IncreaseOverheating(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  422. {
  423. if (m_MaxOverheatingValue > 0)
  424. {
  425. m_OverheatingShots++;
  426. if (!m_CheckOverheating)
  427. m_CheckOverheating = new Timer(CALL_CATEGORY_SYSTEM);
  428. m_CheckOverheating.Stop();
  429. m_CheckOverheating.Run(m_OverheatingDecayInterval, this, "OnOverheatingDecay");
  430. CheckOverheating(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  431. }
  432. }
  433. void CheckOverheating(ItemBase weapon = null, string ammoType = "", ItemBase muzzle_owner = null, ItemBase suppressor = null, string config_to_search = "")
  434. {
  435. if (m_OverheatingShots >= m_ShotsToStartOverheating && IsOverheatingEffectActive())
  436. UpdateOverheating(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  437. if (m_OverheatingShots >= m_ShotsToStartOverheating && !IsOverheatingEffectActive())
  438. StartOverheating(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  439. if (m_OverheatingShots < m_ShotsToStartOverheating && IsOverheatingEffectActive())
  440. StopOverheating(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  441. if (m_OverheatingShots > m_MaxOverheatingValue)
  442. {
  443. m_OverheatingShots = m_MaxOverheatingValue;
  444. }
  445. }
  446. bool IsOverheatingEffectActive()
  447. {
  448. return m_IsOverheatingEffectActive;
  449. }
  450. void OnOverheatingDecay()
  451. {
  452. if (m_MaxOverheatingValue > 0)
  453. m_OverheatingShots -= 1 + m_OverheatingShots / m_MaxOverheatingValue; // The hotter a barrel is, the faster it needs to cool down.
  454. else
  455. m_OverheatingShots--;
  456. if (m_OverheatingShots <= 0)
  457. {
  458. m_CheckOverheating.Stop();
  459. m_OverheatingShots = 0;
  460. }
  461. else
  462. {
  463. if (!m_CheckOverheating)
  464. m_CheckOverheating = new Timer(CALL_CATEGORY_GAMEPLAY);
  465. m_CheckOverheating.Stop();
  466. m_CheckOverheating.Run(m_OverheatingDecayInterval, this, "OnOverheatingDecay");
  467. }
  468. CheckOverheating(this, "", this);
  469. }
  470. void StartOverheating(ItemBase weapon = null, string ammoType = "", ItemBase muzzle_owner = null, ItemBase suppressor = null, string config_to_search = "")
  471. {
  472. m_IsOverheatingEffectActive = true;
  473. ItemBase.PlayOverheatingParticles(this, ammoType, this, suppressor, "CfgWeapons");
  474. }
  475. void UpdateOverheating(ItemBase weapon = null, string ammoType = "", ItemBase muzzle_owner = null, ItemBase suppressor = null, string config_to_search = "")
  476. {
  477. KillAllOverheatingParticles();
  478. ItemBase.UpdateOverheatingParticles(this, ammoType, this, suppressor, "CfgWeapons");
  479. UpdateAllOverheatingParticles();
  480. }
  481. void StopOverheating(ItemBase weapon = null, string ammoType = "", ItemBase muzzle_owner = null, ItemBase suppressor = null, string config_to_search = "")
  482. {
  483. m_IsOverheatingEffectActive = false;
  484. ItemBase.StopOverheatingParticles(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  485. }
  486. void RegisterOverheatingParticle(Particle p, float min_heat_coef, float max_heat_coef, int particle_id, Object parent, vector local_pos, vector local_ori)
  487. {
  488. if (!m_OverheatingParticles)
  489. m_OverheatingParticles = new array<ref OverheatingParticle>;
  490. OverheatingParticle OP = new OverheatingParticle();
  491. OP.RegisterParticle(p);
  492. OP.SetOverheatingLimitMin(min_heat_coef);
  493. OP.SetOverheatingLimitMax(max_heat_coef);
  494. OP.SetParticleParams(particle_id, parent, local_pos, local_ori);
  495. m_OverheatingParticles.Insert(OP);
  496. }
  497. float GetOverheatingCoef()
  498. {
  499. if (m_MaxOverheatingValue > 0)
  500. return (m_OverheatingShots - m_ShotsToStartOverheating) / m_MaxOverheatingValue;
  501. return -1;
  502. }
  503. void UpdateAllOverheatingParticles()
  504. {
  505. if (m_OverheatingParticles)
  506. {
  507. float overheat_coef = GetOverheatingCoef();
  508. int count = m_OverheatingParticles.Count();
  509. for (int i = count; i > 0; --i)
  510. {
  511. int id = i - 1;
  512. OverheatingParticle OP = m_OverheatingParticles.Get(id);
  513. Particle p = OP.GetParticle();
  514. float overheat_min = OP.GetOverheatingLimitMin();
  515. float overheat_max = OP.GetOverheatingLimitMax();
  516. if (overheat_coef < overheat_min && overheat_coef >= overheat_max)
  517. {
  518. if (p)
  519. {
  520. p.Stop();
  521. OP.RegisterParticle(null);
  522. }
  523. }
  524. }
  525. }
  526. }
  527. void KillAllOverheatingParticles()
  528. {
  529. if (m_OverheatingParticles)
  530. {
  531. for (int i = m_OverheatingParticles.Count(); i > 0; i--)
  532. {
  533. int id = i - 1;
  534. OverheatingParticle OP = m_OverheatingParticles.Get(id);
  535. if (OP)
  536. {
  537. Particle p = OP.GetParticle();
  538. if (p)
  539. {
  540. p.Stop();
  541. }
  542. delete OP;
  543. }
  544. }
  545. m_OverheatingParticles.Clear();
  546. delete m_OverheatingParticles;
  547. }
  548. }
  549. //! Infection chance while/after using this item, originally used for wound infection after bandaging, params 'system' and 'param' can allow usage by other systems as well
  550. float GetInfectionChance(int system = 0, Param param = null)
  551. {
  552. return 0.0;
  553. }
  554. float GetDisinfectQuantity(int system = 0, Param param1 = null)
  555. {
  556. return 250;//default value
  557. }
  558. float GetFilterDamageRatio()
  559. {
  560. return 0;
  561. }
  562. //! Returns true if this item has a muzzle (weapons, suppressors)
  563. bool HasMuzzle()
  564. {
  565. if (IsInherited(Weapon) || IsInherited(SuppressorBase))
  566. return true;
  567. return false;
  568. }
  569. //! Returns global muzzle ID. If not found, then it gets automatically registered.
  570. int GetMuzzleID()
  571. {
  572. if (!m_WeaponTypeToID)
  573. m_WeaponTypeToID = new map<string, int>;
  574. if (m_WeaponTypeToID.Contains(GetType()))
  575. {
  576. return m_WeaponTypeToID.Get(GetType());
  577. }
  578. else
  579. {
  580. // Register new weapon ID
  581. m_WeaponTypeToID.Insert(GetType(), ++m_LastRegisteredWeaponID);
  582. }
  583. return m_LastRegisteredWeaponID;
  584. }
  585. /**
  586. \brief Re-sets DamageSystem changes
  587. \return storage version on which the config changes occured (default -1, to be overriden!)
  588. \note Significant changes to DamageSystem in item configs have to be re-set by increasing the storage version and overriding this method. Default return is -1 (does nothing).
  589. */
  590. int GetDamageSystemVersionChange()
  591. {
  592. return -1;
  593. }
  594. // -------------------------------------------------------------------------
  595. void ~ItemBase()
  596. {
  597. if (GetGame() && GetGame().GetPlayer() && (!GetGame().IsDedicatedServer()))
  598. {
  599. PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
  600. int r_index = player.GetHumanInventory().FindUserReservedLocationIndex(this);
  601. if (r_index >= 0)
  602. {
  603. InventoryLocation r_il = new InventoryLocation;
  604. player.GetHumanInventory().GetUserReservedLocation(r_index,r_il);
  605. player.GetHumanInventory().ClearUserReservedLocationAtIndex(r_index);
  606. int r_type = r_il.GetType();
  607. if (r_type == InventoryLocationType.CARGO || r_type == InventoryLocationType.PROXYCARGO)
  608. {
  609. r_il.GetParent().GetOnReleaseLock().Invoke(this);
  610. }
  611. else if (r_type == InventoryLocationType.ATTACHMENT)
  612. {
  613. r_il.GetParent().GetOnAttachmentReleaseLock().Invoke(this, r_il.GetSlot());
  614. }
  615. }
  616. player.GetHumanInventory().ClearUserReservedLocation(this);
  617. }
  618. if (m_LockingSound)
  619. SEffectManager.DestroyEffect(m_LockingSound);
  620. }
  621. // -------------------------------------------------------------------------
  622. static int GetDebugActionsMask()
  623. {
  624. return ItemBase.m_DebugActionsMask;
  625. }
  626. static bool HasDebugActionsMask(int mask)
  627. {
  628. return ItemBase.m_DebugActionsMask & mask;
  629. }
  630. static void SetDebugActionsMask(int mask)
  631. {
  632. ItemBase.m_DebugActionsMask = mask;
  633. }
  634. static void AddDebugActionsMask(int mask)
  635. {
  636. ItemBase.m_DebugActionsMask |= mask;
  637. }
  638. static void RemoveDebugActionsMask(int mask)
  639. {
  640. ItemBase.m_DebugActionsMask &= ~mask;
  641. }
  642. static void ToggleDebugActionsMask(int mask)
  643. {
  644. if (HasDebugActionsMask(mask))
  645. {
  646. RemoveDebugActionsMask(mask);
  647. }
  648. else
  649. {
  650. AddDebugActionsMask(mask);
  651. }
  652. }
  653. // -------------------------------------------------------------------------
  654. void SetCEBasedQuantity()
  655. {
  656. if (GetEconomyProfile())
  657. {
  658. float q_max = GetEconomyProfile().GetQuantityMax();
  659. if (q_max > 0)
  660. {
  661. float q_min = GetEconomyProfile().GetQuantityMin();
  662. float quantity_randomized = Math.RandomFloatInclusive(q_min, q_max);
  663. if (HasComponent(COMP_TYPE_ENERGY_MANAGER))//more direct access for speed
  664. {
  665. ComponentEnergyManager comp = GetCompEM();
  666. if (comp && (comp.GetEnergyMaxPristine() || comp.GetEnergyAtSpawn()))//checking for a potential for energy, we need to check both values, as both are optional, only when both are set to 0, we know the item can't have energy
  667. {
  668. comp.SetEnergy0To1(quantity_randomized);
  669. }
  670. }
  671. else if (HasQuantity())
  672. {
  673. SetQuantityNormalized(quantity_randomized, false);
  674. //PrintString("<==> Normalized quantity for item: "+ GetType()+", qmin:"+q_min.ToString()+"; qmax:"+q_max.ToString()+";quantity:" +quantity_randomized.ToString());
  675. }
  676. }
  677. }
  678. }
  679. //! Locks this item in it's current attachment slot of its parent. This makes the "locked" icon visible in inventory over this item.
  680. void LockToParent()
  681. {
  682. EntityAI parent = GetHierarchyParent();
  683. if (parent)
  684. {
  685. InventoryLocation inventory_location_to_lock = new InventoryLocation;
  686. GetInventory().GetCurrentInventoryLocation(inventory_location_to_lock);
  687. parent.GetInventory().SetSlotLock(inventory_location_to_lock.GetSlot(), true);
  688. }
  689. }
  690. //! Unlocks this item from its attachment slot of its parent.
  691. void UnlockFromParent()
  692. {
  693. EntityAI parent = GetHierarchyParent();
  694. if (parent)
  695. {
  696. InventoryLocation inventory_location_to_unlock = new InventoryLocation;
  697. GetInventory().GetCurrentInventoryLocation(inventory_location_to_unlock);
  698. parent.GetInventory().SetSlotLock(inventory_location_to_unlock.GetSlot(), false);
  699. }
  700. }
  701. override void CombineItemsClient(EntityAI entity2, bool use_stack_max = true)
  702. {
  703. /*
  704. ref Param1<EntityAI> item = new Param1<EntityAI>(entity2);
  705. RPCSingleParam(ERPCs.RPC_ITEM_COMBINE, item, GetGame().GetPlayer());
  706. */
  707. ItemBase item2 = ItemBase.Cast(entity2);
  708. if (GetGame().IsClient())
  709. {
  710. if (ScriptInputUserData.CanStoreInputUserData())
  711. {
  712. ScriptInputUserData ctx = new ScriptInputUserData;
  713. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  714. ctx.Write(-1);
  715. ItemBase i1 = this; // @NOTE: workaround for correct serialization
  716. ctx.Write(i1);
  717. ctx.Write(item2);
  718. ctx.Write(use_stack_max);
  719. ctx.Write(-1);
  720. ctx.Send();
  721. if (IsCombineAll(item2, use_stack_max))
  722. {
  723. GetGame().GetPlayer().GetInventory().AddInventoryReservationEx(item2,null,GameInventory.c_InventoryReservationTimeoutShortMS);
  724. }
  725. }
  726. }
  727. else if (!GetGame().IsMultiplayer())
  728. {
  729. CombineItems(item2, use_stack_max);
  730. }
  731. }
  732. bool IsLiquidPresent()
  733. {
  734. return (GetLiquidType() != 0 && HasQuantity());
  735. }
  736. bool IsLiquidContainer()
  737. {
  738. return m_LiquidContainerMask != 0;
  739. }
  740. int GetLiquidContainerMask()
  741. {
  742. return m_LiquidContainerMask;
  743. }
  744. bool IsBloodContainer()
  745. {
  746. //m_LiquidContainerMask & GROUP_LIQUID_BLOOD ???
  747. return false;
  748. }
  749. bool IsNVG()
  750. {
  751. return false;
  752. }
  753. //! explosive
  754. //! ------------
  755. bool IsExplosive()
  756. {
  757. return false;
  758. }
  759. string GetExplosiveTriggerSlotName()
  760. {
  761. return "";
  762. }
  763. //! ------------
  764. bool IsLightSource()
  765. {
  766. return false;
  767. }
  768. bool CanBeRepairedByCrafting()
  769. {
  770. return true;
  771. }
  772. //--- ACTION CONDITIONS
  773. //direction
  774. bool IsFacingPlayer(PlayerBase player, string selection)
  775. {
  776. return true;
  777. }
  778. bool IsPlayerInside(PlayerBase player, string selection)
  779. {
  780. return true;
  781. }
  782. override bool CanObstruct()
  783. {
  784. PlayerBase player = PlayerBase.Cast(g_Game.GetPlayer());
  785. return !player || !IsPlayerInside(player, "");
  786. }
  787. override bool IsBeingPlaced()
  788. {
  789. return m_IsBeingPlaced;
  790. }
  791. void SetIsBeingPlaced(bool is_being_placed)
  792. {
  793. m_IsBeingPlaced = is_being_placed;
  794. if (!is_being_placed)
  795. OnEndPlacement();
  796. SetSynchDirty();
  797. }
  798. //server-side
  799. void OnEndPlacement() {}
  800. override bool IsHologram()
  801. {
  802. return m_IsHologram;
  803. }
  804. bool CanBeDigged()
  805. {
  806. return m_CanBeDigged;
  807. }
  808. int GetOnDigWormsAmount()
  809. {
  810. return 1;
  811. }
  812. bool CanMakeGardenplot()
  813. {
  814. return false;
  815. }
  816. void SetIsHologram(bool is_hologram)
  817. {
  818. m_IsHologram = is_hologram;
  819. SetSynchDirty();
  820. }
  821. /*
  822. protected float GetNutritionalEnergy()
  823. {
  824. Edible_Base edible = Edible_Base.Cast(this);
  825. return edible.GetFoodEnergy();
  826. }
  827. protected float GetNutritionalWaterContent()
  828. {
  829. Edible_Base edible = Edible_Base.Cast(this);
  830. return edible.GetFoodWater();
  831. }
  832. protected float GetNutritionalIndex()
  833. {
  834. Edible_Base edible = Edible_Base.Cast(this);
  835. return edible.GetFoodNutritionalIndex();
  836. }
  837. protected float GetNutritionalFullnessIndex()
  838. {
  839. Edible_Base edible = Edible_Base.Cast(this);
  840. return edible.GetFoodTotalVolume();
  841. }
  842. protected float GetNutritionalToxicity()
  843. {
  844. Edible_Base edible = Edible_Base.Cast(this);
  845. return edible.GetFoodToxicity();
  846. }
  847. */
  848. // -------------------------------------------------------------------------
  849. override void OnMovedInsideCargo(EntityAI container)
  850. {
  851. super.OnMovedInsideCargo(container);
  852. MiscGameplayFunctions.RemoveAllAttachedChildrenByTypename(this, {Bolt_Base});
  853. }
  854. override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
  855. {
  856. super.EEItemLocationChanged(oldLoc,newLoc);
  857. PlayerBase new_player = null;
  858. PlayerBase old_player = null;
  859. if (newLoc.GetParent())
  860. new_player = PlayerBase.Cast(newLoc.GetParent().GetHierarchyRootPlayer());
  861. if (oldLoc.GetParent())
  862. old_player = PlayerBase.Cast(oldLoc.GetParent().GetHierarchyRootPlayer());
  863. if (old_player && oldLoc.GetType() == InventoryLocationType.HANDS)
  864. {
  865. int r_index = old_player.GetHumanInventory().FindUserReservedLocationIndex(this);
  866. if (r_index >= 0)
  867. {
  868. InventoryLocation r_il = new InventoryLocation;
  869. old_player.GetHumanInventory().GetUserReservedLocation(r_index,r_il);
  870. old_player.GetHumanInventory().ClearUserReservedLocationAtIndex(r_index);
  871. int r_type = r_il.GetType();
  872. if (r_type == InventoryLocationType.CARGO || r_type == InventoryLocationType.PROXYCARGO)
  873. {
  874. r_il.GetParent().GetOnReleaseLock().Invoke(this);
  875. }
  876. else if (r_type == InventoryLocationType.ATTACHMENT)
  877. {
  878. r_il.GetParent().GetOnAttachmentReleaseLock().Invoke(this, r_il.GetSlot());
  879. }
  880. }
  881. }
  882. if (newLoc.GetType() == InventoryLocationType.HANDS)
  883. {
  884. if (new_player)
  885. new_player.ForceStandUpForHeavyItems(newLoc.GetItem());
  886. if (new_player == old_player)
  887. {
  888. if (oldLoc.GetParent() && new_player.GetHumanInventory().LocationGetEntity(oldLoc) == NULL)
  889. {
  890. if (oldLoc.GetType() == InventoryLocationType.CARGO)
  891. {
  892. if (oldLoc.GetParent().GetInventory().TestAddEntityInCargoExLoc(oldLoc, false, false, false, true, false, false))
  893. {
  894. new_player.GetHumanInventory().SetUserReservedLocation(this,oldLoc);
  895. }
  896. }
  897. else
  898. {
  899. new_player.GetHumanInventory().SetUserReservedLocation(this,oldLoc);
  900. }
  901. }
  902. if (new_player.GetHumanInventory().FindUserReservedLocationIndex(this) >= 0)
  903. {
  904. int type = oldLoc.GetType();
  905. if (type == InventoryLocationType.CARGO || type == InventoryLocationType.PROXYCARGO)
  906. {
  907. oldLoc.GetParent().GetOnSetLock().Invoke(this);
  908. }
  909. else if (type == InventoryLocationType.ATTACHMENT)
  910. {
  911. oldLoc.GetParent().GetOnAttachmentSetLock().Invoke(this, oldLoc.GetSlot());
  912. }
  913. }
  914. if (!m_OldLocation)
  915. {
  916. m_OldLocation = new InventoryLocation;
  917. }
  918. m_OldLocation.Copy(oldLoc);
  919. }
  920. else
  921. {
  922. if (m_OldLocation)
  923. {
  924. m_OldLocation.Reset();
  925. }
  926. }
  927. GetGame().GetAnalyticsClient().OnItemAttachedAtPlayer(this,"Hands");
  928. }
  929. else
  930. {
  931. if (new_player)
  932. {
  933. int res_index = new_player.GetHumanInventory().FindCollidingUserReservedLocationIndex(this, newLoc);
  934. if (res_index >= 0)
  935. {
  936. InventoryLocation il = new InventoryLocation;
  937. new_player.GetHumanInventory().GetUserReservedLocation(res_index,il);
  938. ItemBase it = ItemBase.Cast(il.GetItem());
  939. new_player.GetHumanInventory().ClearUserReservedLocationAtIndex(res_index);
  940. int rel_type = il.GetType();
  941. if (rel_type == InventoryLocationType.CARGO || rel_type == InventoryLocationType.PROXYCARGO)
  942. {
  943. il.GetParent().GetOnReleaseLock().Invoke(it);
  944. }
  945. else if (rel_type == InventoryLocationType.ATTACHMENT)
  946. {
  947. il.GetParent().GetOnAttachmentReleaseLock().Invoke(it, il.GetSlot());
  948. }
  949. //it.GetOnReleaseLock().Invoke(it);
  950. }
  951. }
  952. else if (old_player && newLoc.GetType() == InventoryLocationType.GROUND && m_ThrowItemOnDrop)
  953. {
  954. //ThrowPhysically(old_player, vector.Zero);
  955. m_ThrowItemOnDrop = false;
  956. }
  957. if (m_OldLocation)
  958. {
  959. m_OldLocation.Reset();
  960. }
  961. }
  962. }
  963. override void EOnContact(IEntity other, Contact extra)
  964. {
  965. if (m_CanPlayImpactSound)
  966. {
  967. int liquidType = -1;
  968. float impactSpeed = ProcessImpactSoundEx(other, extra, m_ConfigWeight, m_ImpactSoundSurfaceHash, liquidType);
  969. if (impactSpeed > 0.0)
  970. {
  971. m_ImpactSpeed = impactSpeed;
  972. #ifndef SERVER
  973. PlayImpactSound(m_ConfigWeight, m_ImpactSpeed, m_ImpactSoundSurfaceHash);
  974. #else
  975. m_WantPlayImpactSound = true;
  976. SetSynchDirty();
  977. #endif
  978. m_CanPlayImpactSound = (liquidType == -1);// prevents further playing of the sound when the surface is a liquid type
  979. }
  980. }
  981. #ifdef SERVER
  982. if (GetCompEM() && GetCompEM().IsPlugged())
  983. {
  984. if (GetCompEM().GetCordLength() < vector.Distance(GetPosition(), GetCompEM().GetEnergySource().GetPosition()))
  985. GetCompEM().UnplugThis();
  986. }
  987. #endif
  988. }
  989. void RefreshPhysics();
  990. override void OnCreatePhysics()
  991. {
  992. RefreshPhysics();
  993. }
  994. override void OnItemAttachmentSlotChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
  995. {
  996. }
  997. // -------------------------------------------------------------------------
  998. override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
  999. {
  1000. super.OnItemLocationChanged(old_owner, new_owner);
  1001. PlayerBase relatedPlayer = PlayerBase.Cast(old_owner);
  1002. PlayerBase playerNew = PlayerBase.Cast(new_owner);
  1003. if (!relatedPlayer && playerNew)
  1004. relatedPlayer = playerNew;
  1005. if (relatedPlayer && relatedPlayer.GetPerformedActionID() != -1)
  1006. {
  1007. ActionManagerBase actionMgr = relatedPlayer.GetActionManager();
  1008. if (actionMgr)
  1009. {
  1010. ActionBase currentAction = actionMgr.GetRunningAction();
  1011. if (currentAction)
  1012. currentAction.OnItemLocationChanged(this);
  1013. }
  1014. }
  1015. Man ownerPlayerOld = null;
  1016. Man ownerPlayerNew = null;
  1017. if (old_owner)
  1018. {
  1019. if (old_owner.IsMan())
  1020. {
  1021. ownerPlayerOld = Man.Cast(old_owner);
  1022. }
  1023. else
  1024. {
  1025. ownerPlayerOld = Man.Cast(old_owner.GetHierarchyRootPlayer());
  1026. }
  1027. }
  1028. else
  1029. {
  1030. if (new_owner && IsElectricAppliance() && GetCompEM() && GetCompEM().IsPlugged())
  1031. {
  1032. ActionBase action = ActionManagerBase.GetAction(ActionRepositionPluggedItem);
  1033. if (!action || !playerNew || playerNew.GetPerformedActionID() != action.GetID())
  1034. {
  1035. GetCompEM().UnplugThis();
  1036. }
  1037. }
  1038. }
  1039. if (new_owner)
  1040. {
  1041. if (new_owner.IsMan())
  1042. {
  1043. ownerPlayerNew = Man.Cast(new_owner);
  1044. }
  1045. else
  1046. {
  1047. ownerPlayerNew = Man.Cast(new_owner.GetHierarchyRootPlayer());
  1048. }
  1049. }
  1050. if (ownerPlayerOld != ownerPlayerNew)
  1051. {
  1052. if (ownerPlayerOld)
  1053. {
  1054. array<EntityAI> subItemsExit = new array<EntityAI>;
  1055. GetInventory().EnumerateInventory(InventoryTraversalType.PREORDER,subItemsExit);
  1056. for (int i = 0; i < subItemsExit.Count(); i++)
  1057. {
  1058. ItemBase itemExit = ItemBase.Cast(subItemsExit.Get(i));
  1059. itemExit.OnInventoryExit(ownerPlayerOld);
  1060. }
  1061. }
  1062. if (ownerPlayerNew)
  1063. {
  1064. array<EntityAI> subItemsEnter = new array<EntityAI>;
  1065. GetInventory().EnumerateInventory(InventoryTraversalType.PREORDER,subItemsEnter);
  1066. for (int j = 0; j < subItemsEnter.Count(); j++)
  1067. {
  1068. ItemBase itemEnter = ItemBase.Cast(subItemsEnter.Get(j));
  1069. itemEnter.OnInventoryEnter(ownerPlayerNew);
  1070. }
  1071. }
  1072. }
  1073. else if (ownerPlayerNew != null)
  1074. {
  1075. PlayerBase nplayer;
  1076. if (PlayerBase.CastTo(nplayer, ownerPlayerNew))
  1077. {
  1078. array<EntityAI> subItemsUpdate = new array<EntityAI>;
  1079. GetInventory().EnumerateInventory(InventoryTraversalType.PREORDER,subItemsUpdate);
  1080. for (int k = 0; k < subItemsUpdate.Count(); k++)
  1081. {
  1082. ItemBase itemUpdate = ItemBase.Cast(subItemsUpdate.Get(k));
  1083. itemUpdate.UpdateQuickbarShortcutVisibility(nplayer);
  1084. }
  1085. }
  1086. }
  1087. if (old_owner)
  1088. old_owner.OnChildItemRemoved(this);
  1089. if (new_owner)
  1090. new_owner.OnChildItemReceived(this);
  1091. }
  1092. // -------------------------------------------------------------------------------
  1093. override void EEDelete(EntityAI parent)
  1094. {
  1095. super.EEDelete(parent);
  1096. PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
  1097. if (player)
  1098. {
  1099. OnInventoryExit(player);
  1100. if (player.IsAlive())
  1101. {
  1102. int r_index = player.GetHumanInventory().FindUserReservedLocationIndex(this);
  1103. if (r_index >= 0)
  1104. {
  1105. InventoryLocation r_il = new InventoryLocation;
  1106. player.GetHumanInventory().GetUserReservedLocation(r_index,r_il);
  1107. player.GetHumanInventory().ClearUserReservedLocationAtIndex(r_index);
  1108. int r_type = r_il.GetType();
  1109. if (r_type == InventoryLocationType.CARGO || r_type == InventoryLocationType.PROXYCARGO)
  1110. {
  1111. r_il.GetParent().GetOnReleaseLock().Invoke(this);
  1112. }
  1113. else if (r_type == InventoryLocationType.ATTACHMENT)
  1114. {
  1115. r_il.GetParent().GetOnAttachmentReleaseLock().Invoke(this, r_il.GetSlot());
  1116. }
  1117. }
  1118. player.RemoveQuickBarEntityShortcut(this);
  1119. }
  1120. }
  1121. }
  1122. // -------------------------------------------------------------------------------
  1123. override void EEKilled(Object killer)
  1124. {
  1125. super.EEKilled(killer);
  1126. //! item is able to explode in fire
  1127. if (killer && killer.IsFireplace() && CanExplodeInFire())
  1128. {
  1129. if (GetTemperature() >= GameConstants.ITEM_TEMPERATURE_TO_EXPLODE_MIN)
  1130. {
  1131. if (IsMagazine())
  1132. {
  1133. if (Magazine.Cast(this).GetAmmoCount() > 0)
  1134. {
  1135. ExplodeAmmo();
  1136. }
  1137. }
  1138. else
  1139. {
  1140. Explode(DamageType.EXPLOSION);
  1141. }
  1142. }
  1143. }
  1144. }
  1145. override void OnWasAttached(EntityAI parent, int slot_id)
  1146. {
  1147. MiscGameplayFunctions.RemoveAllAttachedChildrenByTypename(this, {Bolt_Base});
  1148. super.OnWasAttached(parent, slot_id);
  1149. if (HasQuantity())
  1150. UpdateNetSyncVariableFloat("m_VarQuantity", GetQuantityMin(), m_VarQuantityMax);
  1151. PlayAttachSound(InventorySlots.GetSlotName(slot_id));
  1152. }
  1153. override void OnWasDetached(EntityAI parent, int slot_id)
  1154. {
  1155. super.OnWasDetached(parent, slot_id);
  1156. if (HasQuantity())
  1157. UpdateNetSyncVariableFloat("m_VarQuantity", GetQuantityMin(), m_VarQuantityMax);
  1158. }
  1159. override string ChangeIntoOnAttach(string slot)
  1160. {
  1161. int idx;
  1162. TStringArray inventory_slots = new TStringArray;
  1163. TStringArray attach_types = new TStringArray;
  1164. ConfigGetTextArray("ChangeInventorySlot",inventory_slots);
  1165. if (inventory_slots.Count() < 1) //is string
  1166. {
  1167. inventory_slots.Insert(ConfigGetString("ChangeInventorySlot"));
  1168. attach_types.Insert(ConfigGetString("ChangeIntoOnAttach"));
  1169. }
  1170. else //is array
  1171. {
  1172. ConfigGetTextArray("ChangeIntoOnAttach",attach_types);
  1173. }
  1174. idx = inventory_slots.Find(slot);
  1175. if (idx < 0)
  1176. return "";
  1177. return attach_types.Get(idx);
  1178. }
  1179. override string ChangeIntoOnDetach()
  1180. {
  1181. int idx = -1;
  1182. string slot;
  1183. TStringArray inventory_slots = new TStringArray;
  1184. TStringArray detach_types = new TStringArray;
  1185. this.ConfigGetTextArray("ChangeInventorySlot",inventory_slots);
  1186. if (inventory_slots.Count() < 1) //is string
  1187. {
  1188. inventory_slots.Insert(this.ConfigGetString("ChangeInventorySlot"));
  1189. detach_types.Insert(this.ConfigGetString("ChangeIntoOnDetach"));
  1190. }
  1191. else //is array
  1192. {
  1193. this.ConfigGetTextArray("ChangeIntoOnDetach",detach_types);
  1194. if (detach_types.Count() < 1)
  1195. detach_types.Insert(this.ConfigGetString("ChangeIntoOnDetach"));
  1196. }
  1197. for (int i = 0; i < inventory_slots.Count(); i++)
  1198. {
  1199. slot = inventory_slots.Get(i);
  1200. }
  1201. if (slot != "")
  1202. {
  1203. if (detach_types.Count() == 1)
  1204. idx = 0;
  1205. else
  1206. idx = inventory_slots.Find(slot);
  1207. }
  1208. if (idx < 0)
  1209. return "";
  1210. return detach_types.Get(idx);
  1211. }
  1212. void ExplodeAmmo()
  1213. {
  1214. //timer
  1215. ref Timer explode_timer = new Timer(CALL_CATEGORY_SYSTEM);
  1216. //min/max time
  1217. float min_time = 1;
  1218. float max_time = 3;
  1219. float delay = Math.RandomFloat(min_time, max_time);
  1220. explode_timer.Run(delay, this, "DoAmmoExplosion");
  1221. }
  1222. void DoAmmoExplosion()
  1223. {
  1224. Magazine magazine = Magazine.Cast(this);
  1225. int pop_sounds_count = 6;
  1226. string pop_sounds[ 6 ] = { "ammopops_1","ammopops_2","ammopops_3","ammopops_4","ammopops_5","ammopops_6" };
  1227. //play sound
  1228. int sound_idx = Math.RandomInt(0, pop_sounds_count - 1);
  1229. string sound_name = pop_sounds[ sound_idx ];
  1230. GetGame().CreateSoundOnObject(this, sound_name, 20, false);
  1231. //remove ammo count
  1232. magazine.ServerAddAmmoCount(-1);
  1233. //if condition then repeat -> ExplodeAmmo
  1234. float min_temp_to_explode = 100; //min temperature for item to explode
  1235. if (magazine.GetAmmoCount() > 0 && GetTemperature() >= min_temp_to_explode) //TODO ? add check for parent -> fireplace
  1236. {
  1237. ExplodeAmmo();
  1238. }
  1239. }
  1240. // -------------------------------------------------------------------------------
  1241. override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
  1242. {
  1243. super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
  1244. const int CHANCE_DAMAGE_CARGO = 4;
  1245. const int CHANCE_DAMAGE_ATTACHMENT = 1;
  1246. const int CHANCE_DAMAGE_NOTHING = 2;
  1247. if (IsClothing() || IsContainer() || IsItemTent())
  1248. {
  1249. float dmg = damageResult.GetDamage("","Health") * -0.5;
  1250. int chances;
  1251. int rnd;
  1252. if (GetInventory().GetCargo())
  1253. {
  1254. chances = CHANCE_DAMAGE_CARGO + CHANCE_DAMAGE_ATTACHMENT + CHANCE_DAMAGE_NOTHING;
  1255. rnd = Math.RandomInt(0,chances);
  1256. if (rnd < CHANCE_DAMAGE_CARGO)
  1257. {
  1258. DamageItemInCargo(dmg);
  1259. }
  1260. else if (rnd < (chances - CHANCE_DAMAGE_NOTHING))
  1261. {
  1262. DamageItemAttachments(dmg);
  1263. }
  1264. }
  1265. else
  1266. {
  1267. chances = CHANCE_DAMAGE_ATTACHMENT + CHANCE_DAMAGE_NOTHING;
  1268. rnd = Math.RandomInt(0,chances);
  1269. if (rnd < CHANCE_DAMAGE_ATTACHMENT)
  1270. {
  1271. DamageItemAttachments(dmg);
  1272. }
  1273. }
  1274. }
  1275. }
  1276. bool DamageItemInCargo(float damage)
  1277. {
  1278. if (GetInventory().GetCargo())
  1279. {
  1280. int item_count = GetInventory().GetCargo().GetItemCount();
  1281. if (item_count > 0)
  1282. {
  1283. int random_pick = Math.RandomInt(0, item_count);
  1284. ItemBase item = ItemBase.Cast(GetInventory().GetCargo().GetItem(random_pick));
  1285. if (!item.IsExplosive())
  1286. {
  1287. item.AddHealth("","",damage);
  1288. return true;
  1289. }
  1290. }
  1291. }
  1292. return false;
  1293. }
  1294. bool DamageItemAttachments(float damage)
  1295. {
  1296. int attachment_count = GetInventory().AttachmentCount();
  1297. if (attachment_count > 0)
  1298. {
  1299. int random_pick = Math.RandomInt(0, attachment_count);
  1300. ItemBase attachment = ItemBase.Cast(GetInventory().GetAttachmentFromIndex(random_pick));
  1301. if (!attachment.IsExplosive())
  1302. {
  1303. attachment.AddHealth("","",damage);
  1304. return true;
  1305. }
  1306. }
  1307. return false;
  1308. }
  1309. override bool IsSplitable()
  1310. {
  1311. return m_CanThisBeSplit;
  1312. }
  1313. //----------------
  1314. override bool CanBeSplit()
  1315. {
  1316. if (IsSplitable() && (GetQuantity() > 1))
  1317. return GetInventory().CanRemoveEntity();
  1318. return false;
  1319. }
  1320. protected bool ShouldSplitQuantity(float quantity)
  1321. {
  1322. // don't call 'CanBeSplit' here, too strict and will introduce a freeze-crash when dismantling fence with a fireplace nearby
  1323. if (!IsSplitable())
  1324. return false;
  1325. // nothing to split?
  1326. if (GetQuantity() <= 1)
  1327. return false;
  1328. // check if we should re-use the item instead of creating a new copy?
  1329. // implicit cast to int, if 'IsSplitable' returns true, these values are assumed ints
  1330. int delta = GetQuantity() - quantity;
  1331. if (delta == 0)
  1332. return false;
  1333. // valid to split
  1334. return true;
  1335. }
  1336. override void SplitIntoStackMaxClient(EntityAI destination_entity, int slot_id )
  1337. {
  1338. if (GetGame().IsClient())
  1339. {
  1340. if (ScriptInputUserData.CanStoreInputUserData())
  1341. {
  1342. ScriptInputUserData ctx = new ScriptInputUserData;
  1343. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  1344. ctx.Write(1);
  1345. ItemBase i1 = this; // @NOTE: workaround for correct serialization
  1346. ctx.Write(i1);
  1347. ctx.Write(destination_entity);
  1348. ctx.Write(true);
  1349. ctx.Write(slot_id);
  1350. ctx.Send();
  1351. }
  1352. }
  1353. else if (!GetGame().IsMultiplayer())
  1354. {
  1355. SplitIntoStackMax(destination_entity, slot_id, PlayerBase.Cast(GetGame().GetPlayer()));
  1356. }
  1357. }
  1358. void SplitIntoStackMax(EntityAI destination_entity, int slot_id, PlayerBase player)
  1359. {
  1360. float split_quantity_new;
  1361. ItemBase new_item;
  1362. float quantity = GetQuantity();
  1363. float stack_max = GetTargetQuantityMax(slot_id);
  1364. InventoryLocation loc = new InventoryLocation;
  1365. if (destination_entity && slot_id != -1 && InventorySlots.IsSlotIdValid(slot_id))
  1366. {
  1367. if (stack_max <= GetQuantity())
  1368. split_quantity_new = stack_max;
  1369. else
  1370. split_quantity_new = GetQuantity();
  1371. if (ShouldSplitQuantity(split_quantity_new))
  1372. {
  1373. new_item = ItemBase.Cast(destination_entity.GetInventory().CreateAttachmentEx(this.GetType(), slot_id));
  1374. if (new_item)
  1375. {
  1376. new_item.SetResultOfSplit(true);
  1377. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1378. AddQuantity(-split_quantity_new, false, true);
  1379. new_item.SetQuantity(split_quantity_new, false, true);
  1380. }
  1381. }
  1382. }
  1383. else if (destination_entity && slot_id == -1)
  1384. {
  1385. if (quantity > stack_max)
  1386. split_quantity_new = stack_max;
  1387. else
  1388. split_quantity_new = quantity;
  1389. if (ShouldSplitQuantity(split_quantity_new))
  1390. {
  1391. if (destination_entity.GetInventory().FindFreeLocationFor(this, FindInventoryLocationType.ANY, loc))
  1392. {
  1393. Object o = destination_entity.GetInventory().LocationCreateEntity(loc, GetType(), ECE_IN_INVENTORY, RF_DEFAULT);
  1394. new_item = ItemBase.Cast(o);
  1395. }
  1396. if (new_item)
  1397. {
  1398. new_item.SetResultOfSplit(true);
  1399. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1400. AddQuantity(-split_quantity_new, false, true);
  1401. new_item.SetQuantity(split_quantity_new, false, true);
  1402. }
  1403. }
  1404. }
  1405. else
  1406. {
  1407. if (stack_max != 0)
  1408. {
  1409. if (stack_max < GetQuantity())
  1410. {
  1411. split_quantity_new = GetQuantity() - stack_max;
  1412. }
  1413. if (split_quantity_new == 0)
  1414. {
  1415. if (!GetGame().IsMultiplayer())
  1416. player.PhysicalPredictiveDropItem(this);
  1417. else
  1418. player.ServerDropEntity(this);
  1419. return;
  1420. }
  1421. if (ShouldSplitQuantity(split_quantity_new))
  1422. {
  1423. new_item = ItemBase.Cast(GetGame().CreateObjectEx(GetType(), player.GetWorldPosition(), ECE_PLACE_ON_SURFACE));
  1424. if (new_item)
  1425. {
  1426. new_item.SetResultOfSplit(true);
  1427. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1428. SetQuantity(split_quantity_new, false, true);
  1429. new_item.SetQuantity(stack_max, false, true);
  1430. new_item.PlaceOnSurface();
  1431. }
  1432. }
  1433. }
  1434. }
  1435. }
  1436. override void SplitIntoStackMaxEx(EntityAI destination_entity, int slot_id)
  1437. {
  1438. float split_quantity_new;
  1439. ItemBase new_item;
  1440. float quantity = GetQuantity();
  1441. float stack_max = GetTargetQuantityMax(slot_id);
  1442. InventoryLocation loc = new InventoryLocation;
  1443. if (destination_entity && slot_id != -1 && InventorySlots.IsSlotIdValid(slot_id))
  1444. {
  1445. if (stack_max <= GetQuantity())
  1446. split_quantity_new = stack_max;
  1447. else
  1448. split_quantity_new = GetQuantity();
  1449. if (ShouldSplitQuantity(split_quantity_new))
  1450. {
  1451. new_item = ItemBase.Cast(destination_entity.GetInventory().CreateAttachmentEx(this.GetType(), slot_id));
  1452. if (new_item)
  1453. {
  1454. new_item.SetResultOfSplit(true);
  1455. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1456. AddQuantity(-split_quantity_new, false, true);
  1457. new_item.SetQuantity(split_quantity_new, false, true);
  1458. }
  1459. }
  1460. }
  1461. else if (destination_entity && slot_id == -1)
  1462. {
  1463. if (quantity > stack_max)
  1464. split_quantity_new = stack_max;
  1465. else
  1466. split_quantity_new = quantity;
  1467. if (ShouldSplitQuantity(split_quantity_new))
  1468. {
  1469. if (destination_entity.GetInventory().FindFreeLocationFor(this, FindInventoryLocationType.ANY, loc))
  1470. {
  1471. Object o = destination_entity.GetInventory().LocationCreateEntity(loc, GetType(), ECE_IN_INVENTORY, RF_DEFAULT);
  1472. new_item = ItemBase.Cast(o);
  1473. }
  1474. if (new_item)
  1475. {
  1476. new_item.SetResultOfSplit(true);
  1477. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1478. AddQuantity(-split_quantity_new, false, true);
  1479. new_item.SetQuantity(split_quantity_new, false, true);
  1480. }
  1481. }
  1482. }
  1483. else
  1484. {
  1485. if (stack_max != 0)
  1486. {
  1487. if (stack_max < GetQuantity())
  1488. {
  1489. split_quantity_new = GetQuantity() - stack_max;
  1490. }
  1491. if (ShouldSplitQuantity(split_quantity_new))
  1492. {
  1493. new_item = ItemBase.Cast(GetGame().CreateObjectEx(GetType(),GetWorldPosition(), ECE_PLACE_ON_SURFACE));
  1494. if (new_item)
  1495. {
  1496. new_item.SetResultOfSplit(true);
  1497. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1498. SetQuantity(split_quantity_new, false, true);
  1499. new_item.SetQuantity(stack_max, false, true);
  1500. new_item.PlaceOnSurface();
  1501. }
  1502. }
  1503. }
  1504. }
  1505. }
  1506. void SplitIntoStackMaxToInventoryLocationClient(notnull InventoryLocation dst)
  1507. {
  1508. if (GetGame().IsClient())
  1509. {
  1510. if (ScriptInputUserData.CanStoreInputUserData())
  1511. {
  1512. ScriptInputUserData ctx = new ScriptInputUserData;
  1513. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  1514. ctx.Write(4);
  1515. ItemBase thiz = this; // @NOTE: workaround for correct serialization
  1516. ctx.Write(thiz);
  1517. dst.WriteToContext(ctx);
  1518. ctx.Send();
  1519. }
  1520. }
  1521. else if (!GetGame().IsMultiplayer())
  1522. {
  1523. SplitIntoStackMaxToInventoryLocation(dst);
  1524. }
  1525. }
  1526. void SplitIntoStackMaxCargoClient(EntityAI destination_entity, int idx, int row, int col)
  1527. {
  1528. if (GetGame().IsClient())
  1529. {
  1530. if (ScriptInputUserData.CanStoreInputUserData())
  1531. {
  1532. ScriptInputUserData ctx = new ScriptInputUserData;
  1533. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  1534. ctx.Write(2);
  1535. ItemBase dummy = this; // @NOTE: workaround for correct serialization
  1536. ctx.Write(dummy);
  1537. ctx.Write(destination_entity);
  1538. ctx.Write(true);
  1539. ctx.Write(idx);
  1540. ctx.Write(row);
  1541. ctx.Write(col);
  1542. ctx.Send();
  1543. }
  1544. }
  1545. else if (!GetGame().IsMultiplayer())
  1546. {
  1547. SplitIntoStackMaxCargo(destination_entity, idx, row, col);
  1548. }
  1549. }
  1550. void SplitIntoStackMaxToInventoryLocation(notnull InventoryLocation dst)
  1551. {
  1552. SplitIntoStackMaxToInventoryLocationEx(dst);
  1553. }
  1554. ItemBase SplitIntoStackMaxToInventoryLocationEx(notnull InventoryLocation dst)
  1555. {
  1556. float quantity = GetQuantity();
  1557. float split_quantity_new;
  1558. ItemBase new_item;
  1559. if (dst.IsValid())
  1560. {
  1561. int slot_id = dst.GetSlot();
  1562. float stack_max = GetTargetQuantityMax(slot_id);
  1563. if (quantity > stack_max)
  1564. split_quantity_new = stack_max;
  1565. else
  1566. split_quantity_new = quantity;
  1567. if (ShouldSplitQuantity(split_quantity_new))
  1568. {
  1569. new_item = ItemBase.Cast(GameInventory.LocationCreateEntity(dst, this.GetType(), ECE_IN_INVENTORY, RF_DEFAULT));
  1570. if (new_item)
  1571. {
  1572. new_item.SetResultOfSplit(true);
  1573. MiscGameplayFunctions.TransferItemProperties(this,new_item);
  1574. AddQuantity(-split_quantity_new, false, true);
  1575. new_item.SetQuantity(split_quantity_new, false, true);
  1576. }
  1577. return new_item;
  1578. }
  1579. }
  1580. return null;
  1581. }
  1582. void SplitIntoStackMaxCargo(EntityAI destination_entity, int idx, int row, int col)
  1583. {
  1584. float quantity = GetQuantity();
  1585. float split_quantity_new;
  1586. ItemBase new_item;
  1587. if (destination_entity)
  1588. {
  1589. float stackable = GetTargetQuantityMax();
  1590. if (quantity > stackable)
  1591. split_quantity_new = stackable;
  1592. else
  1593. split_quantity_new = quantity;
  1594. if (ShouldSplitQuantity(split_quantity_new))
  1595. {
  1596. new_item = ItemBase.Cast(destination_entity.GetInventory().CreateEntityInCargoEx(this.GetType(), idx, row, col, false));
  1597. if (new_item)
  1598. {
  1599. new_item.SetResultOfSplit(true);
  1600. MiscGameplayFunctions.TransferItemProperties(this,new_item);
  1601. AddQuantity(-split_quantity_new, false, true);
  1602. new_item.SetQuantity(split_quantity_new, false, true);
  1603. }
  1604. }
  1605. }
  1606. }
  1607. void SplitIntoStackMaxHandsClient(PlayerBase player)
  1608. {
  1609. if (GetGame().IsClient())
  1610. {
  1611. if (ScriptInputUserData.CanStoreInputUserData())
  1612. {
  1613. ScriptInputUserData ctx = new ScriptInputUserData;
  1614. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  1615. ctx.Write(3);
  1616. ItemBase i1 = this; // @NOTE: workaround for correct serialization
  1617. ctx.Write(i1);
  1618. ItemBase destination_entity = this;
  1619. ctx.Write(destination_entity);
  1620. ctx.Write(true);
  1621. ctx.Write(0);
  1622. ctx.Send();
  1623. }
  1624. }
  1625. else if (!GetGame().IsMultiplayer())
  1626. {
  1627. SplitIntoStackMaxHands(player);
  1628. }
  1629. }
  1630. void SplitIntoStackMaxHands(PlayerBase player)
  1631. {
  1632. float quantity = GetQuantity();
  1633. float split_quantity_new;
  1634. ref ItemBase new_item;
  1635. if (player)
  1636. {
  1637. float stackable = GetTargetQuantityMax();
  1638. if (quantity > stackable)
  1639. split_quantity_new = stackable;
  1640. else
  1641. split_quantity_new = quantity;
  1642. if (ShouldSplitQuantity(split_quantity_new))
  1643. {
  1644. EntityAI in_hands = player.GetHumanInventory().CreateInHands(this.GetType());
  1645. new_item = ItemBase.Cast(in_hands);
  1646. if (new_item)
  1647. {
  1648. new_item.SetResultOfSplit(true);
  1649. MiscGameplayFunctions.TransferItemProperties(this,new_item);
  1650. AddQuantity(-split_quantity_new, false, true);
  1651. new_item.SetQuantity(split_quantity_new, false, true);
  1652. }
  1653. }
  1654. }
  1655. }
  1656. void SplitItemToInventoryLocation(notnull InventoryLocation dst)
  1657. {
  1658. float quantity = GetQuantity();
  1659. float split_quantity_new = Math.Floor(quantity * 0.5);
  1660. if (!ShouldSplitQuantity(split_quantity_new))
  1661. return;
  1662. ItemBase new_item = ItemBase.Cast(GameInventory.LocationCreateEntity(dst, GetType(), ECE_IN_INVENTORY, RF_DEFAULT));
  1663. if (new_item)
  1664. {
  1665. if (new_item.GetQuantityMax() < split_quantity_new)
  1666. {
  1667. split_quantity_new = new_item.GetQuantityMax();
  1668. }
  1669. new_item.SetResultOfSplit(true);
  1670. MiscGameplayFunctions.TransferItemProperties(this, new_item);
  1671. if (dst.IsValid() && dst.GetType() == InventoryLocationType.ATTACHMENT && split_quantity_new > 1)
  1672. {
  1673. AddQuantity(-1, false, true);
  1674. new_item.SetQuantity(1, false, true);
  1675. }
  1676. else
  1677. {
  1678. AddQuantity(-split_quantity_new, false, true);
  1679. new_item.SetQuantity(split_quantity_new, false, true);
  1680. }
  1681. }
  1682. }
  1683. void SplitItem(PlayerBase player)
  1684. {
  1685. float quantity = GetQuantity();
  1686. float split_quantity_new = Math.Floor(quantity / 2);
  1687. if (!ShouldSplitQuantity(split_quantity_new))
  1688. return;
  1689. InventoryLocation invloc = new InventoryLocation;
  1690. bool found = player.GetInventory().FindFirstFreeLocationForNewEntity(GetType(), FindInventoryLocationType.ATTACHMENT, invloc);
  1691. ItemBase new_item;
  1692. new_item = player.CreateCopyOfItemInInventoryOrGroundEx(this, true);
  1693. if (new_item)
  1694. {
  1695. if (new_item.GetQuantityMax() < split_quantity_new)
  1696. {
  1697. split_quantity_new = new_item.GetQuantityMax();
  1698. }
  1699. if (found && invloc.IsValid() && invloc.GetType() == InventoryLocationType.ATTACHMENT && split_quantity_new > 1)
  1700. {
  1701. AddQuantity(-1, false, true);
  1702. new_item.SetQuantity(1, false, true);
  1703. }
  1704. else if (split_quantity_new > 1)
  1705. {
  1706. AddQuantity(-split_quantity_new, false, true);
  1707. new_item.SetQuantity(split_quantity_new, false, true);
  1708. }
  1709. }
  1710. }
  1711. //! Called on server side when this item's quantity is changed. Call super.OnQuantityChanged(); first when overriding this event.
  1712. void OnQuantityChanged(float delta)
  1713. {
  1714. SetWeightDirty();
  1715. ItemBase parent = ItemBase.Cast(GetHierarchyParent());
  1716. if (parent)
  1717. parent.OnAttachmentQuantityChangedEx(this, delta);
  1718. if (IsLiquidContainer())
  1719. {
  1720. if (GetQuantityNormalized() <= 0.0)
  1721. {
  1722. SetLiquidType(LIQUID_NONE);
  1723. }
  1724. else if (GetLiquidType() == LIQUID_NONE)
  1725. {
  1726. ErrorEx("Undefined liquid type quantity changed, please define liquid type first! Using init value.",ErrorExSeverity.INFO);
  1727. SetLiquidType(GetLiquidTypeInit());
  1728. }
  1729. }
  1730. }
  1731. //! Called on server side when some attachment's quantity is changed. Call super.OnAttachmentQuantityChanged(item); first when overriding this event.
  1732. void OnAttachmentQuantityChanged(ItemBase item)
  1733. {
  1734. // insert code here
  1735. }
  1736. //! Called on server side when some attachment's quantity is changed. Call super.OnAttachmentQuantityChanged(item); first when overriding this event.
  1737. void OnAttachmentQuantityChangedEx(ItemBase item , float delta)
  1738. {
  1739. OnAttachmentQuantityChanged(item);
  1740. }
  1741. override void EEHealthLevelChanged(int oldLevel, int newLevel, string zone)
  1742. {
  1743. super.EEHealthLevelChanged(oldLevel,newLevel,zone);
  1744. if (GetGame().IsServer())
  1745. {
  1746. if (newLevel == GameConstants.STATE_RUINED)
  1747. {
  1748. //! drops content of container when ruined in fireplace
  1749. EntityAI parent = GetHierarchyParent();
  1750. if (parent && parent.IsFireplace())
  1751. {
  1752. CargoBase cargo = GetInventory().GetCargo();
  1753. if (cargo)
  1754. {
  1755. for (int i = 0; i < cargo.GetItemCount(); ++i)
  1756. {
  1757. parent.GetInventory().TakeEntityToInventory(InventoryMode.SERVER, FindInventoryLocationType.CARGO, cargo.GetItem(i));
  1758. }
  1759. }
  1760. }
  1761. }
  1762. if (IsResultOfSplit())
  1763. {
  1764. // reset the splitting result flag, return to normal item behavior
  1765. SetResultOfSplit(false);
  1766. return;
  1767. }
  1768. if (m_Cleanness != 0 && oldLevel < newLevel && newLevel != 0)
  1769. {
  1770. SetCleanness(0);//unclean the item upon damage dealt
  1771. }
  1772. }
  1773. }
  1774. // just the split? TODO: verify
  1775. override void OnRightClick()
  1776. {
  1777. super.OnRightClick();
  1778. if (CanBeSplit() && !GetDayZGame().IsLeftCtrlDown() && !GetGame().GetPlayer().GetInventory().HasInventoryReservation(this,null))
  1779. {
  1780. if (GetGame().IsClient())
  1781. {
  1782. if (ScriptInputUserData.CanStoreInputUserData())
  1783. {
  1784. EntityAI root = GetHierarchyRoot();
  1785. Man playerOwner = GetHierarchyRootPlayer();
  1786. InventoryLocation dst = new InventoryLocation;
  1787. // If we have no hierarchy root player and the root is the same as this item the source item is in the vicinity so we want to create the new split item there also
  1788. if (!playerOwner && root && root == this)
  1789. {
  1790. SetInventoryLocationToVicinityOrCurrent(root, dst);
  1791. }
  1792. else
  1793. {
  1794. // Check if we can place the new split item in the same parent where the source item is placed in or otherwise drop it in vicinity
  1795. GetInventory().GetCurrentInventoryLocation(dst);
  1796. if (!dst.GetParent() || dst.GetParent() && !dst.GetParent().GetInventory().FindFreeLocationFor(this, FindInventoryLocationType.CARGO, dst))
  1797. {
  1798. PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
  1799. if (!player.GetInventory().FindFreeLocationFor(this, FindInventoryLocationType.CARGO, dst) || !playerOwner)
  1800. {
  1801. SetInventoryLocationToVicinityOrCurrent(root, dst);
  1802. }
  1803. else
  1804. {
  1805. dst.SetCargo(dst.GetParent(), this, dst.GetIdx(), dst.GetRow(), dst.GetCol(), dst.GetFlip());
  1806. /* hacky solution to check reservation of "this" item instead of null since the gamecode is checking null against null and returning reservation=true incorrectly
  1807. this shouldnt cause issues within this scope*/
  1808. if (GetGame().GetPlayer().GetInventory().HasInventoryReservation(this, dst))
  1809. {
  1810. SetInventoryLocationToVicinityOrCurrent(root, dst);
  1811. }
  1812. else
  1813. {
  1814. GetGame().GetPlayer().GetInventory().AddInventoryReservationEx(null, dst, GameInventory.c_InventoryReservationTimeoutShortMS);
  1815. }
  1816. }
  1817. }
  1818. }
  1819. ScriptInputUserData ctx = new ScriptInputUserData;
  1820. ctx.Write(INPUT_UDT_ITEM_MANIPULATION);
  1821. ctx.Write(4);
  1822. ItemBase thiz = this; // @NOTE: workaround for correct serialization
  1823. ctx.Write(thiz);
  1824. dst.WriteToContext(ctx);
  1825. ctx.Write(true); // dummy
  1826. ctx.Send();
  1827. }
  1828. }
  1829. else if (!GetGame().IsMultiplayer())
  1830. {
  1831. SplitItem(PlayerBase.Cast(GetGame().GetPlayer()));
  1832. }
  1833. }
  1834. }
  1835. protected void SetInventoryLocationToVicinityOrCurrent(EntityAI root, inout InventoryLocation dst)
  1836. {
  1837. if (root)
  1838. {
  1839. vector m4[4];
  1840. root.GetTransform(m4);
  1841. dst.SetGround(this, m4);
  1842. }
  1843. else
  1844. {
  1845. GetInventory().GetCurrentInventoryLocation(dst);
  1846. }
  1847. }
  1848. override bool CanBeCombined(EntityAI other_item, bool reservation_check = true, bool stack_max_limit = false)
  1849. {
  1850. //TODO: delete check zero quantity check after fix double posts hands fsm events
  1851. if (!other_item || GetType() != other_item.GetType() || (IsFullQuantity() && other_item.GetQuantity() > 0) || other_item == this)
  1852. return false;
  1853. if (GetHealthLevel() == GameConstants.STATE_RUINED || other_item.GetHealthLevel() == GameConstants.STATE_RUINED)
  1854. return false;
  1855. //can_this_be_combined = ConfigGetBool("canBeSplit");
  1856. if (!can_this_be_combined)
  1857. return false;
  1858. Magazine mag = Magazine.Cast(this);
  1859. if (mag)
  1860. {
  1861. if (mag.GetAmmoCount() >= mag.GetAmmoMax())
  1862. return false;
  1863. if (stack_max_limit)
  1864. {
  1865. Magazine other_mag = Magazine.Cast(other_item);
  1866. if (other_item)
  1867. {
  1868. if (mag.GetAmmoCount() + other_mag.GetAmmoCount() > mag.GetAmmoMax())
  1869. return false;
  1870. }
  1871. }
  1872. }
  1873. else
  1874. {
  1875. //TODO: delete check zero quantity check after fix double posts hands fsm events
  1876. if (GetQuantity() >= GetQuantityMax() && other_item.GetQuantity() > 0 )
  1877. return false;
  1878. if (stack_max_limit && (GetQuantity() + other_item.GetQuantity() > GetQuantityMax()))
  1879. return false;
  1880. }
  1881. PlayerBase player = null;
  1882. if (CastTo(player, GetHierarchyRootPlayer())) //false when attached to player's attachment slot
  1883. {
  1884. if (player.GetInventory().HasAttachment(this))
  1885. return false;
  1886. if (player.IsItemsToDelete())
  1887. return false;
  1888. }
  1889. if (reservation_check && (GetInventory().HasInventoryReservation(this, null) || other_item.GetInventory().HasInventoryReservation(other_item, null)))
  1890. return false;
  1891. int slotID;
  1892. string slotName;
  1893. if (GetInventory().GetCurrentAttachmentSlotInfo(slotID,slotName) && GetHierarchyParent().GetInventory().GetSlotLock(slotID))
  1894. return false;
  1895. return true;
  1896. }
  1897. bool IsCombineAll(ItemBase other_item, bool use_stack_max = false)
  1898. {
  1899. return ComputeQuantityUsed(other_item, use_stack_max) == other_item.GetQuantity();
  1900. }
  1901. bool IsResultOfSplit()
  1902. {
  1903. return m_IsResultOfSplit;
  1904. }
  1905. void SetResultOfSplit(bool value)
  1906. {
  1907. m_IsResultOfSplit = value;
  1908. }
  1909. int ComputeQuantityUsed(ItemBase other_item, bool use_stack_max = true)
  1910. {
  1911. return ComputeQuantityUsedEx(other_item, use_stack_max);
  1912. }
  1913. float ComputeQuantityUsedEx(ItemBase other_item, bool use_stack_max = true)
  1914. {
  1915. float other_item_quantity = other_item.GetQuantity();
  1916. float this_free_space;
  1917. float stack_max = GetQuantityMax();
  1918. this_free_space = stack_max - GetQuantity();
  1919. if (other_item_quantity > this_free_space)
  1920. {
  1921. return this_free_space;
  1922. }
  1923. else
  1924. {
  1925. return other_item_quantity;
  1926. }
  1927. }
  1928. override void CombineItemsEx(EntityAI entity2, bool use_stack_max = true)
  1929. {
  1930. CombineItems(ItemBase.Cast(entity2),use_stack_max);
  1931. }
  1932. void CombineItems(ItemBase other_item, bool use_stack_max = true)
  1933. {
  1934. if (!CanBeCombined(other_item, false))
  1935. return;
  1936. if (!IsMagazine() && other_item)
  1937. {
  1938. float quantity_used = ComputeQuantityUsedEx(other_item,use_stack_max);
  1939. if (quantity_used != 0)
  1940. {
  1941. float hp1 = GetHealth01("","");
  1942. float hp2 = other_item.GetHealth01("","");
  1943. float hpResult = ((hp1*GetQuantity()) + (hp2*quantity_used));
  1944. hpResult = hpResult / (GetQuantity() + quantity_used);
  1945. hpResult *= GetMaxHealth();
  1946. Math.Round(hpResult);
  1947. SetHealth("", "Health", hpResult);
  1948. AddQuantity(quantity_used);
  1949. other_item.AddQuantity(-quantity_used);
  1950. }
  1951. }
  1952. OnCombine(other_item);
  1953. }
  1954. void OnCombine(ItemBase other_item)
  1955. {
  1956. #ifdef SERVER
  1957. if (!GetHierarchyRootPlayer() && GetHierarchyParent())
  1958. GetHierarchyParent().IncreaseLifetimeUp();
  1959. #endif
  1960. };
  1961. void GetRecipesActions(Man player, out TSelectableActionInfoArray outputList)
  1962. {
  1963. PlayerBase p = PlayerBase.Cast(player);
  1964. array<int> recipesIds = p.m_Recipes;
  1965. PluginRecipesManager moduleRecipesManager = PluginRecipesManager.Cast(GetPlugin(PluginRecipesManager));
  1966. if (moduleRecipesManager)
  1967. {
  1968. EntityAI itemInHands = player.GetHumanInventory().GetEntityInHands();
  1969. moduleRecipesManager.GetValidRecipes(ItemBase.Cast(this), ItemBase.Cast(itemInHands), recipesIds, p);
  1970. }
  1971. for (int i = 0;i < recipesIds.Count(); i++)
  1972. {
  1973. int key = recipesIds.Get(i);
  1974. string recipeName = moduleRecipesManager.GetRecipeName(key);
  1975. outputList.Insert(new TSelectableActionInfo(SAT_CRAFTING, key, recipeName));
  1976. }
  1977. }
  1978. // -------------------------------------------------------------------------
  1979. override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
  1980. {
  1981. super.GetDebugActions(outputList);
  1982. //quantity
  1983. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ADD_QUANTITY, "Quantity +20%", FadeColors.LIGHT_GREY));
  1984. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.REMOVE_QUANTITY, "Quantity -20%", FadeColors.LIGHT_GREY));
  1985. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SET_QUANTITY_0, "Set Quantity 0", FadeColors.LIGHT_GREY));
  1986. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SET_MAX_QUANTITY, "Set Quantity Max", FadeColors.LIGHT_GREY));
  1987. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  1988. //health
  1989. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ADD_HEALTH, "Health +20%", FadeColors.LIGHT_GREY));
  1990. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.REMOVE_HEALTH, "Health -20%", FadeColors.LIGHT_GREY));
  1991. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.DESTROY_HEALTH, "Health 0", FadeColors.LIGHT_GREY));
  1992. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  1993. //temperature
  1994. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ADD_TEMPERATURE, "Temperature +20", FadeColors.LIGHT_GREY));
  1995. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.REMOVE_TEMPERATURE, "Temperature -20", FadeColors.LIGHT_GREY));
  1996. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FLIP_FROZEN, "Toggle Frozen", FadeColors.LIGHT_GREY));
  1997. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  1998. //wet
  1999. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ADD_WETNESS, "Wetness +20", FadeColors.LIGHT_GREY));
  2000. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.REMOVE_WETNESS, "Wetness -20", FadeColors.LIGHT_GREY));
  2001. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  2002. //liquidtype
  2003. if (IsLiquidContainer())
  2004. {
  2005. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.LIQUIDTYPE_UP, "LiquidType Next", FadeColors.LIGHT_GREY));
  2006. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.LIQUIDTYPE_DOWN, "LiquidType Previous", FadeColors.LIGHT_GREY));
  2007. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  2008. }
  2009. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.MAKE_SPECIAL, "Make Special", FadeColors.LIGHT_GREY));
  2010. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  2011. // watch
  2012. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.WATCH_ITEM, "Watch (CTRL-Z)", FadeColors.LIGHT_GREY));
  2013. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.WATCH_PLAYER, "Watch Player", FadeColors.LIGHT_GREY));
  2014. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  2015. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.DELETE, "Delete", FadeColors.RED));
  2016. InventoryLocation loc = new InventoryLocation();
  2017. GetInventory().GetCurrentInventoryLocation(loc);
  2018. if (!loc || loc.GetType() == InventoryLocationType.GROUND)
  2019. {
  2020. if (Gizmo_IsSupported())
  2021. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GIZMO_OBJECT, "Gizmo Object", FadeColors.LIGHT_GREY));
  2022. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.GIZMO_PHYSICS, "Gizmo Physics (SP Only)", FadeColors.LIGHT_GREY)); // intentionally allowed for testing physics desync
  2023. }
  2024. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  2025. }
  2026. // -------------------------------------------------------------------------
  2027. // -------------------------------------------------------------------------
  2028. // -------------------------------------------------------------------------
  2029. override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  2030. {
  2031. super.OnAction(action_id, player, ctx);
  2032. if (GetGame().IsClient() || !GetGame().IsMultiplayer())
  2033. {
  2034. switch (action_id)
  2035. {
  2036. case EActions.GIZMO_OBJECT:
  2037. GetGame().GizmoSelectObject(this);
  2038. return true;
  2039. case EActions.GIZMO_PHYSICS:
  2040. GetGame().GizmoSelectPhysics(GetPhysics());
  2041. return true;
  2042. }
  2043. }
  2044. if (GetGame().IsServer())
  2045. {
  2046. switch (action_id)
  2047. {
  2048. case EActions.DELETE:
  2049. Delete();
  2050. return true;
  2051. }
  2052. }
  2053. if (action_id >= EActions.RECIPES_RANGE_START && action_id < EActions.RECIPES_RANGE_END)
  2054. {
  2055. PluginRecipesManager plugin_recipes_manager = PluginRecipesManager.Cast(GetPlugin(PluginRecipesManager));
  2056. int idWithoutOffset = action_id - EActions.RECIPES_RANGE_START;
  2057. PlayerBase p = PlayerBase.Cast(player);
  2058. if (EActions.RECIPES_RANGE_START < 1000)
  2059. {
  2060. float anim_length = plugin_recipes_manager.GetRecipeLengthInSecs(idWithoutOffset);
  2061. float specialty_weight = plugin_recipes_manager.GetRecipeSpecialty(idWithoutOffset);
  2062. }
  2063. }
  2064. #ifndef SERVER
  2065. else if (action_id == EActions.WATCH_PLAYER)
  2066. {
  2067. PluginDeveloper.SetDeveloperItemClientEx(player);
  2068. }
  2069. #endif
  2070. if (GetGame().IsServer())
  2071. {
  2072. if (action_id >= EActions.DEBUG_ITEM_WATCH_BUTTON_RANGE_START && action_id < EActions.DEBUG_ITEM_WATCH_BUTTON_RANGE_END)
  2073. {
  2074. int id = action_id - EActions.DEBUG_ITEM_WATCH_BUTTON_RANGE_START;
  2075. OnDebugButtonPressServer(id + 1);
  2076. }
  2077. else if (action_id >= EActions.DEBUG_AGENTS_RANGE_INJECT_START && action_id < EActions.DEBUG_AGENTS_RANGE_INJECT_END)
  2078. {
  2079. int agent_id = action_id - EActions.DEBUG_AGENTS_RANGE_INJECT_START;
  2080. InsertAgent(agent_id,100);
  2081. }
  2082. else if (action_id >= EActions.DEBUG_AGENTS_RANGE_REMOVE_START && action_id < EActions.DEBUG_AGENTS_RANGE_REMOVE_END)
  2083. {
  2084. int agent_id2 = action_id - EActions.DEBUG_AGENTS_RANGE_REMOVE_START;
  2085. RemoveAgent(agent_id2);
  2086. }
  2087. else if (action_id == EActions.ADD_QUANTITY)
  2088. {
  2089. if (IsMagazine())
  2090. {
  2091. Magazine mag = Magazine.Cast(this);
  2092. mag.ServerSetAmmoCount(mag.GetAmmoCount() + mag.GetAmmoMax() * 0.2);
  2093. }
  2094. else
  2095. {
  2096. AddQuantity(GetQuantityMax() * 0.2);
  2097. }
  2098. if (m_EM)
  2099. {
  2100. m_EM.AddEnergy(m_EM.GetEnergyMax() * 0.2);
  2101. }
  2102. //PrintVariables();
  2103. }
  2104. else if (action_id == EActions.REMOVE_QUANTITY) //Quantity -20%
  2105. {
  2106. if (IsMagazine())
  2107. {
  2108. Magazine mag2 = Magazine.Cast(this);
  2109. mag2.ServerSetAmmoCount(mag2.GetAmmoCount() - mag2.GetAmmoMax() * 0.2);
  2110. }
  2111. else
  2112. {
  2113. AddQuantity(- GetQuantityMax() * 0.2);
  2114. }
  2115. if (m_EM)
  2116. {
  2117. m_EM.AddEnergy(- m_EM.GetEnergyMax() * 0.2);
  2118. }
  2119. //PrintVariables();
  2120. }
  2121. else if (action_id == EActions.SET_QUANTITY_0) //SetMaxQuantity
  2122. {
  2123. SetQuantity(0);
  2124. if (m_EM)
  2125. {
  2126. m_EM.SetEnergy(0);
  2127. }
  2128. }
  2129. else if (action_id == EActions.SET_MAX_QUANTITY) //SetMaxQuantity
  2130. {
  2131. SetQuantityMax();
  2132. if (m_EM)
  2133. {
  2134. m_EM.SetEnergy(m_EM.GetEnergyMax());
  2135. }
  2136. }
  2137. else if (action_id == EActions.ADD_HEALTH)
  2138. {
  2139. AddHealth("","",GetMaxHealth("","Health")/5);
  2140. }
  2141. else if (action_id == EActions.REMOVE_HEALTH)
  2142. {
  2143. AddHealth("","",-GetMaxHealth("","Health")/5);
  2144. }
  2145. else if (action_id == EActions.DESTROY_HEALTH)
  2146. {
  2147. SetHealth01("","",0);
  2148. }
  2149. else if (action_id == EActions.WATCH_ITEM)
  2150. {
  2151. PluginItemDiagnostic mid = PluginItemDiagnostic.Cast(GetPlugin(PluginItemDiagnostic));
  2152. mid.RegisterDebugItem(ItemBase.Cast(this), PlayerBase.Cast(player));
  2153. #ifdef DEVELOPER
  2154. SetDebugDeveloper_item(this);
  2155. #endif
  2156. }
  2157. else if (action_id == EActions.ADD_TEMPERATURE)
  2158. {
  2159. AddTemperature(20);
  2160. //PrintVariables();
  2161. }
  2162. else if (action_id == EActions.REMOVE_TEMPERATURE)
  2163. {
  2164. AddTemperature(-20);
  2165. //PrintVariables();
  2166. }
  2167. else if (action_id == EActions.FLIP_FROZEN)
  2168. {
  2169. SetFrozen(!GetIsFrozen());
  2170. //PrintVariables();
  2171. }
  2172. else if (action_id == EActions.ADD_WETNESS)
  2173. {
  2174. AddWet(GetWetMax()/5);
  2175. //PrintVariables();
  2176. }
  2177. else if (action_id == EActions.REMOVE_WETNESS)
  2178. {
  2179. AddWet(-GetWetMax()/5);
  2180. //PrintVariables();
  2181. }
  2182. else if (action_id == EActions.LIQUIDTYPE_UP)
  2183. {
  2184. int curr_type = GetLiquidType();
  2185. SetLiquidType(curr_type * 2);
  2186. //AddWet(1);
  2187. //PrintVariables();
  2188. }
  2189. else if (action_id == EActions.LIQUIDTYPE_DOWN)
  2190. {
  2191. int curr_type2 = GetLiquidType();
  2192. SetLiquidType(curr_type2 / 2);
  2193. }
  2194. else if (action_id == EActions.MAKE_SPECIAL)
  2195. {
  2196. auto debugParams = DebugSpawnParams.WithPlayer(player);
  2197. OnDebugSpawnEx(debugParams);
  2198. }
  2199. }
  2200. return false;
  2201. }
  2202. // -------------------------------------------------------------------------
  2203. //! DEPRECATED use OnActivatedByItem below
  2204. //! Called when this item is activated from a trip wire that was stepped on.
  2205. void OnActivatedByTripWire();
  2206. //! Called when this item is activated by other
  2207. void OnActivatedByItem(notnull ItemBase item);
  2208. //----------------------------------------------------------------
  2209. //returns true if item is able to explode when put in fire
  2210. bool CanExplodeInFire()
  2211. {
  2212. return false;
  2213. }
  2214. //----------------------------------------------------------------
  2215. bool CanEat()
  2216. {
  2217. return true;
  2218. }
  2219. //----------------------------------------------------------------
  2220. override bool IsIgnoredByConstruction()
  2221. {
  2222. return true;
  2223. }
  2224. //----------------------------------------------------------------
  2225. //has FoodStages in config?
  2226. bool HasFoodStage()
  2227. {
  2228. string config_path = string.Format("CfgVehicles %1 Food FoodStages", GetType());
  2229. return GetGame().ConfigIsExisting(config_path);
  2230. }
  2231. //! overridden on Edible_Base; so we don't have to parse configs all the time
  2232. FoodStage GetFoodStage()
  2233. {
  2234. return null;
  2235. }
  2236. bool CanBeCooked()
  2237. {
  2238. return false;
  2239. }
  2240. bool CanBeCookedOnStick()
  2241. {
  2242. return false;
  2243. }
  2244. //! cooking-related effect methods
  2245. void RefreshAudioVisualsOnClient( CookingMethodType cooking_method, bool is_done, bool is_empty, bool is_burned );
  2246. void RemoveAudioVisualsOnClient();
  2247. //----------------------------------------------------------------
  2248. bool CanRepair(ItemBase item_repair_kit)
  2249. {
  2250. PluginRepairing module_repairing = PluginRepairing.Cast(GetPlugin(PluginRepairing));
  2251. return module_repairing.CanRepair(this, item_repair_kit);
  2252. }
  2253. //----------------------------------------------------------------
  2254. bool Repair(PlayerBase player, ItemBase item_repair_kit, float specialty_weight)
  2255. {
  2256. PluginRepairing module_repairing = PluginRepairing.Cast(GetPlugin(PluginRepairing));
  2257. return module_repairing.Repair(player, this, item_repair_kit, specialty_weight);
  2258. }
  2259. //----------------------------------------------------------------
  2260. int GetItemSize()
  2261. {
  2262. /*
  2263. vector v_size = this.ConfigGetVector("itemSize");
  2264. int v_size_x = v_size[0];
  2265. int v_size_y = v_size[1];
  2266. int size = v_size_x * v_size_y;
  2267. return size;
  2268. */
  2269. return 1;
  2270. }
  2271. //----------------------------------------------------------------
  2272. //Override for allowing seemingly unallowed moves when two clients send a conflicting message simultaneously
  2273. bool CanBeMovedOverride()
  2274. {
  2275. return m_CanBeMovedOverride;
  2276. }
  2277. //----------------------------------------------------------------
  2278. //Override for allowing seemingly unallowed moves when two clients send a conflicting message simultaneously
  2279. void SetCanBeMovedOverride(bool setting)
  2280. {
  2281. m_CanBeMovedOverride = setting;
  2282. }
  2283. //----------------------------------------------------------------
  2284. /**
  2285. \brief Send message to owner player in grey color
  2286. \return \p void
  2287. @code
  2288. item_stone.MessageToOwnerStatus("Some Status Message");
  2289. @endcode
  2290. */
  2291. void MessageToOwnerStatus(string text)
  2292. {
  2293. PlayerBase player = PlayerBase.Cast(this.GetHierarchyRootPlayer());
  2294. if (player)
  2295. {
  2296. player.MessageStatus(text);
  2297. }
  2298. }
  2299. //----------------------------------------------------------------
  2300. /**
  2301. \brief Send message to owner player in yellow color
  2302. \return \p void
  2303. @code
  2304. item_stone.MessageToOwnerAction("Some Action Message");
  2305. @endcode
  2306. */
  2307. void MessageToOwnerAction(string text)
  2308. {
  2309. PlayerBase player = PlayerBase.Cast(this.GetHierarchyRootPlayer());
  2310. if (player)
  2311. {
  2312. player.MessageAction(text);
  2313. }
  2314. }
  2315. //----------------------------------------------------------------
  2316. /**
  2317. \brief Send message to owner player in green color
  2318. \return \p void
  2319. @code
  2320. item_stone.MessageToOwnerFriendly("Some Friendly Message");
  2321. @endcode
  2322. */
  2323. void MessageToOwnerFriendly(string text)
  2324. {
  2325. PlayerBase player = PlayerBase.Cast(this.GetHierarchyRootPlayer());
  2326. if (player)
  2327. {
  2328. player.MessageFriendly(text);
  2329. }
  2330. }
  2331. //----------------------------------------------------------------
  2332. /**
  2333. \brief Send message to owner player in red color
  2334. \return \p void
  2335. @code
  2336. item_stone.MessageToOwnerImportant("Some Important Message");
  2337. @endcode
  2338. */
  2339. void MessageToOwnerImportant(string text)
  2340. {
  2341. PlayerBase player = PlayerBase.Cast(this.GetHierarchyRootPlayer());
  2342. if (player)
  2343. {
  2344. player.MessageImportant(text);
  2345. }
  2346. }
  2347. override bool IsItemBase()
  2348. {
  2349. return true;
  2350. }
  2351. // Checks if item is of questioned kind
  2352. override bool KindOf(string tag)
  2353. {
  2354. bool found = false;
  2355. string item_name = this.GetType();
  2356. ref TStringArray item_tag_array = new TStringArray;
  2357. GetGame().ConfigGetTextArray("cfgVehicles " + item_name + " itemInfo", item_tag_array);
  2358. int array_size = item_tag_array.Count();
  2359. for (int i = 0; i < array_size; i++)
  2360. {
  2361. if (item_tag_array.Get(i) == tag)
  2362. {
  2363. found = true;
  2364. break;
  2365. }
  2366. }
  2367. return found;
  2368. }
  2369. override void OnRPC(PlayerIdentity sender, int rpc_type,ParamsReadContext ctx)
  2370. {
  2371. //Debug.Log("OnRPC called");
  2372. super.OnRPC(sender, rpc_type,ctx);
  2373. //Play soundset for attachment locking (ActionLockAttachment.c)
  2374. switch (rpc_type)
  2375. {
  2376. #ifndef SERVER
  2377. case ERPCs.RPC_SOUND_LOCK_ATTACH:
  2378. Param2<bool, string> p = new Param2<bool, string>(false, "");
  2379. if (!ctx.Read(p))
  2380. return;
  2381. bool play = p.param1;
  2382. string soundSet = p.param2;
  2383. if (play)
  2384. {
  2385. if (m_LockingSound)
  2386. {
  2387. if (!m_LockingSound.IsSoundPlaying())
  2388. {
  2389. m_LockingSound = SEffectManager.PlaySound(soundSet, GetPosition(), 0, 0, true);
  2390. }
  2391. }
  2392. else
  2393. {
  2394. m_LockingSound = SEffectManager.PlaySound(soundSet, GetPosition(), 0, 0, true);
  2395. }
  2396. }
  2397. else
  2398. {
  2399. SEffectManager.DestroyEffect(m_LockingSound);
  2400. }
  2401. break;
  2402. #endif
  2403. }
  2404. if (GetWrittenNoteData())
  2405. {
  2406. GetWrittenNoteData().OnRPC(sender, rpc_type,ctx);
  2407. }
  2408. }
  2409. //-----------------------------
  2410. // VARIABLE MANIPULATION SYSTEM
  2411. //-----------------------------
  2412. int NameToID(string name)
  2413. {
  2414. PluginVariables plugin = PluginVariables.Cast(GetPlugin(PluginVariables));
  2415. return plugin.GetID(name);
  2416. }
  2417. string IDToName(int id)
  2418. {
  2419. PluginVariables plugin = PluginVariables.Cast(GetPlugin(PluginVariables));
  2420. return plugin.GetName(id);
  2421. }
  2422. //! DEPRECATED (most likely)
  2423. void OnSyncVariables(ParamsReadContext ctx)//with ID optimization
  2424. {
  2425. //Debug.Log("OnSyncVariables called for item: "+ ToString(this.GetType()),"varSync");
  2426. //read the flags
  2427. int varFlags;
  2428. if (!ctx.Read(varFlags))
  2429. return;
  2430. if (varFlags & ItemVariableFlags.FLOAT)
  2431. {
  2432. ReadVarsFromCTX(ctx);
  2433. }
  2434. }
  2435. override void SerializeNumericalVars(array<float> floats_out)
  2436. {
  2437. //some variables handled on EntityAI level already!
  2438. super.SerializeNumericalVars(floats_out);
  2439. // the order of serialization must be the same as the order of de-serialization
  2440. //--------------------------------------------
  2441. if (IsVariableSet(VARIABLE_QUANTITY))
  2442. {
  2443. floats_out.Insert(m_VarQuantity);
  2444. }
  2445. //--------------------------------------------
  2446. if (IsVariableSet(VARIABLE_WET))
  2447. {
  2448. floats_out.Insert(m_VarWet);
  2449. }
  2450. //--------------------------------------------
  2451. if (IsVariableSet(VARIABLE_LIQUIDTYPE))
  2452. {
  2453. floats_out.Insert(m_VarLiquidType);
  2454. }
  2455. //--------------------------------------------
  2456. if (IsVariableSet(VARIABLE_COLOR))
  2457. {
  2458. floats_out.Insert(m_ColorComponentR);
  2459. floats_out.Insert(m_ColorComponentG);
  2460. floats_out.Insert(m_ColorComponentB);
  2461. floats_out.Insert(m_ColorComponentA);
  2462. }
  2463. //--------------------------------------------
  2464. if (IsVariableSet(VARIABLE_CLEANNESS))
  2465. {
  2466. floats_out.Insert(m_Cleanness);
  2467. }
  2468. }
  2469. override void DeSerializeNumericalVars(array<float> floats)
  2470. {
  2471. //some variables handled on EntityAI level already!
  2472. super.DeSerializeNumericalVars(floats);
  2473. // the order of serialization must be the same as the order of de-serialization
  2474. int index = 0;
  2475. int mask = Math.Round(floats.Get(index));
  2476. index++;
  2477. //--------------------------------------------
  2478. if (mask & VARIABLE_QUANTITY)
  2479. {
  2480. if (m_IsStoreLoad)
  2481. {
  2482. SetStoreLoadedQuantity(floats.Get(index));
  2483. }
  2484. else
  2485. {
  2486. float quantity = floats.Get(index);
  2487. SetQuantity(quantity, true, false, false, false);
  2488. }
  2489. index++;
  2490. }
  2491. //--------------------------------------------
  2492. if (mask & VARIABLE_WET)
  2493. {
  2494. float wet = floats.Get(index);
  2495. SetWet(wet);
  2496. index++;
  2497. }
  2498. //--------------------------------------------
  2499. if (mask & VARIABLE_LIQUIDTYPE)
  2500. {
  2501. int liquidtype = Math.Round(floats.Get(index));
  2502. SetLiquidType(liquidtype);
  2503. index++;
  2504. }
  2505. //--------------------------------------------
  2506. if (mask & VARIABLE_COLOR)
  2507. {
  2508. m_ColorComponentR = Math.Round(floats.Get(index));
  2509. index++;
  2510. m_ColorComponentG = Math.Round(floats.Get(index));
  2511. index++;
  2512. m_ColorComponentB = Math.Round(floats.Get(index));
  2513. index++;
  2514. m_ColorComponentA = Math.Round(floats.Get(index));
  2515. index++;
  2516. }
  2517. //--------------------------------------------
  2518. if (mask & VARIABLE_CLEANNESS)
  2519. {
  2520. int cleanness = Math.Round(floats.Get(index));
  2521. SetCleanness(cleanness);
  2522. index++;
  2523. }
  2524. }
  2525. override void WriteVarsToCTX(ParamsWriteContext ctx)
  2526. {
  2527. super.WriteVarsToCTX(ctx);
  2528. //--------------------------------------------
  2529. if (IsVariableSet(VARIABLE_QUANTITY))
  2530. {
  2531. ctx.Write(GetQuantity());
  2532. }
  2533. //--------------------------------------------
  2534. if (IsVariableSet(VARIABLE_WET))
  2535. {
  2536. ctx.Write(GetWet());
  2537. }
  2538. //--------------------------------------------
  2539. if (IsVariableSet(VARIABLE_LIQUIDTYPE))
  2540. {
  2541. ctx.Write(GetLiquidType());
  2542. }
  2543. //--------------------------------------------
  2544. if (IsVariableSet(VARIABLE_COLOR))
  2545. {
  2546. int r,g,b,a;
  2547. GetColor(r,g,b,a);
  2548. ctx.Write(r);
  2549. ctx.Write(g);
  2550. ctx.Write(b);
  2551. ctx.Write(a);
  2552. }
  2553. //--------------------------------------------
  2554. if (IsVariableSet(VARIABLE_CLEANNESS))
  2555. {
  2556. ctx.Write(GetCleanness());
  2557. }
  2558. }
  2559. override bool ReadVarsFromCTX(ParamsReadContext ctx, int version = -1)//with ID optimization
  2560. {
  2561. if (!super.ReadVarsFromCTX(ctx,version))
  2562. return false;
  2563. int intValue;
  2564. float value;
  2565. if (version < 140)
  2566. {
  2567. if (!ctx.Read(intValue))
  2568. return false;
  2569. m_VariablesMask = intValue;
  2570. }
  2571. if (m_VariablesMask & VARIABLE_QUANTITY)
  2572. {
  2573. if (!ctx.Read(value))
  2574. return false;
  2575. if (IsStoreLoad())
  2576. {
  2577. SetStoreLoadedQuantity(value);
  2578. }
  2579. else
  2580. {
  2581. SetQuantity(value, true, false, false, false);
  2582. }
  2583. }
  2584. //--------------------------------------------
  2585. if (version < 140)
  2586. {
  2587. if (m_VariablesMask & VARIABLE_TEMPERATURE)
  2588. {
  2589. if (!ctx.Read(value))
  2590. return false;
  2591. SetTemperatureDirect(value);
  2592. }
  2593. }
  2594. //--------------------------------------------
  2595. if (m_VariablesMask & VARIABLE_WET)
  2596. {
  2597. if (!ctx.Read(value))
  2598. return false;
  2599. SetWet(value);
  2600. }
  2601. //--------------------------------------------
  2602. if (m_VariablesMask & VARIABLE_LIQUIDTYPE)
  2603. {
  2604. if (!ctx.Read(intValue))
  2605. return false;
  2606. SetLiquidType(intValue);
  2607. }
  2608. //--------------------------------------------
  2609. if (m_VariablesMask & VARIABLE_COLOR)
  2610. {
  2611. int r,g,b,a;
  2612. if (!ctx.Read(r))
  2613. return false;
  2614. if (!ctx.Read(g))
  2615. return false;
  2616. if (!ctx.Read(b))
  2617. return false;
  2618. if (!ctx.Read(a))
  2619. return false;
  2620. SetColor(r,g,b,a);
  2621. }
  2622. //--------------------------------------------
  2623. if (m_VariablesMask & VARIABLE_CLEANNESS)
  2624. {
  2625. if (!ctx.Read(intValue))
  2626. return false;
  2627. SetCleanness(intValue);
  2628. }
  2629. //--------------------------------------------
  2630. if (version >= 138 && version < 140)
  2631. {
  2632. if (m_VariablesMask & VARIABLE_TEMPERATURE)
  2633. {
  2634. if (!ctx.Read(intValue))
  2635. return false;
  2636. SetFrozen(intValue);
  2637. }
  2638. }
  2639. return true;
  2640. }
  2641. //----------------------------------------------------------------
  2642. override bool OnStoreLoad(ParamsReadContext ctx, int version)
  2643. {
  2644. m_IsStoreLoad = true;
  2645. if (GetDamageSystemVersionChange() != -1 && version < GetDamageSystemVersionChange())
  2646. {
  2647. m_FixDamageSystemInit = true;
  2648. }
  2649. if (!super.OnStoreLoad(ctx, version))
  2650. {
  2651. m_IsStoreLoad = false;
  2652. return false;
  2653. }
  2654. if (version >= 114)
  2655. {
  2656. bool hasQuickBarIndexSaved;
  2657. if (!ctx.Read(hasQuickBarIndexSaved))
  2658. {
  2659. m_IsStoreLoad = false;
  2660. return false;
  2661. }
  2662. if (hasQuickBarIndexSaved)
  2663. {
  2664. int itmQBIndex;
  2665. //Load quickbar item bind
  2666. if (!ctx.Read(itmQBIndex))
  2667. {
  2668. m_IsStoreLoad = false;
  2669. return false;
  2670. }
  2671. PlayerBase parentPlayer = PlayerBase.Cast(GetHierarchyRootPlayer());
  2672. if (itmQBIndex != -1 && parentPlayer)
  2673. parentPlayer.SetLoadedQuickBarItemBind(this, itmQBIndex);
  2674. }
  2675. }
  2676. else
  2677. {
  2678. // Backup of how it used to be
  2679. PlayerBase player;
  2680. int itemQBIndex;
  2681. if (version == int.MAX)
  2682. {
  2683. if (!ctx.Read(itemQBIndex))
  2684. {
  2685. m_IsStoreLoad = false;
  2686. return false;
  2687. }
  2688. }
  2689. else if (Class.CastTo(player, GetHierarchyRootPlayer()))
  2690. {
  2691. //Load quickbar item bind
  2692. if (!ctx.Read(itemQBIndex))
  2693. {
  2694. m_IsStoreLoad = false;
  2695. return false;
  2696. }
  2697. if (itemQBIndex != -1 && player)
  2698. player.SetLoadedQuickBarItemBind(this,itemQBIndex);
  2699. }
  2700. }
  2701. if (version < 140)
  2702. {
  2703. // variable management system
  2704. if (!LoadVariables(ctx, version))
  2705. {
  2706. m_IsStoreLoad = false;
  2707. return false;
  2708. }
  2709. }
  2710. //agent trasmission system
  2711. if (!LoadAgents(ctx, version))
  2712. {
  2713. m_IsStoreLoad = false;
  2714. return false;
  2715. }
  2716. if (version >= 132)
  2717. {
  2718. RemotelyActivatedItemBehaviour raib = GetRemotelyActivatedItemBehaviour();
  2719. if (raib)
  2720. {
  2721. if (!raib.OnStoreLoad(ctx,version))
  2722. {
  2723. m_IsStoreLoad = false;
  2724. return false;
  2725. }
  2726. }
  2727. }
  2728. m_IsStoreLoad = false;
  2729. return true;
  2730. }
  2731. //----------------------------------------------------------------
  2732. override void OnStoreSave(ParamsWriteContext ctx)
  2733. {
  2734. super.OnStoreSave(ctx);
  2735. PlayerBase player;
  2736. if (PlayerBase.CastTo(player,GetHierarchyRootPlayer()))
  2737. {
  2738. ctx.Write(true); // Keep track of if we should actually read this in or not
  2739. //Save quickbar item bind
  2740. int itemQBIndex = -1;
  2741. itemQBIndex = player.FindQuickBarEntityIndex(this);
  2742. ctx.Write(itemQBIndex);
  2743. }
  2744. else
  2745. {
  2746. ctx.Write(false); // Keep track of if we should actually read this in or not
  2747. }
  2748. SaveAgents(ctx);//agent trasmission system
  2749. RemotelyActivatedItemBehaviour raib = GetRemotelyActivatedItemBehaviour();
  2750. if (raib)
  2751. {
  2752. raib.OnStoreSave(ctx);
  2753. }
  2754. }
  2755. //----------------------------------------------------------------
  2756. override void AfterStoreLoad()
  2757. {
  2758. super.AfterStoreLoad();
  2759. if (m_FixDamageSystemInit)
  2760. {
  2761. PerformDamageSystemReinit();
  2762. }
  2763. if (GetStoreLoadedQuantity() != float.LOWEST)
  2764. {
  2765. SetQuantity(GetStoreLoadedQuantity());
  2766. SetStoreLoadedQuantity(float.LOWEST);//IMPORTANT to do this !! we use 'm_StoreLoadedQuantity' inside SetQuantity to distinguish between initial quantity setting and the consequent(normal gameplay) calls
  2767. }
  2768. }
  2769. override void EEOnAfterLoad()
  2770. {
  2771. super.EEOnAfterLoad();
  2772. if (m_FixDamageSystemInit)
  2773. {
  2774. m_FixDamageSystemInit = false;
  2775. }
  2776. if (GetRemotelyActivatedItemBehaviour())
  2777. GetRemotelyActivatedItemBehaviour().OnAfterLoad();
  2778. }
  2779. bool CanBeDisinfected()
  2780. {
  2781. return false;
  2782. }
  2783. //----------------------------------------------------------------
  2784. override void OnVariablesSynchronized()
  2785. {
  2786. if (m_Initialized)
  2787. {
  2788. #ifdef PLATFORM_CONSOLE
  2789. //bruteforce it is
  2790. if (IsSplitable())
  2791. {
  2792. UIScriptedMenu menu = GetGame().GetUIManager().FindMenu(MENU_INVENTORY);
  2793. if (menu)
  2794. {
  2795. menu.Refresh();
  2796. }
  2797. }
  2798. #endif
  2799. }
  2800. if (!dBodyIsDynamic(this) && m_WantPlayImpactSound)
  2801. {
  2802. PlayImpactSound(m_ConfigWeight, m_ImpactSpeed, m_ImpactSoundSurfaceHash);
  2803. m_WantPlayImpactSound = false;
  2804. }
  2805. if (m_VarQuantity != m_VarQuantityPrev)
  2806. {
  2807. SetWeightDirty();
  2808. m_VarQuantityPrev = m_VarQuantity;
  2809. }
  2810. if (m_VarWet != m_VarWetPrev)
  2811. {
  2812. OnWetChanged(m_VarWet,m_VarWetPrev);
  2813. m_VarWetPrev = m_VarWet;
  2814. }
  2815. if (m_SoundSyncPlay != 0)
  2816. {
  2817. m_ItemSoundHandler.PlayItemSoundClient(m_SoundSyncPlay);
  2818. m_SoundSyncPlay = 0;
  2819. }
  2820. if (m_SoundSyncStop != 0)
  2821. {
  2822. m_ItemSoundHandler.StopItemSoundClient(m_SoundSyncStop);
  2823. m_SoundSyncStop = 0;
  2824. }
  2825. super.OnVariablesSynchronized();
  2826. }
  2827. //------------------------- Quantity
  2828. //----------------------------------------------------------------
  2829. //! Set item quantity[related to varQuantity... config entry], destroy_config = true > if the quantity reaches varQuantityMin or lower and the item config contains the varQuantityDestroyOnMin = true entry, the item gets destroyed. destroy_forced = true means item gets destroyed when quantity reaches varQuantityMin or lower regardless of config setting, returns true if the item gets deleted
  2830. override bool SetQuantity(float value, bool destroy_config = true, bool destroy_forced = false, bool allow_client = false, bool clamp_to_stack_max = true)
  2831. {
  2832. if (!IsServerCheck(allow_client))
  2833. return false;
  2834. if (!HasQuantity())
  2835. return false;
  2836. float min = GetQuantityMin();
  2837. float max = GetQuantityMax();
  2838. if (value <= (min + 0.001))
  2839. value = min;
  2840. if (value == min)
  2841. {
  2842. if (destroy_config)
  2843. {
  2844. bool dstr = ConfigGetBool("varQuantityDestroyOnMin");
  2845. if (dstr)
  2846. {
  2847. m_VarQuantity = Math.Clamp(value, min, max);
  2848. this.Delete();
  2849. return true;
  2850. }
  2851. }
  2852. else if (destroy_forced)
  2853. {
  2854. m_VarQuantity = Math.Clamp(value, min, max);
  2855. this.Delete();
  2856. return true;
  2857. }
  2858. // we get here if destroy_config IS true AND dstr(config destroy param) IS false;
  2859. RemoveAllAgents();//we remove all agents when we got to the min value, but the item is not getting deleted
  2860. }
  2861. float delta = m_VarQuantity;
  2862. m_VarQuantity = Math.Clamp(value, min, max);
  2863. if (GetStoreLoadedQuantity() == float.LOWEST)//any other value means we are setting quantity from storage
  2864. {
  2865. delta = m_VarQuantity - delta;
  2866. if (delta)
  2867. OnQuantityChanged(delta);
  2868. }
  2869. SetVariableMask(VARIABLE_QUANTITY);
  2870. return false;
  2871. }
  2872. //----------------------------------------------------------------
  2873. //! add item quantity[related to varQuantity... config entry], destroy_config = true > if the quantity reaches varQuantityMin or lower and the item config contains the varQuantityDestroyOnMin = true entry, the item gets destroyed. destroy_forced = true means item gets destroyed when quantity reaches varQuantityMin or lower regardless of config setting, returns true if the item gets deleted
  2874. bool AddQuantity(float value, bool destroy_config = true, bool destroy_forced = false)
  2875. {
  2876. return SetQuantity(GetQuantity() + value, destroy_config, destroy_forced);
  2877. }
  2878. //----------------------------------------------------------------
  2879. void SetQuantityMax()
  2880. {
  2881. float max = GetQuantityMax();
  2882. SetQuantity(max);
  2883. }
  2884. override void SetQuantityToMinimum()
  2885. {
  2886. float min = GetQuantityMin();
  2887. SetQuantity(min);
  2888. }
  2889. //----------------------------------------------------------------
  2890. //! Sets quantity in normalized 0..1 form between the item's Min a Max values as defined by item's config(for Min 0 and Max 5000, setting 0.5 will result in value 2500)
  2891. override void SetQuantityNormalized(float value, bool destroy_config = true, bool destroy_forced = false)
  2892. {
  2893. float value_clamped = Math.Clamp(value, 0, 1);//just to make sure
  2894. int result = Math.Round(Math.Lerp(GetQuantityMin(), GetQuantityMax(), value_clamped));
  2895. SetQuantity(result, destroy_config, destroy_forced);
  2896. }
  2897. //----------------------------------------------------------------
  2898. //! Gets quantity in normalized 0..1 form between the item's Min a Max values as defined by item's config(for Min 0 and Max 5000, value 2500 will result in 0.5)
  2899. override float GetQuantityNormalized()
  2900. {
  2901. return Math.InverseLerp(GetQuantityMin(), GetQuantityMax(),m_VarQuantity);
  2902. }
  2903. float GetQuantityNormalizedScripted()
  2904. {
  2905. return GetQuantityNormalized();
  2906. }
  2907. /*void SetAmmoNormalized(float value)
  2908. {
  2909. float value_clamped = Math.Clamp(value, 0, 1);
  2910. Magazine this_mag = Magazine.Cast(this);
  2911. int max_rounds = this_mag.GetAmmoMax();
  2912. int result = value * max_rounds;//can the rounded if higher precision is required
  2913. this_mag.SetAmmoCount(result);
  2914. }*/
  2915. //----------------------------------------------------------------
  2916. override int GetQuantityMax()
  2917. {
  2918. int slot = -1;
  2919. if (GetInventory())
  2920. {
  2921. InventoryLocation il = new InventoryLocation;
  2922. GetInventory().GetCurrentInventoryLocation(il);
  2923. slot = il.GetSlot();
  2924. }
  2925. return GetTargetQuantityMax(slot);
  2926. }
  2927. override int GetTargetQuantityMax(int attSlotID = -1)
  2928. {
  2929. float quantity_max = 0;
  2930. if (IsSplitable()) //only stackable/splitable items can check for stack size
  2931. {
  2932. if (attSlotID != -1)
  2933. quantity_max = InventorySlots.GetStackMaxForSlotId(attSlotID);
  2934. if (quantity_max <= 0)
  2935. quantity_max = m_VarStackMax;
  2936. }
  2937. if (quantity_max <= 0)
  2938. quantity_max = m_VarQuantityMax;
  2939. return quantity_max;
  2940. }
  2941. //----------------------------------------------------------------
  2942. override int GetQuantityMin()
  2943. {
  2944. return m_VarQuantityMin;
  2945. }
  2946. //----------------------------------------------------------------
  2947. int GetQuantityInit()
  2948. {
  2949. return m_VarQuantityInit;
  2950. }
  2951. //----------------------------------------------------------------
  2952. override bool HasQuantity()
  2953. {
  2954. return !(GetQuantityMax() - GetQuantityMin() == 0);
  2955. }
  2956. override float GetQuantity()
  2957. {
  2958. return m_VarQuantity;
  2959. }
  2960. bool IsFullQuantity()
  2961. {
  2962. return GetQuantity() >= GetQuantityMax();
  2963. }
  2964. //Calculates weight of single item without attachments and cargo
  2965. override float GetSingleInventoryItemWeightEx()
  2966. {
  2967. //this needs to be first stored inside local variables, when returned directly during inside return call, the result is completely different due to enforce script bug
  2968. float weightEx = GetWeightEx();//overall weight of the item
  2969. float special = GetInventoryAndCargoWeight();//cargo and attachment weight
  2970. return weightEx - special;
  2971. }
  2972. // Obsolete, use GetSingleInventoryItemWeightEx() instead
  2973. float GetSingleInventoryItemWeight()
  2974. {
  2975. return GetSingleInventoryItemWeightEx();
  2976. }
  2977. override protected float GetWeightSpecialized(bool forceRecalc = false)
  2978. {
  2979. if (IsSplitable()) //quantity determines size of the stack
  2980. {
  2981. #ifdef DEVELOPER
  2982. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
  2983. {
  2984. WeightDebugData data1 = WeightDebug.GetWeightDebug(this);
  2985. data1.SetCalcDetails("TIB1: " + GetConfigWeightModifiedDebugText() +" * " + GetQuantity()+"(quantity)");
  2986. }
  2987. #endif
  2988. return GetQuantity() * GetConfigWeightModified();
  2989. }
  2990. else if (HasEnergyManager())// items with energy manager
  2991. {
  2992. #ifdef DEVELOPER
  2993. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
  2994. {
  2995. WeightDebugData data2 = WeightDebug.GetWeightDebug(this);
  2996. data2.SetCalcDetails("TIB2: "+super.GetWeightSpecialized(forceRecalc)+"(contents weight) + " + GetConfigWeightModifiedDebugText() +" + " + GetCompEM().GetEnergy()+"(energy) * " + ConfigGetFloat("weightPerQuantityUnit") +"(weightPerQuantityUnit)");
  2997. }
  2998. #endif
  2999. return super.GetWeightSpecialized(forceRecalc) + (GetCompEM().GetEnergy() * ConfigGetFloat("weightPerQuantityUnit")) + GetConfigWeightModified();
  3000. }
  3001. else//everything else
  3002. {
  3003. #ifdef DEVELOPER
  3004. if (WeightDebug.m_VerbosityFlags & WeightDebugType.RECALC_FORCED)
  3005. {
  3006. WeightDebugData data3 = WeightDebug.GetWeightDebug(this);
  3007. data3.SetCalcDetails("TIB3: "+super.GetWeightSpecialized(forceRecalc)+"(contents weight) + " + GetConfigWeightModifiedDebugText() +" + " + GetQuantity()+"(quantity) * " + ConfigGetFloat("weightPerQuantityUnit") +"(weightPerQuantityUnit))");
  3008. }
  3009. #endif
  3010. return super.GetWeightSpecialized(forceRecalc) + (GetQuantity() * ConfigGetFloat("weightPerQuantityUnit")) + GetConfigWeightModified();
  3011. }
  3012. }
  3013. //! Returns the number of items in cargo, otherwise returns 0(non-cargo objects). Recursive.
  3014. int GetNumberOfItems()
  3015. {
  3016. int item_count = 0;
  3017. ItemBase item;
  3018. if (GetInventory().GetCargo() != NULL)
  3019. {
  3020. item_count = GetInventory().GetCargo().GetItemCount();
  3021. }
  3022. for (int i = 0; i < GetInventory().AttachmentCount(); i++)
  3023. {
  3024. Class.CastTo(item,GetInventory().GetAttachmentFromIndex(i));
  3025. if (item)
  3026. item_count += item.GetNumberOfItems();
  3027. }
  3028. return item_count;
  3029. }
  3030. //! Obsolete, use GetWeightEx instead
  3031. float GetUnitWeight(bool include_wetness = true)
  3032. {
  3033. float weight = 0;
  3034. float wetness = 1;
  3035. if (include_wetness)
  3036. wetness += GetWet();
  3037. if (IsSplitable()) //quantity determines size of the stack
  3038. {
  3039. weight = wetness * m_ConfigWeight;
  3040. }
  3041. else if (IsLiquidContainer()) //is a liquid container, default liquid weight is set to 1. May revisit later?
  3042. {
  3043. weight = 1;
  3044. }
  3045. return weight;
  3046. }
  3047. //-----------------------------------------------------------------
  3048. override void ClearInventory()
  3049. {
  3050. if ((GetGame().IsServer() || !GetGame().IsMultiplayer()) && GetInventory())
  3051. {
  3052. GameInventory inv = GetInventory();
  3053. array<EntityAI> items = new array<EntityAI>;
  3054. inv.EnumerateInventory(InventoryTraversalType.INORDER, items);
  3055. for (int i = 0; i < items.Count(); i++)
  3056. {
  3057. ItemBase item = ItemBase.Cast(items.Get(i));
  3058. if (item)
  3059. {
  3060. GetGame().ObjectDelete(item);
  3061. }
  3062. }
  3063. }
  3064. }
  3065. //------------------------- Energy
  3066. //----------------------------------------------------------------
  3067. float GetEnergy()
  3068. {
  3069. float energy = 0;
  3070. if (HasEnergyManager())
  3071. {
  3072. energy = GetCompEM().GetEnergy();
  3073. }
  3074. return energy;
  3075. }
  3076. override void OnEnergyConsumed()
  3077. {
  3078. super.OnEnergyConsumed();
  3079. ConvertEnergyToQuantity();
  3080. }
  3081. override void OnEnergyAdded()
  3082. {
  3083. super.OnEnergyAdded();
  3084. ConvertEnergyToQuantity();
  3085. }
  3086. // Converts energy (from Energy Manager) to quantity, if enabled.
  3087. void ConvertEnergyToQuantity()
  3088. {
  3089. if (GetGame().IsServer() && HasEnergyManager() && GetCompEM().HasConversionOfEnergyToQuantity())
  3090. {
  3091. if (HasQuantity())
  3092. {
  3093. float energy_0to1 = GetCompEM().GetEnergy0To1();
  3094. SetQuantityNormalized(energy_0to1);
  3095. }
  3096. }
  3097. }
  3098. //----------------------------------------------------------------
  3099. float GetHeatIsolationInit()
  3100. {
  3101. return ConfigGetFloat("heatIsolation");
  3102. }
  3103. float GetHeatIsolation()
  3104. {
  3105. return m_HeatIsolation;
  3106. }
  3107. float GetDryingIncrement(string pIncrementName)
  3108. {
  3109. string paramPath = string.Format("CfgVehicles %1 EnvironmentWetnessIncrements Drying %2", GetType(), pIncrementName);
  3110. if (GetGame().ConfigIsExisting(paramPath))
  3111. return GetGame().ConfigGetFloat(paramPath);
  3112. return 0.0;
  3113. }
  3114. float GetSoakingIncrement(string pIncrementName)
  3115. {
  3116. string paramPath = string.Format("CfgVehicles %1 EnvironmentWetnessIncrements Soaking %2", GetType(), pIncrementName);
  3117. if (GetGame().ConfigIsExisting(paramPath))
  3118. return GetGame().ConfigGetFloat(paramPath);
  3119. return 0.0;
  3120. }
  3121. //----------------------------------------------------------------
  3122. override void SetWet(float value, bool allow_client = false)
  3123. {
  3124. if (!IsServerCheck(allow_client))
  3125. return;
  3126. float min = GetWetMin();
  3127. float max = GetWetMax();
  3128. float previousValue = m_VarWet;
  3129. m_VarWet = Math.Clamp(value, min, max);
  3130. if (previousValue != m_VarWet)
  3131. {
  3132. SetVariableMask(VARIABLE_WET);
  3133. OnWetChanged(m_VarWet, previousValue);
  3134. }
  3135. }
  3136. //----------------------------------------------------------------
  3137. override void AddWet(float value)
  3138. {
  3139. SetWet(GetWet() + value);
  3140. }
  3141. //----------------------------------------------------------------
  3142. override void SetWetMax()
  3143. {
  3144. SetWet(m_VarWetMax);
  3145. }
  3146. //----------------------------------------------------------------
  3147. override float GetWet()
  3148. {
  3149. return m_VarWet;
  3150. }
  3151. //----------------------------------------------------------------
  3152. override float GetWetMax()
  3153. {
  3154. return m_VarWetMax;
  3155. }
  3156. //----------------------------------------------------------------
  3157. override float GetWetMin()
  3158. {
  3159. return m_VarWetMin;
  3160. }
  3161. //----------------------------------------------------------------
  3162. override float GetWetInit()
  3163. {
  3164. return m_VarWetInit;
  3165. }
  3166. //----------------------------------------------------------------
  3167. override void OnWetChanged(float newVal, float oldVal)
  3168. {
  3169. EWetnessLevel newLevel = GetWetLevelInternal(newVal);
  3170. EWetnessLevel oldLevel = GetWetLevelInternal(oldVal);
  3171. if (newLevel != oldLevel)
  3172. {
  3173. OnWetLevelChanged(newLevel,oldLevel);
  3174. }
  3175. }
  3176. override void OnWetLevelChanged(EWetnessLevel newLevel, EWetnessLevel oldLevel)
  3177. {
  3178. SetWeightDirty();
  3179. }
  3180. override EWetnessLevel GetWetLevel()
  3181. {
  3182. return GetWetLevelInternal(m_VarWet);
  3183. }
  3184. //----------------------------------------------------------------
  3185. override void SetStoreLoad(bool value)
  3186. {
  3187. m_IsStoreLoad = value;
  3188. }
  3189. override bool IsStoreLoad()
  3190. {
  3191. return m_IsStoreLoad;
  3192. }
  3193. override void SetStoreLoadedQuantity(float value)
  3194. {
  3195. m_StoreLoadedQuantity = value;
  3196. }
  3197. override float GetStoreLoadedQuantity()
  3198. {
  3199. return m_StoreLoadedQuantity;
  3200. }
  3201. //----------------------------------------------------------------
  3202. float GetItemModelLength()
  3203. {
  3204. if (ConfigIsExisting("itemModelLength"))
  3205. {
  3206. return ConfigGetFloat("itemModelLength");
  3207. }
  3208. return 0;
  3209. }
  3210. float GetItemAttachOffset()
  3211. {
  3212. if (ConfigIsExisting("itemAttachOffset"))
  3213. {
  3214. return ConfigGetFloat("itemAttachOffset");
  3215. }
  3216. return 0;
  3217. }
  3218. override void SetCleanness(int value, bool allow_client = false)
  3219. {
  3220. if (!IsServerCheck(allow_client))
  3221. return;
  3222. int previousValue = m_Cleanness;
  3223. m_Cleanness = Math.Clamp(value, m_CleannessMin, m_CleannessMax);
  3224. if (previousValue != m_Cleanness)
  3225. SetVariableMask(VARIABLE_CLEANNESS);
  3226. }
  3227. override int GetCleanness()
  3228. {
  3229. return m_Cleanness;
  3230. }
  3231. bool AllowFoodConsumption()
  3232. {
  3233. return true;
  3234. }
  3235. //----------------------------------------------------------------
  3236. // ATTACHMENT LOCKING
  3237. // Getters relevant to generic ActionLockAttachment
  3238. int GetLockType()
  3239. {
  3240. return m_LockType;
  3241. }
  3242. string GetLockSoundSet()
  3243. {
  3244. return m_LockSoundSet;
  3245. }
  3246. //----------------------------------------------------------------
  3247. //------------------------- Color
  3248. // sets items color variable given color components
  3249. override void SetColor(int r, int g, int b, int a)
  3250. {
  3251. m_ColorComponentR = r;
  3252. m_ColorComponentG = g;
  3253. m_ColorComponentB = b;
  3254. m_ColorComponentA = a;
  3255. SetVariableMask(VARIABLE_COLOR);
  3256. }
  3257. //! gets item's color variable as components
  3258. override void GetColor(out int r,out int g,out int b,out int a)
  3259. {
  3260. r = m_ColorComponentR;
  3261. g = m_ColorComponentG;
  3262. b = m_ColorComponentB;
  3263. a = m_ColorComponentA;
  3264. }
  3265. bool IsColorSet()
  3266. {
  3267. return IsVariableSet(VARIABLE_COLOR);
  3268. }
  3269. //! Returns item's PROCEDURAL color as formated string, i.e. "#(argb,8,8,3)color(0.15,0.15,0.15,1.0,CO)"
  3270. string GetColorString()
  3271. {
  3272. int r,g,b,a;
  3273. GetColor(r,g,b,a);
  3274. r = r/255;
  3275. g = g/255;
  3276. b = b/255;
  3277. a = a/255;
  3278. return MiscGameplayFunctions.GetColorString(r, g, b, a);
  3279. }
  3280. //----------------------------------------------------------------
  3281. //------------------------- LiquidType
  3282. override void SetLiquidType(int value, bool allow_client = false)
  3283. {
  3284. if (!IsServerCheck(allow_client))
  3285. return;
  3286. int old = m_VarLiquidType;
  3287. m_VarLiquidType = value;
  3288. OnLiquidTypeChanged(old,value);
  3289. SetVariableMask(VARIABLE_LIQUIDTYPE);
  3290. }
  3291. int GetLiquidTypeInit()
  3292. {
  3293. return ConfigGetInt("varLiquidTypeInit");
  3294. }
  3295. override int GetLiquidType()
  3296. {
  3297. return m_VarLiquidType;
  3298. }
  3299. protected void OnLiquidTypeChanged(int oldType, int newType)
  3300. {
  3301. if (newType == LIQUID_NONE && GetIsFrozen())
  3302. SetFrozen(false);
  3303. }
  3304. //! To be called on moving item within character's inventory; 'player' should never be null
  3305. void UpdateQuickbarShortcutVisibility(PlayerBase player)
  3306. {
  3307. player.SetEnableQuickBarEntityShortcut(this,!GetHierarchyParent() || GetHierarchyParent().GetInventory().AreChildrenAccessible());
  3308. }
  3309. // -------------------------------------------------------------------------
  3310. //! Event called on item when it is placed in the player(Man) inventory, passes the owner as a parameter
  3311. void OnInventoryEnter(Man player)
  3312. {
  3313. PlayerBase nplayer;
  3314. if (PlayerBase.CastTo(nplayer, player))
  3315. {
  3316. m_CanPlayImpactSound = true;
  3317. //nplayer.OnItemInventoryEnter(this);
  3318. nplayer.SetEnableQuickBarEntityShortcut(this,!GetHierarchyParent() || GetHierarchyParent().GetInventory().AreChildrenAccessible());
  3319. }
  3320. }
  3321. // -------------------------------------------------------------------------
  3322. //! Event called on item when it is removed from the player(Man) inventory, passes the old owner as a parameter
  3323. void OnInventoryExit(Man player)
  3324. {
  3325. PlayerBase nplayer;
  3326. if (PlayerBase.CastTo(nplayer,player))
  3327. {
  3328. //nplayer.OnItemInventoryExit(this);
  3329. nplayer.SetEnableQuickBarEntityShortcut(this,false);
  3330. }
  3331. //if (!GetGame().IsDedicatedServer())
  3332. player.GetHumanInventory().ClearUserReservedLocationForContainer(this);
  3333. if (HasEnergyManager())
  3334. {
  3335. GetCompEM().UpdatePlugState(); // Unplug the el. device if it's necesarry.
  3336. }
  3337. }
  3338. // ADVANCED PLACEMENT EVENTS
  3339. override void OnPlacementStarted(Man player)
  3340. {
  3341. super.OnPlacementStarted(player);
  3342. SetTakeable(false);
  3343. }
  3344. override void OnPlacementComplete(Man player, vector position = "0 0 0", vector orientation = "0 0 0")
  3345. {
  3346. if (m_AdminLog)
  3347. {
  3348. m_AdminLog.OnPlacementComplete(player, this);
  3349. }
  3350. super.OnPlacementComplete(player, position, orientation);
  3351. }
  3352. //-----------------------------
  3353. // AGENT SYSTEM
  3354. //-----------------------------
  3355. //--------------------------------------------------------------------------
  3356. bool ContainsAgent(int agent_id)
  3357. {
  3358. if (agent_id & m_AttachedAgents)
  3359. {
  3360. return true;
  3361. }
  3362. else
  3363. {
  3364. return false;
  3365. }
  3366. }
  3367. //--------------------------------------------------------------------------
  3368. override void RemoveAgent(int agent_id)
  3369. {
  3370. if (ContainsAgent(agent_id))
  3371. {
  3372. m_AttachedAgents = ~agent_id & m_AttachedAgents;
  3373. }
  3374. }
  3375. //--------------------------------------------------------------------------
  3376. override void RemoveAllAgents()
  3377. {
  3378. m_AttachedAgents = 0;
  3379. }
  3380. //--------------------------------------------------------------------------
  3381. override void RemoveAllAgentsExcept(int agent_to_keep)
  3382. {
  3383. m_AttachedAgents = m_AttachedAgents & agent_to_keep;
  3384. }
  3385. // -------------------------------------------------------------------------
  3386. override void InsertAgent(int agent, float count = 1)
  3387. {
  3388. if (count < 1)
  3389. return;
  3390. //Debug.Log("Inserting Agent on item: " + agent.ToString() +" count: " + count.ToString());
  3391. m_AttachedAgents = (agent | m_AttachedAgents);
  3392. }
  3393. //!transfer agents from another item
  3394. void TransferAgents(int agents)
  3395. {
  3396. m_AttachedAgents = (m_AttachedAgents | agents);
  3397. }
  3398. // -------------------------------------------------------------------------
  3399. override int GetAgents()
  3400. {
  3401. return m_AttachedAgents;
  3402. }
  3403. //----------------------------------------------------------------------
  3404. /*int GetContaminationType()
  3405. {
  3406. int contamination_type;
  3407. const int CONTAMINATED_MASK = eAgents.CHOLERA | eAgents.INFLUENZA | eAgents.SALMONELLA | eAgents.BRAIN;
  3408. const int POISONED_MASK = eAgents.FOOD_POISON | eAgents.CHEMICAL_POISON;
  3409. const int NERVE_GAS_MASK = eAgents.CHEMICAL_POISON;
  3410. const int DIRTY_MASK = eAgents.WOUND_AGENT;
  3411. Edible_Base edible = Edible_Base.Cast(this);
  3412. int agents = GetAgents();
  3413. if (edible)
  3414. {
  3415. NutritionalProfile profile = Edible_Base.GetNutritionalProfile(edible);
  3416. if (profile)
  3417. {
  3418. agents = agents | profile.GetAgents();//merge item's agents with nutritional agents
  3419. }
  3420. }
  3421. if (agents & CONTAMINATED_MASK)
  3422. {
  3423. contamination_type = contamination_type | EContaminationTypes.ITEM_BADGE_CONTAMINATED;
  3424. }
  3425. if (agents & POISONED_MASK)
  3426. {
  3427. contamination_type = contamination_type | EContaminationTypes.ITEM_BADGE_POISONED;
  3428. }
  3429. if (agents & NERVE_GAS_MASK)
  3430. {
  3431. contamination_type = contamination_type | EContaminationTypes.ITEM_BADGE_NERVE_GAS;
  3432. }
  3433. if (agents & DIRTY_MASK)
  3434. {
  3435. contamination_type = contamination_type | EContaminationTypes.ITEM_BADGE_DIRTY;
  3436. }
  3437. return agents;
  3438. }*/
  3439. // -------------------------------------------------------------------------
  3440. bool LoadAgents(ParamsReadContext ctx, int version)
  3441. {
  3442. if (!ctx.Read(m_AttachedAgents))
  3443. return false;
  3444. return true;
  3445. }
  3446. // -------------------------------------------------------------------------
  3447. void SaveAgents(ParamsWriteContext ctx)
  3448. {
  3449. ctx.Write(m_AttachedAgents);
  3450. }
  3451. // -------------------------------------------------------------------------
  3452. //! Roof check for entity, limited by time (anti-spam solution)
  3453. override void CheckForRoofLimited(float timeTresholdMS = 3000)
  3454. {
  3455. super.CheckForRoofLimited(timeTresholdMS);
  3456. float time = GetGame().GetTime();
  3457. if ((time - m_PreviousRoofTestTime) >= timeTresholdMS)
  3458. {
  3459. m_PreviousRoofTestTime = time;
  3460. SetRoofAbove(MiscGameplayFunctions.IsUnderRoof(this));
  3461. }
  3462. }
  3463. // returns item's protection level against enviromental hazard, for masks with filters, returns the filters protection for valid filter, otherwise 0
  3464. float GetProtectionLevel(int type, bool consider_filter = false, int system = 0)
  3465. {
  3466. if (IsDamageDestroyed() || (HasQuantity() && GetQuantity() <= 0))
  3467. {
  3468. return 0;
  3469. }
  3470. if (GetInventory().GetAttachmentSlotsCount() != 0)//is it an item with attachable filter ?
  3471. {
  3472. ItemBase filter = ItemBase.Cast(FindAttachmentBySlotName("GasMaskFilter"));
  3473. if (filter)
  3474. return filter.GetProtectionLevel(type, false, system);//it's a valid filter, return the protection
  3475. else
  3476. return 0;//otherwise return 0 when no filter attached
  3477. }
  3478. string subclassPath, entryName;
  3479. switch (type)
  3480. {
  3481. case DEF_BIOLOGICAL:
  3482. entryName = "biological";
  3483. break;
  3484. case DEF_CHEMICAL:
  3485. entryName = "chemical";
  3486. break;
  3487. default:
  3488. entryName = "biological";
  3489. break;
  3490. }
  3491. subclassPath = "CfgVehicles " + this.GetType() + " Protection ";
  3492. return GetGame().ConfigGetFloat(subclassPath + entryName);
  3493. }
  3494. //! Called when entity is being created as new by CE/ Debug
  3495. override void EEOnCECreate()
  3496. {
  3497. if (!IsMagazine())
  3498. SetCEBasedQuantity();
  3499. SetZoneDamageCEInit();
  3500. }
  3501. //-------------------------
  3502. // OPEN/CLOSE USER ACTIONS
  3503. //-------------------------
  3504. //! Implementations only
  3505. void Open();
  3506. void Close();
  3507. bool IsOpen()
  3508. {
  3509. return true;
  3510. }
  3511. override bool CanDisplayCargo()
  3512. {
  3513. return IsOpen();
  3514. }
  3515. // ------------------------------------------------------------
  3516. // CONDITIONS
  3517. // ------------------------------------------------------------
  3518. override bool CanPutInCargo(EntityAI parent)
  3519. {
  3520. if (parent)
  3521. {
  3522. if (parent.IsInherited(DayZInfected))
  3523. return true;
  3524. if (!parent.IsRuined())
  3525. return true;
  3526. }
  3527. return true;
  3528. }
  3529. override bool CanPutAsAttachment(EntityAI parent)
  3530. {
  3531. if (!super.CanPutAsAttachment(parent))
  3532. {
  3533. return false;
  3534. }
  3535. if (!IsRuined() && !parent.IsRuined())
  3536. {
  3537. return true;
  3538. }
  3539. return false;
  3540. }
  3541. override bool CanReceiveItemIntoCargo(EntityAI item)
  3542. {
  3543. //removed 15.06. coz of loading from storage -> after load items in cargo was lost -> waiting for proper solution
  3544. //if (GetHealthLevel() == GameConstants.STATE_RUINED)
  3545. // return false;
  3546. return super.CanReceiveItemIntoCargo(item);
  3547. }
  3548. override bool CanReceiveAttachment(EntityAI attachment, int slotId)
  3549. {
  3550. //removed 15.06. coz of loading from storage -> after load items in cargo was lost -> waiting for proper solution
  3551. //if (GetHealthLevel() == GameConstants.STATE_RUINED)
  3552. // return false;
  3553. GameInventory attachmentInv = attachment.GetInventory();
  3554. if (attachmentInv && attachmentInv.GetCargo() && attachmentInv.GetCargo().GetItemCount() > 0)
  3555. {
  3556. if (GetHierarchyParent() && !GetHierarchyParent().IsInherited(PlayerBase))
  3557. return false;
  3558. }
  3559. InventoryLocation loc = new InventoryLocation();
  3560. attachment.GetInventory().GetCurrentInventoryLocation(loc);
  3561. if (loc && loc.IsValid() && !GetInventory().AreChildrenAccessible())
  3562. return false;
  3563. return super.CanReceiveAttachment(attachment, slotId);
  3564. }
  3565. override bool CanReleaseAttachment(EntityAI attachment)
  3566. {
  3567. if (!super.CanReleaseAttachment(attachment))
  3568. return false;
  3569. return GetInventory().AreChildrenAccessible();
  3570. }
  3571. /*override bool CanLoadAttachment(EntityAI attachment)
  3572. {
  3573. //removed 15.06. coz of loading from storage -> after load items in cargo was lost -> waiting for proper solution
  3574. //if (GetHealthLevel() == GameConstants.STATE_RUINED)
  3575. // return false;
  3576. GameInventory attachmentInv = attachment.GetInventory();
  3577. if (attachmentInv && attachmentInv.GetCargo() && attachmentInv.GetCargo().GetItemCount() > 0)
  3578. {
  3579. bool boo = (GetHierarchyParent() && !GetHierarchyParent().IsInherited(PlayerBase));
  3580. ErrorEx("CanLoadAttachment | this: " + this + " | attachment: " + attachment + " | boo: " + boo,ErrorExSeverity.INFO);
  3581. if (GetHierarchyParent() && !GetHierarchyParent().IsInherited(PlayerBase))
  3582. return false;
  3583. }
  3584. return super.CanLoadAttachment(attachment);
  3585. }*/
  3586. // Plays muzzle flash particle effects
  3587. static void PlayFireParticles(ItemBase weapon, int muzzle_index, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  3588. {
  3589. int id = muzzle_owner.GetMuzzleID();
  3590. array<ref WeaponParticlesOnFire> WPOF_array = m_OnFireEffect.Get(id);
  3591. if (WPOF_array)
  3592. {
  3593. for (int i = 0; i < WPOF_array.Count(); i++)
  3594. {
  3595. WeaponParticlesOnFire WPOF = WPOF_array.Get(i);
  3596. if (WPOF)
  3597. {
  3598. WPOF.OnActivate(weapon, muzzle_index, ammoType, muzzle_owner, suppressor, config_to_search);
  3599. }
  3600. }
  3601. }
  3602. }
  3603. // Plays bullet eject particle effects (usually just smoke, the bullet itself is a 3D model and is not part of this function)
  3604. static void PlayBulletCasingEjectParticles(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  3605. {
  3606. int id = muzzle_owner.GetMuzzleID();
  3607. array<ref WeaponParticlesOnBulletCasingEject> WPOBE_array = m_OnBulletCasingEjectEffect.Get(id);
  3608. if (WPOBE_array)
  3609. {
  3610. for (int i = 0; i < WPOBE_array.Count(); i++)
  3611. {
  3612. WeaponParticlesOnBulletCasingEject WPOBE = WPOBE_array.Get(i);
  3613. if (WPOBE)
  3614. {
  3615. WPOBE.OnActivate(weapon, 0, ammoType, muzzle_owner, suppressor, config_to_search);
  3616. }
  3617. }
  3618. }
  3619. }
  3620. // Plays all weapon overheating particles
  3621. static void PlayOverheatingParticles(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  3622. {
  3623. int id = muzzle_owner.GetMuzzleID();
  3624. array<ref WeaponParticlesOnOverheating> WPOOH_array = weapon.m_OnOverheatingEffect.Get(id);
  3625. if (WPOOH_array)
  3626. {
  3627. for (int i = 0; i < WPOOH_array.Count(); i++)
  3628. {
  3629. WeaponParticlesOnOverheating WPOOH = WPOOH_array.Get(i);
  3630. if (WPOOH)
  3631. {
  3632. WPOOH.OnActivate(weapon, 0, ammoType, muzzle_owner, suppressor, config_to_search);
  3633. }
  3634. }
  3635. }
  3636. }
  3637. // Updates all weapon overheating particles
  3638. static void UpdateOverheatingParticles(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  3639. {
  3640. int id = muzzle_owner.GetMuzzleID();
  3641. array<ref WeaponParticlesOnOverheating> WPOOH_array = weapon.m_OnOverheatingEffect.Get(id);
  3642. if (WPOOH_array)
  3643. {
  3644. for (int i = 0; i < WPOOH_array.Count(); i++)
  3645. {
  3646. WeaponParticlesOnOverheating WPOOH = WPOOH_array.Get(i);
  3647. if (WPOOH)
  3648. {
  3649. WPOOH.OnUpdate(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  3650. }
  3651. }
  3652. }
  3653. }
  3654. // Stops overheating particles
  3655. static void StopOverheatingParticles(ItemBase weapon, string ammoType, ItemBase muzzle_owner, ItemBase suppressor, string config_to_search)
  3656. {
  3657. int id = muzzle_owner.GetMuzzleID();
  3658. array<ref WeaponParticlesOnOverheating> WPOOH_array = weapon.m_OnOverheatingEffect.Get(id);
  3659. if (WPOOH_array)
  3660. {
  3661. for (int i = 0; i < WPOOH_array.Count(); i++)
  3662. {
  3663. WeaponParticlesOnOverheating WPOOH = WPOOH_array.Get(i);
  3664. if (WPOOH)
  3665. {
  3666. WPOOH.OnDeactivate(weapon, ammoType, muzzle_owner, suppressor, config_to_search);
  3667. }
  3668. }
  3669. }
  3670. }
  3671. //----------------------------------------------------------------
  3672. //Item Behaviour - unified approach
  3673. override bool IsHeavyBehaviour()
  3674. {
  3675. if (m_ItemBehaviour == 0)
  3676. {
  3677. return true;
  3678. }
  3679. return false;
  3680. }
  3681. override bool IsOneHandedBehaviour()
  3682. {
  3683. if (m_ItemBehaviour == 1)
  3684. {
  3685. return true;
  3686. }
  3687. return false;
  3688. }
  3689. override bool IsTwoHandedBehaviour()
  3690. {
  3691. if (m_ItemBehaviour == 2)
  3692. {
  3693. return true;
  3694. }
  3695. return false;
  3696. }
  3697. bool IsDeployable()
  3698. {
  3699. return false;
  3700. }
  3701. //!how long it takes to deploy this item in seconds
  3702. float GetDeployTime()
  3703. {
  3704. return UATimeSpent.DEFAULT_DEPLOY;
  3705. }
  3706. //----------------------------------------------------------------
  3707. // Item Targeting (User Actions)
  3708. override void SetTakeable(bool pState)
  3709. {
  3710. m_IsTakeable = pState;
  3711. SetSynchDirty();
  3712. }
  3713. override bool IsTakeable()
  3714. {
  3715. return m_IsTakeable;
  3716. }
  3717. // For cases where we want to show object widget which cant be taken to hands
  3718. bool IsActionTargetVisible()
  3719. {
  3720. return false;
  3721. }
  3722. //! Attachment Sound Type getting from config file
  3723. protected void PreLoadSoundAttachmentType()
  3724. {
  3725. string att_type = "None";
  3726. if (ConfigIsExisting("soundAttType"))
  3727. {
  3728. att_type = ConfigGetString("soundAttType");
  3729. }
  3730. m_SoundAttType = att_type;
  3731. }
  3732. override string GetAttachmentSoundType()
  3733. {
  3734. return m_SoundAttType;
  3735. }
  3736. //----------------------------------------------------------------
  3737. //SOUNDS - ItemSoundHandler
  3738. //----------------------------------------------------------------
  3739. string GetPlaceSoundset(); // played when deploy starts
  3740. string GetLoopDeploySoundset(); // played when deploy starts and stopped when it finishes
  3741. string GetDeploySoundset(); // played when deploy sucessfully finishes
  3742. string GetLoopFoldSoundset(); // played when fold starts and stopped when it finishes
  3743. string GetFoldSoundset(); // played when fold sucessfully finishes
  3744. ItemSoundHandler GetItemSoundHandler()
  3745. {
  3746. if (!m_ItemSoundHandler)
  3747. m_ItemSoundHandler = new ItemSoundHandler(this);
  3748. return m_ItemSoundHandler;
  3749. }
  3750. // override to initialize sounds
  3751. protected void InitItemSounds()
  3752. {
  3753. if (GetPlaceSoundset() == string.Empty && GetDeploySoundset() == string.Empty && GetLoopDeploySoundset() == string.Empty)
  3754. return;
  3755. ItemSoundHandler handler = GetItemSoundHandler();
  3756. if (GetPlaceSoundset() != string.Empty)
  3757. handler.AddSound(SoundConstants.ITEM_PLACE, GetPlaceSoundset());
  3758. if (GetDeploySoundset() != string.Empty)
  3759. handler.AddSound(SoundConstants.ITEM_DEPLOY, GetDeploySoundset());
  3760. SoundParameters params = new SoundParameters();
  3761. params.m_Loop = true;
  3762. if (GetLoopDeploySoundset() != string.Empty)
  3763. handler.AddSound(SoundConstants.ITEM_DEPLOY_LOOP, GetLoopDeploySoundset(), params);
  3764. }
  3765. // Start sound using ItemSoundHandler
  3766. void StartItemSoundServer(int id)
  3767. {
  3768. if (!GetGame().IsServer())
  3769. return;
  3770. m_SoundSyncPlay = id;
  3771. SetSynchDirty();
  3772. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).Remove(ClearStartItemSoundServer); // in case one is queued already
  3773. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(ClearStartItemSoundServer, 100);
  3774. }
  3775. // Stop sound using ItemSoundHandler
  3776. void StopItemSoundServer(int id)
  3777. {
  3778. if (!GetGame().IsServer())
  3779. return;
  3780. m_SoundSyncStop = id;
  3781. SetSynchDirty();
  3782. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).Remove(ClearStopItemSoundServer); // in case one is queued already
  3783. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(ClearStopItemSoundServer, 100);
  3784. }
  3785. protected void ClearStartItemSoundServer()
  3786. {
  3787. m_SoundSyncPlay = 0;
  3788. }
  3789. protected void ClearStopItemSoundServer()
  3790. {
  3791. m_SoundSyncStop = 0;
  3792. }
  3793. //! Plays sound on item attach. Be advised, the config structure may slightly change in 1.11 update to allow for more complex use.
  3794. void PlayAttachSound(string slot_type)
  3795. {
  3796. if (!GetGame().IsDedicatedServer())
  3797. {
  3798. if (ConfigIsExisting("attachSoundSet"))
  3799. {
  3800. string cfg_path = "";
  3801. string soundset = "";
  3802. string type_name = GetType();
  3803. TStringArray cfg_soundset_array = new TStringArray;
  3804. TStringArray cfg_slot_array = new TStringArray;
  3805. ConfigGetTextArray("attachSoundSet",cfg_soundset_array);
  3806. ConfigGetTextArray("attachSoundSlot",cfg_slot_array);
  3807. if (cfg_soundset_array.Count() > 0 && cfg_soundset_array.Count() == cfg_slot_array.Count())
  3808. {
  3809. for (int i = 0; i < cfg_soundset_array.Count(); i++)
  3810. {
  3811. if (cfg_slot_array[i] == slot_type)
  3812. {
  3813. soundset = cfg_soundset_array[i];
  3814. break;
  3815. }
  3816. }
  3817. }
  3818. if (soundset != "")
  3819. {
  3820. EffectSound sound = SEffectManager.PlaySound(soundset, GetPosition());
  3821. sound.SetAutodestroy(true);
  3822. }
  3823. }
  3824. }
  3825. }
  3826. void PlayDetachSound(string slot_type)
  3827. {
  3828. //TODO - evaluate if needed and devise universal config structure if so
  3829. }
  3830. void OnApply(PlayerBase player);
  3831. float GetBandagingEffectivity()
  3832. {
  3833. return 1.0;
  3834. };
  3835. //returns applicable selection
  3836. array<string> GetHeadHidingSelection()
  3837. {
  3838. return m_HeadHidingSelections;
  3839. }
  3840. bool HidesSelectionBySlot()
  3841. {
  3842. return m_HideSelectionsBySlot;
  3843. }
  3844. WrittenNoteData GetWrittenNoteData() {};
  3845. void StopItemDynamicPhysics()
  3846. {
  3847. SetDynamicPhysicsLifeTime(0.01);
  3848. m_ItemBeingDroppedPhys = false;
  3849. }
  3850. void PerformDamageSystemReinit()
  3851. {
  3852. array<string> zone_names = new array<string>;
  3853. GetDamageZones(zone_names);
  3854. for (int i = 0; i < zone_names.Count(); i++)
  3855. {
  3856. SetHealthMax(zone_names.Get(i),"Health");
  3857. }
  3858. SetHealthMax("","Health");
  3859. }
  3860. //! Sets zone damages to match randomized global health set by CE (CE spawn only)
  3861. void SetZoneDamageCEInit()
  3862. {
  3863. float global_health = GetHealth01("","Health");
  3864. array<string> zones = new array<string>;
  3865. GetDamageZones(zones);
  3866. //set damage of all zones to match global health level
  3867. for (int i = 0; i < zones.Count(); i++)
  3868. {
  3869. SetHealth01(zones.Get(i),"Health",global_health);
  3870. }
  3871. }
  3872. //!DEPRECATED in use, but returns correct values nontheless. Check performed elsewhere
  3873. bool IsCoverFaceForShave(string slot_name)
  3874. {
  3875. return IsExclusionFlagPresent(PlayerBase.GetFaceCoverageShaveValues());
  3876. }
  3877. void ProcessItemWetness(float delta, bool hasParent, bool hasRootAsPlayer, ItemBase refParentIB)
  3878. {
  3879. if (!hasRootAsPlayer)
  3880. {
  3881. if (refParentIB)
  3882. {
  3883. // parent is wet
  3884. if ((refParentIB.GetWet() >= GameConstants.STATE_SOAKING_WET) && (m_VarWet < m_VarWetMax))
  3885. AddWet(delta * GameConstants.WETNESS_RATE_WETTING_INSIDE);
  3886. // parent has liquid inside
  3887. else if ((refParentIB.GetLiquidType() != 0) && (refParentIB.GetQuantity() > 0) && (m_VarWet < m_VarWetMax))
  3888. AddWet(delta * GameConstants.WETNESS_RATE_WETTING_LIQUID);
  3889. // drying
  3890. else if (m_VarWet > m_VarWetMin)
  3891. AddWet(-1 * delta * GetDryingIncrement("ground") * 2);
  3892. }
  3893. else
  3894. {
  3895. // drying on ground or inside non-itembase (car, ...)
  3896. if (m_VarWet > m_VarWetMin)
  3897. AddWet(-1 * delta * GetDryingIncrement("ground"));
  3898. }
  3899. }
  3900. }
  3901. void ProcessItemTemperature(float delta, bool hasParent, bool hasRootAsPlayer, ItemBase refParentIB)
  3902. {
  3903. if (CanHaveTemperature() && !IsSelfAdjustingTemperature() && !GetHierarchyRoot().IsSelfAdjustingTemperature())
  3904. {
  3905. float target = g_Game.GetMission().GetWorldData().GetBaseEnvTemperatureAtObject(this);
  3906. if (GetTemperature() != target || !IsFreezeThawProgressFinished())
  3907. {
  3908. float heatPermCoef = 1.0;
  3909. EntityAI ent = this;
  3910. while (ent)
  3911. {
  3912. heatPermCoef *= ent.GetHeatPermeabilityCoef();
  3913. ent = ent.GetHierarchyParent();
  3914. }
  3915. SetTemperatureEx(new TemperatureDataInterpolated(target,ETemperatureAccessTypes.ACCESS_WORLD,delta,GameConstants.TEMP_COEF_WORLD,heatPermCoef));
  3916. }
  3917. }
  3918. }
  3919. void HierarchyCheck(out bool hasParent, out bool hasRootAsPlayer, out ItemBase refParentIB)
  3920. {
  3921. // hierarchy check for an item to decide whether it has some parent and it is in some player inventory
  3922. EntityAI parent = GetHierarchyParent();
  3923. if (!parent)
  3924. {
  3925. hasParent = false;
  3926. hasRootAsPlayer = false;
  3927. }
  3928. else
  3929. {
  3930. hasParent = true;
  3931. hasRootAsPlayer = (GetHierarchyRootPlayer() != null);
  3932. refParentIB = ItemBase.Cast(parent);
  3933. }
  3934. }
  3935. protected void ProcessDecay(float delta, bool hasRootAsPlayer)
  3936. {
  3937. // this is stub, implemented on Edible_Base
  3938. }
  3939. bool CanDecay()
  3940. {
  3941. // return true used on selected food clases so they can decay
  3942. return false;
  3943. }
  3944. protected bool CanProcessDecay()
  3945. {
  3946. // this is stub, implemented on Edible_Base class
  3947. // used to determine whether it is still necessary for the food to decay
  3948. return false;
  3949. }
  3950. protected bool CanHaveWetness()
  3951. {
  3952. // return true used on selected items that have a wetness effect
  3953. return false;
  3954. }
  3955. //! Items cannot be consumed if frozen by default. Override for exceptions.
  3956. bool CanBeConsumed(ConsumeConditionData data = null)
  3957. {
  3958. return !GetIsFrozen() && IsOpen();
  3959. }
  3960. override void ProcessVariables()
  3961. {
  3962. bool hasParent = false, hasRootAsPlayer = false;
  3963. ItemBase refParentIB;
  3964. bool wwtu = g_Game.IsWorldWetTempUpdateEnabled();
  3965. bool foodDecay = g_Game.IsFoodDecayEnabled();
  3966. if (wwtu || foodDecay)
  3967. {
  3968. bool processWetness = wwtu && CanHaveWetness();
  3969. bool processTemperature = wwtu && CanHaveTemperature();
  3970. bool processDecay = foodDecay && CanDecay() && CanProcessDecay();
  3971. if (processWetness || processTemperature || processDecay)
  3972. {
  3973. HierarchyCheck(hasParent, hasRootAsPlayer, refParentIB);
  3974. if (processWetness)
  3975. ProcessItemWetness(m_ElapsedSinceLastUpdate, hasParent, hasRootAsPlayer, refParentIB);
  3976. if (processTemperature)
  3977. ProcessItemTemperature(m_ElapsedSinceLastUpdate, hasParent, hasRootAsPlayer, refParentIB);
  3978. if (processDecay)
  3979. ProcessDecay(m_ElapsedSinceLastUpdate, hasRootAsPlayer);
  3980. }
  3981. }
  3982. }
  3983. //! Used in heat comfort calculations only!
  3984. float GetTemperaturePerQuantityWeight()
  3985. {
  3986. return m_TemperaturePerQuantityWeight * GameConstants.ITEM_TEMPERATURE_QUANTITY_WEIGHT_MULTIPLIER;
  3987. }
  3988. override float GetTemperatureFreezeThreshold()
  3989. {
  3990. if (IsLiquidContainer() && GetLiquidType() != LIQUID_NONE)
  3991. return Liquid.GetFreezeThreshold(GetLiquidType());
  3992. return super.GetTemperatureFreezeThreshold();
  3993. }
  3994. override float GetTemperatureThawThreshold()
  3995. {
  3996. if (IsLiquidContainer() && GetLiquidType() != LIQUID_NONE)
  3997. return Liquid.GetThawThreshold(GetLiquidType());
  3998. return super.GetTemperatureThawThreshold();
  3999. }
  4000. override float GetItemOverheatThreshold()
  4001. {
  4002. if (IsLiquidContainer() && GetLiquidType() != LIQUID_NONE)
  4003. return Liquid.GetBoilThreshold(GetLiquidType());
  4004. return super.GetItemOverheatThreshold();
  4005. }
  4006. override float GetTemperatureFreezeTime()
  4007. {
  4008. if (HasQuantity())
  4009. return Math.Lerp(GameConstants.TEMPERATURE_TIME_FREEZE_MIN,Math.Max(GameConstants.TEMPERATURE_TIME_FREEZE_MIN,super.GetTemperatureFreezeTime()),GetQuantityNormalized());
  4010. return super.GetTemperatureFreezeTime();
  4011. }
  4012. override float GetTemperatureThawTime()
  4013. {
  4014. if (HasQuantity())
  4015. return Math.Lerp(GameConstants.TEMPERATURE_TIME_THAW_MIN,Math.Max(GameConstants.TEMPERATURE_TIME_FREEZE_MIN,super.GetTemperatureThawTime()),GetQuantityNormalized());
  4016. return super.GetTemperatureThawTime();
  4017. }
  4018. //! from enviro source
  4019. void AffectLiquidContainerOnFill(int liquid_type, float amount);
  4020. //! from other liquid container source
  4021. void AffectLiquidContainerOnTransfer(int liquidType, float amount, float sourceLiquidTemperature);
  4022. bool IsCargoException4x3(EntityAI item)
  4023. {
  4024. return (item.IsKindOf("Cauldron") || item.IsKindOf("Pot") || item.IsKindOf("FryingPan") || item.IsKindOf("SmallProtectorCase") || (item.IsKindOf("PortableGasStove") && item.FindAttachmentBySlotName("CookingEquipment")));
  4025. }
  4026. void CopyScriptPropertiesFrom(EntityAI oldItem)
  4027. {
  4028. MiscGameplayFunctions.TransferItemProperties(oldItem, this);
  4029. }
  4030. //! Adds a light source child
  4031. void AddLightSourceItem(ItemBase lightsource)
  4032. {
  4033. m_LightSourceItem = lightsource;
  4034. }
  4035. void RemoveLightSourceItem()
  4036. {
  4037. m_LightSourceItem = null;
  4038. }
  4039. ItemBase GetLightSourceItem()
  4040. {
  4041. return m_LightSourceItem;
  4042. }
  4043. //! returns an array of possible finishers
  4044. array<int> GetValidFinishers()
  4045. {
  4046. return null;
  4047. }
  4048. //! If we need a different (handheld)item action widget displayed, the logic goes in here
  4049. bool GetActionWidgetOverride(out typename name)
  4050. {
  4051. return false;
  4052. }
  4053. bool PairWithDevice(notnull ItemBase otherDevice)
  4054. {
  4055. if (GetGame().IsServer())
  4056. {
  4057. ItemBase explosive = otherDevice;
  4058. RemoteDetonatorTrigger trg = RemoteDetonatorTrigger.Cast(this);
  4059. if (!trg)
  4060. {
  4061. trg = RemoteDetonatorTrigger.Cast(otherDevice);
  4062. explosive = this;
  4063. }
  4064. explosive.PairRemote(trg);
  4065. trg.SetControlledDevice(explosive);
  4066. int persistentID = RemotelyActivatedItemBehaviour.GeneratePersistentID();
  4067. trg.SetPersistentPairID(persistentID);
  4068. explosive.SetPersistentPairID(persistentID);
  4069. return true;
  4070. }
  4071. return false;
  4072. }
  4073. //! generic effectivity as a bait for animal catching
  4074. float GetBaitEffectivity()
  4075. {
  4076. float ret = 1.0;
  4077. if (HasQuantity())
  4078. ret *= GetQuantityNormalized();
  4079. ret *= GetHealth01();
  4080. return ret;
  4081. }
  4082. #ifdef DEVELOPER
  4083. override void SetDebugItem()
  4084. {
  4085. super.SetDebugItem();
  4086. _itemBase = this;
  4087. }
  4088. override string GetDebugText()
  4089. {
  4090. string text = super.GetDebugText();
  4091. text += string.Format("Heat isolation(raw): %1\n", GetHeatIsolation());
  4092. text += string.Format("Heat isolation(modified): %1\n", MiscGameplayFunctions.GetCurrentItemHeatIsolation(this));
  4093. return text;
  4094. }
  4095. #endif
  4096. bool CanBeUsedForSuicide()
  4097. {
  4098. return true;
  4099. }
  4100. ///////////////////
  4101. //DEPRECATED BELOW
  4102. //////////////////
  4103. // Backwards compatibility
  4104. void ProcessItemWetnessAndTemperature(float delta, bool hasParent, bool hasRootAsPlayer, ItemBase refParentIB)
  4105. {
  4106. ProcessItemWetness(delta, hasParent, hasRootAsPlayer, refParentIB);
  4107. ProcessItemTemperature(delta, hasParent, hasRootAsPlayer, refParentIB);
  4108. }
  4109. // replaced by ItemSoundHandler
  4110. protected EffectSound m_SoundDeployFinish;
  4111. protected EffectSound m_SoundPlace;
  4112. protected EffectSound m_DeployLoopSoundEx;
  4113. protected EffectSound m_SoundDeploy;
  4114. bool m_IsPlaceSound;
  4115. bool m_IsDeploySound;
  4116. bool m_IsSoundSynchRemote;
  4117. string GetDeployFinishSoundset();
  4118. void PlayDeploySound();
  4119. void PlayDeployFinishSound();
  4120. void PlayPlaceSound();
  4121. void PlayDeployLoopSoundEx();
  4122. void StopDeployLoopSoundEx();
  4123. void SoundSynchRemoteReset();
  4124. void SoundSynchRemote();
  4125. bool UsesGlobalDeploy(){return false;}
  4126. bool CanPlayDeployLoopSound(){return false;}
  4127. bool IsSoundSynchRemote(){return m_IsSoundSynchRemote;}
  4128. bool IsPlaceSound(){return m_IsPlaceSound;}
  4129. bool IsDeploySound(){return m_IsDeploySound;}
  4130. void SetIsPlaceSound(bool is_place_sound);
  4131. void SetIsDeploySound(bool is_deploy_sound);
  4132. }
  4133. EntityAI SpawnItemOnLocation(string object_name, notnull InventoryLocation loc, bool full_quantity)
  4134. {
  4135. EntityAI entity = SpawnEntity(object_name, loc, ECE_IN_INVENTORY, RF_DEFAULT);
  4136. if (entity)
  4137. {
  4138. bool is_item = entity.IsInherited(ItemBase);
  4139. if (is_item && full_quantity)
  4140. {
  4141. ItemBase item = ItemBase.Cast(entity);
  4142. item.SetQuantity(item.GetQuantityInit());
  4143. }
  4144. }
  4145. else
  4146. {
  4147. ErrorEx("Cannot spawn entity: " + object_name,ErrorExSeverity.INFO);
  4148. return NULL;
  4149. }
  4150. return entity;
  4151. }
  4152. void SetupSpawnedItem(ItemBase item, float health, float quantity)
  4153. {
  4154. if (item)
  4155. {
  4156. if (health > 0)
  4157. item.SetHealth("", "", health);
  4158. if (item.CanHaveTemperature())
  4159. {
  4160. item.SetTemperatureDirect(GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE);
  4161. if (item.CanFreeze())
  4162. item.SetFrozen(false);
  4163. }
  4164. if (item.HasEnergyManager())
  4165. {
  4166. if (quantity >= 0)
  4167. {
  4168. item.GetCompEM().SetEnergy0To1(quantity);
  4169. }
  4170. else
  4171. {
  4172. item.GetCompEM().SetEnergy(Math.AbsFloat(quantity));
  4173. }
  4174. }
  4175. else if (item.IsMagazine())
  4176. {
  4177. Magazine mag = Magazine.Cast(item);
  4178. if (quantity >= 0)
  4179. {
  4180. mag.ServerSetAmmoCount(mag.GetAmmoMax() * quantity);
  4181. }
  4182. else
  4183. {
  4184. mag.ServerSetAmmoCount(Math.AbsFloat(quantity));
  4185. }
  4186. }
  4187. else
  4188. {
  4189. if (quantity >= 0)
  4190. {
  4191. item.SetQuantityNormalized(quantity, false);
  4192. }
  4193. else
  4194. {
  4195. item.SetQuantity(Math.AbsFloat(quantity));
  4196. }
  4197. }
  4198. }
  4199. }
  4200. #ifdef DEVELOPER
  4201. ItemBase _itemBase;//watched item goes here(LCTRL+RMB->Watch)
  4202. #endif