THE UNIVERSAL NETWORKING MODULE The published source text of MULTI WORMS is divided into two major files: The game-routines, and the communication module. While the game part with hungry worms is just an example, the communication module is a relatively universal base for making further network-games. Actually, this module is an independent network-game matching all the above specifications, with all the game-specific parts replaced by JSR-calls to the second file. The game-part is then just a set of subroutines - you're free to replace this part by your own game, as described below. But first I'm going to present some outline informations about the networking module itself. (It's allways better to know how the program works, when you're going to use it in your own game.) A game built on this module is working without of the Operating System - all the ROMs are simply banked-out, and the program operates directly on hardware registers. This is probably the best solution for a game, because the O.S. is not very useful for this purpose (a poor character-set and a few VBI-handled variables - that's all we can use), we have maximum of free memory, and we don't have to worry about problems with thousands of modified ROM-versions (Attract mode is one of the smallest troubles). It's also easier to overcome problems with interrupts (see above), when there's no additional OS-code executed before our own interrupt routines. The data-transfer works at the standard speed 19200bps, with a checksum at the end of each data-block. This is compatible with the standard Atari SIO transfer, allowing us to use the same routines for both game-networking and terminal booting. The speed is also reasonable for the use of long cables without of advanced hardware. The main IRQ routine does almost everything around the physical layer of data transfer. While sending a block, first a gap is done using the POKEY's counter as a timer: Instead of starting the transmission a timer is set, and the actual data transfer is started with a certain delay by the IRQ from that timer - leaving enough time for the detection of previous block's end. Ofcourse the end-of-block detection is done at the end of receiving IRQ routine, as described above. Since it's necessary to clear IRQEN as soon as possible to avoid NMI-problems, the routines allways enable only one IRQ type at a time, so that there's no need to detect the interrupt source (saving time). Because of this, the game-program may not use any other IRQ's! (The only common use is keyboard input, which may be easily done also on VBI - as shown in MULTI WORMS source.) The module also takes control over NMI interrupts, executing a part of networking operations on VBI, and calling actual interrupt routines of the game as subroutines. Because the VBI should not freeze IRQ-controlled data transfer for too long time, VBI routines are divided into Immediate and Deferred part - just like the Atari O.S. does. The Immediate part - which must be rather short - is allways executed (unless the NMI is lost), while the Deferred part - which may be long - is sometimes omitted: To avoid IRQ-freezing, the VBI system detects if some IRQ routine was running before NMI - if so, the Deferred part is not executed, allowing the IRQ to finish its work in time. Otherwise, another IRQ's are enabled before executing the Deferred part, so that long Deferred-VBI routines are not blocking further IRQ data-transfer. The communications protocol is relatively simple. The table below shows the structure of all data blocks transferred: ID Length Block type / Sent by Structure (offset, function) ------------------------------------------------- $40 6 0:Log-in accepted / Master +1-2: Random numbers used by terminal +3-4: Game identification bytes +5: Given terminal-number $48 5 1:Log-in request / Terminal +1-2: Random numbers +3-4: Game identification bytes $50+t 2 2:Menu-status question / Master +1: Game-start wanted (0=Not) $58+t 20 3:Menu-status answer / Terminal +1: Ready for game (0=No, 1=Yes) +2-17: Two local player-names +18-19: Random numbers $60+t 122 4:Info-block before game / Master +1: Info-block number +2-121: Game-specific data, or player-names $68+t 2 5:Info-block accepted / Terminal +1: Info-block number $70+t 12 6:New game-step / Master +1: Number of step +2-9: Joysticks of all computers +10-11: Central random numbers $78+t 3 7:Game-step accepted / Terminal +1: Number of step +2: Joysticks of the terminal ($31) 4 SIO Command-block / Booting terminal +0: Device code ($31=Disk drive 1) +1: Command (R=Read, S=Status) +2-3: Number of sector --- 1 SIO ACK-byte / Master (emulating disk drive) +0: A=Accepted, C=Complete executed (A single byte with no checksum!) ($00) 4 Drive status / Master (emulating disk drive) +0: $00=Single density +1-3: $FF, $FE, $00 (common answer) --- 128 Boot-sector / Master (emulating disk drive) +0-127: Data of the sector The first part of the table shows the game-networking blocks, while the rest is actually a very simplified part of the Atari SIO protocol necessary for the Terminal-booting process. All the game-networking blocks begin with one ID-byte (shown in the left column), which is used together with the block-length as the identification of block-type and address. The structure of this byte is following: b7 b6 b5 b4 b3 b2 b1 b0 ------ ---------- ---------- Protocol Block Terminal version type number The communication is allways between the Master and the terminal specified in the ID-byte, only the Log-in blocks are sent with zero as the Terminal-number (because the terminal have no number yet). The block-types 0-7 are corresponding with the table above, and the "Protocol version" bits are allways 01 (MULTI DASH uses 00, other codes are waiting for future use). The terminal-booting process is quite simple: The Master system recognize some SIO-commands coming from the network, and sends data from its own memory as an answer, so that the other computers may read a portion of Master's memory as if it were a disk inserted into a floppy-drive. Once a terminal-computer is switched on, it does try to boot a disk, and so it reads a copy of the game-program from Master into its own memory. To be sure that the program was transferred correctly, a 16-bit checksum of the whole memory-block is checked after boot. Now let's look how the whole system works: First the game program is started in the Master system. Since no terminals are logged-in, the computer doesn't send anything to the serial port, so that no interference with connected peripherals may occur while playing on a single computer. When a terminal is connected and switched on, it starts to boot a disk, and so it gets a copy of the game program from Master's memory. Then, the terminal sends a Log-in request, and gets its own terminal-number from the Master. This is a very important operation, because having unique terminal-numbers is a basic condition for a successful networking. To avoid false log-ins, the transferred data also contain two game-identification bytes (more network-games at a meeting?), and random numbers which must be sent back as a part of valid answer (for the case that two terminals are trying to log-in at the same time). Now the Master each three seconds sends Menu-questions to all the logged-in terminals to be sure that they are still connected. The terminal's answer contains also random numbers as a further arrangement against having two terminals with the same number: If by some mistake two terminals have the same number (possibly caused by connection problems at the time of log-in, or by RESET on the Master), and so both are answering to the same question, the different random numbers coming to the network simultaneously cause the answer to be unreadable for Master, and so the terminal-number is unlogged after a while. Also the terminals are checking the connection by counting the time between received Master's questions (or boot sectors - during a boot the Master sends no questions): When it's quiet for a too long time, the terminal execute the Log-in process again, to resume the connection. After a while, this system overcome all the problems, and every connected terminals are logged-in. Simultaneously, the menu-screens are displayed on every computers, the players are editing their names and making another selections, and then it's finally the time to start the game (the user of the Master system clicks on a "Start" option in his menu). The Master first waits until it's quiet on the network for a few seconds (so that a running boot may be finished), and then it starts to send the Menu-questions again, but now with the "Game start wanted" flag active in it - so the terminals display a message, that the players should get ready for the game. After a while, the players finish their menu-settings (and click on a "Ready" option), and so the Master finally receive all the answers with the "Ready for game" flag set. At this moment, all the player-names are already collected in the Master system, because these are also included in the terminal's answers. Now the Master prepare the map or other game-specific data, and send it to all the terminals - divided into several short blocks; as the last block all the user-names are sent. Once all the blocks are transferred, the game begins. (From this point on, the communication is fully controlled by interrupt-routines, allowing relatively long game-routines to be executed simultaneously.) Now, 10 times a second (a reasonable game-speed, also limited by the data transfer) the Master system starts a new game-step (unless there's a delay caused by heavy communication problems): First the Master reads its own joysticks and generate central random-numbers, then it sends the central joystick-register to all the terminals, and receive the update (i.e. status of terminal's local sticks) as an answer. The block of all network's joystick-data is on each computer written to a buffer, which is then read by the main game-loop as soon as possible. This loop then calls the actual game-routines with ready input data. Although the transmission is done at a different point of the main game-loop for each terminal (to have fast response on local joysticks), the system provides exactly the same data-stream in all the computers. When the game is over, all the computers read some more joystick blocks to clear any additional data hanging around in the system, and jump back to the menu. Since the game works in full on all the computers, the game-results are already available and so there's no need to transfer these via network. To minimize the amount of transferred data, each joystick is encoded into four bits of the terminal-byte on network (two players per computer are supported). The code describes the changes of stick position, and when no change occurs, then the status of FIRE button is encoded (it's nonsence to change the stick position 10 times a second, so there's allways some time left to transfer FIRE). Also the existence of single players is transferred. The codes are: 5 1 6 9 = FIRE is active \ | / 10 = No FIRE 3 - 0 - 4 / | \ 11 = Player not exist 8 2 7 (12-15: unused) A little problem is with the keyboard controls. As I said, it's useful to have a network game playable also without of full amount of joysticks, so my software supports also keyboard as the input device. But since the POKEY chip may only detect one key at a time, it's impossible to do diagonal directions on normal cursor keys. After some experiments, I finally decided to use the system known from a Slovak game called DYNAKILLERS: XL computer: SELECT XE computer: Q | | A - - S START - - SELECT | | SHIFT=FIRE START SHIFT=FIRE A This layout is maybe a bit strange, but with two experienced hands it is playable, and it's probably the best we can do on the Atari keyboard.