Classic Computer Magazine Archive A.N.A.L.O.G. ISSUE 67 / DECEMBER 1988 / PAGE 66


Game Design Workshop
by Craig Patchett




The display list
    You probably already know at this point that the display list is something that describes how the screen will be set up. For example, the display list for a graphics mode zero screen tells the computer that there are to be 24 graphics mode zero lines on the screen. In graphics mode one, it tells the computer that there are to be ten graphics mode one lines and four graphics mode zero lines (remember that graphics mode one is a split-screen mode). The unique thing about the display list, however, is that you can set it up any way you choose. That means you can design a custom screen that is a mix of whichever graphics modes you choose, and the ability to do this comes in very handy when you're trying to design a game with a special look.
    Let's begin by taking a look at a sample display list, in this case for graphics mode 0:

Display list for GRAPHICS 0
(small text)

BLK 8 - leave eight scan
lines blank
BLK 8 - leave eight scan
lines blank
BLK 8 - leave eight scan
lines blank
 
CHR 2 LMS - GRAPHICS 0 lines
                       with screen memory
                      address

JVB - go back to the beginning of the
        display list, wait until the end
        of VBLANK, and do it all over
       again!
JVB LOW
JVB HIGH
FIGURE 1


    If this was the display list that the computer was using, then it would leave the first 24 scan lines blank (because they're not completely visible on the screen) and then put 24 graphics mode zero lines on the screen. Once it was done with that, it would run into the JVB command, which tells it to go back to the beginning of the display list and wait for the end of vertical blank. Why? You'll recall from our previous discussion on the television screen that the screen has to be redrawn every 1/60 of a second, and that vertical blank is the time between screens. So by making the display list into a loop that gets executed after every vertical blank, we make sure that screen gets redrawn properly.
    You probably noticed that I forgot to explain the LMS after the first CHR2 instruction. LMS stands for "Load Memory Scan," which is just a fancy way of saying "Here's where the screen memory is." In the last column we discussed the need for this feature, and you should make sure that you use an LMS whenever you want to change the address of screen memory. The first line on the screen must have an LMS. If the next one doesn't, then the computer will just assume that the screen memory for that line comes right after the screen memory for the previous line. In the case of graphics mode 0, each line needs 40 bytes, so the screen memory for the second line will begin 40 bytes after the screen memory begins for the first line.
    So, what are the steps to creating a display list? First of all, there are a few simple rules that must be followed. If you want to make sure that the whole screen is visible, the display list should begin with three BLK 8 instructions, like in Figure 1. In some cases, like when you're doing vertical scrolling, you may not need them. Assuming you use them, then the main part of the screen should use a total of 192 scan lines if you want to make sure that the bottom of the screen is completely visible. Again, there is no reason why you can't use more. If you use too many, however, the screen will jump. If this happens, just get rid of a few until it stops jumping. The final rule, before we get going, is that no matter what you do to the display list, no matter how badly it gets screwed up, no matter how bizarre the resulting screen looks, you cannot screw up the computer or your program. If something does go wrong, just press System Reset, and you'll go back to a graphics mode 0 screen with your program intact. With these basic rules in mind, let's now take a look at the display list's instruction set.

    BLK n: This instruction is used to leave blank scan lines on the screen. We've already seen one possible use-to leave the top of the screen blank so that the rest will be visible. Blank scan lines are also useful when, for some reason, you're not using part of the screen. The more BLK instructions you use, the faster (just a little) your program will run. Unfortunately, there are very few times when you don't use the entire screen. Personally, I hardly ever use them except at the beginning of the screen.

    JMP: This is a jump instruction, the equivalent of BASIC's GOTO. The only reason it's needed is because the display list is not allowed to cross a 1K boundary. What's a 1K boundary? It's a memory location that is a multiple of 1024. When the GRAPHICS instruction is used, the display list is automatically positioned so that it does not cross such a boundary. When you design your own display lists, however, you may run into this problem (apparently not very often, however, since I have yet to do it). If you do, then you should put a JMP instruction right before the boundary. It's a three-byte instruction (one for the instruction and two for the address to jump to), so it should begin at the boundary address minus three, and then should jump to the boundary address. If this sounds kind of silly, it's only because it is.

    JVB: This is the other jump instruction that we ran across in our example display list above. It tells the computer to go back to the beginning of the display list and wait until the end of vertical blank before drawing the screen again. Like the JMP instruction, it is also three bytes, with the second two specifying the address of the beginning of the display list. You'll see later exactly how to do this.

    CHR: This specifies one of the character modes. For each character mode line on the screen you would use one of these instructions.

    MAP n: This is the same as CHR, except it's used to specify a bit-mapped mode (PLOT and DRAWTO) instead of a character mode.

    So much for the basic display-list instruction set. You may have noticed a few things that were missing, like the LMS instruction, for example. Well, the LMS is actually a modification, not an instruction. What this means is that the LMS, along with three other modifications, is added on to the above instructions. So you would have a CHR 2 LMS instruction, for example, or a CHR 6 LMS HSC instruction, which would be a graphics mode 1 line with LMS and horizontal fine scrolling. Here are the four modifications possible:

    HSC: This is used to specify a horizontally fine-scrolling line.

    VSC: This is used to specify a vertically fine-scrolling line.

    LMS: We already know that this is used to specify the address of screen memory. An instruction with the LMS modification must be followed by a two-byte address.

    DLI: This is used to specify a line with a display list interrupt at the end of it. We'll get into display list interrupts in next month's column.

    You can add any or all of these modifications to the CHR and MAP instructions, but, for obvious reasons, the JMP, JVB and BLK instructions can only have the DLI modification. By this stage, you're probably wondering just how to get from CHR 6 LMS HSC, or whatever, to the number that will get POKEd into the display list. If you look at Figure 2 you will find a chart that gives the values for each of the possible instructions. To use the chart, first go down the left-hand side and find the row with the instruction you want to use. Then look at the top of the chart and find the column with the modifications you want to use. Go down the column until you get to the row you want, and you'll find the correct value. If charts bother you, then there is another way. Each instruction and each modification has its own value. If you take the values of the instruction and the modifications you want and add them all together, you'll get the correct value for the whole thing also. Here are the individual values:


BLK 1:        0
BLK 2:      16
BLK 3:      32
BLK 4:      48
BLK 5:      64
BLK 6:      80
BLK 7:      96
BLK 8:    112

JMP:           1

JVB:          65

CHR n:        n

MAP n:       n

HSC:        16
VSC:        32

LMS:        64

DLI:        128

    `You can check for yourself that this method will give the same values as the chart. Now the big question is, "What are all these different modes?" After all, we've already seen that CHR 2 is not graphics mode 2 but graphics mode 0. What about the other other modes? Here's an explanation of what each of the CHR and MAP modes are:

    CHR 2 is GRAPHICS 0.

    CHR 3 is the same as GRAPHICS 0 except the characters are ten scan lines high instead of eight. This allows you to have lowercase descenders, which means that the tails on "g," "j," "p," "q" and "y" can drop below the line, as they're supposed to. How do you use this mode? The first step is to redefine the character set. Actually, you only have to change the lowercase letters. What will happen is the computer will take the first two bytes of the character description and stick them on the end of the character. It will then make the first two scan lines of the character blank. For non-lowercase characters, it will leave the bytes in order and make the last two scan lines blank.
    You should note that because each character is now ten scan lines high, you can only have 19 rows on the screen (192/10). Make sure of this when you change the display list.

    CHR 4 lets you use multicolored characters. We mentioned this mode briefly in the column on character sets. CHR 4 characters are the same size as graphics mode 0 (CHR 2) characters. The difference, however, is in the size of the pixels that make up the characters. The pixels are the same height in both modes, but in CHR 4, they are twice as wide as in graphics mode 0. Why? In order to have four colors per pixel, there has to be two bits per pixel rather than one. This means that each character will be four pixels wide and eight high. While this isn't much use for designing letters (unless you put two characters side by side), it's great for graphics. Regardless of what you end up using this mode for, here's how the computer interprets a character description byte in this mode:

Although it's true that you have
to know machine language to push
the display list to its limits, there's
more than enough that can be
handled from BASIC.


BITS 7    6
5    4
3    2
1    0
USE
PIXEL 1 PIXEL 2 PIXEL 3 PIXEL 4
FIGURE 3


PIXEL
VALUE

COLOR REGISTER
00
01
10
11
COLOR4 (background)
COLOR0
COLOR1
COLOR2

    Now, there is a way to add one more color to get all five colors on the screen at the same time. If you print a CHR 4 character in inverse video (i.e., the normal character value plus 128), then the pixels with a value of 11 binary will get their color from COLOR3 instead of COLOR2.
    Finally, in case it isn't obvious, you should note that the procedure for designing a character set for this mode is exactly the same as that for graphics mode 0, with the exception, of course, that you will now be using two bits per pixel instead of one.

    CHR 5 is the same as CHR 4 except the characters are twice as high (the same height as graphics mode two).

    CHR 6 is GRAPHICS 1.

    CHR 7 is GRAPHICS 2.

    MAP 8 is GRAPHICS 3.

    MAP 9 is GRAPHICS 4.

    MAP 10 is GRAPHICS 5.

    MAP 11 is GRAPHICS 6.

    MAP 12 is the same as MAP 11 except the pixels are one scan line high instead of two.

    MAP 13 is GRAPHICS 7.

    MAP 14 is the same as MAP 13 except the pixels are one scan line high instead of two. This mode is sometimes called GRAPHICS 7.5 because it's halfway between GRAPHICS 7 and GRAPHICS 8. We'll be using it in our game, so you'll be able to see it in action.

    MAP 15 is GRAPHICS 8.

    Whew! Well, that's all the modes that the Atari makes available for you, with the exception of the GTIA modes or GRAPHICS 9, 10 and 11. We'll be covering those modes later in a special column just for them.
    Okay, now we know almost everything that we need to know to actually design a display list, so let's add a few small details and then actually do some designing. First of all, you should know that locations 560 and 561 hold the address of the beginning of the display list. (PRINT PEEK(560)+PEEK(561)*256 will give you the decimal address.) Let's see, what else? Oh, screen memory is not allowed to cross a 4K boundary (a memory location that is a multiple of 4096). In the GRAPHICS modes, the only time this happens is in graphics modes 8 through 11, since in these modes screen memory takes up a total of 7680 bytes, well over 4096. In these modes, an extra LMS is added to the line where the offensive boundary is crossed. This is also what you should do if you need screen memory to cross a 4K boundary. Simply add LMS to the line that will cross the boundary and have it point to the first address after the boundary.
    I realize that I have presented a lot of information so far without any concrete examples. This is mainly due to the fact that the display list is probably one of the most powerful graphics techniques that the Atari has to offer. Although it's true that you have to know machine language to push the display list to its limits (which is true with all the other techniques as well), there's more than enough that can be handled from BASIC. You've already seen the powers of fine scrolling in the last chapter, and we're now going to see how to go about mixing modes. Before we do, however, you may want to quickly go back to the last month's column and look again at the sections that involved the display list. Now that you have a better understanding of how the display list works, those sections may make a little more sense to you.
    We're now ready to get our screen in the format that we decided on earlier in another column.
    The first step is to get an initial display list and screen memory. There's no reason why we can't start off from scratch, but as long as there's a way for BASIC to help us out, we may as well take advantage of it by using the GRAPHICS command, since it automatically sets up a display list and screen memory that we can fool around with. The question is, which graphics mode do we use? In the past, most people pick the mode that has the biggest screen memory out of the ones they want to mix. That way, they make sure that there will be enough screen memory for the custom screen. It also means that some of the display list won't need to be changed. This method is fine, but it tends to waste memory. For example, in the screen that we're designing, GRAPHICS 7.5 uses the most screen memory at 7680 bytes. But we're not using that many GRAPHICS 7.5 lines.

Display list interrupts (DLIs)
are important and powerful
features of your Atari computer:


    We must figure out the total amount of memory that we need for screen memory. We see that it only comes out to 1360 bytes (16*20 +24*40+3*20+1*20), afar cry from 7680. That gives us two options. We can either set up for GRAPHICS 8, which is the same screen memory as GRAPHICS 7.5) and waste the extra memory, which is fine if you've got it to spare, or we can set up for GRAPHICS 6, which uses 1920 bytes for screen memory, much closer to our 1360. The choice is entirely up to you, but I would recommend wasting as little memory as possible, since the less memory your game requires, the more people that will be able to use it. So this will be the first part of our display list redefinition:

4000 GRAPHICS 22:POKE 55
9,0:POKE 756,CB+2

    Remember, this is a change to the program that we've been developing throughout the previous columns. Our next step is to find the display list so we can go about changing it. We already did that in last month's column, but here's the line again, just to refresh your memory:

5010 DLIST=PEEK(560)+PEE
K(561)*256

    Now we're all set to go in and change the display list. Here are the program lines to do:

5020 POKE DLIST+3,86
5030 L=PEEK(DLIST+4)+44:
POKE DLIST+5,PEEK(DLIST+
5)+(L>255):POKE DLIST+4,
L-256*(L>255)
5040 FOR X=6 TO 20:POKE
DLIST+X,22:NEXT X:FOR X=
24 TO 50:POKE DLIST+X,14
:NEXT X
5050 MEM7=PEEK(88)+PEEK(
89)*256+600
5060 POKE DLIST+21,78:PO
KE DLIST+23,INT(MEM7/256
):POKE DLIST+22,MEM7-INT
(MEM7/256)*256
5070 POKE DLIST+31,78:PO
KE DLIST+33,INT((MEM7+32
0)/256):POKE DLIST+32,ME
M7+320-PEEK(DLIST+33)*25
6
5080 POKE DLIST+41,78:PO
KE DLIST+43,INT((MEM7+64
0)/256):POKE DLIST+42,ME
M7+640-PEEK(DLIST+43)*25
6
5090 POKE DLIST+51,22:PO
KE DLIST+52,22
5100 POKE DLI5T+53,22
5110 POKE DLIST+54,6:POK
E DLIST+55,70:POKE DLIST
+56,PEEK(88):POKE DLIST+
57,PEEK(89)
5120 POKE DLIST+58,65:PO
KE DLIST+59,PEEK(560):PO
KE DLIST+60,PEEK(561)

    And here is the line-by-line explanation:

    5020: This makes the first line a CHR 6 HSC LMS. Remember that the first 24 scan lines are left blank, which requires three BLK 8 instructions. That's why the first CHR 6 line is at DLIST+3 not DUST.

    5030: This is from a previous column, where we decided that we were going to skip over the first 44 bytes of screen memory, using them later to hold the score. If you don't remember why we did this, go back and double-check. In any case, this line sets up the LMS address for the first line on the screen.

    5040: Here we set up 15 more CHR 6 HSC lines and 27 MAP 14 lines. Wait a minute, though. Don't we only want 24 MAP 14 lines? And what happened to DLIST+21 through DLIST+23? The reason that things look a little funny at this point is because we want to set up the MAP 14 area in three sections. Remember that the invaders will eventually move far enough down the screen so that they run into the barriers, which are in the MAP 14 section. When they do this, we want to switch the part of the barriers that they run into to a CHR 6 line. We can do that quite simply, but we have to be careful about screen memory, since one CHR 6 line (20 bytes of screen memory) will be replacing eight MAP 14 lines (320 bytes of screen memory). To avoid a problem, we'll put an LMS at the beginning of each group of eight MAP 14 lines (three groups altogether). You'll see this being done in the next few program lines, and you will then understand why we did things in a funny way here.

    5050: To make sure that the invaders' screen memory is completely separate from the barriers' screen memory, we'll start the barriers' screen memory 600 bytes past the beginning of the invaders' screen memory. Why 600? Why not! Actually, it could have been anything greater than 444 (20 CHR 6 lines times 20 bytes apiece, plus the initial 44 bytes we skipped over). I just chose 600 to make sure there would be no conflicts.

    5060: Now we put the first MAP 14 LMS into the display list. Notice that it fills in the gap we were worrying about earlier.

    5070-5080: Here are the other two MAP 24 LMSes. These two go in the middle of the 27 MAP 14s we put in before. The two LMS addresses replace four of the MAP 14s, leaving 23 intact. Add these to the one we set up in Line 5060, and that gives us the 24 that we wanted initially.


Since the DLI has to do whatever
it does in an extremely short time,
a DLI routine has to be written
in machine language.


    5090-5100: Here we add the last three CHR 6 HSCs. Did you notice that we didn't use an LMS here? That means that screen memory for these three lines will come right after screen memory for the barriers. Is that what we want? No, but the invaders won't appear in these lines until after the MAP 14s have been replaced with CHR 6 HSCs, like I mentioned earlier. Once this happens, the three CHR 6 HSCs here will be attached to the invader screen memory, as they should be.

    5110: We're not done yet. Here we put in the CHR 6 and the CHR 6 LMS for the score line (remember that the address for this LMS is the beginning of the original screen memory).

    5120: Now we finish the display list with a JVB back to the beginning. Note that unless you're doing fancy stuff with alternating display lists, this is the way to end any display list.

    Okay, now our custom display list is in place and ready to go. Unfortunately, we now run into a few problems. First of all, the computer thinks we're in graphics mode 6. This is no problem at the moment, but it will be later when we try to PRINT the score, and when we try and PLOT and DRAWTO in graphics mode 7.5. (There's no problem with the invaders, since we're moving them directly into screen memory.) How do we tell the computer which graphics mode we want to use? Luckily for us, location 87 exists just to tell the computer what graphics mode is being used. All we have to do is POKE location 87 with the graphics mode we want to use (for graphics mode 7.5, we POKE 87,7 since GRAPHICS 7 is the closest thing to it from BASIC). So much for this "problem."
    Our next problem is with screen memory. For example, let's suppose that we hadn't shifted screen memory around and that the score line was at the end of screen memory. What if we wanted to PRINT the score? We could try POSITION 0,23: PRINT #6; "SCORE." Would this work? No, because the computer will print the score 460 (23*20) bytes into screen memory, which would be somewhere in our graphics mode 7.5 area. Because the computer only expects there to be 480 bytes of screen memory in graphics mode one, it will not let you get at the score line. So how do we get around this problem? Locations 88 and 89 point to where the computer thinks screen memory is (there is actually a separate chip called ANTIC that interprets the display list and draws the screen. That's why the computer needs locations 87, 88 and 89). So to print the score, we would change locations 88 and 89 to point to the beginning of the screen memory that the score line uses. Then we can POSITION 0,0 and PRINT #6; "SCORE." Add these lines to our program to see what I mean:


5180 MEM1=PEEK(DLIST+4)+
PEEK[DL15T+5)*256:SCRL=P
EEK(DLIST+56):SCRH=PEEK(
DLIST+57)
5190 POKE 87,1:POKE 88,5
CRL:POKE 89,SCRH:POSITIO
N 0,0:? #6;" SCORE:
0"

    You'll see another example of this next when we draw the barriers.

Display list interrupts
    I know, I know, this section was supposed to be about drawing the barriers. So I lied. But I did mention display list interrupts (DLIs) in the last section, and I promised to explain them; so this will be a relatively quick and painless explanation.
    Everybody says that the DLI is the most powerful feature of Atari computers. I don't know about "most," but it certainly is powerful. DLIs let you change the screen colors partway down the screen or have more than one character set on the screen at the same time. They let you scroll part of the screen in one direction and the other part in another direction. They let you reposition players partway down the screen, so that one player appears to be two, three and more. Anything else they can do is up to your creativity and imagination.
    You already know that a DLI is a modification to a display list instruction. You'll also recall that ANTIC is the chip that is responsible for drawing the screen. Anyway, when ANTIC gets to a display list instruction with a DLI, it first draws that line and then interrupts the 6502 or main chip. The 6502 executes the DLI routine and then goes back to whatever it was doing before the interruption. And that's all there is to a DLI.
    Unfortunately, since the DLI has to do whatever it does in an extremely short amount of time, a DLI routine has to be written in machine language. Luckily though, it's usually very simple machine language. For example, here's a DLI routine to change the color of the screen:

PHA
LSA #212
STA WSYNC
STA COLBK
PLA
RTI

    What this does is save the accumulator value, load the new color value into the accumulator, and then store it into WSYNC at location 54282. When any value is stored into WSYNC, the 6502 refrains from doing anything until the next HBLANK (the time between scan lines). Anyway, then the color value gets stored into the background color register at location 53274, the accumulator is restored to its original value, and we return from the interrupt.
    "But," you may be wondering, "isn't the background color register at location 712?" Actually, only sort of. Location 712 is something called a shadow register, which more or less acts like a messenger to the real color register at location 53274. Does this sound complicated? It is a little. You see, during VBLANK, the value in location 712 is transferred to location 53274. Why? Take another look at the above DLI routine. We'll see it in action a little later on, but for now take my word that it will change the background color, so that part of the screen is one color and the other part is another. Think about this. The DLI changes the color partway down the screen, but how does it know to change it back at the beginning of the next screen? It knows from the shadow register. If it wasn't for the shadow register, you would have to have a DLI at the top of the screen as well. In any case, just remember to change the hardware registers in a DLI, not the shadow registers.
    How does the computer know where the DLI routine is? Locations 512 and 513 hold the address of the DLI routine. So to get a DLI going, you would change the display list, store the routine somewhere safe in memory (somewhere that doesn't shift around, which means you can't store it in a string like other routines), set locations 512 and 513, and then POKE 54286, 192 to turn the DLI on (POKE 54286, 64 will turn it off again). That's all there is to it. Actually, this would be a good time to add our sample routine above to our invaders program and prove to you that it isn't that difficult; so why don't you try adding the following lines to our program:


3100 FOR BYTE=0 TO 10:RE
AD DAT:POKE 1536+BYTE,DA
T:NEXT BYTE
3110 DATA 72,169,212,141
,10,212,141,26,208,104,6
4
5100 POKE DLIST+53,15B:P
OKE 512,0:POKE 513,6:POK
E 54286,192

    Here's an explanation of what you just did:

    3100: This just reads in the data for the routine and stores it in page 6, where it will be safe.

    3110: Here's the data. We'll be taking a closer look at this in a minute, showing you how you can change it for your own use.

    5100: This adds a DLI modification to the display list, sets up the DLI routine address, and turns on the DLI.

    That wasn't too tough now, was it? But, of course, all it does is change the color. What if we wanted more than one DLI? Can we do that? Well, yes, but it starts to get a little more complicated. The problem with having more than one DLI is that we have to update locations 512 and 513 each time we change routines. For example, the first routine would have to update the locations to point to the second routine, the second to point to the third, and so on up to the last routine, which would have to update the locations to point back to the first routine.
    Not too difficult, right? (Assuming you know some machine language.) Right, but this limits what you can do during the DLIs since there is not much time available. Actually you really can't do much more than change a few locations before you run out of time. If you decide to get adventurous and design your own DLIs, and if you try to do a lot of stuff during them, and if the screen looks kind of funny once they're working, then you have probably used up too much time. In other words, don't expect a DLI to do too much. Oh, and DLIs are best suited for making changes to the screen. Save everything else for your regular program.
    Okay, we've now gotten all of the annoying little details out of the way; so let's take a quick look at how you would make changes to the DLI routine I've given you, assuming you want it to do something different. First of all, here's how the numbers in the Line 3110 correspond to the assembly language:


        72  PHA
   169 212  LDA #212
141 10 212  STA NSYNC
141 26 208  STA COLBK
       104  PLA
        64  RTI

    What good does this do you? Well, if you wanted to change to a different color, you could just change the first 212 in Line 3110 to something else. Try it. Also, suppose you wanted to change character sets instead of colors. You would change the first 212 to the page address of the second character set, and then you would change COLBK (26, 208) to CHBASE (9, 212). As you can see, this simple DLI routine can be changed by you in a number of ways to get the specific result you want; so don't be afraid to play. I should warn you, however, to save the program before trying a new DLI. If you did something wrong by mistake, there is a chance that you lock up the machine. If you do, and System Reset doesn't help, just turn the computer off and back on again, and load back the program so you can figure out what went wrong.

Bit-mapping (Part 1)
    This is probably going to be one of the easiest sections in this column, because bitmapping is a relatively simple techniqueat least it is when you're using it for stationary objects, as we are with the barriers. You'll recall that bit-mapping can also be used for simple animation, in which case things can get a little more complicated and also extremely slow. For BASIC games, you're better off only using bitmapping for non-animated objects.
    The first step for bit-mapping is the same as that for character sets and for player/missile graphics, deciding what the object is going to look like. Figure 2 is our barrier shape.





HSC


VSC
HSC
VSC

HSC


VSC
HSC
VSC


HSC


VSC
HSC
VSC

HSC

HSC
VSC

VSC






LMS LMS LMS LMS



LMS LMS LMS LMS










DLI
 
DLI DLI DLI DLI DLI DLI DLI
BLK
1
0







128







BLK 2
16







144







BLK 3
32







160







BLK 4
48







176







BLK 5
64







192







BLK 6
80







208







BLK 7
96







224







BLK 8
112







240







JMP

1







129







JVB

65







193







CHR
2
2
18
34
50
66
82
98
114
130
146
162
178
194
210
226
242
CHR 3
3
19
35
51
67
83
99
115
131
147
163
179
195
211
227
243
CHR 4
4
20
36
52
68
84
100
116
132
148
164
180
196
212
228
244
CHR 5
5
21
37
53
69
85
101
117
133
149
165
181
197
213
229
245
CHR 6
6
22
38
54
70
86
102
118
134
150
166
182
198
214
23
246
CHR 7
7
23
39
55
71
87
103
119
135
151
167
183
199
215
231
247
MAP
8
8
24
40
56
72
88
104
120
136
152
168
184
200
216
232
248
MAp 9
9
25
41
57
73
89
105
121
137
153
169
185
201
217
233
249
MAP 10
10
26
42
58
74
90
106
122
138
154
170
186
202
218
234
250
MAP 11
11
27
43
59
75
91
107
123
139
155
171
187
203
219
235
251
MAP 12
12
28
44
60
76
92
108
124
140
156
172
188
204
220
236
252
MAP 13 
13
29
45
61
77
93
109
125
141
157
173
189
205
221
237
253
MAP 14
14
30
46
62
78
94
110
126
142
158
174
190
206
222
238
254
MAP 15
15
31
47
63
79
95
111
127
143
159
175
191
207
223
239
255
FIGURE 2

Drawing the barriers
    The next question is: How do we draw this quickly and easily? Actually, it should be how do we draw these, since there are supposed to be four barriers, not just one. Well, let's look at the methods available to us. We could PLOT each of the points in the barriers, but that would obviously take too long in this case. We could use PLOT and DRAWTO and draw them line by line. This is better, but let's see what else there is. We could use PLOT, DRAWTO and X10 18 (FILL). This is faster still, but doesn't look quite as neat. Finally, we could store the data for the barriers in a string and then use MOVMEM to transfer this data directly into screen memory. This is by far the quickest method, but we're talking here about 40*24=960 bytes of screen memory, and therefore 960 bytes of string space. Keeping memory requirements down is important, so we'll stay away from this method. What's our final decision then? Well, it comes down to PLOT and DRAW TO or PLOT and DRAWTO with FILL. I'd like to try for a technique that gives the effect of building the barriers, so, as I explained earlier, I personally want to use the visual effect that PLOT and DRAWTO give. There's no reason, however, why FILL could not be added if that's your own personal preference.
    Our next step is to figure out the easiest way to use our chosen technique. We're obviously going to want to use some FOR/NEXT loops, since there is a lot of repetition in the barrier shape (and there are also four identical barriers). Let's break the barrier up into groups of horizontal rectangles, since a PLOT and DRAWTO FOR/NEXT loop is good for drawing rectangles. Figure 3 shows our barrier shape broken up this way.
    Now we have what we need to start programming. What we'll do is set up three nested FOR/NEXT loops. The outside loop will count off the ten rectangles, the next will count off the horizontal lines in each rectangle, and the inside loop will count off the four barriers. We'll store the vital information about each rectangle in a DATA statement so that the loops can get to it easily.
    If I told you right now to try and write the loops I described by yourself, how could you do it? Would you jump right in and start work on the first loop? If you would, then you forgot all about what we discussed at the end of the previous section. (Don't feel too badly, I'm writing this paragraph because I forgot also!) Now do you remember? Because we're using a custom display list, we have to tell the computer where our screen memory is and what mode we're using. The following line will do that for us:


5210 POKE 87,7:POKE 89,I
NT(MEM7/256):POKE 88,MEM
7-PEEK(89)*256:COLOR 3


    Remember that location 87 tells the computer the BASIC mode number, and locations 88 and 89 tell it the location of screen memory. If you're using a graphics mode that doesn't have a BASIC equivalent (as we are here), then choose the BASIC mode that is closest to it.
    Okay, with that out of the way, we can now go ahead and write our loops. Here are the lines to add to our program:


5210 POKE 87,7:POKE 89,I
NT(MEM7/256):POKE 88,MEM
7-PEEK(89)*256:COLOR 3
5230 RESTORE 5260
5240 FOR X=1 TO 10:READ
N,XS,Y,XE:FOR T=N-1 TO 0
 STEP -1:FOR Z=0 TO 3:PL
OT Z*40+9+XS,Y+T:DRAWTO
Z*40+9+XE,Y+T
5250 NEXT Z:NEXT T:NEXT
X
5260 DATA 4,16,28,20,4,1
,20,5,2,15,18,20,2,1,18,
6,2,14,16,20,2,1,16,7,10
,1,6,20,2,2,4,19,2,3,2,1
8,2,4,8,17


    And, of course, the explanation:

    5230: Any time you have a program with more than one set of DATA statements, it's a good idea to RESTORE the first line of the DATA you want to use. Why? When BASIC encounters a READ statement, it will look for the DATA that comes after whatever it read last. It will not look for the DATA closest to the READ statement. So, since you'll be reading data out of order often, the RESTORE becomes a necessity.

    5420-5250: This is our loop. X keeps track of which rectangle we're drawing. N is the number of lines in the current rectangle, XS is the starting X position for the rectangle, Y is the starting Y position, and XE is the ending X position. T keeps track of which line we're drawing within the current rectangle, and Z keeps track of which barrier we're working on. Keeping all this in mind, you should be able to figue out what's going on here.

    5260: This is the data for the rectangles. There are four numbers for each rectangle (N, XS, Y and XE), the meanings for which were discussed above.

    Well, that's about it. (I told you this was easy.) Incidentally, just in case you decide that you prefer to use FILL, here's a brief introduction to using X10 18:

    1. PLOT a point at the lower left-hand corner of your object.
    2. DRAWTO the upper right-hand corner.
    3. DRAWTO the upper left-hand corner.
    4. POSITION the cursor at the lower righthand corner.
    5. POKE location 765 with the number of the color register you want to FILL with. (This number is the same as that you would use with the color command.)
    6. Now do X10 18,#6,0,0,"S:".

    There is one problem with FILL; the area that you're FILLing has to be empty. If there are any points already turned on within the area, FILL won't work correctly.