Hypnospace Outlaw

Hypnospace Outlaw

Modified content, additional content, and total conversions for Hypnospace Outlaw! Must have HypnOS v2.15 or above to create and use mods.

Learn more and find the game on Steam, GOG.com, itch.io, Discord.

Scripting in HypnOS

A reference manual for all scripts in Hypnospace

1 comment

Posted by on


IMPORTANT NOTE TO MODDERS

Please be VERY CLEAR in your description if your mod has spoilers or requires knowledge that folks won't have until they beat the game!

Also, MASSIVE SPOILER WARNING!! PLEASE finish the game before you read this guide!


The below assumes you are running Hypnospace Outlaw v2.20 or later! [UPDATE 2019-11-21: Some scripting is in v2.21 or v2.22a only]

BASIC SCRIPTING CONVENTIONS

Action:Parameters,Separated,By,Comma|Action2:Params . . .

Scripts run at 1 action per tick.

Example: closewindow:Explorer|virus:ButtsDisease|wait:2|webpage:hs\04_teentopia\yougothacked.hsp

The above will close the Explorer, give the player the ButtsDisease virus, wait 2 seconds, then open the You Got Hacked webpage.

Note: If an action other than the below is used, the Script will assume you're trying to run an internal Function. Any named Function in the Hypnospace Outlaw code can be run using the same conventions as scripts: NameOfFunc:Param0,Param1...

HOW TO RUN A SCRIPT

DOING QUICK TESTS:

  1. Enable the console in HypnOS BIOS:
    1. Go to the main menu
    2. Click BIOS in the bottom-right
    3. Turn on the 'Enable Console' checkbox
  2. Choose a save file to log in to HypnOS
  3. Press the ~ or ` or § key to bring up the console
  4. Type in a script and hit Enter (you can also copy a script from elsewhere and paste it using Ctrl+V)

USING SCRIPTS IN YOUR MOD:

  • Type in a script in a webpage's link/script box in the Page Builder. When you click this link, the script will run.
  • Add a script to a text file by adding "script:" to the beginning of the file and run it by:
    • Downloading the file in-game (downloadfile:path\to\file.ext) and running it by double-clicking the icon
    • Running the file directly via script (openfile:path\to\file.ext)
    • Add the script itself, or 'openfile:blah', to your mod's InstallScript or OnBootScript, or UninstallScript

SCRIPT TEXT FILES

Script files are simply text files containing scripts. When naming your script files, please use ONLY lowercase letters, and use one of the extensions listed in the Reference Manual. The file extension you use will determine the file's icon in HypnOS.

  • The first few characters of any script file must be exactly "script:". After that, type in your script(s)!
  • Scripts can be hidden within other file formats (images, videos, etc). Simply change the extension to match the format you want.
    • You can even make it appear to be a normal media file but run a script in the background. For example, here's a virus disguised as an image file:
      [myimage.him] script:openfile:downloads\myimage.png|virus:ButtsDisease
  • Advanced users can run multiple, concurrently running scripts in one file, separated by line-breaks. Each line break denotes a separate "threaded" script.

IMPORTANT NOTES

  • I recommend putting a line-break at the very end of all script, text, data, and ini files, otherwise the hidden character denoting the end of a file can occasionally cause issues with Hypnospace's file reader. Feel free to enter a line-break then "<eof>" or similar if you like, just ensure you have SOMETHING after the end of your script/data file after the end of the data. JSON arrays (chardata.hsd, webpages, etc) do not have this issue.
  • If you're using something other than Windows and Notepad to edit these files, make sure you set line breaks to Windows-style format (\r \n)

SAMWICH FILES

Samwich files were originally intended to have two separate functions: one when "locked" and one when "unlocked". We eventually determined that was too complicated, so we settled on making the "locked" version of the file function the same no matter what, e.g. show a pop-up saying the file is encrypted.

To create a Samwich encrypted file, simply make a text file containing two scripts, formatted like so:
Script:FileLocked
Clean:foo
<blank line>

"Script:FileLocked" is the default, "locked" script, and "Clean:foo" is the "unlocked" script. Leave the FileLocked part to make it appear like a normal, Samwich encrypted file, and replace "foo" with whatever script you want to run when it is "unlocked". Make sure you leave a line break at the end of your script file!!!

Technically, you can use the locked mode (Script) however you please, but it may confuse novice players, and seasoned players may never see it since they know it's a Samwich locked file and are going to simply unlock it immediately.

SCRIPTS

Reference format:
Action:Parameter(s),Separated,By,Comma,[optional parameter]
Description

DESKTOP AND OS SCRIPTS

CreateSystemIcon:icon animation,[icon function],[icon name]
Create a system icon. If only one parameter, the second and third will just copy that parameter.

RemoveSystemIcon:Icon's name
Removes an icon with an icon-to-trash animation.

ChangeSystemIcon:Icon's name,function,[animation]
Changes this icon's function and optionally its animation

StickyNote:[text]
Create StickyNote, populate with param text

Sticker:path\to\image.ext,[0/1]
Spawn this image as a sticker on the player's desktop, second optional parameter will align the sticker to the grid if set to '1'

Notify:text,[time in seconds]
Show text in notification panel attached to HUD

Launcher (no params)
Opens the Launcher (also available: CloseLauncher)

LoadWallpaper:filename.ext
Load an image from the \os\wallpaper\ folder to set as the desktop wallpaper

SwitchScreensaver:screensaver name
Set screensaver to this

StartScreensaver:screensaver name
Start this screensaver, by name

EndScreensaver
Stop the screensaver

ShowTab:Family,Tab,TabSFX#
Activate tab Tab in app Family, play TabSFX#

Shake:App Name
Shake window to get player attention

Theme:ThemeName,[-1]
Switch to this theme, if param 2 is -1 then do it silently

SwitchSoundscapeTheme:ThemeName
Switch the soundscape theme

LoadCursor:cursor theme name
Switch the user's cursor theme

CloseWindow:App Name
Close a window by its name (Warning!! Try the script "Close[AppName]" first, some built-in apps perform special functions upon closing via this function! Example: CloseExplorer)

QuickSwitch
Will activate the QuickSwitch window switcher (like Alt+Tab in Windows)

CloseAllWindows
Basically 'View Desktop' in Windows

KeyboardInput:a single letter or number / OSKeyboardInput:a single letter or number
Emulates keyboard input. NOTE: may not work if the player is using the on-screen keyboard! In some cases you may have to use OSKeyboardInput in that case. You can test if OSKeyboard in on-screen by using the what/not script 'if:IsOnScreen,OSKeyboard'.

PetPoo/PetFood
Spawn pet poo at the pet's location or pet food at the player's cursor

RenamePetGo:PetName
Change the player's pet's name

GoToTutorial:xxx
xxx = the tutorial page's [Group] within tutorial.ini. Make sure Tutorial is opened first (simply use the script function "Tutorial" to open it)

UpgradeHypnocure:1/2/3
Upgrade (or downgrade) the player's Hypnocure version, and open it if it is closed

OPEN/CLOSE AN APPLICATION

Use the following scripts with no parameters to open the associated app (some deprecated and/or unused):

OSKeyboard, HackApp, HAP, Archive, Pets, HypnoCure, Tunebox, InputBox, BrickPlacer, AppMenu, Tutorial, Soundscapes, Explorer, HSPD/Inbox/Cases, Settings, Downloads, CitizenData, QuickCheck, Wallet, Resolve, Eye, Axxelerator

Most of these applications can be closed by using the script 'Close[AppName]', as AppName is formatted above, Example: CloseExplorer

FILE RELATED SCRIPTS

DownloadFile:path\to\file.ext,[FromUser]
Downloads this file from data\Path, if FromUser is included it will force the 'From Source' text to be that username. Otherwise it's based on the webpage the file was downloaded from. DownloadFile scripts not run via a link on a webpage MUST specify a username! Adding an asterisk* to the end of the file name makes it permanent, and it cannot be deleted by the player.

DownloadAllFiles:path\to\folder,[FromUser]
Works exactly the same as DownloadFile, except it downloads ALL files from a folder.

CreateDesktopIcon:path\to\file.ext,FromUsername
Create an icon and put it on the desktop. The path\to\file.ext can just be file.ext if the file exists in the Downloads folder.

CreateFileIcon:Name.ext,Type,Username,Size,File\to\open.ext
Add a custom file icon that can open any file in the data folder (including script files). Add an asterisk* to the end of Name.ext to make it a permanent file.

ForceRecycleFile:Filename.ext
Force a file to be recycled (can't do this to permanent files)

ForceDestroyFile:Filename.ext
Force a file to be destroyed (even permanent files)

DoesFileExist:Filename
Searches through all file lists (including recycle bin), returns 1 if true

Hypnotext:Filename,Content
Display text data in HypnoText viewer.

HypnoImage:Filename,path\to\file.xyz
Display image data in HypnoImage viewer.

HypnoVideo:Filename,path\to\file.xyz
Play video in HypnoVideo viewer.

LockedVideo:path\to\file.xyz,func:param
Play this video with disabled play/pause functionality, and a disabled [X] button, then run this script function

2000Update:path\to\file.xyz,func:param
Play this video with disabled play/pause functionarlity in a locked-down window with no header, buttons, etc, then run this script function

OpenFile:path\to\file.xyz
Open this file

OpenFileClean:path\to\file.xyz
Open this file, if it is a samwich encrypted file, run the 'clean' script

MISC SCRIPTING

Wait:Time in seconds
Waits this number of seconds before performing next action.

WaitSignal:String
Pause this Script and listen for the given signal string before continuing. NOTE: Scripts using WaitSignal can NOT be made persistent!! They must be started each time the player logs in (using OnBootScript in config.ini, or otherwise).

Signal:String
Send this signal to "wake up" a waiting Script

Cooldown:Seconds
Player cannot click for n seconds (shows hourglass mouse) - USE SPARINGLY!

Password:String
Pause this script and ask for a password before continuing. If it matches the String parameter, the Script will continue, otherwise it will be destroyed. Multiple solutions can be entered by separating with '#' i.e. "pass1#pass2#pass3", also ? is a wildcard and will accept any text as an answer.

Repeat:n,[m]
Repeat this Script n times starting at action m (actions start at 0). Omit "m" to repeat entire script.

Persist:0/1
Toggle Script Persistence, i.e. this Script will save itself upon the player quitting and continue the next time they play the game. NOTE: Somes scripts do NOT support persistence!! Please test your scripts thoroughly to make sure they work when using Persist!

SelfDestruct:"me" or filename
Destroys this file - if "selfdestruct:me" is added to a script, the in-game downloaded file it is run from will be destroyed. Use at the end of scripts that act as "installers" so that the player cannot install something twice.

Tag:name
Give a Script a tag name:

EndScript:Tag
Force-end a Script by its tag name (useful for stopping looping scripts)

CitizenData:Name,[-1]
Load CitizenData for this citizen. If param 2 = -1, don't call the window.

Install:Title,Description,Script
Install window with progress bar shows up. Once complete, Description shows up and Script will run.

Uninstall:Title,Description,Script
Uninstall window with progress bar shows up. Once complete, Description shows up and Script will run.

InstallXXX:Item to install - XXX=Wallpaper/Screensaver/SFXTheme/Theme/Soundscape/Pet/Cursor
Install this item to the player's list (can be cancelled by the player)

AddXXX:Item to add - XXX=Wallpaper/Screensaver/SFXTheme/Theme/Soundscape/Pet/Cursor
Adds item to player's list of unlocked items (or spawns that pet).

RemoveXXX:Item to remove - XXX=Wallpaper/Screensaver/SFXTheme/Theme/Soundscape/Cursor
Removes item from player's list of unlocked items

ForceInstaller
Run this script to disable the X button on the installer (forcing players to let the item install)

UnforceInstaller
Run this script to re-enable the X button on the installer

InstallProfHelper/UninstallProfHelper
Professor helper here, ready to help!!! Well, bye then.

LogOff / RestartOS
Pretty self explanatory

LogOffButton / RestartOSButton
Show "are you sure" popup, then do the action if user chooses yes

ZoomImage:path\to\image.png,function:param,path\to\soundfile
This is what powers the effect you see when you find a new Squisherz - the image loads up then zooms in and rotates from a point in the center of the screen, then fades away. Image must be a png, the function:param must have only ONE parameter and will run as soon as the image disappears, and the soundfile will play immediately (do NOT include the .ogg extension here).

PaidParticles:#
Rain this # of coins from the sky

CoinParticles:#
Make this # of coins pop out of the cursor

WEBPAGE SCRIPTING

DelayLoad (no params) - Use ONLY at the beginning of webpage on-load scripts!! Stops the page from loading until this script has completed. Use when changing character Events, variable values, etc, so they complete the change before the page loads! This action also automatically adds 'ContinueLoad' to the end of this script.

ContinueLoad (no params) - Use ONLY within webpage on-load scripts!! Force the page to continue loading if DelayLoad was used previously in this script. This is unecessary except in complex scripts where the last action of the script has a chance to not fire.

Webpage:Path
Loads webpage at given path (always use 'hs\' regardless of capture name)

Anchor:Y Position
Scrolls to this Y position (on 32 px grid, i.e. 2 = 64 px)

Tooltip:Text
If this script is used on a link in a webpage, this is the text that shows when hovering your mouse over i

Buy:Price,Description,[script]
If player accepts purchasing the item, the Script will run. THIS MUST EXIST AT THE END OF YOUR SCRIPT! Everything after "Description" and the comma will only run if the player purchases the item.
Example: Buy:10,Stuff,action1:param1,param2|action2:param1|action3:param1 . . .

SearchGo:String
Search for the String in Hypnospace Explorer

LoadWebpage:URL,0/1,0/1
Load this webpage. If param 2 = 1 then do not show the Explorer window if it is hidden. If param 3 = 1 then treat this as if it was reloaded

Reload:0/1
Reload the current webpage, if param 1 = 1 then do not show the Explorer if it is hidden.

WebpageMusic (no parameters)
Toggle webpage music on/off

WebBack/WebFwd (no parameters)
Go back/forward in Explorer

SetFrame:#
Only for use on webpage Gifs! Sets the frame of the gif to this number (replace # with a ScriptVariable for more exciting uses of this script)

WebToolbar:xxx
Open up this toolbar tool (valid parameters: Hide, Search, Laws, Stamps) - Use 'Hide' or the same one that is currently open to close that toolbar

StopLoadingPage
Immidiately stop loading this webpage

DelayLoad/ContinueLoad
Pause and resume loading a webpage. You can use this in your PageLoad scripts in the Page Builder if you need to perform actions before loading a page.

InstantLoad
Mostly used for debug purposes! Will cause the game to hang for a moment, then the webpage will load instantly. This script is buggy, use with caution!!

MovePageElementsOffscreen
Move all text and images offscreen (used when the Explorer app is closed - may cause unwanted issues and effects!)

PageCursor:0-4
Manually set the mouse effect for this webpage

DisableExplorerStatus
Use this in a PageLoad script in the PageBuilder to hide the Citizen Status at the top of a page

WebAnchorScroll:#
Scroll to this position on a page

POPUPS

Popup:Title, Message, ButtonA Text, ButtonB Text, ButtonA Function, ButtonB Function, ButtonA Param, ButtonB Param, ButtonA CloseWhenClicked (0=true), ButtonB CloseWhenClicked (0=true), [leave blank], Icon (0=none), Window Tag
Most of these parameters are optional and can just be left blank if you're not using it. Example: Popup:Hello World,Hi this is my first popup message!,,,,,,,,,,
Set WindowTag to a unique name to prevent multiple copies of this popup to pop up. Set Icon to 0 for none, or 1-5 to choose an image on the left-hand side (see Modder's Reference Manual).

ad:AdName
Load AdName from data\misc\ads.ini

LoadApp:path\to\app.app
(See Advanced Scripting below for custom app scripting and details)

INPUT BOXES

InputBox:Function,Description,DefaultText
This script can run ANY function using player input as a parameter. Example: InputBox:RenamePet,What name?,April
NOTE: Only one single function can be passed through InputBox, and numbers input into the box are passed as strings.

InputWait:Function[:param optional],Description,[Default text optional]
Input box with 'wait' function attached, which forces the script to wait until user input is complete, then continues. User input text will be inserted as a parameter after 'Function'.

SOUND EFFECTS

SFX:path\to\SoundFile,[param1:val],[param2:val],...
Accepted parameters:
note, vol, pan, loop, decay, attack, sustain, offset, echo, echoamt, vib, vibamt, trem, tremamt, arpeg, arpegseq, tag, rand, skip, shift, shiftamt, ismusic

Example: SFX:alert,echo:0.5,echoamt:4,note:22 - Play alert.ogg at Note 22 (middle C = 24) with Echo every 0.5 seconds dropping by 4db each.

If SoundFile does not include a path, it will be assumed to exist in path: data\audio\sfx\[current sound theme]. Do NOT include the .ogg extension with the SoundFile!

[more details on SFX scripting coming eventually!]

VIRUSES AND BREAKING STUFF

Virus:Name
Activates a virus on by name.

CureVirus:Name
Disables a virus by name

CureAllViruses:Level,[Silent 0/-1]
Turns off all viruses. Virus levels are unsued within the game, simply set the Level parameter to 1 or omit it. If Silent is -1, no particles or sounds will happen upon curing viruses.
If a virus is activated, you can fake a virus cure function that fails to cure any viruses by setting the Level parameter to -1 [note: verify this!]

AddToQuarantine:Name
Adds a virus to the HypnoCure Quarantine list

UpgradeHypnocure:#
Upgrades HypnoCure app to: 1 = Lite, 2 = Plus, 3+ = Pro.

ScreenShake:Magnitude(px),Time(sec)
Shake screen by Magnitude for Time (default: 20,0.4)

BorkInstaller
Run this over and over on a loop to glitch out the installer as it is progressing

RecoveryMode
Show the text "Data Recovered - Please log in to complete recovery progress" on the player's save file upon logging out. This will be reset if the player logs out then back in, or resets HypnOS.

RSOD:Error Text,[Layout]
Perform a Red Screen of Death, display the Error Text, then go to the chosen Layout. Leave Layout blank to go to the boot screen after, then the login screen.

DisableLogOff
There's no turning back now!!! LogOff, Restart, or RSOD must happen for player to continue.

FinalGlitch / FinalGlitch2
Start the "final" sequence of OS explosions. Upon completion, FinalGlitch2 will load the script file \data\downloads\y2kisgo.txt which by default will RSOD, then show the newscaster sequence.

Hanger5000x:0/1
Activate/Deactivate OS hanging every 15-ish seconds

HangGlitch:[time]
Hang the operating system for a specified amount of time, or (0.5 - 1.5) seconds if not specified

DontSaveNow:0/1
1 = Immediately force a Save, then prevent saving past this point. 0 = OK to save the game. Example of usage: we're in the middle of a cutscene and we don't want anything to interrupt the sequence, like if the player Alt-F4's the game or their computer crashes, because if interrupted and saved it might soft-lock thier save file.


CHARACTER/CITIZEN SCRIPTING

Event:Name of event,-1 or 2,CitizenName
Change this Event to on or off for this citizen, -1 is off, 2 is on. 0 and 1 are not used because of late changes in the code and structure of the game.

RandomEvent:Prefix,a,b,-1 or 2,CitizenName
Change a random event (name = Prefix [# random from a to b]) to off or on (-1/2) for this citizen. See the webpage hs\07_open eyed\magicorb.hsp for an example.

ResetTempEvents:CitizenName
Set all TEMP events (TEMP 01, TEMP 02, etc...) to False/0 for this citizen.

AddViolationByName:CitizenName,ViolationType(0-5),Case Name,URL
Usually violations are accrued via the player finding content that violates CHIME on a citizens page, but you can also use this script to manually add violations to a citizen's record. ViolationType follows CHIME (01234) plus the extra S (5) given to you during the final chapter. Case Name is the case this violation is attached to (group name within cases.ini), or "undefined" if none. URL is the page the violation allegedly was found on, or "undefined" if none.

NOTE ON THE FOLLOWING: Detainment, Banning, and the "days" referenced below ended up not being used in Hypnospace proper, these may have unintended effects or no effect.

Flag:CitizenName
Flag character for Merchantsoft HQ to check out. (Use in conjunction with "Flagged" in the Progression ini)

Detain:CitizenName,n
Detain Character for n days (set day to be released from Detainment to Today+n) - If banned, nothing happens.

Ban:CitizenName
Ban character (literally Detain them for INFINITY days)

UnBan:CitizenName
ONLY IF BANNED: Unban character (set day to be released from Detainment to Today)

Forgive:CitizenName
ONLY IF NOT BANNED: Reset character's number of violations, un-detain them

SaveCitizen:CitizenName,0/1
Use this script to save a citizen and prevent them from showing up in the final Outlaw sequence. 0 = not saved, 1 = saved.

ForgiveAllChars
Used at the start of the final chapter to forgive all citizens of all violations, undetain, and/or unban them (does not affect their forgiveness counter)

HYPII SCRIPTING

HypiiSpeak:stuff
Makes Hypii speak out loud "stuff", but only if he's currently not saying anything, or does not have anything queued up to say after his current narration. Add an *asterisk at the beginning of "stuff" to supress the captions (unless "Caption all Hypii speech" is enabled in Settings).

Hypii:stuff / HypiiScript:command:var(s)
Adds speech to Hypii's queue regardless of the number of items currently queued up. Also allows for advanced scripting to make Hypii do things:

  • HypiiScript:speed:# - Set Hypii's speaking speed [must use a numerical #ScriptVariable# in place of #] (0-?)
  • HypiiScript:tone:# - Set Hypii's speaking tone [must use a numerical #ScriptVariable# in place of #] (0-3)
  • HypiiScript:wait:time - Pause Hypii's speaking for some time, in seconds (not currently working for some reason)
  • HypiiScript:move:x,y - Move to this position on screen
  • HypiiScript:moveto:AppName,(sideH),(sideV) - Move to this app window, to this position (sideH = left, right, or center / sideV = top, bottom, or middle)
  • HypiiScript:shy:0/1 - Make Hypii shy of your cursor (0/1 = false/true)
  • HypiiScript:bored:0/1 - Make Hypii bored and spin around the screen until the player moves the mouse or hits a key
  • HypiiScript:kill:1 - You horrible little monster, you

HypiiShutUp
Stop current narration, continue next item in the queue if there is any

HypiiPurge
Stop current narration and completely empty the queue

HypiiGlitch
Hypii glitches out and speaks [unintelligible nonsense] if he is currently speaking

MOD SCRIPTING

ModInstall:ModFolderTitle,[1]
Yeah that's right, you can install a mod from inside another mod. Distribute multiple mod folders in your mod's zip file (all with their own config.ini file) and go crazy! Set 2nd parameter to 1 to make it happen silently (no notification to the user).

ModUninstall:ModFolderTitle,[1]
Uninstall a mod from inside another mod. Set 2nd parameter to 1 to make it happen silently (no notification to the user).

ModBoot:ModFolderTitle
Run the OnBootScript of an installed mod

PLAYER PROGRESSION RELATED SCRIPTING

AddZone:Name of Zone
Add a zone to the player's list of accessible zones. Ex: AddZone:Teentopia

RemoveZone:Name of Zone
Remove a zone to the player's list of accessible zones\

HasZones
Return list of player's accessible zones (for debug)

AddCase:CaseTag,visible(-1,0,1,2)
Add Case to user's list. If n = -1: add as hidden, 0: visible, 1: ready to close, 2: closed.

UpdateCase:CaseTag,visible(-1,0,1,2)
Updates case status to n (see AddCase)

Progress:ProgressTag,value(0/1/2)
Adds ProgressTag to player's progression data, sets it to 0/1/2 (false, true, temporary)
Temporary progress tags (2) are defined as "True until evaluated within the progression logic and found to be false", and will be set back to False (0) when this happens.

TempProgress:ProgressTag
Adds ProgressTag as temporary (i.e. 2)

QuickProgress:string
Loop instantly through all Progression, and any [ProgressTag] within the progression.ini file that includes the text in this script's parameter will be checked immediately. Use this when you want Progression items to happen with zero delay after performing an action.

SetOSVersion:#.##
Set OS Version (i.e. boot up animation). Example: SetOSVersion:1.05. Valid values: 1.02, 1.03, 1.04, 2.00, 2.02.

Email:Title of Email
Player will receive this email (match title of email group in emails.ini, case sensitive)

GetPaid:#
IT'S PAYDAY HECK YES

AddCapture:Capture name
Add capture to player's list of unlocked captures. Ex: AddCapture:hsB

SetCapture:Capture name
Load this capture, only if it is unlocked

HAPNext/HAPPrev
Go to the next/prev Capture in the order they were added using AddCapture (same order as displayed in HAP, top-to-bottom)

SetChapter:#/NextChapter
Set the chapter to #, or go to the next chapter in numerical sequence. This has no effect until the OS is restarted or player logs out and back in. See \data\misc\chapters.ini for details.

PROGRESSION LOGIC SCRIPTING

Progression logic is found within data\misc\progress.ini. Progression logic works by looking at the what/not (if/if not) scripts inside of each progression item in the INI file. Here's a simple progression item, "AbbyGooper", that makes it so once you've found at least 2 Goopers, Abby will start to balk at the fact that you're removing them from her page:

[AbbyGooper]
what=ViolationPoints:AbbyWrites58,2
not=chapter:2
script=persist:1|wait:90|event:GooperRemoved,2,AbbyWrites58

The 'what' script above checks if there are at least two violation points on AbbyWrites58, then the 'not' script makes sure you have not yet reached chapter 2, and if both return TRUE then a script runs setting a character event "GooperRemoved" to true. This triggers Abby's page to update and respond to what's happening to her page.

PROGRESSION WHAT/NOT (IF/IF NOT) SCRIPTING

Progression items can have as many what/not scripts as needed. A 'what' script is the same as asking "if x is true then return true" and a 'not' script is the same as asking "if x is not true then return true", where x is the script following the "what= " or "not= ".

Reference format:
Query:Parameter(s)
Returns true if...

ViolationPoints:CitizenName,n
Citizen current violation points >= n

Flagged:CharacterName
Citizen currently flagged

*Banned:CharacterName [deprecated]
Citizen currently banned

*Detained:CitizenName [deprecated]
Citizen currently detained

NumViolations:CitizenName,n,m
Citizen number of violations for a specific violation type, n (0 based - 0 = Content Infringement, etc) is >= m violations

TotalViolations:CitizenName,n
Citizen *total* violations >=n

TotalFlagged:CitizenName,n
Total times player has flagged a Citizen >= n

*TotalDetainments:CitizenName,n [deprecated]
Total times Citizen detained >= n

*TotalForgiven:CitizenName,n [deprecated]
Total times Citizen forgiven >= n

*TotalResolved:CitizenName,n [deprecated]
Citizen (Forgiven+Detainments) >=n

Event:CitizenName,EventName
This event is True for this Citizen

Downloaded:Filename
True if that filename is downloaded

HasVirus:[name]
Player is currently infected by this virus. If Name is empty, then returns true on ANY virus.

Progress:ProgressTag,[n]
n is optional, return true if ProgressTag is true, or if n>0 returns true if ProgressTag has accumulated >= n

Money:n
Player has >= n Hypnocoin

FoundViolations:n
Player has found >= n violations total

CitizensFlagged:n
Accumulative number of citizens Flagged by the player >= n

*CitizensDetained:n [deprecated]
Accumulative number of Detained citizens >= n

*CitizensBanned:n [deprecated]
Accumulative number of Banned citizens >= n

*CitizensForgive:n [deprecated]
Accumulative number of Forgiven citizens >= n

*DaysSinceViolation:n [deprecated]
if player hasn't found a violation in >= n days

CaseViolations:n,CaseName
if >= n violations in this case

IsGroupActive:GroupName
If internal code group "GroupName" is active, returns true

IsArchived:url
If this URL has been visited by the player during Archive mode, within the capture specified by the url (important!!)

HasSeenPage:url
If this URL has been visited by the player ever, within the capture specified by the url (important!!)

Chapter:n
If Chapter >= n. To ensure the chapter is exactly "n", use: what=chapter:(n) and not=chapter:(n+1)

IsOnScreen:WindowName
If a window by this name is on-screen

ADVANCED SCRIPTING

CREATING CUSTOM "FUNCTIONS"

Text script files can be organized to run multiple, concurrent scripts simply by putting a line-break in between each script. Using this functionality, if you'd like to create a bunch of scripts that you can call on demand without having to use OpenFile each time, you can do so by running a batch of scripts via your mod's OnBootScript to open a script file containing multiple scripts that all loop infinitely and are called via Signals. For example:

MyScripts.txt:

script:waitsignal:MyScripts_AddOne|addvar:Foo,1|repeat:99999,0

waitsignal:MyScripts_HypiiFoo|Hypii:The value of Foo is #Foo#|repeat:99999,0

waitsignal:MyScripts_DLImage|DownloadFile:path/to/image#Foo#.png|repeat:99999,0

Now you can call any of these "functions" by using the script Signal:MyScripts_AddOne at any time!

SCRIPT VARIABLES

Initialize a variable in a script with var:VarName (your mod's install script is a good place for this) then use their values in your script parameters by using #VarName# (replace VarName with the name of your variable).

VarNames must:

  • have no spaces
  • have no special characters
  • be less than 16 characters long

VarNames are case sensitive!

You can use as many variables as you like! Be sure to use unique variable names though, so that you do not interfere with other mods' variables! I recommend giving each of your variables a prefix, i.e. 'MyModVar1'.

Also, #VarName# can be used in text objects on Hypnospace webpages, so you can have a page show the player their 'stats' as you track them, or other stuff I dunno get creative with it!!

Misc/debug variable scripting:
listallvars
Shows a popup with all variables and their values
listallvarnames Shows a popup with the name of every variable
listvars:VarName,[VarName2],[VarName3]... Popup with the name and value of all variables listed in the parameters

Initialize a variable in memory:
var:VarName

Set and convert variables:
setvar:VarName,[value]
vartoint:VarName
vartofloat:VarName
vartostring:VarName
deletevar:VarName
setvar will also initialize the variable if it has not yet been initialized

Set to a random number:
randvar:VarName,low,high

Mathematical operations:
addvar:VarName,[value(s)]*
subvar:VarName,[value(s)]*
multivar:VarName,[value(s)]*
dividevar:VarName,[value(s)]*
modvar:VarName,[value]
powervar:VarName,[value]

Round to closest integer, round up, round down:
roundvar:VarName,[value]
ceilvar:VarName,[value]
floorvar:VarName,[value]

String operations:
concatvar:VarName,[value(s)]*
leftvar:VarName,length
rightvar:VarName,length
midvar:VarName,start index,length
zeropadvar:VarName,length

*multiple values separated by comma can be used here

ADVANCED VARIABLE SCRIPTING

Set to a variable from another data source [ADVANCED, HypnOS v2.21 and above]:
For help with these scripts, look in your Enforcer#.sav save file to see the key/value pairs for the items in these data sources
setvartoprog:VarName,ProgressionKey (returns current value of this item from the Progression data source)*
setvartosave:VarName,SaveDataKey (returns current value of this item from the SaveData data source)*
setvartosetting:VarName,SettingsKey (returns current value of this item from the Settings data source)*
setvartoglobal:VarName,GlobalSettingsKey (returns current value of this item from the GlobalSettings data source)*
setvartovirus:VarName,VirusKey (returns current value of this item from the Viruses data source)*
setvarbyfunc:VarName,function:parameter (set a variable to the return data of any script function that returns data, returns 0 if no data returned)
*returns "null" if the key does not exist. Keys are case sensitive, Viruses keys are always all lowercase.

Copy the value of one variable to another variable:
setvarbyname:VarName,VarName2*

This will result in VarName being set to the current value of VarName2
*setvarbyname does NOT initialize variables! Make sure to use var:VarName first if the variable VarName is not yet initialized.

You can set a variable by its name via another variable, for example:
setvar:Foo,Bar|setvar:#Foo#,12345
The above will result in setting the variable "Bar" to 12345.

You can also do the above with setvarbyname, for example:
var:Test|setvar:Foo,Bar|setvar:Bar,12345|setvarbyname:Test,#Foo#
This will result in setting the variable 'Test' to the value of 'Bar', 12345.

WHAT/NOT (IF/IF NOT) STATEMENTS WITHIN SCRIPTS

What/Not scripts (see 'Progression What/Not Scripting' above) can be used directly in normal scripts using 'if' and 'not', see examples below. All 'if' statements return true if the result is = to the parameter. Use 'not' instead of 'if' if you'd like to find if it's < the #, or utilize 'else'. Parameters can be replaced with a #VarName#.

Usage:
if:query,parameter1,[parameter2],[etc]
not:query,parameter1,[parameter2],[etc]

List of what/not related scripts:
if, not, else, endif

In addition to the Progression What/Nots you can use if/not:compare statements to compare two #VarName# script variables.

Comparators:
if:compare,[a],[operator],[b]
operator can be =, ==, !=, <>, <, <=, >, >=

EXAMPLES

Simple if/then/else example comparing two variables, #Foo# and #Bar#:

if:#Foo#,==,#Bar#|Hypii:Equal!|else|if:#Foo#,>,#Bar#|Hypii:Greater!|else|Hypii:Lesser!

Math quiz via scripting:
var:Input|var:A|var:B|var:Correct|var:Wrong|var:Result|randvar:A,0,10|roundvar:A|randvar:B,0,10|roundvar:B|setvar:Result,0|addvar:Result,#A#,#B#|inputwait:setvar:Input,What is #A# + #B#?|vartoint:Input|if:compare,#Result#,=,#Input#|Hypii:Correct!|addvar:Correct,1|else|Hypii:Nope. The correct answer was #Result#.|addvar:Wrong,1|endif|repeat:4,2|addvar:Wrong,#Correct#|Popup:Results,You got #Correct#/#Wrong# questions right.

...and add a Hypnocoin prize (10 * number correct) at the end of the quiz:
var:Prize|setvar:Prize,10|multiplyvar:Prize,#Correct#|getpaid:#Prize#

Open a random script file (script01.txt - script09.txt):
var:FileID|randvar:FileID,0,10|floorvar:FileID|zeropadvar:FileID,2|setvar:FileToOpen,path\to\script|concatvar:FileToOpen,#FileID#,.txt|openfile:#FileToOpen#
This will result in, for example: openfile:path\to\script01.txt

CUSTOM APPS

Check out test.app within data\downloads. Load it up in-game with the script LoadApp:downloads\test.app or OpenFile:downloads\test.app, or download the app by using DownloadFile:downloads\test.app.

Here's what it does:
peanuts

The best way to learn how custom apps work is to check out the scripting and ini data in this file: ...data\downloads\test.app :)

Custom app INI file explanation:

Note: Almost all of the parameters past the = sign can be replaced with a script variable, i.e. #VarName#. Again, check out the test.app file for details on how this can be used!

[data] (The [data] group must come first, and has details on the app's window, tabs, and scripting.)
name= (Your app's internal name)
title= (The window header's title)
subtitle= (The window header's subtitle)
icon=0-23 (The icon at the top-left, leave blank or omit for the default star icon)
header=0/1 (whether or not there is a header)
transparent=0/1 (whether or not the window has a transparent center)
drag=0/1 (whether or not the player can drag the window around)
width=164 (pixel width)
height=70 (pixel height)
tab=Hello,footab (add as many tab= items as you need to keep your app's controls behind separate tabs - see the top of the Settings app for an example of tabs)
tab=World,bartab (World = the text the tab displays, bartab = the internal name of this tab)
script=* (script to run when the app is opened, leave blank if none)
closescript= (script to run when the app is closed, leave blank if none)

[text01] (a text object. Add as many as you need, increasing the ## by one for each additional text object)
x=12 (x pixels from left edge of the window)
y=24 (y pixels from the top edge of the window)
width=140 (pixel width)
height=60 (pixel height)
tab=footab (the tab this text object exists in - leave blank for visible in all tabs)
behind=0/1 (whether or not this object is behind the window - i.e. z-order)
colorgroup=TextDark (the color group for this text object - see data\os\themes\[themename]\colortable.ini for selections)
colorstyle= (the color style for this text object, some groups have just one style, "Color", and this can be left blank - see data\os\themes\[themename]\colortable.ini for selections)
text=Hello World (display this text. Encase in {{brackets}} to use line breaks, and use \p \t \n, and #VarName# if you like)
align=left (left/right)
vertalign=top (top/bottom)

[button01] (a button object. Add as many as you need, increasing the ## by one for each additional button)
x=130 (x pixels from left edge of the window)
y=54 (y pixels from top edge of the window)
text=Add 1 (text to display on the button)
tab=footab (the tab this button object exists in - leave blank for visible in all tabs)
script=foo (script to run when the button is clicked)

[image01] (an image object. Add up to 32 images to your app, increasing the ## by one for each additional image. Note that there can be up to 32 images TOTAL shared between ALL CUSTOM APPS!! Try to keep the number of images reasonable.)
x=70 (x pixels from left edge of the window)
y=44 (y pixels from top edge of the window)
width=20 (pixel width)
height=20 (pixel height)
tab=footab (the tab this image object exists in - leave blank for visible in all tabs)
image=path\to\image.png (path after the root HypnOS data folder)
behind=0/1 (whether or not this object is behind the window - i.e. z-order)
script=foo (script to run when the image is clicked - leave blank for no script)

*If there's a script= within [data], the window will not open until the script is done running! If you have a longer or repeating script that needs to run upon window opening, put it in a separate script file and use openfile:path\to\script.txt instead.

Custom app scripts:
LoadApp:path\to\yourapp.app - Load up the app
CloseWindow:AppName - Close this app (does NOT run the app's closescript)
RefreshApp:AppName - Reload the app's text and image objects (in case variables have been updated, etc)
ShowTab:AppName,Tab,[sfx 1-4] - Show this tab in this app (leave [sfx] blank for no tab sounds)



Did we miss something? Or is a script not working as it shows above? Let us know!! Contact us via Discord, Twitter, etc! Links can be found at Hypnospace.net

Comments

Join the community or sign in with your gaming account to join the conversation:

Spanospy
Spanospy @spanospy

The discord is also a good resource for finding more information about an action, including some actions that are unused or not listed here. Just ask on their modding channel, or use discord's search feature.