Closer Look: ZIG

Previous Post
Next Post

Closer Look: ZIG

April 10, 2017, 11:25 p.m.

What makes ZIG so powerful compared to ZZT is its extended programming capabilities. Let's take a quick look at the commands it adds or modifies from ZZT-OOP:

#addstat name var char
This is how variables are added to the sidebar. Pick a name, a variable to display, and a character to represent the variable. #delstat can remove a stat.

#become objectname
While ZZT can have an object become another element, ZIG offers the (not yet implemented) ability to transform an object into an object defined in an object library.

There is an included library that for whatever reason wasn't recognized by the editor, but I do remember it working back when ZIG was a new release. It includes recreations of ZZT's player, ammo, torches, keys, doors, lions, tigers, and bears. So people new to ZIG didn't have to immediately code a player from scratch like I would have.

#bind objectname
ZZT's #bind can be used to tell an object to discard its own code, and instead point to another object's. Good for memory, less good when you realize that means #zapping labels like objects that take multiple shots to be destroyed ends up making every single object with that code has its label zapped.

ZIG takes a more practical approach in a world where a decent computer may well have over 128 megabytes of memory and just copies the code rather than pointing to it. This would be extremely useful for action games which constantly hit memory issues in ZZT due to not being able to use #bind effectively.

#bindappend objectname
This one appends code onto an existing object.I'm not sure what the intent with this is, but I'm sure you can be clever with it somehow.

#change [color] char [color] char
This command is similar to ZZT's but since ZIG only has objects, the match is based on the object's character. In addition, the colors support can be done in MegaZeux's style of "cFB" with a hex number 0-F for the foreground and background, giving it a broader reach over ZZT's seven defined color names.

#changearea x1 y1 x2 y2 [color] char [color]
#change but only to a certain rectangular region on the board!

#char char
Same as ZZT, change an object's appearance.

#clear/#set flag
Same as ZZT, set a boolean flag off or on. ZIG has no restrictions on how many flags can be defined compared to ZZT's 10 however.

#clone objectname x y
Creates a copy of an object as the given coordinates. In ZZT there is no way to duplicate an object without waiting for a duplicator to trigger. This could easily be used for spawning enemies.

#color color
Like #char, but for an object's color. Although ZZT will execute #become red object, this causes a new red object to be spawned and the current object's code to be lost. (Using #put s red object and having a different object try to overwrite the other does work though? ZZT is weird.)

#cycle n
Sets the object's speed. ZIG allows for decimal numbers for more precise control of speed compared to ZZT where every cycle is ~0.10 seconds.

#die
Destroys the object, just like ZZT, however ZIG prevents the board's last object from dying.

#end
Stops running code! Same as ZZT.

#endgame
Ends the game's execution until the player presses escape. Same as ZZT if you ignore the ability to cheat when dead and bring the player back to life.

#fade out/restore speed
Fades the screen to black over speed number of cycles. Having a visual effect as a single line of code instead of having to mess with palettes makes things a lot easier. #fade restore will fade back in.

#focus
Sets an object as the focus object. Only one object can be the focus in ZIG, and that object is the only one that can send :touch messages to other objects and also is the target referenced when an object tries to #go seek to move towards what is most likely the player.

#ghost/#solid
Disables collision for an object until #solid is used.

#give var amount/#take amount var [label]
Gives and takes an amount from a variable. This is the same as ZZT and can be used instead of performing arithmetic.

#go dir (or /dir)
Moves an object! This is the same as ZZT where the object will try to move in that direction endlessly until it succeeds.

#try dir [label]
Moves an object, but gives up if it can't. An optional label allows handling a failed move. This is the same as ZZT.

#walk dir
Moves an object endlessly in the given direction. This is the same as ZZT.

#idle (or /i)
Idles for a cycle. Same as ZZT. The manual here says that a single tick is 0.25 seconds, but that has to be a typo as a cycle there is again, 0.10 seconds. ZIG feels about as fast as ZZT normally.

#if (condition/flag) then (command)
Allows comparing values and jumping to labels or executing commands like ZZT. The lack of elements means comparisons like #if not any lion nolions is no longer an option. Similarly, the manual makes no mention of #if contact label to jump to a label when adjacent to the focus object. This command may actually be more versatile in ZZT.

#lines 25/43
ZIG actually supports changing the text mode from a 25 line mode to a 43 line mode.

zig_497
zig_498

This causes only the top 8 pixels of a character to be rendered, but the same character set is used. The idea of square characters is a good one, but ZIG's implementation of it doesn't seem very friendly. The manual also warns anybody who uses 43 line mode to remember to switch back to 25 when the game ends.

#loadfont filename.zch
Loads a font. This allows for even more dynamic graphics if 256 characters aren't enough.

#loadmod modname.mod
Loads and plays a MOD file. If you're lucky enough to hear it.

#playmod/#pausemod
Plays/Pauses the currently loaded MOD file.

#move x y [layer]
Moves the object to the specified coordinates and layer. Object teleportation like this is completely impossible in ZZT.

#movetoboard board
Moves the object to a different board. ZZT has a player on every board which is moved around as needed when switching boards, but here you can move anything anywhere.

#offset x y / auto
Sets the board's view offset for camera panning. Auto centers the view on the object that called it. I'm surprised there isn't a command to center it on the focus object.

#playwav filename
More sound! This time for wav files.

#lock/#unlock
Locking an object prevents it from receiving external messages until it is unlocked. This is the same as ZZT.

#restart
Jumps to the beginning of the object's code, just like ZZT.

#restore/#zap
Zaps a label, preventing it from being matched next time a label is searched for like :touch or :shot. #restore undoes this. In ZZT #restore unzaps every zapped label. The ZIG manual doesn't mention if this is still the case.

#scroll x1 y1 x2 y2 x y
Not implemented. This scrolls a section of the board x times horizontally and y times vertically.

#send [(all/all but) / objectname]:]label
Sends an object to a label like ZZT. #send dance will send the executing object to :dance. #send frank:dance will send any object named frank to :dance. #send all:dance will send every object to :dance. ZZT has all of these as well.

ZIG adds #send all but frank:dance where every object except for frank would jump to :dance. ZZT has #send others:dance where every object excluding the one that called the command makes the jump. I'm not sure why ZIG doesn't implement this.

#shiftchar c x y
Shifts a character x pixels vertically and y horizontally. This was shown in the demo with the gem.

#sidebar 1/0
Toggles whether the sidebar is displayed.

#transport board / #transportfocus board
Changes the board that's rendered. This can optionally transport the focus object as well. Contrast with #movetoboard which would move an object, but keep the current board on screen.

#viewport x1 y1 x2 y2
Sets a rectangle for the visible potion of the screen to be rendered.

#vislayers a b c...
Toggles visibility of layers on or off. Something like the "Galshina" text in Aelk's cutscene could have been on their own layer and then hidden to show more of the town underneath with this.

That's all of ZIG's commands in XOP, but there are still some more features with variables. Some of them are read-only, but the author can create more which can be modified

%me.x / %me.y / %me.layer / %me.char / %me.color
These return the relevant values of an object.

%curboard
This returns the number of the board that is currently loaded.

%prop1 - 4
ZIG's object libraries allow authors to define custom parameters to be filled in which use these four variables. Similar to ZZT's settings for enemies like intelligence or firing rate.

%mess.x / %mess.y / %mess.color / %mess.time
Unlike ZZT's messages which always appear as color changing text along the board's bottom row, ZIG's can be moved around. %mess.time is left unexplained but presumably is how long the message stays on screen.

Custom variables can be simply defined with the %name syntax, and these can be referenced by the HUD or other objects. There's no mention of variable scope so I'd assume any user variable is global compared to MegaZeux where variables can be local if necessary.

Lastly, there are a few operators. Interestingly, the first one is "alligned" with two l's, matching the typo in ZZT-OOP but no support for "aligned". To be fair, I didn't know aligned only had a single l for years after discovering ZZT so perhaps Jacob Hammond had the same issue.

There's also keyb key which is how custom controls are handled. An object loops and checks for things like #if keyb m missiles.

There's a not operator for inversing values, blocked for checking if an object has anything next to it.

rnd # can be used to generate random integers, something miles beyond ZZT's awful hacks for attempting randomness.

There are the basic arithmetic operators, +, -, *, /, >, <, and = for making comparisons.

Perhaps the most notable one is getobjname dir, which can be combined with #send to send a message to an adjacent object.

The XOP language offers quite a bit of options to those willing to work with it. It's not as accessible as ZZT, but is still simple enough that I feel like a child could pick up the essentials at least.

Final Thoughts

ZIG has a lot of tools, and while what's there is miles beyond anything ZZT can do, it just never went anywhere. Its core concept of being an in between of MegaZeux's power and ZZT's simplicity was a sound one. That's a niche that certainly had merit in the early 2000s. At the time, MegaZeux was difficult to run and ZZT had essentially peaked in terms of new mechanics to exploit.

ZIG had a few tricks up its sleeve to boost its chances of success. ZIG games were permitted to be uploaded to z2 meaning that any releases would get put on the front page. There was a continual exposure to ZIG in the ZZT community. (It's also for the best since it makes ZIG easily the best preserved failed ZZT clone of which there were many.) If you were a ZZTer at the time, you were exposed to ZIG.

ZIG's issues weren't as severe at the time as well. Releasing MS-DOS programs in the 21st century was an odd choice, but it worked. Mainstream gaming may have been releasing titles solely for Windows, but as long as Windows had its MS-DOS compatibility, ZIG was safe. Had ZIG been more successful, ports outside of MS-DOS would have become essential just a few years down the line, but with its source code available, it would have been "easy", at least compared to ZZT where you're working with a disassembly or just eyeballing it.

However, ZIG was unable to overcome its shortcomings from a lack of save support and notoriously broken audio support. This definitely slowed its adoption from the very beginning and no saves is probably the single biggest strike against ZIG. ZZT games of the era were longer and more story driven worlds where having to start from scratch every time. The lack of saves' influence can be seen in what ZIG worlds were released. Everything is tailored towards being short and direct games. Arcadey dungeon crawls and horrible platformers whereas Aelk's Zelda-like inspiration is the exception.

ZIG also never took off with the big names at the time. Most of the authors of ZIG's games were ZZTers that nobody really thought twice about when it came to their releases. That so many of ZIG's games aren't fun to play didn't do them any favors either. A considerable number of ZIG games are focused on online multiplayer, something ZIG wasn't designed for, taking advantage instead of screen and keyboard sharing as some loophole to crudely pull it off. Aelk and Dysan's Temple are the only ZIG games that really feel like they were created to work with what ZIG offered rather than shoehorn a gameplay mechanic into ZIG.

ZZT as a medium was always about compromising and working with and around its designed limitations. It works because people quickly learn to expect that sort of thing. To an outsider, surrounding a player with objects, which then send a message to another object to control comes off as bizarre, but it's what often needs to be done in ZZT. Torches representing clips of ammunition or gems being used as magic points involves the person at the keyboard accepting these things the way one accepts the scenery in a play. It's obviously a masquerade, but there's an agreement to go along with it.

ZIG meanwhile gives the programmer a chance to do away with all that, the object in a platformer jumping and falling from gravity really is the object controlled by the player. The sidebar can say clips or magic. The need for constant compromise is greatly subdued, but instead all these online games are immediately going back to requiring compromise with the nature of lag and the illusion that your ZIG.EXE file is in fact a deathmatch sever. You can still play along with these conceits, but the whole point of ZIG is that it's supposed to stop players from having to do so.

ZIG was a good idea, and honestly one that was well executed for what it was trying to do. In the end, what ZIG actually could do and what people wanted to do with ZIG just weren't compatible.

The Closer Looks series is a part of the Worlds of ZZT project, committed to the preservation of ZZT and its history which sometimes isn't actually ZZT at all.
Support Worlds of ZZT on Patreon!
Previous Post
Next Post