This document will help describe various functions in ZZT. Much of it is technical rather than practical. If you have any questions, comments, or further information, please e-mail me at nanobot@mysticalwinds.zzn.com PLAYER COUNTER USAGE The player's function involves 8 known 2-byte counters and 8 known 1-byte counters beside its parameters. The counters are as follows (note that an asterisk (*) marks a counter whose name is not regularly accessible in OOP): 2-byte: Ammo Gems Health Torches TorchCycles* EnergizerCycles* Score Time 1-byte: BlueKey* GreenKey* CyanKey* RedKey* PurpleKey* YellowKey* WhiteKey* PlayerChar* Ammo- When the player attempts to move and is blocked by an ammo, this counter is incremented by 5. When the spacebar is pressed or one of the arrow keys in pressed in the presence of the shift key being held down and the player begins the shooting sequence, the player tries to decrease this counter by 1. If the counter is currently set to 0 at this point, it doesn't decrease it further and instead aborts the function. Gems- When the player attempts to move and is blocked by a gem, this counter is incremented by 1. The Gems counter is directly before the series of key counters in the memory/world data. Because of this location, when the player tries to work with the black key, which it wasn't meant to be able to do, it uses standard location and ends up in the second byte of the Gems counter where it assumed the black key byte would be located at. The first byte in each 2-byte counter is the 0-255 value and the second is the one that is multiplied by 256 to add on to the first byte, so when the second byte is set to 1, the Gems counter (assuming for the moment that it was previously set to 0) is set to 256, which is 256 times the 1 that it was set to when it meant to set the black key. Health- When the player attempts to move and is blocked by a gem, this counter is incremented by 1. When the player "picks up" a harmful element such as a bullet or a creature, if the EnergizerCycles counter is less than 1, the Health counter is decreased by 10. When the Active Controller Element (ACE)--the first stat element in the board's data--is destroyed by a harmful element such as a bullet or a creature, the new ACE goes through the "hurt" function and the Health counter is decreased by 10. Torches- When the player attempts to move and is blocked by a torch, this counter is incremented by 1. When the player finds that the "T" key is pressed and the TorchCycles counter is set to 0, the player tries to decrease the torches counter by 1. If it can, it begins the lit torch sequence. If it is unable, it displays the "You don't have any torches" message and aborts. TorchCycles- When the player finds that the "T" key is pressed and has at least one torch, this counter is set to 200. Every cycle, the player decreases this counter by 1 and updates the torch length sidebar display accordingly. While the TorchCycles counter has a value greater than 1, the player removes "darkness" overlay tiles in an approximate 53-pixel radius relative to the coordinates of the first stat element in the board data (usually the player), and the first player in the board data places darkness tiles everywhere outside the 19 by 11 character area about its own coordinates, with the exceptions of the placements of players, torches, and passages. When the TorchCycles counter reaches 1, the "Torch Deactivation" sound is played and the player who first read that the counter was at 1 places darkness overlay tiles inside the 19 by 11 character area about its own coordinates. The counter is then set to zero and all players cease torch functions. EnergizerCycles- When the player attempts to move and is blocked by an energizer, this counter is set to 75 and every object on the board is sent to the "ENERGIZED" label. Every cycle, the player decreases this counter by 1. While it is greater than 1, the player cycles its background color in the following order: 7 (gray), 0 (black), 3 (cyan), 0, 6 (brown), 0, 2 (green), 0, 5 (purple), 0, 1 (blue), 0, 4 (red), 0. Note that this is the actual color of the player, so if an energizer is duplicated onto a player "clone" on a title screen and you enter the editor, the color of the player will appear different. The PlayerChar counter is also toggled. When the EnergizerCycles counter reaches 10, the player causes the "Energizer Deactivate" sound to play, but the function still continues normally. When it reaches 1, however, the player changes its color back to white on dark blue and the counter is set to zero. Score- When the player attempts to move and is blocked by a gem, this counter is incremented by 10. When creatures are killed, they also increase the Score counter, but it is done by the creatures themselves, not the player. Time- I am currently unable to collect solid evidence that this is in fact a player-controlled counter. I know that the Time counter is only worked automatically during game play, but having more than one player on the board doesn't affect the speed in which the counter is decreased. Every 10 cycles, the counter is increased by 1. The number that is displayed in the sidebar is the difference between the Time counter and the BoardTime counter, which remains constant for the board. When that difference reaches 10, the warning sound and message are displayed. The cycle after the Time counter reaches the BoardTime counter, the player is hurt (the standard loss of 10 Health and the sound effect plays), and the Time counter is reset to 0. If anyone can prove whether or not the Time counter is controlled by the player, please e-mail me at nanobot@mysticalwinds.zzn.com Keys- When the player attempts to move and is blocked by a key, the player checks the corresponding Key counter. If it is set to 0, the player "captures" the key element like any other item and sets the corresponding Key counter to 1. If it is set to anything other than 0, the "Already have key" sound and message are displayed and the player doesn't move. When the player attempts to move and is blocked by a door, the player checks the corresponding Key counter. If it is set to 0, the "Need a key" sound and message are displayed and the player doesn't move. If it is set to anything other than 0, the player "captures" the door element like any other item and sets the corresponding Key counter to 0. PlayerChar- When the EnergizerCycles counter is greater than 1, the player toggles the PlayerChar counter each cycle. The PlayerChar counter is used to determine the character that the player is displayed as. The PlayerChar counter may simply be a single binary bit, meaning that the player can only be displayed as one of the two standard smilies (char #1 or #2). However, if the counter is actually a byte-long counter, the player could be displayed as any character, though it would probably require an external hack. --- PLAYER/CLONE MOVEMENT Every player on the board, regardless of whether or not it is the "active" player, performs the exact same functions. They may not all have the same results, since some functions work relative to the coordinates of the first stat element in the board's data, which is usually what is considered the active player. Players that are not the "active" player are sometimes called player clones or dummies. If there is one thing that anyone knows about them, it's that the active player "sticks" to them. When you attempt to move in a direction that the clone isn't blocked in, the active player jumps to that direction of the clone and can't move any further. I'm going to explain why that happens. Every player on the board reacts in the same way to a keystroke. When you press up, every player on the board begins the function to move up. Each one tests for items and such using its own coordinates as is expected. However, instead of altering its own coordinates when it finally moves, it is programmed to change the coordinates of the first stat element in the board data, the Active Controller Element (ACE). Each player works in the order they are in the board data--the order in which they were placed on the board. The ACE works first and sets its coordinates to one space above its previous coordinates, so the ACE has moved up. The next player then does the same function in the same cycle immediately after the ACE, but instead of changing its own coordinates, it is set to change the ACE's coordinates to one above its own coordinates. The player is now "stuck." This continues to the last player in the board data. Because the ACE does in fact move before the other players cause it to stick, the last player doesn't consider itself to be blocked by the ACE, so no matter how many times your try to move in that direction, the ACE will always remain there as long as the current last player remains the current last player in the board data. So to summarize, the ACE will always end up in the pressed direction of the last player in the board data that isn't already blocked in that direction by something other than the ACE. Demonstration- Create an object on an otherwise empty board with the following code: #cycle 1 /rnd/rnd/rnd/rnd/rnd/rnd/rnd /rnd/rnd/rnd/rnd/rnd/rnd/rnd #put rndp rndne player #restart Now start it. Continuously press directions as the object lays down more players. You'll note that you'll always jump next to the most recently placed player unless it is blocked by another or a wall. --- PLAYER-ELEMENT REACTIONS The following section is information about how players react when they attempt to move and are blocked by various elements. Empty- The player takes the step, meaning that its X Step value is added to its x coordinate and its Y Step value is added to its y coordinate. Board Edge- The player reads its X and Y Steps and switches to the board whose value is in the corresponding "Board to (direction)" byte in the board header. The ACE on the destination board has its x or y coordinate (depending on the previous player's Steps) set to the corresponding coordinate of the previous ACE. The adjacent coordinate is set to an automatic value based on the previous player's X and Y Steps. The player perform no further action. Element #2- The player performs no further action. Monitor- The player performs no further action. Player- The player performs no further action. Ammo- The player increments the Ammo counter by 5, displays "Ammunition - 5 shots per container." if it has not yet done so in that playing session, and plays "cc#d". The ammo is turned into an empty (any stats remain) and the player takes the step. Torch- The player increments the Torches counter by 1, displays "Torch - used for lighting in the underground." if it has not yet done so in that playing session, and plays "case". The torch is turned into an empty (any stats remain) and the player takes the step. Gem- The player increments the Gems and Health counters by 1, increments the Score counter by 10, displays "Gems give you Health!" if it has not yet done so in that playing session, and plays "+c-gec". The gem is turned into an empty (any stats remain) and the player takes the step. Key- The player checks the Key counter corresponding to the key element's color. If it is set to 0, the player sets it to 1, displays "You now have the " followed by the corresponding color word and " key.", and plays "+cegcegceg+sc". The key is turned into an empty (any stats remain) and the player takes the step. If the Key counter is set to anything other than 0, the player displays "You already have a " followed by the corresponding color word and " key!", and plays "sc-c". The player performs no further action. Door- The player checks the Key counter corresponding to the door element's color. If it is set to 0, the player displays "The " followed by the corresponding color word and " door is locked!", and plays "--gc". The player performs no further action. If the Key counter is set to anything other than 0, the player sets it to 0, displays "The " followed by the corresponding color word and " door is now open.", and plays "cgbcgb+ic". The door is turned into an empty (any stats remain) and the player takes the step. Scroll- The player causes the scroll to begin executing its code and takes the step the following cycle. Note that the player does not itself change the scroll into an empty, and instead the scroll simply removes its presence and its stat block, leaving behind whatever is beneath it. The player then takes the step. If the scroll was previously statless and couldn't remove itself, ZZT attempts to have the scroll and player at the same place at the same time, resulting in a crash. Passage- The player switches to the board whose value is in the first parameter of the passage. The ACE on the destination board has its x and y coordinates switched to the coordinates of the first passage of the same color as the passage on the source board in the destination board's data if one exists. Otherwise, the ACE maintains the coordinates it had preset. Duplicator- The player performs no further action. Bomb- The player checks the bomb's first parameter. If it is set to 0, the player sets the parameter to 9, displays "Bomb activated!", and plays "cf+cf+c". The player performs no further action. If the parameter is set to anything other than 0, the player checks the element that occupies the coordinates in which the player's X Step value is added to the bomb's x coordinate and the player's Y Step value is added to the bomb's y coordinate. If that destination space isn't occupied by a non-pushable "massive" element, the bomb's x and y coordinates are shifted to it and the player takes the step. Otherwise, the player performs no further action. Energizer- The player sets the EnergizerCycles counter to 75, sends all objects on the board to the label "ENERGIZED", displays "Energizer - you are invincible" if it has not yet done so in that playing session, and plays "s.-cd#e". The energizer is turned into an empty (any stats remain) and the player takes the step. Star- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The star is removed (reverted to the statless "under" element) and the player takes the step. Clockwise- The player performs no further action. Counter- The player performs no further action. Bullet- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The bullet is removed (reverted to the statless "under" element) and the player takes the step. Water- The player displays "Your way is blocked by water." and plays "+c+c". The player performs no further action. Forest- The player displays "A path is cleared through the forest." if it has not yet done so in that playing session and plays "a". The forest is turned into an empty (any stats remain) and the player takes the step. Solid- The player performs no further action. Normal- The player performs no further action. Breakable- The player performs no further action. Boulder- The player checks the element that occupies the coordinates in which the player's X Step value is added to the boulder's x coordinate and the player's Y Step value is added to the boulder's y coordinate. If that destination space isn't occupied by a non-pushable "massive" element, the boulder's x and y coordinates are shifted to it and the player takes the step. Otherwise, the player performs no further action. SliderNS- The player checks its Y Step. If it is set to anything other than 0, the player checks the element that occupies the coordinates in which the player's X Step value is added to the slider's x coordinate and the player's Y Step value is added to the slider's y coordinate. If that destination space isn't occupied by a non-pushable "massive" element, the slider's x and y coordinates are shifted to it and the player takes the step. Otherwise, the player performs no further action. SliderEW- The player checks its X Step. If it is set to anything other than 0, the player checks the element that occupies the coordinates in which the player's X Step value is added to the slider's x coordinate and the player's Y Step value is added to the slider's y coordinate. If that destination space isn't occupied by a non-pushable "massive" element, the slider's x and y coordinates are shifted to it and the player takes the step. Otherwise, the player performs no further action. Fake- The player displays "A fake wall - secret passage!" if it has not yet done so in that playing session. The player takes the step, setting the fake element and its colors to the player's "under" information. Invisible- The player displays "You are blocked by an invisible wall." and plays "--dc". The invisible is turned into a normal (any stats remain) and the player performs no further action. BlinkWall- The player performs no further action. Transporter- The player compares its X and Y Steps with the transporter's. If both corresponding values are equal to each other, it then checks the element that occupies the coordinates in which the player's X Step is added to the transporter's x coordinate and the Y Step is added to the transporter's y coordinate. If it is that destination space isn't blocked by a non-pushable "massive" element, the player plays "c+d-e+f#-g#+a#c+d" its coordinates are set to that destination space. If it is blocked, it checks for another transporter whose x and y coordinates are off the original transporter's by a positive multiple of both the X and Y Steps of the original transporter and has its X and Y Steps negative of the original's. If such a transporter exists, the player plays "c+d-e+f#-g#+a#c+d" and its coordinates are set to the Steps of the original transporter plus the coordinates of the closest transporter that fits the guidelines. Otherwise, the player performs no further action. Line- The player performs no further action. Ricochet- The player performs no further action. Horizontal BlinkWall Ray- The player performs no further action. Bear- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The bear is removed (reverted to the statless "under" element) and the player takes the step. Ruffian- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The ruffian is removed (reverted to the statless "under" element) and the player takes the step. Object- The player sends the object to the TOUCH label and performs no further action. Slime- The player sends the slime to its last stage where it turns into a breakable, bypassing the reproduction stage, and performs no further action. The player assumes that the slime has stats, so if it is in fact statless, it will alter an illegal part of the memory which will cause ZZT to crash. Shark- The player performs no further action. All damage to the player is handled by the shark, meaning that whether with or without stats, the player isn't hurt simply by touching a shark. SpinningGun- The player performs no further action. Pusher- The player performs no further action. Lion- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The lion is removed (reverted to the statless "under" element) and the player takes the step. Tiger- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The tiger is removed (reverted to the statless "under" element) and the player takes the step. Verticle BlinkWall Ray- The player performs no further action. Head- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The head is removed (reverted to the statless "under" element) and the player takes the step. Segment- The player decrements the Health counter by 10, changes its color to 7F (white on light grey), displays "Ouch!", and plays "--c+c-d#+d#". The segment is removed (reverted to the statless "under" element) and the player takes the step. Element #46- The player performs no further action. Blue Text- The player performs no further action. Green Text- The player performs no further action. Cyan Text- The player performs no further action. Red Text- The player performs no further action. Purple Text- The player performs no further action. Brown Text- The player performs no further action. White Text- The player performs no further action. --- SCROLL FUNCTIONS Scrolls are exactly the same as object in almost every aspect of their function. In fact, in terms of their actual game function, scrolls can do everything that objects can do. However, they also have automatic functions. A scroll has a few automatically executed commands, the number depending on whether or not the last one is actually a command executed by the scroll or the standard item "capture" function of the player. The scroll's name is set automatically: Scroll. I believe that it would have the same function as an object's name that you can set using the @ operator, but I am unable to prove that because the SEND command can only send to objects, not scrolls. Next, the scroll doesn't execute any of its code until the player touches it. At this point, it performs the actual OOP code (not just text) in its data, but not before executing this line: #PLAY c-c+d-d+e-e+f-f+g-g I know that the PLAY command operates how it does because of the way it is stored in the ZZT.EXE binary. Unlike using the standard sound effect code, the actual string of notes can be seen in OOP format when viewing ZZT.EXE in byte display mode. However, the PLAY line does not work like having it on the first line. If the first line in the actual OOP code of the scroll begins with the @ operator, the name will be set just like in an object. Regardless, the sound effect still plays before any of the code is executed. Probably one of the most crucial functions of the scroll in terms of OOP use is the fact that the scroll dies the cycle after the player touches it. This leads to why I believe that the player actually "captures" it like other items, rather than the scroll killing itself. No matter the position in the scroll's code, it will always die immediately after the first cycle has been completed. One argument against the idea that it is the player's doing, however, is the fact that the player will not always replace the scroll. If the scroll's text is more than one line long, the player will remain where it was. If it is the player's doing, there may be a function directly related to scrolls in this way, but it is doubtful as to why Tim Sweeney would go to these extra measures when a simpler one would suffice. Externally of the OOP code, scrolls also have a few obvious differences from objects. Scrolls do not read their first parameter for their character as objects do, and instead stick to character #232. Also, scrolls cycle their colors from color 9 (light blue) to 15 (light white) in order. Scrolls of different colors (low intensity of with background colors) will instantly revert to a high intensity on black color. Since the color cycling is a function performed by the scroll itself, scrolls without stats remain whatever color they are given. Scrolls without stats should be used carefully, however, since they will cause ZZT to crash if the player touches one. --- BOMBS Bombs have an interesting function, and very much resemble the player's usage of torches in a way. By default, the first parameter of a bomb is set to 0. This means that the bomb is inactive. When the player touches a bomb, if its first parameter is set to 0 the PLAYER makes the sound and the "Bomb activated" message appear (tested with a statless bomb) and then sets the parameter to 9. The bomb then decreases the parameter one value each cycle and changes its char to the value of the parameter. At each cycle, the bomb makes a "tick" or "tock" sound, depending on whether the parameter value is even or odd. When the parameter is greater than 0, the bomb is pushable (statless bombs are not). When the bomb's parameter reaches a value of 2, it begins the explosion function. This involves elements within an approximate 53-pixel radius about the center of the bomb. Every empty in that area is changed into a breakable of a random color between 9 (light blue) and 15 (light white) with a black background. Keep in mind that these are normal statless breakables. Every object in the area is sent to the BOMBED label, and if the player is in the area he is hurt (the regular loss of 10 Health and the sound effect). The next cycle, the bomb changes every breakable in that 53-pixel radius (counting the breakables it placed and any that already existed) into empties and the bomb dies. Since the player sets the bomb's parameter when it touches it and not the bomb, a small bug appears when the player touches a statless bomb. Since there isn't any stat information about that bomb, it gets confused and all statless bombs on the board, once refreshed, appear as nines, though they don't perform any further function. --- BLACK HOLES Black holes, as they are known, are actually empties with stats. In fact, there may be different types of black holes. Anything that something can walk on, once stats are added, may be considered a black hole. The prime characteristic of black holes is that the player tends to "hop" over them. Why is this? It has to do with a glitch caused when two blocks of stat information in the board data try to direct to the same coordinates. When mixed with movement, the result leaves the player an extra space ahead. When there is a line of black holes, the player continues to hop over many at once. What stops it is probably just the end of its cycle. --- BOARD EDGES The best way to figure out why something works the way it does, in my opinion, is to think of what the creator would find the easiest method to do something. Board edges are fairly good examples of this. Tim Sweeney found that it would be easier to have the player actually control the board switching operation rather than some global operator. To suit the way the player already worked, Tim simply produced a new element that would have absolutely no function whatsoever. The only way it has any importance is that its Element Identification Number is unique and completely distinguishable among all other elements. It also prevents possible problems caused by using a preexisting element that could exist somewhere else on the board. When the player sees the Element Identification Number of the board edge when it attempts to move there, it knows to jump to the board switching function. This allows a clean board transition without all of that coordinate checking/comparing mess. It simply retains either its x or y coordinate (depending on the direction it's moving), and jumps to the corresponding side with that adjacent coordinate. Each board is, internally, surrounded by board edges. All except for those along the East side are out of view, and the ones on the East side blend in well with the overlay sidebar. To prevent things like objects from messing up the board edges, Tim also made a limitation for PUTing elements by creating a bounds check system. Unfortunately, he got the y coordinate for the bottom row off by one, resulting in the inability to PUT anything in the bottom row of the viewable section of the board. He probably forgot to count the top board edge layer. --- BLINKWALLS Blinkwalls have a function similar in concept to bombs. It starts off waiting for the number of cycles that its first parameter is set to. After this initial wait, it begins its function cycle. It checks its X Step. If it is set to a value other than 0, regardless of the Y Step, it will work with horizontal blinkwall rays. Otherwise, it will work with vertical blinkwall rays. It then looks at the coordinates of the X and Y Steps relative to itself. If there is a blinkwall ray of the orientation it is set to look for by its X Step at those coordinates, it begins the clearing function. Otherwise, it begins the placing function. In the placing function, it looks at the focus coordinates and determines the element there. If there is a player there, it destroys the player like a bullet, star, or bomb would. Then, whether there was a player there or not, if there is an empty there it places a blinkwall ray of the given orientation at the focus coordinates. It then increments the focus coordinates by the X and Y Steps and repeats the process. If something other than an empty was there, it aborts the function. In the clearing function, it works with its coorinates like the placing function, but instead of searching for empties and placing blinkwall rays, it searches for blinkwall rays and places empties. The function is aborted as soon as it comes in contact with an element other than a blinkwall ray along its path. The cycle interval between each initial check of whether to place or clear is set by the blinkwall's second parameter.