BUILDSNA : BANKSET 0
ORG #38 : EI : RET
ORG #100 : RUN #100
struct sprite
positionx defw
positiony defw
donnees defw
sprLargeur defb ; si zéro, liste terminée
sprHauteur defb
adresseEcran defw ; pour la restitution
resLargeur defb ; pour la restitution (si 0, ne rien faire)
resHauteur defb ; pour la restitution
adresseSauvegarde defw ; pour la restitution
endstruct
ld sp,#100 : ei
ld bc,#7F00+%10001100+%00 : out (c),c ; MODE 0
ld hl,palette : ld bc,#7F00
setPalette out (c),c : inc c : inc b : outi : ld a,(hl) : or a : jr nz,setPalette
reboucle
ld iy,tableauTic : call RestituerPortionEcran ; ne fera rien à la première exécution
ld iy,tableauTic : call BougeSprite
ld iy,tableauTic : ld a,#C0 : ld (videoBank),a
call AfficherTableauSprite : call WaitVBL : ld bc,#BC00+12 : out (c),c : ld bc,#BD30 : out (c),c
ld iy,tableauToc : call RestituerPortionEcran ; ne fera rien à la première exécution
ld iy,tableauToc : call BougeSprite
ld iy,tableauToc : ld a,#80 : ld (videoBank),a
call AfficherTableauSprite : call WaitVBL : ld bc,#BC00+12 : out (c),c : ld bc,#BD20 : out (c),c
jr reboucle
;---------------------------------------------------------------------
BougeSprite
;---------------------------------------------------------------------
ld hl,(.positionx) : ld de,(.bougex) : add hl,de : ld (.positionx),hl : ld (iy+sprite.positionx),hl ; bouger et mettre à jour la structure courante
ld hl,(.positiony) : ld de,(.bougey) : add hl,de : ld (.positiony),hl : ld (iy+sprite.positiony),hl ; idem pour le Y
; gérer les changements de direction
ld a,(.bougey) : or a : jr z,.testx
; on bouge en Y, tester le min et le max
ld a,(.positiony) : cp -18 : jp z,.aDroite
cp 184 : jp z,.aGauche
ret
.testx
ld a,(.positionx) : cp #FC : jr z,.enHaut
cp 76 : jr z,.enBas
ret
.aDroite ld hl,0 : ld (.bougey),hl : inc l : ld (.bougex),hl : ret
.aGauche ld hl,0 : ld (.bougey),hl : dec hl : ld (.bougex),hl : ret
.enBas ld hl,0 : ld (.bougex),hl : inc l : inc l : ld (.bougey),hl : ret
.enHaut ld hl,0 : ld (.bougex),hl : dec hl : dec hl : ld (.bougey),hl : ret
.positionx defw 76
.positiony defw 164
.bougex defw 0
.bougey defw 2
tableauTic
defw 0 ; posx
defw 0 ; posy
defw donnees_sprite
defb 9,36 ; dimensions
defw 0
defb 0,0
defw tamponTic
defs {sizeof}sprite ; une structure vide pour arrêter le tableau
tableauToc
defw 0 ; posx
defw 0 ; posy
defw donnees_sprite
defb 9,36 ; dimensions
defw 0
defb 0,0
defw tamponToc
defs {sizeof}sprite ; une structure vide pour arrêter le tableau
;----------------------------------------------------
WaitVBL
ld b,#F5
.loop in a,(c) : rra : jr nc,.loop : ret
;----------------------------------------------------
AfficherTableauSprite
;----------------------------------------------------
.loop
ld (iy+sprite.resLargeur),0 ; la largeur de restitution sera notre TAG qu'il faut restituer
ld hl,(iy+sprite.positionx)
bit 7,h : jr nz,.testGauche ; si c'est négatif on fait le test de gauche
; on teste le débordement à droite (80 octets en configuration standard)
ld de,80 : or a : sbc hl,de
jp m,.hautBas
jr .horsEcran
.testGauche
ld a,(iy+sprite.sprlargeur) : add l : ld l,a : ld a,h : adc 0
jp m,.horsEcran ; négatif hors écran, reste à tester le zéro
ld a,l : or a : jr z,.horsEcran ; on fait un raccourci de calcul car on partait d'une position négative
; quasiment le même code de tester le débordement en vertical
.hautBas
ld hl,(iy+sprite.positiony)
bit 7,h : jr nz,.testHaut ; si c'est négatif on fait le test du haut
; on teste le débordement en bas de l'écran de 200 lignes
ld de,200 : or a : sbc hl,de
jp m,.affiche
jr .horsEcran
.testHaut
ld a,(iy+sprite.sprhauteur) : add l : ld l,a : ld a,h : adc 0
jp m,.horsEcran ; négatif hors écran, reste à tester le zéro
ld a,l : or a : jr z,.horsEcran ; on fait un raccourci de calcul car on partait d'une position négative
.affiche
ld b,#C0 : videoBank=$-1 ; bank vidéo par défaut
ld c,(iy+sprite.positionx) ; on peut ne lire que 16 bits à la même adresse, merci le little endian
ld hl,(iy+sprite.positiony)
ld de,(iy+sprite.donnees)
ld a,(iy+sprite.sprlargeur) : ld xl,a
ld a,(iy+sprite.sprhauteur) : ld xh,a
push iy ; car notre routine de sprite masqué utilise YL ...
call AfficheSprite
pop iy
.horsEcran
; ajouter ici une condition de bouclage, par exemple sur les données...
ld de,{sizeof}sprite : add iy,de
ld a,(iy+sprite.sprlargeur) : or a ; tester la largeur du prochain sprite
jp nz,.loop ; on reboucle si le prochaine sprite n'a pas une largeur nulle
ret
;----------------------------------------------------
AfficheSprite
;----------------------------------------------------
; BC=page + coordonnée X (0-79) / HL=coordonnée Y (0-199) / DE=adresse des données du sprite
; XL=largeur du sprite en octets / XH=hauteur du sprite en nombre de lignes
bit 7,h : jr z,.pasClipHaut ; si le Y est positif ou nul, pas de clipping en haut
; XH est la hauteur affichable, on soustrait le Y négatif
push hl : ld a,xh : add l : ld l,a : ld a,h : adc 0 : ld h,a : ld a,l : ld xh,a : pop hl
; vu qu'on saute des lignes, il faut avancer le pointeur de données
ld a,l : ex hl,de : ld d,0 : ld e,xl
.sauteLignes add hl,de : inc a : jr nz,.sauteLignes ; +simple qu'une multiplication
ex hl,de ; remettre le pointeur dans DE
ld hl,0 ; tout est corrigé, on dit qu'on part maintenant de la ligne 0
.pasClipHaut
; pour rester sur des comparaisons 8 bits, on peut soustraire sprHauteur à hauteur et comparer à sprY
ld a,200 : sub xh : cp l : jr nc,.pasClipBas ;
ld a,200 : sub l : ld xh,a ; nouvelle hauteur +petite
.pasClipBas
xor a ; offsetDebut par défaut
bit 7,c : jr z,.pasClipGauche
ld a,c : add xl : ld xl,a ; nouvelle largeur
ld a,c : neg ; nouvel offsetDebut
ld c,0 ; nouveau X en zéro
.pasClipGauche
ld (offsetDebut),a ; soit zéro, soit celui calculé lors du clipping
ld a,c : add xl : cp 81 ; largeur+1 rapport à la comparaison souhaitée
ld a,0 : jr c,.pasClipDroite ; A=0 au cas où on n'ait pas de clipping, pour reset offsetFin
ld a,xl : exa ; on met la largeur du sprite de côté
ld a,80 : sub c : ld xl,a ; nouvelle largeur de sprite
exa ; on récupère la largeur d'origine
sub xl
.pasClipDroite
ld (offsetFin),a
call CalculeAdressePixel
;----------------------------------------------------------------------------------------------------
; ici le clipping est terminé, on a des coordonnées dans l'écran et des tailles qui ne débordent pas
; IY n'est pas encore altéré, on peut inscire nos infos de sauvegarde du fond
ld (iy+sprite.adresseEcran),hl
ld a,xl : ld (iy+sprite.resLargeur),a
ld a,xh : ld (iy+sprite.resHauteur),a
call SauvegarderPortionEcran
;----------------------------------------------------------------------------------------------------
; HL=destination écran
; DE=toujours l'adresse source des données
ld bc,hl ; on utilise BC comme destination écran
ld h,hi(tableTransparence)
.afficheLignes
ld a,xl : ld yl,a ; chargeur la largeur d'une ligne dans YL
push bc ; on met l'adresse de début de la ligne de côté
ld a,e : add #12 : offsetDebut=$-1 : ld e,a : ld a,d : adc 0 : ld d,a
.pixelMasque
ld a,(de) ; lire le sprite
ld l,a ; octet du sprite dans L
ld a,(bc) ; on récupère l'octet de l'écran
and (hl) ; on applique le masque
or l ; on fusionne avec la donnée du sprite
ld (bc),a ; on remet dans l'écran
inc bc
inc de ; et on incrémente data+ecran
dec yl
jr nz,.pixelMasque
ld a,e : add #12 : offsetFin=$-1 : ld e,a : ld a,d : adc 0 : ld d,a
pop bc ; on récupère l'adresse du début de ligne
; et on calcule le passage à la ligne suivante
; notre routine de passage à la ligne suivante, adaptée pour BC
ld a,b : add 8 : ld b,a ; ajouter #800 à DE
and #38 ; on teste si on déborde de la bank (passage de page+#3800 à page+#0000)
jr nz,.nextLine ; pas zéro, on est toujours dans le même bloc de lignes
ld a,80 : add c : ld c,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc b : ld b,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
.nextLine
dec xh ; notre compteur de lignes
jr nz,.afficheLignes
ret
;----------------------------------------------------
SauvegarderPortionEcran
;----------------------------------------------------
; HL=source écran
; DE=tampon de sauvegarde
push de,hl
ld de,(iy+sprite.adresseSauvegarde)
ld a,xh : ld yh,a ; sauvegarde de XH
ld b,0
.sauvegardeLignes
ld c,xl ; chargeur la largeur d'une ligne
push hl ; on met l'adresse de début de la ligne de côté
ldir
pop hl ; on récupère l'adresse du début de ligne
; et on calcule le passage à la ligne suivante
ld a,h : add 8 : ld h,a ; ajouter #800 à HL
and #38 ; on teste si on déborde de la bank (passage de page+#3800 à page+#0000)
jr nz,.nextLine ; pas zéro, on est toujours dans le même bloc de lignes
ld a,80 : add l : ld l,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc h : ld h,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
.nextLine
dec xh ; notre compteur de lignes
jr nz,.sauvegardeLignes
ld a,yh : ld xh,a ; restitution de XH
pop hl,de
ret
;----------------------------------------------------
RestituerPortionEcranReboucle
;----------------------------------------------------
ld bc,{sizeof}sprite : add iy,bc ; sprite suivant!
;----------------------------------------------------
RestituerPortionEcran
;----------------------------------------------------
ld a,(iy+sprite.sprLargeur) : or a : ret z ; terminé
ld a,(iy+sprite.resLargeur) : or a : ret z ; terminé aussi ^_^
ld xl,a : ld a,(iy+sprite.resHauteur) : ld xh,a
ld hl,(iy+sprite.adresseSauvegarde)
ld de,(iy+sprite.adresseEcran)
ld b,0
.restitueLignes
ld c,xl ; chargeur la largeur d'une ligne
push de ; on met l'adresse de début de la ligne de côté
ldir
pop de ; on récupère l'adresse du début de ligne
; et on calcule le passage à la ligne suivante
ld a,d : add 8 : ld d,a ; ajouter #800 à HL
and #38 ; on teste si on déborde de la bank (passage de page+#3800 à page+#0000)
jr nz,.nextLine ; pas zéro, on est toujours dans le même bloc de lignes
ld a,80 : add e : ld e,a ; on ajoute 80 (largeur d'une ligne en octets) pour passer au bloc suivant
ld a,#C0 : adc d : ld d,a ; et on enlève #4000 (additionner #C000 c'est comme enlever #4000)
.nextLine
dec xh ; notre compteur de lignes
jr nz,.restitueLignes
jp RestituerPortionEcranReboucle
;----------------------------------------------------
CalculeAdressePixel
;----------------------------------------------------
; B=page vidéo #00, #40, #80 ou #C0
; C=coordonnée X (0-79)
; HL=coordonnée Y (0-199)
; adresse de la ligne dans HL en résultat
add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2
ld a,lo(tableau) : add l : ld l,a : ld a,h : adc hi(tableau): ld h,a
ld a,(hl) : inc hl
ld h,(hl) : ld l,a
add hl,bc ; ajouter la position X en octets et la page!
ret
;-------------------
adresse_ecran=#0000
largeur_ecran=80
;-------------------
tableau
;-------------------
repeat 25
repeat 8
defw adresse_ecran
adresse_ecran+=#800
rend
adresse_ecran+=largeur_ecran
adresse_ecran-=#4000
rend
align 256
;-------------------
tableTransparence
;-------------------
repeat 256,x
px=x-1 ; car le compteur va par défaut de 1 à 256 et non 0 à 255
masque=0
if (px & (128|32|8|2))==0
masque|=128|32|8|2 ; pour cet octet on conservera les données écran
endif
if (px & (64|16|4|1))==0
masque|=64|16|4|1 ; pour cet octet on conservera les données écran
endif
defb masque
rend
palette defb #4D,#54,#56,#5C,#46,#5E,#40,#47,#43,#4E,#4B,#4C,0 ; Rose en zéro
donnees_sprite incbin 'hibouZero.bin'
tamponTic defs 9*36
tamponToc defs 9*36
org #8000 : incbin 'foretZero.bin'
org #C000 : incbin 'foretZero.bin'
|