The Glulx specification has very little to say about this capability. The basic description of the opcode in section 2.11 reads:
@setiosys L1 L2
Set the I/O system mode and rock. If the system L1 is not supported by the interpreter, it will default to the “null” system (0).
These systems are currently defined:
- 0: The null system. All output is discarded. (When the Glulx machine starts up, this is the current system.)
- 1: The filtering system. The rock (L2) value should be the address of a Glulx function. This function will be called for every character output (with the character value as its sole argument). The function’s return value is ignored.
- 2: The Glk system. All output will be handled through Glk function calls, sent to the current Glk stream.
- 20: The FyreVM channel system. See section 0.2, “Glulx and Other IF Systems”.
The values 140-14F are reserved for extension projects by ZZO38. These are not documented here.
It is important to recall that when Glulx starts up, the Glk I/O system is not set. And when Glk starts up, there are no windows and no current output stream. To make anything appear to the user, you must first do three things: select the Glk I/O system, open a Glk window, and set its stream as the current one. (It is illegal in Glk to send output when there is no stream set. Sending output to Glulx’s “null” I/O system is legal, but pointless.)
There’s also a little more in section 1.3.5 about how the “filtering” subsystem interacts with the call stack, but it doesn’t do much to illuminate the utility of this opcode.
The normal mode of a running game is mode 2, but the part of interest here is the “filtering system”, which is mode 1. As hinted above, when this mode is set, every character of output is submitted to this routine instead of being handled normally by the interpreter, and the return value is ignored. The utility may not be immediately apparent, but what it allows you to do as the author is inspect every outbound character and decide how to handle it, either by ignoring it, printing it, or transforming it in some way.
Conveniently, from the compiler’s perspective, the name of a routine is functionally the same as its address here.
Since the return value is ignored, the only thing that matters is what your “filtering” routine prints in response to a given input character. As a simple example, imagine a routine to produce “static” in output, such as might happen in a radio transmission:
Include (-
Global chance_of_static_pct;
[ StaticText char lc r ;
lc = glk_char_to_lower(char);
r = random(100);
if (r <= (+ percent chance of static +) && lc >= 'a' && lc <= 'z')
glk_put_char_uni('*');
else
glk_put_char_uni(char);
];
-).
Percent chance of static is initially 30.
To activate static filter:
(- @setiosys 1 StaticText; -).
To return to unfiltered output:
(- @setiosys 2 0; -).
To say (T - text) with (N - number) percent static:
now percent chance of static is N;
activate static filter;
say T;
return to unfiltered output.
When play begins:
say "We're getting close to the energy source, Captain. It's starting to affect our communicators." with 15 percent static.
The logic of the “filtering” routine can be arbitrarily complex. What eu1’s post does is allow any I7 phrase to be swapped in as the “filtering” routine, with the following widget:
Include (-
[ set_io_system phrase;
phrase = phrase-->1;
@setiosys 1 phrase;
];
-).
To switch to printing by (P - a phrase Unicode character -> nothing): (- set_io_system({P}); -).
So, to modify the static example to use this method:
Include (-
[ set_io_system phrase;
phrase = phrase-->1;
@setiosys 1 phrase;
];
-).
To switch to printing by (P - a phrase Unicode character -> nothing): (- set_io_system({P}); -).
Include Unicode Character Names by Graham Nelson.
To add (C - a Unicode character) to the story’s output: (- glk_put_char_uni({C}); -).
newline translates into Unicode as 10. [not in the extension]
Definition: a Unicode character is white space if it is Unicode space or it is Unicode newline.
Percent chance of static is initially 30.
To print (C - a Unicode character) with static (this is static filter):
if a random chance of percent chance of static in 100 succeeds and C is not white space:
add Unicode asterisk to the story's output;
otherwise:
add C to the story's output.
To say (T - text) with (N - number) percent static:
now percent chance of static is N;
switch to printing by static filter;
say T;
return to unfiltered output.
When play begins:
say "The interference is getting worse, Captain." with 35 percent static.