The IC10 is the programmable chip in Stationeers. It sits in an IC housing, connects to the data cable and can read values from devices, do math and switch devices. The language looks like assembler: one instruction per line, no brackets, no loop commands, only jumps. That sounds dry, but it is learned quickly, and after that the station runs itself while you are outside bashing ore.
What the chip does per tick
- The game runs in ticks of 0.5 seconds, so two per second.
- Per tick the chip executes at most 128 instructions.
- Device values only change once per tick. Read the same sensor ten times in the same tick and you get the same value ten times.
That is why every main loop needs a yield: it ends the current tick and continues at the same spot in the next one.
Registers
The chip has 16 freely usable storage slots for numbers, r0 to r15. On top of that come two with a special job:
| Register | Purpose |
|---|---|
r0 … r15 | free for your own values |
sp (r16) | stack pointer for push, pop, peek (the stack holds 512 values) |
ra (r17) | return address for jal |
All values are decimal numbers. True and false are simply 1 and 0.
Addressing devices
There are two ways:
Via the pins d0 to d5. On the IC housing you use the screwdriver to set which device is on which pin. Then l r0 d0 Temperature reads the temperature from the device on pin 0. db is the housing itself. Six pins fill up fast.
Via the data network by type and name. lbn reads, sbn writes, and both act on all devices of one type with a specific name on the same data network:
lbn r0 -1252983604 HASH("Raum") Temperature 0
sbn 24258244 HASH("Heizung") On 1
- The first number is the prefab hash of the device type, here Gas Sensor (
StructureGasSensor) and Wall Heater (StructureWallHeater). HASH("Raum")is the hash of the name you gave the device in game with the Labeller ("Raum" is German for room).- The last number when reading is the batch mode: what should come out if several devices match?
| Batch mode | Value | Result |
|---|---|---|
| Average | 0 | average of all matching devices |
| Sum | 1 | sum |
| Minimum | 2 | smallest value |
| Maximum | 3 | largest value |
| Count | 4 | number of matching devices |
For measurements 0 (Average) is almost always right. With Sum, two sensors at 20 °C each suddenly turn into 40 °C, and nobody notices until someone builds the second sensor.
If lbn with Average finds not a single matching device, it returns NaN (not a number). Every comparison with NaN is false, every calculation with it gives NaN again. A typo in the name quietly shuts down the whole control loop this way. Catch it with bnan or snan, see Common Mistakes.
Batch commands only work over the data cable, not via the pins. So the housing needs a data cable to the devices.
define and alias
Nobody can read raw numbers in code three weeks later, not even you. So:
define NAME valuegives a number a name. Ideal for prefab hashes and thresholds.alias name r0gives a register (or pin) a name.
define SENSOR -1252983604 # Gas sensor
define ZIEL 294.15 # 21 C in Kelvin
alias tRaum r0
lbn tRaum SENSOR HASH("Raum") Temperature 0
HASH("...") is replaced by the number as soon as the program is loaded. That is why define RAUM HASH("Raum") works too.
The game calculates temperatures in Kelvin: 0 °C is 273.15 K. So 21 °C is 294.15.
Labels and jumps
A label is a name with a colon, alone on a line. Jumps go to that name:
| Command | Meaning |
|---|---|
j start | always jump |
beq a b target | jump if a equals b |
bne a b target | jump if a does not equal b |
blt a b target | jump if a is less than b |
bgt a b target | jump if a is greater than b |
bnan a target | jump if a is not a number |
jal target | jump and store the return address in ra (subroutine, return with j ra) |
Always use labels, never line numbers. If you insert a line at the top, all the numbers shift and the program jumps into nowhere.
The first program: heater with hysteresis
A gas sensor named "Raum" (room) measures the temperature. Below 18 °C all wall heaters named "Heizung" (heater) switch on, above 21 °C they switch off again. In between everything stays as it is. This gap is called hysteresis and keeps the heater from clicking on and off every second.
# Room heater with hysteresis
define SENSOR -1252983604 # Gas sensor
define HEIZUNG 24258244 # Wall heater
define KALT 291.15 # 18 C: heat below this
define WARM 294.15 # 21 C: off above this
alias tRaum r0
alias heizen r1
move heizen 0
start:
yield
lbn tRaum SENSOR HASH("Raum") Temperature 0
bnan tRaum start
blt tRaum KALT an
bgt tRaum WARM aus
j schalten
an:
move heizen 1
j schalten
aus:
move heizen 0
schalten:
sbn HEIZUNG HASH("Heizung") On heizen
j start
How to read it:
- Numbers and registers get names.
start:is the beginning of the endless loop.yieldwaits for the next tick.- Read the sensor. If NaN comes back (sensor missing or misnamed), go back to the start without switching anything.
- Too cold:
heizento 1. Too warm: to 0. In between: unchanged. - All heaters named "Heizung" get the value. Then start over.
The hard limits
| Limit | Value |
|---|---|
| Lines per program | 128 |
| Characters per line | 90 |
| Characters in the whole program | 4096 |
| Registers | r0–r15 (plus sp, ra) |
| Pins | d0–d5 and db |
| Instructions per tick | 128 |
Everything counts: blank lines, comment lines, labels, define and alias. With detailed comments, the character limit is usually the one you hit first, not the line count.
Small traps for beginners
- Commands are lowercase and exact:
move, notmov;j, notjmp. - Numbers without exponent:
100000, not1e5. - If the program runs past the last line, the chip stops for good. Without an error message. Every program ends with a jump back.
sleep 5waits 5 seconds, not 5 ticks.- No umlauts in device names you address via
HASH. The chip only stores plain characters, "Küche" (kitchen) turns into something else when written, and the hash no longer matches.
Continue with How I Write IC10 and Common Mistakes. If you want to practise in game: the IC10 Editor Tablet checks code as you type and has a simulator.