Research & Development Got a well-founded knack with ROM hacking? Love reverse-engineering the Pokémon games? Or perhaps you love your assembly language. This is the spot for polling and gathering your ideas, and then implementing them! Share your hypothesis, get ideas from others, and collaborate to create!

Ad Content
Reply
 
Thread Tools
  #1   Link to this post, but load the entire thread.  
Old November 17th, 2018 (11:30 AM). Edited November 26th, 2018 by ghoulslash.
ghoulslash's Avatar
ghoulslash ghoulslash is offline
     
    Join Date: Mar 2016
    Gender: Male
    Posts: 109
    I know this was implemented in the Emerald battle engine upgrade, and there was some work done by FBI a few years ago on it, but I want to have a collaborative effort on getting this working for Fire Red, especially for hacks that won't use the dissasembly projects.

    EDIT: Delta posted a link to a more completed version.

    I researched this topic a year ago or so and was able to get a working version with some graphical side effects that I will explain later.

    Background info for the curious:
    Spoiler:
    There are likely multiple ways to do this; the easiest in my opinion is to use battle scripts. There is already a battle script command that brings the trainer sprite out. This command is cmd53, and it takes an argument either 0x0 or 0x1: the former will bring the player sprite out (there is potentially utility here..), or 0x1 for the opposing trainer (not sure what would happen if used in a wild battle).

    The problem is that the game never intended to have a battle continue if this command was called, so that the object defined for animation targets gets set to the trainer sprite. These obj IDs are stored in 0x02023d44 in the same order as the banks would be (player 1, enemy 1, player 2, enemy 2).

    The other problem is that (as hard as I was willing to look back when I originally researched this) there is no trainer_slide_out command. There is certainly a function to do it, as that is what happens at the beginning of the the trainer battle, but in lieu of finding this, I used whirlwind's animation.

    Of course, the trainer sprite object still exists, so we should delete it so that it does not get used in attack animations. The aforementioned graphical issue is related to this; the trainer sprite gets stuck in VRAM, so several moves (Pound, Agility, Quick Attack, etc), generate the trainer sprite again even when the object is deleted. I do not know enough about VRAM functions or the object data structure to know how to fix this at the moment, though it's been a while since I looked at most of this stuff.


    Implementation:
    So wherever we want to have the trainer interrupt, we need a battle script to be run at that point in the battle. A logical place for the end-of-turn would be after all of the weather, etc checks that occur. Fortunately, there is a table at 0x17bc4 that runs end-of-turn routines and battle scripts if necessary. There is a limiter at 0x17b98 so we can easily repoint and expand this table to add more global end-of-turn effects (note that the last entry in the original table must always be last)

    We can run a battle script from here to make the trainer enter the screen, play a custom string, and then use my whirlwind animation hack to push the trainer offscreen, resetting all of the object targets (introduced in the spoiler above).

    Note: this works from a functional standpoint, but the trainer sprite is still prevalent in the VRAM or object data structure somehow and will show up again in several attacks such as Pound, Agility, etc. Entering the pokemon menu and returning fixes this problem.


    Here is a test case using the global end-of-turn battle scripts. The following code expands the global effect table and loads a string and battle script if a specific byte in RAM is set (so you can load a certain number of strings). It includes the whirlwind anim hack. It deletes the trainer object afterwards but the aforementioned graphical issue is not solved.
    Spoiler:

    Main code: compile and insert, noting the .org locations
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global TrainerInterrupt_EndTurn
    
    .include "bs_macros.asm"
    
    .equ Offset, 0xYYYYYY  @ insert loc (no 0x08 prefix)
    .equ romsize, 0x08000000
    .equ var8001, 0x020370ba
    .equ var8002, 0x020370bc
    .equ ATK_WHIRLWIND, 0x12
    
    @ change this if you want
    .equ SlideInRAM, 0x0203e05d
    
    
    
    .org 0x17b98, 0xff
    .byte 0xb
    
    .org 0x17bc0, 0xff
    .word (romsize+GlobalEffects)
    
    .org 0x72688, 0xff
    .byte 0x0, 0x48, 0x0, 0x47
    .word (romsize+anim_hack+1)
    
    .org Offset, 0xff
    .align 2
    anim_hack:
    	ldr r1, [sp]	@move anim table
    	add r0, r3, r1
    	
    CheckTrainerSlide:
    	ldr r1, =SlideInRAM
    	ldrb r1, [r1, #0x1]		@0x0203e05e - changes whirlwind anim (change if you want)
    	cmp r1, #0x0
    	bne TrainerSlideOut
    	
    NormalAnim:	
    	ldr r0, [r0, #0x0]
    	b StoreAnim
    	
    TrainerSlideOut:
    	ldr r0, =(0x081c9a24)
    	
    StoreAnim:
    	str r0, [r5]
    	
    Return:
    	ldr r0, =(0x08072690 +1)
    	bx r0	
    
    
    battle_script:
    copyarray var8002 0x02023d44 0x4		@ save object banks into var8002-3
    cmd53 0x1	@ trainer slide out
    waitstate
    printstring 0x184	@ print string
    pause 0x20
    sethalfword AttackRAM ATK_WHIRLWIND
    copyarray var8001 TargetBank 0x1		@ save target bank into var8001
    setbyte TargetBank 0x1
    setbyte 0x0203e05e 0x1		@ whirlwind anim hack
    attackanimation
    waitanimation
    pause 0x20
    setbyte SlideInRAM 0x0		@ reset trainer slide
    setbyte 0x0203e05e 0x0		@ reset whirlwind anim hack
    copyarray TargetBank var8001 0x1	@ return target bank
    callasm romsize+reset_objs+1		@ reset object banks
    end2
    
    .align 2
    GlobalEffects:
    .word 0x08017bf0
    .word 0x08017c76
    .word 0x08017d3c
    .word 0x08017e08
    .word 0x08017ee4
    .word 0x08017f9c
    .word 0x08018050
    .word 0x080180d4
    .word 0x08018144
    .word 0x0801819c
    .word (romsize+slide_in)
    .word 0x08018220	@must be last
    
    slide_in:
    	ldr r0, =SlideInRAM		@ram to activate, load string from table
    	ldrb r0, [r0]	
    	cmp r0, #0x0	@ does nothing if set to zero
    	beq NoSlide
    	
    LoadString:
    	sub r0, #0x1	@ start at 0
    	lsl r0, r0, #0x2
    	ldr r1, =(romsize+StringTable)
    	add r0, r0, r1
    	ldr r0, [r0]
    	ldr r1, .Setword
    	str r0, [r1]		@ set string to play
    	
    LoadScript:
    	ldr r1, .ScriptPointer
    	ldr r0, =(romsize+battle_script)
    	str r0, [r1]
    	ldr r3, =(0x080181dc +1)
    	bx r3	
    	
    NoSlide:
    	ldr r2, =(0x080181fc +1)
    	bx r2
    	
    .align 2
    StringTable:
    .word (romsize+String)
    @etc...	
    
    .align 2
    reset_objs:
    	push {r4, lr}
    	ldr r0, .ObjectBanks
    	ldrb r1, [r0, #0x1]		@ trainer sprite obj
    	mov r4, r1
    	ldr r5, =var8002
    	ldr r0, [r5]	@ old object banks
    	ldr r1, .ObjectBanks
    	str r0, [r1]	@ return object bank data
    	mov r0, #68
    	mul r0, r1
    	ldr r1, .Objects
    	add r0, r0, r1
    	bl ObjDelete		@ delete trainer sprite obj
    	
    exit_loop:
    	pop {r4}
    	pop {r0}
    	bx r0
    	
    	
    ObjDelete:
    	ldr r2, =(0x08076030 +1)
    	bx r2
    	
    .align 2
    .Setword:	.word 0x0203c020
    .ScriptPointer:	.word 0x02023d74
    .ObjectBanks:	.word 0x02023d44
    .Objects:	.word 0x0202063c
    
    String:	.byte S_, c_, a_, r_, e_, d_, Space, P_, o_, t_, t_, e_, r_, QMark, NewBox, 0xff
    You'll need to download the attached bs_macros.asm and insert this sethalfword command I wrote as well (or can just use setbyte since Whirlwind is 1 byte). I have it as command 0xFB
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    .global sethalfword_battle
    /*
    battle command to set half word
    command 0xfb
    insert pointer+1 at [battle_commands + 4*0xFB] to make this battle script command 0xFB
    */
    
    main:
    	push {r1-r4, lr}
    	ldr r0, .ScriptPointer
    	ldr r0, [r0, #0x0]		@script loc
    	ldrb r1, [r0, #0x1]
    	ldrb r2, [r0, #0x2]
    	lsl r2, r2, #0x08
    	orr r1, r2
    	ldrb r2, [r0, #0x3]
    	lsl r2, r2, #0x10
    	orr r1, r2
    	ldrb r2, [r0, #0x4]
    	lsl r2, r2, #0x18
    	orr r1, r2
    	
    	ldr r0, .ScriptPointer
    	ldr r2, [r0]
    	ldrb r3, [r2, #0x5]
    	ldrb r4, [r2, #0x6]
    	lsl r4, r4, #0x8
    	orr r3, r4
    	strh r3, [r1]
    	add r2, #0x7
    	str r2, [r0]
    	
    end:
    	pop {r1-r4}
    	pop {r0}
    	bx r0
    	
    .align 2
    .ScriptPointer:	.word 0x02023d74


    Of course, there are plenty of other applications and ways to implement this design. The meat of the research is around cmd53 and the pokemon objects. The main holdup for this to be complete is finding a way to completely remove the trainer sprite from the graphics after the fact. This may be a trivial solution with a simple in-game function, but I have limited experience with graphics-based asm. I will note that going into the pokemon party menu and returning fixes the problem, making me think that it has something to do with the object data.
    Attached Files
    File Type: asm bs_macros.asm‎ (21.7 KB, 5 views) (Save to Dropbox)
    __________________
    https://github.com/ghoulslash
    Reply With Quote
      #2   Link to this post, but load the entire thread.  
    Old November 24th, 2018 (9:12 AM).
    eMMe97 eMMe97 is offline
       
      Join Date: Jan 2015
      Posts: 40
      I have problems about compiling. I download the asm file, but if it compiles it is empty ...
      What should I write inside?
      For example I insert first routine at 900000, second routine at A00000, I must edit them?
      Thancks for help :)
      Reply With Quote
        #3   Link to this post, but load the entire thread.  
      Old November 25th, 2018 (12:22 AM).
      Delta231's Avatar
      Delta231 Delta231 is offline
      A noob
         
        Join Date: May 2016
        Location: India
        Gender: Male
        Nature: Bold
        Posts: 675
        Someone has already done it.
        __________________
        HGSS OWs in FR Style
        Fire Red NSE Bookmarks


        A supporter of


        Reply With Quote
          #4   Link to this post, but load the entire thread.  
        Old November 26th, 2018 (7:30 AM).
        ghoulslash's Avatar
        ghoulslash ghoulslash is offline
           
          Join Date: Mar 2016
          Gender: Male
          Posts: 109
          Quote:
          Originally Posted by Delta231 View Post
          Someone has already done it.
          Good find! I'll update the main post.

          Quote:
          Originally Posted by eMMe97 View Post
          I have problems about compiling. I download the asm file, but if it compiles it is empty ...
          What should I write inside?
          For example I insert first routine at 900000, second routine at A00000, I must edit them?
          Thancks for help :)
          For assembly files with .org locations, it will assemble empty files except for the data at the specified offsets, so the assembled file just looks empty. Of course, I would refer you to Delta's posted link since it is more complete and more functional than my test case :)
          __________________
          https://github.com/ghoulslash
          Reply With Quote
            #5   Link to this post, but load the entire thread.  
          Old January 4th, 2019 (3:47 AM).
          eMMe97 eMMe97 is offline
             
            Join Date: Jan 2015
            Posts: 40
            I have a compatibility problem with this version https://gitgud.io/pfero/trainer_sliding and the MrDollSteak's Decap. and Attack Rombase (Version 1.5a).

            I change source/scripts.h and source/scripts.s with 0x300 (before 0x200)
            I change version/firered/insert.asm:bs_execute_handle and source/script_commands.h with 0xFF (before 0xF8).
            But...it doesn't work :(
            I see the offset 0x080d77be is used by both patch...I don't understand how to fix this problem...Help me please :(
            Reply With Quote
              #6   Link to this post, but load the entire thread.  
            Old January 4th, 2019 (8:04 AM). Edited January 4th, 2019 by Delta231.
            Delta231's Avatar
            Delta231 Delta231 is offline
            A noob
               
              Join Date: May 2016
              Location: India
              Gender: Male
              Nature: Bold
              Posts: 675
              Quote:
              Originally Posted by eMMe97 View Post
              I have a compatibility problem with this version https://gitgud.io/pfero/trainer_sliding and the MrDollSteak's Decap. and Attack Rombase (Version 1.5a).

              I change source/scripts.h and source/scripts.s with 0x300 (before 0x200)
              I change version/firered/insert.asm:bs_execute_handle and source/script_commands.h with 0xFF (before 0xF8).
              But...it doesn't work :(
              I see the offset 0x080d77be is used by both patch...I don't understand how to fix this problem...Help me please :(
              You just need to change linker script which is in version/firered and read install.md as well for compiling instructions.

              There is a big note there I will put it here.


              The patch modifies the battle string loading function, to load a custom string, for string 0x200 (by default). This only happens when using a string ID bigger than 0x17C (for Emerald) or 0x181 (for Fire Red). If you've applied a patch that repoints the table or otherwise modifies the code to expand the table, you might encounter problems with it. This might happen for example when combined with patches that add new move effects. Consider either modifying the string ID used in the patch (source/scripts.h and source/scripts.s) or modifying string_hook (in the corresponding version/ directory) to do whatever suits you best.

              Additionally, for Fire Red only, this patch implements the trainer_back_slide battle scripting command. This isn't done by repointing and expanding the battle scripting command table, but by hooking one of the functions that reads it, and overriding the behavior for command 0xf8. If you've applied any patch that repoints this table or otherwise modifies the code to expand the table, you might encounter problems with it. This might happen for example when combined with patches that add new move effects. Consider modifying the command ID used in the patch (version/firered/insert.asm:bs_execute_handle and source/script_commands.h) and/or pointing the command to the right function (version/firered/insert.asm:battlecommand_trainer_back_slide, see the generated *.patched.sym file for an address).
              __________________
              HGSS OWs in FR Style
              Fire Red NSE Bookmarks


              A supporter of


              Reply With Quote
                #7   Link to this post, but load the entire thread.  
              Old January 4th, 2019 (8:19 AM).
              eMMe97 eMMe97 is offline
                 
                Join Date: Jan 2015
                Posts: 40
                I had already read those instructions and done what they said to do, but as I wrote at some point I can not continue because two routines come into conflict and a bug occurs.
                Reply With Quote
                  #8   Link to this post, but load the entire thread.  
                Old January 5th, 2019 (6:06 AM).
                Delta231's Avatar
                Delta231 Delta231 is offline
                A noob
                   
                  Join Date: May 2016
                  Location: India
                  Gender: Male
                  Nature: Bold
                  Posts: 675
                  Quote:
                  Originally Posted by eMMe97 View Post
                  I had already read those instructions and done what they said to do, but as I wrote at some point I can not continue because two routines come into conflict and a bug occurs.
                  Could elaborate?
                  __________________
                  HGSS OWs in FR Style
                  Fire Red NSE Bookmarks


                  A supporter of


                  Reply With Quote
                    #9   Link to this post, but load the entire thread.  
                  Old January 10th, 2019 (2:32 AM).
                  eMMe97 eMMe97 is offline
                     
                    Join Date: Jan 2015
                    Posts: 40
                    Solved (more or less...)!
                    If you want to apply in a hack rom patched by MrDollSteak's Decap. and Attack Rombase (Version 1.5a)...
                    1) change source/scripts.h and source/scripts.s with 0x300 (before 0x200);
                    2) change version/firered/insert.asm:bs_execute_handle and source/script_commands.h with 0xFF (before 0xF8);
                    3) edit trainer_sliding-master\version\firered like this:

                    Code:
                    .arm.little
                    .thumb
                    
                    .open "firered.gba", "firered.patched.gba", 0x08000000
                    
                    .definelabel free_space, 0x08(offset)
                    
                    .definelabel battle_malloc_hook, 0x0802e0fa
                    .definelabel battle_malloc_ret, 0x0802e104|1
                    
                    .definelabel battle_free_hook, 0x0802e1f8
                    .definelabel battle_free_ret, 0x0802e200|1
                    
                    .definelabel sliding_hook, 0x08013c26
                    .definelabel sliding_hook_buffer, 0x02023DD0
                    .definelabel sliding_hook_turn_value_cleanup, 0x08015330|1
                    .definelabel sliding_hook_ret, 0x08013d20|1
                    .definelabel sliding_hook_continue, 0x08013c30|1
                    
                    .definelabel string_hook, 0x080d77be
                    .definelabel string_hook_buffer, 0x0202298c
                    .definelabel string_hook_ret, 0x080d77e2|1
                    .definelabel string_hook_decode, 0x080d77dc|1
                    
                    bs_commands equ 0x0895f480
                    .definelabel battlecommand_trainer_slide_ptr, (bs_commands + 0x53 * 4)
                    .definelabel battlecommand_trainer_slide, 0x080250dc|1
                    
                    .definelabel bs_execute_hook, 0x08015c58
                    .definelabel battlecommand_trainer_back_slide_battler, 0x02023bc4
                    .definelabel battlecommand_trainer_back_slide_emit, 0x0800e114|1
                    .definelabel battlecommand_trainer_back_slide_unk, 0x08017248|1
                    
                    .org battle_malloc_hook
                        ldr r0, =battle_malloc_handle|1
                        bx r0
                    .pool
                    
                    .org battle_free_hook
                        ldr r0, =battle_free_handle|1
                        bx r0
                    .pool
                    
                    .org sliding_hook
                        ldr r0, =sliding_hook_handle|1
                        bx r0
                    .pool
                    
                    .org string_hook
                        ldr r0, =string_hook_handle|1
                        bx r0
                    .pool
                    
                    .org battlecommand_trainer_slide_ptr
                    .word battlecommand_trainer_slide_handle|1
                    
                    .org bs_execute_hook
                        ldr r2, =bs_execute_handle|1
                        bx r2
                    .pool
                    
                    
                    .org free_space
                    .incbin "trainer_sliding_firered.bin"
                    .include "trainer_sliding_firered.asm"
                    
                    battle_malloc_handle:
                    ; This hooks right after all of the other battle structs have been allocated
                    
                    ; State:
                    ; r0-r3, lr are fair game.
                    
                    	; Run the few instructions we've overwritten
                        mov r0, r5
                        ldr r1, =calloc
                        bl @@bx_r1
                        mov r1, r0
                        str r1, [r4]
                    
                        bl battle_malloc
                    
                        ldr r1, =battle_malloc_ret
                    @@bx_r1:
                        bx r1
                    
                    .pool
                    
                    battle_free_handle:
                    ; This hooks right after all of the other battle structs have been freed
                    
                    ; State:
                    ; r5 = 0
                    ; r0-r3, lr are fair game.
                    
                        ; Run the few instructions we've overwritten
                        ldr r0, [r4]
                        ldr r1, =free
                        bl @@bx_r1
                        str r5, [r4]
                    
                        bl battle_free
                    
                        ldr r1, =battle_free_ret
                    @@bx_r1:
                        bx r1
                    
                    .pool
                    
                    sliding_hook_handle:
                    ; This hooks right after Perish Song/Future Sight are handled at the end of a turn.
                    ; If a battle effect is executed, it's supposed to return early.
                    
                    ; State:
                    ; r0-r3, lr are fair game.
                    
                    ; Return hooks:
                    ; sliding_hook_ret:
                    ;   Returns early from the hooked function.
                    ; sliding_hook_continue:
                    ;   Continues running the end-of-turn function, looking for other effects to
                    ;   run and doing other end-of-turn-y stuff.
                    
                    	bl turn_end_slide
                    	cmp r0, #0
                    	beq @@continue
                    
                    	ldr r1, =sliding_hook_ret
                    	bx r1
                    
                    @@continue:
                    	; Run the few instructions we've overwritten
                        mov r0, #0
                        ldr r1, =sliding_hook_turn_value_cleanup
                        bl @@bx_r1
                    	ldr r2, =sliding_hook_buffer
                    	ldr r0, [r2]
                    
                    	ldr r1, =sliding_hook_continue
                    @@bx_r1:
                    	bx r1
                    
                    .pool
                    
                    string_hook_handle:
                    ; This hooks the default case in the battle string engine,
                    ;  when a string ID is higher than the size of the string table.
                    ; We can load our custom strings here.
                    
                    ; State:
                    ; r6 = String ID
                    ; r0-r10, lr are fair game.
                    
                    ; Addresses of interest:
                    ; string_buffer:
                    ;   Contains the resulting string to print. Not sure how big it is.
                    ;   Should be filled with a single terminator (0xFF) if no string was found.
                    
                    ; Return hooks:
                    ; string_hook_decode:
                    ;   r7 = String pointer
                    ;   Decodes the string, copying it to string_hook_buffer in the process.
                    ; string_hook_ret:
                    ;   Returns from the string loading function. Should have a valid string in
                    ;   string_hook_buffer.
                    
                        mov r0, r6
                        bl get_custom_string
                        cmp r0, #0
                        beq @@ret
                    
                        ; Decode the string
                    	mov r7, r0
                    	ldr r0, =string_hook_decode
                    	bx r0
                    
                    @@ret:
                    	; Run the few instructions we've overwritten
                    	ldr r1, =string_hook_buffer
                    	mov r0, #0xFF
                    	strb r0, [r1]
                    	ldr r0, =string_hook_ret
                    	bx r0
                    
                    .pool
                    
                    battlecommand_trainer_slide_handle:
                    ; This replaces the original trainer_slide command.
                    
                    ; We extend the trainer_slide command to handle some values in a different fashion.
                    ; See slide_save_obj for details.
                    
                        push {lr}
                        bl slide_save_obj
                        cmp r0, #0
                        pop {r0}
                        bne @@bx_r0
                        mov lr, r0
                        ldr r0, =battlecommand_trainer_slide
                    @@bx_r0:
                        bx r0
                    
                    .pool
                    
                    bs_execute_handle:
                    ; This hooks the function used to run some battle scripts,
                    ;  after fetching the next command ID from bs_pointer.
                    ; There are more functions where the command IDs are interpreted,
                    ;  but this is the only one that we need to interpret trainer_back_slide.
                    
                    ; State:
                    ; r0 = Command ID
                    ; r1 = Pointer to bs_commands
                    ; r2, r3 and lr are fair game, the rest should be preserved.
                    
                        pop {r2}
                        mov lr, r2
                    
                        cmp r0, #0xf9
                        beq battlecommand_trainer_back_slide
                    
                        ; Run whatever command was called upon
                        lsl r0, #2
                        add r0, r1
                        ldr r0, [r0]
                        bx r0
                    
                    .pool
                    
                    battlecommand_trainer_back_slide:
                    ; Port of trainer_back_slide from emerald into firered
                    
                        push {r4, r5, lr}
                    
                        ; Get the argument, make sure any value bigger than 1 is 1.
                        ldr r5, =bs_pointer
                        ldr r0, [r5]
                        ldrb r0, [r0, #1]
                        cmp r0, #0
                        beq @@zero
                        mov r0, #1
                    @@zero:
                    
                        ; Get and save the position
                        ldr r1, =get_battler_at_position
                        bl @@bx_r1
                        ldr r4, =battlecommand_trainer_back_slide_battler
                        strb r0, [r4]
                    
                        ; Emit a trainer slide back
                        mov r0, #0
                        ldr r1, =battlecommand_trainer_back_slide_emit  ; Fun fact: This function is never used in the game
                        bl @@bx_r1
                    
                        ; Call an unknown function
                        ldrb r0, [r4]
                        ldr r1, =battlecommand_trainer_back_slide_unk
                        bl @@bx_r1
                    
                        ; Skip to the next command
                        ldr r0, [r5]
                        add r0, #2
                        str r0, [r5]
                    
                        pop {r4, r5}
                        pop {r0}
                        bx r0
                    
                    @@bx_r1:
                        bx r1
                    
                    .pool
                    
                    ; Set up a dummy table for the sliding trainer messages.
                    _sliding_trainers:
                        .word 0
                        .word 0
                    
                    .org sliding_trainers
                    .word _sliding_trainers
                    
                    .close
                    Reply With Quote
                    Reply

                    Quick Reply

                    Join the conversation!

                    Create an account to post a reply in this thread, participate in other discussions, and more!

                    Create a PokéCommunity Account
                    Ad Content
                    Thread Tools

                    Posting Rules
                    You may not post new threads
                    You may not post replies
                    You may not post attachments
                    You may not edit your posts

                    BB code is On
                    Smilies are On
                    [IMG] code is On
                    HTML code is Off

                    Forum Jump


                    All times are GMT -8. The time now is 3:33 PM.