recipes.helper.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import type { FluidProductPrototype, ItemProductPrototype, RecipePrototype } from "../lua-api/models.ts";
  2. import type { Item } from "../process-data.models.ts";
  3. export type Ingredient = {
  4. type: "fluid" | "item";
  5. itemId: string;
  6. amount: number;
  7. };
  8. export type Recipe = {
  9. name: string;
  10. icon?: string;
  11. subgroup: string;
  12. order?: string;
  13. /** The [categories](prototype:RecipeCategory) of this recipe. Controls which machines can craft this recipe.
  14. The built-in categories can be found [here](https://wiki.factorio.com/Data.raw#recipe-category). The base `"crafting"` category can not contain recipes with fluid ingredients or products.
  15. The array must contain at least one category, it cannot be empty. */
  16. categories?: string[];
  17. /** The amount of time it takes to make this recipe. Must be `> 0.001`. Equals the number of seconds it takes to craft at crafting speed `1`. */
  18. energy_required?: number;
  19. /** Whether the recipe is allowed to have the extra inserter overload bonus applied (4 * stack inserter stack size). */
  20. allow_inserter_overload?: boolean;
  21. allow_productivity?: boolean;
  22. allow_quality?: boolean;
  23. allow_speed?: boolean;
  24. /** Used to determine how many extra items are put into an assembling machine before it's considered "full enough". See [insertion limits](https://wiki.factorio.com/Inserters#Insertion_limits).
  25. If set to `0`, it instead uses the following formula: `1.166 / (energy_required / the assembler's crafting_speed)`, rounded up, and clamped to be between`2` and `100`. The numbers used in this formula can be changed by the [UtilityConstants](prototype:UtilityConstants) properties `dynamic_recipe_overload_factor`, `minimum_recipe_overload_multiplier`, and `maximum_recipe_overload_multiplier`. */
  26. overload_multiplier?: number;
  27. ingredients?: Ingredient[];
  28. results?: Array<ItemProductPrototype | FluidProductPrototype>;
  29. };
  30. export function getRecipeIcon(recipe: RecipePrototype, mainProduct: Item | undefined): string {
  31. if (recipe.icons || recipe.icon) return `recipe/${recipe.name}.png`;
  32. if (mainProduct && mainProduct.icon) return mainProduct.icon;
  33. console.warn(`No icon found for :${recipe.name}`);
  34. return "";
  35. }
  36. export function getRecipeSubGroup(recipe: RecipePrototype, mainProduct: Item | undefined): string {
  37. if (recipe.subgroup) return recipe.subgroup;
  38. if (mainProduct) return mainProduct.subgroup;
  39. return "other";
  40. }
  41. export function getMainProductName(recipe: RecipePrototype): string {
  42. if (recipe.results?.length == 1) {
  43. return recipe.results[0].name;
  44. } else if (recipe.results && recipe.main_product) {
  45. const mainProduct = recipe.main_product;
  46. const result = recipe.results.find((r) => r.name === mainProduct);
  47. if (result) {
  48. return result.name;
  49. }
  50. throw new Error(`Main product '${mainProduct}' declared by recipe '${recipe.name}' not found in results`);
  51. }
  52. return "";
  53. }
  54. export function parseRecipe(recipe: RecipePrototype, itemsMap: Record<string, Item>): Recipe {
  55. const rawIngredient = Array.isArray(recipe.ingredients) ? recipe.ingredients : [];
  56. const ingredients = rawIngredient.map((i) => ({ itemId: i.name, amount: i.amount, type: i.type }));
  57. const mainProduct = itemsMap[getMainProductName(recipe)];
  58. const r: Recipe = {
  59. name: recipe.name,
  60. icon: getRecipeIcon(recipe, mainProduct),
  61. subgroup: getRecipeSubGroup(recipe, mainProduct),
  62. energy_required: recipe.energy_required,
  63. allow_inserter_overload: recipe.allow_inserter_overload,
  64. overload_multiplier: recipe.overload_multiplier,
  65. order: recipe.order ?? mainProduct.order,
  66. categories: recipe.categories ?? ["crafting"],
  67. ingredients,
  68. results: recipe.results,
  69. };
  70. if (recipe.allow_productivity) r.allow_productivity = true;
  71. if (recipe.allow_quality) r.allow_quality = true;
  72. if (recipe.allow_speed) r.allow_speed = true;
  73. return r;
  74. }