*
*
*         ***********************************
*         *                                 *
*         *    GAG1: Pousse-pousse écran    *
*         *                                 *
*         ***********************************
*
*
*    Syntaxe:   GAG1 [tempo] [commande]
*
*    Ce module assure:
*         - sans la commande QUIT: l'implantation du programme en mémoire,
*                                  (ou la modification de ses paramètres). 
*
*         - avec la commande QUIT: la terminaison de la tache.
*
*
*    Sont gérés: - l'effacement du pointeur au bout de Tempo1
*                - une touche de "hot key" appelée par Left Amiga + Esc
*
*
*    Les constantes suivantes régissent les timings du programme
*    et les valeurs par défaut (tempo2).
*
Tempo1    equ       5         5 secondes avant effacement pointeur
Tempo2    equ       30        30 secondes avant action
*
*    Ces deux constantes déterminent la cadence du timer
*
Delay1    equ       999999    delay jusqu'au temps de l'action (en µs)
Delay2    equ       40000     delay en cours d'action (en µs)
*                             (si 0: on n'appelle pas BE100).
*
*
*    Le programme appelle 3 labels à définir:
*
*         BD100     Action à réaliser quand la tempo est écoulée
*                   (init du blanker ou autre)
*         BE100     Action réalisée toutes les Delay2 µs, une fois la
*                   tempo écoulée.
*         BF100     Fin des actions précédentes pour retour au mode
*                   d'affichage normal.
*
          nolist
          include   "exec/types.i"
          include   "exec/memory.i"
          include   "exec/io.i"
          include   "exec/interrupts.i" 
          include   "libraries/dosextens.i"
          include   "graphics/copper.i"
          include   "graphics/gfxbase.i"
          include   "devices/input.i"
          include   "devices/inputevent.i"
          include   "devices/timer.i"
          list
          xdef      _main
          xref      _DOSBase,_stdout
          xref      _CreatePort,_DeletePort
          xref      _CreateStdIO,_DeleteStdIO
          xref      _LVOAllocMem,_LVOFreeMem,_LVOAllocEntry,_LVOFreeEntry
          xref      _LVOOpenLibrary,_LVOCloseLibrary
          xref      _LVOFindPort,_LVOFindTask,_LVOForbid
          xref      _LVOPutMsg,_LVOGetMsg,_LVOWaitPort,_LVOReplyMsg
          xref      _LVOOutput,_LVOWrite,_LVOLoadSeg,_LVOExit,_LVOExecute
          xref      _LVOUnLoadSeg,_LVOCreateProc,_LVOOpen,_LVOClose
          xref      _CreateExtIO,_DeleteExtIO
          xref      _LVOOpenDevice,_LVOCloseDevice
          xref      _LVODoIO,_LVOSendIO
*
AbsExecBase    equ  4
*
*  Définition des message (on utilise une IO standard pour support)
*
MSG_Cmd   equ       IO_COMMAND          Notre commande
MSG_HK    equ       IO_DATA             adresse de la commande Hot Key
MSG_Tempo equ       IO_ACTUAL           valeur de la tempo
MSG_AdSeg equ       IO_LENGTH           adresse du Segment du process
MSG_stdio equ       IO_OFFSET           adresse stdout
MSG_Used  equ       IO_ERROR            -1 si message utilisé (input.event)
MSG_Flags equ       IO_FLAGS            flags (input.event)
*
*    Commandes utilisées
*
CMD_Exit  equ       'EX'
CMD_Param equ       'PA'
CMD_Event equ       'EV'
*
*
_main     move.l    4(sp),d7            nombre d'arguments
          move.l    8(sp),a4            adresse liste des arguments
          lea       BA(pc),a5           Base des données
*
*    Gestion du systeme lanceur / process
*
          move.l    AbsExecBase,a6
          lea       DosName(pc),a1
          moveq     #0,d0
          jsr       _LVOOpenLibrary(a6) open Dos library
          move.l    d0,BaseDos-BA(a5)
*
          lea       CA101-BA(a5),a1
          jsr       _LVOFindPort(a6)    Cherche port du process
          move.l    d0,AA101-BA(a5)     Port du Process
          bne       BA200               B si process existe
*
          lea       CA102-BA(a5),a1
          jsr       _LVOFindPort(a6)    Cherche Port de l'installeur
          move.l    d0,AA102-BA(a5)     Port de l'installeur
          bne       BA300               B si process en lancement
          page
*
*    On est en phase d'installation: création port de l'installeur
*    -------------------------------------------------------------
*
BA100     bsr       BA800               Extraction des arguments
          bmi       BA165               B si demande usage: fin
          clr.l     -(sp)               Priorité
          pea       CA102-BA(a5)        Nom du port
          jsr       _CreatePort
          addq.l    #8,sp
          move.l    d0,AA102-BA(a5)     Adresse port de l'installeur
*
*    Prise en compte des arguments de la ligne de commande
*
          tst.l     d3                  demande de quitter
          beq.s     BA105               B si pas 'QUIT'
          lea       MA100-BA(a5),a0     erreur: le process n'est pas present
          bsr       BA900
          bra       BA160               Désallocation et fin
*
*    Chargement du Programme
*
BA105     move.l    BaseDos-BA(a5),a6
          move.l    (a4),d1             Nom du module
          jsr       _LVOLoadSeg(a6)     Chargement
          move.l    d0,AA103-BA(a5)     adr du segment
          bne.s     BA110               B si OK
          lea       MA101-BA(a5),a0     message d'erreur
          bsr       BA900
          bra       BA160               Désallocation et fin
*
*    Création du Process
*
BA110     lea       CA103-BA(a5),a0     Nom du Process
          move.l    a0,d1
          clr.l     d2                  Priorité
          move.l    d0,d3               segment
          move.l    #4000,d4            stack size
          jsr       _LVOCreateProc(a6)
          move.l    d0,d5               Process identifier (ad port)
          bne.s     BA115               B si OK
          lea       MA101-BA(a5),a0     message d'erreur
          bsr       BA900
          bra.s     BA155               Désallocation et fin
*
*    Création d'un message pour démarrer le process
*
BA115     move.l    AA102-BA(a5),-(sp)  adresse du port associé
          jsr       _CreateStdIO
          addq.l    #4,sp
          move.l    d0,AA104-BA(a5)     pour nettoyage plus tard
          move.l    d0,a1               adresse du message
*
          move.l    AbsExecBase,a6
          move.l    d5,a0               port pour startup
          jsr       _LVOPutMsg(a6)      envoi message de démarrage process
*
*    On attend maintenant un message demandant les args
*
          move.l    AA102-BA(a5),a0     port de l'installeur
          jsr       _LVOWaitPort(a6)
*
*    On récupère celui qu'on nous a envoyé pour répondre
*
          move.l    AA102-BA(a5),a0     notre port
          jsr       _LVOGetMsg(a6)      récupère le message du process
*
*    On charge la réponse
*
          move.l    d0,a1               adresse du message
          bsr       BA720               chargement des arguments
          jsr       _LVOReplyMsg(a6)
*
*    On attend la prise en compte avant de terminer
*
          move.l    AA102-BA(a5),a0     port de l'installeur
          jsr       _LVOWaitPort(a6)
          move.l    AA102-BA(a5),a0     notre port
          jsr       _LVOGetMsg(a6)      récupère le message du process
          move.l    d0,a1
          jsr       _LVOReplyMsg(a6)    on répond qu'on s'en va
*
*    Petite info à l'utilisateur pour dire que ça marche
*
          lea       MA102-BA(a5),a0
          bsr       BA900
*
*    Le process tourne comme un grand, on peut partir
*
BA150     clr.l     AA103-BA(a5)        pour ne pas faire UnLoadSeg !
          move.l    AA104-BA(a5),-(sp)  message inutile
          jsr       _DeleteStdIO
          addq.l    #4,sp
*
BA155     move.l    AA103-BA(a5),d1     Segment
          beq.s     BA160               B si pas chargé
          move.l    BaseDos-BA(a5),a6
          jsr       _LVOUnLoadSeg(a6)
*
BA160     move.l    AA102-BA(a5),-(sp)  notre port
          jsr       _DeletePort
          addq.l    #4,sp
*
          move.l    BaseDos-BA(a5),a1
          move.l    AbsExecBase,a6
          jsr       _LVOCloseLibrary(a6)
BA165     moveq     #0,d0               code d'erreur
          rts
          page
*
*    Le process est present, il faut le modifier
*    -------------------------------------------
*
BA200     bsr       BA800               Extraction des arguments
          bmi.s     BA165               B si demande usage: fin
          clr.l     -(sp)               Priorité
          pea       CA102-BA(a5)        Nom du port
          jsr       _CreatePort
          addq.l    #8,sp
          move.l    d0,AA102-BA(a5)     Adresse port de modif
*
*    Préparation d'un message
*
          move.l    d0,-(sp)            adresse port pour réponse
          jsr       _CreateStdIO
          addq.l    #4,sp
          move.l    d0,AA201-BA(a5)     adresse du message
*
*    Prise en compte des arguments de la ligne de commande
*
          move.l    d0,a1               adresse du message
          bsr       BA720               préparation du message
          tst.l     d3                  demande de quitter
          beq.s     BA205               B si pas demande de quitter
          move.w    #CMD_Exit,MSG_Cmd(a1)
*
*    Et on envoie le message au process
*
BA205     move.l    AA101-BA(a5),a0     destinataire
          jsr       _LVOPutMsg(a6)
*
*    On attend sa réponse
*
          move.l    AA102-BA(a5),a0     adresse de notre port
          jsr       _LVOWaitPort(a6)
          move.l    AA102-BA(a5),a0
          jsr       _LVOGetMsg(a6)      on récupère notre message
*
*    On extrait l'adresse du segment pour faire l'UnLoad si QUIT
*
          lea       MA201-BA(a5),a0     info transmission arguments
          tst.l     d3
          beq.s     BA210               B si pas Exit
          move.l    d0,a1               adresse du message
          move.l    MSG_AdSeg(a1),d1    adresse du segment
          move.l    BaseDos-BA(a5),a6
          jsr       _LVOUnLoadSeg(a6)
          lea       MA202-BA(a5),a0     info programme terminé
BA210     bsr       BA900
*
*    On a bien bossé, on peut s'en aller
*
          move.l    AA201-BA(a5),-(sp)  notre message
          jsr       _DeleteStdIO        on supprime
          addq.l    #4,sp
          bra       BA160               c'est la fin !
          page
*
*    On entre en execution du process: on l'initialise
*    -------------------------------------------------
*
BA300     clr.l     -(sp)               Priorité
          pea       CA101-BA(a5)        Nom du port
          jsr       _CreatePort
          addq.l    #8,sp
          move.l    d0,AA301-BA(a5)     Adresse port du process
*
*    On se prépare un message pour dialogue avec le lanceur
*
          move.l    d0,-(sp)            adresse de notre port
          jsr       _CreateStdIO        le message sera retourné par le
          addq.l    #4,sp               lanceur pour indiquer les args.
          move.l    d0,VA301-BA(a5)      adresse de notre message
*
*    On envoie notre message et on attend la réponse
*
          lea       CA102-BA(a5),a1
          jsr       _LVOFindPort(a6)    Cherche Port de l'installeur
          move.l    d0,AA302-BA(a5)     Port de l'installeur
*
          move.l    VA301-BA(a5),a1     message
          move.l    d0,a0               port destinataire
          jsr       _LVOPutMsg(a6)      envoi message de démarrage process
*
*    On attend maintenant la réponse nous renvoyant les args
*
          move.l    AA301-BA(a5),a0     port du process
          jsr       _LVOWaitPort(a6)
          move.l    AA301-BA(a5),a0
          jsr       _LVOGetMsg(a6)      récupération du message
          move.l    d0,a1               adresse du message
*
*    Récupération des arguments transmis
*
          bsr.s     BA700
          move.l    MSG_AdSeg(a1),AA303-BA(a5)    adr du segment
*
*    On fait un aller-retour de message pour signaler qu'on peut
*    maintenant fonctionner seul (arguments récupérés).
*
          move.l    AA302-BA(a5),a0
          jsr       _LVOPutMsg(a6)
          move.l    AA301-BA(a5),a0     port du process
          jsr       _LVOWaitPort(a6)
          move.l    AA301-BA(a5),a0
          jsr       _LVOGetMsg(a6)      récupération du message
*
*    notre message est maintenant inutile, on le supprime
*
          move.l    VA301-BA(a5),-(sp)
          jsr       _DeleteStdIO
          addq.l    #4,sp
          bra       BB100               Vers init de l'action
*
*
*    Code de sortie du process
*    -------------------------
*
BA350     move.l    AA301-BA(a5),-(sp)  notre port
          jsr       _DeletePort
          addq.l    #4,sp
*
*    Multitache bloqué, on retourne l'adresse de notre segment
*
          move.l    AbsExecBase,a6
          jsr       _LVOForbid(a6)      inhibe switching
          move.l    VA301-BA(a5),a1     adresse du message
          move.l    AA303-BA(a5),MSG_AdSeg(a1)
          jsr       _LVOReplyMsg(a6)
*
*    Et on sort discrètement !
*
          move.l    BaseDos-BA(a5),a6
          moveq     #0,d1               code de retour
          jsr       _LVOExit(a6)
          bra       *                   pour ne pas pédaler dans la semoule
*
*    Récupération des arguments transmis par message
*    -----------------------------------------------
*         (a1 = adresse du message)
*
BA700     move.l    MSG_Tempo(a1),VA302-BA(a5)    valeur de la tempo
          move.l    MSG_stdio(a1),_stdout         standard output
          move.l    MSG_HK(a1),a2                 adresse commande hot key
          lea       VA303-BA(a5),a0               adresse de notre HK
BA705     move.b    (a2)+,(a0)+                   transfert commande
          bne.s     BA705
          rts
*
*    Routine de chargement des arguments dans le message
*    ---------------------------------------------------
*         (a1 = adresse du message)
*
BA720     move.w    #CMD_Param,MSG_Cmd(a1)
          lea       VA802-BA(a5),a0
          move.l    a0,MSG_HK(a1)       commande sur hot key
          move.l    VA801-BA(a5),MSG_Tempo(a1)
          move.l    AA103-BA(a5),MSG_AdSeg(a1)
          move.l    _stdout,MSG_stdio(a1)
          rts
*
*
*    Routine de récupération des arguments de la ligne de commande
*    -------------------------------------------------------------
*
BA800     clr.b     VA802-BA(a5)        pas de hot commande
          move.w    #Tempo2,VA801-BA(a5) tempo par défaut
*
*    Si on vient de Workbench, on n'a pas d'arguments et on cherche le
*    nom du programme
*
          move.l    a6,-(sp)
          move.l    AbsExecBase,a6
          suba.l    a1,a1
          jsr       _LVOFindTask(a6)    qui sommes nous ?
          move.l    (sp)+,a6
          move.l    d0,a1
          tst.l     pr_CLI(a1)          d'ou venons-nous ??
          bne.s     BA805               On vient du CLI
          moveq     #0,d7               WB: donc pas d'arguments
          lea       LN_NAME(a1),a4      adresse du nom du programme
*
*    Rassuré quand à nos origines, on continue
*
BA805     moveq     #0,d3               demande de quitter
          subq.w    #2,d7               nombre d'arguments
          bmi       BA855               B si pas d'arguments
          movem.l   a4/d7,-(sp)
          addq.l    #4,a4               pointe sur adr premier argument
*
*    Controle si c'est une demande de syntaxe
*
          move.l    (a4),a1             adr premier argument
          cmpi.b    #'?',(a1)
          bne.s     BA810               B si pas demande de syntaxe
          lea       MA801-BA(a5),a0
          bsr       BA900               message info syntaxe
          not.l     d3
          bra.s     BA850
*
*    Récupération d'une valeur éventuelle de tempo
*
BA810     bsr.s     BA875               Get un chiffre
          bmi.s     BA825               B si pas chiffre: pas tempo
          moveq     #0,d1
BA815     mulu      #10,d1
          add.w     d0,d1
          bsr.s     BA875               Get chiffre suivant
          bpl.s     BA815
*
          cmpi.w    #Tempo1+1,d1        Valeur mini de la tempo
          bge.s     BA820
          moveq     #Tempo1+1,d1
BA820     move.w    d1,VA801-BA(a5)     Valeur de la tempo
          addq.l    #4,a4               passage à l'arg suivant
          subq.w    #1,d7               il en reste un de moins
          bmi.s     BA850               B s'il n'y en a plus
*
*    Extraction de la commande (hot key)
*
BA825     lea       VA802-BA(a5),a1     notre ligne de commande
BA830     move.l    (a4)+,a0            l'argument
BA835     move.b    (a0)+,(a1)+         copie de l'argument
          bne.s     BA835
          move.b    #' ',-1(a1)         recrée le séparateur
          dbra      d7,BA830            argument suivant
          clr.b     -1(a1)              fin de la chaine
*
*    La commande est-elle QUIT ?
*
          tst.b     VA802+4-BA(a5)
          bne.s     BA850               Pas quatre lettres
          move.l    VA802-BA(a5),d0
*
*    Forcage en majuscules
*
          moveq     #3,d1
BA840     ror.l     #8,d0
          cmpi.b    #'a',d0
          blt.s     BA845
          cmpi.b    #'z',d0
          bgt.s     BA845
          subi.b    #$20,d0
BA845     dbra      d1,BA840
          cmpi.l    #'QUIT',d0
          bne.s     BA850
          addq.w    #1,d3               Indique demande d'Exit
*
*    Retour après extraction
*
BA850     movem.l   (sp)+,a4/d7
BA855     tst.l     d3
          rts
*
*    Extraction d'un chiffre (négatif si pas chiffre)
*
BA875     moveq     #0,d0
          move.b    (a1)+,d0
          cmpi.b    #'0',d0
          blt.s     BA880               B si pas chiffre
          cmpi.b    #'9',d0
          bgt.s     BA880               B si pas chiffre
          subi.b    #'0',d0             décodage
          rts
BA880     moveq     #-1,d0              indique erreur
          rts
*
*    Sortie du message d'erreur (adresse dans a0)
*    --------------------------------------------
*
BA900     move.l    a0,-(sp)
          bsr       _RBputs
          addq.l    #4,sp
          rts
          page
*
*
*    Préparation de l'action du blanker
*    ----------------------------------
*
*    Allocation de la memoire nécessaire
*
BB100     move.l    AbsExecBase,a6
          lea       CB101-BA(a5),a0     liste d'allocation
          jsr       _LVOAllocEntry(a6)
          move.l    d0,AB101-BA(a5)
*
*    Ouverture librairie graphique
*
          lea       GfxName-BA(a5),a1
          moveq     #0,d0
          jsr       _LVOOpenLibrary(a6)
          move.l    d0,BaseGfx-BA(a5)
*
*    Création d'un message pour transmission des évènements input.device
*
          move.l    AA301-BA(a5),-(sp)  adresse de notre port
          jsr       _CreateStdIO
          addq.l    #4,sp
          move.l    d0,AB102-BA(a5)     adresse du message
          move.l    d0,a0
          move.w    #CMD_Event,MSG_Cmd(a0) type du message
          clr.b     MSG_Used(a0)        message libre
*
*    Préparation du dialogue avec le input device
*
          clr.l     -(sp)               priorité = 0
          clr.l     -(sp)               pas de nom
          jsr       _CreatePort
          addq.l    #8,sp
          move.l    d0,AB103-BA(a5)     adresse du port
*
          move.l    d0,-(sp)
          jsr       _CreateStdIO
          addq.l    #4,sp
          move.l    d0,AB104-BA(a5)     adresse IOB input.device
*
          move.l    d0,a1
          lea       CB102-BA(a5),a0     'input.device'
          jsr       _LVOOpenDevice(a6)
*
*    Connexion du handler au input.device
*
          move.l    AB101-BA(a5),a0     adr Memlist
          move.l    Mem_Intrp(a0),a0    adr struct interrupt
          move.b    #NT_INTERRUPT,LN_TYPE(a0)
          move.b    #51,LN_PRI(a0)
          lea       BX100(pc),a1
          move.l    a1,IS_CODE(a0)      adr du handler
          move.l    a5,IS_DATA(a0)      adr des donnees
*
          move.l    AB104-BA(a5),a1     IOB input.device
          move.w    #IND_ADDHANDLER,IO_COMMAND(a1)
          clr.b     IO_FLAGS(a1)
          move.l    a0,IO_DATA(a1)      adr struct interrupt
          jsr       _LVODoIO(a6)        connexion du handler
*
*    Ouverture du timer.device sur le port commun
*
          move.l    #IOTV_SIZE,-(sp)
          move.l    AA301-BA(a5),-(sp)  adr port
          jsr       _CreateExtIO
          addq.l    #8,sp
          move.l    d0,AB105-BA(a5)
*
          move.l    d0,a1
          lea       CB103-BA(a5),a0     'timer.device'
          moveq     #UNIT_VBLANK,d0
          moveq     #0,d1
          jsr       _LVOOpenDevice(a6)
*
*    On lance le timer et c'est parti !
*
          move.l    #Delay1,VB101-BA(a5)
          bsr       BX200               lancement timer
          clr.l     VA301-BA(a5)        pas de message: on tourne
          bra.s     BC100               Go sur le boulot
*
*
*    Désallocation des ressources
*
BB500     move.l    AbsExecBase,a6
          move.l    AB105-BA(a5),a1     IOB Timer
          jsr       _LVOCloseDevice(a6)
*
          move.l    #IOTV_SIZE,-(sp)
          move.l    AB105-BA(a5),-(sp)  IOB Timer
          jsr       _DeleteExtIO
          addq.l    #8,sp
*
          move.l    AB104-BA(a5),a1     IOB input.device
          move.w    #IND_REMHANDLER,IO_COMMAND(a1)
          move.l    AB101-BA(a5),a0     adr Memlist
          move.l    Mem_Intrp(a0),IO_DATA(a1)
          jsr       _LVODoIO(a6)        déconnexion handler interrupt
*
          move.l    AB104-BA(a5),a1     IOB input.device
          jsr       _LVOCloseDevice(a6)
*
          move.l    AB104-BA(a5),-(sp)  input.device IO bloc
          jsr       _DeleteStdIO
          addq.l    #4,sp
*
          move.l    AB103-BA(a5),-(sp)  adr port dialogue input.device
          jsr       _DeletePort
          addq.l    #4,sp
*
          move.l    BaseGfx-BA(a5),a1
          jsr       _LVOCloseLibrary(a6)
*
          move.l    AB102-BA(a5),-(sp)  Adresse message évènements
          jsr       _DeleteStdIO
          addq.l    #4,sp
*
          move.l    AB101-BA(a5),a0     Adresse Memlist
          jmp       _LVOFreeEntry(a6)   et fin
          page
*
*    Boucle principale du process
*    ----------------------------
*
*    Définition des bits des messages (dans d7)
*
EVTimer   equ  0    message timer out
EVHK      equ  1    on a frappé Letf Amiga + Esc
EVAutre   equ  2    Evenement autre (hors messages externes)
*
*    a4 contient l'adresse du message
*
*    Attente d'un message
*
BC100     move.l    AA301-BA(a5),a0     adresse du port
          move.l    AbsExecBase,a6
          jsr       _LVOWaitPort(a6)
          move.w    VC104-BA(a5),d7     Init flags messages reçus
*
*    Vidage du port avant traitement des messages
*
BC105     move.l    AA301-BA(a5),a0     adresse du port
          jsr       _LVOGetMsg(a6)
          tst.l     d0
          beq.s     BC125               B si port vide: traiter
          move.l    d0,a4
*
*    Message évènement
*
          cmpi.w    #CMD_Event,MSG_Cmd(a4) évènement input device
          bne.s     BC110               B si pas évènement
          or.b      MSG_Flags(a4),d7    récupération évènements
          clr.b     MSG_Used(a4)        indique message libre
          bra.s     BC105
*
*    Message timer
*
BC110     cmpi.w    #TR_ADDREQUEST,IO_COMMAND(a4)
          bne.s     BC115               B si pas timer
          bset      #EVTimer,d7
          bra.s     BC105
*
*    Autre message: il est externe, on sauve son adresse
*
BC115     move.l    a4,VA301-BA(a5)     adr message necessitant un Reply
          bra.s     BC105               continuer de vider
*
*    Traitement des messages reçus
*
*    Demande de modification des paramètres
*
BC125     tst.l     VA301-BA(a5)        un message externe ?
          beq.s     BC130               B si pas de message externe
          move.l    VA301-BA(a5),a1     adresse du message
          cmpi.w    #CMD_Param,MSG_Cmd(a1)
          bne.s     BC130               B si pas modifications paramètres
*
*    Modification des paramètres: prise en compte
*
          bsr       BA700               prise en compte
          jsr       _LVOReplyMsg(a6)    on répond
          clr.l     VA301-BA(a5)        plus rien d'externe
          bset      #EVAutre,d7         on reinit le traitement
*
*    Message Hot Key: Left Amiga + Esc
*
BC130     bclr      #EVHK,d7
          beq.s     BC140               B si pas Hot Key
          tst.b     VA303-BA(a5)
          beq.s     BC140               B s'il n'y a pas de commande
          move.l    BaseDos-BA(a5),a6
          lea       CC101-BA(a5),a0
          move.l    a0,d1
          move.l    #1006,d2
          jsr       _LVOOpen(a6)        open NIL:
          move.l    d0,d6               sauve filehandle
*
          lea       VA303Ex-BA(a5),a0
          move.l    a0,d1               commande
          move.l    d6,d2               Filehandle pour input
          move.l    d6,d3               filehandle pour output
          jsr       _LVOExecute(a6)
*
          move.l    d6,d1
          jsr       _LVOClose(a6)       close NIL:
          move.l    AbsExecBase,a6
          bset      #EVAutre,d7         pour reinit
*
*    Traitement d'un évènement autre: reinit de l'action
*
BC140     bclr      #EVAutre,d7
          beq.s     BC145               B si pas évènement
          clr.w     VC101-BA(a5)        Compteur temps Sprite
          clr.w     VC102-BA(a5)        Compteur action
          bclr      #Actif,VC103-BA(a5) stoppe action
          beq.s     BC145               B si déjà stoppée
          bsr       BF100               Routine de stop
          move.l    #Delay1,VB101-BA(a5) reinit delay timer
*
*    Message du timer: il est out, on le relance
*
BC145     bclr      #EVTimer,d7
          beq.s     BC165               B si pas timer
*
*    Est-on en attente de quitter ?
*
          tst.l     VA301-BA(a5)        adresse message d'exit
          bne.s     BC190               B si attente d'exit
BC150     bsr       BX200               relance timer
          addq.w    #1,VC101-BA(a5)     inc compteur sprite
          addq.w    #1,VC102-BA(a5)     inc compteur action
*
*    Effacement de la sprite pointeur au bout de la tempo
*
          cmpi.w    #Tempo1,VC101-BA(a5)
          bgt.s     BC155               B si déjà effacée
          blt.s     BC165               B si pas encore
          bsr.s     BC200               Effacement sprite
          bra.s     BC165               Fin
*
*    Action au bout de la tempo 2
*
BC155     move.w    #Tempo1,VC101-BA(a5) saturation compteur sprite
          move.w    VC102-BA(a5),d0     Compteur action
          cmp.w     VA302-BA(a5),d0     Valeur demandée
          blt.s     BC165               B si pas encore
          bset      #Actif,VC103-BA(a5) indique action
          bne.s     BC160               B si déjà en cours d'action
          move.l    #Delay2,VB101-BA(a5) passage sur delay 2
          bsr       BD100               appel init action
          bsr.s     BC200               effacement sprite
          bra.s     BC165
*
*    Action en cours
*
BC160     move.w    VA302-BA(a5),VC102-BA(a5)     saturation compteur
          bsr       BE100               action
BC165     bra       BC100               on retourne attendre les messages
*
*    Demande d'exit: On stoppe l'action
*
BC190     btst      #Actif,VC103-BA(a5) action en cours
          beq.s     BC195               b si déjà à l'arrêt
          bsr       BF100               Stoppe l'action
BC195     bsr.s     BC250               Restitution pointeur
          bsr       BB500               désallocation ressources
          bra       BA350               Exit
*
*
*    Gestion du pointeur: suppression
*    --------------------------------
*
BC200     move.l    AB101-BA(a5),a0     adr Memlist
          move.l    Mem_Sprite(a0),a0   adr de notre sprite
          move.l    a0,d1
          move.l    #$fe00ff00,(a0)     init Sprite
          move.l    BaseGfx-BA(a5),a0
          move.l    gb_copinit(a0),a0
          lea       copinit_sprstrtup(a0),a0 adr de la sprite pointeur
          cmp.w     #$120,(a0)          Registre de la sprite 0
          bne.s     BC210               B si impossible
          cmp.w     #$122,4(a0)
          bne.s     BC210               B si impossible
*
*    Sauvegarde adresse sprite originale
*
          move.w    2(a0),d0
          swap      d0
          move.w    6(a0),d0
          cmp.l     d1,d0               adr de notre sprite
          beq.s     BC210               on ne sauve pas notre sprite
          move.l    d0,VC201-BA(a5)
*
*    Substitution par notre sprite
*
          move.w    d1,6(a0)            adr de notre sprite
          swap      d1
          move.w    d1,2(a0)
BC210     rts
*
*
*    Gestion du pointeur: réaffichage
*    --------------------------------
*
BC250     move.l    VC201-BA(a5),d0     adr de la sprite d'origine
          beq.s     BC260               B si pas sauvée
          move.l    BaseGfx-BA(a5),a0
          move.l    gb_copinit(a0),a0
          lea       copinit_sprstrtup(a0),a0 adr de la sprite pointeur
          move.w    d0,6(a0)
          swap      d0
          move.w    d0,2(a0)
BC260     clr.l     VC201-BA(a5)        reset adresse sauvegarde sprite
          rts
*
*
*    Handler du Input device
*    -----------------------
*
*    Entree: a0 = adresse de la struct InputEvent
*            a1 = adresse de BA (base des donnees)
*
*    Retour: d0 = adresse de la struct InputEvent (egale à a0 en entrée)
*
BX100     move.l    a0,-(sp)            sauve structure InputEvent
          movem.l   a4-a6/d7,-(sp)      sauve
          move.l    a1,a5               base des donnees
          move.l    a0,a4               adr input event
*
*    Test si evenement à prendre en compte
*
          moveq     #0,d7               pas d'évènement
BX110     move.b    ie_Class(a4),d0
          beq.s     BX120               B si évènement null
          cmpi.b    #IECLASS_TIMER,d0
          beq.s     BX120               B si timer: ignorer
          bset      #EVAutre,d7         Evènement à prendre en compte
          cmpi.b    #IECLASS_RAWKEY,d0
          bne.s     BX120               B si pas clavier
          cmpi.w    #$0045,ie_Code(a4)  Esc
          bne.s     BX120               B si pas touche Esc
          move.w    ie_Qualifier(a4),d0
          ori.w     #$8007,d0           Ignore Shift et Caps Lock
          cmpi.w    #$8047,d0           Touche Left Amiga
          bne.s     BX120               B si pas Left Amiga + Esc
          bset      #EVHK,d7            Evenement Hot Key
          clr.b     ie_Class(a4)        On supprime l'évenement
*
*    Passage à l'évènement suivant, s'il existe
*
BX120     move.l    ie_NextEvent(a4),d0
          beq.s     BX130               B si fin de liste
          move.l    d0,a4
          bra.s     BX110
*
*    Création du message vers notre tache
*
BX130     tst.l     d7                  évènement significatif ?
          beq.s     BX150               B si RAS
*
BX140     move.l    AB102-BA(a5),a1     adresse du message
          tst.b     MSG_Used(a1)        message libre ?
          bne.s     BX150               utilisé: on ignore
          move.b    d7,MSG_Flags(a1)    charge les flags
          subq.b    #1,MSG_Used(a1)     indique utilisation
          move.l    AA301-BA(a5),a0     port destinataire
          jsr       _LVOPutMsg(a6)
*
*    Retour au handler système
*
BX150     movem.l   (sp)+,a4-a6/d7      restaure
          move.l    (sp)+,d0            struct InputEvent
          rts
*
*
*    Routine de lancement du Timer
*    -----------------------------
*
BX200     move.l    AbsExecBase,a6
          move.l    AB105-BA(a5),a1     Timer IO block
          clr.l     IOTV_TIME+TV_SECS(a1)
          move.l    VB101-BA(a5),IOTV_TIME+TV_MICRO(a1)
          beq.s     BX205                    B si arret timer
          move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
          clr.w     VC104-BA(a5)             prendre en compte timer
          jmp       _LVOSendIO(a6)           relance timer et retour
BX205     bset      #EVTimer,VC104+1-BA(a5)  ignorer timer
          rts
          page
*
*         Donnees de la base du blanker
*         -----------------------------
*
          cnop      0,2
BA        equ       *                   Base adressage données
BaseDos   dc.l      0
BaseGfx   dc.l      0    
*
DosName   dc.b      'dos.library',0
GfxName   dc.b 'graphics.library',0
*
AA101     dc.l      0                   Adresse du port du process
AA102     dc.l      0                   Adresse du port de l'installeur
AA103     dc.l      0                   Adresse Segment du process
AA104     dc.l      0                   Adresse message de lancement
AA201     equ       AA104               Adresse message demande d'Exit
AA301     equ       AA101               Adresse du port du process
AA302     equ       AA102               Adresse du port de l'installeur
AA303     equ       AA103               Adresse segment du process
AB101     dc.l 0    Adresse de la MemList
AB102     dc.l 0    Adresse du message pour transmission input events
AB103     dc.l 0    Adresse du port de dialogue avec input.device
AB104     dc.l 0    Adresse IO Bloc de dialogue input.device
AB105     dc.l 0    Adresse IO Bloc Timer.device
*
CA101     dc.b      'RB-PrtP',0         Nom du port du process
CA102     dc.b      'RB-PrtI',0         Nom du port de l'installeur
CA103     dc.b      'RB-Proc',0         Nom du process
*
*    Memory list pour allocation mémoire
*
          cnop 0,4
CB101     ds.b LN_SIZE
          dc.w 2
          dc.l MEMF_PUBLIC!MEMF_CHIP!MEMF_CLEAR   Sprite effacement pointeur
          dc.l 12
          dc.l MEMF_PUBLIC!MEMF_CLEAR             Struct interrupt input.dev
          dc.l IS_SIZE
*
Mem_Sprite     equ  ML_ME          Position adresse Sprite
Mem_Intrp      equ  ML_ME+8        position structure interrupt (input.dev)
*
CB102     dc.b 'input.device',0
CB103     dc.b 'timer.device',0
CC101     dc.b 'NIL:',0
*
*
MA100     dc.b      'Sans effet: programme non actif',$a,0
MA101     dc.b      'Echec au lancement du programme',$a,0
MA102     dc.b      'GAG1 installé',$a,0
MA201     dc.b      'Paramètres modifiés',$a,0
MA202     dc.b      'GAG1 est terminé',$a,0
MA801     dc.b      'USAGE: GAG1 [tempo] [commande | QUIT]',$a
          dc.b      '       tempo:    temps en secondes avant effet',$a
          dc.b      '       commande: commande lancée par Left Amiga + Esc'
          dc.b      $a,0
*
VA301     equ       AA104               adr du message du process
VA302     dc.w      0                   Valeur de la tempo
*
*    Pour libérer le prog lors de la commande, il faut faire "Run Cmd"
*    d'ou la constante qui suit, qui doit impérativement précéder VA303.
*
VA303Ex   dc.b      'Run '
VA303     ds.b      80                  Commande hot key
VA801     equ       VA302               Argument tempo
VA802     equ       VA303               commande hot key
VB101     dc.l 0              Delay du timer en microsecondes
VC101     dc.w 0              Compteur temps effacement sprite pointeur
VC102     dc.w 0              Compteur temps démarrage action
VC103     dc.w 0              Flag
Actif     equ  0              Bit du Flag: action en cours
VC104     dc.w 0              Flag par défaut pour réception messages
VC201     dc.l 0              Sauve adresse de la sprite d'origine
          page
*
*         Routines de gestion de l'ecran Pousse-Pousse
*         --------------------------------------------
*
*    Trois entrées:  BD100    Debut (initialisation)
*                    BE100    Action (toutes les 0,1 secondes)
*                    BF100    Fin (désallocation)
*
          nolist
          include   "intuition/intuitionbase.i"
          include   "intuition/screens.i"
          include   "graphics/gels.i"
          list
          xref      _LVOOpenScreen,_LVOCloseScreen
          xref      _LVOScreenToFront,_LVOScreenToBack
          xref      _LVOLoadRGB4,_LVOBltBitMap
          xref      _LVOSetDrMd,_LVOSetAPen,_LVOMove,_LVODraw
          xref      _LVORectFill,_LVOSetPointer,_LVOClearPointer
          xref      _LVOInitGels,_LVOAddBob,_LVORemIBob
          xref      _LVOInitBitMap,_LVOInitRastPort
          xref      _LVOSortGList,_LVODrawGList
*
*    Démarrage de l'action: préparation des ressources
*    -------------------------------------------------
*
BD100     clr.b     LD101-BA(a5)        Ressources non OK
          lea       IntuiName(pc),a1
          moveq     #0,d0
          jsr       _LVOOpenLibrary(a6)
          move.l    d0,BaseIntui-BA(a5)
          beq       BD130               B si open impossible
*
*    Recherche de l'écran avant pour creation struct ecran de travail
*
          move.l    d0,a1               IntuitionBase
          move.l    ib_FirstScreen(a1),a1 ecran le plus avant
          move.l    a1,AD101-BA(a5)     sauve adr du screen copié
          lea       VD100(pc),a0        adr écran à batir
*
          move.w    sc_LeftEdge(a1),ns_LeftEdge(a0)
          move.w    sc_TopEdge(a1),ns_TopEdge(a0)
          move.w    sc_Width(a1),ns_Width(a0)
          move.w    sc_Height(a1),ns_Height(a0)
          move.b    sc_DetailPen(a1),ns_DetailPen(a0)
          move.b    sc_BlockPen(a1),ns_BlockPen(a0)
          clr.l     ns_Font(a0)
          clr.l     ns_DefaultTitle(a0)
          clr.l     ns_Gadgets(a0)
          clr.l     ns_CustomBitMap(a0)
          lea       sc_BitMap(a1),a2
          moveq     #0,d0
          move.b    bm_Depth(a2),d0
          move.w    d0,ns_Depth(a0)
          lea       sc_ViewPort(a1),a2
          move.w    vp_Modes(a2),ns_ViewModes(a0)
          move.w    #CUSTOMSCREEN!SCREENQUIET!SCREENBEHIND,ns_Type(a0)
*
*    Détermination de la taille des blocs et des delta mouvement
*
          moveq     #32,d0              largeur en LoRes
          moveq     #1,d1               dX
          cmpi.w    #320,sc_Width(a1)
          ble.s     BD105               B si LoRes
          moveq     #64,d0
          moveq     #2,d1
BD105     move.w    d0,VD101-BA(a5)     Largeur du bloc
          divu      d1,d0
          move.w    d0,VD103-BA(a5)     nombre de mouvements horizontaux
          move.w    d1,VD110+2-BA(a5)   dX
          neg.w     d1
          move.w    d1,VD111+2-BA(a5)   -dX
*
          moveq     #25,d0              Pour 200 lignes
          moveq     #1,d1               dY
          cmpi.w    #200,sc_Height(a1)
          ble.s     BD110
          moveq     #32,d0              pour 256 lignes
          cmpi.w    #256,sc_Height(a1)
          ble.s     BD110
          moveq     #50,d0              pour 400 lignes
          moveq     #2,d1               dY
          cmpi.w    #400,sc_Height(a1)
          ble.s     BD110
          moveq     #64,d0              pour 512 lignes
BD110     move.w    d0,VD102-BA(a5)     Hauteur du bloc
          divu      d1,d0
          move.w    d0,VD104-BA(a5)     nombre de mouvements verticaux
          move.w    d1,VD112+4-BA(a5)   dY
          neg.w     d1
          move.w    d1,VD113+4-BA(a5)   -dY
*
*    Calcul de la mémoire nécessaire pour l'image du Bob
*
          move.w    VD101-BA(a5),d0     largeur  en pixels
          lsr.w     #3,d0               largeur en octets
          mulu      VD102-BA(a5),d0     hauteur en lignes
          mulu      VD100+ns_Depth-BA(a5),d0     nb de planes
          move.l    d0,CD101A-BA(a5)    taille memoire image du Bob
*
*    Allocation de la mémoire nécessaire
*
          lea       CD101-BA(a5),a0     adr MemList
          jsr       _LVOAllocEntry(a6)
          tst.l     d0
          bmi       BD130               B si echec d'allocation
          move.l    d0,AD100-BA(a5)     adr MemList réelle
          move.l    d0,a4
*
*    Ouverture de l'écran
*
          move.l    BaseIntui-BA(a5),a6
          lea       VD100(pc),a0             adr struct NewScreen
          jsr       _LVOOpenScreen(a6)
          move.l    d0,AD102-BA(a5)          adr du screen
          beq       BD130                    B si open impossible
*
*    Reproduction des couleurs par utilisation de la meme ColorMap
*
          move.l    AD101-BA(a5),a0          ecran modele
          lea       sc_ViewPort(a0),a0       adr du ViewPort modèle
          move.l    vp_ColorMap(a0),a0       adr de la ColorMap modèle
          move.l    cm_ColorTable(a0),a1     adr table couleurs du modèle
          moveq     #0,d0
          move.w    cm_Count(a0),d0          nombre de couleurs
          move.l    AD102-BA(a5),a0          adr de notre écran
          lea       sc_ViewPort(a0),a0       adr de notre ViewPort
          move.l    BaseGfx-BA(a5),a6
          jsr       _LVOLoadRGB4(a6)         affectation des couleurs
*
*    On fixe la couleur d'effacement: couleur 0
*
          move.l    AD102-BA(a5),a0          adr de notre écran
          lea       sc_RastPort(a0),a1       de son RastPort
          moveq     #0,d0                    couleur
          jsr       _LVOSetAPen(a6)
*
*    Préparation des structures d'animation
*
          move.l    AD003(a4),a2        adr struct GelsInfo
          move.l    AD008(a4),gi_nextLine(a2)  array 8 words requis
          move.l    AD009(a4),gi_lastColor(a2) array 8 pointeurs requis
          move.b    gb_SpriteReserved(a6),d0   sprites systeme
          not.b     d0
          andi.b    #$fc,d0                    indispensable !!!
          move.b    d0,gi_sprRsrvd(a2)         sprites utilisables
          clr.w     gi_leftmost(a2)            positions limites
          move.l    AD102-BA(a5),a0            notre Screen
          move.w    sc_Width(a0),d0
          subq.w    #1,d0
          move.w    d0,gi_rightmost(a2)
          clr.w     gi_topmost(a2)
          move.w    sc_Height(a0),d0
          subq.w    #1,d0
          move.w    d0,gi_bottommost(a2)
          lea       sc_RastPort(a0),a0  notre rastport
          move.l    a2,rp_GelsInfo(a0)  adr de nos gels dans le RastPort
          move.l    AD001(a4),a0        adr dummy head VSprite
          move.l    AD002(a4),a1        adr dummy tail VSprite
          jsr       _LVOInitGels(a6)
*
*    Initialisation des structures d'animation
*
          move.l    AD006(a4),a1        adr struct VSprite
          move.l    AD007(a4),a0        adr struct Bob
          move.l    a1,bob_BobVSprite(a0)  link
          move.l    a0,vs_VSBob(a1)
          move.w    VD101-BA(a5),d0     largeur Bob en pixels
          lsr.w     #4,d0               largeur en Words
          move.w    d0,vs_Width(a1)     largeur Bob
          move.w    VD102-BA(a5),vs_Height(a1)    hauteur Bob
          move.w    VD100+ns_Depth-BA(a5),vs_Depth(a1) nb de planes
          move.l    AD005(a4),vs_ImageData(a1)    adr image du Bob
          move.b    #$FF,vs_PlanePick(a1)
          clr.b     vs_PlaneOnOff(a1)
*
*    Ajout du Bob au système
*
          move.l    AD102-BA(a5),a1          adr du Screen
          lea       sc_RastPort(a1),a1       adr du RastPort
          jsr       _LVOAddBob(a6)
*
*
*    Initialisation des adresses des blocs:
*
*    les blocs sont dans l'ordre, de gauche a droite et de haut en bas.
*    Il comprennent 4 mots:
*    X0, Y0    coordonnées dans notre écran
*    X1, Y1    coordonnées dans l'écran d'origine
*
          move.l    AD004(a4),a0        adresse de la table des blocs
          moveq     #7,d3               8 rangées
          moveq     #0,d1               Y
BD115     moveq     #9,d2               10 colonnes
          moveq     #0,d0               X
BD120     move.w    d0,(a0)+
          move.w    d1,(a0)+
          move.w    d0,(a0)+
          move.w    d1,(a0)+
          add.w     VD101-BA(a5),d0     largeur du bloc
          dbra      d2,BD120
          add.w     VD102-BA(a5),d1     hauteur du bloc
          dbra      d3,BD115
*
          moveq     #79,d2
          move.w    d2,VD105-BA(a5)     position origine du trou
*
*    Dessin des blocs de l'ecran avant passage de l'écran en avant
*
BD125     bsr       BG100               affichage d'un bloc
          dbra      d2,BD125
*
*
*    Passage de l'écran en avant
*
          move.l    AD102-BA(a5),a0
          move.l    BaseIntui-BA(a5),a6
          jsr       _LVOScreenToFront(a6)
*
*    Passage sur la séquence init / mouvements
*
          move.w    #79,VD106-BA(a5)    compteur de rafraichissement
          lea       BE200(pc),a0        Prochain traitement
          move.l    a0,AD103-BA(a5)     Aiguillage
          sne       LD101-BA(a5)        Indique tout OK
*
BD130     rts
*
*
*    Cours d'action: on pousse pousse !!!
*    ------------------------------------
*
*    Controle que tout est correct pour executer
*
BE100     tst.b     LD101-BA(a5)       Flag système correct
          beq.s     BD130              B si problème de ressource: exit
*
*    Verification qu'il n'y a pas eu de changement d'écran
*
          move.l    AD100-BA(a5),a4       adresse MemList
          move.l    BaseIntui-BA(a5),a1
          move.l    ib_FirstScreen(a1),a1 écran le plus avant (le notre)
          move.l    sc_NextScreen(a1),d0  second écran (le modèle)
          cmp.l     AD101-BA(a5),d0       écran copié
          beq.s     BE105                 B si pas de changement
*
*    Changement d'écran: on permute aussi
*
          bsr       BF100               On ferme tout
          bra       BD100               et on refait avec le nouvel écran
*
*    Aiguillage vers le traitement en cours
*
BE105     move.l    AD103-BA(a5),a0     Aiguillage courant
          jmp       (a0)                vers le traitement
*
*
*    Traitement 1: Choix et préparation du prochain déplacement
*    ----------------------------------------------------------
*
*    Détermination des mouvements possibles dans les 4 sens
*
*    1- Possibilité de déplacement du trou vers la gauche
*
BE200     moveq     #0,d0
          moveq     #-1,d2              Pour mouvements impossibles
          move.w    VD105-BA(a5),d0     position du trou
          move.w    d0,d1
          divu      #10,d0              10 colonnes
          swap      d0                  reste de la division
          tst.w     d0
          beq.s     BE205               B si pas possible d'aller à gauche
          move.w    d1,d2               position du trou
          subq.w    #1,d2               numéro de la case à permuter
BE205     move.w    d2,VD110-BA(a5)     Trou vers la gauche
*
*    2- Possibilité de déplacement du trou vers la droite
*
          moveq     #-1,d2
          cmpi.w    #9,d0
          bge.s     BE210               B si pas possible d'aller à droite
          move.w    d1,d2
          addq.w    #1,d2               numéro de la case à permuter
BE210     move.w    d2,VD111-BA(a5)     Trou vers la droite
*
*    3- Possibilité de déplacement du trou vers le haut
*
          moveq     #-1,d2
          move.w    VD105-BA(a5),d0     position du trou
          cmpi.w    #9,d0
          ble.s     BE215               B si pas possible de le remonter
          move.w    d0,d2
          sub.w     #10,d2              numéro de la case à permuter
BE215     move.w    d2,VD112-BA(a5)     Trou vers le haut
*
*    4- Possibilité de déplacement du trou vers le bas
*
          moveq     #-1,d2
          cmpi.w    #70,d0
          bge.s     BE220               B si pas possible de descendre
          move.w    d0,d2
          add.w     #10,d2              numéro de la case à permuter
BE220     move.w    d2,VD113-BA(a5)     Trou vers le bas
*
*    Sélection aléatoire d'un des 4 mouvements (parmi les possibles)
*
BE225     move.w    VE101-BA(a5),d0     nombre aleatoire
          mulu      $DFF006,d0          au lieu de 331
          add.w     #5,d0
          divu      #97,d0
          swap      d0
          move.w    d0,VE101-BA(a5)     Nombre aléatoire
*
          andi.w    #3,d0
          cmp.w     VE104-BA(a5),d0     pour empècher le mouvement
          beq.s     BE225               inverse du précédent
          move.w    d0,d2
          add.w     d0,d0               * 2
          add.w     d2,d0               * 3
          add.w     d0,d0               * 6
          lea       VD110-BA(a5),a0     premier cas possible
          move.w    0(a0,d0.w),d1       cas sollicité
          bmi.s     BE225               B si pas possible
*
*    Rangement de la case à permuter pour action qui suit
*
          move.w    d1,VE102-BA(a5)     numéro de la case
          move.l    2(a0,d0.w),VE102+2-BA(a5) deltas mouvement
*
*    Mémorisation du dernier mouvement pour empècher le retour
*
          eor.w     #$01,d2
          move.w    d2,VE104-BA(a5)     dernier mouvement
*
*    Mise à jour compteur de mouvements
*
          move.w    VD103-BA(a5),d0     Nb mouvements horizontaux
          tst.w     VE102+2-BA(a5)      mouvement horizontal
          bne.s     BE230               B si mouvement horizontal
          move.w    VD104-BA(a5),d0     Nb mouvements verticaux
BE230     move.w    d0,VE103-BA(a5)     compteur de mouvements
*
*    Préparation à la séquence suivante: le déplacement
*
          lea       BE300(pc),a0
          move.l    a0,AD103-BA(a5)     Aiguillage
          rts
*
*
*    Gestion du mouvement de la case pas à pas
*
*    Pour la gestion de l'effacement, chaque mouvement a sa propre séquence
*
BE300     move.w    VE102-BA(a5),d0     numéro de la case en mouvement
          asl.w     #3,d0               mul 8
          move.l    AD004(a4),a2        adr table des blocs
          add.w     d0,a2               adresse du descripteur du bloc
*
*    Affichage de la case en mouvement
*
          bsr       BG200               copie de l'image du Bob
*
*    Mise à jour des coordonnées de la case avant son réaffichage
*
          move.w    VE102+2-BA(a5),d0   dX
          add.w     d0,(a2)
          move.w    VE102+4-BA(a5),d0   dY
          add.w     d0,2(a2)
*
          move.l    AD006(a4),a0        adr de la struct VSprite
          move.w    (a2),vs_X(a0)       X Bob
          move.w    2(a2),vs_Y(a0)      Y Bob
          bsr       BG300               Affichage du Bob de la case
*
*    Pour la gestion de l'effacement, chaque mouvement a sa propre séquence
*
          moveq     #0,d0
          moveq     #0,d1
          moveq     #0,d2
          moveq     #0,d3
          move.w    VE102+2-BA(a5),d0   dX
          beq.s     BE315               B si mouvement vertical
          bmi.s     BE305               B si trou vers la droite
*
*    La case va vers la droite: on efface sa gauche
*
          move.w    (a2),d0             X case
          move.w    d0,d2
          subq.w    #1,d2               position finale X effacement
          sub.w     VE102+2-BA(a5),d0   X début effacement
          bra.s     BE310
*
*    La case va vers la gauche: on efface sa droite
*
BE305     move.w    (a2),d2             X case
          add.w     VD101-BA(a5),d2     largeur du bloc
          move.w    d2,d0               X début effacement
          sub.w     VE102+2-BA(a5),d2   X fin effacement
          subq.w    #1,d2
BE310     move.w    2(a2),d1            Y case
          move.w    d1,d3
          add.w     VD102-BA(a5),d3     Hauteur du bloc
          subq.w    #1,d3               Y final effacement
          bra.s     BE330               vers effacement
*
*    Mouvements verticaux de la case
*
BE315     move.w    VE102+4-BA(a5),d0   dY
          bmi.s     BE320               B si trou vers le bas
*
*    La case va vers le bas: on efface le dessus
*
          move.w    2(a2),d1                 Y case
          move.w    d1,d3
          subq.w    #1,d3                    Y final effacement
          sub.w     d0,d1                    Y debut effacement
          bra.s     BE325
*
*    La case va vers le haut: on efface le bas
*
BE320     move.w    2(a2),d3                 Y case
          add.w     VD102-BA(a5),d3          hauteur bloc
          move.w    d3,d1                    Y debut effacement
          sub.w     d0,d3                    dY
          subq.w    #1,d3
BE325     move.w    (a2),d0                  X case
          move.w    d0,d2
          add.w     VD101-BA(a5),d2          largeur du bloc
          subq.w    #1,d2                    X final effacement
*
*    Commande d'effacement du bord de la case
*
BE330     move.l    AD102-BA(a5),a1          notre écran
          lea       sc_RastPort(a1),a1       notre RastPort
          jsr       _LVORectFill(a6)         effacement
*
*    Test si c'est le dernier mouvement de la case
*
          subq.w    #1,VE103-BA(a5)     Compteur de mouvements
          bne.s     BE345               B si mouvement en cours
*
*    Mouvement terminé: le trou a pris la position de la case
*
          move.l    AD004(a4),a0        adr table des blocs
          move.w    VD105-BA(a5),d0     position du trou
          asl.w     #3,d0
          add.w     d0,a0                    adresse coordonnees du trou
          move.w    VE102-BA(a5),VD105-BA(a5) Case en mouvement  -> trou
          move.l    (a0),d0                  permut. coordonnees case/trou
          move.l    (a2),(a0)+
          move.l    d0,(a2)+
          move.l    (a0),d0
          move.l    (a2),(a0)
          move.l    d0,(a2)
          lea       BE200(pc),a0          Pour nouveau déplacement
          move.l    a0,AD103-BA(a5)       Aiguillage
*
*    Rafraichissement du reste de l'affichage
*
BE345     moveq     #09,d3              Par 10 cases
BE350     move.w    VD106-BA(a5),d2     case à rafraichir
          bsr.s     BG100               réaffichage
          subq.w    #1,VD106-BA(a5)
          bpl.s     BE355
          move.w    #79,VD106-BA(a5)    reinit compteur
BE355     dbra      d3,BE350
          rts
*
*
*    Stop de l'action: libération des ressources
*    -------------------------------------------
*
BF100     move.l    AD100-BA(a5),a4     adr de la MemList
          tst.b     LD101-BA(a5)        Flag système complet
          beq.s     BF165               B si pas complet
*
*    Retrait du Bob et unlink structures d'animation
*
          move.l    AD007(a4),a0        adresse du Bob
          ori.w     #BF_BOBSAWAY,bob_BobFlags(a0) RemBob
          bsr       BG300               mise à jour Bob
          move.l    AD102-BA(a5),a0     adresse du screen
          lea       sc_RastPort(a0),a0
          clr.l     rp_GelsInfo(a0)     unlink 
*
*
BF165     move.l    BaseIntui-BA(a5),a6
          move.l    AD102-BA(a5),d0     Adresse du Screen
          beq.s     BF170               B si pas de Screen
          move.l    d0,a0
          jsr       _LVOScreenToBack(a6)
          move.l    AD102-BA(a5),a0
          jsr       _LVOCloseScreen(a6)
          clr.l     AD102-BA(a5)
*
BF170     move.l    AbsExecBase,a6
          move.l    AD100-BA(a5),d0     adr MemList
          beq.s     BF175               B si pas allouée
          move.l    d0,a0
          jsr       _LVOFreeEntry(a6)
          clr.l     AD100-BA(a5)
*
BF175     move.l    BaseIntui-BA(a5),d0
          beq.s     BF180               B si pas Open
          move.l    d0,a1
          jsr       _LVOCloseLibrary(a6)
          clr.l     BaseIntui-BA(a5)
BF180     rts
*
*
*         Routines d'intéret général
*         --------------------------
*
*    Affichage d'un bloc: d2 = numéro du bloc
*
BG100     movem.l   d2-d7,-(sp)
          move.l    AD004(a4),a0        adr table des blocs
          cmp.w     VD105-BA(a5),d2     numéro du bloc
          beq.s     BG105               On n'affiche pas le trou
          asl.w     #3,d2               mul 8
          add.w     d2,a0               adresse du bloc concerné
          moveq     #0,d0
          moveq     #0,d1
          moveq     #0,d2
          moveq     #0,d3
          moveq     #0,d4
          moveq     #0,d5
          move.w    (a0)+,d2            X destination
          move.w    (a0)+,d3            Y destination
          move.w    (a0)+,d0            X source
          move.w    (a0),d1             Y source
          move.w    VD101-BA(a5),d4     largeur du bloc
          move.w    VD102-BA(a5),d5     hauteur du bloc
          move.l    #$c0,d6             MinTerm = Copy
          moveq     #-1,d7              All planes
          move.l    AD102-BA(a5),a1     notre écran
          lea       sc_BitMap(a1),a1    notre BitMap
          move.l    AD101-BA(a5),a0     screen du modèle
          lea       sc_BitMap(a0),a0    BitMap du modèle
          move.l    BaseGfx-BA(a5),a6
          jsr       _LVOBltBitMap(a6)
BG105     movem.l   (sp)+,d2-d7
          rts
*
*
*    Routine de copie de la case source dans l'image du Bob
*    ------------------------------------------------------
*
*    Entrée: a2 = adresse du descripteur de la case dans la table
*
*    Registres:     d5   adr relative début image dans un plane
*                   d4   valeur a ajouter apres chaque ligne copiée
*                   d3   nombre de words à copier par ligne
*                   d2   index planes
*                   d1   index lignes
*                   d0   index words dans une ligne
*                   a3   pointeur adresse dans le plane
*                   a1   pointeur adresse dans l'image du Bob
*
BG200     movem.l   d2-d5/a3,-(sp)
          move.l    AD101-BA(a5),a0     adr struct Screen
          lea       sc_BitMap(a0),a0    adr de la BitMap source
          move.w    6(a2),d5            Y source
          mulu      bm_BytesPerRow(a0),d5
          moveq     #0,d0
          move.w    4(a2),d0            X source en pixels
          lsr.w     #3,d0                        en octets
          add.l     d0,d5               adr début case dans un plane
          moveq     #0,d4
          move.w    VD101-BA(a5),d4     largeur bloc en pixels
          lsr.w     #3,d4                            en octets
          move.w    d4,d3
          lsr.w     #1,d3               largeur bloc en words
          subq.w    #1,d3               largeur bloc pour index
          neg.w     d4
          add.w     bm_BytesPerRow(a0),d4    modulo pour une ligne
          move.w    VD100+ns_Depth-BA(a5),d2 nombre de planes
          subq.w    #1,d2               nombre de planes pour index
*
*    Boucle de copie de l'image du Bob
*
          lea       bm_Planes(a0),a0    Adr table des planes
          move.l    AD005(a4),a1        adr image du Bob
BG205     move.l    (a0)+,a3            adr plane
          add.l     d5,a3               position dans le plane
          move.w    VD102-BA(a5),d1     hauteur case
          subq.w    #1,d1               nombre de lignes pour index
BG210     move.w    d3,d0               index mots par ligne
BG215     move.w    (a3)+,(a1)+         copie
          dbra      d0,BG215
          add.l     d4,a3               passage ligne suivante
          dbra      d1,BG210            ligne suivante
          dbra      d2,BG205            plan suivant
*
          movem.l   (sp)+,d2-d5/a3
          rts
*
*    Routine d'affichage du Bob
*    --------------------------
*
*    Etrange: plante en Gourou Meditation si on appelle SortGList ???
*         (parce-qu'il n'y a qu'un Bob ????)
*
BG300     move.l    AD102-BA(a5),a0     notre screen
          lea       sc_RastPort(a0),a1  son RastPort
          lea       sc_ViewPort(a0),a0  son ViewPort
          move.l    BaseGfx-BA(a5),a6
          jmp       _LVODrawGList(a6)   et retour
*
*    Cette routine fait normalement partie de ma librairie personnelle
*    Je la fait figurer ici pour ne pas devoir donner la librairie
*    plutôt volumineuse !
*
*    Substitution de puts
*    --------------------
*
*    int  RBputs(char *s)
*    D0
*
_RBputs   movem.l   d2-d3/a6,-(sp)
          move.l    _DOSBase,a6
          move.l    _stdout,d1          filehandle
          beq.s     puts2               B si pas de stdout
          move.l    16(sp),d2           adresse chaine
          move.l    d2,a0
          moveq     #-1,d3
puts1     addq.l    #1,d3               calcul longueur chaine
          tst.b     (a0)+
          bne.s     puts1
          jsr       _LVOWrite(a6)
puts2     moveq     #0,d0
          movem.l   (sp)+,d2-d3/a6
          rts
*
*    Données du programme
*
*    Définitions fictives pour la MemList
*
AD001     equ  ML_ME     adr dummy VSprite 1
AD002     equ  ML_ME+8   adr dummy VSprite 2
AD003     equ  ML_ME+16  adr struct GelsInfo
AD004     equ  ML_ME+24  adr table des blocs
AD005     equ  ML_ME+32  adr de l'image du Bob
AD006     equ  ML_ME+40  adr de la struct VSprite de notre Bob
AD007     equ  ML_ME+48  adr de notre struct Bob
AD008     equ  ML_ME+56  adr des 8 mots pour nextLine de GelsInfo
AD009     equ  ML_ME+64  adr des 8 pointeurs pour lastColor de GelsInfo
*
AD100     dc.l 0         Adresse de la MemList allocation mémoire
AD101     dc.l 0         Adresse de l'écran d'origine
AD102     dc.l 0         Adresse de notre propre écran
AD103     dc.l 0         Aiguillage: adresse du traitement en cours
*
*    MemList pour allocation de la mémoire requise
*
          cnop 0,4
CD101     ds.b LN_SIZE
          dc.w 9                        Nb de blocs demandés
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l vs_SIZEOF                Dummy VSprite 1
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l vs_SIZEOF                Dummy VSprite 2
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l gi_SIZEOF                Struct GelsInfo
          dc.l MEMF_PUBLIC
          dc.l 80*8                     Table adresse des blocs
          dc.l MEMF_CHIP
CD101A    dc.l 0                        Taille du Bob (calculée)
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l vs_SIZEOF                notre struct VSprite
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l bob_SIZEOF               notre struct Bob
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l 8*2                      nextLine pour GelsInfo
          dc.l MEMF_PUBLIC!MEMF_CLEAR
          dc.l 8*4                      lastcolor pour GelsInfo
*
LD101     dc.b 0         Flag: -1 si ressources OK pour execution
*
          cnop 0,2
VD100     ds.b ns_SIZEOF La structure NewScreen que nous construisons
VD101     dc.w 0         Largeur d'un bloc en pixels
VD102     dc.w 0         Hauteur d'un bloc en pixels
VD103     dc.w 0         Nombre de mouvements horizontaux par case
VD104     dc.w 0         Nombre de mouvements verticaux par case
VD105     dc.w 0         Numéro de la case du trou
VD106     dc.w 0         Compteur de cases rafraichies
*
*    Définition des mouvements possibles
*
VD110     dc.w 0,0,0     position, dX, dY (Trou vers la gauche)
VD111     dc.w 0,0,0     position, dX, dY (Trou vers la droite)
VD112     dc.w 0,0,0     position, dX, dY (Trou vers le haut)
VD113     dc.w 0,0,0     position, dX, dY (Trou vers le bas)
VE101     dc.w 0         Nombre aléatoire
VE102     dc.w 0,0,0     Case en mouvement, dX, dY
VE103     dc.w 0         Compteur de mouvements de la case
VE104     dc.w 0         Inverse du dernier mouvement
*
BaseIntui dc.l 0         Base Intuition.library
*
IntuiName dc.b 'intuition.library',0
          cnop      0,4
          end
