A.N.A.L.O.G. ISSUE 10 / MARCH 1983 / PAGE 73

MOVING PLAYERS IN BASIC

16K cassette or disk

by Tom Hudson

Just before issue #9 of A.N.A.L.O.G. went to press, I was handed a letter from Long Mai of Salt Lake City, Utah (see the Reader Comment section of this issue). Like many BASIC programmers, he was frustrated by BASIC’s snail-like pace, and asked for a machine-language subroutine that could be used with BASIC to move player-missile graphics around on the screen.

Unfortunately, it was too late to write such an article for issue #9, but here it is, along with fully documented assembly-language code.

THE PROBLEM

Player-missile graphics are one of the most powerful graphic features of the ATARI 400/800 computer systems. Unlike traditional graphics, players and missiles can be moved around on the screen without disturbing the existing display. In order to use players and missiles, one must first reserve a portion of memory. Once this is done, the user can begin designing and displaying the players and missiles.

The problems begin when the user wants to move a player or missile around on the screen. Horizontal movement is done easily. A POKE to the appropriate horizontal position memory location will move the desired player to any horizontal location on the screen. If the user wants to move a player or missile vertically, he or she must copy the P/M bit image to another location in memory. BASIC is too slow to do this, but it can call a machine-language subroutine to do the “dirty work.”

THE PROGRAM

The BASIC program listed here will allow the user to move any player around on the screen. It calls the P/M movement subroutine, shown in the Assembly language listing.

As listed, the program will move a shape around on the screen at random. The shape of the player is stored as a series of bytes in the string “P0$”. By altering the data in line 420, you can change the shape that appears on the screen. There are currently 7 bytes in line 420, but this can be changed by altering lines 130, 290 and 420.

Lines 110-180 set up the subroutine and turn on the P/M graphics. Lines 220-310 are for demonstration purposes only. You can put your program code in this section.

Line 110 – Loads the string PMMOV$ with the P/M movement subroutine.

Line 130 – Places the data that defines the graphics shape into the string P0$.

Line 140 – Tell the system where the P/M memory starts.

Line 150 – Saves the P/M base address.

Line 160 – Saves the graphics data string address.

Line 170 – Turns on P/M direct memory access.

Line 180 – Sets the color of player to light blue.

Line 220 – Initialize the X and Y coordinates of the player.

Line 230-280 – Alter the X and Y coordinates to move the player.

Line 290 – This USR call moves the player to the desired X and Y location. This statement has 7 parameters inside the USR parentheses:

A=USR(MOVE,0,PMB,PMD,X,Y,7)

“MOVE” is set up in line 110. Do not change this variable. It is the address of the P/M mover subroutine.

“0” means that we want to move player zero. This value can range from 0 to 3, moving players through 3.

“PMB” is the P/M base address. Do not change this value.

“PMD” is the address of the string that holds the player image data. This should be set to the address of the string you are using to hold your player shape data. If your player shape data is in a string called “PL$,” you could replace “PMD” with “ADR(PL$)”.

An “X” and “Y” are the horizontal and vertical coordinates when you want to place your player. X ranges from 0-255, and Y ranges from 0-127. “7” in this case indicates that our player is 7 bytes long (see line 130 and the player image data in line 420). If your player is 10 bytes long, place a “10” here.

SUMMARY

This program should help out anyone who wants to use player-missile graphics from BASIC. If there are any questions, write me care of A.N.A.L.O.G. (please include a pre-addressed, stamped envelope). If there is a specific application you would like to see appear in a future issue, just ask. You never know — there may be hundreds of other readers who would like the same information.

Listing 1

10 REM *****************************
20 REM * P/M MOVER SUBROUTINE DEMO *
30 REM *                           *
40 REM *       BY TOM HUDSON       *
50 REM *                           *
60 REM *  A.N.A.L.O.G. COMPUTING   *
70 REM *****************************
80 REM 
90 REM *********** SETUP ***********
100 REM 
110 DIM PMMOV$(100),P0$(30):MOVE=ADR(PMMOV$):FOR X=1 TO 100:READ N:PMMOV$(X)=CHR$(N):NEXT X:REM *READ ML DATA*
120 REM *** NOW READ SHAPE DATA ***
130 FOR X=1 TO 7:READ N:P0$(X)=CHR$(N):NEXT X
140 PMBASE=INT((PEEK(145)+3)/4)*4:POKE 54279,PMBASE:REM *** SET UP P/M AREA ***
150 PMB=PMBASE*256
160 PMD=ADR(P0$):REM *** P/M DATA ADDRESS ***
170 POKE 559,46:POKE 53277,3:REM *** P/M DMA ***
180 POKE 704,136:REM *** PLAYER 0 COLOR ***
190 REM 
200 REM **** YOUR PROGRAM HERE! ****
210 REM 
220 X=128:Y=64
230 XI=1-INT(RND(0)*3):YI=1-INT(RND(0)*3)
240 X=X+XI:Y=Y+YI
250 IF X<50 THEN X=50:GOTO 270
260 IF X>190 THEN X=190
270 IF Y<20 THEN Y=20:GOTO 290
280 IF Y>110 THEN Y=110
290 A=USR(MOVE,0,PMB,PMD,X,Y,7)
300 IF RND(0)>0.95 THEN 230
310 GOTO 240
320 REM 
330 REM *** PM MOVER DATA ***
340 REM 
350 DATA 216,104,104,104,133,213,104,24,105,2,133,206,104,133,205,104,133,204,104,133,203,104,104,133,208
360 DATA 104,104,133,209,104,104,24,101,209,133,207,166,213,240,16,165,205,24,105,128,133,205,165,206,105
370 DATA 0,133,206,202,208,240,160,0,162,0,196,209,144,19,196,207,176,15,132,212,138,168,177,203,164
380 DATA 212,145,205,232,169,0,240,4,169,0,145,205,200,192,128,208,224,166,213,165,208,157,0,208,96
390 REM 
400 REM *** PLAYER IMAGE DATA ***
410 REM 
420 DATA 255,129,129,231,129,129,255

(see D:CHECK 2, p. 26)

10 DATA 532,930,996,64,0,483,544,265,989,74,765,328,743,901,536,8870
160 DATA 729,778,445,101,552,79,854,968,479,928,983,921,954,424,374,9561
310 DATA 704,84,588,90,639,732,435,188,185,191,83,56,3887

Assembly Language Listing

;
;PLAYER-MISSILE MOVER SUBROUTINE
;
;BY TOM HUDSON
;A.N.A.L.O.G. COMPUTING #10
;

;
;PAGE ZERO USAGE
;

PMSTR	=	$CB	;P/M BASIC STRING
PLADR	=	$CD	;PLAYER ADDRESS
PMEND	=	$CF	;PLAYER IMAGE END
XPOS	=	$D0	;X POSITION
YPOS	=	$D1	;Y POSITION
HOLD	=	$D4	;HOLD AREA
PLNUM	=	$D5	;PLAYER # TO MOVE

;
;OPERATING SYSTEM EQUATES
;

HPOSP0	=	$D000

;
;PROGRAM STARTS HERE!
;

	ORG	$6000	;ANY ADDRESS

START	CLD		;CLEAR DECIMAL MODE
	PLA		;DISCARD
	PLA		;DISCARD # HI
	PLA		;PULL PLAYER # LO
	STA	PLNUM	;AND SAVE IT!
	PLA		;PULL P/M BASE HI
	CLC		;ADD OFFSET TO GET
	ADC	#2	;PLAYER MEMORY ADDR
	STA	PLADR+1	;AND SAVE!
	PLA		;PULL P/M BASE LO
	STA	PLADR	;AND SAVE!
	PLA		;PULL STRING HI
	STA	PMSTR+1	;AND SAVE!
	PLA		;PULL STRING LO
	STA	PMSTR	;AND SAVE!
	PLA		;DISCARD X HI
	PLA		;PULL X LO
	STA	XPOS	;AND SAVE IT!
	PLA		;DISCARD Y HI
	PLA		;PULL Y LO
	STA	YPOS	;AND SAVE IT!
	PLA		;DISCARD LENGTH HI
	PLA		;PULL LENGTH LO
	CLC		;ADD Y POSITION
	ADC	YPOS	;TO GET END 
	STA	PMEND	;AND SAVE IT!
	LDX	PLNUM	;GET PLAYER#
	BEQ	ENDCAL	;NO INDEX NEEDED!
PLCALC	LDA	PLADR	;ADD 128 TO
	CLC		;PLAYER
	ADC	#128	;ADDRESS
	STA	PLADR	;TO
	LDA	PLADR+1	;POINT TO
	ADC	#0	;NEXT
	STA	PLADR+1	;PLAYER.
	DEX		;ANOTHER ADJUSTMENT?
	BNE	PLCALC	;YES!
ENDCAL	LDY	#0	;ZERO P/M COUNT
	LDX	#0	;ZERO STRING COUNT
COPYLP	CPY	YPOS	;COPYING DATA YET?
	BCC	ZERO	;NO!
	CPY	PMEND	;FINISHED COPYING?
	BCS	ZERO	;YES!
	STY	HOLD	;SAVE Y REG
	TXA		;MOVE X REG...
	TAY		;TO Y REGISTER
	LDA	(PMSTR),Y	;GET P/M BYTE
	LDY	HOLD	;GET P/M OFFSET
	STA (PLADR),Y	;CHANGE PLAYER!
	INX		;NEXT STRING BYTE.
	LDA	#0	;FORCE BRANCH
	BEQ	NEXT	;TO NEXT BYTE!
ZERO	LDA	#0	;ZERO OUT...
	STA	(PLADR),Y	;PLAYER BYTE!
NEXT	INY		;NEXT P/M BYTE
	CPY	#128	;DONE W/COPY?
	BNE	COPYLP	;NOT DONE YET!
	LDX	PLNUM	;GET PLAYER #
	LDA	XPOS	;NOW JUST SET
	STA	HPOSP0,X	;X LOCATION!
	RTS		;FINIS!

	.END
A.N.A.L.O.G. ISSUE 11 / MAY 1983 / PAGE 29

MOVING MISSILES IN BASIC

16K Cassette or Disk

by Tom Hudson

Last issue, I presented a machine-language subroutine which enabled BASIC programmers to move players around on the screen quickly. Shortly after the issue was sent to readers, I received a letter from Jeff Stefanski (see the Reader Comment section of this issue). Jeff asked for a modification to allow the subroutine to move missiles as well.

Rather than modify the existing player movement subroutine, I decided to write a new, stand-alone missile movement subroutine. It can be used by itself if only missiles are desired, or can be used in conjunction with the player mover from A.N.A.L.O.G. #10 if both players and missiles are needed.

Following this article are two listings. The first is a BASIC program which demonstrates the use of the missile movement subroutine. The second listing is the fully documented assembler source code for the subroutine.

What Are Missiles?

Hidden deep inside each ATARI computer is a mysterious graphics ability known as player-missile graphics. These graphics work with any graphics mode, and can be moved around on the screen without disturbing any other graphics.

Why are these graphics called players and missiles? PLAYERS are eight pixels (picture elements) wide and therefore can be used to create fairly detailed images, such as spaceships, cars, or other animated figures representing the player. MISSILES, on the other hand, are only TWO pixels wide. They were designed to be used as simple projectiles, because of their limited resolution.

The Demonstration Program

Enter Listing 1 into your computer. Before running it, be sure to SAVE it, as a mistake in typing the assembly-language code could “lock-up” your computer, making it necessary to re-enter the program. When RUN, this program will place the numbers 1-4 on the screen using the four missiles and move them around randomly. Let’s walk through the program and see what each line does.

Line 200 – This line loads the machine-language missile movement subroutine into a string called “MISMOV$.” This subroutine will be called whenever we want to move a missile on the screen.

Line 240 – This line sets up four string variables, M0$ through M3$. These strings will hold missile shape data. These strings are currently set up as 6 bytes long, which limits the missile graphics images to 6 pixels in height. You can change this length to up to 128 bytes, making the missile image 128 pixels high.

Lines 250-280 – These lines READ the DATA in lines 690-750 into the missile shape strings set up in line 240. Once again, note that each line reads 6 bytes into the appropriate string. To make missile images of different height, change the 6 to the desired value.

Lines 290-320 – These lines set up the player-missile area in memory and activate them. Line 320 sets the player-missile priority to 1. This causes the players and missiles to appear “in front” of other graphics. These lines should not be changed.

Lines 330-360 – Since there is no SETCOLOR command for player-missile graphics, we must POKE the appropriate color values into the P/M color registers. To get the color number, use the formula:

COLOR POKE VALUE = (COLOR NUMBER *16)
                 + BRIGHTNESS

Line 370 – Sets the background color to black.

Line 410 – Dimensions two arrays, X and Y. These arrays will be used to hold the X and Y coordinates of each missile.

Line 420 – This line initializes all the missiles’ X coordinates to 128 and the Y coordinates to 64. These coordinates will place the missiles at the center of the screen.

Line 430 – This line starts a FOR-NEXT loop which will process each missile, from missile to missile 3.

Lines 440-490 – These lines randomly change the X and Y coordinates of the missiles, which will make them wander around on the screen.

Line 500 – Depending on the missile number (I) this line transfers control to the appropriate USR statement in order to move the desired missile.

Lines 510-540 – These lines send the X and Y coordinate information to the missile movement subroutine. Line 510 moves missile 0, 520 moves missile 1, etc. Let’s look at line 510:

A=USR(MISL,0,PMB,ADR(M0$),X(0),Y(0),6):GOTO 550

This statement has 7 parameters inside the USR parentheses.

“MISL” is set up in line 200. Do not change this variable. It is the address of the missile mover subroutine.

“0” means we want to move missile zero. Note that line 520 has a “1” here, since it moves missile 1. This value can range from 0 to 3, and will move the appropriate missile.

“PMB” is the player-missile base address, which was calculated in line 300. Do not change this variable.

“ADR(M0$)” tells the missile mover where to get the missile image data. In this case, we want the subroutine to use the information in the string variable M0$. Try changing this to “ADR(M1$)” and RUN the program. You will see two “2’s” moving on the screen. This is because the string Ml$ contains the data for the number 2, and it is now used in both missile and missile 1.

X(0) is the X coordinate where we want to place missile 0. You can place any number or variable here, ranging from 0-255.

Y(0) is the Y coordinate where we want to place missile 0. You can place any number or variable here, ranging from 0-127.

“6” tells the subroutine how many bytes are used for the player image. In this case our missiles are 6 bytes long (see lines 240, 250, and 690). If you want a different number of bytes (resulting in a different missile height), change these lines accordingly.

Line 550 – This line completes the FOR-NEXT loop set up in line 430.

Line 560 – This line passes control to line 430, causing the program to loop forever, moving the missiles randomly until you press the BREAK key.

Lines 600-640 – These lines contain the DATA for the missile mover routine. Do not change these values.

Line 690 – DATA for M0$, the number “1.”

Line 710 – DATA for Ml$, the number “2.”

Line 730 – DATA for M2$, the number “3.”

Line 750 – DATA for M3$, the number “4.”

Creating Your Own Missile Images

Now, that we have walked through the program and studied what each line does, let’s design our own missile image. Since we’re limited to 2 pixels in width, the image will have to be very simple. Of course, it can be any height up to 128 pixels.

The numbers that the demonstration program moved around on the screen are very simple. Figure 1 shows how the number 2 was turned into DATA in line 710.

      2+1 =3
        1 =1
      2+1 =3
      2   =2
      2   =2
      2+1 =3
Figure 1

The shape we will make is shown in Figure 2.

        1 =1
        1 =1
      2+1 =3
          =0
      2+1 =3
          =0
      2+1 =3
      2   =2
      2   =2
Figure 2

Now let’s put our shape into demonstration program. We’ll use missile number to show the image, so replace line 690 with the following:

690 DATA 1,1,3,0,3,0,3,2,2
This missile image is 9 bytes long, so it will be necessary to change lines 240, 250 and 510 as follows:
240 DIM M0$(9),M1$(6),M2$(6),M3$(6)
250 FOR I=1 TO 9:READ N:M0$(I)=CHR$(N):NEXT I:REM *** MISSILE 0 ***
510 A=USR(MISL,0,PMB,ADR(M0$),X(0),Y(0),9):GOTO 550

After the program is changed, RUN it. You will see the numbers 2,3, and 4 on the screen, along with the shape we just defined. It’s that simple!

Summary

Using players and missiles in BASIC can be very fast and easy when a machine-language subroutine is used to perform time-consuming operations. This demonstration program may be used as a framework for more complex programs. Simply replace lines 410-560 with your own program code, and you’re all set to begin exploring the wonders of player-missile graphics!

If you have any questions or suggestions about this article write me care of A.N.A.L.O.G. Be sure to include a pre-addressed, stamped envelope if you would like a reply.

Listing 1

100 REM *****************************
110 REM *  MISSILE SUBROUTINE DEMO  *
120 REM *                           *
130 REM *       BY TOM HUDSON       *
140 REM *                           *
150 REM *  A.N.A.L.O.G. COMPUTING   *
160 REM *****************************
170 REM 
180 REM *********** SETUP ***********
190 REM 
200 DIM MISMOV$(114):MISL=ADR(MISMOV$):FOR X=1 TO 114:READ N:MISMOV$(X)=CHR$(N):NEXT X:REM *READ ML DATA*
210 REM 
220 REM *** LOAD MISSILE IMAGES ***
230 REM 
240 DIM M0$(6),M1$(6),M2$(6),M3$(6)
250 FOR I=1 TO 6:READ N:M0$(I)=CHR$(N):NEXT I:REM *** MISSILE 0 ***
260 FOR I=1 TO 6:READ N:M1$(I)=CHR$(N):NEXT I:REM *** MISSILE 1 ***
270 FOR I=1 TO 6:READ N:M2$(I)=CHR$(N):NEXT I:REM *** MISSILE 2 ***
280 FOR I=1 TO 6:READ N:M3$(I)=CHR$(N):NEXT I:REM *** MISSILE 3 ***
290 PMBASE=INT((PEEK(145)+3)/4)*4:POKE 54279,PMBASE:REM *** SET UP P/M AREA ***
300 PMB=PMBASE*256
310 POKE 559,46:POKE 53277,3:REM *** P/M DMA ***
320 POKE 623,1:REM *** P/M PRIORITY ***
330 POKE 704,134:REM *** P/M 0 COLOR ***
340 POKE 705,136:REM *** P/M 1 COLOR ***
350 POKE 706,138:REM *** P/M 2 COLOR ***
360 POKE 707,142:REM *** P/M 3 COLOR ***
370 SETCOLOR 2,0,0:REM *** BACKGROUND IS BLACK ***
380 REM 
390 REM **** YOUR PROGRAM HERE! ****
400 REM 
410 DIM X(3),Y(3)
420 FOR I=0 TO 3:X(I)=128:Y(I)=64:NEXT I
430 FOR I=0 TO 3
440 XI=2-INT(RND(0)*5):YI=2-INT(RND(0)*5)
450 X(I)=X(I)+XI:Y(I)=Y(I)+YI
460 IF X(I)<50 THEN X(I)=50:GOTO 480
470 IF X(I)>190 THEN X(I)=190
480 IF Y(I)<20 THEN Y(I)=20:GOTO 500
490 IF Y(I)>110 THEN Y(I)=110
500 ON I+1 GOTO 510,520,530,540
510 A=USR(MISL,0,PMB,ADR(M0$),X(0),Y(0),6):GOTO 550
520 A=USR(MISL,1,PMB,ADR(M1$),X(1),Y(1),6):GOTO 550
530 A=USR(MISL,2,PMB,ADR(M2$),X(2),Y(2),6):GOTO 550
540 A=USR(MISL,3,PMB,ADR(M3$),X(3),Y(3),6)
550 NEXT I
560 GOTO 430
570 REM 
580 REM *** MISSILE MOVER DATA ***
590 REM 
600 DATA 216,104,104,104,133,213,104,133,206,104,24,105,128,133,205,165,206,105,1,133,206,104,133,204,104
610 DATA 133,203,104,104,133,208,104,104,133,209,104,104,24,101,209,133,207,160,0,162,0,134,212,169,252
620 DATA 166,213,240,7,10,10,9,3,202,208,249,166,212,49,205,145,205,196,209,144,30,196,207,176,26
630 DATA 132,212,138,168,177,203,164,213,240,5,10,10,136,208,251,164,212,17,205,145,205,232,169,0,240
640 DATA 0,200,192,128,208,196,166,213,165,208,157,4,208,96
650 REM 
660 REM *** MISSILE IMAGE DATA ***
670 REM 
680 REM "1"
690 DATA 1,1,1,1,1,1
700 REM "2"
710 DATA 3,1,3,2,2,3
720 REM "3"
730 DATA 3,1,3,1,1,3
740 REM "4"
750 DATA 1,3,3,1,1,1

CHECKSUM DATA
(See D:CHECK/C:CHECK,p.26)

100 DATA 778,122,244,236,250,743,796,95,82,101,420,79,336,85,653,5020
250 DATA 303,310,317,324,918,525,764,956,925,934,943,937,145,102,581,8984
400 DATA 80,27,287,293,985,719,583,574,556,545,765,333,343,353,205,6648
550 DATA 751,724,103,504,109,674,637,146,251,237,99.405,105,342,282,5369
700 DATA 322,279,330,282,338,280,1831

Assembly Language Listing

;	--------------------------
;	MISSILE MOVER SUBROUTINE
;	--------------------------

;	--------------------------
;	BY TOM HUDSON
;	A.N.A.L.O.G. COMPUTING #11
;	--------------------------

;	--------------------------
;	PAGE ZERO USAGE
;	--------------------------

PMSTR	=	$CB	;P/M BASIC STRING
MADR	=	$CD	;MISSILE ADDRESS
PMEND	=	$CF	;MISSILE IMAGE END
XPOS	=	$D0	;X POSITION
YPOS	=	$D1	;Y POSITION
HOLD	=	$D4	;HOLD AREA
MNUM	=	$D5	;MISSILE # TO MOVE

;	------------------------
;	OPERATING SYSTEM EQUATES
;	------------------------

HPOSM0	=	$D004

;	------------------------
;	SUBROUTINE STARTS HERE!
;	------------------------

	ORG	$6000	;ANY ADDRESS

START	CLD		;CLEAR DECIMAL MODE
	PLA		;DISCARD
	PLA		;DISCARD # HI
	PLA		;PULL MISSILE # LO
	STA	MNUM	;AND SAVE IT!
	PLA		;PULL P/M BASE HI
	STA	MADR+1	;AND SAVE!
	PLA		;PULL P/M BASE LO
	CLC		;OFFSET INTO
	ADC	#128	;MISSILE AREA
	STA	MADR	;AND SAVE!
	LDA	MADR+1	;OFFSET MISSILE
	ADC	#1	;ADDR HI
	STA	MADR+1	
	PLA		;PULL STRING HI
	STA	PMSTR+1	;AND SAVE!
	PLA		;PULL STRING LO
	STA	PMSTR	;AND SAVE!
	PLA		;DISCARD X HI
	PLA		;PULL X LO
	STA	XPOS	;AND SAVE IT!
	PLA		;DISCARD Y HI
	PLA		;PULL Y LO
	STA	YPOS	;AND SAVE IT!
	PLA		;DISCARD LENGTH HI
	PLA		;PULL LENGTH LO
	CLC		;ADD Y POSITION
	ADC	YPOS	;TO GET END 
	STA	PMEND	;AND SAVE IT!
	LDY	#0	;ZERO P/M COUNT
	LDX	#0	;ZERO STRING COUNT
COPYLP	STX	HOLD	;SAVE X REG
	LDA	#$FC	;SET HIGH 6 BITS
	LDX	MNUM	;GET MISSILE #
	BEQ	ZEROIT	;IF 0, DON'T SHIFT
ZERSHF	ASL	A	;SHIFT LEFT...
	ASL	A	;TWO BITS
	ORA	#3	;SET LOWER 2 BITS
	DEX		;DONE SHIFTING?
	BNE	ZERSHF	;NO!
ZEROIT	LDX	HOLD	;RESTORE X REG
	AND	(MADR),Y	;ZERO OUT...
	STA	(MADR),Y	;MISSILE BYTE!
	CPY	YPOS	;COPYING DATA YET?
	BCC	NEXT	;NO!
	CPY	PMEND	;FINISHED COPYING?
	BCS	NEXT	;YES!
	STY	HOLD	;SAVE Y REG
	TXA		;MOVE X REG...
	TAY		;TO Y REGISTER
	LDA	(PMSTR),Y	;GET P/M BYTE
	LDY	MNUM	;SHIFT BIT IMAGE
	BEQ	ENDBS	;IF NOT MISSILE 0
BYTSHF	ASL	A	;SHIFT LEFT...
	ASL	A	;2 BITS
	DEY		;MORE TO SHIFT?
	BNE	BYTSHF	;YES!
ENDBS	LDY	HOLD	;GET P/M OFFSET
	ORA	(MADR),Y	;'OR' BITS
	STA (MADR),Y	;CHANGE MISSILE!
	INX		;NEXT STRING BYTE.
	LDA	#0	;FORCE BRANCH
	BEQ	NEXT	;TO NEXT BYTE!
NEXT	INY		;NEXT P/M BYTE
	CPY	#128	;DONE W/COPY?
	BNE	COPYLP	;NOT DONE YET!
	LDX	MNUM	;GET MISSILE #
	LDA	XPOS	;NOW JUST SET
	STA	HPOSM0,X	;X LOCATION!
	RTS		;FINIS!

	.END