Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
recipebase.c
Go to the documentation of this file.
2 const int MAXIMUM_RESULTS = 10;
3 const float DEFAULT_SPAWN_DISTANCE = 0.5;
4 class RecipeBase
5 {
6  string m_ItemsToCreate[MAXIMUM_RESULTS];
7  ref array<string> m_Ingredients[MAX_NUMBER_OF_INGREDIENTS];
8  ref array<string> m_SoundCategories[MAX_NUMBER_OF_INGREDIENTS];
9 
11 
12  ItemBase m_IngredientsSorted[MAX_NUMBER_OF_INGREDIENTS]; //if the recipe is valid, this array will contain all ingredients sorted against the recipe ingredients
13 
14  //ref array<string> m_ItemsToCreate;
15 
16  //string m_Result;
17  ref array<ItemBase> m_IngredientsToBeDeleted = new array<ItemBase>;
18  string m_Name;
19 
20  int m_ID;
21  int m_NumberOfResults;
22  float m_AnimationLength = 1;//animation length in relative time units
23  float m_Specialty = 0;// value > 0 for roughness, value < 0 for precision
24  bool m_IsInstaRecipe;//should this recipe be performed instantly without animation
25  //bool m_IsActionType;//will this recipe be also a user action(only set true if you know what you are doing)
26  bool m_AnywhereInInventory;//is this recipe valid even when neither of the items is in hands
27  //array<string> ptr;
28 
29  float m_MinQuantityIngredient[MAX_NUMBER_OF_INGREDIENTS];
30  float m_MaxQuantityIngredient[MAX_NUMBER_OF_INGREDIENTS];
31  float m_MinDamageIngredient[MAX_NUMBER_OF_INGREDIENTS];
32  float m_MaxDamageIngredient[MAX_NUMBER_OF_INGREDIENTS];
33 
34  bool m_IngredientUseSoftSkills[MAX_NUMBER_OF_INGREDIENTS];
35  float m_IngredientAddHealth[MAX_NUMBER_OF_INGREDIENTS];
36  float m_IngredientAddQuantity[MAX_NUMBER_OF_INGREDIENTS];
37  float m_IngredientSetHealth[MAX_NUMBER_OF_INGREDIENTS];
38  bool m_IngredientDestroy[MAX_NUMBER_OF_INGREDIENTS];
39 
40 
41  bool m_ResultSetFullQuantity[MAXIMUM_RESULTS];
42  float m_ResultSetQuantity[MAXIMUM_RESULTS];
43  float m_ResultSetHealth[MAXIMUM_RESULTS];
44  float m_ResultSpawnDistance[MAXIMUM_RESULTS];
45  int m_ResultToInventory[MAXIMUM_RESULTS];
46  int m_ResultInheritsHealth[MAXIMUM_RESULTS];
47  int m_ResultInheritsColor[MAXIMUM_RESULTS];
48  int m_ResultReplacesIngredient[MAXIMUM_RESULTS];
49  bool m_ResultUseSoftSkills[MAXIMUM_RESULTS];
50 
51 
52 
53  void RecipeBase()
54  {
55 
56  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
57  {
58  m_Ingredients[i] = new array<string>;
59  m_SoundCategories[i] = new array<string>;
60  m_IngredientsSorted[i] = NULL;
61  }
62 
63  for(i = 0; i < MAXIMUM_RESULTS; i++)
64  {
65  m_ResultSpawnDistance[i] = DEFAULT_SPAWN_DISTANCE;
66  }
67 
68  m_NumberOfResults = 0;
69  //m_IsActionType = false;
70 
71  m_Name = "RecipeBase default name";
72  Init();
73  }
74 
75  void Init();
76 
77  float GetLengthInSecs()
78  {
79  return m_AnimationLength * CRAFTING_TIME_UNIT_SIZE;
80  }
81 
82  float GetSpecialty()
83  {
84  return m_Specialty;
85  }
86 
87  bool IsRecipeAnywhere()
88  {
89  return m_AnywhereInInventory;
90  }
91 
92  bool CheckIngredientMatch(ItemBase item1, ItemBase item2)
93  {
94  if( item1 == NULL || item2 == NULL ) return false;
95 
96  m_Items[0] = item1;
97  m_Items[1] = item2;
98 
99  bool found = false;
100  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)//all ingredients
101  {
102  found = false;
103  array<string> tempArray = m_Ingredients[i];
104  for(int x = 0; x < tempArray.Count(); x++)//particular ingredient array
105  {
106  for(int z = 0; z < MAX_NUMBER_OF_INGREDIENTS; z++)
107  {
108  if( m_Items[z] != NULL )
109  {
110  ItemBase item = m_Items[z];
111  if( tempArray.Get(x) == item.GetType() || GetGame().IsKindOf(item.GetType(),tempArray.Get(x)))
112  {
113  found = true;//we found a match
114  //m_IngredientsSorted.Insert(item);
115  m_IngredientsSorted[i] = item;
116  m_Items[z] = NULL;
117  }
118  }
119  if(found) break;//we found a match, no need to check the remaining ingredients
120  }
121  if(found) break;//we found a match, no need to check this m_Ingredient array
122  }
123  if(!found) return false;// no match within an m_Ingredient array, no reason to continue the search, recipe is invalid
124  }
125  if(found)
126  {
127  return true;
128  }
129  else
130  {
131  return false;
132  }
133  }
134 
135  void InsertIngredient(int index, string ingredient)
136  {
137  InsertIngredientEx(index, ingredient, "");
138  }
139 
140  void InsertIngredientEx(int index, string ingredient, string soundCategory)
141  {
142  array<string> ptr = m_Ingredients[index];
143  ptr.Insert(ingredient);
144  m_SoundCategories[index].Insert(soundCategory);
145  }
146 
147  void RemoveIngredient(int index, string ingredient)
148  {
149  array<string> ptr = m_Ingredients[index];
150  for(int i = 0; i < ptr.Count(); i++)
151  {
152  if(ptr[i] == ingredient)
153  {
154  ptr.Remove(i);
155  m_SoundCategories[index].Remove(i);
156  return;
157  }
158  }
159  }
160 
161 
162  void AddResult(string item)
163  {
164  m_ItemsToCreate[m_NumberOfResults] = item;
165  m_NumberOfResults++;
166  }
167 
168  string GetName()
169  {
170  return m_Name;
171  }
172 
173  bool IsInstaRecipe()
174  {
175  return m_IsInstaRecipe;
176  }
177 
178 
179 
180  //spawns results in the world
181  void SpawnItems(ItemBase ingredients[], PlayerBase player, array<ItemBase> spawned_objects/*out*/)
182  {
183  //vector item_position = player.GetPosition() + ( player.GetDirection() * 1 );
184  //Debug.Log("SpawnItems called","recipes");
185  spawned_objects.Clear();//just to make sure
186  EntityAI object = NULL;
187 
188  for(int i = 0; i < m_NumberOfResults; i++)
189  {
190  string item_to_spawn = m_ItemsToCreate[i];
191 
192  if( m_ResultInheritsColor[i] != -1 )
193  {
194  ItemBase item = ingredients[m_ResultInheritsColor[i]];
195  //string class_name = item.GetType();
196  string color = item.ConfigGetString("color");
197  string new_class_name = m_ItemsToCreate[i] + color;
198  item_to_spawn = new_class_name;
199  }
200 
201  if( m_ResultToInventory[i] == -1 )
202  {
203  Debug.Log(" = "+m_ResultToInventory[i].ToString(),"recipes");
204  /*
205  InventoryLocation inv_loc = new InventoryLocation;
206  if (player.GetInventory().FindFirstFreeLocationForNewEntity(item_to_spawn, FindInventoryLocationType.ANY, inv_loc))
207  {
208  object = SpawnItemOnLocation(item_to_spawn, inv_loc, false);
209  }
210  */
211  object = player.GetInventory().CreateInInventory(item_to_spawn);
212  }
213  else if (m_ResultToInventory[i] >= 0)
214  {
215  /*
216  object = player.SpawnEntityOnGroundOnCursorDir(item_to_spawn, 0.5);
217 
218  ItemBase item_swap_with = ingredients[m_ResultToInventory[i]];
219  player.SwapEntities(true, item_swap_with, EntityAI.Cast(object));
220  */
221  }
222  else if ( m_ResultToInventory[i] == -2 )
223  {
224  object = player.GetInventory().CreateEntityInCargo(item_to_spawn);
225  }
226  if( !object )
227  {
228  //spawning in inventory failed, spawning on the ground instead.....
229  object = player.SpawnEntityOnGroundOnCursorDir(item_to_spawn, m_ResultSpawnDistance[i]);
230  if( !object)
231  {
232  Error("failed to spawn entity "+item_to_spawn+" , make sure the classname exists and item can be spawned");
233  }
234  }
235  spawned_objects.Insert(ItemBase.Cast(object));
236  //Debug.Log("spawning item "+item_to_spawn,"recipes");
237  object = null;
238  }
239 
240  }
241 
242  //applies final modifications to results
243  void ApplyModificationsResults(ItemBase sorted[], array<ItemBase> results, ItemBase result, PlayerBase player)
244  {
245  float all_ingredients_health = 0;//this is used later in results
246  float all_ingredients_health01 = 0;//combined damage % of ingredients
247  int value_delta;
248  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
249  {
250  ItemBase ingrd = ItemBase.Cast(sorted[i]);
251  all_ingredients_health += ingrd.GetHealth("", "");//accumulate health of all ingredients, used in results
252  all_ingredients_health01 += ingrd.GetHealth01("", "");
253  }
254  //------------------- results ----------------------
255  for(i = 0; i < m_NumberOfResults; i++)
256  {
257  ItemBase res = results.Get(i);
258  if(!res)
259  {
260  continue;
261  }
262 
263  bool use_soft_skills = m_ResultUseSoftSkills[i];
264 
265  if( res.IsItemBase() )
266  {
267  value_delta = m_ResultSetQuantity[i];
268 
269  ItemBase resIb = ItemBase.Cast(res);
270 
271  if( use_soft_skills )
272  {
273  value_delta = player.GetSoftSkillsManager().AddSpecialtyBonus(value_delta, m_Specialty);
274  }
275 
276  if( !resIb.IsMagazine() )//is not a magazine
277  {
278  if( m_ResultSetFullQuantity[i] == 1 )//<------m_ResultSetFullQuantity
279  {
280  resIb.SetQuantityMax();
281  }
282  else if( value_delta != -1 )//<------m_ResultSetQuantity
283  {
284  resIb.SetQuantity( value_delta );
285  }
286  }
287  else//is magazine
288  {
289  Magazine mgzn = Magazine.Cast(resIb);
290  if( m_ResultSetFullQuantity[i] == 1 )//<------m_ResultSetFullQuantity
291  {
292  mgzn.ServerSetAmmoMax();
293  }
294  else if( value_delta != -1 )//<------m_ResultSetQuantity
295  {
296  mgzn.ServerSetAmmoCount( value_delta );
297  }
298  }
299  }
300  if( m_ResultSetHealth[i] != -1 )//<------m_ResultSetHealth
301  {
302  value_delta = m_ResultSetHealth[i];
303  if( use_soft_skills )
304  {
305  value_delta = player.GetSoftSkillsManager().AddSpecialtyBonus(value_delta, m_Specialty);
306  }
307  res.SetHealth("","",value_delta);
308  }
309  if( m_ResultInheritsHealth[i] != -1 )//<------m_ResultInheritsHealth
310  {
311  if( m_ResultInheritsHealth[i] >= 0 )
312  {
313  int ing_number = m_ResultInheritsHealth[i];
314  ItemBase ing = sorted[ing_number];
315 
316  if( ing )
317  {
318  //float ing_health = ing.GetHealth("","");
319  float ing_health01 = ing.GetHealth01("","");
320  res.SetHealth("", "", ing_health01 * res.GetMaxHealth("",""));
321  Debug.Log("Inheriting health from ingredient:"+m_ResultInheritsHealth[i].ToString(),"recipes");
322  }
323  }
324  else if( m_ResultInheritsHealth[i] == -2 )
325  {
326  //float average_health = all_ingredients_health / MAX_NUMBER_OF_INGREDIENTS;
327  float average_health01 = all_ingredients_health01 / MAX_NUMBER_OF_INGREDIENTS;
328  res.SetHealth("", "", average_health01 * res.GetMaxHealth("",""));
329  }
330  }
331 
332  if( m_ResultReplacesIngredient[i] != -1 )//<------ResultReplacesIngredient
333  {
334  if( m_ResultReplacesIngredient[i] > -1 )
335  {
336  int ing_num = m_ResultReplacesIngredient[i];
337  ItemBase ingr = sorted[ing_num];
338 
339  if( ingr )
340  {
341  MiscGameplayFunctions.TransferItemProperties(ingr, res);
342  MiscGameplayFunctions.TransferInventory(ingr, res, player);
343  }
344  }
345  }
346  }
347  }
348 
349 
350  void DeleleIngredientsPass()
351  {
352  for(int i = 0; i < m_IngredientsToBeDeleted.Count(); i++)
353  {
354  ItemBase ingredient = m_IngredientsToBeDeleted.Get(i);
355  ingredient.Delete();
356  }
357  m_IngredientsToBeDeleted.Clear();
358  }
359 
360  //applies final modifications to ingredients
361  void ApplyModificationsIngredients(ItemBase sorted[], PlayerBase player)
362  {
363  //---------------------- ingredients ----------------------
364  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
365  {
366  ItemBase ingredient = sorted[i];
367 
368  if( m_IngredientDestroy[i] == 1 )//<------m_IngredientDestroy
369  {
370  if( ingredient ) m_IngredientsToBeDeleted.Insert(ingredient);
371  //ingredient.Delete();
372  //sorted[i] = NULL;
373  }
374  else
375  {
376  bool use_soft_skills = m_IngredientUseSoftSkills[i];
377 
378  if( m_IngredientAddHealth[i] != 0 )//<------m_IngredientAddHealth
379  {
380  float health_delta = m_IngredientAddHealth[i];
381  if( use_soft_skills )
382  {
383  if(health_delta <0) health_delta = player.GetSoftSkillsManager().SubtractSpecialtyBonus(health_delta, m_Specialty);
384  else health_delta = player.GetSoftSkillsManager().AddSpecialtyBonus(health_delta, m_Specialty);
385  }
386  ingredient.AddHealth("","",health_delta);
387  }
388  else if(m_IngredientSetHealth[i] != -1)//<------m_IngredientSetHealth
389  {
390  float new_health = m_IngredientSetHealth[i];
391  ingredient.SetHealth("","",new_health);
392  }
393  if( m_IngredientAddQuantity[i] != 0 )//<------m_IngredientAddQuantity
394  {
395  float quantity_delta = m_IngredientAddQuantity[i];
396 
397  if( use_soft_skills )
398  {
399  if(quantity_delta <0) quantity_delta = player.GetSoftSkillsManager().SubtractSpecialtyBonus(quantity_delta, m_Specialty);
400  else quantity_delta = player.GetSoftSkillsManager().AddSpecialtyBonus(quantity_delta, m_Specialty);
401  }
402 
403  if( !ingredient.IsMagazine() )
404  {
405  ItemBase obj = ingredient;
406  bool isDestroyed = obj.AddQuantity(quantity_delta, true);
407  if( isDestroyed )
408  {
409  //if (obj) m_IngredientsToBeDeleted.Insert(obj);
410  continue;
411  }
412  }
413  else
414  {
415  Magazine mag = Magazine.Cast(ingredient);
416  int newQuantity = mag.GetAmmoCount() + quantity_delta;
417  if( newQuantity <= 0 )
418  {
419  if(mag) m_IngredientsToBeDeleted.Insert(mag);
420  continue;
421  }
422  else
423  {
424  mag.ServerSetAmmoCount( newQuantity );
425  }
426  }
427  }
428  }
429  }
430  }
431 
432  //checks the recipe conditions
433  bool CheckConditions(ItemBase sorted[])
434  {
435  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
436  {
437  ItemBase ingredient = sorted[i];
438  if( !ingredient.IsMagazine() )
439  {
440  if( ingredient.GetQuantityMax() !=0 && m_MinQuantityIngredient[i] >= 0 && ingredient.GetQuantity() < m_MinQuantityIngredient[i] )
441  {
442  //Debug.Log("Recipe condition check failing1: m_MinQuantityIngredient","recipes");
443  return false;
444  }
445  if( m_MaxQuantityIngredient[i] >= 0 && ingredient.GetQuantity() > m_MaxQuantityIngredient[i] )
446  {
447  //Debug.Log("Recipe condition check failing1: m_MaxQuantityIngredient","recipes");
448  return false;
449  }
450  }
451  else
452  {
453  Magazine mag1 = Magazine.Cast(ingredient);
454  if( m_MinQuantityIngredient[i] >= 0 && mag1.GetAmmoCount() < m_MinQuantityIngredient[i] )
455  {
456  //Debug.Log("Recipe condition check failing1: m_MinQuantityIngredient[0]","recipes");
457  return false;
458  }
459  if( m_MaxQuantityIngredient[i] >= 0 && mag1.GetAmmoCount() > m_MaxQuantityIngredient[i] )
460  {
461  //Debug.Log("Recipe condition check failing1: m_MaxQuantityIngredient[0]","recipes");
462  return false;
463  }
464  }
465  int dmg3 = ingredient.GetHealthLevel();
466  if( m_MinDamageIngredient[i] >= 0 && ingredient.GetHealthLevel() < m_MinDamageIngredient[i] )
467  {
468  int dmg = ingredient.GetHealthLevel();
469  //Debug.Log("Recipe condition check failing1: m_MinDamageIngredient[0]","recipes");
470  return false;
471  }
472  if( m_MaxDamageIngredient[i] >= 0 && ingredient.GetHealthLevel() > m_MaxDamageIngredient[i] )
473  {
474  int dmg2 = ingredient.GetHealthLevel();
475  //Debug.Log("Recipe condition check failing1: m_MaxDamageIngredient[0]","recipes");
476  return false;
477  }
478  }
479  return true;
480  }
481 
482  //checks overall validity of this recipe
483  bool CheckRecipe(ItemBase item1, ItemBase item2, PlayerBase player)
484  {
485  if( item1 == NULL || item2 == NULL )
486  {
487  Error("recipe invalid, at least one of the ingredients is NULL");
488  return false;
489  }
490 
491  ItemBase item_in_hand = player.GetItemInHands();
492 
493  if( !IsRecipeAnywhere() && (item1 != item_in_hand && item2 != item_in_hand) )
494  {
495  return false;
496  }
497 
498  m_IngredientsSorted[0] = item1;
499  m_IngredientsSorted[1] = item2;
500 
501  if( CanDo( m_IngredientsSorted, player ) && CheckConditions( m_IngredientsSorted ) )
502  {
503  return true;
504  }
505  return false;
506  }
507 
508  void OnSelectedRecipe(ItemBase item1, ItemBase item2, PlayerBase player)
509  {
510  if( item1 == NULL || item2 == NULL )
511  {
512  Error("CheckRecipe: recipe invalid, at least one of the ingredients is NULL");
513  //Debug.Log("recipe invalid, at least one of the ingredients is NULL","recipes");
514  return;
515  }
516  OnSelected(item1,item2,player);
517  }
518 
519  void OnSelected(ItemBase item1, ItemBase item2, PlayerBase player)
520  {
521 
522  }
523 
524  //performs this recipe
525  void PerformRecipe(ItemBase item1, ItemBase item2, PlayerBase player)
526  {
527  if( item1 == NULL || item2 == NULL )
528  {
529  Error("PerformRecipe: recipe invalid, at least one of the ingredients is NULL");
530  Debug.Log("PerformRecipe: at least one of the ingredients is NULL","recipes");
531  }
532  /*
533  m_IngredientsSorted[0] = item1;
534  m_IngredientsSorted[1] = item2;
535  */
536 
537  /*
538  Debug.Log("PerformRecipe Ingredient 1: "+ToString(item1.Ptr().GetType()),"recipes");
539  Debug.Log("PerformRecipe Ingredient 2: "+ToString(item2.Ptr().GetType()),"recipes");
540  */
541  if( CheckRecipe(item1,item2,player) )
542  {
543  array<ItemBase> spawned_objects = new array<ItemBase>;
544  SpawnItems(m_IngredientsSorted, player,spawned_objects );
545 
546  ApplyModificationsResults(m_IngredientsSorted, spawned_objects, NULL, player);
547  ApplyModificationsIngredients(m_IngredientsSorted, player);
548 
549  ApplySoftSkillsSpecialty(player);
550 
551  Do( m_IngredientsSorted, player, spawned_objects, m_Specialty );
552 
553 
554  DeleleIngredientsPass();
555  }
556  else
557  {
558  Debug.Log("CheckRecipe failed on server","recipes");
559  }
560  }
561 
562  void ApplySoftSkillsSpecialty(PlayerBase player)
563  {
564  player.GetSoftSkillsManager().AddSpecialty(m_Specialty);
565  }
566 
567  bool CanDo(ItemBase ingredients[], PlayerBase player)
568  {
569  //Debug.Log("Called Can Do on a recipe id:" + m_ID.ToString(),"recipes");
570  for ( int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
571  {
572  if (ingredients[i].GetInventory() && ingredients[i].GetInventory().AttachmentCount() > 0)
573  return false;
574  }
575 
576  return true;
577  }
578 
579  void Do(ItemBase ingredients[], PlayerBase player, array<ItemBase> results, float specialty_weight)
580  {
581  //Debug.Log("Called Do on a recipe id:" + m_ID.ToString(),"recipes");
582  }
583 
584  int GetID()
585  {
586  return m_ID;
587  }
588 
589 
590  void SetID(int id)
591  {
592  m_ID = id;
593  }
594 
595  void GetAllItems(array<string> items)
596  {
597  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
598  {
599  array<string> ptr = m_Ingredients[i];
600 
601  for(int x = 0; x < ptr.Count(); x++)
602  {
603  items.Insert( ptr.Get(x) );
604  }
605  }
606  }
607 
608  string GetSoundCategory(int ingredientIndex, ItemBase item)
609  {
610  string itemType = item.GetType();
611  array<string> ptr = m_Ingredients[ingredientIndex];
612 
613  for (int x = 0; x < ptr.Count(); x++)
614  {
615  if (GetGame().IsKindOf(itemType, ptr.Get(x)))
616  {
617  return m_SoundCategories[ingredientIndex].Get(x);
618  }
619  }
620  return "";
621  }
622 
623 
624 
625 
626  bool IsItemInRecipe(string item)
627  {
628  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
629  {
630  array<string> ptr = m_Ingredients[i];
631 
632  for(int x = 0; x < ptr.Count(); x++)
633  {
634  if( ptr.Get(x) == item ) return true;
635  }
636  }
637  return false;
638  }
640  int GetIngredientMaskForItem(string item)
641  {
642  int mask = 0;
643 
644  for(int i = 0; i < MAX_NUMBER_OF_INGREDIENTS; i++)
645  {
646  array<string> ptr = m_Ingredients[i];
647 
648  for(int x = 0; x < ptr.Count(); x++)
649  {
650  if( ptr.Get(x) == item )
651  {
652  mask = ((int)Math.Pow(2, i)) | mask;
653  }
654  }
655  }
656  return mask;
657  }
658 }
ItemBase
Definition: inventoryitem.c:730
GetGame
proto native CGame GetGame()
Error
void Error(string err)
Messagebox with error message.
Definition: endebug.c:90
m_Name
string m_Name
Definition: bioslobbyservice.c:35
RecipeBase
Definition: recipebase.c:4
ToString
proto string ToString()
PlayerBase
Definition: playerbaseclient.c:1
MAX_NUMBER_OF_INGREDIENTS
const int MAX_NUMBER_OF_INGREDIENTS
Definition: recipebase.c:1
DEFAULT_SPAWN_DISTANCE
const float DEFAULT_SPAWN_DISTANCE
Definition: recipebase.c:3
array< string >
x
Icon x
int
Param3 int
Debug
Definition: debug.c:13
CRAFTING_TIME_UNIT_SIZE
const float CRAFTING_TIME_UNIT_SIZE
Definition: constants.c:590
Math
Definition: enmath.c:6
m_ID
protected int m_ID
ID of effect, given by SEffectManager when registered (automatically done when playing through it)
Definition: effect.c:49
EntityAI
Definition: building.c:5
MAXIMUM_RESULTS
const int MAXIMUM_RESULTS
Definition: recipebase.c:2