# Syntax

The Script Terminal lets you automate blocks using a simple, line-based scripting language.

Each line is a command. When the terminal receives a redstone signal, it dispatches each command in order.

---

## How It Works

Commands are built up of chainable parts:

| Part       | Purpose                                                                       |
| ---------- | ----------------------------------------------------------------------------- |
| `Executor` | Performs an action on the target block. Always takes an argument.             |
| `Getter`   | Reads a value from the world or target block. Never takes an argument.        |
| `Mapper`   | Transforms the current value into another value. Sometimes takes an argument. |

The simplest valid command is an executor with its associated argument:

```
set_redstone 15
```

Here `set_redstone` is the executor and `15` is its argument.

---

## Conditionals

Use `if` or `unless` before an executor to make it conditional:

```
if <condition> <executor>
unless <condition> <executor>
```

The `condition` is a getter → mapper chain that produces a Boolean value (`true` or `false`).

- `if` runs the executor when the condition is `true`
- `unless` runs the executor when the condition is `false`

Example:

```
if redstone > 7 set_redstone 0
```

Here, `redstone > 7` is the condition.  
If it evaluates to `true`, the executor `set_redstone` runs with argument `0`.

I.e. this command sets redstone to 0 only if the target block is receiving a signal strength of 8 or higher.

---

## Conditionals with alternatives

Add `else` to provide an alternative if the condition fails:

```
if <condition> <executor> else <executor>
unless <condition> <executor> else <executor>
```

- For `if`:
    - If the condition is `true`, the first executor runs
    - If the condition is `false`, the second executor runs

- For `unless`:
    - If the condition is `false`, the first executor runs
    - If the condition is `true`, the second executor runs

Example:

```
if redstone > 7 set_redstone 0 else set_redstone 15
```

Here, `redstone > 7` is the condition.

- If it evaluates to `true`, `set_redstone 0` runs
- If it evaluates to `false`, `set_redstone 15` runs

This command sets redstone to 0 when the signal strength is 8 or higher, and 15 otherwise.

---

## Wait

Use `wait <cycles>` to pause execution for a number of cycles:

Example:

```
set_redstone 15
wait 2
set_redstone 0
```

`<cycles>` is a whole number from 1 to 64. Anything else, or no number at all, waits one cycle.

`wait` behaves like an executor, but cannot be used with `if`, `unless`, or `else`.

It always runs when reached, and delays the dispatch of following commands.

---

> The remaining concepts are more advanced and are not required to get started. It is recommended to become familiar 
> with the above material before continuing, and return to these topics as needed.

---

## Coordinate Types

Arguments support Minecraft's relative (`~`) and local (`^`) coordinate syntax, resolved relative to the terminal's position.

Examples

```
if pos == ~ ~1 ~ set_redstone 15
if pos == ^3 ^ ^-12 set_redstone 0
```

The coordinates are resolved when the command is dispatched, not when it's executed.

---

## Addresses

Typing out coordinates by hand is error-prone, especially when using many positions at once. The **Address Pad** lets you save block positions under memorable names and refer to them in scripts with a `@name` token.

**Saving addresses** — hold an Address Pad and:

- **Right-click a block** to save its position as a new address (up to 15 per pad).
- **Right-click the air** to open a screen for renaming and removing saved addresses.

Address names may contain letters, digits, `.`, and `_`.

**Using addresses** — right-click a Script Terminal with the Address Pad to attach it. Once attached, any of its saved addresses can be used wherever a coordinate argument is expected, by writing `@` followed by the name:

```
take_items @input_chest
put_items @furnace
if block == minecraft:lava_cauldron use @bucket_dropoff
```

Each `@name` is substituted with the saved position's absolute `x y z` coordinates when the command is dispatched, exactly as if you had typed them out.

> **Addresses only work from a Script Terminal with an attached Address Pad.** They are resolved by the terminal using its pad, so a `@name` token will *not* resolve from other command sources such as command blocks or chat — only literal coordinates and the `~` / `^` syntax work there.

---

## value_of()

Use `value_of(...)` in place of a literal argument to compute a value at runtime:

Example:

```
set_redstone value_of(pos y - 50)
```

The expression inside can be any getter → mapper chain, so long as it returns the required argument type.

---

## Expression Aliases

Use `#def <name> = <expression>` at the top of a script to give a reusable name to a getter → mapper chain:

```
#def first_line = page_contents get_line 1

write_page value_of(first_line)
```

Alias names may contain letters, digits, and `_`, and cannot start with a digit.

Declarations are read from the top of the script. Blank lines are ignored while reading declarations, and the first nonblank line that does not start with `#` ends the declaration section.

Aliases may reference aliases declared earlier:

```
#def line_1 = page_contents get_line 1
#def line_2 = page_contents get_line 2
#def combined = line_2 + "\n" + value_of(line_1)

write_page value_of(combined)
```

Later aliases with the same name replace earlier aliases for following declarations and commands.

Alias bodies must start with a getter or an earlier alias, then may continue with mappers.

---

## Variables

A variable is a value the Script Terminal keeps between lines. A Serial Bus can be asked for a value, and the terminal stores it for later lines to use, at any bus on the network.

Declare one with `#var <name> = <literal>`:

```
#var page = 1
```

- The value must be a literal: a number, `true` or `false`, or a string. Use `#def` for getters and mappers.
- A variable has no fixed type: like a literal alias, it is whatever its current value reads as. A value that does not suit the place it is used fails on that line, like any other command.
- Names follow the alias rules. A variable cannot be declared twice, and cannot share a name with an alias: whichever is lower in the script is an error.

A variable is used like an alias, wherever an expression starts. Each line carries the variable's value as it stands when the line is sent, so every bus sees the same value. An alias may use a variable declared above it, and takes its value the same way.

```
set_redstone value_of(page)
if page > 8 set_redstone 15 else set_redstone 0
```

### Asking a Serial Bus for a value

Every command the terminal sends stays on the Data Cable for one tick, then the cable goes blank until the next command. A bus can answer while it is blank:

- `request_value <value>` is an executor. The bus that runs it puts the value on the cable when the cable goes blank, for one tick. Use `if pos == ...` to pick which bus answers.
- `receive_value <name>` stores the answer to the last command sent in a variable declared above it. The terminal keeps that answer until it sends another command. Like `wait`, it works only on the Script Terminal and cannot be used with `if`, `unless` or `else`. Unlike `wait`, it takes no time: the line after it runs straight away. A looping script still takes at least 2 ticks per pass, however many free lines it has.

```
#var page = 1
if pos == @lectern request_value value_of(page_number)
receive_value page
if pos == @lamp set_redstone value_of(page)
```

`wait` and `receive_value` send nothing, so a `wait` between a `request_value` and its `receive_value` does not lose the answer.

`receive_value` stores whatever value was answered. It leaves the variable unchanged only if there is no answer, or if more than one bus answered: two answers at once are two senders, which garble the cable like any others.

Variables keep their values across loop passes, and go back to their declared literals when the script is edited and at the start of each new powered run.

---
