factoriax.engine.placement#
Put machines on the map, take them off again, and aim them.
Every function here acts on one tile: the tile that the player faces. A player
who carries a machine item turns that item into a machine on the tile. A player
can also turn the machine on that tile back into an item. Nothing in this
module runs on its own. Each function answers a player action from
factoriax.engine.step.
A placed machine lives in two places at the same time, and the two must agree.
state.machine_types[y, x] gives the kind of machine on a tile.
state.tile_entity[y, x] gives the entity slot that holds its contents, or
-1 for an empty tile. The slot itself carries the position, the facing, the
health, and the contents of the machine. Every function here that changes one
of the three changes all three.
The slots are a pool of fixed size, E of them, fixed when the level is
built. A slot is free when ent_y < 0. place_machine() takes the free
slot with the lowest number, and pickup_machine() gives one back. A long
game therefore reuses slots and grows no array. A map with every slot in use
refuses a new placement, and the player keeps the item.
Every function uses a mask and not a branch, because these functions run under
jit. An action that cannot happen is not an error and raises nothing. It
writes the state back unchanged. A caller cannot separate a refused placement
from a placement that worked by the return value alone. It must compare the
state before and after the call.
- factoriax.engine.placement.apply_repair(state: EnvState, params: EnvParams, player_idx: int | Array) EnvState#
Restore the entity in front of the player to full health.
The base engine treats REPAIR as a full restore with no item cost. A wrapper that wants another rule, such as a repair for each tick, an item cost, or a partial restore, rewrites
REPAIRtoNOOPbefore it callsstep_env. The wrapper then applies its own update tostate.ent_health.The function does nothing when the target tile is outside the map, when the tile holds no entity, or when the entity is already at full health for its type.
No code path in the engine lowers
ent_health. Placement sets it to full and pickup clears it to zero, so in the base engine every placed machine is already at full health. This function therefore has nothing to restore. A caller can reach it, but it changes nothing.ISSUES.mdrecords this.- Parameters:
state – State to read.
params – The function does not read this argument. It is present for the shared player-action signature.
player_idx – Player that repairs the machine.
- Returns:
New state, with
ent_healthraised to full on the target slot. The state is unchanged in every other case.- Return type:
- factoriax.engine.placement.get_tile_in_front(state: EnvState, player_idx: int | Array) tuple[Array, Array]#
Return the tile one step ahead of a player, in the way they face.
Every player action in this module targets this tile. A player never acts on the tile under them.
The function does not clip the result, so the result can name a tile outside the map. A player on an edge who faces outward gets such a tile. Callers test the bounds themselves and mask. This function raises nothing.
- Parameters:
state – State to read. The function reads
player_positionsandplayer_directions.player_idx – Player to look ahead of. This value indexes the first axis of both player arrays.
- Returns:
(tx, ty), the column first and the row second, in the(x, y)order ofplayer_positions. A grid lookup takes them in the other order, asstate.map[ty, tx]. A player with the unset direction 0 gets their own tile back, because row 0 ofDIRECTIONSis a zero offset.- Return type:
- factoriax.engine.placement.is_placeable_item(item_type: int | Array) Array#
Report whether an item becomes a machine on the map.
Most items are materials, and no action can place them.
PLACEABLE_ITEMSlists the items that a player can place, andITEM_TO_MACHINE_ARRAYmaps each one to a machine kind.- Parameters:
item_type – Item id to test. This must be a scalar. The function does not broadcast over an array of items, because the reduction collapses every axis.
- Returns:
Scalar bool. True when the item appears in
PLACEABLE_ITEMS.- Return type:
- factoriax.engine.placement.is_valid_placement_tile(state: EnvState, tx: Array, ty: Array) Array#
Report whether a machine can stand on a tile.
Three conditions refuse a tile. The tile is outside the map, or its block is one of
SOLID_BLOCKSsuch as stone or water, or a machine already stands on it. An ore block is not solid, so a player can place a miner on the patch that it works.The function ignores the players. A tile with another player on it passes this test, so a player can place a machine under another player.
- Parameters:
state – State to read. The function reads
mapandmachine_types.tx – Target column. The value can fall outside the map, and this function exists to refuse that case.
ty – Target row. The value can fall outside the map.
- Returns:
Bool, with the shape of
tx. True only when all three conditions pass.- Return type:
- factoriax.engine.placement.pickup_machine(state: EnvState, params: EnvParams, player_idx: int | Array) EnvState#
Take the machine in front of the player back into the inventory.
This function is the reverse of
place_machine(). The machine becomes an item again, the tile empties, and the function clears the entity slot and returns it to the free pool for the next placement.Everything that the machine held comes back with it:
ent_buf, bothent_asm_inslots, andent_asm_out. A pickup of a working assembler therefore costs its progress, but none of its items.Three conditions gate the pickup. A machine stands on the tile, the machine is at full health for its kind, and the whole payout fits in the inventory of the player. No stack can pass
PLAYER_MAX_STACK.The room test is all or nothing. A payout of only the part that fits destroys the rest together with the machine. The function therefore refuses a pickup that passes a stack limit, and the player must withdraw some of the contents first. This is the one case where a full inventory blocks a pickup that all other conditions allow.
- Parameters:
state – State to read.
params – The function does not read this argument. It is present for the shared player-action signature.
player_idx – Player that picks the machine up.
- Returns:
New state, with
player_inventory,machine_types,tile_entity, and everyent_field of the freed slot updated. The state is unchanged when the function refuses the pickup.- Return type:
- factoriax.engine.placement.place_machine(state: EnvState, params: EnvParams, player_idx: int | Array, item_type: int | Array) EnvState#
Spend one carried item to stand a machine on the tile in front.
Four conditions must all hold. The player carries one of the item or more, the item is placeable, the target tile is free, and a free entity slot exists. If one condition fails, the state comes back unchanged and the player keeps the item. The function does not report which condition failed.
The new machine takes the facing of the player, so a player must stand in the correct direction before placement to aim a belt or an arm. The machine starts at the
MACHINE_MAX_HEALTHof its kind, with an empty buffer.The function clears the buffer of the reused slot, and nothing else. It leaves the craft fields
ent_powerand theent_asm_arrays as they were. This is safe only becausepickup_machine()sets all of them to zero when it frees a slot.CAUTION: A new path that frees a slot must also clear those fields. Without that, a newly placed assembler starts with a half-finished craft.
- Parameters:
state – State to read.
params – The function does not read this argument. It is present so that the player-action functions in this module share one signature, and
factoriax.engine.stepcan dispatch to them with no special case.player_idx – Player that places the machine.
item_type – Item to spend.
ITEM_TO_MACHINE_ARRAYturns it into a machine kind.
- Returns:
New state, with
player_inventory,machine_types,tile_entity, and theent_y,ent_x,ent_type,ent_direction,ent_health,ent_buf_type, andent_buf_countof the new slot updated. The state is unchanged when the function refuses the placement.- Return type:
- factoriax.engine.placement.set_machine_direction(state: EnvState, player_idx: int | Array, target_dir: int | Array) EnvState#
Aim the machine in front of the player at a given direction.
A player turns a placed machine to route a belt line, and does not pick every piece up again. The function writes the direction directly and does not turn the machine by one step. A second call with the same argument therefore changes nothing.
The facing of a machine means a different thing for each kind. It gives the tile that a miner, a belt, or a splitter pushes into, and the two tiles that an arm joins. On a
CROSSINGthe one byte holds both axis directions, so a write aims the vertical flow and the horizontal flow together.CROSSING_AXIS_DIRSunpacks the pair.The function does nothing when the tile is outside the map or holds no machine.
- Parameters:
state – State to read.
player_idx – Player that aims the machine.
target_dir –
Directionvalue to write. The function does not validate it. It stores a value outside 1 to 4 as given, and the passes that index a direction table with it are defined over 0 to 4 only.
- Returns:
New state, with
ent_directionupdated on the target slot. The state is unchanged in every other case.- Return type: