View difference between Paste ID: 3zdP8gNL and
SHOW: | | - or go back to the newest paste.
1-
1+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;
3
;; This file installs a very complex custom GFX routine
4
;; to SMAS SMB1. Ths file aims at accomplishing several
5
;; goals:
6
;;
7
;; 1) Custom GFX per level
8
;;	SMAS SMB1 uses a system to insert GFX which is designed
9
;;	to save space. This proves inefficient to the modern hacker,
10
;;	so of course, making a better GFX loading system is a must.
11
;;
12
;; 2) Allowing up to 0x1000 GFX files
13
;;	If GFX per level routine is to be created, it is obvious that
14
;;	there should be more GFX to choose from. Following Lunar Magic's
15
;;	design, the limit will be set at 0x1000 which is more than reasonable.
16
;;
17
;; 3) LZ2 Compression
18
;;	Having 0x1000 GFX files exist uncompressed is a very bad idea!
19
;;	LZ2 Compression is a popular algorithm used by SMW, Yoshi's Island,
20
;;	Zelda III, and other great SNES games. SMAS does not use this, so
21
;;	it would be smart to implement it.
22
;;
23
;; 4) Fix several problems caused by (1) through (3)
24
;;	Many issues have arisen due to installing all the previous ASM hacks.
25
;;	Most notable are any cutscene GFX (game over, time up, prelevel scene,
26
;;	save princess peach scene, etc.) So we need to fix all of that.
27
;;
28
;; That is indeed a lot to cover and the length and true complexual
29
;; nature of the GFX.asm file (and it's sibling branches) will show
30
;; that. 
31
;;
32
;; You can modify this, but be careful. A lot of what goes on in this
33
;; file is deeply integrated to other parts of the game.
34
;;
35
;; Code ©2009-2010 spel werdz rite (SWR)
36
;;
37
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
39
40
41
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
42
;;
43
;; Definitions of stuff
44
;;
45
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46
!AnimGFX1 = $7F4000		;\
47
!AnimGFX2 = $7F5000		;|RAM address locations of where
48
!AnimGFX3 = $7F6000		;|the animated GFX will be stored.
49
!AnimGFX4 = $7F7000		;/
50
51
!MainGFX = $7F8000		;This serves as a GFX "template" when doing VRAM transfers
52
53
!PlayerGFX1 = $7F8000		;Page 1 of the current player's GFX
54
!PlayerGFX2 = $7F9000		;Page 2 of the current player's GFX
55
56
!MiscGFX = $7FA000		;Holds some extra GFX data for random cutscenes
57
!PrincessGFX = $7FB000		;GFX data of the "Rescue Princess" cutscene
58
59
60
61
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
62
;;
63
;; This clears some old data and makes a 
64
;; few modications to certain bytes, as
65
;; well as jump to new routines when needed.
66
;;
67
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
68
69
;GFX Initialization Routine
70
ORG $03812B
71
	REP $59 : NOP
72
ORG $03812B
73
	JSL InitGFX
74
	
75
ORG $049266
76
	JSL LoadCutsceneGFX
77
78
ORG $049313
79
	;JSL LoadNextLevelGFX
80
81
ORG $049655
82
	REP $03 : NOP
83
	
84
;Changes which address to load the Player GFX from.
85
ORG $04D834
86
	dw !PlayerGFX1
87
ORG $04D847
88
	REP $0D : NOP
89
	LDA #$7F
90
91
ORG $04DD87
92
	db $7F
93
ORG $04DD9C
94
	db $B0
95
96
ORG $04ED2E
97
	REP $2C : NOP
98
ORG $04ED2E
99
	RTL
100
101
;Changes addresses of animation frame GFX files.
102
ORG $05E64C
103
	db $7F
104
ORG $05E654
105
	db $00
106
ORG $05E687
107
	db $7F
108
ORG $05E699
109
	db $AB
110
	
111
ORG $05E6AF
112
	REP $01CA : NOP
113
ORG $05E6B1
114
	JML LoadLevelGFX
115
116
117
118
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
119
;;
120
;; These are some fundamental data files
121
;; which insert the LZ2 data and get their pointers.
122
;;
123
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
124
incsrc SMB1/GFX/Files.asm
125
incsrc SMB1/GFX/Tables.asm
126
incsrc SMB1/GFX/Files_Locs.asm
127
incsrc SMB1/GFX/Files_Ptrs.asm
128
129
130
131
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
;;
133
;; This is the actual start of the GFX ASM hack.
134
;; It's a pretty big mess, but I've tried my best
135
;; to keep it legible.
136
;;
137
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138
ORG !GFX
139
	incsrc SMB1/GFX/LZ2.asm
140
DoDecompress:
141
	LDA.l GFX_Lo,x
142
	STA.b !LZ2_Lo
143
	LDA.l GFX_Hi,x
144
	STA.b !LZ2_Hi
145
	LDA.l GFX_Bk,x
146
	STA.b !LZ2_Bk
147
	JMP DecompressGFXPage
148
149
150
151
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
152
;;
153
;; This is a GFX Initialization routine. At the
154
;; start of a game, the standard GFX file are
155
;; loaded into the respective spots. This is
156
;; sort of the "fallback" template for all GFX.
157
;;
158
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159
	incsrc SMB1/GFX/Static.asm
160
InitGFX:
161
	PHB
162
	PHP
163
	PHK
164
	PLB
165
	REP #$10
166
	SEP #$20
167
168
	LDA.b #$80				;\
169
	STA.w $2115				;|This mostly just sets up some pre-DMA
170
	LDA.b #$7F				;|trasnfer stuff, like disabling interrupts
171
	STA.w $4304				;|and selecting transfer locations.
172
	STA.b !Raw_Bk				;|
173
	LDX.w #$1801				;|
174
	STX.w $4300				;|
175
	LDX.w #!MainGFX				;|
176
	STX.b !Raw_Lo				;/
177
	
178
	LDY.w #$0010
179
-
180
	LDX.w InitGFX_Table1,y			;\
181
	JSR DoDecompress			;|This nifty little loop gets the default GFX files
182
	LDX.w InitGFX_Table2,y			;|from InitGFX_Table1, decompresses their GFX, stores
183
	STX.w $2116				;|it !MainGFX, then sets up a DMA transfer to a location
184
	LDX.w #!MainGFX				;|selected by InitGFX_Table2. The idea is to set up the
185
	STX.w $4302				;|default GFX for the game.
186
	LDX.w #$1000				;|See SMB1/GFX/Static.asm for tables.
187
	STX.w $4305				;|
188
	LDA.b #$01				;|
189
	STA.w $420B				;|
190
	REP 2 : DEY				;|
191
	BPL -					;/
192
	
193
	LDX.w #!MiscGFX				;\
194
	STX.b !Raw_Lo				;|!MiscGFX is a RAM location with a GFX file designed to never
195
	LDX.w #$0026				;|change (unless you want it to). The purpose of this DMA transer
196
	JSR DoDecompress			;|is to take the 2BPP GFX from GFX file $26 and permanently save it.
197
	LDX.w #$5000				;|It's used mostly in the status bar, but also for the water animation
198
	STX.w $2116				;|in underwater levels.
199
	LDX.w #!MiscGFX+$800			;|Because it's only $800 bytes, I'm considering making this a raw GFX
200
	STX.w $4302				;|ROM location to free up some RAM. You free to modify this and do so
201
	LDX.w #$0800				;|yourself. Please don't ask me how though. Like I said before, modifcation
202
	STX.w $4305				;|is for experience users only.
203
	LDA.b #$01				;|
204
	STA.w $420B				;/
205
	
206
	LDY.w #$0006
207
-
208
	LDX.w AnimGFX_Table1,y			;\
209
	STX.b !Raw_Lo				;|This routine is very straightforward: Load the animated GFX RAM location,
210
	LDX.w AnimGFX_Table2,y			;|then the GFX file to store there, then just decompress it. Note that we're
211
	JSR DoDecompress			;|not doing a DMA transfer. Just writing the animated GFX to the desired RAM location.
212
	REP 2 : DEY				;|The game takes care of the actual anmation when the event occurs.
213
	BPL -					;/
214
	
215
	LDX.w #!PrincessGFX			;\
216
	STX.b !Raw_Lo				;|This is also straightforward: Take GFX file $000E (saved princess cutscene GFX) and
217
	LDX.w #$000E				;|save it to #!PrincessGFX. The game will load it when the even occurs.
218
	JSR DoDecompress			;/
219
	
220
	PLP
221
	PLB
222
	RTL
223
224
225
226
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
227
;;
228
;; This routine aims at inserting custom GFX
229
;; into the DMA when they are needed. The only
230
;; two cutscenes I've noticed are needed are
231
;; Game Over and Time Up screens.
232
;;
233
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234
LoadCutsceneGFX:
235
	PHP
236
	PHB
237
	PHK
238
	PLB
239
	REP #$10
240
	SEP #$20
241
	
242
	LDA.b #$80				;\
243
	STA.w $2115				;|Sets up a DMA transfer for the cutscene.
244
	LDA.b #$7F				;|If you are unsure why !MainGFX is always used,
245
	STA.w $4304				;|it's because it's not a static RAM table. It's use
246
	STA.w !Raw_Bk				;|is to have a GFX page exist for a DMA transfer, so it
247
	LDX.w #$1801				;|can be used pretty much at any time. The othr RAM tables
248
	STX.w $4300				;|however are supposed to be static (you can change them
249
	LDX.w #!MainGFX				;|if you have a way which suites what you need done).
250
	STX.b !Raw_Lo				;|
251
	STX.w $4302				;/
252
	
253
	LDX.w #$0011				;GFX011 is the Game Over/Time Up GFX
254
	JSR DoDecompress
255
	LDX.w #$3400
256
	STX.w $2116
257
	LDX.w #$1000
258
	STX.w $4305
259
	LDA.b #$01
260
	STA.w $420B
261
	
262
	LDX.w #!MainGFX+$800
263
	STX.w $4302
264
	LDX.w #$001B				;GFX01B also has Game Over/Time Up GFX
265
	JSR DoDecompress
266
	LDX.w #$2C00
267
	STX.w $2116
268
	LDX.w #$0800
269
	STX.w $4305
270
	LDA.b #$01
271
	STA.w $420B
272
	
273
	PLB
274
	PLP
275
	RTL
276
277
278
279
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
280
;;
281
;; This is the grand daddy of the custom GFX loading.
282
;; This routine is the core of getting all GFX from pointers
283
;; and loading them to their respective levels. So as
284
;; you will guess, it's pretty long and probably a little
285
;; complex. But it shouldn't be too bad to get through
286
;; most of it.
287
;;
288
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
289
LoadLevelGFX:
290
	PHP
291
	PHB
292
	PHK
293
	PLB
294
	REP #$10
295
	SEP #$20	
296
	PEI (!Raw_Lo)				;\
297
	PEI (!Raw_Bk)				;|These values need to be re-pushed onto the stack.
298
	PEI (!Pointer_Hi)			;/
299
	
300
	LDX.w #!MainGFX				;\
301
	STX.b !Raw_Lo				;|Sets up !MainGFX for several DMA Transfers.
302
	LDA.b #$7F				;|The objective of the following loop is to load
303
	STA.b !Raw_Bk				;|the level pointer, determine the GFX file, decompress
304
	STA.w $4304				;|that GFX page, and do a DMA transfer to it's respective
305
	LDA.b #$80				;|location. Then repeat for all level GFX (objects and sprites).
306
	STA.w $2115				;|This was not an easy algorithm to set up and I'm sure
307
	LDX.w #$1801				;|it could use some work.
308
	STX.w $4300				;/
309
310
	LDY.w #$000E
311
-
312
	REP #$30				;We keep the REP in the loop because the status register will change.
313
	TYA					;\
314
	REP 7 : ASL A				;|The pointer is now a multiple of $100 bytes (for each loop index).
315
	STA.b !Pointer_Lo			;/
316
	LDA.w $0750				;\
317
	AND.w #$007F				;|We now add to the pointer index the current level value.
318
	CLC					;|We're not done yet though, there are other factors at play.
319
	ADC.b !Pointer_Lo			;|
320
	STA.b !Pointer_Lo			;/
321
	LDA.w $07FC				;\
322
	AND.w #$0002				;|$07FC is the "Difficult Quest" flag. I've made some major modifications
323
	BEQ +					;|to allow for a whole new quest (set by 2 or 3). Therefore, levels in this
324
	LDA.w #$0080				;|region will add $80 bytes to the index
325
	CLC					;|
326
	ADC.b !Pointer_Lo			;/
327
+
328
	ASL A					;We double the index because it's relative to words, not bytes.
329
	TAX
330
	LDA.l GFX_Table1,x			;\
331
	CMP.w #$FFFF				;|A lot is going on here, so it may be a tad confusing. First, we check
332
	BEQ +					;|GFX_Tabale1 indexed by the conditions we made earlier. If the value is
333
	AND.w #$0FFF				;|$FFFF, that means no value has been selected so we go to the default (which
334
	TAX					;|is selected from GFX_Table3, which matches InitGFXTable1, but with switched
335
	BRA ++					;|values to match the indexes). If it isn't $FFFF, then our value is the GFX
336
+						;|index, then we move on to decompress it.
337
	LDX GFX_Table3,y			;/
338
++
339
	SEP #$20				;This is why we keep the REP #$30 in the loop at the beginning.
340
	JSR DoDecompress			;\
341
	LDX.w GFX_Table2,y			;|We now have the GFX page decompressed to !MainGFX. So we look up
342
	STX.w $2116				;|GFX_Table2 to determine which VRAM address we will store it to.
343
	LDX.w #!MainGFX				;|The rest is just a standard DMA transfer.
344
	STX.w $4302				;|
345
	LDX.w #$1000				;|
346
	STX.w $4305				;|
347
	LDA.b #$01				;|
348
	STA.w $420B				;/
349
	REP 2 : DEY
350
	BPL -
351
	
352
	REP #$30				
353
	LDA.w $0750				;Now you may be wondering what this extra routine is for when it pretty much
354
	AND.w #$007F				;follows the pattern of the loop that came before it. The third GFX file in VRAM
355
	STA.b !Pointer_Lo			;is the layer 2 BG for levels. In SMAS SMB1, bonus levels switch the BG if you are
356
	LDA.w $07FC				;Luigi. So what this does search for a flag in the ObjGFX_Table3 table (set from $1000).
357
	AND.w #$0002				;If it is set, the routine checks if luigi is playing. If both are true, it increments
358
	BEQ +					;the GFX file and selects that one instead. You can use this to your advantage. If you
359
	LDA.w #$0080				;want to change the BG for when it's Luigi, make sure the next GFX file is the desired one.
360
	CLC					;You can use example of this code for other cool effects too. =P
361
	ADC.b !Pointer_Lo		
362
+
363
	ASL A
364
	TAX
365
	LDA.w ObjGFX_Table3,x
366
	CMP.w #$FFFF
367
	BEQ LoadPlayerGFX
368
	PHA
369
	AND.w #$0FFF
370
	TAX
371
	PLA
372
	AND.w #$1000
373
	STA.w $02F8
374
	BEQ +
375
	LDA.w $0EC2
376
	AND.w #$00FF
377
	BEQ +
378
	INX
379
+
380
	SEP #$20
381
	JSR DoDecompress
382
	LDX.w #$2000
383
	STX.w $2116
384
	LDX.w #!MainGFX
385
	STX.w $4302
386
	LDX.w #$1000
387
	STX.w $4305
388
	LDA.b #$01
389
	STA.w $420B
390
391
LoadPlayerGFX:
392
	LDY.w #$0002
393
-
394
	LDX.w PlayerGFX_Table1,y		;The objective of this loop is to determine which player
395
	STX.b !Raw_Lo				;is selected, obtain the GFX for said player, then store it
396
	LDX.w PlayerGFX_Table2,y		;!PlayerGFX1 and !PlayerGFX2. Note that the two values don't
397
	LDA.w $0EC2				;mean GFX for Player 1 and Player 2 repectively. The player GFX
398
	AND.b #$FF				;take two pages. So the addresses represent the first and second
399
	BEQ  +					;page respectively. Thus, it is necessarry to call this at level
400
	LDX.w PlayerGFXTable2+4,y		;load and not during the Initialization routine.
401
+						;This is another event when I feel I should have raw GFX and just
402
	CPX.w #$FFFF				;handle it during the init routine. It would free up more RAM and
403
	BEQ +					;save on loading time.
404
	JSR DoDecompress
405
+
406
	DEY
407
	DEY
408
	BPL -
409
410
	PLX : STX !Pointer_Hi			;\
411
	PLX : STX !Raw_Bk			;|Pulling the orignal value back from the stack
412
	PLX : STX !Raw_Lo			;/
413
	PLB
414
	PLP
415
	RTL