Skip to content

External Functions Reference

External functions allow you to add dynamic behavior to your Ink scripts. These functions can check game state, manipulate strings, generate random values, and more.

Content State Functions

Check if content has been unlocked or viewed by the player.

ink
// Check if a gallery item is unlocked
~ temp isUnlocked = IsGalleryItemUnlocked("photo-001")

// Check if a gallery item has been seen by the player
~ temp isSeen = IsGalleryItemSeen("photo-001")

When to use: To create branching dialogue based on what photos/videos the player has discovered.

Example:

ink
{IsGalleryItemSeen("crime-scene-photo"):
    You've already seen the crime scene photo. What do you think?
- else:
    I have a photo I need to show you. It's... disturbing.
}

News Functions

ink
// Check if a news article is unlocked
~ temp isUnlocked = IsNewsUnlocked("article-001")

// Check if a news article has been read
~ temp isRead = IsNewsRead("article-001")

When to use: To reference news articles in conversations or require players to read certain articles before progressing.

Example:

ink
{IsNewsRead("breaking-news-sarah"):
    I see you read the news about Sarah. Terrible, isn't it?
- else:
    Have you checked the news today? You should.
}

Note Functions

ink
// Check if a note is unlocked
~ temp isUnlocked = IsNoteUnlocked("note-001")

// Check if a note has been read
~ temp isRead = IsNoteRead("note-001")

When to use: To check if the player has discovered and read important notes or clues.

Example:

ink
{IsNoteRead("sarah-diary"):
    So you read Sarah's diary. Now you understand why she was scared.
- else:
    There's something in Sarah's notes app you need to see.
}

Contact Functions

ink
// Check if a contact is unlocked
~ temp isUnlocked = IsContactUnlocked("contact-alex")

// Check if a conversation is unlocked
~ temp isConvUnlocked = IsConversationUnlocked("conv-001")

// Get unread message count for a conversation
~ temp unreadCount = GetUnreadMessageCount("conv-001")

When to use: To create dynamic dialogue based on who the player has met or messaged.

Example:

ink
{IsContactUnlocked("detective-morgan"):
    The detective is already on the case. We should wait for their update.
- else:
    Maybe we should contact the police?
}

Important: Contacts are automatically unlocked when a conversation containing that contact is unlocked. For example, unlocking a conversation with #unlockConversation:alex will automatically unlock the "alex" contact. You typically don't need to manually unlock contacts unless you want to add someone to the contact list without starting a conversation.


Location Functions

ink
// Check if a location is unlocked
~ temp isUnlocked = IsLocationUnlocked("coffee-shop")

// Check if a location has been viewed on the map
~ temp isSeen = IsLocationSeen("coffee-shop")

When to use: To create branching dialogue based on what locations the player has discovered or visited.

Example:

ink
{IsLocationUnlocked("crime-scene"):
    I see you found the crime scene on your map. Have you been there yet?
    {IsLocationSeen("crime-scene"):
        Good, you've checked it out. What did you find?
    - else:
        You should go there and investigate.
    }
- else:
    I'll send you the location of the crime scene. #unlockLocation:crime-scene
}

Note: A location is "unlocked" when it appears on the player's map (either via initial: true or #unlockLocation tag). A location is "seen" when the player has viewed its details on the map.


Player Functions

Access information about the player's account and authentication status.

ink
// Get player's full name
~ temp name = GetPlayerName()

// Get player's email address
~ temp email = GetPlayerEmail()

// Get player's first name only
~ temp firstName = GetPlayerFirstName()

// Get player's last name only
~ temp lastName = GetPlayerLastName()

// Get player's initials
~ temp initials = GetPlayerInitials()

// Check if player is logged in
~ temp isLoggedIn = IsPlayerLoggedIn()

When to use: To personalize the story with the player's actual name or check authentication.

Example:

ink
Wait... I have your details here. Your real name is {GetPlayerFirstName()}, isn't it?
No worries, {GetPlayerName()}, let's continue.

{IsPlayerLoggedIn():
    Your account is verified. Let's proceed.
- else:
    Please log in to continue with this investigation.
}

Player Input Functions

Get text, image, or location input from the player during conversations.

ink
// Get text that the player typed (use with #text_input tag)
~ temp playerText = GetPlayerInput()

// Get gallery item ID that player attached (use with #attach_image tag)
~ temp attachedImage = GetAttachedGalleryItem()

// Get player's current location (use with #location_input or #location_input_gps tags)
~ temp latitude = GetPlayerLocationLatitude()
~ temp longitude = GetPlayerLocationLongitude()

When to use: When you need the player to provide custom text, select an image, or share their location.

Example:

ink
What's your name?
* [Continue]
  # text_input:Enter your name
  ~ player_name = GetPlayerInput()
  -> confirm_name

== confirm_name ==
Thank you, {player_name}. Nice to meet you.
-> END

Image attachment example:

ink
Can you send me a photo for verification?
* [Continue]
  # attach_image:Select a photo
  ~ attached_item = GetAttachedGalleryItem()
  -> verify_photo

== verify_photo ==
Thanks for sending that photo. Let me check it...
-> END

Location input example:

ink
Where did you see her?
* [Send location] #location_input:Where did you see her?
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  Thanks for sharing that location!
  Let me check coordinates {lat}, {lng}...
  -> END

Location Functions

Work with GPS coordinates and location-based gameplay.

ink
EXTERNAL GetPlayerLocationLatitude()
EXTERNAL GetPlayerLocationLongitude()
EXTERNAL IsWithinDistance(lat, lng, targetLat, targetLng, radiusMeters)
EXTERNAL GetDistanceBetween(lat, lng, targetLat, targetLng)
EXTERNAL IsWithinDistanceOfLocation(lat, lng, locationId, radiusMeters)
EXTERNAL GetDistanceFromLocation(lat, lng, locationId)

Get Player Location

ink
// Get player's latitude
~ temp lat = GetPlayerLocationLatitude()

// Get player's longitude
~ temp lng = GetPlayerLocationLongitude()

When to use: With #location_input or #location_input_gps tags to get the player's shared location.

Important: These functions return the location the player shared, not their real-time GPS location. The player must first share their location using a location input tag.


Check Distance

ink
// Check if player is within a radius (in meters) of a target location
~ temp isNearby = IsWithinDistance(playerLat, playerLng, targetLat, targetLng, radiusMeters)

Parameters:

  • playerLat - Player's latitude
  • playerLng - Player's longitude
  • targetLat - Target location latitude
  • targetLng - Target location longitude
  • radiusMeters - Radius in meters (e.g., 100 for 100 meters)

Returns: true if player is within the radius, false otherwise

When to use: To verify if the player is at a specific location for location-based puzzles or gameplay.

Example:

ink
Prove you're at the crime scene.
* [Send GPS location] #location_input_gps:Prove you're at the scene
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  ~ temp targetLat = 51.5074
  ~ temp targetLng = -0.1278
  ~ temp isAtScene = IsWithinDistance(lat, lng, targetLat, targetLng, 100)
  
  {isAtScene:
    Perfect! You're at the scene. I can confirm your location.
  - else:
    You're not at the crime scene. You need to be within 100 meters.
  }
  -> END

Get Distance Between Points

ink
// Get distance in meters between two locations
~ temp distance = GetDistanceBetween(lat1, lng1, lat2, lng2)

Parameters:

  • lat1 - First location latitude
  • lng1 - First location longitude
  • lat2 - Second location latitude
  • lng2 - Second location longitude

Returns: Distance in meters (rounded to nearest meter)

When to use: To calculate how far the player is from a target location or between two points.

Example:

ink
Where are you right now?
* [Share location] #location_input_gps:Share your current location
  ~ temp playerLat = GetPlayerLocationLatitude()
  ~ temp playerLng = GetPlayerLocationLongitude()
  ~ temp targetLat = 51.5074
  ~ temp targetLng = -0.1278
  ~ temp distance = GetDistanceBetween(playerLat, playerLng, targetLat, targetLng)
  
  You're {distance} meters away from the bar where Sarah was last seen.
  
  {distance < 500:
    You're pretty close! Keep going.
  - distance < 2000:
    You're in the area. About {distance / 1000} km away.
  - else:
    That's quite far. You're {distance / 1000} km away.
  }
  -> END

Check Distance to Location (by ID)

ink
// Check if player is within a radius of a defined location
~ temp isNearby = IsWithinDistanceOfLocation(playerLat, playerLng, "coffee-shop", radiusMeters)

Parameters:

  • playerLat - Player's latitude
  • playerLng - Player's longitude
  • locationId - ID of the location (filename without .json)
  • radiusMeters - Radius in meters (e.g., 100 for 100 meters)

Returns: true if player is within the radius, false otherwise (or if location doesn't exist)

When to use: When you want to check if the player is near a location defined in your locations/ directory, without hardcoding coordinates.

Example:

ink
Prove you're at the coffee shop.
* [Send GPS location] #location_input_gps:Share your location
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  ~ temp isAtCoffeeShop = IsWithinDistanceOfLocation(lat, lng, "coffee-shop", 50)
  
  {isAtCoffeeShop:
    Perfect! You're at the coffee shop. I can confirm your location.
  - else:
    You're not at the coffee shop. You need to be within 50 meters.
  }
  -> END

Tip: This is cleaner than IsWithinDistance() when working with predefined locations, as you don't need to hardcode coordinates in your Ink script.


Get Distance to Location (by ID)

ink
// Get distance in meters to a defined location
~ temp distance = GetDistanceFromLocation(playerLat, playerLng, "coffee-shop")

Parameters:

  • playerLat - Player's latitude
  • playerLng - Player's longitude
  • locationId - ID of the location (filename without .json)

Returns: Distance in meters (rounded to nearest meter), or -1 if location doesn't exist

When to use: To calculate how far the player is from a location defined in your locations/ directory.

Example:

ink
Where are you right now?
* [Share location] #location_input_gps:Share your current location
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  ~ temp distance = GetDistanceFromLocation(lat, lng, "coffee-shop")
  
  {distance == -1:
    Error: Location not found.
    -> END
  }
  
  You're {distance} meters away from the coffee shop.
  
  {distance < 100:
    You're right there! Go inside.
  - distance < 500:
    You're very close. Just a short walk.
  - distance < 2000:
    You're in the area. About {distance / 1000} km away.
  - else:
    That's quite far. You're {distance / 1000} km away.
  }
  -> END

Tip: Always check for -1 to handle cases where the location ID doesn't exist.


Complete Location-Based Example (Using Coordinates)

ink
EXTERNAL GetPlayerLocationLatitude()
EXTERNAL GetPlayerLocationLongitude()
EXTERNAL IsWithinDistance(lat, lng, targetLat, targetLng, radiusMeters)
EXTERNAL GetDistanceBetween(lat, lng, targetLat, targetLng)

== check_location ==
I need you to go to the location where Sarah was last seen. #typing:3s
The coordinates are 51.5074, -0.1278. #pin:51.5074,-0.1278
Let me know when you're there. #typing:2s

* [I'm at the location] #location_input_gps:Share your GPS location to confirm
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  ~ temp targetLat = 51.5074
  ~ temp targetLng = -0.1278
  ~ temp distance = GetDistanceBetween(lat, lng, targetLat, targetLng)
  ~ temp isNearby = IsWithinDistance(lat, lng, targetLat, targetLng, 50)
  
  {isNearby:
    Perfect! You're at the scene. I can see you're only {distance}m away.
    Look around carefully. What do you see?
    -> at_scene
  - distance < 200:
    You're close ({distance}m away), but not quite there yet.
    The exact location is just a bit further.
    -> check_location
  - else:
    You're {distance}m away from the location. That's too far.
    You need to be within 50 meters to investigate properly.
    -> check_location
  }

== at_scene ==
// Player is now at the correct location
-> END

Complete Location-Based Example (Using Location ID)

ink
EXTERNAL GetPlayerLocationLatitude()
EXTERNAL GetPlayerLocationLongitude()
EXTERNAL IsWithinDistanceOfLocation(lat, lng, locationId, radiusMeters)
EXTERNAL GetDistanceFromLocation(lat, lng, locationId)

== check_coffee_shop ==
I need you to go to the coffee shop where Sarah was last seen. #typing:3s
Check your map for the location. #unlockLocation:coffee-shop
Let me know when you're there. #typing:2s

* [I'm at the coffee shop] #location_input_gps:Share your GPS location to confirm
  ~ temp lat = GetPlayerLocationLatitude()
  ~ temp lng = GetPlayerLocationLongitude()
  ~ temp distance = GetDistanceFromLocation(lat, lng, "coffee-shop")
  ~ temp isNearby = IsWithinDistanceOfLocation(lat, lng, "coffee-shop", 50)
  
  {distance == -1:
    Error: Location not found. Please contact support.
    -> END
  }
  
  {isNearby:
    Perfect! You're at the coffee shop. I can see you're only {distance}m away.
    Look around carefully. What do you see?
    -> at_coffee_shop
  - distance < 200:
    You're close ({distance}m away), but not quite there yet.
    The coffee shop is just a bit further.
    -> check_coffee_shop
  - else:
    You're {distance}m away from the coffee shop. That's too far.
    You need to be within 50 meters to investigate properly.
    -> check_coffee_shop
  }

== at_coffee_shop ==
// Player is now at the correct location
-> END

String Functions

Powerful string manipulation and comparison functions for dynamic text handling.

String Comparison

ink
// Check if string starts with prefix
~ temp startsWithHello = StringStartsWith(playerName, "Hello")

// Check if string ends with suffix
~ temp endsWithExe = StringEndsWith(filename, ".exe")

// Check if string contains substring
~ temp containsError = StringContains(message, "error")

// Exact string equality
~ temp isEqual = StringEquals(input, "yes")

// Case-insensitive equality
~ temp isYes = StringEqualsIgnoreCase(input, "YES")

When to use: To check player input or create dynamic responses based on text content.

Example:

ink
What's your name?
~ temp name = GetPlayerInput()

{StringStartsWith(name, "Dr"):
    Ah, a doctor! Welcome, {name}.
- StringStartsWith(name, "Mr"):
    Good to meet you, {name}.
- else:
    Hello, {name}!
}

String Manipulation

ink
// Convert to uppercase
~ temp upper = StringToUpper("hello") // "HELLO"

// Convert to lowercase
~ temp lower = StringToLower("HELLO") // "hello"

// Trim whitespace from both ends
~ temp trimmed = StringTrim("  hello  ") // "hello"

// Replace first occurrence
~ temp replaced = StringReplace("hello world", "world", "there")

// Replace all occurrences
~ temp allReplaced = StringReplaceAll("foo foo foo", "foo", "bar")

When to use: To clean up or modify player input or format text dynamically.

Example:

ink
~ temp location = GetPlayerInput()
~ temp cleanLocation = StringTrim(location)
~ temp upperLocation = StringToUpper(cleanLocation)

You found it at {upperLocation}. Got it.

String Information

ink
// Get string length
~ temp length = StringLength("hello") // 5

// Check if string is empty
~ temp isEmpty = StringIsEmpty("") // true

// Find index of substring (-1 if not found)
~ temp index = StringIndexOf("hello world", "world") // 6

When to use: To validate player input or check text properties.

Example:

ink
~ temp answer = GetPlayerInput()

{StringIsEmpty(answer):
    You didn't enter anything. Please try again.
- StringLength(answer) < 3:
    That's too short. Please be more specific.
- else:
    Thank you for your response: {answer}
}

String Extraction

ink
// Get substring from start position to end
~ temp sub = StringSubstring("hello world", 6) // "world"

// Get substring with specific length
~ temp sub = StringSubstring("hello world", 0, 5) // "hello"

// Split string by delimiter (returns pipe-separated values)
~ temp parts = StringSplit("apple,banana,orange", ",") // "apple|banana|orange"

When to use: To extract parts of text or parse structured input.


String Validation

ink
// Check if string is numeric
~ temp isNum = StringIsNumeric("123") // true
~ temp notNum = StringIsNumeric("abc") // false

// Check if string matches regex pattern
~ temp isEmail = StringMatchesPattern(email, "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$")
~ temp isPhone = StringMatchesPattern(phone, "^\\d{3}-\\d{3}-\\d{4}$")

When to use: To validate player input like emails, phone numbers, or other formatted data.

Example:

ink
What's your email address?
~ temp email = GetPlayerInput()

{StringMatchesPattern(email, "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"):
    Email saved: {email}
- else:
    That doesn't look like a valid email address. Please try again.
}

Time Functions

Work with dates, times, and time-based conditions.

ink
// Get current hour (0-23)
~ temp hour = GetCurrentHour()

// Get current day of week as number (0=Sunday, 6=Saturday)
~ temp dayNum = GetCurrentDay()

// Get day of week as string ("Monday", "Tuesday", etc.)
~ temp dayName = GetDayOfWeek()

// Check if it's weekend (Saturday or Sunday)
~ temp isWeekend = IsWeekend()

// Get time of day ("morning", "afternoon", "evening", or "night")
~ temp timeOfDay = GetTimeOfDay()

When to use: To create time-sensitive dialogue or events that change based on when the player is playing.

Example:

ink
{GetTimeOfDay() == "morning":
    Good morning! Early start today?
- GetTimeOfDay() == "afternoon":
    Good afternoon! How's your day going?
- GetTimeOfDay() == "evening":
    Good evening! Long day?
- else:
    You're up late! Can't sleep?
}

{IsWeekend():
    At least it's the weekend, right?
- else:
    Shouldn't you be at work on a {GetDayOfWeek()}?
}

Utility Functions

Random number generation and probability for dynamic, unpredictable events.

ink
// Roll a dice with N sides (returns 1 to N)
~ temp roll = RollDice(6) // 1-6

// Random integer between min and max (inclusive)
~ temp num = RandomInt(1, 100)

// Random choice from list of options
~ temp choice = RandomChoice("apple", "banana", "orange")

// Probability check (percentage chance of true)
~ temp success = Chance(75) // 75% chance of true

When to use: To add randomness and replayability to your story.

Example:

ink
You search the room...

{Chance(30):
    You find a hidden compartment! #gallery:secret-photo
- else:
    Nothing unusual here.
}

// Random NPC response
{RandomChoice("Maybe.", "I'm not sure.", "Let me think about it."):
    -> continue_conversation
}

API Functions

Advanced functions that connect to external services (requires API to be enabled).

ink
// Check if story tools/API are enabled
~ temp toolsEnabled = GetStoryToolsStatus()

// Detect object in a gallery image (returns confidence 0.0-1.0)
~ temp faceConfidence = DetectObjectInGalleryImage("photo-001", "face")
~ temp carConfidence = DetectObjectInGalleryImage("photo-001", "car")

When to use: For advanced stories with AI-powered image analysis.

Example:

ink
~ tools_enabled = GetStoryToolsStatus()

{tools_enabled == 1:
    Let me run this through our facial recognition system... #typing:3s
    ~ face_confidence = DetectObjectInGalleryImage(attached_item, "face")
    {face_confidence > 0.7:
        Perfect. I can clearly see a face in this photo.
    - face_confidence > 0.3:
        The image quality isn't great, but I can make out a face.
    - else:
        I'm having trouble detecting a face in this photo.
    }
- else:
    Our systems are currently offline. I'll review this manually.
}

Complete Examples

Personalized Greeting

ink
== start ==
{GetTimeOfDay() == "morning":
    Good morning, {GetPlayerFirstName()}!
- GetTimeOfDay() == "afternoon":
    Good afternoon, {GetPlayerFirstName()}!
- else:
    Hello, {GetPlayerFirstName()}!
}
-> END

Conditional Content Based on Progress

ink
{IsNewsRead("breaking-news-001") && IsNoteRead("note-001") && IsGalleryItemSeen("photo-001"):
    You've reviewed all the evidence. Time to make a decision.
- else:
    You should review all the evidence first before we continue.
}

Location-Based Branching

ink
{IsLocationUnlocked("crime-scene") && IsLocationSeen("crime-scene"):
    I see you've checked out the crime scene. What did you think?
- IsLocationUnlocked("crime-scene"):
    The crime scene is on your map. You should go there and investigate.
- else:
    I'll send you the location of the crime scene. #unlockLocation:crime-scene
}

String Validation for Player Input

ink
What's your email address?
* [Continue]
  # text_input:Enter your email
  ~ temp email = GetPlayerInput()
  -> validate_email

== validate_email ==
{StringMatchesPattern(email, "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"):
    Email saved: {email}
    -> END
- else:
    That doesn't look like a valid email address.
    -> ask_email_again
}

Random Events with Probability

ink
You search the abandoned warehouse...

{Chance(40):
    You find something! #typing:2s
    {RandomChoice("A torn piece of fabric.", "A discarded phone.", "Fresh footprints."):
        -> found_clue
    }
- else:
    Nothing of interest here. The place is empty.
    -> END
}

Time-Based Dialogue

ink
{GetCurrentHour() >= 22 || GetCurrentHour() < 6:
    It's {GetCurrentHour()}:00. You should be sleeping!
- IsWeekend():
    Happy {GetDayOfWeek()}! Any plans for the weekend?
- else:
    Another {GetDayOfWeek()}. How's work going?
}

Best Practices

Input Validation

Always validate player input before using it:

ink
~ temp input = GetPlayerInput()
~ temp cleanInput = StringTrim(input)

{StringIsEmpty(cleanInput):
    Please enter something.
- StringLength(cleanInput) < 3:
    Please be more specific.
- else:
    -> process_input
}

Error Handling

Check if content exists before referencing it:

ink
{IsGalleryItemUnlocked("photo-001"):
    {IsGalleryItemSeen("photo-001"):
        You've already looked at that photo.
    - else:
        Take a look at the photo I sent you.
    }
- else:
    I don't have that photo yet.
}

Combining Functions

Use multiple functions together for complex logic:

ink
~ temp name = GetPlayerInput()
~ temp cleanName = StringTrim(name)
~ temp firstName = StringSubstring(cleanName, 0, StringIndexOf(cleanName, " "))

{StringIsEmpty(firstName):
    ~ firstName = cleanName
}

Nice to meet you, {firstName}!

Function Reference Summary

CategoryFunctionReturnsDescription
GalleryIsGalleryItemUnlocked(id)booleanCheck if gallery item is unlocked
IsGalleryItemSeen(id)booleanCheck if gallery item has been viewed
NewsIsNewsUnlocked(id)booleanCheck if news article is unlocked
IsNewsRead(id)booleanCheck if news article has been read
NotesIsNoteUnlocked(id)booleanCheck if note is unlocked
IsNoteRead(id)booleanCheck if note has been read
ContactsIsContactUnlocked(id)booleanCheck if contact is unlocked
IsConversationUnlocked(id)booleanCheck if conversation is unlocked
GetUnreadMessageCount(id)numberGet unread message count
LocationsIsLocationUnlocked(id)booleanCheck if location is unlocked
IsLocationSeen(id)booleanCheck if location has been viewed
PlayerGetPlayerName()stringGet player's full name
GetPlayerEmail()stringGet player's email
GetPlayerFirstName()stringGet player's first name
GetPlayerLastName()stringGet player's last name
GetPlayerInitials()stringGet player's initials
IsPlayerLoggedIn()booleanCheck if player is authenticated
InputGetPlayerInput()stringGet player's text input
GetAttachedGalleryItem()stringGet attached image ID
GetPlayerLocationLatitude()numberGet player's shared latitude
GetPlayerLocationLongitude()numberGet player's shared longitude
LocationIsWithinDistance(lat, lng, targetLat, targetLng, radius)booleanCheck if within radius (meters)
GetDistanceBetween(lat1, lng1, lat2, lng2)numberGet distance in meters
IsWithinDistanceOfLocation(lat, lng, locationId, radius)booleanCheck if within radius of location
GetDistanceFromLocation(lat, lng, locationId)numberGet distance to location (meters)
StringStringStartsWith(str, prefix)booleanCheck if string starts with prefix
StringEndsWith(str, suffix)booleanCheck if string ends with suffix
StringContains(str, substring)booleanCheck if string contains substring
StringEquals(str1, str2)booleanExact equality check
StringEqualsIgnoreCase(str1, str2)booleanCase-insensitive equality
StringToUpper(str)stringConvert to uppercase
StringToLower(str)stringConvert to lowercase
StringTrim(str)stringRemove whitespace
StringReplace(str, find, replace)stringReplace first occurrence
StringReplaceAll(str, find, replace)stringReplace all occurrences
StringLength(str)numberGet string length
StringIsEmpty(str)booleanCheck if empty
StringIndexOf(str, substring)numberFind substring index
StringSubstring(str, start, length?)stringExtract substring
StringSplit(str, delimiter)stringSplit string (pipe-separated)
StringIsNumeric(str)booleanCheck if numeric
StringMatchesPattern(str, regex)booleanMatch regex pattern
TimeGetCurrentHour()numberGet hour (0-23)
GetCurrentDay()numberGet day of week (0-6)
GetDayOfWeek()stringGet day name
IsWeekend()booleanCheck if weekend
GetTimeOfDay()stringGet time period
UtilityRollDice(sides)numberRoll N-sided dice
RandomInt(min, max)numberRandom integer
RandomChoice(...items)stringRandom choice from list
Chance(percentage)booleanProbability check
APIGetStoryToolsStatus()numberCheck if API enabled (1/0)
DetectObjectInGalleryImage(id, object)numberDetect object (0.0-1.0)

Next Steps

Released under the MIT License.