# SUBPROGRAMS

## Recommended Posts

Since I am both not understanding and misunderstanding Subprograms, I thought I would run some tests to find out what passing a variable is and how it works. (In the program I've been writing the variables never pass, and I'm not even sure when they need to be passed or left alone) Probably another 10 tests to do after this, but here's something. In some of the looped RUNS of the subprogram testing program I only wrote down the first results, because the other results were expected, and I took screenshots of all 10 runs. Just lazy to write all that down.

These tests may seem silly, or not even make sense, but it is just an attempt to understand.

```RUN 1
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
70 DISPLAY AT(6,12):"CALLING SUBPROGRAM..."
80 CALL TEST
85 GOTO 85
90 SUB TEST
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2 SUBPROGRAM= X=0 Y= 0 Z=0 X+Y=0
RUN 2
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
70 DISPLAY AT(6,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
85 GOTO 85
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5
RUN 3
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
70 DISPLAY AT(6,12):"CALLING SUBPROGRAM..."
80 CALL TEST(A,B)
85 GOTO 85
90 SUB TEST(A,B)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2 SUBPROGRAM= X=0 Y= 0 Z=0 X+Y=0
RUN 4
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
70 DISPLAY AT(6,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
85 GOTO 85
90 SUB TEST(A,B)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RUN 5 & 6
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
25 FOR I=1 TO 3
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
70 DISPLAY AT(6,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
83 X=4 :: Y=6
84 DISPLAY AT(23,1):"PRESS A LETTER"
85 ACCEPT AT(24,1):L\$
86 NEXT I
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
5 RESULTS- MAIN= X=3 Y=2 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5
6 RESULTS- MAIN= X=4 Y=6 SUBPROGRAM= X=4 Y= 6 Z=10 X+Y=10
RUN 7
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5
25 FOR I=1 TO 3
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
65 DISPLAY AT(5,12):"X+Y= ";Z
70 DISPLAY AT(9,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
83 X=4 :: Y=6
84 DISPLAY AT(23,1):"PRESS A LETTER"
85 ACCEPT AT(24,1):L\$
86 NEXT I
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2 X+Y=0 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5
RUN 8
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5 :: Z=0
25 FOR I=1 TO 3
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
65 DISPLAY AT(5,12):"X+Y= ";Z
70 DISPLAY AT(9,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
83 X=4 :: Y=6
84 DISPLAY AT(23,1):"PRESS A LETTER"
85 ACCEPT AT(24,1):L\$
86 NEXT I
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2  X+Y=0 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5
RUN 9
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5 :: Z=0
25 FOR I=1 TO 3
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
63 Z=X+Y
65 DISPLAY AT(5,12):"X+Y= ";Z
70 DISPLAY AT(9,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
83 X=4 :: Y=6
84 DISPLAY AT(23,1):"PRESS A LETTER"
85 ACCEPT AT(24,1):L\$
86 NEXT I
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2  X+Y=5 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5
RUN 10
10 !SUBTEST
20 X=3 :: Y=2 :: A=4 :: B=5 :: Z=0
25 FOR I=1 TO 3
30 CALL SCREEN(4) :: CALL CLEAR
40 DISPLAY AT(2,:"MAIN PROGRAM"
50 DISPLAY AT(3,:"------------"
60 DISPLAY AT(4,12):"X= ";X;"Y= ";Y
63 Z=X+Y+1
65 DISPLAY AT(5,12):"X+Y= ";Z
70 DISPLAY AT(9,12):"CALLING SUBPROGRAM..."
80 CALL TEST(X,Y)
83 X=4 :: Y=6
84 DISPLAY AT(23,1):"PRESS A LETTER"
85 ACCEPT AT(24,1):L\$
86 NEXT I
90 SUB TEST(X,Y)
100 Z=X+Y
110 DISPLAY AT(15,:"SUBPROGRAM"
120 DISPLAY AT(16,:"----------"
130 DISPLAY AT(17,12):"X= ";X;"Y= ";Y
140 DISPLAY AT(19,12):"Z= ";Z
150 DISPLAY AT(21,12):"X+Y= ";Z
160 SUBEND
RESULTS- MAIN= X=3 Y=2  X+Y=6 SUBPROGRAM= X=3 Y= 2 Z=5 X+Y=5

```

Edited by orion1052003

Nice.

##### Share on other sites

Since I am both not understanding and misunderstanding Subprograms, I thought I would run some tests to find out what passing a variable is and how it works. (In the program I've been writing the variables never pass, and I'm not even sure when they need to be passed or left alone) Probably another 10 tests to do after this, but here's something. In some of the looped RUNS of the subprogram testing program I only wrote down the first results, because the other results were expected, and I took screenshots of all 10 runs. Just lazy to write all that down.

These tests may seem silly, or not even make sense, but it is just an attempt to understand.

That is certainly a good way to learn.

The major detail to remember with subprograms in TI Extended Basic is that variables are local, i.e., the names of variables have meaning only within program units. Naming a variable "X" in a subprogram does not give it access to a variable named "X" in the main program and, of course, vice versa. The only way to do that is to pass the variables by name in a parameter list, as you discovered in your tests. They do not need to have the same name. In fact, that is part of the confusion. You can use the same names; but, that can visually imply they are the same and lead to confusion. I did not peruse your tests enough to see whether you already did this; but, a good way to demonstrate this is to change the order of variables with the same name in your parameter lists as follows:

```100 CALL CLEAR
110 X=10::Y=20
120 PRINT "BEFORE SUB CALL--"
130 PRINT "   X,Y: ";X,Y
140 CALL JUNK(X,Y)
150 PRINT "AFTER SUB CALL--"
160 PRINT "   X,Y: ";X,Y
170 SUB JUNK(Y,X)
180 X=3::Y=300
190 SUBEND
```

You will find after the call to JUNK that X = 300 and Y = 3 because what matters is the order in the parameter list, not the names of the variables. X is first in CALL JUNK(X,Y); but, the first variable in SUB JUNK(Y,X) is JUNK's Y (not the same variable as the main program's Y), i.e., JUNK's Y references the main program's X. This is hard to swallow because the same variable names are in use. It may be a little easier to take if you change the subprogram's variable names to A and B:

```100 CALL CLEAR
110 X=10::Y=20
120 PRINT "BEFORE SUB CALL--"
130 PRINT " X,Y: ";X,Y
140 CALL JUNK(X,Y)
150 PRINT "AFTER SUB CALL--"
160 PRINT " X,Y: ";X,Y
170 SUB JUNK(B,A)
180 A=3::B=300
190 SUBEND
```

You will get exactly the same output.

What you are telling SUB JUNK(B,A) in CALL JUNK(X,Y) is to do to X what it does to B and to do to Y what it does to A simply by the order of the variables in the parameter list.

...lee

##### Share on other sites

I never use sub programs.. Someone sometimes said they were slower and I believed them.

##### Share on other sites

This is a Joystick tester program and a test to see if SUBPROGRAMS will work with it. The CALL COINC works, but the "meteor" will appear over and over in the loop. Which seems to mean you can't use subprograms to call adversaries for the game player. It is at magnification one, so the meteor resembles a small piece of hair.

```100 !TEST PROGRAM-USE CALL LOCATE WITH JOYST
110 P1=15 :: P2=10
120 CALL CLEAR :: CALL SCREEN(6)
130 A\$=RPT\$("F",16) :: CALL CHAR(96,A\$)
140 CALL SPRITE(#1,96,2,89,121)!JOYST DOT
143 S\$=RPT\$("F",16) :: CALL CHAR(104,S\$)
145 CALL SPRITE(#2,104,16,57,223)!STATIONARY DOT
150 DR=100 :: DC=100
160 CALL HCHAR(1,16,104)!UP
170 CALL HCHAR(24,16,112)!DOWN
180 CALL HCHAR(12,3,120)!LEFT
190 CALL HCHAR(12,30,128)!RIGHT
192 M\$="00000000000F10204980A0829041221C0000000000C020A02020204080000000"!METEOR
193 CALL CHAR(128,M\$) :: MDR=193 :: MDC=1
195 CALL SPRITE(#3,128,16,MDR,MDC)!METEOR 1,169,20,-20
200 CALL JOYST(1,X,Y)
210 CALL COLOR(10,P1,P1,11,P1,P1,12,P1,P1,13,P1,P1)
220 R=R-Y/4 :: C=C+X/4
230 DR=DR-Y*4 :: DC=DC+X*4
260 CALL LOCATE(#1,DR,DC)
270 CALL KEY(1,K,S)
280 DISPLAY AT(16,1):"SAME KEY=0 NEW KEY=1 NO KEY PRESS=-1"
290 DISPLAY AT(18,5):"KEY= ";K;"STATUS= ";S
300 DISPLAY AT(20,1):"X= ";X;"Y= ";Y
310 DISPLAY AT(21,1):"R= ";R;"C= ";C
320 DISPLAY AT(22,1):"DR= ";DR;"DC= ";DC
330 IF Y=4 AND X=0 THEN CALL COLOR(10,P2,P2)
340 IF Y=0 AND X=4 THEN CALL COLOR(13,P2,P2)
350 IF Y=-4 AND X=0 THEN CALL COLOR(11,P2,P2)
360 IF Y=0 AND X=-4 THEN CALL COLOR(12,P2,P2)
365 CALL COINC(#1,#2,10,C) :: IF C THEN CALL SOUND(300,-2,10)
368 DISPLAY AT(14,12):"C= ";C
369 CALL METEOR(MDR,MDC)
370 GOTO 200
1071 SUB METEOR(DR,DC)
1072 DR=1 :: DC=169
1075 CALL COINC(#1,#3,10,CO) :: IF CO THEN CALL SOUND(300,-2,10) :: CALL DELSPRITE(#3)
1078 !HOWLONGSHOULDMETEORLAST?
1079 SUBEND
```

##### Share on other sites

Subprograms should work just fine to do your bidding.

I am not sure what you are trying to do with the subprogram. First, statement 193 does not reflect the comment, i.e., no motion. Statement 1072 sets the meteor sprite's coordinates, but does nothing with them. Since sprite #3 (meteor) has no motion and is sitting at row 193 and column 1 (essentially off-screen at the bottom left), the IF in statement 1075 will never be TRUE unless sprite #1 is moved to that location.

...lee

##### Share on other sites

I never use sub programs.. Someone sometimes said they were slower and I believed them.

That may be true, but your code can be MUCH clearer and easier to read with them.

Mark

##### Share on other sites

Here's a nice sprite designer program that I wrote back in about 2006 I think. It uses sub-programs heavily, as a result I think the code itself is quite easy to read.

```40 DATA 120,124,128,132,136,140
50 CALL CLEAR :: CALL MAGNIFY(4):: CALL SCREEN(2):: FOR I=1 TO 14 :: CALL COLOR(I,15,1):: NEXT I :: CALL COLOR(4,5,1)
60 CALL CHAR(92,"F8F0F0F89C0E0703000000000000000000000000000000000000000000000000")
70 A\$="AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55AA55"
80 CALL CHAR(88,"08080006C6191B061D336142444A3400003C6282848A54E05CFC60DED8561400")
90 RESTORE 40 :: FOR I=1 TO 6 :: READ A :: CALL CHAR(A,A\$):: NEXT I
100 CALL CHARPAT(ASC(":"),A\$):: CALL CHAR(ASC("@"),A\$)
110 CALL SPRITE(#2,120,15,16,156):: CALL SPRITE(#3,124,15,16,204)
120 CALL SPRITE(#4,128,15,60,156):: CALL SPRITE(#5,132,15,60,204):: CALL SPRITE(#6,136,15,104,156):: CALL SPRITE(#7,140,15,104,204)
130 CALL CHAR(60,"0000001818000000"):: CALL CHAR(62,"FEFEFEFEFEFEFE00")
140 CX=1 :: CY=2 :: OPTION BASE 1 :: DIM C\$(16,4),C(16,4):: SZ=1
150 CALL INIT(C\$(,),C(,))
160 CALL HELP
170 CALL SPRITE(#1,92,4,(CY*-4,(CX*+14)
180 CALL KEY(0,K,S):: IF K=-1 THEN 180
190 IF K=101 THEN CY=CY-1 :: IF CY<2 THEN CY=17 ELSE GOTO 170
200 IF K=120 THEN CY=CY+1 :: IF CY>17 THEN CY=2 ELSE GOTO 170
210 IF K=115 THEN CX=CX-1 :: IF CX<1 THEN CX=16 ELSE GOTO 170
220 IF K=100 THEN CX=CX+1 :: IF CX>16 THEN CX=1 ELSE GOTO 170
230 IF K=48 THEN CALL POINT(CY-1,CX,C\$(,),C(,))
240 IF K=73 THEN CALL INVERT(C\$(,),C(,))
250 IF K=68 THEN CALL DOWN(C\$(,),C(,))
260 IF K=85 THEN CALL UP(C\$(,),C(,))
270 IF K=76 THEN CALL LEFT(C\$(,),C(,))
280 IF K=50 THEN SZ=SZ XOR 1 :: CALL MAGNIFY(3+SZ)
290 IF K=82 THEN CALL RIGHT(C\$(,),C(,))
300 IF K=72 THEN CALL HFLIP(C\$(,),C(,))
310 IF K=86 THEN CALL VFLIP(C\$(,),C(,))
320 IF K=78 THEN CALL SCRATCH(C\$(,),C(,))
330 IF K=65 THEN CALL ASSIGN(C\$(,),C(,))
340 IF K=71 THEN CALL LOADGRID(C\$(,),C(,))
350 IF K=70 THEN CALL FILEMENU(C\$(,),C(,))
360 IF K=74 THEN CALL LFSPRITE(C\$(,),C(,))
370 IF K=87 THEN CALL ANIMATE(C\$(,),C(,))
380 GOTO 170
390 ! #############
400 SUB INIT(C\$(,),C(,))
410 CALL BUSY :: DISPLAY AT(1,1):"Sprite designer v1.2 M.Wills"
420 CALL NEW(C\$(,),C(,)):: CALL DONE
430 SUBEND
440 ! #############
450 SUB NEW(C\$(,),C(,)):: CALL BUSY
460 FOR Y=1 TO 16 :: FOR X=1 TO 4 :: C\$(Y,X)="<<<<" :: C(Y,X)=0 :: NEXT X :: NEXT Y
470 CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
480 SUBEND
490 ! #############
500 SUB DRAWGRID(C\$(,),C(,)):: CALL BUSY
510 FOR Y=1 TO 16 :: XX=1 :: FOR X=1 TO 4 :: DISPLAY AT(Y+1,XX)SIZE(4):C\$(Y,X):: XX=XX+4 :: NEXT X :: NEXT Y :: CALL DONE
520 SUBEND
530 ! #############
540 SUB POINT(Y,X,C\$(,),C(,))
550 S=INT((X-1)/4)+1 :: P=3-(X-1)AND 3 :: C(Y,S)=C(Y,S)XOR 2^P
560 CALL GETNYBBLE(C(Y,S),N\$):: DISPLAY AT(Y+1,((S-1)*4)+1)SIZE(4):N\$:: C\$(Y,S)=N\$
570 SUBEND
580 ! #############
590 SUB GETNYBBLE(V,N\$)
600 IF V=0 THEN GOSUB 620 ELSE ON V GOSUB 630,640,650,660,670,680,690,700,710,720,730,740,750,760,770
610 SUBEXIT
620 N\$="<<<<" :: RETURN
630 N\$="<<<>" :: RETURN
640 N\$="<<><" :: RETURN
650 N\$="<<>>" :: RETURN
660 N\$="<><<" :: RETURN
670 N\$="<><>" :: RETURN
680 N\$="<>><" :: RETURN
690 N\$="<>>>" :: RETURN
700 N\$="><<<" :: RETURN
710 N\$="><<>" :: RETURN
720 N\$="><><" :: RETURN
730 N\$="><>>" :: RETURN
740 N\$=">><<" :: RETURN
750 N\$=">><>" :: RETURN
760 N\$=">>><" :: RETURN
770 N\$=">>>>" :: RETURN
780 SUBEND
790 ! ################
800 SUB INVERT(C\$(,),C(,)):: CALL BUSY
810 FOR Y=1 TO 16 :: FOR X=1 TO 4 :: C(Y,X)=15-C(Y,X):: CALL GETNYBBLE(C(Y,X),N\$):: C\$(Y,X)=N\$ :: NEXT X :: NEXT Y :: CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
820 SUBEND
830 ! ##############
840 SUB DOWN(C\$(,),C(,))
850 DIM T\$(1,4),T(1,4)
860 CALL BUSY :: FOR X=1 TO 4 :: T\$(1,X)=C\$(16,X):: T(1,X)=C(16,X):: NEXT X
870 FOR Y=16 TO 2 STEP -1 :: FOR X=1 TO 4 :: C\$(Y,X)=C\$(Y-1,X):: C(Y,X)=C(Y-1,X):: NEXT X :: NEXT Y
880 FOR X=1 TO 4 :: C\$(1,X)=T\$(1,X):: C(1,X)=T(1,X):: NEXT X :: CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
890 SUBEND
900 ! #############
910 SUB UP(C\$(,),C(,))
920 DIM T\$(1,4),T(1,4)
930 CALL BUSY :: FOR X=1 TO 4 :: T\$(1,X)=C\$(1,X):: T(1,X)=C(1,X):: NEXT X
940 FOR Y=2 TO 16 :: FOR X=1 TO 4 :: C\$(Y-1,X)=C\$(Y,X):: C(Y-1,X)=C(Y,X):: NEXT X :: NEXT Y
950 FOR X=1 TO 4 :: C\$(16,X)=T\$(1,X):: C(16,X)=T(1,X):: NEXT X :: CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
960 SUBEND
970 ! ##############
980 SUB LEFT(C\$(,),C(,))
990 CALL BUSY
1000 FOR Y=1 TO 16 :: T4=C(Y,4)*2 :: IF T4>15 THEN C4=1 ELSE C4=0
1010 T3=C(Y,3)*2 :: IF T3>15 THEN C3=1 ELSE C3=0
1020 T2=C(Y,2)*2 :: IF T2>15 THEN C2=1 ELSE C2=0
1030 T1=C(Y,1)*2 :: IF T1>15 THEN C1=1 ELSE C1=0
1040 T4=T4 AND 15 :: T3=T3 AND 15 :: T2=T2 AND 15 :: T1=T1 AND 15
1050 C(Y,1)=T1 OR C2 :: C(Y,2)=T2 OR C3 :: C(Y,3)=T3 OR C4 :: C(Y,4)=T4 OR C1
1060 CALL GETNYBBLE(C(Y,1),N\$):: C\$(Y,1)=N\$ :: CALL GETNYBBLE(C(Y,2),N\$):: C\$(Y,2)=N\$ :: CALL GETNYBBLE(C(Y,3),N\$):: C\$(Y,3)=N\$
1070 CALL GETNYBBLE(C(Y,4),N\$):: C\$(Y,4)=N\$ :: NEXT Y
1080 CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
1090 SUBEND
1100 ! ############
1110 SUB RIGHT(C\$(,),C(,)):: CALL BUSY
1120 FOR Y=1 TO 16 :: C1=(C(Y,1)AND 1)*8 :: C2=(C(Y,2)AND 1)*8 :: C3=(C(Y,3)AND 1)*8 :: C4=(C(Y,4)AND 1)*8
1130 T1=INT(C(Y,1)/2):: T2=INT(C(Y,2)/2):: T3=INT(C(Y,3)/2):: T4=INT(C(Y,4)/2)
1140 C(Y,1)=T1 OR C4 :: C(Y,2)=T2 OR C1 :: C(Y,3)=T3 OR C2 :: C(Y,4)=T4 OR C3
1150 CALL GETNYBBLE(C(Y,1),N\$):: C\$(Y,1)=N\$ :: CALL GETNYBBLE(C(Y,2),N\$):: C\$(Y,2)=N\$ :: CALL GETNYBBLE(C(Y,3),N\$):: C\$(Y,3)=N\$
1160 CALL GETNYBBLE(C(Y,4),N\$):: C\$(Y,4)=N\$ :: NEXT Y
1170 CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
1180 SUBEND
1190 ! ##############
1200 SUB HFLIP(C\$(,),C(,)):: CALL BUSY
1210 DIM T\$(16,4),T(16,4):: FOR Y=1 TO 16 :: XX=4 :: FOR X=1 TO 4
1220 IF C(Y,X)=0 THEN T(Y,XX)=0 ELSE ON C(Y,X)GOSUB 1260,1270,1280,1290,1300,1310,1320,1330,1340,1350,1360,1370,1380,1390,1400
1230 XX=XX-1 :: NEXT X :: NEXT Y
1240 FOR Y=1 TO 16 :: FOR X=1 TO 4 :: C(Y,X)=T(Y,X):: CALL GETNYBBLE(C(Y,X),N\$):: C\$(Y,X)=N\$ :: NEXT X :: NEXT Y :: CALL DRAWGRID(C\$(,),C(,))
1250 SUBEXIT
1260 T(Y,XX)=8 :: RETURN
1270 T(Y,XX)=4 :: RETURN
1280 T(Y,XX)=12 :: RETURN
1290 T(Y,XX)=2 :: RETURN
1300 T(Y,XX)=10 :: RETURN
1310 T(Y,XX)=6 :: RETURN
1320 T(Y,XX)=14 :: RETURN
1330 T(Y,XX)=1 :: RETURN
1340 T(Y,XX)=9 :: RETURN
1350 T(Y,XX)=5 :: RETURN
1360 T(Y,XX)=13 :: RETURN
1370 T(Y,XX)=3 :: RETURN
1380 T(Y,XX)=11 :: RETURN
1390 T(Y,XX)=7 :: RETURN
1400 T(Y,XX)=15 :: RETURN
1410 CALL DONE :: SUBEND
1420 ! ##############
1430 SUB VFLIP(C\$(,),C(,)):: CALL BUSY :: DIM T(16,4)
1440 YY=16 :: FOR Y=1 TO 16 :: FOR X=1 TO 4 :: T(YY,X)=C(Y,X):: NEXT X :: YY=YY-1 :: NEXT Y
1450 FOR Y=1 TO 16 :: FOR X=1 TO 4 :: CALL GETNYBBLE(T(Y,X),N\$):: C\$(Y,X)=N\$ :: C(Y,X)=T(Y,X):: NEXT X :: NEXT Y :: CALL DRAWGRID(C\$(,),C(,))
1460 SUBEND
1470 SUB BUSY :: CALL PATTERN(#1,88):: SUBEND
1480 SUB DONE :: CALL PATTERN(#1,140):: SUBEND
1490 SUB HELP
1500 DISPLAY AT(18,1):"[email protected]  [email protected] [email protected]   [email protected] down  [email protected] up  [email protected] [email protected] [email protected] l/r   [email protected] u/d  [email protected] grid"
1510 DISPLAY AT(22,1):"[email protected]  [email protected]  [email protected] [email protected] [email protected] sprite on grid"
1520 SUBEND
1530 ! ##########
1540 SUB SCRATCH(C\$(,),C(,)):: CALL HCHAR(18,1,32,6*32)
1550 DISPLAY AT(20,1):"Erase grid? y/n" :: ACCEPT AT(20,16)SIZE(1)VALIDATE("YNyn"):A\$
1560 IF A\$="y" OR A\$="Y" THEN CALL NEW(C\$(,),C(,))
1570 CALL HELP
1580 SUBEND
1590 ! ########
1600 SUB ASSIGN(C\$(,),C(,))
1610 CALL HCHAR(18,1,32,6*32)
1620 DISPLAY AT(19,1):"Assign design to 1-6:" :: ACCEPT AT(19,22)SIZE(1)VALIDATE("123456"):V\$ :: IF V\$="" THEN CALL HELP :: SUBEXIT
1630 H\$="0123456789ABCDEF" :: CALL BUSY
1640 A\$="" :: FOR Y=1 TO 16 :: FOR X=1 TO 2 :: A\$=A\$&SEG\$(H\$,C(Y,X)+1,1):: NEXT X :: NEXT Y
1650 FOR Y=1 TO 16 :: FOR X=3 TO 4 :: A\$=A\$&SEG\$(H\$,C(Y,X)+1,1):: NEXT X :: NEXT Y
1660 V=116+(VAL(V\$)*4)
1670 CALL CHAR(V,A\$):: CALL HELP :: CALL DONE
1680 SUBEND
1690 ! ##########
1710 H\$="0123456789ABCDEF" :: FOR I=1 TO 4
1720 DISPLAY AT(18,1):"Enter data for character";I
1730 ACCEPT AT(19,1)SIZE(16)VALIDATE("0123456789ABCDEF"):A\$ :: CALL BUSY
1740 IF I=1 THEN Y=1 ELSE IF I=2 THEN Y=9 ELSE IF I=3 THEN Y=1 ELSE Y=9
1750 IF I<3 THEN S=1 ELSE S=3
1760 FOR M=1 TO LEN(A\$)
1770 V=POS(H\$,SEG\$(A\$,M,1),1)-1
1780 C(Y,S)=V :: CALL GETNYBBLE(C(Y,S),N\$):: C\$(Y,S)=N\$ :: IF M/2<>INT(M/2)THEN S=S+1 ELSE S=S-1
1790 IF M/2=INT(M/2)THEN Y=Y+1
1800 NEXT M :: CALL DRAWGRID(C\$(,),C(,)):: NEXT I
1810 CALL HELP :: CALL DONE
1820 SUBEND
1830 ! ###########
1840 SUB SAVEDATA
1850 CALL HCHAR(18,1,32,6*32)
1860 DISPLAY AT(18,1):"Enter device and file name, eg DSK1.SPRITES etc		 Press enter to abort"
1870 ACCEPT AT(21,1)SIZE(15)VALIDATE("_-#@.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):FN\$
1880 IF FN\$="" THEN CALL HELP :: SUBEXIT
1890 CALL BUSY :: OPEN #1:FN\$,DISPLAY ,VARIABLE 80,OUTPUT
1900 RESTORE 40
1910 FOR I=1 TO 6 :: B\$=" DATA " :: READ V :: FOR II=V TO V+3 :: CALL CHARPAT(II,T\$):: CALL SPLIT(T\$,B\$):: NEXT II
1920 PRINT #1:SEG\$(B\$,1,LEN(B\$)-1):: NEXT I
1930 CLOSE #1 :: CALL HELP :: CALL DONE
1940 SUBEND
1950 ! ##############
1960 SUB SPLIT(A\$,B\$)
1970 FOR I=1 TO 16 STEP 4 :: B\$=B\$&">"&SEG\$(A\$,I,4)&"," :: NEXT I
1980 SUBEND
1990 ! ##########
2010 CALL HCHAR(18,1,32,6*32):: DISPLAY AT(19,1):"S=SAVE    L=LOAD		    Press enter to abort"
2020 ACCEPT AT(21,1)SIZE(1)VALIDATE("sSlL"):A\$
2030 IF A\$="" THEN CALL HELP :: SUBEXIT
2040 IF A\$="s" OR A\$="S" THEN CALL SAVEDATA
2050 IF A\$="l" OR A\$="L" THEN CALL LOADDATA(C\$(,),C(,))
2060 CALL HELP
2070 SUBEND
2080 ! ##########
2100 CALL HCHAR(18,1,32,6*32):: DISPLAY AT(20,1):"Enter device and filename   Eg DSK1.SPRITES			 Press Enter to abort"
2110 ACCEPT AT(23,1)SIZE(15)VALIDATE("_-#@.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"):FN\$
2120 IF FN\$="" THEN CALL HELP :: SUBEXIT
2130 CALL BUSY :: OPEN #1:FN\$,INPUT ,DISPLAY ,VARIABLE 80
2140 IF EOF(1)<>0 THEN 2170
2150 RESTORE :: FOR I=1 TO 6 :: LINPUT #1:A\$ :: LINPUT #1:B\$ :: A\$=A\$&B\$
2160 A\$=SEG\$(A\$,8,LEN(A\$)):: B\$="" :: XX=1 :: FOR X=1 TO 16 :: B\$=B\$&SEG\$(A\$,XX,4):: XX=XX+6 :: NEXT X :: READ V :: CALL CHAR(V,B\$):: NEXT I
2170 CLOSE #1
2180 CALL DONE :: SUBEND
2190 ! ############
2200 SUB LFSPRITE(C\$(,),C(,))
2210 CALL HCHAR(18,1,32,6*32):: DISPLAY AT(19,1):"Load grid from which sprite?" :: ACCEPT AT(20,1)SIZE(1)VALIDATE("123456"):S\$ :: CALL HELP
2220 IF S\$="" THEN SUBEXIT ELSE S=VAL(S\$)
2230 CALL BUSY :: SP=116+(S*4)
2240 CALL CHARPAT(SP,P1\$):: CALL CHARPAT(SP+1,P2\$):: CALL CHARPAT(SP+2,P3\$):: CALL CHARPAT(SP+3,P4\$):: H\$="0123456789ABCDEF"
2250 P\$=P1\$&P2\$&P3\$&P4\$
2260 Y=1 :: FOR I=1 TO 31 STEP 2
2270 V\$=SEG\$(P\$,I,1):: V1=POS(H\$,V\$,1)-1 :: V\$=SEG\$(P\$,I+1,1):: V2=POS(H\$,V\$,1)-1
2280 CALL GETNYBBLE(V1,N\$):: C\$(Y,1)=N\$ :: CALL GETNYBBLE(V2,N\$):: C\$(Y,2)=N\$ :: C(Y,1)=V1 :: C(Y,2)=V2 :: Y=Y+1 :: NEXT I
2290 Y=1 :: FOR I=33 TO 63 STEP 2
2300 V\$=SEG\$(P\$,I,1):: V1=POS(H\$,V\$,1)-1 :: V\$=SEG\$(P\$,I+1,1):: V2=POS(H\$,V\$,1)-1
2310 CALL GETNYBBLE(V1,N\$):: C\$(Y,3)=N\$ :: CALL GETNYBBLE(V2,N\$):: C\$(Y,4)=N\$ :: C(Y,3)=V1 :: C(Y,4)=V2 :: Y=Y+1 :: NEXT I
2320 CALL DRAWGRID(C\$(,),C(,)):: CALL DONE
2330 SUBEND
2340 ! #################
2350 SUB ANIMATE(C\$(,),C(,)):: CALL COLOR(#1,1)
2360 FOR I=2 TO 17 :: CALL HCHAR(I,3,32,16):: NEXT I
2370 DISPLAY AT(3,1):"Frame [email protected]" :: DISPLAY AT(4,2):"1234565432"
2380 ACCEPT AT(4,2)VALIDATE(DIGIT)SIZE(-10)\$
2390 CALL DRAWGRID(C\$(,),C(,)):: CALL DONE :: SUBEND

```

##### Share on other sites

Subprograms are useful for breaking down your program's functions... a good one is to have a subprogram to play all the sound effects, which uses an ON GOTO so all you need to do is pass a single value to indicate which sound you want to play.

What annoyed me about this is that they explicitly BLOCK the use of recursive subprograms... the one kind of programming challenge that they could actually be USEFUL for, and it's denied. (For good reasons, I'll admit, but still...)

##### Share on other sites

Lee, thanks for pointing that out. I think I forgot to add some statements.

I made a program called JOYPROG.

First, I was just trying to make a test that would show the joystick values. It ended being 4 dots for the directions, one of which will light up when you move in that direction. Also, it shows some values on screen of variables like X,Y,R, and C. Then, it became a test to try CALL LOCATE with JOYST. Then I figured to test COINC. I put a stationary dot on screen, you can move your dot, touch the stationary one, and it beeps a coincidence. I wanted to try subprograms

on a game, and I couldn't get em to work. I thought, why not try these subprograms one at a time in this test program?

Changed the name to JOYSUB.

In line 193 I set the Meteor coordinates for off screen. In 195 I create the Sprite, off screen and stationary. In the comment I remind myself of where it should start on screen and how fast it should go in the subprogram.

I think I should have put 1074 CALL LOCATE(#3,DR,DC) :: CALL MOTION(#3,20,-20)

The meteor probably appears to move because it is repeatedly called inside the loop. But since it is stuck at the spot like you said, Sprite #1 has to

be moved there by the joystick and it registers a coincidence. I just added line 1074.

Now it moves across screen, but gets cut off and starts again. Probably this happens each time as the sub is called. I guess CALL LOCATE and some statements have to be dome outside of subprograms, due to the looping effect?

##### Share on other sites

I think I should have put 1074 CALL LOCATE(#3,DR,DC) :: CALL MOTION(#3,20,-20)

The meteor probably appears to move because it is repeatedly called inside the loop. But since it is stuck at the spot like you said, Sprite #1 has to

be moved there by the joystick and it registers a coincidence. I just added line 1074.

Now it moves across screen, but gets cut off and starts again. Probably this happens each time as the sub is called. I guess CALL LOCATE and some statements have to be dome outside of subprograms, due to the looping effect?

You could put some more conditional statements in the subprogram to

• react to where the meteor is on the screen, especially if you only want it to make one pass of the screen.
• not relocate the meteor if it is in motion
• create a variable in the subprogram to keep track of whether the meteor is moving or crashed (deleted or hidden). Variables local to subprograms and not part of the parameter list retain their values from one call to the next.

Unless you're just doing it here to get a handle on how to pass variables to and from subprograms, you really don't need the parameters in the METEOR subprogram because they are changed only in the subprogram and you don't do anything with the changed values when you return to the main program. Also, rather than deleting the meteor sprite, you could park it off-screen until you want it to do something. I may be just stating the obvious here. I'll stop rambling now.

...lee

Edited by Lee Stewart

##### Share on other sites

Can you do a CALL SOUND and a CALL COINC at the same time? Or does it actually do one and then the other next? I ask because I hear that CALL SOUND is the only command or SUB that can run while another statement is running. While maybe DATA does that too.

##### Share on other sites

The 99/4A does not have any co-processors, in the sense that they don't execute some sort of code. You only have the 9900 CPU to work with, which means nothing really happens "at the same time". The sound chip in the 99/4A, once set to a tone, will continue playing that tone until it is told to be quite, change its tone, etc. The BASIC/XB SOUND subroutine has the option to wait until the sound is finished before executing the next instruction, or by using a negative duration the SOUND subroutine will start the sound playing, then move on to the next instruction. BASIC then has to go back and check if the sound is done and turn off the sound chip (BASIC checks if it should shut off the sound every 1/60th of a second via the system ISR (interrupt service routine)). In this sense, the sound is playing truly in parallel with the 9900 CPU, but unless told to shut off, the sound chip would continue to play the same tone indefinitely.

##### Share on other sites

Can you do a CALL SOUND and a CALL COINC at the same time? Or does it actually do one and then the other next? I ask because I hear that CALL SOUND is the only command or SUB that can run while another statement is running. While maybe DATA does that too.

The statements do not actually execute at the same time; but, once CALL SOUND is executed, the computer does not wait for the sound to complete before continuing with the remaining computer statements unless it encounters another CALL SOUND statement with a positive duration. Then, of course, it waits for the previous sound to complete. The CPU (TMS9900) can only do one thing at a time; but, once the sound data is passed to the sound processor, the CPU can do other things and thus appear to be doing two things at once.

DATA is not really an executable statement. It is declaring a storage location to be referenced later by a READ statement.

...lee

##### Share on other sites

The BASIC/XB SOUND subroutine has the option to wait until the sound is finished before executing the next instruction, or by using a negative duration the SOUND subroutine will start the sound playing, then move on to the next instruction.

I think the way you stated this is misleading. The SOUND routine does not have "the option to wait ...". Rather, the SOUND routine's option is to cancel a previously initiated sound "by using a negative duration". If there is no previously initiated sound still playing, the SOUND routine starts playing the sound and "move on to the next instruction" regardless of the duration value.

...lee

##### Share on other sites

Lee he

The BASIC/XB SOUND subroutine has the option to wait until the sound is finished before executing the next instruction, or by using a negative duration the SOUND subroutine will start the sound playing, then move on to the next instruction.

I think the way you stated this is misleading. The SOUND routine does not have "the option to wait ...". Rather, the SOUND routine's option is to cancel a previously initiated sound "by using a negative duration". If there is no previously initiated sound still playing, the SOUND routine starts playing the sound and "move on to the next instruction" regardless of the duration value.

...lee

Lee well this is the source code so see for yourself what happens in XB.

```										VRMSND EQU   >0379
<0135> AA0B D7,80,CC	 SOUND   DCEQ VRMSND,@>83CC	 Insure previous sound started
<0136> AA10 6A,0B							BS	  SOUND
<0137> AA12 31,00,09						MOVE 9,[email protected],[email protected]

```

It waits till the previous sound list is done this is the XB source code for CALL SOUND, I did not modify it in RXB.

Edited by RXB

##### Share on other sites

It waits till the previous sound list is done this is the XB source code for CALL SOUND, I did not modify it in RXB.

I believe that's what I said, Rich.

What I was trying to clarify (perhaps not well) is that Matthew's explanation seemed to imply that the programmer can decide to make the currently executing SOUND call wait for its own sound list to complete before going on to the next instruction, when, in fact, that is not so. It never waits on anything except a previous sound list to complete (unless, of course, the current SOUND call includes a negative duration---then it just cuts off the previous sound and goes on).

Thanks for the code.

...lee

##### Share on other sites

Yeah, thanks for the clarification. I didn't review the SOUND subprogram before posting, and it has been a while since I used it. A quick test shows that SOUND starts playing a tone and goes on with the program. Any subsequent SOUND commands will wait on the previous sound to finish (which does block execution of the program), unless the duration is negative - in which case the new sound interrupts any previously playing sound (as Lee stated.)

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.