• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Completed Advanced CPU control (Force shield/crouch and reversal actions)

Altimor

Smash Rookie
Joined
Feb 26, 2017
Messages
10


From traditional fighting game terminology, a reversal is an action performed immediately after regaining control from knockdown, hitstun, or blockstun.

Z+Dpad down: Start reversal recording. You will take control of the CPU and be able to record up to 40 frames. Recording starts from your first input.
Z+Dpad up: Clear recording.
Z+Dpad right: Toggle force shield.
Z+Dpad left: Toggle force crouch.

$Advanced CPU Control [Altimor]
C206B02C 0000008D
4800000D 48000098
00000000 7C6802A6
90610004 9421FFF8
80630004 2C030000
4082003C 3C008037
6000F1E4 7C0803A6
386003FC 4E800021
80A1000C 90650004
38A00000 38000000
7C832A14 90040000
38A50004 2C0503FC
4180FFF0 7C651B78
8001000C 38210008
7C0803A6 4E800020
38600000 907F0620
907F0624 907F0638
907F063C 907F0650
907F065C 4E800020
2C040000 40820134
4E800020 7FE3FB78
3C00800A 60002040
7C0803A6 4E800021
2C030000 40820180
809F065C 2C040014
40820018 38600001
9065000C 887E006C
9065001C 4800037C
2C040018 40820010
38600000 90650038
48000368 88DE006C
1CC60004 7CC62A14
80660028 70630012
2C030012 41820018
2C040012 40820010
80650020 68630001
90650020 80660028
70630011 2C030011
41820018 2C040011
40820010 80650024
68630001 90650024
90860028 80C5001C
887E006C 7C033000
40820300 8065000C
2C030001 40820020
2C040000 408202EC
38600001 90650010
38600000 90650014
9065000C 80650010
2C030001 408202CC
80650014 2C030000
41810040 809F0620
4BFFFEF9 809F0624
4BFFFEF1 809F0638
4BFFFEE9 809F063C
4BFFFEE1 809F0650
4BFFFED9 809F065C
4BFFFED1 4800028C
38600001 90650038
80650014 1C630018
3863003C 7C651A14
C03F0620 D0230000
C03F0624 D0230004
C03F0638 D0230008
C03F063C D023000C
C03F0650 D0230010
809F065C 90830014
4BFFFE61 80650014
38630001 2C030028
4082000C 38600000
90650010 90650014
48000220 80650014
2C030000 4182005C
2C030001 4182000C
C01F002C D0050018
80650014 3863FFFF
1C630018 3863003C
7C651A14 C0230000
D03F0620 C0230004
D03F0624 C0230008
D03F0638 C023000C
D03F063C C0230010
D03F0650 80830014
909F065C 480001BC
80850010 2C040001
4082000C 4BFFFDCD
480001A8 809F0010
2C04000E 41820038
2C040027 41820030
2C040028 41820028
2C0400B2 41820020
2C0400B3 41820018
2C0400B5 41820010
2C0400B6 41820008
40820038 80650020
2C030001 40820014
4BFFFD79 38600040
907F065C 4800001C
80650024 2C030001
40820010 4BFFFD5D
3C60BF80 907F0624
80650038 2C030001
40820128 2C0400B5
41820014 2C04004B
41800020 2C04005B
41810018 38600001
90650000 38600000
90650004 480000FC
80650000 2C030001
408200F0 80650004
2C030000 4181005C
2C040026 4182004C
2C04000E 41820044
2C0400B3 4182003C
2C04002A 40820024
809E002C C0240894
C00401F4 FC010040
41800010 80042340
2C000000 40820014
809E002C 88042218
5400CFFF 41820094
C01F002C D0050008
80650004 1C630018
3863003C 7C651A14
C0230000 C0050008
FC210032 C0050018
FC210032 D03F0620
C0230004 D03F0624
C0230008 D03F0638
C023000C D03F063C
C0230010 D03F0650
80830014 807F0010
2C0300B3 40820014
80650004 2C030000
40820008 60840040
909F065C 80650004
38630001 2C030028
4082000C 38600000
90650000 90650004
3C008016 6000B0FC
7C0803A6 4E800021
60000000 00000000
*Control with Z+Dpad

Code:
# 8006B02C - PlayerThink_ControllerInputsToDataOffset, after buttons are set

bl get_data
b start

.set OFFSET_PLAYING, 0
.set OFFSET_PLAY_FRAME, 4
.set OFFSET_PLAY_DIR, 8
.set OFFSET_RECORD_ON_RELEASE, 12
.set OFFSET_RECORDING, 16
.set OFFSET_RECORD_FRAME, 20
.set OFFSET_RECORD_DIR, 24
.set OFFSET_RECORD_PORT, 28
.set OFFSET_SHIELD, 32
.set OFFSET_CROUCH, 36
.set OFFSET_LAST_BUTTONS, 40
.set OFFSET_REVERSAL_ENABLED, 56
.set OFFSET_RECORDING_BUF, 60
.set RECORDING_FRAME_SIZE, 24 # joystick X+Y, cstick X+Y, L/R, Buttons, 4 bytes each
.set RECORDING_FRAME_COUNT, 40
.set DATA_SIZE, OFFSET_RECORDING_BUF + RECORDING_FRAME_SIZE * RECORDING_FRAME_COUNT

.space 4 # Pointer to data on heap

.align 2
# Store pointer to data in r5
get_data:
    mflr r3
    stw r3, 4(r1)
    stwu r1, -8(r1)

    lwz r3, 4(r3)
    cmpwi r3, 0
    bne initialized

    # Call #_HSD_MemAlloc
    lis r0, 0x8037
    ori r0, r0, 0xF1E4
    mtlr r0
    li r3, DATA_SIZE
    blrl

    # Store in data pointer
    lwz r5, 12(r1)
    stw r3, 4(r5)

    # Fill with zeroes
    li r5, 0
    li r0, 0
    memset_loop:
    add r4, r3, r5
    stw r0, 0(r4)
    addi r5, r5, 4
    cmpwi r5, DATA_SIZE
    blt memset_loop

    initialized:
    mr r5, r3

    lwz r0, 12(r1)
    addi r1, r1, 8
    mtlr r0
    blr

zero_inputs:
    li r3, 0
    stw r3, 0x620(r31)
    stw r3, 0x624(r31)
    stw r3, 0x638(r31)
    stw r3, 0x63C(r31)
    stw r3, 0x650(r31)
    stw r3, 0x65C(r31)
    blr


# Function to check if the recording should start (saves space)
check_input:
    cmpwi r4, 0
    bne recording_start
    blr

start:
    # Check DataOffset_HumanOrCPUCheck_0ForHuman
    mr r3, r31
    lis r0, 0x800A
    ori r0, r0, 0x2040
    mtlr r0
    blrl
    cmpwi r3, 0
    bne cpu

    # Check for Z+dpad down to start recording
    lwz r4, 0x65C(r31)
    cmpwi r4, 0x14
    bne no_recording_input

    li r3, 1
    stw r3, OFFSET_RECORD_ON_RELEASE(r5)
    lbz r3, 0x6C(r30)
    stw r3, OFFSET_RECORD_PORT(r5)
    b end

    no_recording_input:
    # Check for Z+dpad up to clear recording
    cmpwi r4, 0x18
    bne no_clear_input

    li r3, 0
    stw r3, OFFSET_REVERSAL_ENABLED(r5)
    b end

    no_clear_input:
    # r6 = r5 + port * 4, for acccessing last buttons
    lbz r6, 0x6C(r30)
    mulli r6, r6, 4
    add r6, r6, r5

    # Check for Z+dpad right to toggle CPU shield
    lwz r3, OFFSET_LAST_BUTTONS(r6)
    andi. r3, r3, 0x12
    cmpwi r3, 0x12
    beq no_toggle_shield_input
    cmpwi r4, 0x12
    bne no_toggle_shield_input

    lwz r3, OFFSET_SHIELD(r5)
    xori r3, r3, 1
    stw r3, OFFSET_SHIELD(r5)

    no_toggle_shield_input:
    # Check for Z+dpad left to toggle CPU crouch
    lwz r3, OFFSET_LAST_BUTTONS(r6)
    andi. r3, r3, 0x11
    cmpwi r3, 0x11
    beq no_toggle_crouch_input
    cmpwi r4, 0x11
    bne no_toggle_crouch_input

    lwz r3, OFFSET_CROUCH(r5)
    xori r3, r3, 1
    stw r3, OFFSET_CROUCH(r5)

    no_toggle_crouch_input:
    # Store buttons
    stw r4, OFFSET_LAST_BUTTONS(r6)

    # Check that this is the port that started the recording
    lwz r6, OFFSET_RECORD_PORT(r5)
    lbz r3, 0x6C(r30)
    cmpw r3, r6
    bne end

    # Check if recording on release of buttons
    lwz r3, OFFSET_RECORD_ON_RELEASE(r5)
    cmpwi r3, 1
    bne no_record_on_release

    cmpwi r4, 0
    bne end
    li r3, 1
    stw r3, OFFSET_RECORDING(r5)
    li r3, 0
    stw r3, OFFSET_RECORD_FRAME(r5)
    stw r3, OFFSET_RECORD_ON_RELEASE(r5)

    no_record_on_release:
    # Check if recording
    lwz r3, OFFSET_RECORDING(r5)
    cmpwi r3, 1
    bne end

    # Check if recording has already started
    lwz r3, OFFSET_RECORD_FRAME(r5)
    cmpwi r3, 0
    bgt recording

    # Wait until input is received to record the first frame
    lwz r4, 0x620(r31) # Joystick X
    bl check_input
    lwz r4, 0x624(r31) # Joystick Y
    bl check_input
    lwz r4, 0x638(r31) # CStick X
    bl check_input
    lwz r4, 0x63C(r31) # CStick Y
    bl check_input
    lwz r4, 0x650(r31) # L/R
    bl check_input
    lwz r4, 0x65C(r31) # Buttons
    bl check_input

    b end

    recording_start:
    li r3, 1
    stw r3, OFFSET_REVERSAL_ENABLED(r5)

    recording:
    # Write to reversal recording
    lwz r3, OFFSET_RECORD_FRAME(r5)
    mulli r3, r3, RECORDING_FRAME_SIZE
    addi r3, r3, OFFSET_RECORDING_BUF
    add r3, r5, r3

    lfs f1, 0x620(r31) # Joystick X
    stfs f1, 0(r3)
    lfs f1, 0x624(r31) # Joystick Y
    stfs f1, 4(r3)
    lfs f1, 0x638(r31) # CStick X
    stfs f1, 8(r3)
    lfs f1, 0x63C(r31) # CStick Y
    stfs f1, 12(r3)
    lfs f1, 0x650(r31) # L/R
    stfs f1, 16(r3)
    lwz r4, 0x65C(r31) # Buttons
    stw r4, 20(r3)

    # Zero them out so only CPU moves
    bl zero_inputs

    # Increment frame counter
    lwz r3, OFFSET_RECORD_FRAME(r5)
    addi r3, r3, 1

    # Check if recording is complete
    cmpwi r3, RECORDING_FRAME_COUNT
    bne continue_recording

    li r3, 0
    stw r3, OFFSET_RECORDING(r5)

    continue_recording:
    stw r3, OFFSET_RECORD_FRAME(r5)

    b end

    cpu:
    # Use inputs that are currently being recorded
    lwz r3, OFFSET_RECORD_FRAME(r5)
    cmpwi r3, 0
    beq recording_not_started
    cmpwi r3, 1
    beq after_first_frame

    # Store direction
    lfs f0, 0x2C(r31)
    stfs f0, OFFSET_RECORD_DIR(r5)

    after_first_frame:
    lwz r3, OFFSET_RECORD_FRAME(r5)
    subi r3, r3, 1 # Current frame index hasn't been written yet
    mulli r3, r3, RECORDING_FRAME_SIZE
    addi r3, r3, OFFSET_RECORDING_BUF
    add r3, r5, r3

    lfs f1, 0(r3) # Joystick X
    stfs f1, 0x620(r31)
    lfs f1, 4(r3) # Joystick Y
    stfs f1, 0x624(r31)
    lfs f1, 8(r3) # CStick X
    stfs f1, 0x638(r31)
    lfs f1, 12(r3) # CStick Y
    stfs f1, 0x63C(r31)
    lfs f1, 16(r3) # L/R
    stfs f1, 0x650(r31)
    lwz r4, 20(r3) # Buttons
    stw r4, 0x65C(r31)

    b end

    recording_not_started:
    # Stop inputting things if getting ready to record
    lwz r4, OFFSET_RECORDING(r5)
    cmpwi r4, 1
    bne recording_not_pending
    bl zero_inputs
    b end

    recording_not_pending:
    # Animation state
    lwz r4, 0x10(r31)

    cmpwi r4, 0x0E # Wait
    beq check_shield
    cmpwi r4, 0x27 # Squat
    beq check_shield
    cmpwi r4, 0x28 # SquatWait
    beq check_shield
    cmpwi r4, 0xB2 # GuardOn
    beq check_shield
    cmpwi r4, 0xB3 # Guard
    beq check_shield
    cmpwi r4, 0xB5 # GuardSetOff
    beq check_shield
    cmpwi r4, 0xB6 # GuardReflect
    beq check_shield

    bne no_crouch

    check_shield:
    # Set shield
    lwz r3, OFFSET_SHIELD(r5)
    cmpwi r3, 1
    bne no_shield
    bl zero_inputs
    li r3, 0x40
    stw r3, 0x65C(r31)

    b no_crouch

    no_shield:
    # Set crouch
    lwz r3, OFFSET_CROUCH(r5)
    cmpwi r3, 1
    bne no_crouch
    bl zero_inputs
    lis r3, 0xBF80 # -1.0
    stw r3, 0x624(r31)

    no_crouch:
    # Check if reversals are enabled
    lwz r3, OFFSET_REVERSAL_ENABLED(r5)
    cmpwi r3, 1
    bne end

    # Start reversal playback if in damage state
    cmpwi r4, 0xB5 # GuardSetOff
    beq hit
    cmpwi r4, 0x4B
    blt no_hit
    cmpwi r4, 0x5B
    bgt no_hit

    hit:
    li r3, 1
    stw r3, OFFSET_PLAYING(r5)
    li r3, 0
    stw r3, OFFSET_PLAY_FRAME(r5)
    b end

    no_hit:
    # Check that a reversal should be played back
    lwz r3, OFFSET_PLAYING(r5)
    cmpwi r3, 1
    bne end

    # Check if playback has already started
    lwz r3, OFFSET_PLAY_FRAME(r5)
    cmpwi r3, 0
    bgt playback

    # Check for neutral state
    cmpwi r4, 0x26 # DamageFall
    beq playback_start
    cmpwi r4, 0x0E # Wait
    beq playback_start
    cmpwi r4, 0xB3 # Guard
    beq playback_start

    # Landing
    cmpwi r4, 0x2A
    bne iasa
    lwz r4, 0x2C(r30)
    lfs f1, 0x894(r4)
    lfs f0, 0x1F4(r4)
    fcmpo cr0, f1, f0
    blt iasa
    lwz r0, 0x2340(r4)
    cmpwi r0, 0
    bne playback_start

    # Other IASA
    iasa:
    lwz r4, 0x2C(r30)
    lbz r0, 0x2218(r4)
    extrwi. r0, r0, 1, 24
    beq end

    playback_start:
    # Store direction
    lfs f0, 0x2C(r31)
    stfs f0, OFFSET_PLAY_DIR(r5)

    playback:
    # Read from reversal recording
    lwz r3, OFFSET_PLAY_FRAME(r5)
    mulli r3, r3, RECORDING_FRAME_SIZE
    addi r3, r3, OFFSET_RECORDING_BUF
    add r3, r5, r3

    lfs f1, 0(r3) # Joystick X
    lfs f0, OFFSET_PLAY_DIR(r5)
    fmul f1, f1, f0
    lfs f0, OFFSET_RECORD_DIR(r5)
    fmul f1, f1, f0
    stfs f1, 0x620(r31)
    lfs f1, 4(r3) # Joystick Y
    stfs f1, 0x624(r31)
    lfs f1, 8(r3) # CStick X
    stfs f1, 0x638(r31)
    lfs f1, 12(r3) # CStick Y
    stfs f1, 0x63C(r31)
    lfs f1, 16(r3) # L/R
    stfs f1, 0x650(r31)

    lwz r4, 20(r3) # Buttons

    # Hold shield for the first frame of an OOS reversal
    lwz r3, 0x10(r31)
    cmpwi r3, 0xB3 # Guard
    bne no_oos
    lwz r3, OFFSET_PLAY_FRAME(r5)
    cmpwi r3, 0
    bne no_oos
    ori r4, r4, 0x40

    no_oos:
    stw r4, 0x65C(r31)

    # Increment frame counter
    lwz r3, OFFSET_PLAY_FRAME(r5)
    addi r3, r3, 1

    # Check if playback is complete
    cmpwi r3, RECORDING_FRAME_COUNT
    bne continue_playback

    li r3, 0
    stw r3, OFFSET_PLAYING(r5)

    continue_playback:
    stw r3, OFFSET_PLAY_FRAME(r5)

    end:
    # Overwritten instruction
    lis r0, 0x8016
    ori r0, r0, 0xB0FC
    mtlr r0
    blrl
 
Last edited:

Acryte

Smash Ace
Joined
Mar 30, 2005
Messages
986
It works fine and 20XX's infinite shield feature is good to use with this.
This is awesome stuff. For too long has my 20XX been lacking toggles for training.

So sick. Any future interest in recording to 1 of like 5 slots and randomizing the choice? Then you could practice reactions on recoveries... like you could make it CC techroll etc.
 
Last edited:
Top Bottom