• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[ASM & Hex] Creating a new day/night system (using colour filters in Fire Red)

  • 13
    Posts
    7
    Years
    • Seen Sep 12, 2019
    Hi folks,

    I'm looking to develop my own day/night system that checks a statusbyte and applies a coloured filter depending on the time of day. This is how the widely used DNS tool works.

    I can't work out how to tint the screen colour on Fire Red using ASM at all though, despite looking through the IDB, checking how the DNS tool itself works etc. Could anyone here help me understand how to apply a filter to the screen?

    Thank you!
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Hi folks,

    I'm looking to develop my own day/night system that checks a statusbyte and applies a coloured filter depending on the time of day. This is how the widely used DNS tool works.

    I can't work out how to tint the screen colour on Fire Red using ASM at all though, despite looking through the IDB, checking how the DNS tool itself works etc. Could anyone here help me understand how to apply a filter to the screen?

    Thank you!

    The existing tint functions only get applied to the palette when the palette is initially loaded, which doesn't really help if you want the palette to change over time (you'll only notice a change when the map is refreshed).

    What you need to do is make a function that acts similarly to the function that applies the built-in tints (load_palette_3) but instead make it run every frame. Basically this means you must loop through all the colours in the in-memory palette copy (palette_bg_unfaded and palette_obj_unfaded) and apply your filter to each colour. The engine will take care of copying these colours to palette RAM (in the vblank handler).

    Once you have written this function to modify the palette, you can make it get called every frame by hooking into c1_overworld_normal (just before it returns) and adding a call to your function.
     

    Deokishisu

    Mr. Magius
  • 990
    Posts
    18
    Years
    What you need to do is make a function that acts similarly to the function that applies the built-in tints (load_palette_3) but instead make it run every frame. Basically this means you must loop through all the colours in the in-memory palette copy (palette_bg_unfaded and palette_obj_unfaded) and apply your filter to each colour. The engine will take care of copying these colours to palette RAM (in the vblank handler).

    Once you have written this function to modify the palette, you can make it get called every frame by hooking into c1_overworld_normal (just before it returns) and adding a call to your function.

    Related but unrelated, can we use the built-in tint functionality to overwrite (instead of tint) specific colors in a palette when (re)loaded with a minor rewrite? Or would the palette be overwritten by GameFreak's engine on the next VBlank, requiring a different approach? I know that messing with palettes can be tricky because of how GameFreak handles them.
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Related but unrelated, can we use the built-in tint functionality to overwrite (instead of tint) specific colors in a palette when (re)loaded with a minor rewrite? Or would the palette be overwritten by GameFreak's engine on the next VBlank, requiring a different approach? I know that messing with palettes can be tricky because of how GameFreak handles them.

    Yes you can do that. It will not be overwritten on vblank because it's (palette_xxx_unfaded) a copy of the palette memory in EWRAM, not in Palette RAM . The only way it will be overwritten is if there is another routine that gets run later that writes to the same buffer.

    Basically, GameFreak handled the palettes by having two buffers in EWRAM: palette_xxx_unfaded and palette_xxx_faded. The palette_xxx_unfaded is the working buffer and this is where everything loads palettes into. Near the end of a callback, the function 080704D0 (fade_and_return_progress_probably) is usually called. This handles the fadescreen-like commands and will fade every colour in palette_xxx_unfaded to a given fade colour (usually black or white, but it can be any colour). This faded copy gets written to palette_xxx_faded. Finally, when the vblank handler is called this usually calls the function 08070474 (gpu_pal_upload). This function copies the palette_xxx_faded buffer to palette RAM (and applies handles some specialised palette fading cases with the built-in IO register-controlled blending).

    In case you're wondering, this practice of maintaining a buffer for palettes, tilemaps, etc. is quite common (and actually is the recommended approach). It's called double buffering, where a working buffer is used to write images during the frame and then swapped with an active buffer (copied to) during vblank so that the display never shows the buffer being worked on and thus causing screen tearing. Therefore, as long as you write to the working buffer and not directly to Pallete RAM/VRAM/whereever you should be good. It's just an issue of reading the code and figuring out where that buffer is.
     
  • 13
    Posts
    7
    Years
    • Seen Sep 12, 2019
    The existing tint functions only get applied to the palette when the palette is initially loaded, which doesn't really help if you want the palette to change over time (you'll only notice a change when the map is refreshed).

    What you need to do is make a function that acts similarly to the function that applies the built-in tints (load_palette_3) but instead make it run every frame. Basically this means you must loop through all the colours in the in-memory palette copy (palette_bg_unfaded and palette_obj_unfaded) and apply your filter to each colour. The engine will take care of copying these colours to palette RAM (in the vblank handler).

    Once you have written this function to modify the palette, you can make it get called every frame by hooking into c1_overworld_normal (just before it returns) and adding a call to your function.

    Alright, thanks. So this function causes the palettes to reload whenever it is run? As for running it every frame, there is a frame counter in the game time update function at 05487C - would I be able to hook into the function and run it like that?
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Alright, thanks. So this function causes the palettes to reload whenever it is run? As for running it every frame, there is a frame counter in the game time update function at 05487C - would I be able to hook into the function and run it like that?

    No, the palettes are loaded from that buffer every frame. You just need to write a function to write to that buffer every frame, by hooking into a function.

    You don't want to hook into the main loop (i.e., at 05487C), because you only want D/N to work on the overworld. If you hooked there it would apply that to the titlescreen, intro, battles, pokedex and all that which is obviously not good. Use c1_overworld_normal - it's called every frame when you're on the overworld.
     
    Back
    Top