;  Sourcecodedemo fuer Cracker -
; -- Journal Assemblerkurs 4 ---
; --- Cubescroller , Sprites ---
;   (c) 1990 Doctor Mabuse of
;	  Alpha Flight
; ------ Programmadresse -------
jmp		$50000		; Der Programmbeginn wird auf
org		$50000		; $50000 festgesetzt
load		$50000
>extern	"ffff",$70000,$20000	; Vor dem Start des Programmes einmal
				; mit y Befehl Grafik einladen. Das Bild
				; mit dem Font ist identisch mit dem
				; aus Assembler Kurs 3 !
; ---------- Offsets -----------
openlibrary= 	-408		; Hier sind vordefinierte Adressen
closelibrary= 	-414		; und Offsets, die wir spaeter
forbid= 	-132		; brauchen werden
permit= 	-138
execbase= 	$04
; ------------------------------
start:
movem.l d0-d7/a0-a6,-(a7)	; Alle Register retten damit am Ende
				; des Programms alles wiederherge-
				; stellt werden kann
; ------------------------------
; -- Graphics Libary oeffnen ---
				; Mit der Exec-Library Funktion
				; Openlibray wird die Graphics
				; Library geoffnet. Dazu holen wir
				; uns die Basisadresse der Offsetliste
move.l	execbase,a6		; aus der Adresse $4=Execbase.
lea	gfxname,a1 	
jsr	openlibrary(a6)		; Die Routine wird angesprungen und
move.l	d0,gfxbase		; wir bekommen als Ergebnis die
				; Adresse der Ofsetliste der GFX-
				; Library. (Etwas Kompliziert)
; -- Multitasking abschalten ---
				; Da der Interrupt der Betriebssystems
				; immer mitlaeuft muessen wir das
move.l	execbase,a6		; Multitasking des Amiga ausschalten,
jsr	forbid(a6)		; was wir hiermit tun.
; ---- Copperfeld erzeugen -----
				; Hier werden die scrollenden Farb-
				; balken vorbereitet. Dabei wird eine
				; Liste mit entsprechenden Copperbe-
				; fehlen mittels der folgenden Schlei-
move.l	#copfield,a0		; fe erzeugt.
move.w	#$e009,d0		; Anfangszeile der Farbbalken laden.
move.w	#30-1,d1		; Groesse
move.l	#scrolldats,a1		; Kruemmungsdaten
move.w	#$4000+[30*88],d2	; Spiegelung Zeile 30 - 0
loop1:
move.w	d0,(a0)+		; Copperbefehl 'wait' erzeugen.
move.w	#$fffe,(a0)+ 

move.w	#$0102,(a0)+
move.w	#$0000,(a0)+

move.w	#$00e2,(a0)+
move.w	d2,(a0)+
add.w	#$2c,d2
move.w	#$00ea,(a0)+
move.w	d2,(a0)+

move.w	#$102,(a0)+		; Scrollregister
move.w	(a1)+,(a0)+

sub.w	#$84,d2
add.w	#$0100,d0		; Wait auf naechste Zeile stellen.
dbra	d1,loop1		; Aeussere Schleife
; ------ Speicher Loeschen -----
move.l	#$72580,a0
move.w	#$3000,d0
loop3:
move.l	#0,(a0)+
dbra	d0,loop3
; -- Eigene CListe einsetzen ---
move.l		gfxbase,a0
add.l		#$26,a0
move.w		#$0080,$dff096
move.l		(a0),oldcopper
move.l		#newcopper,$dff080
move.w		#$8080,$dff096
; -------- IRQ umbiegen --------
move.w	$dff01c,irqsave		; IRQ Maske speichern
bset	#$f,irqsave		; Spaeteres zurueckschreiben vorbereiten
move.w	#$7fff,$dff09a		; Alle Interrupte abschalten
move.l	$6c,oldirq		; Alten Interrupt speichern
move.l	#newirq,$6c		; Eigenen Vektor reinsetzen
move.w	#$c028,$dff09a		; Erwuenschte Interrupte wieder zulassen
; ------------------------------
;  Hauptprogramm Warteschleife -
				; Jetzt laeuft das Demo nur durch den
main:				; Interrupt. Waehrenddessen wird hier
btst	#6,$bfe001		; auf das Druecken der Mousetaste
bne	main			; gewartet
; ------------------------------
; ------ Abschaltroutine -------
move.l	oldirq,$6c		; IRQ Vektor zurueckschreiben
move.w	irqsave,$dff09a		; Alte IRQ Maske zurueckschreiben
; alte Copperliste wiederholen -
move.w	#$0080,$dff096
move.l	oldcopper,$dff080	; Zurueckschreiben
move.w	#$8080,$dff096
; --- GFX-Library schliessen ---
move.l	execbase,a6		; Mit closelibrary wird die GFX-
move.l	gfxbase,a1		; Library geschlossen.
jsr	closelibrary(a6)
; -- Multitasking einschalten --
move.l	execbase,a6		; Und das Multitasking wieder erlaubt.
jsr	permit(a6)
; ----- Programmaussprung ------
movem.l	(a7)+,d0-d7/a0-a6	; Alle Register zurueckholen und
rts				; verabschieden.
; ------------------------------
; --------- Interrupt ----------
newirq:				; Hier ist Beginn unserer Interrupt-
movem.l	d0-d7/a0-a6,-(sp)	; outine. Zuerst alle Register retten.
; ------- Subroutinen  ---------
bsr	spriterout

; -- Scrollroutine anspringen --
bsr	scrollroutine
; ------- Interruptende --------
movem.l	(sp)+,d0-d7/a0-a6	; Zuerst die Register zurueckholen
move.w	#$0028,$dff09c		; Interrupt Request Register setzen
rte				; IRQ verlassen
; --------- Register -----------
oldirq:	dc.l	0		; Alter IRQ Vector
irqsave:dc.l	0		; Altes IRQ Maskingregister
; ------- Spriteroutine --------
spriterout:
				; X Koordinate. Naechste Sinus Stelle
move.w	sinx+2,d0		; ermitteln. Hier Schrittweite holen.
add.w	d0,sinx			; Draufaddieren.
cmp.w	#256*2,sinx		; Maximalwert abfragen
bcs	sp2
sub.w	#256*2,sinx		; Dann zuruecksubtrahieren.
sp2:

move.w	siny+2,d0
add.w	d0,siny
cmp.w	#256*2,siny
bcs	sp3
sub.w	#256*2,siny
sp3:
move.l	#positions,a2

move.w	#8-1,d4			; Anzahl Sprites

move.l	#sinlist,a0		; X-Position aus Sinusliste holen
add.w	sinx,a0
move.l	#sinlist,a1		; Y-Position
add.w	siny,a1

sploop:

move.w	(a0),d0
muls	#150,d0			; Breite (Aendere sie mal!!!!!)
asr.l	#8,d0			; Durch 256 teilen (Pseudokommazahl)
add.l	#280,d0			; Mitte

move.w	(a1),d1
muls	#120,d1			; Hoehe
asr.l	#8,d1			; Durch 256 teilen (Pseudokommazahl)
add.l	#162,d1			; Y-Mitte

bsr	spos

add.w	#8,a2			; Naechte Stelle in Copperliste
sub.w	sinx+4,a0		; X/Y Abstaende zum naeschten Ball
sub.w	siny+4,a1		; hinzuaddieren

dbra	d4,sploop		; Zaehlvariable
rts
; -- Spriteposition berechnen --
spos:				; Die Spritepositionen stehen in den
				; beiden Kontrollwoertern im Sprite-
				; datenfeld, oder direkt in der Copper-
				; liste. Die Daten sind 9 Bit breit!
				; Aufgrund der seltsamen Verteilung in 
				; den Steuerwoertern stehen nur 8 Bit
				; zusammen. In dieser Berechnungroutine
				; werden die neunten Bits abgefragt und
				; gegebenenfalls in Lo Teil des 2.
				; Steuerworts eingetragen. Das werdet
				; ihr aber kaum ganz kapieren, ohne
				; euch z.B. im Amiga Intern das Sprite-
				; kapitel durchzulesen!!!

move.w	d1,d2
lsl	#8,d2			; Hochshiften
lsl	#8,d1
bcc	spp1			; 9. Bit?
bset	#1,d2			; Dann setzen
bset	#2,d2
spp1:
add.w	#$1000,d2		; Hoehe des Sprite * $100
bcc	spp2			; 9. Bit?
bset	#1,d2			; Dann setzen
spp2:

lsr	#1,d0			; Shifen
bcc	spp3			; Ungerade Zahl?
bset	#0,d2			; Dann Bit setzen
spp3:
;bset	#7,d1

add.w	d0,d1

move.w	d1,2(a2)			; Positionen vor Sprites
move.w	d2,6(a2)		; schreiben
rts
; -- Register - Spriteroutine --
sinx:	dc.w	0,2,14		; Position / Schrittweite / Ballabstand
siny:	dc.w	0,4,18		; Wichtig: Schrittweite gerade Zahlen!!!!
sprite:				; Bitinformationen des Sprite
dc.w	$0070,$0000				; Steuerwoerter
dc.w	%0000011111100000,%0000011111100000	; Die Sprites koennen
dc.w	%0001100000011000,%0001111111100000	; bekanntlich vier Farben
dc.w	%0010000000000100,%0011111111111000	; haben, brauchen also
dc.w	%0100000000000010,%0111111111111100	; 2 Planes. Diese muessen
dc.w	%0100000000000010,%0111111111111100	; zeilenweise hinterein-
dc.w	%1000000000000001,%1111111111111110	; ander liegen, wie hier
dc.w	%1001111101111001,%1111111111111110	; vorgefuehrt. An Stellen
dc.w	%1001100000011001,%1111111111111110	; wo beide Planes eine
dc.w	%1001100000011001,%1111111111111110	; 0 haben, ist der Sprite
dc.w	%1001111100011001,%1111111111111110	; transparent.
dc.w	%1000000000110001,%1111111111111110
dc.w	%0100000001100010,%0111111111111100
dc.w	%0100000000000010,%0111111111111100
dc.w	%0010000000000100,%0011111111111000
dc.w	%0001100000011000,%0001111111100000
dc.w	%0000011111100000,%0000000000000000
dc.w	0,0				; Sprite Abschluss (Wichtig!)
; Ueberhang Werte
DC.W	$FF05,$FF04,$FF03,$FF02,$FF01,$FF01,$FF00,$FF00
DC.W	$FF00,$FF00,$FF00,$FF01,$FF01,$FF02,$FF03,$FF04
DC.W	$FF05,$FF06,$FF08,$FF09,$FF0B,$FF0D,$FF0F,$FF11
DC.W	$FF13,$FF16,$FF19,$FF1B,$FF1E,$FF21,$FF24,$FF28
DC.W	$FF2B,$FF2F,$FF32,$FF36,$FF3A,$FF3E,$FF42,$FF47
DC.W	$FF4B,$FF4F,$FF54,$FF59,$FF5E,$FF63,$FF68,$FF6D
DC.W	$FF72,$FF77,$FF7C,$FF82,$FF87,$FF8D,$FF93,$FF98
DC.W	$FF9E,$FFA4,$FFAA,$FFB0,$FFB6,$FFBC,$FFC2,$FFC8
DC.W	$FFCE,$FFD4,$FFDA,$FFE1,$FFE7,$FFED,$FFF3,$FFFA
sinlist:			; 256 Sinuswerte
DC.W	$0000,$0006,$000D,$0013,$0019,$001F,$0026,$002C
DC.W	$0032,$0038,$003E,$0044,$004A,$0050,$0056,$005C
DC.W	$0062,$0068,$006D,$0073,$0079,$007E,$0084,$0089
DC.W	$008E,$0093,$0099,$009E,$00A2,$00A7,$00AC,$00B1
DC.W	$00B5,$00B9,$00BE,$00C2,$00C6,$00CA,$00CE,$00D1
DC.W	$00D5,$00D8,$00DC,$00DF,$00E2,$00E5,$00E7,$00EA
DC.W	$00ED,$00EF,$00F1,$00F3,$00F5,$00F7,$00F8,$00FA
DC.W	$00FB,$00FC,$00FD,$00FE,$00FF,$00FF,$0100,$0100
DC.W	$0100,$0100,$0100,$00FF,$00FF,$00FE,$00FD,$00FC
DC.W	$00FB,$00FA,$00F8,$00F7,$00F5,$00F3,$00F1,$00EF
DC.W	$00ED,$00EA,$00E7,$00E5,$00E2,$00DF,$00DC,$00D8
DC.W	$00D5,$00D1,$00CE,$00CA,$00C6,$00C2,$00BE,$00B9
DC.W	$00B5,$00B1,$00AC,$00A7,$00A2,$009D,$0098,$0093
DC.W	$008E,$0089,$0084,$007E,$0079,$0073,$006D,$0068
DC.W	$0062,$005C,$0056,$0050,$004A,$0044,$003E,$0038
DC.W	$0032,$002C,$0026,$001F,$0019,$0013,$000D,$0006
DC.W	$0000,$FFFA,$FFF3,$FFED,$FFE7,$FFE1,$FFDA,$FFD4
DC.W	$FFCE,$FFC8,$FFC2,$FFBC,$FFB6,$FFB0,$FFAA,$FFA4
DC.W	$FF9E,$FF98,$FF93,$FF8D,$FF87,$FF82,$FF7C,$FF77
DC.W	$FF72,$FF6D,$FF67,$FF62,$FF5E,$FF59,$FF54,$FF4F
DC.W	$FF4B,$FF47,$FF42,$FF3E,$FF3A,$FF36,$FF32,$FF2F
DC.W	$FF2B,$FF28,$FF24,$FF21,$FF1E,$FF1B,$FF19,$FF16
DC.W	$FF13,$FF11,$FF0F,$FF0D,$FF0B,$FF09,$FF08,$FF06
DC.W	$FF05,$FF04,$FF03,$FF02,$FF01,$FF01,$FF00,$FF00
DC.W	$FF00,$FF00,$FF00,$FF01,$FF01,$FF02,$FF03,$FF04
DC.W	$FF05,$FF06,$FF08,$FF09,$FF0B,$FF0D,$FF0F,$FF11
DC.W	$FF13,$FF16,$FF19,$FF1B,$FF1E,$FF21,$FF24,$FF28
DC.W	$FF2B,$FF2F,$FF32,$FF36,$FF3A,$FF3E,$FF42,$FF47
DC.W	$FF4B,$FF4F,$FF54,$FF59,$FF5E,$FF63,$FF68,$FF6D
DC.W	$FF72,$FF77,$FF7C,$FF82,$FF87,$FF8D,$FF93,$FF98
DC.W	$FF9E,$FFA4,$FFAA,$FFB0,$FFB6,$FFBC,$FFC2,$FFC8
DC.W	$FFCE,$FFD4,$FFDA,$FFE1,$FFE7,$FFED,$FFF3,$FFFA
; ------- Scrollroutine --------
scrollroutine:
; --- Oberste Zeile zuunterst --
;            kopieren
move.l	#$74000+[00*88],a0
move.l	#$74000+[60*88],a1
move.w	#22-1,d0
copy:
move.l	(a0)+,(a1)+
dbra	d0,copy
; ---- Links/ Hoch scrollen ----
move.l	#$74000+[01*88],$dff050		; Startadresse
move.l	#$73ffe+[00*88],$dff054		; Destinationadresse
move.l	#$00000000,$dff064		; Kein Modulo, da ganze Breite
move.l	#$fffffff8,$dff044		; Maske
move.l	#$d9f00000,$dff040		; Kontrollregister
move.w	#[60*2]*64+$16,$dff058		; Hoehe und Breite. Gleichzeitig
					; Startbefehl
wait1:
btst	#6,$dff002			; Blitteroperation abwarten
bne.s	wait1
; ------------------------------
add.w	#3,scroll		; Geschwindigkeit in Pixeln
cmp.w	#27,scroll		; Zeichenabstand in Pixeln
bcs.s	no
move.w	#0,scroll		; Zuruecksetzen
bra.s	printchar		; neues zeichen ausgeben
no:
rts
; ------------------------------
printchar:
clr.l		d0
clr.l		d1
move.l		pointer,a0		; Zeichen holen
move.b		(a0),d0
sub.b		#48,d0			; erstes Zeichen des Zeichensatz
bpl		nnm
move.b		#16,d0			; sonst Leerzeichen
nnm:
move.b		d0,d1
divu		#10,d1			; 20 Character pro Zeile
move.w		d1,d2
swap		d1
move.w		d1,d3
mulu		#4,d3			; 2 Bytes Breit
mulu		#22*80,d2		; 22 Zeilen a 80 Bytes hoch
add.w		d2,d3
move.l		#$70000,d0		; Anfangsadresse Zeichensatz
add.w		d3,d0
move.l		d0,$dff050
move.l		#$74028+[30*88],d0	; Blit Ziel
move.l		d0,$dff054
move.l		#$00240028,$dff064	; Modulo
move.l		#$ffffffff,$dff044	; Maske
move.l		#$09f00000,$dff040	; Modus
move.w		#[18*2]*64+2,$dff058	; Hoehe, Breite und Start
add.l		#1,pointer		; naechstes Zeichen
cmp.l		#ende,pointer
bcs		eee
move.l		#message+0,pointer	; Neuer Start des Scrollers
eee:
wait2:
btst		#6,$dff002	; Warten auf Blitter
bne.s		wait2
rts
; ------------------------------
scroll:		dc.w	0
pointer:	dc.l	message
message:
DC.B	"    THATS A GREAT TUBE SCROLL ISN'T IT:  WELL OF COURSE ITS "
DC.B	"NOT PERFECT:  WITH SOME MORE TIME YOU CAN MANIPULATE THE "
DC.B	"BITPLANES SO THAT THE SCROLLER GETS A MUCH MORE 3 DIMENSIONAL "
DC.B	"EFFECT:  REMEMBER; ITS NOT MY JOB TO CODE YOUR DEMOS:  YOULL "
DC.B	"STILL HAVE TO DO THIS ON YOUR OWN:  SEE YOU IN THE NEXT "
DC.B	"SOURCE CODE::::::::::::                 DOCTOR MABUSE::::: "
DC.B	"                             "
ende:
even				; gerade Adresse garantieren
; ------------------------------
; -------- Copperliste ---------
newcopper:			; Unsere Copperliste
dc.w 	$008e,$2881,$0090,$30d1 ; linke obere und rechte untere 
				; Koordinaten des BildschirmFenster
dc.w 	$0092,$0038,$0094,$00d0 ; DataFetch Start Stop Register
dc.w 	$0108,$0028,$010a,$0030	; Modulo Werte der Bitplanes
dc.w 	$0102,$0000,$0104,$0064 ; BitPlane Control Reg. #1 u. #2
				; Scrollwerte, Prioritaeten von
				; Playfields und Sprites!!!!!!
dc.w 	$0100,$4700		; BitPlane Control Reg. #0
				; 4 Bitplanes + Dual-Playfield
planes:
dc.w    $00e0,$0007,$00e2,$0000	; 1. Plane 1. Field
dc.w	$00e4,$0007,$00e6,$4000	; 1. Plane 2. Field
dc.w	$00e8,$0007,$00ea,$0028	; 2. Plane 1. Field
dc.w	$00ec,$0007,$00ee,$402c	; 1. Plane 2. Field

dc.w	$0120,sprite/$10000,$0122,sprite	; Spritepointer setzen.
dc.w	$0124,sprite/$10000,$0126,sprite	; Mit dieser trickreichen
dc.w	$0128,sprite/$10000,$012a,sprite	; Methode teilt man die
dc.w	$012c,sprite/$10000,$012e,sprite	; Adresse in Hi und Lo
dc.w	$0130,sprite/$10000,$0132,sprite	; Spritepointer setzen.
dc.w	$0134,sprite/$10000,$0136,sprite	; Mit dieser trickreichen
dc.w	$0138,sprite/$10000,$013a,sprite	; Methode teilt man die
dc.w	$013c,sprite/$10000,$013e,sprite	; Adresse in Hi und Lo

rgb:
dc.w	$0180,$0000,$0182,$0660	; Farben als RGB-Werte
dc.w	$0184,$0880,$0186,$0aa0
dc.w	$0190,$0000,$0192,$0aa0	; Farben des 2. Fields
dc.w	$0194,$0dd0,$0196,$0ff0
dc.w	$01a2,$0aa0,$01a4,$0dd0,$01a6,$0ff0	; Sprites 1+2
dc.w	$01aa,$0a00,$01ac,$0d00,$01ae,$0f00	; Sprites 3+4
dc.w	$01b2,$0090,$01b4,$00c0,$01b6,$00e0	; Sprites 5+6
dc.w	$01ba,$023f,$01bc,$045f,$01be,$067f	; Sprites 7+8

dc.w	$2009,$fffe		; Warten bis Sprite gelesen wurde!
				; Achtung, hier parktiziere ich die
				; Methode der sogenannten kontrollwort-
				; losen Sprites. Dadurch kann man 8
				; Sprites mit dem gleichen Datenfeld
				; aber unterschiedlichen Positionen
				; darstellen. Dabei muss man dem Kon-
				; wort des Sprites eine Position ganz
				; am Anfang des Bildschirmaufbaus geben.
				; Der Copper kann dann nach dem
				; initialisieren mit einer neuen Sprite-
				; position bestueckt werden.

positions:			; Hier stehen die neuen Spritepoostionen
dc.w	$0140,$5040,$0142,$6000	; die direkt in das Copperregister ge-
dc.w	$0148,$5050,$014a,$6000	; schrieben werden. Das geht aber erst
dc.w	$0150,$5060,$0152,$6000	; Wenn der Sprite schon initialisiert
dc.w	$0158,$5070,$015a,$6000	; ist, deshalb erst warten!
dc.w	$0160,$5080,$0162,$6000
dc.w	$0168,$5090,$016a,$6000
dc.w	$0170,$50a0,$0172,$6000
dc.w	$0178,$50b0,$017a,$6000

dc.w	$e009,$fffe,$0108,$0030,$010a,$0030
dc.w	$00e6,$4000+[30*88]
dc.w	$00ee,$402c+[30*88]

copfield:			; Hier ist wieder Speicher fuer das
blk.w	30*5*2,0		; Copperfeld reserviert. Wichtig! Der
				; Platz muss genau hinkommen, sonst
				; lernt ihr den freundlichen Buddisten
				; kennen, gelle?! Nach dem Copperfeld
				; muesst ihr die Bitplanepointer wieder
dc.w	$fe09,$fffe		; auf eine vernuenftige Adresse setzen,
dc.w	$00e2,$2800,$00e6,$2800	; oder abschalten. Ansonsten werdet ihr
dc.w	$00ea,$2800,$00ee,$2800	; Grafikfehler sehen.


dc.w	$ffff,$fffe		; Code fuer Ende der Copperliste
; ------ Kruemmungsdaten -------
scrolldats:
dc.w	$88,$97,$a6,$a6,$b5,$b5,$b5,$c4,$c4,$c4
dc.w	$c4,$c4,$d3,$d3,$d3,$d3,$d3,$d3,$c4,$c4
dc.w	$c4,$c4,$c4,$b5,$b5,$b5,$a6,$a6,$97,$88
; ------ Systemregister --------
gfxbase:	dc.l 	0
oldcopper:	dc.l	0
gfxname:
dc.b 	"graphics.library",0,0

prgend:
