edible_base.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111
  1. class Edible_Base : ItemBase
  2. {
  3. const string DIRECT_COOKING_SLOT_NAME = "DirectCooking";
  4. const string SOUND_BAKING_START = "Baking_SoundSet";
  5. const string SOUND_BAKING_DONE = "Baking_Done_SoundSet";
  6. const string SOUND_BOILING_START = "Boiling_SoundSet";
  7. const string SOUND_BOILING_DONE = "Boiling_Done_SoundSet";
  8. const string SOUND_DRYING_START = "Drying_SoundSet";
  9. const string SOUND_DRYING_DONE = "Drying_Done_SoundSet";
  10. const string SOUND_BURNING_DONE = "Food_Burning_SoundSet";
  11. protected bool m_MakeCookingSounds;
  12. protected SoundOnVehicle m_SoundCooking; //! DEPRECATED
  13. protected EffectSound m_SoundEffectCooking;
  14. protected string m_SoundPlaying;
  15. ref FoodStage m_FoodStage;
  16. protected float m_DecayTimer;
  17. protected float m_DecayDelta = 0.0;
  18. protected FoodStageType m_LastDecayStage = FoodStageType.NONE;
  19. protected ParticleSource m_HotVaporParticle;
  20. private CookingMethodType m_CookedByMethod;
  21. void Edible_Base()
  22. {
  23. if (HasFoodStage())
  24. {
  25. m_FoodStage = new FoodStage(this);
  26. RegisterNetSyncVariableInt("m_FoodStage.m_FoodStageType", FoodStageType.NONE, FoodStageType.COUNT);
  27. RegisterNetSyncVariableFloat("m_FoodStage.m_CookingTime", 0, 600, 0);
  28. m_SoundPlaying = "";
  29. m_CookedByMethod = CookingMethodType.NONE;
  30. RegisterNetSyncVariableInt("m_CookedByMethod", CookingMethodType.NONE, CookingMethodType.COUNT);
  31. RegisterNetSyncVariableBool("m_MakeCookingSounds");
  32. }
  33. }
  34. override void EEInit()
  35. {
  36. super.EEInit();
  37. UpdateVisualsEx(true); //forced init visuals, mostly for debugs and SP
  38. }
  39. override void EEDelete(EntityAI parent)
  40. {
  41. super.EEDelete(parent);
  42. RemoveAudio();
  43. if (m_HotVaporParticle)
  44. m_HotVaporParticle.Stop();
  45. }
  46. override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
  47. {
  48. super.EEItemLocationChanged(oldLoc, newLoc);
  49. //! disable sounds (from cooking)
  50. if (oldLoc.GetType() == InventoryLocationType.ATTACHMENT || oldLoc.GetType() == InventoryLocationType.CARGO)
  51. {
  52. switch (oldLoc.GetParent().GetType())
  53. {
  54. case "FryingPan":
  55. case "Pot":
  56. case "Cauldron":
  57. case "SharpWoodenStick":
  58. MakeSoundsOnClient(false);
  59. break;
  60. }
  61. //! check for DirectCooking slot name
  62. if (oldLoc.GetSlot() > -1 && InventorySlots.GetSlotName(oldLoc.GetSlot()).Contains(DIRECT_COOKING_SLOT_NAME))
  63. {
  64. MakeSoundsOnClient(false);
  65. }
  66. }
  67. if (oldLoc.IsValid())
  68. ResetCookingTime();
  69. if (CanHaveTemperature())
  70. UpdateVaporParticle();
  71. }
  72. void UpdateVisualsEx(bool forced = false)
  73. {
  74. if (GetFoodStage())
  75. GetFoodStage().UpdateVisualsEx(forced);
  76. }
  77. bool Consume(float amount, PlayerBase consumer)
  78. {
  79. AddQuantity(-amount, false, false);
  80. OnConsume(amount, consumer);
  81. return true;
  82. }
  83. void OnConsume(float amount, PlayerBase consumer)
  84. {
  85. if (GetTemperature() > PlayerConstants.CONSUMPTION_DAMAGE_TEMP_THRESHOLD)
  86. {
  87. consumer.ProcessDirectDamage(DamageType.CUSTOM, this, "", "EnviroDmg", "0 0 0", PlayerConstants.CONSUMPTION_DAMAGE_PER_BITE);
  88. }
  89. }
  90. //! Filter agents from the item (override on higher implementations)
  91. int FilterAgents(int agentsIn)
  92. {
  93. int foodStageType;
  94. FoodStage foodStage = GetFoodStage();
  95. if (foodStage)
  96. foodStageType = foodStage.GetFoodStageType();
  97. //! if no per FoodStage/Nutrition override is set, remove possible Food Poisoning to prevent double punishment from Bloody Hands
  98. NutritionalProfile nutritionalProfile = GetNutritionalProfile(this, ClassName(), foodStageType);
  99. if ((agentsIn & eAgents.SALMONELLA == eAgents.SALMONELLA) && (nutritionalProfile.m_Agents == 0 || nutritionalProfile.m_AgentsPerDigest == 0))
  100. agentsIn &= ~eAgents.FOOD_POISON;
  101. return agentsIn;
  102. }
  103. //food staging
  104. override bool CanBeCooked()
  105. {
  106. return false;
  107. }
  108. override bool CanBeCookedOnStick()
  109. {
  110. return false;
  111. }
  112. override float GetTemperatureFreezeTime()
  113. {
  114. if (GetFoodStage())
  115. {
  116. switch (m_FoodStage.GetFoodStageType())
  117. {
  118. case FoodStageType.DRIED:
  119. return super.GetTemperatureFreezeTime() * GameConstants.TEMPERATURE_FREEZE_TIME_COEF_DRIED;
  120. case FoodStageType.BURNED:
  121. return super.GetTemperatureFreezeTime() * GameConstants.TEMPERATURE_FREEZE_TIME_COEF_BURNED;
  122. default:
  123. return super.GetTemperatureFreezeTime();
  124. }
  125. }
  126. return super.GetTemperatureFreezeTime();
  127. }
  128. override float GetTemperatureThawTime()
  129. {
  130. if (GetFoodStage())
  131. {
  132. switch (m_FoodStage.GetFoodStageType())
  133. {
  134. case FoodStageType.DRIED:
  135. return super.GetTemperatureThawTime() * GameConstants.TEMPERATURE_THAW_TIME_COEF_DRIED;
  136. case FoodStageType.BURNED:
  137. return super.GetTemperatureThawTime() * GameConstants.TEMPERATURE_THAW_TIME_COEF_BURNED;
  138. default:
  139. return super.GetTemperatureThawTime();
  140. }
  141. }
  142. return super.GetTemperatureThawTime();
  143. }
  144. override bool CanItemOverheat()
  145. {
  146. return super.CanItemOverheat() && (!GetFoodStage() || (IsFoodBurned() || !GetFoodStage().CanTransitionToFoodStageType(FoodStageType.BURNED))); //for foodstaged items - either is burned, or it can't get burned
  147. }
  148. //================================================================
  149. // SYNCHRONIZATION
  150. //================================================================
  151. void Synchronize()
  152. {
  153. SetSynchDirty();
  154. }
  155. override void OnVariablesSynchronized()
  156. {
  157. super.OnVariablesSynchronized();
  158. //UpdateVisualsEx(); //performed on client only
  159. //update audio
  160. if (m_MakeCookingSounds)
  161. {
  162. RefreshAudio();
  163. }
  164. else
  165. {
  166. RemoveAudio();
  167. }
  168. if (CanHaveTemperature())
  169. UpdateVaporParticle();
  170. }
  171. //================================================================
  172. // AUDIO EFFECTS (WHEN ON DCS)
  173. //================================================================
  174. void MakeSoundsOnClient(bool soundstate, CookingMethodType cookingMethod = CookingMethodType.NONE)
  175. {
  176. m_MakeCookingSounds = soundstate;
  177. m_CookedByMethod = cookingMethod;
  178. Synchronize();
  179. }
  180. protected void RefreshAudio()
  181. {
  182. string soundName = "";
  183. FoodStageType currentFoodStage = GetFoodStageType();
  184. FoodStageType nextFoodStage = GetNextFoodStageType(m_CookedByMethod);
  185. if (currentFoodStage == FoodStageType.BURNED)
  186. {
  187. soundName = SOUND_BURNING_DONE;
  188. }
  189. else
  190. {
  191. switch (m_CookedByMethod)
  192. {
  193. case CookingMethodType.BAKING:
  194. {
  195. if (nextFoodStage == FoodStageType.BAKED)
  196. soundName = SOUND_BAKING_START;
  197. else if (currentFoodStage == FoodStageType.BAKED)
  198. soundName = SOUND_BAKING_DONE;
  199. else
  200. soundName = "";
  201. break;
  202. }
  203. case CookingMethodType.BOILING:
  204. {
  205. if (nextFoodStage == FoodStageType.BOILED)
  206. soundName = SOUND_BOILING_START;
  207. else if (currentFoodStage == FoodStageType.BOILED)
  208. soundName = SOUND_BOILING_DONE;
  209. else
  210. soundName = "";
  211. break;
  212. }
  213. case CookingMethodType.DRYING:
  214. {
  215. if (nextFoodStage == FoodStageType.DRIED)
  216. soundName = SOUND_DRYING_START;
  217. else if (currentFoodStage == FoodStageType.DRIED)
  218. soundName = SOUND_DRYING_DONE;
  219. else
  220. soundName = "";
  221. break;
  222. }
  223. default:
  224. soundName = "";
  225. break;
  226. }
  227. if (nextFoodStage == FoodStageType.BURNED)
  228. {
  229. if (soundName == "") //on 'bad' transitions only, indicates bad outcome
  230. {
  231. soundName = SOUND_BURNING_DONE;
  232. }
  233. else // pre-emptive burning sounds replace regular ones
  234. {
  235. array<float> nextStageProperties = new array<float>();
  236. nextStageProperties = FoodStage.GetAllCookingPropertiesForStage(nextFoodStage, null, GetType());
  237. float nextStageTime = nextStageProperties.Get(eCookingPropertyIndices.COOK_TIME);
  238. float progress01 = GetCookingTime() / nextStageTime;
  239. if (progress01 > Cooking.BURNING_WARNING_THRESHOLD)
  240. {
  241. soundName = SOUND_BURNING_DONE;
  242. }
  243. }
  244. }
  245. }
  246. SoundCookingStart(soundName);
  247. }
  248. protected void RemoveAudio()
  249. {
  250. m_MakeCookingSounds = false;
  251. SoundCookingStop();
  252. }
  253. //================================================================
  254. // SERIALIZATION
  255. //================================================================
  256. override void OnStoreSave(ParamsWriteContext ctx)
  257. {
  258. super.OnStoreSave(ctx);
  259. if (GetFoodStage())
  260. {
  261. GetFoodStage().OnStoreSave(ctx);
  262. }
  263. // food decay
  264. ctx.Write(m_DecayTimer);
  265. ctx.Write(m_LastDecayStage);
  266. }
  267. override bool OnStoreLoad(ParamsReadContext ctx, int version)
  268. {
  269. if (!super.OnStoreLoad(ctx, version))
  270. return false;
  271. if (GetFoodStage())
  272. {
  273. if (!GetFoodStage().OnStoreLoad(ctx, version))
  274. return false;
  275. }
  276. if (version >= 115)
  277. {
  278. if (!ctx.Read(m_DecayTimer))
  279. {
  280. m_DecayTimer = 0.0;
  281. return false;
  282. }
  283. if (!ctx.Read(m_LastDecayStage))
  284. {
  285. m_LastDecayStage = FoodStageType.NONE;
  286. return false;
  287. }
  288. }
  289. UpdateVisualsEx(true); //forced init visuals
  290. Synchronize();
  291. return true;
  292. }
  293. override void AfterStoreLoad()
  294. {
  295. super.AfterStoreLoad();
  296. Synchronize();
  297. }
  298. //get food stage
  299. override FoodStage GetFoodStage()
  300. {
  301. return m_FoodStage;
  302. }
  303. //food types
  304. override bool IsMeat()
  305. {
  306. return false;
  307. }
  308. override bool IsCorpse()
  309. {
  310. return false;
  311. }
  312. override bool IsFruit()
  313. {
  314. return false;
  315. }
  316. override bool IsMushroom()
  317. {
  318. return false;
  319. }
  320. //================================================================
  321. // NUTRITIONAL VALUES
  322. //================================================================
  323. //food properties
  324. static float GetFoodTotalVolume(ItemBase item, string classname = "", int food_stage = 0)
  325. {
  326. Edible_Base food_item = Edible_Base.Cast(item);
  327. if (food_item && food_item.GetFoodStage())
  328. {
  329. return FoodStage.GetFullnessIndex(food_item.GetFoodStage());
  330. }
  331. else if (classname != "" && food_stage)
  332. {
  333. return FoodStage.GetFullnessIndex(null, food_stage, classname);
  334. }
  335. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  336. return GetGame().ConfigGetFloat( class_path + " fullnessIndex" );
  337. }
  338. static float GetFoodEnergy(ItemBase item, string classname = "", int food_stage = 0)
  339. {
  340. Edible_Base food_item = Edible_Base.Cast(item);
  341. if (food_item && food_item.GetFoodStage())
  342. {
  343. return FoodStage.GetEnergy(food_item.GetFoodStage());
  344. }
  345. else if (classname != "" && food_stage)
  346. {
  347. return FoodStage.GetEnergy(null, food_stage, classname);
  348. }
  349. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  350. return GetGame().ConfigGetFloat( class_path + " energy" );
  351. }
  352. static float GetFoodWater(ItemBase item, string classname = "", int food_stage = 0)
  353. {
  354. Edible_Base food_item = Edible_Base.Cast(item);
  355. if (food_item && food_item.GetFoodStage())
  356. {
  357. return FoodStage.GetWater(food_item.GetFoodStage());
  358. }
  359. else if (classname != "" && food_stage)
  360. {
  361. return FoodStage.GetWater(null, food_stage, classname);
  362. }
  363. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  364. return GetGame().ConfigGetFloat( class_path + " water" );
  365. }
  366. static float GetFoodNutritionalIndex(ItemBase item, string classname = "", int food_stage = 0)
  367. {
  368. Edible_Base food_item = Edible_Base.Cast(item);
  369. if (food_item && food_item.GetFoodStage())
  370. {
  371. return FoodStage.GetNutritionalIndex(food_item.GetFoodStage());
  372. }
  373. else if (classname != "" && food_stage)
  374. {
  375. return FoodStage.GetNutritionalIndex(null, food_stage, classname);
  376. }
  377. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  378. return GetGame().ConfigGetFloat( class_path + " nutritionalIndex" );
  379. }
  380. static float GetFoodToxicity(ItemBase item, string classname = "", int food_stage = 0)
  381. {
  382. Edible_Base food_item = Edible_Base.Cast(item);
  383. if (food_item && food_item.GetFoodStage())
  384. {
  385. return FoodStage.GetToxicity(food_item.GetFoodStage());
  386. }
  387. else if (classname != "" && food_stage)
  388. {
  389. return FoodStage.GetToxicity(null, food_stage, classname);
  390. }
  391. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  392. return GetGame().ConfigGetFloat( class_path + " toxicity" );
  393. }
  394. static int GetFoodAgents(ItemBase item, string classname = "", int food_stage = 0)
  395. {
  396. Edible_Base food_item = Edible_Base.Cast(item);
  397. if (food_item && food_item.GetFoodStage())
  398. {
  399. return FoodStage.GetAgents(food_item.GetFoodStage());
  400. }
  401. else if (classname != "" && food_stage)
  402. {
  403. return FoodStage.GetAgents(null, food_stage, classname);
  404. }
  405. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  406. return GetGame().ConfigGetInt( class_path + " agents" );
  407. }
  408. static float GetFoodDigestibility(ItemBase item, string classname = "", int food_stage = 0)
  409. {
  410. Edible_Base food_item = Edible_Base.Cast(item);
  411. if (food_item && food_item.GetFoodStage())
  412. {
  413. return FoodStage.GetDigestibility(food_item.GetFoodStage());
  414. }
  415. else if (classname != "" && food_stage)
  416. {
  417. return FoodStage.GetDigestibility(null, food_stage, classname);
  418. }
  419. string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
  420. return GetGame().ConfigGetInt( class_path + " digestibility" );
  421. }
  422. static float GetAgentsPerDigest(ItemBase item, string className = "", int foodStage = 0)
  423. {
  424. Edible_Base foodItem = Edible_Base.Cast(item);
  425. if (foodItem && foodItem.GetFoodStage())
  426. {
  427. return FoodStage.GetAgentsPerDigest(foodItem.GetFoodStage());
  428. }
  429. else if (className != "" && foodStage)
  430. {
  431. return FoodStage.GetAgentsPerDigest(null, foodStage, className);
  432. }
  433. string classPath = string.Format("cfgVehicles %1 Nutrition", className);
  434. return GetGame().ConfigGetInt(classPath + " agentsPerDigest");
  435. }
  436. static NutritionalProfile GetNutritionalProfile(ItemBase item, string classname = "", int food_stage = 0)
  437. {
  438. NutritionalProfile profile = new NutritionalProfile();
  439. profile.m_Energy = GetFoodEnergy(item, classname, food_stage);
  440. profile.m_WaterContent = GetFoodWater(item, classname, food_stage);
  441. profile.m_NutritionalIndex = GetFoodNutritionalIndex(item, classname, food_stage);
  442. profile.m_FullnessIndex = GetFoodTotalVolume(item, classname, food_stage);
  443. profile.m_Toxicity = GetFoodToxicity(item, classname, food_stage);
  444. profile.m_Agents = GetFoodAgents(item, classname, food_stage);
  445. profile.m_Digestibility = GetFoodDigestibility(item, classname, food_stage);
  446. profile.m_AgentsPerDigest = GetAgentsPerDigest(item, classname, food_stage);
  447. return profile;
  448. }
  449. //================================================================
  450. // FOOD STAGING
  451. //================================================================
  452. FoodStageType GetFoodStageType()
  453. {
  454. return GetFoodStage().GetFoodStageType();
  455. }
  456. //food stage states
  457. bool IsFoodRaw()
  458. {
  459. if ( GetFoodStage() )
  460. {
  461. return GetFoodStage().IsFoodRaw();
  462. }
  463. return false;
  464. }
  465. bool IsFoodBaked()
  466. {
  467. if ( GetFoodStage() )
  468. {
  469. return GetFoodStage().IsFoodBaked();
  470. }
  471. return false;
  472. }
  473. bool IsFoodBoiled()
  474. {
  475. if ( GetFoodStage() )
  476. {
  477. return GetFoodStage().IsFoodBoiled();
  478. }
  479. return false;
  480. }
  481. bool IsFoodDried()
  482. {
  483. if ( GetFoodStage() )
  484. {
  485. return GetFoodStage().IsFoodDried();
  486. }
  487. return false;
  488. }
  489. bool IsFoodBurned()
  490. {
  491. if ( GetFoodStage() )
  492. {
  493. return GetFoodStage().IsFoodBurned();
  494. }
  495. return false;
  496. }
  497. bool IsFoodRotten()
  498. {
  499. if ( GetFoodStage() )
  500. {
  501. return GetFoodStage().IsFoodRotten();
  502. }
  503. return false;
  504. }
  505. //food stage change
  506. void ChangeFoodStage( FoodStageType new_food_stage_type )
  507. {
  508. GetFoodStage().ChangeFoodStage( new_food_stage_type );
  509. }
  510. FoodStageType GetNextFoodStageType( CookingMethodType cooking_method )
  511. {
  512. return GetFoodStage().GetNextFoodStageType( cooking_method );
  513. }
  514. string GetFoodStageName( FoodStageType food_stage_type )
  515. {
  516. return GetFoodStage().GetFoodStageName( food_stage_type );
  517. }
  518. bool CanChangeToNewStage( CookingMethodType cooking_method )
  519. {
  520. return GetFoodStage().CanChangeToNewStage( cooking_method );
  521. }
  522. //Use this to receive food stage from another Edible_Base
  523. void TransferFoodStage( notnull Edible_Base source )
  524. {
  525. if ( !source.GetFoodStage())
  526. return;
  527. m_LastDecayStage = source.GetLastDecayStage();
  528. ChangeFoodStage(source.GetFoodStage().GetFoodStageType());
  529. m_DecayTimer = source.GetDecayTimer();
  530. m_DecayDelta = source.GetDecayDelta();
  531. }
  532. //! called on server
  533. void OnFoodStageChange(FoodStageType stageOld, FoodStageType stageNew)
  534. {
  535. HandleFoodStageChangeAgents(stageOld,stageNew);
  536. UpdateVisualsEx(); //performed on server only
  537. }
  538. //! removes select agents on foodstage transitions
  539. void HandleFoodStageChangeAgents(FoodStageType stageOld, FoodStageType stageNew)
  540. {
  541. switch (stageNew)
  542. {
  543. case FoodStageType.BAKED:
  544. case FoodStageType.BOILED:
  545. case FoodStageType.DRIED:
  546. RemoveAllAgentsExcept(eAgents.BRAIN|eAgents.HEAVYMETAL);
  547. break;
  548. case FoodStageType.BURNED:
  549. RemoveAllAgentsExcept(eAgents.BRAIN|eAgents.HEAVYMETAL);
  550. break;
  551. }
  552. }
  553. //================================================================
  554. // COOKING
  555. //================================================================
  556. //cooking time
  557. float GetCookingTime()
  558. {
  559. return GetFoodStage().GetCookingTime();
  560. }
  561. void SetCookingTime( float time )
  562. {
  563. GetFoodStage().SetCookingTime( time );
  564. //synchronize when calling on server
  565. Synchronize();
  566. }
  567. void ResetCookingTime()
  568. {
  569. if (GetFoodStage())
  570. {
  571. GetFoodStage().SetCookingTime(0);
  572. Synchronize();
  573. }
  574. }
  575. //replace edible with new item (opening cans)
  576. void ReplaceEdibleWithNew( string typeName )
  577. {
  578. PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
  579. if (player)
  580. {
  581. ReplaceEdibleWithNewLambda lambda = new ReplaceEdibleWithNewLambda(this, typeName, player);
  582. player.ServerReplaceItemInHandsWithNew(lambda);
  583. }
  584. else
  585. Error("ReplaceEdibleWithNew - cannot use edible without player");
  586. }
  587. int GetConsumptionPenaltyContext()
  588. {
  589. return EConsumptionPenaltyContext.DRINK|EConsumptionPenaltyContext.EAT;
  590. }
  591. override void SetActions()
  592. {
  593. super.SetActions();
  594. AddAction(ActionAttach);
  595. AddAction(ActionDetach);
  596. }
  597. protected void SoundCookingStart(string sound_name)
  598. {
  599. #ifndef SERVER
  600. if (m_SoundPlaying != sound_name)
  601. {
  602. SoundCookingStop();
  603. m_SoundEffectCooking = SEffectManager.PlaySound(sound_name, GetPosition(), 0, 0, true);
  604. m_SoundPlaying = sound_name;
  605. }
  606. #endif
  607. }
  608. protected void SoundCookingStop()
  609. {
  610. #ifndef SERVER
  611. if (m_SoundEffectCooking)
  612. {
  613. m_SoundEffectCooking.Stop();
  614. m_SoundEffectCooking = null;
  615. m_SoundPlaying = "";
  616. }
  617. #endif
  618. }
  619. override bool CanDecay()
  620. {
  621. return false;
  622. }
  623. override bool CanProcessDecay()
  624. {
  625. return !GetIsFrozen() && ( GetFoodStageType() != FoodStageType.ROTTEN );
  626. }
  627. override void ProcessDecay( float delta, bool hasRootAsPlayer )
  628. {
  629. m_DecayDelta = 0.0;
  630. delta *= DayZGame.Cast(GetGame()).GetFoodDecayModifier();
  631. m_DecayDelta += ( 1 + ( 1 - GetHealth01( "", "" ) ) );
  632. if ( hasRootAsPlayer )
  633. m_DecayDelta += GameConstants.DECAY_RATE_ON_PLAYER;
  634. /*Print( "-------------------------" );
  635. Print( this );
  636. Print( m_DecayTimer );
  637. Print( m_DecayDelta );
  638. Print( m_LastDecayStage );*/
  639. if ( IsFruit() || IsMushroom() )
  640. {
  641. // fruit, vegetables and mushrooms
  642. if ( m_LastDecayStage != GetFoodStageType() )
  643. {
  644. switch ( GetFoodStageType() )
  645. {
  646. case FoodStageType.RAW:
  647. m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  648. m_LastDecayStage = FoodStageType.RAW;
  649. break;
  650. case FoodStageType.BOILED:
  651. m_DecayTimer = ( GameConstants.DECAY_FOOD_BOILED_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BOILED_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  652. m_LastDecayStage = FoodStageType.BOILED;
  653. break;
  654. case FoodStageType.BAKED:
  655. m_DecayTimer = ( GameConstants.DECAY_FOOD_BAKED_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BAKED_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  656. m_LastDecayStage = FoodStageType.BAKED;
  657. break;
  658. case FoodStageType.DRIED:
  659. case FoodStageType.BURNED:
  660. case FoodStageType.ROTTEN:
  661. default:
  662. m_DecayTimer = -1;
  663. m_LastDecayStage = FoodStageType.NONE;
  664. return;
  665. }
  666. //m_DecayTimer = m_DecayTimer / 1000.0;
  667. }
  668. m_DecayTimer -= ( delta * m_DecayDelta );
  669. if ( m_DecayTimer <= 0 )
  670. {
  671. if ( m_LastDecayStage != FoodStageType.NONE )
  672. {
  673. // switch to decayed stage
  674. if ( ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
  675. {
  676. ChangeFoodStage( FoodStageType.ROTTEN );
  677. }
  678. if ( m_LastDecayStage == FoodStageType.RAW )
  679. {
  680. int rng = Math.RandomIntInclusive( 0, 100 );
  681. if ( rng > GameConstants.DECAY_FOOD_FRVG_DRIED_CHANCE )
  682. {
  683. ChangeFoodStage( FoodStageType.ROTTEN );
  684. }
  685. else
  686. {
  687. if ( CanChangeToNewStage( FoodStageType.DRIED ) )
  688. {
  689. ChangeFoodStage( FoodStageType.DRIED );
  690. }
  691. else
  692. {
  693. ChangeFoodStage( FoodStageType.ROTTEN );
  694. }
  695. }
  696. }
  697. }
  698. }
  699. }
  700. else if ( IsMeat() )
  701. {
  702. // meat
  703. if ( m_LastDecayStage != GetFoodStageType() )
  704. {
  705. switch ( GetFoodStageType() )
  706. {
  707. case FoodStageType.RAW:
  708. m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  709. m_LastDecayStage = FoodStageType.RAW;
  710. break;
  711. case FoodStageType.BOILED:
  712. m_DecayTimer = ( GameConstants.DECAY_FOOD_BOILED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BOILED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  713. m_LastDecayStage = FoodStageType.BOILED;
  714. break;
  715. case FoodStageType.BAKED:
  716. m_DecayTimer = ( GameConstants.DECAY_FOOD_BAKED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BAKED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  717. m_LastDecayStage = FoodStageType.BAKED;
  718. break;
  719. case FoodStageType.DRIED:
  720. m_DecayTimer = ( GameConstants.DECAY_FOOD_DRIED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_DRIED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  721. m_LastDecayStage = FoodStageType.DRIED;
  722. break;
  723. case FoodStageType.BURNED:
  724. case FoodStageType.ROTTEN:
  725. default:
  726. m_DecayTimer = -1;
  727. m_LastDecayStage = FoodStageType.NONE;
  728. return;
  729. }
  730. }
  731. m_DecayTimer -= ( delta * m_DecayDelta );
  732. if ( m_DecayTimer <= 0 )
  733. {
  734. if ( m_LastDecayStage != FoodStageType.NONE )
  735. {
  736. // switch to decayed stage
  737. if ( ( m_LastDecayStage == FoodStageType.DRIED ) || ( m_LastDecayStage == FoodStageType.RAW ) || ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
  738. {
  739. ChangeFoodStage( FoodStageType.ROTTEN );
  740. }
  741. }
  742. }
  743. }
  744. else if ( IsCorpse() )
  745. {
  746. // corpse
  747. if ( m_LastDecayStage != GetFoodStageType() )
  748. {
  749. switch ( GetFoodStageType() )
  750. {
  751. case FoodStageType.RAW:
  752. m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_CORPSE + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_CORPSE * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  753. m_LastDecayStage = FoodStageType.RAW;
  754. break;
  755. case FoodStageType.BURNED:
  756. case FoodStageType.ROTTEN:
  757. default:
  758. m_DecayTimer = -1;
  759. m_LastDecayStage = FoodStageType.NONE;
  760. return;
  761. }
  762. }
  763. m_DecayTimer -= ( delta * m_DecayDelta );
  764. if ( m_DecayTimer <= 0 )
  765. {
  766. if ( m_LastDecayStage != FoodStageType.NONE )
  767. {
  768. // switch to decayed stage
  769. if ( ( m_LastDecayStage == FoodStageType.DRIED ) || ( m_LastDecayStage == FoodStageType.RAW ) || ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
  770. {
  771. ChangeFoodStage( FoodStageType.ROTTEN );
  772. }
  773. }
  774. }
  775. }
  776. else
  777. {
  778. // opened cans
  779. m_DecayTimer -= ( delta * m_DecayDelta );
  780. if ( ( m_DecayTimer <= 0 ) && ( m_LastDecayStage == FoodStageType.NONE ) )
  781. {
  782. m_DecayTimer = ( GameConstants.DECAY_FOOD_CAN_OPEN + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_DRIED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
  783. m_LastDecayStage = FoodStageType.RAW;
  784. //m_DecayTimer = m_DecayTimer / 1000.0;
  785. }
  786. else
  787. {
  788. if ( m_DecayTimer <= 0 )
  789. {
  790. InsertAgent(eAgents.FOOD_POISON, 1);
  791. m_DecayTimer = -1;
  792. }
  793. }
  794. }
  795. }
  796. protected void UpdateVaporParticle()
  797. {
  798. if (GetGame().IsDedicatedServer())
  799. return;
  800. if (m_VarTemperature >= GameConstants.STATE_HOT_LVL_TWO && !m_HotVaporParticle)
  801. {
  802. InventoryLocation invLoc = new InventoryLocation();
  803. GetInventory().GetCurrentInventoryLocation(invLoc);
  804. if (invLoc && (invLoc.GetType() == InventoryLocationType.GROUND || invLoc.GetType() == InventoryLocationType.HANDS || invLoc.GetType() == InventoryLocationType.ATTACHMENT))
  805. {
  806. ParticleManager ptcMgr = ParticleManager.GetInstance();
  807. if (ptcMgr)
  808. {
  809. m_HotVaporParticle = ParticleManager.GetInstance().PlayOnObject(ParticleList.ITEM_HOT_VAPOR, this);
  810. m_HotVaporParticle.SetParticleParam(EmitorParam.SIZE, 0.3);
  811. m_HotVaporParticle.SetParticleParam(EmitorParam.BIRTH_RATE, 10);
  812. m_HotVaporParticle.SetParticleAutoDestroyFlags(ParticleAutoDestroyFlags.ON_STOP);
  813. }
  814. }
  815. }
  816. else if (m_HotVaporParticle)
  817. {
  818. if (m_VarTemperature <= GameConstants.STATE_HOT_LVL_TWO)
  819. {
  820. m_HotVaporParticle.Stop();
  821. m_HotVaporParticle = null;
  822. return;
  823. }
  824. InventoryLocation inventoryLoc = new InventoryLocation();
  825. GetInventory().GetCurrentInventoryLocation(inventoryLoc);
  826. if (invLoc && (invLoc.GetType() != InventoryLocationType.GROUND && invLoc.GetType() != InventoryLocationType.HANDS))
  827. {
  828. m_HotVaporParticle.Stop();
  829. m_HotVaporParticle = null;
  830. }
  831. }
  832. }
  833. override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
  834. {
  835. if (GetFoodStage())
  836. {
  837. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_NUTRITIONS_DATA, "Food Nutritions Data", FadeColors.WHITE));
  838. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_PREV, "Food Stage Prev", FadeColors.WHITE));
  839. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_NEXT, "Food Stage Next", FadeColors.WHITE));
  840. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  841. }
  842. super.GetDebugActions(outputList);
  843. }
  844. override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  845. {
  846. super.OnAction(action_id, player, ctx);
  847. if ( GetGame().IsServer() )
  848. {
  849. if ( action_id == EActions.FOOD_STAGE_PREV )
  850. {
  851. int food_stage_prev = GetFoodStageType() - 1;
  852. if (food_stage_prev <= 0)
  853. {
  854. food_stage_prev = FoodStageType.COUNT - 1;
  855. }
  856. ChangeFoodStage(food_stage_prev);
  857. return true;
  858. }
  859. else if ( action_id == EActions.FOOD_STAGE_NEXT )
  860. {
  861. int food_stage_next = GetFoodStageType() + 1;
  862. if (food_stage_next >= FoodStageType.COUNT )
  863. {
  864. food_stage_next = FoodStageType.RAW;
  865. }
  866. ChangeFoodStage(food_stage_next);
  867. return true;
  868. }
  869. }
  870. #ifdef DIAG_DEVELOPER
  871. if (action_id == EActions.FOOD_NUTRITIONS_DATA)
  872. {
  873. PrintNutritionsData();
  874. return true;
  875. }
  876. #endif
  877. return false;
  878. }
  879. override string GetDebugText()
  880. {
  881. string debug_output;
  882. debug_output = super.GetDebugText();
  883. debug_output+="m_CookedByMethod:"+m_CookedByMethod+"\n";
  884. debug_output+="m_MakeCookingSounds:"+m_MakeCookingSounds+"\n";
  885. return debug_output;
  886. }
  887. //================================================================
  888. // GENERAL GETTERS
  889. //================================================================
  890. override float GetBaitEffectivity()
  891. {
  892. float ret = super.GetBaitEffectivity();
  893. if (IsFoodRotten())
  894. {
  895. ret *= 0.5;
  896. }
  897. return ret;
  898. }
  899. float GetDecayTimer()
  900. {
  901. return m_DecayTimer;
  902. }
  903. float GetDecayDelta()
  904. {
  905. return m_DecayDelta;
  906. }
  907. FoodStageType GetLastDecayStage()
  908. {
  909. return m_LastDecayStage;
  910. }
  911. #ifdef DIAG_DEVELOPER
  912. private void PrintNutritionsData()
  913. {
  914. string nutritionsData = "";
  915. FoodStage stage = GetFoodStage();
  916. FoodStageType stageType = stage.GetFoodStageType();
  917. NutritionalProfile profile = GetNutritionalProfile(this, ClassName(), stageType);
  918. if (profile)
  919. {
  920. nutritionsData = string.Format("Item: %1\n\n", this);
  921. nutritionsData += string.Format("Stage name: %1\n", GetFoodStageName(stageType));
  922. nutritionsData += string.Format("Energy: %1\n", profile.m_Energy);
  923. nutritionsData += string.Format("Water content: %1\n", profile.m_WaterContent);
  924. nutritionsData += string.Format("Nutritional index: %1\n", profile.m_NutritionalIndex);
  925. nutritionsData += string.Format("Fullness index: %1\n", profile.m_FullnessIndex);
  926. nutritionsData += string.Format("Toxicity (obsolete): %1\n", profile.m_Toxicity);
  927. nutritionsData += string.Format("Digestibility: %1\n", profile.m_Digestibility);
  928. if (profile.IsLiquid())
  929. nutritionsData += string.Format("Liquid type: %1\n", profile.m_LiquidClassname);
  930. nutritionsData += string.Format("Agents: %1\n", profile.m_Agents);
  931. nutritionsData += string.Format("Agents per consume: %1\n", profile.m_AgentsPerDigest);
  932. }
  933. nutritionsData += "-----\n";
  934. Debug.Log(nutritionsData);
  935. }
  936. #endif
  937. //////////////////////////////////////////
  938. //DEPRECATED
  939. //////////////////////////////////////////
  940. void UpdateVisuals()
  941. {
  942. UpdateVisualsEx();
  943. }
  944. }
  945. class ReplaceEdibleWithNewLambda : TurnItemIntoItemLambda
  946. {
  947. void ReplaceEdibleWithNewLambda(EntityAI old_item, string new_item_type, PlayerBase player) { }
  948. };