I got 8 Points and the room description is a mess.
I checked what could cause the error and when deleting my little health system, it works fine with z3. This is the code i used:
Constant MAX_HEALTH 100;
Global health_score 70;
Verb 'health'
* -> Health;
[ HealthSub;
if (health_score == 0) {
deadflag=1;
"^You have no health left! You collapse to the ground.";}
else
if (health_score < 50) {
"^You feel weak and your health is low. Your current health is ", health_score, " out of a possible ", MAX_HEALTH, ".";}
else {
"^You feel strong and healthy. Your current health is ", health_score, " out of a possible ", MAX_HEALTH, ".";}];
[ HealPlayer points;
health_score = health_score + points;
if (health_score > MAX_HEALTH)
health_score = MAX_HEALTH;
"You regain ", points, " Healthpoints.";];
[ TakeDamage points;
health_score = health_score - points;
if (health_score < 0)
health_score = 0;
"You loose ", points, " Healthpoints.";];
before [;
listen:
if (self.listened == 0){
score = score + 3;
self.listened = 1;
print
"You close your eyes and let the sounds of the forest envelop you. The gentle rustling of leaves in the light
breeze whispers secrets of the woods, while the soft chirping of birds weaves a melody that speaks of life hidden among
the trees. Occasionally, you catch the faint buzz of insects darting through the air and the distant creak of wood as the
ancient trees shift ever so slightly in the wind. The forest feels alive, a harmonious symphony of nature that soothes
your senses and draws you deeper into its tranquil embrace. ";
Healplayer (5);
HealthSub();}
else {
print
"You can still hear the birds chirping, their song weaving through the air like a gentle, familiar melody.
The rustling leaves accompany the birds, forming a soft symphony that feels both comforting and timeless.^";}
return true;],
This all works fine in z5 but not in z3. It would be nice if you had a hint what went wrong with my code when running it in z3;=)
PunyInform is very finicky about the declaration of globals in a z3 file. Most importantly, you must declare your own globals afterInclude "globals.h"; If you don’t, it will screw up the status line.
In Z3, the interpreter draws the status line, using the first three globals in the game. It interprets the first one as an object name (usually the current location), drawn at the top left, and the second and third as numbers (usually either score/turns or hours:minutes), drawn at the top right. There’s a flag you can set in the header to decide whether there’s a slash or a colon between those two.
This means when you put your health_score global at the top, that’s getting interpreted as an object name to print, giving gibberish. Declare that afterglobals.h to ensure the location goes first.
(Notably, some Z3 games do mess around with the order of globals to change what’s at the top left. Iirc Suspended puts the current actor there instead of the current location.)
(This is also why Trinity is the first game to do anything fancy with the status line: it was in the Z4 format, which gave the game full control of the status line, and it used that to center the room name, do the quote boxes, and so on.)
(Z3 does give games control of an upper window, only ever used for the sonarscope in Seastalker, and in Z4 they said “hey wait that could be used to make a status line, we can just ditch the interpreter-controlled status line altogether and let the game do that with the upper window opcodes”.)
Technically, it’s z3 that is finicky. If you declare a global before including the first library file, and compile to z3, you’re in trouble, and this goes for any Inform 6 library.
(PunyInform is finicky about some other parts, where it’s a choice made to keep the library as small and fast as possible, e.g. you have to declare all entry point routines except Initialise before including “puny.h”)
The file minimal.inf has comments to guide authors regarding where to put what.
Compile with -e to use abbreviations, making text compression more effective. Unless you have created your own abbreviations, you get a set of 64 abbreviations that are included with PunyInform. When you get close to a release, you want to create a set of 96 custom abbreviations that are tailored to your game. You use the tool ZAbbrevMaker to find the best abbreviations.
So, your game is currently 74 KB without abbreviations. WIth proper abbreviations, you’ll get it down to maybe 68 KB. The library is about 25-30 KB of that, depending on which optionals you’ve enabled. This means the content that you created for the game this far takes up about 38-43 KB, and you can add another (128-68 =) 60 KB before running out of space in the z3 format.
If you switch to z5, you can write a game of about 190 KB, if you want it playable using Ozmoo on a C64 with a single 1541 disk drive. The exact size depends on the size of dynamic memory, as all non-dynamic memory has to fit on a disk side. 185 KB is pretty much guaranteed to work, but you can probably squeeze in 190 or even 195 KB. (The interpreter and dynamic memory are stored on disk 1, while non-dynamic memory is stored on disk 2)
Is there any advantage to using z3 on a C64 with a 1541 floppy or an equivalent emulation? Or can you use z5 directly without any drawbacks? And are there older systems where z3 is absolutely necessary and z5 does not work?
As for the question of getting something to run smoothly on a C64, it’s more about how you write your program than about the choice of z3 vs z5:
Use a small and efficient library (CHECK, as you’re using PunyInform)
In your code, opt for solutions that require a minimum of computations at runtime. E.g. only keep daemons running when they’re needed, avoid iterating over all objects unless absolutely necessary, etc.
Do all you can to keep the file size down, e.g. optimize text compression, avoid code duplication etc. This makes for less swapping.
Try to keep the size of dynamic memory down. This makes for less swapping and makes save and restore faster. Make arrays static when possible, use the cheap scenery extension, set MAX_SCOPE, MAX_TIMERS etc to the numbers you actually need.
Use manual scope updates in PunyInform. It’s not hard, and it makes a big difference. Also consider using OPTIONAL_MANUAL_SCOPE_BOOST (read up on this in the manual).
For the best player experience, use the preload optimization feature of Ozmoo. This means all the core parts of the library are loaded before the game starts, so there will be little or no swapping during the first moves. This does require a local installation of Ozmoo, as Ozmoo Online doesn’t support it.
There are more tips in the PunyInform Game Author’s Guide.
To get an idea of what difference these tips make, try playing the Inform 6 game Advent.z5 on a C64, and then play the PunyInform version. The filesize goes from 135 KB to 78 KB, but that’s far from the only reason why the PunyInform version is faster. When running on a C64 with an REU (RAM Expansion Unit), swapping is crazy fast, and yet GET ALL in the well house is ~4x faster in the PunyInform version.
(The Inform 6 version is available as advent.z5 under games/zcode at if-archive. The PunyInform version built for C64 and other computers can be found at 350p Adventure )