Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Stack Bug in ZXB 1.2.5-r1489 ?
#1
I was updating fourspriter to use SUBs as opposed to gotos. Probably slower, but a little cleaner on the interface to the user.

Anyway, as it stands the main program:

Calls initialize for the first sprite
which calls a dummy "data" routine (which is really just for asm. The first line is return. It only calls it to make sure it's not peephole optimized out)
Comes back to main
calls coords for the first sprite
comes back to main
calls initialize for the second sprite
which calls the dummy data routine again......

and then it goes wrong. It never comes back from this data routine this second time, even though it should return immediately. In fact, it restarts the main program again. Over and over - and then after a few cycles, crashes.


I confirmed the code does the same thing with 1.23 and 1.22; and I didn't think they had the stack bugs, so it could be something I'm doing wrong, I suppose. I can't really see what could go wrong with "return" being the only statement, though.

The code is a bit complex, and is unfinished; but hopefully you can see where I'm going. It has testing PRINTs in it. Just copy and paste and see if it behaves the same way for you.

Code:
SUB fspInitialize (n as uByte, a as uByte, b as uByte, c as uByte, d as uByte)  'Initialize Sprite: n (sprite number 0-3);a,b,c,d (UDG number 0-20,99 means the sprite won't be printed)
PRINT AT 0,0;"Initialize" : PAUSE 1: PAUSE 0
fspData() : REM call the data sub to make sure it isn't optimized out of the compile. That call just returns.
PRINT AT 2,0;"FSPData came back to Initialize" : PAUSE 1: PAUSE 0
IF n>3 OR a>20 or b>20 or c>20 or d>20 then return : END IF : REM Bounds checking - so a bad function call doesn't poke all over memory.
DIM targetAddr as uInteger
targetAddr=@fspDataStart+(48*n)
POKE targetAddr,a
targetAddr=targetAddr+1
POKE targetAddr,b
targetAddr=targetAddr+1
POKE targetAddr,c
targetAddr=targetAddr+1
POKE targetAddr,d
PRINT AT 3,0;"We're at the end of Initialize"
PAUSE 1:PAUSE 0
END SUB

SUB fspDisable (n as UByte)
IF n>3 then return : END IF
POKE @fspDataStart+48*n,99
end SUB

SUB fspCoord (n as uByte, x as uByte, y as uByte)   'Set sprite coords: n (sprite number);x,y (vertical,horizontal coords)
IF n>3 then return : END IF
DIM targetAddr as uInteger
targetAddr=@fspDataStart+4+48*n
POKE targetAddr,x
targetAddr=targetAddr+1
POKE targetAddr,y
rem targetAddr=targetAddr+1
rem POKE targetAddr,x
rem targetAddr=targetAddr+1
rem POKE targetAddr,y
END SUB

SUB fspAttrs (n as uByte, attra as uByte, attrb as uByte, attrc as uByte, attrd as uByte) 'Set sprite attrs: n (sprite number);a,b,c,d (UDG attrs)
IF n>3 then return : END IF
DIM targetAddr as uInteger
targetAddr=@fspDataStart+40+48*n
POKE targetAddr,attra
targetAddr=targetAddr+1
POKE targetAddr,attrb
targetAddr=targetAddr+1
POKE targetAddr,attrc
targetAddr=targetAddr+1
POKE targetAddr,attrd
END SUB

FUNCTION fspAttrByte(fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte) as uByte
    if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then return 0: END IF: Rem bounds check
    return (fspFlash shl 7) + (fspBright shl 6) + (fspPaper shl 3) + fspInk
END FUNCTION

SUB fspAttr(n as uByte,fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte)
    if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then return : END IF: Rem bounds check
    DIM attrByte as uByte
    attrByte=fspAttrByte(fspInk,fspPaper,fspBright,fspFlash)
    fspAttrs(n,fspAttrByte,fspAttrByte,fspAttrByte,fspAttrByte)
END SUB    

SUB fspData()
fspDataStart:
RETURN : REM if called we should return immediately. This sub is for data and ASM only.
REM This routine contains Fourspriter data and code that is called by other routines. In effect, it's a dummy subroutine.
REM It is called by fspInitialize in order to ensure it is included in the build.

ASM
;; 16x16 Sprites moving a character each frame
;; Copyleft 2009 The Mojon Twins.
;; Pergreñado por na_th_an
;; Uses UDGs (it reads the address from the system variables).
;; It moves up to 4 sprites, preserving the backgrounds.

datap:                        ; each block is 48 bytes long. [This comment originally said 40 bytes, and it's clearly 48]
;; Sprite 1
udgs1:      defb   0,0,0,0      ; Four UDGs of the first sprite.
x_pos1:     defb   0            ; X position in chars.
y_pos1:     defb   0            ; Y position in chars.
cx_pos1:    defb   0            ; Previous X position in chars.
cy_pos1:    defb   0            ; Previous Y position in chars.
buffer1:    defb   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0         ; Background Gfx buffer.
attrs1:     defb   7,7,7,7      ; Sprite ATTRs
buffatrs1:  defb   0,0,0,0      ; Background Attr's buffer

;; Sprite 2
udgs2:      defb   0,0,0,0
x_pos2:     defb   0
y_pos2:     defb   0
cx_pos2:    defb   0
cy_pos2:    defb   0
buffer2:    defb   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
attrs2:     defb   7,7,7,7
buffatrs2:  defb   0,0,0,0

;; Sprite 3
udgs3:      defb   0,0,0,0
x_pos3:     defb   0
y_pos3:     defb   0
cx_pos3:    defb   0
cy_pos3:    defb   0
buffer3:    defb   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
attrs3:     defb   7,7,7,7
buffatrs3:  defb   0,0,0,0

;; Sprite 4
udgs4:      defb   0,0,0,0
x_pos4:     defb   0
y_pos4:     defb   0
cx_pos4:    defb   0
cy_pos4:    defb   0
buffer4:    defb   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
attrs4:     defb   7,7,7,7
buffatrs4:  defb   0,0,0,0

;; General use coordinates
xpos:      defb    0
ypos:      defb    0
cxpos:      defb   0
cypos:      defb    0

;; Sprite control is done writing a certain number
;; in the Sprite's first UDG
;; If the first UDG is 99, it won't be printed

docopy:      
         call   get_scr_address   ; Dirección (xpos, ypos) en BC
         ld      l,    c
         ld      h,    b         ; Dirección (xpos, ypos) en HL        
        
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
        
         ret
        
;; Esta función devuelve en bc la dirección de memoria
;; de la posición (xpos, ypos) en carácteres. Extraído de código
;; por BloodBaz.

get_scr_address:
         push    de
         ld       a,   (xpos)
         and      31
         ld      c,   a
         ld      a,   (ypos)
         ld      d,   a
         and      24
         add      a,   64
         ld      b,    a
         ld      a,   d
         and      7
         rrca
         rrca
         rrca
         or      c
         ld      c,    a
         pop      de
         ret
              
;; Esta función devuelve en bc la dirección de memoria
;; de la posición (xpos, ypos) dentro del archivo de atributos.
;; Adaptado de código por Jonathan Cauldwell.

;; 010110YY YYYXXXXX

get_attr_address:
        
         ld      a,    (ypos)      ; Cogemos y
         rrca
         rrca
         rrca               ; La multiplicamos por 32
         ld      c,   a         ; nos lo guardamos en c
         and      3            ; ponemos una mascarita 00000011
         add      a,   88         ; 88 * 256 = 22528, aquí empieza el tema
         ld      b,   a         ; Hecho el bite superior.
         ld      a,   c         ; Nos volvemos a traer y * 32
         and      224            ; Mascarita 11100000
         ld      c,   a         ; Lo volvemos a poner en c
         ld      a,   (xpos)      ; Cogemos x
         add      a,    c         ; Le sumamos lo que teníamos antes.
         ld      c,   a         ; Listo. Ya tenemos en BC la dirección.
         ret
        
spare:      defb   85,85,85,85,85,85,85, 85
END ASM
END SUB


SUB fspErase()
asm
;; Routine to save the background to the buffer

;borra_sprites:

; pointer = datap
; for (i = 0; i < 4; i ++) {
;    CX = *(pointer + 6)
;    CY = *(pointer + 7)
;    scr_address = get_scr_address (CX, CY);
;    for (j = 0; j < 8; j ++) {
;       *scr_address = *(pointer + 8 + j);
;      scr_address += 256;
;    }
;    scr_address = get_scr_address (CX+1, CY);
;    for (j = 0; j < 8; j ++) {
;       *scr_address = *(pointer + 16 + j);
;      scr_address += 256;
;    }
;    scr_address = get_scr_address (CX, CY+1);
;    for (j = 0; j < 8; j ++) {
;       *scr_address = *(pointer + 24 + j);
;      scr_address += 256;
;    }
;    scr_address = get_scr_address (CX+1, CY+1);
;    for (j = 0; j < 8; j ++) {
;       *scr_address = *(pointer + 32 + j);
;      scr_address += 256;
;    }
;    pointer += 40;
; }

         ld       de, datap      ;
         ld      b,   4         ;
i4chars2:   push   bc
        
         ;;
         ld      a,   (de)
         cp      99
         jr      z,   nxt2

         ;; A

         inc      de
         inc      de
         inc      de
         inc      de
         inc      de
         inc      de
        
         ; Obtenemos xpos = CX
         ld      a,   (de)
         ld      hl,   xpos
         ld      (hl), a
        
         inc    de
        
         ; Obtenemos ypos = CY
         ld      a,   (de)
         ld      hl, ypos
         ld      (hl), a
        
         inc    de
        
         ;; B
        
         ; Pintamos el primer char
         call   borra_char
                  
         ; xpos++
         ld      hl, xpos
         inc      (hl)
        
         ;; C
        
         ; Pintamos el segundo char
         call   borra_char

         ; xpos --
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos ++
         ld      hl, ypos
         inc      (hl)
        
         ;; D
        
         ; Pintamos el tercer char
         call    borra_char

         ; xpos++
         ld      hl, xpos
         inc      (hl)
        
         ;; E

         ; Pintamos el cuarto char
         call   borra_char
        
         ;; attr
         inc      de
         inc      de
         inc      de
         inc      de
        
         ;;
        
         ; xpos --
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos --
         ld      hl, ypos
         ld      a, (hl)
         dec      a
         ld      (hl), a
              
         ;
         call   get_attr_address
        
         ;
         call   copyattrs
        
         ;
        
nxt2:      pop      bc
         djnz    i4chars2        
      
jp fspErase_end


borra_char:            
         call   get_scr_address   ;
         ld      l,    c
         ld      h,    b         ;
        
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
         ld      a,   (de)
         ld      (hl), a
         inc      h
         inc      de
        
         ret
        



fspErase_end:

end asm
END SUB


SUB fspBufferBackground()
asm
init_sprites:                  

; pointer = datap
; for (i = 0; i < 4; i ++) {
;    X = *(pointer + 4);                           // A
;    Y = *(pointer + 5);
;    scr_address = get_scr_address (X, Y);               // B
;    for (j = 0; j < 8; j ++) {
;       *(pointer + 8 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X+1, Y);            // C
;    for (j = 0; j < 8; j ++) {
;       *(pointer + 16 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X, Y+1);            // D
;    for (j = 0; j < 8; j ++) {
;       *(pointer + 24 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X+1, Y+1);            // E
;    for (j = 0; j < 8; j ++) {
;       *(pointer + 32 + j) = *scraddress;
;       scraddress += 256;
;    }
;    pointer = pointer + 40;
; }

         ld       de, datap      ;

         ld      b,   4         ;
i4chars:   push   bc
        
         ;;
         ld      a,   (de)
         cp      99
         jr      z,   nxt1

         ;; A

         inc      de
         inc      de
         inc      de
         inc      de

         ;
         ld      a,   (de)
         ld      hl,   xpos
         ld      (hl), a
        
         inc    de
        
         ;
         ld      a,   (de)
         ld      hl, ypos
         ld      (hl), a
        
         inc    de
         inc    de
         inc    de
        
         ;; B
        
         ;
         call   copia_char
        
         ; xpos++
         ld      hl, xpos
         inc      (hl)
        
         ;; C
        
         ;
         call    copia_char

         ; xpos --
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos ++
         ld      hl, ypos
         inc      (hl)
        
         ;; D
        
         ;
         call    copia_char

         ; xpos++
         ld      hl, xpos
         inc      (hl)
        
         ;; E
        
         ;
         call   copia_char
        

         ;; Now we point to the ATTR buffer,adding 4:
         inc      de
         inc      de
         inc      de
         inc      de
        
         ;;
        
         ; xpos --
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos --
         ld      hl, ypos
         ld      a, (hl)
         dec      a
         ld      (hl), a
              
         ;
         call   get_attr_address
        
         ;
         ld      l,    c
         ld      h,    b
         ld      bc, 31
         ld      a,   (hl)
         ld      (de), a         ; Primer carácter
         inc      hl
         inc      de
         ld      a,    (hl)  
         ld      (de), a         ; Segundo carácter
         add      hl,   bc
         inc      de
         ld      a,   (hl)
         ld      (de), a         ; Tercer carácter
         inc      hl
         inc      de
         ld      a,    (hl)
         ld      (de), a         ; Cuarto carácter
         inc      de            

         ; Fin del bucle
        
nxt1:      pop      bc
         djnz    i4chars
        
         ;ret
jp fspBufferBackground_end
        
copia_char:
         call   get_scr_address   ;
         ld      l,    c
         ld      h,    b         ;
        
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
         ld      a,   (hl)
         ld      (de), a
         inc      h
         inc      de
        
         ret  ; Subroutines don't need to return themselves.

fspBufferBackground_end:        
;; Routine to move the sprites:

end asm
END SUB

SUB fspRedraw()
asm
   halt
end asm

   ';call borra_sprites            ; Erase the sprites
   fspErase()
   ';call init_sprites               ; Save background
   fspBufferBackground()
   ';call draw_sprites            ; print sprites
   fspDraw()
   ';call update_coordinates         ; update coordinates :)
   fspUpdate()
   ';ret

END SUB

SUB fspDraw()
asm
;; Print sprites routine
;; UDGs are labeled from  0 to 21. The addres of the UDG is:
;; *(23675) + 256 * *(23676) + 8 * N
draw_sprites:
         ld       de, datap      ;
         ld      b,   4         ;
i4chars3:   push   bc
         ld      a,   (de)
         cp      99
         jr      z,   nxt3
         ;; copiar aquí "de" a un buffer
         call   charsabuff
         ; Obtenemos xpos
         ld      a,   (de)
         ld      hl,   xpos
         ld      (hl), a
         inc    de
         ; Obtenemos ypos
         ld      a,   (de)
         ld      hl, ypos
         ld      (hl), a
         inc    de
         inc    de
         inc    de
         push    de
        
         ld      hl, bufchars
         call   getde
         call   docopy
         ; xpos++
         ld      hl, xpos
         inc      (hl)
         ; Dirección del gráfico
         ld      hl, bufchars
         inc      hl
         call   getde
         ; Pintamos el segundo char
         call   docopy
         ; xpos--
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos ++
         ld      hl, ypos
         inc      (hl)
         ; Dirección del gráfico
         ld      hl, bufchars
         inc      hl
         inc      hl
         call   getde
         ; Pintamos el tercer char
         call   docopy
         ; xpos ++
         ld      hl, xpos
         inc      (hl)
         ; Dirección del gráfico
         ld      hl, bufchars
         inc      hl
         inc      hl
         inc      hl
         call    getde
        
         ; Pintamos el cuarto char
         call   docopy
                    
         pop      de
        
         ; de = de + 32
         ld      bc, 32
         ld      h, d
         ld      l, e
         add      hl, bc
         ld      d, h
         ld      e, l
        
         ;; attr
        
         ; xpos --
         ld      hl, xpos
         ld      a, (hl)
         dec      a
         ld      (hl), a
        
         ; ypos --
         ld      hl, ypos
         ld      a, (hl)
         dec      a
         ld      (hl), a
              
         ;
         call   get_attr_address
        
         ;
         call   copyattrs
        
         inc      de
         inc      de
         inc      de
         inc      de            ;
        
nxt3:      pop      bc
         djnz    i4chars3
        
         ;ret
jp fspDraw_end

;; Esta función calcula la posición en memoria del UDG apuntado por
;; el número que está en la dirección hl.
        
getde:      ld      a, (hl)
         ld      d, a
         ld      hl, 23676
         ld      a, (hl)
         ld      e, a
         ld      hl, 23675
         ld      a, (hl)
         ld      l, a
         ld      a, e
         ld      h, a
         ;;      HL = *(23675) + 256 * *(23676)
         ld      a, d
         rlca
         rlca
         rlca   ; a = N * 8
         ld      d, 0
         ld      e, a
         add      hl, de
         ld      d, h
         ld      e, l
         ret


bufchars:   defb   0,0,0, 0      ;

charsabuff: ld      hl,   bufchars
         ld      a, (de)
         ld      (hl), a
         inc      de
         inc      hl
         ld      a, (de)
         ld      (hl), a
         inc      de
         inc      hl
         ld      a, (de)
         ld      (hl), a
         inc      de
         inc      hl
         ld      a, (de)
         ld      (hl), a
         inc      de
         inc      hl
         ret
                  
copyattrs:   ld      l,    c
         ld      h,    b
         ld      bc, 31
         ld      a,   (de)
         ld      (hl), a         ; Primer carácter
         inc      hl
         inc      de            
         ld      a,    (de)  
         ld      (hl), a         ; Segundo carácter
         add      hl,   bc
         inc      de
         ld      a,   (de)
         ld      (hl), a         ; Tercer carácter
         inc      hl
         inc      de
         ld      a,    (de)
         ld      (hl), a         ; Cuarto carácter
         inc      de            ; Ahora de apunta a datap+48, o sea, al siguiente sprite.
         ret
fspDraw_end:
END ASM
END SUB

SUB fspUpdate()
asm
update_coordinates:
         ld       de, datap      ; Apuntamos a la zona de datos
         ld      hl, datap      ; idem

         ld      b,   4         ; 4 iteraciones
i4chars4:   push   bc

         ;; Para cada sprite hay que hacer:
         ;; *(datap + 6) = *(datap + 4)
         ;; *(datap + 7) = *(datap + 5)
        
         inc      de
         inc      de
         inc      de
         inc      de
         ld      a, (de)         ; a = X
         inc      hl
         inc      hl
         inc    hl
         inc      hl
         inc      hl
         inc      hl
         ld      (hl), a         ; CX = a
        
         inc    de
         ld      a, (de)         ; a = Y
         inc    hl
         ld      (hl), a         ; CY = a

         inc      hl
        
         ;; hl = hl + 40
         ld      bc, 40
         add      hl, bc
        
         ;; de = hl
         ld      d, h
         ld      e, l
        
         pop      bc
         djnz    i4chars4
         ;ret
END ASM
END SUB


#include <sinclair.bas>
#include <memcopy.bas>
#include <keys.bas>


100 DIM gentle (0 to 3,0 to 7) AS uByte => {  { 15, 15, 15, 15, 15, 15, 13, 15} , _
     { 240, 144, 208, 208, 240, 240, 176, 240} , _
     { 15, 14, 63, 0, 0, 12, 26, 30} , _
     { 176, 112, 252, 0, 0, 48, 104, 120}}

110 POKE Uinteger 23675, @gentle(0,0)


    memcopy (0,16384,4092)
    LET gx=10:LET gy=10:let dx=3:let dy=3:let tx=6:let ty=6:let cx=18:let cy=18
    let dmx=1:let dmy=1:let tmx=-1:let tmy=-1:let cmx=1:let cmy=-1
    fspInitialize (0,0,1,2,3)
    PRINT AT 5,0;"We came back from Initialize the first time" : PAUSE 1: PAUSE 0
    fspCoord (0,gy,gx)
    PRINT AT 6,0;"We came back from fspCoord the first time": PAUSE 1: PAUSE 0
    CLS
    fspInitialize (1,0,1,2,3)
    PRINT AT 7,0;"We came back from Initialize the second time" : PAUSE 1: PAUSE 0    
    fspCoord (1,dy,dx)
    fspInitialize (2,0,1,2,3)
    fspCoord (2,ty,tx)
    fspInitialize (3,0,1,2,3)
    fspCoord (3,cy,cx)
    fspAttrs (0,31,31,31,31)
    fspAttrs (1,12,12,12,12)
    fspAttrs (2,26,26,26,26)
    fspAttrs (3,6,6,6,6)
    

DO

    IF MULTIKEYS(KEYO)<>0 and gx>0 THEN LET gx=gx-1: END IF
    IF MULTIKEYS(KEYP)<>0 and gx<30 THEN LET gx=gx+1:END IF
    IF MULTIKEYS(KEYQ)<>0 and gy>0 THEN LET gy=gy-1 :END IF
    IF MULTIKEYS(KEYA)<>0 and gy<22 THEN LET gy=gy+1: END IF


    let dx=dx+dmx:if dx=0 or dx=30 then let dmx=-dmx : END IF
    let dy=dy+dmy:if dy=0 or dy=22 then let dmy=-dmy: END IF
    let tx=tx+tmx:if tx=0 or tx=30 then let tmx=-tmx: END IF
    let ty=ty+tmy:if ty=0 or ty=22 then let tmy=-tmy: END IF
    let cx=cx+cmx:if cx=0 or cx=30 then let cmx=-cmx: END IF
    let cy=cy+cmy:if cy=0 or cy=22 then let cmy=-cmy: END IF
pause 2
    fspCoord (0,gx,gy)
    fspCoord (1,dx,dy)
    fspCoord (2,tx,ty)
    fspCoord (3,cx,cy)
    fspRedraw()
loop
Reply


Messages In This Thread

Forum Jump:


Users browsing this thread: 2 Guest(s)