*************************
*** OPAA-Player V1.00 ***
*************************
** Date: 12.12.93 *******
*************************
* ----------------------------------------------------------------------- *
* - Dieses Programm stellt animierte OPAA-Objekte,
* - die im Assembler-Format von OPAA gespeichert wurden,
* - auf dem Bildschirm dar.
* -
* - Wichtig: Es müssen folgende Dateien vorhanden sein, damit Player
* - die Animation darstellen kann:
* -
* - Datei mit Endung ".ass" -> Objektdaten (im ASS-Format)
* - 	Endung ".ani" -> Animationsdaten
* - 	Endung ".col" -> Farbpalette
* -
* - Wird eine Datei nicht gefunden bricht Player mit der Fehlermeldung:
* - "File not found!" ab.
* ----------------------------------------------------------------------- *

	opt	p+  * positionsunabhängigen Code erzeugen

	include	"OPAA:Assembler/Includes/OPAA-Files.i"

* - Libraries - *
*--  exec  --*
_LVOAddIntServer	EQU	-168 
_LVORemIntServer	EQU	-174 
_LVOAllocMem		EQU	-198 
_LVOFreeMem		EQU	-210 
_LVOOpenLibrary	EQU	-552 
_LVOCloseLibrary	EQU	-414

*--  graphics  --*
_LVOLoadRGB4		EQU	-192 
_LVOWaitBlit		EQU	-228 
_LVOOwnBlitter	EQU	-456 
_LVODisownBlitter	EQU	-462 

* --- dos --- *
_LVOOpen		EQU	-30 
_LVOClose		EQU	-36 
_LVORead		EQU	-42 
_LVOWrite		EQU	-48 
_LVOOutput		EQU	-60 

* --- intuition --- *
_LVOCloseScreen	EQU	-66 
_LVOCloseWindow	EQU	-72 
_LVOOpenScreen	EQU	-198 
_LVOOpenWindow	EQU	-204 
_LVOViewAddress	EQU	-294 


* - Blitter - *
_bltcpt	equ	$48
_bltbpt	equ	$4c
_bltapt	equ	$50
_bltdpt	equ	$54
_bltcmod	equ	$60
_bltbmod	equ	$62
_bltamod	equ	$64
_bltdmod	equ	$66
_bltcdat	equ	$70
_bltbdat	equ	$72
_bltadat	equ	$74
_bltafwm	equ	$44
_bltalwm	equ	$46
_bltcon0	equ	$40
_bltcon1	equ	$42
_bltsize	equ	$58

IS_DATA		equ	$E
IS_CODE		equ	$12
ln_Pri		equ	9
ns_DefaultTitle	equ	$14

_minSpeed	equ	1
_maxSpeed	equ	99

* ---------- *
* - Makros - *
* ---------- *
callsys	macro
	move.l	4.w,a6
	jsr	_LVO\1(a6)
	endm
callint	macro
	move.l	_IntBase(pc),a6
	jsr	_LVO\1(a6)
	endm
callgfx	macro
	move.l	_GfxBase(pc),a6
	jsr	_LVO\1(a6)
	endm
calldos	macro
	move.l	_DosBase(pc),a6
	jsr	_LVO\1(a6)
	endm
	


* ------------------ *
* - Programmbeginn - *
* ------------------ *
_main	lea.l	_DosParamAddr(pc),a1
	move.l	a0,(a1)
	lea.l	_DosParamLen(pc),a1
	move.l	d0,(a1)
	
	lea.l	_DosName(pc),a1
	moveq	#0,d0
	callsys	OpenLibrary
	lea.l	_DosBase(pc),a0
	move.l	d0,(a0)
	beq	.LibErr0

	lea.l	_IntName(pc),a1
	moveq	#0,d0
	callsys	OpenLibrary
	lea.l	_IntBase(pc),a0
	move.l	d0,(a0)
	beq	.LibErr1
	
	lea.l	_GfxName(pc),a1
	moveq	#0,d0
	callsys	OpenLibrary
	lea.l	_GfxBase(pc),a0
	move.l	d0,(a0)
	beq.s	.LibErr2
	

	   bsr.s	sub	* Spring ins Hauptprogramm


	move.l	_GfxBase(pc),a1
	callsys	CloseLibrary
	
.LibErr2	move.l	_IntBase(pc),a1
	callsys	CloseLibrary

.LibErr1	move.l	_DosBase(pc),a1
	callsys	CloseLibrary

.LibErr0	moveq	#0,d0
	rts

* ----------------------- *
* - Versionsbezeichnung - *
* ----------------------- *
	dc.b	"$VER Player 1.00 (12.12.93)"
	even 


* ----------------- *
* - Hauptprogramm - *
* ----------------- *
sub	move.l	_DosParamLen(pc),d0
	cmp.l	#1,d0
	beq	NoFileGiven

	bsr	CopyFileName
	bsr	GetParameters
	bmi	End0

	bsr	LoadASS
	bmi	End0

	bsr	LoadCol
	bmi	End1
	bsr	OpenScreen
	bmi	End1
	
	bsr	LoadAni
	bmi	End2
	
	bsr	GetAniObjNr

	move.w	_AniObjNr(pc),d0	* d0=ObjektNr.
	move.w	_XPos(pc),d1		* d1=X-Position
	move.w	_YPos(pc),d2		* d2=Y-Position
	bsr	MoveObj

	bsr	InitVbInt
	bmi	End3




.Loop	btst	#6,$bfe001	* linke Maustaste abfragen
	bne.s	.Loop




	bsr	FreeVbInt

End3	bsr	FreeAniStore
	
End2	bsr	CloseScreen

End1	move.l	_ObjAddr(pc),a1 * Speicher von Objekte freigeben
	move.l	_ObjSize(pc),d0
	callsys	FreeMem

End0	rts

	


******************
* Unterprogramme *
******************

*** Screen ***

* --------------- *
* - Open Screen - *
* --------------- *
OpenScreen	lea.l	_ScnWidthInB(pc),a0   * Ermittle Bildschirm-
	move.w	_NewScreen+04(pc),d0     * Breite in Bytes
	lsr.w	#3,d0
	move.w	d0,(a0)

	lea.l	_NewScreen(pc),a0     * Öffne Screen
	lea.l	_ScreenName(pc),a1
	move.l	a1,ns_DefaultTitle(a0)
	callint	OpenScreen
	lea.l	_Screen(pc),a1
	move.l	d0,(a1)
	beq	ErrorRts
	move.l	d0,a0
	
	lea.l	_Bp1(pc),a1
	move.l	$c0(a0),(a1)
	lea.l	_Bp2(pc),a1
	move.l	$c4(a0),(a1)	
	lea.l	_Bp3(pc),a1
	move.l	$c8(a0),(a1)
	lea.l	_Bp4(pc),a1
	move.l	$cc(a0),(a1)
	lea.l	_Bp5(pc),a1	
	move.l	$d0(a0),(a1)	

	add.l	#$2c,d0
	lea.l	_VPort(pc),a0
	move.l	d0,(a0)
	
	add.l	#-$2c+$54,d0
	lea.l	_RPort(pc),a0
	move.l	d0,(a0)
	
	add.l	#-$54+$b8,d0
	lea.l	_BitMap(pc),a0
	move.l	d0,(a0)
	
	move.l	_VPort(pc),a0		* init. Farben
	lea.l	_Buffer(pc),a1
	moveq	#32,d0
	callgfx	LoadRGB4

	move.l	_VPort(pc),a0
	lea.l	_ColMap(pc),a1
	move.l	$4(a0),(a1)

	callint	ViewAddress
	move.l	_View(pc),a0
	move.l	d0,(a0)
	
	bra	OkRts


* ------------------- *
* - Schließe Screen - *
* ------------------- *
CloseScreen	move.l	_Screen(pc),a0
	callint	CloseScreen
	rts



********************************
*** Vertical Blank Interrupt ***
********************************
	
* ---------------------------------------- *
* - VerticalBlank-Interrupt Installieren - *
* ---------------------------------------- *
_vbIntStoreSz	equ	50

InitVbInt	moveq	#_vbIntStoreSz,d0   * Interrupt-Datenspeicher 
	move.l	#1!$10000,d1        * allokieren
	callsys	AllocMem
	lea.l	_vbIntStruct(pc),a0
	move.l	d0,IS_DATA(a0)      * und in Struktur schreiben
	beq	ErrorRts

	lea.l	vbIntCode(pc),a1    * Adresse des Interrupt-Codes
	move.l	a1,IS_CODE(a0)      * in Struktur schreiben

	move.b	#5,ln_Pri(a0)       * Priorität setzten

	moveq	#5,d0               * Interrupt-Server einbauen
	lea.l	_vbIntStruct(pc),a1
	callsys	AddIntServer

	bra	OkRts
	

* ----------------------------- *
* - Freigabe des VbInterrupts - *
* ----------------------------- *
FreeVbInt	moveq	#5,d0	      * Interrupt-Server ausklinken
	lea.l	_vbIntStruct(pc),a1
	callsys	RemIntServer

	lea.l	_vbIntStruct(pc),a0 * Interrupt-Daten-Speicher
	move.l	IS_DATA(a0),a1      * freigeben
	move.l	#_vbIntStoreSz,d0
	callsys	FreeMem

	rts


* --------------------------------- *
* - Vertical-Blank-Interrupt-Code - *
* --------------------------------- *
_XPos	dc.w	100
_YPos	dc.w	70

vbIntCode	movem.l	d0-d7/a0-a6,-(sp)    * alle Register auf Stack

* - bei jedem vbInterrupt: schreibe Sprt-Addr in Sprt-Register, falls Sprites
	bsr	SprtOnScreen

* - Überprüfe Animationsgeschwindigkeit
	lea.l	_AniSpeedCnt(pc),a0 * Animationsgeschw.
	subq.w	#1,(a0)
	bne.s	.vbIntEnd
	move.w	_AniSpeed(pc),(a0)

	lea.l	_AniDelay(pc),a0    * Verzögerungsfaktor
	subq.b	#1,(a0)
	bne.s	.vbIntEnd

	bsr	GetAniObjNr	       * Nr. nächstes Objekt holen

* - Objekt auf Bildschirm
	move.w	_AniObjNr(pc),d0	* d0=ObjektNr.
	move.w	_XPos(pc),d1		* d1=X-Position
	move.w	_YPos(pc),d2		* d2=Y-Position
	bsr	MoveObj

* - Ende des vbInterrupts
.vbIntEnd	movem.l	(sp)+,d0-d7/a0-a6    * Alle Register wiederherstellen
	rts


* ------------------------------------------------ *
* - Hole Nr. des nächsten Objektes der Animation - *
* - und speichere Nr. in _AimObjNr
* ------------------------------------------------ *
_AniObjNr	ds.w	1 * Nummer der aktuellen Animationssequenz
_AniSpeed	ds.w	1 * Animationsgeschwindigkeit
_AniSpeedCnt	dc.w	_minSpeed * Zähler für Animationsgeschw.

_ActAniStore	ds.w	1 * aktueller Animationsspeicher
_ActSeqNr	ds.w	1 * aktuelle SequenzNr.
_ActNrOfSeq	ds.w	1 * aktuelle Anzahl Sequenzen
_AniDelay	ds.b	1 * Verzögerungsfaktor der akt. Anim.sequenz
	even
_Direction	ds.w	1 * Ablaufrichtung (0)=forw./(1)=backw./(-1)=f+b
_ActDirection	ds.w	1 * aktuelle Richtung (0)=forw. / (1)=backw.


GetAniObjNr	move.l	_AniStore(pc),a0
	move.l	a0,a1
	move.w	_ActAniStore(pc),d0
	add.w	d0,d0
	addq.w	#2,d0
	add.w	d0,a1
	add.w	(a1),a0

	lea.l	_ActNrOfSeq(pc),a1
	move.w	0(a0),(a1)
	
	move.w	_ActSeqNr(pc),d0
	add.w	d0,d0

	lea.l	_AniObjNr(pc),a1
	move.b	4(a0,d0.w),1(a1)

	lea.l	_AniDelay(pc),a1
	move.b	5(a0,d0.w),(a1)

	lea.l	_ActDirection(pc),a1
	lea.l	_Direction(pc),a2
	lea.l	_ActSeqNr(pc),a3

	tst.w	(a1)
	beq	.Forward
	
* - Rückwärts - *
.Backward	subq.w	#1,(a3)
	bpl.s	.End
	tst.w	(a2)
	bmi.s	.ForwBack
	move.w	_ActNrOfSeq(pc),(a3)
	subq.w	#1,(a3)
	rts

.ForwBack	addq.w	#2,(a3)
	move.w	#0,(a1)
	rts

* - Vorwärts - *
.Forward	addq.w	#1,(a3)
	move.w	(a3),d0
	cmp.w	_ActNrOfSeq(pc),d0
	bne.s	.End
	tst.w	(a2)
	bmi.s	.ForwBack2
	move.w	#0,(a3)
	rts
	
.ForwBack2	subq.w	#2,(a3)
	move.w	#1,(a1)
.End	rts



***********************
*** Objekt-Routinen ***
***********************

* ---------------------------------- *
* - Überprüfe ob Bob od. Sprite ---- *
* - und springe in entspr. Routine - *
* ---------------------------------- *
* Übergabe:	d3.w	(0)=Bob / (1)=Sprite
* ---------------------------------- *
MoveObj	move.w	_ObjType(pc),d3	* d3: (0)=Bob / (1)=Sprite
	move.l	_ObjAddr(pc),a0	* a0=Zeiger auf Objekte im Speicher
	tst.w	d3
	beq	MoveBob

	bra	MoveSprite

	

* ----------------------------- *
* - bringe Bob auf Bildschirm - *
* ----------------------------- *
* Übergabe:	a0.l	Zeiger auf Objekte im Speicher
*
*	d0.w	Objektnummer
*	d1.w	x-Koordinate in Bildpunkten
*	d2.w	y-Koordinate in Bildpunkten
*
*	Adressen der Screen-Bitplanes müssen in Label _Bp1-_Bp5
*	gespeichert sein
* --------------------------------- *
MoveBob	movem.l	d0-d7/a0-a1/a5,-(sp)

	lea.l	$dff000,a5	* Basisadresse -> a5

	bsr	OwnBlitter	* Blitter reservieren
	
	add.w	d0,d0	* Offset holen
	move.w	ass_OffsList(a0,d0.w),d0

	move.w	ass_Width(a0,d0.w),d3	* Breite des Objekts
	move.w	_ScnWidthInB(pc),d4
	subq.w	#2,d4
	sub.w	d3,d4
	sub.w	d3,d4
	move.w	d4,_bltdmod(a5)
	move.w	#-2,_bltamod(a5)
	
	addq.w	#1,d3
	move.w	ass_Height(a0,d0.w),d6	* Höhe des Objekts
	lsl.w	#6,d6
	or.w	d3,d6
	
	move.w	ass_Depth(a0,d0.w),d7	* Bitplane-Anzahl
	subq.w	#1,d7
	
	move.w	d1,d3	* ermittle Verschiebung nach
	and.w	#$f,d3	* Rechts bei Ausgabe auf Screen
	lsl.w	#8,d3
	lsl.w	#4,d3
	or.w	#%0000100111110000,d3
	move.w	d3,_bltcon0(a5)
	move.w	#0,_bltcon1(a5)

	mulu.w	#40,d2	* d2 = X/8 + Y*40
	lsr.w	#3,d1
	and.w	#$fe,d1
	add.w	d1,d2

	lea.l	ass_GfxData(a0,d0.w),a1	* Zeiger auf Source-Bitplane
	move.l	a1,_bltapt(a5)	* Source-Zeiger -> Register
	
	lea.l	_Bp1(pc),a0    * Adresse, ab der die Adressen
			 * der Bitplanes gespeichert
			 * sind -> a0
	
	move.l	#$ffff0000,_bltafwm(a5) * Maskierung $ffff 0000
	
.anpl22	move.l	(a0)+,a1	      * Adresse der Bitpl. -> a1
	add.w	d2,a1	      * addiert: X/8 + 40*Y
	bsr	BlitterBusy	      * überprüfe: Blitter frei?
	move.l	a1,_bltdpt(a5)      * Zielbitplane -> Register
	move.w	d6,_bltsize(a5)     * Blit-Start
	dbra	d7,.anpl22

	bsr	DisOwnBlitter       * Blitter-Freigabe

	movem.l	(sp)+,d0-d7/a0-a1/a5
	rts


* ------------------------ *
* - Sprite positionieren - *
* ------------------------ *
* Übergabe:	a0.l	Zeiger auf Offsetliste der Objekte
*
*	d0.w	Objektnummer
*	d1.w	x-Koordinate in Lo-Res Bildpunkten
*	d2.w	y-Koordinate in Lo-Res Bildpunkten
*
*	Speichert Spriteanzahl in Adresse _SprtAnz
*	Speichert Spriteadressen ab Adresse _SprtAddr
* ------------------------ *
_SprtAnz	dc.w	-1	* Anz. verwendeter Sprites (0-7)
_SprtAddr	ds.l	12	* Adressen der verwendeten Sprites (max. 12)

MoveSprite	movem.w	d1-d2,-(sp)   * x/y-Koordinate auf Stack
	
	add.w	d0,d0	* Offset holen
	move.w	ass_OffsList(a0,d0.w),d0

	move.w	ass_Height(a0,d0.w),d2	* Höhe der Sprites
	move.w	ass_Depth(a0,d0.w),d3	* attached/not attached

	lea.l	_SprtAnz(pc),a1
	move.w	ass_Width(a0,d0.w),d4	* Breite des Objekts
	tst.w	d3
	beq.s	.NotAtt1
	add.w	d4,d4	
.NotAtt1	subq.w	#1,d4
	move.w	d4,(a1)       * Anzahl benutzer Sprites -> _SprtAnz
	
	lea.l	ass_GfxData(a0,d0.w),a1	* Adresse, ab der die Grafikdaten beginnen
	movem.w	(sp)+,d0-d1		* x/y-Koordinate nach d0/d1
	lea.l	_SprtAddr(pc),a3	* Adresse, ab der die Anfangsadr.
				* der Sprites gespeichert werden
				* sollen -> a3
	moveq	#-1,d5
.Loop	move.l	a1,(a3)+	* Speichert Spriteaddr.
	move.l	a1,a0
	bsr	MakeCtrlWord  * erstellt die Kontrollworte
	
	tst.w	d3
	beq.s	.NotAtt2
	addq.w	#1,d5
	beq.s	.Next
	moveq	#-1,d5	
.NotAtt2	add.w	#16,d0	* X-Koordinate um 16 erhöhen
.Next	addq.l	#8,a1
	add.w	d2,a1
	add.w	d2,a1
	add.w	d2,a1
	add.w	d2,a1
	dbra	d4,.loop

	bra.s	SprtOnScreen
	


* ------------------------------------- *
* - erstelle die Sprite Kontrollworte - *
* ------------------------------------- *
* Übergabe:	a0.l	Adresse des einzelnen Sprites
*
*	d0.w	x-Koordinate
*	d1.w	y-Koordinate
*	d2.w	Höhe des Sprites (von 1  bis x)
*	d3.b	(1): attached / (0): not attached
* ------------------------------------- *
MakeCtrlWord	movem.l	d0-d4/a0,-(sp)

	add.w	#127,d0
	add.w	#42,d1
	move.b	d1,(a0)+
	
	move.b	d0,d4
	and.b	#%001,d4

	lsr.w	#1,d0
	move.b	d0,(a0)+
	
	btst	#8,d1
	beq.s	.NoE8
	or.w	#%100,d4

.NoE8	add.w	d2,d1
	
	btst	#8,d1
	beq.s	.NoL8
	or.w	#%010,d4

.NoL8	move.b	d1,(a0)+

	tst.b	d3
	beq.s	.NotAttached
	or.w	#%10000000,d4

.NotAttached	move.b	d4,(a0)+

	movem.l	(sp)+,d0-d4/a0
	rts


* ------------------------------------------------------------ *
* - Schreibt die Adresse der Sprites in die entspr. Register - *
* - damit die Sprites auch auf dem Bildschirm erscheinen ----- *
* - Wichtig: Routine bei jedem Vertical Blank Interrupt aufrufen
* ------------------------------------------------------------ *
SprtOnScreen	move.w	_ObjType(pc),d0  * überüfe ob Objekte=Sprites
	beq.s	.Rts

	move.w	_SprtAnz(pc),d0   * überüfe ob Spriteaddressen
	bmi.s	.Rts	    * gespeichert sind
	cmp.w	#8,d0	    * überprüfe ob mehr als 8
	bcs.s	.OK	    * Sprites benötigt
	moveq	#7,d0	    * max. 8 Sprites mögl.
.OK	lea.l	_SprtAddr(pc),a0
	lea.l	$dff120,a1
.Loop	move.l	(a0)+,(a1)+
	dbra	d0,.Loop
.Rts	rts



* ----------------- *
* - blitter-check - *
* ----------------- *
BlitterBusy	movem.l	d0-d1/a0-a1,-(sp)
	callgfx	WaitBlit
	movem.l	(sp)+,d0-d1/a0-a1
	rts

OwnBlitter	movem.l	d0-d1/a0-a1,-(sp)
	callgfx	WaitBlit
	callgfx	OwnBlitter
	movem.l	(sp)+,d0-d1/a0-a1
	rts

DisownBlitter	movem.l	d0-d1/a0-a1/a5,-(sp)
	callgfx	WaitBlit
	callgfx	DisOwnBlitter
	movem.l	(sp)+,d0-d1/a0-a1/a5
	rts



*** Laden ***

* ------------------------- *
* - Lade Farbdatei (.col) - *
* ------------------------- *
LoadCol	moveq	#0,d0	* d0=0 ==> Endung ".col" bei Open
	bsr	OpenLoad	* Öffne Datei zum Laden
	bmi	FileNotFound	* Fehler: Datei gefunden

	move.l	_File(pc),d1	* Lese erste 8 Zeichen (Identifik.)
	lea.l	_Buffer(pc),a0
	move.l	a0,d2
	moveq	#12,d3
	calldos	Read
	
	lea.l	_Buffer(pc),a0 * Überprüfe Identifikation
	cmp.l	#"OPAA",(a0)
	bne	WrongFormat	* Fehler: Falsches Format
	cmp.l	#"1COL",4(a0)
	bne	WrongFormat	* Fehler: Falsches Format

	move.l	_File(pc),d1	* Lese Farbdaten
	lea.l	_Buffer(pc),a0
	move.l	a0,d2
	moveq	#64,d3
	calldos	Read
	
	bsr	CloseFile	* Schließe Datei

	bra	OkRts	* Alles OK!
	
_Buffer	ds.b	64	* Puffer für Ladeoperationen


* ---------------------------------------- *
* - Lade Objekdatei im ASS-Format (.ass) - *
* ---------------------------------------- *
_ObjAddr	ds.l	1	* Zeiger auf Objekdaten
_ObjSize	ds.l	1	* Größe der Objekdaten
_ObjType	ds.w	1	* (0)=Bob / (1)=Sprite

LoadASS	moveq	#1,d0	* d0=1 --> Endung ".ass" bei Open
	bsr	OpenLoad	* Öffne Datei zum Laden
	bmi	FileNotFound	* Fehler: Datei gefunden
	
	move.l	_File(pc),d1	* Lese ID (12 Bytes)
	lea.l	_Buffer(pc),a0
	move.l	a0,d2
	moveq	#ass_IDLen,d3
	calldos	Read
	
	lea.l	_Buffer(pc),a0 * Überprüfe Identifikation
	cmp.l	#"OPAA",(a0)
	bne	WrongFormat	* Fehler: Falsches Format
	cmp.l	#"1ASS",4(a0)
	bne	WrongFormat	* Fehler: Falsches Format

	lea.l	_Buffer(pc),a0
	move.l	ass_FileLen(a0),d0 * Hole Länge der Datei
	lea.l	_ObjSize(pc),a1 * Dateilänge -> _ObjSize
	move.l	d0,(a1)
	moveq	#2,d1	* (2)=ChipMem
	callsys	AllocMem	* reserviere Speicher
	lea.l	_ObjAddr(pc),a0
	move.l	d0,(a0)
	beq	ErrorRts

	move.l	_File(pc),d1	* Lese Objekt- u. Grafikdaten
	move.l	d0,d2	* Adresse -> d2
	move.l	_ObjSize(pc),d3 * Dateilänge
	calldos	Read
	
	bsr	CloseFile	* Schließe Datei

	move.l	_ObjAddr(pc),a0
	lea.l	_ObjType(pc),a1
	move.w	ass_ObjType(a0),(a1)	* Bob/Sprite ???

	lea.l	_NewScreen(pc),a1
	move.w	ass_ScnWidth(a0),4(a1)
	move.w	ass_ScnHeight(a0),6(a1)
	move.w	ass_ScnDepth(a0),8(a1)
	move.w	ass_ScnMode+2(a0),$c(a1)

	bra	OkRts


* ------------------------------- *
* - Lade Animationsdatei (.ani) - *
* ------------------------------- *
_AniAddr	ds.l	1	* Zeiger auf Objekdaten
_AniSize	equ	1020	* Größe Animationsdaten

LoadAni	moveq	#2,d0	* d0=2 --> Endung ".ani" bei Open
	bsr	OpenLoad	* Öffne Datei zum Laden
	bmi	FileNotFound	* Fehler: Datei gefunden
	
	move.l	_File(pc),d1	* Lese Identifikation (12 Bytes)
	lea.l	_Buffer(pc),a0
	move.l	a0,d2
	moveq	#8+4,d3
	calldos	Read
	
	lea.l	_Buffer(pc),a0 * Überprüfe Identifikation
	cmp.l	#"OPAA",(a0)
	bne	WrongFormat	* Fehler: Falsches Format
	cmp.l	#"1ANI",4(a0)
	bne	WrongFormat	* Fehler: Falsches Format

	moveq	#0,d0
	move.l	8(a0),d0      * Größer der Ani-Datei
	bsr	AllocAniStore
	bmi	.ErrorEnd

*** Lade Animationsdaten

	move.l	_File(pc),d1  * Lese Offsetliste+Animationsdaten
	move.l	_AniStore(pc),d2
	move.l	_AniStoreSize(pc),d3
	calldos	Read
	tst.l	d0
	beq	.ErrorEnd
	
*** Ende 

.End	bsr	CloseFile
	bra	OkRts

.ErrorEnd	bsr	CloseFile
	bra	ErrorRts


* ------------------------------------------ *
* - Allokiere Speicher für Animationsdaten - *
* ------------------------------------------ *
* in:	d0.l	Size
* ------------------------------------------ *
_AniStore	ds.l	1
_AniStoreSize	ds.l	1

AllocAniStore	lea.l	_AniStoreSize(pc),a0
	move.l	d0,(a0)
	moveq	#1,d1	* (1)=PublicMem
	callsys	AllocMem	* reserviere Speicher
	lea.l	_AniStore(pc),a0
	move.l	d0,(a0)
	beq	ErrorRts
	bra	OkRts

FreeAniStore	lea.l	_AniStore(pc),a0
	move.l	(a0),a1
	cmp.l	#0,a1
	beq.s	.End
	move.l	#0,(a0)
	move.l	_AniStoreSize(pc),d0
	callsys	FreeMem
.End	rts


	
* -------------------------------------- *
* - Kopiere Dos-Parameter in _FileName - *
* -------------------------------------- *
_FileName	ds.b	50
_FileNameLen	ds.w	1

CopyFileName	move.l	_DosParamAddr(pc),a0
	lea.l	_FileName(pc),a1
	moveq	#0,d0
.CopyLoop	cmp.b	#" ",(a0)
	beq.s	.End
	cmp.b	#$a,(a0)
	beq.s	.End
	move.b	(a0)+,(a1)+
	addq.w	#1,d0
	bra.s	.CopyLoop
.End	lea.l	_FileNameLen(pc),a0
	move.w	d0,(a0)
	rts


* ----------------------- *
* - Ändere Datei-Endung - *
* ----------------------- *
* Übergabe	d0.w	Datei-Endung (0-2)
* ----------------------- *	
_SuffixTab	dc.b	".col"	* (0)
	dc.b	".ass"	* (1)
	dc.b	".ani"	* (2)

CgeSuffix	lea.l	_SuffixTab(pc),a0
	add.w	d0,d0
	add.w	d0,d0
	add.w	d0,a0
	
	lea.l	_FileName(pc),a1
	add.w	_FileNameLen(pc),a1

	move.b	(a0)+,(a1)+
	move.b	(a0)+,(a1)+
	move.b	(a0)+,(a1)+
	move.b	(a0)+,(a1)+
	move.b	#0,(a1)+
	
	rts


* ------------------------- *
* - Öffne Datei zum Laden - *
* ------------------------- *
* Übergabe:	d0.w	Datei-Endung (0-2)
*
* Rückgabe:	d0.w	(0)=alles Ok / (-1) Fehler
* ------------------------- *
_File	ds.l	1


OpenLoad	bsr	CgeSuffix

	lea.l	_FileName(pc),a0
	move.l	a0,d1
	move.l	#1005,d2		* Mode OldFile
	calldos	Open
	lea.l	_File(pc),a0
	move.l	d0,(a0)
	beq	ErrorRts
	bra	OkRts


* ------------------ *
* - Schließe Datei - *
* ------------------ *
CloseFile	move.l	_File(pc),d1
	calldos	Close
	rts
	


* ------------------------------------------------------------ *
* - Hole Animationsgeschwindigkeit vom CLI-Übergabeparameter - *
* ------------------------------------------------------------ *
GetParameters	move.l	_DosParamAddr(pc),a0
	
	moveq	#0,d1
.Loop	addq.w	#1,d1
	cmp.b	#$a,0(a0,d1.w)
	beq	NoSpeed
	cmp.b	#" ",0(a0,d1.w)
	bne.s	.Loop

	lea.l	_Buffer(pc),a1
	moveq	#-1,d2
.Loop2	addq.w	#1,d1
	cmp.b	#$a,0(a0,d1.w)
	beq.s	.Cont
	cmp.b	#" ",0(a0,d1.w)
	beq.s	.Cont
	move.b	0(a0,d1.w),(a1)+
	addq.w	#1,d2
	bra.s	.Loop2

.Cont	lea.l	_Direction(pc),a1
	move.b	1(a0,d1.w),(a1)
	
	tst.w	d2
	bmi	NoSpeed
	beq.s	.OneNr
	cmp.w	#2,d2
	bcc	SpeedOoRange

.TwoNr	lea.l	_Buffer(pc),a1
	moveq	#0,d0
	move.b	(a1)+,d0
	sub.w	#48,d0
	move.w	d0,d1
	lsl.w	#3,d0	*
	add.w	d1,d0	* d0=d0*10
	add.w	d1,d0	*
	move.b	(a1)+,d1
	sub.w	#48,d1
	add.b	d1,d0
	bra.s	.StoreSpeed

.OneNr	lea.l	_Buffer(pc),a1
	moveq	#0,d0
	move.b	(a1)+,d0
	sub.w	#48,d0

.StoreSpeed	cmp.w	#_minSpeed,d0
	bcs	SpeedOoRange
	cmp.w	#_maxSpeed+1,d0
	bcc	SpeedOoRange
	lea.l	_AniSpeed(pc),a0
	move.w	d0,(a0)	


* ------------------------------------------------------- *
* - Hole Ablaufrichtung für Animation vom CLI-Parameter - *
* ------------------------------------------------------- *
GetDirection	lea.l	_Direction(pc),a0
	lea.l	_ActDirection(pc),a1
	moveq	#0,d0
	move.b	(a0),d0
	sub.w	#48,d0
	cmp.w	#1,d0
	beq.s	.Forward
	cmp.w	#2,d0
	beq.s	.Backward
	cmp.w	#3,d0
	beq.s	.ForwBack
	bra	WrongDirect
	
.Forward	move.w	#0,(a0)
	move.w	#0,(a1)
	bra	OkRts

.Backward	move.w	#1,(a0)
	move.w	#1,(a1)
	bra	OkRts

.ForwBack	move.w	#-1,(a0)
	move.w	#0,(a1)
	bra	OkRts


* ------------------- *
* - Ausgabe ins CLI - *
* ------------------- *
* Übergabe	a0.l	Zeiger auf Text
*	d3.l	Text-Länge
* ------------------- *
OutToCli	move.l	a0,d2
	calldos	Output
	move.l	d0,d1
	calldos	Write	
	bra	ErrorRts


* -------------------- *
* - Fehlermeldungen  - *
* -------------------- *
FileNotFound	lea.l	_FNFText(pc),a0
	move.l	#_FNFTextLen,d3
	bra.s	OutToCli

NotEnoughMem	lea.l	_NEMText(pc),a0
	move.l	#_NEMTextLen,d3
	bra.s	OutToCli

WrongFormat	lea.l	_WFText(pc),a0
	move.l	#_WFTextLen,d3
	bra.s	OutToCli
	
NoFileGiven	lea.l	_NFGText(pc),a0
	move.l	#_NFGTextLen,d3
	bra.s	OutToCli
	
SpeedOoRange	lea.l	_SORText(pc),a0
	move.l	#_SORTextLen,d3
	bra.s	OutToCli

NoSpeed	lea.l	_NSText(pc),a0
	move.l	#_NSTextLen,d3
	bra.s	OutToCli
	
WrongDirect	lea.l	_WDText(pc),a0
	move.l	#_WDTextLen,d3
	bra.s	OutToCli
	

* - Error-Text - *
_FNFText	dc.b	10,"Error: File not found",10,10
_FNFTextLen	equ	*-_FNFText

_NEMText	dc.b	10,"Error: Not enough memory",10,10
_NEMTextLen	equ	*-_NEMText

_WFText	dc.b	10,"Error: File has wrong format",10,10
_WFTextLen	equ	*-_WFText

_NFGText	dc.b	"Usage: Player <FileName> <speed> <direction>",10
	dc.b	"       <speed>:     1-99 (1=fast / 99=slow)",10
	dc.b	"       <direction>: 1=forward / 2=backward / 3=forward+backward",10
	dc.b	"       Write FileName without suffix!!!",10
_NFGTextLen	equ	*-_NFGText
	even

_SORText	dc.b	10,"Error: Speed out of range (1-99)",10,10
_SORTextLen	equ	*-_SORText

_NSText	dc.b	10,"Error: No speed given",10,10
_NSTextLen	equ	*-_NSText

_WDText	dc.b	10,"Error: Wrong direction (1-3)",10,10
_WDTextLen	equ	*-_WDText



*********************************************

* -------------------------- *
* - Return mit/ohne Fehler - *
* -------------------------- *
OkRts	movem.l	d0,-(sp)
	moveq	#0,d0	* Zero-Flag setzten
	movem.l	(sp)+,d0
	rts

ErrorRts	movem.l	d0,-(sp)
	moveq	#-1,d0	* N-Flag setzen
	movem.l	(sp)+,d0	
	rts
	


**************
* Strukturen *
**************
	
*** VerticalBlank-Struktur ***
_vbIntStruct	dc.l	0
	dc.l	0
	dc.b	2	* Type
	dc.b	0	* Pri
	dc.l	0
	ds.l	1	* IS_DATA
	ds.l	1	* IS_CODE


***  NewScreen-Struktur ***
_NewScreen	dc.w	0,0,320,256,5
	dc.b	3,1
	dc.w	$4000,0
	dc.l	0
	ds.l	1	* ScreenName
	dc.l	0,0

_ScreenName	dc.b	"» OPAA « ASS-Player V1.00",0
	even

_ScnWidthInB	ds.w	1	* Screen-Breite in Bytes


**********
* Labels *
**********

* - Libraries - *

_DosParamAddr	ds.l	1
_DosParamLen	ds.l	1

_IntName	dc.b	"intuition.library",0
_GfxName	dc.b	"graphics.library",0
_DosName	dc.b	"dos.library",0
	even
_IntBase	ds.l	1
_GfxBase	ds.l	1
_DosBase	ds.l	1


* - Screen - *

_Screen	ds.l	1

_VPort	ds.l	1
_RPort	ds.l	1
_BitMap	ds.l	1
_ColMap	ds.l	1
_View	ds.l	1
_Bp1	ds.l	1
_Bp2	ds.l	1
_Bp3	ds.l	1
_Bp4	ds.l	1
_Bp5	ds.l	1


	End
