Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
playerstomach.c
Go to the documentation of this file.
2{
3 ref NutritionalProfile m_Profile;
4 float m_Amount;
5 int m_FoodStage;
6 //bool m_IsLiquid;
7 string m_ClassName;
8 int m_Agents;
9 protected float m_Temperature;
10
11 void StomachItem(string class_name, float amount, NutritionalProfile profile,int foodstage, int agents, float temperature)
12 {
13 m_Amount = amount;
14 m_Profile = profile;
15 //m_IsLiquid = is_liquid;
16 m_FoodStage = foodstage;
17 m_ClassName = class_name;
18 m_Agents = agents;
19 m_Temperature = temperature;
20 }
21
22 string GetClassName()
23 {
24 return m_ClassName;
25 }
26
27 /*
28 void SetLiquid(bool is_liquid)
29 {
30 m_IsLiquid = is_liquid;
31 }
32
33 bool IsLiquid()
34 {
35 return m_IsLiquid;
36 }*/
37
39 {
40 return m_FoodStage;
41 }
42
43 void SetFoodStage(int food_stage)
44 {
45 m_FoodStage = food_stage;
46 }
47
48 // returns grams or ml's of this item/liquid
49 float GetAmount()
50 {
51 return m_Amount;
52 }
53
54 // adds grams or ml's of this item/liquid
55 void AddAmount(float amount)
56 {
57 m_Amount += amount;
58 }
59
60 void AddAgents(int agents)
61 {
62 m_Agents = m_Agents | agents;
63 }
64
66 {
67 return m_Temperature;
68 }
69
70 // adjust temperature based on the fraction of the new amount compared to the original amount
71 void AddTemperature(float temperature, float fraction)
72 {
73 float currentTempFraction = (1 - 1/fraction) * m_Temperature;
74 float newTempFraction = (1/fraction) * temperature;
75
76 m_Temperature = currentTempFraction + newTempFraction;
77 }
78
79
80 // "digests" given amount, "outs" nutritional components, and returns 'true' if leads to complete item digestion(no amount left)
81 bool ProcessDigestion(float digestion_points, out float water, out float energy, out float toxicity, out float volume, out int agents, out float consumed_amount)
82 {
83 agents = m_Agents;
84 consumed_amount = GetNutritions(digestion_points, m_Profile, water, energy, toxicity);
85 m_Amount -= consumed_amount;
86 volume = m_Profile.GetFullnessIndex() * m_Amount;
87 return(m_Amount < 0.001);
88 }
89
90 float GetNutritions(float digestion_points, NutritionalProfile profile, out float water, out float energy, out float toxicity)
91 {
92 float energy_per_unit = profile.GetEnergy() / 100;
93 float water_per_unit = profile.GetWaterContent() / 100;
94 float toxicity_per_unit = profile.GetToxicity();
95 float digestability = profile.GetDigestibility();
96
97 if (digestability == 0)//if undefined
98 {
99 digestability = 1;
100 }
101
102 float consumed_quantity = digestion_points * digestability;
103
104 if (m_Amount < consumed_quantity)
105 {
106 consumed_quantity = m_Amount;
107 }
108 if (consumed_quantity > 0)
109 {
110 water = consumed_quantity * water_per_unit;
111 energy = consumed_quantity * energy_per_unit;
112 toxicity = consumed_quantity * toxicity_per_unit;
113 }
114 return consumed_quantity;
115 }
116}
117
118class PlayerStomach
119{
120 const int DIGESTING_WATER = 1;
121 const int DIGESTING_ENERGY = 2;
122
123 const int quantity_bit_offset = 16;
124 const int id_bit_offset = 4;//based on food stage count(+1 for safe measure)
125 static int CHECKSUM;
126 const float DIGESTION_POINTS = PlayerConstants.DIGESTION_SPEED;
127 const int ACCEPTABLE_QUANTITY_MAX = 32768;
129 static ref map<string, int> m_NamesToIDs = new map<string, int>;
130 static ref map<int, string> m_IDsToNames = new map<int, string>;
131 static const bool m_InitData = PlayerStomach.InitData();
133 int m_AgentTransferFilter;//bit mask that prevents agents set in the mask from passing to the player
138 protected float m_StomachTemperature;
139 const int STORAGE_VERSION = 106;
140
141
143 {
144 m_Player = player;
145 }
146
147
149 {
150 return m_StomachVolume;
151 }
152
154 {
156 }
157
159 {
160 m_StomachContents.Clear();
161 m_StomachVolume = 0.0;
163 }
164
165 // Reduce content of the stomach by provided percentage
166 void ReduceContents(float percent)
167 {
168 percent = Math.Clamp(percent, 0, 100);
169 float reduction = percent * 0.01;
170
171 foreach (StomachItem item : m_StomachContents)
172 {
173 item.AddAmount( -(item.GetAmount() * reduction) );
174 }
175
176 m_StomachVolume -= m_StomachVolume * reduction;
177 }
178
179 void SetAgentTransferFilter(int filter_agents)
180 {
182 }
183
185 {
187 }
188
189 static void RegisterItem(string classname, int id)
190 {
191 int hash = classname.Hash();
192 CHECKSUM = CHECKSUM^hash; //xor hash vs current checksum
193 m_NamesToIDs.Insert(classname, id);
194 m_IDsToNames.Insert(id, classname);
195 }
196
197 static string GetClassnameFromID(int id)
198 {
199 return m_IDsToNames.Get(id);
200 }
201
202 static int GetIDFromClassname(string name)
203 {
204 if (!m_NamesToIDs.Contains(name))
205 return -1;
206 return m_NamesToIDs.Get(name);
207 }
208
209 static bool InitData()
210 {
211 TStringArray all_paths = new TStringArray;
212
213 all_paths.Insert("CfgVehicles");
214 all_paths.Insert("cfgLiquidDefinitions");
215
216 string config_path;
217 string child_name;
218 int scope;
219 string path;
220 int consumable_count;
221 for(int i = 0; i < all_paths.Count(); i++)
222 {
223 config_path = all_paths.Get(i);
224 int children_count = GetGame().ConfigGetChildrenCount(config_path);
225
226 for(int x = 0; x < children_count; x++)
227 {
228 GetGame().ConfigGetChildName(config_path, x, child_name);
229 path = config_path + " " + child_name;
230 scope = GetGame().ConfigGetInt(config_path + " " + child_name + " scope");
231 bool should_check = 1;
232 if (config_path == "CfgVehicles" && scope == 0)
233 {
234 should_check = 0;
235 }
236
237 if (should_check)
238 {
239 bool has_nutrition = GetGame().ConfigIsExisting(path + " Nutrition");
240 bool has_stages = GetGame().ConfigIsExisting(path + " Food");
241
242 if (has_nutrition || has_stages)
243 {
244 //Print("child name:" + child_name);
245 RegisterItem(child_name, consumable_count);//consumable_count value serves as an unique ID for each item
246 consumable_count++;
247 }
248 }
249 }
250 }
251 //Print("consumable_count " + consumable_count);
252 return true;
253 }
254
256 {
257 return STORAGE_VERSION;
258 }
259
261 {
262 return (m_DigestingType != 0);
263 }
264
266 {
267 return m_DigestingType;
268 }
269
271 {
273
274 int stomachItemsCount = m_StomachContents.Count();
275 if (stomachItemsCount == 0)
276 return;
277
278 StomachItem item;
279
280 for (int i = 0; i < stomachItemsCount; i++)
281 {
282 item = m_StomachContents[i];
284 }
285
286 m_StomachTemperature = m_StomachTemperature / stomachItemsCount;
287 }
288
289 void Update(float delta_time)
290 {
291 ProcessNutrients(delta_time);
292 }
293
294 void ProcessNutrients(float delta_time)
295 {
296 m_DigestingType = 0;
297
298 StomachItem item;
299 int stomachItemsCount = m_StomachContents.Count();
300 if (stomachItemsCount == 0)
301 return;
302
303 float digestionPointsPerItem = (DIGESTION_POINTS / stomachItemsCount) * delta_time;
304 m_StomachVolume = 0;//reset, it's accumulated with each pass
305 for (int i = stomachItemsCount - 1; i >= 0; i--)
306 {
307 item = m_StomachContents[i];
308 float water, energy, toxicity, volume, consumedAmount;
309 int agents;
310
311 if (item.ProcessDigestion(digestionPointsPerItem, water, energy, toxicity, volume, agents, consumedAmount))
312 {
313 m_StomachContents.Remove(i);
315 }
316
317 m_StomachVolume += volume;
318 m_Player.GetStatEnergy().Add(energy);
319 m_Player.GetStatWater().Add(water);
320
321 if (energy > 0)
323
324 if (water > 0)
326
328 float amountOfAgents = item.m_Profile.m_AgentsPerDigest;
329 if (amountOfAgents == 0)
330 amountOfAgents = consumedAmount;
331
333 if ((item.m_Agents & eAgents.FOOD_POISON) == eAgents.FOOD_POISON && m_Player.HasBloodyHands())
334 amountOfAgents = Math.Max(amountOfAgents, PlayerConstants.BLOODY_HANDS_FOOD_POISON_AGENT_INCREMENT);
335
336 DigestAgents(agents, amountOfAgents);
337 }
338 }
339
340 void DigestAgents(int agents, float quantity)
341 {
342 if (!agents)
343 return;
344
345 agents = agents & (~m_AgentTransferFilter);//filter against the agent filter mask
346 int highestBit = Math.Log2(agents) + 1;
347 for (int i = 0; i < highestBit; ++i)
348 {
349 int agent = (1 << i)& agents;
350 if (agent)
351 {
352 float rndPct = Math.RandomFloatInclusive(PlayerConstants.STOMACH_DIGEST_AGENT_RANDOM_MIN, PlayerConstants.STOMACH_DIGEST_AGENT_RANDOM_MAX);
353 if (rndPct != 0)
354 quantity += quantity * rndPct;
355 m_Player.m_AgentPool.DigestAgent(agent, quantity);
356 }
357 }
358 }
359
361 {
362 float amountByAgent = 0.0;
363 foreach (StomachItem item : m_StomachContents)
364 {
365 if ((item.m_Agents & agent) == agent)
366 amountByAgent += item.m_Amount;
367 }
368
369 return amountByAgent;
370 }
371
373 {
374 float amount = GetVolumeContainingAgent(agent);
375 if (amount > 0.0)
376 return Math.InverseLerp(0.0, GetStomachVolume(), amount);
377
378 return 0.0;
379 }
380
382 {
383 Print("================================");
384 for(int i = 0; i < m_StomachContents.Count(); i++)
385 {
386 string itemname = m_StomachContents.Get(i).m_ClassName;
387 float amount = m_StomachContents.Get(i).GetAmount();
388 int food_stage = m_StomachContents.Get(i).GetFoodStage();
389 int agents = m_StomachContents.Get(i).m_Agents;
390 Print(">");
391 Print("itemname:" + itemname);
392 Print("amount:" + amount);
393 Print("food_stage:" + food_stage);
394 Print("agents:" + agents);
395 Print(">");
396 }
397 Print("m_StomachVolume:" + m_StomachVolume);
398 Print("================================");
399 }
400
401 void AddToStomach(string class_name, float amount, int food_stage = 0, int agents = 0, float temperature = 0)
402 {
403 if (GetIDFromClassname(class_name) == -1)
404 return;
405
406 NutritionalProfile profile = Liquid.GetNutritionalProfileByName(class_name);
407 if (!profile)
408 profile = Edible_Base.GetNutritionalProfile(null, class_name, food_stage);
409
410 if (profile)
411 {
412 // sanity checks start
413 if (amount > ACCEPTABLE_QUANTITY_MAX || amount < 0)
414 amount = 0;
415
416 if (food_stage < 0 || food_stage > ACCEPTABLE_FOODSTAGE_MAX)
417 food_stage = FoodStageType.RAW;
418 // sanity checks end
419
420 agents = agents | profile.GetAgents();
421 bool found = false;
422 int count = m_StomachContents.Count();
423 for(int i = 0; i < count; i++)
424 {
425 StomachItem stomachItem = m_StomachContents.Get(i);
426 if (stomachItem.GetClassName() == class_name && stomachItem.m_Agents == agents)
427 {
428 if (profile.IsLiquid() || stomachItem.GetFoodStage() == food_stage)
429 {
430 float fraction = 1;
431 if (amount != 0)
432 fraction = (stomachItem.m_Amount + amount) / amount;
433
434 stomachItem.AddTemperature(temperature, fraction);
435 stomachItem.AddAmount(amount);
436 stomachItem.AddAgents(agents); //nutrition profile agents
437 found = true;
438 }
439 }
440 }
441
442 if (!found)
443 m_StomachContents.Insert(new StomachItem(class_name, amount, profile, food_stage, agents, temperature));
444
446 }
447 }
448
450 {
451 ctx.Write(PlayerStomach.CHECKSUM);
452 ctx.Write(m_StomachContents.Count());
453 StomachItem stomachItem;
454 for(int i = 0; i < m_StomachContents.Count();i++)
455 {
456 stomachItem = m_StomachContents.Get(i);
457 int id = PlayerStomach.GetIDFromClassname(stomachItem.m_ClassName);
458 //Print("SAVE id:" + id);
459 //Print("SAVE id_bit_offset:" + id_bit_offset);
460
461 int writeResult = stomachItem.m_FoodStage | (id << id_bit_offset);
462 writeResult = writeResult | ((int)stomachItem.m_Amount << quantity_bit_offset);
463 ctx.Write(writeResult);
464 ctx.Write(stomachItem.m_Agents);
465 ctx.Write((int)stomachItem.GetTemperature());
466 //Print("SAVE writeResult:" + writeResult);
467 }
468 //Print("SAVE CHECKSUM:" + PlayerStomach.CHECKSUM);
469 }
470
471 bool OnStoreLoad(ParamsReadContext ctx, int version)
472 {
473 int checksum, count;
474 if (!ctx.Read(checksum))
475 {
476 return false;
477 }
478
479 if (!ctx.Read(count))
480 {
481 return false;
482 }
483 for (int i = 0; i < count; ++i)
484 {
485 int value, agents, temperature;
486 if (!ctx.Read(value))
487 return false;
488
489 if (!ctx.Read(agents))
490 return false;
491
492 if (version >= 140 && !ctx.Read(temperature))
493 return false;
494
495 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
496 {
497 int amount = value >> quantity_bit_offset;//isolate amount bits
498 int id_mask = Math.Pow(2, quantity_bit_offset) - 1;
499 int id = (id_mask & value) >> id_bit_offset;//isolate id bits
500 int food_mask = Math.Pow(2, id_bit_offset) - 1;
501 int food_stage = value & food_mask;
502 //Print("LOAD value:" + value);
503 //Print("LOAD id:" + id);
504 //Print("LOAD id_bit_offset:" + id_bit_offset);
505 //Print("LOAD food_stage:" + food_stage);
506 string classname = GetClassnameFromID(id);
507 AddToStomach(classname, amount, food_stage, agents, temperature);
508 }
509 }
510 //Print("LOAD checksum:" + checksum);
511 if (checksum != CHECKSUM)
512 {
513 Print("Stomach checksum fail");
514 }
515 return true;
516 }
517
519 {
520 int count = m_StomachContents.Count();
521 for(int i = 0; i < m_StomachContents.Count();i++)
522 {
523 int id = PlayerStomach.GetIDFromClassname(m_StomachContents.Get(i).m_ClassName);
524 int food_stage = m_StomachContents.Get(i).m_FoodStage;
525 int agents = m_StomachContents.Get(i).m_Agents;
526 float amount = m_StomachContents.Get(i).m_Amount;
527 float temperature = m_StomachContents.Get(i).GetTemperature();
528 Param5<int,int,int,float,float> p5 = new Param5<int,int,int,float,float>(id, food_stage, agents, amount, temperature);
529 object_out.Insert(p5);
530 }
531 Param1<float> p1 = new Param1<float>(m_StomachVolume);
532 object_out.Insert(p1);
533 Param1<float> paramTemp = new Param1<float>(m_StomachTemperature);
534 object_out.Insert(paramTemp);
535 return count;
536
537 }
538}
Param3 int
int m_Agents
PlayerSpawnPresetDiscreteItemSetSlotData name
one set for cargo
static NutritionalProfile GetNutritionalProfile(ItemBase item, string classname="", int food_stage=0)
Definition enmath.c:7
Serialization general interface. Serializer API works with:
Definition serializer.c:56
int GetFoodStage()
void SetFoodStage(int food_stage)
float m_Temperature
float GetNutritions(float digestion_points, NutritionalProfile profile, out float water, out float energy, out float toxicity)
void StomachItem(string class_name, float amount, NutritionalProfile profile, int foodstage, int agents, float temperature)
float GetAmount()
string GetClassName()
bool ProcessDigestion(float digestion_points, out float water, out float energy, out float toxicity, out float volume, out int agents, out float consumed_amount)
void AddTemperature(float temperature, float fraction)
void AddAmount(float amount)
void AddAgents(int agents)
float GetTemperature()
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
eAgents
Definition eagents.c:3
ref FoodStage m_FoodStage
FoodStageType
Definition foodstage.c:2
proto native CGame GetGame()
proto void Print(void var)
Prints content of variable to console/log.
array< string > TStringArray
Definition enscript.c:709
DayZPlayer m_Player
Definition hand_events.c:42
Icon x
void OnStoreSave(ParamsWriteContext ctx)
int GetStorageVersion()
class ModifierDebugObj STORAGE_VERSION
bool OnStoreLoad(ParamsReadContext ctx, int version)
class OptionSelectorMultistate extends OptionSelector class_name
int m_DigestingType
void AddToStomach(string class_name, float amount, int food_stage=0, int agents=0, float temperature=0)
void PrintUpdate()
float GetVolumeContainingAgent01(eAgents agent)
void ClearContents()
void ReduceContents(float percent)
const int ACCEPTABLE_QUANTITY_MAX
void UpdateStomachTemperature()
const int ACCEPTABLE_FOODSTAGE_MAX
int GetAgentTransferFilter()
bool IsDigesting()
float GetStomachTemperature()
const float DIGESTION_POINTS
class StomachItem DIGESTING_WATER
const int quantity_bit_offset
void DigestAgents(int agents, float quantity)
int GetDebugObject(array< ref Param > object_out)
const int DIGESTING_ENERGY
bool m_Digesting
void ProcessNutrients(float delta_time)
int GetDigestingType()
float m_StomachTemperature
float GetStomachVolume()
void SetAgentTransferFilter(int filter_agents)
ref array< ref StomachItem > m_StomachContents
const int id_bit_offset
float m_StomachVolume
float GetVolumeContainingAgent(eAgents agent)
int m_AgentTransferFilter
void PlayerStomach(PlayerBase player)