fireplacebase.c 78 KB

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