;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Exemple d'utilisation de sprites
;	Le programme affiche en noir les touches appuyés par l'usager
;	Ce programme gère les 2 controlleurs
;	La ligne du haut représente le controlleur1 et celle du bas le controlleur 2
;	Création: Louis Marchand, 22 août 2016
;	License: MIT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;;;;;;; Entète de la rom ;;;;;;;;;;;
	.inesprg 1 ; 1 banque de 16KB (2 banque de 8KB) pour le programme
	.ineschr 1 ; 1 banque de 8KB pour les image (2 tables de motifs)
	.inesmap 0 ; mapper 0 = NROM, Banque par défaut
	.inesmir 1 ; Mirroir vertical de l'image de fond

;;;;;;; Le code commence ici ;;;;;;;;
	.code

	.bank 0   ; Banque 0 (8KB de $C000 à $DFFF)
	.org $C000  ; goto location $C000.


Start:
	SEI         ; Arreter les interruption, Met le bit I du registre P (etat du processeur) a 1
	CLD         ; Arrete le mode decimal. Met le bit D du registre P à 0
	LDX #$40
	STX $4017  ;  Met $40 dans le registre de controle de l'APU pour arreter les interruptions de l'APU
	LDX #$FF
	TXS         ; Initialise la pile. Place X ($FF$ comme octet moins significatif de l'adresse de la pile). La pile est toujours entre $0100 et $01FF.
	INX         ; Lorsqu'on incremente X qui contient $FF, C tombe à 0
	STX $2000  ;  Arrete les interruption NMI (Bit 7 du registre Contrôle PPU)
	STX $2001  ;  N'affiche rien (Voir bits 3 à 7 du registre Masque PPU)
	STX $4010  ;  Arrete les interruption logiciel

	JSR vblankwait	; Place l'adresse en cour sur la pile et branche vers la routine "vblankwait"

clrmem:
	LDA #$00
	STA $0000,  x		; Place tous les octets à 0 (", x" correspond a l'adressage indexe avec le registre x)
	STA $0100,  x
	STA $0300,  x
	STA $0400,  x
	STA $0500,  x
	STA $0600,  x
	STA $0700, x
	LDA #$FE
	STA $0200, x		; Placer tous les sprite en dehors de l'écran
	INX
	BNE clrmem		; Branche si non zero (lorsque x a fait le tour des valeurs de $00 à $FF)

	JSR vblankwait	; Place l'adresse en cour sur la pile et branche vers la routine "vblankwait"

;;;;  Initialise le PPU  ;;;;

LoadPalettes:
 	LDA $2002    		; Lire le registre d'etat du PPU ou annuler le latch de $2006 (s'il y a lieu)
	LDA #$3F	
	STA $2006    		; Place les 8 bits les plus significatifs de l'adresse $3F00 dans $2006
	LDA #$00
	STA $2006    		; Place les 8 bits les moins significatifs de l'adresse $3F00 dans $2006
	LDX #0
LoadPalettesLoop:
	LDA Palette, x		; Charge les donnees de la palette (", x" correspond a l'adressage indexe avec le registre x)
	STA $2007		; Place les informations du PPU (l'adresse d'écriture de $2007 incrémente automatiquement de 1 octet après chaque ecriture)
	INX			; Prochain index a aller chercher dans la palette en memoire rom (etiquette palette+x)
	CPX #32            
	BNE LoadPalettesLoop 	; La palette est completement copiees si x est à 32=16x2

; Initialisation des sprites
	LDX #0
LoadSpritesData:
	LDA SpriteData, x	; SpriteData est en ROM (lecture seule). Pour pouvoir modifier
	STA $0200, x		; ces sprites, nous transférons les données des sprites en RAM
	INX
	CPX #64		; il y a 16 sprites de 4 octets (donc 64 octets) à transférer en RAM
	BNE LoadSpritesData
	

;;;;  Fin de l'initialisation de données  ;;;;

	JSR vblankwait	; Place l'adresse en cour sur la pile et branche vers la routine "vblankwait"

	JSR activePPU

Forever:
	LDX #$00
	LDY #$00
	LDA #$01	; Écrire $01 et $00 dans $4016 place l'état du controlleur 1 dans $4016 et du controlleur 2 dans $4017
	STA $4016
	LDA #$00
	STA $4016
ReadButtonLoop:			; Valide chaque bouton
	jsr CheckButtonOnY      ;
	BEQ NotReadButton
	JMP FinReadButtonCTRL
NotReadButton:			; Bouton non press
	JSR SetSecondPaletteToSpriteOnX ;
	LDA $1;é
	JSR SetSpriteAOnX
FinReadButtonCTRL:
	INX					; Prochain sprite (4 octets par sprite) et prochain bouton
	INX
	INX
	INX
	CPX #32			; Controller 1 terminé. 8 boutons lu (8*4=32)
	BNE FinReadButton1
	INY
	JMP ReadButtonLoop
FinReadButton1
	CPX #64			; Controller 2 terminé. . 16 boutons lu (16*4=64)
	BNE ReadButtonLoop

ENDLOOP:
	JMP Forever     ;Boucle sans fin, le processus se fera lors d'interruption NMI

ConsiderController1OnButtonA:
	LDY $4016
	RTS

CheckButtonOnY:
	LDA $4016, y		; Lit l'état du controlleur (si Y est à 0, lit $4016 et si Y est à 1, lit $4017)
	AND #%00000001		; Le bouton est appuyé si le AND ne retourne pas 0.
	RTS

SetSpriteAOnX:
	STA $0201,X
	RTS

SetFirstPaletteToSpriteOnX:
	ORA $0202, x		; Bouton pressé; Met les bits d'attribut du sprite à 1
	STA $0202, x
	RTS

SetSecondPaletteToSpriteOnX:
	LDA #%11111100
	AND $0202, x		; Met les bits d'attribut du sprite à 0
	STA $0202, x
	RTS

NMI:
	LDA #$00
	STA $2003
	LDA #$02
	STA $4014

	RTI             ; retourne de l'interruption
	
activePPU:
	LDA #%10010100		; Active les interruption NMI, table de motif: sprite = 0 et image de fond = 1
	STA $2000
	LDA #%00010110		; Active l'image de fond et les sprites
	STA $2001
	RTS

vblankwait:			; Routine qui attend que l'écran ait terminé de s'afficher (pour éviter les problèmes visuels)
	BIT $2002		; Bit place les Code de condition N, V, Z.
	BPL vblankwait	; Si le bit 7 est allumé, on a un vblank (BPL = N flag clear, le bit de negatif = bit 7)
	RTS				; Effectue un branchement vers l'adresse sur le dessus de la pile (Voir "JSR vblankwait")



;;;;; La prochaine section est une partie du ROM de la cartouche il est possible de mettre du code ici. Nous allons l'utiliser pour mettre des constantes ;;;;;;

	.bank 1		; Banque 1 (8KB de $E000 à $FFFF)
	.org $E000	; Donnees en lecture seulement

Palette:
	.db $09, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00	; Palette de l'image de fond
	.db $09, $10, $10, $10, $3F, $3F, $3F, $3F, $3F, $3F, $3F, $3F, $3F, $3F, $3F, $3F	; Palette des sprites


SpriteData:
	.db $40, 0, %00000000, $10	; Sprite A (CTRL 1)
	.db $40, 1, %00000000, $2F	; Sprite B (CTRL 1)
	.db $40, 2, %00000000, $4E	; Sprite Select (CTRL 1)
	.db $40, 3, %00000000, $6D	; Sprite Start (CTRL 1)
	.db $40, 4, %00000000, $8C	; Sprite Haut (CTRL 1)
	.db $40, 5, %00000000, $AB	; Sprite Bas (CTRL 1)
	.db $40, 6, %00000000, $CA	; Sprite Gauche (CTRL 1)
	.db $40, 7, %00000000, $E9	; Sprite Gauche (CTRL 1)

	.db $80, 0, %00000000, $10	; Sprite A (CTRL 2)
	.db $80, 1, %00000000, $2F	; Sprite B (CTRL 2)
	.db $80, 2, %00000000, $4E	; Sprite Select (CTRL 2)
	.db $80, 3, %00000000, $6D	; Sprite Start (CTRL 2)
	.db $80, 4, %00000000, $8C	; Sprite Haut (CTRL 2)
	.db $80, 5, %00000000, $AB	; Sprite Bas (CTRL 2)
	.db $80, 6, %00000000, $CA	; Sprite Gauche (CTRL 2)
	.db $80, 7, %00000000, $E9	; Sprite Gauche (CTRL 2)



	.org $FFFA	; vecteur d'interruption commence à $FFFA

	.dw NMI		; Interruption NMI (vblank). Adresse $FFFA
	.dw Start	; Interruption Reset (demarrage). Adresse $FFFC
	.dw 0		; Interruption logiciel (instruction BRK). Adresse $FFFE




;;;;; La prochaine section est une partie du ROM qui correspond aux adresse $0000 à $1FFF de la vram du PPU ;;;;;;

	.bank 2        ; change to bank 2
	.org $0000	; Motif de Sprite
SpriteA:	; Tuile 0
	.db %00011000
	.db %00100100 
	.db %00100100
	.db %01111110
	.db %01000010
	.db %10000001
	.db %10000001
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteB:	; Tuile 1
	.db %11111100 
	.db %10000010
	.db %10000010 
	.db %11111100
	.db %10000010
	.db %10000010
	.db %11111100
	.db %00000000 

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteSelect:	; Tuile 2
	.db %01001111 
	.db %10101000
	.db %10001000 
	.db %01001110
	.db %00101000
	.db %10101000
	.db %01001111
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteStart:	; Tuile 3
	.db %01000111 
	.db %10100010
	.db %10000010 
	.db %01000010
	.db %00100010
	.db %10100010
	.db %01000010
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteHaut:	; Tuile 4
	.db %00010000 
	.db %00111000
	.db %01010100 
	.db %10010010
	.db %00010000
	.db %00010000
	.db %00010000
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteBas:	; Tuile 5
	.db %00010000
	.db %00010000 
	.db %00010000
	.db %10010010
	.db %01010100
	.db %00111000
	.db %00010000
	.db %00000000 

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteGauche:	; Tuile 6
	.db %00010000 
	.db %00100000
	.db %01000000 
	.db %11111111
	.db %01000000
	.db %00100000
	.db %00010000
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000

SpriteDroit:	; Tuile 7
	.db %00001000 
	.db %00000100
	.db %00000010 
	.db %11111111
	.db %00000010
	.db %00000100
	.db %00001000
	.db %00000000

	.db %00000000 
	.db %00000000
	.db %00000000 
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000
	.db %00000000


