LIST
You can read more about lists in ink on the official documentation.
ink provides a powerful system for tracking state via lists. A list in ink is not an array — it is closer to an enum or a boolean set that can hold one or multiple values at the same time.
In the ink + Pixi'VN integration, both LIST declarations and VAR variables holding list values are stored in the Pixi'VN storage.
Define
A list is defined with the LIST keyword followed by its name and a comma-separated sequence of possible values.
LIST items = sword, key, potionLIST works like an enum: each entry is a named constant with an implicit numeric value (the first entry = 1, the second = 2, and so on). You can use these names in conditions and assignments — ink handles the numeric comparison for you.
In Pixi'VN storage, the declaration above creates the following entries:
- a list definition called
itemswith numeric values[1, 2, 3] items.sword = 1items.key = 2items.potion = 3
The entries are stored under the qualified name listName.entryName, just like accessing a member of an enum via its namespace.
Pixi'VN vs. native ink — use the qualified name
In native ink you can reference a list entry either by its short name (sword) or by its qualified name (items.sword) and they are equivalent.
In Pixi'VN you must always use the qualified form items.sword. If you write just sword, Pixi'VN will look for a generic storage entry whose key is "sword" — it will not resolve to the list member. This is a common source of bugs when porting or reading ink scripts.
The LIST statement simultaneously defines the possible values (as named constants) and a variable (with the same name as the list) that holds the current state.
By default, none of the values are "active". You can make a value active from the start by wrapping it in brackets:
LIST kettleState = cold, (boiling), recently_boiled
// the kettle starts boilingVAR with a list value
You can also create a variable that holds a list value using VAR:
VAR inventory = ()In Pixi'VN storage, the declaration above creates:
- a list called
inventorythat is empty (or with elements if specified)
For example, VAR inventory = (sword, potion) creates an inventory list that initially contains sword and potion.
You can use the same set of states in multiple variables:
LIST daysOfTheWeek = Monday, Tuesday, Wednesday, Thursday, Friday
VAR today = daysOfTheWeek.Monday
VAR tomorrow = daysOfTheWeek.TuesdayIn Pixi'VN storage, the declaration above creates entries such as daysOfTheWeek.Monday = 1, daysOfTheWeek.Tuesday = 2, … Always use the qualified form daysOfTheWeek.Monday — not the bare Monday — when referencing an entry in Pixi'VN ink.
设置
Change the current value of a list variable using the ~ logic syntax:
~ kettleState = kettleState.cold
~ kettleState = kettleState.boilingFor multi-valued lists, you can assign several values at once:
~ DoctorsInSurgery = (DoctorsInSurgery.Adams, DoctorsInSurgery.Bernard)Or clear the list entirely:
~ DoctorsInSurgery = ()Adding and removing entries
Use += and -= to add or remove individual entries without touching the rest of the list:
~ DoctorsInSurgery += DoctorsInSurgery.Adams
~ DoctorsInSurgery -= DoctorsInSurgery.Eamonn
~ DoctorsInSurgery += (DoctorsInSurgery.Eamonn, DoctorsInSurgery.Denver)
~ DoctorsInSurgery -= (DoctorsInSurgery.Adams, DoctorsInSurgery.Eamonn, DoctorsInSurgery.Denver)Adding an entry that is already present, or removing one that isn't, does nothing — no error is produced.
Step forward / backward
Because list values have an implicit numeric order, you can step through them with ++ and --:
LIST PancakeState = ingredients_gathered, batter_mix, pan_hot, pancakes_tossed, ready_to_eat
~ PancakeState++ // advances to the next stateGet / Query
Reading the current value
Print the current value of a list variable using the standard {...} syntax — it outputs the value's name:
LIST volumeLevel = off, quiet, medium, loud, deafening
VAR lecturersVolume = volumeLevel.quiet
The lecturer's voice becomes {lecturersVolume}.Testing a single value
{ kettleState == kettleState.cold:
The kettle is cool to the touch.
- else:
The outside of the kettle is very warm!
}Testing for containment (has / ?)
Use has (or ?) to check whether a value is present in a multi-valued list:
{ DoctorsInSurgery has DoctorsInSurgery.Eamonn:
Dr Eamonn is polishing his glasses.
}
{ DoctorsInSurgery ? (DoctorsInSurgery.Adams, DoctorsInSurgery.Bernard):
Dr Adams and Dr Bernard are having a hushed argument in one corner.
}Use hasnt (or !?) to negate:
{ DoctorsInSurgery !? DoctorsInSurgery.Eamonn:
Dr Eamonn has left.
}Testing for emptiness
A list evaluates to true unless it is empty:
{ DoctorsInSurgery: The surgery is open today. | Everyone has gone home. }Comparison operators
List values carry numeric weights (first value = 1, second = 2, …), so you can compare them:
{ lecturersVolume < volumeLevel.deafening:
~ lecturersVolume++
}Exact equality (==) on a multi-valued list means set equality — both lists must contain exactly the same entries:
{ DoctorsInSurgery == (DoctorsInSurgery.Adams, DoctorsInSurgery.Bernard):
Dr Adams and Dr Bernard are having a loud argument.
}List functions
ink provides several built-in functions for working with lists.
| Function | Description |
|---|---|
LIST_COUNT(list) | Number of active entries |
LIST_MIN(list) | Lowest active entry |
LIST_MAX(list) | Highest active entry |
LIST_RANDOM(list) | A random active entry |
LIST_ALL(list) | All possible entries (active and inactive) |
LIST_VALUE(entry) | Numeric value of an entry (first = 1) |
LIST_INVERT(list) | Returns all entries not currently active |
LIST_RANGE(list, min, max) | Slice of the full list between two values |
LIST DoctorsInSurgery = (Adams), Bernard, (Cartwright), Denver, Eamonn
{LIST_COUNT(DoctorsInSurgery)} // "2"
{LIST_MIN(DoctorsInSurgery)} // "Adams"
{LIST_MAX(DoctorsInSurgery)} // "Cartwright"
{LIST_RANDOM(DoctorsInSurgery)} // "Adams" or "Cartwright"
{LIST_ALL(DoctorsInSurgery)} // "Adams, Bernard, Cartwright, Denver, Eamonn"Converting between values and numbers
LIST volumeLevel = off, quiet, medium, loud, deafening
// number → name: LIST_VALUE returns the integer (first entry = 1)
The lecturer has {LIST_VALUE(volumeLevel.deafening) - LIST_VALUE(lecturersVolume)} notches left.
// number → value: use the list name as a function
LIST Numbers = one, two, three
VAR score = Numbers.one
~ score = Numbers(2) // score is now "two"Custom numeric values
By default values are numbered 1, 2, 3, … You can assign your own:
LIST primeNumbers = two = 2, three = 3, five = 5Usage patterns
Ambiguous names
If two lists share an entry name, qualify it with the list name:
LIST colours = red, green, blue, purple
LIST moods = mad, happy, blue
VAR status = colours.blue // must be explicitReusing list types in multiple variables
A LIST declaration defines both the set of possible values and a variable. You can create additional variables of the same "type" using VAR:
LIST heatedWaterStates = cold, boiling, recently_boiled
VAR kettleState = heatedWaterStates.cold
VAR potState = heatedWaterStates.coldBoth kettleState and potState hold values drawn from heatedWaterStates.
Intersection (^)
Use ^ to find the overlap between two lists:
LIST CoreValues = strength, courage, compassion, greed, nepotism, self_belief
VAR desiredValues = (CoreValues.strength, CoreValues.courage, CoreValues.compassion, CoreValues.self_belief)
VAR actualValues = (CoreValues.greed, CoreValues.nepotism, CoreValues.self_belief)
{desiredValues ^ actualValues} // prints "self_belief"
{ desiredValues ^ actualValues: The new president has at least one desirable quality. }