*************************
*** 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
