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 |