@8bit_era Thank you for the detailed explanations. While I was aware of alter, it’s not something I’d considered in this case or indeed experimented with very much. What I had not previously realised was that alter fires even when there is no default report text to alter, which is the case with on go. Looking at the Cosmos source code I now see that it does fire for on go, so that’s a neat solution.
Very nice. I have wanted to disable the “Take All, Drop All” action several times. This will make it easy.
How is take all supposed to work when you have defined a carry limit and taking all exceeds that limit? I haven’t built take all or drop all into my system but I have built it for limited inventory. I’m just curious how it should work. Does it get some of the items or none at all?
Generally TAKE ALL converts to separate taking actions on each of the items available. So you might get:
>TAKE ALL
Casserole dish: Taken.
Socket wrench: Taken.
Bottle of ink: You don’t have room to take that.
Golden statuette: You don’t have room to take that.
You could probably make this look nicer, if you cared to, but I don’t think any players will be put out if your game makes an arbitrary choice of which items to take when there isn’t room to take everything.
How does the edit: Z-machine Arcturus work when you have
-
Object called “all”
-
Object called “all” that is in the same location as other objects
I suspect take all works in (1) with little trouble.
How does it work in (2)?
The Z-machine doesn’t care, as it doesn’t have a parser built-in.
Each game must come with its own parser (or no parser, if it doesn’t need one, like a CYOA game, or a Tetris clone or something). The parser is typically provided by the library.
I am certainly enjoying experimentation with this new language. I have installed it on my RPi 5, an internet facing Ubuntu server and of course Windoze. Win 11 balks at Actaea but Windows Frotz works well with the Z5 game files.
Never know? IFComp 2027…
Actaea is actually fine on Win 11, it just needs two things Windows will not do for you. First, start it through the Python launcher: py actaea story.z5. Second, the window needs a Python with tkinter: quick test is py -c "import tkinter". If that errors, re-run the python.org installer, choose Modify, and tick “tcl/tk and IDLE”. With those two, the full Actaea window comes up, no third mystery. (Without tkinter it currently drops silently to a bare text pipe, which might be exactly the “balking” you saw)
One more mode worth knowing about, since you have an RPi and an Ubuntu server in the mix: actaea --console story.z5 plays in the terminal itself, full status line, styles and colours, in the manner of frotz and fizmo, which makes it a lovely fit for playing over SSH on that internet-facing box. The one place --console does not exist is native Windows, whose Python ships no curses; there Actaea falls back to the plain pipe, though under WSL the console mode plays fine. So: window on the desktops, --console on the servers, and --headless if you ever want to drive it from scripts or walkthrough files or debug your own games.
(I’ve updated the documentation on Windows)!
Thank you for the additional details on actaea.
I have been using --headless as well. It works on a NetBSD remote server but not --console. I do not have admin privilegees on that server so my configuration options are limited. They do not support Frotz or any other z5 apps that I can find.
I’m looking forward to writing. I have been consumed by other things since last November.
I wanted to highlight some recent Arcturus updates.
Arcturus update: the parser learns parts of speech (arcc 1.10.0 / Cosmos 1.13.0)
A recent field-report turned into the biggest parser upgrade since the verbs overhaul. Everything ships now; update with arcc --update.
Core changes, every language benefits:
- Adjectives. Mark a word with
>in a words list (words couch, sofa, >red) and the parser knows its class. Matching follows Infocom’s ZIL model: a noun match outranks an adjective-only match, a lone adjective still finds its object, and two red things in scope get the honest question: Which do you mean, the red couch or the red guitar? - Trigger words.
words #chest, box, trunk: when generous synonym lists make two things tie, the thing whose#word was typed wins silently. Two typed triggers still ask. - Library-owned switch state. Declare a thing
binaryand the library flips it, refuses “already on/off” honestly, and couples light on lamps (binary+lit). Your handlers only change the wording. The equivalent tobinaryisswitchablein other languages. - Packs own their orthography and pronouns. Language packs now declare fold tables and multi-role pronoun words; the machinery is language-neutral and folds away when unused.
German (german.granule):
- Declare
words türonce; bothtürandtuertypes. The fold table (ä→ae, ö→oe, ü→ue, ß→ss) registers every crossword spelling automatically. This helps retro game developers with German accented characters, as they don’t have to declare multiple words, because on most retro computers you can only type ASCII chars. - One adjective stem carries every declension:
>rotmatches rote, roten, roter, rotes, rotem. Nouns are never touched. - Pronouns work like German: ihm reaches masculine and neuter, sie feminine and plural, ihnen is new. The most recent mention wins.
- Pronominal adverbs: damit, darauf, darin, daran and the short forms.
nimm den schlüssel und schliess damit die tür aufjust works. - The two-noun split no longer misreads names like Tür aus Eiche.
As always: what you don’t use costs nothing; a game without any of this compiles byte-identical. Details in the handbook (chapters 3, 14, 21) and the worked examples (features/adjectives, features/trigger).
The NPC ENGINE has arrived - living characters, declared instead of hand-wired.
summon.npcengine and a character can patrol a route of rooms (opening doors on its way with opens_doors), wander a territory (rooms, or a whole room kind), or be sent on an errand (send(verger, chapel)) that walks the real room graph one honest step per turn, doors and all. The player watches it happen: “The watchman heads east.”, “The watchman arrives from the west.”, in all three shipped languages. The controls make a large cast cheap on real 8-bit hardware: every character starts hibernated, inactive at zero per-turn cost, until resume(watchman) wakes them; the same calls on npc_engine itself are a master gate that freezes the whole town for a cutscene and restores the exact mix after. Two events ride the ordinary pipeline (npc_arrives, npc_blocked), and the classic addressed imperative arrives with it: WATCHMAN, GO NORTH reaches the character’s own on command, which decides; the default politely refuses. Games that never summon.npcenginecompile byte-identical, proven file by file (arcc 1.12.0, Cosmos 1.15.0).
get it via arcc --update
Yes, the engine has its own section in the handbook’s granule catalog, chapter 22:
https://github.com/ByteProject/Arcturus/blob/main/docs/01-arcturus-handbook.md#npcengine
The player-facing order syntax has its companion section in chapter 12:
https://github.com/ByteProject/Arcturus/blob/main/docs/01-arcturus-handbook.md#commanding-characters-the-addressed-imperative
And the playable showcase, The Night Rounds, is at:
https://github.com/ByteProject/Arcturus/blob/main/examples/granules/npcengine.storyarc
New in Arcturus: multiple player characters (arcc 1.13.0, Cosmos 1.16.0)
summon.maniacswap gives a game more than one playable character, Maniac Mansion style.
Mark a character playable and the player can type BECOME MAREN (German: WERDE, Spanish: ENCARNA) to swap into her. It works from anywhere, even between maps that never connect, so two castaways on two shores can carry one story. The body you leave freezes exactly where and as it was, holding its own inventory, standing in its room like anyone else; score and turns travel with you. ME and MYSELF always mean whoever you are right now.
The story decides when a swap is right, with an ordinary handler on the body:
on become
if signal_lamp is not active
change refused to true
say "Not without the signal."
stop
continue
maniacswap is its own granule and needs nothing else: if all you want is Maniac Mansion style character switching, this is the whole feature. If your game also runs the NPC engine, the two enhance each other naturally: take over your patrolling watchman and his rounds pause while you drive; leave him and he stands where you left him until the story resumes his rounds.
As always: pay for use. A game that never summons it compiles byte for byte identical, and BECOME is not even a word in it.
Docs: https://github.com/ByteProject/Arcturus/blob/main/docs/01-arcturus-handbook.md#maniacswap
Worked example: https://github.com/ByteProject/Arcturus/blob/main/examples/granules/maniacswap.storyarc
Update with arcc --update.
Your second link (the commanding-characters one) does not work (in that it doesn’t find a section)
Actaea 2.0 is out with a massive overhaul!
Actaea, the Arcturus reference interpreter, got a massive overhaul and is now a full-featured desktop application. Actaea is a Z-machine standard 1.1 compliant version 5/8 interpreter, that also offers extended support for arc_image, providing authors the perfect playground to develop and test their games.
- Three selectable typefaces, set in a selected serif for long reading sessions, a clean one, and a retro typeface. The fonts ship with Actaea, nothing to install.
- Long passages page with [MORE] instead of scrolling past unread.
- Two window shapes: the portrait Modern (4:5) and the classic 4:3. The window remembers its size, position, and settings between sessions.
actaea --install-appinstalls it as a native application on macOS, Linux, and Windows, with file associations for .z5, .z8, and .zblorb, while it stays fully usable from the command line withactaea --console.arcc --updatecontinues to update everything in place when the tools are kept together.- Various bug fixes and enhancements.
About the app icon: the design picks up the Arcturus star artwork, which has been the major theme since I released the programming language itself, and crosses it with the compass rose interpreters traditionally wear, set against the Milky Way.
Update with arcc --update, or get the toolchain here: GitHub - ByteProject/Arcturus: New tricks for the Infocom Z-machine · GitHub
Full Actaea 2.0 documentation is available here: Arcturus/docs/06-actaea.md at main · ByteProject/Arcturus · GitHub
All this sounds totally awesome. I really like the character automation too. Interestingly, i often pick 4:5 as a comfortable IF playing ratio. Is this used anywhere else? Perhaps it’s a standard for some terps i don’t use. Nevertheless, it’s a good choice.
Thank you very much
I think Gargoyle does 4:5 as well.
@Dannii @zarf, I ran into a ZVM issue this week and thought you would rather hear it with the diagnosis than as a bug report with a screenshot. One of the Arcturus authors used Lectrote to test a .z5 game that makes use of arc_image. The Arcturus compiler folds the opcode away if the game doesn’t use arc_image.
Arcturus games can carry pictures, and that uses one custom opcode, draw_image at EXT:0x80, from the range the Standard sets aside for game designers. The story only issues it when the interpreter says it can show pictures (Flags 1 bit 1), and section 14 asks interpreters to ignore unknown extended opcodes between EXT:29 and EXT:255. dfrotz, fizmo and Actaea all play these files happily as plain text. Lectrote 1.4.5 (ZVM 1.1.6) gives me a blank screen and this:
Error: Unknown opcode #1128 at pc=12565
What is happening: ZVM compiles a whole basic block before it runs any of it, and a conditional branch does not end a block. So the opcode behind my capability check gets decoded even though the running story would never reach it, and the unknown code stops the engine there. In my case that was the call at boot, which is why there was nothing on screen at all. This will bite any story that uses the private opcode range, not only mine.
It looks like a small thing to put right: an entry for unknown EXT codes that consumes the operands and does nothing.
On my side I have already worked around it, so nobody is stuck meanwhile. The opcode now sits alone in a routine that is only called once the capability check has passed, and since a routine is decoded when it is called, an engine that decodes ahead never meets it. A little compiler work and the cost per game is just eight bytes. I went this route because you never know what else is out there that may fail. You might want to look into this anyway.
And if you ever fancy showing the pictures rather than just the text: the hook I added to ZVM in my Proteus fork is only a few lines. No strings, it would just be nice to see it work in Lectrote and Parchment.
That sounds like a good bug to fix, regardless. Dialog does similar capability checks (e.g. it checks the Standard revision in the header right before calling @set_true_color or @print_unicode) which would become a problem if a new Standard was ever newer than the oldest ZVM.
I haven’t touched ZVM’s code generator in a long time, but I don’t think I’d want it to just ignore unknown opcodes.
Moving the draw_image call into its own function sounds like the right solution to me. That will keep it safe from any JIT quirks. (At least until I try to pre-analyse functions in the next code generator I eventually want to develop. I’ll have to keep custom opcodes in mind.)




