Tutorial : Logiciels Complémentaires à Lunar Magic : les custom blocks/ASM
Les custom blocks :
Bon, pour arriver à concocter quelques custom blocs, il faut d’abord se munir de blocktool, de translhexion, du bloc-notes, de spritetool, bien sur de Lunar Magic et d’une rom de Super Mario World et enfin du fichier d’aide qui se trouve ici. Note : ayez sous les yeux la partie RAM Map de smw central là. Comme ce tuto risque d’être un peu long, je vais le décomposer en 3 parties : les bases de l’ASM, créer son bloc et enfin des exemples de custom blocs. 1. Les bases de l’ASM (ou étude théorique) D’abord, ‘y faut dire 65C816 ASM pour la snes (tuh…). Pour ceux qui ne connaissent pas cela veut dire ASseMbly(eur). C’est le langage informatique qu’utilise la snes. En réalité il existe plusieurs versions d'assembleur, une pour chaque processeur. Ici je vais vous apprendre l'ASM 65C816 car c'est celui qui nous intéresse. Quand vous ouvrez la rom avec Translhexion, vous voyez la forme hexadécimal de l’ASM (pour ceux qui ne savent pas comment utiliser translhexion ni blocktool, reportez vous aux tutos de cette discussion ; je suppose que vous savez ce qu’est l’hexadécimal puisque vous savez utiliser Lunar Magic…). On appelle cet ensemble de chiffre le "machine code" in english ou en français le langage machine. C'est le langage compréhensible par la snes. Pour pouvoir traduire l'ASM en fichier executable ou ici en fichier.bin qui contiendra le langage machine, il faut un compilateur, un logiciel qui traduira le fichier source dans lequel se trouve le code source (l'ASM est utilisé dans le code source). On dit que l'assembleur est un langage compilé car il est traduit une fois pour toute. Let's go ! Bon. Commençons par le commencement. L’ASM est fait d’opcodes et de valeurs. Les opcodes correspondent à des actions à effectuer. Les valeurs, bah… ce sont des valeurs. Les valeurs peuvent être directes : un nombre, là comme ça, au hasard, 007 ^^ ; ou indirectes (nous allons voir ça après). Sachez qu’en faisant de l’ASM, vous avez à disposition des registers(res) : l’accumulator(eur), les X et Y registers, le stack, le processor status ou flag register (celui-là est particulier). Le plus important est l’accumulator : il vous permet de stocker 1 valeur mais peut être utilisé indéfiniment. Ca fait beaucoup de notion, nan ? un petit exemple : LDA #$07 STA $7E0DBF ‘paniquez pas j’vous explique. LDA et STA sont des opcodes. #$07 est une valeur directe, $0DBF indirecte. Traduction : LDA veut dire LoaD Accumulator (je noterai accumulator A par la suite) et STA STore A. Les valeurs directes en hexadécimal sont précédées de #$ et en binaire de #%, et les valeurs indirectes sont simplement précédées de $ puisqu’elle viennent de la RAM. Ce qui veut dire que ce code met dans l’A la valeur en héxa 07 et restitue la valeur de l’A à l’adresse 7E0DBF. Si on regarde dans la RAM Map de smwcentral, il s’agit du compteur de pièces. Si vous faites un bloc avec ce code (on verra ça après), le bloc remet le compteur des pièces à 7. Note pour les valeurs indirectes, le 7E n’est pas obligatoire, ainsi que les 2 zéros s’il y en a après : $7E0019 devient $19. Attention : on ne supprime pas les deux derniers zéros. Ex : $7E1900 ne sera jamais $19. Eh ben là vous avez déjà appris...le tiers de cette partie ! on continue avec d’autres opcodes : STZ : STore Zero to memory. STZ $0DBF -> met 0 à l’adresse 0DBF (Mario a plus de pièces ^^) INC : INCrement A or memory. INC $0DBF -> augmente de 1 la valeur indirecte de l’adresse 0DBF (Mario gagne une pièce) DEC : DECrement A or memory. DEC $0DBF -> diminue de 1 la valeur indirecte de l’adresse 0DBF (Mario perd une pièce) Ca continue... En réalité il me semble qu’il y en a 92. Vous pouvez avoir une vue d’ensemble en ouvrant le fichier d’aide dont j’ai parlé au début (en anglais) ASL : Left Shift A or memory. Multiplie par 2 l’A. Ex : A=15, ASL, A=30 LSR : Right Shift A or memory. Divise par 2 l’A. Note : si le résultat est avec une virgule (en gros si ça tombe en xx,5), on garde la partie entière (on garde xx). TAX : Transfer A to X. Transfert la valeur de l’A au register X (j’expliquerai après) TAX, TAY, TXY, TYA,... même principe XBA : eXchange B and A. Echange le "high byte" (dans un nombre avec xxyy, xx est le high byte) avec le "low byte"(yy). Ex : A=1523, XBA, A=2315 Note sur les bits : 1 byte = 8bits = xx, 2 bytes = 16bits = xxxx, 3 bytes = 24bits = xxxxxx, etc... REP : Reset Processor Status et SEP: SEt Processor status flag. Quand vous avez une adresse en 2 byte, les manips ne marcheront pas. Vous devez donc utiliser : REP #$20 -> A passe en 16 bits REP #$30 -> A, X et Y passent en 16 bits REP #$10 -> X et Y passent en 16bits SEP #$20 -> A retourne en 8 bits SEP #$30 -> A, X et Y retournent en 8bits SEP #$10 -> X et Y retournent en 8 bits J'explique ce qu'est le processor status ou flag register : c'est un ensemble de 8 bits (ex : 01000101) dont chaque bit se met sur 0 ou 1 en fonction des opérations effectuées. On a : N V M X D I Z C N : negative flag V : overflow flag M : "m" (?) flag X : "x" (?) flag D : decimal flag I : interrupt flag Z : zero flag C : carry flag Bon je vous explique quand même X et Y : ils fonctionnent à peu près pareil que l'A, mais ils ont d'autres propriétés, notamment une très importante : l'indexing (le fait de pouvoir stocker plusieurs valeur à la fois (je ne vous l'expliquerais pas car je ne le comprend pas, mais sachez qu'il est SUPER utile dans les custom sprites)). Préférez l'A ^^. Cela dit cela peut être utile si vous voulez ne pas utilisez l'A pour telle raison. Après il y a le stack : il vous permet de stocker une valeur un moment, puis de la remettre ensuite. C'est comme une pile de livres : vous mettez un livre sur cette pile, vous effectuez n'importe quoi, mais après vous reprenez le livre. Opcodes liés au stack : PHA : PusH A. Prend un "livre" ou valeur de l'accumulator et le met sur le stack. PLA : PuLl A. Remet à sa place le "livre" ou valeur déposée précédemment. Voici maintenant 2 opcodes tout à fait inutile xD : NOP : NO oPération. Celui ci ne fera strictement rien STP : StoP the Clock. Celui la "freeze" le jeu : la partie se bloque. Et maintenant des très importants : CMP : CoMPare A with memory et BEQ : Branch if EQual, BNE : Branch if Not Equal Un petit exemple va vous permettre de comprendre : LDA $0DBF met le nb de pièces de mario dans l'A... CMP #$20 ...compare cette valeur avec le nombre 20 (en décimal, 32)... BNE retour ...si ces 2 valeurs ne sont pas égales, aller à l'étiquette retour... INC $0DBF ...sinon, augmenter les pièces de 1... retour : RTS ...retourner au jeu. Donc si vous n'avez pas 32 pièces, vous n'aurez pas une pièce en plus. CMP associé à BEQ, BNE,... sont utilisé pour les branchements. Quand vous utilisez CMP, on soustrait la valeur de l'A à la valeur derrière l'opcode : si les deux valeurs sont identiques, le zero flag est mis sur ON. BEQ branche alors si le zero flag = ON. C'est pourquoi vous pouvez voir des BEQ ou BNE tout seul : ils utilisent le zero flag directement. Il existe aussi : BCS (BGE) : Branch if GrEater than -> si valeur > A, carry flag = ON donc BCS branche si carry flag = ON BCC (BLT) : Branch if Less Than -> branche si carry flag = OFF BPL : Branch if Plus -> branche si negative flag = OFF BMI : Branch if Minus -> branche si negative flag = ON Les deux dépendent du negative flag : une valeur directe est dite positive si <#$80, et négative si >=#$80 (si vous voulez savoir : positive : de #%00000000 à #%01111111 ; négative : de #%10000000 à #%11111111) BVC : Branch if oVerflow Clear -> branche si overflow flag = OFF BVS : Branch if oVerflow Set -> branche si overflow flag = ON, c'est-à-dire s'ils dépassent #$FF ou #$00. Ces deux-là en revanche dépendent de l'overflow flag ; je l'expliquerai dans la partie ADC/SBC. Avez-vous remarqué ? J'ai mis RTS... RTS : ReTurn from Subroutine. Cet opcode doit terminer chaque bloc. Pourquoi ? parce que ça dit à la snes de retourner aux actions possibles de Mario, au jeu... Voyez cela comme ça : .....(jeu).............(Mario touche/frappe un bloc)->[action du bloc........RTS].......(jeu)..... Quand vous tapez un bloc, le jeu est "jumped", littéralement "sauté", par l'opcode : JSR : Jump to SubRoutine. JSL : Jump to Subroutine Long. Cet opcode utilisé dans un bloc bascule vers une autre subroutine (comme par exemple la routine ou Mario devient petit ou gros) ; les opcodes situés à l'adresse indiquée sont effectuées (s'il n'y en pas, c'est le gros bug). Vous pouvez trouver des subroutines dans la ROM Map de smwcentral (conseil : cliquez sur type pour les trier, elles se trouveront à la fin). Si vous voulez savoir comment ça marche, JSL met la location de votre code dans le stack et bascule vers ladite subroutine. Le RTL : Return to Subroutine Long à la fin de la subroutine repioche la localisation de votre code dans le stack. C'est le même principe avec RTS : le saut vers votre code a mis la localition "vers le jeu" dans le stack. RTS à la fin utilise alors cette donnée pour y retourner ; donc si vous mettez qqch dans le stack lors de votre code et que vous ne le reprenez pas, RTS va vous envoyer n'importe où ! Attention : l'adresse à mettre lors de l'utilisation de JSL est la snes adresse. Ex : JSL $00F5B7 bascule vers la subroutine qui blesse Mario RTS Ce bloc est donc comme une "black piranhe plant" ^^ JSR doit être utilisé avec RTS, et JSL avec RTL. Simple ? JMP : JuMP JML : JuMp Long Idem sauf qu'on peut basculer vers une étiquette. Allez les derniers : ADC : ADd with Carry. Ajoute la valeur directe d'après à l'A. SBC : SuBstract with Carry. Soustrait la valeur d'après à l'A. CLC : Clear Carry flag SEC : SEt Carry flag Ces quatre opcodes doivent être associés pour éviter de drôles de résultats. En effet, ADC et SBC dépendent du "carry flag" : si le carry flag est mis en quelle que sorte sur ON (1), ADC ajoutera votre valeur à l'A + 1 ; si le carry flag est mis sur OFF (0), SBC ôtera votre valeur à l'A et enlèvera aussi 1. Pour éviter toute interférence, on utilise CLC avec ADC et SEC avec SBC. Note : si l'addition dépasse #$FF ou est en dessous de #$00, le compteur reprend à l'exact opposé. Ex : #$FF + #$01 = #$00, #$FF + #$02 = #$ 01, #$00 - #$02 = #$FE, ... Donc #$100 = #$00 et #$-01 = #$FF. Quand les compteurs reprennent à ces valeurs, l'overflow flag esy mis sur ON. Note 2 : les seules opérations possibles sont les additions/soustraction avec les registers. Les multiplications et divisions sont infaisables (sauf les multiplications et divisions rapides avec ASL et LSR). Ce qui nous amène donc aux... Les boucles Vous voulez augmenter telle valeur de, disons trente, INC ne marchera pas (à moins de mettre 30 INC ^^), et malheureusement on ne veut pas utiliser ADC. Que faire ? et bien on fait des boucles ! un petit exemple : LDA $0DBF Met le nb de pièces dans l'A... boucle : ...étiquette... INC ...augmente de 1 l'A... CMP #$70 ...comparer cette valeur avec #$70... BNE boucle ...si ces deux valeurs ne sont pas égales, retourner à "boucle"... STA $0DBF ...sinon réinsérer les pièces dans le compteur... RTS ...retour. Si on fait un bloc avec ce code, on a un bloc qui augmente les pièces de Mario jusqu'à 70, d'où l'inutilité de ADC qui ne peut pas régler le compteur de pièces sur un tel nombre. Maintenant les boucles de multiplication : PHY Sauvegarde Y dans le stack... LDY $0DBF ...y met le nb de pièces... LDA #$00 ...met 0 dans l'A... boucle : CLC ...carry flag = OFF... ADC #$03 ...A + 3... DEY ...diminue de 1 Y... CPY #$00 ...comparer Y avec 0... BNE boucle ...si les deux valeurs ne sont pas égales, aller à boucle... STA #$0DBF ...sinon remettre le nb de pièces ds le compteur... PLY ...remettre la valeur de Y... RTS ...retour. Ce code multiplie le nb de pièces par 3. En réalité, il augmente l'A de 3 autant de fois qu'il y a de pièces (le nb de Y), ce qui revient au même, non ? Voila pour la première partie. Si vous avez déjà compris cela, ça ira tout seul après ^^. |
Très beau boulo frachement, il ne manquais plus que ça pour notre petite bande de hackeurs :P ça deviens de la programmation plus que de l'édition mais bon, c'est génial ^^
|
en francais ça veut dire quoi ?
fin je comprend pas j'ai tous lol rien a faire peut t-on expliquer plus clairement ? |
Mario 34500 c'est simplement trop dur pour toi, mais ça reste du Français et SL a ecrit tout ça entierement de lui meme me semble t-il, il faut donc feliciter son boulot meme si ça ne te concerne pas.
|
c'est du bon boulot mais il faut une explication plus logique car les code il faut savoir les bases ça c'est pas gagner car j'ai aussi fait cette erreur mais bon boulot
|
Avant de demander aux autres de parler français tu devrais peut-être t'appliquer un peu sur ton orthographe :D
|
Citation:
En revanche tu peux poser des questions sur des points que tu ne comprend pas n'hésite pas ;) |
je voudrazis créer un bloc qui donne un champi si mario est petit mais une pièce seulement si mario est super, feu ou capé . pourrais-tu me donner quelques conseils et surtout me dire si il existe pas déjà ???
|
Non je ne crois pas que le block existe (à ma connaissance:P ).
Donc pour le faire je peux déjà te dire ce que tu as besoin : - tu dois utiliser : l'adresse du status de Mario : $0019 CMP et les branchements - il est possible que tu utilise : l'adresse du compteur de pièces : $0DBF Bon : Si tu veux un question bloc : - Utilise : LDA $0019 CMP #$00 BEQ/BNE (j'ai un doute) nothing LDA #$01 STA $0019 nothing : RTS Comme c'est un bloc 1pièce, s'il fait rien il te donnera une pièce. Mais il te donnera une pièce avec le champi (attention : mario ne grandira pas comme lorsqu'il a un champi : il sera en big mario d'un seul coup). Donc autre possibilité : ... BEQ/BNE nada LDA.. STA.. RTS nada : LDA $0DBF CLC ADC #$01 STA $0DBF LDA #$01 STA $1DFC RTS Tout en le mettant en nothing block. Mais PB car si le nb pièce = 99, block met les pièce à A0 ou un truc comme ça. Donc encore mieux : ... B.. nadadenadita LDA #$1F STA $1693 LDY #$01 RTS nadadenadita : RTS Tout en le mettant en 1pièce bloc. Si mario petit, block = flower block dc mushroom block. - si tu veux un block activable de tt les cotés : ... B.. nooooon,rienderien,nooooon,jeneregretterien (nan je rigole) LDA #$01 STA $0019 RTS nianianian : 2 possibilté : 1. LDA #$2B STA $1693 LDY #$00 RTS MAIS suis pas sûr que ça marche. 2. LDA $0DBF CLC ADC #$01 STA $0DBF LDA #$01 STA $1DFC RTS Celle-ci marchera je pense. Tu vois, il y a plein de possibilité ! adapte ton code à ce que tu veux |
houlà, chargé!
garaararag |
oui je sais :lol:
c'est venu tt seul mais ça peut t'aider tu sais :D |
heu merci de m'avoir mâché le boulot, mais j'ai un blème, le bloc que j'ai "crée" agit pareil qu'un invisible coin question block !
|
:huh:
Ca va être dur de le régler comme ça. Dis-moi d'abord ton code et le block acts like et je pourrais peut être te dire ce qui ne va pas :D |
en fait j'ai mis ça comme code :
BEQ nothing LDA #$1F STA $1693 LDY #$01 RTS nothing : LDA $0DBF CLC ADC #$01 STA $0DBF LDA #$01 STA $1DFC RTS et ensuite j'ai suivi la pratique pas à pas pour avoir un bloc-17-pièces (seulement la partie pour l'insérer dans blktool, puis dans LM tkt) en gros j'ai mis que ce bloc act like 124, et en valeur sur bloktool, 0,-1,-1,-1,-1,0, etc.... |
Bon alors...
Il manque l'opcode pour comparer. Tu l'as peut être mis, Mais je le dis quand même : LDA $0019 CMP #$00 BNE nothing Les ... étaient pour ne pas répéter LDA..CMP.. Ensuite si tu as mis un block 1 pièce, et que tu met un code qui augmente de 1 le compteur, ca va te donner 2 pièces au lieu d'une. Soit tu garde le code : LDA $0DBF CLC ADC #$01 STA $0DBF LDA #$01 STA $1DFC et tu met block acts like 129 (nothing block) ; soit tu enlève le code (ca donne : nothing : RTS ) et tu met le block acts like 124 (block 1 pièce). Je préfère plutôt pour la deuxième solution car on évite un bug possible lorsque les pièces sont à 99. Donc préfère la solution où le block acts like est 124. Voilà ;D . Là ca devrait marcher (sauf peut être pour le BEQ/BNE (je penche pour BNE) dont je ne suis pas sûr) |
sinon, au lieu de donner une pièce ce qui était déjà très généreux, il donne... kedal(mais sauf si mario pitit tu le sais), ça serait bien ça! :D pour ne pas te compliquer et m'emmeler les pinceaux, pourrais-tu me donner le code final qui conviendrait le mieux ?
je voudrais faire un copie-colle, c'est pas tres honnete mais j'y cale vraiment rien , meme avec ton tuto! :wacko: |
J'ai pas tout compris... tu veux qu'il ne donne rien du tout à présent ? (lorsque mario pas = à chtit évidemment)
|
heu oui c'est ça T_T
désolé de te faire ièch :( |
Mon cher noob-ou-pas, non tu ne me fais pas iech parce que l'ASM c'est mon truc ;D . Je tiens quand même à m'excuser royalement car je viens de me pencher sur le block et je l'ai créer sans souci. Pourquoi alors je m'excuse ? parce que je t'ai embrouillé totalement avec tout mes trucs alors que c'est pourtant très simple :blush: . Je te donne le code que tu peux recopier ne t'en fais pas je ne t'en voudrai pas ;) :
LDA $0019 charger le status de mario... CMP #$00 ...comparer ac 0 (0=petit mario)... BNE rien ... si mario pas petit, aller à rien (donc ne rien faire)... LDA #$1F \ STA $1693 |...sinon faire agir le bloc comme un mushroom bloc... LDY #$01 / rien : RTS ...retour. Mettre le block acts like à 124 pour quand même avoir une pièce, et sur 129 pour rien du tout. Et désolé pour le retard. Edit : et c'est pas grave de pas comprendre à vrai dire c'est normal car je sais que j'ai dû vraiment t'embrouiller... |
Fuseau horaire GMT +2. Il est actuellement 02h42. |
vBulletin® v.3.8.7, Copyright ©2000-2024, Jelsoft Enterprises Ltd.