; This uses MaxTile Allocation mode, see the MaxTile documentation for more information. ; The snow effect has a lot of legacy code (from 2011) and opportunities for optimization. Try it yourself! ; 1 to enable transparency effects, 0 otherwise !ENABLE_TRANSLUCENCY = 0 ; 1 to make the snow don't update on pause, 0 otherwise. ; normally you will use '1' for regular levels and '0' for overworld. !STOP_ON_PAUSE = 1 ; Snow density or amount of snow sprites. 1 is the smallest and 128 is the maximum. ; Setting "128" will make no other sprite tiles appear since the SNES can only render ; up to 128 sprites. If you only have Mario + 1/2 enemies on your level, use 120. !SNOW_DENSITY = 48 ; 0 is max priority (appears in front of all sprites) and 3 is the lowest (appears behind all sprites) !PRIORITY = 0 ; The snowflake tile to use. !SNOWFLAKE_TILE = $A3 ; 1 for SP3/SP4, 0 for SP0/SP1 !SNOWFLAKE_SP = 1 ; RAM defines. These RAM defines are only used while the snow effect is active ; (in other words, you can reuse again when you're not using snow) !7e = $3600 !7f = $3601 !7c = $3602 !7d = $3603 !1a_copy = $3604 !1c_copy = $3606 ; MaxTile shared routines maxtile_flush_nmstl = $0084A8 maxtile_get_sprite_slot = $0084AC maxtile_get_slot = $0084B0 maxtile_finish_oam = $0084B4 init: %invoke_sa1(snowfall_init) main: if !ENABLE_TRANSLUCENCY == 1 lda.b #%00110000 sta $40 endif if !STOP_ON_PAUSE == 1 lda $73d4 bne .return endif %invoke_sa1(sa1_code) .return rtl sa1_code: phb phk plb jsr snowfall_main plb rtl snowfall_init: phb phk plb rep #$20 lda $1a sta !1a_copy lda $1c sta !1c_copy sep #$20 ; waste time and random for best results ldx #$7f - jsr sa1rand dex bpl - ; this loops though each snow flake and initializes it. ldx #$00 - rep #$20 txa asl ; x2 asl ; x4 asl ; x8 sta $00 sep #$20 jsr snowinit inx cpx.b #!SNOW_DENSITY beq + bra - + plb rtl snowfall_main: ; this asks maxtile to allocate the amount of slots requested ; which on this case is the amount of snowflakes. rep #$30 ldy.w #!SNOW_DENSITY lda.w #!PRIORITY jsl maxtile_get_slot sep #$30 bcs .ok ; return if maxtile refused to give the requested amount rts .ok ; copy the pointer maxtile gave, this is important since we use ; #$40 as data bank. rep #$10 ldy $3102 sty $02 ldy $3100 phb lda #$40 pha plb ; unroll macro speedup(value) lda.w *$08+$4030ca sta $0000,y lda.w *$08+$4030cb sta $0001,y lda.w *$08+$4030cd sta $0002,y lda.w *$08+$4030cc sta $0003,y phy ldy $02 lda.w *$08+$4030ce and #$01 sta $0000,y iny sty $02 ply iny iny iny iny endmacro macro loop() %speedup(!x) !x #= !x+1 endmacro ; this can be converted into a normal loop ; the advantage is that you will be able to change ; the amount of snow during the game play. !x = 0 rep !SNOW_DENSITY : %loop() plb sep #$10 lda $9d bne + ; this is used for detecting changes in the scrolling ; and apply the changes to the snow flakes. rep #$20 lda $1a sec sbc !1a_copy sta $0e lda $1c sec sbc !1c_copy sta $0c lda $1a sta !1a_copy lda $1c sta !1c_copy sep #$20 ; loop though each snow flake ldx #$00 - rep #$20 txa asl ; x2 asl ; x4 asl ; x8 sta $00 sep #$20 jsr snowcode inx cpx.b #!SNOW_DENSITY beq + bra - + rts ; A snow. ; $00-$01 = RAM ptr. !xSpeed = $4030c8,x !ySpeed = $4030c9,x !xPos = $4030ca,x !yPos = $4030cb,x !yxppccct = $4030cc,x !snowtile = $4030cd,x !free = $4030ce,x !backX = $4030cf,x macro snowinit_randomstart() phx sep #$10 jsr sa1rand rep #$10 plx endmacro snowinit: ;\ snow init phx ;| php ;| preserve x & p sei ;| rep #$10 ;| disable irq & x/y = 16-bit ldx $00 ;/ load ram pointer lda #$01 ;\ setup division sta $2250 ;/ lda #$00 sta !free %snowinit_randomstart() lda !7c clc adc #$08 eor !7d and #$07 sta !xSpeed %snowinit_randomstart() lda !7c and #$01 clc adc #!SNOWFLAKE_TILE sta !snowtile %snowinit_randomstart() lda !7c and #$01 beq .noTransparency lda.b #%00111110|!SNOWFLAKE_SP sta !yxppccct bra .skip .noTransparency lda.b #%00110000|!SNOWFLAKE_SP sta !yxppccct .skip %snowinit_randomstart() rep #$20 lda !7c and #$7fff sta $2251 lda #$5555 sta $2253 sep #$20 lda $2306 clc adc #$01 sta !ySpeed %snowinit_randomstart() lda !7c sta !xPos sta !backX %snowinit_randomstart() lda !7c sta !yPos plp plx rts ;=========================; ; Snow Frame-a-Frame Code ; ;=========================; snowcode: phx php rep #$10 ldx $00 lda !backX clc adc !xSpeed sta !backX rep #$20 and #$00ff asl a tay sep #$20 lda.w CosTable+1,y adc !xPos sta !xPos lda.w CosTable+1,y bmi + lda #$00 + adc !free sta !free lda !xPos sec sbc $0e sta !xPos xba lda !free sbc $0f sta !free rep #$20 xba cmp #$fff0 sep #$20 bpl + lda #$ff sta !xPos inc sta !free + lda !free cmp #$01 bne + lda #$ff sta !free lda #$f9 sta !xPos + lda !yPos clc adc !ySpeed sec sbc $0c sta !yPos cmp #$df bcs .Reset .nvm plp plx rts .Reset cmp #$f0 bcs .nvm jsr snowinit lda #$f9 sta !yPos plp plx rts ;=====================; ; Cossine Table ; ;=====================; CosTable: dw $0100, $0100, $0100, $00FF, $00FF, $00FE, $00FD, $00FC, $00FB, $00FA, $00F8, $00F7 dw $00F5, $00F3, $00F1, $00EF, $00ED, $00EA, $00E7, $00E5, $00E2, $00DF, $00DC, $00D8 dw $00D5, $00D1, $00CE, $00CA, $00C6, $00C2, $00BE, $00B9, $00B5, $00B1, $00AC, $00A7 dw $00A2, $009D, $0098, $0093, $008E, $0089, $0084, $007E, $0079, $0073, $006D, $0068 dw $0062, $005C, $0056, $0050, $004A, $0044, $003E, $0038, $0032, $002C, $0026, $001F dw $0019, $0013, $000D, $0006, $0000, $FFFA, $FFF3, $FFED, $FFE7, $FFE1, $FFDA, $FFD4 dw $FFCE, $FFC8, $FFC2, $FFBC, $FFB6, $FFB0, $FFAA, $FFA4, $FF9E, $FF98, $FF93, $FF8D dw $FF87, $FF82, $FF7C, $FF77, $FF72, $FF6D, $FF68, $FF63, $FF5E, $FF59, $FF54, $FF4F dw $FF4B, $FF47, $FF42, $FF3E, $FF3A, $FF36, $FF32, $FF2F, $FF2B, $FF28, $FF24, $FF21 dw $FF1E, $FF1B, $FF19, $FF16, $FF13, $FF11, $FF0F, $FF0D, $FF0B, $FF09, $FF08, $FF06 dw $FF05, $FF04, $FF03, $FF02, $FF01, $FF01, $FF00, $FF00, $FF00, $FF00, $FF00, $FF01 dw $FF01, $FF02, $FF03, $FF04, $FF05, $FF06, $FF08, $FF09, $FF0B, $FF0D, $FF0F, $FF11 dw $FF13, $FF16, $FF19, $FF1B, $FF1E, $FF21, $FF24, $FF28, $FF2B, $FF2F, $FF32, $FF36 dw $FF3A, $FF3E, $FF42, $FF47, $FF4B, $FF4F, $FF54, $FF59, $FF5E, $FF63, $FF68, $FF6D dw $FF72, $FF77, $FF7C, $FF82, $FF87, $FF8D, $FF93, $FF98, $FF9E, $FFA4, $FFAA, $FFB0 dw $FFB6, $FFBC, $FFC2, $FFC8, $FFCE, $FFD4, $FFDA, $FFE1, $FFE7, $FFED, $FFF3, $FFFA dw $0000, $0006, $000D, $0013, $0019, $001F, $0026, $002C, $0032, $0038, $003E, $0044 dw $004A, $0050, $0056, $005C, $0062, $0068, $006D, $0073, $0079, $007E, $0084, $0089 dw $008E, $0093, $0098, $009D, $00A2, $00A7, $00AC, $00B1, $00B5, $00B9, $00BE, $00C2 dw $00C6, $00CA, $00CE, $00D1, $00D5, $00D8, $00DC, $00DF, $00E2, $00E5, $00E7, $00EA dw $00ED, $00EF, $00F1, $00F3, $00F5, $00F7, $00F8, $00FA, $00FB, $00FC, $00FD, $00FE dw $00FF, $00FF, $0100, $0100 ;=====================; ; SA-1 Random Number ; ; ; ; $7c-$7d - result ; ; $7e-$7f - ram used ; ;=====================; sa1rand: phx ldx #$01 jsr .rand dex jsr .rand plx rts .rand lda !7e asl asl sec adc !7e sta !7e asl !7f lda #$20 bit !7f bcc .label1 beq .label2 bne .label3 .label1 bne .label2 .label3 inc !7f .label2 lda !7f eor !7e sta !7c,x rts