This is an alternate version of OPL2’s wiki page.
Overview
| Datatype | Description |
|---|---|
| Bool | 0 for false, else for true |
| Decimal | 32-bit integral number |
| Float | 32-bit floating-point number |
| Path | Filename without extension, case-insensitive |
| String | ASCII text |
| Text | Shift-JIS text |
Scripts are in Shift-JIS encoding, with player-facing text in the non-ASCII range. Newlines should use CRLF and indentation use tabs—not spaces.
Single-line comments extend from an octothorpe (#) to an end-of-line and may appear after commands.
Multi-line comments begin and end with a dollar sign ($).
Commands begin with a percent sign (%) and are case-sensitive.
Arguments are colon (,) delimited and end with a semicolon (;); argumentless commands don’t end with a semicolon.
Text to be shown via the text field is simply placed at its desired location; no command needed.
Lines implicitly wrap at 25 characters (even in the middle of a word) or explicitly with %r.
The text field never automatically pauses; %K or %k must be used to allow the player to read it.
Note that player-facing English and other ASCII characters must use fullwidth characters.
Tips:
- Room locations are defined by points in the main room model.
Common room points:
loc_pos00: Near the centerloc_pos01: In front of something to sit onloc_pos02: On top of something- Nonexistent points use position=(0, 0, 0) rotation=(0, 0, 0)
- When linking multiple button menus together, use
%W0;at the start of each to prevent the text field from flashing
Statements
| Statement | Function | Example |
|---|---|---|
| :<S:label>; | Label location | :next; |
| &<D:name_idx> | Runtime character name | &0 |
Commands
| Command | Function | Example |
|---|---|---|
| Audio | ||
| %M{<P:.ogg>},<D:ignored>; | Plays music (loops); stops if no filename specified | %MBGM01,0; / %M,0; |
| %MA{<P:.ogg>},<D:ignored>; | Plays environment sound (loops); stops if no filename specified | %MAse09,0; / %MA,0; |
| %MS{<P:.ogg>},<D:ignored>; | Plays sound effect (doesn’t loop); stops if no filename specified | %MSse30,0; / %MS,0; |
| %o{<P:.ogg>}; | Plays voice (doesn’t loop); stops if no filename specified | %o0002; / %o; |
| %oR<D:char_idx>,<D:minFile>,<D:maxFile>,<F:minTime_secs>,<F:maxTime_secs>; | Plays random voices (%04d.ogg) with random delays; stops if minFile is less than 0 | %oR0,0453,0458,0.5,1; / %oR0,-1,0,0,0; |
| Camera | ||
| %c{<P:.tcm>},<B:repeat>; | Runs camera track | %ccam2_3,0; / %c,0; |
| %cl<B:lock>; | Toggles player control | %cl0; |
| %cp<S:point>; | Sets location in the room (only when locked) | %cploc_pos00; |
| %cu<D:char_idx>,<F:x>,<F:y>,<F:z>; | Sets first-person “up vector” | %cu0,0.0,1.0,0.0; |
| %cv<D:char_idx>,<D:point>; | Sets first-person look-at point (to loc_sight%02d) | %cv0,1; |
| Character Model | ||
| %ma<D:char_idx>,<D:part_idx>,<P:.tmb>; | Loads item | %ma0,1,imo_eye_01; |
| %mc<D:char_idx>,<D:0=front,1=behind,2=mouth>,<B:censor>; | Shows or hides area’s censor | %mc0,0,1; |
| %md<D:char_idx>,<D:part_idx>; | Removes item | %md0,5; |
| %mh<D:char_idx>,<D:0=upper,1=lower>,<D:0=on,1=half,2=off>; | Toggles underclothes’ state | %mh0,1,1; |
| %ml<D:char_idx>,<P:.tmb>; | Loads body and removes other items | %ml0,imo_bodyA_00; |
| %mm<D:char_idx>,<P:.tsb>; | Loads animation | %mm0,event_01; |
| %mp<D:char_idx>,<S:point>; | Sets location in the room | %mp0,loc_pos00; |
| %mr | Restarts character animations and clears the text field | %mr |
| %mv<D:char_idx>,<B:visible>; | Toggles visibility | %mv1,1; |
| Character Lighting | ||
| %la<D:light_idx>,<F:r>,<F:g>,<F:b>; | Sets ambient color | %la1,0.2,0.2,0.2; |
| %ld<D:light_idx>,<F:r>,<F:g>,<F:blue>; | Sets diffuse color | %ld1,0.2,0.2,0.2; |
| %le<D:light_idx>,<B:visible>; | Toggles visibility | %le1,1; |
| %ls<D:light_idx>,<F:r>,<F:g>,<F:b>; | Sets specular color | %ls1,0.8,0.8,0.8; |
| %lv<D:light_idx>,<F:x>,<F:y>,<F:z>; | Sets rotation | %lv1,1,1,1; |
| Flow Control | ||
| %G<P:.txt>; | Runs script | %Gtitle; |
| %I | Shows defined buttons and waits for player selection | %I |
| %i{*}<T:text>,<S:label>; | Defines button (max 8) that jumps to label when clicked or is disabled if text begins with an asterisk | %iTalk to Her,zen01; / %i*Talk to Her,zen01; |
| %J<S:label>; | Jumps to label | %Jnext; |
| %L<S:label>; | Calls label as subroutine (max depth is 16) | %Linit_char; |
| %l | Exits subroutine | %l |
| %Q | Quits game | %Q |
| %w<D:duration_frames>; | Waits | %w100; |
| Room Model | ||
| %mb<D:room_idx>,{<P:.tmb>}; | Loads model; removes if no filename specified | %mb1,room_03A; / %mb1,; |
| %mn<D:room_idx>,<P:.tsb>; | Loads animation | %mn1,room_03A; |
| %mV<D:room_idx>,<B:visible>; | Toggles visibility | %mV0,0; |
| Text Field | ||
| %K | Pauses text field then clears it | %K |
| %k | Pauses text field | %k |
| %n{<S:color_byte>}{<T:text>}; | Sets header field, which is pinned as the first line; clears if no options specified; ignores any text preceding the color code | %nText; / %n&0; / %n; |
| %R | Clears text field | %R |
| %r | Inserts newline | %r |
| User Interface | ||
| %f<D:0=3D,1=all>,<D:opacity>,<D:duration_frames>; | Fades screen; opacity 0 is black, 255 is transparent, and 512 is colored (uses fade.psd) | %f1,255,120; |
| %g{<P:.psd>}; | Shows image (first layer only); hides if no filename specified | %gtitle2; / %g; |
| %q<B:enable>; | Toggles quit hotkey; when enabled, Escape jumps to SystemExit (if it exists) or runs script.txt; delayed by text field pauses | %q1; |
| %T<B:visible>; | Toggles title image | %T1; |
| %W<B:visible>; | Toggles text field | %W1; |
| %WG<B:visible>; | Toggles character gauges, controlled by variable 128 for female and 129 for male | %WG1; |
| %X | Closes customization screen; only useful in label SystemExit since the CS pauses execution | %X |
| %Z<B:0=room,1=char>; | Opens customization screen; not implemented for rooms | %Z1; |
| Variable | ||
| %E<D:var_idx>,<S:comparison>,<D:value>,<S:label>; | Evaluates condition and jumps to label if true | %E18,=,1,h_mode; |
| %S<D:var_idx>,<S:operation>,<D:value>; | Sets variable | %S18,=,1; |
Bugs:
%oRwill crash if: no previous%ocommand executed, previous%ocommand was%o;, or%o;executes while%oRis active
Comparisons
| Operator | Truth State |
|---|---|
| = | Equal to |
| != | Not equal to |
| > | Greater than |
| >= | Greater than or equal to |
| < | Less than |
Operations
| Operator | Action |
|---|---|
| = | Assignment |
| + | Addition |
| - | Subtraction |
Indexes
Character
Range is [0, 7]; other indexes cause corruption.
Indexes not in [0, 1] cause corruption in %cu, %cv; and are ignored in %oR.
- Main female
- Main male
Color
Range is [1, 2]; other indexes cause corruption.
These indexes are raw character codes! E.g., %nblue;; note the usually-invisible character between “n” and “b”.
- Blue →←
- Pink →←
Light
Range is [0, 7]; other indexes are ignored.
Name
Range is [0, 3]; other indexes cause corruption.
- Male (colored if in
%n) - Female (colored if in
%n) - Male
- Female
Part
Range is [0, 31]; other indexes cause corruption.
- Body (Use
%ml) - Eyes
- Upper underclothes
- Lower underclothes
- Socks
- Upper outer clothes
- Lower outer clothes
- Head item
- Face item
- Neck item
- Arm item
- Shoes
- Hair
Room
Range is [0, 7]; other indexes cause corruption.
- Main
Variable
Range is [0, 255]; other indexes cause corruption. All are initialized to zero and indexes in [128, 255] persist between runs as pl2state.dat.