fireplace.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. class Fireplace extends FireplaceBase
  2. {
  3. bool m_ContactEventProcessing;
  4. void Fireplace()
  5. {
  6. //Particles - default for FireplaceBase
  7. PARTICLE_FIRE_START = ParticleList.CAMP_FIRE_START;
  8. PARTICLE_SMALL_FIRE = ParticleList.CAMP_SMALL_FIRE;
  9. PARTICLE_NORMAL_FIRE = ParticleList.CAMP_NORMAL_FIRE;
  10. PARTICLE_SMALL_SMOKE = ParticleList.CAMP_SMALL_SMOKE;
  11. PARTICLE_NORMAL_SMOKE = ParticleList.CAMP_NORMAL_SMOKE;
  12. PARTICLE_FIRE_END = ParticleList.CAMP_FIRE_END;
  13. PARTICLE_STEAM_END = ParticleList.CAMP_STEAM_2END;
  14. SetEventMask( EntityEvent.CONTACT | EntityEvent.TOUCH );
  15. //! universal temperature sources overrides
  16. m_UTSSettings.m_TemperatureItemCap = GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE;
  17. m_UTSSettings.m_TemperatureCap = 20;
  18. m_ThawnSurfaceUnderSupport = true;
  19. }
  20. override protected void InitializeTemperatureSources()
  21. {
  22. m_UTSLFireplace = new UniversalTemperatureSourceLambdaFireplace();
  23. m_UTSLFireplace.SetSmallFireplaceTemperatureMax(PARAM_SMALL_FIRE_TEMPERATURE);
  24. m_UTSLFireplace.SetNormalFireplaceTemperatureMax(PARAM_OUTDOOR_FIRE_TEMPERATURE);
  25. m_UTSource = new UniversalTemperatureSource(this, m_UTSSettings, m_UTSLFireplace);
  26. }
  27. override bool IsBaseFireplace()
  28. {
  29. return true;
  30. }
  31. override bool CanObstruct()
  32. {
  33. return IsOven();
  34. }
  35. override bool CanProxyObstruct()
  36. {
  37. return IsOven();
  38. }
  39. override void EOnTouch( IEntity other, int extra )
  40. {
  41. ContactEvent( other, GetPosition() );
  42. }
  43. override void EOnContact( IEntity other, Contact extra )
  44. {
  45. ContactEvent( other, extra.Position );
  46. }
  47. void ContactEvent( IEntity other, vector position )
  48. {
  49. if ( GetGame().IsServer() && !m_ContactEventProcessing && dBodyIsActive(this) && !IsSetForDeletion() )
  50. {
  51. m_ContactEventProcessing = true;
  52. MiscGameplayFunctions.ThrowAllItemsInInventory(this, 0);
  53. CheckForDestroy();
  54. m_ContactEventProcessing = false;
  55. }
  56. }
  57. //attachments
  58. override bool CanReceiveAttachment( EntityAI attachment, int slotId )
  59. {
  60. if ( !super.CanReceiveAttachment(attachment, slotId) )
  61. return false;
  62. ItemBase item = ItemBase.Cast( attachment );
  63. //cookware
  64. if ( ( item.Type() == ATTACHMENT_CAULDRON ) || ( item.Type() == ATTACHMENT_COOKING_POT ) )
  65. {
  66. if ( FindAttachmentBySlotName( "CookingTripod" ) || IsOven() )
  67. return true;
  68. return false;
  69. }
  70. if ( item.Type() == ATTACHMENT_FRYING_PAN )
  71. {
  72. if ( IsOven() )
  73. return true;
  74. return false;
  75. }
  76. // food on direct cooking slots
  77. if ( item.IsKindOf( "Edible_Base" ) )
  78. {
  79. if ( IsOven() )
  80. return true;
  81. return false;
  82. }
  83. //tripod
  84. if ( item.IsInherited(TripodBase) )
  85. {
  86. if (!IsOven() && !GetHierarchyParent())
  87. return true;
  88. return false;
  89. }
  90. //stones
  91. if ( item.Type() == ATTACHMENT_STONES )
  92. {
  93. if ( !GetHierarchyParent() && !IsBurning() )
  94. return true;
  95. return false;
  96. }
  97. return true;
  98. }
  99. override bool CanDisplayAttachmentSlot( int slot_id )
  100. {
  101. string slot_name = InventorySlots.GetSlotName(slot_id);
  102. if ( super.CanDisplayAttachmentSlot(slot_id) )
  103. {
  104. if ( slot_name != "CookingEquipment" || FindAttachmentBySlotName( "CookingTripod" ) )
  105. return true;
  106. }
  107. return false;
  108. }
  109. override bool CanLoadAttachment( EntityAI attachment )
  110. {
  111. if ( !super.CanLoadAttachment(attachment) )
  112. return false;
  113. ItemBase item = ItemBase.Cast( attachment );
  114. //cookware
  115. if ( ( item.Type() == ATTACHMENT_CAULDRON ) || ( item.Type() == ATTACHMENT_COOKING_POT ) )
  116. {
  117. //if ( IsItemTypeAttached( ATTACHMENT_TRIPOD ) /*|| IsOven()*/ )
  118. return true;
  119. }
  120. if ( item.Type() == ATTACHMENT_FRYING_PAN )
  121. {
  122. //if ( IsOven() )
  123. return true;
  124. }
  125. // food on direct cooking slots
  126. //if ( IsOven() )
  127. //{
  128. if ( item.IsKindOf( "Edible_Base" ) )
  129. return true;
  130. //}
  131. //tripod
  132. if ( item.Type() == ATTACHMENT_TRIPOD )
  133. {
  134. if ( /*!IsOven() &&*/ GetHierarchyParent() == NULL )
  135. return true;
  136. }
  137. //stones
  138. if ( item.Type() == ATTACHMENT_STONES )
  139. {
  140. if ( GetHierarchyParent() /*|| IsBurning()*/ )
  141. return false;
  142. return true;
  143. }
  144. return true;
  145. }
  146. override bool CanReleaseAttachment( EntityAI attachment )
  147. {
  148. if (!super.CanReleaseAttachment(attachment))
  149. {
  150. return false;
  151. }
  152. ItemBase item = ItemBase.Cast(attachment);
  153. //stones
  154. if (item.Type() == ATTACHMENT_STONES)
  155. {
  156. if (IsBurning())
  157. {
  158. return false;
  159. }
  160. int stone_quantity = item.GetQuantity();
  161. if (HasStoneCircle() && stone_quantity <= 8)
  162. {
  163. return false;
  164. }
  165. if (IsOven())
  166. {
  167. return false;
  168. }
  169. }
  170. return true;
  171. }
  172. override void EEItemAttached(EntityAI item, string slot_name)
  173. {
  174. super.EEItemAttached(item, slot_name);
  175. ItemBase item_base = ItemBase.Cast(item);
  176. if (IsKindling(item_base) || IsFuel(item_base))
  177. {
  178. AddToFireConsumables(item_base);
  179. }
  180. //cookware
  181. if (item_base.IsCookware())
  182. SetCookingEquipment(item_base);
  183. if (GetGame().IsServer() && !IsOven())
  184. {
  185. if (item_base.Type() == ATTACHMENT_COOKING_POT)
  186. item_base.SetAnimationPhase(ANIMATION_COOKWARE_HANDLE, 0);
  187. if (item.Type() == ATTACHMENT_CAULDRON)
  188. item_base.SetAnimationPhase(ANIMATION_CAULDRON_HANDLE, 0);
  189. }
  190. // direct cooking/smoking slots
  191. bool edible_base_attached = false;
  192. switch (slot_name)
  193. {
  194. case "DirectCookingA":
  195. m_DirectCookingSlots[0] = item_base;
  196. edible_base_attached = true;
  197. break;
  198. case "DirectCookingB":
  199. m_DirectCookingSlots[1] = item_base;
  200. edible_base_attached = true;
  201. break;
  202. case "DirectCookingC":
  203. m_DirectCookingSlots[2] = item_base;
  204. edible_base_attached = true;
  205. break;
  206. case "SmokingA":
  207. m_SmokingSlots[0] = item_base;
  208. edible_base_attached = true;
  209. break;
  210. case "SmokingB":
  211. m_SmokingSlots[1] = item_base;
  212. edible_base_attached = true;
  213. break;
  214. case "SmokingC":
  215. m_SmokingSlots[2] = item_base;
  216. edible_base_attached = true;
  217. break;
  218. case "SmokingD":
  219. m_SmokingSlots[3] = item_base;
  220. edible_base_attached = true;
  221. break;
  222. }
  223. //TODO
  224. //add SetViewIndex when attaching various attachments
  225. RefreshFireplaceVisuals();
  226. }
  227. override void EEItemDetached(EntityAI item, string slot_name)
  228. {
  229. super.EEItemDetached(item, slot_name);
  230. ItemBase item_base = ItemBase.Cast(item);
  231. if (IsKindling(item_base) || IsFuel(item_base))
  232. {
  233. RemoveFromFireConsumables(GetFireConsumableByItem(item_base));
  234. }
  235. //cookware
  236. if (item_base.IsCookware())
  237. {
  238. ClearCookingEquipment(item_base);
  239. item_base.RemoveAudioVisualsOnClient();
  240. }
  241. if (item_base.IsLiquidContainer()) //boiling bottle effects stop
  242. item_base.RemoveAudioVisualsOnClient();
  243. if (GetGame().IsServer())
  244. {
  245. if (item_base.Type() == ATTACHMENT_COOKING_POT)
  246. item_base.SetAnimationPhase(ANIMATION_COOKWARE_HANDLE, 1);
  247. if (item_base.Type() == ATTACHMENT_CAULDRON)
  248. item_base.SetAnimationPhase(ANIMATION_CAULDRON_HANDLE, 1);
  249. }
  250. // direct cooking/smoking slots
  251. switch (slot_name)
  252. {
  253. case "DirectCookingA":
  254. m_DirectCookingSlots[0] = null;
  255. break;
  256. case "DirectCookingB":
  257. m_DirectCookingSlots[1] = null;
  258. break;
  259. case "DirectCookingC":
  260. m_DirectCookingSlots[2] = null;
  261. break;
  262. case "SmokingA":
  263. m_SmokingSlots[0] = null;
  264. break;
  265. case "SmokingB":
  266. m_SmokingSlots[1] = null;
  267. break;
  268. case "SmokingC":
  269. m_SmokingSlots[2] = null;
  270. break;
  271. case "SmokingD":
  272. m_SmokingSlots[3] = null;
  273. break;
  274. }
  275. //no attachments left, no cargo items & no ashes are present
  276. CheckForDestroy();
  277. RefreshFireplaceVisuals();
  278. }
  279. override void SetCookingEquipment(ItemBase equipment)
  280. {
  281. super.SetCookingEquipment(equipment);
  282. TripodBase stand = TripodBase.Cast(FindAttachmentBySlotName("CookingTripod"));
  283. if (stand)
  284. {
  285. if (equipment)
  286. stand.LockToParent();
  287. else
  288. stand.UnlockFromParent();
  289. }
  290. }
  291. override void OnBeforeTryDelete()
  292. {
  293. super.OnBeforeTryDelete();
  294. MiscGameplayFunctions.DropAllItemsInInventoryInBounds(this, m_HalfExtents);
  295. }
  296. override bool IsPrepareToDelete()
  297. {
  298. return GetInventory().AttachmentCount() == 0 && !IsBurning() && !HasAshes();
  299. }
  300. //CONDITIONS
  301. //this into/outo parent.Cargo
  302. override bool CanPutInCargo(EntityAI parent)
  303. {
  304. if (!super.CanPutInCargo(parent))
  305. {
  306. return false;
  307. }
  308. if (HasAshes() || IsBurning() || HasStones() || HasStoneCircle() || IsOven() || !IsCargoEmpty() || HasCookingStand())
  309. {
  310. return false;
  311. }
  312. return true;
  313. }
  314. override bool CanRemoveFromCargo( EntityAI parent )
  315. {
  316. return true;
  317. }
  318. //cargo item into/outo this.Cargo
  319. override bool CanReceiveItemIntoCargo( EntityAI item )
  320. {
  321. if ( GetHierarchyParent() )
  322. return false;
  323. return super.CanReceiveItemIntoCargo( item );
  324. }
  325. override bool CanLoadItemIntoCargo( EntityAI item )
  326. {
  327. if (!super.CanLoadItemIntoCargo( item ))
  328. return false;
  329. if ( GetHierarchyParent() )
  330. return false;
  331. return true;
  332. }
  333. //hands
  334. override bool CanPutIntoHands(EntityAI parent)
  335. {
  336. if (!super.CanPutIntoHands(parent))
  337. {
  338. return false;
  339. }
  340. if (HasAshes() || IsBurning() || HasStones() || HasStoneCircle() || IsOven() || !IsCargoEmpty() || HasCookingStand())
  341. {
  342. return false;
  343. }
  344. return true;
  345. }
  346. override bool CanDisplayAttachmentCategory( string category_name )
  347. {
  348. if ( !super.CanDisplayAttachmentCategory( category_name ) )
  349. return false;
  350. if ( IsOven() )
  351. {
  352. if ( category_name == "CookingEquipment" )
  353. return false;
  354. if ( ( category_name == "DirectCooking" ) || ( category_name == "Smoking" ) )
  355. return true;
  356. }
  357. else
  358. {
  359. if ( category_name == "CookingEquipment" )
  360. return true;
  361. if ( ( category_name == "DirectCooking" ) || ( category_name == "Smoking" ) )
  362. return false;
  363. }
  364. return true;
  365. }
  366. override bool CanAssignAttachmentsToQuickbar()
  367. {
  368. return false;
  369. }
  370. override float HeightStartCheckOverride()
  371. {
  372. return 0.5;
  373. }
  374. //particles
  375. override bool CanShowSmoke()
  376. {
  377. return !IsOven();
  378. }
  379. void DestroyClutterCutter( Object clutter_cutter )
  380. {
  381. GetGame().ObjectDelete( clutter_cutter );
  382. }
  383. override void RefreshPhysics()
  384. {
  385. super.RefreshPhysics();
  386. //Oven
  387. if ( IsOven() )
  388. {
  389. RemoveProxyPhysics( ANIMATION_OVEN );
  390. AddProxyPhysics( ANIMATION_OVEN );
  391. }
  392. else
  393. {
  394. RemoveProxyPhysics( ANIMATION_OVEN );
  395. }
  396. //Tripod
  397. if ( IsItemTypeAttached( ATTACHMENT_TRIPOD ) )
  398. {
  399. RemoveProxyPhysics( ANIMATION_TRIPOD );
  400. AddProxyPhysics( ANIMATION_TRIPOD );
  401. }
  402. else
  403. {
  404. RemoveProxyPhysics( ANIMATION_TRIPOD );
  405. }
  406. }
  407. override void RefreshFireplacePhysics()
  408. {
  409. RefreshPhysics();
  410. }
  411. //on store save/load
  412. override void OnStoreSave( ParamsWriteContext ctx )
  413. {
  414. super.OnStoreSave(ctx);
  415. if ( GetGame().SaveVersion() >= 110 )
  416. {
  417. // save stone circle state
  418. ctx.Write( m_HasStoneCircle );
  419. // save stone oven state
  420. ctx.Write( m_IsOven );
  421. }
  422. }
  423. override bool OnStoreLoad( ParamsReadContext ctx, int version )
  424. {
  425. if ( !super.OnStoreLoad(ctx, version) )
  426. return false;
  427. if ( version >= 110 )
  428. {
  429. // read stone circle state
  430. if ( !ctx.Read( m_HasStoneCircle ) )
  431. {
  432. m_HasStoneCircle = false;
  433. return false;
  434. }
  435. // read stone oven state
  436. if ( !ctx.Read( m_IsOven ) )
  437. {
  438. m_IsOven = false;
  439. return false;
  440. }
  441. }
  442. return true;
  443. }
  444. override void AfterStoreLoad()
  445. {
  446. super.AfterStoreLoad();
  447. if ( IsBurning() )
  448. {
  449. if ( !m_ClutterCutter )
  450. {
  451. m_ClutterCutter = GetGame().CreateObjectEx( OBJECT_CLUTTER_CUTTER, GetPosition(), ECE_PLACE_ON_SURFACE );
  452. m_ClutterCutter.SetOrientation( GetOrientation() );
  453. }
  454. }
  455. }
  456. //================================================================
  457. // IGNITION ACTION
  458. //================================================================
  459. // Item-to-item fire distribution
  460. override bool HasFlammableMaterial()
  461. {
  462. return true;
  463. }
  464. override bool CanBeIgnitedBy(EntityAI igniter = NULL)
  465. {
  466. return HasAnyKindling() && !IsBurning() && !GetHierarchyParent();
  467. }
  468. override bool CanIgniteItem(EntityAI ignite_target = NULL)
  469. {
  470. return IsBurning();
  471. }
  472. override bool IsIgnited()
  473. {
  474. return IsBurning();
  475. }
  476. override void OnIgnitedTarget( EntityAI target_item )
  477. {
  478. }
  479. override void OnIgnitedThis( EntityAI fire_source )
  480. {
  481. //remove grass
  482. Object cc_object = GetGame().CreateObjectEx( OBJECT_CLUTTER_CUTTER , GetPosition(), ECE_PLACE_ON_SURFACE );
  483. cc_object.SetOrientation ( GetOrientation() );
  484. GetGame().GetCallQueue( CALL_CATEGORY_GAMEPLAY ).CallLater( DestroyClutterCutter, 200, false, cc_object );
  485. //start fire
  486. StartFire();
  487. if ( fire_source )
  488. {
  489. Man player = fire_source.GetHierarchyRootPlayer();
  490. if ( player )
  491. {
  492. EFireIgniteType ignate_type = EFireIgniteType.Unknow;
  493. if ( fire_source.ClassName() == "Matchbox" )
  494. {
  495. ignate_type = EFireIgniteType.Matchbox;
  496. }
  497. else if ( fire_source.ClassName() == "Roadflare" )
  498. {
  499. ignate_type = EFireIgniteType.Roadflare;
  500. }
  501. else if ( fire_source.ClassName() == "HandDrillKit" )
  502. {
  503. ignate_type = EFireIgniteType.HandDrill;
  504. }
  505. SyncEvents.SendPlayerIgnatedFireplace( player, ignate_type );
  506. }
  507. }
  508. }
  509. override bool IsThisIgnitionSuccessful( EntityAI item_source = NULL )
  510. {
  511. SetIgniteFailure( false );
  512. Param1<bool> failure;
  513. //check kindling
  514. if ( !HasAnyKindling() )
  515. {
  516. return false;
  517. }
  518. //check roof
  519. if ( !IsOven() )
  520. {
  521. if ( !IsCeilingHighEnoughForSmoke() && IsOnInteriorSurface() )
  522. {
  523. return false;
  524. }
  525. }
  526. //check surface
  527. if ( IsOnWaterSurface() )
  528. {
  529. return false;
  530. }
  531. //check wetness
  532. if ( IsWet() )
  533. {
  534. SetIgniteFailure( true );
  535. failure = new Param1<bool>( GetIgniteFailure() );
  536. GetGame().RPCSingleParam( this, FirePlaceFailure.WET, failure, true );
  537. return false;
  538. }
  539. // check if the fireplace isnt below a roof
  540. // excluding this check whein oven stage
  541. CheckForRoofLimited(0);
  542. if ( !IsOven() && !IsRoofAbove() )
  543. {
  544. // if not, check if there is strong rain or wind
  545. if ( IsRainingAbove() )
  546. {
  547. SetIgniteFailure( true );
  548. failure = new Param1<bool>( GetIgniteFailure() );
  549. GetGame().RPCSingleParam( this, FirePlaceFailure.WET, failure, true );
  550. return false;
  551. }
  552. if ( IsWindy() )
  553. {
  554. SetIgniteFailure( true );
  555. failure = new Param1<bool>( GetIgniteFailure() );
  556. GetGame().RPCSingleParam( this, FirePlaceFailure.WIND, failure, true );
  557. return false;
  558. }
  559. }
  560. return true;
  561. }
  562. //================================================================
  563. // FIREPLACE ENTITY
  564. //================================================================
  565. static Fireplace IgniteEntityAsFireplace( notnull EntityAI entity, notnull EntityAI fire_source )
  566. {
  567. //get player
  568. PlayerBase player = PlayerBase.Cast( fire_source.GetHierarchyRootPlayer() );
  569. //create fireplace
  570. Fireplace fireplace = Fireplace.Cast( GetGame().CreateObjectEx( "Fireplace" , entity.GetPosition(), ECE_PLACE_ON_SURFACE ) );
  571. //attach
  572. if ( !GetGame().IsMultiplayer() ) //clear inventory reservation (single player)
  573. {
  574. InventoryLocation loc = new InventoryLocation;
  575. entity.GetInventory().GetCurrentInventoryLocation( loc );
  576. player.GetInventory().ClearInventoryReservationEx( entity, loc );
  577. }
  578. if ( GetGame().IsServer() && GetGame().IsMultiplayer() )
  579. {
  580. player.ServerTakeEntityToTargetAttachment( fireplace, entity ); // multiplayer server side
  581. }
  582. else
  583. {
  584. player.LocalTakeEntityToTargetAttachment( fireplace, entity ); // single player or multiplayer client side
  585. }
  586. //start fire
  587. fireplace.StartFire();
  588. fireplace.OnIgnitedThis(fire_source);
  589. return fireplace;
  590. }
  591. static bool CanIgniteEntityAsFireplace(notnull EntityAI entity)
  592. {
  593. //check surface
  594. if (FireplaceBase.IsEntityOnWaterSurface(entity))
  595. {
  596. return false;
  597. }
  598. entity.CheckForRoofLimited(); //TODO: limit more severely? Should update at least once during UATimeSpent.FIREPLACE_IGNITE
  599. if (!entity.IsRoofAbove())
  600. return !FireplaceBase.IsRainingAboveEntity(entity);
  601. //check ceiling (enough space for smoke)
  602. if (IsEntityOnInteriorSurface(entity) && MiscGameplayFunctions.IsUnderRoof(entity, FireplaceBase.MIN_CEILING_HEIGHT))
  603. {
  604. return false;
  605. }
  606. return true;
  607. }
  608. //================================================================
  609. // ADVANCED PLACEMENT
  610. //================================================================
  611. override void SetActions()
  612. {
  613. super.SetActions();
  614. AddAction(ActionPlaceFireplaceIntoBarrel);
  615. AddAction(ActionPlaceFireplaceIndoor);
  616. AddAction(ActionPlaceOvenIndoor);
  617. AddAction(ActionTogglePlaceObject);
  618. AddAction(ActionPlaceObject);
  619. AddAction(ActionBuildOven);
  620. AddAction(ActionDismantleOven);
  621. AddAction(ActionBuildStoneCircle);
  622. AddAction(ActionDismantleStoneCircle);
  623. }
  624. }