fireplacebase.c 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844
  1. enum FireplaceFireState
  2. {
  3. NO_FIRE = 1,
  4. START_FIRE = 2,
  5. SMALL_FIRE = 3,
  6. NORMAL_FIRE = 4,
  7. END_FIRE = 5,
  8. EXTINGUISHING_FIRE = 6,
  9. EXTINGUISHED_FIRE = 7,
  10. REIGNITED_FIRE = 8,
  11. COUNT = 9 //for net sync purposes
  12. }
  13. enum FirePlaceFailure
  14. {
  15. WIND = 0,
  16. WET = 1,
  17. }
  18. class FireplaceBase : ItemBase
  19. {
  20. //State params
  21. protected bool m_IsBurning = false;
  22. protected bool m_HasAshes = false;
  23. protected bool m_IsOven = false;
  24. protected bool m_HasStoneCircle = false;
  25. protected bool m_NoIgnite = false;
  26. protected int m_OvenAttachmentsLockState = -1;
  27. protected FireplaceFireState m_FireState = FireplaceFireState.NO_FIRE;
  28. protected FireplaceFireState m_LastFireState = FireplaceFireState.NO_FIRE; //for synchronization purposes
  29. protected vector m_HalfExtents;
  30. //Fireplace params
  31. protected float m_FuelBurnRateMP = 1.0; //! determines how fast will the fuel item burn before spending (lower is better)
  32. //cooking
  33. protected ref Cooking m_CookingProcess;
  34. //temperature simulation constants
  35. const float PARAM_SMALL_FIRE_TEMPERATURE = 150; //! maximum fireplace temperature of a small fire (degree Celsius)
  36. const float PARAM_NORMAL_FIRE_TEMPERATURE = 1000; //! maximum fireplace temperature of a normal fire (degree Celsius)
  37. const float PARAM_OUTDOOR_FIRE_TEMPERATURE = 500; //! maximum fireplace temperature of an outdoor fire (degree Celsius)
  38. const float PARAM_MIN_FIRE_TEMPERATURE = 30; //! minimum fireplace temperature under which the fireplace is inactive (degree Celsius)
  39. const float PARAM_TEMPERATURE_INCREASE = 10; //! how much will temperature increase when fireplace is burning (degree Celsius per second)
  40. const float PARAM_TEMPERATURE_DECREASE = 10; //! how much will temperature decrease when fireplace is cooling (degree Celsius per second)
  41. const float PARAM_MAX_WET_TO_IGNITE = 0.2; //! maximum wetness value when the fireplace can be ignited
  42. const float PARAM_MIN_TEMP_TO_REIGNITE = 30; //! minimum fireplace temperature under which the fireplace can be reignited using air only (degree Celsius)
  43. const float PARAM_IGNITE_RAIN_THRESHOLD = 0.1; //! maximum rain value when the fireplace can be ignited
  44. const float PARAM_BURN_WET_THRESHOLD = 0.40; //! maximum wetness value when the fireplace is able to burn
  45. const float PARAM_WET_HEATING_DECREASE_COEF = 0.01; //! value for calculating wetness loss during heating process
  46. const float PARAM_WET_COOLING_DECREASE_COEF = 0.002; //! value for calculating wetness loss during cooling process
  47. const float PARAM_FIRE_CONSUM_RATE_AMOUNT = 0.5; //! base value of fire consumption rate (how many base energy will be spent on each update)
  48. const float PARAM_BURN_DAMAGE_COEF = 5.0; //! value for calculating damage on items located in fireplace cargo
  49. const float PARAM_FULL_HEAT_RADIUS = 2.0; //! radius in which objects are fully heated by fire
  50. const float PARAM_HEAT_RADIUS = 4.0; //! radius in which objects are heated by fire
  51. const float PARAM_MAX_TRANSFERED_TEMPERATURE = 20; //! maximum value for temperature that will be transfered to player (environment)
  52. //staging constants
  53. const int MIN_STONES_TO_BUILD_CIRCLE = 8; //! minimum amount of stones for circle
  54. const int MIN_STONES_TO_BUILD_OVEN = 16; //! minimum amount of stones for oven
  55. const int MAX_TEMPERATURE_TO_DISMANTLE_OVEN = 40; //! maximum temperature for dismantling oven
  56. const float MIN_CEILING_HEIGHT = 5; //! min height of ceiling for fire to be ignited
  57. //fuel constants
  58. const float FUEL_BURN_RATE_DEFAULT = 1.0;
  59. const float FUEL_BURN_RATE_STONES = 0.92;
  60. const float FUEL_BURN_RATE_OVEN = 0.85;
  61. //! cooking
  62. const float PARAM_COOKING_TEMP_THRESHOLD = 100; //! temperature threshold for starting coooking process (degree Celsius)
  63. //! timer constants
  64. const int TIMER_HEATING_UPDATE_INTERVAL = 3; //! update interval duration of heating process (seconds)
  65. const int TIMER_COOLING_UPDATE_INTERVAL = 3; //! update interval duration of cooling process (seconds)
  66. //! direct cooking slots
  67. const int DIRECT_COOKING_SLOT_COUNT = 3;
  68. const int SMOKING_SLOT_COUNT = 4;
  69. const float SMOKING_SPEED = 1; // per second
  70. // stage lifetimes
  71. const int LIFETIME_FIREPLACE_STONE_CIRCLE = 172800;
  72. const int LIFETIME_FIREPLACE_STONE_OVEN = 604800;
  73. const float IGNITE_WIND_THRESHOLD = 0.8; //fireplace can not be ignited above this multiple of max wind
  74. protected const float RAIN_EFFECT_LIMIT = 0.4; //! rain level that triggers fireplace to start soaking
  75. protected const float SNOWFALL_EFFECT_LIMIT = 1.3; //! snowfall level that triggers fireplace to start soaking
  76. protected const float RAIN_WETNESS_INCREASE = 0.02; //! value for calculating of wetness that fireplace gain when raining
  77. protected const float SNOWFALL_WETNESS_INCREASE = 0.01; //! value for calculating of wetness that fireplace gain when raining
  78. //Timers
  79. protected ref Timer m_HeatingTimer;
  80. protected ref Timer m_CoolingTimer;
  81. // Light entity
  82. protected FireplaceLight m_Light;
  83. protected float m_LightDistance = 2000;
  84. //Attachments
  85. protected ItemBase m_CookingEquipment;
  86. protected ItemBase m_DirectCookingSlots[DIRECT_COOKING_SLOT_COUNT];
  87. protected ItemBase m_SmokingSlots[SMOKING_SLOT_COUNT];
  88. protected ref FireConsumable m_ItemToConsume;
  89. //Particles - default for FireplaceBase
  90. protected int PARTICLE_FIRE_START = ParticleList.CAMP_FIRE_START;
  91. protected int PARTICLE_OVEN_FIRE_START = ParticleList.CAMP_STOVE_FIRE_START;
  92. protected int PARTICLE_SMALL_FIRE = ParticleList.CAMP_SMALL_FIRE;
  93. protected int PARTICLE_NORMAL_FIRE = ParticleList.CAMP_NORMAL_FIRE;
  94. protected int PARTICLE_OVEN_FIRE = ParticleList.CAMP_STOVE_FIRE;
  95. protected int PARTICLE_SMALL_SMOKE = ParticleList.CAMP_SMALL_SMOKE;
  96. protected int PARTICLE_NORMAL_SMOKE = ParticleList.CAMP_NORMAL_SMOKE;
  97. protected int PARTICLE_FIRE_END = ParticleList.CAMP_FIRE_END;
  98. protected int PARTICLE_OVEN_FIRE_END = ParticleList.CAMP_STOVE_FIRE_END;
  99. protected int PARTICLE_STEAM_END = ParticleList.CAMP_STEAM_2END;
  100. protected int PARTICLE_STEAM_EXTINGUISHING = ParticleList.CAMP_STEAM_EXTINGUISH_START;
  101. protected int PARTICLE_NO_IGNITE_WIND = ParticleList.CAMP_NO_IGNITE_WIND;
  102. //
  103. protected Particle m_ParticleFireStart;
  104. protected Particle m_ParticleSmallFire;
  105. protected Particle m_ParticleNormalFire;
  106. protected Particle m_ParticleSmallSmoke;
  107. protected Particle m_ParticleNormalSmoke;
  108. protected Particle m_ParticleFireEnd;
  109. protected Particle m_ParticleSteamEnd;
  110. protected Particle m_ParticleSteamExtinguishing;
  111. //Sounds
  112. const string SOUND_FIRE_HEAVY = "HeavyFire_SoundSet";
  113. const string SOUND_FIRE_LIGHT = "LightFire_SoundSet";
  114. const string SOUND_FIRE_NO_FIRE = "NoFuelFire_SoundSet";
  115. const string SOUND_FIRE_EXTINGUISHING = "ExtinguishByWater_SoundSet";
  116. const string SOUND_FIRE_EXTINGUISHED = "ExtinguishByWaterEnd_SoundSet";
  117. //
  118. protected EffectSound m_SoundFireLoop;
  119. protected EffectSound m_SoundFire;
  120. //
  121. //Fuel
  122. //Kindling / Fuel item types
  123. protected static ref map<typename, ref FireConsumableType> m_FireConsumableTypes;
  124. protected ref map<ItemBase, ref FireConsumable> m_FireConsumables;
  125. //Player action / status messages
  126. const string MESSAGE_IGNITE_IGNIT_ITEM_DAMAGED = "You cannot start fire. Fireplace is ruined.";
  127. const string MESSAGE_IGNITE_NO_KINDLING = "There needs to be some kindling to start a fire.";
  128. const string MESSAGE_IGNITE_TOO_WET = "The fireplace is too wet to be ignited.";
  129. const string MESSAGE_IGNITE_RAIN = "The fire went out because of the rain.";
  130. const string MESSAGE_IGNITE_WIND = "The fire went out because of the wind.";
  131. const string MESSAGE_IGNITE_IN_WATER = "I cannot ignite the fireplace in the water.";
  132. const string MESSAGE_IGNITE_UNDER_LOW_ROOF = "I cannot ignite the fireplace here, the is not enough room.";
  133. const string MESSAGE_REIGNITE_NO_KINDLING = "There needs to be some kindling to start a fire.";
  134. const string MESSAGE_REIGNITE_RAIN = "Cannot reignite fireplace in rain.";
  135. const string MESSAGE_REIGNITE_TOO_WET = "The fireplace is too wet to be reignited.";
  136. const string MESSAGE_BURY_ASHES_FAILED_NOT_EMPTY = "Cannot bury ashes. There are sill items in it.";
  137. const string MESSAGE_BURY_ASHES_FAILED_SURFACE = "Cannot bury ashes on hard surface.";
  138. const string MESSAGE_BURY_ASHES_FAILED_BURNING = "Cannot bury ashes, the fireplace is still burning.";
  139. const string MESSAGE_BURY_ASHES_FAILED_TOO_HOT = "Cannot bury ashes, the fireplace is too hot.";
  140. const string MESSAGE_CANNOT_BUILD_OVEN = "Cannot build oven.";
  141. const string MESSAGE_CANNOT_DISMANTLE_OVEN = "Cannot dismantle oven.";
  142. //Visual animations
  143. const string ANIMATION_ASHES = "Ashes";
  144. const string ANIMATION_KINDLING = "Kindling";
  145. const string ANIMATION_STICKS = "Sticks";
  146. const string ANIMATION_WOOD = "Wood";
  147. const string ANIMATION_BURNT_WOOD = "BurntWood";
  148. const string ANIMATION_STONE = "Stone";
  149. const string ANIMATION_STONES = "StonesCircle";
  150. const string ANIMATION_TRIPOD = "Tripod";
  151. const string ANIMATION_OVEN = "Oven";
  152. const string ANIMATION_INVENTORY = "Inventory";
  153. const string ANIMATION_COOKWARE_HANDLE = "handleRotate";
  154. const string ANIMATION_CAULDRON_HANDLE = "handle1Rotate";
  155. //Visual textures and materials
  156. const string MATERIAL_FIREPLACE_GLOW = "dz\\gear\\cooking\\data\\stoneground.rvmat";
  157. const string MATERIAL_FIREPLACE_NOGLOW = "dz\\gear\\cooking\\data\\stonegroundnoemit.rvmat";
  158. //Attachment types
  159. //Fuel
  160. typename ATTACHMENT_STICKS = WoodenStick;
  161. typename ATTACHMENT_FIREWOOD = Firewood;
  162. //Kindling
  163. typename ATTACHMENT_RAGS = Rag;
  164. typename ATTACHMENT_BANDAGE = BandageDressing;
  165. typename ATTACHMENT_BOOK = ItemBook;
  166. typename ATTACHMENT_BARK_OAK = Bark_Oak;
  167. typename ATTACHMENT_BARK_BIRCH = Bark_Birch;
  168. typename ATTACHMENT_PAPER = Paper;
  169. typename ATTACHMENT_GIFTWRAP = GiftWrapPaper;
  170. typename ATTACHMENT_PUNCHEDCARD = PunchedCard;
  171. typename ATTACHMENT_EYEMASK_COLORBASE = EyeMask_ColorBase;
  172. //Other
  173. typename ATTACHMENT_TRIPOD = Tripod;
  174. typename ATTACHMENT_COOKINGSTAND = CookingStand;
  175. typename ATTACHMENT_STONES = Stone;
  176. typename ATTACHMENT_COOKING_POT = Pot;
  177. typename ATTACHMENT_FRYING_PAN = FryingPan;
  178. typename ATTACHMENT_CAULDRON = Cauldron;
  179. //
  180. const string OBJECT_CLUTTER_CUTTER = "ClutterCutterFireplace";
  181. protected Object m_ClutterCutter;
  182. //area damage
  183. protected ref AreaDamageManager m_AreaDamage;
  184. //quantity
  185. protected float m_TotalEnergy;
  186. // Noise
  187. ref NoiseParams m_NoisePar;
  188. private bool m_CanNoise = true; // Flip every fireplace update to limit amount of noise generation
  189. // UniversalTemperatureSource
  190. protected ref UniversalTemperatureSource m_UTSource;
  191. protected ref UniversalTemperatureSourceSettings m_UTSSettings;
  192. protected ref UniversalTemperatureSourceLambdaFireplace m_UTSLFireplace;
  193. // surface wetness on heat modification
  194. protected const float WET_SURFACE_INCREMENT = 0.06; //! size of wetness increment (per FP heating tick) added to overall FP wetness when ignited on wet surface
  195. protected float m_SurfaceUnderWetnessModifier
  196. protected bool m_ThawnSurfaceUnderSupport;
  197. protected ref UnderObjectDecalSpawnSettings m_UnderObjectDecalSpawnSettings;
  198. protected ref UnderObjectDecalSpawnComponent m_UnderObjectDecalSpawnComponent;
  199. //================================================================
  200. // INIT / STORE LOAD-SAVE
  201. //================================================================
  202. //Constructor
  203. protected void FireplaceBase()
  204. {
  205. //STATIC: define kindling types
  206. if (!m_FireConsumableTypes)
  207. {
  208. m_FireConsumableTypes = new ref map<typename, ref FireConsumableType>();
  209. m_FireConsumableTypes.Insert(ATTACHMENT_RAGS, new FireConsumableType(ATTACHMENT_RAGS, 8, true, "Rags"));
  210. m_FireConsumableTypes.Insert(ATTACHMENT_BANDAGE, new FireConsumableType(ATTACHMENT_BANDAGE, 8, true, "MedicalBandage"));
  211. m_FireConsumableTypes.Insert(ATTACHMENT_BOOK, new FireConsumableType(ATTACHMENT_BOOK, 20, true, "Book"));
  212. m_FireConsumableTypes.Insert(ATTACHMENT_BARK_OAK, new FireConsumableType(ATTACHMENT_BARK_OAK, 10, true, "OakBark"));
  213. m_FireConsumableTypes.Insert(ATTACHMENT_BARK_BIRCH, new FireConsumableType(ATTACHMENT_BARK_BIRCH, 8, true, "BirchBark"));
  214. m_FireConsumableTypes.Insert(ATTACHMENT_PAPER, new FireConsumableType(ATTACHMENT_PAPER, 5, true, "Paper"));
  215. m_FireConsumableTypes.Insert(ATTACHMENT_GIFTWRAP, new FireConsumableType(ATTACHMENT_GIFTWRAP, 5, true, "GiftWrapPaper"));
  216. m_FireConsumableTypes.Insert(ATTACHMENT_PUNCHEDCARD, new FireConsumableType(ATTACHMENT_PUNCHEDCARD, 5, true, "PunchedCard"));
  217. m_FireConsumableTypes.Insert(ATTACHMENT_EYEMASK_COLORBASE, new FireConsumableType(ATTACHMENT_EYEMASK_COLORBASE, 5, true, "EyeMask_ColorBase"));
  218. //define fuel types
  219. m_FireConsumableTypes.Insert(ATTACHMENT_STICKS, new FireConsumableType(ATTACHMENT_STICKS, 30, false, "WoodenStick"));
  220. m_FireConsumableTypes.Insert(ATTACHMENT_FIREWOOD, new FireConsumableType(ATTACHMENT_FIREWOOD, 100, false, "Firewood"));
  221. }
  222. //calculate total energy
  223. CalcAndSetTotalEnergy();
  224. //define fuel / kindling items (fire consumables)
  225. m_FireConsumables = new map<ItemBase, ref FireConsumable>();
  226. //default burning parameters
  227. SetFuelBurnRateMP(FUEL_BURN_RATE_DEFAULT);
  228. //synchronized variables
  229. RegisterNetSyncVariableBool("m_IsBurning");
  230. RegisterNetSyncVariableBool("m_HasAshes");
  231. RegisterNetSyncVariableBool("m_IsOven");
  232. RegisterNetSyncVariableBool("m_HasStoneCircle");
  233. RegisterNetSyncVariableBool("m_RoofAbove");
  234. RegisterNetSyncVariableInt("m_FireState", FireplaceFireState.NO_FIRE, FireplaceFireState.COUNT);
  235. RegisterNetSyncVariableBool("m_IsSoundSynchRemote");
  236. RegisterNetSyncVariableBool("m_IsPlaceSound");
  237. RegisterNetSyncVariableBool("m_NoIgnite");
  238. m_HalfExtents = vector.Zero;
  239. m_SurfaceUnderWetnessModifier = 0.0;
  240. m_UTSSettings = new UniversalTemperatureSourceSettings();
  241. m_UTSSettings.m_ManualUpdate = true;
  242. m_UTSSettings.m_TemperatureItemCap = GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE;
  243. m_UTSSettings.m_TemperatureCap = PARAM_MAX_TRANSFERED_TEMPERATURE;
  244. m_UTSSettings.m_RangeFull = PARAM_FULL_HEAT_RADIUS;
  245. m_UTSSettings.m_RangeMax = PARAM_HEAT_RADIUS;
  246. m_UTSSettings.m_EnableOnTemperatureControl = true;
  247. m_UTSSettings.m_ActiveTemperatureThreshold = 250.0;
  248. m_UTSSettings.m_InactiveTemperatureThreshold = 475.0;
  249. m_UnderObjectDecalSpawnSettings = new UnderObjectDecalSpawnSettings();
  250. m_UnderObjectDecalSpawnSettings.m_RandomizeRotation = true;
  251. m_UnderObjectDecalSpawnSettings.m_PositionOffset = "0 0.05 0";
  252. m_UnderObjectDecalSpawnSettings.m_ScaleMax = 1.0;
  253. }
  254. protected void ~FireplaceBase()
  255. {
  256. DestroyAreaDamage();
  257. if (GetLightEntity())
  258. GetLightEntity().FadeOut();
  259. if (m_ThawnSurfaceUnderSupport && m_UnderObjectDecalSpawnComponent)
  260. {
  261. m_UnderObjectDecalSpawnComponent.RemoveDecal();
  262. m_UnderObjectDecalSpawnComponent = null;
  263. }
  264. }
  265. override void EEInit()
  266. {
  267. super.EEInit();
  268. //refresh visual on init
  269. RefreshFireplaceVisuals();
  270. if (m_CookingProcess == null)
  271. m_CookingProcess = new Cooking();
  272. if (GetGame().IsServer() || !GetGame().IsMultiplayer())
  273. {
  274. InitializeTemperatureSources();
  275. }
  276. if (m_ThawnSurfaceUnderSupport && !m_UnderObjectDecalSpawnComponent)
  277. {
  278. m_UnderObjectDecalSpawnComponent = new UnderObjectDecalSpawnComponent(m_UnderObjectDecalSpawnSettings, this);
  279. m_UnderObjectDecalSpawnComponent.SpawnDecal();
  280. }
  281. }
  282. override void EEItemAttached(EntityAI item, string slot_name)
  283. {
  284. super.EEItemAttached(item, slot_name);
  285. //cookware
  286. switch (item.Type())
  287. {
  288. case ATTACHMENT_CAULDRON:
  289. case ATTACHMENT_COOKING_POT:
  290. case ATTACHMENT_FRYING_PAN:
  291. SetCookingEquipment(ItemBase.Cast(item));
  292. break;
  293. }
  294. }
  295. override void OnItemLocationChanged(EntityAI old_owner, EntityAI new_owner)
  296. {
  297. super.OnItemLocationChanged(old_owner, new_owner);
  298. //refresh physics after location change (with delay)
  299. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(RefreshFireplacePhysics);
  300. InventoryLocation loc = new InventoryLocation();
  301. GetInventory().GetCurrentInventoryLocation(loc);
  302. if (loc.GetType() == InventoryLocationType.GROUND)
  303. {
  304. if (IsOpen() && !IsOven())
  305. CheckForRoofLimited(0); //roof check when moved to ground
  306. if (m_ThawnSurfaceUnderSupport && !m_UnderObjectDecalSpawnComponent)
  307. {
  308. m_UnderObjectDecalSpawnComponent = new UnderObjectDecalSpawnComponent(m_UnderObjectDecalSpawnSettings, this);
  309. m_UnderObjectDecalSpawnComponent.SpawnDecal();
  310. }
  311. }
  312. else
  313. {
  314. if (m_ThawnSurfaceUnderSupport && m_UnderObjectDecalSpawnComponent)
  315. {
  316. m_UnderObjectDecalSpawnComponent.RemoveDecal();
  317. m_UnderObjectDecalSpawnComponent = null;
  318. }
  319. }
  320. m_SurfaceUnderWetnessModifier = GetSurfaceWetnessOnHeatModifier(this);
  321. }
  322. override void OnAttachmentRuined(EntityAI attachment)
  323. {
  324. switch (attachment.Type())
  325. {
  326. case ATTACHMENT_TRIPOD:
  327. case ATTACHMENT_COOKINGSTAND:
  328. int slot = InventorySlots.GetSlotIdFromString("CookingEquipment");
  329. EntityAI ent = GetInventory().FindAttachment(slot);
  330. if (ent)
  331. {
  332. switch (ent.Type())
  333. {
  334. case ATTACHMENT_COOKING_POT:
  335. case ATTACHMENT_CAULDRON:
  336. case ATTACHMENT_FRYING_PAN:
  337. vector direction = ent.GetDirection();
  338. float dot = vector.Dot(direction, vector.Forward);
  339. float angle = Math.Acos(dot);
  340. if (direction[0] < 0)
  341. {
  342. angle = -angle;
  343. }
  344. float cos = Math.Cos(angle);
  345. float sin = Math.Sin(angle);
  346. GetInventory().DropEntityInBounds(InventoryMode.SERVER, this, ent, "2 0 2", angle, cos, sin);
  347. break;
  348. }
  349. }
  350. attachment.Delete();
  351. break;
  352. }
  353. }
  354. override void EEDelete(EntityAI parent)
  355. {
  356. super.EEDelete(parent);
  357. SetFireState(FireplaceFireState.NO_FIRE);
  358. // cleanup particles (for cases of leaving burning fplace and going back outside of network bubble)
  359. #ifndef SERVER
  360. StopAllParticlesAndSounds();
  361. #endif
  362. }
  363. //on store save/load
  364. override void OnStoreSave(ParamsWriteContext ctx)
  365. {
  366. super.OnStoreSave(ctx);
  367. //Save ashes state
  368. ctx.Write(m_HasAshes);
  369. //Save fuel burn rate MP
  370. ctx.Write(m_FuelBurnRateMP);
  371. //Save burning state
  372. ctx.Write(m_IsBurning);
  373. }
  374. override bool OnStoreLoad(ParamsReadContext ctx, int version)
  375. {
  376. if (!super.OnStoreLoad(ctx, version))
  377. return false;
  378. //--- Fireplace data ---
  379. //Load ashes state
  380. if (!ctx.Read(m_HasAshes))
  381. {
  382. m_HasAshes = false; //set default
  383. return false;
  384. }
  385. //Load temperature loss MP
  386. if (version < 139 && !ctx.Read(m_TemperatureLossMP))
  387. {
  388. m_TemperatureLossMP = 1.0; //set default
  389. return false;
  390. }
  391. //Load fuel burn rate MP
  392. if (!ctx.Read(m_FuelBurnRateMP))
  393. {
  394. m_FuelBurnRateMP = 1.0; //set default
  395. return false;
  396. }
  397. //Load burning state, if true start fire
  398. if (!ctx.Read(m_IsBurning))
  399. {
  400. m_IsBurning = false; //set default
  401. return false;
  402. }
  403. //---
  404. return true;
  405. }
  406. override void AfterStoreLoad()
  407. {
  408. super.AfterStoreLoad();
  409. Synchronize();
  410. //start fire
  411. if (IsBurning())
  412. {
  413. if (GetGame() && GetGame().IsServer())
  414. {
  415. StartFire(true); //will be auto-synchronized when starting fire
  416. }
  417. }
  418. }
  419. //================================================================
  420. // SYNCHRONIZATION
  421. //================================================================
  422. void Synchronize()
  423. {
  424. if (GetGame() && GetGame().IsServer())
  425. {
  426. SetSynchDirty();
  427. if (GetGame().IsMultiplayer() && GetGame().IsServer())
  428. {
  429. //Refresh visuals (on server)
  430. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(RefreshFireplaceVisuals);
  431. }
  432. }
  433. }
  434. override void OnVariablesSynchronized()
  435. {
  436. super.OnVariablesSynchronized();
  437. RefreshFireplaceVisuals();
  438. RefreshFireParticlesAndSounds(false);
  439. if (IsPlaceSound())
  440. {
  441. PlayPlaceSound();
  442. }
  443. if (IsBaseFireplace() && !IsOven())
  444. {
  445. if (m_IsBurning && !m_AreaDamage)
  446. {
  447. CreateAreaDamage();
  448. }
  449. else if (!m_IsBurning && m_AreaDamage)
  450. {
  451. DestroyAreaDamage();
  452. }
  453. }
  454. if (m_ThawnSurfaceUnderSupport && m_UnderObjectDecalSpawnComponent)
  455. m_UnderObjectDecalSpawnComponent.UpdateSize(Math.InverseLerp(0.0, GetTemperatureMax() * 0.6, GetTemperature()));
  456. }
  457. //================================================================
  458. // BASE
  459. //================================================================
  460. //States
  461. //check fireplace types
  462. override bool IsFireplace()
  463. {
  464. return true;
  465. }
  466. bool IsBaseFireplace()
  467. {
  468. return false;
  469. }
  470. bool IsBarrelWithHoles()
  471. {
  472. return false;
  473. }
  474. bool IsFireplaceIndoor()
  475. {
  476. return false;
  477. }
  478. bool IsIndoorOven()
  479. {
  480. return false;
  481. }
  482. override bool CanHaveWetness()
  483. {
  484. return true;
  485. }
  486. override bool CanHaveTemperature()
  487. {
  488. return true;
  489. }
  490. override bool GetCookingTargetTemperature(out float temperature)
  491. {
  492. temperature = GetTemperature();
  493. return true;
  494. }
  495. override bool IsSelfAdjustingTemperature()
  496. {
  497. return m_IsBurning || (m_CoolingTimer && m_CoolingTimer.IsRunning())); //FireplaceFireState.NO_FIRE?
  498. }
  499. protected void InitializeTemperatureSources()
  500. {
  501. m_UTSLFireplace = new UniversalTemperatureSourceLambdaFireplace();
  502. m_UTSLFireplace.SetSmallFireplaceTemperatureMax(PARAM_SMALL_FIRE_TEMPERATURE);
  503. m_UTSLFireplace.SetNormalFireplaceTemperatureMax(PARAM_NORMAL_FIRE_TEMPERATURE);
  504. m_UTSource = new UniversalTemperatureSource(this, m_UTSSettings, m_UTSLFireplace);
  505. }
  506. //cooking equipment
  507. ItemBase GetCookingEquipment()
  508. {
  509. return m_CookingEquipment;
  510. }
  511. void SetCookingEquipment(ItemBase equipment)
  512. {
  513. m_CookingEquipment = equipment;
  514. }
  515. void ClearCookingEquipment(ItemBase pItem)
  516. {
  517. if (m_CookingProcess)
  518. {
  519. m_CookingProcess.TerminateCookingSounds(pItem);
  520. }
  521. SetCookingEquipment(null);
  522. }
  523. //! DEPRECATED
  524. void ClearCookingEquipment()
  525. {
  526. SetCookingEquipment(null);
  527. }
  528. bool DirectCookingSlotsInUse()
  529. {
  530. for (int i = 0; i < DIRECT_COOKING_SLOT_COUNT; i++)
  531. {
  532. if (m_DirectCookingSlots[i])
  533. {
  534. return true;
  535. }
  536. }
  537. return false;
  538. }
  539. bool SmokingSlotsInUse()
  540. {
  541. for (int i = 0; i < SMOKING_SLOT_COUNT; i++)
  542. {
  543. if (m_SmokingSlots[i])
  544. {
  545. return true;
  546. }
  547. }
  548. return false;
  549. }
  550. //! [DEPRECATED]
  551. void DestroyFireplace()
  552. {
  553. DeleteSafe();
  554. }
  555. override bool IsPrepareToDelete()
  556. {
  557. return IsEmpty() && !IsBurning() && !HasAshes();
  558. }
  559. override void OnChildItemRemoved(InventoryItem item)
  560. {
  561. super.OnChildItemRemoved(item);
  562. CheckForDestroy();
  563. }
  564. override void CheckForDestroy()
  565. {
  566. if (IsPrepareToDelete())
  567. {
  568. MiscGameplayFunctions.DropAllItemsInInventoryInBounds(this, m_HalfExtents);
  569. super.CheckForDestroy();
  570. }
  571. }
  572. //================================================================
  573. // VISUAL
  574. //================================================================
  575. //Fireplace visual
  576. void RefreshFireplaceVisuals()
  577. {
  578. if (IsHologram())
  579. {
  580. return;
  581. }
  582. // Light
  583. #ifndef SERVER
  584. if (IsBurning())
  585. {
  586. //turn light on
  587. if (!GetLightEntity())
  588. {
  589. SetLightEntity(FireplaceLight.Cast(ScriptedLightBase.CreateLight(FireplaceLight, GetPosition(), 20)));
  590. GetLightEntity().AttachOnMemoryPoint(this, "light");
  591. }
  592. if (GetLightEntity() && GetLightEntity().GetBrightness() > 0)
  593. {
  594. // change brightness based on the distance of player to the fireplace
  595. Object player = GetGame().GetPlayer();
  596. float lightDist = m_LightDistance;
  597. if (IsOven())
  598. {
  599. lightDist = 50;
  600. }
  601. if (player)
  602. {
  603. if (vector.DistanceSq(player.GetPosition(), this.GetPosition()) > lightDist * lightDist)
  604. {
  605. GetLightEntity().FadeBrightnessTo(0, 5);
  606. }
  607. else
  608. {
  609. GetLightEntity().FadeBrightnessTo(FireplaceLight.m_FireplaceBrightness, 5);
  610. }
  611. }
  612. // The following solves an issue with the light point clipping through narrow geometry
  613. if (IsItemTypeAttached(ATTACHMENT_STONES) || IsBarrelWithHoles() || IsFireplaceIndoor())
  614. {
  615. GetLightEntity().SetInteriorMode();
  616. }
  617. else
  618. {
  619. GetLightEntity().SetExteriorMode();
  620. }
  621. }
  622. }
  623. else
  624. {
  625. //turn light off
  626. if (GetLightEntity())
  627. {
  628. GetLightEntity().FadeOut();
  629. }
  630. }
  631. #endif
  632. //set default burn parameters based on fireplace type
  633. if (IsBarrelWithHoles() || IsFireplaceIndoor() || IsIndoorOven() || IsOven())
  634. {
  635. SetFuelBurnRateMP(FUEL_BURN_RATE_OVEN);
  636. }
  637. else if (HasStoneCircle())
  638. {
  639. SetFuelBurnRateMP(FUEL_BURN_RATE_STONES);
  640. }
  641. else
  642. {
  643. SetFuelBurnRateMP(FUEL_BURN_RATE_DEFAULT);
  644. }
  645. // Oven attachments
  646. if (IsOven())
  647. {
  648. //lock attachment slots
  649. if (!m_OvenAttachmentsLockState)
  650. {
  651. LockOvenAttachments(true);
  652. }
  653. }
  654. else
  655. {
  656. //unlock attachment slots
  657. if (m_OvenAttachmentsLockState)
  658. {
  659. LockOvenAttachments(false);
  660. }
  661. }
  662. //VISUAL STATES
  663. //Fuel state
  664. if (GetGame().IsServer())
  665. {
  666. // Sticks state
  667. if (IsItemTypeAttached(ATTACHMENT_STICKS))
  668. SetAnimationPhase(ANIMATION_STICKS, 0);
  669. else
  670. SetAnimationPhase(ANIMATION_STICKS, 1);
  671. // Firewood state
  672. if (IsItemTypeAttached(ATTACHMENT_FIREWOOD))
  673. {
  674. if (IsBurning() && HasAshes())
  675. {
  676. SetAnimationPhase(ANIMATION_BURNT_WOOD, 0); // Because this might not be set under certain circumstances
  677. SetAnimationPhase(ANIMATION_WOOD, 1);
  678. }
  679. else if (IsWet() || !IsBurning())
  680. {
  681. SetAnimationPhase(ANIMATION_BURNT_WOOD, 1);
  682. SetAnimationPhase(ANIMATION_WOOD, 0);
  683. }
  684. else
  685. {
  686. SetAnimationPhase(ANIMATION_BURNT_WOOD, 1);
  687. SetAnimationPhase(ANIMATION_WOOD, 0);
  688. }
  689. }
  690. else
  691. {
  692. SetAnimationPhase(ANIMATION_WOOD, 1);
  693. SetAnimationPhase(ANIMATION_BURNT_WOOD, 1);
  694. }
  695. // Kindling state
  696. if (GetKindlingCount() != 0)
  697. SetAnimationPhase(ANIMATION_KINDLING, 0);
  698. else
  699. SetAnimationPhase(ANIMATION_KINDLING, 1);
  700. // Ashes state
  701. if (HasAshes())
  702. SetAnimationPhase(ANIMATION_ASHES, 0);
  703. else
  704. SetAnimationPhase(ANIMATION_ASHES, 1);
  705. // Stone variations
  706. if (HasStones())
  707. {
  708. if (HasStoneCircle())
  709. {
  710. SetAnimationPhase(ANIMATION_STONES, 0);
  711. SetAnimationPhase(ANIMATION_STONE, 1);
  712. }
  713. else if (IsOven())
  714. {
  715. SetAnimationPhase(ANIMATION_OVEN, 0);
  716. SetAnimationPhase(ANIMATION_STONE, 1);
  717. }
  718. else
  719. {
  720. //! single stone; everything else hidden
  721. SetAnimationPhase(ANIMATION_STONES, 1);
  722. SetAnimationPhase(ANIMATION_OVEN, 1);
  723. SetAnimationPhase(ANIMATION_STONE, 0);
  724. }
  725. }
  726. else
  727. {
  728. SetAnimationPhase(ANIMATION_STONE, 1); //! hide stones stack completely
  729. }
  730. }
  731. //refresh physics (with delay)
  732. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(RefreshFireplacePhysics);
  733. }
  734. //! DEPRECATED
  735. protected void SetBurntFirewood()
  736. {
  737. if (GetGame().IsServer() && IsInAnimPhase(ANIMATION_WOOD))
  738. {
  739. SetAnimationPhase(ANIMATION_WOOD, 1);
  740. SetAnimationPhase(ANIMATION_BURNT_WOOD, 0);
  741. }
  742. }
  743. //Refresh fireplace object physics
  744. void RefreshFireplacePhysics();
  745. protected void RefreshFireParticlesAndSounds(bool force_refresh)
  746. {
  747. FireplaceFireState fire_state = GetFireState();
  748. if (m_LastFireState != fire_state || force_refresh)
  749. {
  750. switch (fire_state)
  751. {
  752. case FireplaceFireState.START_FIRE:
  753. {
  754. //particles
  755. ParticleFireStartStart();
  756. //sounds
  757. SoundFireStop();
  758. SoundFireLightStart();
  759. break;
  760. }
  761. case FireplaceFireState.SMALL_FIRE:
  762. {
  763. //particles
  764. ParticleFireStartStop();
  765. ParticleSmallFireStart();
  766. if (CanShowSmoke())
  767. ParticleSmallSmokeStart();
  768. else
  769. ParticleSmallSmokeStop();
  770. ParticleNormalFireStop();
  771. ParticleNormalSmokeStop();
  772. ParticleSteamExtinguishingStop();
  773. //sounds
  774. SoundFireStop();
  775. SoundFireLightStart();
  776. break;
  777. }
  778. case FireplaceFireState.NORMAL_FIRE:
  779. {
  780. //particles
  781. ParticleFireStartStop();
  782. ParticleSmallFireStop();
  783. ParticleSmallSmokeStop();
  784. ParticleNormalFireStart();
  785. if (CanShowSmoke())
  786. ParticleNormalSmokeStart();
  787. else
  788. ParticleNormalSmokeStop();
  789. ParticleSteamExtinguishingStop();
  790. //sounds
  791. SoundFireStop();
  792. SoundFireHeavyStart();
  793. break;
  794. }
  795. case FireplaceFireState.END_FIRE:
  796. {
  797. //particles
  798. ParticleFireStartStop();
  799. ParticleSmallFireStop();
  800. ParticleSmallSmokeStop();
  801. ParticleNormalFireStop();
  802. ParticleNormalSmokeStop();
  803. ParticleFireEndStart();
  804. //sounds
  805. SoundFireStop();
  806. SoundFireNoFireStart();
  807. break;
  808. }
  809. case FireplaceFireState.EXTINGUISHING_FIRE: //TODO add steam particles when extinguishing
  810. {
  811. //particles
  812. ParticleFireStartStop();
  813. ParticleSmallFireStop();
  814. ParticleSmallSmokeStop();
  815. ParticleNormalFireStop();
  816. ParticleNormalSmokeStop();
  817. ParticleFireEndStop();
  818. ParticleSteamExtinguishingStart();
  819. //sounds
  820. SoundFireStop();
  821. SoundFireExtinguishingStart();
  822. break;
  823. }
  824. case FireplaceFireState.EXTINGUISHED_FIRE: //TODO add steam particles when fireplace is extinguished
  825. {
  826. //particles
  827. ParticleFireStartStop();
  828. ParticleSmallFireStop();
  829. ParticleSmallSmokeStop();
  830. ParticleNormalFireStop();
  831. ParticleNormalSmokeStop();
  832. ParticleFireEndStop();
  833. ParticleSteamExtinguishingStop();
  834. if (CanShowSmoke())
  835. ParticleSteamEndStart();
  836. else
  837. ParticleSteamEndStop();
  838. //sounds
  839. SoundFireStop();
  840. SoundFireExtinguishedStart();
  841. SoundFireNoFireStart();
  842. break;
  843. }
  844. case FireplaceFireState.REIGNITED_FIRE:
  845. {
  846. //particles
  847. ParticleFireStartStart();
  848. ParticleSmallFireStop();
  849. ParticleSmallSmokeStop();
  850. ParticleNormalFireStop();
  851. ParticleNormalSmokeStop();
  852. ParticleFireEndStop();
  853. ParticleSteamEndStop();
  854. //sounds
  855. SoundFireStop();
  856. break;
  857. }
  858. case FireplaceFireState.NO_FIRE:
  859. {
  860. //particles
  861. ParticleFireStartStop();
  862. ParticleSmallFireStop();
  863. ParticleSmallSmokeStop();
  864. ParticleNormalFireStop();
  865. ParticleNormalSmokeStop();
  866. ParticleFireEndStop();
  867. ParticleSteamEndStop();
  868. ParticleSteamExtinguishingStop();
  869. //sounds
  870. SoundFireStop();
  871. break;
  872. }
  873. }
  874. m_LastFireState = fire_state;
  875. }
  876. }
  877. protected void StopAllParticlesAndSounds()
  878. {
  879. // go through all fireplace particles
  880. if (m_ParticleFireStart)
  881. StopParticle(m_ParticleFireStart);
  882. if (m_ParticleSmallFire)
  883. StopParticle(m_ParticleSmallFire);
  884. if (m_ParticleNormalFire)
  885. StopParticle(m_ParticleNormalFire);
  886. if (m_ParticleSmallSmoke)
  887. StopParticle(m_ParticleSmallSmoke);
  888. if (m_ParticleNormalSmoke)
  889. StopParticle(m_ParticleNormalSmoke);
  890. if (m_ParticleFireEnd)
  891. StopParticle(m_ParticleFireEnd);
  892. if (m_ParticleSteamEnd)
  893. StopParticle(m_ParticleSteamEnd);
  894. if (m_ParticleSteamExtinguishing)
  895. StopParticle(m_ParticleSteamExtinguishing);
  896. // go through all fireplace sounds
  897. if (m_SoundFireLoop)
  898. StopSoundSet(m_SoundFireLoop);
  899. if (m_SoundFire)
  900. StopSoundSet(m_SoundFire);
  901. }
  902. bool CanShowSmoke()
  903. {
  904. return true;
  905. }
  906. //Fireplace fire intensity
  907. void RefreshFireState()
  908. {
  909. float temperature = GetTemperature();
  910. //if it's burning
  911. if (IsBurning())
  912. {
  913. //Start fire
  914. if (temperature <= PARAM_MIN_FIRE_TEMPERATURE)
  915. {
  916. if (GetFireState() != FireplaceFireState.START_FIRE)
  917. {
  918. SetFireState(FireplaceFireState.START_FIRE);
  919. }
  920. }
  921. //Small fire
  922. else if (temperature <= PARAM_SMALL_FIRE_TEMPERATURE)
  923. {
  924. if (GetFireState() != FireplaceFireState.SMALL_FIRE)
  925. {
  926. SetFireState(FireplaceFireState.SMALL_FIRE);
  927. }
  928. }
  929. //Normal fire
  930. else if (temperature > PARAM_SMALL_FIRE_TEMPERATURE)
  931. {
  932. if (GetFireState() != FireplaceFireState.NORMAL_FIRE)
  933. {
  934. SetFireState(FireplaceFireState.NORMAL_FIRE);
  935. }
  936. }
  937. }
  938. }
  939. //================================================================
  940. // PARTICLES & SOUNDS
  941. //================================================================
  942. //returns true if particle started, false if not
  943. protected bool PlayParticle(out Particle particle, int particle_type, vector pos, bool worldpos = false)
  944. {
  945. if (!particle && GetGame() && (!GetGame().IsDedicatedServer()))
  946. {
  947. if (!worldpos)
  948. {
  949. particle = ParticleManager.GetInstance().PlayOnObject(particle_type, this, pos);
  950. }
  951. else
  952. {
  953. particle = ParticleManager.GetInstance().PlayInWorld(particle_type, pos);
  954. }
  955. return true;
  956. }
  957. return false;
  958. }
  959. //returns true if particle stopped, false if not
  960. protected bool StopParticle(out Particle particle)
  961. {
  962. if (particle && GetGame() && (!GetGame().IsDedicatedServer()))
  963. {
  964. particle.Stop();
  965. particle = NULL;
  966. return true;
  967. }
  968. return false;
  969. }
  970. //start fire
  971. protected void ParticleFireStartStart()
  972. {
  973. if (IsOven())
  974. {
  975. PlayParticle(m_ParticleFireStart, PARTICLE_OVEN_FIRE_START, GetFireEffectPosition());
  976. }
  977. else
  978. {
  979. PlayParticle(m_ParticleFireStart, PARTICLE_FIRE_START, GetFireEffectPosition());
  980. }
  981. }
  982. protected void ParticleFireStartStop()
  983. {
  984. StopParticle(m_ParticleFireStart);
  985. }
  986. //small fire
  987. protected void ParticleSmallFireStart()
  988. {
  989. if (IsOven())
  990. {
  991. PlayParticle(m_ParticleSmallFire, PARTICLE_OVEN_FIRE, GetFireEffectPosition());
  992. }
  993. else
  994. {
  995. PlayParticle(m_ParticleSmallFire, PARTICLE_SMALL_FIRE, GetFireEffectPosition());
  996. }
  997. }
  998. protected void ParticleSmallFireStop()
  999. {
  1000. StopParticle(m_ParticleSmallFire);
  1001. }
  1002. //normal fire
  1003. protected void ParticleNormalFireStart()
  1004. {
  1005. if (IsOven())
  1006. {
  1007. PlayParticle(m_ParticleNormalFire, PARTICLE_OVEN_FIRE, GetFireEffectPosition());
  1008. }
  1009. else
  1010. {
  1011. PlayParticle(m_ParticleNormalFire, PARTICLE_NORMAL_FIRE, GetFireEffectPosition());
  1012. }
  1013. }
  1014. protected void ParticleNormalFireStop()
  1015. {
  1016. StopParticle(m_ParticleNormalFire);
  1017. }
  1018. //small smoke
  1019. protected void ParticleSmallSmokeStart()
  1020. {
  1021. PlayParticle(m_ParticleSmallSmoke, PARTICLE_SMALL_SMOKE, GetSmokeEffectPosition());
  1022. //calculate air resistance
  1023. float actual_height;
  1024. if (GetCeilingHeight(actual_height))
  1025. {
  1026. float air_resistance = GetAirResistanceForSmokeParticles(actual_height);
  1027. //alter smoke height
  1028. m_ParticleSmallSmoke.SetParameter(-1, EmitorParam.AIR_RESISTANCE, air_resistance);
  1029. }
  1030. if (IsRoofAbove() || !IsOpen() || IsOven())
  1031. {
  1032. m_ParticleSmallSmoke.SetParameter(-1, EmitorParam.WIND, false);
  1033. }
  1034. }
  1035. protected void ParticleSmallSmokeStop()
  1036. {
  1037. StopParticle(m_ParticleSmallSmoke);
  1038. }
  1039. //normal smoke
  1040. protected void ParticleNormalSmokeStart()
  1041. {
  1042. PlayParticle(m_ParticleNormalSmoke, PARTICLE_NORMAL_SMOKE, GetSmokeEffectPosition());
  1043. //calculate air resistance
  1044. float actual_height;
  1045. if (GetCeilingHeight(actual_height))
  1046. {
  1047. float air_resistance = GetAirResistanceForSmokeParticles(actual_height);
  1048. //alter smoke height
  1049. m_ParticleNormalSmoke.SetParameter(-1, EmitorParam.AIR_RESISTANCE, air_resistance);
  1050. }
  1051. if (IsRoofAbove() || !IsOpen() || IsOven())
  1052. {
  1053. m_ParticleNormalSmoke.SetParameter(-1, EmitorParam.WIND, false);
  1054. }
  1055. }
  1056. protected void ParticleNormalSmokeStop()
  1057. {
  1058. StopParticle(m_ParticleNormalSmoke);
  1059. }
  1060. //fire end
  1061. protected void ParticleFireEndStart()
  1062. {
  1063. if (IsOven())
  1064. {
  1065. PlayParticle(m_ParticleFireEnd, PARTICLE_OVEN_FIRE_END, GetFireEffectPosition());
  1066. }
  1067. else
  1068. {
  1069. PlayParticle(m_ParticleFireEnd, PARTICLE_FIRE_END, GetFireEffectPosition());
  1070. }
  1071. }
  1072. protected void ParticleFireEndStop()
  1073. {
  1074. StopParticle(m_ParticleFireEnd);
  1075. }
  1076. protected void ParticleFireWindyNoIgniteStart()
  1077. {
  1078. if (IsOven())
  1079. {
  1080. PlayParticle(m_ParticleFireEnd, PARTICLE_OVEN_FIRE_END, GetFireEffectPosition());
  1081. }
  1082. else
  1083. {
  1084. PlayParticle(m_ParticleFireEnd, PARTICLE_NO_IGNITE_WIND, GetFireEffectPosition());
  1085. }
  1086. }
  1087. //steam extinguishing
  1088. protected void ParticleSteamExtinguishingStart()
  1089. {
  1090. PlayParticle(m_ParticleSteamExtinguishing, PARTICLE_STEAM_EXTINGUISHING, GetFireEffectPosition());
  1091. }
  1092. protected void ParticleSteamExtinguishingStop()
  1093. {
  1094. StopParticle(m_ParticleSteamExtinguishing);
  1095. }
  1096. //steam end
  1097. protected void ParticleSteamEndStart()
  1098. {
  1099. PlayParticle(m_ParticleSteamEnd, PARTICLE_STEAM_END, GetFireEffectPosition());
  1100. }
  1101. protected void ParticleSteamEndStop()
  1102. {
  1103. StopParticle(m_ParticleSteamEnd);
  1104. }
  1105. protected void ParticleWetNoIgniteStart()
  1106. {
  1107. PlayParticle(m_ParticleSteamEnd, PARTICLE_STEAM_END, GetFireEffectPosition());
  1108. }
  1109. protected void ParticleWetNoIgniteStop()
  1110. {
  1111. StopParticle(m_ParticleSteamEnd);
  1112. }
  1113. bool GetCeilingHeight(out float actual_height)
  1114. {
  1115. vector from = this.GetPosition();
  1116. vector to = this.GetPosition();
  1117. from[1] = from[1] + 1.0;
  1118. to[1] = to[1] + MIN_CEILING_HEIGHT;
  1119. vector contactPos;
  1120. vector contactDir;
  1121. int contactComponent;
  1122. bool hit = DayZPhysics.RaycastRV(from, to, contactPos, contactDir, contactComponent, NULL, NULL, this);
  1123. actual_height = vector.Distance(from, contactPos) + 1.0;
  1124. return hit;
  1125. }
  1126. float GetAirResistanceForSmokeParticles(float actual_height)
  1127. {
  1128. float air_res;
  1129. actual_height = Math.Clamp(actual_height, 0, 36);
  1130. air_res = (6 - actual_height) * 0.33;
  1131. air_res = Math.Clamp(air_res, 0, 2);
  1132. return air_res;
  1133. }
  1134. //Particle Positions
  1135. //Get local fire and smoke effect position
  1136. protected vector GetFireEffectPosition()
  1137. {
  1138. return Vector(0, 0.05, 0);
  1139. }
  1140. protected vector GetSmokeEffectPosition()
  1141. {
  1142. return Vector(0, 0.05, 0);
  1143. }
  1144. //================================================================
  1145. // SOUNDS
  1146. //================================================================
  1147. //Burning
  1148. //Start
  1149. protected void SoundFireLightStart()
  1150. {
  1151. PlaySoundSetLoop(m_SoundFireLoop, SOUND_FIRE_LIGHT, 1.0, 1.0);
  1152. }
  1153. protected void SoundFireHeavyStart()
  1154. {
  1155. PlaySoundSetLoop(m_SoundFireLoop, SOUND_FIRE_HEAVY, 1.0, 2.0);
  1156. }
  1157. protected void SoundFireNoFireStart()
  1158. {
  1159. PlaySoundSetLoop(m_SoundFireLoop, SOUND_FIRE_NO_FIRE, 2.0, 2.0);
  1160. }
  1161. protected void SoundFireExtinguishedStart()
  1162. {
  1163. PlaySoundSet(m_SoundFire, SOUND_FIRE_EXTINGUISHED, 0.1, 0.1);
  1164. }
  1165. protected void SoundFireWetNoIgniteStart()
  1166. {
  1167. PlaySoundSet(m_SoundFire, SOUND_FIRE_EXTINGUISHED, 0.1, 0.1);
  1168. }
  1169. protected void SoundFireExtinguishingStart()
  1170. {
  1171. PlaySoundSetLoop(m_SoundFireLoop, SOUND_FIRE_EXTINGUISHING, 1.0, 0.5);
  1172. }
  1173. protected void SoundFireWindyNoIgniteStart()
  1174. {
  1175. PlaySoundSet(m_SoundFire, "ExtinguishByWind_SoundSet", 0, 0);
  1176. }
  1177. //Stop
  1178. protected void SoundFireStop()
  1179. {
  1180. StopSoundSet(m_SoundFireLoop);
  1181. }
  1182. //================================================================
  1183. // FUEL / KINDLING
  1184. //================================================================
  1185. //Add to fire consumables
  1186. protected void AddToFireConsumables(ItemBase item)
  1187. {
  1188. m_FireConsumables.Insert(item, new FireConsumable(item, GetFireConsumableTypeEnergy(item)));
  1189. CalcAndSetQuantity();
  1190. }
  1191. protected float GetFireConsumableTypeEnergy(ItemBase item)
  1192. {
  1193. FireConsumableType fireConsumableType = m_FireConsumableTypes.Get(item.Type());
  1194. if (!fireConsumableType)
  1195. {
  1196. //! support for inherited classes; second pass of lookup inside FireConsumableType
  1197. int count = m_FireConsumableTypes.Count();
  1198. for (int i = 0; i < count; ++i)
  1199. {
  1200. if (item.IsInherited(m_FireConsumableTypes.GetKey(i)))
  1201. fireConsumableType = m_FireConsumableTypes.GetElement(i);
  1202. }
  1203. }
  1204. if (fireConsumableType)
  1205. return fireConsumableType.GetEnergy();
  1206. return 0;
  1207. }
  1208. //Remove from fire consumables
  1209. protected void RemoveFromFireConsumables(FireConsumable fire_consumable)
  1210. {
  1211. if (fire_consumable)
  1212. {
  1213. m_FireConsumables.Remove(fire_consumable.GetItem());
  1214. delete fire_consumable;
  1215. }
  1216. CalcAndSetQuantity();
  1217. }
  1218. protected FireConsumable GetFireConsumableByItem(ItemBase item)
  1219. {
  1220. return m_FireConsumables.Get(item);
  1221. }
  1222. //Set fuel / kindling to consume
  1223. //Sets the item with the lowest energy value as item that will be consumed next
  1224. //Returns reference to set fire consumable
  1225. protected FireConsumable SetItemToConsume()
  1226. {
  1227. if (m_FireConsumables.Count() == 0)
  1228. {
  1229. m_ItemToConsume = null;
  1230. }
  1231. else
  1232. {
  1233. for (int i = 0; i < m_FireConsumables.Count(); ++i)
  1234. {
  1235. ItemBase key = m_FireConsumables.GetKey(i);
  1236. FireConsumable fireConsumable = m_FireConsumables.Get(key);
  1237. if (i == 0)
  1238. {
  1239. m_ItemToConsume = fireConsumable;
  1240. }
  1241. else
  1242. {
  1243. if (fireConsumable.GetEnergy() < m_ItemToConsume.GetEnergy())
  1244. {
  1245. m_ItemToConsume = fireConsumable;
  1246. }
  1247. }
  1248. }
  1249. }
  1250. //refresh visual
  1251. RefreshFireplaceVisuals();
  1252. return m_ItemToConsume;
  1253. }
  1254. protected FireConsumable GetItemToConsume()
  1255. {
  1256. return m_ItemToConsume;
  1257. }
  1258. //Spend item that is used as consumable for fire (fuel, kindling)
  1259. //if 'amount == 0', the whole quantity will be consumed (quantity -= 1)
  1260. //debug
  1261. //int m_debug_fire_consume_time = 0;
  1262. protected void SpendFireConsumable(float amount)
  1263. {
  1264. //spend item
  1265. FireConsumable fireConsumable = GetItemToConsume();
  1266. if (!fireConsumable)
  1267. {
  1268. //Set new item to consume
  1269. fireConsumable = SetItemToConsume();
  1270. }
  1271. if (fireConsumable)
  1272. {
  1273. ItemBase item = fireConsumable.GetItem();
  1274. fireConsumable.SetRemainingEnergy(fireConsumable.GetRemainingEnergy() - amount);
  1275. if (fireConsumable.GetRemainingEnergy() <= 0 || amount == 0)
  1276. {
  1277. //set ashes
  1278. if (!HasAshes())
  1279. {
  1280. SetAshesState(true);
  1281. }
  1282. if (item.IsAnyInherited({ItemBook, Paper, GiftWrapPaper, EyeMask_ColorBase}))
  1283. {
  1284. RemoveFromFireConsumables(fireConsumable);
  1285. item.Delete();
  1286. }
  1287. else
  1288. {
  1289. //if there is nothing left, delete and remove old consumable, set new fire consumable
  1290. if (item.GetQuantity() <= 1)
  1291. {
  1292. //remove item from fuel items
  1293. RemoveFromFireConsumables(fireConsumable);
  1294. }
  1295. else
  1296. {
  1297. fireConsumable.SetRemainingEnergy(fireConsumable.GetEnergy());
  1298. }
  1299. item.AddQuantity(-1);
  1300. SetItemToConsume();
  1301. }
  1302. }
  1303. }
  1304. CalcAndSetQuantity();
  1305. }
  1306. //! Returns count of all kindling type items (define in 'm_KindlingTypes') attached to fireplace
  1307. protected int GetKindlingCount()
  1308. {
  1309. int attachmentsCount = GetInventory().AttachmentCount();
  1310. int kindlingCount = 0;
  1311. for (int i = 0; i < attachmentsCount; ++i)
  1312. {
  1313. ItemBase item = ItemBase.Cast(GetInventory().GetAttachmentFromIndex(i));
  1314. if (IsKindling(item))
  1315. kindlingCount++;
  1316. }
  1317. return kindlingCount;
  1318. }
  1319. //! Returns count of all fuel type items (define in 'm_FuelTypes') attached to fireplace
  1320. protected int GetFuelCount()
  1321. {
  1322. int attachmentsCount = GetInventory().AttachmentCount();
  1323. int fuelCount = 0;
  1324. for (int i = 0; i < attachmentsCount; ++i)
  1325. {
  1326. ItemBase item = ItemBase.Cast(GetInventory().GetAttachmentFromIndex(i));
  1327. if (IsFuel(item))
  1328. fuelCount++;
  1329. }
  1330. return fuelCount;
  1331. }
  1332. //! Returns if item attached to fireplace is kindling
  1333. protected bool IsKindling(ItemBase item)
  1334. {
  1335. FireConsumableType fireConsumableType = m_FireConsumableTypes.Get(item.Type());
  1336. if (!fireConsumableType)
  1337. {
  1338. //! support for inherited classes; second pass of lookup inside FireConsumableType
  1339. int count = m_FireConsumableTypes.Count();
  1340. for (int i = 0; i < count; ++i)
  1341. {
  1342. if (item.IsInherited(m_FireConsumableTypes.GetKey(i)))
  1343. fireConsumableType = m_FireConsumableTypes.GetElement(i);
  1344. }
  1345. }
  1346. return fireConsumableType && fireConsumableType.IsKindling();
  1347. }
  1348. //! Returns if item attached to fireplace is fuel
  1349. protected bool IsFuel(ItemBase item)
  1350. {
  1351. FireConsumableType fireConsumableType = m_FireConsumableTypes.Get(item.Type());
  1352. if (!fireConsumableType)
  1353. {
  1354. //! support for inherited classes; second pass of lookup inside FireConsumableType
  1355. int count = m_FireConsumableTypes.Count();
  1356. for (int i = 0; i < count; ++i)
  1357. {
  1358. if (item.IsInherited(m_FireConsumableTypes.GetKey(i)))
  1359. fireConsumableType = m_FireConsumableTypes.GetElement(i);
  1360. }
  1361. }
  1362. return fireConsumableType && !fireConsumableType.IsKindling();
  1363. }
  1364. //Has attachments of given type
  1365. bool IsItemTypeAttached(typename item_type)
  1366. {
  1367. return GetAttachmentByType(item_type) != null;
  1368. }
  1369. //Has attachments of required quantity
  1370. bool IsItemAttachedQuantity(typename item_type, float quantity)
  1371. {
  1372. ItemBase item = ItemBase.Cast(GetAttachmentByType(item_type));
  1373. return item.GetQuantity() >= quantity;
  1374. }
  1375. //Has last attached item
  1376. bool HasLastAttachment()
  1377. {
  1378. return GetInventory().AttachmentCount() == 1;
  1379. }
  1380. //Has last fuel/kindling attached
  1381. bool HasLastFuelKindlingAttached()
  1382. {
  1383. return (GetFuelCount() + GetKindlingCount()) == 1;
  1384. }
  1385. //================================================================
  1386. // FIRE STATE
  1387. //================================================================
  1388. //Is fireplace burning?
  1389. bool IsBurning()
  1390. {
  1391. return m_IsBurning;
  1392. }
  1393. //Set burning state
  1394. protected void SetBurningState(bool is_burning)
  1395. {
  1396. m_IsBurning = is_burning;
  1397. }
  1398. //Are ashes present in fireplace?
  1399. bool HasAshes()
  1400. {
  1401. return m_HasAshes;
  1402. }
  1403. //Set ashes state
  1404. protected void SetAshesState(bool has_ashes)
  1405. {
  1406. m_HasAshes = has_ashes;
  1407. }
  1408. //Is in oven state
  1409. bool IsOven()
  1410. {
  1411. return m_IsOven;
  1412. }
  1413. bool HasStoneCircle()
  1414. {
  1415. return m_HasStoneCircle;
  1416. }
  1417. bool HasStones()
  1418. {
  1419. EntityAI attached_item = GetAttachmentByType(ATTACHMENT_STONES);
  1420. return attached_item && attached_item.GetQuantity() > 0;
  1421. }
  1422. int GetAttachedStonesCount()
  1423. {
  1424. if (HasStones())
  1425. {
  1426. return GetAttachmentByType(ATTACHMENT_STONES).GetQuantity();
  1427. }
  1428. return 0;
  1429. }
  1430. void SetOvenState(bool is_oven)
  1431. {
  1432. if (m_IsOven != is_oven)
  1433. {
  1434. m_IsOven = is_oven;
  1435. GetInventory().SetSlotLock(InventorySlots.GetSlotIdFromString("Stones") , is_oven);
  1436. Synchronize();
  1437. }
  1438. }
  1439. void SetStoneCircleState(bool has_stonecircle)
  1440. {
  1441. if (m_HasStoneCircle != has_stonecircle)
  1442. {
  1443. m_HasStoneCircle = has_stonecircle;
  1444. GetInventory().SetSlotLock(InventorySlots.GetSlotIdFromString("Stones") , has_stonecircle);
  1445. Synchronize();
  1446. }
  1447. }
  1448. //Fuel burn rate MP
  1449. protected float GetFuelBurnRateMP()
  1450. {
  1451. return m_FuelBurnRateMP;
  1452. }
  1453. protected void SetFuelBurnRateMP(float value)
  1454. {
  1455. m_FuelBurnRateMP = value;
  1456. }
  1457. //Get fire state
  1458. protected int GetFireState()
  1459. {
  1460. return m_FireState;
  1461. }
  1462. //Sets fire state
  1463. protected void SetFireState(FireplaceFireState state)
  1464. {
  1465. if (m_FireState != state)
  1466. {
  1467. m_FireState = state;
  1468. Synchronize();
  1469. }
  1470. }
  1471. void SetExtinguishingState()
  1472. {
  1473. SetFireState(FireplaceFireState.EXTINGUISHING_FIRE);
  1474. }
  1475. //================================================================
  1476. // FIRE PROCESS
  1477. //================================================================
  1478. //Start the fire process
  1479. // 1. start heating
  1480. // 2. heating
  1481. // 3. stop heating
  1482. void StartFire(bool force_start = false)
  1483. {
  1484. //stop cooling process if active
  1485. if (m_CoolingTimer)
  1486. {
  1487. m_CoolingTimer.Stop();
  1488. m_CoolingTimer = null;
  1489. }
  1490. //start fire
  1491. if (!IsBurning() || force_start)
  1492. {
  1493. //roof check
  1494. CheckForRoofLimited(0);
  1495. SetItemToConsume();
  1496. SetBurningState(true);
  1497. StartHeating();
  1498. //Update navmesh
  1499. if (!IsFireplaceIndoor())
  1500. {
  1501. SetAffectPathgraph(false, true);
  1502. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(GetGame().UpdatePathgraphRegionByObject, 100, false, this);
  1503. }
  1504. }
  1505. Synchronize();
  1506. }
  1507. //Start heating
  1508. protected void StartHeating()
  1509. {
  1510. //visual
  1511. SetObjectMaterial(0, MATERIAL_FIREPLACE_GLOW);
  1512. if (IsWindy() && !IsRoofAbove() && IsOpen() && !IsOven() && !IsBarrelWithHoles())
  1513. {
  1514. StopFire();
  1515. return;
  1516. }
  1517. if (GetWet() > PARAM_BURN_WET_THRESHOLD)
  1518. {
  1519. StopFire(FireplaceFireState.EXTINGUISHED_FIRE);
  1520. return;
  1521. }
  1522. //create area damage
  1523. if (IsBaseFireplace() && !IsOven())
  1524. CreateAreaDamage();
  1525. m_HeatingTimer = new Timer(CALL_CATEGORY_GAMEPLAY);
  1526. m_HeatingTimer.Run(TIMER_HEATING_UPDATE_INTERVAL, this, "Heating", null, true);
  1527. m_CookingProcess.SetCookingUpdateTime(TIMER_HEATING_UPDATE_INTERVAL);
  1528. //Setup the noise parameters on fire start
  1529. m_NoisePar = new NoiseParams();
  1530. if (IsRoofAbove() || IsOven() || IsFireplaceIndoor()) //If we have a roof, we are probably inside
  1531. m_NoisePar.LoadFromPath("CfgVehicles FireplaceBase NoiseFireplaceSpecial");
  1532. else
  1533. m_NoisePar.LoadFromPath("CfgVehicles FireplaceBase NoiseFireplaceBase");
  1534. }
  1535. //Do heating
  1536. protected void Heating()
  1537. {
  1538. float temperature;
  1539. float temperatureModifier = 0;
  1540. if (IsOpen() && !IsOven())
  1541. CheckForRoofLimited(1000 * TIMER_HEATING_UPDATE_INTERVAL * 5);
  1542. //check burning conditions
  1543. if (GetWet() > PARAM_BURN_WET_THRESHOLD)
  1544. {
  1545. StopFire(FireplaceFireState.EXTINGUISHED_FIRE);
  1546. return;
  1547. }
  1548. else
  1549. {
  1550. if (m_FireConsumables.Count() == 0)
  1551. {
  1552. StopFire();
  1553. return;
  1554. }
  1555. }
  1556. //spend actual fire consumable
  1557. float amount = PARAM_FIRE_CONSUM_RATE_AMOUNT * GetFuelBurnRateMP() * TIMER_HEATING_UPDATE_INTERVAL;
  1558. SpendFireConsumable(amount);
  1559. //set wetness and alter temperature modifier (which will lower temperature increase because of soaking)
  1560. float rain = GetGame().GetWeather().GetRain().GetActual();
  1561. float combinedWindAndSnowfall = MiscGameplayFunctions.GetCombinedSnowfallWindValue();
  1562. if ((rain >= RAIN_EFFECT_LIMIT || combinedWindAndSnowfall >= SNOWFALL_EFFECT_LIMIT) && !IsRoofAbove() && IsOpen() && !IsOven())
  1563. {
  1564. if (rain > combinedWindAndSnowfall)
  1565. {
  1566. AddWetnessToFireplace(RAIN_WETNESS_INCREASE * rain);
  1567. temperatureModifier = PARAM_TEMPERATURE_DECREASE * rain;
  1568. }
  1569. else
  1570. {
  1571. AddWetnessToFireplace(SNOWFALL_WETNESS_INCREASE * combinedWindAndSnowfall);
  1572. temperatureModifier = PARAM_TEMPERATURE_DECREASE * combinedWindAndSnowfall;
  1573. }
  1574. }
  1575. //subtract wetness when heating and not raining above
  1576. else
  1577. {
  1578. AddWetnessToFireplace(-PARAM_WET_HEATING_DECREASE_COEF);
  1579. }
  1580. if (m_SurfaceUnderWetnessModifier > 0.0)
  1581. AddWetnessToFireplace(m_SurfaceUnderWetnessModifier * WET_SURFACE_INCREMENT);
  1582. // FLAT temperature increase
  1583. temperature = GetTemperature() + (PARAM_TEMPERATURE_INCREASE * TIMER_HEATING_UPDATE_INTERVAL) - temperatureModifier;
  1584. temperature = Math.Clamp(temperature, g_Game.GetMission().GetWorldData().GetBaseEnvTemperatureAtObject(this), m_UTSLFireplace.m_NormalFireplaceTemperatureMax);
  1585. SetTemperatureDirect(temperature); //direct heating (non-systematic approach), freezing, overheating, and other stuff inside 'SetTemperatureEx' are therefore UNHANDLED here!
  1586. m_UTSLFireplace.SetFuelCount(GetFuelCount()); //legacy reasons
  1587. m_UTSLFireplace.SetCurrentTemperature(temperature); //legacy reasons
  1588. m_UTSource.Update(m_UTSSettings, m_UTSLFireplace);
  1589. //get newly changed temperature
  1590. temperature = GetTemperature();
  1591. //check fire state
  1592. if (GetFireState() != FireplaceFireState.EXTINGUISHING_FIRE)
  1593. {
  1594. RefreshFireState();
  1595. }
  1596. //damage cargo items
  1597. BurnItemsInFireplace();
  1598. //manage cooking equipment (this applies only for case of cooking pot on a tripod)
  1599. if (HasCookingStand() && m_CookingEquipment)
  1600. {
  1601. CookWithEquipment();
  1602. }
  1603. float cookingItemTemperature;
  1604. int i;
  1605. // manage cooking on direct cooking slots
  1606. if (DirectCookingSlotsInUse())
  1607. {
  1608. for (i = 0; i < DIRECT_COOKING_SLOT_COUNT; i++)
  1609. {
  1610. if (m_DirectCookingSlots[i])
  1611. {
  1612. cookingItemTemperature = m_DirectCookingSlots[i].GetTemperature();
  1613. CookOnDirectSlot(m_DirectCookingSlots[i], cookingItemTemperature, temperature);
  1614. }
  1615. }
  1616. }
  1617. // manage smoking slots
  1618. if (SmokingSlotsInUse())
  1619. {
  1620. for (i = 0; i < SMOKING_SLOT_COUNT; i++)
  1621. {
  1622. if (m_SmokingSlots[i])
  1623. {
  1624. SmokeOnSmokingSlot(m_SmokingSlots[i], cookingItemTemperature, temperature);
  1625. }
  1626. }
  1627. }
  1628. //Make noise for AI, only at night
  1629. if (GetGame().GetWorld().IsNight() && m_CanNoise)
  1630. {
  1631. NoiseSystem noise = GetGame().GetNoiseSystem();
  1632. if (noise && m_NoisePar)
  1633. {
  1634. noise.AddNoisePos(this, GetPosition(), m_NoisePar, NoiseAIEvaluate.GetNoiseReduction(GetGame().GetWeather()));
  1635. }
  1636. m_CanNoise = false;
  1637. }
  1638. else
  1639. m_CanNoise = true;
  1640. Synchronize();
  1641. }
  1642. //Stop the fire process
  1643. // 1. start cooling
  1644. // 2. cooling
  1645. // 3. stop cooling
  1646. void StopFire(FireplaceFireState fire_state = FireplaceFireState.END_FIRE)
  1647. {
  1648. //roof check
  1649. if (IsBurning())
  1650. CheckForRoofLimited(0);
  1651. StopHeating();
  1652. SpendFireConsumable(0);
  1653. SetBurningState(false);
  1654. StartCooling();
  1655. SetFireState(fire_state);
  1656. //Update navmesh
  1657. if (!IsFireplaceIndoor())
  1658. {
  1659. SetAffectPathgraph(false, false);
  1660. GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(GetGame().UpdatePathgraphRegionByObject, 100, false, this);
  1661. }
  1662. Synchronize();
  1663. }
  1664. protected void StopHeating()
  1665. {
  1666. if (!m_HeatingTimer)
  1667. return;
  1668. m_HeatingTimer.Stop();
  1669. m_HeatingTimer = null;
  1670. }
  1671. protected void StartCooling()
  1672. {
  1673. if (m_HeatingTimer)
  1674. {
  1675. m_HeatingTimer.Stop();
  1676. m_HeatingTimer = null;
  1677. }
  1678. //Start cooling
  1679. m_CoolingTimer = new Timer(CALL_CATEGORY_GAMEPLAY);
  1680. m_CoolingTimer.Run(TIMER_COOLING_UPDATE_INTERVAL, this, "Cooling", null, true);
  1681. m_CookingProcess.SetCookingUpdateTime(TIMER_COOLING_UPDATE_INTERVAL);
  1682. }
  1683. protected void Cooling()
  1684. {
  1685. float temperature = GetTemperature();
  1686. float temperatureModifier = 0;
  1687. if (IsOpen() && !IsOven())
  1688. CheckForRoofLimited(1000 * TIMER_HEATING_UPDATE_INTERVAL * 5);
  1689. if (!IsBurning() && temperature >= 10)
  1690. {
  1691. //set wetness and alter temperature modifier (which will lower temperature increase because of soaking)
  1692. float rain = GetGame().GetWeather().GetRain().GetActual();
  1693. float combinedWindAndSnowfall = MiscGameplayFunctions.GetCombinedSnowfallWindValue();
  1694. if ((rain >= RAIN_EFFECT_LIMIT || combinedWindAndSnowfall >= SNOWFALL_EFFECT_LIMIT) && !IsRoofAbove() && IsOpen() && !IsOven())
  1695. {
  1696. if (rain > combinedWindAndSnowfall)
  1697. {
  1698. AddWetnessToFireplace(RAIN_WETNESS_INCREASE * rain);
  1699. temperatureModifier = PARAM_TEMPERATURE_DECREASE * rain;
  1700. }
  1701. else
  1702. {
  1703. AddWetnessToFireplace(SNOWFALL_WETNESS_INCREASE * combinedWindAndSnowfall);
  1704. temperatureModifier = PARAM_TEMPERATURE_DECREASE * combinedWindAndSnowfall;
  1705. }
  1706. }
  1707. else //subtract wetness
  1708. {
  1709. AddWetnessToFireplace(-PARAM_WET_COOLING_DECREASE_COEF);
  1710. }
  1711. //calculate already obtained wetness (e.g. extinguished by water)
  1712. float wetness = GetWet();
  1713. temperatureModifier = temperatureModifier + (PARAM_TEMPERATURE_DECREASE * wetness);
  1714. // COMBINED temperature decrease
  1715. float target = g_Game.GetMission().GetWorldData().GetBaseEnvTemperatureAtObject(this);
  1716. //FLAT for wetness
  1717. float flatWetTarget = GetTemperature() - temperatureModifier;
  1718. flatWetTarget = Math.Clamp(flatWetTarget,target,GetTemperatureMax());
  1719. SetTemperatureDirect(flatWetTarget);
  1720. //INTERPOLATED for regular cooling
  1721. SetTemperatureEx(new TemperatureDataInterpolated(target,ETemperatureAccessTypes.ACCESS_FIREPLACE,TIMER_COOLING_UPDATE_INTERVAL,GameConstants.TEMP_COEF_FIREPLACE_COOLING));
  1722. m_UTSLFireplace.SetFuelCount(GetFuelCount());
  1723. m_UTSLFireplace.UpdateFireplaceTemperature(m_UTSSettings);
  1724. m_UTSource.Update(m_UTSSettings, m_UTSLFireplace);
  1725. //get newly changed temperature
  1726. temperature = GetTemperature();
  1727. //damage cargo items
  1728. BurnItemsInFireplace();
  1729. //cook with equipment if temperature of equipment is still high
  1730. if (m_CookingEquipment)
  1731. {
  1732. float cookEquipTemp = m_CookingEquipment.GetTemperature();
  1733. if (cookEquipTemp >= PARAM_COOKING_TEMP_THRESHOLD)
  1734. {
  1735. //cook
  1736. CookWithEquipment();
  1737. }
  1738. }
  1739. float cookingItemTemperature;
  1740. int i;
  1741. // manage cooking on direct cooking slots
  1742. if (DirectCookingSlotsInUse())
  1743. {
  1744. for (i = 0; i < DIRECT_COOKING_SLOT_COUNT; i++)
  1745. {
  1746. if (m_DirectCookingSlots[i])
  1747. CookOnDirectSlot(m_DirectCookingSlots[i], cookingItemTemperature, temperature);
  1748. }
  1749. }
  1750. // manage smoking slots
  1751. if (SmokingSlotsInUse())
  1752. {
  1753. for (i = 0; i < SMOKING_SLOT_COUNT; i++)
  1754. {
  1755. if (m_SmokingSlots[i])
  1756. SmokeOnSmokingSlot(m_SmokingSlots[i], cookingItemTemperature, temperature);
  1757. }
  1758. }
  1759. }
  1760. else
  1761. {
  1762. //stop cooling
  1763. if (Math.AbsFloat(temperature) < 10)
  1764. {
  1765. StopCooling();
  1766. }
  1767. }
  1768. }
  1769. protected void StopCooling()
  1770. {
  1771. //stop all fire visuals
  1772. SetFireState(FireplaceFireState.NO_FIRE);
  1773. SetObjectMaterial(0, MATERIAL_FIREPLACE_NOGLOW);
  1774. //Stop cooling
  1775. m_CoolingTimer.Stop();
  1776. m_CoolingTimer = NULL;
  1777. //destroy area damage
  1778. DestroyAreaDamage();
  1779. //remove cookware audio visuals
  1780. if (GetCookingEquipment())
  1781. {
  1782. Bottle_Base cooking_pot = Bottle_Base.Cast(GetCookingEquipment());
  1783. if (cooking_pot)
  1784. cooking_pot.RemoveAudioVisualsOnClient();
  1785. }
  1786. if (DirectCookingSlotsInUse())
  1787. {
  1788. for (int i = 0; i < DIRECT_COOKING_SLOT_COUNT; i++)
  1789. {
  1790. if (m_DirectCookingSlots[i])
  1791. {
  1792. Bottle_Base cookingpot = Bottle_Base.Cast(m_DirectCookingSlots[i]);
  1793. if (cookingpot)
  1794. cookingpot.RemoveAudioVisualsOnClient();
  1795. FryingPan fryingpan = FryingPan.Cast(m_DirectCookingSlots[i]);
  1796. if (fryingpan)
  1797. fryingpan.RemoveAudioVisualsOnClient();
  1798. Edible_Base itsfood = Edible_Base.Cast(m_DirectCookingSlots[i]);
  1799. if (itsfood)
  1800. itsfood.MakeSoundsOnClient(false);
  1801. }
  1802. }
  1803. }
  1804. }
  1805. //================================================================
  1806. // COOKING
  1807. //================================================================
  1808. protected void CookWithEquipment()
  1809. {
  1810. if (m_CookingProcess == null)
  1811. m_CookingProcess = new Cooking();
  1812. m_CookingProcess.CookWithEquipment(m_CookingEquipment);
  1813. }
  1814. Cooking GetCookingProcess()
  1815. {
  1816. if (m_CookingProcess == null)
  1817. m_CookingProcess = new Cooking();
  1818. return m_CookingProcess;
  1819. }
  1820. protected void CookOnDirectSlot(ItemBase slot_item, float temp_equip, float temp_ext)
  1821. {
  1822. if (m_CookingProcess == null)
  1823. m_CookingProcess = new Cooking();
  1824. m_CookingProcess.CookWithEquipment(slot_item);
  1825. }
  1826. protected void SmokeOnSmokingSlot(ItemBase slot_item, float temp_equip, float temp_ext)
  1827. {
  1828. if (m_CookingProcess == NULL)
  1829. m_CookingProcess = new Cooking();
  1830. // smoking slots accept only individual meat/fruit/veg items
  1831. Edible_Base ingr = Edible_Base.Cast(slot_item);
  1832. if (ingr)
  1833. m_CookingProcess.SmokeItem(ingr, FireplaceBase.TIMER_HEATING_UPDATE_INTERVAL * FireplaceBase.SMOKING_SPEED);
  1834. }
  1835. //================================================================
  1836. // FIRE VICINITY
  1837. //================================================================
  1838. //apply damage to all items, raise temperature to only specific items
  1839. protected void BurnItemsInFireplace()
  1840. {
  1841. //! cargo
  1842. CargoBase cargo = GetInventory().GetCargo();
  1843. for (int i = 0; i < cargo.GetItemCount(); i++)
  1844. {
  1845. ItemBase item = ItemBase.Cast(cargo.GetItem(i));
  1846. //add temperature
  1847. AddTemperatureToItemByFire(item);
  1848. //set damage
  1849. AddDamageToItemByFireEx(item, false, false);
  1850. //remove wetness
  1851. AddWetnessToItem(item, -PARAM_WET_HEATING_DECREASE_COEF);
  1852. }
  1853. //! attachments
  1854. for (int j = 0; j < GetInventory().AttachmentCount(); ++j)
  1855. {
  1856. ItemBase attachment = ItemBase.Cast(GetInventory().GetAttachmentFromIndex(j));
  1857. //add temperature
  1858. AddTemperatureToItemByFire(attachment);
  1859. //set damage
  1860. AddDamageToItemByFireEx(attachment, false, true);
  1861. //remove wetness
  1862. AddWetnessToItem(attachment, -PARAM_WET_HEATING_DECREASE_COEF);
  1863. }
  1864. }
  1865. //moves temperature of the item to the fire temperature (can cool down item!)
  1866. protected void AddTemperatureToItemByFire(ItemBase item)
  1867. {
  1868. if (item.CanHaveTemperature())
  1869. {
  1870. float fireplaceTemp = GetTemperature();
  1871. float itemTemp = item.GetTemperature();
  1872. float heatPermCoef = item.GetHeatPermeabilityCoef();
  1873. float tempCoef;
  1874. float deltaTime;
  1875. if (m_HeatingTimer && m_HeatingTimer.IsRunning())
  1876. {
  1877. deltaTime = TIMER_HEATING_UPDATE_INTERVAL;
  1878. tempCoef = GameConstants.TEMP_COEF_FIREPLACE_HEATING;
  1879. }
  1880. else if (m_CoolingTimer && m_CoolingTimer.IsRunning())
  1881. {
  1882. deltaTime = TIMER_COOLING_UPDATE_INTERVAL;
  1883. tempCoef = GameConstants.TEMP_COEF_FIREPLACE_COOLING;
  1884. }
  1885. else
  1886. {
  1887. return;
  1888. }
  1889. item.SetTemperatureEx(new TemperatureDataInterpolated(fireplaceTemp,ETemperatureAccessTypes.ACCESS_FIREPLACE,deltaTime,tempCoef,heatPermCoef));
  1890. }
  1891. }
  1892. //! DEPRECATED
  1893. protected void AddTemperatureToFireplace(float amount) {};
  1894. //add damage to item by fire
  1895. protected void AddDamageToItemByFireEx(ItemBase item, bool can_be_ruined, bool pAttachment)
  1896. {
  1897. if (!item)
  1898. return;
  1899. //! fireplace cargo only (recursive)
  1900. if (!pAttachment)
  1901. {
  1902. //! cargo item attachments
  1903. GameInventory itemInventory = item.GetInventory();
  1904. if (itemInventory)
  1905. {
  1906. array<EntityAI> entities = new array<EntityAI>();
  1907. itemInventory.EnumerateInventory(InventoryTraversalType.INORDER, entities);
  1908. foreach (EntityAI ent : entities)
  1909. {
  1910. if (ent != this)
  1911. {
  1912. ent.DecreaseHealth(PARAM_BURN_DAMAGE_COEF,!ent.IsKindOf("Grenade_Base"));
  1913. }
  1914. }
  1915. }
  1916. }
  1917. else //direct attachments
  1918. {
  1919. float timerCoef = 1.0;
  1920. if (m_HeatingTimer && m_HeatingTimer.IsRunning())
  1921. timerCoef = TIMER_HEATING_UPDATE_INTERVAL;
  1922. else if (m_CoolingTimer && m_CoolingTimer.IsRunning())
  1923. timerCoef = TIMER_COOLING_UPDATE_INTERVAL;
  1924. switch (item.Type())
  1925. {
  1926. case ATTACHMENT_TRIPOD:
  1927. case ATTACHMENT_COOKINGSTAND:
  1928. case ATTACHMENT_COOKING_POT:
  1929. case ATTACHMENT_CAULDRON:
  1930. case ATTACHMENT_FRYING_PAN:
  1931. item.DecreaseHealth(GameConstants.FIRE_ATTACHMENT_DAMAGE_PER_SECOND * timerCoef, false);
  1932. break;
  1933. }
  1934. //! fuel & kindling
  1935. if (IsFuel(item) || IsKindling(item))
  1936. {
  1937. if (item.GetHealthLevel() < GameConstants.STATE_BADLY_DAMAGED)
  1938. item.DecreaseHealth(PARAM_BURN_DAMAGE_COEF, false);
  1939. }
  1940. }
  1941. }
  1942. //add wetness on item
  1943. protected void AddWetnessToItem(ItemBase item, float amount)
  1944. {
  1945. float wetness = item.GetWet();
  1946. wetness = wetness + amount;
  1947. wetness = Math.Clamp(wetness, 0, 1); //wetness <0-1>
  1948. item.SetWet(wetness);
  1949. }
  1950. //add wetness on fireplace
  1951. void AddWetnessToFireplace(float amount)
  1952. {
  1953. //add wetness
  1954. float wetness = GetWet();
  1955. wetness = wetness + amount;
  1956. wetness = Math.Clamp(wetness, 0, 1); //wetness <0-1>
  1957. SetWet(wetness);
  1958. //decrease temperature
  1959. if (amount > 0)
  1960. {
  1961. float temperature = GetTemperature();
  1962. temperature = temperature * (1 - (wetness * 0.5));
  1963. temperature = Math.Clamp(temperature, PARAM_MIN_FIRE_TEMPERATURE, PARAM_NORMAL_FIRE_TEMPERATURE);
  1964. SetTemperatureDirect(temperature);
  1965. m_UTSLFireplace.SetFuelCount(GetFuelCount()); //legacy reasons
  1966. m_UTSLFireplace.SetCurrentTemperature(temperature); //legacy reasons
  1967. }
  1968. }
  1969. //! DEPRECATED
  1970. protected void TransferHeatToNearPlayers() {}
  1971. //Create and Destroy damage radius around the fireplace when starting/stopping burning process
  1972. void CreateAreaDamage()
  1973. {
  1974. //destroy area damage if some already exists
  1975. DestroyAreaDamage();
  1976. //create new area damage
  1977. m_AreaDamage = new AreaDamageLoopedDeferred(this);
  1978. m_AreaDamage.SetDamageComponentType(AreaDamageComponentTypes.HITZONE);
  1979. m_AreaDamage.SetExtents("-0.30 0 -0.30", "0.30 0.75 0.30");
  1980. m_AreaDamage.SetLoopInterval(0.5);
  1981. m_AreaDamage.SetDeferDuration(0.5);
  1982. m_AreaDamage.SetHitZones({ "Head","Torso","LeftHand","LeftLeg","LeftFoot","RightHand","RightLeg","RightFoot" });
  1983. m_AreaDamage.SetAmmoName("FireDamage");
  1984. m_AreaDamage.Spawn();
  1985. }
  1986. void DestroyAreaDamage()
  1987. {
  1988. if (m_AreaDamage)
  1989. {
  1990. m_AreaDamage.Destroy();
  1991. }
  1992. }
  1993. //! DEPRECATED
  1994. bool IsFacingFireplace(PlayerBase player)
  1995. {
  1996. ErrorEx("Deprecated method", ErrorExSeverity.INFO);
  1997. return false;
  1998. }
  1999. //================================================================
  2000. // ACTIONS
  2001. //================================================================
  2002. // --- Actions / Action conditions
  2003. //Check if there is some kindling attached
  2004. bool HasAnyKindling()
  2005. {
  2006. return GetKindlingCount() > 0;
  2007. }
  2008. //Check if the weather is too windy
  2009. static bool IsWindy()
  2010. {
  2011. //check wind
  2012. float wind_speed = GetGame().GetWeather().GetWindSpeed();
  2013. float wind_speed_threshold = GetGame().GetWeather().GetWindMaximumSpeed() * FireplaceBase.IGNITE_WIND_THRESHOLD;
  2014. return (wind_speed >= wind_speed_threshold);
  2015. }
  2016. bool GetIgniteFailure()
  2017. {
  2018. return m_NoIgnite;
  2019. }
  2020. void SetIgniteFailure(bool failure)
  2021. {
  2022. m_NoIgnite = failure;
  2023. }
  2024. //Check if the fireplace is too wet to be ignited
  2025. static bool IsEntityWet(notnull EntityAI entity_ai)
  2026. {
  2027. return (entity_ai.GetWet() >= FireplaceBase.PARAM_MAX_WET_TO_IGNITE);
  2028. }
  2029. bool IsWet()
  2030. {
  2031. return FireplaceBase.IsEntityWet(this);
  2032. }
  2033. //check if fireplace is opened
  2034. override bool IsOpen()
  2035. {
  2036. return true;
  2037. }
  2038. //Check if there is enough space for smoke
  2039. bool IsCeilingHighEnoughForSmoke()
  2040. {
  2041. return !MiscGameplayFunctions.IsUnderRoof(this, FireplaceBase.MIN_CEILING_HEIGHT);
  2042. }
  2043. //Check if it's raining and there is only sky above fireplace
  2044. static bool IsRainingAboveEntity(notnull EntityAI entity_ai)
  2045. {
  2046. return (GetGame() && (GetGame().GetWeather().GetRain().GetActual() >= FireplaceBase.PARAM_IGNITE_RAIN_THRESHOLD));
  2047. }
  2048. bool IsRainingAbove()
  2049. {
  2050. return FireplaceBase.IsRainingAboveEntity(this);
  2051. }
  2052. //Check there is water surface bellow fireplace
  2053. static bool IsEntityOnWaterSurface(notnull EntityAI entity_ai)
  2054. {
  2055. vector fireplacePosition = entity_ai.GetPosition();
  2056. string surfaceType;
  2057. g_Game.SurfaceGetType3D(fireplacePosition[0], fireplacePosition[1] + g_Game.SurfaceGetSeaLevel(), fireplacePosition[2], surfaceType);
  2058. if (!surfaceType)
  2059. {
  2060. float waterLevelDiff = fireplacePosition[1] - g_Game.SurfaceGetSeaLevel();
  2061. return waterLevelDiff < 0.5;
  2062. }
  2063. else if (surfaceType.Contains("water"))
  2064. {
  2065. return true;
  2066. }
  2067. return false;
  2068. }
  2069. protected float GetSurfaceWetnessOnHeatModifier(notnull EntityAI entity)
  2070. {
  2071. string surfaceType
  2072. int liquidType;
  2073. g_Game.SurfaceUnderObjectCorrectedLiquid(entity, surfaceType, liquidType);
  2074. return Surface.GetParamFloat(surfaceType, "wetnessOnHeatModifier");
  2075. }
  2076. bool IsOnWaterSurface()
  2077. {
  2078. return FireplaceBase.IsEntityOnWaterSurface(this);
  2079. }
  2080. //check if the surface is interior
  2081. static bool IsEntityOnInteriorSurface(notnull EntityAI entity_ai)
  2082. {
  2083. string surfaceType;
  2084. vector fireplacePosition = entity_ai.GetPosition();
  2085. GetGame().SurfaceGetType3D(fireplacePosition[0], fireplacePosition[1] + 1.0, fireplacePosition[2], surfaceType);
  2086. return (GetGame().ConfigGetInt("CfgSurfaces " + surfaceType + " interior") == 1);
  2087. }
  2088. bool IsOnInteriorSurface()
  2089. {
  2090. return FireplaceBase.IsEntityOnInteriorSurface(this);
  2091. }
  2092. //Checks if has not additional items in it
  2093. override bool IsEmpty()
  2094. {
  2095. return (GetInventory().GetCargo().GetItemCount() == 0 && GetInventory().AttachmentCount() == 0);
  2096. }
  2097. //Checks if it has no items in cargo
  2098. bool IsCargoEmpty()
  2099. {
  2100. return (GetInventory().GetCargo().GetItemCount() == 0);
  2101. }
  2102. bool HasCookingStand()
  2103. {
  2104. return GetInventory().FindAttachment(InventorySlots.GetSlotIdFromString("CookingTripod")) != null;
  2105. }
  2106. //Check if object is in animation phase
  2107. bool IsInAnimPhase(string anim_phase)
  2108. {
  2109. return GetAnimationPhase(anim_phase) == 0;
  2110. }
  2111. bool IsSpaceFor(vector size)
  2112. {
  2113. array<Object> objs = {};
  2114. if (GetGame().IsBoxCollidingGeometry(GetWorldPosition() + Vector(0, size[1] * 0.5 + 0.1, 0), GetDirection().VectorToAngles(), size, ObjIntersect.View, ObjIntersect.Geom, {this}, objs))
  2115. {
  2116. foreach (Object obj : objs)
  2117. {
  2118. if (dBodyGetInteractionLayer(obj) == PhxInteractionLayers.ITEM_LARGE)
  2119. return false;
  2120. }
  2121. }
  2122. return true;
  2123. }
  2124. override bool CanSwapEntities(EntityAI otherItem, InventoryLocation otherDestination, InventoryLocation destination)
  2125. {
  2126. if (!otherDestination || otherDestination.GetParent() == this)
  2127. {
  2128. return false;
  2129. }
  2130. return true;
  2131. }
  2132. //Action condition for building oven
  2133. bool CanBuildOven()
  2134. {
  2135. return !IsOven() && !IsBurning() && (GetAttachedStonesCount() >= MIN_STONES_TO_BUILD_OVEN) && !FindAttachmentBySlotName("CookingTripod") && !HasStoneCircle() && IsSpaceForOven();
  2136. }
  2137. bool IsSpaceForOven()
  2138. {
  2139. const float size = 0.6;
  2140. return IsSpaceFor(Vector(size, size, size));
  2141. }
  2142. //Action condition for stone circle
  2143. bool CanBuildStoneCircle()
  2144. {
  2145. return !HasStoneCircle() && !IsOven() && !IsBurning() && (GetAttachedStonesCount() >= MIN_STONES_TO_BUILD_CIRCLE) && IsSpaceForCircle();
  2146. }
  2147. bool IsSpaceForCircle()
  2148. {
  2149. return IsSpaceFor(Vector(0.9, 0.1, 0.9));
  2150. }
  2151. //Action condition for dismantling oven
  2152. bool CanDismantleOven()
  2153. {
  2154. return (IsOven() && !IsBurning() && !DirectCookingSlotsInUse() && !SmokingSlotsInUse() && GetTemperature() <= MAX_TEMPERATURE_TO_DISMANTLE_OVEN);
  2155. }
  2156. //Action condition for dismantling stone circle
  2157. bool CanDismantleStoneCircle()
  2158. {
  2159. return (HasStoneCircle() && !IsOven() && !IsBurning());
  2160. }
  2161. bool CanCookOnStick()
  2162. {
  2163. return (GetTemperature() >= PARAM_COOKING_TEMP_THRESHOLD);
  2164. }
  2165. //Can extinguish fire
  2166. bool CanExtinguishFire()
  2167. {
  2168. return IsBurning();
  2169. }
  2170. FireplaceLight GetLightEntity()
  2171. {
  2172. return m_Light;
  2173. }
  2174. void SetLightEntity(FireplaceLight light)
  2175. {
  2176. m_Light = light;
  2177. }
  2178. //================================================================
  2179. // ADVANCED PLACEMENT
  2180. //================================================================
  2181. override void OnPlacementComplete(Man player, vector position = "0 0 0", vector orientation = "0 0 0")
  2182. {
  2183. super.OnPlacementComplete(player, position, orientation);
  2184. if (GetGame().IsServer())
  2185. {
  2186. //remove grass
  2187. Object cc_object = GetGame().CreateObjectEx(OBJECT_CLUTTER_CUTTER , position, ECE_PLACE_ON_SURFACE);
  2188. cc_object.SetOrientation(orientation);
  2189. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(GetGame().ObjectDelete, 1000, false, cc_object);
  2190. SetIsPlaceSound(true);
  2191. }
  2192. }
  2193. override string GetPlaceSoundset()
  2194. {
  2195. return "placeFireplace_SoundSet";
  2196. }
  2197. //================================================================
  2198. // QUANITTY
  2199. //================================================================
  2200. // calculates and sets total energy based on possible (fuel/kinidling) item attachments
  2201. protected void CalcAndSetTotalEnergy()
  2202. {
  2203. if (GetGame() && GetGame().IsServer())
  2204. {
  2205. m_TotalEnergy = 0;
  2206. foreach (FireConsumableType fireConsumableType : m_FireConsumableTypes)
  2207. {
  2208. string quantityConfigPath = string.Format("CfgVehicles %1 varQuantityMax", fireConsumableType.GetItemType().ToString());
  2209. string stackMaxConfigPath = string.Format("CfgSlots Slot_%1 stackMax", fireConsumableType.GetAttSlot());
  2210. if (GetGame().ConfigIsExisting(quantityConfigPath))
  2211. {
  2212. float quantityMax = GetGame().ConfigGetFloat(quantityConfigPath);
  2213. }
  2214. if (GetGame().ConfigIsExisting(stackMaxConfigPath))
  2215. {
  2216. float stackMax = GetGame().ConfigGetFloat(stackMaxConfigPath);
  2217. }
  2218. //debug
  2219. //Print(fireConsumableType.GetItemType().ToString() + " quantityMax = " + quantityMax.ToString() + " [" + (quantity_max*fire_consumable_type.GetEnergy()).ToString() + "] | stack_max = " + stack_max.ToString() + " [" + (stack_max*fire_consumable_type.GetEnergy()).ToString() + "]");
  2220. if (stackMax > 0)
  2221. {
  2222. m_TotalEnergy += stackMax * fireConsumableType.GetEnergy();
  2223. }
  2224. else
  2225. {
  2226. m_TotalEnergy += quantityMax * fireConsumableType.GetEnergy();
  2227. }
  2228. }
  2229. //debug
  2230. //Print("Total energy = " + m_TotalEnergy.ToString());
  2231. }
  2232. }
  2233. // calculates and sets current quantity based on actual (fuel/kinidling) item attachments
  2234. protected void CalcAndSetQuantity()
  2235. {
  2236. if (GetGame() && GetGame().IsServer())
  2237. {
  2238. float remainingEnergy;
  2239. foreach (FireConsumable fireConsumable : m_FireConsumables)
  2240. {
  2241. float quantity = fireConsumable.GetItem().GetQuantity();
  2242. if (quantity > 0)
  2243. {
  2244. remainingEnergy += ((quantity - 1) * fireConsumable.GetEnergy()) + fireConsumable.GetRemainingEnergy();
  2245. //Print(fireConsumable.GetItem().GetType() + " remaining energy = " + (((quantity - 1) * fire_consumable.GetEnergy()) + fire_consumable.GetRemainingEnergy()).ToString());
  2246. }
  2247. else
  2248. {
  2249. remainingEnergy += fireConsumable.GetRemainingEnergy();
  2250. //Print(fireConsumable.GetItem().GetType() + " remaining energy = " + (fireConsumable.GetRemainingEnergy().ToString()));
  2251. }
  2252. }
  2253. SetQuantity(remainingEnergy / m_TotalEnergy * GetQuantityMax());
  2254. }
  2255. }
  2256. override void OnAttachmentQuantityChanged(ItemBase item)
  2257. {
  2258. super.OnAttachmentQuantityChanged(item);
  2259. CalcAndSetQuantity();
  2260. }
  2261. override bool CanReleaseAttachment(EntityAI attachment)
  2262. {
  2263. if (!super.CanReleaseAttachment(attachment))
  2264. return false;
  2265. ItemBase item = ItemBase.Cast(attachment);
  2266. if (IsKindling(item) || IsFuel(item))
  2267. {
  2268. return !IsBurning();
  2269. }
  2270. return true;
  2271. }
  2272. void LockOvenAttachments(bool lock)
  2273. {
  2274. //Print("LockOvenAttachments");
  2275. //string path_cooking_equipment = "" + CFG_VEHICLESPATH + " " + GetType() + " GUIInventoryAttachmentsProps CookingEquipment attachmentSlots";
  2276. string path_cooking_equipment = string.Format("%1 %2 GUIInventoryAttachmentsProps CookingEquipment attachmentSlots", CFG_VEHICLESPATH, GetType());
  2277. //string path_direct_cooking = "" + CFG_VEHICLESPATH + " " + GetType() + " GUIInventoryAttachmentsProps DirectCooking attachmentSlots";
  2278. string path_direct_cooking = string.Format("%1 %2 GUIInventoryAttachmentsProps DirectCooking attachmentSlots", CFG_VEHICLESPATH, GetType());
  2279. if (GetGame().ConfigIsExisting(path_cooking_equipment) && GetGame().ConfigIsExisting(path_direct_cooking))
  2280. {
  2281. array<string> arr_cooking_equipment = new array<string>;
  2282. array<string> arr_direct_cooking = new array<string>;
  2283. GetGame().ConfigGetTextArray(path_cooking_equipment,arr_cooking_equipment);
  2284. GetGame().ConfigGetTextArray(path_direct_cooking,arr_direct_cooking);
  2285. for (int i = 0; i < arr_cooking_equipment.Count(); i++)
  2286. {
  2287. if (lock != GetInventory().GetSlotLock(InventorySlots.GetSlotIdFromString(arr_cooking_equipment[i])))
  2288. {
  2289. GetInventory().SetSlotLock(InventorySlots.GetSlotIdFromString(arr_cooking_equipment[i]),lock);
  2290. //Print("attachment lock: " + arr_cooking_equipment[i] + " " + lock);
  2291. }
  2292. }
  2293. for (i = 0; i < arr_direct_cooking.Count(); i++)
  2294. {
  2295. if (lock == GetInventory().GetSlotLock(InventorySlots.GetSlotIdFromString(arr_direct_cooking[i])))
  2296. {
  2297. GetInventory().SetSlotLock(InventorySlots.GetSlotIdFromString(arr_direct_cooking[i]),!lock);
  2298. //Print("attachment lock: " + arr_direct_cooking[i] + " " + !lock);
  2299. }
  2300. }
  2301. }
  2302. m_OvenAttachmentsLockState = lock;
  2303. }
  2304. override bool DisassembleOnLastDetach()
  2305. {
  2306. return true;
  2307. }
  2308. override void OnRPC(PlayerIdentity sender, int rpc_type, ParamsReadContext ctx)
  2309. {
  2310. super.OnRPC(sender, rpc_type, ctx);
  2311. ref Param1<bool> p = new Param1<bool>(false);
  2312. if (ctx.Read(p))
  2313. {
  2314. bool failure = p.param1;
  2315. }
  2316. switch (rpc_type)
  2317. {
  2318. case FirePlaceFailure.WIND:
  2319. if (failure)
  2320. {
  2321. ParticleFireWindyNoIgniteStart();
  2322. SoundFireStop();
  2323. SoundFireWindyNoIgniteStart();
  2324. }
  2325. break;
  2326. case FirePlaceFailure.WET:
  2327. if (failure)
  2328. {
  2329. ParticleWetNoIgniteStart();
  2330. SoundFireStop();
  2331. SoundFireWetNoIgniteStart();
  2332. }
  2333. break;
  2334. }
  2335. }
  2336. //================================================================
  2337. // DEBUG
  2338. //================================================================
  2339. //Debug menu Spawn Ground Special
  2340. override void OnDebugSpawn()
  2341. {
  2342. ItemBase firewood = ItemBase.Cast(GetInventory().CreateInInventory("Firewood"));
  2343. firewood.SetQuantity(firewood.GetQuantityMax());
  2344. ItemBase sticks = ItemBase.Cast(GetInventory().CreateInInventory("WoodenStick"));
  2345. sticks.SetQuantity(sticks.GetQuantityMax());
  2346. ItemBase stone = ItemBase.Cast(GetInventory().CreateInInventory("Stone"));
  2347. stone.SetQuantity(stone.GetQuantityMax());
  2348. GetInventory().CreateInInventory("Rag");
  2349. SpawnEntityOnGroundPos("PetrolLighter", GetPosition());
  2350. }
  2351. override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
  2352. {
  2353. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ACTIVATE_ENTITY, "Ignite", FadeColors.LIGHT_GREY));
  2354. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.DEACTIVATE_ENTITY, "Extinguish", FadeColors.LIGHT_GREY));
  2355. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.LIGHT_GREY));
  2356. super.GetDebugActions(outputList);
  2357. }
  2358. override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  2359. {
  2360. if (super.OnAction(action_id, player, ctx))
  2361. return true;
  2362. if (GetGame().IsServer() || !GetGame().IsMultiplayer())
  2363. {
  2364. if (action_id == EActions.ACTIVATE_ENTITY)
  2365. {
  2366. OnIgnitedThis(null);
  2367. }
  2368. else if (action_id == EActions.DEACTIVATE_ENTITY)
  2369. {
  2370. StopFire();
  2371. }
  2372. }
  2373. return false;
  2374. }
  2375. ///////////////////////////
  2376. //DEPRECATED STUFF BELOW//
  2377. /////////////////////////
  2378. const float PARAM_ITEM_HEAT_MIN_TEMP = 40;//!DEPRECATED
  2379. const float PARAM_ITEM_HEAT_TEMP_INCREASE_COEF = 10; //! value for calculating temperature increase on each heat update interval (degree Celsius)
  2380. const float PARAM_ITEM_HEAT_TEMP_HEATING_COEF = 1.0; //! multiplies temperature change on heating
  2381. const float PARAM_MAX_ITEM_HEAT_TEMP_INCREASE = 200; //! maximum value of temperature of items in fireplace when heating (degree Celsius)
  2382. const float PARAM_HEAT_THROUGH_AIR_COEF = 0.1; //! DEPRECATED value for calculation of heat transfered from fireplace through air to player (environment)
  2383. const float TEMPERATURE_LOSS_MP_DEFAULT = 1.0;
  2384. const float TEMPERATURE_LOSS_MP_STONES = 0.90; //10% boost
  2385. const float TEMPERATURE_LOSS_MP_OVEN = 0.75; //25% boost
  2386. const float PARAM_COOKING_EQUIP_MAX_TEMP = 250; //! maximum temperature of attached cooking equipment (degree Celsius)
  2387. const float PARAM_COOKING_EQUIP_TEMP_INCREASE = 10; //! how much will temperature increase when attached on burning fireplace (degree Celsius)
  2388. const float DIRECT_COOKING_SPEED = 1.5; // per second
  2389. const float PARAM_WET_INCREASE_COEF = 0.02; //! value for calculating of wetness that fireplace gain when raining
  2390. protected float m_TemperatureLossMP = 1.0;//! determines how fast will the fireplace loose its temperature when cooling (lower is better)
  2391. //Temperature loss MP
  2392. protected float GetTemperatureLossMP()
  2393. {
  2394. return m_TemperatureLossMP;
  2395. }
  2396. protected void SetTemperatureLossMP(float value)
  2397. {
  2398. m_TemperatureLossMP = value;
  2399. }
  2400. // DEPRECATED
  2401. protected void AddDamageToItemByFire(ItemBase item, bool can_be_ruined)
  2402. {
  2403. AddDamageToItemByFireEx(item,can_be_ruined,false);
  2404. }
  2405. /////////////////////////
  2406. //////////////////////////
  2407. ///////////////////////////
  2408. }