I got an error when running z3 instead of z5

Hello again;=)

When I compile to z5 everythings works fine and looks like this:

I start in the clearing and my score is 0.

Compiling it to z3 I got no error, but now it looks like this:

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;=)

Thomas

I suspect the compiler has overrun some z3 hardware limit and failed to report an error about it.

Can you post the statistics and memory map when it’s compiled the bad way? That is, the result of compiling with the -s -z flags.

1 Like
C:\PunyInform\lib>inform6 explore -v3 -s -z
Inform 6.42 for Win32 (10th February 2024)
Dynamic +---------------------+   00000
memory  |       header        |
        +---------------------+   00040
        |    abbreviations    |
        + - - - - - - - - - - +   00042
        | abbreviations table |
        +---------------------+   00102
        |  header extension   |
        +---------------------+   0010a
        |  property defaults  |
        + - - - - - - - - - - +   00148
        |       objects       |
        + - - - - - - - - - - +   004b1
        | object short names, |
        | common prop values  |
        + - - - - - - - - - - +   00f25
        | class numbers table |
        + - - - - - - - - - - +   00f2f
        | symbol names table  |
        + - - - - - - - - - - +   01103
        | indiv prop values   |
        +---------------------+   0112d
        |  global variables   |
        + - - - - - - - - - - +   0130d
        |       arrays        |
        +=====================+   016cd
Readable|    grammar table    |
memory  + - - - - - - - - - - +   01c6d
        |       actions       |
        + - - - - - - - - - - +   01d1b
        |   parsing routines  |
        + - - - - - - - - - - +   01d1d
        |     adjectives      |
        +---------------------+   01d1d
        |     dictionary      |
        +---------------------+   0264d
        |    static arrays    |
        +=====================+   02668
Above   |       Z-code        |
readable+---------------------+   08ae0
memory  |       strings       |
        +---------------------+   1281e
In:  7 source code files              7563 syntactic lines
 11292 textual lines                342919 characters (ISO 8859-1 Latin1)
Allocated:
  1366 symbols                      646559 bytes of memory
Out:   Version 3 "Standard" story file 1.241202 (74.5K long):
     4 classes                          97 objects
    98 global vars (maximum 233)      1440 variable/array space
    77 verbs                           335 dictionary entries
   154 grammar lines (version 2)       249 grammar tokens (unlimited)
    87 actions                          30 attributes (maximum 32)
    26 common props (maximum 29)        12 individual props (unlimited)
 62651 characters used in text       44846 bytes compressed (rate 0.715)
     0 abbreviations (maximum 64)      308 routines (unlimited)
  5778 instructions of Z-code         3413 sequence points
  9832 bytes readable memory used (maximum 65536)
 75806 bytes used in Z-machine       55266 bytes free in Z-machine
Completed in 0.049 seconds

C:\PunyInform\lib>

PunyInform is very finicky about the declaration of globals in a z3 file. Most importantly, you must declare your own globals after Include "globals.h"; If you don’t, it will screw up the status line.

4 Likes

Oh, jeez. I was totally wrong then! Sorry…

In Z5, the game draws its own 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 after globals.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”.)

5 Likes

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.

3 Likes

Thank you all, now with the global at the right place everything works fine with my z3;=)

When i used -s -z above it shows me:

75806 bytes used in Z-machine 55266 bytes free in Z-machine

Are the bytes free the right value to care , when I want to run it on a Commodore 64?

Great thanks to all of you, I learned a lot…

Thomas

2 Likes

75806+55266=131072 (128kB). This is the max size allowed in the spec for z3.

C64 can run games a bit bigger than that, depending on setup if you go to z5. I don’t have the exact limit, but see Ozmoo for guidelines.

1 Like

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)

2 Likes

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?

Thomas

C64 handles “big” files no problem, and Z5 is so much more powerful than Z3 in many ways. So I decided to always go for it.

Some of the “minor” systems don’t handle Z5 very well, though, or not at all. TRS80, or Texas Intruments iirc.

1 Like

Also, z5 has features that z3 lacks, which might be important if you use any of them.

1 Like

Stefan Vogt is probably the person who knows the most about which systems support what, in terms of Z-code. In the readme text for his Puny BuildTools ( GitHub - ByteProject/Puny-BuildTools: PunyInform CLI and retro disk image factory for Infocom Z-machine games ), he says these systems support z3 but not z5:

VIC20/PET, DEC Rainbow, TRS CoCo/Dragon64, Osborne1, Ti99/4a, Oric, Kaypro

2 Likes

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.

1 Like

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 )

1 Like

Thanks for all these explanations, which go very deep into detail. I will try it all when gettng better;=)

1 Like