123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561 |
- enum CookingMethodType
- {
- NONE = 0, //no cooking method available
- BAKING = 1,
- BOILING = 2,
- DRYING = 3,
- TIME = 4,
-
- COUNT
- }
- class Cooking
- {
- static const float TIME_WITH_SUPPORT_MATERIAL_COEF = 1.0; //! time modifier used when not using support material
- static const float TIME_WITHOUT_SUPPORT_MATERIAL_COEF = 2.0; //! time modifier used when using support material
- static const float COOKING_FOOD_TIME_INC_VALUE = 2; //! time increase when cooking a food
- static const float COOKING_LARD_DECREASE_COEF = 25; //! how many units from quantity of lard are remove at each stage
- static const float COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_NONE = 25; //! how many units from quantity of item are removed at each FoodStage change when support material is NOT used
- static const float COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_LARD = 0; //! NOT USED.
- static const float DEFAULT_COOKING_TEMPERATURE = 150; //default temperature for cooking (e.g. cooking on stick)
- static const float FOOD_MAX_COOKING_TEMPERATURE = 150; //
- static const float PARAM_BURN_DAMAGE_COEF = 0.05; //value for calculating damage on items located in fireplace CargoGrid
- static const float LIQUID_BOILING_POINT = 150; //default boiling point for liquids, overriden by 'liquidBoilingThreshold' in cfgLiquidDefinitions
- static const float LIQUID_VAPOR_QUANTITY = 2; //vaporization quantity loss
- static const float SOLID_OVERHEAT_QUANTITY = 2; //solid overheat quantity loss
-
- static const float BURNING_WARNING_THRESHOLD = 0.75; //! 0..1, validly cooked item will pre-emptively start emitting burning sounds when this close to being burned
- typename COOKING_EQUIPMENT_POT = Pot;
- typename COOKING_EQUIPMENT_FRYINGPAN = FryingPan;
- typename COOKING_EQUIPMENT_CAULDRON = Cauldron;
- typename COOKING_INGREDIENT_LARD = Lard;
-
- protected float m_UpdateTime = 1; //set by the item/system using cooking
-
- void SetCookingUpdateTime(float val)
- {
- m_UpdateTime = val;
- }
-
- void ProcessItemToCook(notnull ItemBase pItem, ItemBase cookingEquip, Param2<CookingMethodType, float> pCookingMethod, out Param2<bool, bool> pStateFlags)
- {
- Edible_Base item_to_cook = Edible_Base.Cast(pItem);
- if (item_to_cook && item_to_cook.CanBeCooked())
- {
- //! update food
- UpdateCookingState(item_to_cook, pCookingMethod.param1, cookingEquip, pCookingMethod.param2);
-
- //check for done state for boiling and drying
- if (item_to_cook.IsFoodBoiled() || item_to_cook.IsFoodDried())
- {
- pStateFlags.param1 |= true;
- }
- //! check for done state from baking (exclude Lard from baked items)
- else if (item_to_cook.IsFoodBaked() && item_to_cook.Type() != Lard)
- {
- pStateFlags.param1 |= true;
- }
- //! check for burned state
- else if (item_to_cook.IsFoodBurned())
- {
- pStateFlags.param2 |= true;
- }
- }
- else
- {
- //add temperature to item
- if (pItem != cookingEquip) //1st order item already handled by the fireplace directly!
- AddTemperatureToItem(pItem, null, 0);
-
- int liquidType = pItem.GetLiquidType();
- bool handleLiquid = pItem.IsLiquidContainer() && liquidType != LIQUID_NONE;
- bool isLiquiBoiling = handleLiquid && pItem.GetTemperature() >= Liquid.GetBoilThreshold(liquidType);
-
- //handle items that can actually overheat
- if (pItem.CanItemOverheat())
- {
- //handle qty first
- if (pItem.HasQuantity() && pItem.GetQuantityNormalized() > 0)
- {
- if (handleLiquid)
- {
- if (pItem.IsItemOverheated() || isLiquiBoiling) //overheat causes qty loss here!
- pItem.AddQuantity(-LIQUID_VAPOR_QUANTITY,false);
- }
- else if (pItem.IsItemOverheated())
- {
- pItem.AddQuantity(-SOLID_OVERHEAT_QUANTITY,true);
- }
- }//next handle damage
- else if (!pItem.IsCookware() && pItem.IsItemOverheated()) //cookware already damaged by fireplace, skipping
- {
- pItem.DecreaseHealth(PARAM_BURN_DAMAGE_COEF * 100);
- }
- }
- else
- {
- if (!pItem.IsCookware()) //cookware already damaged by fireplace, skipping
- pItem.DecreaseHealth(PARAM_BURN_DAMAGE_COEF * 100);
-
- if (isLiquiBoiling)
- pItem.AddQuantity(-LIQUID_VAPOR_QUANTITY,false);
- }
-
- //last handle agents
- if (isLiquiBoiling)
- pItem.RemoveAllAgentsExcept(eAgents.HEAVYMETAL);
- }
- }
- //COOKING PROCESS
- //--- Cooking with equipment (pot)
- //Returns 1 if the item changed its cooking stage, 0 if not
- int CookWithEquipment(ItemBase cooking_equipment, float cooking_time_coef = 1)
- {
- bool is_empty = true;
-
- //check cooking conditions
- if (cooking_equipment == null)
- return 0;
-
- if (cooking_equipment.IsRuined())
- return 0;
-
- //manage items in cooking equipment
- Param2<bool, bool> stateFlags = new Param2<bool, bool>(false, false); // 1st - done; 2nd - burned
- Param2<CookingMethodType, float> cookingMethodWithTime = GetCookingMethodWithTimeOverride(cooking_equipment);
- if (cooking_time_coef != 1)
- cookingMethodWithTime.param2 = cooking_time_coef;
-
- //handle the cooking equipment/direct cooking first
- ProcessItemToCook(cooking_equipment, cooking_equipment, cookingMethodWithTime, stateFlags);
-
- //cooking method may have changed due to liquid evaporating, refresh..
- if (cooking_equipment.IsCookware() && cooking_equipment.IsLiquidContainer())
- {
- cookingMethodWithTime = GetCookingMethodWithTimeOverride(cooking_equipment);
- if (cooking_time_coef != 1)
- cookingMethodWithTime.param2 = cooking_time_coef;
- }
-
- //handle the cooking inside of a container last
- CargoBase cargo = cooking_equipment.GetInventory().GetCargo();
- if (cargo)
- {
- int count = cargo.GetItemCount();
- is_empty = count == 0;
-
- //process items
- for (int i = 0; i < count; i++)
- {
- ProcessItemToCook(ItemBase.Cast(cargo.GetItem(i)), cooking_equipment, cookingMethodWithTime, stateFlags);
- }
- }
-
- //manage equipment EFFECTS
- int liquidType = cooking_equipment.GetLiquidType();
- //handle liquid boiling EFFECTS
- if (cooking_equipment.IsLiquidContainer() && liquidType != LIQUID_NONE)
- {
- if (cooking_equipment.GetTemperature() >= Liquid.GetBoilThreshold(liquidType))
- {
- //handle boiling audiovisuals for any liquid container
- cooking_equipment.RefreshAudioVisualsOnClient(cookingMethodWithTime.param1, stateFlags.param1, is_empty, stateFlags.param2);
- }
- else
- {
- cooking_equipment.RemoveAudioVisualsOnClient();
- }
- }
- else if (cooking_equipment.IsCookware())
- {
- //handle non-boiling audiovisuals for cookware only
- cooking_equipment.RefreshAudioVisualsOnClient(cookingMethodWithTime.param1, stateFlags.param1, is_empty, stateFlags.param2);
- }
-
- return 1;
- }
-
- //Returns 1 if the item changed its cooking stage, 0 if not
- int CookOnStick( Edible_Base item_to_cook, float cook_time_inc )
- {
- if ( item_to_cook && item_to_cook.CanBeCookedOnStick() )
- {
- //update food
- return UpdateCookingStateOnStick( item_to_cook, cook_time_inc );
- }
-
- return 0;
- }
-
- //Returns 1 if the item changed its cooking stage, 0 if not
- protected int UpdateCookingState(Edible_Base item_to_cook, CookingMethodType cooking_method, ItemBase cooking_equipment, float cooking_time_coef)
- {
- //food properties
- float food_temperature = item_to_cook.GetTemperature();
-
- //{min_temperature, time_to_cook, max_temperature (optional)}
- //get next stage name - if next stage is not defined, next stage name will be empty "" and no cooking properties (food_min_temp, food_time_to_cook, food_max_temp) will be set
- FoodStageType new_stage_type = item_to_cook.GetNextFoodStageType(cooking_method);
-
- float food_min_temp = 0;
- float food_time_to_cook = 0;
-
- //Set next stage cooking properties if next stage possible
- if (item_to_cook.CanChangeToNewStage(cooking_method)) // new_stage_type != NONE
- {
- array<float> next_stage_cooking_properties = new array<float>();
- next_stage_cooking_properties = FoodStage.GetAllCookingPropertiesForStage(new_stage_type, null, item_to_cook.GetType());
-
- food_min_temp = next_stage_cooking_properties.Get(eCookingPropertyIndices.MIN_TEMP); //checked after temperature is changed
- food_time_to_cook = next_stage_cooking_properties.Get(eCookingPropertyIndices.COOK_TIME);
- }
-
- //add temperature
- AddTemperatureToItem(item_to_cook, cooking_equipment, food_min_temp);
-
- //decrease qty of burned items (or cookable items that can't be burned)
- if (item_to_cook.IsItemOverheated())
- DecreaseCookedItemQuantity(item_to_cook,COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_NONE);
-
- //add cooking time if the food can be cooked by this method
- if (food_min_temp > 0 && food_temperature >= food_min_temp)
- {
- //! enable cooking SoundEvent
- item_to_cook.MakeSoundsOnClient(true,cooking_method);
-
- float new_cooking_time = item_to_cook.GetCookingTime() + COOKING_FOOD_TIME_INC_VALUE * cooking_time_coef;
- item_to_cook.SetCookingTime(new_cooking_time);
-
- //progress to next stage
- if (item_to_cook.GetCookingTime() >= food_time_to_cook)
- {
- //! Change food stage to new, IF DIFFERENT
- if (item_to_cook.GetFoodStageType() != new_stage_type)
- {
- item_to_cook.ChangeFoodStage(new_stage_type);
-
- if (cooking_equipment && cooking_equipment != item_to_cook)
- {
- if (cooking_method == CookingMethodType.BAKING)
- {
- ItemBase lard = GetItemTypeFromCargo(COOKING_INGREDIENT_LARD, cooking_equipment);
- if (lard)
- {
- //decrease lard quantity
- float lardQuantity = lard.GetQuantity() - COOKING_LARD_DECREASE_COEF;
- lardQuantity = Math.Clamp(lardQuantity, 0, lard.GetQuantityMax());
- lard.SetQuantity(lardQuantity);
- }
- else
- {
- //! any foodstage without lard
- DecreaseCookedItemQuantity(item_to_cook, COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_NONE);
- }
- }
- }
- else
- {
- //! any foodstage without lard
- DecreaseCookedItemQuantity(item_to_cook, COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_NONE);
- }
- }
-
- //reset cooking time
- item_to_cook.ResetCookingTime();
-
- return 1;
- }
- }
- else
- {
- item_to_cook.MakeSoundsOnClient(false);
- }
-
- return 0;
- }
-
- //Returns 1 if the item changed its cooking stage, 0 if not
- protected int UpdateCookingStateOnStick( Edible_Base item_to_cook, float cook_time_inc )
- {
- //food properties
- float food_temperature = item_to_cook.GetTemperature();
-
- //{min_temperature, time_to_cook, max_temperature (optional)}
- //get next stage name - if next stage is not defined, next stage name will be empty "" and no cooking properties (food_min_temp, food_time_to_cook, food_max_temp) will be set
- FoodStageType new_stage_type = item_to_cook.GetNextFoodStageType( CookingMethodType.BAKING );
- float food_min_temp = 0;
- float food_time_to_cook = 0;
- bool is_done = false; // baked
- bool is_burned = false; // burned
-
- //Set next stage cooking properties if next stage possible
- if ( item_to_cook.CanChangeToNewStage( CookingMethodType.BAKING ) )
- {
- array<float> next_stage_cooking_properties = new array<float>;
- next_stage_cooking_properties = FoodStage.GetAllCookingPropertiesForStage( new_stage_type, null, item_to_cook.GetType() );
-
- food_min_temp = next_stage_cooking_properties.Get( eCookingPropertyIndices.MIN_TEMP );
- food_time_to_cook = next_stage_cooking_properties.Get( eCookingPropertyIndices.COOK_TIME );
- }
-
- if (item_to_cook.GetInventory().IsAttachment())
- {
- //add temperature
- AddTemperatureToItem(item_to_cook, null, food_min_temp);
- }
-
- //add cooking time if the food can be cooked by this method
- if (food_min_temp > 0 && food_temperature >= food_min_temp)
- {
- //refresh audio
- item_to_cook.MakeSoundsOnClient(true, CookingMethodType.BAKING);
-
- float new_cooking_time = item_to_cook.GetCookingTime() + cook_time_inc;
- item_to_cook.SetCookingTime( new_cooking_time );
-
- //progress to next stage
- if (item_to_cook.GetCookingTime() >= food_time_to_cook)
- {
- //! Change food stage to new, IF DIFFERENT
- if (item_to_cook.GetFoodStageType() != new_stage_type)
- {
- item_to_cook.ChangeFoodStage(new_stage_type);
-
- DecreaseCookedItemQuantity(item_to_cook, COOKING_FOOD_QUANTITY_DECREASE_AMOUNT_NONE);
- }
- //reset cooking time
- item_to_cook.ResetCookingTime();
- return 1;
- }
- }
- else
- {
- item_to_cook.MakeSoundsOnClient(false);
- }
-
- return 0;
- }
-
- void SmokeItem(Edible_Base item_to_cook, float cook_time_inc)
- {
- if (item_to_cook)
- {
- float new_cook_time = item_to_cook.GetCookingTime() + cook_time_inc;
- float drying_cook_time = FoodStage.GetCookingPropertyFromIndex(eCookingPropertyIndices.COOK_TIME, FoodStageType.DRIED, null, item_to_cook.GetType());
- float drying_cook_temp = FoodStage.GetCookingPropertyFromIndex(eCookingPropertyIndices.MIN_TEMP, FoodStageType.DRIED, null, item_to_cook.GetType());
- float itemTemp = item_to_cook.GetTemperature();
-
- if (itemTemp >= drying_cook_temp)
- {
- switch (item_to_cook.GetFoodStageType())
- {
- case FoodStageType.RAW:
- item_to_cook.SetCookingTime(new_cook_time);
-
- if (item_to_cook.GetCookingTime() >= drying_cook_time)
- {
- item_to_cook.ChangeFoodStage(FoodStageType.DRIED);
- item_to_cook.ResetCookingTime();
- }
- break;
-
- default:
- item_to_cook.SetCookingTime(new_cook_time);
-
- if (item_to_cook.GetCookingTime() >= drying_cook_time)
- {
- item_to_cook.ChangeFoodStage(FoodStageType.BURNED);
- item_to_cook.ResetCookingTime();
- }
- break;
- }
- }
- }
- }
-
- void TerminateCookingSounds(ItemBase pItem)
- {
- Edible_Base edible;
- if (pItem)
- {
- CargoBase cargo = pItem.GetInventory().GetCargo();
- if (cargo) // cookware
- {
- for (int i = 0; i < cargo.GetItemCount(); i++)
- {
- edible = Edible_Base.Cast(cargo.GetItem(i));
- if (edible)
- {
- edible.MakeSoundsOnClient(false);
- }
- }
- }
- else
- {
- edible = Edible_Base.Cast(pItem);
- if (edible)
- {
- edible.MakeSoundsOnClient(false);
- }
- }
- }
- }
-
- //! Cooking data
- protected ItemBase GetItemTypeFromCargo( typename item_type, ItemBase cooking_equipment )
- {
- CargoBase cargo = cooking_equipment.GetInventory().GetCargo();
- if (cargo)
- {
- for (int i = 0; i < cargo.GetItemCount(); i++)
- {
- EntityAI entity = cargo.GetItem(i);
- if (entity.Type() == item_type)
- {
- ItemBase item = ItemBase.Cast(entity);
-
- return item;
- }
- }
- }
-
- return null;
- }
-
- protected Param2<CookingMethodType, float> GetCookingMethodWithTimeOverride(ItemBase cooking_equipment)
- {
- if (cooking_equipment.IsCookware())
- {
- if (cooking_equipment.GetQuantity() > 0)
- {
- if (cooking_equipment.GetLiquidType() == LIQUID_GASOLINE)
- {
- //! when cooking in gasoline, jump to drying state(will be burnt then)
- return new Param2<CookingMethodType, float>(CookingMethodType.DRYING, TIME_WITHOUT_SUPPORT_MATERIAL_COEF);
- }
- return new Param2<CookingMethodType, float>(CookingMethodType.BOILING, TIME_WITH_SUPPORT_MATERIAL_COEF);
- }
-
- if (GetItemTypeFromCargo(COOKING_INGREDIENT_LARD, cooking_equipment))
- {
- //has lard in cargo, slower process
- return new Param2<CookingMethodType, float>(CookingMethodType.BAKING, TIME_WITH_SUPPORT_MATERIAL_COEF);
- }
- if (cooking_equipment.GetInventory().GetCargo().GetItemCount() > 0)
- {
- return new Param2<CookingMethodType, float>(CookingMethodType.BAKING, TIME_WITHOUT_SUPPORT_MATERIAL_COEF);
- }
-
- return new Param2<CookingMethodType, float>(CookingMethodType.NONE, TIME_WITHOUT_SUPPORT_MATERIAL_COEF);
- }
- else if (cooking_equipment.IsLiquidContainer() && cooking_equipment.GetQuantity() > 0 && cooking_equipment.GetLiquidType() != LIQUID_GASOLINE) //fake 'boiling' on liquid containers, for effects playback
- {
- return new Param2<CookingMethodType, float>(CookingMethodType.BOILING, TIME_WITH_SUPPORT_MATERIAL_COEF);
- }
-
- return new Param2<CookingMethodType, float>(CookingMethodType.BAKING, TIME_WITHOUT_SUPPORT_MATERIAL_COEF);
- }
-
- Edible_Base GetFoodOnStick( ItemBase stick_item )
- {
- Edible_Base food_on_stick = Edible_Base.Cast( stick_item.GetAttachmentByType( Edible_Base ) );
- return food_on_stick;
- }
-
- float GetTimeToCook( Edible_Base item_to_cook, CookingMethodType cooking_method )
- {
- FoodStageType food_stage_type = item_to_cook.GetNextFoodStageType( cooking_method );
- return FoodStage.GetCookingPropertyFromIndex( eCookingPropertyIndices.COOK_TIME, food_stage_type, null, item_to_cook.GetType());
- }
- float GetMinTempToCook( Edible_Base item_to_cook, CookingMethodType cooking_method )
- {
- FoodStageType food_stage_type = item_to_cook.GetNextFoodStageType( cooking_method );
- return FoodStage.GetCookingPropertyFromIndex( eCookingPropertyIndices.MIN_TEMP, food_stage_type, null, item_to_cook.GetType());
- }
-
- //add temperature to item
- protected void AddTemperatureToItem( ItemBase cooked_item, ItemBase cooking_equipment, float min_temperature )
- {
- if (!GetGame().IsServer())
- return;
-
- if (cooked_item == cooking_equipment) //solves direct cooking double heating
- return;
-
- if (cooked_item.CanHaveTemperature())
- {
- float itemTemp = cooked_item.GetTemperature();
- //set target temperature
- float targetTemp;
- if (!cooked_item.GetHierarchyRoot().GetCookingTargetTemperature(targetTemp)) //if not valid, fallback values enter the equation
- {
- if (cooking_equipment)
- targetTemp = cooking_equipment.GetTemperature();
- else
- targetTemp = DEFAULT_COOKING_TEMPERATURE;
- }
-
- //adjust temperature
- if (targetTemp != itemTemp || !cooked_item.IsFreezeThawProgressFinished())
- {
- float heatPermCoef = 1.0;
- if (cooking_equipment)
- heatPermCoef = cooking_equipment.GetHeatPermeabilityCoef();
- heatPermCoef *= cooked_item.GetHeatPermeabilityCoef();
- cooked_item.SetTemperatureEx(new TemperatureDataInterpolated(targetTemp,ETemperatureAccessTypes.ACCESS_COOKING,m_UpdateTime,GameConstants.TEMP_COEF_COOKING_DEFAULT,heatPermCoef));
- }
- }
- }
-
- protected void DecreaseCookedItemQuantity(notnull Edible_Base pItem, float pAmount = 0.0)
- {
- if (GetGame().IsServer())
- {
- float quantity = pItem.GetQuantity() - pAmount;
- quantity = Math.Clamp(quantity, 0, pItem.GetQuantityMax());
- pItem.SetQuantity(quantity);
- }
- }
-
- ////////////////////////////
- //DEPRECATED cooking stuff
- //! DEPRECATED
- protected CookingMethodType GetCookingMethod(ItemBase cooking_equipment)
- {
- if (cooking_equipment.Type() == COOKING_EQUIPMENT_POT || cooking_equipment.Type() == COOKING_EQUIPMENT_CAULDRON)
- {
- //has water, but not petrol dammit X)
- if (cooking_equipment.GetQuantity() > 0 && cooking_equipment.GetLiquidType() != LIQUID_GASOLINE)
- {
- return CookingMethodType.BOILING;
- }
-
- //has lard in cargo
- if (GetItemTypeFromCargo(COOKING_INGREDIENT_LARD, cooking_equipment))
- {
- return CookingMethodType.BAKING;
- }
- return CookingMethodType.DRYING;
- }
-
- if (cooking_equipment.Type() == COOKING_EQUIPMENT_FRYINGPAN)
- {
- if (GetItemTypeFromCargo(COOKING_INGREDIENT_LARD, cooking_equipment))
- {
- return CookingMethodType.BAKING;
- }
- return CookingMethodType.DRYING;
- }
- return CookingMethodType.NONE;
- }
- }
|