123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- class StomachItem
- {
- ref NutritionalProfile m_Profile;
- float m_Amount;
- int m_FoodStage;
- //bool m_IsLiquid;
- string m_ClassName;
- int m_Agents;
- protected float m_Temperature;
-
- void StomachItem(string class_name, float amount, NutritionalProfile profile,int foodstage, int agents, float temperature)
- {
- m_Amount = amount;
- m_Profile = profile;
- //m_IsLiquid = is_liquid;
- m_FoodStage = foodstage;
- m_ClassName = class_name;
- m_Agents = agents;
- m_Temperature = temperature;
- }
-
- string GetClassName()
- {
- return m_ClassName;
- }
-
- /*
- void SetLiquid(bool is_liquid)
- {
- m_IsLiquid = is_liquid;
- }
-
- bool IsLiquid()
- {
- return m_IsLiquid;
- }*/
-
- int GetFoodStage()
- {
- return m_FoodStage;
- }
-
- void SetFoodStage(int food_stage)
- {
- m_FoodStage = food_stage;
- }
-
- // returns grams or ml's of this item/liquid
- float GetAmount()
- {
- return m_Amount;
- }
-
- // adds grams or ml's of this item/liquid
- void AddAmount(float amount)
- {
- m_Amount += amount;
- }
-
- void AddAgents(int agents)
- {
- m_Agents = m_Agents | agents;
- }
-
- float GetTemperature()
- {
- return m_Temperature;
- }
-
- // adjust temperature based on the fraction of the new amount compared to the original amount
- void AddTemperature(float temperature, float fraction)
- {
- float currentTempFraction = (1 - 1/fraction) * m_Temperature;
- float newTempFraction = (1/fraction) * temperature;
-
- m_Temperature = currentTempFraction + newTempFraction;
- }
-
-
- // "digests" given amount, "outs" nutritional components, and returns 'true' if leads to complete item digestion(no amount left)
- bool ProcessDigestion(float digestion_points, out float water, out float energy, out float toxicity, out float volume, out int agents, out float consumed_amount)
- {
- agents = m_Agents;
- consumed_amount = GetNutritions(digestion_points, m_Profile, water, energy, toxicity);
- m_Amount -= consumed_amount;
- volume = m_Profile.GetFullnessIndex() * m_Amount;
- return(m_Amount < 0.001);
- }
-
- float GetNutritions(float digestion_points, NutritionalProfile profile, out float water, out float energy, out float toxicity)
- {
- float energy_per_unit = profile.GetEnergy() / 100;
- float water_per_unit = profile.GetWaterContent() / 100;
- float toxicity_per_unit = profile.GetToxicity();
- float digestability = profile.GetDigestibility();
-
- if (digestability == 0)//if undefined
- {
- digestability = 1;
- }
-
- float consumed_quantity = digestion_points * digestability;
-
- if (m_Amount < consumed_quantity)
- {
- consumed_quantity = m_Amount;
- }
- if (consumed_quantity > 0)
- {
- water = consumed_quantity * water_per_unit;
- energy = consumed_quantity * energy_per_unit;
- toxicity = consumed_quantity * toxicity_per_unit;
- }
- return consumed_quantity;
- }
- }
- class PlayerStomach
- {
- const int DIGESTING_WATER = 1;
- const int DIGESTING_ENERGY = 2;
-
- const int quantity_bit_offset = 16;
- const int id_bit_offset = 4;//based on food stage count(+1 for safe measure)
- static int CHECKSUM;
- const float DIGESTION_POINTS = PlayerConstants.DIGESTION_SPEED;
- const int ACCEPTABLE_QUANTITY_MAX = 32768;
- const int ACCEPTABLE_FOODSTAGE_MAX = FoodStageType.COUNT - 1;
- static ref map<string, int> m_NamesToIDs = new map<string, int>;
- static ref map<int, string> m_IDsToNames = new map<int, string>;
- static const bool m_InitData = PlayerStomach.InitData();
- ref array<ref StomachItem> m_StomachContents = new array<ref StomachItem>;
- int m_AgentTransferFilter;//bit mask that prevents agents set in the mask from passing to the player
- bool m_Digesting;
- int m_DigestingType;
- PlayerBase m_Player;
- float m_StomachVolume;
- protected float m_StomachTemperature;
- const int STORAGE_VERSION = 106;
-
-
- void PlayerStomach(PlayerBase player)
- {
- m_Player = player;
- }
-
- float GetStomachVolume()
- {
- return m_StomachVolume;
- }
-
- float GetStomachTemperature()
- {
- return m_StomachTemperature;
- }
-
- void ClearContents()
- {
- m_StomachContents.Clear();
- m_StomachVolume = 0.0;
- m_StomachTemperature = 0;
- }
-
- // Reduce content of the stomach by provided percentage
- void ReduceContents(float percent)
- {
- percent = Math.Clamp(percent, 0, 100);
- float reduction = percent * 0.01;
-
- foreach (StomachItem item : m_StomachContents)
- {
- item.AddAmount( -(item.GetAmount() * reduction) );
- }
-
- m_StomachVolume -= m_StomachVolume * reduction;
- }
-
- void SetAgentTransferFilter(int filter_agents)
- {
- m_AgentTransferFilter;
- }
-
- int GetAgentTransferFilter()
- {
- return m_AgentTransferFilter;
- }
-
- static void RegisterItem(string classname, int id)
- {
- int hash = classname.Hash();
- CHECKSUM = CHECKSUM^hash; //xor hash vs current checksum
- m_NamesToIDs.Insert(classname, id);
- m_IDsToNames.Insert(id, classname);
- }
-
- static string GetClassnameFromID(int id)
- {
- return m_IDsToNames.Get(id);
- }
-
- static int GetIDFromClassname(string name)
- {
- if (!m_NamesToIDs.Contains(name))
- return -1;
- return m_NamesToIDs.Get(name);
- }
-
- static bool InitData()
- {
- TStringArray all_paths = new TStringArray;
-
- all_paths.Insert("CfgVehicles");
- all_paths.Insert("cfgLiquidDefinitions");
-
- string config_path;
- string child_name;
- int scope;
- string path;
- int consumable_count;
- for(int i = 0; i < all_paths.Count(); i++)
- {
- config_path = all_paths.Get(i);
- int children_count = GetGame().ConfigGetChildrenCount(config_path);
-
- for(int x = 0; x < children_count; x++)
- {
- GetGame().ConfigGetChildName(config_path, x, child_name);
- path = config_path + " " + child_name;
- scope = GetGame().ConfigGetInt(config_path + " " + child_name + " scope");
- bool should_check = 1;
- if (config_path == "CfgVehicles" && scope == 0)
- {
- should_check = 0;
- }
-
- if (should_check)
- {
- bool has_nutrition = GetGame().ConfigIsExisting(path + " Nutrition");
- bool has_stages = GetGame().ConfigIsExisting(path + " Food");
-
- if (has_nutrition || has_stages)
- {
- //Print("child name:" + child_name);
- RegisterItem(child_name, consumable_count);//consumable_count value serves as an unique ID for each item
- consumable_count++;
- }
- }
- }
- }
- //Print("consumable_count " + consumable_count);
- return true;
- }
-
- int GetStorageVersion()
- {
- return STORAGE_VERSION;
- }
-
- bool IsDigesting()
- {
- return (m_DigestingType != 0);
- }
-
- int GetDigestingType()
- {
- return m_DigestingType;
- }
-
- protected void UpdateStomachTemperature()
- {
- m_StomachTemperature = 0;
-
- int stomachItemsCount = m_StomachContents.Count();
- if (stomachItemsCount == 0)
- return;
-
- StomachItem item;
-
- for (int i = 0; i < stomachItemsCount; i++)
- {
- item = m_StomachContents[i];
- m_StomachTemperature += item.GetTemperature();
- }
-
- m_StomachTemperature = m_StomachTemperature / stomachItemsCount;
- }
-
- void Update(float delta_time)
- {
- ProcessNutrients(delta_time);
- }
-
- void ProcessNutrients(float delta_time)
- {
- m_DigestingType = 0;
-
- StomachItem item;
- int stomachItemsCount = m_StomachContents.Count();
- if (stomachItemsCount == 0)
- return;
-
- float digestionPointsPerItem = (DIGESTION_POINTS / stomachItemsCount) * delta_time;
- m_StomachVolume = 0;//reset, it's accumulated with each pass
- for (int i = stomachItemsCount - 1; i >= 0; i--)
- {
- item = m_StomachContents[i];
- float water, energy, toxicity, volume, consumedAmount;
- int agents;
- if (item.ProcessDigestion(digestionPointsPerItem, water, energy, toxicity, volume, agents, consumedAmount))
- {
- m_StomachContents.Remove(i);
- UpdateStomachTemperature();
- }
- m_StomachVolume += volume;
- m_Player.GetStatEnergy().Add(energy);
- m_Player.GetStatWater().Add(water);
-
- if (energy > 0)
- m_DigestingType |= DIGESTING_ENERGY;
-
- if (water > 0)
- m_DigestingType |= DIGESTING_WATER;
-
- //! try amount from nutritions/food stage first
- float amountOfAgents = item.m_Profile.m_AgentsPerDigest;
- if (amountOfAgents == 0)
- amountOfAgents = consumedAmount;
-
- //! food poisoning specific override by bloody hands
- if ((item.m_Agents & eAgents.FOOD_POISON) == eAgents.FOOD_POISON && m_Player.HasBloodyHands())
- amountOfAgents = Math.Max(amountOfAgents, PlayerConstants.BLOODY_HANDS_FOOD_POISON_AGENT_INCREMENT);
- DigestAgents(agents, amountOfAgents);
- }
- }
-
- void DigestAgents(int agents, float quantity)
- {
- if (!agents)
- return;
- agents = agents & (~m_AgentTransferFilter);//filter against the agent filter mask
- int highestBit = Math.Log2(agents) + 1;
- for (int i = 0; i < highestBit; ++i)
- {
- int agent = (1 << i)& agents;
- if (agent)
- {
- float rndPct = Math.RandomFloatInclusive(PlayerConstants.STOMACH_DIGEST_AGENT_RANDOM_MIN, PlayerConstants.STOMACH_DIGEST_AGENT_RANDOM_MAX);
- if (rndPct != 0)
- quantity += quantity * rndPct;
- m_Player.m_AgentPool.DigestAgent(agent, quantity);
- }
- }
- }
- float GetVolumeContainingAgent(eAgents agent)
- {
- float amountByAgent = 0.0;
- foreach (StomachItem item : m_StomachContents)
- {
- if ((item.m_Agents & agent) == agent)
- amountByAgent += item.m_Amount;
- }
-
- return amountByAgent;
- }
- float GetVolumeContainingAgent01(eAgents agent)
- {
- float amount = GetVolumeContainingAgent(agent);
- if (amount > 0.0)
- return Math.InverseLerp(0.0, GetStomachVolume(), amount);
-
- return 0.0;
- }
- void PrintUpdate()
- {
- Print("================================");
- for(int i = 0; i < m_StomachContents.Count(); i++)
- {
- string itemname = m_StomachContents.Get(i).m_ClassName;
- float amount = m_StomachContents.Get(i).GetAmount();
- int food_stage = m_StomachContents.Get(i).GetFoodStage();
- int agents = m_StomachContents.Get(i).m_Agents;
- Print(">");
- Print("itemname:" + itemname);
- Print("amount:" + amount);
- Print("food_stage:" + food_stage);
- Print("agents:" + agents);
- Print(">");
- }
- Print("m_StomachVolume:" + m_StomachVolume);
- Print("================================");
- }
-
- void AddToStomach(string class_name, float amount, int food_stage = 0, int agents = 0, float temperature = 0)
- {
- if (GetIDFromClassname(class_name) == -1)
- return;
-
- NutritionalProfile profile = Liquid.GetNutritionalProfileByName(class_name);
- if (!profile)
- profile = Edible_Base.GetNutritionalProfile(null, class_name, food_stage);
-
- if (profile)
- {
- // sanity checks start
- if (amount > ACCEPTABLE_QUANTITY_MAX || amount < 0)
- amount = 0;
- if (food_stage < 0 || food_stage > ACCEPTABLE_FOODSTAGE_MAX)
- food_stage = FoodStageType.RAW;
- // sanity checks end
-
- agents = agents | profile.GetAgents();
- bool found = false;
- int count = m_StomachContents.Count();
- for(int i = 0; i < count; i++)
- {
- StomachItem stomachItem = m_StomachContents.Get(i);
- if (stomachItem.GetClassName() == class_name && stomachItem.m_Agents == agents)
- {
- if (profile.IsLiquid() || stomachItem.GetFoodStage() == food_stage)
- {
- float fraction = 1;
- if (amount != 0)
- fraction = (stomachItem.m_Amount + amount) / amount;
-
- stomachItem.AddTemperature(temperature, fraction);
- stomachItem.AddAmount(amount);
- stomachItem.AddAgents(agents); //nutrition profile agents
- found = true;
- }
- }
- }
-
- if (!found)
- m_StomachContents.Insert(new StomachItem(class_name, amount, profile, food_stage, agents, temperature));
-
- UpdateStomachTemperature();
- }
- }
-
- void OnStoreSave(ParamsWriteContext ctx)
- {
- ctx.Write(PlayerStomach.CHECKSUM);
- ctx.Write(m_StomachContents.Count());
- StomachItem stomachItem;
- for(int i = 0; i < m_StomachContents.Count();i++)
- {
- stomachItem = m_StomachContents.Get(i);
- int id = PlayerStomach.GetIDFromClassname(stomachItem.m_ClassName);
- //Print("SAVE id:" + id);
- //Print("SAVE id_bit_offset:" + id_bit_offset);
-
- int writeResult = stomachItem.m_FoodStage | (id << id_bit_offset);
- writeResult = writeResult | ((int)stomachItem.m_Amount << quantity_bit_offset);
- ctx.Write(writeResult);
- ctx.Write(stomachItem.m_Agents);
- ctx.Write((int)stomachItem.GetTemperature());
- //Print("SAVE writeResult:" + writeResult);
- }
- //Print("SAVE CHECKSUM:" + PlayerStomach.CHECKSUM);
- }
-
- bool OnStoreLoad(ParamsReadContext ctx, int version)
- {
- int checksum, count;
- if (!ctx.Read(checksum))
- {
- return false;
- }
-
- if (!ctx.Read(count))
- {
- return false;
- }
- for (int i = 0; i < count; ++i)
- {
- int value, agents, temperature;
- if (!ctx.Read(value))
- return false;
- if (!ctx.Read(agents))
- return false;
-
- if (version >= 140 && !ctx.Read(temperature))
- return false;
- if (checksum == CHECKSUM)//if checksum matches, add to stomach, otherwise throw the data away but go through the de-serialization to keep the stream intact
- {
- int amount = value >> quantity_bit_offset;//isolate amount bits
- int id_mask = Math.Pow(2, quantity_bit_offset) - 1;
- int id = (id_mask & value) >> id_bit_offset;//isolate id bits
- int food_mask = Math.Pow(2, id_bit_offset) - 1;
- int food_stage = value & food_mask;
- //Print("LOAD value:" + value);
- //Print("LOAD id:" + id);
- //Print("LOAD id_bit_offset:" + id_bit_offset);
- //Print("LOAD food_stage:" + food_stage);
- string classname = GetClassnameFromID(id);
- AddToStomach(classname, amount, food_stage, agents, temperature);
- }
- }
- //Print("LOAD checksum:" + checksum);
- if (checksum != CHECKSUM)
- {
- Print("Stomach checksum fail");
- }
- return true;
- }
- int GetDebugObject(array<ref Param> object_out)
- {
- int count = m_StomachContents.Count();
- for(int i = 0; i < m_StomachContents.Count();i++)
- {
- int id = PlayerStomach.GetIDFromClassname(m_StomachContents.Get(i).m_ClassName);
- int food_stage = m_StomachContents.Get(i).m_FoodStage;
- int agents = m_StomachContents.Get(i).m_Agents;
- float amount = m_StomachContents.Get(i).m_Amount;
- float temperature = m_StomachContents.Get(i).GetTemperature();
- Param5<int,int,int,float,float> p5 = new Param5<int,int,int,float,float>(id, food_stage, agents, amount, temperature);
- object_out.Insert(p5);
- }
- Param1<float> p1 = new Param1<float>(m_StomachVolume);
- object_out.Insert(p1);
- Param1<float> paramTemp = new Param1<float>(m_StomachTemperature);
- object_out.Insert(paramTemp);
- return count;
-
- }
- }
|