debug equ 0

; tests :
; - kaos : new game, load, save, quit, perdre (&restart this game), finir le jeu
; - utility : csb hall make new adv, hint rejette csb hall
; - kaos : accepte partie dm1 -> csb


; attention :
; df0: écrit en dur dans "usio"
; voir pourquoi console.device et nil: dans "swsh"
; df0:, trackdisk.device dans "hint", + console.device
; df0:, trackdisk.device dans "fio1"
; trackdisk.device dans "cnfg"
; dans "kaos" : console.device, nil:, df0:, dungeonmaster:, dungeonsave:,
;  disk.resource, trackdisk.device

; arguments : rien charge le jeu, qqch charge l'utility disk


; fichier .ftl :

; header : 20 bytes
; 0	w	6160
; 2	w	header checksum (voir routine u49ee)
; 4	w	0002
; 6	b	01
; 7	b	00

; 12	w	taille du tableau des hunks (limité à #$64 sinon erreur)
;		en fait il y a systématiquement 0003
; 14	n*12b	tableau hunks, 12 bytes par entrée :
;	0	w	type : 0010, 0011 ou 0012 (l'existence des trois est
;			nécessaire sinon erreur, autres types sont ignorés)
;	2	w	0001
;	4	l	offset dans le fichier
;	8	l	taille
;			(ça + 3*12 bytes + hdr= $14 -> taille totale du fichier)

; hunk type 0010 (= table de jumps)
; 0	l	taille bss + table jmp
; 4	l	taille datas (après traitement), lus depuis hunk 11 / zone 1
; 8	l	taille de la table de jumps (2* taille données lues hunk 10)
; c	l	taille bss
; 10	l	(recopié directement dans struct à remplir)
; 14	l 	taille (répétée ici) du hunk 12 (= code)
; 18	l	taille du hunk 11
; 1c	w	(ignoré)
; 1e	w	flag (???)
; 22	w	checksum hunk, contenu + ce header (sans cette valeur elle-même)
; 24	w	checksum hunk 12 (code)
; 26	w	checksum hunk 11 (données brutes)
; taille header : 40 bytes ($28)
; suite = série de .l = offset des jmp (table reloc32), jmp = deb code + offset


; hunk type 0011
; 0	w	(inutilisé ?) - la valeur constatée est 0001
; 2	l	taille zone 1
; 6	l	taille zone 2
; zone 1
;	w	si <>0, .w écrit directement
;		si = 0, .w supplémentaire (doit être pair !) qui indique le
;		nombre d'octets à 0 qu'il faut écrire (+2 car le mot =0 est
;		écrit aussi)
; zone 2
;	w	reloc16 à faire dans zone de datas, l'offset (normalement, il
;		doit être négatif) s'entend à partir de la fin de la zone
;		(qui correspond au début du bss)

; hunk type 0012 (= code)

; description de struct .ftl devant routine 41e4
; struct ftl library :
; 0	l	pointeur sur lib suivante
; 4	l	pointeur sur lib précédente
; 8	l	nom (4car.)
; c	$1c.b	struct (ftl exe)
; 28	l	api adr
; 2c	w	bit 0 : lib éjectable
; 2e	w	version
; 30	w	open count

; struct ftl exe :
; 0	l	adr bss
; 4	l
; 8	l
; c	l	adr table jmp (8 bytes/jmp)
; 10	l	vient directement de (header40bytes + $10)
; 14	l
; 18	l	adr zone de mémoire qui reçoit le .ftl

; deb
 ifne debug
 lea patch,a1
 endc
 move.b (a0),d0
 cmpi.b #10,d0
 sne flag		; 00 csb ff utility
 lea dos(pc),a1
 moveq #37,d0
 move.l 4.w,a6
 jsr -$228(a6)
 move.l d0,dosb
 bne.s .ok
 moveq #-1,d0
 rts
.ok
 bsr main
 move.l dosb,a1
 move.l 4.w,a6
 jsr -$19e(a6)
 moveq #0,d0
 rts


; BJELoad
; ce programme lance le "APPA.FTL" et fournit un certain nombre d'api.
; il gère le format particulier des exécutables .FTL
; (attention : checksums sur tout le fichier)

; fonction main (ne prend pas de paramètres)
main
 link a5,#-$1e
 jsr u4880		; init variables et close wb
 clr.l -(a7)
 pea -$1e(a5)
 pea $41505041		; exec "APPA"
 jsr u4ee6		; = 4162
 lea $c(a7),a7
 move.w d0,-2(a5)	; return code
 jsr u4970
 unlk a5
 rts

; (*buf, base_functs, n°funct, l1, l2=nouvelle routine)
; patch d'une fonction, renvoie ancienne adr routine
; buffer rempli :
; 0	w	43f9	lea xx,a1
; 2	l	*l1
; 6	w	4ef9	jmp xx
; 8	l	l2 (adr nouvelle routine)
; c	l	4afc4e73 (illegal/rte), id
; 10	l	ancienne adr (celle renvoyée dans d0)
; 14	l	adr structure de l'ancien patch (ou 0 si 1er)
; 18	l	adr fonction (adr du .l modifié par le patch)
u3eca link a5,#0
 movem.l d4/a2-a3,-(a7)
 movea.l 8(a5),a2
 move.l $10(a5),d0	; n° fonction
 asl.l #2,d0		; *4
 move.l $c(a5),d4	; base fonctions
 sub.l d0,d4
 movea.l d4,a0
 movea.l (a0),a3	; -> adr fonction
 move.w #$43f9,(a2)
 movea.l $14(a5),a0
 move.l (a0),2(a2)
 move.w #$4ef9,6(a2)
 move.l $18(a5),8(a2)
 move.l #$4afc4e73,$c(a2)
 move.l d4,$18(a2)
 move.l a3,-(a7)
 jsr u49bc(pc)		; la routine est-elle déjà un patch ?
 addq.w #4,a7
 tst.w d0
 beq.s u3f20
 move.l a2,$14(a3)
u3f20 move.l a3,$10(a2)
 clr.l $14(a2)
 movea.l d4,a0
 move.l a2,(a0)		; nouvelle adr
 move.l a3,d0		; ancienne adr
 movem.l (a7)+,d4/a2-a3
 unlk a5
 rts

; remove patch (adr)
u3f3c link a5,#0
 move.l a2,-(a7)
 movea.l 8(a5),a2
 tst.l $14(a2)
 bne.s u3f5c
 movea.l $18(a2),a0
 move.l $10(a2),(a0)
 bra.s u3f66
u3f5c movea.l $14(a2),a0
 move.l $10(a2),$10(a0)
u3f66 move.l $10(a2),-(a7)
 jsr u49bc(pc)
 addq.w #4,a7
 tst.w d0
 beq.s u3f84
 movea.l $10(a2),a0
 move.l $14(a2),$14(a0)
u3f84 movea.l $18(a2),a0
 move.l (a0),d0
 movea.l (a7)+,a2
 unlk a5
 rts


; open file (name_4car.l, *id)
; (ouvre fichier xxxx.ftl)

; routine patchée
; 16 caractères de + -> link #-$1c au lieu de #$c
u3f90 link a5,#-$1c
 movem.l a0-a1,-(a7)
 move.l 8(a5),-$c(a5)
 move.l #$2e46544c,-8(a5)	; ".FTL"
 clr.l -4(a5)
 bsr getdrw		; dans bje.i, ajoute le rep (csb ou utility)
 move.l $c(a5),-(a7)	; reçoit file id
; pea -$c(a5)		; file name
 move.l a0,-(a7)	; -> new file name (drw/file.ftl)
 jsr u4da6		; = 4b2a
 addq.w #8,a7
 tst.b d0
 beq.s u3fd2
 moveq #1,d0
u3fc8
 movem.l (a7)+,a0-a1
 unlk a5
 rts
u3fd2 moveq #0,d0
 bra.s u3fc8

; open ftl library ("file", version)
u3fd6 link a5,#-$20
 movem.l d4-d6/a2-a3,-(a7)
 clr.l -4(a5)
 move.l 8(a5),-(a7)	; "file"
 pea v96be		; liste
 jsr u4e96		; recherche
 addq.w #8,a7
 movea.l d0,a2
 move.l a2,d0
 beq.s u4008
 addq.w #1,$30(a2)	; ajouter 1 à open cnt
 bra u40bc
u4008 moveq #0,d6
 pea -4(a5)		; -> file id
 move.l 8(a5),-(a7)
 jsr u4ef6		; open file
 addq.w #8,a7
 tst.b d0
 bne u40aa		; oups... not found
 pea -$20(a5)		; struct
 move.l -4(a5),-(a7)	; file
 jsr u4e56		; load .ftl
 addq.w #8,a7
 tst.w d0
 bne.s u40aa		; oups...
 move.l -4(a5),-(a7)
 jsr u4db6		; close
 addq.w #4,a7
 clr.l -4(a5)		; indiquer fichier fermé
 moveq #1,d6
 clr.l -(a7)		; param
 pea -$20(a5)		; struct
 jsr u4e46		; = 4cd4 (launch .ftl)
 addq.w #8,a7
 movea.l d0,a2
 tst.l d0
 beq.s u40aa
 move.w $2e(a2),d0	; version nbr
 cmp.w $e(a5),d0
 blt.s u40aa
 lea -$20(a5),a0	; struct
 movea.l a0,a3
 move.l a2,d4		; lib base
 add.l #$c,d4
 moveq #0,d5
u4074 movea.l a3,a0
 addq.l #1,a3
 movea.l d4,a1
 addq.l #1,d4
 move.b (a0),(a1)	; copy struct (0-1b) to lib base (c to 27)
 addq.w #1,d5
 cmp.w #$1c,d5
 bcs.s u4074
 move.l v96ca,$28(a2)	; api
 move.w #1,$30(a2)
 clr.w $2c(a2)
 move.l a2,-(a7)	; struct ftl lib
 pea v96be		; deb liste
 jsr u4e66		; = 4804 (add to list)
 addq.w #8,a7
 bra.s u40bc
u40aa tst.w d6
 beq.s u40ba
 pea -$20(a5)
 jsr u4e36		; = 4766 (free ftl file)
 addq.w #4,a7
u40ba suba.l a2,a2
u40bc tst.l -4(a5)
 beq.s u40d4
 move.l -4(a5),-(a7)
 jsr u4db6
 addq.w #4,a7		; = 4b62 (close)
u40d4 move.l a2,d0
 movem.l (a7)+,d4-d6/a2-a3
 unlk a5
 rts

; close library
u40de link a5,#0
 move.l a2,-(a7)
 move.l 8(a5),-(a7)	; lib name
 pea v96be
 jsr u4e96		; recherche base lib
 addq.w #8,a7
 movea.l d0,a2
 move.l a2,d0		; si pas trouvé, exit
 beq.s u413e
 subq.w #1,$30(a2)	; open cnt -1
 tst.w $30(a2)
 bne.s u413e
 btst #0,$2d(a2)	; lib éjectable ?
 beq.s u413e
 move.w #3,-(a7)
 move.l a2,-(a7)
 jsr u4d4c		; appel fonction #3 (lib_eject)
 addq.w #6,a7
 move.l a2,-(a7)
 jsr u4e76		; remove lib from list
 addq.w #4,a7
 pea $c(a2)
 jsr u4e36		; = 4766 (free ftl file)
 addq.w #4,a7
u413e movea.l (a7)+,a2
 unlk a5
 rts

; rend une lib ftl éjectable au dernier closelib, param (adr_lib)
u4144 link a5,#0
 movea.l 8(a5),a0
 bset #0,$2d(a0)
 unlk a5
 rts

; load & exec ftl file ("file", *struct, param)
u4162 link a5,#-4
 movem.l d4-d5/a2,-(a7)
 movea.l $c(a5),a2	; buf
 moveq #0,d5
 clr.l -4(a5)
 pea -4(a5)		; reçoit file id
 move.l 8(a5),-(a7)	; file name (4 car.)
 jsr u4ef6		; = 3f90, open file
 addq.w #8,a7
 tst.b d0
 beq.s u4192
 moveq #$1d,d4		; erreur : file not found
 bra.s u41b4
u4192 move.l a2,-(a7)	; struct
 move.l -4(a5),-(a7)	; file
 jsr u4e56		; = 41e4 (load .ftl)
 addq.w #8,a7
 move.w d0,d4		; erreur si <>0
 bne.s u41b4
 moveq #1,d5
 move.l $10(a5),-(a7)	; param (pour "APPA" : 0)
 move.l a2,-(a7)	; struct
 jsr u4e46		; = 4cd4 (lance .ftl)
 addq.w #8,a7
u41b4 tst.w d5		; si erreur, ftl file déjà éjecté par 41e4
 beq.s u41c2
 move.l a2,-(a7)	; free mem (ftl file)
 jsr u4e36		; = 4766
 addq.w #4,a7
u41c2 tst.l -4(a5)	; fichier ouvert ?
 beq.s u41da
 move.l -4(a5),-(a7)	; close file
 jsr u4db6		; = 4b62 (close)
 addq.w #4,a7
u41da move.w d4,d0	; renvoyer le code d'erreur (0 si ok)
 movem.l (a7)+,d4-d5/a2
 unlk a5
 rts

; routine de chargement d'un .ftl, remplit aussi la structure passée en param
; renvoie 0 si ok, sinon code d'erreur
; params : file_id, *struct

; variables locales :
; -$62	$28 .b	header morcif $10 (les 40 bytes)
; -$3a	$14 .b	header global
; -$26	l	taille de la table reloc32 -> compteur de boucle
; -$22	l	taille relocs data (données brutes) -> "
; -$1e	l	taille datas (id)
; -$1a	l	adr de chargement des 3 hunks, données brutes
; -$16	l	adr buf temporaire (si alloué)
; -$12	l	adr code (hunk $12)
; -$e	l	adr bss
; -$a	l	adr datas (adr deb, correspond à buffer+$18)
; -6	w	n° du hunk $12 (*12 pour offset)
; -4	w	n° du hunk $10
; -2	w	n° du hunk $11

; buffer (structure) passé en paramètre = struct ftl exe (à remplir ici)

; les adresses de buffers à allouer sont à 0 si le buffer n'est pas alloué
; -> sert à tester si un freemem doit être fait en sortant

; la zone du .ftl reçoit, dans l'ordre :
; - la data (décodée + relocs)
; - le bss
; - la table de jmp : (8 bytes / reloc)
;	0	w	(non initialisé)
;	2	w	4ef9 (jmp)
;	4	w	<adr>	base du calcul : début du code (pris en -$12)
; - le code (non modifié, sauf relocs)

u41e4 link a5,#-$62
 movem.l d4-d7/a2-a3,-(a7)
 suba.l a3,a3			; recevra les 3*12 bytes
 movea.l $c(a5),a0		; structure à remplir
 clr.l $18(a0)			; zone qui recevra le fichier
 clr.l -$16(a5)			; zone temporaire
 pea -$3a(a5)			; tableau local
 pea $14.w			; taille : 20 bytes
 move.l 8(a5),-(a7)		; file
 jsr u4dd6			; = 4bac (read)
 lea $c(a7),a7
 tst.b d0
 beq.s u4222
 move.w #$200,d5
 bra u4710
u4222 cmpi.w #$6160,-$3a(a5)	; marque du .ftl
 bne.s u4240
 cmpi.w #2,-$36(a5)		; offs 4
 bne.s u4240
 cmpi.b #1,-$34(a5)		; offs 6
 bne.s u4240
 tst.b -$33(a5)			; offs 7
 beq.s u4246
u4240 moveq #1,d5		; erreur : format de fichier
 bra u4710
u4246 cmpi.w #$64,-$28(a5)	; offs $12 (en fait ça vaut systématiquement 3)
 bls.s u4254
 moveq #$1a,d5			; erreur : overflow
 bra u4710
u4254 move.w -$28(a5),d0	; offs $12 (-> 3)
 mulu #$c,d0
 moveq #0,d1
 move.w d0,d1
 move.l d1,d6
 move.l d6,-(a7)		; allocmem (d6 = 12 bytes * [offs12 = 3])
 jsr u4d86			; = 4aae
 addq.w #4,a7
 movea.l d0,a3
 tst.l d0
 bne.s u427a
 move.w #$201,d5		; oups : out of mem
 bra u4710
u427a move.l a3,-(a7)		; read 3*12 bytes -> a3
 move.l d6,-(a7)
 move.l 8(a5),-(a7)
 jsr u4dd6			; = 4bac (read file,size,adr)
 lea $c(a7),a7
 tst.b d0
 beq.s u4298
 move.w #$202,d5		; read error
 bra u4710
u4298 move.l a3,-(a7)		; tableau 12 bytes
 pea -$3a(a5)			; entête
 jsr u49ee(pc)			; calc chksum
 addq.w #8,a7
 cmp.w -$38(a5),d0		; offs 2
 beq.s u42b0
 moveq #$e,d5			; header checksum error
 bra u4710
u42b0 move.w #$ffff,-4(a5)	; n° qui a le type #$10 (ffff si pas trouvé)
 move.w #$ffff,-2(a5)		; n° qui a le type #$11
 move.w #$ffff,-6(a5)		; n° qui a le type #$12
 moveq #0,d5			; boucle de lecture : d5 = 0,1,2
 bra u437c
u42c8 move.w d5,d0
 mulu #$c,d0
 move.l d0,d1			; offset entrée courante
 moveq #0,d0
 move.w 0(a3,d1.l),d0		; 1er word = type
 bra u4366
u42da move.w d5,d0
 mulu #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 cmpi.w #1,2(a0)		; 2e word = 1
 beq.s u42f2
 moveq #$14,d5			; sinon erreur
 bra u4710
u42f2 cmpi.w #$ffff,-4(a5)
 bne.s u4300
 move.w d5,-4(a5)		; mettre val si pas déjà trouvé
 bra.s u4306
u4300 moveq #$17,d5
 bra u4710
u4306 bra.s u437a
u4308 move.w d5,d0
 mulu #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 cmpi.w #1,2(a0)		; 2e word = 1
 beq.s u4320
 moveq #$15,d5			; sinon erreur
 bra u4710
u4320 cmpi.w #$ffff,-2(a5)	; si pas déjà trouvé
 bne.s u432e
 move.w d5,-2(a5)		; n° entrée de tab
 bra.s u4334
u432e moveq #$18,d5		; si déjà trouvé, erreur
 bra u4710
u4334 bra.s u437a
u4336 move.w d5,d0
 mulu #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 cmpi.w #1,2(a0)		; 2e word = 1
 beq.s u434e
 moveq #$16,d5			; sinon erreur
 bra u4710
u434e cmpi.w #$ffff,-6(a5)	; si pas déjà trouvé
 bne.s u435c
 move.w d5,-6(a5)		; n° d'entrée de tab
 bra.s u4362
u435c moveq #$19,d5		; si déjà trouvé, erreur
 bra u4710
u4362				; bra.s u437a
u4364 bra.s u437a
u4366 sub.l #$10,d0
 beq u42da			; si val=#$10 -> 42da
 subq.l #1,d0			; si val=#$11 -> 4308
 beq.s u4308			; si val=#$12 -> 4336
 subq.l #1,d0
 beq.s u4336
 bra.s u4364			; sinon on passe cette entrée de tableau
u437a addq.w #1,d5
u437c cmp.w -$28(a5),d5		; suivant...
 bcs u42c8
 cmpi.w #$ffff,-4(a5)		; pas trouvé de #$10, erreur
 beq.s u439c
 cmpi.w #$ffff,-2(a5)		; pas trouvé de #$11, erreur
 beq.s u439c
 cmpi.w #$ffff,-6(a5)		; pas trouvé de #$12, erreur
 bne.s u43a2
u439c moveq #2,d5
 bra u4710
u43a2 move.w -4(a5),d0
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 4(a0),-(a7)		; offset
 move.l 8(a5),-(a7)		; file
 jsr u4dc6			; = 4b84 (seek)
 addq.w #8,a7
 tst.b d0
 beq.s u43ca
 move.w #$203,d5		; seek error
 bra u4710
u43ca pea -$62(a5)
 pea $28.w
 move.l 8(a5),-(a7)
 jsr u4dd6			; read (file, taille=#$28, buf -$62)
 lea $c(a7),a7
 tst.b d0
 beq.s u43ec
 move.w #$204,d5		; read error
 bra u4710
u43ec move.l -$5e(a5),d0	; offset 4 (taille datas)
 add.l -$62(a5),d0		; offset 0 (taille bss + table jmp)
 add.l -$4e(a5),d0		; offset $14 (taille du code)
 move.l d0,d6			; -> taille totale zone à allouer pour .ftl
 add.l #$c,d6			; +12
 move.l d6,-(a7)
 jsr u4d86			; -> taille allocmem
 addq.w #4,a7
 movea.l d0,a2
 movea.l $c(a5),a0
 move.l d0,$18(a0)		; buf+$18 = adr de cette zone
 move.l a2,d0
 bne.s u4420
 move.w #$205,d5		; out of mem
 bra u4710
u4420 move.l a2,d0		; adresse de ram
 addq.l #1,d0
 bclr #0,d0			; arrondie .w (elle l'est déjà)
 move.l d0,-$a(a5)
 move.l -$a(a5),d0
 add.l -$5e(a5),d0		; offset 4 (taille datas)
 addq.l #1,d0			; (arrondi : ça doit être l'opérateur cast
 bclr #0,d0			; qui compile ça)
 move.l d0,-$e(a5)		; -> adr bss
 move.l -$e(a5),d0
 add.l -$62(a5),d0		; offset 0 (taille bss + table jmp)
 addq.l #1,d0
 bclr #0,d0
 move.l d0,-$12(a5)		; -> adr code
 move.w -4(a5),d0		; n° morcif type 10
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> taille
 move.w -2(a5),d0		; n°morcif type 11
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d0		; -> taille
 cmp.l d6,d0			; branche si d0<=d6
 bls.s u4484
 move.w -2(a5),d0
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> maximum des deux
u4484 move.w -6(a5),d0		; et id avec morcif type 12
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d0
 cmp.l d6,d0
 bls.s u44a8
 move.w -6(a5),d0
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> d6 = taille maxi des trois
; si le code est le plus gros morceau et le flag est off, on utilise la zone
; où on mettra le code comme buffer temporaire (économie de ram)
; (le code étant lu en dernier)
u44a8 tst.w -$44(a5)		; offset 1e
 bne.s u44b4
 cmp.l -$4e(a5),d6		; offset 14 (taille du code)
 bls.s u44e0			; branche si d6 <= taillecode
u44b4 move.l d6,d0		; taille buffer tmp = max de ce qu'on y mettra
 addq.l #1,d0
 move.l d0,-(a7)
 jsr u4d86			; allocmem
 addq.w #4,a7
 move.l d0,-$16(a5)		; -> adr buf tmp
 bne.s u44d0
 move.w #$206,d5		; out of mem
 bra u4710
u44d0 move.l -$16(a5),d0
 addq.l #1,d0
 bclr #0,d0
 move.l d0,-$1a(a5)		; charger les données dans ce buffer
 bra.s u44e6
u44e0 move.l -$12(a5),-$1a(a5)	; sinon les charger là où on mettra le code
u44e6 movea.l -$1a(a5),a2
 move.l -$e(a5),d4		; adr bss (offset c = taille bss)
 add.l -$56(a5),d4		; + (offset c) -> d4 (adr où placer table jmp)
 move.w -4(a5),d0		; hunk type 10
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> taille table reloc32
 sub.l #$28,d6			; - les 40 bytes déjà chargées (= entête)
 move.l a2,-(a7)		; adr
 move.l d6,-(a7)		; taille
 move.l 8(a5),-(a7)		; file
 jsr u4dd6			; = 4bac (read)
 lea $c(a7),a7
 tst.b d0
 beq.s u4526
 move.w #$207,d5		; read error
 bra u4710
u4526 move.l d6,-(a7)		; taille (du tableau reloc32)
 move.l a2,-(a7)		; adr
 jsr u4a4e(pc)			; checksum zone
 addq.w #8,a7
 move.w d0,d7
 pea $28.w
 pea -$62(a5)
 jsr u4a4e(pc)			; + checksum des 40 1eres bytes
 addq.w #8,a7
 add.w d0,d7
 move.w d7,d0
 sub.w -$40(a5),d0		; enlever la valeur du checksum dans le calcul
 cmp.w -$40(a5),d0		; et comparer
 beq.s u4554
 moveq #$f,d5			; hunk checksum error
 bra u4710
u4554 move.l d6,-$26(a5)	; taille (sans les 40 bytes)
 bra.s u4576
u455a movea.l d4,a0		; remplir table jmp : 0.w, jmp <ea> (8 bytes)
 move.w #$4ef9,2(a0)		; jmp <adr>
 move.w #$7100,(a0)		; ajout au prog initial, pour lisibilité code
; movea.l d4,a0
 move.l -$12(a5),d0		; adr du code
 add.l (a2),d0			; offset indiqué (dest jmp)
 move.l d0,4(a0)
 addq.l #8,d4
 addq.l #4,a2
 subq.l #4,-$26(a5)
u4576 tst.l -$26(a5)
 bgt.s u455a
 movea.l -$1a(a5),a2		; adresse de chargement données brutes
 move.l -$a(a5),d4		; adr datas
 move.w -2(a5),d0		; hunk 11
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> taille (offs 8 tab12), données brutes
 move.w -2(a5),d0		; hunk 11
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 4(a0),-(a7)		; -> offset (pris à l'offset 4 du tab12)
 move.l 8(a5),-(a7)		; file
 jsr u4dc6			; = 4b84 (seek)
 addq.w #8,a7
 tst.b d0
 beq.s u45bc
 move.w #$208,d5		; seek error
 bra u4710
u45bc move.l a2,-(a7)		; adr
 move.l d6,-(a7)		; taille
 move.l 8(a5),-(a7)		; file
 jsr u4dd6			; = 4bac (read)
 lea $c(a7),a7
 tst.b d0
 beq.s u45da
 move.w #$209,d5		; read error
 bra u4710
u45da move.l d6,-(a7)		; taille (données brutes)
 move.l a2,-(a7)		; adr
 jsr u4a78(pc)			; -> checksum
 addq.w #8,a7
 move.w d0,d7
 cmp.w -$3c(a5),d7
 beq.s u45f2
 moveq #$10,d5			; checksum error
 bra u4710
u45f2 move.l 2(a2),-$1e(a5)	; taille datas
 move.l 6(a2),-$22(a5)		; taille table reloc16 datas
 adda.l #$a,a2			; passer l'entête
u4604 tst.l -$1e(a5)
 bls.s u4634
 move.w (a2),d5			; traitement datas
 movea.l d4,a0
 move.w d5,(a0)			; mot direct
 addq.l #2,a2
 subq.l #2,-$1e(a5)
 addq.l #2,d4
 tst.w d5
 bne.s u4632
 move.w (a2),d5
 addq.l #2,a2
 subq.l #2,-$1e(a5)
 bra.s u462e
u4626 movea.l d4,a0		; octets nuls
 clr.b (a0)
 addq.l #1,d4
 subq.w #1,d5
u462e tst.w d5
 bhi.s u4626
u4632 bra.s u4604
u4634 tst.l -$22(a5)		; relocations...
 bls.s u4650
 move.w (a2),d0			; offset (négatif)
 movea.l -$e(a5),a0
 adda.w d0,a0			; par rapport au début du bss (= fin data)
 move.l -$e(a5),d0
 add.l d0,(a0)			; -> ajouter adr (offset // fin_data=deb_bss)
 addq.l #2,a2
 subq.l #2,-$22(a5)		; suivant...
 bra.s u4634
u4650 tst.w -$44(a5)		; offset 1e = flag
 beq.s u465c
 movea.l -$1a(a5),a2		; -> charger dans buf tmp alloué
 bra.s u4660
u465c movea.l -$12(a5),a2	; adr où mettre le code (lu direct dedans)
u4660 move.w -6(a5),d0		; hunk $12 (code)
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 8(a0),d6		; -> taille
 move.w -6(a5),d0
 muls #$c,d0
 movea.l d0,a0
 adda.l a3,a0
 move.l 4(a0),-(a7)		; -> offset
 move.l 8(a5),-(a7)		; file
 jsr u4dc6			; = 4b84 (seek)
 addq.w #8,a7
 tst.b d0
 beq.s u4696
 move.w #$210,d5		; seek error
 bra.s u4710
u4696 move.l a2,-(a7)		; adr
 move.l d6,-(a7)		; taille
 move.l 8(a5),-(a7)		; file
 jsr u4dd6			; = 4bac (read)
 lea $c(a7),a7
 tst.b d0
 beq.s u46b2
 move.w #$211,d5		; read error
 bra.s u4710
u46b2 tst.w -$44(a5)		; offset 1e
 beq.s u46d0
; voir appa.ftl : decrunch code
 move.l -$12(a5),-(a7)		; adr dest code
 move.l -$1a(a5),-(a7)		; adr code lu (buf tmp)
 jsr u4ed6			; = 4860 (decrunch code, routine dans appa.ftl)
; -> sans le patch, ce jsr va sur la routine qui donne "ftl fatal loader error"
; échoue si la marque "5223" est absente au début du code
 addq.w #8,a7
 tst.w d0
 bge.s u46d0
 moveq #$1b,d5
 bra.s u4710
u46d0 move.l -$4e(a5),-(a7)	; offset $14 -> taille du hunk $12 (code)
 move.l -$12(a5),-(a7)
 jsr u4a78(pc)			; -> checksum (.b)
 addq.w #8,a7
 move.w d0,d7
 cmp.w -$3e(a5),d7		; offset $24
 beq.s u46ea
 moveq #$11,d5			; erreur checksum
 bra.s u4710
u46ea movea.l $c(a5),a0		; structure à remplir
 move.l -$e(a5),(a0)		; adr bss
 movea.l $c(a5),a0
 movea.l -$e(a5),a1
 adda.l -$56(a5),a1		; adr table jmp
 addq.l #2,a1			; +2 (1er word inutilisé, pour alignement *8)
 move.l a1,$c(a0)		; -> adr 1er jmp
 movea.l $c(a5),a0
 move.l -$52(a5),$10(a0)	; recopie directe...
; code ajouté pour patches
 move.l (a0),-(a7)		; adr - sera (a5) dans le prog
 move.l 8(a5),-(a7)		; file
 bsr getfname			; (routine de bje.i)
 move.l d0,(a7)			; -> file name
 bsr patch			; (routine de bje.i)
 addq.l #8,a7
;
 moveq #0,d5			; pas d'erreur
; on arrive ici en cas d'erreur (code dans d5)
u4710 move.l a3,d0		; si a3=0, buffer non alloué
 beq.s u471e
 move.l a3,-(a7)		; sinon, le libérer (contient les 3*12 bytes)
 jsr u4d96			; = 4af2 (free mem)
 addq.w #4,a7
u471e tst.l -$16(a5)		; si on a alloué un buffer temporaire,
 beq.s u4730
 move.l -$16(a5),-(a7)		; le libérer.
 jsr u4d96			; = 4af2 (free mem)
 addq.w #4,a7
u4730 tst.w d5			; si erreur,
 beq.s u475c
 movea.l $c(a5),a0
 tst.l $18(a0)			; et si zone du .ftl allouée,
 beq.s u475c
 movea.l $c(a5),a0		; la libérer aussi.
 move.l $18(a0),-(a7)
 jsr u4d96			; = 4af2 (free mem)
 addq.w #4,a7
 movea.l $c(a5),a0
 clr.l $18(a0)			; indiquer zone non allouée
u475c move.w d5,d0		; return code
 movem.l (a7)+,d4-d7/a2-a3
 unlk a5
 rts

; free (ftl file), libère ram
u4766 link a5,#0
 move.l a2,-(a7)
 movea.l 8(a5),a2
 tst.l $18(a2)		; mem déjà libérée
 beq.s u4792
 move.l $18(a2),-(a7)	; adr de chargement
 jsr u4d96		; = 4af2 (freeentry)
 addq.w #4,a7
 clr.l $18(a2)		; indiquer mem libre
u4792 movea.l (a7)+,a2
 unlk a5
 rts

; initialise tête de liste pour liste vide
u4798 link a5,#0
 move.l a2,-(a7)
 movea.l 8(a5),a2
 movea.l a2,a0
 addq.l #4,a0
 move.l a0,(a2)		; (a2) pointe sur 4(a2)
 clr.l 4(a2)		; 4(a2) = 0
 move.l a2,8(a2)	; 8(a2) pointe sur (a2)
 movea.l (a7)+,a2
 unlk a5
 rts

; recherche dans liste (liste, "nom") -> d0=adr (node) ou 0 si pas trouvé
u47c2 link a5,#0
 movem.l d4/a2,-(a7)
 movea.l 8(a5),a2
 move.l $c(a5),d4
 movea.l (a2),a2
u47da tst.l (a2)
 beq.s u4800
 move.l 8(a2),d0
 cmp.l d4,d0
 bne.s u47f6
 move.l a2,d0
u47ee movem.l (a7)+,d4/a2
 unlk a5
 rts
u47f6 movea.l (a2),a2
 bra.s u47da
u4800 moveq #0,d0
 bra.s u47ee

; ajouter élément dans liste (*liste, *élément)
; ajoute l'élément en début de liste
u4804 link a5,#0
 movem.l a2-a3,-(a7)
 movea.l 8(a5),a2	; liste
 movea.l $c(a5),a3	; élément à ajouter
 move.l a2,4(a3)	; elt.pred = list
 move.l (a2),(a3)	; elt.suiv = list.suiv
 move.l a3,(a2)		; list.suiv = elt
 movea.l (a3),a0
 move.l a3,4(a0)	; (elt.suiv).pred = elt
 movem.l (a7)+,a2-a3
 unlk a5
 rts

; enlever l'élément de la liste (*élément)
u4836 link a5,#0
 move.l a2,-(a7)
 movea.l 8(a5),a2	; élément
 movea.l 4(a2),a0
 move.l (a2),(a0)	; (elt.pred).suiv = elt.suiv
 movea.l (a2),a0
 move.l 4(a2),4(a0)	; (elt.suiv).pred = elt.pred
 movea.l (a7)+,a2
 unlk a5
 rts

; erreur : routine non réellement appelée (donne erreur fatal error msg)
; le pointeur sur cette routine est modifié par "appa" qui lui substitue sa
; propre routine.
u4860 link a5,#0
 pea $700.w
 jsr u4e16
 addq.w #4,a7
 unlk a5
 rts

; init
u4880 link a5,#0
 move.l d4,-(a7)
 move.l #$5052494d,v9690	; "PRIM"
 move.l a4,d0			; jsr u4d42
 move.l d0,v9694		; v9694 = $c(a0)
 move.l v96ca,v96b0
 clr.w v96b8
 clr.w v96b4
 move.w #5,v96b6
 clr.l v96ba
 pea v96be			; initialise struct minlist en v96be
 jsr u4e86			; =4798
 addq.w #4,a7
 if 0
 moveq #0,d4
 pea $1f.w
 pea u492a(pc)			; intuition.library
 jsr u593c			; OpenLibrary
 addq.w #8,a7
 move.l d0,v9610		; ibase
 beq.s u491e
u48e8 jsr u598e			; CloseWorkbench
 tst.w d0
 bne.s u490a
 move.w d4,d0			; essayer 12 fois...
 addq.w #1,d4
 cmp.w #$c,d0
 bge.s u490a
 pea $19.w			; ...toutes les demi-secondes
 jsr u582a			; Delay
 addq.w #4,a7
 bra.s u48e8
u490a
 move.l v9610,-(a7)
 jsr u58e6			; CloseLibrary
 addq.w #4,a7
 clr.l v9610
u491e
 endc
 move.l v96ca,d0
 move.l (a7)+,d4
 unlk a5
 rts

u493c link a5,#0
 move.l a2,-(a7)
 movea.l 8(a5),a2
 move.w #3,-(a7)
 move.l a2,-(a7)
 jsr u4d4c
 addq.w #6,a7
 move.l a2,-(a7)
 jsr u4e76		; = 4836
 addq.w #4,a7
 pea $c(a2)
 jsr u4e36		; = 4766
 addq.w #4,a7
 movea.l (a7)+,a2
 unlk a5
 rts

u4970 link a5,#0
 movem.l d4-d5/a2-a3,-(a7)
 lea v96be,a0
 movea.l a0,a2
u4980 movea.l a2,a3
 moveq #0,d5
 move.w d5,d4
u4986 movea.l (a3),a3
 movea.l a2,a0
 addq.l #4,a0
 cmpa.l a0,a3
 beq.s u49a6
 addq.w #1,d4
 tst.w $30(a3)
 bne.s u49a4
 movea.l 4(a3),a3
 move.l (a3),-(a7)
 bsr.s u493c
 addq.w #4,a7
 addq.w #1,d5
u49a4 bra.s u4986
u49a6 tst.w d4
 beq.s u49b2
 tst.w d5
 beq.s u49b2
 cmp.w d4,d5
 blt.s u4980
u49b2 movem.l (a7)+,d4-d5/a2-a3
 unlk a5
 rts

; teste si une routine est un patch (0.w=43f9, 6.w=4ef9, c.l=4afc4e73)
; -> d0=1 si oui, 0 si non
u49bc link a5,#0
 movea.l 8(a5),a0
 cmpi.w #$43f9,(a0)
 bne.s u49e8
 movea.l 8(a5),a0
 cmpi.w #$4ef9,6(a0)
 bne.s u49e8
 movea.l 8(a5),a0
 cmpi.l #$4afc4e73,$c(a0)
 bne.s u49e8
 moveq #1,d0
 bra.s u49ea
u49e8 moveq #0,d0
u49ea unlk a5
 rts

; calcul checksum entête fichier .ftl
u49ee link a5,#0
 movem.l d4-d6/a2,-(a7)
 moveq #0,d5
 movea.l 8(a5),a2		; entête .ftl
 moveq #4,d4
u49fe moveq #0,d0		; offs 4 to 13
 move.w d4,d0			; add bytes(*4à$13) to num (d5)
 moveq #0,d1
 move.b 0(a2,d0.l),d1
 mulu d4,d1
 add.w d1,d5
 addq.w #1,d4
 cmp.w #$14,d4
 bcs.s u49fe
 movea.l $c(a5),a2		; tableau 12 bytes
 movea.l 8(a5),a0		; entête
 move.w $12(a0),d6		; nb d'entrées de tableau
 mulu #$c,d6			; -> taille totale
 moveq #0,d4
 bra.s u4a40
u4a28 moveq #0,d0
 move.w d4,d0
 moveq #0,d1
 move.b 0(a2,d0.l),d1		; byte
 move.w d4,d0
 and.w #$ff,d0
 addq.w #1,d0			; n=(offs and ff)+1
 mulu d0,d1			; byte * n
 add.w d1,d5			; ajouté à num (d5)
 addq.w #1,d4
u4a40 cmp.w d6,d4
 bcs.s u4a28
 move.w d5,d0			; renvoie somme
 movem.l (a7)+,d4-d6/a2
 unlk a5
 rts

; renvoie checksum zone (simple add.w)
u4a4e link a5,#0
 movem.l d4-d5/a2,-(a7)
 movea.l 8(a5),a2		; adr
 move.l $c(a5),d4		; taille
 moveq #0,d5
u4a60 tst.l d4
 ble.s u4a6e
 movea.l a2,a0
 addq.l #2,a2
 add.w (a0),d5
 subq.l #2,d4
 bra.s u4a60
u4a6e move.w d5,d0
 movem.l (a7)+,d4-d5/a2
 unlk a5
 rts

; checksum zone (addition .b -> un .w)
u4a78 link a5,#0
 movem.l d4-d5/a2,-(a7)
 movea.l 8(a5),a2		; adr
 move.l $c(a5),d4		; taille
 moveq #0,d5
u4a8a tst.l d4
 ble.s u4a9c
 movea.l a2,a0
 addq.l #1,a2
 moveq #0,d0
 move.b (a0),d0
 add.w d0,d5
 subq.l #1,d4
 bra.s u4a8a
u4a9c move.w d5,d0
 movem.l (a7)+,d4-d5/a2
 unlk a5
 rts

; cette fonction se comporte exactement comme AllocEntry
; -> allocmem (taille), renvoie adr (stocke taille dans le 1er long) ou 0=err
u4aae link a5,#-4
 clr.l -(a7)		; flags = 0
 move.l 8(a5),d0
 addq.l #4,d0
 move.l d0,-(a7)	; taille +4
 jsr u58f6		; AllocMem
 addq.w #8,a7
 move.l d0,-4(a5)
 bne.s u4ad8
 moveq #0,d0		; erreur si 0
u4ad4 unlk a5
 rts
u4ad8 movea.l -4(a5),a0	; adr mem allouée
 addq.l #4,-4(a5)	; +4 (1er long = taille)
 move.l 8(a5),d0
 addq.l #4,d0
 move.l d0,(a0)		; taille demandée +4 -> taille réelle
 move.l -4(a5),d0	; renvoie adr zone
 bra.s u4ad4

; et voici le FreeEntry (voir fonction précédente)
u4af2 link a5,#-8
 move.l 8(a5),-8(a5)
 tst.l -8(a5)
 beq.s u4b26
 subq.l #4,-8(a5)
 movea.l -8(a5),a0
 move.l (a0),-4(a5)
 move.l -4(a5),-(a7)
 move.l -8(a5),-(a7)
 jsr u591c		; FreeMem
 addq.w #8,a7
u4b26 unlk a5
 rts

; open file ("file",*id), renvoie 0 si ok et remplit file_id
u4b2a link a5,#-4
 pea $3ed.w
 move.l 8(a5),-(a7)
 jsr u584e		; Open
 addq.w #8,a7
 move.l d0,-4(a5)
 bne.s u4b52
 moveq #1,d0
u4b4e unlk a5
 rts
u4b52 movea.l $c(a5),a0
 move.l -4(a5),(a0)
 moveq #0,d0
 bra.s u4b4e

; close (file), ne fait rien si file=0
u4b62 link a5,#0
 tst.l 8(a5)
 beq.s u4b80
 move.l 8(a5),-(a7)
 jsr u57f6		; Close
 addq.w #4,a7
u4b80 unlk a5
 rts

; seek absolu dans fichier (file, offset)
u4b84 link a5,#0
 pea $ffffffff.w	; mode (position absolue positive)
 move.l $c(a5),-(a7)	; offset
 move.l 8(a5),-(a7)	; file
 jsr u587e		; Seek
 lea $c(a7),a7
 moveq #0,d0
 unlk a5
 rts

; lecture dans fichier (file, taille, adr), renvoie d0=0 si ok
u4bac link a5,#0
 move.l $c(a5),-(a7)	; taille
 move.l $10(a5),-(a7)	; adr
 move.l 8(a5),-(a7)	; file
 jsr u586c		; Read
 lea $c(a7),a7
 cmp.l $c(a5),d0
 beq.s u4bde
 moveq #1,d0
u4bd6 unlk a5
 rts
u4bde moveq #0,d0
 bra.s u4bd6

; affichage d'un message sur la console (comme PutStr)
u4be2 link a5,#-4
 jsr u5860		; -> Output
 move.l d0,-4(a5)
 beq.s u4c1c
 move.l 8(a5),-(a7)
 jsr u52f2		; -> strlen (chaine)
 addq.w #4,a7
 ext.l d0
 move.l d0,-(a7)
 move.l 8(a5),-(a7)
 move.l -4(a5),-(a7)
 jsr u58ae		; write (output, chaine, taille)
 lea $c(a7),a7
u4c1c unlk a5
 rts

u4c20 link a5,#-6
 jsr u5842
 move.l d0,-4(a5)
 beq.s u4c5a
 pea 1.w
 move.l -4(a5),-(a7)
 jsr u58a0
 addq.w #8,a7
 move.w d0,-6(a5)
 moveq #0,d0
 move.b -5(a5),d0
u4c52 unlk a5
 rts
u4c5a moveq #0,d0
 bra.s u4c52

u4c5e link a5,#-6
 jsr u5842
 move.l d0,-4(a5)
 beq.s u4c9a
 pea 1.w
 pea -5(a5)
 move.l -4(a5),-(a7)
 jsr u586c
 lea $c(a7),a7
 move.b -5(a5),d0
 ext.w d0
u4c92 unlk a5
 rts
u4c9a moveq #0,d0
 bra.s u4c92

; message d'erreur et stop
u4c9e link a5,#0
 pea u4cbc(pc)			; ftl fatal loader error
 jsr u4de6			; = 4be2
 addq.w #4,a7
u4cb2 bra.s u4cb2		; bra infini
 unlk a5
 rts

; lance programme .ftl (*struct, param)
u4cd4 link a5,#-4
 movea.l 8(a5),a0		; struct
 move.l (a0),-(a7)		; adr bss
 movea.l 8(a5),a0
 move.l $c(a0),-(a7)		; adr table jmp
 move.l v96ca,-(a7)		; adr des api
 move.l $c(a5),-(a7)		; param
 move.l 8(a5),-(a7)		; *struct
 bsr.s u4d0c
 lea $14(a7),a7
 move.l d0,-4(a5)		; return code
 move.l -4(a5),d0
 unlk a5
 rts

; lance l'exe ftl, avec (a5) = bss. Paramètres empilés : (*api, *struct, param)
; -> pour une fois, c'est un link a6 ! Serait-ce de l'asm ?
u4d0c link a6,#0
 movem.l d3-d7/a2-a6,-(a7)
 move.l $c(a6),-(a7)		; param
 move.l 8(a6),-(a7)		; *struct
 move.l $10(a6),-(a7)		; adr api
 movea.l $14(a6),a0		; table jmp (1er = point d'entrée)
 movea.l $18(a6),a5		; bss
 jsr (a0)
 lea $c(a7),a7
 movem.l (a7)+,d3-d7/a2-a6
 unlk a6
 rts

; routine vide
u4d36 link a5,#0
 unlk a5
 rts

; appel fonction (base_lib, n°)
u4d4c link a5,#0
 movem.l d3-d7/a2-a6,-(a7)
 movea.l 8(a5),a0		; base lib
 move.w $c(a5),d0		; fct num
 moveq #-4,d1
 muls d0,d1
 movea.l 0(a0,d1.l),a1		; -> adr fonction
 movea.l $c(a0),a5		; bss
 jsr (a1)
 movem.l (a7)+,d3-d7/a2-a6
 unlk a5
 rts

u4d86 movea.l v96ca,a0		; 4aae	adr = allocmem (taille)
 movea.l -$3c(a0),a1
 move.w #$f,d0
 jmp (a1)
u4d96 movea.l v96ca,a0		; 4af2	freemem (adr)
 movea.l -$40(a0),a1
 move.w #$10,d0
 jmp (a1)
u4da6 movea.l v96ca,a0		; 4b2a	err = open ("file", *id)
 movea.l -$44(a0),a1
 move.w #$11,d0
 jmp (a1)
u4db6 movea.l v96ca,a0		; 4b62	close (file)
 movea.l -$48(a0),a1
 move.w #$12,d0
 jmp (a1)
u4dc6 movea.l v96ca,a0		; 4b84	seek (file, offset)
 movea.l -$4c(a0),a1
 move.w #$13,d0
 jmp (a1)
u4dd6 movea.l v96ca,a0		; 4bac	err = read (file, taille, adr)
 movea.l -$50(a0),a1
 move.w #$14,d0
 jmp (a1)
u4de6 movea.l v96ca,a0		; 4be2	putstr (*chaine)
 movea.l -$58(a0),a1
 move.w #$16,d0
 jmp (a1)
u4e16 movea.l v96ca,a0		; 4c9e	ftl fatal error
 movea.l -$54(a0),a1
 move.w #$15,d0
 jmp (a1)
u4e36 movea.l v96ca,a0		; 4766	free ftl file
 movea.l -$18(a0),a1
 move.w #6,d0
 jmp (a1)
u4e46 movea.l v96ca,a0		; 4cd4 launch.ftl (*struct, param)
 movea.l -$1c(a0),a1
 move.w #7,d0
 jmp (a1)
u4e56 movea.l v96ca,a0		; 41e4	read ftl file
 movea.l -$14(a0),a1
 move.w #5,d0
 jmp (a1)
u4e66 movea.l v96ca,a0		; 4804	addtolist (list, elt)
 movea.l -$2c(a0),a1
 move.w #$b,d0
 jmp (a1)
u4e76 movea.l v96ca,a0		; 4836	remfromlist (elt)
 movea.l -$30(a0),a1
 move.w #$c,d0
 jmp (a1)
u4e86 movea.l v96ca,a0		; 4798	init struct minlist
 movea.l -$34(a0),a1
 move.w #$d,d0
 jmp (a1)
u4e96 movea.l v96ca,a0		; 47c2	cherche élément dans liste
 movea.l -$38(a0),a1
 move.w #$e,d0
 jmp (a1)
u4ed6 movea.l v96ca,a0		; 4860	(patché par "APPA")
 movea.l -$64(a0),a1
 move.w #$19,d0
 jmp (a1)
u4ee6 movea.l v96ca,a0		; 4162	load & exec ftl file
 movea.l -$68(a0),a1
 move.w #$1a,d0
 jmp (a1)
u4ef6 movea.l v96ca,a0		; 3f90	err = open ("xxxx".l + ".ftl", *id)
 movea.l -$6c(a0),a1
 move.w #$1b,d0
 jmp (a1)


; fonctions système appelées :
;u52f2	; strlen (*char)
;u57f6	; Close (file)
;u582a	; Delay (n)
u5842	; Input ()
;u584e	; Open ("file", mode)
;u5860	; Output ()
;u586c	; Read (file, adr, size)
;u587e	; Seek (file, offs, mode)
u58a0	; WaitForChar (file, timeout)
;u58ae	; Write (file, adr, size)
;u58e6	; CloseLibrary (lib)
;u58f6	; AllocMem (taille, flags)
;u591c	; FreeMem (adr, taille)
;u593c	; OpenLibrary ("lib", ver)
;u598e	; CloseWorkbench ()
 illegal	; envoyer erreur si appel fonction non faite

; liste des api :
; adr		num	offs
; u4d36		1d	-$74	(routine vide)
; u3f3c
; u3f90		1b	-$6c	err = open.ftl ("file".l, *id)
; u4162		1a	-$68	err = exec ("file", *struct, param)
; u4860		19	-$64	(routine patchée par APPA)
; u4c5e
; u4c20
; u4be2		16	-$58	PutStr (*texte)
; u4c9e		15	-$54	ftl fatal loader error
; u4bac		14	-$50	err = read (file, taille, adr)
; u4b84		13	-$4c	seek (file, offset)
; u4b62		12	-$48	close (file)
; u4b2a		11	-$44	file = open ("file", *id)
; u4af2		10	-$40	freemem (adr)
; u4aae		f	-$3c	adr = allocmem (taille)
; u47c2		e	-$38	adr = find (list, nom)
; u4798		d	-$34	initstructlist (adr)
; u4836		c	-$30	remfromlist (élément)
; u4804		b	-$2c	addtolist (list, élément)
; u4144		a	-$28	ejectlib (lib), lib éjectée quand opencnt=0
; u40de		9	-$24	close_ftl_lib ("name")
; u3fd6		8	-$20	open_ftl_library ("file", version)
; u4cd4		7	-$1c	launch.ftl (*struct, param)
; u4766		6	-$18	free_ftl_file (*struct)
; u41e4		5	-$14	err = loadftl (file, *struct)
; u3eca		4	-$10	patch (*buf, functs, n°fct, *data_a1, code)

; datas dans code
;u492a dc.b "intuition.library",0
u4cbc dc.b "FTL Fatal Loader Error",10,0

; data, 228 bytes		(-$1d6c)
v9610 ds.l 1
 dc.l u4d36,u3f3c,u3f90,u4162,u4860,u4c5e,u4c20,u4be2,u4c9e,u4bac,u4b84
 dc.l u4b62,u4b2a,u4af2,u4aae,u47c2,u4798,u4836,u4804,u4144,u40de,u3fd6
 dc.l u4cd4,u4766,u41e4,u3eca
; v967c
 ds.l 3
v9688 ds.l 2
v9690 ds.l 1		; "PRIM"
v9694 ds.l 1		; a4
; v9698
 ds.l 6
v96b0 ds.l 1		; v9688
v96b4 ds.w 1		; 0
v96b6 ds.w 1		; 5
v96b8 ds.w 1		; 0
v96ba ds.l 1		; 0
v96be ds.l 3		; struct minlist vide
v96ca dc.l v9688


; allocmem (taille, flags)
u58f6
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d0
 move.l $c(a5),d1
 move.l 4.w,a6
 jsr -$c6(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; freemem (adr, taille)
u591c
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),a1
 move.l $c(a5),d0
 move.l 4.w,a6
 jsr -$d2(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; strlen (*char)
u52f2
 link a5,#0
 move.l a0,-(a7)
 move.l 8(a5),a0
.loop
 tst.b (a0)+
 bne.s .loop
 sub.l 8(a5),a0
 move.l a0,d0
 subq.l #1,d0
 move.l (a7)+,a0
 unlk a5
 rts

; open (file, mode)
u584e
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d1
 move.l $c(a5),d2
 move.l dosb,a6
 jsr -$1e(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; close (file)
u57f6
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d1
 move.l dosb,a6
 jsr -$24(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; read (file, adr, taille)
u586c
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d1
 move.l $c(a5),d2
 move.l $10(a5),d3
 move.l dosb,a6
 jsr -$2a(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; write (file, adr, taille)
u58ae
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d1
 move.l $c(a5),d2
 move.l $10(a5),d3
 move.l dosb,a6
 jsr -$30(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; seek (file, offs, mode)
u587e
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d1
 move.l $c(a5),d2
 move.l $10(a5),d3
 move.l dosb,a6
 jsr -$42(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; output
u5860
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l dosb,a6
 jsr -$3c(a6)
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; get file name from file handler
getfname
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l dosb,a6
 move.l 8(a5),d1	; file handler (FH)
 move.l #fib,d2		; file info block
 jsr -$186(a6)		; ExamineFH
 tst.l d0		; 0 indique un problème
 beq.s .exit
; bne.s .ok
; moveq #0,d0		; fail
; bra.s .exit
;.ok
 move.l fib_name,d0
.exit
 movem.l (a7)+,d1-a6
 unlk a5
 rts

getfsize
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l dosb,a6
 move.l 8(a5),d1	; file handler (FH)
 move.l #fib,d2		; file info block
 jsr -$186(a6)		; ExamineFH
 tst.l d0		; 0 indique un problème
 beq.s .exit
 move.l fib+124,d0	; -> taille fichier
.exit
 movem.l (a7)+,d1-a6
 unlk a5
 rts

; ajoute le drawer (rep1/rep2) au nom du fichier -> (a0)=nom complet
getdrw
 lea rep1(pc),a1
 tst.b flag
 beq.s .csb
 lea rep2(pc),a1
.csb
 move.l a1,d0
.loop0 tst.b (a1)+
 bne.s .loop0
 subq.l #1,a1
 lea -$c(a5),a0
.loop1
 move.b -(a1),-(a0)
 cmp.l a1,d0
 bne.s .loop1
 rts


dos dc.b "dos.library",0	; 12c
rep1 dc.b "DungeonMaster/",0
rep2 dc.b "FTL_CSB_Utility/",0	; attention : taille maxi
rep3 dc.b "DungeonSave/",0
 even
dosb ds.l 1
flag ds.w 1		; 0 pour csb disk, <>0 pour utility disk

 bss
fib			; !: longword align
 ds.b 8
fib_name		; (buffer réutilisé pour stockage file names)
 ds.b 252
; total struct : 260 bytes

 code
; zone nouvelles routines
f10				; test write protect (renvoyer<>0 = writeenable)
f58				; test file exists (renvoyer 1 : ignoré)
fnp				; nop
 moveq #1,d0			; (sert de breakpoint)
 rts
fb				; base
 dc.w $72,fnp-fb,$7a,f4c-fb,$8a,fnp-fb
 dc.w $9a,fnp-fb,$aa,fnp-fb
 dc.w $b2,fnp-fb,$ba,f48-fb,$c2,fnp-fb,$ca,f58-fb
 dc.w $d2,fnp-fb,$da,fnp-fb,$e2,fnp-fb,$ea,f74-fb
 dc.w $f2,f10-fb,$fa,f40-fb,$102,f70-fb,$10a,f54-fb
 dc.w $112,f28-fb,$11a,f6c-fb,$122,f3c-fb,$12a,f50-fb
 dc.w $132,f24-fb,$13a,f38-fb,$142,fnp-fb
 dc.w 0				; fin de liste
f6c				; sizeof (buf)
 move.l #$ea,d0
f70				; invalid (buf), ne rien faire
 rts
f24				; nb lect connectés
 moveq #0,d0
 rts
f74				; initbuf (buf, 0, dev:filename)
 link a6,#0
 movem.l a0-a2,-(a7)
 move.l 8(a6),a0		; buf
 move.w #$52a3,(a0)		; id
 clr.l 4(a0)			; pas de fichier ouvert
 lea 9(a0),a0			; name à offset 9
 move.l 16(a6),a1		; filename
 lea rep2(pc),a2
 cmpi.w #"1:",(a1)
 beq.s .okcpy
 lea rep3(pc),a2
 cmpi.w #"2:",(a1)
 bne.s .cpy
.okcpy
 addq.l #2,a1
.cpy0
 move.b (a2)+,(a0)+		; rep/
 bne.s .cpy0
 subq.l #1,a0
.cpy
 move.b (a1)+,(a0)+		; file
 bne.s .cpy
 movem.l (a7)+,a0-a2
 unlk a6
 rts
f54				; open (buf, num)
 move.l 4(a7),a0
 move.b 9(a7),8(a0)
 pea $3ed.w
 pea 9(a0)
 bsr u584e
 addq.l #8,a7
 move.l d0,4(a0)
 seq d0
 andi.l #4,d0			; file not found = 4
 rts
f50				; open new (buf)
 move.l 4(a7),a0
 pea $3ee.w
 pea 9(a0)
 bsr u584e
 addq.l #8,a7
 move.l d0,4(a0)
 seq d0
 andi.l #8,d0			; write error = 8
 rts
f4c				; close (buf)
 move.l 4(a7),a0
 move.l 4(a0),d0
 beq.s zoups
 move.l d0,-(a7)
 bsr u57f6
 addq.l #4,a7
 clr.l 4(a0)
 moveq #0,d0
 rts
zoups
 moveq #3,d0			; invalid param = 3
 rts
f3c				; err = read (buf, taille, adr)
 move.l 4(a7),a0
 tst.l 4(a0)
 beq.s zoups
 move.l 12(a7),a1
 move.l 8(a7),d0
 move.l d0,-(a7)		; taille
 move.l a1,-(a7)		; adr
 move.l 4(a0),-(a7)		; handle
 bsr u586c
 lea 12(a7),a7
 cmp.l 8(a7),d0
 sne d0
 andi.l #7,d0			; read error = 7
 rts
f38				; err = write (buf, taille, adr)
 move.l 4(a7),a0
 tst.l 4(a0)
 beq zoups
 move.l 12(a7),a1
 move.l 8(a7),d0
 move.l d0,-(a7)		; taille
 move.l a1,-(a7)		; adr
 move.l 4(a0),-(a7)		; handle
 bsr u58ae
 lea 12(a7),a7
 cmp.l 8(a7),d0
 sne d0
 andi.l #8,d0			; write error = 8
 rts
f40				; err = seek (buf, offset)
 move.l 4(a7),a0
 move.l 4(a0),4(a7)
 beq zoups
 bra u4b84			; seek (file, offset)
f28				; test si fichier ouvert
 move.l 4(a7),a0
 tst.l 4(a0)
 seq d0
 rts
f48				; filesize (buf,*size)
 move.l 4(a7),a0
 move.l 8(a7),a1		; dest
 move.l 4(a0),-(a7)		; file handler
 bsr getfsize
 addq.l #4,a7
 move.l d0,(a1)
 seq d0
 andi.l #1,d0
 rts


; patch (file, adr_base)
; effectue les patchs dans l'exe ftl juste chargé, adr_base est (a5) dans le ftl
patch
 link a5,#0
 movem.l d1-a6,-(a7)
 move.l 8(a5),d0	; file
 move.l $c(a5),a0	; base
 cmpi.l #"CNFG",d0
 beq.s .cnfg
 cmpi.l #"VDEO",d0
 beq.s .vdeo
 cmpi.l #"ANIM",d0
 beq.s .anim
 cmpi.l #"USIO",d0
 beq .usio
 cmpi.l #"CEDT",d0
 beq .cedt
 cmpi.l #"FIO1",d0
 beq .fio1
 cmpi.l #"HINT",d0
 beq .hint
 cmpi.l #"APPB",d0
 beq .appb
 cmpi.l #"KAOS",d0
 beq.s .kaos
.exit
 move.l 4.w,a6
 jsr -$27c(a6)		; CacheClearU
 movem.l (a7)+,d1-a6
 unlk a5
 rts

.cnfg
 tst.b flag
 bne.s .cnfg0
 move.w #$6616,$4bc(a0)		; no disk check (game disk)
 bra .exit
.cnfg0
 move.w #$6616,$46e(a0)		; no disk check (utility disk)
 bra .exit

.vdeo
 move.w #$4e75,$1b36(a0)	; no set function
 move.l #$4e714e71,$27f0(a0)	; no wb close
 bra .exit

.anim
 pea .anim0(pc)			; ajouter rep/ à nom fichier (.dat, snd/mus)
 move.l (a7)+,$1d4(a0)
 move.l #$4e714ef9,$160a(a0)	; aga patch (bug de chg. brightness aga/ocs)
 pea .anim1(pc)			; (visible sur titre juste avant kaos)
 move.l (a7)+,$160e(a0)
 bra .exit
.anim0
 movem.l a0-a1,-(a7)		; save regs
 lea fib_name,a1		; dest
 lea rep1(pc),a0		; src1 (rep/)
 tst.b flag
 beq.s .acsb
 lea rep2(pc),a0
.acsb bsr.s .cpystr
 move.l 12(a7),a0		; src2 (file.dat)
 bsr.s .cpystr
 movem.l (a7)+,a0-a1		; recup regs
 pea $3ed.w
 pea fib_name
 jsr u584e			; open
 addq.l #8,a7
 rts
.cpystr
 move.b (a0)+,(a1)+
 bne.s .cpystr
 subq.l #1,a1
 rts
.anim1
 movem.l d0-d3/a0-a3/a6,-(a7)
 move.l -$8e(a5),a6		; graphics
 move.l -$7e(a5),a0
 move.l $108(a0),a0		; screen
 move.l $30(a0),a1
 lea $2c(a0),a0			; a0=vp
 move.l 4(a1),a1		; a1=colors
 moveq #16,d0			; count
 jsr -$c0(a6)			; loadrgb4
 movem.l (a7)+,d0-d3/a0-a3/a6
 movem.l (a7)+,d7/a4		; instructions remplacées
 unlk a6
 rts

.usio
 move.l #$4e714eb9,$652(a0)	; remplacer df0: par le bon répertoire
 pea .usio0(pc)			; (pour appel Lock)
 move.l (a7)+,$656(a0)
 move.l #$4e714e71,$65a(a0)
 bra .exit
.usio0
 move.l (a7)+,d0
 pea -2.w
 tst.b flag
 bne.s .utilit
 pea rep1(pc)
 bra.s .ucsb
.utilit
 pea rep2(pc)
.ucsb
 move.l d0,-(a7)
 jmp $f2(a5)

.cedt
 move.w #$4eb9,$769e(a0)	; l'empêcher de "bouffer" toute la chip mem
 pea .cedt0(pc)			; et doit pouvoir tourner sans fast mem
 move.l (a7)+,$76a0(a0)
 move.w #$607c,$76a4(a0)
 move.w #$4eb9,$7c62(a0)	; accepter parties sauvées dm1 st
 pea .cedt2(pc)
 move.l (a7)+,$7c64(a0)
 move.w #$6014,$7dd8(a0)	; ne pas foirer les portraits dm1 (save to dm1)
 move.w #$210,$7e70(a0)
 move.w #$6014,$7e8a(a0)
 move.w #$210,$7f22(a0)
 adda.l #$8000,a0		; (modifs en c000, e000)
 move.l #$70004e71,$4798(a0)	; ne pas chercher le type de disk
 move.b #$60,$47a4(a0)
 move.w #$4e75,$6082(a0)	; requête "insert save disk" supprimée
 bra .exit
.cedt0
 move.l #$20000,-(a7)		; avail (fast -> any)
 jsr $5da(a5)
 addq.l #4,a7
 bsr.s .cedt1
 move.l d0,-$41e(a5)
 clr.l -(a7)
 move.l d0,-(a7)
 jsr $5d2(a5)
 addq.l #8,a7
 move.l d0,-$416(a5)
 move.l #$20004,-(a7)		; avail (chip)
 jsr $5da(a5)
 addq.l #4,a7
 bsr.s .cedt1
 move.l d0,-$422(a5)
 pea 2.w
 move.l d0,-(a7)
 jsr $5d2(a5)
 addq.l #8,a7
 move.l d0,-$41a(a5)
 rts
.cedt1
 subi.l #$4000,d0		; (le add ffffc000 original)
 cmpi.l #$80000,d0		; maximiser à 512k
 bcs.s .cedt1a
 move.l #$80000,d0
.cedt1a rts

.cedt2 move.w $17c(a0),d0
 cmpi.w #1,d0
 bne.s .cedt3
 moveq #3,d0
 move.w d0,$17c(a0)
.cedt3 move.w d0,-$c(a6)
 rts

.fio1
 move.w #$4e75,$1108(a0)	; pas de test lecteurs à startup
 lea fb(pc),a1			; tab pour changer les 27 fonctions
 move.l a1,d1
 moveq #26,d0
.fio2 move.w (a1)+,a2		; fonction
 add.l a0,a2
 move.w (a1)+,a3		; nouvelle adresse
 lea (a3,d1.l),a3
 move.l a3,2(a2)		; faire la modif
 tst.w (a1)
 bne.s .fio2
 bra .exit

.hint
 move.w #$4eb9,d0		; l'empêcher de "bouffer" toute la ram
 lea .hint0(pc),a1
 move.w d0,$6542(a0)		; max 512k chip
 move.l a1,$6544(a0)
 move.w d0,$65ba(a0)		; max 512k fast
 move.l a1,$65bc(a0)
 clr.w $659c(a0)		; avail fast -> avail any (ne plus planter)
 clr.w $65c6(a0)		; alloc fast -> alloc any (si pas de fast ram)
 move.w #$4eb9,$525a(a0)	; remplacer dev: par rep/
 pea .hint2(pc)
 move.l (a7)+,$525c(a0)
 adda.l #$8000,a0
 move.w #$4e71,$96(a0)		; no test lects.
 bra .exit
.hint0
 cmpi.l #$80000,d0
 bcs.s .hint1
 move.l #$80000,d0
.hint1 rts
.hint2
 move.w #2,-$93c(a5)		; 2 lecteurs virtuels sur les 2 rep
 pea rep2(pc)
 move.l (a7)+,-$93a(a5)		; 1er = utility/
 pea rep3(pc)
 move.l (a7)+,-$936(a5)		; 2e = save/
 rts

.appb
 tst.b flag			; pas de patch pour utility/appb
 bne .exit
 pea .appb0
 move.l (a7)+,$24(a0)		; lang=fnch - virer choix langue
 bra .exit			; (car utility disk n'a pas de choix de langue)
.appb0
 move.l 8(a7),a0
 move.l #"FNCH",4(a0)
 rts

.kaos
 move.l #$4e714e71,d1
 move.w #$4e75,$12d0(a0)	; no set function
 moveq #"/",d0			; remplacer : par /
 move.b d0,-$21(a0)
 move.b d0,-$71(a0)
 move.b d0,-$91(a0)
 move.b d0,-$b1(a0)
 move.l #$4e714eb9,$162e(a0)	; ne pas bouffer toute la chip mem
 pea .kaos1(pc)
 move.l (a7)+,$1632(a0)
 move.w #$4e75,$566a(a0)	; routine vbl-disk
 move.w #$4e75,$6242(a0)	; lecture protection en -$4480
 move.l #$70004e75,$1e5e(a0)	; check master disk
 move.l #$4e714eb9,$64b2(a0)	; aga patch
 pea .kaos2(pc)
 move.l (a7)+,$64b6(a0)
 move.w d1,$64ba(a0)
 move.w #$4e75,$403c(a0)	; protection check 1
 move.w d1,$726e(a0)		; check 2
 move.w d1,$728e(a0)
 move.w #$4e75,$46fa(a0)	; disk
 move.b #$60,$481a(a0)		; system error 60 (suffit pas)
 move.b #$60,$2e82(a0)		; system error 60 (crack inspiré de version ST)
 adda.l #$10000,a0
 move.w #$4ef9,-$4874(a0)	; remplacer df0: par dungeonsave/
 pea .kaos3(pc)
 move.l (a7)+,-$4872(a0)
 move.w #$4e75,$2382(a0)	; disk
 adda.l #$10000,a0
 move.w d1,-$7a4(a0)		; check 3
 move.w #$4e75,-$6aae(a0)	; routine cachée
 move.b #$60,-$77a6(a0)		; check 4
 move.l #$303c4cac,-$41a8(a0)	; code checksum 1 et 2
 move.w #$4e75,-$41a4(a0)
 move.l #$303c5238,-$3652(a0)	; code checksum 3
 move.l #$303c8e88,-$3e2(a0)	; code checksum 4
 move.w #$254,$4224(a0)		; disk check (save)
 move.b #3,$44b3(a0)		; enlever option format du menu
 move.b #3,$44b9(a0)
 move.b #-1,$44cb(a0)
 move.w #$6042,$4576(a0)
 move.w d1,$4614(a0)		; save : ne pas rejeter master disk
 move.l d1,$5316(a0)		; load : id.
 move.l d1,$53da(a0)
 move.b #$60,-$7bd8(a0)		; par sécurité (sys err 60 ?)
 bra .exit
.kaos1
 move.l -$45c0(a5),d0
 subi.l #$4000,d0
 cmpi.l #$80000,d0
 bcs.s .kaos1a
 move.l #$80000,d0
.kaos1a move.l d0,-$45c0(a5)
 rts
.kaos2
 move.l a0,-(a7)
 move.l $36(a0),a0		; $32(a0) +4
 move.l 4(a0),a0
 bsr.s .kaos2a
 move.l (a7)+,a0
 pea $32(a0)
 jsr $cc2(a5)
 addq.l #4,a7
 rts
.kaos2a cmpi.w #$8e,(a0)
 beq.s .kaos2b
 tst.l (a0)+
 bpl.s .kaos2a
 rts
.kaos2b move.b #$2c,2(a0)
 rts
.kaos3
 movem.l a0-a2,-(a7)
 lea fib_name,a2
 lea -$48(a5),a1		; .dat
 bsr.s .kaos3a
 lea -$32(a5),a1		; .bak
 bsr.s .kaos3a
 movem.l (a7)+,a0-a2
 addq.l #6,a7			; instructions remplacées
 move.l (a7)+,d7
 rts
.kaos3a lea rep3(pc),a0
 move.l a2,d7
.kaos3l1 move.b (a0)+,(a2)+	; rep3/
 bne.s .kaos3l1
 subq.l #1,a2
 move.l (a1),a0
 addq.l #4,a0			; passer le "df0:"
.kaos3l2 move.b (a0)+,(a2)+	; csbgame.dat|bak
 bne.s .kaos3l2
 move.l d7,(a1)
 rts
