PZX
PZX, or ProngZeux, is a fork of MegaZeux written by zzo38 that focuses primarily on support for FORTH, a low-level, stack-driven programming language.
- Win32 binaries and source-codes is available at: http://zzo38computer.org/mzx1/mzx_extended/
- Documentation is available at: http://zzo38computer.org/mzx1/mzx_extended/doc/
Features
The biggest contribution of this particular fork is FORTH support. Other changes include the ability to use the old ALT+D function in the editor (only zzo38 seems to remember what this is or use the function to begin with), deferred expressions, extended kinds, new overlay modes and SMZX modes of dubious utility (including the one that draws overlay on the outside of the viewport instead of inside, one that draws only the overlay and not the board, an SMZX mode that uses 16 colors per character (reducing the resolution per character to 4x7), and a blinking text mode), meanings for the other bits in lava_walk, and displacement overlay modes which allow adjustment of the overlay by individual pixels.
zzo38 also corrected a long standing, esoteric bug in the handling of built-in spider webs, which has been merged (with changes) into the existing codebase.
To make backward compatibility, the way it works, is if the first line of the global robot is a comment with a greater than sign at beginning (optionally followed by a filename), it will activate PZX mode. If there is a filename, that is the file containing the Forth codes.
Deferred Expressions
A deferred expression is sort of like having function calls for calling another expression. The operator , sets the current parameter value to the left side and then evaluates the right side, the operator p gets the current parameter, and the operator ` allows you to use a deferred expression.
Because parentheses are used to evaluate expression, it uses square brackets to mean a deferred expression. It will convert [] to () when accessing a deferred expression.
The ` operator is two of ` with the name of string in between (including the dollar sign), and it call the deferred expression. You can also use ` operator with * followed by a Forth word instead of a string, in which case it will instead call that Forth word to determine the value of the expression.
Extended Kinds
You can create extended kinds 0x80 to 0xFE (128 to 254) using Forth codes.
In order to create a extended kind you must indicate:
- The number assigned to it
- The character used to represent it (255 means use the parameter, like a CustomBlock does, and negative number mean various other things)
- The A_ flags associated with it
- How the parameter is decided (the parameter type can come from any built-in)
- The name
And then you can optionally define events for it, such as what happens when it is shot, updated, touched by the player, underneath the player, and so on. Which events are used depends on the A_ flags, although it is possible to have A_ flags without the corresponding events (for example, the simplest way to prevent the player from pushing something that is normally pushable is to give the object the A_ITEM flag without a corresponding event).
Some new A_ flags have been implemented:
- A_BREAKABLE
- A_USERFLAG
- A_CRUSH
- A_INVISIBLE
- A_ELEMENT (3 bits, and in Forth codes you use AE_WATER and so on instead of typing A_ELEMENT)
Overlay Modes
Mode 4 makes it draw the overlay outside of the viewport instead of on the inside of the viewport.
Mode 65 and 66 makes it to not draw the board, and only draw the overlay. (This feature actually already existed in MegaZeux, but there was previously no access to it during the game.)
Mode 0x7? prevents it from drawing anything at all, allowing Forth codes direct access to the text_video.
There are also displacement overlay modes 0xA?, 0xB?, 0xE?, which allows pixel-accuracy for drawing characters, and also can make individual pixels transparent (so you can see the character drawn underneath).
Graphics Modes
Modes 0 to 3 are same as normal MegaZeux. Mode 64 to 67 are the mode for 16 colors per character. Mode 141 makes blinking text.
Use of Attribute Flags
The flags are as follows (any combination can be used, except for a few exceptions):
- A_PUSHNS: Allows object to be pushed north/south
- A_PUSHEW: Allows object ot be push east/west
- A_PUSHABLE: Object can be pushed in any direction (Do not combine with A_PUSHNS or A_PUSHEW)
- A_ITEM: Calls EV.ITEM event when player touches it. Player will not automatically push or stand on this object
- A_UPDATE: EV.UPDATE event will be called every step unless freeze time is active
- A_HURTS: Causes damage when player hits it
- A_UNDER: Things can stand on this
- A_ENTRANCE: Parameter is a board number, if the player steps here it will teleport the player to that board
- A_EXPLODE: Object is explosive
- A_BLOW_UP: Object can blow up
- A_SHOOTABLE: Player bullets and neutral bullets can destroy this
- A_BREAKABLE: Any bullets can destroy this (Do not combine with A_SHOOTABLE or A_SPEC_SHOT)
- A_ENEMY: Used in various purposes by MegaZeux
- A_AFFECTSTOOD: Calls EV.AFFECTSTOOD event every step if the player is standing here
- A_SPEC_SHOT: Calls EV.SHOT event if hit by a bullet
- A_SPEC_PUSH: Object can be pushed in any direction
- A_SPEC_BOMB: Calls EV.BOMB event when explosion hits it
- A_SPEC_STOOD: Player can stand here, even if other things can't
- A_USERFLAG: Does nothing
- A_CRUSH: Object can be crushed like in ZZT
- A_INVISIBLE: Draws using under color, or draws black if this is the under object
- A_SEEBLIND: Object is visible even if the player is blind
There are also element flags (up to one of these flags can be used):
- AE_WATER: Things that are not allowed to move onto water won't move onto here
- AE_FIRE: Things that are not allowed to move onto fire won't move onto here
- AE_LAVA: Things that are not allowed to move onto lava won't move onto here, also cannot be pushed or pushed onto
- AE_GOOP: Things that are not allowed to move onto goop won't move onto here, also cannot be pushed or pushed onto
- AE_THINWEB: Spiders that can move on thin webs are allowed to step here
- AE_THICKWEB: Spiders that can move on thick webs are allowed to step here
- AE_PLAYER: Cannot be pushed by things that react with the player
Use of Events
The following events exist in game and are not corresponding to any particular object:
- EV.PLAYERMOVING ( dir edge offset -- cancel ) Called to determine whether or not the player is allowed to move
- EV.KEYBOARD ( key -- canceldefault ) Called when a key is pushed, can tell it to cancel the default function of that key
- EV.LOADED ( category -- ) When game is started or restored
- EV.ENTERED ( category -- ) When the board is switched
- EV.BULLETHIT ( offset bulletoffset parameter -- category ) Indicates that a bullet is about to hit something solid
- EV.GLOBAL ( slowed slowdown -- slowed ) Called on every cycle
These events are corresponding to specific objects (add the extended kind number to the event code):
- EV.PUSH ( offset dir category distance -- ) Called when an object is being pushed
- EV.ITEM ( offset dir -- remove ) Called when the player touches an object with A_ITEM flag
- EV.AFFECTSTOOD ( offset -- ) The player is stand on object with A_AFFECTSTOOD
- EV.UPDATE ( offset -- ) Something with A_UPDATE is being updated
- EV.SHOT ( offset bulletoffset dir bullettype -- ) Something with A_SPEC_SHOT is being hit by a bullet
- EV.BOMB ( offset -- ) Something with A_SPEC_BOMB is hit by an explosion
- EV.LAZER ( lazeroffset offset dir -- blocking ) Object hit by lazer beam, can block lazer or allow beam to be transmitted through
- EV.ARRIVE ( offset -- ) Another object has arrived on top of this object
- EV.TESTPUSH ( offset dir category distance -- cancel ) Testing whether or not an object is allowed to be pushed
The following events are used in the editor:
- EV.EDITORKEY ( color thing param offset key keymod -- color thing param offset canceldefault ) A key is pushed during editing
- EV.BEFOREADDBOARD ( -- ? ) Before a new board is being added, the current board will be the old current board
- EV.AFTERADDBOARD ( ? -- ) After a new board is added, during processing of event the current board will be the newly added board, even if it would change back afterward
Examples of Forth Codes
Please note that all examples are case-insensitive, just like anything else in MegaZeux.
ZZT Keys
Here is a code to implement a ZZT key (please note this is a simplified version, its only function here is to disallow you from holding multiple keys of the same color):
INCLUDE megazeux.4th $80 12 A_ITEM A_PUSHABLE + 0 EXTKIND ZztKey ZztKey EV.ITEM + :EVENT DROP BOARD_COLOR + @ DUP TAKEKEY SWAP GIVEKEY DROP IF "You already have the key!" SETMESG 9 BISFX 0 ELSE "You now have the key." SETMESG 8 BISFX 1 THEN ;
I will explain each line and part of line one by one so that you can follow:
INCLUDE megazeux.4th
This loads the standard libraries of Forth codes.
$80
We will assign number 0x80 (128 in decimal) to the new kind of object. Only numbers 0x80 to 0xFE (128 to 254) can be used, because other numbers are used by built-ins. (Dollar signs indicate hexadecimal numbers in Forth codes)
12
This means it will display as character 12.
A_ITEM A_PUSHABLE +
This object will have the A_ITEM and A_PUSHABLE flags (meaning it is pushable by anything other than the player, and the player can interact with it).
0
It will not ask for a parameter when placed in the editor.
EXTKIND ZztKey
Creates the extended kind using the values from the stack, and calls it ZztKey. The name ZztKey is now used in the editor and can be used in Robotic codes as well. It is also usable in Forth codes as a constant.
ZztKey EV.ITEM + :EVENT
Adding ZztKey to EV.ITEM gets the number of the item event for the ZztKey. :EVENT tells it to start compiling an event code.
DROP
The top parameter passed to the EV.ITEM event is dir, which we aren't using, so we DROP it.
BOARD_COLOR + @
BOARD_COLOR represents the base address of the board color array. We add that to the next parameter (offset) and fetch the value, which is the color of the object (the key) at that offset.
DUP
We are using the color twice, so we duplicate it.
TAKEKEY
Attempt to take away that color of key from the player, and gets a success code.
SWAP
We want to pass the color, not the success code to GIVEKEY, so we SWAP it.
GIVEKEY DROP
Attempt to give a key of that color to the player. If the player already had that color, it was taken away so we now give it back. If that is not the case, then we still need to give a key to the player, which means the player is now picking up the key. We don't care whether or not this is successful (it always will be), so we drop the success code.
IF
Now we are entering a conditional block. The last value that hasn't been used yet is the success of TAKEKEY. So, the part between IF and ELSE is the true part (success taking the key away from the player), the part between ELSE and THEN is the false part (the key couldn't be taken, so it was given)
"You already have the key!" SETMESG 9 BISFX
Gives the player a message and plays a sound effect.
0
Zero is the value returned from the event (the "remove" parameter), meaning the object shouldn't be removed from the screen.
ELSE "You now have the key." SETMESG 8 BISFX
Another message and sound effect.
1
Any non-zero value means the object will be removed from the screen (because the player has just picked up the key).
THEN
The end of a conditional block. If using the word THEN here confuses you, you can use a code to make ENDIF work instead, but the reason THEN is used is because this is a different kind of THEN than it is is BASIC, in Forth the THEN is like "do this, and then do this..." rather than "if this then this..."
;
And this signals the end of the event code, and exits compile mode.
ZZT Gems
INCLUDE megazeux.4th : GIVE DUP COUNTER@ ROT + SWAP COUNTER! ; 1 VARIABLE NEEDS-GEM-MESSAGE $81 4 A_ITEM A_PUSHABLE + A_CRUSH + A_SHOOTABLE + 0 EXTKIND ZztGem ZztGem EV.ITEM + :EVENT DROP DROP 1 BISFX 1 "GEMS" GIVE 1 "HEALTH" GIVE 10 "SCORE" GIVE NEEDS-GEM-MESSAGE @ IF "Gems give you health!" SETMESG 0 NEEDS-GEM-MESSAGE ! THEN 1 ;