User:Stkptr/sandbox

From Esolang
Jump to navigation Jump to search
??
Paradigm(s) imperative, event-driven
Designed by Eiko, Ori randomizer community
Appeared in 2020
Memory system variable-based
Dimensions one-dimensional
Computational class Finite state automata
Reference implementation Ori WOTW randomizer
File extension(s) .wotwr, .wotwrh

The Ori and the Will of the Wisps Randomizer is a configurable game randomizer for Ori and the Will of the Wisps. The randomizer supports a seed language, which is capable of performing event-driven behavior depending on the player's progress.

Syntax

Seed files are made up of lines. Lines can include comments which begin with //. Commands are in the general form:

a|b|x|y|z|...

The a and b parameters together form a|b which is the uberstate specification. Uberstates are values that are tracked by the game. When an uberstate is changed or reached, commands corresponding to the uberstate are evaluated. The uberstate specification's first element is the uberGroup and the second is the uberState uberGroup|uberState. The other parameters form the pickup.

Semantics

Uberstates can have one of several different types, with types being either boolean-valued or number-valued. Bare uberstate specifications determine evaluation by determining if the value changed, and if the value is now truthy. Positive number values are considered truthy, with negative and zero values being falsy.

The uberstate can also be compared to produce a different coercion. The comparison operators are =, >, >=, <, <=. An example compared uberState is 14019|26318>=5 (taken from the documentation). This compares the Hand-to-Hand skill uberState 14019|26318 with 5. When this uberState reaches a value which meets the condition, it will trigger the pickup. Subsequent changes which meet the condition will not trigger the pickup. However, a change which does not meet the condition, followed by one which does, will trigger the pickup.

Most uberStates correspond to either locations which can be reached by the player, skills the player can increase, or other types of data which are kept track of by the save system. There are other additional "pseudo-location" uberStates which activate on different conditions, including certain key combinations, actions, general locations, etc.

Pickups have the form group|param|param|.... The group determines the type of change which happens when the pickup is triggered.

Group ID Parameters Behavior
0 Spirit Light ID places a Spirit Light
1 resource ID places a resource pickup
2 item ID places an item pickup
3 shard ID grants shard
4 command, ... miscellaneous commands
5 teleporter ID places a teleporter
6 text/flags... displays the text in a textbox, formatted according to the flags
7 none implicit multipickup group, automatically created when multiple pickups are defined for a single uberState
8 uberGroup, uberState, type, value, skip? writes a typed value to an uberState
9 event triggers world events
10 bonus ID places bonus items
11 bonus ID places bonus upgrades
12 hint deprecated zone hint
13 hint, ... deprecated key hint
14 relic ID places a relic
15 category, ... progress for relics
16 wheel, position, ... creates a wheel
17 command, ... alters shop items

The uberState update pickup is perhaps the most versatile. With it, chains of execution can be triggered, conditionally so. By default, an uberState update will allow for updates down the chain to occur. Using the skip parameter, the next n changes of a variable will not trigger updates. For instance:

a|b|8|x|y|bool|true|skip=1
x|y|6|State xy was triggered.

If we trigger the ab state, then the xy state will also be triggered. Since the uberState pickup triggered by the ab state is set to skip, the state triggered by xy will not be affected. If the skip is removed, then triggering ab will trigger xy, which displays the text.

The value parameter is quite versatile, supporting a basic expression syntax.

Form Example Result
constant 7 sets the uberState to the given constant
+expr +5, +$(9|15) increments the uberState by an amount
-expr -5, -$(9|15) decrements the uberState by an amount
$(uberGroup|uberState) $(9|15) expands to the value of the given uberState
[min, max] [0, 10], [$(9|14), $(9|15)] expands to a random value between min and max, inclusive

The group 4 pickup has a range of functions:

Command Parameters Effect
0 autosaves the game
1 resource, quantity sets a resource to a quantity
2 saves the game as a checkpoint
3 "the magic has vanished from the forest"
4 deprecated stop if equal
5 deprecated stop if greater than
6 deprecated stop if less than
0 flag allow/disallow the player to open the Kwolok door before Hollow
8 x, y teleports Ori to the given x, y coordinates
12 health sets Ori's health to the given amount
13 energy sets Ori's energy to the given amount
14 light sets Ori's spirit light to the given amount
15 slot, ability equips an ability in a slot
16 keybind presses a keybind
17 uberGroup, uberState, value, pickup grant pickup if the uberState is equal to value
18 uberGroup, uberState, value, pickup grant pickup if the uberState is greater than value
19 uberGroup, uberState, value, pickup grant pickup if the uberState is less than value
20 uberGroup, uberState disable syncing the given uberState in multiplayer
21 uberGroup, uberState enable syncing the given uberState in multiplayer
22 ID, x, y, label? creates a warp icon with optional label
23 ID removes a warp icon
24 x1, y1, x2, y2, pickup grant pickup if Ori is in the bounding box
25 value, pickup grant pickup if the triggering uberState is equal to value
26 value, pickup grant pickup if the triggering uberState is greater than value
27 value, pickup grant pickup if the triggering uberState is less than value
28 ability unequip an ability
29 ID, text assign the string builder with the given ID to the specified text
30 ID, text append the text to the specified string builder
31 set icon override
32 clear icon override

String builders can be accessed in message pickups (group 6) with the syntax ${builder ID}, e.g. ${0} will expand to the content in string builder 0.

uberStates can be set as timers using the syntax timer: uberGroup|uberState|uberGroup|uberState. The first uberState is the boolean toggle, which causes the second float uberState to increase each frame by the amount of seconds since the last frame.

Pickups with the same triggering state are grouped together into multipickups. The execution of these multipickups occurs like so:

  1. Sort the pickups such that the general triggers (no condition) occur first and the conditional triggers occur last, without altering the order within each type
  2. Execute the pickups top to bottom
  • If the pickup alters an uberState which is triggered on, handle those triggers before continuing

Computational class

The chain behavior of group 8 allows for a mostly straightforward implementation of counter machines. At the start, several uberStates are initialized to 1. These are the counters, one for each original counter, with an additional one for testing the state. Another state is initialized to 1, the program counter.

This implementation uses the notation when uberState = value set uberState as expression (type) corresponding to uberState|8|uberState|type|expression. There are three instruction forms, unconditional increment and decrement, and conditional jump. In this construction, the uberState p|c is the program counter, c|0 is counter 0, c|1 counter one, t|0 test counter zero, etc. state shall be the state corresponding to this instruction, n being the counter to alter, next state being the target state.

Start

when Init set counter0 as 1 (bigint)
when Init set counter1 as 1 (bigint)
...
when Init set countern as 1 (bigint)
when Init set temporary as 1 (bigint)
when Init set PC as 1 (int)
3|0|8|c|0|bigint|1
3|0|8|c|1|bigint|1
...
3|0|8|c|n|bigint|1
3|0|8|t|0|bigint|1
3|0|8|p|c|int|1

Increment

when PC = state set countern as +1 (bigint)
when PC = state set PC as next state (int)
p|c=state|8|c|n|bigint|+1
p|c=state|8|p|c|int|next state

Decrement

when PC = state set countern as -1 (bigint)
when PC = state set PC as next state (int)
p|c=state|8|c|n|bigint|-1
p|c=state|8|p|c|int|next state

Since the language only has conditional execution on state change, in fact only execution ever on state change, testing the value of a counter is somewhat tricky using only the group 8 pickup. The most apparent method is to use a temporary counter. The counter is set to 0, then the counter to test is copied into it. Since counters start and only ever can go as low as 1, there is a definite state change which occurs. Two additional pickups then affect the jump. Since pickups on a given uberState will always execute when that condition occurs, two auxiliary variables are used to store the jump targets before the jump occurs.

// at start of the program, appears once
when temporary = 1 set PC as $(zero) (int)
when temporary > 1 set PC as $(nonzero) (int)
t|0=1|8|p|c|int|$(j|0)
t|0>1|8|p|c|int|$(j|1)
// prepare temp and targets
when PC = state set temporary as 0 (bigint)
when PC = state set zero as zero state (int)
when PC = state set nonzero as nonzero state (int)
// copy over counter, triggering the jump
when PC = state set temporary as $(countern) (bigint)
p|c=state|8|t|0|bigint|0
p|c=state|8|j|0|int|zero state
p|c=state|8|j|1|int|nonzero state
p|c=state|8|p|c|bigint|$(c|n)

This scheme can translate any counter machine into the seed language. Note, however, the use of the fictional bigint type. As stated previously, the only types available are int, byte, boolean, float, and teleporter. Since int is limited to 32 bits, and there are a limited amount of uberStates, this means that the language is in the class of finite state automata.

As noted by the example, the addition of an arbitrary sized integer type would realize Turing completeness. This is not the only way Turing completeness could be achieved. The string builder system would be able to realize a queue if starting characters could be read and removed, or a stack if ending characters could be read and removed. Reading here referring to the ability to transition state on. An arbitrary sized queue is Turing complete by implementing tag, with a pair of unbounded stacks being Turing complete by constructing a Turing machine. Adding the ability to directly compare the lengths of strings with no intermediate operations would allow for the implementation of incrementing machines.

External links