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
#2
In this case, it's a bug in your program: in fspInitialize you call fspData():
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.
    ...
And later call fspDisable() with n = 0:
Code:
SUB fspDisable (n as UByte)
    IF n>3 then return : END IF
    POKE @fspDataStart+48*n,99
    end SUB
Look carefully at the above code and now look at fsbData definition:
Code:
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.
    ...

When you call fspDisable(0) you're effectively *destroying* the RETURN sentence of fspData(), because you're doing
POKE @fspDataStart, 99 (which is @RETURN address). Rewriting fspData this way, fixes the bug:
Code:
SUB fspData()
    RETURN : REM if called we should return immediately. This sub is for data and ASM only.

fspDataStart: REM this label *AFTER* return to avoid being POKEd

    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.
    ...
Reply
#3
Very, very well spotted. This is why you make the compiler, and I just break it :-)

You are right - the return was put in later on, and it should be before the label, not after it.

Your explanation confused me a little at first, because I'm quite certain I don't call fspdisable at all - but I DO call fspCoords, which pokes exactly where you say.

Erk.


Thankyou for clearing that up!

It turns out I fixed it by redesigning where all the code is, more or less by accident. It does show that mixing compiled code with assembler and worst of all using poke can leave you with unintentional self-modifying code!

Now I feel bad I made you dig through my rookie mistake!

Thanks, Boriel. I bow to your superior skills Wink
Reply
#4
I've finally fixed the -O2 -O3 bugs. Please download 1.2.5-r1489f
<!-- m --><a class="postlink" href="http://www.boriel.com/files/zxb/zxbasic-1.2.5r1489f.msi">http://www.boriel.com/files/zxb/zxbasic-1.2.5r1489f.msi</a><!-- m -->

This release should be a Release Candidate (RC1).
If there are no more bugs to fix, we can finally release it and move to 1.2.6 and add bOR, bAND and bXOR to the language. :!:
Reply
#5
I've downloaded the new version (1.2.5-r1489f) and tried to compile my last crap game. It compiled OK with version 1.2.5-r1489 and no optimization.

Now, with no optimization I get this message (and it compiles OK):
Code:
> Executing: C:\Archivos de programa\ConTEXT\ConExec.exe -i "C:\Archivos de programa\Boriel Tm\ZX Basic Compiler\zxb.exe" -T -B -a  -S 28000 clash3.bas

memcopy.bas:29: warning: SUB 'memcopy' declared as FASTCALL with 3 parameters
> Execution finished.


With optimization -O 2, or -O 3 I get this message (and it doesn't compile):

Code:
> Executing: C:\Archivos de programa\ConTEXT\ConExec.exe -i "C:\Archivos de programa\Boriel Tm\ZX Basic Compiler\zxb.exe" -T -B -a  -O 2 -S 28000 clash3.bas

INFO: BORDER is not defined. No optimization is done.
INFO: COPY_ATTR is not defined. No optimization is done.
INFO: CLS is not defined. No optimization is done.
INFO: BRIGHT is not defined. No optimization is done.
INFO: BOLD_TMP is not defined. No optimization is done.
INFO: PRINT_STR is not defined. No optimization is done.
INFO: PRINT_EOL_ATTR is not defined. No optimization is done.
INFO: ITALIC_TMP is not defined. No optimization is done.
INFO: BRIGHT_TMP is not defined. No optimization is done.
INFO: INVERSE_TMP is not defined. No optimization is done.
INFO: __FTOU32REG is not defined. No optimization is done.
INFO: __EQ32 is not defined. No optimization is done.
INFO: PRINT_EOL is not defined. No optimization is done.
INFO: __PAUSE is not defined. No optimization is done.
INFO: __EQ16 is not defined. No optimization is done.
INFO: FLASH_TMP is not defined. No optimization is done.
INFO: __AND8 is not defined. No optimization is done.
INFO: __ABS8 is not defined. No optimization is done.
INFO: __STOP is not defined. No optimization is done.
INFO: __MUL8_FAST is not defined. No optimization is done.
INFO: BEEP is not defined. No optimization is done.
memcopy.bas:29: warning: SUB 'memcopy' declared as FASTCALL with 3 parameters
clash3.bas:27: warning: Function 'attr' is never called and has been ignored
clash3.bas:66: warning: Function 'setattr' is never called and has been ignored
clash3.bas:27: warning: Function 'point' is never called and has been ignored
clash3.bas:29: warning: Function 'screen' is never called and has been ignored
clash3.bas:26: warning: Function 'input' is never called and has been ignored
clash3.bas:22: warning: Function 'GetKey' is never called and has been ignored
clash3.bas:59: warning: Function 'GetKeyScanCode' is never called and has been ignored
clash3.bas:1: warning: Function 'psprite' is never called and has been ignored
clash3.bas:19: warning: Function 'orsprite' is never called and has been ignored
clash3.bas:12: warning: Function 'cpattr' is never called and has been ignored
clash3.bas:20: warning: Function 'rstattr' is never called and has been ignored
clash3.bas:29: warning: Variable 'dest' is never used
clash3.bas:29: warning: Variable 'source' is never used
clash3.bas:29: warning: Variable 'length' is never used
clash3.bas:41: warning: Variable 'scancode' is never used
Traceback (most recent call last):
  File "zxb.py", line 244, in <module>
  File "zxb.py", line 209, in main
  File "optimizer.pyc", line 2021, in optimize
  File "optimizer.pyc", line 1316, in update_goes_and_comes
IndexError: list index out of range
> Execution finished.


It's probably my code (I'm so proud of its crapyness...) but maybe the last lines of the optimization message tells you something. I don't want to make you search within a long, untidy, unsorted and crap piece of code, so if you can point me to what should I look for, I'll do. Or if you think it's my code's fault I'll let it as is (it compiles without optimization and that more than enough for me).

Anyway, if you still want to see my code, I'll send you the .bas file, the attachments and also the .tzx file so you can play and delight yourself (or not).
Reply
#6
By the way, when I intalled this last version (1.2.5 r1489f) I had to manually uninstall the previous one. This is probably OK, but as in previous versions instalations it just overwrited the old data, I thought I better tell you just in case.
Reply
#7
apenao Wrote:I've downloaded the new version (1.2.5-r1489f) and tried to compile my last crap game. It compiled OK with version 1.2.5-r1489 and no optimization.

Now, with no optimization I get this message (and it compiles OK):
Code:
> Executing: C:\Archivos de programa\ConTEXT\ConExec.exe -i "C:\Archivos de programa\Boriel Tm\ZX Basic Compiler\zxb.exe" -T -B -a  -S 28000 clash3.bas

memcopy.bas:29: warning: SUB 'memcopy' declared as FASTCALL with 3 parameters
> Execution finished.

With optimization -O 2, or -O 3 I get this message (and it doesn't compile):

Code:
Traceback (most recent call last):
  File "zxb.py", line 244, in <module>
  File "zxb.py", line 209, in main
  File "optimizer.pyc", line 2021, in optimize
  File "optimizer.pyc", line 1316, in update_goes_and_comes
IndexError: list index out of range
> Execution finished.

It's probably my code (I'm so proud of its crapyness...) but maybe the last lines of the optimization message tells you something.
If your code were not ok, the compiler should just end with a compiler error, not with an internal *crash*. This is a compiler bug. :?
I need your code to debug this. If you don't want to publish it here (for whatever reason, contact with me with a private message). Another option is to shorten the code to minimum portion which produces this error.
Reply
#8
apenao Wrote:By the way, when I installed this last version (1.2.5 r1489f) I had to manually uninstall the previous one. This is probably OK, but as in previous versions installations it just overwritten the old data, I thought I better tell you just in case.
This should not happen. Every version should automatically uninstall the previous one. What happened exactly?
On the other hand, try to completely uninstall and reinstall de compiler: If you change any of the installed files in the zxbasic directory (or place a .bas file there), the uninstaller will leave the changed/new files there (all .MSI installers do this, to preserve user modifications; this feature is not unique to ZX BASIC)
Reply
#9
1> Optimize - Admittedly not with the latest version (I've been leaving Optimization off lately), I've seen this same problem with update_comes_and_goes - it seems to happen with larger programs, though obviously I haven't tried any sizing games to find out if that's the case.

2> Installation. For some but not all of the recent beta versions now, I've had the issue where the installer refuses to install because it says there's a newer version already installed. This latest build, I had to uninstall and reinstall. No files in the program folder are modified.
Reply
#10
1) My program: I will send you the program. I have no problem posting it here, but it's quite long and comes with some binary attachments that can't be posted here. I won't be able to do that until tonight thought. I'll also try to isolate parts of the program to see if I can see where the problem is.

2) Instalation: The same as britlion said, but I had some custom .bas files in the library.
Reply
#11
apenao Wrote:1) My program: I will send you the program. I have no problem posting it here, but it's quite long and comes with some binary attachments that can't be posted here. I won't be able to do that until tonight thought. I'll also try to isolate parts of the program to see if I can see where the problem is.
Ok, send me private msg then.

Quote:2) Installation: The same as britlion said, but I had some custom .bas files in the library.
If you put new files in any subdirectory, those files will be unchanged upon uninstallation, so these files and it's folders will be there. The best way to use your own library files is work on a local directory out of the ZX BASIC directories, and use #include "file.bas" instead of #include <file.bas>. This is explained either in the Wiki or in this forum, but I cannot find where Tongue
Reply
#12
Here goes the .bas listing of the program. I'll post the custom library files following this. I have to think of a way to send the binary files.

Ladies and gentlemen, prepare yourself to witness the future of videogames:

Colour Clash of the Titans (aka Trash of the Titans - aka Crap of the Titans - aka Ruins Fighter VII Turbo):

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




REM INICIALIZAR VARIABLES
    DIM bicho as uinteger: DIM enemigo as uinteger
    LET protaizda=@arqueroizda: LET protadcha=@arquerodcha
    LET eneizda=@zeusizda: LET enedcha=@zeusdcha
    LET bicho=protadcha: LET enemigo=enedcha
    DIM ACEL AS BYTE: DIM DIF AS BYTE: DIM DIFY AS BYTE
    DIM GOLPE AS UBYTE: DIM GOLPEE AS UBYTE: DIM HERIDA AS UBYTE: DIM HERIDAE AS UBYTE
    LET GOLPE=0: LET GOLPEE=0: LET HERIDA=0: LET HERIDAE=0
    LET ACEL=0
    LET gfxproyizda=@flechaizda: LET gfxproydcha=@flechadcha
    LET gfxproyeizda=@rayo: LET gfxproyedcha=@rayo

    DIM VIDA AS UBYTE: DIM VIDAE AS UBYTE
    LET VIDA=192: LET VIDAE=192
    DIM salto as ubyte: DIM disparo as ubyte: DIM saltoE as ubyte: DIM disparoE as ubyte
    LET salto=0: LET disparo=0 : LET saltoE=0: LET disparoE=0
    LET X=174:LET Y=200 : LET XA=174:LET YA=200 :let frame=0
    LET XE=174:LET YE=40 : LET XAE=174:LET YAE=40 :let frameE=0
    LET dispx=0:let dispy=0:let dispxa=0:let dispya=0
    LET dispxe=0: let dispye=0: let dispxea=0: let dispyea=0
    DIM VELOCIDAD AS UBYTE: DIM VELOCIDADE AS UBYTE: DIM VELDISPARO AS UBYTE: DIM VELDISPAROE AS UBYTE: DIM SALTAR AS UBYTE: DIM SALTARE AS UBYTE: DIM FUERZA AS UBYTE: DIM FUERZAE AS UBYTE
    DIM DEMO AS UBYTE: DIM DEMOTIME AS UINTEGER
    DIM PAUSA AS UINTEGER

    spriteh (16)
    

    border 0
    
menu:
     LET DEMOTIME=1200

     PAPER 0:INK 7
     CLS
     BRIGHT 1
     PRINT BOLD 1; AT 0,3; INK 1;"C";INK 2;"O";INK 3;"L";INK 4;"O";INK 5;"U";INK 6;"R";INK 7;" CLASH OF THE TITANS"
     PRINT INK 4;AT 2,4;"P: 1 PLAYER"
     PRINT INK 7; AT 6,1;"H:SELECT HERO"
     PRINT INK 6; AT 8,2;"MACISTE"
     PRINT INK 4;AT 9,2;"ZEUS"
     PRINT INK 5;AT 10,2;"HADES"
     PRINT INK 3;AT 11,2;"LEGOLAS"
     BRIGHT 0
     PRINT INK 7; AT 6,16;"R:SELECT RIVAL"
     PRINT INK 6; AT 8,17;"LEGOLAS"
     PRINT INK 4;AT 9,17;"HADES"
     PRINT INK 5;AT 10,17;"ZEUS"
     PRINT INK 3;AT 11,17;"MACISTE"
     BRIGHT 1
     PRINT AT 14,5;INK 7;"S:SELECT SCENARIO"
     PRINT AT 15,2;INK 1;"RUINS OF THE ANCIENT GREECE"
     PRINT AT 16,2;INK 3;"RUINS OF THE BRITISH EMPIRE"
     PRINT AT 17,2;INK 4;"RUINS OF THE ISLAND EGOS"
     PRINT AT 18,2;INK 6;"RUINS OF THE WORLD'S SOUL"
     PRINT AT 19,2;INK 2;"RUINS OF THE SPANISH ECONOMY"

     PRINT ITALIC 1;INK 1;PAPER 7;BRIGHT 0;INVERSE 1; AT 22,8;"ENTER TO START"
    
     INK 2
     PLOT 6,140: DRAW -3,0:DRAW -2,-2:DRAW 0,-46:DRAW 2,-2: DRAW 112,0: DRAW 2,2: DRAW 0,46: DRAW -2,2: DRAW -3,0
     PLOT 127,140: DRAW -3,0:DRAW -2,-2:DRAW 0,-46:DRAW 2,-2: DRAW 120,0: DRAW 2,2: DRAW 0,46: DRAW -2,2: DRAW -3,0
     INK 6
     PLOT 38,76: DRAW -35,0:DRAW -2,-2: DRAW 0,-46:DRAW 2,-2: DRAW 241,0: DRAW 2,2: DRAW 0,46: DRAW -2,2: DRAW -67,0
     INK 1
     PLOT 30,172: DRAW -27,0:DRAW -2,-2: DRAW 0,-20:DRAW 2,-2: DRAW 241,0:DRAW 2,2: DRAW 0,20:DRAW -2,2:DRAW -27,0
     LET HERO=0:LET RIVAL=0:LET SCENARIO=0:LET JUGADORES=1


menudos:
     LET ALEA=INT (RND*300): IF ALEA=0 THEN PRINT ITALIC 1;BOLD 1;INK INT (RND*7)+1;AT 0,10;"TRASH": ELSE IF ALEA=1 THEN PRINT ITALIC 1;BOLD 1;INK INT (RND*7)+1;AT 0,10;"CRAP ":ELSE IF ALEA=2 THEN PRINT AT 0,10;ITALIC 1;BOLD 1;INK INT (RND*7)+1;"CLASH":END IF:END IF:END IF
     PRINT AT 8+HERO,1;INK INT (RND*7)+1;">"
     PRINT AT 8+RIVAL,16;INK INT (RND*7)+1;">"
     PRINT AT 15+SCENARIO,1;INK INT (RND*7)+1;">"
     IF MULTIKEYS (KEYH)<>0 THEN PRINT AT 8+HERO,1;" ":LET HERO=HERO+1:PAUSE 1:PAUSE 5:IF HERO>3 THEN LET HERO=0:END IF:END IF
     IF MULTIKEYS (KEYR)<>0 THEN PRINT AT 8+RIVAL,16;" ":LET RIVAL=RIVAL+1:PAUSE 1:PAUSE 5:IF RIVAL>3 THEN LET RIVAL=0:END IF:END IF
     IF MULTIKEYS (KEYS)<>0 THEN PRINT AT 15+SCENARIO,1;" ":LET SCENARIO=SCENARIO+1:PAUSE 1:PAUSE 5:IF SCENARIO>4 THEN LET SCENARIO=0:END IF:END IF
     IF MULTIKEYS (KEYP)<>0 THEN LET JUGADORES=JUGADORES+1:PAUSE 1: PAUSE 10:IF JUGADORES =3 THEN LET JUGADORES=1:END IF: END IF
     IF JUGADORES=1 THEN PRINT INK 4;AT 2,4;"P: 1 PLAYER             ";AT 3,3;"O:LEFT P:RIGHT U:UP M:FIRE";AT 4,3;"                           ":ELSE PRINT INK 5;AT 2,16;"P: 2 PLAYERS";AT 4,3;"Q:LEFT W:RIGHT R:UP V:FIRE":END IF
     IF MULTIKEYS (KEYENTER)<>0 THEN GOTO INICIO: END IF
     LET DEMOTIME=DEMOTIME-1: IF DEMOTIME=0 THEN LET DEMO=1:LET HERO=INT (RND*4):LET RIVAL=INT (RND*4):LET SCENARIO=INT (RND*5):LET CAMINO=1:GOTO INICIO:END IF
     GOTO menudos
     PAUSE 1:PAUSE 0
INICIO:
       IF HERO=0 THEN LET protaizda=@macisteizda: LET protadcha=@macistedcha: LET gfxproyizda=@ondaizda: LET gfxproydcha=@ondadcha:LET VELOCIDAD=1:LET VELDISPARO=1:LET FUERZA=3: LET SALTAR=80:END IF
       IF HERO=1 THEN LET protaizda=@zeusizda: LET protadcha=@zeusdcha: LET gfxproyizda=@rayo: LET gfxproydcha=@rayo:LET VELOCIDAD=1:LET VELDISPARO=2:LET FUERZA=2: LET SALTAR=90:END IF
       IF HERO=2 THEN LET protaizda=@etizda: LET protadcha=@etdcha: LET gfxproyizda=@telefono: LET gfxproydcha=@telefono:LET VELOCIDAD=2:LET VELDISPARO=2:LET FUERZA=2: LET SALTAR=48:END IF
       IF HERO=3 THEN LET protaizda=@arqueroizda: LET protadcha=@arquerodcha: LET gfxproyizda=@flechaizda: LET gfxproydcha=@flechadcha:LET VELOCIDAD=2:LET VELDISPARO=3:LET FUERZA=1: LET SALTAR=60:END IF

       IF RIVAL=0 THEN LET eneizda=@arqueroizda: LET enedcha=@arquerodcha: LET gfxproyeizda=@flechaizda: LET gfxproyedcha=@flechadcha:LET VELOCIDADE=2:LET VELDISPAROE=3:LET FUERZAE=1: LET SALTARE=60:END IF
       IF RIVAL=1 THEN LET eneizda=@etizda: LET enedcha=@etdcha: LET gfxproyeizda=@telefono: LET gfxproyedcha=@telefono:LET VELOCIDADE=2:LET VELDISPAROE=2:LET FUERZAE=2: LET SALTARE=48:END IF
       IF RIVAL=2 THEN LET eneizda=@zeusizda: LET enedcha=@zeusdcha: LET gfxproyeizda=@rayo: LET gfxproyedcha=@rayo:LET VELOCIDADE=1:LET VELDISPAROE=2:LET FUERZAE=2: LET SALTARE=90:END IF
       IF RIVAL=3 THEN LET eneizda=@macisteizda: LET enedcha=@macistedcha: LET gfxproyeizda=@ondaizda: LET gfxproyedcha=@ondadcha:LET VELOCIDADE=1:LET VELDISPAROE=1:LET FUERZAE=3: LET SALTARE=80:END IF

       LET bicho=protaizda: LET enemigo=enedcha

       IF SCENARIO>0 THEN GOTO ESCENARIOUNO: END IF
       unchunk (@partenon,16384,3927)
       GOTO JUEGO
ESCENARIOUNO:
       IF SCENARIO>1 THEN GOTO ESCENARIODOS: END IF
       unchunk (@stonehedge,16384,3372)
       GOTO JUEGO
ESCENARIODOS:
       IF SCENARIO>2 THEN GOTO ESCENARIOTRES: END IF
       unchunk (@pascua,16384,3997)
       GOTO JUEGO
ESCENARIOTRES:
       IF SCENARIO>3 THEN GOTO ESCENARIOCUATRO: END IF
       unchunk (@ny,16384,3652)
       GOTO JUEGO
ESCENARIOCUATRO:
       unchunk (@marbella,16384,3049)



JUEGO:
    LET VIDA=192: LET VIDAE=192
    LET salto=0: LET disparo=0 : LET saltoE=0: LET disparoE=0
    LET X=174:LET Y=200 : LET XA=174:LET YA=200 :let frame=0
    LET XE=174:LET YE=40 : LET XAE=174:LET YAE=40 :let frameE=0
    LET XDISP=0:let YDISP=0:let XDISPE=0:let YDISPE=0
    LET GOLPE=0: LET GOLPEE=0: LET HERIDA=0: LET HERIDAE=0

memcopy (@logo,16384,2048)
memcopy (@logo+2048,22528,256)

       IF DEMO=1 THEN PRINT AT 12,4;PAPER 1;INK 6;FLASH 1;ITALIC 1;"ENTER TO EXIT DEMO MODE":END IF

     cpbuffer(X,Y,@buser)
     andsprite (X,Y,bicho)
     xorsprite (X,Y,bicho+64)

     andsprite (32,232,bicho)
     xorsprite (32,232,bicho+64)

     cpbuffer(XE,YE,@buserene)
     andsprite (XE,YE,enemigo)
     xorsprite (XE,YE,enemigo+64)

     andsprite (32,8,enemigo)
     xorsprite (32,8,enemigo+64)

bucle:

    IF DEMO=1 THEN GOTO DEMOMODE: END IF


    LET O=MULTIKEYS(KEYO)
    LET P= MULTIKEYS(KEYP)
    LET M=MULTIKEYS(KEYM)
    LET Q=MULTIKEYS(KEYU):IF Q>0 AND salto=0 THEN LET salto=SALTAR:END IF
    IF M>0 AND O>0 AND disparo=0 THEN LET disparo=1:LET XDISP=X: LET YDISP=Y-16: LET XDISPA=X:LET YDISPA=Y-16: LET PROY=gfxproyizda: LET MOVPROY=-VELDISPARO: END IF
    IF M>0 AND P>0 AND disparo=0 THEN LET disparo=1:LET XDISP=X: LET YDISP=Y+16: LET XDISPA=X:LET YDISPA=Y+16: LET PROY=gfxproydcha: LET MOVPROY=VELDISPARO:END IF

    IF JUGADORES=1 THEN GOTO INTELIGENCIA: END IF

    LET OE=MULTIKEYS(KEYQ)
    LET PE= MULTIKEYS(KEYW)
    LET QE=MULTIKEYS(KEYV)
    LET R=MULTIKEYS(KEYR):IF R>0 AND saltoE=0 THEN LET saltoE=SALTARE:END IF
    IF QE>0 AND OE>0 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE-16: LET XDISPAE=XE:LET YDISPAE=YE-16: LET PROYE=gfxproyeizda: LET MOVPROYE=-VELDISPAROE: END IF
    IF QE>0 AND PE>0 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE+16: LET XDISPAE=XE:LET YDISPAE=YE+16: LET PROYE=gfxproyedcha: LET MOVPROYE=VELDISPAROE:END IF

    GOTO DECISIONIMPRIME

REM MOVIMIENTO ENEMIGO
INTELIGENCIA:
    LET PE=0:LET PO=0:LET QE=0:LET DIF=X-XE: LET DIFY=Y-YE
    IF Y>YE AND Y-YE>36 THEN LET PE=1:ELSE LET PE=0:END IF
    IF Y<YE AND YE-Y>36 THEN LET OE=1:ELSE LET OE=0:END IF


    IF disparo=1 AND saltoE=0 THEN LET QE=1: END IF

    IF QE>0 AND saltoE=0 THEN LET saltoE=SALTARE:END IF
    
    IF Y>YE AND ABS DIF<20 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE+16: LET XDISPAE=XE:LET YDISPAE=YE+16: LET PROYE=gfxproyedcha: LET MOVPROYE=VELDISPAROE: END IF
    IF Y<YE AND ABS DIF<20 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE-16: LET XDISPAE=XE:LET YDISPAE=YE-16: LET PROYE=gfxproyeizda: LET MOVPROYE=-VELDISPAROE: END IF

    IF Y>YE AND Y<80 THEN LET PE=1:END IF
    IF YE>Y AND Y>176 THEN LET OE=1:END IF

DECISIONIMPRIME:
    IF O+P>0 OR salto>0 OR OE+PE>0 OR saltoE>0  OR disparo>0 OR disparoE>0 THEN GOSUB imprime : END IF

goto bucle

DEMOMODE:
    IF MULTIKEYS (KEYENTER)<>0 THEN GOTO menu: END IF
    LET P=0:LET O=0:LET Q=0
    IF Y<40 THEN LET CAMINO=0:END IF
    IF Y>210 THEN LET CAMINO=1: END IF
    IF CAMINO=1 THEN LET O=1:END IF
    IF CAMINO=0 THEN LET P=1: END IF


SEGUNDAOPCION:

    IF disparoE=1 AND salto=0 THEN LET Q=1: END IF

    IF Q>0 AND salto=0 THEN LET salto=SALTAR:END IF
    
    IF Y<YE AND disparo=0 THEN LET disparo=1:LET XDISP=X: LET YDISP=Y+16: LET XDISPA=X:LET YDISPA=Y+16: LET PROY=gfxproydcha: LET MOVPROY=VELDISPARO: END IF
    IF Y>YE AND disparo=0 THEN LET disparo=1:LET XDISP=X: LET YDISP=Y-16: LET XDISPA=X:LET YDISPA=Y-16: LET PROY=gfxproyizda: LET MOVPROY=-VELDISPARO: END IF

    LET PE=0:LET PO=0:LET QE=0:LET DIF=X-XE: LET DIFY=Y-YE
    IF Y>YE AND Y-YE>36 THEN LET PE=1:ELSE LET PE=0:END IF
    IF Y<YE AND YE-Y>36 THEN LET OE=1:ELSE LET OE=0:END IF

    IF disparo=1 AND saltoE=0 THEN LET QE=1: END IF

    IF QE>0 AND saltoE=0 THEN LET saltoE=SALTARE:END IF
    
    IF Y>YE AND ABS DIF<20 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE+16: LET XDISPAE=XE:LET YDISPAE=YE+16: LET PROYE=gfxproyedcha: LET MOVPROYE=VELDISPAROE: END IF
    IF Y<YE AND ABS DIF<20 AND disparoE=0 THEN LET disparoE=1:LET XDISPE=XE: LET YDISPE=YE-16: LET XDISPAE=XE:LET YDISPAE=YE-16: LET PROYE=gfxproyeizda: LET MOVPROYE=-VELDISPAROE: END IF

    IF Y>YE AND Y<80 THEN LET PE=1:END IF
    IF YE>Y AND Y>176 THEN LET OE=1:END IF

    GOTO DECISIONIMPRIME

stop
imprime:
     IF O<>0 AND Y>8 THEN LET Y=Y-VELOCIDAD:LET bicho=protaizda:let frame=frame+1:if frame>1 then let frame=0:end if:  END IF
     IF P<>0 AND Y<232 THEN LET Y=Y+VELOCIDAD: LET bicho=protadcha:let frame=frame+1:if frame>1 then let frame=0:end if: END IF
     IF salto>SALTAR/2 THEN LET X=X-1:LET salto=salto-1:
        ELSE IF salto<1+SALTAR/2 AND salto>0 THEN LET X=X+1: LET salto=salto-1: END IF: END IF

     IF OE>0 AND YE>8 THEN LET YE=YE-VELOCIDADE:LET enemigo=eneizda:let frameE=frameE+1:if frameE>1 then let frameE=0:end if:  END IF
     IF PE>0 AND YE<232 THEN LET YE=YE+VELOCIDADE: LET enemigo=enedcha:let frameE=frameE+1:if frameE>1 then let frameE=0:end if: END IF
     IF saltoE>SALTARE/2 THEN LET XE=XE-1:LET saltoE=saltoE-1:
        ELSE IF saltoE<1+SALTARE/2 AND saltoE>0 THEN LET XE=XE+1: LET saltoE=saltoE-1: END IF: END IF

    asm
    halt
    end asm
movbicho:

     rstbuffer(XA,YA,@buser)
     rstbuffer(XAE,YAE,@buserene)

saltouno:
     cpbuffer(XE,YE,@buserene)
     cpbuffer(X,Y,@buser)
     if disparo<1 then goto saltodos: end if
     xorsprite (XDISPA,YDISPA,PROY)

saltodos:
     if disparoE<1 then goto saltodosmedio: end if
     xorsprite (XDISPAE,YDISPAE,PROYE)
saltodosmedio:
     andsprite (X,Y,bicho+frame*32)
     xorsprite (X,Y,bicho+64+frame*32)
movenemigo:


     andsprite (XE,YE,enemigo+frameE*32)
     xorsprite (XE,YE,enemigo+64+frameE*32)
     if disparo<1 then goto saltotres : end if
     xorsprite (XDISP,YDISP,PROY)
saltotres:
     if disparoE<1 then goto saltotresmedio : end if
     xorsprite (XDISPE,YDISPE,PROYE)

saltotresmedio:
    LET XA=X:LET YA=Y:LET XAE=XE:LET YAE=YE
    if disparo<1 then goto saltocuatro:END IF
    LET YDISP=YDISP+MOVPROY
    IF YDISP<1 OR YDISP>240 THEN LET disparo=0:gosub DISPEND: END IF
    let YDISPA=YDISP
saltocuatro:
    if disparoE<1 then goto saltocuatromedio:END IF
    LET YDISPE=YDISPE+MOVPROYE
    IF YDISPE<1 OR YDISPE>240 THEN LET disparoE=0:gosub DISPEND: END IF
    let YDISPAE=YDISPE
saltocuatromedio:
    for coluno=1 to FUERZAE:GOSUB COLISIONESUNO:NEXT
    FOR COLDOS=1 TO FUERZA:GOSUB COLISIONESDOS:NEXT
    return
DISPIZDA:

     LET disparo=2
    return
DISPEND:

     return
    
COLISIONESUNO:
    IF Y-YDISPE>16 THEN RETURN: END IF
    IF X-XDISPE>16 THEN RETURN: END IF
    LET GOLPE=GOLPE+1
    BEEP .005,RND*8
    PAPER 8: INK 8
    PLOT 248,192-GOLPE
    DRAW 7,0
    IF GOLPE>64 THEN GOTO GANAENE : END IF
    RETURN
COLISIONESDOS:
    IF YE-YDISP>16 THEN RETURN: END IF
    IF XE-XDISP>16 THEN RETURN: END IF
    LET GOLPEE=GOLPEE+1
    BEEP .005,RND*8
    PAPER 8: INK 8
    PLOT 40,192-GOLPEE
    DRAW 7,0
    IF GOLPEE>64 THEN GOTO GANAPROTA : END IF
    RETURN
GANAENE:
        PRINT FLASH 1;PAPER 2;INK 7; BOLD 1; AT 15,12;"PLY2 WIN!":PAUSE 1:PAUSE 50:FOR PAUSA=O TO 30000:NEXT:GOTO menu
GANAPROTA:
        PRINT FLASH 1;PAPER 3;INK 1; BOLD 1; AT 15,12;"PLY1 WIN!":PAUSE 1:PAUSE 50:FOR PAUSA=O TO 30000:NEXT: GOTO menu
    end

#include <sprite.bas>
#include <spritebuffer.bas>
#include <unchunk.bas>

ondaizda:
ASM

ondaizda:
    DEFB      0,  0,  4,  0, 28,128, 57,136
    DEFB     99, 25,102, 51,204,103,216,204
    DEFB    216,204,204,103,102, 51, 99, 25
    DEFB     57,136, 28,128,  4,  0,  0,  0
END ASM
ondadcha:
ASM
    DEFB      0,  0,  0, 32,  1, 56, 17,156
    DEFB    152,198,204,102,230, 51, 51, 27
    DEFB     51, 27,230, 51,204,102,152,198
    DEFB     17,156,  1, 56,  0, 32,  0,  0
END ASM
telefono:
ASM
    DEFB    127,254,255,255,255,255,240, 15
    DEFB    112, 14,  0,  0,  4, 16, 15,248
    DEFB     25, 44, 29,100, 63,254, 46,178
    DEFB     36,154,127,255,127,255,127,255
END ASM

etizda:
ASM
et:
    DEFB    128,  1,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,192,  0,  0,  0,  0,  0
    DEFB      0,  0,224,  0,128,  1,128,  1
    DEFB    224,  1,192,  0,192,  0,192,  0
    DEFB    192,  0,192,  0,192,  0,192,  0
    DEFB    192,  0,192,  0,128,  0,128,  0
    DEFB    128,  1,224,  3,224,  7,224,  7
    DEFB      0,  0, 63,252,127,254, 79,238
    DEFB    111,254,127,254, 31,230,127,  6
    DEFB      0, 62,  3,254, 31,254,127,254
    DEFB     15,254,  6,236, 14, 28, 62,124
    DEFB      0,  0, 15,252, 31,254, 18,110
    DEFB     23,126, 31,254, 16,230, 31,198
    DEFB      0, 62,  3,254, 31,254, 63,252
    DEFB     15,248,  1,176,  3,240, 15,240
END ASM
etdcha:
ASM
etdcha:
    DEFB    128,  1,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  3,  0,  0,  0,  0
    DEFB      0,  0,  0,  7,128,  1,128,  1
    DEFB    128,  7,  0,  3,  0,  3,  0,  3
    DEFB      0,  3,  0,  3,  0,  3,  0,  3
    DEFB      0,  3,  0,  3,  0,  1,  0,  1
    DEFB    128,  1,192,  7,224,  7,224,  7
    DEFB      0,  0, 63,252,127,254,119,242
    DEFB    127,246,127,254,103,248, 96,254
    DEFB    124,  0,127,192,127,248,127,254
    DEFB    127,240, 55, 96, 56,112, 62,124
    DEFB      0,  0, 63,240,127,248,118, 72
    DEFB    126,232,127,248,103,  8, 99,248
    DEFB    124,  0,127,192,127,248, 63,252
    DEFB     31,240, 13,128, 15,192, 15,240

END ASM
macistedcha:
ASM
macistedcha:
    DEFB    192,  7,192,  7,192,  7,192,  7
    DEFB    192,  3,128,  1,128,  1,128,  1
    DEFB    128,  1,128,  1,192,  1,224,  3
    DEFB    248, 15,248,  7,248,  3,248,  3
    DEFB    224,  3,224,  3,224,  3,224,  3
    DEFB    224,  3,192,  1,192,  0,192,  0
    DEFB    192,  0,224,  0,240,  7,224, 15
    DEFB    192,  1,192,  1,192,129,193,195
    DEFB     15,224, 29,176, 31,240, 15, 96
    DEFB      3,128, 27,184, 59,220, 55,236
    DEFB     59,236, 29,220, 13,216,  3,192
    DEFB      3, 64,  3, 96,  3,176,  3,216
    DEFB      7,240, 15,104, 15,248,  7, 48
    DEFB      1,192, 13,232, 27,252, 29,246
    DEFB     14,246,  6,240,  1,224,  3,192
    DEFB     15, 96, 30,116, 24, 60, 12, 24
END ASM
macisteizda:
ASM
macisteizda:
    DEFB    224,  3,224,  3,224,  3,224,  3
    DEFB    192,  3,128,  1,128,  1,128,  1
    DEFB    128,  1,128,  1,128,  3,192,  7
    DEFB    240, 31,224, 31,192, 31,192, 31
    DEFB    192,  7,192,  7,192,  7,192,  7
    DEFB    192,  7,128,  3,  0,  3,  0,  3
    DEFB      0,  3,  0,  7,224, 15,240,  7
    DEFB    128,  3,128,  3,129,  3,195,131
    DEFB      7,240, 13,184, 15,248,  6,240
    DEFB      1,192, 29,216, 59,220, 55,236
    DEFB     55,220, 59,184, 27,176,  3,192
    DEFB      2,192,  6,192, 13,192, 27,192
    DEFB     15,224, 22,240, 31,240, 12,224
    DEFB      3,128, 23,176, 63,216,111,184
    DEFB    111,112, 15, 96,  7,128,  3,192
    DEFB      6,240, 46,120, 60, 24, 24, 48
END ASM
arquerodcha:
ASM
    DEFB    240, 63,224, 15,224,  7,224,  3
    DEFB    192,  1,128,  0,128,  0,192,  0
    DEFB    224, 16,240, 24,224, 56,224, 17
    DEFB    240,  3,240,  7,240, 15,240, 31
    DEFB    240, 63,224, 15,224,  7,224,  3
    DEFB    192,  1,128,  0,128,  0,192,  0
    DEFB    224,  0,224,  0,224,  0,224,  1
    DEFB    224,  3,194,  7,135,  7,131,131
    DEFB      7,128, 15, 64, 15,240,  7,168
    DEFB     27, 68, 54,242, 57,126, 30,143
    DEFB     14,193,  1, 66, 14,130, 15, 68
    DEFB      5,168,  5,176,  7,128,  7,192
    DEFB      7,128, 15, 64, 15,240,  7,168
    DEFB     27, 68, 54,242, 57,126, 30,143
    DEFB     14,193,  1, 66, 14,130, 15,116
    DEFB     13,136, 24,192, 48,112, 56, 56
END ASM
arqueroizda:
ASM
    DEFB    252, 15,240,  7,224,  7,192,  7
    DEFB    128,  3,  0,  1,  0,  1,  0,  3
    DEFB      8,  7, 24, 15, 28,  7,136,  7
    DEFB    192, 15,224, 15,240, 15,248, 15
    DEFB    252, 15,240,  7,224,  7,192,  7
    DEFB    128,  3,  0,  1,  0,  1,  0,  3
    DEFB      0,  7,  0,  7,  0,  7,128,  7
    DEFB    192,  7,224, 67,224,225,193,193
    DEFB      1,224,  2,240, 15,240, 21,224
    DEFB     34,216, 79,108,126,156,241,120
    DEFB    131,112, 66,128, 65,112, 34,240
    DEFB     21,160, 13,160,  1,224,  3,224
    DEFB      1,224,  2,240, 15,240, 21,224
    DEFB     34,216, 79,108,126,156,241,120
    DEFB    131,112, 66,128, 65,112, 46,240
    DEFB     17,176,  3, 24, 14, 12, 28, 28
END ASM
flechaizda:
ASM
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0, 24, 18,120, 36
    DEFB    255,252,120, 36, 24, 18,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
END ASM
flechadcha:
ASM
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0, 72, 24, 36, 30
    DEFB     63,255, 36, 30, 72, 24,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
END ASM
zeusizda:
ASM
    DEFB    224, 63,192, 31,224, 15,224, 15
    DEFB    192,  7,128,  3,  0,  1,  0,  1
    DEFB      0,  1,128,  3,128,  7,128,  7
    DEFB    128,  7,128,  1,128,  0,192,  0
    DEFB    224, 63,192, 31,224, 15,224, 15
    DEFB    192,  7,128,  3,  0,  1,  0,  1
    DEFB      0,  1, 96,  1,240,  1,224,  3
    DEFB    192,  7,128,  7,  0,  7,  0,  7
    DEFB     15,128, 31,192,  9, 96,  0, 32
    DEFB     31,160, 25,184, 95,132,175, 20
    DEFB     47, 44, 47, 56, 38, 48, 38,  0
    DEFB     40, 16, 40,  8, 40,  6, 15,254
    DEFB     15,128, 31,192,  9, 96,  0, 32
    DEFB     31,160, 25,184, 95,132,175, 20
    DEFB    151, 20, 11, 20,  4, 28, 10,  0
    DEFB     17, 16, 48,144, 96, 16,127,240
END ASM
zeusdcha:
ASM
    DEFB    252,  7,248,  3,240,  7,240,  7
    DEFB    224,  3,192,  1,128,  0,128,  0
    DEFB    128,  0,192,  1,224,  1,224,  1
    DEFB    224,  1,128,  1,  0,  1,  0,  3
    DEFB    252,  7,248,  3,240,  7,240,  7
    DEFB    224,  3,192,  1,128,  0,128,  0
    DEFB    128,  0,128,  6,128, 15,192,  7
    DEFB    224,  3,224,  1,224,  0,224,  0
    DEFB      1,240,  3,248,  6,144,  4,  0
    DEFB      5,248, 29,152, 33,250, 40,245
    DEFB     52,244, 28,244, 12,100,  0,100
    DEFB      8, 20, 16, 20, 96, 20,127,240
    DEFB      1,240,  3,248,  6,144,  4,  0
    DEFB      5,248, 29,152, 33,250, 40,245
    DEFB     40,233, 40,208, 56, 32,  0, 80
    DEFB      8,136,  9, 12,  8,  6, 15,254
END ASM
rayo:
ASM
    DEFB      0,  0,  0,  0,  0,  7,  0, 11
    DEFB      1, 21,  2,170,  5, 84, 10,168
    DEFB     21, 80, 42,160, 84, 64,168,  0
    DEFB    208,  0,224,  0,  0,  0,  0,  0
END ASM
buser:
ASM
buser:
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
END ASM
buserene:
ASM
buserene:
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
        defb 0,0,0,0,0,0,0,0
END ASM


marbella:
asm
incbin"marbella.rle"
END ASM
ny:
asm
incbin"ny.rle"
END ASM
pascua:
asm
incbin"pascua.rle"
END ASM
stonehedge:
asm
incbin"stonehedge.rle"
END ASM
logo:
asm
incbin"ruinsfighter.bin"
END ASM
partenon:
ASM
incbin"partenon.rle"
END ASM
Reply
#13
Unchunk: This is the uncompression routine by S.Romero (I think, but not sure) posted in the Speccy.org wiki:

Code:
SUB unchunk (source as uinteger,display as uinteger,size as uinteger)
POKE uinteger @datosch,source: POKE uinteger @datosch+2,display: POKE uinteger @datosch+4,size
gosub chunk
END SUB
datosch:
ASM
sourcech:      defw 0
displaych:     defw 0
sizech:        defw 0
END ASM
chunk:
ASM
; Prueba de descompresion RLE
  ; Desempaquetamos un SCR comprimido con RLE sobre la pantalla
  ;ORG 32768

  ; Cargamos los datos y preparamos nuestra rutina
  LD HL, (sourcech)
  LD DE, (displaych)
  LD BC, (sizech)
  ;CALL RLE_decompress




;;
;; RLE_decompress
;; Descomprime un bloque de datos RLE de memoria a memoria.
;;
;; Entrada a la rutina:
;;
;; HL = dirección origen de los datos RLE.
;; DE = destino donde descomprimir los datos.
;; BC = tamaño de los datos comprimidos.
;;
RLE_decompress:

RLE_dec_loop:
   ld a,(hl)                          ; leemos un byte

   cp 192
   jp nc, RLE_dec_compressed          ; si byte > 192 = está comprimido
   ld (de), a                         ; si no está comprimido, escribirlo
   inc de
   inc hl
   dec bc

RLE_dec_loop2:
   ld a,b
   or c
   jr nz, RLE_dec_loop
   ret                                 ; miramos si hemos acabado

RLE_dec_compressed:                    ; bucle para descompresión
   push bc  
   and 63                              ; cogemos el numero de repeticiones
   ld b, a                             ; lo salvamos en B
   inc hl                              ; y leemos otro byte (dato a repetir)
   ld a, (hl)

RLE_dec_loop3:
   ld (de),a                           ; bucle de escritura del dato B veces
   inc de
   djnz RLE_dec_loop3
   inc hl
   pop bc                              ; recuperamos BC
   dec bc                              ; Este DEC BC puede hacer BC=0 si los datos
                                       ; RLE no correctos. Cuidado (mem-smashing).
   dec bc
   jr RLE_dec_loop2
   ret
END ASM
Reply
#14
Sprite.bas: This is a sprite shifting routine by Johnatan Cauldwell. I modified it a bit so it could not only XOR graphics, but also AND, OR and stright PRINT. I only use the AND and XOR because I love masked graphics.

It's too slow ATM, so it flickers a lot (which is good for a game made for the crap games compo). I want to make a version that works in a backbuffer and then copy the buffer to screen. In fact that's what I am doing at the moment (the transfer routine), but it's my first ever assembler routine and I'm having problems Smile I'll post it when it's finished Smile

Code:
SUB psprite (xd as ubyte,yd as ubyte,gfx as uinteger)
POKE @esprite,xd: POKE @esprite+1,yd: POKE Uinteger (@esprite+2),gfx
POKE @xor1,121:POKE @xor2,122:POKE @xor3,123
gosub printsprite
END SUB

SUB xorsprite (xd as ubyte,yd as ubyte,gfx as uinteger)
POKE @esprite,xd: POKE @esprite+1,yd: POKE Uinteger (@esprite+2),gfx
POKE @xor1,169:POKE @xor2,170:POKE @xor3,171:POKE @mask+1,0: POKE @carry,167':POKE @esprite+5,7:'POKE @esprite+4,255':POKE @esprite+6,60
gosub printsprite
END SUB

SUB andsprite (xd as ubyte,yd as ubyte,gfx as uinteger)
POKE @esprite,xd: POKE @esprite+1,yd: POKE Uinteger (@esprite+2),gfx
POKE @xor1,161:POKE @xor2,162:POKE @xor3,163:POKE @mask+1,255:POKE @carry,0':POKE @esprite+5,0:POKE @esprite+4,246'230':POKE @esprite+6,0
gosub printsprite
END SUB

SUB orsprite (xd as ubyte,yd as ubyte,gfx as uinteger)
POKE @esprite,xd: POKE @esprite+1,yd: POKE Uinteger (@esprite+2),gfx
POKE @xor1,177:POKE @xor2,178:POKE @xor3,179
gosub printsprite
END SUB

SUB spriteh (h as ubyte)
POKE @altura+1,h
END SUB



esprite:
ASM
xp: defb 0
yp: defb 0
gfxdir: defw 0




; This is the sprite routine and expects coordinates in (c ,b) form,
; where c is the vertical coord from the top of the screen (0-176), and
; b is the horizontal coord from the left of the screen (0 to 240).
; Sprite data is stored as you'd expect in its unshifted form as this
; routine takes care of all the shifting itself.  This means that sprite
; handling isn't particularly fast but the graphics only take 1/8th of the
; space they would require in pre-shifted form.

; On entry HL must point to the unshifted sprite data.

sprit7: xor 7               ; complement last 3 bits.
       inc a               ; add one for luck!
sprit3: rl d                ; rotate left...
       rl c                ; ...into middle byte...
       rl e                ; ...and finally into left character cell.
       dec a               ; count shifts we've done.
       jr nz,sprit3        ; return until all shifts complete.

; Line of sprite image is now in e + c + d, we need it in form c + d + e.

       ld a,e              ; left edge of image is currently in e.
       ld e,d              ; put right edge there instead.
       ld d,c              ; middle bit goes in d.
       ld c,a              ; and the left edge back into c.
       jr sprit0           ; we've done the switch so transfer to screen.
END ASM
printsprite:
ASM
sprite:
       ld hl,(gfxdir)
       ld bc,(xp)
       ld (dispx),bc       ; store coords in dispx for now.
       call scadd          ; calculate screen address.
END ASM
altura:
ASM
       ld a,16             ; height of sprite in pixels.
sprit1: ex af,af'           ; store loop counter.
       push de             ; store screen address.
       ld c,(hl)           ; first sprite graphic.
       inc hl              ; increment poiinter to sprite data.
       ld d,(hl)           ; next bit of sprite image.
       inc hl              ; point to next row of sprite data.
       ld (sprtmp),hl      ; store it for later.
END ASM
mask:
ASM
       ld e,0              ; blank right byte for now.
       ld a,b              ; b holds y position.
       and 7               ; how are we straddling character cells?
       jr z,sprit0         ; we're not straddling them, don't bother shifting.
       cp 8                ; 5 or more right shifts needed?
       jr nc,sprit7        ; yes, shift from left as it's quicker.
end asm
carry:
asm
       and a               ; oops, carry flag is set so clear it.
sprit2: rr c                ; rotate left byte right...
       rr d                ; ...through middle byte...
       rr e                ; ...into right byte.
       dec a               ; one less shift to do.
       jr nz,sprit2        ; return until all shifts complete.
sprit0: pop hl              ; pop screen address from stack.
       ld a,(hl)           ; what's there already.
END ASM
xor1:
ASM
       xor c               ; merge in image data.   a9 169             a1  161               79 121           b1  177
       ld (hl),a           ; place onto screen.
       inc l               ; next character cell to right please.
       ld a,(hl)           ; what's there already.
END ASM
xor2:
ASM
       xor d               ; merge with middle bit of image.    aa  170           a2 162            7a 122      b2  178
       ld (hl),a           ; put back onto screen.
       inc l               ; next bit of screen area.
       ld a,(hl)           ; what's already there.
END ASM
xor3:
ASM
       xor e               ; right edge of sprite image data.     ab 171            a3 163             7b 123         b3    179
       ld (hl),a           ; plonk it on screen.
       ld a,(dispx)        ; vertical coordinate.
       inc a               ; next line down.
       ld (dispx),a        ; store new position.
       and 63              ; are we moving to next third of screen?
       jr z,sprit4         ; yes so find next segment.
       and 7               ; moving into character cell below?
       jr z,sprit5         ; yes, find next row.
       dec l               ; left 2 bytes.
       dec l               ; not straddling 256-byte boundary here.
       inc h               ; next row of this character cell.
sprit6: ex de,hl            ; screen address in de.
       ld hl,(sprtmp)      ; restore graphic address.
       ex af,af'           ; restore loop counter.
       dec a               ; decrement it.
       jp nz,sprit1        ; not reached bottom of sprite yet to repeat.
       ret                 ; job done.
sprit4: ld de,30            ; next segment is 30 bytes on.
       add hl,de           ; add to screen address.
       jp sprit6           ; repeat.
sprit5: ld de,63774         ; minus 1762.
       add hl,de           ; subtract 1762 from physical screen address.
       jp sprit6           ; rejoin loop.


; This routine returns a screen address for (c, b) in de.

scadd:  ld a,c              ; get vertical position.
       and 7               ; line 0-7 within character square.
       add a,64            ; 64 * 256 = 16384 (Start of screen display)
       ld d,a              ; line * 256.
       ld a,c              ; get vertical again.
       rrca                ; multiply by 32.
       rrca
       rrca
       and 24              ; high byte of segment displacement.
       add a,d             ; add to existing screen high byte.
       ld d,a              ; that's the high byte sorted.
       ld a,c              ; 8 character squares per segment.
       rlca                ; 8 pixels per cell, mulplied by 4 = 32.
       rlca                ; cell x 32 gives position within segment.
       and 224             ; make sure it's a multiple of 32.
       ld e,a              ; vertical coordinate calculation done.
       ld a,b              ; y coordinate.
       rrca                ; only need to divide by 8.
       rrca
       rrca
       and 31              ; squares 0 - 31 across screen.
       add a,e             ; add to total so far.
       ld e,a              ; hl = address of screen.
       ret


dispx: defb 0        ; general-use coordinates.
dispy: defb 0
sprtmp: defw 0          ; sprite temporary address.

END ASM
Reply
#15
apenao Wrote:Here goes the .bas listing of the program. I'll post the custom library files following this. I have to think of a way to send the binary files.
You should be able to upload .zip files attached to the previous message (I'm enabling them). :wink:
Reply


Forum Jump:


Users browsing this thread: 7 Guest(s)