factoriax.engine.crafting#
Craft a recipe by hand, from the inventory of the player.
A player craft finishes in the step that starts it. The inputs leave the
inventory and the output arrives in the same call. This module therefore never
reads the ticks field of a recipe. An assembler that runs the same recipe
pays a cost that the player does not pay.
Recipes come from recipe_table, not
from a module global. A scenario can therefore supply its own book, and a
balance overlay can change the counts with no new XLA graph.
Every function here is traceable and takes one player index. An action applies to one player in each step, so no function here works on all players at the same time.
- factoriax.engine.crafting.can_afford_recipe(state: EnvState, params: EnvParams, player_idx: int | Array, recipe_idx: int | Array) Array#
Test whether a player holds every input that one craft of a recipe needs.
This function tests the inputs only. Space for the output is a separate question.
craft_recipe()asks that question before it writes, so a recipe that the player can afford can still fail to craft.The function tests each of the two input slots of the recipe on its own. A slot with the padding value
ItemType.EMPTYpasses. This is correct only because a recipe names each input item one time at most.RecipeBookenforces that rule when it builds the table. With a repeated item, one slot alone can pass the test, and the craft then takes the count below zero.- Parameters:
state – State to read. The function does not modify it.
params – Supplies
recipe_table. This function reads the book of the scenario, if the scenario has one.player_idx – Player whose inventory the function reads.
recipe_idx – Row of the recipe table. The value must be a real row. This function does not accept
-1, butcraft_recipe()does.
- Returns:
Scalar bool. True when the player holds each named input in the required count or more.
- Return type:
- factoriax.engine.crafting.count_item_in_inventory(state: EnvState, player_idx: int | Array, item_type: int | Array) Array#
Count the items of one type that a player carries.
- Parameters:
state – State to read. The function does not modify it.
player_idx – Row of
player_inventoryto read. The function does not test the bounds. Underjit, an index past the player count reads a clamped row and raises nothing.item_type –
ItemTypevalue to count.
- Returns:
Scalar int16 count. Zero means that the player holds none of this item. An item with no recipe and no source also reads as zero.
- Return type:
- factoriax.engine.crafting.craft_recipe(state: EnvState, params: EnvParams, player_idx: int | Array, recipe_idx: int | Array) EnvState#
Craft one batch of a recipe into the inventory of a player, in this step.
The function consumes the inputs of the recipe and adds
output_countof its output. It refuses the whole craft, and never a part of it, in three cases:The recipe row does not exist.
The player cannot afford the inputs.
The output passes the stack limit of the player.
A refused craft leaves the inventory exactly as it was, so a caller can issue the action at any time.
One call crafts one batch. A hand craft takes no time, so this function never reads
ticks. The player pays none of the delay that the same recipe costs an assembler.- Parameters:
state – State to craft from.
params – Supplies
recipe_table, which fixes the inputs, output, and yield.player_idx – Player whose inventory the function charges and credits.
recipe_idx – Row of the recipe table, or
-1when the active table has no recipe for the item. The value-1is normal and is not an error. ACRAFT_action names an item, and the book of a scenario does not have to produce every item that the action space can name. The function clamps the gather to a real row and gates the craft off, so such a call does nothing.
- Returns:
A new state. Its
player_inventoryholds the result of the craft. After a refused craft that inventory is equal to the input inventory. Every other field passes through unchanged.- Return type: