;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Note: This is a version with a modified table system.
; Some of the descriptions are partially incorrect
;
; Generic ExGFX Uploader v1.2*
; coded by edit1754
;
; This patch can be used to upload layer 3 tilemaps, since ExGFX files are compressed
; with a format (LZ2 or LZ3) that's far more space-efficient than stripe image.
; (I may release a tutorial on how to do this).
;
; The maximum size of an ExGFX file is 0x1B00 (6912) bytes due to decompression buffer size.
; If you need to upload a larger chunk of data, split it up into multiple ExGFX files.
;
; The format of the tables is as follows:
; - The 'Pointers' table contains local addresses to individual "GFX set" tables.
; - They default to $0000. Any value $0000-$7FFF means there is no pointer assigned.
; - To assign a "GFX Set" table to a certain level, replace '$0000' with the table's label.
; - GFX set tables consist of multiple double-word rows (dw $xxxx,$xxxx)
; - The first $xxxx is the VRAM address divided by 2. To upload to $7000, enter $3800
; - The second $xxxx is the ExGFX file number. To upload ExGFX233, enter $0233.
; - Each table is terminated by 'dw $FFFF' or any value $8000-$FFFF ($FFFF is by convention)
; - The ending line can be omitted in order to include the next table's graphics as well.
;   (this can be used as a space-saving technique)
; - Multple levels can share the same GFX Set table.
;
; UPDATE 1.1.1: now restores compatiblity with ExGFX80-FF in LM1.7
; - if you need to use genericuploader.asm for a LM1.6 ROM for whatever reason,
;   find: $0FF94F and replace with $0FF1DD
;   find: $0FF950 and replace with $0FF1DE
;
; UPDATE 1.1.2: no longer integrates LC_LZ2 optimization patch
; - also moved restored hijack to REVERT_genericuploader.asm
;   (APPLY THIS TO YOUR ROM FIRST IF YOU USED A VERSION BEFORE v1.1!!)
;
; UPDATE 1.2: new more efficient table format.
;
; **THIS PATCH WILL NOT WORK PROPERLY UNTIL YOU DO THE FOLLOWING**
; - In Lunar Magic 1.82+, under the Options menu, select 'Compression Options'
; - Select either "LC_LZ2 - Optimized for Speed" or "LC_LZ3 - Better Compression"
; - This is because the optimized decompression routines store the size of decompressed
;   data into a RAM address so that it can be determined when uploading to VRAM.
; - Otherwise, the patch will copy the wrong amount of data to the VRAM.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
header
lorom

		!GFXBuffer = $7F837E

		!LevelNum = $010B	; Address used by levelnum.ips, don't change

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; levelnum.ips (disassembly) - credit goes to BMF for this
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ORG $05D8B9
		JSR LevelNumCode

ORG $05DC46
LevelNumCode:	LDA.b $0E  		; Load level number, 1st part of hijacked code
		STA.w !LevelNum		; Store it in free RAM
		ASL A    		; 2nd part of hijacked code
		RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Hijacks
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

org $00A9DA
autoclean	JSL Main
		NOP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Main Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

freecode

reset bytes

Main:		LDA.b #$80		; \ hijacked
		STA.w $2115		; / code
		LDA.b $71		; \  return if
		CMP.b #$0A		;  | Mario is in a
		BEQ .Return		; /  no-Yoshi intro
		LDA $0100		; \
		CMP.b #$12		;  | only if at
		BEQ .InLevel		;  | beginning of
		CMP #$04		;  | level
		BNE .Return		; /

.InLevel	PHB : PHK : PLB		; back up B, K -> B
		REP #%00110000		; 16-bit A/X/Y

		LDA $010B
		LDY #$0000
.Loop		CMP.w LevelPointerDataTable+0,y
		BCC .LoopNext
		CMP.w LevelPointerDataTable+2,y
		BCS .LoopNext
		LDA.w LevelPointerDataTable+4,y
		BPL +
		TAY

-		LDX.w $0000,y		; Get VRAM Address
		BMI +			; $8000+ means get out of here; we're done.
		LDA.w $0002,y		; Get ExGFX File Number
		JSR UploadGFXFile	; Upload
		INY #4			; Next entry index
		BRA -			; loop
+
		SEP #%00110000		; 8-bit A/X/Y
		PLB			; restore B

.Return		RTL

.LoopNext	TYA
		CLC : ADC.w #$0006
		TAY
		LDA $010B
		BRA .Loop

UploadGFXFile:	PHY			; back up Y
		PHX			; back up X
		CMP.w #$0032		; \ < 32, use code
		BCC .GFX00to31		; / for GFX 00-31
		CMP.w #$0080		; \ still < 80,
		BCC .UploadReturn	; / return
		CMP.w #$0100		; \ > 100, use code
		BCS .ExGFX100toFFF	; / for 100-FFF
.GFX80toFF	AND.w #$007F		; reset most significant bit
		STA.b $8A		; \
		ASL A			;  | multiply by 3 using
		CLC			;  | shift-add method
		ADC.b $8A		; /
		TAY			; -> Y
		LDA.l $0FF94F		; \
		STA.b $06		;  | $0FF94F-$0FF950 contains the pointer
		LDA.l $0FF950		;  | for the ExGFX table for 80-FF
		STA.b $07		; /
		BRA .FinishDecomp	; branch to next step

.UploadReturn	PLX
		PLY
		RTS

.GFX00to31	TAX			; ExGFX file -> X
		LDA.l $00B992,x		; \
		STA $8A			;  | copy ExGFX
		LDA.l $00B9C4,x		;  | pointer to
		STA $8B			;  | $8A-$8C
		LDA.l $00B9F6,x		;  |
		STA $8C			; /
		BRA .FinishDecomp2	; branch to next step

.ExGFX100toFFF	;SEC			; \ subtract #$100
		SBC.w #$0100		; / SEC commented out because the BCS that branches here would only branch if the carry flag were already set
		STA.b $8A		; \
		ASL A			;  | multiply result
		CLC			;  | by 3 to get
		ADC.b $8A		;  | index
		TAY			; /
		LDA.l $0FF873		; \
		STA.b $06		;  | $0FF873-$0FF875 contans the pointer
		LDA.l $0FF874		;  | for the ExGFX table for 100-FFF
		STA.b $07		; /
.FinishDecomp	LDA.b [$06],y		; \ Get low byte.
		STA.b $8A		; / and high byte
		INC.b $06		; Increase pointer position by 1.
		BNE .NoCrossBank		; \
		SEP #%00100000		;  | allow bank crossing
		INC $08			;  | (not sure if this is necessary here)
		REP #%00100000		; /
.NoCrossBank	LDA.b [$06],y		; \ Get the high byte (again)
		STA.b $8B		; / and bank byte.
.FinishDecomp2	LDA.w #!GFXBuffer	; \ GFX buffer low
		STA.b $00		; / and high byte
		SEP #%00100000		; 8-bit A
		LDA.b #!GFXBuffer>>16	; \ GFX buffer
		STA.b $02		; / bank byte
		PHK			; \
		PEA.w .Ret1-1		;  | local JSL to LZ2 routine
		PEA $84CE		;  | (afterwards A/X/Y all 8-bit)
		JML $00B8DC		; /
.Ret1		REP.b #%00010000	; 16-bit X/Y
		PLX			; \ restore X, X is the
		STX.w $2116		; / VRAM destination
		LDA.b #%00000001	; \ control
		STA.w $4300		; / register
		LDA.b #$18		; \ dma to
		STA.w $4301		; / [21]18
		LDX.w #!GFXBuffer	; \
		STX.w $4302		;  | source
		LDA.b #!GFXBuffer>>16	;  | of data
		STA.w $4304		; /
		LDX.b $8D		; \ size of decompressed
		STX.w $4305		; / GFX File
		LDA.b #%00000001	; \ start DMA
		STA.w $420B		; / transfer
		REP #%00100000		; 16-bit A
		PLY			; restore Y
		RTS

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Level Pointers - Point to sets of graphics files to upload
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LevelPointerDataTable:
	dw $0002,$0004,IndustrialField
	dw $0006,$0007,IndustrialField
	dw $0025,$0029,IndustrialField
	dw $0136,$0137,IndustrialField
	dw $002E,$002F,Snowball
;	dw $0015,$0016,MountainLake
;	dw $0045,$0046,MountainLake
;	dw $004B,$004C,MountainLake
	dw $00C5,$00C6,IndustrialField
	dw $00DD,$00DE,LevelDDStuff
	dw $0103,$0104,L3Desert
	dw $0123,$0124,CCastleBG
	dw $0074,$0075,CCastleBG
	dw $007C,$007D,CCastleBG
	dw $0088,$008B,CCastleBG
	dw $012E,$012F,GearCastle
	dw $0145,$0146,L3Desert
	dw $0148,$0149,Circle
	dw $0171,$0172,GearCastle
	dw $000A,$000B,BlurryForestBG
	dw $00A5,$00A7,BlurryForestBG
	dw $000C,$000D,BlurryForestBG
	dw $0068,$0069,BlurryForestBG
	dw $000F,$0010,BlurryForestBG
	dw $01AA,$01AC,CaveBG1
	dw $0054,$0055,CaveBG2
	dw $0058,$0059,CaveBG2
	dw $0079,$007A,CaveBG2
	dw $0144,$0145,CaveBG2
	dw $014B,$014C,CaveBG2
	dw $01D9,$01DA,CaveBG2
	dw $012B,$012C,Rust
	dw $01DB,$01DC,Rust
	dw $01DD,$01DE,Rust
	dw $0046,$0049,Briar
	dw $0070,$0071,Flislands
	dw $011C,$011D,Flislands
	dw $013C,$013E,Flislands
	dw $013F,$0140,Flislands
	dw $0000,$0200,$0000
	


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GFX Tables - Sets of graphic files to upload, indexed by the pointer tables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LevelDDStuff:
		dw $5000,$0259
		dw $FFFF

IndustrialField:
		dw $3800,$0580
		dw $5000,$0581
		dw $FFFF
		
BlurryForestBG:
		dw $5000,$05C4
		dw $5800,$05C4
		dw $FFFF
		
CaveBG1:
		dw $5000,$05C6
		dw $FFFF
		
CaveBG2:	
		dw $5000,$05CA
		dw $5800,$05CB
		dw $FFFF
		
;MountainLake:
;		dw $5000,$0583	;TODO when I actually get these ready, append 5C1 to end of 5C0
;		dw $FFFF
		
GearCastle:
		dw $5000,$05C0
		dw $FFFF

CCastleBG:
		dw $5000,$05C2
		dw $FFFF

L3Desert:
		dw $5000,$05C5
		dw $FFFF

Circle:
		dw $5000,$05C7
		dw $FFFF
		
Snowball:
		dw $5400,$05C8
		dw $FFFF

Rust:
		dw $5000,$05D0
		dw $5800,$05D1
		dw $FFFF

Briar:
		dw $5000,$05D3
		dw $5800,$05D3
		dw $FFFF
		
Flislands:
		dw $5000,$05D5
		dw $5800,$05D6
		dw $FFFF
End:
print "Insert Size: ",bytes," bytes"