fireplacebase.c 78 KB

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