Custom X-Change Life macros you can use in mods

Javascript Macros

X-Change Life uses a customized version of the Twine Harlowe engine. The following custom macros are for modders – these are some macros we have added to Twine Harlowe in order to extend its functionality.

1. average

Function: Calculates the average of a series of numbers.
Usage:

(set: $avg to (average: 1, 2, 3, 4, 5))  <!-- $avg will be 3 -->

2. rnd

Function: Rounds a number to a specified precision.
Usage:

(set: $rounded to (rnd: 3.14159, 2))  <!-- $rounded will be 3.14 -->

3. indexof

Function: Finds the 1-based index of an item in an array. Returns -1 if the item is not found.
Usage:

(set: $index to (indexof: (a: "apple", "banana", "cherry"), "banana"))  <!-- $index will be 2 -->

4. intersection

Function: Calculates the intersection of two arrays, returning their common elements.
Usage:

(set: $common to (intersection: (a: "apple", "banana"), (a: "banana", "cherry")))  <!-- $common will be (a: "banana") -->

5. savegameto

Function: Saves the game to the specified slot name.
Usage:

(savegameto: "slot1")  <!-- Saves the game to slot "slot1" -->

6. win

Function: Checks if the variable $result is “pass”.
Usage:

(set: $result to "pass")
(set: $didWin to (win:))  <!-- $didWin will be true -->

7. is_fem

Function: Checks if the character’s gender is female.
Usage:

(set: $character to (dm: "gender", "female"))
(set: $isFemale to (is_fem:))  <!-- $isFemale will be true -->

8. is_male

Function: Checks if the character’s gender is male.
Usage:

(set: $character to (dm: "gender", "male"))
(set: $isMale to (is_male:))  <!-- $isMale will be true -->

9. is_preg

Function: Checks if the character is pregnant.
Usage:

(set: $character to (dm: "pregnant", "true"))
(set: $isPregnant to (is_preg:))  <!-- $isPregnant will be true -->

10. knows_preg

Function: Checks if the character’s pregnancy is known.
Usage:

(set: $character to (dm: "pregnancy known", "true"))
(set: $knowsPregnancy to (knows_preg:))  <!-- $knowsPregnancy will be true -->

11. is_bim

Function: Checks if the character has the “bimbo” side effect.
Usage:

(set: $character to (dm: "side effects", (a: "bimbo")))
(set: $isBimbo to (is_bim:))  <!-- $isBimbo will be true -->

12. is_pp

Function: Checks if the character has the “people pleaser” side effect.
Usage:

(set: $character to (dm: "side effects", (a: "people pleaser")))
(set: $isPeoplePleaser to (is_pp:))  <!-- $isPeoplePleaser will be true -->

13. pill

Function: Checks if the value of $pill_taken matches the provided pill name (case-insensitive).
Usage:

(set: $pill_taken to "Cum-Cure")
(set: $isCumCure to (pill: "cum-cure"))  <!-- $isCumCure will be true -->

14. clamp

Function: Clamps a number within a specified range.
Usage:

(set: $clampedValue to (clamp: 15, 10, 20))  <!-- $clampedValue will be 15 -->
(set: $clampedValue to (clamp: 25, 10, 20))  <!-- $clampedValue will be 20 -->

15. currency

Function: Formats a number as currency (USD) without cents.
Usage:

(set: $formattedCurrency to (currency: 1234))  <!-- $formattedCurrency will be "$1,234" -->

16. del

Function: Deletes the specified variables.
Usage:

(del: "$variable1", "$variable2")  <!-- Deletes $variable1 and $variable2 -->

17. outfitdb

Function: Retrieves a list of outfits for a specified character, optionally filtered by outfit IDs.
Usage:

(set: $outfits to (outfitdb: "characterName"))  <!-- Retrieves all outfits for "characterName" -->
(set: $filteredOutfits to (outfitdb: "characterName", (a: "outfit1", "outfit2")))  <!-- Retrieves specific outfits for "characterName" -->

18. getoutfit

Function: Retrieves details of a specific outfit by its ID.
Usage:

(set: $outfitDetails to (getoutfit: "characterName category outfitName"))  <!-- Retrieves details of the specified outfit -->

19. checkdm

Function: Checks if a datamap contains a specified value based on an operation.
Usage:

(set: $dm to (dm: "key1", "value1", "key2", (a: "value2", "value3")))
(set: $result1 to (checkdm: $dm, "key1", "is", "value1"))  <!-- $result1 will be true -->
(set: $result2 to (checkdm: $dm, "key2", "contains", "value2"))  <!-- $result2 will be true -->

20. newseed

Function: Generates a new seed based on the current time.
Usage:

(set: $seed to (newseed:))  <!-- Generates a seed string based on the current time -->

21. clearstandardvars

Function: Clears standard variables.
Usage:

(clearstandardvars:)  <!-- Clears standard variables -->

22. twist

Function: Generates a random integer between a specified minimum and maximum value (inclusive) using the Mersenne Twister algorithm.
Usage:

(set: $randomNumber to (twist: 1, 10))  <!-- Generates a random number between 1 and 10 using Mersenne Twister algorithm -->

Note: This macro uses the Mersenne Twister algorithm, which provides a higher degree of randomness compared to Harlowe’s native randomness functions.

23. twirl

Function: Picks a random value from a list of arguments using the Mersenne Twister algorithm.
Usage:

(set: $randomValue to (twirl: "apple", "banana", "cherry"))  <!-- Picks a random fruit from the list using Mersenne Twister algorithm -->

Note: This macro uses the Mersenne Twister algorithm, which provides a higher degree of randomness compared to Harlowe’s native randomness functions.

24. twisted

Function: Shuffles an array using the Fisher-Yates algorithm with the Mersenne Twister algorithm for randomness.
Usage:

(set: $shuffledArray to (twisted: (a: "apple", "banana", "cherry")))  <!-- Shuffles the array using Fisher-Yates algorithm with Mersenne Twister algorithm -->

Note: This macro uses the Mersenne Twister algorithm, which provides a higher degree of randomness compared to Harlowe’s native randomness functions.

25. remove

Function: Removes a specified number of occurrences of an item from an array.
Usage:

(set: $originalArray to (a: "apple", "banana", "cherry", "apple"))
(set: $modifiedArray to (remove: $originalArray, "apple", 1))  <!-- Removes one occurrence of "apple" -->

Harlowe Macros

There are custom harlowe macros that you can also use. These are slightly different than the ones above since they perform native harlowe functions, opposed to the ones above that do background things in javascript. These are usually utility macros that shorten other functions or allows you to cut out repeated tasks.

🎥 Media & Visuals

$pic

Parameters:
(str) image_path, (str) position = "left", (str) css_class = "small"

Function:
Displays an image from the img/ folder. Optional parameters adjust position and CSS class. "small" sets width to 50%.

Usage Examples:

($pic:"places/gym/locker room.jpg") ($pic:"places/gym/locker room.jpg","left") ($pic:"places/gym/locker room.jpg","right","small")


$vid

Parameters:
(str) video_path, (str) position = "left"

Function:
Embeds an autoplaying, looping video with mute behavior determined by $audio_toggle. Optional "left" or "right" positions it using top_left_pic or top_right_pic.

Usage Examples:

($vid:"scenes/characters/jade/sex/workout/02 get towel.mp4") ($vid:"scenes/characters/jade/sex/workout/02 get towel.mp4","left")

🖼 Display & Styling

$centered

Parameters:
(codehook) _content

Function:
Wraps content in a centered <div class='options'> block. Used to center text or UI blocks visually.

Usage Examples:

($centered: ["You feel warm and slutty inside."]) ($centered: [(print:"<b>Warning:</b> You're being watched.")])

$highlight

Parameters:
(codehook) _content

Function:
Displays the content inside a <span class='highlight'>, useful for drawing attention to text.

Usage Examples:

($highlight: ["Objective Updated!"]) ($highlight: [(print:$her_name + " seems impressed.")])

$shadow

Parameters:
(codehook) _content

Function:
Displays the content inside a <span class='shadow'> for stylized text with a drop-shadow effect.

Usage Examples:

($shadow: ["Your heart skips a beat."]) ($shadow: [(print:"Round " + $round_number)])

$bimbo

Parameters:
(codehook) _content

Function:
Wraps the content in a <span class='bimbo'> and centers it in a <div class='options'>. Used for bimbo-styled thoughts or narration.

Usage Examples:

($bimbo: ["Like, I dunno what that means... but it sounds sexy! 💋"]) ($bimbo: [(print:"Ughhh... math is, like, soooo hard!")])

$bimbo_dialogue

Parameters:
(codehook) _content

Function:
Displays the content as bimbo-styled dialogue wrapped in quotation marks so you don’t have to add them.

Usage Examples:

($bimbo_dialogue: [Omigod, did you, like, feel that too?])
($bimbo_dialogue: [(twirl:"This is like, so totally embarrassing... *nervous giggle*","Omigosh, I'm like, so sorry! Was I using too much teeth? My jaw's just sooo tiny compared to your huge-")])

$heading

Parameters:
(str) _text

Function:
Displays _text in a large heading styled using the palette color, with a shadow effect.

Usage Examples:

($heading: "New Objective") ($heading: "Alexia’s Bedroom")

$notification

Parameters:
(str) _message

Function:
Displays _message inside a <mark> block that fades in and out automatically.

Usage Examples:

($notification: "You gained 1 charm.")($notification: "Your outfit is now dirty.")

$notification_still

Parameters:
(str) _message

Function:
Displays _message inside a non-animated <mark> block. Remains visible until removed by logic.

Usage Examples:

($notification_still: "Your makeup has worn off.") ($notification_still: "You have unread messages.")

🔊 Audio & Sound Control


$play

Parameters:
(any) type, (str) track, (str) delay = "none"

Function:
Plays a sound or music track. Supports custom routing based on type:

  • "sound", "sex loop", "ambience", "song"
  • Directory-specific: "scene", "story", "secretary", "workout"

Usage Examples:

($play:"sound","wet_squish") <!-- Plays a sound effect immediately --> 
($play:"ambience","cafe") <!-- Plays ambience immediately --> 
($play:"sex loop","slow_ride") <!-- Loops a sex sound --> 
($play:"scene","thwack","2s") <!-- Delays playback 2 seconds --> 
($play:"song no loop","main_theme") <!-- Plays a song once without looping -->

💬 Text & Language Tools


$caps

Parameters:
(str) sentence

Function:
Capitalizes the first letter of each word in the string.

Usage Examples:

(set:_title to ($caps:"just another slutty day")) (print:_title) <!-- Output: Just Another Slutty Day --> 
(print: $caps's "turn me into a girl") <!-- Output: Turn Me Into A Girl -->

💾 Storage Macros


$get_session_storage / $get_local_storage

Parameters:
(str) name, (any) default

Function:
Reads a value from browser session or local storage. Returns the default if nothing is found.

Usage Examples:

(set:_mood to ($get_session_storage:"last_mood","bored")) (set:_flags to ($get_local_storage:"debug_flags",(a:)))

$set_session_storage / $set_local_storage

Parameters:
(str) name, (any) value

Function:
Saves a value into session or local storage.

Usage Examples:

($set_session_storage:"last_mood","humiliated") ($set_local_storage:"debug_flags",(a:"showIDs"))

$delete_global_variable

Parameters:
(str) var_name

Function:
Resets a named variable by setting it to 0. Used to “delete” global state cleanly.

Usage Examples:

($delete_global_variable:"$her_name") <!-- Resets $her_name to 0 -->

$use_global

Parameters:
(str) var_name, (str) js_var_name, (codehook) hook

Function:
Temporarily loads a JS value, runs a hook with it, then resets the Twine variable.

Usage Examples:

($use_global: "$scene_select", "window.GE.scene_select", [(set:$scene to $scene_select)])

🧪 Logic & Utility


$char_passage

Parameters:
(str) base_passage, (codehook) core, (codehook) fallback

Function:
Tries to display a character-specific version of a passage for non-base girls (modded). Falls back to a default block if none exists.

Usage Examples:

($char_passage:"sex transactional kiss",[
      (set:$kiss_variant to (cond:
      $character's "race" is "white", "kiss " + (text:(twist:1,3)),
      $character's "race" is "latin", "kiss " + (text:(twist:4,6)),
      $character's "id" is "asian", "kiss " + (text:(twist:7,8)),
      $character's "id" is "black", "kiss " + (text:(twist:9,10)),
      "kiss"
      )
    )],[(set:$kiss_variant to "kiss")])

$passage_tags

Parameters:
(str) tag

Function:
Inserts a “blank” section with the assigned tag, so modders can inject code into this location. Popular for options like adding a new button in a set list of options – mall locations, pills, etc.

Usage Examples:

($passage_tags:"bar_options")
<!-- 
Then you'd inject code into that spot like this: 
:: new bar options [bar_options]
{(link:"yell at a patron")[etc]}
--> 

$rnd

Parameters:
(num) value, (num) precision

Function:
Rounds a number to a given decimal precision.

Usage Examples:

(set:_chance to ($rnd:0.75488,2)) <!-- _chance = 0.75 --> 
(print: $rnd:12.347,1) <!-- Output: 12.3 -->

$clamp

Parameters:
(num) value, (num) min, (num) max

Function:
Limits a value between a minimum and maximum. If the value is lower than min, returns min; if higher than max, returns max.

Usage Examples:

(set:_speed to ($clamp:12,5,10)) <!-- _speed = 10 --> 
(set:_volume to ($clamp:-3,0,100)) <!-- _volume = 0 --> 
(set:_sanity to ($clamp:$sanity,0,100)) <!-- Ensures stat stays in bounds -->

🧠 Mood & Status


$set_mood

Parameters:
(str) mood_name, (str) reason

Function:
Sets the current mood, including icon, stat changes, and duration. Triggers mood refresh visuals. Mood must exist (current existing moods are “awesome”, “bored”, and “humiliated”.)

Usage Examples:

($set_mood:"humiliated","because ' + (text: $her_name) + ' rejected you due to your small cock.")
($set_mood:"bored","because you've been hanging around the house too much recently!")

$set_status

Parameters:
(str) status_name, (str) reason

Function:
Adds a temporary status effect that modifies charm, intellect, or fitness. Triggers status display and stat refresh. Status must exist (current existing statuses are “cum breath”, “nasty cum breath”, “cum shoes”, “walking funny”.)

Usage Examples:

($set_status:"cum breath","' + (text: $npc's "sex name") + ' came in your mouth, and your breath smells...")

($set_status:"walking funny","You're not walking straight... maybe because your ass was so ruthlessly physically dominated in that machine...")

🕹 Game Interaction


$register_orgasm

Parameters:
None

Function:
Logs an orgasm event, resets arousal, reduces action points, and updates stats.

Usage Examples:

($register_orgasm:) <!-- Call at the end of orgasm scenes -->

$simple_option

Parameters:
(str) result, (...str) labels

Function:
Creates simple clickable links to set $choice and optionally go to next, display, or use nostop logic.

Usage Examples:

($simple_option:"passage","transition type (optional)","choice 1","choice 2","choice 3") <!-- Any number of choices -->

($simple_option:"buy flowers","Daisies","Roses","Lilies")
<!-- ^ this is the same as 
(link:"Daisies")[(set:$choice to "Daisies")($cs:"buy flowers")
(link:"Roses")[(set:$choice to "Roses")($cs:"buy flowers")
(link:"Lilies")[(set:$choice to "Lilies")($cs:"buy flowers")
-->

if you add "display" then it uses (display:) instead of ($cs)
($simple_option:"buy flowers","display","Daisies","Roses","Lilies")

if you use "next", then it uses ($nx) instead.
($simple_option:"buy flowers","next","Daisies","Roses","Lilies")

$cs

Parameters:
(str) passage_name

Function:
Sets $next and displays the "change screen" passage.

*Special note: Calling this will clear the content on the “center screen” and replace it with the passage that you call, but it will leave the left and right sidebars alone. The exception to this rule is if the passage you call is a [fullscreen] passage.

Usage Examples:

($cs:"scene 04 page 2")
($cs:"scene 04 page 3")

$nx

Parameters:
(str) passage_name

Function:
Sets $next and displays the "next" passage. This works similar to $cs except it replaces the ENTIRE screen. This means the passage you call needs to be [fullscreen] and rebuild both the left and right sidebars.

Usage Examples:

($nx:"Go to the bar")($nx:"Do chores")($nx:"Workout")

💰 Economy & Currency


$gain_money

Parameters:
(num) amount

Function:
Adds money to the player’s total and updates the money display with a visual fade-up transition. Also plays a “kaching” sound if the amount is greater than zero.

Usage Examples:

($gain_money:50) <!-- Adds $50 and shows animated currency update --> ($gain_money:200) <!-- Plays sound and fades in the new amount -->

$pay_money

Parameters:
(num) amount

Function:
Subtracts money from the player. Ensures balance never drops below zero. Updates display and plays a cash sound.

Usage Examples:

($pay_money:25) <!-- Deducts $25 and updates the money display --> ($pay_money:100) <!-- Deducts and plays sound if amount > 0 -->

🔥 Arousal & Emotion


$gain_arousal

Parameters:
(num) gain

Function:
Sets $gain to the given value and displays the "gain arousal" passage. Used to increment arousal in a stylized way.

Usage Examples:

($gain_arousal:10) <!-- Increases arousal by 10 and shows UI feedback -->($gain_arousal:5) <!-- Triggers gain arousal logic for smaller amounts -->

🎲 Skill Checks


$willpower_check

Parameters:
(str) next_passage, (num) difficulty

Function:
Performs a willpower check based on a fixed chance (101 - difficulty). If successful, jumps to the next_passage.

Usage Examples:

($willpower_check:"resist temptation",40) <!-- 61% chance to resist --> ($willpower_check:"walk away",70) <!-- 31% chance to succeed -->

$charm_check

Parameters:
(str) next_passage, (num) difficulty

Function:
Performs a charm-based skill check. Chance is calculated from charm * 10, averaged with 101 - difficulty.

Usage Examples:

($charm_check:"flirt with him",60) <!-- Based on player’s charm stat --> ($charm_check:"convince guard",75) <!-- Harder charm check -->

$intellect_check

Parameters:
(str) next_passage, (num) difficulty

Function:
Performs an intellect-based skill check. Chance is based on intellect * 10, blended with 101 - difficulty.

Usage Examples:

($intellect_check:"solve puzzle",50) <!-- Average difficulty logic check --> ($intellect_check:"hack the console",80) <!-- Requires high intellect -->

$fitness_check

Parameters:
(str) next_passage, (num) difficulty

Function:
Performs a fitness-based skill check. Chance uses fitness * 10 with a difficulty modifier.

Usage Examples:

($fitness_check:"climb out window",65) <!-- Physical escape or action --> ($fitness_check:"lift heavy object",40) <!-- Easier physical task -->