Bonjour à tous, je poste ce code qui me donne beaucoup de mal afin de solliciter votre aide. Il est censé faire avancer un personnage en alternant deux sprites l'un après l'autre, mais lors de son exécution, il s'arrête sur l'écran graphique en affichant le deuxième sprite :
.nolist
#define end .end
#define END .end
#define equ .equ
#define EQU .equ
#include "ti83asm.inc"
#include "tokens.inc"
.list
#define warrior_x 8265h
#define warrior_y 8266h

.org 9327h
call _CLRLCDFULL
call _runIndicOff
call _GRBUFCLR
call _homeUp
call _Axes
ld a, 30
ld (warrior_x), a
ld a, 30
ld (warrior_y), a
ld l, 0
ld h, 1
push hl ;initialisation en phase 1 du cycle de course

getkey :
call putwarrior
ld a, 0ffh
out (1), a
ld a,0feh
out (1), a
in a, (1)
cp 254
jp z, up
cp 247
jp z, down
ld a, 0ffh
out (1), a
ld a, 0fdh
out (1), a
in a, (1)
cp 191
jp z, quit
call putwarrior
ld a, (warrior_x)
inc a
ld (warrior_x), a
pop hl
ld a, h
xor 1 ; permet d'inverser l'indicateur sur 0 ou 1 pour alterner les images warrior_run1 et warrior_run2
ld h, a
ld l, 0
push hl
jp getkey
down :
call putwarrior
ld a, (warrior_y)
cp 51
jp z, getkey
dec a
ld (warrior_y), a
jp getkey

up :
call putwarrior
ld a, (warrior_y)
or a
jp z, getkey
inc a
ld (warrior_y), a
jp getkey

putwarrior :
pop hl
ld a, h
or a ;on effectue le test pour savoir si l'on est dans la première ou la deuxième phase du cycle de course
call z, putwarrior_first ;si le résultat est nul c'est que l'on est en première phase du cycle de course
call nz, putwarrior_second ;sinon on est en deuxième phase..
ld h, a
ld l, 0
push hl
ld a, (warrior_y)
ld l, a
ld a, (warrior_x)
call sprite
call _GRBUFCPY_V
ret

putwarrior_first :
ld ix, warrior_run1
ld b, 13
ret

putwarrior_second :
ld ix, warrior_run2
ld b, 12
ret

quit :
pop hl
call _CLRLCDFULL
call _GRBUFCLR
call _dispDone
ret

warrior_run1 :
.db %01111100
.db %00000000
.db %00111000
.db %00111000
.db %00111001
.db %00010010
.db %01111100
.db %10010000
.db %10011110
.db %00010010
.db %00100000
.db %01000000
.db %10000000

warrior_run2 :
.db %01111100
.db %00000000
.db %00111000
.db %00111000
.db %00111010
.db %00010010
.db %01111100
.db %10010000
.db %10011110
.db %00010010
.db %11110010
.db %00000000



sprite:
ld e, l
ld h, 0
ld d, h
add hl,de
add hl,de
add hl,hl
add hl,hl
ld e, a
and 7
ld c, a
srl e
srl e
srl e
add hl,de
ld de,plotSScreen
add hl,de

putSpriteLoop1:
sl1: ld d, (ix)
ld e, 0
ld a, c
or a
jr z, putSpriteSkip1

putSpriteLoop2:
srl d
rr e
dec a
jr nz,putSpriteLoop2

putSpriteSkip1:
ld a, (hl)
xor d
ld (hl),a
inc hl
ld a,(hl)
xor e
ld (hl),a
ld de,11
add hl,de
inc ix
djnz putSpriteLoop1
ret

.end END
En vous remerciant, d'avance.

Mystery_Enigma
Regarde ton code pour "putwarrior":
call putwarrior
;...
putwarrior:
pop hl
;...
push hl
ret

Ce pop hl ne te donnera pas ce que tu as pushé, il mettra l'octet après l'addresse où tu as fait le call à putwarrior dans hl. Un call ne fonctionne pas comme un saut normale, il met l'addresse après l'instruction sur le stack pour y retourner quand la routine qu'on appelle se finira (un ret saute à la dernière addresse dans le stack). Alors, quand le ret s'exécute, on ira à l'addresse que tu as mise sur le stack dans ta routine.
Donc si je comprends bien je dois retirer ma valeur dans hl avec "pop" avant mon "call putwarrior" à chaque fois que cela sera nécessaire; c'est ça ?
Oui il faut toujours que tes push soient aussi nombreux que tes pop entre le début et la fin d'une portion de programme.

Et il faut pas faire de pop après un label appelé par un call (ou alors il faut en faire plusieurs et rempiler aussitôt).

De plus, si ta pile n'est pas équilibrée, tu finis par perdre ton adresse de retour comme l'a dit chickendude.
Un call, c'est un boite noire. A l'intérieur, cela se comporte comme un nouveau programme.

Contrairement au 8086, les passages de paramètre par la pile se font peu en z80 (ou alors nous sommes peu à le faire tout simplement).Si cela était ce que tu voulais faire, passe plutôt par des registres si besoin ou par la mémoire au cas ou les registres ne suffisent pas.

edit : cross
Deja si tu as 2 sprites seulement il te suffit de tester :
Est-ce que ix == warrior_run1
Si oui alors mettre warrior_run2 dans ix
Sinon mettre warrior_run1 dans ix

Ou alors tu fais :
ajouter 12 à ix
si ix > warrior_run2 alors mettre warrior_run1 dans ix
Ca marchera aussi si tu as plus que deux sprites ça.

Ne stocke pas un boolean ou une variable si petite dans hl, utilise a ou b.


Merci pour ton aide Contra, j'ai appliqué la première méthode que tu m'as donné pour mouvoir mon sprite. Seulement maintenant il y a un problème avec l’effacement du sprite (décidément !).
Voici le code :

...
#define warrior_x 8265h
#define warrior_y 8266h

.org 9327h
call _CLRLCDFULL
call _runIndicOff
call _GRBUFCLR
call _homeUp
call _Axes
ld a, 30
ld (warrior_x), a
ld a, 30
ld (warrior_y), a

getkey :

call putwarrior
ld a, (warrior_x)
inc a
ld (warrior_x), a
ld a, 0ffh
out (1), a
ld a,0feh
out (1), a
in a, (1)
cp 254
jp z, up
cp 247
jp z, down
ld a, 0ffh
out (1), a
ld a, 0fdh
out (1), a
in a, (1)
cp 191
jp z, quit
call erase_warrior
jp getkey
down :
call erase_warrior
ld a, (warrior_y)
or a
jp z, getkey
dec a
ld (warrior_y), a
jp getkey

up :
call erase_warrior
ld a, (warrior_y)
cp 51
jp z, getkey
inc a
ld (warrior_y), a
jp getkey

erase_warrior:
ld b, 13
ld a, (warrior_y)
ld l, a
ld a, (warrior_x)
call sprite
call _GRBUFCPY_V
ret

putwarrior :
ld hl, warrior_run2
sbc hl, ix
ld a, l
call z, putwarrior_first ;si le résultat est nul c'est que l'on est en première phase du cycle de course
call nz, putwarrior_second ;sinon on est en deuxième phase..
ld b, 13
ld a, (warrior_y)
ld l, a
ld a, (warrior_x)
call sprite
call _GRBUFCPY_V
ret

putwarrior_first :
ld ix, warrior_run1
ret

putwarrior_second :
ld ix, warrior_run2
ret

quit :
call _CLRLCDFULL
call _GRBUFCLR
call _dispDone
ret

warrior_run1 :
.db %01111100
.db %00000000
.db %00111000
.db %00111000
.db %00111001
.db %00010010
.db %01111100
.db %10010000
.db %10011110
.db %00010010
.db %00100000
.db %01000000
.db %10000000

warrior_run2 :
.db %01111100
.db %00000000
.db %00111000
.db %00111000
.db %00111000
.db %01010000
.db %10111000
.db %10010111
.db %00011000
.db %00010100
.db %11110010
.db %00000001
.db %00000000
...[routine sprite]
Voici quelque chose qui marche chez moi :
.nolist
#define EQU .equ
#include "includes/ti83asm.inc"
#include "includes/tokens.inc"
#define warrior_x 8265h
#define warrior_y 8266h
.list

.org 9327h

; Header pour ION
xor a ; xor car on n'utilise pas les libs
jr nc,start
.db "Warrior",0

start:

call _CLRLCDFULL
call _runIndicOff
call BUFCLR
call BUFCOPY
ld a, 30
ld (warrior_x), a
ld e, a
ld a, 30
ld (warrior_y), a
;ld ix, warrior_run1
;call DRAW_SPRITE
;call BUFCOPY
;call WAITKEY
;ret

getkey:
call erase_warrior
ld a, (warrior_x)
inc a
ld (warrior_x), a
call putwarrior
ld a, 0ffh
out (1), a
ld a,0feh
out (1), a
in a, (1)
cp 254
jp z, up
cp 247
jp z, down
ld a, 0ffh
out (1), a
ld a, 0fdh
out (1), a
in a, (1)
cp 191
jp z, quit
jp getkey
down:
call erase_warrior
ld a, (warrior_y)
or a
jp z, getkey
dec a
ld (warrior_y), a
jp getkey

up:
call erase_warrior
ld a, (warrior_y)
cp 51
jp z, getkey
inc a
ld (warrior_y), a
jp getkey

erase_warrior:
;ld b, 13
push ix ; sauver ix
ld ix, blank
ld a, (warrior_y)
ld e, a
ld a, (warrior_x)
call DRAW_SPRITE
call _GRBUFCPY_V
pop ix
ret

putwarrior:
;call erase_warrior
ld hl, warrior_run2
;push ix
;pop de
;;;;sbc hl, ix ;; PROBLEME ici
;sbc hl, de
ld a, l
call z, putwarrior_first ;si le résultat est nul c'est que l'on est en première phase du cycle de course
call putwarrior_second ;sinon on est en deuxième phase..
;ld b, 13
ld a, (warrior_y)
ld e, a
ld a, (warrior_x)
call DRAW_SPRITE
call _GRBUFCPY_V
ret

putwarrior_first:
ld ix, warrior_run1
ret

putwarrior_second:
ld ix, warrior_run2
ret

quit:
call _CLRLCDFULL
call _GRBUFCLR
call _dispDone
ret


; a = x
; e = y
; ix = sprite
DRAW_SPRITE:

; y * 12
ld hl, 0
ld d, 0
add hl, de ; 1
add hl, de ; 2
add hl, de ; 3
add hl, hl ; 6
add hl, hl ; 12

; x / 8
ld d, 0
ld e, a
srl e ; / 2
srl e ; / 4
srl e ; / 8
add hl, de

; A present on a le decalage dans hl

ld de, plotsscreen ; Prendre le debut du graphbuffer
add hl, de ; Puis ajouter le decalage

ld b,00000111b ; Get the remainder of x/8
and b
ld c, a ; Sauver dans c
cp 0 ; Is this sprite aligned to 8*n,y?
jp z,ds_aligne
jp ds_non_aligne


ds_aligne:
ld b, 8 ; Sprite 8 de hauteur
ds_aligne_loop:
push bc
ld a, (ix)
ld (hl), a
ld de, 12
inc ix
add hl, de
pop bc
djnz ds_aligne_loop

jp ds_fin

; a= decalage
ds_non_aligne:
ld b, 8
ds_non_aligne_loop:
push bc
ld b, c ; On va utiliser le nombre de rotations comme compteur
ld a, (ix) ; L'octet qu'il faut decaler
inc ix
ld e, 0

ds_shift_loop:
push bc ; Ici on sauve en meme temps le compteur b et le decalage c
; Mettre la carry a 0?
srl a ; Decaler a vers la droite et ce qui sort va en carry
rr e ; Injecter la carry dans e

pop bc
djnz ds_shift_loop

ld (hl), a ; Ecrire le premier octet
inc hl ; Avancer d'un cran
ld a, e
ld (hl), a ; Ecrire le second octet

ld de, 11
add hl, de

pop bc
djnz ds_non_aligne_loop

ds_fin:
ret



blank:
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b

warrior_run1:
.db 00111000b
.db 00111001b
.db 00010010b
.db 01111100b
.db 10010000b
.db 10011110b
.db 00010010b
.db 00100000b

warrior_run2:
.db 00111000b
.db 00111000b
.db 01010000b
.db 10111000b
.db 10010111b
.db 00011000b
.db 00010100b
.db 11110010b


Avec Makefile :
all: WARRIOR

WARRIOR: warrior.bin
bin2var warrior.bin WARRIOR.83p

warrior.bin: *.asm
spasm main.asm warrior.bin
clean:
rm -f *.8xp
rm -f *.lst

.PHONY: all clean



A propos de ton code :
- Pas d'espace après un label car spasm n'aime pas ça (tu dois utiliser tasm je pense)
- C'est quoi sbc hl, ix ? Apparemment ça n'existe pas !

A propos de l'effacement :
Plusieurs techniques:
- Soit effacer l'écran entier à chaque fois (on dit "bliter" l'écran)
- Soit faire écrire le même sprite avec un masque xor
- Soit ecrire un sprite blanc (ici blank)
- Soit faire la meme chose avec un masque and et un sprite qui contient seulement la forme du sprite.

J'ai modifié ton code avec ma routine de sprite perso et des sprites 8x8, il faudra que tu retouche mais bon si tu comprends c'est l'essentiel.


sbc hl,ix n'existe pas, hl/ix/iy sont interchangeables, les versions ix/iy ont la même valeur hexa, seulement avec un préfixe (je crois que c'est $DD pour ix, $FD pour iy). C'est pour ça qu'ils prennent toujours un octet plus que la version hl. Donc il n'y a pas d'instruction que prenne les deux comme arguments.

Et une autre méthode:
-récrire tout l'écran chaque frame (ce que nous faisons dans notre projet wink)

Mais comme tu n'as qu'un sprite, je crois qu'il serait mieux d'XOR ton sprite après avoir affiché le gbuf (graphbuffer/plotsscreen) à l'écran.

Une autre chose: quand tu peux, il est mieux d'utiliser les registres 8-bit car ils sont plus petits et beaucoup plus rapides. Le registre IX (et IY, mais on n'en sert que de très rares occasions parce que l'OS l'utilise et n'aime pas que sa valeur change).
@Contra :Merci, ton programme marche à merveille malgré le changement de compilateur (et oui, j'utilise TASM pour compiler mes codes ^^, du coup j'ai dû rajouter des tabulations au début de chacune de tes instructions et modifier certaines de tes romcalls, mais sinon tout le reste n'a pas changé).
Cependant, je pense qu'il doit y avoir un souci avec l'alternance des sprites car je ne vois que warrior_run2 qui s'affiche à chaque fois (à moins que ce soit tellement rapide que je ne distingue même pas l'alternance entre les deux hum!)
Si tu veux voir ce que ça donne pour ton code "légèrement retouché" :
.nolist
#define end .end
#define END .end
#define equ .equ
#define EQU .equ
#include "ti83asm.inc"
#include "tokens.inc"
.list
#define warrior_x 8265h
#define warrior_y 8266h

.org 9327h

; Header pour ION
xor a ; xor car on n'utilise pas les libs
jr nc,start
.db "Warrior",0

start:

call _CLRLCDFULL
call _runIndicOff
call _GRBUFCLR
call _GRBUFCPY_V
ld a, 30
ld (warrior_x), a
ld e, a
ld a, 30
ld (warrior_y), a

getkey:
call erase_warrior
ld a, (warrior_x)
inc a
ld (warrior_x), a
call putwarrior
ld a, 0ffh
out (1), a
ld a,0feh
out (1), a
in a, (1)
cp 254
jp z, up
cp 247
jp z, down
ld a, 0ffh
out (1), a
ld a, 0fdh
out (1), a
in a, (1)
cp 191
jp z, quit
jp getkey

down:
call erase_warrior
ld a, (warrior_y)
or a
jp z, getkey
dec a
ld (warrior_y), a
jp getkey

up:
call erase_warrior
ld a, (warrior_y)
cp 51
jp z, getkey
inc a
ld (warrior_y), a
jp getkey

erase_warrior:
push ix ; sauver ix
ld ix, blank
ld a, (warrior_y)
ld e, a
ld a, (warrior_x)
call DRAW_SPRITE
call _GRBUFCPY_V
pop ix
ret

putwarrior:
ld hl, warrior_run2
ld a, l
call z, putwarrior_first ;si le résultat est nul c'est que l'on est en première phase du cycle de course
call putwarrior_second ;sinon on est en deuxième phase..
ld a, (warrior_y)
ld e, a
ld a, (warrior_x)
call DRAW_SPRITE
call _GRBUFCPY_V
ret

putwarrior_first:
ld ix, warrior_run1
ret

putwarrior_second:
ld ix, warrior_run2
ret

quit:
call _CLRLCDFULL
call _GRBUFCLR
call _dispDone
ret


; a = x
; e = y
; ix = sprite
DRAW_SPRITE:

; y * 12
ld hl, 0
ld d, 0
add hl, de ; 1
add hl, de ; 2
add hl, de ; 3
add hl, hl ; 6
add hl, hl ; 12

; x / 8
ld d, 0
ld e, a
srl e ; / 2
srl e ; / 4
srl e ; / 8
add hl, de

; A present on a le decalage dans hl

ld de, plotsscreen ; Prendre le debut du graphbuffer
add hl, de ; Puis ajouter le decalage

ld b,00000111b ; Prend le reste de x/8
and b
ld c, a ; Sauver dans c
cp 0 ;Ce sprite est-il aligné avec 8*n,y?
jp z,ds_aligne
jp ds_non_aligne


ds_aligne:
ld b, 8 ; Sprite 8 de hauteur

ds_aligne_loop:
push bc
ld a, (ix)
ld (hl), a
ld de, 12
inc ix
add hl, de
pop bc
djnz ds_aligne_loop
jp ds_fin

; a= decalage
ds_non_aligne:
ld b, 8
ds_non_aligne_loop:
push bc
ld b, c ; On va utiliser le nombre de rotations comme compteur
ld a, (ix) ; L'octet qu'il faut decaler
inc ix
ld e, 0

ds_shift_loop:
push bc ; Ici on sauve en même temps le compteur b et le decalage c
; Mettre la carry a 0?
srl a ; Decaler a vers la droite et ce qui sort va en carry
rr e ; Injecter la carry dans e

pop bc
djnz ds_shift_loop

ld (hl), a ; Ecrire le premier octet
inc hl ; Avancer d'un cran
ld a, e
ld (hl), a ; Ecrire le second octet

ld de, 11
add hl, de

pop bc
djnz ds_non_aligne_loop

ds_fin:
ret



blank:
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b

warrior_run1:
.db 00111000b
.db 00111001b
.db 00010010b
.db 01111100b
.db 10010000b
.db 10011110b
.db 00010010b
.db 00100000b

warrior_run2:
.db 00111000b
.db 00111000b
.db 01010000b
.db 10111000b
.db 10010111b
.db 00011000b
.db 00010100b
.db 11110010b

.end END


Par contre, est-il totalement impossible d'utiliser des sprites de plus de 8 pixels de hauteur? Parce que sinon je vais devoir me repencher sur leur esthétique ...

@chickendude : Désolé, je croyais que ix et iy pouvaient être considérés ,dans leur fonctionnement, comme les autres registres 16 bits. Merci pour l'info grin
Utilise un débugger avec un breakpoint pour être sûr que tes 2 sprites s'affichent correctement...
Je crois que j'avais regardé pour le code que je t'ai donné.

Il n'est pas du tout impossible d'afficher plus que du 8x8, tu peux faire ce que tu veux. Généralement on utilise 8x8 ou 16x16 mais rien n'empêche de faire d'autres combinaisons.

Le truc c'est que les routines des sprite vont être un peu compliquées et plus lentes si tu veux faire du 12x20 ou des trucs "exotiques" smile
Rappelle toi que l'écran est composé d'octets donc 8 bits.
Et que dès qu'un sprite n'est pas aligné il faut utiliser des décalages...

Tu peux utiliser cette routine si tu veux :
putLargeSprite

;=======================
;LargeSprite
;by Joe Wingbermuehle
;=======================
;Does: Copy a sprite to the gbuf
;Input: ix=sprite address, a='x', l='y', b='height' (in pixels), c='width' (in bytes, e.g. 2 would be 16)
;Output: The sprite is copied to the gbuf
;-----------------------
largeSprite:
di ;turn interrupts off (we want to use shadow registers)
ex af,af'
;exchange af with af' \
ld a,c ;ld c in a (a = 'width') | for not destroying a ('x')
push af ;push a |
ex af,af'
;exchange back | and 'width' is now in a' (saved)
ld e,l ;e = 'y'
ld h,$00 ;h = 0
ld d,h ;d = 0
add hl,de ;'y' *2 \
add hl,de ; *3 | calculate 'y' *12 because 'y' is 'in rows'
add hl,hl ; *6 | (screen is 12 bytes in length)
add hl,hl ; *12 /
ld e,a ;e = 'x'
and $07 ;and %00000111
ld c,a ;last 3 bits in c (amount of bits to shift all bytes)
srl e ;e/2 | shifting e ('x') 3 bits to the right
srl e ; /4 | %11111111 becomes %00011111 for example
srl e ; /8 /
add hl,de ;hl = 'y'; de = 'x' (rounded) | add them
ld de, gbuf ;de = the adress of graph buffer
add hl,de ;add hl to the adress of the gbuf
largeSpriteLoop1:
push hl ;save adress
largeSpriteLoop2:
ld d,(ix) ;first sprite data in d
ld e,$00 ;e = 0
ld a,c ;a = c (to not destroy c)
or a ;is a = 0? (same as cp 0)
jr z,largeSpriteSkip1 ;if theres nothing to shift (a = 0) loop it
largeSpriteLoop3:
srl d ;shift one bit to the right; put the destroyed bit in the carry flag
rr e ;put the carry flag in e (%00000000 becomes %10000000 if carry flag = 1)

dec a ;decrease counter (with was 'the amount of bits to shift')
jr nz,largeSpriteLoop3 ;if the counter is not 0 loop back
largeSpriteSkip1:
ld a,(hl) ;graphbyte in a
xor d ;xor first byte of sprite (that can be changed to 'or d' if you want a OR-routine)
ld (hl),a ;back to buffer
inc hl ;increase pointer
ld a,(hl) ;graphbyte in a
xor e ;xor with shifted sprite byte (change to 'or e' for OR-routine)
ld (hl),a ;back to buffer
inc ix ;increase sprite adress
ex af,af'
;exchange af with af' ( a is now the 'width' from the first line)
dec a ;decrease 'width'
push af ;push the 'width'
ex af,af'
;exchange back
pop af ;pop the 'width'
jr nz,largeSpriteLoop2 ;if a is not 0 (if a = 0 then we would be done) loop it
pop hl ;pop gbuf adress (search the last push hl!)
pop af ;pop | to restore the real 'width'
push af ;push /
ex af,af'
;af' must be the original 'width' when loop 'largeSpriteLoop1'
ld de,$0C ;ld de,12
add hl,de ;next line
djnz largeSpriteLoop1 ;if not b = 0 loop (b = height of sprite)
pop af ;pop because we dont want a stack problem smile
ret ;return


Mais il faut aussi pense à la taille des autres éléments du jeu (et donc les collision). Des tailles bizarres impliquent des collisions très dures à détecter.
Ceci devrait marcher sans problème, désolé je n'avais pas vu ta réponse jusqu'aujourd'hui :
#include "ti83asm.inc"
#include "tokens.inc"

#define warrior_x 8265h
#define warrior_y 8266h

.org 9327h

; Header pour ION
	xor a ; xor car on n'utilise pas les libs
	jr nc,start
.db "Warrior",0

start:
	call _CLRLCDFULL
	call _runIndicOff
	ld hl,$1E1E		;30 (hex 1E) dans h et l
	ld (warrior_x),hl
getkey:
	ld hl,warrior_x
	inc (hl)
	call putwarrior
	call erase_warrior
	ld hl,warrior_y
	ld a, 0ffh
	out (1), a
	dec a			;$FF-1=$FE
	out (1), a
	in a, (1)
	bit 3,a
	call z, down
	rra
	call nc, up

	ld a, 0ffh
	out (1), a
	ld a, 0fdh
	out (1), a
	in a, (1)
	cp 191
	jr z, quit
	jr getkey

down:
;	call erase_warrior
	dec (hl)
	ret p
	inc (hl)
	ret

up:
;	call erase_warrior
	ld a, (hl)
	cp 55
	ret z
	inc (hl)
	ret

erase_warrior:
	push ix ; sauver ix
	ld ix, blank
	ld a, (warrior_y)
	ld e, a
	ld a, (warrior_x)
	call DRAW_SPRITE
;	call _GRBUFCPY_V
	pop ix
	ret

putwarrior:
	ld hl, warrior_run2
	ld a, ixl
	cp l
	ld ix,warrior_run1
	jr nz,skip
	ld ix,warrior_run2
skip:
	ld hl,warrior_x
	ld a,(hl)
	inc hl
	ld e,(hl)
	call DRAW_SPRITE
	call _GRBUFCPY_V
	ret

;putwarrior_first:
;	ld ix, warrior_run1
;	ret
;
;putwarrior_second:
;	ld ix, warrior_run2
;	ret

quit:
	call _CLRLCDFULL
	call _dispDone
	ret


	; a = x
	; e = y
	; ix = sprite
DRAW_SPRITE:

	; y * 12
	ld hl, 0
	ld d, h
	add hl, de ; 1
	add hl, de ; 2
	add hl, de ; 3
	add hl, hl ; 6
	add hl, hl ; 12

	; x / 8
	ld e, a
	srl e ; / 2
	srl e ; / 4
	srl e ; / 8
	add hl, de

	; A present on a le decalage dans hl

	ld de, plotsscreen ; Prendre le debut du graphbuffer
	add hl, de ; Puis ajouter le decalage

;	ld b,00000111b ; Prend le reste de x/8
	and 7
	ld c, a ; Sauver dans c
	or a ;Ce sprite est-il aligné avec 8*n,y?
	ld b,8
	jr nz, ds_non_aligne

ds_aligne:
ds_aligne_loop:
	push bc
	ld a, (ix)
	ld (hl), a
	ld de, 12
	inc ix
	add hl, de
	pop bc
	djnz ds_aligne_loop
	jp ds_fin

	; a= decalage
ds_non_aligne:
ds_non_aligne_loop:
	push bc
	ld b, c ; On va utiliser le nombre de rotations comme compteur
	ld a, (ix) ; L'octet qu'il faut decaler
	inc ix
	ld e, 0

ds_shift_loop:
	push bc ; Ici on sauve en même temps le compteur b et le decalage c
	; Mettre la carry a 0?
	srl a ; Decaler a vers la droite et ce qui sort va en carry
	rr e ; Injecter la carry dans e

	pop bc
	djnz ds_shift_loop

	ld (hl), a ; Ecrire le premier octet
	inc hl ; Avancer d'un cran
	ld a, e
	ld (hl), a ; Ecrire le second octet

	ld de, 11
	add hl, de

	pop bc
	djnz ds_non_aligne_loop

ds_fin:
	ret



blank:
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b
.db 00000000b

warrior_run1:
.db 00111000b
.db 00111001b
.db 00010010b
.db 01111100b
.db 10010000b
.db 10011110b
.db 00010010b
.db 00100000b

warrior_run2:
.db 00111000b
.db 00111000b
.db 01010000b
.db 10111000b
.db 10010111b
.db 00011000b
.db 00010100b
.db 11110010b
Juste, pourquoi tu rends ton programme compatible Ion si c'est pour ne pas utiliser ses routines ?

Sinon y'a moyen d'optimiser pas mal, notamment en mettant l'adresse des sprites dans une table qu'il suffira de lire selon l'animation ou en faisant adresse_sprites+8*animation (l'un ou l'autre selon le nombre totale de sprites, qui peut être assez élevé si tu as plusieurs directions).

Dis-le si c'est pas clair, j'te ferai un code.