edible_base.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  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. super.GetDebugActions(outputList);
  836. if (GetFoodStage())
  837. {
  838. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_NUTRITIONS_DATA, "Food Nutritions Data", FadeColors.WHITE));
  839. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_PREV, "Food Stage Prev", FadeColors.WHITE));
  840. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_NEXT, "Food Stage Next", FadeColors.WHITE));
  841. }
  842. }
  843. override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  844. {
  845. super.OnAction(action_id, player, ctx);
  846. if ( GetGame().IsServer() )
  847. {
  848. if ( action_id == EActions.FOOD_STAGE_PREV )
  849. {
  850. int food_stage_prev = GetFoodStageType() - 1;
  851. if (food_stage_prev <= 0)
  852. {
  853. food_stage_prev = FoodStageType.COUNT - 1;
  854. }
  855. ChangeFoodStage(food_stage_prev);
  856. return true;
  857. }
  858. else if ( action_id == EActions.FOOD_STAGE_NEXT )
  859. {
  860. int food_stage_next = GetFoodStageType() + 1;
  861. if (food_stage_next >= FoodStageType.COUNT )
  862. {
  863. food_stage_next = FoodStageType.RAW;
  864. }
  865. ChangeFoodStage(food_stage_next);
  866. return true;
  867. }
  868. }
  869. #ifdef DIAG_DEVELOPER
  870. if (action_id == EActions.FOOD_NUTRITIONS_DATA)
  871. {
  872. PrintNutritionsData();
  873. return true;
  874. }
  875. #endif
  876. return false;
  877. }
  878. override string GetDebugText()
  879. {
  880. string debug_output;
  881. debug_output = super.GetDebugText();
  882. debug_output+="m_CookedByMethod:"+m_CookedByMethod+"\n";
  883. debug_output+="m_MakeCookingSounds:"+m_MakeCookingSounds+"\n";
  884. return debug_output;
  885. }
  886. //================================================================
  887. // GENERAL GETTERS
  888. //================================================================
  889. override float GetBaitEffectivity()
  890. {
  891. float ret = super.GetBaitEffectivity();
  892. if (IsFoodRotten())
  893. {
  894. ret *= 0.5;
  895. }
  896. return ret;
  897. }
  898. float GetDecayTimer()
  899. {
  900. return m_DecayTimer;
  901. }
  902. float GetDecayDelta()
  903. {
  904. return m_DecayDelta;
  905. }
  906. FoodStageType GetLastDecayStage()
  907. {
  908. return m_LastDecayStage;
  909. }
  910. #ifdef DIAG_DEVELOPER
  911. private void PrintNutritionsData()
  912. {
  913. string nutritionsData = "";
  914. FoodStage stage = GetFoodStage();
  915. FoodStageType stageType = stage.GetFoodStageType();
  916. NutritionalProfile profile = GetNutritionalProfile(this, ClassName(), stageType);
  917. if (profile)
  918. {
  919. nutritionsData = string.Format("Item: %1\n\n", this);
  920. nutritionsData += string.Format("Stage name: %1\n", GetFoodStageName(stageType));
  921. nutritionsData += string.Format("Energy: %1\n", profile.m_Energy);
  922. nutritionsData += string.Format("Water content: %1\n", profile.m_WaterContent);
  923. nutritionsData += string.Format("Nutritional index: %1\n", profile.m_NutritionalIndex);
  924. nutritionsData += string.Format("Fullness index: %1\n", profile.m_FullnessIndex);
  925. nutritionsData += string.Format("Toxicity (obsolete): %1\n", profile.m_Toxicity);
  926. nutritionsData += string.Format("Digestibility: %1\n", profile.m_Digestibility);
  927. if (profile.IsLiquid())
  928. nutritionsData += string.Format("Liquid type: %1\n", profile.m_LiquidClassname);
  929. nutritionsData += string.Format("Agents: %1\n", profile.m_Agents);
  930. nutritionsData += string.Format("Agents per consume: %1\n", profile.m_AgentsPerDigest);
  931. }
  932. nutritionsData += "-----\n";
  933. Debug.Log(nutritionsData);
  934. }
  935. #endif
  936. //////////////////////////////////////////
  937. //DEPRECATED
  938. //////////////////////////////////////////
  939. void UpdateVisuals()
  940. {
  941. UpdateVisualsEx();
  942. }
  943. }
  944. class ReplaceEdibleWithNewLambda : TurnItemIntoItemLambda
  945. {
  946. void ReplaceEdibleWithNewLambda(EntityAI old_item, string new_item_type, PlayerBase player) { }
  947. };