True, with locally-executing code it can be hard to notice the effect at human-scale if you’re spending 99% of the time blocked in a read and only 1% of the time doing timer processing. But that still means that 1% of the time the player’s key/mouse input would get lost.
Construct a story that has a different balance of processing time (even if less realistic) to magnify the effect, and it becomes more obvious.
To use an analogy, I encountered a web app a while back where every individual keystroke in a form field is round-tripped to the server and then overwrites the text in the field. (Essentially, it was doing server-side validation.) When the app is running on the local machine and relatively idle, everything functions perfectly.
Load the local machine up with other processing work, though, or put it on a remote server instead (so you have network latency), and the cracks start showing. The user will type two characters in the time it takes to roundtrip one, and then their second character disappears. While not identical to the IFVM case, this is a logical extension of that kind of behaviour.
If mouse-clicks are in the terminating characters table, then that solves the “multiple clicks in one read” problem neatly. If they’re not, then things get tricky. Logically I would expect that it would update the coords for the last click made during the read and report the number of clicks (anywhere) as individual characters, as I said before.
This does break the dictionary parsing, but the raw text is still reported to the story, so it could detect the parsing failure, walk through the characters itself, strip out the clicks, then resubmit it for dictionary parsing (or for continued input, if the player didn’t press enter yet). It’s probably not the best way to handle mouse input (not least because there’s inherent latency when not interrupting the read on click) but it should theoretically work.
Perhaps another slightly more realistic case might be a story that wants fully real-time input, and so always uses
@read_char and never
@read. Perhaps it’s doing the parsing entirely itself, or perhaps it’s not even parser-based at all (although then probably the Z-Machine is not the right format to use).
Such a story would be alternating between sitting in
@read_char waiting for input, doing some input processing and updating the world state because the player just pressed a key, or doing some background processing to update the state due to a timeout (perhaps some background animation, or it’s a real-time game and it has to update the enemy’s actions while the player isn’t doing anything).
The first two cases are obviously not problems – the player is very unlikely to press a second key in the time it takes to process the first key. Even fast typists just aren’t that fast. The third case, however, is where the problem occurs. You cannot possibly guarantee that the player won’t just happen to press a key an instant after the
@read_char exits due to timer and before it starts the next one. The faster the processing time is, the less likely this is to occur, of course, but it can never be zero probability.
And this means a loss of input. In a parser game, the player might shrug it off and just hit the key again. In a real-time game, that might be the difference between making an attack or jump and not, and the player will swear loudly at the game’s poor input performance and possibly ragequit.