Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
edible_base.c
Go to the documentation of this file.
2{
3 const string DIRECT_COOKING_SLOT_NAME = "DirectCooking";
4
5 const string SOUND_BAKING_START = "Baking_SoundSet";
6 const string SOUND_BAKING_DONE = "Baking_Done_SoundSet";
7 const string SOUND_BOILING_START = "Boiling_SoundSet";
8 const string SOUND_BOILING_DONE = "Boiling_Done_SoundSet";
9 const string SOUND_DRYING_START = "Drying_SoundSet";
10 const string SOUND_DRYING_DONE = "Drying_Done_SoundSet";
11 const string SOUND_BURNING_DONE = "Food_Burning_SoundSet";
12
13 protected bool m_MakeCookingSounds;
14 protected SoundOnVehicle m_SoundCooking;
16 protected string m_SoundPlaying;
17 ref FoodStage m_FoodStage;
18 protected float m_DecayTimer;
19 protected float m_DecayDelta = 0.0;
22
23 private CookingMethodType m_CookedByMethod;
24
25 void Edible_Base()
26 {
27 if (HasFoodStage())
28 {
29 m_FoodStage = new FoodStage(this);
30
31 RegisterNetSyncVariableInt("m_FoodStage.m_FoodStageType", FoodStageType.NONE, FoodStageType.COUNT);
32 RegisterNetSyncVariableFloat("m_FoodStage.m_CookingTime", 0, 600, 0);
33
34 m_SoundPlaying = "";
35 m_CookedByMethod = CookingMethodType.NONE;
36 RegisterNetSyncVariableInt("m_CookedByMethod", CookingMethodType.NONE, CookingMethodType.COUNT);
37 RegisterNetSyncVariableBool("m_MakeCookingSounds");
38 }
39 }
40
41 override void EEInit()
42 {
43 super.EEInit();
44
45 UpdateVisualsEx(true); //forced init visuals, mostly for debugs and SP
46 }
47
48 override void EEDelete(EntityAI parent)
49 {
50 super.EEDelete(parent);
51
53
55 m_HotVaporParticle.Stop();
56 }
57
58 override void EEItemLocationChanged(notnull InventoryLocation oldLoc, notnull InventoryLocation newLoc)
59 {
60 super.EEItemLocationChanged(oldLoc, newLoc);
61
63 if (oldLoc.GetType() == InventoryLocationType.ATTACHMENT || oldLoc.GetType() == InventoryLocationType.CARGO)
64 {
65 switch (oldLoc.GetParent().GetType())
66 {
67 case "FryingPan":
68 case "Pot":
69 case "Cauldron":
70 case "SharpWoodenStick":
71 MakeSoundsOnClient(false);
72 break;
73 }
74
76 if (oldLoc.GetSlot() > -1 && InventorySlots.GetSlotName(oldLoc.GetSlot()).Contains(DIRECT_COOKING_SLOT_NAME))
77 {
78 MakeSoundsOnClient(false);
79 }
80 }
81
82 if (oldLoc.IsValid())
84
87 }
88
89 void UpdateVisualsEx(bool forced = false)
90 {
91 if (GetFoodStage())
92 GetFoodStage().UpdateVisualsEx(forced);
93 }
94
95 bool Consume(float amount, PlayerBase consumer)
96 {
97 AddQuantity(-amount, false, false);
98 OnConsume(amount, consumer);
99
100 return true;
101 }
102
103 void OnConsume(float amount, PlayerBase consumer)
104 {
105 if (GetTemperature() > PlayerConstants.CONSUMPTION_DAMAGE_TEMP_THRESHOLD)
106 {
107 consumer.ProcessDirectDamage(DamageType.CUSTOM, this, "", "EnviroDmg", "0 0 0", PlayerConstants.CONSUMPTION_DAMAGE_PER_BITE);
108 }
109 }
110
112 int FilterAgents(int agentsIn)
113 {
114 int foodStageType;
115
116 FoodStage foodStage = GetFoodStage();
117 if (foodStage)
118 foodStageType = foodStage.GetFoodStageType();
119
121 NutritionalProfile nutritionalProfile = GetNutritionalProfile(this, ClassName(), foodStageType);
122 if ((agentsIn & eAgents.SALMONELLA == eAgents.SALMONELLA) && (nutritionalProfile.m_Agents == 0 || nutritionalProfile.m_AgentsPerDigest == 0))
123 agentsIn &= ~eAgents.FOOD_POISON;
124
125 return agentsIn;
126 }
127
128 //food staging
129 override bool CanBeCooked()
130 {
131 return false;
132 }
133
134 override bool CanBeCookedOnStick()
135 {
136 return false;
137 }
138
139 override float GetTemperatureFreezeTime()
140 {
141 if (GetFoodStage())
142 {
143 switch (m_FoodStage.GetFoodStageType())
144 {
145 case FoodStageType.DRIED:
146 return super.GetTemperatureFreezeTime() * GameConstants.TEMPERATURE_FREEZE_TIME_COEF_DRIED;
147
148 case FoodStageType.BURNED:
149 return super.GetTemperatureFreezeTime() * GameConstants.TEMPERATURE_FREEZE_TIME_COEF_BURNED;
150
151 default:
152 return super.GetTemperatureFreezeTime();
153 }
154 }
155
156 return super.GetTemperatureFreezeTime();
157 }
158
159 override float GetTemperatureThawTime()
160 {
161 if (GetFoodStage())
162 {
163 switch (m_FoodStage.GetFoodStageType())
164 {
165 case FoodStageType.DRIED:
166 return super.GetTemperatureThawTime() * GameConstants.TEMPERATURE_THAW_TIME_COEF_DRIED;
167
168 case FoodStageType.BURNED:
169 return super.GetTemperatureThawTime() * GameConstants.TEMPERATURE_THAW_TIME_COEF_BURNED;
170
171 default:
172 return super.GetTemperatureThawTime();
173 }
174 }
175
176 return super.GetTemperatureThawTime();
177 }
178
179 override bool CanItemOverheat()
180 {
181 return super.CanItemOverheat() && (!GetFoodStage() || (IsFoodBurned() || !GetFoodStage().CanTransitionToFoodStageType(FoodStageType.BURNED))); //for foodstaged items - either is burned, or it can't get burned
182 }
183
184 //================================================================
185 // SYNCHRONIZATION
186 //================================================================
187 void Synchronize()
188 {
189 SetSynchDirty();
190 }
191
192 override void OnVariablesSynchronized()
193 {
194 super.OnVariablesSynchronized();
195
196 //UpdateVisualsEx(); //performed on client only
197
198 //update audio
200 {
201 RefreshAudio();
202 }
203 else
204 {
205 RemoveAudio();
206 }
207
208 if (CanHaveTemperature())
210 }
211
212 //================================================================
213 // AUDIO EFFECTS (WHEN ON DCS)
214 //================================================================
215 void MakeSoundsOnClient(bool soundstate, CookingMethodType cookingMethod = CookingMethodType.NONE)
216 {
217 m_MakeCookingSounds = soundstate;
218 m_CookedByMethod = cookingMethod;
219
220 Synchronize();
221 }
222
223 protected void RefreshAudio()
224 {
225 string soundName = "";
226
227 FoodStageType currentFoodStage = GetFoodStageType();
228 FoodStageType nextFoodStage = GetNextFoodStageType(m_CookedByMethod);
229
230 if (currentFoodStage == FoodStageType.BURNED)
231 {
232 soundName = SOUND_BURNING_DONE;
233 }
234 else
235 {
236 switch (m_CookedByMethod)
237 {
238 case CookingMethodType.BAKING:
239 {
240 if (nextFoodStage == FoodStageType.BAKED)
241 soundName = SOUND_BAKING_START;
242 else if (currentFoodStage == FoodStageType.BAKED)
243 soundName = SOUND_BAKING_DONE;
244 else
245 soundName = "";
246 break;
247 }
248
249 case CookingMethodType.BOILING:
250 {
251 if (nextFoodStage == FoodStageType.BOILED)
252 soundName = SOUND_BOILING_START;
253 else if (currentFoodStage == FoodStageType.BOILED)
254 soundName = SOUND_BOILING_DONE;
255 else
256 soundName = "";
257 break;
258 }
259
260 case CookingMethodType.DRYING:
261 {
262 if (nextFoodStage == FoodStageType.DRIED)
263 soundName = SOUND_DRYING_START;
264 else if (currentFoodStage == FoodStageType.DRIED)
265 soundName = SOUND_DRYING_DONE;
266 else
267 soundName = "";
268 break;
269 }
270
271 default:
272 soundName = "";
273 break;
274 }
275
276 if (nextFoodStage == FoodStageType.BURNED)
277 {
278 if (soundName == "") //on 'bad' transitions only, indicates bad outcome
279 {
280 soundName = SOUND_BURNING_DONE;
281 }
282 else // pre-emptive burning sounds replace regular ones
283 {
284 array<float> nextStageProperties = new array<float>();
285 nextStageProperties = FoodStage.GetAllCookingPropertiesForStage(nextFoodStage, null, GetType());
286 float nextStageTime = nextStageProperties.Get(eCookingPropertyIndices.COOK_TIME);
287 float progress01 = GetCookingTime() / nextStageTime;
288 if (progress01 > Cooking.BURNING_WARNING_THRESHOLD)
289 {
290 soundName = SOUND_BURNING_DONE;
291 }
292 }
293 }
294 }
295
296 SoundCookingStart(soundName);
297 }
298
299 protected void RemoveAudio()
300 {
301 m_MakeCookingSounds = false;
303 }
304
305 //================================================================
306 // SERIALIZATION
307 //================================================================
309 {
310 super.OnStoreSave(ctx);
311
312 if (GetFoodStage())
313 {
314 GetFoodStage().OnStoreSave(ctx);
315 }
316
317 // food decay
318 ctx.Write(m_DecayTimer);
319 ctx.Write(m_LastDecayStage);
320 }
321
322 override bool OnStoreLoad(ParamsReadContext ctx, int version)
323 {
324 if (!super.OnStoreLoad(ctx, version))
325 return false;
326
327 if (GetFoodStage())
328 {
329 if (!GetFoodStage().OnStoreLoad(ctx, version))
330 return false;
331 }
332
333 if (version >= 115)
334 {
335 if (!ctx.Read(m_DecayTimer))
336 {
337 m_DecayTimer = 0.0;
338 return false;
339 }
340 if (!ctx.Read(m_LastDecayStage))
341 {
343 return false;
344 }
345 }
346
347 UpdateVisualsEx(true); //forced init visuals
348 Synchronize();
349
350 return true;
351 }
352
353 override void AfterStoreLoad()
354 {
355 super.AfterStoreLoad();
356
357 Synchronize();
358 }
359
360 //get food stage
361 override FoodStage GetFoodStage()
362 {
363 return m_FoodStage;
364 }
365
366 //food types
367 override bool IsMeat()
368 {
369 return false;
370 }
371
372 override bool IsCorpse()
373 {
374 return false;
375 }
376
377 override bool IsFruit()
378 {
379 return false;
380 }
381
382 override bool IsMushroom()
383 {
384 return false;
385 }
386
387 //================================================================
388 // NUTRITIONAL VALUES
389 //================================================================
390 //food properties
391 static float GetFoodTotalVolume(ItemBase item, string classname = "", int food_stage = 0)
392 {
393 Edible_Base food_item = Edible_Base.Cast(item);
394 if (food_item && food_item.GetFoodStage())
395 {
396 return FoodStage.GetFullnessIndex(food_item.GetFoodStage());
397 }
398 else if (classname != "" && food_stage)
399 {
400 return FoodStage.GetFullnessIndex(null, food_stage, classname);
401 }
402 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
403 return GetGame().ConfigGetFloat( class_path + " fullnessIndex" );
404
405 }
406
407 static float GetFoodEnergy(ItemBase item, string classname = "", int food_stage = 0)
408 {
409 Edible_Base food_item = Edible_Base.Cast(item);
410 if (food_item && food_item.GetFoodStage())
411 {
412 return FoodStage.GetEnergy(food_item.GetFoodStage());
413 }
414 else if (classname != "" && food_stage)
415 {
416 return FoodStage.GetEnergy(null, food_stage, classname);
417 }
418 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
419 return GetGame().ConfigGetFloat( class_path + " energy" );
420 }
421
422 static float GetFoodWater(ItemBase item, string classname = "", int food_stage = 0)
423 {
424 Edible_Base food_item = Edible_Base.Cast(item);
425 if (food_item && food_item.GetFoodStage())
426 {
427 return FoodStage.GetWater(food_item.GetFoodStage());
428 }
429 else if (classname != "" && food_stage)
430 {
431 return FoodStage.GetWater(null, food_stage, classname);
432 }
433 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
434 return GetGame().ConfigGetFloat( class_path + " water" );
435 }
436
437 static float GetFoodNutritionalIndex(ItemBase item, string classname = "", int food_stage = 0)
438 {
439 Edible_Base food_item = Edible_Base.Cast(item);
440 if (food_item && food_item.GetFoodStage())
441 {
442 return FoodStage.GetNutritionalIndex(food_item.GetFoodStage());
443 }
444 else if (classname != "" && food_stage)
445 {
446 return FoodStage.GetNutritionalIndex(null, food_stage, classname);
447 }
448 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
449 return GetGame().ConfigGetFloat( class_path + " nutritionalIndex" );
450
451 }
452
453 static float GetFoodToxicity(ItemBase item, string classname = "", int food_stage = 0)
454 {
455 Edible_Base food_item = Edible_Base.Cast(item);
456 if (food_item && food_item.GetFoodStage())
457 {
458 return FoodStage.GetToxicity(food_item.GetFoodStage());
459 }
460 else if (classname != "" && food_stage)
461 {
462 return FoodStage.GetToxicity(null, food_stage, classname);
463 }
464 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
465 return GetGame().ConfigGetFloat( class_path + " toxicity" );
466 }
467
468 static int GetFoodAgents(ItemBase item, string classname = "", int food_stage = 0)
469 {
470 Edible_Base food_item = Edible_Base.Cast(item);
471 if (food_item && food_item.GetFoodStage())
472 {
473 return FoodStage.GetAgents(food_item.GetFoodStage());
474 }
475 else if (classname != "" && food_stage)
476 {
477 return FoodStage.GetAgents(null, food_stage, classname);
478 }
479 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
480 return GetGame().ConfigGetInt( class_path + " agents" );
481 }
482
483 static float GetFoodDigestibility(ItemBase item, string classname = "", int food_stage = 0)
484 {
485 Edible_Base food_item = Edible_Base.Cast(item);
486 if (food_item && food_item.GetFoodStage())
487 {
488 return FoodStage.GetDigestibility(food_item.GetFoodStage());
489 }
490 else if (classname != "" && food_stage)
491 {
492 return FoodStage.GetDigestibility(null, food_stage, classname);
493 }
494 string class_path = string.Format("cfgVehicles %1 Nutrition", classname);
495 return GetGame().ConfigGetInt( class_path + " digestibility" );
496 }
497
498 static float GetAgentsPerDigest(ItemBase item, string className = "", int foodStage = 0)
499 {
500 Edible_Base foodItem = Edible_Base.Cast(item);
501 if (foodItem && foodItem.GetFoodStage())
502 {
503 return FoodStage.GetAgentsPerDigest(foodItem.GetFoodStage());
504 }
505 else if (className != "" && foodStage)
506 {
507 return FoodStage.GetAgentsPerDigest(null, foodStage, className);
508 }
509 string classPath = string.Format("cfgVehicles %1 Nutrition", className);
510 return GetGame().ConfigGetInt(classPath + " agentsPerDigest");
511 }
512
513 static NutritionalProfile GetNutritionalProfile(ItemBase item, string classname = "", int food_stage = 0)
514 {
516 profile.m_Energy = GetFoodEnergy(item, classname, food_stage);
517 profile.m_WaterContent = GetFoodWater(item, classname, food_stage);
518 profile.m_NutritionalIndex = GetFoodNutritionalIndex(item, classname, food_stage);
519 profile.m_FullnessIndex = GetFoodTotalVolume(item, classname, food_stage);
520 profile.m_Toxicity = GetFoodToxicity(item, classname, food_stage);
521 profile.m_Agents = GetFoodAgents(item, classname, food_stage);
522 profile.m_Digestibility = GetFoodDigestibility(item, classname, food_stage);
523 profile.m_AgentsPerDigest = GetAgentsPerDigest(item, classname, food_stage);
524
525 return profile;
526 }
527
528 //================================================================
529 // FOOD STAGING
530 //================================================================
532 {
533 return GetFoodStage().GetFoodStageType();
534 }
535
536 //food stage states
538 {
539 if ( GetFoodStage() )
540 {
541 return GetFoodStage().IsFoodRaw();
542 }
543
544 return false;
545 }
546
548 {
549 if ( GetFoodStage() )
550 {
551 return GetFoodStage().IsFoodBaked();
552 }
553
554 return false;
555 }
556
558 {
559 if ( GetFoodStage() )
560 {
561 return GetFoodStage().IsFoodBoiled();
562 }
563
564 return false;
565 }
566
568 {
569 if ( GetFoodStage() )
570 {
571 return GetFoodStage().IsFoodDried();
572 }
573
574 return false;
575 }
576
578 {
579 if ( GetFoodStage() )
580 {
581 return GetFoodStage().IsFoodBurned();
582 }
583
584 return false;
585 }
586
588 {
589 if ( GetFoodStage() )
590 {
591 return GetFoodStage().IsFoodRotten();
592 }
593
594 return false;
595 }
596
597 //food stage change
598 void ChangeFoodStage( FoodStageType new_food_stage_type )
599 {
600 GetFoodStage().ChangeFoodStage( new_food_stage_type );
601 }
602
604 {
605 return GetFoodStage().GetNextFoodStageType( cooking_method );
606 }
607
608 string GetFoodStageName( FoodStageType food_stage_type )
609 {
610 return GetFoodStage().GetFoodStageName( food_stage_type );
611 }
612
614 {
615 return GetFoodStage().CanChangeToNewStage( cooking_method );
616 }
617
618 //Use this to receive food stage from another Edible_Base
619 void TransferFoodStage( notnull Edible_Base source )
620 {
621 if ( !source.GetFoodStage())
622 return;
623 m_LastDecayStage = source.GetLastDecayStage();
624 ChangeFoodStage(source.GetFoodStage().GetFoodStageType());
625 m_DecayTimer = source.GetDecayTimer();
626 m_DecayDelta = source.GetDecayDelta();
627 }
628
631 {
632 HandleFoodStageChangeAgents(stageOld,stageNew);
633 UpdateVisualsEx(); //performed on server only
634 }
635
638 {
639 switch (stageNew)
640 {
641 case FoodStageType.BAKED:
642 case FoodStageType.BOILED:
643 case FoodStageType.DRIED:
644 RemoveAllAgentsExcept(eAgents.BRAIN|eAgents.HEAVYMETAL);
645 break;
646
647 case FoodStageType.BURNED:
648 RemoveAllAgentsExcept(eAgents.BRAIN|eAgents.HEAVYMETAL);
649 break;
650 }
651 }
652
653 //================================================================
654 // COOKING
655 //================================================================
656 //cooking time
658 {
659 return GetFoodStage().GetCookingTime();
660 }
661
662 void SetCookingTime( float time )
663 {
664 GetFoodStage().SetCookingTime( time );
665
666 //synchronize when calling on server
667 Synchronize();
668 }
669
671 {
672 if (GetFoodStage())
673 {
674 GetFoodStage().SetCookingTime(0);
675 Synchronize();
676 }
677 }
678
679 //replace edible with new item (opening cans)
680 void ReplaceEdibleWithNew( string typeName )
681 {
682 PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
683 if (player)
684 {
685 ReplaceEdibleWithNewLambda lambda = new ReplaceEdibleWithNewLambda(this, typeName, player);
686 player.ServerReplaceItemInHandsWithNew(lambda);
687 }
688 else
689 Error("ReplaceEdibleWithNew - cannot use edible without player");
690 }
691
696
697 override void SetActions()
698 {
699 super.SetActions();
700
701 AddAction(ActionAttach);
703 }
704
705 protected void SoundCookingStart(string sound_name)
706 {
707 #ifndef SERVER
708 if (m_SoundPlaying != sound_name)
709 {
711
712 m_SoundEffectCooking = SEffectManager.PlaySound(sound_name, GetPosition(), 0, 0, true);
713 m_SoundPlaying = sound_name;
714 }
715 #endif
716 }
717
718 protected void SoundCookingStop()
719 {
720 #ifndef SERVER
722 {
725 m_SoundPlaying = "";
726 }
727 #endif
728 }
729
730 override bool CanDecay()
731 {
732 return false;
733 }
734
735 override bool CanProcessDecay()
736 {
737 return !GetIsFrozen() && ( GetFoodStageType() != FoodStageType.ROTTEN );
738 }
739
740 override void ProcessDecay( float delta, bool hasRootAsPlayer )
741 {
742 m_DecayDelta = 0.0;
743
744 delta *= DayZGame.Cast(GetGame()).GetFoodDecayModifier();
745 m_DecayDelta += ( 1 + ( 1 - GetHealth01( "", "" ) ) );
746 if ( hasRootAsPlayer )
747 m_DecayDelta += GameConstants.DECAY_RATE_ON_PLAYER;
748
749 /*Print( "-------------------------" );
750 Print( this );
751 Print( m_DecayTimer );
752 Print( m_DecayDelta );
753 Print( m_LastDecayStage );*/
754
755 if ( IsFruit() || IsMushroom() )
756 {
757 // fruit, vegetables and mushrooms
759 {
760 switch ( GetFoodStageType() )
761 {
762 case FoodStageType.RAW:
763 m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
765 break;
766
767 case FoodStageType.BOILED:
768 m_DecayTimer = ( GameConstants.DECAY_FOOD_BOILED_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BOILED_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
770 break;
771
772 case FoodStageType.BAKED:
773 m_DecayTimer = ( GameConstants.DECAY_FOOD_BAKED_FRVG + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BAKED_FRVG * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
775 break;
776
777 case FoodStageType.DRIED:
778 case FoodStageType.BURNED:
779 case FoodStageType.ROTTEN:
780 default:
781 m_DecayTimer = -1;
783 return;
784 }
785
786 //m_DecayTimer = m_DecayTimer / 1000.0;
787 }
788
789 m_DecayTimer -= ( delta * m_DecayDelta );
790
791 if ( m_DecayTimer <= 0 )
792 {
793 if ( m_LastDecayStage != FoodStageType.NONE )
794 {
795 // switch to decayed stage
796 if ( ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
797 {
799 }
800 if ( m_LastDecayStage == FoodStageType.RAW )
801 {
802 int rng = Math.RandomIntInclusive( 0, 100 );
803 if ( rng > GameConstants.DECAY_FOOD_FRVG_DRIED_CHANCE )
804 {
806 }
807 else
808 {
809 if ( CanChangeToNewStage( FoodStageType.DRIED ) )
810 {
812 }
813 else
814 {
816 }
817 }
818 }
819 }
820 }
821
822 }
823 else if ( IsMeat() )
824 {
825 // meat
827 {
828 switch ( GetFoodStageType() )
829 {
830 case FoodStageType.RAW:
831 m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
833 break;
834
835 case FoodStageType.BOILED:
836 m_DecayTimer = ( GameConstants.DECAY_FOOD_BOILED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BOILED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
838 break;
839
840 case FoodStageType.BAKED:
841 m_DecayTimer = ( GameConstants.DECAY_FOOD_BAKED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_BAKED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
843 break;
844
845 case FoodStageType.DRIED:
846 m_DecayTimer = ( GameConstants.DECAY_FOOD_DRIED_MEAT + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_DRIED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
848 break;
849
850 case FoodStageType.BURNED:
851 case FoodStageType.ROTTEN:
852 default:
853 m_DecayTimer = -1;
855 return;
856 }
857 }
858
859 m_DecayTimer -= ( delta * m_DecayDelta );
860
861 if ( m_DecayTimer <= 0 )
862 {
863 if ( m_LastDecayStage != FoodStageType.NONE )
864 {
865 // switch to decayed stage
866 if ( ( m_LastDecayStage == FoodStageType.DRIED ) || ( m_LastDecayStage == FoodStageType.RAW ) || ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
867 {
869 }
870 }
871 }
872 }
873 else if ( IsCorpse() )
874 {
875 // corpse
877 {
878 switch ( GetFoodStageType() )
879 {
880 case FoodStageType.RAW:
881 m_DecayTimer = ( GameConstants.DECAY_FOOD_RAW_CORPSE + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_RAW_CORPSE * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
883 break;
884
885 case FoodStageType.BURNED:
886 case FoodStageType.ROTTEN:
887 default:
888 m_DecayTimer = -1;
890 return;
891 }
892 }
893
894 m_DecayTimer -= ( delta * m_DecayDelta );
895
896 if ( m_DecayTimer <= 0 )
897 {
898 if ( m_LastDecayStage != FoodStageType.NONE )
899 {
900 // switch to decayed stage
901 if ( ( m_LastDecayStage == FoodStageType.DRIED ) || ( m_LastDecayStage == FoodStageType.RAW ) || ( m_LastDecayStage == FoodStageType.BOILED ) || ( m_LastDecayStage == FoodStageType.BAKED ) )
902 {
904 }
905 }
906 }
907 }
908 else
909 {
910 // opened cans
911 m_DecayTimer -= ( delta * m_DecayDelta );
912
913 if ( ( m_DecayTimer <= 0 ) && ( m_LastDecayStage == FoodStageType.NONE ) )
914 {
915 m_DecayTimer = ( GameConstants.DECAY_FOOD_CAN_OPEN + ( Math.RandomFloat01() * ( GameConstants.DECAY_FOOD_DRIED_MEAT * ( GameConstants.DECAY_TIMER_RANDOM_PERCENTAGE / 100.0 ) ) ) );
917 //m_DecayTimer = m_DecayTimer / 1000.0;
918 }
919 else
920 {
921 if ( m_DecayTimer <= 0 )
922 {
923 InsertAgent(eAgents.FOOD_POISON, 1);
924 m_DecayTimer = -1;
925 }
926 }
927 }
928 }
929
930 protected void UpdateVaporParticle()
931 {
932 if (GetGame().IsDedicatedServer())
933 return;
934
935 if (m_VarTemperature >= GameConstants.STATE_HOT_LVL_TWO && !m_HotVaporParticle)
936 {
938 GetInventory().GetCurrentInventoryLocation(invLoc);
939 if (invLoc && (invLoc.GetType() == InventoryLocationType.GROUND || invLoc.GetType() == InventoryLocationType.HANDS || invLoc.GetType() == InventoryLocationType.ATTACHMENT))
940 {
941 ParticleManager ptcMgr = ParticleManager.GetInstance();
942 if (ptcMgr)
943 {
944 m_HotVaporParticle = ParticleManager.GetInstance().PlayOnObject(ParticleList.ITEM_HOT_VAPOR, this);
948 }
949 }
950 }
951 else if (m_HotVaporParticle)
952 {
953 if (m_VarTemperature <= GameConstants.STATE_HOT_LVL_TWO)
954 {
955 m_HotVaporParticle.Stop();
956 m_HotVaporParticle = null;
957 return;
958 }
959
960 InventoryLocation inventoryLoc = new InventoryLocation();
961 GetInventory().GetCurrentInventoryLocation(inventoryLoc);
962 if (invLoc && (invLoc.GetType() != InventoryLocationType.GROUND && invLoc.GetType() != InventoryLocationType.HANDS))
963 {
964 m_HotVaporParticle.Stop();
965 m_HotVaporParticle = null;
966 }
967 }
968 }
969
970 override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
971 {
972 if (GetFoodStage())
973 {
974 outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_NUTRITIONS_DATA, "Food Nutritions Data", FadeColors.WHITE));
975 outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_PREV, "Food Stage Prev", FadeColors.WHITE));
976 outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.FOOD_STAGE_NEXT, "Food Stage Next", FadeColors.WHITE));
977 outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
978 }
979
980 super.GetDebugActions(outputList);
981 }
982
983 override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
984 {
985 super.OnAction(action_id, player, ctx);
986
987 if ( GetGame().IsServer() )
988 {
989 if ( action_id == EActions.FOOD_STAGE_PREV )
990 {
991 int food_stage_prev = GetFoodStageType() - 1;
992 if (food_stage_prev <= 0)
993 {
994 food_stage_prev = FoodStageType.COUNT - 1;
995 }
996 ChangeFoodStage(food_stage_prev);
997 return true;
998 }
999 else if ( action_id == EActions.FOOD_STAGE_NEXT )
1000 {
1001 int food_stage_next = GetFoodStageType() + 1;
1002 if (food_stage_next >= FoodStageType.COUNT )
1003 {
1004 food_stage_next = FoodStageType.RAW;
1005 }
1006 ChangeFoodStage(food_stage_next);
1007 return true;
1008 }
1009
1010 }
1011
1012 #ifdef DIAG_DEVELOPER
1013 if (action_id == EActions.FOOD_NUTRITIONS_DATA)
1014 {
1015 PrintNutritionsData();
1016 return true;
1017 }
1018 #endif
1019
1020 return false;
1021 }
1022
1023 override string GetDebugText()
1024 {
1025 string debug_output;
1026
1027 debug_output = super.GetDebugText();
1028
1029 debug_output+="m_CookedByMethod:"+m_CookedByMethod+"\n";
1030 debug_output+="m_MakeCookingSounds:"+m_MakeCookingSounds+"\n";
1031
1032 return debug_output;
1033 }
1034
1035 //================================================================
1036 // GENERAL GETTERS
1037 //================================================================
1038
1039 override float GetBaitEffectivity()
1040 {
1041 float ret = super.GetBaitEffectivity();
1042
1043 if (IsFoodRotten())
1044 {
1045 ret *= 0.5;
1046 }
1047
1048 return ret;
1049 }
1050
1052 {
1053 return m_DecayTimer;
1054 }
1055
1057 {
1058 return m_DecayDelta;
1059 }
1060
1065
1066 #ifdef DIAG_DEVELOPER
1067 private void PrintNutritionsData()
1068 {
1069 string nutritionsData = "";
1070
1071 FoodStage stage = GetFoodStage();
1072 FoodStageType stageType = stage.GetFoodStageType();
1073
1074 NutritionalProfile profile = GetNutritionalProfile(this, ClassName(), stageType);
1075 if (profile)
1076 {
1077 nutritionsData = string.Format("Item: %1\n\n", this);
1078 nutritionsData += string.Format("Stage name: %1\n", GetFoodStageName(stageType));
1079 nutritionsData += string.Format("Energy: %1\n", profile.m_Energy);
1080 nutritionsData += string.Format("Water content: %1\n", profile.m_WaterContent);
1081 nutritionsData += string.Format("Nutritional index: %1\n", profile.m_NutritionalIndex);
1082 nutritionsData += string.Format("Fullness index: %1\n", profile.m_FullnessIndex);
1083 nutritionsData += string.Format("Toxicity (obsolete): %1\n", profile.m_Toxicity);
1084 nutritionsData += string.Format("Digestibility: %1\n", profile.m_Digestibility);
1085
1086 if (profile.IsLiquid())
1087 nutritionsData += string.Format("Liquid type: %1\n", profile.m_LiquidClassname);
1088
1089 nutritionsData += string.Format("Agents: %1\n", profile.m_Agents);
1090 nutritionsData += string.Format("Agents per consume: %1\n", profile.m_AgentsPerDigest);
1091 }
1092
1093 nutritionsData += "-----\n";
1094
1095 Debug.Log(nutritionsData);
1096 }
1097 #endif
1098
1100 //DEPRECATED
1103 {
1104 UpdateVisualsEx();
1105 }
1106}
1107
1109{
1110 void ReplaceEdibleWithNewLambda(EntityAI old_item, string new_item_type, PlayerBase player) { }
Param4< int, int, string, int > TSelectableActionInfoWithColor
Definition entityai.c:97
eBleedingSourceType GetType()
void ActionDetach()
void AddAction(typename actionName)
Definition debug.c:2
override void OnStoreSave(ParamsWriteContext ctx)
static float GetAgentsPerDigest(ItemBase item, string className="", int foodStage=0)
bool IsFoodRaw()
FoodStageType GetFoodStageType()
string m_SoundPlaying
Definition edible_base.c:16
float m_DecayDelta
Definition edible_base.c:19
override string GetDebugText()
EffectSound m_SoundEffectCooking
DEPRECATED.
Definition edible_base.c:15
float GetDecayDelta()
bool m_MakeCookingSounds
Definition edible_base.c:13
FoodStageType GetNextFoodStageType(CookingMethodType cooking_method)
bool IsFoodBoiled()
void HandleFoodStageChangeAgents(FoodStageType stageOld, FoodStageType stageNew)
removes select agents on foodstage transitions
override bool IsMushroom()
int GetConsumptionPenaltyContext()
override bool IsFruit()
float GetDecayTimer()
void SoundCookingStart(string sound_name)
override bool OnStoreLoad(ParamsReadContext ctx, int version)
override bool IsCorpse()
override bool CanDecay()
override float GetBaitEffectivity()
static float GetFoodTotalVolume(ItemBase item, string classname="", int food_stage=0)
string GetFoodStageName(FoodStageType food_stage_type)
void OnFoodStageChange(FoodStageType stageOld, FoodStageType stageNew)
called on server
void SoundCookingStop()
static float GetFoodEnergy(ItemBase item, string classname="", int food_stage=0)
override bool IsMeat()
ParticleSource m_HotVaporParticle
Definition edible_base.c:21
float GetCookingTime()
void UpdateVisuals()
void SetCookingTime(float time)
static float GetFoodDigestibility(ItemBase item, string classname="", int food_stage=0)
void ResetCookingTime()
void RefreshAudio()
override void ProcessDecay(float delta, bool hasRootAsPlayer)
FoodStageType GetLastDecayStage()
override void SetActions()
SoundOnVehicle m_SoundCooking
Definition edible_base.c:14
float m_DecayTimer
Definition edible_base.c:18
static float GetFoodToxicity(ItemBase item, string classname="", int food_stage=0)
static float GetFoodNutritionalIndex(ItemBase item, string classname="", int food_stage=0)
static int GetFoodAgents(ItemBase item, string classname="", int food_stage=0)
override bool CanProcessDecay()
bool IsFoodRotten()
void ChangeFoodStage(FoodStageType new_food_stage_type)
void RemoveAudio()
override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
override FoodStage GetFoodStage()
void UpdateVaporParticle()
bool IsFoodBaked()
bool CanChangeToNewStage(CookingMethodType cooking_method)
ref FoodStage m_FoodStage
Definition edible_base.c:17
FoodStageType m_LastDecayStage
Definition edible_base.c:20
override void AfterStoreLoad()
bool IsFoodDried()
void ReplaceEdibleWithNew(string typeName)
static NutritionalProfile GetNutritionalProfile(ItemBase item, string classname="", int food_stage=0)
static float GetFoodWater(ItemBase item, string classname="", int food_stage=0)
bool IsFoodBurned()
override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
void TransferFoodStage(notnull Edible_Base source)
Wrapper class for managing sound through SEffectManager.
Definition effectsound.c:5
override void Stop()
Stops sound.
InventoryLocation.
provides access to slot configuration
Definition enmath.c:7
Entity which has the particle instance as an ObjectComponent.
static override Particle PlayOnObject(int particle_id, Object parent_obj, vector local_pos="0 0 0", vector local_ori="0 0 0", bool force_world_rotation=false)
Creates a particle emitter, attaches it on the given object and activates it.
proto native void SetParticleAutoDestroyFlags(ParticleAutoDestroyFlags flags)
Enables the particle to automatically clean up itself when ending or stopping.
override void SetParticleParam(int parameter_id, float value)
Set the value of a parameter of all emitors in the particle.
Manager class for managing Effect (EffectParticle, EffectSound)
static EffectSound PlaySound(string sound_set, vector position, float play_fade_in=0, float stop_fade_out=0, bool loop=false)
Create and play an EffectSound.
Serialization general interface. Serializer API works with:
Definition serializer.c:56
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
CookingMethodType
Definition cooking.c:2
DamageType
exposed from C++ (do not change)
EActions
Definition eactions.c:2
eAgents
Definition eagents.c:3
const string SOUND_BURNING_DONE
const string SOUND_BAKING_DONE
const string SOUND_DRYING_START
const string SOUND_BAKING_START
const string SOUND_DRYING_DONE
Edible_Base ItemBase ReplaceEdibleWithNewLambda(EntityAI old_item, string new_item_type, PlayerBase player)
const string SOUND_BOILING_DONE
const string SOUND_BOILING_START
float GetTemperature()
override bool CanHaveTemperature()
FoodStageType
Definition foodstage.c:2
proto native CGame GetGame()
void Error(string err)
Messagebox with error message.
Definition endebug.c:90
EmitorParam
Definition envisual.c:114
const int SAT_DEBUG_ACTION
Definition constants.c:454
class JsonUndergroundAreaTriggerData GetPosition
InventoryLocationType
types of Inventory Location
override void InsertAgent(int agent, float count=1)
Definition itembase.c:8795
override void RemoveAllAgentsExcept(int agent_to_keep)
Definition itembase.c:8790
bool AddQuantity(float value, bool destroy_config=true, bool destroy_forced=false)
add item quantity[related to varQuantity... config entry], destroy_config = true > if the quantity re...
Definition itembase.c:8202
bool HasFoodStage()
Definition itembase.c:7466
void ParticleManager(ParticleManagerSettings settings)
Constructor (ctor)
ParticleAutoDestroyFlags
Flags to pass to ParticleSource.SetParticleAutoDestroyFlags.