← Documentation
Built-in Functions
Loreline comes with a collection of built-in functions you can call from expressions, text interpolation, or as standalone statements.
New to Loreline? Start with the Writer's Guide to learn about beats, choices, and state management first. Come back here when you need details about a specific function.
Quick reference
| Category |
Functions |
| Math |
floor ceil round abs min max clamp pow |
| Random |
random chance seed_random random_float |
| Timing |
wait |
| Type conversion |
float string bool |
| String |
string_upper string_lower string_contains string_replace string_split string_trim string_index string_sub string_starts string_ends string_repeat string_length |
| Text |
plural (+ pipe syntax) |
| Array |
array_add array_pop array_prepend array_shift array_remove array_index array_has array_sort array_reverse array_join array_pick array_shuffle array_copy array_length |
| Map |
map_keys map_has map_get map_set map_remove map_copy map_length |
| Story state |
current_beat has_beat beat_visits |
| Choice introspection |
choices choices_all choices_disabled |
Math
| Function |
Description |
floor(n) |
Rounds a number down to the nearest whole number. floor(3.7) returns 3. |
ceil(n) |
Rounds a number up to the nearest whole number. ceil(3.2) returns 4. |
round(n) |
Rounds a number to the nearest whole number. round(3.5) returns 4. |
abs(n) |
Returns the positive version of a number. abs(-5) returns 5. |
min(a, b) |
Returns the smaller of two values. min(3, 7) returns 3. |
max(a, b) |
Returns the larger of two values. max(3, 7) returns 7. |
clamp(value, low, high) |
Keeps a value within a range. clamp(10, 0, 5) returns 5. |
pow(base, exp) |
Raises a number to a power. pow(2, 3) returns 8. |
health = clamp(health + healing, 0, max_health)
damage = min(attack_power, enemy_health)
Random
| Function |
Description |
random(min, max) |
Returns a random whole number between min and max (inclusive). |
chance(n) |
Returns true with a 1-in-n probability. chance(3) has roughly a 33% chance of being true. |
seed_random(seed) |
Sets the random seed for reproducible results. After calling this, all random functions produce the same sequence every time. |
random_float(min, max) |
Returns a random decimal number from min up to (but not including) max. |
roll = random(1, 6)
You rolled a $roll!
if chance(4)
You find a rare gem on the ground!
Timing
| Function |
Description |
wait(seconds) |
Pauses the script for the given number of seconds before continuing. |
The ground begins to shake...
wait(2)
A massive boulder crashes through the wall!
Type conversion
| Function |
Description |
float(value) |
Converts a value to a number. Strings like "3.14" are converted. Returns 0 if conversion fails. |
string(value) |
Converts any value to text. string(42) returns "42". |
bool(value) |
Converts a value to true or false. Zero, empty strings, empty arrays, and null are false; everything else is true. |
String
| Function |
Description |
string_upper(text) |
Converts all letters to uppercase. string_upper("hello") returns "HELLO". |
string_lower(text) |
Converts all letters to lowercase. string_lower("HELLO") returns "hello". |
string_contains(text, needle) |
Checks if a string contains a piece of text. string_contains("hello world", "world") returns true. |
string_replace(text, from, to) |
Replaces every occurrence of a piece of text. string_replace("hello world", "world", "there") returns "hello there". |
string_split(text, separator) |
Splits a string into an array. string_split("a,b,c", ",") returns "a", "b", "c"]. |
string_trim(text) |
Removes whitespace from the beginning and end. string_trim(" hello ") returns "hello". |
string_index(text, needle) |
Finds where a piece of text first appears (starting from 0), or -1 if not found. string_index("hello", "ll") returns 2. |
string_sub(text, start, length) |
Extracts a portion of a string. string_sub("ABCDEF", 0, 3) returns "ABC". |
string_starts(text, prefix) |
Checks if a string begins with the given prefix. string_starts("hello world", "hello") returns true. |
string_ends(text, suffix) |
Checks if a string ends with the given suffix. string_ends("hello world", "world") returns true. |
string_repeat(text, count) |
Repeats the text the given number of times. string_repeat("ab", 3) returns "ababab". |
string_length(text) |
Returns the number of characters in a string. string_length("hello") returns 5. |
if string_contains(message, "help")
Someone needs assistance!
words = string_split(sentence, " ")
The sentence has $array_length(words) words.
if string_starts(name, "Sir")
You bow before the knight.
All string_ functions also support dot notation: drop the string_ prefix and call the function directly on the value. For example, string_upper(name) can be written as name.upper(), and string_contains(msg, "help") as msg.contains("help"). This also works on literals and can be chained:
title = "hello".upper()
greeting = " hello world ".trim().upper()
Text
| Function |
Description |
plural(count, singular, plural) |
Returns singular when count is 1, plural otherwise. Works for both noun plurals and verb conjugation in any language. |
items = 3
You found $items $plural(items, "coin", "coins").
// "You found 3 coins."
boxes = 1
There $plural(boxes, "is", "are") $boxes $plural(boxes, "box", "boxes") here.
// "There is 1 box here."
There is also a shorthand pipe syntax for the common case. After a numeric $expression, write singular|plural and it will resolve automatically:
items = 3
You found $items coin|coins.
// "You found 3 coins."
boxes = 1
$boxes (box was|boxes were) found.
// "1 box was found."
Use parentheses for multi-word alternatives. Escape with | if you need a literal pipe character. The pipe syntax only activates after a numeric expression. Otherwise | is kept as-is.
Array
| Function |
Description |
array_add(array, value) |
Adds an element to the end of an array. |
array_pop(array) |
Removes and returns the last element. Returns null if empty. |
array_prepend(array, value) |
Adds an element to the beginning of an array. |
array_shift(array) |
Removes and returns the first element. Returns null if empty. |
array_remove(array, value) |
Finds and removes the first occurrence of a value. Returns true if found. |
array_index(array, value) |
Finds the position of a value (starting from 0), or -1 if not found. |
array_has(array, value) |
Checks if an array contains a given value. |
array_sort(array) |
Sorts the array in place and returns it. |
array_reverse(array) |
Reverses the array in place and returns it. |
array_join(array, separator) |
Combines all elements into a string. array_join(["a", "b", "c"], ", ") returns "a, b, c". |
array_pick(array) |
Returns a random element. Affected by seed_random. |
array_shuffle(array) |
Shuffles the array in place and returns it. Affected by seed_random. |
array_copy(array) |
Returns a shallow copy of the array. |
array_length(array) |
Returns the number of elements in an array. |
items = ["sword", "shield"]
array_add(items, "potion")
if array_has(inventory, "golden key")
You unlock the ancient door.
greetings = ["Hello!", "Hey there!", "Welcome!"]
barista: $array_pick(greetings)
All array_ functions also support dot notation. For example, array_add(items, "sword") can be written as items.add("sword"), and array_join(items, ", ") as items.join(", "). This works on literals too:
sorted = [3, 1, 2].sort().join(", ") // "1, 2, 3"
Map
| Function |
Description |
map_keys(map) |
Returns an array of all keys in the map. |
map_has(map, key) |
Checks if a key exists in the map. |
map_get(map, key) |
Gets the value for a key. Returns null if the key doesn't exist. |
map_set(map, key, value) |
Stores a value under a key. |
map_remove(map, key) |
Removes a key and its value. Returns true if the key existed. |
map_copy(map) |
Returns a shallow copy of the map. |
map_length(map) |
Returns the number of keys in a map. |
map_set(inventory_counts, "arrows", 20)
count = map_get(inventory_counts, "arrows")
You have $count arrows left.
All map_ functions also support dot notation. For example, map_get(stats, "hp") can be written as stats.get("hp"):
keys = { name: "Alice", age: 30 }.keys()
Story state
| Function |
Description |
current_beat() |
Returns a reference to the beat that is currently running. When used in text (current_beat()), it displays the beat name. Can be compared to a string: current_beat() == "MyBeat". |
has_beat(name) |
Checks whether a beat with the given name exists and can be reached from where you are. Accepts a string (has_beat("MyBeat")) or a beat reference (has_beat(MyBeat)). |
beat_visits() |
Returns how many times the current beat has been entered. |
beat_visits(name) |
Returns how many times the named beat has been entered. Accepts a string (beat_visits("MyBeat")) or a beat reference (beat_visits(MyBeat)). |
if has_beat("SecretEnding")
choice
Try the secret path -> SecretEnding
Beat names can be used directly as references in expressions. This enables dot notation for beat functions. For example, beat_visits(CoffeeShop) can also be written as CoffeeShop.visits():
beat CoffeeShop
if beat_visits() == 1
Welcome to the coffee shop!
else
Welcome back! You've visited $CoffeeShop.visits() times.
Choice introspection
| Function |
Description |
choices() |
Returns an array of text for all currently enabled choice options. |
choices_all() |
Returns an array of text for all choice options, whether enabled or disabled. |
choices_disabled() |
Returns an array of text for all disabled choice options. |
These functions are useful inside choice option bodies to inspect what options were available when the player made their pick:
choice
Coffee
if choices().length() > 2
barista: So many options today, and you picked coffee!
else
barista: Limited menu today, good choice.
Tea
barista: A classic.
Juice if hasJuice
barista: Fresh squeezed!
You can also use choices() in a choice option condition. Here, the fallback only appears when all - prefixed options have been chosen in previous visits:
choice
- Coffee
barista: Here's your coffee!
- Tea
barista: Here's your tea!
- Juice
barista: Fresh squeezed!
Anything left? if !choices()
barista: Sorry, we're all out. Come back tomorrow!