Conditionals allow parts of your level to be triggered only when certain requirements are met. These can be applied to almost all events.
There are two ways to enter the conditionals menu:
1. The directional sign in the top left corner when selecting most events.
2. The 'Conditionals' button in the Actions tab.
The conditionals menu looks like this:
This menu will eventually contain all the conditions you end up using in your level, to allow for easy access and reuse.
The name of the condition is only used as a title, so pick something that makes sense to you.
There are five types of conditions:
You can also delete a condition with the Delete button at the bottom. Note that deleting a condition will remove it from all events that use it.
Once created, conditions can be modified or duplicated from the conditionals menu by hovering over the condition.
The duplicate button (on the left) will make a copy of the condition, while the wrench button (on the right) will allow you to modify the condition. Duplicating the condition will not automatically apply the new condition to all events that used the old condition.
You can decide whether an event should be triggered or not by attaching conditionals to it.
A condition that is highlighted blue means that it be satisfied if the condition is true, while a condition that is highlighted red means that it will be satisfied if the condition is false.
All conditions on an event must be satisfied for the event to be triggered.
For example, an event with this set of conditions will only trigger if the most recent hit was a Perfect and the Language is not set to English.
Hovering over the directional sign on an event with conditions will display a helpful summary of the conditions attached.
The clock icon in the top right lets you set the duration of a condition, which is the window of time in which the event can be triggered (by satisfying all the conditions). The event will not trigger if all conditions are not met at any time within the duration. The conditions will not be checked before the event is passed by the playhead.
Note that the conditions are checked every frame of the duration, which means that the event can be triggered multiple times. For example, an event with a duration of 8 beats will check if all conditions are met for the next 8 beats, possibly triggering more than once.
A condition with a duration of 0 beats will only trigger once, immediately when the event is passed by the timeline.
Setting the play style allows you to change the behaviour of the playhead (the scrolling white line on the timeline). Note that changing the play style will not change the behaviour of the music. The music will continue playing as if the play style did not change.
There are 6 possible play styles: Normal, Loop, LoopBeatsOnly, Prolong, Immediately, and ExtraImmediately.
Do not loop or jump to bar 1, this will cause issues.
Ths is the default behaviour. The playhead advances through bars in sequential order.
This causes the playhead to restart the current bar upon reaching the end of the current bar. This will repeat until the play style is changed to something else.
This causes the playhead to restart the current bar upon reaching the end of the current bar, but subsequent times only plays the beats (i.e. without the vfx).
This causes the playhead to stop at the end of the current bar until the play style is changed to something else. The game will wait for the end of a bar (music-wise) before changing the play style away from Prolong in order to maintain sync.
Note that since the playhead no longer moves, you will get stuck unless you have a conditional that eventually triggers and changes the play style.
Using the activeDialogues
mod automatically sets the play style to Prolong, which lets dialogue remain on screen until user input is received.
This causes the playhead to jump to another bar after a prebar of approximately 667ms. The absolute bar number can be given, or a relative bar number from the current bar can be given instead.
Unlike the SetNextBar()
custom method, this event can be executed in the middle of a bar (or even the middle of a beat).
This will almost certainly cause your level to desync from the music, as the jump is performed immediately after the prebar delay ends. This can be remedied with some planning.
This is similar to Immediately, but causes the playhead to jump to another bar quicker, with a delay of approximately 300ms.
This will also almost certainly cause your level to desync from the music.
Helpful example video from @huantian#4880: https://discord.com/channels/296802696243970049/833132643234349097/844302910862917683
Tags allow groups of events to be executed together, as many times as needed.
Multiple events can be given the same tag. When the tag is run, all the events will be executed as if the playhead jumped to the first event with the tag and started running from there. Note that the maximum distance between events with the same tag is 1 bar. Any longer and you will encounter unexpected behaviour.
A common way to work around the 1 bar maximum is by creating a 99-beat bar at the very end of the level.
Tagged events can be called as many times as needed simply by running the tag multiple times. This allows for event re-use and better organization. Tags can also be disabled, which prevents them from being run.
Note: Currently, tagged Play Sound events are not well-supported. When running the tag, the Play Sound event will be triggered slightly later than expected (approximately 300ms). There are 2 workarounds (not recommended):
- Moving the Play Sound event earlier relative to other tagged events.
- You may need to create a useless event to act as an anchor if there are no other tagged events.
- Running the tag with the custom method and changing the execution time to OnPreBar.
- This will cause other tagged VFX events will be executed at a different relative time.
Pressing Shift-0 will toggle the visibility of the tag field on each event. Each event can only contain one tag. Upon tagging, the lower-left corner of the event will be coloured orange.
Tagged events do not play when the playhead passes over them, unlike normal events. This means they can be placed anywhere in the level. Instead, the tags must be run with a separate event.
Note: When scrubbing, tagged VFX events are currently bugged and will be played when the playhead passes over them. Playing the level from bar 1 does not have this issue.
Note: Do not have an event call its own tag at any point. Upon scrubbing at any point other than bar 1, the game will crash.
Tagged events can be run in two ways:
The Tag Action event can be found near the bottom of the VFX list. Select the Run Tag
or Run All Tags Containing Text
action from the dropdown, and provide the tag's name. The tag will be executed as soon as the playhead passes over the Tag Action event, unless the Tag Action event itself is tagged (see the section on layering tags below).
This requires a Call Custom Method event (near the bottom of the VFX list). Both RunTag()
and RunEventsWithTag()
do the same thing, and need to be provided the tag name prepended with str:
.
The Tag Action event supports enabling and disabling specific tags, as well as all tags containing a specified text.
The corresponding custom methods are listed below: (replace tagName
with your tag's name)
EnableTag(str:tagName)
DisableTag(str:tagName)
EnableTagsContaining(str:tagName)
DisableTagsContaining(str:tagName)
While the effect can be replicated using conditionals, these events can come in handy when combined with certain special tags.
Special tags are prepended onto your tag name, like shown below. These tags will be automatically run every time their condition is met, without needing to be run manually with an event.
Tag | Condition |
---|---|
[onHit] |
Every time a beat is hit |
[onMiss] |
Every time a beat is missed |
[onHeldPressHit] |
Every time a held beat's press is hit |
[onHeldReleaseHit] |
Every time a held beat's release is hit |
[onHeldPressMiss] |
Every time a held beat's hit is missed |
[onHeldReleaseMiss] |
Every time a held beat's release is missed |
[rowX] (X is a number) |
Modifies the tag to only apply to one row |
For the [rowX]
event, X is a 0-indexed number. For example, the tag [onHit][row0]
will run every time a beat on row 1 is hit. If the row does not exist, it will apply to all rows (i.e. the tag will be ignored).
These special tags can also be the target of Enable/Disable Tag events. Because they are executed so frequently, it is much simpler to enable/disable the tag than to manage conditionals around them.
For more complex groupings, you may want to consider running a tag from another tag (known as layering). Since the Tag Action and Call Custom Method events can both be tagged, you can have one tag execute multiple tags in this fashion.
There are two types of variables: read-only and editable. The value of read-only variables cannot be changed manually, while they can be changed in editable variables.
There are currently 3 types of editable variables: integers (i), floats (f), and booleans (b). 10 of each variable are currently accessible. The names of variables cannot be changed, only their values.
true
or false
.The variable buttonPressCount
acts like an integer (and can be modified accordingly), but is additionally incremented whenever the player presses.
These are special variables that provide some information about the current level or state of the game. The value of these variables cannot be modified, they can only be read.
Variable Name | Definition |
---|---|
bpm |
The currently set bpm |
barNumber |
The current bar number |
numEarlyHits |
The current number of early hits |
numLateHits |
The current number of late hits |
numPerfectHits |
The current number of perfect hits |
numMisses |
The current number of misses (without mistake weighting) |
numMistakes |
The current number of mistakes (with mistake weighting) |
XPress (X is a key) |
true immediately when X is pressed, false otherwise |
XRelease |
true immediately when X is released, false otherwise |
XIsPressed |
true while X is being held down, false otherwise |
List of allowed keys: p1
, p2
, anyPlayer
, up
, down
, left
, right
.
Variables can be used in 3 locations:
Variables can be read or modified in the Custom Method Name field. This can be combined with tags and conditionals to allow programmatic usage of variables.
This supports the operators ++
, --
, and =
.
Examples: i1++
, i2 = 4
Variables can be displayed in these events using interpolation. Simply surround the expression with braces.
Examples: I have {i1} apples
, We have {i1 + i2} pears
Variables can be read in the Expression field of a condition. These can be combined with operators ==
, !=
, >
, <
.
Examples: i1 == 1
, i2 > i3
In addition to the comparison operators, there are also the mathematical operators +
, -
, *
, /
, and %
(modulo).
Overall description for the thingy
Read-only variables
Variables that can be set to change different parts about the game. (Are mods just variables?)