• 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.

Code: ASM Resource Thread

MUGCAP

Creator of PLA GBA and PKMN F&E Rom Hacks
2
Posts
1
Years
    • Seen May 5, 2024

    Changing the Player's Overworld ingame


    Intro:

    I recently made this routine, it's kind of limited in the sense that you can only be change to 30 different overworlds (excluding the special version of the default characters). While it is limited, I don't really think that that's a problem (you'd probably only be OWs swapping to 2-3 different OWs the entire game anyways, so unless you wanted to player to play as more than 30 characters, this routine will work just fine for you). It's also a little "smaller" in comparison to JPAN's 6 seperate routines which he used (though in his favor, I don't think his limits the amount like mine). I blame the table, it's weird. Actually the whole overworld loading thing is weird..it's done in like 9 places lol.

    I should also note that if the OW you're changing to doesn't have a running frame, things are going to look weird when you try to run~

    How to insert:

    Compile into free space the following routine:
    Spoiler:


    Now navigate to 0x5CA4C and insert the following byte changes:
    Code:
    00 48 00 47 XX XX XX 08
    Where XX XX XX is where you inserted this routine +1.


    Usage:

    The routine requires two conditions to toggle.
    1) Flag 0x406 is set
    2) Var 0x8000 is not 0xFF

    As you may have guessed you need to set variable 0x8000 to a value which matches the overworld you want the player to transform into. Please note that for the effect to happen, you need to warp first.
    Here's a list of values and their corresponding sprite to the left:
    Spoiler:

    While no particular value will cause a crash, I've excluded values which are "repeated" OWs. If you experience bugs, use it in conjunction with the backsprite hack I made. If you still have bugs, report them here!

    I have a small problem. If it is resolved, I will be able to continue the development of my Hack Rom. A bug happens, when I open any menu. The player's Sprite returns to the original (but with the new palette changed by the routine.) I searched a lot but didn't find any solution. I am very grateful if you can help me.
     

    ThePuffinMan

    Some person who plays games
    13
    Posts
    6
    Years
  • Hello. I've recently got interested in FireRed ROM hacking and I'm trying to make my own ROM hack. I have followed Blah's beginner ASM tutorial about inserting ASM routines into my ROM. I have gone up to the last step of that tutorial where I have to use the "callasm" command and run my routine from my ROM. I spent hours researching online but I cannot find an answer. My query is, how do I insert this ability effect routine into my ROM hack? I am using Mr. DollSteak's ROM base v1.5a, and the routine is adding the abilities Toxic Boost and Flare Boost from the Ability Resource Thread. I am also using karatekid552's THUMB editor. So far, I have tested the compilation, created a .bin file and have inserted the script into my ROM at offset 0xC4F004 because I was told you must reverse the bytes. Assistance is much appreciated, thank you.

    The script code is in the spoiler below:

    Spoiler:
     
    31
    Posts
    3
    Years
  • Stats on the Pokédex screen replacing the weight comparison


    ASM Resource Thread
    ASM Resource Thread
    ASM Resource Thread

    Code:
    .thumb
    
    @ credits to DoesntKnowHowToPlay and Squeetz
    
    .equ rom, 0x08000000
    .equ offset, 0x
    
    .org 0x10611E, 0xFF
    	.byte 0x43, 0xE0
    	
    .org 0x106370, 0xFF
    	.byte 0x0, 0x48, 0x0, 0x47
    	.word main + rom + 1
    
    .org 0x106530, 0xFF
    	.byte 0xCE, 0xE0
    	
    .org 0x452200, 0xFF
    	.byte 0xA
    
    .org offset, 0xFF
    main:
        mov r5, #4
        str r5, [sp]
        str r6, [sp, #4]
        mov r0, r10
        cmp r0, #0
        beq unknown_base_stats
    
    hp:
        mov r0, #0
        bl print_stat
        mov r3, #4 @ y co-ord
        str r3, [sp]
        mov r3, #0 @ x co-ord
        ldr r5, write_method
        bl call_via_r5
        
    atk:
        mov r0, #1
        bl print_stat
        mov r3, #4 @ y co-ord
        str r3, [sp]
        mov r3, #0x2C @ x co-ord
        ldr r5, write_method
        bl call_via_r5
         
    def:
        mov r0, #2
        bl print_stat
        mov r3, #18 @ y co-ord
        str r3, [sp]
        mov r3, #0 @ x co-ord
        ldr r5, write_method
        bl call_via_r5
         
    spa:
        mov r0, #4
        bl print_stat
        mov r3, #18 @ y co-ord
        str r3, [sp]
        mov r3, #0x2C @ x co-ord
        ldr r5, write_method
        bl call_via_r5
         
    spd:
        mov r0, #5
        bl print_stat
        mov r3, #32 @ y co-ord
        str r3, [sp]
        mov r3, #0 @ x co-ord
        ldr r5, write_method
        bl call_via_r5
         
    spe:
        mov r0, #3
        bl print_stat
        mov r3, #32 @ y co-ord
        str r3, [sp]
        mov r3, #0x2C @ x co-ord
        ldr r5, write_method
        bl call_via_r5
        
    print_ability_one:
        ldr r0, [sp, #0x1C]
        mov r3, #0x1C
        mul r0, r3
        ldr r1, base_stats
    	ldr r1, [r1]
        mov r3, #0x16
        add r1, r1, r3
        add r1, r0, r1
        ldr r3, abilities
    	ldr r3, [r3]
        ldrb r2, [r1]
        mov r1, #0xD
        mul r1, r2
        add r2, r1, r3    
        ldr r1, [r7]
        add r1, #0x53
        ldrb r1, [r1]
        mov r0, r1
        mov r1, #0
        mov r3, #46
        str r3, [sp]
        mov r3, #0
        ldr r5, write_method
        bl call_via_r5
        
    print_ability_two:
        ldr r0, [sp, #0x1C]
        mov r3, #0x1C
        mul r0, r3
        ldr r1, base_stats
    	ldr r1, [r1]
        mov r3, #0x16
        add r1, r1, r3
        add r1, r0, r1
        ldrb r2, [r1, #1]
        ldrb r5, [r1, #0]
        ldr r3, abilities
    	ldr r3, [r3]
        cmp r2, r5
        beq return
        cmp r2, #0
        beq return
        mov r1, #0xD
        mul r1, r2
        add r2, r1, r3
        
        ldr r1, [r7]
        add r1, #0x53
        ldrb r1, [r1]
        mov r0, r1
        mov r1, #0
        mov r3, #60
        str r3, [sp]
        mov r3, #0
        ldr r5, write_method
        bl call_via_r5
        b return
        
    unknown_base_stats:
        mov r0, r1
        mov r1, #0
        ldr r2, str_unknown
        mov r3, #4 @ y co-ord
        str r3, [sp]
        mov r3, #0 @ x co-ord
        ldr r5, write_method
        bl call_via_r5
        
    return:
        mov r5, #0
        ldr r0, return_loc
        bx r0
        
    print_stat:
        push {lr}
        ldr r3, [sp, #0x20]
        mov r1, #0x1C
        mul r3, r1
        ldr r2, base_stats
    	ldr r2, [r2]
        add r2, r3
        add r2, r0
        ldrb r1, [r2]
        mov r4, r0
        ldr r0, fcode_buffer2
        mov r3, #0
        cmp r1, #99
        bhi no_leading_zeroes
        cmp r1, #9
        bhi one_leading_zero
    
    two_leading_zeroes:
        str r3, [r0]
        add r0, #1
    
    one_leading_zero:
        str r3, [r0]
        add r0, #1
    
    no_leading_zeroes:
        mov r3, #3
        ldr r5, int_to_str
        bl call_via_r5
        
        mov r2, r4
        ldr r0, displayed_string
        ldr r1, str_table
        lsl r2, r2, #2
        add r1, r2
        ldr r1, [r1]
        ldr r5, fdecoder
        bl call_via_r5
        ldr r1, [r7]
        add r1, #0x53
        ldrb r1, [r1]
        mov r0, r1
        mov r1, #0
        ldr r2, displayed_string
        pop {r5}
        
    call_via_r5:
        bx r5
    
    .align 2
        base_stats:             .word 0x1BC + rom
        abilities:              .word 0x1C0 + rom
        str_table:              .word table + rom
        str_unknown:            .word capture + rom
        fcode_buffer2:          .word 0x02021CD0
        displayed_string:       .word 0x02021D18
        int_to_str:             .word 0x08008E78|1
        fdecoder:               .word 0x08008FCC|1
        write_method:           .word 0x081047C8|1
        return_loc:             .word 0x08106380|1
    table:
    	.word stat_hp + rom
    	.word stat_atk + rom
    	.word stat_def + rom
    	.word stat_spe + rom
    	.word stat_spa + rom
    	.word stat_spd + rom
    	
    stat_hp:
    	.byte 0xC2, 0xCA, 0x0, 0x0, 0xFD, 0x2, 0xFF
    	
    stat_atk:
    	.byte 0xBB, 0xE8, 0xDF, 0x0, 0xFD, 0x2, 0xFF 
    	
    stat_def:
    	.byte 0xBE, 0xD9, 0xDA, 0x0, 0xFD, 0x2, 0xFF
    	
    stat_spe:
    	.byte 0xCD, 0xE4, 0xD9, 0x0, 0xFD, 0x2, 0xFF
    	
    stat_spa:
    	.byte 0xCD, 0xE4, 0xBB, 0x0, 0xFD, 0x2, 0xFF
    	
    stat_spd:
    	.byte 0xCD, 0xE4, 0xBE, 0x0, 0xFD, 0x2, 0xFF
    	
    capture:
    	.byte 0xBD, 0xD5, 0xE4, 0xE8, 0xE9, 0xE6, 0xD9, 0x0, 0xDA, 0xE3, 0xE6, 0xFE, 0xE1, 0xE3, 0xE6, 0xD9, 0x0, 0xDD, 0xE2, 0xDA, 0xE3, 0xE6, 0xE1, 0xD5, 0xE8, 0xDD, 0xE3, 0xE2, 0xAB, 0xFF

    Thanks to DoesntKnowHowToPlay for the base routine which I slightly edited / optimised, and to Squeetz for making the routine into a form that can be applied as a patch.

    is there a way to implement this also on emerald sir?....
     

    sylingga

    Red Everywhere
    86
    Posts
    10
    Years
    • Seen May 6, 2024
    Is there any ASM that can provide mirror battle?
    that copied our party pokemon, then battle with same our pokemon.
     
    4
    Posts
    1
    Years
    • Seen Jul 6, 2023

    Temporarily disabling EXP gains from battle


    It was brought to my attention by some requesters that for their battle/tournament events they wouldn't want their Pokemon leveling up. This routine disables the exp gains in battle. Note that the player can still use stuff like Rare Candy to level. The fix to that is exactly the same as this, but with slight modifications. I hope you don't give the player a chance to rare candy in battle though or I will go to your hack's thread and severly criticize your lack of common sense :c


    How to insert:

    Compile and insert the following routine into free space:

    Spoiler:


    Now navigate to 0x21CFA and insert the following byte changes:
    Code:
    00 00 00 49 08 47 XX XX XX 08
    Where XX XX XX is the reverse hex pointer to where you inserted this routine +1.

    Usage:

    If flag 0x202 is set, the EXP gains will be disabled. Obviously, to re-enable just clear the flag.
    Currently the way I'm doing this is by making the game act like the player's party is already max level, so therefore they don't gain exp :)
     
    4
    Posts
    1
    Years
    • Seen Jul 6, 2023
    After testing out I found that this routine doesnt work as intended. After every battle the game just restarts. With or without flag set doesnt matter.

    I just found out im using the wrong rom as base. In FireRed 1.0 it should work fine but not in BPRE
    Does someone know where the battle scripts in BPRE are so I can find a solution myself?
     
    Last edited:
    192
    Posts
    6
    Years
  • Hello. I've recently got interested in FireRed ROM hacking and I'm trying to make my own ROM hack. I have followed Blah's beginner ASM tutorial about inserting ASM routines into my ROM. I have gone up to the last step of that tutorial where I have to use the "callasm" command and run my routine from my ROM. I spent hours researching online but I cannot find an answer. My query is, how do I insert this ability effect routine into my ROM hack? I am using Mr. DollSteak's ROM base v1.5a, and the routine is adding the abilities Toxic Boost and Flare Boost from the Ability Resource Thread. I am also using karatekid552's THUMB editor. So far, I have tested the compilation, created a .bin file and have inserted the script into my ROM at offset 0xC4F004 because I was told you must reverse the bytes. Assistance is much appreciated, thank you.

    The script code is in the spoiler below:

    Spoiler:

    I can help you via Discord if you want.
    You will need to copy from .text to .Return2: .word 0x0803F0E1
    Paste in the THUMB editor Compiler tool.
    And under the "Compile" option, select the option for "output to bin".

    Open your file in a hexadecimal editor (I ask you to use Hex Maniac Advance) and you can paste it in your hack (in a safe address, with FFs).

    In the address, 03F0C4 (Use Ctrl + G and paste this in HMA), insert 00 48 00 47 <address that you inserted the compiled bin routine(Maybe the last byte you must insert a +1 byte)> [When you use "<", HMA recognize as anchor to a address. Close with ">"]
     
    7
    Posts
    5
    Years
    • Age 32
    • Seen Apr 17, 2024
    For fire red
    does anyone know of a way to talk to an NPC and change the pokemon's ability to its hidden ability?
    Thank you
     
    Last edited:

    jmynes

    Jordank
    4
    Posts
    1
    Years
  • Unfortunately, all three links under Evolution Moves in the thread OP go to the same post:

    This post has no archive, and is linked to a 404 on github

    Ghoulslash posted an updated version of one of the routines a few posts lower on the same page, it's maybe possible to recreate the scripts, but I'm unfamiliar with them.
     
    42
    Posts
    8
    Years
    • Seen May 15, 2024
    I sort of understand how Move Tutors work, but I wanted to make an 'improved' Move Tutor in Fire Red that worked like a shop...

    Instead of only being able to teach one move, they would have a list of moves (I think I would need to use the normal Move Tutor list though just to ensure learn capability? Though I would be looking to expand the list of tutor moves with HMA)
    Would it be possible to ASM a Move Tutor 'shop' that would allow your Pokémon to learn moves for a certain price?

    (I also wanted to make an item you could give them that would remove the price)
     
    Last edited:
    4
    Posts
    160
    Days
    • Seen May 14, 2024
    May some tell how to run asm every step in Fire Red V1.0
    I tried changing bytes at 0x6D5F6 with 01 4A 10 47 00 00 XX XX XX 08
    BUT It didn't went well either game freeze or refresh when I move in game
    Here in this thread I tried Blah's HP regeneration but when I moved game freeze Please tell me why and how to fix it
     
    42
    Posts
    8
    Years
    • Seen May 15, 2024
    So, I made a new item to use in place of the field move Fly

    Currently, it works via directly calling C4EF9 as its field effect (the part of Fly that brings up the map, and one selects a location to go to)
    However, there are two problems I need help solving:

    1. Because it calls the Fly script, it also calls the Fly animation - but the Pokémon shown is always the Pokémon shown in the first slot of the party. I want to change this so using the item shows a 'special' Charizard sprite, but without the Pokéball animation (preferably while keeping the regular animation of Fly in case anyone uses the field move)
    2. Whilst Fly outright cannot be used indoors, the item can - though when a location is selected it goes back to the Pokémon menu instead of executing the Fly animation. However, with certain map types one can still use the item to Fly even if Fly itself does not work. I need the item to outright fail if the player tries using it in an inappropriate location (maybe by saying something like "there's no signal!")

    This probably might have been easier to do via C code, but I need it in ASM form (since I'm not using the decomp)



    ...also, I think I found a problem with the custom givepokemon command (or maybe it is the initial "custom moves" routine you need to place somewhere)? I don't know if it's the routine itself or the way my particular ROM is interacting with it (I have an expanded moves table, though I can give Pokémon with custom moves after Psycho Boost without issue), but...

    If a Pokémon has less than four unique level up moves, if it is encountered (wild or Trainer without custom moves) or given at a level where it would know all of those moves already, then the move slots after its last known move do strange things.

    e.g. if it only has one unique move, then move two becomes glitched up (I assume it is reading the terminator bytes FFFFFFFF as a move somehow) and then move 3 and 4 are taken from presumably the next Pokémon (it seems to be Wobbuffet, judging by Counter and Mirror Coat)
    ASM Resource Thread

    Caterpie would have Tackle, String Shot, FFFF and Harden (from Metapod)

    I have not encountered any problems when levelling up Pokémon to even over level 100 - only directly obtaining or encountering them at a high enough level.

    Spoiler:
     
    Last edited:
    9
    Posts
    7
    Years
    • Seen yesterday
    The following development is done by DoesntKnowHowToPlay, and I have no part in it. This has been re-posted as the original link had died.

    [FR] Displaying IV's on the stat screen
    A small piece of ASM that allows you to view IV's in the Pokémon stat screen.

    ASM Resource Thread
    ASM Resource Thread
    ASM Resource Thread

    • Step 1 - Image insert
    First, insert the following image using NSE or TileMolester. Remember the address where you put it:
    Spoiler:


    • Step 2 - Actual ASM
    Next you will need to insert the following ASM. It doesn't matter where, but do remember where you put it.
    Code:
    cmp r0, #0x0
    beq Abort
    cmp r0, #0x3
    bgt Abort
    cmp r0, #0x1
    bne StandardAbort
    b Start
    
    Abort:
    ldr r1, .AbortAddr
    bx r1
    
    StandardAbort:
    ldr r1, .StandardAbortAddr
    bx r1
    
    .align 2
    .AbortAddr: .word 0x08137bfd
    .StandardAbortAddr: .word 0x08137bf9
    
    Start:
    ldr r0, .ActiveMonPtr
    ldr r1, .ActiveOffset
    ldr r0, [r0, #0x0]
    add r6, r0, r1
    
    add sp, #-0x18
    
    HPIV:
    mov r0, r6
    mov r1, #0x27
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x6
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    
    AtkIV:
    mov r0, r6
    mov r1, #0x28
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x17
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    
    DefIV:
    mov r0, r6
    mov r1, #0x29
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x24
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    SAtkIV:
    mov r0, r6
    mov r1, #0x2B
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x31
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    
    SDefIV:
    mov r0, r6
    mov r1, #0x2C
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x3E
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    
    SpeedIV:
    mov r0, r6
    mov r1, #0x2A
    bl Decrypter
    
    mov r5, r0
    lsr r5, r5, #0x1
    mov r0, #0x40
    mul r5, r0, r5
    
    mov r1, #0x80
    str r1, [sp, #0x0]
    str r1, [sp, #0x4]
    
    #x, y position
    mov r2, #0xC
    str r2, [sp, #0x8]
    mov r1, #0x4B
    str r1, [sp, #0xc]
    
    #x, y size
    mov r2, #0x10
    str r2, [sp, #0x10]
    mov r1, #0x8
    str r1, [sp, #0x14]
    
    mov r0, #0x3
    ldr r1, .GraphicAddr
    add r1, r5
    mov r2, #0x0
    mov r3, #0x0
    bl GraphicHandler
    
    
    
    add sp, #0x18
    b Abort
    
    
    GraphicHandler:
    ldr r4, .HandlerAddr
    bx r4
    
    Decrypter:
    ldr r2, .DecrypterAddr
    bx r2
    
    .align 2
    .GraphicAddr: .word [B]0x08XXXXXX[/B]
    .HandlerAddr: .word 0x080041f1
    .ActiveMonPtr: .word 0x0203b140
    .ActiveOffset: .word 0x00003290
    .MonIndex: .word 0x0203b16c
    .DecrypterAddr: .word 0x0803FBE9


    Replace the 0x08XXXXXX with the address of the image you just inserted (no +1 or reverse needed).

    • Step 3 - Byte changes
    1. At 0x137BF0, place 00 49 08 47 followed by a pointer to the code you just inserted plus one (for example, if you inserted it at 0x800000, you will place 00 49 08 47 01 00 80 08 at 0x137BF0).
    2. At 0x137BE4, place 01 20 03 E0.

    Ending notes
    With that, you should be good to go. In typical Pokémon fashion, this code does not give you the specific values; it instead gives you a unique two-value range. If you want to change that it's rather easy; cut every line starting with lsr in the code and reassemble it, then adjust the image so it has 32 meaningful values instead of 16.

    Credits
    DoesntKnowHowToPlay - Actual code, image
    Lunos - He did the actual Google cache magic too find it

    Again, this is done by DoesntKnowHowToPlay, and it is not done by me. Any credit should go DoesntKnowHowToPlay, and not me.
    I've used this code in my rom hack. Stats with 0/1 IV's seem to correctly give the E- however anything else seems to produce jumbled characters. I used HexManiacAdvanced to copy its version of this code into my game. That does work correctly but Radical Red uses the Gen 5 stat screen so the placements are a bit off. I've copied each code into a text editor to try and find the differences and have changed bits and pieces but anything I change at all just completely breaks the stat screen. Any ideas on what I should do?
     

    Attachments

    • ASM Resource Thread
      Srambled.png
      4.5 KB · Views: 3
    • ASM Resource Thread
      RadicalRed.png
      2.7 KB · Views: 2
    Back
    Top