La Place des Développeurs Asmsx par un noob #3: orienter et animer le héros... de la réutilisation du timer de Metalion/Konami
Là je suis content de moi (enfin jusqu'à la prochaine intervention de Z80 ou Metalion ) , j'ai bien compris le mécanisme du timer proposé par Metalion (et à peu près celui de Z80 ) et je l'ai utilisé pour l'animation du héros toutes les 8 frames.
Dans mon programme: Le timer s'appelle VAR_TIMER et l'ancien vblank s'appelle REFRESH_OLD (pour éviter les droits d'auteur à Metalion ).
Blague à part passons au sujet du post:
Dans les données j'assigne les valeurs de sprites voulues suivant la direction de la manette en omettant volontaire la position neutre (0). J'ai modifié un peu les déplacements en privilégiant des déplacements horizontaux lors d'un mouvement en diagonale pour plus de souplesse... (on peut opter pour le vertical mais il faut adapter l'orientation du sprite en conséquence) je sais pas si c'est une bonne idée
Je crée juste une variable pour la gestion de l'animation.
En fait il est directement intégré dans le sous programme de gestion des mouvements du héros. L'animation est directement liée au mouvement de la manette.
Pour l'orientation ça fonctionne comme pour la gestion des déplacements.
Pour l'animation.. bah si on a compris le post de Metalion...
Je n'aime pas le fait de rappeler 2 fois de suites la variable d'animation du héros... Juste parce que j'ai toujours l'impression qu'on peut mieux faire.
En rédigeant ce post j'ai pensé au fait que dans plusieurs jeux MSX les héros se déplacent de 8 en 8 et pas toujours "au pixel près". En plus je dois gérer le fait que le perso doit pouvoir se retourner sans se déplacer...Je me penche sur la question...
Dans mon programme: Le timer s'appelle VAR_TIMER et l'ancien vblank s'appelle REFRESH_OLD (pour éviter les droits d'auteur à Metalion ).
Blague à part passons au sujet du post:
Orientation et animation du héros
données et variables à mettre en place
Dans les données j'assigne les valeurs de sprites voulues suivant la direction de la manette en omettant volontaire la position neutre (0). J'ai modifié un peu les déplacements en privilégiant des déplacements horizontaux lors d'un mouvement en diagonale pour plus de souplesse... (on peut opter pour le vertical mais il faut adapter l'orientation du sprite en conséquence) je sais pas si c'est une bonne idée
Je crée juste une variable pour la gestion de l'animation.
Code ASM :
;---------------------------------------------------------- ; Données ;---------------------------------------------------------- ; (...) ; orientation du heros VAL_ORI_H: ;------ 1, 2, 3, 4, 5, 6, 7, 8 db 0,16,16,16,32,48,48,48 ; ;---------------------------------------------------------- ; VARIABLES ;---------------------------------------------------------- .page 3 ; ; (...) ; variable pour la tempo VAR_TIMER: ds1 ;hook original H.TIMI REFRESH_OLD: ds5 ; variable animation heros VAR_ANI_H: ds1
Le sous programme
En fait il est directement intégré dans le sous programme de gestion des mouvements du héros. L'animation est directement liée au mouvement de la manette.
Pour l'orientation ça fonctionne comme pour la gestion des déplacements.
Pour l'animation.. bah si on a compris le post de Metalion...
Je n'aime pas le fait de rappeler 2 fois de suites la variable d'animation du héros... Juste parce que j'ai toujours l'impression qu'on peut mieux faire.
Code ASM :
;---------------------------------------------------------- GST_DEP_Heros:;---- Gestion mouvement ----- ;---------------------------------------------------------- ; xor a; A=0 (test clavier) call GTSTCK; A= direction flèches clavier cp 0; Si A=0 jr nz,@@GST_MOVE; si non (a<>0) saut à la boucle inc a; si oui A=A+1 (A=1) call GTSTCK; A= direction manette 1 cp 0; Si A=0 jr nz,@@GST_MOVE; si non (a<>0) saut à la boucle ret ; ;Gestion mouvement @@GST_MOVE: push af; sauve a (valeur joystick) ; Orientation sprite dec a; on décale de -1 pour partir de 0 ldhl,VAL_ORI_H; HL = adr. orientation heros ldb,0; mise dans BC de a ldc,a; " addhl,bc; HL = On met HL à l'adresse correspondant à adresse d'orientation voulue. lda,[hl]; on met la valeur dans a ; Animation sprite push af; sauve a (orientation héros) lda,[VAR_TIMER]; Chargement du timer and7; toutes les 8 frames jpnz,@@suite; saut à "pas de modif" si NON lda,[VAR_ANI_H]; rappel de la variable d'animation xor 8; inversion (0 ou 8) ld[VAR_ANI_H],a; sauvegarde de la variable @@suite: lda,[VAR_ANI_H]; rappel de la variable d'animation ... hum ld b,a; mise dans b pour l'ajouter à... pop af; l'orientation du héros sauvegardée add a,b; addition... ld [VAR_SPRITES+(0*4)+2],a; N° 1er sprite heros (plan0) inc a; inca; + inc a; 4 inca; ld [VAR_SPRITES+(1*4)+2],a ; N° 2nd sprite heros(plan1)
En rédigeant ce post j'ai pensé au fait que dans plusieurs jeux MSX les héros se déplacent de 8 en 8 et pas toujours "au pixel près". En plus je dois gérer le fait que le perso doit pouvoir se retourner sans se déplacer...Je me penche sur la question...
Le MSXien le plus à l'ouest ... ou presque
MSXosaure :
Là je suis content de moi (enfin jusqu'à la prochaine intervention de Z80 ou Metalion ) , j'ai bien compris le mécanisme du timer proposé par Metalion (et à peu près celui de Z80 ) et je l'ai utilisé pour l'animation du héros toutes les 8 frames.
Ben faudrait que je t'explique ou plutôt que je finisse de décrire les fondements et concept du moteur de jeux.
MSXosaure :
En rédigeant ce post j'ai pensé au fait que dans plusieurs jeux MSX les héros se déplacent de 8 en 8 et pas toujours "au pixel près". En plus je dois gérer le fait que le perso doit pouvoir se retourner sans se déplacer...Je me penche sur la question...
Les héros ne se déplacent pas de 8 en 8, mais les test de collision avec le décors se font eux par bloc de 8x8. Voir 16x16 quand les blocs de décors sont de cette taille
Se retourner ça se gère simplement si tu introduis la notion de statut pour ton objet (héros et ennemis) et que pour chacun des statut (état) de ton objet tu créé une ou des relations vers un autre état.
C'est pour ça que je disais précédemment qu'il fallait établir à l'avance les actions mais aussi l'environnement dans lequel ton objet va évoluer.
Donc tu doit lister tous les états que va pouvoir prendre ton héros (objet) et les transitions possible de tel état vers tel autre.
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
z80 :
Les héros ne se déplacent pas de 8 en 8, mais les test de collision avec le décors se font eux par bloc de 8x8. Voir 16x16 quand les blocs de décors sont de cette taille
Se retourner ça se gère simplement si tu introduis la notion de statut pour ton objet (héros et ennemis) et que pour chacun des statut (état) de ton objet tu créé une ou des relations vers un autre état.
C'est pour ça que je disais précédemment qu'il fallait établir à l'avance les actions mais aussi l'environnement dans lequel ton objet va évoluer.
Donc tu doit lister tous les états que va pouvoir prendre ton héros (objet) et les transitions possible de tel état vers tel autre.
MSXosaure :
En rédigeant ce post j'ai pensé au fait que dans plusieurs jeux MSX les héros se déplacent de 8 en 8 et pas toujours "au pixel près". En plus je dois gérer le fait que le perso doit pouvoir se retourner sans se déplacer...Je me penche sur la question...
Les héros ne se déplacent pas de 8 en 8, mais les test de collision avec le décors se font eux par bloc de 8x8. Voir 16x16 quand les blocs de décors sont de cette taille
Se retourner ça se gère simplement si tu introduis la notion de statut pour ton objet (héros et ennemis) et que pour chacun des statut (état) de ton objet tu créé une ou des relations vers un autre état.
C'est pour ça que je disais précédemment qu'il fallait établir à l'avance les actions mais aussi l'environnement dans lequel ton objet va évoluer.
Donc tu doit lister tous les états que va pouvoir prendre ton héros (objet) et les transitions possible de tel état vers tel autre.
Pour les déplacements 8x8, en fait il suffit de lancer une détection avec le décor touts les déplacements de 8 pixels, ça ok. Mais ce que je voulais dire c'est que lors d'un changement de direction le héros ne se trouve pas "à cheval" sur un élément de décor et ça se fera en jouant sur le timer et la lecture de la manette, non?
Pour la gestion c'est sur qu'il aurait fallu savoir on j'allais.
Pour l'objet "héros" et la gestion de retournement, peut-on raisonner comme ça :
Début
Héros dans une direction.
Détection d'un déplacement au "stick"
le déplacement correspond à la direction
THEN mouvement
ELSE retournement(enfin alignement dans le sens envoé par la manette)
retour Début
Enfin cette série de post a pour but aussi d'apprendre quelques astuces de programmation en asm, le "timer" par exemple ou comment préparer un programme et la gestion des objets
Le MSXien le plus à l'ouest ... ou presque
Quelques petites simplifications
Code :
Edité par
Metalion
Le 22/10/2014 à 08h19
; Animation sprite
ld b,a ; plus rapide que push af et permet de préparer l'addition
ld a,[VAR_TIMER]
and 7
ld a,[VAR_ANI_H] ; charger a ne modifie pas les flags (pour le 'jp nz') et permet d'anticiper l'opération
jp nz,@@suite
xor 8
ld [VAR_ANI_H],a
@@suite:
add a,b
ld [VAR_SPRITES+(0*4)+2],a
add 4 ; plus rapide que 4x 'inc a'
ld [VAR_SPRITES+(1*4)+2],a
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
MSXosaure :
Pour les déplacements 8x8, en fait il suffit de lancer une détection avec le décor touts les déplacements de 8 pixels, ça ok. Mais ce que je voulais dire c'est que lors d'un changement de direction le héros ne se trouve pas "à cheval" sur un élément de décor et ça se fera en jouant sur le timer et la lecture de la manette, non?
Pour la gestion c'est sur qu'il aurait fallu savoir on j'allais.
Pour l'objet "héros" et la gestion de retournement, peut-on raisonner comme ça :
Début
Héros dans une direction.
Détection d'un déplacement au "stick"
le déplacement correspond à la direction
THEN mouvement
ELSE retournement(enfin alignement dans le sens envoé par la manette)
retour Début
Enfin cette série de post a pour but aussi d'apprendre quelques astuces de programmation en asm, le "timer" par exemple ou comment préparer un programme et la gestion des objets
Pour la gestion c'est sur qu'il aurait fallu savoir on j'allais.
Pour l'objet "héros" et la gestion de retournement, peut-on raisonner comme ça :
Début
Héros dans une direction.
Détection d'un déplacement au "stick"
le déplacement correspond à la direction
THEN mouvement
ELSE retournement(enfin alignement dans le sens envoé par la manette)
retour Début
Enfin cette série de post a pour but aussi d'apprendre quelques astuces de programmation en asm, le "timer" par exemple ou comment préparer un programme et la gestion des objets
Je vais faire chieur, mais ce que je d'écris n'est pas lié au seul langage ASM (assembleur) tu peux transposer ces méthodes en BASIC, C, PYTHON, PASCAL, C++, etc...
Pour répondre à ta question, il te faut programmer un gestionnaire de déplacement et un d'animation. Le gestionnaire d'animation sera appelé par le gestionnaire de déplacement ou sera dans la liste des appels effectué à chaque VBL. En gros:
Code ASM :
Hook VBL: CALL Gest_Hero: CALL Gest_Ennemis CALL Dessine_Plan CALL PlayMusic_And_SFX RET Gest_Heros: CALL LectureManette ; retourne l'état de la manette dans A (direction et bouton tir/saut, perso je trouve que c'est bien aussi de sauvegarder cet état dans une variable en mémoire... LD B,A ; sauvegarde l'état manette LD A,(HeroStat) CP VersDroite JP Z,Gest_Droite CP VersGauche JP Z,Gest_Gauche CP VersHaut JP Z,Gest_Haut CP VersBas JP Z,Gest_Bas CP EnPause JP Z,Gest_Pause CP Saute JP Z,Gest_Saute Gest_Indefini:
Si tu arrives ici, prévoir quelque chose parce que tu as du affecter un état pas dans la liste ci-dessus
Code ASM :
Gest_Droite: LD A,B ; récup de la manette ici tu mets du code pour tester toute les actions possibles qui ont pour point de départ la marche vers la droite Est-ce qu'on veut sauter? -> si oui alors change le statut du héro pour qu'il soit dans l'état "saut", JP Gest_SautDroite Si il ne saute pas, est-ce qu'il tir? -> si oui création d'un objet tir ayant pour direction la direction du sens de marche du héro, avec une vitesse au minimum égale à celle du héro. Est-ce qu'on continu à aller à droite? -> si oui alors saut à la fin de gestion du Héro (Gest_Fin), sinon modifi l'état en fonction de l'action etc... Gest_SautDroite: ajoute de l'accélération en Y (bas vers haut), sature la vitesse, si vitesse max Y atteinte alors vitesseY=0 et passage en statut "ChuteDroite" ou "ChuteGauche fonction de l'état de la manette... Si toujours vers la droite alors on maintient la vitesse (voir on continu à l'augmenter si pas encore au maxi) de déplacement vers la droite et on met à jour la positionX du Héro. Si ni droite ni gauche, on maintient le sens droite, mais on vas réduire la vitesse à chaque VBL (vitesse = vitesse - accel) jusqu'à atteindre une vitesse nulle Si gauche alors le héros change de direction -> statut passe à "SautGauche" , maintient sa vitesse ou on l'augmente si pas encore arrivé à saturation, etc... etc... Gest_Fin: Ici on va tester les collision avec le décors et ajuster la position du Héro en conséquence En suite on appel le gestionnaire d'animation du Héro (d’animation des Objet dans l'absolu, à laquelle on passe en paramètre "Héros")
Je me rends compte qu'il est important à ce stade de bien comprendre la notion de pointeur et de structure.
En effet prenons le cas d'un objet (le héros par exemple), l'animation est une suite de forme et de nombre de sprites à afficher toutes les "N" VBL. Pour gérer ça il faut faire uns structure dans laquelle on va décrire la position des différent sprite relativement à la position de l'objet (du Héros).
Exemple simple:
Votre objet fait 16 pixel de large et 32 de haut et est animé en deux phases seulement, séparées en deux temps, le premier dure 2 VBL et le second 3 VBL.
On va devoir définir un structure comme suit:
Code ASM :
Edité par
z80
Le 22/10/2014 à 13h31
Hero_Fixe: DB 2 ; nb VBL DW HeroFixe1 ; pointeur vers la structure qui définie les sprites et leur position pour la frame1 DB 3 ; nb VBL DW HeroFixe2 ; pointeur vers la structure qui définie les sprites et leur position pour la frame2 DB 0 ; nb VBL = 0 alors retour au début HeroFixe1: DB 0,0 ; offsetX, offsetY DW Data0HeroFixe1 ; pointeur vers les donnés du sprite bas pour la frame1 DB 0,16 ; offsetX, offsetY DW Data1HeroFixe1 ; pointeur vers les donnés du sprite haut pour la frame1 HeroFixe2: DB 0,0 ; offsetX, offsetY DW Data0HeroFixe2 ; pointeur vers les donnés du sprite bas pour la frame1 DB 0,16 ; offsetX, offsetY DW Data1HeroFixe2 ; pointeur vers les donnés du sprite haut pour la frame1 Chaque objet à l'écran possède sa structure propre en RAM. Cette structure contient des donnée comme: décompteur de VBL, pointeeur vers la structure de l'animation (animation qui dépend du statut de l'objet (marche à droite, marche à gauche, saute à droite, etc...), vitesse, accel, positionX, positiony, taileX, tailleY,etc... Lors de l'animation on charge le décompteur avec le nombre de VBL, à chaque VBL on parcourt la liste des objets (liste de pointeur sur les structures d'objets). pour chaque objet on actualise sa positionX et positionY, on vérifie si le décompteur de l'objet à atteint zéro, si oui on parcour la structure d'animation de l'objet pour charger la nouvelle frame. Etc...
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
On voit tout de suite les marques indélébiles de la POO ...
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
Metalion :
On voit tout de suite les marques indélébiles de la POO ...
En fait j'ai appris sur le tas, pas eu besoin de cours
Et les jeux fais jusqu'à maintenant, nous avons toujours séparé le héros des ennemis. Ce qui avec un peu de recule comme je le disais dans un précédent post n'a pas vraiment de sens puisqu'au final un héros ou des ennemis c'est du pareil au même
Dans X-TAZY, les ennemis peuvent créer eux même d'autres ennemis.
Les notion de structures et de pointeurs ne sont pas l’apanache des programmeurs en C et C++. Les programmeur en assembleur manipule naturellement les pointeurs, alors que dans le monde du C et C++ cela tient du Guru voir du Chamanisme!
Je pense que c'est lié à l'abstraction induite par ces langages ou on a pas besoin de connaitre le fonctionnement du jeux d'instruction et des modes d'adressage du CPU pour pouvoir travailler avec un pointeur...
Comme l'auteur du GR8BIT je pense qu'un bon programmeur (efficace) est un programmeur qui connait bien son hardware (CPU, VDP etc...)
Les pointeurs sont des outils puissants
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
MSXosaure :
Euh Z80 j'ai pas prévu que mon perso saute...
Sinon, je n'ai déjà pas les automatismes proposés par Metalion sur son post sur la simplification, alors...
Et sur le dernier exemple dans ton post je suis un peu largué...
Sinon, je n'ai déjà pas les automatismes proposés par Metalion sur son post sur la simplification, alors...
Et sur le dernier exemple dans ton post je suis un peu largué...
Pas grave
On est ici pour échanger je sais que ça peu parraitre compliqué voir abstrait. Peut-être que si je trouve un peut de temps pour coder un exemple... Mais mon temps libre est pratiquement inexistant en ce moment...
Tu as raison avant de sauter il faut marcher
TurboR GT (1Mo), CANON V20! ( en kit, modif 2+ en cours)
Pas encore retrouvés: V9990, Grafx9000, SUNRISE IDE 2x CF, SUNRISE MOONSOUND, FM PAC, MUSIC MODULE, NMS8280, SD SNATCHER,...
z80 :
Pas grave
On est ici pour échanger je sais que ça peu parraitre compliqué voir abstrait. Peut-être que si je trouve un peut de temps pour coder un exemple... Mais mon temps libre est pratiquement inexistant en ce moment...
Tu as raison avant de sauter il faut marcher
MSXosaure :
Euh Z80 j'ai pas prévu que mon perso saute...
Sinon, je n'ai déjà pas les automatismes proposés par Metalion sur son post sur la simplification, alors...
Et sur le dernier exemple dans ton post je suis un peu largué...
Sinon, je n'ai déjà pas les automatismes proposés par Metalion sur son post sur la simplification, alors...
Et sur le dernier exemple dans ton post je suis un peu largué...
Pas grave
On est ici pour échanger je sais que ça peu parraitre compliqué voir abstrait. Peut-être que si je trouve un peut de temps pour coder un exemple... Mais mon temps libre est pratiquement inexistant en ce moment...
Tu as raison avant de sauter il faut marcher
Pas de problème, pour ma part je sors de quasiment un an sans MSX, du coup je me consacre qu'à ce qui me passionne, la programmation...
Et oui, c'est sur qu'un exemple concret m'aiderai à bien comprendre... Mais c'est déjà bien de ta part d evouloir partager tes connaissances
Le MSXien le plus à l'ouest ... ou presque
Je reviens encore une fois à mon post sur l'animation que j'avais fait précédemment, c'est aussi la méthode que j'ai plus ou moins utilisé.
En fonction de la direction du stick, je faisais appel à une "fonction" qui modifie l'aspect du sprite. Dès que la touche de direction est lâchée, il reprenait sa position normale.
C'est vrai qu'en fait c'est un peu comme la POO, l'objet est ici le personnage à animer, et il y a toute une série de "variables" qui peuvent lui être propres (coordonnées, aspect du sprite...).
En fonction de la direction du stick, je faisais appel à une "fonction" qui modifie l'aspect du sprite. Dès que la touche de direction est lâchée, il reprenait sa position normale.
C'est vrai qu'en fait c'est un peu comme la POO, l'objet est ici le personnage à animer, et il y a toute une série de "variables" qui peuvent lui être propres (coordonnées, aspect du sprite...).
MSX un jour, MSX toujours !
MSXosaure :
Sinon, je n'ai déjà pas les automatismes proposés par Metalion sur son post sur la simplification, alors...
C'est pas grave MSXosaure ... Je ne les ait pas tous du premier coup non plus
C'est souvent en relisant mon code, que je l'optimise.
L'important, dans un premier temps, c'est que cela marche !
Optimiser le code, cela n'est utile que quand on recherche à diminuer le temps d'exécution, quand on doit gérer une série d'action en un temps donné (pendant le temps d'une interruption VBLANK, par exemple).
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
granced :
Je reviens encore une fois à mon post sur l'animation que j'avais fait précédemment, c'est aussi la méthode que j'ai plus ou moins utilisé.
En fonction de la direction du stick, je faisais appel à une "fonction" qui modifie l'aspect du sprite. Dès que la touche de direction est lâchée, il reprenait sa position normale.
C'est vrai qu'en fait c'est un peu comme la POO, l'objet est ici le personnage à animer, et il y a toute une série de "variables" qui peuvent lui être propres (coordonnées, aspect du sprite...).
En fonction de la direction du stick, je faisais appel à une "fonction" qui modifie l'aspect du sprite. Dès que la touche de direction est lâchée, il reprenait sa position normale.
C'est vrai qu'en fait c'est un peu comme la POO, l'objet est ici le personnage à animer, et il y a toute une série de "variables" qui peuvent lui être propres (coordonnées, aspect du sprite...).
Oui mais là c'est l'inverse, il faut que l'objet "héros" garde la dernière direction enregistrée.
J'ai opté pour une "non-action" et ça a le mérite de marcher.
L'idéal aurait peut-être été de créer 3 animations pour la marche du personnage avec une intermédiaire rappelée par une variable pour la position arretée du héros.
On peut lui ajouter une position tir, etc...Du coup ça fait pas mal de variables à gérer et autant de sprites...
Le MSXien le plus à l'ouest ... ou presque
Je crois que même 2 animations c'est déjà pas mal pour un déplacement. Regarde Snake dans Metal Gear, il n'a que 2 positions en plus de la position arrêtée dans chaque direction.
MSX un jour, MSX toujours !
granced :
Regarde Snake dans Metal Gear, il n'a que 2 positions en plus de la position arrêtée dans chaque direction.
Euh ... Regarde mieux, Granced : il y a 40 macro-sprites (et donc états) différents pour Snake dans MG1
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie