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

In Progress The Impossible Cancel

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
The “Impossible Cancel” is a project meant to recreate a playable version of Melee Impossible.
The original author did not provide a code, or any information to work with.

As a result, in addition to being a code (in development) this project is largely an R&D effort and aims to document as much as possible about the involved mechanics.

The project aims to eventually recreate Turbo Mode, but currently uses manually input L/R (Edit - light shield) presses in order to create an action state cancel that may be applied at any time. Works with B-specials, as well as normal movements like running or dodging.


---

Update 4/29/2016

Get the newest code here. Here are some instructions on how to install it.
See the update post for more info:
Code:
-==-
Impossible Cancel v0.20 (library)
Stable recreation of "Melee Impossible"
[Punkline]
Version -- DOL Offset ------ Hex to Replace ---------- ASM Code

1.02 ----- 0x8006b090--- C03F0650 -> Branch
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
bl <ICNCv020_softCancel>
9061FFF8 7FC3F378
83C1FFF8 C0228874
00000000


<ICNCv020_softCancel>
#r3= external player data offset
#experimental
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 480000F8
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000
bl <ICNCv020_animationSpeedCancel>
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000
bl <ICNCv020_abortActionState>
807F0010 2C03001D
41800034 2C030026
4181002C 2C1C0000
41820024 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
bl 0x80096900
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020


<ICNCv020_animationSpeedCancel>
#r3= external player data offset
#--sets animation speed to x1000
#--updates player frame stuff, which uses animation speed to create frame unit size
#--updates player article stuff (mask out bit 0x80 of player.0x2270 if you want to avoid projectiles)
#--attempts player animation interrupt check (cancels action state)
#--sets animation speed back to old speed if still == x1000 (cases where cancel fails)
7C0802A6 90010004
9421FFE8 BFC10010
83E3002C C03F089C
D021FFF8 C022E864
807F0000
bl 0x8006f190
807F0000
bl 0x8006eba4
807F0000
bl 0x8006C80C
807F0000
bl 0x8006A360
C002E864 C03F089C
FC010000 40820010
C021FFF8 807F0000
bl 0x8006f190
BBC10010 38210018
80010004 7C0803A6
4E800020


<ICNCv020_abortActionState>
#r3= external player data offset
#--if player is in air, set animation interrupt to transition into falling
#--else, set animation interrupt to transition into standing
#--set 0x904 to a non-0 value (bypasses frame logic check for next call)
#--attempt player animation interrupt check (cancels action state)
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 4182003C
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000
bl 0x8006A360
83E10008 38210010
80010004 7C0803A6
4E800020
$Impossible Cancel v0.20 [Punkline]
C206B090 0000006A
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
48000019 9061FFF8
7FC3F378 83C1FFF8
C0228874 4800030C
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 48000104
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000 480000B9
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000 4800011D
807F0010 2C03001D
41800040 2C030026
41810038 2C1C0000
41820030 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
3D808009 618C6900
7D8803A6 4E800021
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020 7C0802A6
90010004 9421FFE8
BFC10010 83E3002C
C03F089C D021FFF8
C022E864 807F0000
3D808006 618CF190
7D8803A6 4E800021
807F0000 3D808006
618CEBA4 7D8803A6
4E800021 807F0000
3D808006 618CC80C
7D8803A6 4E800021
807F0000 3D808006
618CA360 7D8803A6
4E800021 C002E864
C03F089C FC010000
4082001C C021FFF8
807F0000 3D808006
618CF190 7D8803A6
4E800021 BBC10010
38210018 80010004
7C0803A6 4E800020
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 41820048
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000 3D808006
618CA360 7D8803A6
4E800021 83E10008
38210010 80010004
7C0803A6 4E800020
60000000 00000000

I’ve made my syntax highlighted ASM available at a glance here:
Code:
/*Impossible Cancel v0.20 (library) [Punkline]
Stable recreation of "Melee Impossible" -- an unavailable cancel code that was apparently never playable.
Now available in the following forms, in descending order of flexibility and complexity:

--Soft Cancel -- safe, stable, versatile, customizable, really big
--Animation Speed Cancel -- safe, may cause glitchs in limited cases (special thanks to Achilles for this concept!)
--Abort Action State -- simple, rigid, potentially unsafe when used from falling states

Any or all of this library may be included in MCM (or a DOL mod)
Doing so will allow codes to be written that utilize these cancels from any context
*/

#example injection mod:

#Impossible Cancel 0.20 (Melee 1.02) [Punkline]
#@8006b090: lfs f1, 0x0650 (r31)        (checking analog input for digitization)
#lr, cr0 and f0 are safe to use
#r3 == internal player data offset 0x65C (digital button data)
#r30 == external player data offset 0x0 (player entity)
#r31 == internal player data offset 0x0 (player data)
#f1 == to become analog L/R value for current frame
#0x778C(rtoc) == 0.0 (no analog L/R press to digitize)

lfs f1, 0x0650 (r31)     #original instruction, loads current frame L/R value for digitization in digital buttons
lfs f0, -0x778C (rtoc)    #load 0.0 for comparison
fcmpu cr0, f0, f1        #compare to current L/R value
beq return               #return if not pressed
lfs f1, 0x654(r31)       #else, check last frame value
fcmpu cr0, f0, f1
bne return               #if this isn't empty, then analog button was not pressed on this frame


stw r3, -0x8(sp)         #temporarily store this; it gets saved in r30 (which is backed up in call)
mr r3, r30
lwz r30, -0x8(sp)         #swaps r3 and r30; so we pass and save registers appropriately
bl <ICNCv020_softCancel>
stw r3, -0x8(sp)
mr r3, r30
lwz r30, -0x8(sp)         #swap registers again, everything back to normal~

return:
lfs f1, -0x778C (rtoc)    #Sheild nop overwrites Original Instruction
.long 0x00000000         #hard return (compiled by MCM)





/*ICNCv020_softCancel
r3 = player entity
This function uses some extra logic to wrap conditions around a procedure that
tries to intelligently uses both of the other cancles provided in this library.
Experimental.
*/

mflr r0
stw r0, 0x4(sp)
stwu sp, -0xD0(sp)
stfd f1, 0x8(sp)
stmw r3, 0x10(sp)       #follow your dreams~
lwz r31, 0x2C(r3)

loopCancel:        #some moves will continue canceling until they reach a wait state
#First we parse an array of data located in the inline data table after these instructions
lwz r30, 0x4(r31)    #r30 = (real) player character ID
lbz r29, 0x2073(r31)    #r29 = (real) player move ID
li r28, 0        #r28 = bool (force special falling?)
li r27, 0        #r27 = bool (force preservation?)
li r26, 0        #r26 = bool (loop cancel?)
bl getParseDataTable
mflr r3            # r3 = parse data pointer
lhz r4, 0(r3)        # r4 = starting hword entry from data table

parseLoop:
rlwinm. r0,r4,0,25,31    #check if the (7-bit) move ID is 00
beq grabCheck        #if so, terminate loop (00 is a termination code)
cmpw r0, r29        #else, start parsing the entry
bne parseNextEntry    #check for move ID match
rlwinm r0,r4,24,26,31
cmpw r0, r30        #check for character ID match
bne parseNextEntry
#at this point, we've found an entry in the table that matches our current character move
#so we save the bools for the code to use later in order to make some decisions about how to work the cancel

#--The parse is basically answering the following questions for us:
rlwinm r28,r4,17,31,31    #do we want to convert non-special air wait states into special falling?
rlwinm r27,r4,18,31,31    #do we want to avoid "aborting" the action state if we have problems?
rlwinm r26,r4,25,31,31    #do we want to keep canceling this move until it reaches a wait state?
b grabCheck

parseNextEntry:
lhzu r4,2(r3)        #load next hword to be parsed
b parseLoop        #loop back to actually parse it

getParseDataTable:
#This is an inline data table. It contains hardcoded variables that get parsed by the above system.
#It's possible to organize this table as a standalone function--but this data has little remote application...
#--Each hword in the array is an entry that is parsed like so:
#0x8000 - bool         -- "force special falling" -- the cancel will assign special falling instead of falling
#0x4000 - bool         -- "force preservation" -- the cancel will avoid using the "abort actionstate" fallback
#0x3F00 - 6-bit ID     -- internal character ID (specifies a character for "character move")
#0x0080 - bool         -- "continue cancel until wait state"
#0x007F - 7-bit ID     -- common move ID (specifies a move for "character move")
#--0x00 as a move ID is a termination code for the parse loop
blrl    #any branches to "parseData" will return with a pointer to the data in lr
.hword 0x0191    #fox laser
.hword 0x0194    #fox shine

.hword 0x8113    #fox firefox
.hword 0x8493    #kirby upB

.hword 0x0496    #kirby foxB
.hword 0x049C    #kirby NessB

.hword 0x04A2    #kirby jpB
.hword 0x04A9    #kirby falcoB

.hword 0x0594    #Bowser downB
.hword 0x8713    #Sheik upB

.hword 0x4794    #Sheik downB
.hword 0x0991    #Ness B

.hword 0x0C94    #Pikachu thunder
.hword 0x8C13    #Pikachu quick attack

.hword 0x0E94    #yoshi downB
.hword 0x0F91    #JP B

.hword 0x9013    #Mewtwo Teleport
.hword 0x9313    #Zelda upB

.hword 0x5394    #Zelda downB
.hword 0x1691    #Falco laser

.hword 0x1694    #Falco Shine
.hword 0x9613    #Falco firebird

.hword 0x1794    #Pichu thunder
.hword 0x9713    #Pichu quick attack

.hword 0x0000    #terminate parse
.hword 0x0000
#make sure to pad this if necessary in order to stay 32-bit aligned

grabCheck:
#Check if player is holding another player.
#-- We want to prevent a "soulbreaker" glitch, so we handle this by making the grab expire
lwz r3, 0x1A58(r31)        #grabbed player entity slot
cmpwi r3, 0
beq ASblacklist
lwz r3, 0x2C(r3)        #if a player entity is in this slot, then load data
li r0, 0
stw r0, 0x1A4C(r3)        #kill breakout countdown
b return            #and simply return

ASblacklist:    #a hardcoded blacklist that stops the cancel during certain moves/action states
#-- for some wait states, this is to prevent technical problems that may arise from wait-state interrupt logic
#-- for other states, it is mostly for the sake of preserving gameplay mechanics

lwz r25, 0x10(r31)    #player action state; we're going to check this again later, so save in r25

cmpwi r25, 0x11        #masks out AS 0x00-0x11 (death-walking)
ble SFcheckAndReturn    #-- without this you can cancel your death animation and rack up SDs. Almost kept it.

#these are some whitelist entries; to be exceptions for the "wait state" check that follows
#they're kind of last-minute additions that can be optimized, but allow this to cancel jumps and things
cmpwi r25, 0x18        #kneebend
beq beginCancel
cmpwi r25, 0x27        #squat
beq beginCancel
cmpwi r25, 0x29        #squat reverse
blt waitCheck
cmpwi r25, 0x2B
ble beginCancel
cmpwi r25, 0x46
blt waitCheck
cmpwi r25, 0x4A        #various landings
ble beginCancel
cmpwi r25, 0xE9
blt waitCheck
cmpwi r25, 0xEC        #various dodges
ble beginCancel

waitCheck:
cmpwi r29, 0            #r29 still holds move Id, 00 is used for a large range of wait-like states
beq SFcheckAndReturn    #this return will terminate looping cancels when canceling whole moves
cmpwi r29, 0x58        #parasol falling; canceling this allows for infinite jumps...
beq SFcheckAndReturn

beginCancel:
#before starting, we use this bit to turn the player invisible
#while invisibility isn't a feature of this code, doing this prevents particles from spawning during cancel
lbz r3, 0x221e(r31)
ori r0, r3, 0x80
stb r0, 0x221e(r31)    #temporarily make player invisible, to stop particle spawns

#Now, we try the animation speed cancel. We do this by calling ICNv020_animationSpeedCancel
lwz r3, 0(r31)
bl <ICNCv020_animationSpeedCancel>

#The call doesn't return without updating some player stuff that should make the effect immediate
#so now we check the action state to make sure there was a transition
lwz r3, 0x10(r31)    #current action state
cmpw r3, r25        #compare with saved action state
beq abortActionState    #if the state hasn't changed, we attempt to (conditionally) use the other cancel method

#At this point, we've successfully used the animation speed cancel
#we just need to check to see if we're going to loop the cancel again from the parsed bool in r26
cmpwi r26, 0
bne loopCancel
b SFcheckAndReturn    #if not, then return; because we're finished~

abortActionState:    #branch here when animation speed cancel doesn't seem to work
#Sometimes it isn't possible to use a frame timer threshold to force an "animation interrupt"
#in these cases we use a less-safe cancel method--but with an animation interrupt function known to be safe.
#the drawback of this cancel is that it destroys the current action state progression, and preserves no subaction event data
#--In most cases, animation cancels can even be used in a similar fashion for a similar result
#the advantage however, is that this method may cancel things that otherwise softlock the player with an animation speed cancel

cmpwi r27, 0        #first make sure the "force preservation" option (from the parse) doesn't apply to this move
bne SFcheckAndReturn    #if it does, then return. It's assumed that moves given this option will actually cancel properly.

lwz r3, 0x4(r31)    #---Throwing this little bit in to cover up an old bug with 0x904
cmpwi r3, 7        #DI animations (like with falling states) cause the 0x904 cancel to freeze the game
bne notSheik        #sheik's chain whip uses DI animations
lwz r3, 0x10(r31)    #It isn't covered by "wait" states, so we add that here for now...
cmpwi r3, 0x15e
beq SFcheckAndReturn
cmpwi r3, 0x161
beq SFcheckAndReturn    #A messy mess. This allows the chain to be used cleanly, however.

notSheik:
lwz r3, 0(r31)
bl <ICNCv020_abortActionState>        #else, call abortActinState

SFcheckAndReturn:    #this does a check to see if we should convert state into a special falling state (helpless)
lwz r3, 0x10(r31)
cmpwi r3, 0x1D        #beginning of regular falling states
blt return
cmpwi r3, 0x26        #ending of regular falling states (includes damage fall)
bgt return
#under these circumstances, we just need to check the "force special falling" bool before we have enough info
#if it's == true, then we're going to convert the action state into a special falling
cmpwi r28, 0
beq return
#Since these are already assumed to be wait states, a normal animation interrupt will not work correctly.
#Instead, the action state needs to transition in some othere way. This can be tricky if the state isn't known at compile time
#Luckily we only need a specific state, which can be easily accomplished by setting up a call like so:
lwz r3, 0(r31)
li r4, 1        #this is how common air dodges handle calls to the special falling AS transition
li r5, 1
lwz r6, -0x514C(r13)    #floats
lfs f1, 0x340(r6)
lfs f2, 0x344(r6)
li r6, 0
bl 0x80096900

return:
lbz r26, 0x221e(r31)    #to ensure that the character is visible, we will mask out the invisibility bit we used to stop particles
andi. r26, r26, 0x7F    #currently this doesn't handle the few cases where you cancel into a state meant to be invisible
stb r26, 0x221e(r31)

lmw r3, 0x10(sp)
lfd f1, 0x8(sp)
addi sp, sp, 0xD0
lwz r0, 0x4(sp)
mtlr r0
blr





/*ICNCv020_animationSpeedCancel
r3 = player entity
This subroutine makes calls to the following game functions in order to void action state frame logic:
-- (8006F190) animationSpeedChange
-- (8006EBA4) ac_AS_AnimationFrameUpdate&More
-- (8006C80C) player article/projectile update/spawn function (?)
-- (8006A360) animation interrupt update (? -- "playerThinkAgain")

Successful animation interrupts are usually invoked by this nullification of frame logic;
however, it is dependent on the function pointed to in 0x2200 (0x21a0 internal)
-- it's possible to modify the above pointer in order to change the effect of this cancel before calling
-- doing this with wait states however may cause softlocks in a few character moves

This method of cancel will resolve subaction data and may be used to continue natural state progression
!!Because of this, an unsuccessfully handled cancel will sometimes result in 1000x frames worth of particle spawns
          -- an easy way to handle this is to prefix a call to this function with a write to this bit:

                lbz r26, 0x221e(r31)    #bit 0x80 in this byte makes the player turn invisible at some point in a frame update
            #    this bit is checked by GFX parses in order to skip particle spawns
*/

#the core of this concept was courteously provided by Achilles1515 on smashboards~

mflr r0
stw r0, 0x4(sp)
stwu sp, -0x18(sp)
stmw r30, 0x10(sp)
lwz r31, 0x2C(r3)       #trying to get in the habit of doing this in my prolog--good practice for player stuff

lfs f1, 0x89C(r31)      #we're going to store this so that we can optionally restore it before returning
stfs f1, -0x8(sp)       #

lfs f1,-0x179C(rtoc)    # load 1000.0 from table of contents; f1 function argument
                        #    f1=newframespeed, r3= "external player data offset" (I may adopt that notation)
lwz r3, 0(r31)        #make sure to pass player entity struct; do this properly by loading the pointer at 0x0(internal player)
bl 0x8006f190

#Now, to immediately force the effects of this animation speed transition,
#we make a call to the function that appears to be responsible for updating player action state frames
#it calls a number of functions that update the player based on the frame of the current action state.
#--this includes the player subaction event parsing loop function; which will (in theory) ignore all "timer" events
#Before returning, animation speed is returned to what it was before the action state transition (if it is still x1000.0)

#all of the following simply require the argument r3= external player data offset
#update frame (ac_AS_AnimationFrameUpdate&More) -- reads action state data, and other stuff
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006eba4
#update character projectile/article spawns -- will stop model spawining issues
lwz r3, 0(r31)        #in sequence with the previous call, this will also properly update projectile spawns
bl 0x8006C80C
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end is important)
lwz r3, 0(r31)        #this call softens up a blrl into the player's currently stored animation interrupt
bl 0x8006A360           #I haven't looked into it very far, so it may do other things as well

return:
lfs f0, -0x179C(rtoc)              #"1000.0"
lfs f1, 0x89C(r31)
fcmpu cr0, f1, f0               #make sure current animation speed hasn't been altered by action state change
bne noSpeedReset
lfs f1,-0x8(sp)                 # otherwise, load our original animation speed and restore it
                        #    f1=newframespeed, r3= external player data offset
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006f190

noSpeedReset:
lmw r30, 0x10(sp)
addi sp, sp, 0x18
lwz r0, 0x4(sp)
mtlr r0
blr







/*ICNCv020_abortActionState
r3 = player entity
This subroutine checks the ground/air state in order to assign standing/falling animation interrupts
player.0x904 (external) is used to create a "shortcut" to the assigned action state; aborting the previous one
--special falling interrupts are preserved, but will only apply to the current action state transition.
--"playerThinkAgain" is called in order to make this state change happen before returning
*/
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x10(sp)
stw r31, 0x8(sp)
lwz r31, 0x2C(r3)

lbz r3, 0x2073(r31)       #player move ID
cmpwi r3, 0
beq return        #don't attempt cancel on wait states

lwz r3, 0xE0(r31)
cmpwi r3, 0        #check if in air or on ground
beq ground
air:
lis r3, 0x800C
ori r3, r3, 0xB2F8    #animation interrupt used by "jump"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
b abortPoke
ground:
lis r3, 0x8009
ori r3, r3, 0x9E80    #animation interrupt used by "rebound"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
abortPoke:
li r3, 1
stw r3, 0x8A4(r31)    #do a hard 0x904 cancel that uses the animation interrupt pointer we just set
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end)
lwz r3, 0(r31)        #make sure to pass player entity struct;
bl 0x8006A360

return:
lwz r31, 0x8(sp)
addi sp, sp, 0x10
lwz r0, 0x4(sp)
mtlr r0
blr









(v0.20 demo video)

---

Legacy experiments:
The original concept explored what looks like an exploit involving action state frame mechanics via the memory address located at player.0x904. It was very unstable, but I created a heavy-handed actionstate mask that allows the concept to be exploited relatively safely. This version is very stable and has very few problems, but is quite large all on its own:

$Impossible Cancel v0.1.4b (Melee 1.02) [Punkline]
C206B090 0000002F
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200F4
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200A4 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810070
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820028
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000


Achilles suggested a far more elegant solution that involves utilizing the same mechanic that the game uses to make L-canceled aerial landing animations speed up. The idea is that by changing your animation speed to something ridiculous, you can effectively create an action state transition that takes only a single frame.

This comes with some animation-related glitches, but it is a far more stable solution than the above and thus requires much less code to work smoothly. Here’s an early implementation of an experimental fix for one of these animation problems related to spawning particle effects:

$Animation Cancel Concept v0.1.2 (Melee 1.02) [Achilles1515] [Punkline]
C206B844 00000007
838306C8 579F0001
41820028 579F06F7
40820020 C022E864
3FE08006 63FFF190
7FE803A6 7C7F1B78
4E800021 7FE3FB78
7C7C1B78 00000000
C2071048 00000006
80A308FC 3CC0447A
7C053000 60650060
40820014 3CC08007
60C611C4 7CC803A6
4E800020 80CA0008
60000000 00000000


There was some discussion about turning this into a special game type that used slow-motion in order to give players time to consider their technical options. Here are a couple versions of the Impossible Cancel (with animation bugs~) that incorporate early versions of a variable slowmo engine:

$Slowmo Combo Concept A (Melee 1.02) [Punkline]
C237E24C 00000016
48000018 3C1000A0
00000000 00125000
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C2069B64 0000000A
7C8802A6 48000005
7D4802A6 7C8803A6
394AFEFC 809A089C
3C60447A 7C041800
40A20020 888A0001
886A0002 7C841A14
886A0003 7C041800
41810008 988A0002
7F4AD378 7F43D378
60000000 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEA4 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B380064
7F1EC378 00000000
$Slowmo Combo Concept B (Melee 1.02)[Punkline]
C237E24C 00000016
48000018 604000A0
00000000 002932E0
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEFC 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B3A0064
7F1EC378 00000000

Original post with lots of info about early concepts:
(contains a lot of images, videos, documents, and codes exploring external player data offsets 0x904, 0x908, 0x444, and 0x44C)
Hey guys. First post here on smashboards.

Has anyone played around with Character Data offset 0x904 (from the RAM Address List?)

Poking it lets you cancel your action state on the next frame, and it isn’t picky about what actions it can be applied to. It’s a lot of fun, really unstable, and was virtually undocumented the last time I checked these forums.

Somebody left a note about it in the RAM Address List, but it just mentioned that poking it to “40c00000” (float “6.0”) will cancel the current action state. Indeed it does, and in fact any non-0 value will work--so for the sake of simplicity I’ve used “1” throughout my examples here.

Let me back up a little and explain that I’m not really much of a programmer, and I haven’t played a smash game in almost a decade.

I found this board sometime back in April 2015 while searching for how the Melee Impossible video was … possible. My search turned up very little, so I watched Dan’s excellent primer on writing Gecko Codes and meant to try and figure it out. (Thanks Dan!)

It didn’t take long for me to stumble upon 0x904 in the RAM Address List, so I’m assuming some of you have at least tried poking it.

I’ve spent some time experimenting with it and now I have a lot of information that doesn’t seem to be documented anywhere here. Admittedly, I don’t frequent these forums very often so I could be mistaken. I searched pretty fervently back in April-May for some answers however, and found no information.

Now that there’s a nice little sub-forum dedicated to posting codes, I figured this would be a great place to dump some info and maybe collaborate a little. My intention is to reproduce Melee Impossible in a form that is actually playable.

Here’s everything that I think I understand~

---

I remember reading a lot of speculation about how IASA frames couldn't be responsible for Melee Impossible. I know very little about IASA frames, or subactions for that matter. I think I remember people saying IASA frames would only work easily with normals, or something.

Ant-D claims in his video description (and paraphrases in his blog) that he “hacked/modified the game so that it is possible to L-Cancel any move whatsoever. This includes everything from running, B-specials, and grounded smash attacks.”

As far as I can tell, 0x904 has nothing to do with IASA frames. I could be wrong of course, but I don’t even know what it has to do with action states, really; as it appears to be a part of a function responsible for blending some animation keyframes.

Regardless, it can be applied to any action state just as Ant-D reported his hack could.

He also mentioned in his thread that he wouldn’t release his ASM code because his “‘mod is only stable when playing the game frame by frame. It will crash on different action states otherwise.”

This seemed to confuse some people, but makes perfect sense if you have the code to play around with.

I believe that by writing this 0x904 poke in a hook to the L/R button-press code in the main character loop, you end up with a cute little gecko code that perfectly resembles Melee Impossible. Verbatim! So try it yourself, if you’d like:

$Impossible Cancel v0.1.1 (Melee 1.02) [Punkline]
C206B0A4 00000002
38600001 907E0904
901F065C 00000000

The problem is that canceling from many specific action states (referred to as “problem states” in my notes) causes a consistent freezing behavior. One of these problem states is the falling state--in any of its forms.

The function that writes the digitized analog values as button presses to char data offset 0x6BC every frame is where our hook is (light L/R presses are represented as an ‘8’ in the leftmost nibble of the value stored in 0x6BC); and so our cancel code (as it is currently handled) gets executed every frame that the button is held down.

This results in a really common freezing behavior while holding L/R for any longer than a single frame in the air--as the action state that follows a canceled aerial action is a problem state (falling.) Here’s a slightly fleshed out list of the states that cause freezing behavior:
  • Falling animations
    • (these animations are permuted by DI inputs)
    • (note that the index of action state IDs includes a forward/back falling ID for each type of falling; but these seem to be vestigial as they appear unused by any of the normal characters)
  • Flinching and being grabbed.
  • Looping animations.
  • Animations with a “wait” state (some charge animations, or pikachu’s thunder)
    • (note that this surprisingly doesn’t include charged smashes)
Also, here are a few other circumstances where the game will freeze during a cancel. They are less generalized, and perhaps more telling of a cause:
  • GaW running animation (appears to have no blended keyframes in movement animations, as other characters do)
  • Sheik’s Chain (DI inputs determine the animation and function of this action, just like falling animations)
  • Mewtwo/Zelda/Sheik teleport landing on platform (with horizontal momentum)
  • Probably a bunch of other stuff that might be difficult to test.
In other words, playing without frame-perfect inputs and a bit of clairvoyance results in problem states triggering freezes like land mines. I’m almost certain that this is why Ant-D tried to explain that TASing was necessary to utilize his hack, and is probably why he thought it was too incomplete/embarrassing/whatever to release.

---

So, what can we do about these instabilities? It would be fairly simple to add conditions to the poke that act like filters for problem states, but this presents a new issue where “blacklisted” problem states are then completely unaffected by the cancel code.

This means that every blacklisted state limits the scope of the Impossible Cancel. It does however stop the freezing behavior and make things playable as demonstrated by this slight modification to the last code:

$Impossible Cancel v0.1.2 (Melee 1.02) [Punkline]
C206B0A4 00000005
807E0070 2C03001D
4180000C 2C030026
4081000C 38600001
907E0904 901F065C
60000000 00000000

This only covers a small bracket of action state IDs that account for falling states. You can try it in place of the 0.1.1 code though, and then not have to worry about freezing aerial attacks that wouldn’t otherwise be problematic.

For a long time, I used this code to test everything. I took a couple passes at each of the characters and searched for each of their problem states to be recorded in this document. This uncovered a second issue with this blacklist method, which is that there are simply too many problem states to individually blacklist using conditions like these.

You see, action states past 0x155 on the index are assigned uniquely by character, and so the conditions list becomes 2-dimensional. Specifying the characterID, actionstateID pairs necessary to identify each problem state results in an impractically long code because it has to account for (at least) each of the following:

I’m still learning how to read and write this stuff, but I made an ammature attempt to fit all of this information into a series of LONG variables and have a loop just read them off like normal conditional checks. I don’t recommend trying it, but I did leave some heavy comments in my dev journal if you’d like to review it.

$Impossible Cancel v0.1.3b (Melee 1.02) [Punkline]
C206B0A4 0000003A
480000E0 00000015
001D0026 00300030
004B005B 00910093
009F009F 00A300A3
00B700B7 00BF00BF
00CE00E3 00ED00FD
010A0154 01166364
696C6E71 03037277
04045556 57585962
64666768 696A6B6C
6D6E7476 78798185
86898A8D 05055659
5E5F6064 65666A06
14595C5E 61070756
5A5D5E60 61080857
5A5D5E61 62676B70
75090962 65720A0B
55560C17 585B5D60
68696C6D 0D0D580E
0E5D6265 66696A6E
700F0F55 56575859
5C5D5E5F 6465666A
10105657 5B5C5F60
1111585B 5C5E6162
121A565A 1313585B
18185700 309700C8
00000000 00000000
00000000 00000000
7C6802A6 48000005
7FE802A6 7C6803A6
3BFFFFE4 929F0004
92DF0008 92FF000C
931F0010 82DE0070
82FE0064 8A9F0000
A31F0002 7F18F850
A0780000 7C161800
41800010 A0780002
7C161800 40810080
3A94FFFC 3B180004
2C140000 4181FFDC
8A9F0001 88780000
7C171800 40820030
8C780001 2C030020
4081FFF8 3A800000
2C030020 40810018
60630100 7C161800
8C780001 41820038
4BFFFFE8 3A94FFFF
3B180001 2C140000
4181FFBC 2C170009
4182000C 2C170013
4082000C 2C160027
4182000C 38600001
907E0904 829F0004
82DF0008 82FF000C
831F0010 3BFE0060
901F065C 38600000
987F065C 00000000

It’s quite large, but actually pretty stable. Blacklisting every problem state by hand is obviously an accountability though, and the blacklist is far from perfect. In the end, I think this approach is too aggressive to be practical.

---

Let’s back up again. If we take a look at how 0x904 behaves, we can exploit something that provides a far more passive approach to fixing this problem.

0x904 appears to store a non-0 float value that determines the duration (in frames) of blended keyframe animations. These blending frames only seem to appear in some actions that revert back into standing or running states, as well as Peach’s float animation. They also appear in a select few B-specials.

0x908--the address just next-door--increments each frame (usually in whole float numbers) so long as 0x904 is not equal to 0. This increment stops once it is greater than or equal to the number stored in 0x904.

In other words, 0x904 defines a timer, and 0x908 increments it. This most commonly appears in the standing animation.

gfycat

The timer appears to control a blending effect that uses a keyframe (which is probably stored somewhere) from a previous animation to blend with a frame from a new animation.

Canceling the “squat” action so far has provided the best demonstration of this effect that I’ve been able to reproduce. Normally a standing or running animation will use 6.0 frames (0x40c00000) for the blend duration. For some reason, the crouching animation uses 30.0 frames (0x41f00000) and applies it to the animation AFTER the squat (idle crouching.) By canceling the squat action with a 0x904 poke, you can apply those naturally occurring 30.0 frames of blending to the squat (transition) animation instead of the idle crouch--and the effect becomes very dramatic.

gfycat

Poking 0x904 will have one of the 3 following effects:

  • If 0x904 is already 0--which is most of the time--poking it to ANY non-0 value has the effect of knocking the player out of their current action state
  • If 0x904 is storing a value, poking it to any non-0 value changes the number of frames that the current animation gets blended with the last one. Action states are NOT canceled under these circumstances.
    • Poking it to 0 in these cases cancels the animation.

When this keyframe blend function is not being used (which is most of the time,) setting the value of 0x904 to any non-0 value will set up the cancel effect on the following frame.

gfycat

When poking 0x908 (the current blend frame) along with 0x904 (blend duration) so that 0x908 == 0x904; the effect of the cancel is exactly the same, however instead of freezing during problem states, the blend process will lock the animation of the state as the last blended frame (usually standing, running, or falling.) This removes the freezing behavior from all common problem states, including all* B-specials, and repairs itself on the next action state load--which appears to function as normal.

* Sheik is a sole exception from my playtesting; her chain whip freezes appear to be related to falling freezes.

gfycat

Taking another pass at all of the characters using pokes to both 0x904 and 0x908 simultaneously, I made an updated document that accounts for the few remaining problem states (as I could find them.)


As you can see, the only remaining freezing behaviors are falling states and Sheik’s chain whip animations. Everything else is a state that I’ve identified as a “glitch” state.

It’s a little amusing to me that so many of the vanilla glitches can be accounted for by premature cancels. Many of them can be replicated via the Impossible Cancel, and so the game-breaking ones are represented in the above summary as purple.

It's interesting to note that with the 0x908 exploit, falling states can be canceled (and have a frozen animation, like other corrected problem states) only if there is absolutely no directional input. This doesn’t happen with a bare 0x904 poke, and I believe it may be an important clue.

If you don’t account for the glitch states, falling animations and Sheik’s weird input for her chain whip animation remain as the sole freezing behaviors that can be accounted for via a blacklist condition. A code written under these pretenses is consequently very small:

$Impossible Cancel v0.1.4a (Melee 1.02) [Punkline]
C206B090 0000000D
831E06B0 2C180000
41820054 831E0070
2C180026 40810040
2C18015D 41820020
2C18015E 41820018
2C180160 41820010
2C180161 41820008
48000010 831E0064
2C180007 41820010
3B000001 931E0904
931E0908 7FD8F378
3BFE0060 C0228874
60000000 00000000

This small version accounts for none of the glitch states, so it can be pretty unplayable with some characters. There's also one more freezing behavior. It’s the only other one I could identify, and it can’t be covered up with the 0x908 exploit. It’s also kind of weird.

To reproduce it in the above code, pick a former problem state like Pikachu’s charge/thunder attack, or Bowser’s down-B attack. While holding shield (light or heavy,) without rolling or dodging, do a directional shield jump into an aerial containing the former problem state before canceling the jump as you leave the ground.

If you did this correctly, the game should freeze. It happens accidentally quite often with any characters that had former problem states, and I believe it has something to do with shield angle, or the directional jump animation.

The reason I suspect this is because the only other 2 remaining freezing behaviors are Sheik’s whip and directional falling animations. All of these 3 behaviors seem to have their animations permuted by directional inputs, and appear to use no subactions.

I don’t know how to fix this, but I do know that this commonality might help us eventually find a solution.

With the exception of this one freezing behavior; the loop written for 0.1.3b can be refined to include only falling, the glitch states, and Sheik’s chain states.

To ease the potential of accidentally canceling shields, as well as the general input problems with using L/R as the cancel button during ground attacks… all versions of 0.1.4 disable the light shield mechanic of the game in favor of the cancel function. Eventually, I hope to refine this into a more elegant solution.

In addition, I’ve attempted to create a semi-automatic input method. The cancel effect cycles action states along their natural progression rather than immediately jumping to a standing state. This means that by simply writing out the logic for semi-automatic inputs, you end up having to press the button several times to progress through a single move that uses multiple actions…

I thought this might be desirable in some aspects, but in others it’s very cumbersome. Instead, what I did was create a semi-automatic trigger that uses a flag to start automatically canceling every single frame; whether the button is held down or not. This involved changing the position of the hook slightly.

Then, by including all standing-like states in the blacklist, reaching a standing-like state will stop the automatic canceling every frame. The resulting effect is a semi-automatic trigger that progresses through entire moves rather than single actions. It’s experimental, and it does make some really technical cancels impossible; but I think it makes inputs less cumbersome in general.

Heavy shields still work; but they also may trigger the above mentioned freezing behavior. If you intend to use my sloppy ASM proof-of-concept in actual gameplay, be prepared with savestates and avoid canceling jumps out of your shield:

$Impossible Cancel v0.1.4b (Melee 1.02) [Punkline]
C206B090 0000002F
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200F4
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200A4 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810070
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820028
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000

Here’s a dumb video I quickly made awhile back to demonstrate a few of the vanilla glitches I’ve kept in this version. They are mostly harmless, but there’s quite a lot of incredibly stupid things you can do with them. Note that the soulbreaker glitches are actually blacklisted; only demonstrated


---

That about wraps up everything I’ve done to make Ant-D’s concept more playable. I intend to further explore directional inputs and their effects on animations--as well as some other addresses referenced in the functions that use 0x904.

---

I have some remaining notes that are more or less just about the functionality of this cancel concept.

The above examples address the majority of freezing behaviors, but in a way that doesn’t allow for the involved actions to be canceled. This is preferable to freezing the game of course, but it limits the application of this cancel effect.

Earlier on--when I was still learning how to make sense of PPC instructions--I was searching for addresses in undocumented areas of the RAM Address List in Dolphin for any correlation to problem states. I found a relationship in address 0x444, which appears to be an address that stores floats for a timer function involved in queuing subaction commands using synchronous and asynchronous timers.

No new subactions are read while the timer in 0x444 is counting down. I didn’t really understand this at first, but I did see it counting down--so I experimented by poking the value to 0 on top of my 0x904 poke. It had very interesting effects on the character I was testing at the time:


Suddenly, with this extra poke, all of the former problem states for Pikachu responded to the cancel effect...

Lets take a quick look at 0x44C, a close neighbor of 0x444. I was quite excited to find this one.

0x44C points to a position in a list that looks like this:


After comparing this to some data in Crazy Hand, it dawned on me that 0x44C points to the next subaction command.

And indeed, you can manipulate subactions by manipulating this pointer. I tested this very briefly by identifying Marth’s down-a IASA frame command, and pointing to it in 0x44C after pausing in the middle of his smash attack. This resulted in allowing me to cleanly start a new smash attack like a natural IASA frame.

I believe this means that you could (in theory) save the address currently in 0x44C somewhere and replace it with a pointer to some fake subactions you’ve written in another area in memory; using the old 0x44C pointer as a return branch. It would allow you to append, skip, or replace subactions procedurally with code!

With an understanding of the syntax, it could also be used to monitor subactions as they are happening, perhaps utilizing them as complex conditions.

I imagine that with some knowledge of how subactions are encoded (which I expect a lot of you have) you could exploit this address for all kinds of beautiful things.

Anyway, I don’t want to stray too far from the topic. Brutishly exploiting 0x444 (specific to subaction timers) works wonders for some of the previously gimped Pikachu article spawns. It doesn’t however have the same effect on Link’s article spawns, for example.

gfycat

In particular--hitboxes, article spawns, sound effects, particles and some character model flashes seem to rely on these “timer” subaction commands for progression through an action. Without any of these timers, all available subaction commands are read in the same frame; but they are still each individually read.

The number of these timer subactions present in a whole action determines how many "keyframes" are read at different times during the action. In other words, all subactions are instantaneous except for these timer subactions that write to 0x444.

It would appear that a single 0x444 poke is all Pikachu's moves need to skip the meat of their action, but not Link's. I'll have to confirm this after taking a long look at their subactions with 0x44C.

I would offer some documentation for this code, but it's the exact same code as 0.1.4b, except that it pokes 0x444 to 0 on top of the 0x904/0x908 pokes.

$Impossible Cancel v0.1.4c (Melee 1.02) [Punkline]
C206B090 00000030
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200FC
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200AC 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810078
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820030
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
3B000000 931E0444
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000

I wrote a really buggy variation of 0.1.4c that tries to use a second hook inside of the function responsible for this subaction timer. The idea was to use the flag I’d made for the semi-auto input as a trigger to poke 0x444 to 0 instead of 0x904 to 1. Then, the second hook inside the subaction function (within the same frame) recognizes the flag stored in the first hook code as a LONG variable, and continuously pokes 0x444 to 0 every time it is executed (once per subaction command.) This becomes self perpetuating because of the location of the second hook.

Once the subaction command “00000000” (padding between whole actions) is read in by 0x44C, the loop automatically terminates, so (in theory) this should completely “flush” subactions in a single frame. Once 0x44C is empty, only then does 0x904 get poked to 1 in order to invoke the cancel effect.

I remember trying this experiment very late at night and having abysmal results that I didn’t want to debug; so I ended up with a really buggy code that wasn’t playable. It did at least allow me to make this TAS video, where Link’s article spawns are NOT cut off by the cancel.


As always you’re welcome to try it… but it’s quite unplayable. Something about the way I wrote it breaks the logic for the blacklist, and so it makes aerials freeze the game all over again. I think it has to do with the 0x444 poke to 0 transition into the second hook, as subactions often seem to “disappear” in all actions before the next former-problem state triggers a freeze.

It’s interesting to see what actions are like without any subactions though (not really,) and it’s possible to test it with TAS if you’re interested.

$Impossible Cancel v0.1.4d (Melee 1.02) [Punkline]
C206B090 00000032
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 41820108
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200B8 82DE0444
2C160000 408200AC
82DE0070 82FE0064
8A9F0004 A33F0006
7F39F850 A3190000
7C16C000 41800010
A3190002 7C16C000
40810078 3A94FFFC
3B390004 2C140000
4181FFDC 8A9F0005
8B190000 7C17C000
40820030 8F190001
2C180020 4081FFF8
3A800000 2C180020
40810018 63180100
7C16C000 8F190001
41820030 4BFFFFE8
3A94FFFF 3B390001
2C140000 4181FFBC
3B000001 931E0904
931E0908 3F000000
931E0444 4800000C
3B000000 9B1F0000
829F0008 82DF000C
82FF0010 833F0014
82BF0018 3BFE0060
7FD8F378 C0228874
60000000 00000000
C20732B0 0000000A
7FC802A6 48000005
7FA802A6 7FC803A6
3BBDFE9C 939D0008
8BDB006C 2C1E0003
4181001C 7FDEEA14
8B9E0000 2C1C0001
4082000C 3F800000
939B0444 3BDB0060
839D0008 3BBB0444
28000000 00000000

While this obviously appears to work with Link, I guess it isn't quite the solution. Where a single 0x444 poke would allow for Pikachu to spam his thunder and Link to only cancel his bombs; a continuous 0x444 poke allows for Link to spam his bombs, and Pikachu to only cancel his thunder.

I think I'll soon try using 0x44C as a replacement for action state ID and character ID checks. I'd like to see if everything (with the exception of the falling states and Sheik's whip) can be covered by a subaction blacklist.

Also, this subaction “flush” might be refined with a more intelligent condition to allow for all article spawns to resolve before cancels; and possibly even other things like hitboxes.

--

Finally, a little footnote about the case where 0x904 is already storing a float number. I mentioned this early on, but normally 0x904 only stores a float value during something like a standing action; so there’s no real reason to cancel these as they’ll only start a new standing action. There are however a few B-specials that use blending frames like this, and poking 0x904 to 1 will not allow these states to be canceled like everything else can.

Off the top of my head, the only 3 B-special actions effected by this are Marth/Roy’s side-B swipes (2nd, 3rd, and 4th only,) Luigi’s Green Missile, and the Ice Climbers’ recovery animation.

Each of these cases can still be canceled by poking 0x904 to 0 instead of 1. I haven’t included this in any of my codes, but I think it could be very simply implemented. One weird thing to consider is that sometimes, doing this in a standing animation will blend with a T-pose.

---

Anyway, that’s about everything I’ve got so far. I have a lot to learn still, but I hope that this information is sufficient enough to compensate for the apparent lack thereof surrounding this cancel concept. If anyone has any comments, suggestions, or critiques I’ll do my best to respond in a helpful manner and edit any information accordingly.

Also, feel free to play around with any of these codes/concepts and discuss your own ideas. I think there’s a lot left to be discovered about this address and its related mechanics.

Update with information about how to use animation interrupts and player updates to make previous exploits much safer:
There is a table at and around external player data offset 0x2200 that contains function pointers which--collectively--describe a lot of the variable functionality of the current action state for an allocated player in game.

They look like this, and there are likely a lot more of them than I’ve listed:

  • 0x21F0 - player grab? function pointer (I don’t know much about these)
  • 0x21F4 - (somehow related to grabbing)
  • 0x21F8 - held player behavior? function pointer

  • 0x21FC - IASA function pointer (Input-based interrupts)
  • >0x2200 - Animation interrupt function pointer (expiring state interrupts)
  • 0x2204 - Player physics function pointer
  • 0x2208 - Collisions function pointer
  • 0x220C - Camera function pointer

  • 0x221C - Character Article Function pointer? - appears to handle character article behavior of some kind… including the projectile flag set by player event 60.
Each and every one of these are used by an update function in order to link the functions they point to for the frame update via BLRL. The corresponding blrl locations, with screenshots:


  • 0x21FC - 8006b808 (PlayerThink_ControllerInputsToDataOffset)
  • >0x2200 - 8006ab74 (PlayerThinkAgain)
  • 0x2204 - 8006b8ac (PlayerThink_Physics)
  • 0x2208 - 8006c3a4 (zz_006c27c)
  • 0x220C - 8006da30 (zz_006d9ec)

  • 0x221C - 8006c9c0 (zz_006c80c) (the projectile flag is located in 0x80 of byte 0x2270)
In particular, for this code, the animation interrupt function used by the BLRL in “PlayerThinkAgain” is responsible for the “cancel” behavior. Knowing about this structure allows us to intercept the decision that the game makes about making action state transitions when a state expires.

---

From what little I’ve been able to surmise, the only reason that the 0x904 exploit (gone over in some detail at the spoilered bottom of my update op) seems to work at all is because of this check:



This function gets called from most animation interrupt functions (and many other functions) presumably as a way of defining a frame at which the transition is supposed to happen. It compares player 0x904 to 0, and if it isn’t equal to 0 then it skips the normal check routine and is conditionally handled (by the procedure branched to in yellow.)

This appears to involve flags used by the same table the game uses to look up player bones when assigning hitboxes... I don’t really know what that’s all about, but it seems like an interesting thing to investigate later.

---

The animation speed cancel introduced by Achilles presumably does an effectively similar thing; as the resulting return from this function is usually the same. It artificially increases the frame multiplier; which logically passes a similar result by sort of “flooding the gate.”

So, despite their slightly different approaches-- In each case, the animation interrupt runs its designated action state call immediately rather than on time.

The animation speed cancel however is particularly handy, because it has an effect on many other functions, and effects many frame-dependent behaviors. While this is slightly impeding in the scope of what it fully includes, it is also extremely useful for preserving action state data between action states. In this regard, I’ve done what I can to really take advantage of its ability to artificially progress through a move in my “soft” cancel.

---

I’ve adapted each of these former concepts into individual standalone functions that may be used to cancel an action state very simply in different (default) ways:

These are simplified versions of the core mechanics used in the “soft” cancel code. They may be used from many contexts without issue; though are each problematic under certain circumstances.

<ICNCv020_AnimationSpeedCancel>
#r3= external player data offset
#--sets animation speed to x1000
#--updates player frame stuff, which uses animation speed to create frame unit size
#--updates player article stuff (mask out bit 0x80 of player.0x2270 if you want to avoid projectiles)
#--attempts player animation interrupt check (cancels action state)
#--sets animation speed back to old speed if still == x1000 (cases where cancel fails)
7C0802A6 90010004
9421FFE8 BFC10010
83E3002C C03F089C
D021FFF8 C022E864
807F0000
bl 0x8006f190
807F0000
bl 0x8006eba4
807F0000
bl 0x8006C80C
807F0000
bl 0x8006A360
C002E864 C03F089C
FC010000 40820010
C021FFF8 807F0000
bl 0x8006f190
BBC10010 38210018
80010004 7C0803A6
4E800020


<ICNCv020_abortActionState>
#r3= external player data offset
#--if player is in air, set animation interrupt to transition into falling
#--else, set animation interrupt to transition into standing
#--set 0x904 to a non-0 value (bypasses frame logic check for next call)
#--attempt player animation interrupt check (cancels action state)
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 4182003C
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000
bl 0x8006A360
83E10008 38210010
80010004 7C0803A6
4E800020

The full cancel that I’ve called “soft cancel” utilizes both of these simple cancels in tandem, but they can be used on their own in most circumstances without any fatal issues.

The animation speed cancel is set up to preserve the next action state when canceling, but can also be used like the second cancel to less candidly “abort” an action state transition by preemptively setting the player’s animation interrupt pointer to a proper wait state (for standing, falling, special falling, etc.)

The “abort action state” cancel almost completely nullifies the rest of the action state by forcing an animation interrupt with only a call to PlayerThinkAgain to soften up the transition into a wait state.

---

By making a call to the function that this animation interrupt gets linked via BLRL (PlayerThinkAgain) we can update the player so that the transition is immediate within our code.

From the old animation speed cancel code--after making a call to the frame speed changing function--we can update the player’s frame data by calling this function (8006eba4) If we do this, we’ll get all subaction events to resolve like they normally would--but within the context of our call.

This is because the function is just an array of calls to these 4 other functions:

  • (8006e9b4) - ? -- I recall this being important to 0x904 and 0x908. I’ll try to take better notes about it later.
  • (80073240) - player subaction event parsing loop -- reads an animation frame’s worth of data
  • (800707b0) - ??
  • (800db500) - ??

To only surmise based on what little I know; this call seems to be important for updating data in a player’s current frame, and is called at least once every frame for ever character.

This call we’re making doesn’t account for any flags that may only have been initialized for other update functions to read through its execution--as many subaction events (and other things?) seem to create. This isn’t too much of a problem, but weird cancels account for a great number of the game’s normal vanilla glitches (like ice climbers’ icicles not despawning, link’s hookshot superjump, mewtwo’s “soulbreaker” grab, etc.)

Many of these will pop up while using “hard” (simple) cancels.

“Soulbreaker” glitches are easily handled by setting the grabbed player’s breakout timer to 0.

In addition, this function (8006c80c) may be called with the player frame update in order to handle what appears to be character-related article spawns; including a BLRL that links to the pointer in 0x221C, and seems to handle the projectile flag set by player event 60. The only exception I’ve witnessed is fox’s throw-laser projectiles; which might be handled by a special function elsewhere.

Making the above calls together appears to fix a number of glitches, and makes projectiles spawn before a cancel. Interesting to note that you can set this 0x221C pointer and then manually set the flag (bit 0x80 of player.0x2270) in order to spawn some character projectiles that are appropriate to your current character when this update function gets called.

Some known article functions used by the blrl link in this character article update function:

Code:
Character Projectile/Article spawning functions (Melee v1.02)
Update function 8006c80c -- (uses blrl to link to the following)
    internal player data offset 0x22BC -- contains pointer used by blrl
Projectile "spawn flag" is a flag used by player subaction event 60 to denote spawn timing for projectiles
    internal player data offset 0x2210 (bit 0x80) -- projectile spawn flag

Function    Uses spawn flag?    Description            Extra Notes
80095efc    0    (all thrown items)            universal throw, excludes aerial z-drops
800ce1d4    1    Use Ray Gun 
800d80f4    1    Use Super Scope (small bullets) 
800d86b8    1    Use Super Scope (charged bullet, any amount) 
800cd914    1    Use Star Rod 
800cdb9c    1    Use Lip Stick 
800ce650    1    Use Fire Flower            appears to have special interrupt logic

800e0ee0    1    Mario/Doc fireball/pill 
800e1248    0    Mario/Doc cape 
8014295c    1    Luigi fireball 
8011d018    1    Peach turnip 
8011d424    0    Peach parasol (startup) 
8011e174    0    Peach Toad 
8011e230    0    Peach Toad spore cloud 
80134590    0    Bowser down-B fall 
80134518    0    Bowser down-B land 
8012e110    1    Yoshi egg 
8012e644    0    Yoshi down-B land 
800bbcc0    0    Become Yoshi Egg (after grab) 
8010db3c    0    DK down-B 
8010e0cc    0    DK side-B 
800e5f28    0    Fox/Falco Laser 
N/A?        1    Fox/Falco Laser throw        These throws use projectile flag, but with some other function; not our common blrl
800e845c    0    Fox/Falco shine start 
800e83e0    0    Fox/Falco shine hold 
800e9df8    0    Fox/Falco side-B 
800e719c    0    Fox/Falco up-B start 
800e7100    0    Fox/Falco up-B launch 
80116b70    1    Ness PK fire 
80114eb8    0    Ness yoyo            used in both up and down smash
8011f500    0    IC icicle 
80122d2c    0    IC frost 
80123218    0    Nana up-B rope            only used by nana (subplayer)
800f21e8    0    Kirby up-B projectile            only on landing
800f53ac    0    Kiry Hammer 
800f9260    1    Kirby-Mario/Doc 
800f98f4    1    Kirby-Luigi 
8010c288    0    Kirby-Peach (toad) 
8010c344    0    Kirby-Peach (toad spore) 
800fe0e0    0    Kirby-Fox/Falco 
801090d4    0    Kirby-Popo/Nana 
80105a34    0    Kirby-Zelda 
80106db0    0    Kirby-Sheik 
8010cfb0    0    Kirby-GAW start            notable that GAW has no start/finish like this
8010ce5c    0    Kirby-GAW finish 
8010b1f4    0    Kirby-Marth/Roy 
800be6ac    0    Escape from Kirby star (after grab) projectile 
8012a074    1    Samus rocket 
8012adf0    1    Samus bomb 
8013a830    0    Zelda B 
801396ac    0    Zelda teleport start 
8013979c    0    Zelda teleport finish 
8013adb4    0    Zelda -> Sheik start 
8013aeac    0    Zelda -> Sheik finish 
80112d44    0    Sheik needle(s) throw 
8011097c    0    Sheik chain 
80112ed8    0    Sheik teleport start 
80113038    0    Sheik teleport finish 
80114034    0    Sheik -> Zelda start 
8011412c    0    Sheik -> Zelda finish 
800ec210    1    (y)Link boomerang 
800eb7c8    1    (y)Link bomb 
800eba4c    0    (y)Link up-B 
801277ac    1    Pi(ka)chu thunder            flag is near start of animation
80124c90    0    Pi(ka)chu start up charge 
80124d2c    0    Pi(ka)chu launch from charge 
8013c94c    0    JP sing 
8013ce7c    0    JP rest 
80146c08    0    Mewtwo side-B 
80146594    0    Mewtwo down-B 
801450a0    0    Mewtwo teleport start 
80145164    0    Mewtwo teleport finish 
80146594    0    GAW jab            many of GAW normals use models (articles?) that trigger these
8014ab48    0    GAW down-A 
8014a848    0    GAW f-smash 
8014b3a8    0    GAW u-air 
8014b45c    0    GAW u-air landing 
8014b1b4    0    GAW b-air 
8014b268    0    GAW b-air landing    other normals do not appear to use this blrl despite spawning models...
8014e4f0    0    GAW B 
8014c46c    0    GAW judgement 
8014def0    0    GAW up-B 
8014cbf4    0    GAW oil spill            only when used on full bucket
801365a8    0    Marth/Roy B            on attack

Noteworthy projectile moves that do not seem to appear on this list:
Bowser flame
Ness PK thunder
Ness PK flash
Samus (un)charge shot
Zelda fire/explode
(y)Link arrow
Pi(ka)chu B
Mewtwo shadowball

---

If an animation interrupt can’t be achieved from a state without some kind of special expiration condition (like, letting go of the B button, or often something more subtle than that) then the pointer in 0x2200 may be manually set to an animation interrupt function of your choice before attempting the call to PlayerThinkAgain.

By doing this with an interrupt function that transitions into a wait state like stand, fall, or special fall; you can usually safely use either cancel method to manually assign these action states and “skip” the remaining actionstate data.

I’ve opted to call PlayerThinkAgain for the interrupt to be handled in my code by a more natural context than calling the interrupt function directly; just to be safe.
 
Last edited:

Aerros11

Smash Journeyman
Joined
Sep 5, 2009
Messages
284
You discovered turbo mode o__o'|l!?

I really hope this becomes stable for a special melee <3
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Yeah! At least, that's the plan. I think there's a good chance, once I (or anyone else) figures out why the remaining instabilities are a problem.

As it stands, this is a little bit distinct from turbo mode. It's a lot closer to Melee Impossible, where the cancel is manually input via L/R presses; and so they can be applied to any action (not just attacks) at any time.

If you're interested in how this cancel method might be applied to a real turbo mode, try looking at character data offset 0x44C (assuming you're using Melee 1.02, use the address stored in 0x80453130, and offset it by 0x44C using a calculator.)

This address stores a pointer that describes the next subaction command, which is where IASA frames are specified.

If you manipulate this address, you can point it to whatever you like. I think it's possible to inject subactions this way.

I haven't looked into this at all, but I know that somebody also left an address for IASA frame check function in the SSBM Data sheet.

If you created a gecko code that injected IASA commands into every move, and then made a hook in the IASA frame check that applied this 0x904 cancel, it'd probably be a convenient method of recreating the conditions for turbo mode.

Edit: I'll try and see how this behaves later this week, if I can. I don't think it'd quite be enough to make turbo mode, but it might be a start.

Also, some mysterious hero left an entry for 0x904 in the RAM address list at least 6 months ago. It was just under the name "???"
 
Last edited:
Joined
Oct 10, 2011
Messages
1,126
Location
Boise, ID
NNID
dansalvato
Wtf dude is this like your PhD dissertation lol

I only skimmed it so far but this is pretty awsome.
 

zankyou

Smash Lord
Joined
Sep 12, 2014
Messages
1,055
Wow you took this a lot further than I did. I ended up making an array for the actions and whether or not they could be canceled. But I couldnt figure out how to make it so that when you cancel with L or R it doesnt immediately shield on the next frame.
 

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
This is a crazy awesome thread. Those TAS vids are out of this world cool.

So I read through this thread and then came up with this quick code. Maybe you can find use for it and combine it with something else, like disabling light shielding. It "cancels" animations by changing the animation speed to 1000 whenever L/R trigger is instant pressed. The character will instantly transition into whatever action state naturally comes next. I imagine it is stable though, but not thoroughly tested or anything.

Code:
inject @ 8006b844 - mr r28,r3
- in PlayerThink_Physics (of some sort) function, every frame per player
- at this point, r3 = external char data offset pointer


lwz    r28,0x6c8(r3)    # load instant buttons
rlwinm.    r31,r28,0,0,0    # check for (80000000) = l/r analog or dig or z button
beq-    END
rlwinm.    r31,r28,0,27,27    # check for (00000010) = Z button, skip if so
bne-    END
lfs    f1,-0x179C(r2)    # load 1000 from table of contents, function input
lis    r31,0x8006
ori    r31,r31,0xf190    # 8006f190 = FrameSpeedChange, f1=newframespeed, r3=external player data offset
mtlr    r31
mr    r31,r3        # save r3 (r31 gets stored to stack in 8006f190)
blrl        
mr    r3,r31        # restore r3

END:
mr r28,r3        # default code line
 
Last edited:

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Dan Salvato Dan Salvato
LOL. Yeah, sorry about the wall of text. I’ve had a lot of fun working on this so far.

Alongside your twitch video and a little bit of extra reading; exploring the functions and memory addresses behind this concept has basically taught me everything that I know about ASM. Thanks btw, for basically providing that.

Z zankyou
Ugh, I know what you mean. My 0.1.3b code is essentially just that; except I tried to split it into 2 arrays, with the latter one being a 2D array. The first one grabs all the action states that apply to every character (> 0x155) and the second one tries to assign the ones that need character IDs.

The immediate shield interruption on ground cancels was driving me nuts. I ended up just disabling light shields by changing my hook slightly in the main character loop to the place where analog (float) L/R inputs get summarized as a bit, and clobbering the appropriate float register with 0.

In one of my next versions, I’d like to put a condition on this that re-enables light shields something like 4-6 frames after a ground cancel using a stored timer. It’d be easy to tack onto the semi-auto input I used for 0.1.4b... I actually remember trying to do this early on, but it was while I was testing other things and it complicated my troubleshooting. I might try to re-implement this sometime soon.

BTW, for the longest time I thought an array was going to save this thing. It still basically is, for the case of “glitch states.”

I kept running into really strange cases for problem states though, like Mewtwo/Zelda’s teleport causing a freeze ONLY if you landed on a platform with horizontal momentum. Or this 1 frame in a safe action from peach’s side-B that would freeze with just the right DI. Cases like these made me decide an array of action states was specifying things too strictly. I got lucky while experimenting with 0x908, which solves just about everything without relying on an array, or ANYTHING really to define what a problem state “is.”

Aerros11 Aerros11
I forgot to mention, if you’re looking for something 100% stable that you can plop into a fancy dol mod, it’s relatively simple to “whitelist” a limited scope of action states for the cancel. If you do this for just normals (for example) then your only problem state is “rapid jab,” and it can easily be excluded.

The result is a small, safe code that works for just normal attacks:

$Impossible Cancel (Normals Only) (Melee 1.02) [Punkline]
C206B090 00000007
831E06B0 2C180000
41820028 831E0070
2C18002C 4180001C
2C180045 41810014
2C180030 4182000C
3B000001 931E0904
C0228874 00000000

ATM, this is the best I can offer for something “completely” stable. 0.1.4b is pretty close, but there’s still freezing behavior related to jumping out of shield that I’ve not been able to figure out.

Achilles1515 Achilles1515
Hahahaha, I love you Achilles. Whenever I’m reading through something here, I always see you around pulling stuff out of thin air like this lol.

I LOVE this idea, and I'm playing around with it atm. It doesn’t involve any weird DI game freezes! Most of the behaviors I’ve marked as “glitch states” persist, but that’s to be expected because of their nature (unspawning IC projectiles, broken link boomerang timer, unspawning prop models, etc.) It’s interesting to note that this re-fixed Link’s hookshot superjump though, lol.

I did notice however that when particles spawn (from things like charging B-specials,) their spawn rate is also increased by 1000x, and it makes for sudden FPS drops. It’s quite a spectacle when it happens. I think these are subactions though, particularly graphic effects, right? So maybe this could be solved with 0x44C?

You know, I’ve spent some time with this project, but it really does account for ALL of my experience with this any of this stuff. I’m still learning a lot every time I open Dolphin.

Your code is really informative to me, because it explains a little bit about the automation of the stack and how it can be used to store variables when calling other functions out of their context like that. At least, I think that’s what you did.

I’ve sort of got an idea of how the stack works, but no idea how to use it for sweet, clean solutions like that. Does this work because r31 is a “global” register like on this list? I don’t really understand rtoc either; did you just know beforehand that rtoc -0x179C would hold float 1000.0?

---

A QUICK UPDATE:

So earlier this week I tried to tear up the subaction function I was using for my 0.1.4d subaction “flusher” code. I used an abandoned Sheets project I had lying around that splits up and highlights function dumps from dolphin to provide some comments about how it works:

The function seems to run once per frame (per character) and is in charge of managing 0x444 (subaction timer,) 0x448 (subaction frame,) and 0x44C (next subaction command.) It has a few areas worth mentioning:

The first half of the function manages 0x448 and 0x444. They increment and decrement respectively, and 0x448 appears to reference 0x8F4 (“action state frame.”) What’s interesting though is that 0x444 appears to have a special “skip” code (0x7FF7FFFF) for skipping its decrement instructions. This frequently appears in dash actions, I’ve noticed.

The second half is about reading subactions from 0x44C. The end of the function has a condition that will run when 0x444 is 0, which checks if 0x44C contains a pointer. If it does, then it loops back 34 lines, to check everything all over again before continuing the frame. This lets it queue up subactions between timer commands.

Within this loop are 2 calls. The BL is a static branch that runs for every loop iteration. The function it calls checks the first byte of the subaction command pointed to in 0x44C and (sometimes) uses it as an offset for a pointer to use in a BLRL. So far, I’ve only seen Sync and Async subactions trigger this BLRL, but I haven’t looked into it very far. I’m not entirely sure what these do yet, but they obviously seem to be related to the timer.

The BL returns either a 1 or 0 to indicate whether or not it called a timer function. If it didn’t call a timer function, then the second call is constructed in a similar manner to the first BLRL, where the subaction’s first byte is used as an offset.

I think that this second BLRL is responsible for parsing subaction commands. I’ve dumped a few functions that get called from here into this document, along with my comments for “subaction_frame” and “subaction_timer”

Next week I’ll definitely be looking into this some more. I’ll also be fooling around with Achilles’ new cancel concept, and might start trying to see if it’s possible to inject IASA subactions. I may also work on a new light shield solution.
 
Last edited:

Aerros11

Smash Journeyman
Joined
Sep 5, 2009
Messages
284
Aerros11 Aerros11
I forgot to mention, if you’re looking for something 100% stable that you can plop into a fancy dol mod, it’s relatively simple to “whitelist” a limited scope of action states for the cancel. If you do this for just normals (for example) then your only problem state is “rapid jab,” and it can easily be excluded.

The result is a small, safe code that works for just normal attacks:

$Impossible Cancel (Normals Only) (Melee 1.02) [Punkline]
C206B090 00000007
831E06B0 2C180000
41820028 831E0070
2C18002C 4180001C
2C180045 41810014
2C180030 4182000C
3B000001 931E0904
C0228874 00000000

ATM, this is the best I can offer for something “completely” stable. 0.1.4b is pretty close, but there’s still freezing behavior related to jumping out of shield that I’ve not been able to figure out.
Canceling attacks is a pretty huge boost of offense to balance in a regular melee setting without any form of parrying. Maybe if V-canceling were replaced with the clash animation [Rebound] (and 0 knockback) this could be perfectly viable as a new intense version of melee.~

But for that, clashing would have to be enabled for aerial attacks as well. This would look funny and I doubt anyone will give balancing this a try but it's the best way in my opinion. Thanks for the code at any rate.

You sure picked this hacking bit up quickly by the way
 
Last edited:

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Achilles1515 Achilles1515
I took a look at one of the functions I dumped from the subaction_frame blrl that parses 0x44C.

Here’s the one for graphicEffect:

It does a lot of stuff, but branches only happen at the top and bottom. I looked at these for a minute and it seemed like it was doing a sort of “else” call under certain conditions, and pointing the PC here seemed to stop the currently spawning particle.

I wrote a code that hooks from the beginning of what I assume are parsing instructions for this kind of subaction, and made a condition that checks animation speed. If it's equal to 1000, then it just branches over to the "else" function.

When you use it together with your code, it stops particles from recreating the big bang every time you cancel. I just plopped it on the end of it here:

$Animation Cancel Concept v0.1.2 (Melee 1.02) [Achilles1515] [Punkline]
C206B844 00000007
838306C8 579F0001
41820028 579F06F7
40820020 C022E864
3FE08006 63FFF190
7FE803A6 7C7F1B78
4E800021 7FE3FB78
7C7C1B78 00000000
C2071048 00000006
80A308FC 3CC0447A
7C053000 60650060
40820014 3CC08007
60C611C4 7CC803A6
4E800020 80CA0008
60000000 00000000

I’ve only tested it briefly, but from what I’ve seen this is very stable. I really think this might lead to full, stable release soon. It might be possible to get this to spawn particles at a 1:1000 ratio in order to correct the particles, rather than basically NOP them.

You can bet I’ll be messing around with this all week. Thanks a ton for this, dude.

Aerros11 Aerros11
You know, that’s a brilliant idea. I don’t quite know how to do something like that, but I think I know where I’d start looking. That’s definitely something I’ll think about.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Punkline, that is smart thinking. The function you found is indeed what controls creating subaction graphics. Other notes I have about subaction commands:

Code:
0x803c06e8 (RAM) - start of subaction event function pointers

To find a function for a subaction:
Take the command byte and divide by 4.

% If less than (decimal) 10,
-->
multiply by 4, add to 803b9840. Pointer at that address points to the subaction function


% If greater than or equal to (decimal) 10
-->
Subtract 10 (decimal).
Multiply by 4, convert back to hex, and add to 3c06e8.
Pointer at that address points to the subaction function.


A Few Nice Subaction Functions:

80071028   SubactionEvent_0x28_GFXSpawn
8007121C   SubactionEvent_0x2C_HitboxMelee_StoreInfoToDataOffset
802790C0   SubactionEvent_0x2C_HitboxProjectile_StoreInfoToDataOffset
800717D8   SubactionEvent_0x40_HitboxRemove
80071820   SubactionEvent_0x4C_AutoCancel_Enable/Disable
80071950   SubactionEvent_0x5C_IASAEnable
80071A14   SubactionEvent_0x66_BodyStateChange_Character
80071A9C   SubactionEvent_0x70_BodyStateChange_Hurtbubble
80071D40   SubactionEvent_0x7C_CharacterModelModifiers(e.g. Link Sword)
80072A5C   SubactionEvent_0xB8_BodyAura (e.g. Hit by Fire)
80072BF4   SubactionEvent_0xCC_DamageSelf
80072E4C   SubactionEvent_0xDC_GFX&SFX
80073008   SubactionEvent_0xE0_SmashAttackHold
Analyzing the functions within a specific SubactionEvent function can net you some really powerful skills.

800bffd0 GFX/ColorOverlay_Apply

20XX NBA Jam Mode
-Going from Fire to Darkness-Fire


Savestate Savestate flieskiller flieskiller
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Another idea.

I could be wrong because I've never tried this game mode with another human, but I feel like getting extremely technical, fast, and smart with your impossible cancels, especially in close combat, would require inhuman reaction speeds. Sort of similar to your TAS vids, what if the game speed dropped to 0.5x every time an attack landed. Then you implemented a function, executed every frame, that monitors the game speed and if less than 1.0x, will ramp the game speed back up to 1.0x at a fairly quick rate (maybe only half a second or so).

So after you land an attack, it gives you a chance to think about and execute stringing impossible canceled attacks together.

Also, should you not be able to cancel during hitlag?

If this becomes a stable, and fun game mode, I can implement it in the 20XX pack, probably replacing the Slo-Mo Special Game Mode.
Code:
Disable Slo-Mo Melee Game Speed Modification
041BA5B4 4E800020


Slo-Mo Melee Mode Check to put at beginning of functions (arbitrary registers):
lis    r14,0x8048
lbz    r14,-0x62D0(r14) #load menu controller major (80479d30)
cmpwi    r14,0x12    #is this slo-mo melee mode?
bne-    END

#stuff to execute in slo-mo melee mode

END:
 
Last edited:

Aerros11

Smash Journeyman
Joined
Sep 5, 2009
Messages
284
Another idea.

I could be wrong because I've never tried this game mode with another human, but I feel like getting extremely technical, fast, and smart with your impossible cancels, especially in close combat, would require inhuman reaction speeds. Sort of similar to your TAS vids, what if the game speed dropped to 0.5x every time an attack landed. Then you implemented a function, executed every frame, that monitors the game speed and if less than 1.0x, will ramp the game speed back up to 1.0x at a fairly quick rate (maybe only half a second or so).

So after you land an attack, it gives you a chance to think about and execute stringing impossible canceled attacks together.

Also, should you not be able to cancel during hitlag?

If this becomes a stable, and fun game mode, I can implement it in the 20XX pack, probably replacing the Slo-Mo Special Game Mode.
Code:
Disable Slo-Mo Melee Game Speed Modification
041BA5B4 4E800020


Slo-Mo Melee Mode Check to put at beginning of functions (arbitrary registers):
lis    r14,0x8048
lbz    r14,-0x62D0(r14) #load menu controller major (80479d30)
cmpwi    r14,0x12    #is this slo-mo melee mode?
bne-    END

#stuff to execute in slo-mo melee mode

END:
Better if slow down on cancel, not on attack hit?
 

Savestate

Smash Cadet
Joined
Apr 14, 2015
Messages
38
Location
Greensboro, NC
Sort of similar to your TAS vids, what if the game speed dropped to 0.5x every time an attack landed. Then you implemented a function, executed every frame, that monitors the game speed and if less than 1.0x, will ramp the game speed back up to 1.0x at a fairly quick rate (maybe only half a second or so).
[/code]
Hmm, what if 2/3rds slowdown was activated if two players' distances were within a certain range, and when an attack is put out at this range it pushed down to 1/2? It's not too hard to use the distance formula with two characters' x/y positions. You just need to hardcode the slowdown distance as a floating point number and use that in the calculation of the distance using the distance formula. I will definitely have to mess with this this weekend.
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Hey guys, another quick update.

I had a little field day with your slowmo idea, Achilles1515 Achilles1515 . Aerros11 Aerros11 has a good point about the slowmo being useful on cancel, but after writing and testing it I’ve found this creates an annoying disconnection with its predictability, as anyone can just rapidly cancel things all willy nilly in order to alter the global speed.

Savestate Savestate has the right idea, I think; where proximity has a big role in keeping the effect from becoming overwhelming, or frustrating. I think though the same thing can be more or less achieved more simply along Achilles’ original idea of just making it on attack, so that it’s just contact-based. I’m really interested to see what that would look and feel like though, so I’m anticipating whatever you write up.

I actually just wanted to play around with values for now, so I wrote something that I guess you can think of as a concept for a slowmo engine. I’d like to stress concept, as I have no idea how to optimize it.

It has a main hook that does a basic calculation for game speed using variables contained in the head of the code. You can edit them as default values before you save them into dolphin, or in the middle of a match using debug dolphin (or other codes.)

I’ve included 2 hooks that act as events to accumulate slowmo (on combo gain, on cancel) and my old hook from some of the earlier Impossible Cancel codes that helps easily disable light shield for applying the cancel and monitor any per-player values.

Note that this code (by default) assumes a normal gap between c2 codes from the vanilla code handler:

$Slowmo Combo Concept A - Combos (Melee 1.02) [Punkline]
C237E24C 00000016
48000018 3C1000A0
00000000 00125000
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C2069B64 0000000A
7C8802A6 48000005
7D4802A6 7C8803A6
394AFEFC 809A089C
3C60447A 7C041800
40A20020 888A0001
886A0002 7C841A14
886A0003 7C041800
41810008 988A0002
7F4AD378 7F43D378
60000000 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEA4 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B380064
7F1EC378 00000000
Edit: ASM

It’s really just another unoptimized experiment, but I tried to write it out in a way that should be easy to take apart. It references stored values in a little table of memory in the head of first c2 code. I used this to play with variables for the slowmo calculation for a pretty long time and came up with very different results by exploring the extremes. I encourage you to tweak the default settings.

At the moment, frame counts are limited to the byte range, but you can of course extend them.

1byte-
0x0: frameThreshold -determines frame where speed is 100% slow, defines slowmo acceleration
0x1: slowIncrement -determines the number of frames added with each accumulation of slowmo
0x2: frameCountdown -stores current countdown frame, keeps track of slowmo accumulation
0x3: maxFrame -determines maximum frame count for countdown, defines slowmo duration cap
0x4: hitlagFlag -keeps memory of whether or not somebody is experiencing hitlag

4byte-
0x8: addDenom - Numerator is added to this to create denominator, defines slowmo speed limit
0xC: register storage
0x10 register storage




It uses 4 hooks, and each references this data table at the top of the first code. I don’t know how to do this properly, but so far I’ve been getting by with this little dance:

0x00 mflr rA
0x04 bl 0x4
0x08 mflr rB #<<rB now points to 0x08
0x0C mtlr rA #restore previous LR
0x10 subi rB, rB, 0xOFFSET #<<rB now points wherever you like, relative to 0x08

I think I remember reading that there was a gecko op for pointing to codes, but I never ended up figuring it out. I’d like to optimize this if possible, so let me know if there’s a better way.

Anyway, here’s some pseudocode:

Code:
@GlobalFrameTick (once per frame)
is frame == 0? Then set Denominator to = Numerator RETURN
Decrement frame, unless somebody is experiencing hitlag
calculate slowmo value:
    if frame > threshold, then set Denominator to = addDenom + Numerator
    else, Denominator = frame*(threshold/addDenom) + Numerator

@??? (on combo accumulation?) (references both attacker and defender player pointers)
is frame + increment <= maxFrame?
then frame += increment

@actionstateLoad (Memcheck on “action state count,” for player)
is player.animationSpeed = 1000.0 and frame + increment <= maxFrame?
then frame += increment

@player.mainLoop (once per frame, per player -- L/R analog summary)
#f1 = interpreted L/R Analog value, used by game to summarize light shield
is player.hitlag != 0? then mark hitlagFlag for global tick to see
is this frame’s L/R != 0, and last frame’s L/R == 0?
    then call FrameSpeedChange with f1 = 1000.0, and r3=player.0x0
f1 = 0 (to stop light shield)
In other words, hook 1 stores the variables and updates the gamespeed, 2 detects attacks from combos, 3 detects cancels during actionstate load, and 4 monitors hitlag for global flag, applies cancel on light L/R, and diables light shield.

You can take away hooks 2-4 and replace them with other codes that take advantage of the same variables in different ways, if you’d like to really play with this.

It’s just an experiment though, and I’m pretty sure be writing more of these later… I’m really curious if slowmo can be achieved with frameSpeedChange rather than actually slowing down the game speed with the speed denominator. My hope is that it would result in a slowmo method that doesn’t drop any frames.

---

Also, while this cancel is now quite stable; there are plenty of animation related glitches with conditions that eerily resemble the problems I had with 0x904 and 0x908. A good example is how all falling animations can’t be canceled, and attempting to will just cause your tumble spin animation (or whatever falling state) to become hilariously fast.

It’s only aesthetics in many cases, but at least some of the characters I’ve tested also have these uncancelable actions that break the fluidity of control you feel just because they can’t be canceled like everything else; especially with the slowmo mod and the shield disabled. It really feels like a lot of control now, too.

These uncancelable actions line up pretty neatly with other actions that caused issues in my previous codes so far, but there are several exclusions that don’t seem to have any trouble.

My experiments with Link and Pikachu using 0x904 and 0x444 allowed me to fuss with things at the subaction level, and that seemed to be the key to getting Link’s bombs and boomerangs to cancel neatly. I see pikachu has been influenced in about the same way as my 0.1.4C code, so I guess I’ll keep fussing with subactions.
 
Last edited:

Savestate

Smash Cadet
Joined
Apr 14, 2015
Messages
38
Location
Greensboro, NC
Ok, I don't know if this is relevant to the area in the character data you're working with, but setting the byte at 0x2218 to 0xC0 allows all normal moves to be interrupted. Nothing else though.

Code:
addi r3, r30, 0

addi sp, sp, -4
stw r31, 0(sp)

li r31, 0xC0
stb r31, 0x2218(r4)

lwz r31, 0(sp)
addi sp, sp, 4
Code:
C206B804 00000004
387E0000 3821FFFC
93E10000 3BE000C0
9BE42218 83E10000
38210004 00000000
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Ok, I don't know if this is relevant to the area in the character data you're working with, but setting the byte at 0x2218 to 0xC0 allows all normal moves to be interrupted. Nothing else though.

Code:
addi r3, r30, 0

addi sp, sp, -4
stw r31, 0(sp)

li r31, 0xC0
stb r31, 0x2218(r4)

lwz r31, 0(sp)
addi sp, sp, 4
Code:
C206B804 00000004
387E0000 3821FFFC
93E10000 3BE000C0
9BE42218 83E10000
38210004 00000000
That is the IASA on/off flag. Not by my computer at the moment, but look at the function for IASA_Enable that I mentioned above. And it shouldn't need to be 0xC0, but just needs to contain 0x80. If you wanted to enable it via a code like you made, you should load the current 0x2218 byte, rlwimi a 1 bit into the correct location to make (00000080), then store it back to 0x2218. Just check that IASA enable function.
 
Last edited:

Savestate

Smash Cadet
Joined
Apr 14, 2015
Messages
38
Location
Greensboro, NC
To slow the game down with frameSpeedChange, you'd probably need to slow down a bunch of other physics related things, which might get really hairy. I've been messing around with the speed denominator a bit though and put together a little code that slows the game down when a physical hit connects, and slowly ramps back up to normal speed. This way, as long as you can keep a combo going, it'll stay relatively slow.

Code:
# 0x8007892c
# Sets speed to 1/5th normal speed
# when a direct attack connects

addi sp, sp, -8
stw r30, 0(sp)
stw r31, 4(sp)

lis r31, 0x8043
ori r31, r31, 0x2A2C

lis r30, 0x0033
ori r30, r30, 0x7F98

stw r30, 0(r31)

lwz r30, 0(sp)
lwz r31, 4(sp)
addi sp, sp, 8

fmr f31, f1
Code:
# 0x80390D08
# executed once per frame
# ramps frame speed back to normal speed

backup_stack:
subi sp,sp,16
stw r28,0(r1)
stw r29,4(r1)
stw r30,8(r1)
stw r31,12(r1)

load_speed:
lis r31,0x8043
ori r31,r31,0x2A2C
lwz r30,0(r31)

orig_speed:
lis r29,0x000A
ori r29,r29,0x4CB8

get_difference:
sub r29,r30,r29
li r28,32
cmpw r29,r28
bgt- ramp_speed
set_to_orig_speed:
lis r29,0x000A
ori r29,r29,0x4CB8
stw r29,0(r31)
b restore_stack

ramp_speed:
divwu r29,r29,r28
sub r30,r30,r29
stw r30,0(r31)

restore_stack:
lwz r28,0(r1)
lwz r29,4(r1)
lwz r30,8(r1)
lwz r31,12(r1)
addi r1,r1,16

replacement:
subi r3,r3,7296
Gecko Code

Code:
C207892C 00000007
3821FFF8 93C10000
93E10004 3FE08043
63FF2A2C 3FC00033
63DE7F98 93DF0000
83C10000 83E10004
38210008 FFE00890
60000000 00000000
C2390D08 0000000E
3821FFF0 93810000
93A10004 93C10008
93E1000C 3FE08043
63FF2A2C 83DF0000
3FA0000A 63BD4CB8
7FBDF050 3B800020
7C1DE000 41810014
3FA0000A 63BD4CB8
93BF0000 48000010
7FBDE396 7FDDF050
93DF0000 83810000
83A10004 83C10008
83E1000C 38210010
3863E380 00000000
Video in Action:
 

flieskiller

Smash Journeyman
Joined
Jan 3, 2013
Messages
426
^
Can you set the speed reduction length based on attack power (like Knockback or damage)?
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Savestate Savestate Nice! So this has a hook that detects “on hit” events, and sets the slow all the way to 1/5th speed on each hit? The effect is a lot stronger than the default values on my code, so it’s a lot more noticeable. I think I can tweak mine to resemble that.

Sorry for the delay on the ASM for my concept above. Let me step through it really briefly to better illustrate how to use it. First, here's a more explanatory diagram:


First, the code defines a maximum frame, to describe a time resolution for the accumulation to cap at.

Then, it sets a threshold frame, which is simply the frame on the scale that tells the code to calculate 100% slowmo effect. This can be altered to change the acceleration of slowmo accumulation.

Then, it defines an increment value, which is just a number that other hooks can use to scale the incremental accumulation of slowmo. In your case, increment would be == threshold.

Then, it sets a speed limit by defining addDenom, which is just a value that gets added to the value of the numerator in order to create the speed used for 100% slowdown when calculating the denominator. The default 1/1 speed is 0xA4CB8, which is a clean 675,000 in dec, so “addDenom” is added to 675,000 in order to create the denominator value used in the update hook.

I’ve tweaked these values, and excluded the hook for detecting cancels so that it better resembles your code. I think I'll extend all of these frame variables to 2-byte in my next version, and include a decrement value:

$Slowmo Combo Concept B (Melee 1.02)[Punkline]
C237E24C 00000016
48000018 604000A0
00000000 002932E0
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEFC 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B3A0064
7F1EC378 00000000

This should let you play with the length/strength/acceleration of the slowmo effect mid-game, without having to rewrite anything. Just poke the red values that are in the head of the code (follow branch 8037E24C)

Alternatively, you can edit them as default values when entering the code.

---

Also, thanks a ton for pointing out the IASA flag. And Achilles1515 Achilles1515 for clarifying which bit it was. I have a bunch of subaction function dumps I was going to scrutinize this weekend (thanks for making that simple for me too, Achilles,) and I remembered seeing the IASA function was tiny as hell, and branched into nothing. I noticed it poking a character data value in the 0x2000 range, so I was suspicious it might be this simple.

I find it really interesting that such powerful statuses can be described by these simple flags. Some of my earliest experiments in trying to get the shield to play nice with my cancel involved these flags too. I'm curious about what else they do, as they're referenced everywhere.

I'm also eager to try using the stack pointer like you just did in your code o_o


flieskiller flieskiller I think this would be a good example of something that'd be easy to append. It depends though if either of those values are integers.

The above code consists of hook 1 (on global tick, update slowmo) hook 2 (on attack, increment slowmo for update,) and hook 3, which deals with the cancel.

Hook 2 basically looks like this:

onAttack
if frame + increment <= maxFrame, then frame += increment

I don’t know how damage or knockback values are calculated, but if they are just integers then it’d be as simple as replacing the above with the following:

onAttack (or maybe, onKnockback)
if frame + (increment * knockback) <= maxFrame, then frame += (increment * knockback)

Increment could then be set to a low value that multiplies by knockback, which would then be applied on hit.
 
Last edited:

flieskiller

Smash Journeyman
Joined
Jan 3, 2013
Messages
426
^ Both knockback and damage applied to the player are floats... However, idk if it can be found, but the amount of frames in hitstun for the hit player is surely an integer, so it could be searched to be used. Also, can it scale with speed too? (Young Link up-b would be faster than a knee for instance)
 

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Nice video, Savestate Savestate . That's pretty much exactly what I was thinking in my head. I'd have to play with the code to get a feel for if 1/5 is a good slow down speed or not (have not tested the code yet).


flieskiller flieskiller , I can foresee slowing the game down even more on stronger attacks being a possible nuisance. But it really just depends on what speeds you go down to. Because Melee, in a way, already has a built in game slowdown on strong hits, which is hitlag. So if you heavily slow down, while the amount of frames in hitlag increases, then both players spend more time in hitlag frames, basically doing nothing which might get annoying.


The slo-mo thing just can't:

1) Be annoying or "too much".

2) Significantly extend match length.


Also savestate, I did a quick check and noticed your injection point for slowing the game down on hit does not get exectuted for projectiles and attacks like Fox/Falco side-b.


Below might be a better injection point, which should get executed for any attack that causes hitlag. It also allows you to easily experiment with Flieskiller's suggestion.






Side Note:

It makes me very happy to see new ASM hackers in the Workshop.
 
Last edited:

ProDevin

Smash Rookie
Joined
Dec 18, 2015
Messages
5
I might sound really stupid by saying this, but are you able to make another code to not press L/R each time you want to cancel? I have no GameCube adapter/controller to actually get the cancels (having to use keyboard controls) and that I can't really change the stats due to not knowing much.
 

gamerfreak5665

Smash Rookie
Joined
Dec 19, 2014
Messages
11
Wow Punkline Punkline , this is incredible! I don't really understand all the technical stuff, but I've been trying to cancel moves manually with Crazy Hand program, randomly putting in IASA slots in moves to see if they would work. This makes things a lot easier. I appreciate your effort in making Melee Impossible Cancel a reality!
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Necromancy update: 4/29/2016
Impossible Projectiles Cancel v0.20


Hey!

My apologies to those who were involved with this project earlier on. I made a volley of experiments to try out some of your suggestions, but then got stuck after some silliness in my code started crashing the game. I ended up taking a break to read up on a few things that were giving me issues, and I guess I then let my other projects distract me after taking some time to build up a better fundamental understanding of what I’m doing with code.

My old gecko codes are wretchedly naive. My new code probably is as well; however I know a lot more about ASM at this point (and a bit more about Melee) so I’m confident I can give this project some TLC.

I took some time to rewrite it as something that handles all of the things that were slowing me down before in the past. It is by no means final, and still has a lot of fat to be trimmed--but is very stable.

---

I’ve made a couple of revisions out of my many former concepts. They create two different methods of invoking the same animation interrupt blrl.

A third (much larger) experimental code uses the two revisions together in order to sort of cover up each other’s weaknesses and provide an extremely flexible cancel.

I've provided a C2 and injection mod package containing them all. I recommend using the injection mod, which makes great use of MCM’s special branch syntax and can be used to write other codes with the same functions.

While still unoptimized, the results of this experimental cancel are quite effective and will probably closely resemble (in function) the kind used in a completed v1.00 release:

Get the newest code here:
Code:
-==-
Impossible Cancel v0.20 (library)
Stable recreation of "Melee Impossible"
[Punkline]
Version -- DOL Offset ------ Hex to Replace ---------- ASM Code

1.02 ----- 0x8006b090--- C03F0650 -> Branch
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
bl <ICNCv020_softCancel>
9061FFF8 7FC3F378
83C1FFF8 C0228874
00000000


<ICNCv020_softCancel>
#r3= external player data offset
#experimental
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 480000F8
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000
bl <ICNCv020_animationSpeedCancel>
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000
bl <ICNCv020_abortActionState>
807F0010 2C03001D
41800034 2C030026
4181002C 2C1C0000
41820024 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
bl 0x80096900
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020


<ICNCv020_animationSpeedCancel>
#r3= external player data offset
#--sets animation speed to x1000
#--updates player frame stuff, which uses animation speed to create frame unit size
#--updates player article stuff (mask out bit 0x80 of player.0x2270 if you want to avoid projectiles)
#--attempts player animation interrupt check (cancels action state)
#--sets animation speed back to old speed if still == x1000 (cases where cancel fails)
7C0802A6 90010004
9421FFE8 BFC10010
83E3002C C03F089C
D021FFF8 C022E864
807F0000
bl 0x8006f190
807F0000
bl 0x8006eba4
807F0000
bl 0x8006C80C
807F0000
bl 0x8006A360
C002E864 C03F089C
FC010000 40820010
C021FFF8 807F0000
bl 0x8006f190
BBC10010 38210018
80010004 7C0803A6
4E800020


<ICNCv020_abortActionState>
#r3= external player data offset
#--if player is in air, set animation interrupt to transition into falling
#--else, set animation interrupt to transition into standing
#--set 0x904 to a non-0 value (bypasses frame logic check for next call)
#--attempt player animation interrupt check (cancels action state)
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 4182003C
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000
bl 0x8006A360
83E10008 38210010
80010004 7C0803A6
4E800020
$Impossible Cancel v0.20 [Punkline]
C206B090 0000006A
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
48000019 9061FFF8
7FC3F378 83C1FFF8
C0228874 4800030C
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 48000104
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000 480000B9
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000 4800011D
807F0010 2C03001D
41800040 2C030026
41810038 2C1C0000
41820030 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
3D808009 618C6900
7D8803A6 4E800021
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020 7C0802A6
90010004 9421FFE8
BFC10010 83E3002C
C03F089C D021FFF8
C022E864 807F0000
3D808006 618CF190
7D8803A6 4E800021
807F0000 3D808006
618CEBA4 7D8803A6
4E800021 807F0000
3D808006 618CC80C
7D8803A6 4E800021
807F0000 3D808006
618CA360 7D8803A6
4E800021 C002E864
C03F089C FC010000
4082001C C021FFF8
807F0000 3D808006
618CF190 7D8803A6
4E800021 BBC10010
38210018 80010004
7C0803A6 4E800020
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 41820048
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000 3D808006
618CA360 7D8803A6
4E800021 83E10008
38210010 80010004
7C0803A6 4E800020
60000000 00000000

I’ve made my syntax highlighted ASM available at a glance here:
Code:
/*Impossible Cancel v0.20 (library) [Punkline]
Stable recreation of "Melee Impossible" -- an unavailable cancel code that was apparently never playable.
Now available in the following forms, in descending order of flexibility and complexity:

--Soft Cancel -- safe, stable, versatile, customizable, really big
--Animation Speed Cancel -- safe, may cause glitchs in limited cases (special thanks to Achilles for this concept!)
--Abort Action State -- simple, rigid, potentially unsafe when used from falling states

Any or all of this library may be included in MCM (or a DOL mod)
Doing so will allow codes to be written that utilize these cancels from any context
*/

#example injection mod:

#Impossible Cancel 0.20 (Melee 1.02) [Punkline]
#@8006b090: lfs f1, 0x0650 (r31)        (checking analog input for digitization)
#lr, cr0 and f0 are safe to use
#r3 == internal player data offset 0x65C (digital button data)
#r30 == external player data offset 0x0 (player entity)
#r31 == internal player data offset 0x0 (player data)
#f1 == to become analog L/R value for current frame
#0x778C(rtoc) == 0.0 (no analog L/R press to digitize)

lfs f1, 0x0650 (r31)     #original instruction, loads current frame L/R value for digitization in digital buttons
lfs f0, -0x778C (rtoc)    #load 0.0 for comparison
fcmpu cr0, f0, f1        #compare to current L/R value
beq return               #return if not pressed
lfs f1, 0x654(r31)       #else, check last frame value
fcmpu cr0, f0, f1
bne return               #if this isn't empty, then analog button was not pressed on this frame


stw r3, -0x8(sp)         #temporarily store this; it gets saved in r30 (which is backed up in call)
mr r3, r30
lwz r30, -0x8(sp)         #swaps r3 and r30; so we pass and save registers appropriately
bl <ICNCv020_softCancel>
stw r3, -0x8(sp)
mr r3, r30
lwz r30, -0x8(sp)         #swap registers again, everything back to normal~

return:
lfs f1, -0x778C (rtoc)    #Sheild nop overwrites Original Instruction
.long 0x00000000         #hard return (compiled by MCM)





/*ICNCv020_softCancel
r3 = player entity
This function uses some extra logic to wrap conditions around a procedure that
tries to intelligently uses both of the other cancles provided in this library.
Experimental.
*/

mflr r0
stw r0, 0x4(sp)
stwu sp, -0xD0(sp)
stfd f1, 0x8(sp)
stmw r3, 0x10(sp)       #follow your dreams~
lwz r31, 0x2C(r3)

loopCancel:        #some moves will continue canceling until they reach a wait state
#First we parse an array of data located in the inline data table after these instructions
lwz r30, 0x4(r31)    #r30 = (real) player character ID
lbz r29, 0x2073(r31)    #r29 = (real) player move ID
li r28, 0        #r28 = bool (force special falling?)
li r27, 0        #r27 = bool (force preservation?)
li r26, 0        #r26 = bool (loop cancel?)
bl getParseDataTable
mflr r3            # r3 = parse data pointer
lhz r4, 0(r3)        # r4 = starting hword entry from data table

parseLoop:
rlwinm. r0,r4,0,25,31    #check if the (7-bit) move ID is 00
beq grabCheck        #if so, terminate loop (00 is a termination code)
cmpw r0, r29        #else, start parsing the entry
bne parseNextEntry    #check for move ID match
rlwinm r0,r4,24,26,31
cmpw r0, r30        #check for character ID match
bne parseNextEntry
#at this point, we've found an entry in the table that matches our current character move
#so we save the bools for the code to use later in order to make some decisions about how to work the cancel

#--The parse is basically answering the following questions for us:
rlwinm r28,r4,17,31,31    #do we want to convert non-special air wait states into special falling?
rlwinm r27,r4,18,31,31    #do we want to avoid "aborting" the action state if we have problems?
rlwinm r26,r4,25,31,31    #do we want to keep canceling this move until it reaches a wait state?
b grabCheck

parseNextEntry:
lhzu r4,2(r3)        #load next hword to be parsed
b parseLoop        #loop back to actually parse it

getParseDataTable:
#This is an inline data table. It contains hardcoded variables that get parsed by the above system.
#It's possible to organize this table as a standalone function--but this data has little remote application...
#--Each hword in the array is an entry that is parsed like so:
#0x8000 - bool         -- "force special falling" -- the cancel will assign special falling instead of falling
#0x4000 - bool         -- "force preservation" -- the cancel will avoid using the "abort actionstate" fallback
#0x3F00 - 6-bit ID     -- internal character ID (specifies a character for "character move")
#0x0080 - bool         -- "continue cancel until wait state"
#0x007F - 7-bit ID     -- common move ID (specifies a move for "character move")
#--0x00 as a move ID is a termination code for the parse loop
blrl    #any branches to "parseData" will return with a pointer to the data in lr
.hword 0x0191    #fox laser
.hword 0x0194    #fox shine

.hword 0x8113    #fox firefox
.hword 0x8493    #kirby upB

.hword 0x0496    #kirby foxB
.hword 0x049C    #kirby NessB

.hword 0x04A2    #kirby jpB
.hword 0x04A9    #kirby falcoB

.hword 0x0594    #Bowser downB
.hword 0x8713    #Sheik upB

.hword 0x4794    #Sheik downB
.hword 0x0991    #Ness B

.hword 0x0C94    #Pikachu thunder
.hword 0x8C13    #Pikachu quick attack

.hword 0x0E94    #yoshi downB
.hword 0x0F91    #JP B

.hword 0x9013    #Mewtwo Teleport
.hword 0x9313    #Zelda upB

.hword 0x5394    #Zelda downB
.hword 0x1691    #Falco laser

.hword 0x1694    #Falco Shine
.hword 0x9613    #Falco firebird

.hword 0x1794    #Pichu thunder
.hword 0x9713    #Pichu quick attack

.hword 0x0000    #terminate parse
.hword 0x0000
#make sure to pad this if necessary in order to stay 32-bit aligned

grabCheck:
#Check if player is holding another player.
#-- We want to prevent a "soulbreaker" glitch, so we handle this by making the grab expire
lwz r3, 0x1A58(r31)        #grabbed player entity slot
cmpwi r3, 0
beq ASblacklist
lwz r3, 0x2C(r3)        #if a player entity is in this slot, then load data
li r0, 0
stw r0, 0x1A4C(r3)        #kill breakout countdown
b return            #and simply return

ASblacklist:    #a hardcoded blacklist that stops the cancel during certain moves/action states
#-- for some wait states, this is to prevent technical problems that may arise from wait-state interrupt logic
#-- for other states, it is mostly for the sake of preserving gameplay mechanics

lwz r25, 0x10(r31)    #player action state; we're going to check this again later, so save in r25

cmpwi r25, 0x11        #masks out AS 0x00-0x11 (death-walking)
ble SFcheckAndReturn    #-- without this you can cancel your death animation and rack up SDs. Almost kept it.

#these are some whitelist entries; to be exceptions for the "wait state" check that follows
#they're kind of last-minute additions that can be optimized, but allow this to cancel jumps and things
cmpwi r25, 0x18        #kneebend
beq beginCancel
cmpwi r25, 0x27        #squat
beq beginCancel
cmpwi r25, 0x29        #squat reverse
blt waitCheck
cmpwi r25, 0x2B
ble beginCancel
cmpwi r25, 0x46
blt waitCheck
cmpwi r25, 0x4A        #various landings
ble beginCancel
cmpwi r25, 0xE9
blt waitCheck
cmpwi r25, 0xEC        #various dodges
ble beginCancel

waitCheck:
cmpwi r29, 0            #r29 still holds move Id, 00 is used for a large range of wait-like states
beq SFcheckAndReturn    #this return will terminate looping cancels when canceling whole moves
cmpwi r29, 0x58        #parasol falling; canceling this allows for infinite jumps...
beq SFcheckAndReturn

beginCancel:
#before starting, we use this bit to turn the player invisible
#while invisibility isn't a feature of this code, doing this prevents particles from spawning during cancel
lbz r3, 0x221e(r31)
ori r0, r3, 0x80
stb r0, 0x221e(r31)    #temporarily make player invisible, to stop particle spawns

#Now, we try the animation speed cancel. We do this by calling ICNv020_animationSpeedCancel
lwz r3, 0(r31)
bl <ICNCv020_animationSpeedCancel>

#The call doesn't return without updating some player stuff that should make the effect immediate
#so now we check the action state to make sure there was a transition
lwz r3, 0x10(r31)    #current action state
cmpw r3, r25        #compare with saved action state
beq abortActionState    #if the state hasn't changed, we attempt to (conditionally) use the other cancel method

#At this point, we've successfully used the animation speed cancel
#we just need to check to see if we're going to loop the cancel again from the parsed bool in r26
cmpwi r26, 0
bne loopCancel
b SFcheckAndReturn    #if not, then return; because we're finished~

abortActionState:    #branch here when animation speed cancel doesn't seem to work
#Sometimes it isn't possible to use a frame timer threshold to force an "animation interrupt"
#in these cases we use a less-safe cancel method--but with an animation interrupt function known to be safe.
#the drawback of this cancel is that it destroys the current action state progression, and preserves no subaction event data
#--In most cases, animation cancels can even be used in a similar fashion for a similar result
#the advantage however, is that this method may cancel things that otherwise softlock the player with an animation speed cancel

cmpwi r27, 0        #first make sure the "force preservation" option (from the parse) doesn't apply to this move
bne SFcheckAndReturn    #if it does, then return. It's assumed that moves given this option will actually cancel properly.

lwz r3, 0x4(r31)    #---Throwing this little bit in to cover up an old bug with 0x904
cmpwi r3, 7        #DI animations (like with falling states) cause the 0x904 cancel to freeze the game
bne notSheik        #sheik's chain whip uses DI animations
lwz r3, 0x10(r31)    #It isn't covered by "wait" states, so we add that here for now...
cmpwi r3, 0x15e
beq SFcheckAndReturn
cmpwi r3, 0x161
beq SFcheckAndReturn    #A messy mess. This allows the chain to be used cleanly, however.

notSheik:
lwz r3, 0(r31)
bl <ICNCv020_abortActionState>        #else, call abortActinState

SFcheckAndReturn:    #this does a check to see if we should convert state into a special falling state (helpless)
lwz r3, 0x10(r31)
cmpwi r3, 0x1D        #beginning of regular falling states
blt return
cmpwi r3, 0x26        #ending of regular falling states (includes damage fall)
bgt return
#under these circumstances, we just need to check the "force special falling" bool before we have enough info
#if it's == true, then we're going to convert the action state into a special falling
cmpwi r28, 0
beq return
#Since these are already assumed to be wait states, a normal animation interrupt will not work correctly.
#Instead, the action state needs to transition in some othere way. This can be tricky if the state isn't known at compile time
#Luckily we only need a specific state, which can be easily accomplished by setting up a call like so:
lwz r3, 0(r31)
li r4, 1        #this is how common air dodges handle calls to the special falling AS transition
li r5, 1
lwz r6, -0x514C(r13)    #floats
lfs f1, 0x340(r6)
lfs f2, 0x344(r6)
li r6, 0
bl 0x80096900

return:
lbz r26, 0x221e(r31)    #to ensure that the character is visible, we will mask out the invisibility bit we used to stop particles
andi. r26, r26, 0x7F    #currently this doesn't handle the few cases where you cancel into a state meant to be invisible
stb r26, 0x221e(r31)

lmw r3, 0x10(sp)
lfd f1, 0x8(sp)
addi sp, sp, 0xD0
lwz r0, 0x4(sp)
mtlr r0
blr





/*ICNCv020_animationSpeedCancel
r3 = player entity
This subroutine makes calls to the following game functions in order to void action state frame logic:
-- (8006F190) animationSpeedChange
-- (8006EBA4) ac_AS_AnimationFrameUpdate&More
-- (8006C80C) player article/projectile update/spawn function (?)
-- (8006A360) animation interrupt update (? -- "playerThinkAgain")

Successful animation interrupts are usually invoked by this nullification of frame logic;
however, it is dependent on the function pointed to in 0x2200 (0x21a0 internal)
-- it's possible to modify the above pointer in order to change the effect of this cancel before calling
-- doing this with wait states however may cause softlocks in a few character moves

This method of cancel will resolve subaction data and may be used to continue natural state progression
!!Because of this, an unsuccessfully handled cancel will sometimes result in 1000x frames worth of particle spawns
          -- an easy way to handle this is to prefix a call to this function with a write to this bit:

                lbz r26, 0x221e(r31)    #bit 0x80 in this byte makes the player turn invisible at some point in a frame update
            #    this bit is checked by GFX parses in order to skip particle spawns
*/

#the core of this concept was courteously provided by Achilles1515 on smashboards~

mflr r0
stw r0, 0x4(sp)
stwu sp, -0x18(sp)
stmw r30, 0x10(sp)
lwz r31, 0x2C(r3)       #trying to get in the habit of doing this in my prolog--good practice for player stuff

lfs f1, 0x89C(r31)      #we're going to store this so that we can optionally restore it before returning
stfs f1, -0x8(sp)       #

lfs f1,-0x179C(rtoc)    # load 1000.0 from table of contents; f1 function argument
                        #    f1=newframespeed, r3= "external player data offset" (I may adopt that notation)
lwz r3, 0(r31)        #make sure to pass player entity struct; do this properly by loading the pointer at 0x0(internal player)
bl 0x8006f190

#Now, to immediately force the effects of this animation speed transition,
#we make a call to the function that appears to be responsible for updating player action state frames
#it calls a number of functions that update the player based on the frame of the current action state.
#--this includes the player subaction event parsing loop function; which will (in theory) ignore all "timer" events
#Before returning, animation speed is returned to what it was before the action state transition (if it is still x1000.0)

#all of the following simply require the argument r3= external player data offset
#update frame (ac_AS_AnimationFrameUpdate&More) -- reads action state data, and other stuff
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006eba4
#update character projectile/article spawns -- will stop model spawining issues
lwz r3, 0(r31)        #in sequence with the previous call, this will also properly update projectile spawns
bl 0x8006C80C
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end is important)
lwz r3, 0(r31)        #this call softens up a blrl into the player's currently stored animation interrupt
bl 0x8006A360           #I haven't looked into it very far, so it may do other things as well

return:
lfs f0, -0x179C(rtoc)              #"1000.0"
lfs f1, 0x89C(r31)
fcmpu cr0, f1, f0               #make sure current animation speed hasn't been altered by action state change
bne noSpeedReset
lfs f1,-0x8(sp)                 # otherwise, load our original animation speed and restore it
                        #    f1=newframespeed, r3= external player data offset
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006f190

noSpeedReset:
lmw r30, 0x10(sp)
addi sp, sp, 0x18
lwz r0, 0x4(sp)
mtlr r0
blr







/*ICNCv020_abortActionState
r3 = player entity
This subroutine checks the ground/air state in order to assign standing/falling animation interrupts
player.0x904 (external) is used to create a "shortcut" to the assigned action state; aborting the previous one
--special falling interrupts are preserved, but will only apply to the current action state transition.
--"playerThinkAgain" is called in order to make this state change happen before returning
*/
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x10(sp)
stw r31, 0x8(sp)
lwz r31, 0x2C(r3)

lbz r3, 0x2073(r31)       #player move ID
cmpwi r3, 0
beq return        #don't attempt cancel on wait states

lwz r3, 0xE0(r31)
cmpwi r3, 0        #check if in air or on ground
beq ground
air:
lis r3, 0x800C
ori r3, r3, 0xB2F8    #animation interrupt used by "jump"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
b abortPoke
ground:
lis r3, 0x8009
ori r3, r3, 0x9E80    #animation interrupt used by "rebound"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
abortPoke:
li r3, 1
stw r3, 0x8A4(r31)    #do a hard 0x904 cancel that uses the animation interrupt pointer we just set
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end)
lwz r3, 0(r31)        #make sure to pass player entity struct;
bl 0x8006A360

return:
lwz r31, 0x8(sp)
addi sp, sp, 0x10
lwz r0, 0x4(sp)
mtlr r0
blr












To briefly summarize how this differs from old versions:

  • Calls to various player update functions have been used in order to make the old animation speed cancel immediate and properly handle article spawns.
    • This includes the handling of the flag in bit 0x80 of byte 0x2270; which is set by player event 60 during specific action states. As a result, projectile spawns are preserved. This may be controlled by manipulating the flag.
    • This also makes transitions “frame-perfect” and allows simultaneous inputs with a cancel to skip wait states.
  • In instances where the animation speed cancel is unsuccessful in canceling a move, player.0x2200 has been used to reassign natural animation interrupts before using the simple 0x904 poke method to create a hard “shortcut” that preserves no action state data; aborting any queued up subaction events, or the like--but in a consistently safe way.
Each of the former concepts seem to be capable of separately handling just a few cases that the other can’t when attempting the player.0x2200 manipulation before an interrupt check. Both don’t respond very well to being used during wait states (like standing or falling) and in the case of the old 0x904 poke method can still result in a frozen game (not crashed; recoverable via savestate.) (for anyone curious, here’s where ground-zero is for the old freezing behavior)

So, the bigger “soft” cancel that uses each of them handles just about everything else behind the scenes to create a versatile application of everything I know about naturally canceling an action state. It should really be able to take a beating.

---

My previous concepts have been included in the form of small, optimized standalone functions (see “simple cancels” in the “forcing animation interrupts” notes spoiler below; or the code ASM/injection mod package.)

They may be called to provide the same cancel methods used by the above “soft” cancel from the context of any code that you might be writing yourself. Doing so from a limited context will allow you to take advantage of a much smaller code size in order to accomplish more focused applications of the same cancel concepts.

Eventually, I’ll be adapting parts of the “soft” cancel into an optimized 3rd function.

More details about “animation interrupts,” (like those definable by Crazy Hand 3.1+ Move Logic table @Tater, @Ampers, @tatatat0) -- and how this concept has been exploited in my new code :

There is a table at and around external player data offset 0x2200 that contains function pointers which--collectively--describe a lot of the variable functionality of the current action state for an allocated player in game.

They look like this, and there are likely a lot more of them than I’ve listed:

  • 0x21F0 - player grab? function pointer (I don’t know much about these)
  • 0x21F4 - (somehow related to grabbing)
  • 0x21F8 - held player behavior? function pointer
  • 0x21FC - IASA function pointer (Input-based interrupts)
  • >0x2200 - Animation interrupt function pointer (expiring state interrupts)
  • 0x2204 - Player physics function pointer
  • 0x2208 - Collisions function pointer
  • 0x220C - Camera function pointer
  • 0x221C - Character Article Function pointer? - appears to handle character article behavior of some kind… including the projectile flag set by player event 60.
Each and every one of these are used by an update function in order to link the functions they point to for the frame update via BLRL. The corresponding blrl locations, with screenshots:

  • 0x21FC - 8006b808 (PlayerThink_ControllerInputsToDataOffset)
  • >0x2200 - 8006ab74 (PlayerThinkAgain)
  • 0x2204 - 8006b8ac (PlayerThink_Physics)
  • 0x2208 - 8006c3a4 (zz_006c27c)
  • 0x220C - 8006da30 (zz_006d9ec)
  • 0x221C - 8006c9c0 (zz_006c80c) (the projectile flag is located in 0x80 of byte 0x2270)
In particular, for this code, the animation interrupt function used by the BLRL in “PlayerThinkAgain” is responsible for the “cancel” behavior. Knowing about this structure allows us to intercept the decision that the game makes about making action state transitions when a state expires.

---

From what little I’ve been able to surmise, the only reason that the 0x904 exploit (gone over in some detail at the spoilered bottom of my update op) seems to work at all is because of this check:



This function gets called from most animation interrupt functions (and many other functions) presumably as a way of defining a frame at which the transition is supposed to happen. It compares player 0x904 to 0, and if it isn’t equal to 0 then it skips the normal check routine and is conditionally handled (by the procedure branched to in yellow.)

This appears to involve flags used by the same table the game uses to look up player bones when assigning hitboxes... I don’t really know what that’s all about, but it seems like an interesting thing to investigate later.

---

The animation speed cancel introduced by Achilles presumably does an effectively similar thing; as the resulting return from this function is usually the same. It artificially increases the frame multiplier; which logically passes a similar result by sort of “flooding the gate.”

So, despite their slightly different approaches-- In each case, the animation interrupt runs its designated action state call immediately rather than on time.

The animation speed cancel however is particularly handy, because it has an effect on many other functions, and effects many frame-dependent behaviors. While this is slightly impeding in the scope of what it fully includes, it is also extremely useful for preserving action state data between action states. In this regard, I’ve done what I can to really take advantage of its ability to artificially progress through a move in my “soft” cancel.

---

I’ve adapted each of these former concepts into individual standalone functions that may be used to cancel an action state very simply in different (default) ways:

These are simplified versions of the core mechanics used in the “soft” cancel code. They may be used from many contexts without issue; though are each problematic under certain circumstances.

<ICNCv020_AnimationSpeedCancel>
#r3= external player data offset
#--sets animation speed to x1000
#--updates player frame stuff, which uses animation speed to create frame unit size
#--updates player article stuff (mask out bit 0x80 of player.0x2270 if you want to avoid projectiles)
#--attempts player animation interrupt check (cancels action state)
#--sets animation speed back to old speed if still == x1000 (cases where cancel fails)
7C0802A6 90010004
9421FFE8 BFC10010
83E3002C C03F089C
D021FFF8 C022E864
807F0000
bl 0x8006f190
807F0000
bl 0x8006eba4
807F0000
bl 0x8006C80C
807F0000
bl 0x8006A360
C002E864 C03F089C
FC010000 40820010
C021FFF8 807F0000
bl 0x8006f190
BBC10010 38210018
80010004 7C0803A6
4E800020


<ICNCv020_abortActionState>
#r3= external player data offset
#--if player is in air, set animation interrupt to transition into falling
#--else, set animation interrupt to transition into standing
#--set 0x904 to a non-0 value (bypasses frame logic check for next call)
#--attempt player animation interrupt check (cancels action state)
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 4182003C
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000
bl 0x8006A360
83E10008 38210010
80010004 7C0803A6
4E800020

The full cancel that I’ve called “soft cancel” utilizes both of these simple cancels in tandem, but they can be used on their own in most circumstances without any fatal issues.

The animation speed cancel is set up to preserve the next action state when canceling, but can also be used like the second cancel to less candidly “abort” an action state transition by preemptively setting the player’s animation interrupt pointer to a proper wait state (for standing, falling, special falling, etc.)

The “abort action state” cancel almost completely nullifies the rest of the action state by forcing an animation interrupt with only a call to PlayerThinkAgain to soften up the transition into a wait state.

---

By making a call to the function that this animation interrupt gets linked via BLRL (PlayerThinkAgain) we can update the player so that the transition is immediate within our code.

From the old animation speed cancel code--after making a call to the frame speed changing function--we can update the player’s frame data by calling this function (8006eba4) If we do this, we’ll get all subaction events to resolve like they normally would--but within the context of our call.

This is because the function is just an array of calls to these 4 other functions:

  • (8006e9b4) - ? -- I recall this being important to 0x904 and 0x908. I’ll try to take better notes about it later.
  • (80073240) - player subaction event parsing loop -- reads an animation frame’s worth of data
  • (800707b0) - ??
  • (800db500) - ??

To only surmise based on what little I know; this call seems to be important for updating data in a player’s current frame, and is called at least once every frame for ever character.

This call we’re making doesn’t account for any flags that may only have been initialized for other update functions to read through its execution--as many subaction events (and other things?) seem to create. This isn’t too much of a problem, but weird cancels account for a great number of the game’s normal vanilla glitches (like ice climbers’ icicles not despawning, link’s hookshot superjump, mewtwo’s “soulbreaker” grab, etc.)

Many of these will pop up while using “hard” (simple) cancels.

“Soulbreaker” glitches are easily handled by setting the grabbed player’s breakout timer to 0.

In addition, this function (8006c80c) may be called with the player frame update in order to handle what appears to be character-related article spawns; including a BLRL that links to the pointer in 0x221C, and seems to handle the projectile flag set by player event 60. The only exception I’ve witnessed is fox’s throw-laser projectiles; which might be handled by a special function elsewhere.

Making the above calls together appears to fix a number of glitches, and makes projectiles spawn before a cancel. Interesting to note that you can set this 0x221C pointer and then manually set the flag (bit 0x80 of player.0x2270) in order to spawn some character projectiles that are appropriate to your current character when this update function gets called.

Some known article functions used by the blrl link in this character article update function:

Code:
Character Projectile/Article spawning functions (Melee v1.02)
Update function 8006c80c -- (uses blrl to link to the following)
    internal player data offset 0x22BC -- contains pointer used by blrl
Projectile "spawn flag" is a flag used by player subaction event 60 to denote spawn timing for projectiles
    internal player data offset 0x2210 (bit 0x80) -- projectile spawn flag

Function    Uses spawn flag?    Description            Extra Notes
80095efc    0    (all thrown items)            universal throw, excludes aerial z-drops
800ce1d4    1    Use Ray Gun     
800d80f4    1    Use Super Scope (small bullets)     
800d86b8    1    Use Super Scope (charged bullet, any amount)     
800cd914    1    Use Star Rod     
800cdb9c    1    Use Lip Stick     
800ce650    1    Use Fire Flower            appears to have special interrupt logic

800e0ee0    1    Mario/Doc fireball/pill     
800e1248    0    Mario/Doc cape     
8014295c    1    Luigi fireball     
8011d018    1    Peach turnip     
8011d424    0    Peach parasol (startup)     
8011e174    0    Peach Toad     
8011e230    0    Peach Toad spore cloud     
80134590    0    Bowser down-B fall     
80134518    0    Bowser down-B land     
8012e110    1    Yoshi egg     
8012e644    0    Yoshi down-B land     
800bbcc0    0    Become Yoshi Egg (after grab)     
8010db3c    0    DK down-B     
8010e0cc    0    DK side-B     
800e5f28    0    Fox/Falco Laser     
N/A?        1    Fox/Falco Laser throw        These throws use projectile flag, but with some other function; not our common blrl
800e845c    0    Fox/Falco shine start     
800e83e0    0    Fox/Falco shine hold     
800e9df8    0    Fox/Falco side-B     
800e719c    0    Fox/Falco up-B start     
800e7100    0    Fox/Falco up-B launch     
80116b70    1    Ness PK fire     
80114eb8    0    Ness yoyo            used in both up and down smash
8011f500    0    IC icicle     
80122d2c    0    IC frost     
80123218    0    Nana up-B rope            only used by nana (subplayer)
800f21e8    0    Kirby up-B projectile            only on landing
800f53ac    0    Kiry Hammer     
800f9260    1    Kirby-Mario/Doc     
800f98f4    1    Kirby-Luigi     
8010c288    0    Kirby-Peach (toad)     
8010c344    0    Kirby-Peach (toad spore)     
800fe0e0    0    Kirby-Fox/Falco     
801090d4    0    Kirby-Popo/Nana     
80105a34    0    Kirby-Zelda     
80106db0    0    Kirby-Sheik     
8010cfb0    0    Kirby-GAW start            notable that GAW has no start/finish like this
8010ce5c    0    Kirby-GAW finish     
8010b1f4    0    Kirby-Marth/Roy     
800be6ac    0    Escape from Kirby star (after grab) projectile     
8012a074    1    Samus rocket     
8012adf0    1    Samus bomb     
8013a830    0    Zelda B     
801396ac    0    Zelda teleport start     
8013979c    0    Zelda teleport finish     
8013adb4    0    Zelda -> Sheik start     
8013aeac    0    Zelda -> Sheik finish     
80112d44    0    Sheik needle(s) throw     
8011097c    0    Sheik chain     
80112ed8    0    Sheik teleport start     
80113038    0    Sheik teleport finish     
80114034    0    Sheik -> Zelda start     
8011412c    0    Sheik -> Zelda finish     
800ec210    1    (y)Link boomerang     
800eb7c8    1    (y)Link bomb     
800eba4c    0    (y)Link up-B     
801277ac    1    Pi(ka)chu thunder            flag is near start of animation
80124c90    0    Pi(ka)chu start up charge     
80124d2c    0    Pi(ka)chu launch from charge     
8013c94c    0    JP sing     
8013ce7c    0    JP rest     
80146c08    0    Mewtwo side-B     
80146594    0    Mewtwo down-B     
801450a0    0    Mewtwo teleport start     
80145164    0    Mewtwo teleport finish     
80146594    0    GAW jab            many of GAW normals use models (articles?) that trigger these
8014ab48    0    GAW down-A     
8014a848    0    GAW f-smash     
8014b3a8    0    GAW u-air     
8014b45c    0    GAW u-air landing     
8014b1b4    0    GAW b-air     
8014b268    0    GAW b-air landing    other normals do not appear to use this blrl despite spawning models...
8014e4f0    0    GAW B     
8014c46c    0    GAW judgement     
8014def0    0    GAW up-B     
8014cbf4    0    GAW oil spill            only when used on full bucket
801365a8    0    Marth/Roy B            on attack

Noteworthy projectile moves that do not seem to appear on this list:
Bowser flame
Ness PK thunder
Ness PK flash
Samus (un)charge shot
Zelda fire/explode
(y)Link arrow
Pi(ka)chu B
Mewtwo shadowball

---

If an animation interrupt can’t be achieved from a state without some kind of special expiration condition (like, letting go of the B button, or often something more subtle than that) then the pointer in 0x2200 may be manually set to an animation interrupt function of your choice before attempting the call to PlayerThinkAgain.

By doing this with an interrupt function that transitions into a wait state like stand, fall, or special fall; you can usually safely use either cancel method to manually assign these action states and “skip” the remaining actionstate data.

I’ve opted to call PlayerThinkAgain for the interrupt to be handled in my code by a more natural context than calling the interrupt function directly; just to be safe.

---

Some known bugs with this version --

  • Superjumps. Everywhere. You can cancel far more states than you used to be able to, and as a result you can superjump and stall with a lot more moves.
    • I’ve taken some measures to preserve special falling states in most moves; however canceling the very first frame of certain states results in an interesting glitch that seems to bypass this in a few cases. I highlighted the effects of this in my falco portion of the demo video. I think it’s probably a simple fix, but I’ll need to look into it.
    • The actual physics of a superjump are entirely untouched at this point. I’ve got a range of ideas about how to address this, so I’m just sort of waiting to get the core mechanics of the cancel settled before looking into it very deeply.
  • Canceling Yoshi’s egg roll just as he hits the floor to start spinning will preserve the squashed (dimensional) transformation it causes as a part of its animation. It doesn’t go away on new action states, and can accumulate over successive transformations. I vaguely recall there being some other Yoshi-egg related transformation issues in vanilla Melee. I have some ideas about how to look into it.
  • A silly bug involving my manipulation of the player invisibility bit keeps Mewtwo/Zelda/Sheik teleports visible when canceling the startup animation. It looks spooky as heck, but is otherwise just a very transient visual glitch

---

I’ll be bouncing around my projects a bit. Next up for this project though, I’ll be focusing on the suggestions made earlier in this thread. Feel free to make any more~

There’s stuff that still needs to be done to the cancel code, but it’s quite functional at this point. More than anything it just needs to be optimized in some places for the sake of code size. The soft cancel is still in an experimental phase.

I believe I can apply what I’ve learned and try Aerros11 Aerros11 ’s defensive clash cancel suggestion. Also I have some notes (somewhere...) that detail how I’m going to rewrite the slowmo concept to be more flexible. I believe it will be able to handle all of the suggestions made prior about scaling intelligently with other variables. On paper, anyway.

As a standalone function library, the slowmo engine might become a separate development thread--as it will be applicable in many different contexts besides what I end up using it for here.

If that goes smoothly, I’m curious if I can use the two libraries together to make up the bulk of a special slowmo gametype in the form of an injection mod package. Achilles1515 Achilles1515 , Savestate Savestate , flieskiller flieskiller , DRGN DRGN

---

@omegagmaster the nature of the things I’ve used to make this updated code possible can be exploited to manipulate action state transitions via simple memory edits. More to the point; I believe this means you can get some incredibly specific results with the same edits just by using Achilles’ Custom Character Data subaction event. For example:

Cancel into falling state:
F8FF0014 020021A0 800CB2F8 020008A4 00000001

Cancel into special falling state:
F8FF0014 020021A0 80099BD0 020008A4 00000001

Cancel into standing state:
F8FF0014 020021A0 800CB2F8 020008A4 00000001

These will be applied to the next player frame, when used. I’ll post any more notes I can make about this in your request thread later. It should be noted that I haven’t actually tried these yet.

Furthermore, there’s some structure in static RAM (803C2800 and 803C12E0) that I’m unfamiliar with--but that seems to describe pointers for all of the functions used by the interrupt pointers. I don’t know of a similar structure for simple action state transition functions; but I know that all of indexed interrupt functions organize calls to said simple transition functions.

I think this means it’d be possible to reference interrupts via ID? It would make it more convenient than using a full pointer for creating a dedicated subaction event syntax.

---

G gamerfreak5665 It's been a pleasure working on this code. I actually wanted to thank you! I used to TAS Smash 64 back in the day (just for fun) and was in awe when I realized I could do it with Melee too. I believe I had this realization after watching your Falco All-Star TAS. I was only exposed to Melee Impossible in the first place because I binged your channel long enough to make it a suggested video LOL.

@MagicScrumpy I tuned into some of your streams a couple times last year while you were still experimenting with Turbo characters in Crazy Hand. I had no idea what you were doing at the time, but it opened my eyes to a lot of possibilities. I’d like to extend this thanks to you as well~

A little note to TAS users (or people with robot fingers) -- this new cancel code is frame-perfect. It operates all in a single frame, and does so on top of the normal frame calculation. This means that with the right input, you may transition between action states without going into a wait state. I believe this was only possible during hitlag in my former codes.

I’ve some ideas about how to exploit this in order to try and recreate some non-IASA based Turbo Mode input mechanics by making a different version of the “Soft” cancel used in this new code.

This project has always been my platform for trying to experiment with how to make that possible, however I’ve only recently learned enough about the structure of the game to begin really playing with it.

ProDevin ProDevin was the d-pad macro code of any use to you?

I’ll be posting any notes about Turbo Mode developments in your request thread, including any test codes. It’ll probably be awhile though, so let me know if you have any trouble using this new cancel.
 
Last edited:

DRGN

Technowizard
Moderator
Premium
Joined
Aug 20, 2005
Messages
2,175
Location
Sacramento, CA
Crazy stuff! Maybe it could be a cool new game mode in 20XX. :D Or part of some Event Matches!
 
Last edited:

Darkgamer200229

Smash Rookie
Joined
Apr 6, 2015
Messages
13
Location
Somewhere
NNID
mariposa322
The “Impossible Cancel” is a project meant to recreate a playable version of Melee Impossible.
The original author did not provide a code, or any information to work with.

As a result, in addition to being a code (in development) this project is largely an R&D effort and aims to document as much as possible about the involved mechanics.

The project aims to eventually recreate Turbo Mode, but currently uses manually input L/R presses in order to create an action state cancel that may be applied at any time. Works with B-specials, as well as normal movements like running or dodging.


---

Update 4/29/2016

Get the newest code here. See update post for more info:
Code:
-==-
Impossible Cancel v0.20 (library)
Stable recreation of "Melee Impossible"
[Punkline]
Version -- DOL Offset ------ Hex to Replace ---------- ASM Code

1.02 ----- 0x8006b090--- C03F0650 -> Branch
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
bl <ICNCv020_softCancel>
9061FFF8 7FC3F378
83C1FFF8 C0228874
00000000


<ICNCv020_softCancel>
#r3= external player data offset
#experimental
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 480000F8
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000
bl <ICNCv020_animationSpeedCancel>
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000
bl <ICNCv020_abortActionState>
807F0010 2C03001D
41800034 2C030026
4181002C 2C1C0000
41820024 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
bl 0x80096900
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020


<ICNCv020_animationSpeedCancel>
#r3= external player data offset
#--sets animation speed to x1000
#--updates player frame stuff, which uses animation speed to create frame unit size
#--updates player article stuff (mask out bit 0x80 of player.0x2270 if you want to avoid projectiles)
#--attempts player animation interrupt check (cancels action state)
#--sets animation speed back to old speed if still == x1000 (cases where cancel fails)
7C0802A6 90010004
9421FFE8 BFC10010
83E3002C C03F089C
D021FFF8 C022E864
807F0000
bl 0x8006f190
807F0000
bl 0x8006eba4
807F0000
bl 0x8006C80C
807F0000
bl 0x8006A360
C002E864 C03F089C
FC010000 40820010
C021FFF8 807F0000
bl 0x8006f190
BBC10010 38210018
80010004 7C0803A6
4E800020


<ICNCv020_abortActionState>
#r3= external player data offset
#--if player is in air, set animation interrupt to transition into falling
#--else, set animation interrupt to transition into standing
#--set 0x904 to a non-0 value (bypasses frame logic check for next call)
#--attempt player animation interrupt check (cancels action state)
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 4182003C
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000
bl 0x8006A360
83E10008 38210010
80010004 7C0803A6
4E800020
$Impossible Cancel v0.20 [Punkline]
C206B090 0000006A
C03F0650 C0028874
FC000800 4182002C
C03F0654 FC000800
40820020 9061FFF8
7FC3F378 83C1FFF8
48000019 9061FFF8
7FC3F378 83C1FFF8
C0228874 4800030C
7C0802A6 90010004
9421FF30 D8210008
BC610010 83E3002C
83DF0004 8BBF2073
3B800000 3B600000
3B400000 48000041
7C6802A6 A0830000
5480067F 41820068
7C00E800 40820020
5480C6BE 7C00F000
40820014 549C8FFE
549B97FE 549ACFFE
48000044 A4830002
4BFFFFD0 4E800021
01910194 81138493
0496049C 04A204A9
05948713 47940991
0C948C13 0E940F91
90139313 53941691
16949613 17949713
00000000 807F1A58
2C030000 41820014
8063002C 38000000
90031A4C 48000104
833F0010 2C190011
408100B0 2C190018
4182004C 2C190027
41820044 2C190029
4180002C 2C19002B
40810034 2C190046
4180001C 2C19004A
40810024 2C1900E9
4180000C 2C1900EC
40810014 2C1D0000
41820068 2C1D0058
41820060 887F221E
60600080 981F221E
807F0000 480000B9
807F0010 7C03C800
41820010 2C1A0000
4082FED8 48000034
2C1B0000 4082002C
807F0004 2C030007
40820018 807F0010
2C03015E 41820014
2C030161 4182000C
807F0000 4800011D
807F0010 2C03001D
41800040 2C030026
41810038 2C1C0000
41820030 807F0000
38800001 38A00001
80CDAEB4 C0260340
C0460344 38C00000
3D808009 618C6900
7D8803A6 4E800021
8B5F221E 735A007F
9B5F221E B8610010
C8210008 382100D0
80010004 7C0803A6
4E800020 7C0802A6
90010004 9421FFE8
BFC10010 83E3002C
C03F089C D021FFF8
C022E864 807F0000
3D808006 618CF190
7D8803A6 4E800021
807F0000 3D808006
618CEBA4 7D8803A6
4E800021 807F0000
3D808006 618CC80C
7D8803A6 4E800021
807F0000 3D808006
618CA360 7D8803A6
4E800021 C002E864
C03F089C FC010000
4082001C C021FFF8
807F0000 3D808006
618CF190 7D8803A6
4E800021 BBC10010
38210018 80010004
7C0803A6 4E800020
7C0802A6 90010004
9421FFF0 93E10008
83E3002C 887F2073
2C030000 41820048
807F00E0 2C030000
41820014 3C60800C
6063B2F8 907F21A0
48000010 3C608009
60639E80 907F21A0
38600001 907F08A4
807F0000 3D808006
618CA360 7D8803A6
4E800021 83E10008
38210010 80010004
7C0803A6 4E800020
60000000 00000000

I’ve made my syntax highlighted ASM available at a glance here:
Code:
/*Impossible Cancel v0.20 (library) [Punkline]
Stable recreation of "Melee Impossible" -- an unavailable cancel code that was apparently never playable.
Now available in the following forms, in descending order of flexibility and complexity:

--Soft Cancel -- safe, stable, versatile, customizable, really big
--Animation Speed Cancel -- safe, may cause glitchs in limited cases (special thanks to Achilles for this concept!)
--Abort Action State -- simple, rigid, potentially unsafe when used from falling states

Any or all of this library may be included in MCM (or a DOL mod)
Doing so will allow codes to be written that utilize these cancels from any context
*/

#example injection mod:

#Impossible Cancel 0.20 (Melee 1.02) [Punkline]
#@8006b090: lfs f1, 0x0650 (r31)        (checking analog input for digitization)
#lr, cr0 and f0 are safe to use
#r3 == internal player data offset 0x65C (digital button data)
#r30 == external player data offset 0x0 (player entity)
#r31 == internal player data offset 0x0 (player data)
#f1 == to become analog L/R value for current frame
#0x778C(rtoc) == 0.0 (no analog L/R press to digitize)

lfs f1, 0x0650 (r31)     #original instruction, loads current frame L/R value for digitization in digital buttons
lfs f0, -0x778C (rtoc)    #load 0.0 for comparison
fcmpu cr0, f0, f1        #compare to current L/R value
beq return               #return if not pressed
lfs f1, 0x654(r31)       #else, check last frame value
fcmpu cr0, f0, f1
bne return               #if this isn't empty, then analog button was not pressed on this frame


stw r3, -0x8(sp)         #temporarily store this; it gets saved in r30 (which is backed up in call)
mr r3, r30
lwz r30, -0x8(sp)         #swaps r3 and r30; so we pass and save registers appropriately
bl <ICNCv020_softCancel>
stw r3, -0x8(sp)
mr r3, r30
lwz r30, -0x8(sp)         #swap registers again, everything back to normal~

return:
lfs f1, -0x778C (rtoc)    #Sheild nop overwrites Original Instruction
.long 0x00000000         #hard return (compiled by MCM)





/*ICNCv020_softCancel
r3 = player entity
This function uses some extra logic to wrap conditions around a procedure that
tries to intelligently uses both of the other cancles provided in this library.
Experimental.
*/

mflr r0
stw r0, 0x4(sp)
stwu sp, -0xD0(sp)
stfd f1, 0x8(sp)
stmw r3, 0x10(sp)       #follow your dreams~
lwz r31, 0x2C(r3)

loopCancel:        #some moves will continue canceling until they reach a wait state
#First we parse an array of data located in the inline data table after these instructions
lwz r30, 0x4(r31)    #r30 = (real) player character ID
lbz r29, 0x2073(r31)    #r29 = (real) player move ID
li r28, 0        #r28 = bool (force special falling?)
li r27, 0        #r27 = bool (force preservation?)
li r26, 0        #r26 = bool (loop cancel?)
bl getParseDataTable
mflr r3            # r3 = parse data pointer
lhz r4, 0(r3)        # r4 = starting hword entry from data table

parseLoop:
rlwinm. r0,r4,0,25,31    #check if the (7-bit) move ID is 00
beq grabCheck        #if so, terminate loop (00 is a termination code)
cmpw r0, r29        #else, start parsing the entry
bne parseNextEntry    #check for move ID match
rlwinm r0,r4,24,26,31
cmpw r0, r30        #check for character ID match
bne parseNextEntry
#at this point, we've found an entry in the table that matches our current character move
#so we save the bools for the code to use later in order to make some decisions about how to work the cancel

#--The parse is basically answering the following questions for us:
rlwinm r28,r4,17,31,31    #do we want to convert non-special air wait states into special falling?
rlwinm r27,r4,18,31,31    #do we want to avoid "aborting" the action state if we have problems?
rlwinm r26,r4,25,31,31    #do we want to keep canceling this move until it reaches a wait state?
b grabCheck

parseNextEntry:
lhzu r4,2(r3)        #load next hword to be parsed
b parseLoop        #loop back to actually parse it

getParseDataTable:
#This is an inline data table. It contains hardcoded variables that get parsed by the above system.
#It's possible to organize this table as a standalone function--but this data has little remote application...
#--Each hword in the array is an entry that is parsed like so:
#0x8000 - bool         -- "force special falling" -- the cancel will assign special falling instead of falling
#0x4000 - bool         -- "force preservation" -- the cancel will avoid using the "abort actionstate" fallback
#0x3F00 - 6-bit ID     -- internal character ID (specifies a character for "character move")
#0x0080 - bool         -- "continue cancel until wait state"
#0x007F - 7-bit ID     -- common move ID (specifies a move for "character move")
#--0x00 as a move ID is a termination code for the parse loop
blrl    #any branches to "parseData" will return with a pointer to the data in lr
.hword 0x0191    #fox laser
.hword 0x0194    #fox shine

.hword 0x8113    #fox firefox
.hword 0x8493    #kirby upB

.hword 0x0496    #kirby foxB
.hword 0x049C    #kirby NessB

.hword 0x04A2    #kirby jpB
.hword 0x04A9    #kirby falcoB

.hword 0x0594    #Bowser downB
.hword 0x8713    #Sheik upB

.hword 0x4794    #Sheik downB
.hword 0x0991    #Ness B

.hword 0x0C94    #Pikachu thunder
.hword 0x8C13    #Pikachu quick attack

.hword 0x0E94    #yoshi downB
.hword 0x0F91    #JP B

.hword 0x9013    #Mewtwo Teleport
.hword 0x9313    #Zelda upB

.hword 0x5394    #Zelda downB
.hword 0x1691    #Falco laser

.hword 0x1694    #Falco Shine
.hword 0x9613    #Falco firebird

.hword 0x1794    #Pichu thunder
.hword 0x9713    #Pichu quick attack

.hword 0x0000    #terminate parse
.hword 0x0000
#make sure to pad this if necessary in order to stay 32-bit aligned

grabCheck:
#Check if player is holding another player.
#-- We want to prevent a "soulbreaker" glitch, so we handle this by making the grab expire
lwz r3, 0x1A58(r31)        #grabbed player entity slot
cmpwi r3, 0
beq ASblacklist
lwz r3, 0x2C(r3)        #if a player entity is in this slot, then load data
li r0, 0
stw r0, 0x1A4C(r3)        #kill breakout countdown
b return            #and simply return

ASblacklist:    #a hardcoded blacklist that stops the cancel during certain moves/action states
#-- for some wait states, this is to prevent technical problems that may arise from wait-state interrupt logic
#-- for other states, it is mostly for the sake of preserving gameplay mechanics

lwz r25, 0x10(r31)    #player action state; we're going to check this again later, so save in r25

cmpwi r25, 0x11        #masks out AS 0x00-0x11 (death-walking)
ble SFcheckAndReturn    #-- without this you can cancel your death animation and rack up SDs. Almost kept it.

#these are some whitelist entries; to be exceptions for the "wait state" check that follows
#they're kind of last-minute additions that can be optimized, but allow this to cancel jumps and things
cmpwi r25, 0x18        #kneebend
beq beginCancel
cmpwi r25, 0x27        #squat
beq beginCancel
cmpwi r25, 0x29        #squat reverse
blt waitCheck
cmpwi r25, 0x2B
ble beginCancel
cmpwi r25, 0x46
blt waitCheck
cmpwi r25, 0x4A        #various landings
ble beginCancel
cmpwi r25, 0xE9
blt waitCheck
cmpwi r25, 0xEC        #various dodges
ble beginCancel

waitCheck:
cmpwi r29, 0            #r29 still holds move Id, 00 is used for a large range of wait-like states
beq SFcheckAndReturn    #this return will terminate looping cancels when canceling whole moves
cmpwi r29, 0x58        #parasol falling; canceling this allows for infinite jumps...
beq SFcheckAndReturn

beginCancel:
#before starting, we use this bit to turn the player invisible
#while invisibility isn't a feature of this code, doing this prevents particles from spawning during cancel
lbz r3, 0x221e(r31)
ori r0, r3, 0x80
stb r0, 0x221e(r31)    #temporarily make player invisible, to stop particle spawns

#Now, we try the animation speed cancel. We do this by calling ICNv020_animationSpeedCancel
lwz r3, 0(r31)
bl <ICNCv020_animationSpeedCancel>

#The call doesn't return without updating some player stuff that should make the effect immediate
#so now we check the action state to make sure there was a transition
lwz r3, 0x10(r31)    #current action state
cmpw r3, r25        #compare with saved action state
beq abortActionState    #if the state hasn't changed, we attempt to (conditionally) use the other cancel method

#At this point, we've successfully used the animation speed cancel
#we just need to check to see if we're going to loop the cancel again from the parsed bool in r26
cmpwi r26, 0
bne loopCancel
b SFcheckAndReturn    #if not, then return; because we're finished~

abortActionState:    #branch here when animation speed cancel doesn't seem to work
#Sometimes it isn't possible to use a frame timer threshold to force an "animation interrupt"
#in these cases we use a less-safe cancel method--but with an animation interrupt function known to be safe.
#the drawback of this cancel is that it destroys the current action state progression, and preserves no subaction event data
#--In most cases, animation cancels can even be used in a similar fashion for a similar result
#the advantage however, is that this method may cancel things that otherwise softlock the player with an animation speed cancel

cmpwi r27, 0        #first make sure the "force preservation" option (from the parse) doesn't apply to this move
bne SFcheckAndReturn    #if it does, then return. It's assumed that moves given this option will actually cancel properly.

lwz r3, 0x4(r31)    #---Throwing this little bit in to cover up an old bug with 0x904
cmpwi r3, 7        #DI animations (like with falling states) cause the 0x904 cancel to freeze the game
bne notSheik        #sheik's chain whip uses DI animations
lwz r3, 0x10(r31)    #It isn't covered by "wait" states, so we add that here for now...
cmpwi r3, 0x15e
beq SFcheckAndReturn
cmpwi r3, 0x161
beq SFcheckAndReturn    #A messy mess. This allows the chain to be used cleanly, however.

notSheik:
lwz r3, 0(r31)
bl <ICNCv020_abortActionState>        #else, call abortActinState

SFcheckAndReturn:    #this does a check to see if we should convert state into a special falling state (helpless)
lwz r3, 0x10(r31)
cmpwi r3, 0x1D        #beginning of regular falling states
blt return
cmpwi r3, 0x26        #ending of regular falling states (includes damage fall)
bgt return
#under these circumstances, we just need to check the "force special falling" bool before we have enough info
#if it's == true, then we're going to convert the action state into a special falling
cmpwi r28, 0
beq return
#Since these are already assumed to be wait states, a normal animation interrupt will not work correctly.
#Instead, the action state needs to transition in some othere way. This can be tricky if the state isn't known at compile time
#Luckily we only need a specific state, which can be easily accomplished by setting up a call like so:
lwz r3, 0(r31)
li r4, 1        #this is how common air dodges handle calls to the special falling AS transition
li r5, 1
lwz r6, -0x514C(r13)    #floats
lfs f1, 0x340(r6)
lfs f2, 0x344(r6)
li r6, 0
bl 0x80096900

return:
lbz r26, 0x221e(r31)    #to ensure that the character is visible, we will mask out the invisibility bit we used to stop particles
andi. r26, r26, 0x7F    #currently this doesn't handle the few cases where you cancel into a state meant to be invisible
stb r26, 0x221e(r31)

lmw r3, 0x10(sp)
lfd f1, 0x8(sp)
addi sp, sp, 0xD0
lwz r0, 0x4(sp)
mtlr r0
blr





/*ICNCv020_animationSpeedCancel
r3 = player entity
This subroutine makes calls to the following game functions in order to void action state frame logic:
-- (8006F190) animationSpeedChange
-- (8006EBA4) ac_AS_AnimationFrameUpdate&More
-- (8006C80C) player article/projectile update/spawn function (?)
-- (8006A360) animation interrupt update (? -- "playerThinkAgain")

Successful animation interrupts are usually invoked by this nullification of frame logic;
however, it is dependent on the function pointed to in 0x2200 (0x21a0 internal)
-- it's possible to modify the above pointer in order to change the effect of this cancel before calling
-- doing this with wait states however may cause softlocks in a few character moves

This method of cancel will resolve subaction data and may be used to continue natural state progression
!!Because of this, an unsuccessfully handled cancel will sometimes result in 1000x frames worth of particle spawns
          -- an easy way to handle this is to prefix a call to this function with a write to this bit:

                lbz r26, 0x221e(r31)    #bit 0x80 in this byte makes the player turn invisible at some point in a frame update
            #    this bit is checked by GFX parses in order to skip particle spawns
*/

#the core of this concept was courteously provided by Achilles1515 on smashboards~

mflr r0
stw r0, 0x4(sp)
stwu sp, -0x18(sp)
stmw r30, 0x10(sp)
lwz r31, 0x2C(r3)       #trying to get in the habit of doing this in my prolog--good practice for player stuff

lfs f1, 0x89C(r31)      #we're going to store this so that we can optionally restore it before returning
stfs f1, -0x8(sp)       #

lfs f1,-0x179C(rtoc)    # load 1000.0 from table of contents; f1 function argument
                        #    f1=newframespeed, r3= "external player data offset" (I may adopt that notation)
lwz r3, 0(r31)        #make sure to pass player entity struct; do this properly by loading the pointer at 0x0(internal player)
bl 0x8006f190

#Now, to immediately force the effects of this animation speed transition,
#we make a call to the function that appears to be responsible for updating player action state frames
#it calls a number of functions that update the player based on the frame of the current action state.
#--this includes the player subaction event parsing loop function; which will (in theory) ignore all "timer" events
#Before returning, animation speed is returned to what it was before the action state transition (if it is still x1000.0)

#all of the following simply require the argument r3= external player data offset
#update frame (ac_AS_AnimationFrameUpdate&More) -- reads action state data, and other stuff
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006eba4
#update character projectile/article spawns -- will stop model spawining issues
lwz r3, 0(r31)        #in sequence with the previous call, this will also properly update projectile spawns
bl 0x8006C80C
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end is important)
lwz r3, 0(r31)        #this call softens up a blrl into the player's currently stored animation interrupt
bl 0x8006A360           #I haven't looked into it very far, so it may do other things as well

return:
lfs f0, -0x179C(rtoc)              #"1000.0"
lfs f1, 0x89C(r31)
fcmpu cr0, f1, f0               #make sure current animation speed hasn't been altered by action state change
bne noSpeedReset
lfs f1,-0x8(sp)                 # otherwise, load our original animation speed and restore it
                        #    f1=newframespeed, r3= external player data offset
lwz r3, 0(r31)        #make sure to pass player entity struct
bl 0x8006f190

noSpeedReset:
lmw r30, 0x10(sp)
addi sp, sp, 0x18
lwz r0, 0x4(sp)
mtlr r0
blr







/*ICNCv020_abortActionState
r3 = player entity
This subroutine checks the ground/air state in order to assign standing/falling animation interrupts
player.0x904 (external) is used to create a "shortcut" to the assigned action state; aborting the previous one
--special falling interrupts are preserved, but will only apply to the current action state transition.
--"playerThinkAgain" is called in order to make this state change happen before returning
*/
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x10(sp)
stw r31, 0x8(sp)
lwz r31, 0x2C(r3)

lbz r3, 0x2073(r31)       #player move ID
cmpwi r3, 0
beq return        #don't attempt cancel on wait states

lwz r3, 0xE0(r31)
cmpwi r3, 0        #check if in air or on ground
beq ground
air:
lis r3, 0x800C
ori r3, r3, 0xB2F8    #animation interrupt used by "jump"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
b abortPoke
ground:
lis r3, 0x8009
ori r3, r3, 0x9E80    #animation interrupt used by "rebound"
stw r3, 0x21A0(r31)    #animation interrupt function pointer
abortPoke:
li r3, 1
stw r3, 0x8A4(r31)    #do a hard 0x904 cancel that uses the animation interrupt pointer we just set
#update action state with animation interrupt (ac_playerThinkAgain -- the blrl towards the end)
lwz r3, 0(r31)        #make sure to pass player entity struct;
bl 0x8006A360

return:
lwz r31, 0x8(sp)
addi sp, sp, 0x10
lwz r0, 0x4(sp)
mtlr r0
blr









(v0.20 demo video)

---

Legacy experiments:
The original concept explored what looks like an exploit involving action state frame mechanics via the memory address located at player.0x904. It was very unstable, but I created a heavy-handed actionstate mask that allows the concept to be exploited relatively safely. This version is very stable and has very few problems, but is quite large all on its own:

$Impossible Cancel v0.1.4b (Melee 1.02) [Punkline]
C206B090 0000002F
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200F4
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200A4 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810070
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820028
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000


Achilles suggested a far more elegant solution that involves utilizing the same mechanic that the game uses to make L-canceled aerial landing animations speed up. The idea is that by changing your animation speed to something ridiculous, you can effectively create an action state transition that takes only a single frame.

This comes with some animation-related glitches, but it is a far more stable solution than the above and thus requires much less code to work smoothly. Here’s an early implementation of an experimental fix for one of these animation problems related to spawning particle effects:

$Animation Cancel Concept v0.1.2 (Melee 1.02) [Achilles1515] [Punkline]
C206B844 00000007
838306C8 579F0001
41820028 579F06F7
40820020 C022E864
3FE08006 63FFF190
7FE803A6 7C7F1B78
4E800021 7FE3FB78
7C7C1B78 00000000
C2071048 00000006
80A308FC 3CC0447A
7C053000 60650060
40820014 3CC08007
60C611C4 7CC803A6
4E800020 80CA0008
60000000 00000000


There was some discussion about turning this into a special game type that used slow-motion in order to give players time to consider their technical options. Here are a couple versions of the Impossible Cancel (with animation bugs~) that incorporate early versions of a variable slowmo engine:

$Slowmo Combo Concept A (Melee 1.02) [Punkline]
C237E24C 00000016
48000018 3C1000A0
00000000 00125000
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C2069B64 0000000A
7C8802A6 48000005
7D4802A6 7C8803A6
394AFEFC 809A089C
3C60447A 7C041800
40A20020 888A0001
886A0002 7C841A14
886A0003 7C041800
41810008 988A0002
7F4AD378 7F43D378
60000000 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEA4 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B380064
7F1EC378 00000000
$Slowmo Combo Concept B (Melee 1.02)[Punkline]
C237E24C 00000016
48000018 604000A0
00000000 002932E0
00000000 00000000
7C0802A6 48000005
7CA802A6 7C0803A6
38A5FFE4 9065000C
90850010 3C808043
60842A2C 88050002
2C000000 40820010
80640008 90640000
48000044 88650004
2C030001 88650002
4182000C 3863FFFF
98650002 88050000
7C001800 80650008
41800010 7C6303D6
88050002 7C6301D6
80040008 7C630214
90640000 38000000
98050004 8065000C
80850010 80A3C05C
60000000 00000000
C20410E0 00000008
7D8802A6 48000005
7DE802A6 7D8803A6
39EFFF44 898F0001
8B6F0002 7D8CDA14
8B6F0003 7C0CD800
41810008 998F0002
7F4CD378 7F4FD378
83610024 00000000
C206B090 0000000E
7FC802A6 48000005
7F2802A6 7FC803A6
3B39FEFC 83D819BC
2C1E0000 4182000C
3BC00001 9BD90004
83D806B0 2C1E0000
41820030 83D806B4
2C1E0000 40820024
3F208006 6339F190
7F2803A6 C022E864
7C791B78 7F03C378
4E800021 7F23CB78
C0228874 3B3A0064
7F1EC378 00000000

Original post with lots of info about early concepts:
(contains a lot of images, videos, documents, and codes exploring external player data offsets 0x904, 0x908, 0x444, and 0x44C)
Hey guys. First post here on smashboards.

Has anyone played around with Character Data offset 0x904 (from the RAM Address List?)

Poking it lets you cancel your action state on the next frame, and it isn’t picky about what actions it can be applied to. It’s a lot of fun, really unstable, and was virtually undocumented the last time I checked these forums.

Somebody left a note about it in the RAM Address List, but it just mentioned that poking it to “40c00000” (float “6.0”) will cancel the current action state. Indeed it does, and in fact any non-0 value will work--so for the sake of simplicity I’ve used “1” throughout my examples here.

Let me back up a little and explain that I’m not really much of a programmer, and I haven’t played a smash game in almost a decade.

I found this board sometime back in April 2015 while searching for how the Melee Impossible video was … possible. My search turned up very little, so I watched Dan’s excellent primer on writing Gecko Codes and meant to try and figure it out. (Thanks Dan!)

It didn’t take long for me to stumble upon 0x904 in the RAM Address List, so I’m assuming some of you have at least tried poking it.

I’ve spent some time experimenting with it and now I have a lot of information that doesn’t seem to be documented anywhere here. Admittedly, I don’t frequent these forums very often so I could be mistaken. I searched pretty fervently back in April-May for some answers however, and found no information.

Now that there’s a nice little sub-forum dedicated to posting codes, I figured this would be a great place to dump some info and maybe collaborate a little. My intention is to reproduce Melee Impossible in a form that is actually playable.

Here’s everything that I think I understand~

---

I remember reading a lot of speculation about how IASA frames couldn't be responsible for Melee Impossible. I know very little about IASA frames, or subactions for that matter. I think I remember people saying IASA frames would only work easily with normals, or something.

Ant-D claims in his video description (and paraphrases in his blog) that he “hacked/modified the game so that it is possible to L-Cancel any move whatsoever. This includes everything from running, B-specials, and grounded smash attacks.”

As far as I can tell, 0x904 has nothing to do with IASA frames. I could be wrong of course, but I don’t even know what it has to do with action states, really; as it appears to be a part of a function responsible for blending some animation keyframes.

Regardless, it can be applied to any action state just as Ant-D reported his hack could.

He also mentioned in his thread that he wouldn’t release his ASM code because his “‘mod is only stable when playing the game frame by frame. It will crash on different action states otherwise.”

This seemed to confuse some people, but makes perfect sense if you have the code to play around with.

I believe that by writing this 0x904 poke in a hook to the L/R button-press code in the main character loop, you end up with a cute little gecko code that perfectly resembles Melee Impossible. Verbatim! So try it yourself, if you’d like:

$Impossible Cancel v0.1.1 (Melee 1.02) [Punkline]
C206B0A4 00000002
38600001 907E0904
901F065C 00000000

The problem is that canceling from many specific action states (referred to as “problem states” in my notes) causes a consistent freezing behavior. One of these problem states is the falling state--in any of its forms.

The function that writes the digitized analog values as button presses to char data offset 0x6BC every frame is where our hook is (light L/R presses are represented as an ‘8’ in the leftmost nibble of the value stored in 0x6BC); and so our cancel code (as it is currently handled) gets executed every frame that the button is held down.

This results in a really common freezing behavior while holding L/R for any longer than a single frame in the air--as the action state that follows a canceled aerial action is a problem state (falling.) Here’s a slightly fleshed out list of the states that cause freezing behavior:
  • Falling animations
    • (these animations are permuted by DI inputs)
    • (note that the index of action state IDs includes a forward/back falling ID for each type of falling; but these seem to be vestigial as they appear unused by any of the normal characters)
  • Flinching and being grabbed.
  • Looping animations.
  • Animations with a “wait” state (some charge animations, or pikachu’s thunder)
    • (note that this surprisingly doesn’t include charged smashes)
Also, here are a few other circumstances where the game will freeze during a cancel. They are less generalized, and perhaps more telling of a cause:
  • GaW running animation (appears to have no blended keyframes in movement animations, as other characters do)
  • Sheik’s Chain (DI inputs determine the animation and function of this action, just like falling animations)
  • Mewtwo/Zelda/Sheik teleport landing on platform (with horizontal momentum)
  • Probably a bunch of other stuff that might be difficult to test.
In other words, playing without frame-perfect inputs and a bit of clairvoyance results in problem states triggering freezes like land mines. I’m almost certain that this is why Ant-D tried to explain that TASing was necessary to utilize his hack, and is probably why he thought it was too incomplete/embarrassing/whatever to release.

---

So, what can we do about these instabilities? It would be fairly simple to add conditions to the poke that act like filters for problem states, but this presents a new issue where “blacklisted” problem states are then completely unaffected by the cancel code.

This means that every blacklisted state limits the scope of the Impossible Cancel. It does however stop the freezing behavior and make things playable as demonstrated by this slight modification to the last code:

$Impossible Cancel v0.1.2 (Melee 1.02) [Punkline]
C206B0A4 00000005
807E0070 2C03001D
4180000C 2C030026
4081000C 38600001
907E0904 901F065C
60000000 00000000

This only covers a small bracket of action state IDs that account for falling states. You can try it in place of the 0.1.1 code though, and then not have to worry about freezing aerial attacks that wouldn’t otherwise be problematic.

For a long time, I used this code to test everything. I took a couple passes at each of the characters and searched for each of their problem states to be recorded in this document. This uncovered a second issue with this blacklist method, which is that there are simply too many problem states to individually blacklist using conditions like these.

You see, action states past 0x155 on the index are assigned uniquely by character, and so the conditions list becomes 2-dimensional. Specifying the characterID, actionstateID pairs necessary to identify each problem state results in an impractically long code because it has to account for (at least) each of the following:


I’m still learning how to read and write this stuff, but I made an ammature attempt to fit all of this information into a series of LONG variables and have a loop just read them off like normal conditional checks. I don’t recommend trying it, but I did leave some heavy comments in my dev journal if you’d like to review it.

$Impossible Cancel v0.1.3b (Melee 1.02) [Punkline]
C206B0A4 0000003A
480000E0 00000015
001D0026 00300030
004B005B 00910093
009F009F 00A300A3
00B700B7 00BF00BF
00CE00E3 00ED00FD
010A0154 01166364
696C6E71 03037277
04045556 57585962
64666768 696A6B6C
6D6E7476 78798185
86898A8D 05055659
5E5F6064 65666A06
14595C5E 61070756
5A5D5E60 61080857
5A5D5E61 62676B70
75090962 65720A0B
55560C17 585B5D60
68696C6D 0D0D580E
0E5D6265 66696A6E
700F0F55 56575859
5C5D5E5F 6465666A
10105657 5B5C5F60
1111585B 5C5E6162
121A565A 1313585B
18185700 309700C8
00000000 00000000
00000000 00000000
7C6802A6 48000005
7FE802A6 7C6803A6
3BFFFFE4 929F0004
92DF0008 92FF000C
931F0010 82DE0070
82FE0064 8A9F0000
A31F0002 7F18F850
A0780000 7C161800
41800010 A0780002
7C161800 40810080
3A94FFFC 3B180004
2C140000 4181FFDC
8A9F0001 88780000
7C171800 40820030
8C780001 2C030020
4081FFF8 3A800000
2C030020 40810018
60630100 7C161800
8C780001 41820038
4BFFFFE8 3A94FFFF
3B180001 2C140000
4181FFBC 2C170009
4182000C 2C170013
4082000C 2C160027
4182000C 38600001
907E0904 829F0004
82DF0008 82FF000C
831F0010 3BFE0060
901F065C 38600000
987F065C 00000000

It’s quite large, but actually pretty stable. Blacklisting every problem state by hand is obviously an accountability though, and the blacklist is far from perfect. In the end, I think this approach is too aggressive to be practical.

---

Let’s back up again. If we take a look at how 0x904 behaves, we can exploit something that provides a far more passive approach to fixing this problem.

0x904 appears to store a non-0 float value that determines the duration (in frames) of blended keyframe animations. These blending frames only seem to appear in some actions that revert back into standing or running states, as well as Peach’s float animation. They also appear in a select few B-specials.

0x908--the address just next-door--increments each frame (usually in whole float numbers) so long as 0x904 is not equal to 0. This increment stops once it is greater than or equal to the number stored in 0x904.

In other words, 0x904 defines a timer, and 0x908 increments it. This most commonly appears in the standing animation.

gfycat

The timer appears to control a blending effect that uses a keyframe (which is probably stored somewhere) from a previous animation to blend with a frame from a new animation.

Canceling the “squat” action so far has provided the best demonstration of this effect that I’ve been able to reproduce. Normally a standing or running animation will use 6.0 frames (0x40c00000) for the blend duration. For some reason, the crouching animation uses 30.0 frames (0x41f00000) and applies it to the animation AFTER the squat (idle crouching.) By canceling the squat action with a 0x904 poke, you can apply those naturally occurring 30.0 frames of blending to the squat (transition) animation instead of the idle crouch--and the effect becomes very dramatic.

gfycat

Poking 0x904 will have one of the 3 following effects:

  • If 0x904 is already 0--which is most of the time--poking it to ANY non-0 value has the effect of knocking the player out of their current action state
  • If 0x904 is storing a value, poking it to any non-0 value changes the number of frames that the current animation gets blended with the last one. Action states are NOT canceled under these circumstances.
    • Poking it to 0 in these cases cancels the animation.

When this keyframe blend function is not being used (which is most of the time,) setting the value of 0x904 to any non-0 value will set up the cancel effect on the following frame.

gfycat

When poking 0x908 (the current blend frame) along with 0x904 (blend duration) so that 0x908 == 0x904; the effect of the cancel is exactly the same, however instead of freezing during problem states, the blend process will lock the animation of the state as the last blended frame (usually standing, running, or falling.) This removes the freezing behavior from all common problem states, including all* B-specials, and repairs itself on the next action state load--which appears to function as normal.

* Sheik is a sole exception from my playtesting; her chain whip freezes appear to be related to falling freezes.

gfycat

Taking another pass at all of the characters using pokes to both 0x904 and 0x908 simultaneously, I made an updated document that accounts for the few remaining problem states (as I could find them.)


As you can see, the only remaining freezing behaviors are falling states and Sheik’s chain whip animations. Everything else is a state that I’ve identified as a “glitch” state.

It’s a little amusing to me that so many of the vanilla glitches can be accounted for by premature cancels. Many of them can be replicated via the Impossible Cancel, and so the game-breaking ones are represented in the above summary as purple.

It's interesting to note that with the 0x908 exploit, falling states can be canceled (and have a frozen animation, like other corrected problem states) only if there is absolutely no directional input. This doesn’t happen with a bare 0x904 poke, and I believe it may be an important clue.

If you don’t account for the glitch states, falling animations and Sheik’s weird input for her chain whip animation remain as the sole freezing behaviors that can be accounted for via a blacklist condition. A code written under these pretenses is consequently very small:

$Impossible Cancel v0.1.4a (Melee 1.02) [Punkline]
C206B090 0000000D
831E06B0 2C180000
41820054 831E0070
2C180026 40810040
2C18015D 41820020
2C18015E 41820018
2C180160 41820010
2C180161 41820008
48000010 831E0064
2C180007 41820010
3B000001 931E0904
931E0908 7FD8F378
3BFE0060 C0228874
60000000 00000000

This small version accounts for none of the glitch states, so it can be pretty unplayable with some characters. There's also one more freezing behavior. It’s the only other one I could identify, and it can’t be covered up with the 0x908 exploit. It’s also kind of weird.

To reproduce it in the above code, pick a former problem state like Pikachu’s charge/thunder attack, or Bowser’s down-B attack. While holding shield (light or heavy,) without rolling or dodging, do a directional shield jump into an aerial containing the former problem state before canceling the jump as you leave the ground.

If you did this correctly, the game should freeze. It happens accidentally quite often with any characters that had former problem states, and I believe it has something to do with shield angle, or the directional jump animation.

The reason I suspect this is because the only other 2 remaining freezing behaviors are Sheik’s whip and directional falling animations. All of these 3 behaviors seem to have their animations permuted by directional inputs, and appear to use no subactions.

I don’t know how to fix this, but I do know that this commonality might help us eventually find a solution.

With the exception of this one freezing behavior; the loop written for 0.1.3b can be refined to include only falling, the glitch states, and Sheik’s chain states.

To ease the potential of accidentally canceling shields, as well as the general input problems with using L/R as the cancel button during ground attacks… all versions of 0.1.4 disable the light shield mechanic of the game in favor of the cancel function. Eventually, I hope to refine this into a more elegant solution.

In addition, I’ve attempted to create a semi-automatic input method. The cancel effect cycles action states along their natural progression rather than immediately jumping to a standing state. This means that by simply writing out the logic for semi-automatic inputs, you end up having to press the button several times to progress through a single move that uses multiple actions…

I thought this might be desirable in some aspects, but in others it’s very cumbersome. Instead, what I did was create a semi-automatic trigger that uses a flag to start automatically canceling every single frame; whether the button is held down or not. This involved changing the position of the hook slightly.

Then, by including all standing-like states in the blacklist, reaching a standing-like state will stop the automatic canceling every frame. The resulting effect is a semi-automatic trigger that progresses through entire moves rather than single actions. It’s experimental, and it does make some really technical cancels impossible; but I think it makes inputs less cumbersome in general.

Heavy shields still work; but they also may trigger the above mentioned freezing behavior. If you intend to use my sloppy ASM proof-of-concept in actual gameplay, be prepared with savestates and avoid canceling jumps out of your shield:

$Impossible Cancel v0.1.4b (Melee 1.02) [Punkline]
C206B090 0000002F
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200F4
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200A4 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810070
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820028
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000

Here’s a dumb video I quickly made awhile back to demonstrate a few of the vanilla glitches I’ve kept in this version. They are mostly harmless, but there’s quite a lot of incredibly stupid things you can do with them. Note that the soulbreaker glitches are actually blacklisted; only demonstrated


---

That about wraps up everything I’ve done to make Ant-D’s concept more playable. I intend to further explore directional inputs and their effects on animations--as well as some other addresses referenced in the functions that use 0x904.

---

I have some remaining notes that are more or less just about the functionality of this cancel concept.

The above examples address the majority of freezing behaviors, but in a way that doesn’t allow for the involved actions to be canceled. This is preferable to freezing the game of course, but it limits the application of this cancel effect.

Earlier on--when I was still learning how to make sense of PPC instructions--I was searching for addresses in undocumented areas of the RAM Address List in Dolphin for any correlation to problem states. I found a relationship in address 0x444, which appears to be an address that stores floats for a timer function involved in queuing subaction commands using synchronous and asynchronous timers.

No new subactions are read while the timer in 0x444 is counting down. I didn’t really understand this at first, but I did see it counting down--so I experimented by poking the value to 0 on top of my 0x904 poke. It had very interesting effects on the character I was testing at the time:


Suddenly, with this extra poke, all of the former problem states for Pikachu responded to the cancel effect...

Lets take a quick look at 0x44C, a close neighbor of 0x444. I was quite excited to find this one.

0x44C points to a position in a list that looks like this:


After comparing this to some data in Crazy Hand, it dawned on me that 0x44C points to the next subaction command.

And indeed, you can manipulate subactions by manipulating this pointer. I tested this very briefly by identifying Marth’s down-a IASA frame command, and pointing to it in 0x44C after pausing in the middle of his smash attack. This resulted in allowing me to cleanly start a new smash attack like a natural IASA frame.

I believe this means that you could (in theory) save the address currently in 0x44C somewhere and replace it with a pointer to some fake subactions you’ve written in another area in memory; using the old 0x44C pointer as a return branch. It would allow you to append, skip, or replace subactions procedurally with code!

With an understanding of the syntax, it could also be used to monitor subactions as they are happening, perhaps utilizing them as complex conditions.

I imagine that with some knowledge of how subactions are encoded (which I expect a lot of you have) you could exploit this address for all kinds of beautiful things.

Anyway, I don’t want to stray too far from the topic. Brutishly exploiting 0x444 (specific to subaction timers) works wonders for some of the previously gimped Pikachu article spawns. It doesn’t however have the same effect on Link’s article spawns, for example.

gfycat

In particular--hitboxes, article spawns, sound effects, particles and some character model flashes seem to rely on these “timer” subaction commands for progression through an action. Without any of these timers, all available subaction commands are read in the same frame; but they are still each individually read.

The number of these timer subactions present in a whole action determines how many "keyframes" are read at different times during the action. In other words, all subactions are instantaneous except for these timer subactions that write to 0x444.

It would appear that a single 0x444 poke is all Pikachu's moves need to skip the meat of their action, but not Link's. I'll have to confirm this after taking a long look at their subactions with 0x44C.

I would offer some documentation for this code, but it's the exact same code as 0.1.4b, except that it pokes 0x444 to 0 on top of the 0x904/0x908 pokes.

$Impossible Cancel v0.1.4c (Melee 1.02) [Punkline]
C206B090 00000030
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 418200FC
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200AC 82DE0070
82FE0064 8A9F0004
A33F0006 7F39F850
A3190000 7C16C000
41800010 A3190002
7C16C000 40810078
3A94FFFC 3B390004
2C140000 4181FFDC
8A9F0005 8B190000
7C17C000 40820030
8F190001 2C180020
4081FFF8 3A800000
2C180020 40810018
63180100 7C16C000
8F190001 41820030
4BFFFFE8 3A94FFFF
3B390001 2C140000
4181FFBC 3B000001
931E0904 931E0908
3B000000 931E0444
4800000C 3B000000
9B1F0000 829F0008
82DF000C 82FF0010
833F0014 82BF0018
3BFE0060 7FD8F378
C0228874 00000000

I wrote a really buggy variation of 0.1.4c that tries to use a second hook inside of the function responsible for this subaction timer. The idea was to use the flag I’d made for the semi-auto input as a trigger to poke 0x444 to 0 instead of 0x904 to 1. Then, the second hook inside the subaction function (within the same frame) recognizes the flag stored in the first hook code as a LONG variable, and continuously pokes 0x444 to 0 every time it is executed (once per subaction command.) This becomes self perpetuating because of the location of the second hook.

Once the subaction command “00000000” (padding between whole actions) is read in by 0x44C, the loop automatically terminates, so (in theory) this should completely “flush” subactions in a single frame. Once 0x44C is empty, only then does 0x904 get poked to 1 in order to invoke the cancel effect.

I remember trying this experiment very late at night and having abysmal results that I didn’t want to debug; so I ended up with a really buggy code that wasn’t playable. It did at least allow me to make this TAS video, where Link’s article spawns are NOT cut off by the cancel.


As always you’re welcome to try it… but it’s quite unplayable. Something about the way I wrote it breaks the logic for the blacklist, and so it makes aerials freeze the game all over again. I think it has to do with the 0x444 poke to 0 transition into the second hook, as subactions often seem to “disappear” in all actions before the next former-problem state triggers a freeze.

It’s interesting to see what actions are like without any subactions though (not really,) and it’s possible to test it with TAS if you’re interested.

$Impossible Cancel v0.1.4d (Melee 1.02) [Punkline]
C206B090 00000032
48000058 000E0016
001D0026 00CD00CE
00DB00DE 040F5556
57585986 8905055F
60656606 145E6107
075D5E60 610A0B55
560E0E5D 626E1010
5F600000 00000000
10260038 00000000
00000000 00000000
00000000 00000000
7F0802A6 48000005
7FE802A6 7F0803A6
3BFFFFDC 831E06B0
2C180000 41820108
929F0008 92DF000C
92FF0010 933F0014
92BF0018 8ABE006C
7EB5FA14 831E06B4
2C180000 4082000C
3B000001 9B150000
8B150000 2C180001
408200B8 82DE0444
2C160000 408200AC
82DE0070 82FE0064
8A9F0004 A33F0006
7F39F850 A3190000
7C16C000 41800010
A3190002 7C16C000
40810078 3A94FFFC
3B390004 2C140000
4181FFDC 8A9F0005
8B190000 7C17C000
40820030 8F190001
2C180020 4081FFF8
3A800000 2C180020
40810018 63180100
7C16C000 8F190001
41820030 4BFFFFE8
3A94FFFF 3B390001
2C140000 4181FFBC
3B000001 931E0904
931E0908 3F000000
931E0444 4800000C
3B000000 9B1F0000
829F0008 82DF000C
82FF0010 833F0014
82BF0018 3BFE0060
7FD8F378 C0228874
60000000 00000000
C20732B0 0000000A
7FC802A6 48000005
7FA802A6 7FC803A6
3BBDFE9C 939D0008
8BDB006C 2C1E0003
4181001C 7FDEEA14
8B9E0000 2C1C0001
4082000C 3F800000
939B0444 3BDB0060
839D0008 3BBB0444
28000000 00000000

While this obviously appears to work with Link, I guess it isn't quite the solution. Where a single 0x444 poke would allow for Pikachu to spam his thunder and Link to only cancel his bombs; a continuous 0x444 poke allows for Link to spam his bombs, and Pikachu to only cancel his thunder.

I think I'll soon try using 0x44C as a replacement for action state ID and character ID checks. I'd like to see if everything (with the exception of the falling states and Sheik's whip) can be covered by a subaction blacklist.

Also, this subaction “flush” might be refined with a more intelligent condition to allow for all article spawns to resolve before cancels; and possibly even other things like hitboxes.

--

Finally, a little footnote about the case where 0x904 is already storing a float number. I mentioned this early on, but normally 0x904 only stores a float value during something like a standing action; so there’s no real reason to cancel these as they’ll only start a new standing action. There are however a few B-specials that use blending frames like this, and poking 0x904 to 1 will not allow these states to be canceled like everything else can.

Off the top of my head, the only 3 B-special actions effected by this are Marth/Roy’s side-B swipes (2nd, 3rd, and 4th only,) Luigi’s Green Missile, and the Ice Climbers’ recovery animation.

Each of these cases can still be canceled by poking 0x904 to 0 instead of 1. I haven’t included this in any of my codes, but I think it could be very simply implemented. One weird thing to consider is that sometimes, doing this in a standing animation will blend with a T-pose.

---

Anyway, that’s about everything I’ve got so far. I have a lot to learn still, but I hope that this information is sufficient enough to compensate for the apparent lack thereof surrounding this cancel concept. If anyone has any comments, suggestions, or critiques I’ll do my best to respond in a helpful manner and edit any information accordingly.

Also, feel free to play around with any of these codes/concepts and discuss your own ideas. I think there’s a lot left to be discovered about this address and its related mechanics.

Update with information about how to use animation interrupts and player updates to make previous exploits much safer:
How do I use this?
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
How do I use this?

Use either the injection mod package or the C2 Gecko code. They're just different methods of installing the same code. (See the spoiler at the top of my OP for the code text)

After you have the code installed, “light shield” L/R inputs will be replaced with the cancel effect.

I recommend using the injection mod package. MCM will save you the gecko code handler space for other smaller codes. The C2 gecko code may be very easily used with Dolphin, however.

To use the injection mod package, first you’ll need Melee Code Manager.
  • Copy the injection mod package text from my post
  • Paste it into a normal text file
  • Save it in the “Mods Library” folder of your Melee Code Manager directory. Call it something that makes sense to you, like “Impossible Cancel”
  • Select a ISO/GCM you want to modify in MCM and go to the “Injection Mods” tab to find the code you just added.


  • Toggle on “Impossible Cancel” and hit the "Save Changes" button.

The game will now contain the code by default.





C2 codes have a convenient pipeline in the Dolphin Emulator that can be used like this:
  • First make sure “Enable Cheats” is checked on the “General” tab of your config window.
  • Right click on Melee from Dolphin and click “Properties”
  • Click the “Gecko Codes” tab, click the “edit config” button
  • Copy the C2 code text from my post
  • Paste it under the “[Gecko]” tag, or any other codes you’ve already entered


  • Save the text file.
  • Make sure the code is enabled on the checklist before starting the game.

To use the C2 code on consoles, check out the spoiler at the top of this other thread.

---

DRGN DRGN I hope so! There’s a lot of stuff that needs some attention first though. Hopefully it’ll come along nicely~

At the moment, the experimental cancel in 0.20 uses a lot of lengthy logic to meticulously accomplish some things that might be handled more passively. I’m hopeful it can be chopped up and shrunken down in another pass after I’ve explored a few things.
 
Last edited:

Darkgamer200229

Smash Rookie
Joined
Apr 6, 2015
Messages
13
Location
Somewhere
NNID
mariposa322
Use either the injection mod package or the C2 Gecko code. They're just different methods of installing the same code. (See the spoiler at the top of my OP for the code text)

After you have the code installed, “light shield” L/R inputs will be replaced with the cancel effect.

I recommend using the injection mod package. MCM will save you the gecko code handler space for other smaller codes. The C2 gecko code may be very easily used with Dolphin, however.

To use the injection mod package, first you’ll need Melee Code Manager.
  • Copy the injection mod package text from my post
  • Paste it into a normal text file
  • Save it in the “Mods Library” folder of your Melee Code Manager directory. Call it something that makes sense to you, like “Impossible Cancel”
  • Select a ISO/GCM you want to modify in MCM and go to the “Injection Mods” tab to find the code you just added.


  • Toggle on “Impossible Cancel” and hit the "Save Changes" button.

The game will now contain the code by default.





C2 codes have a convenient pipeline in the Dolphin Emulator that can be used like this:
  • First make sure “Enable Cheats” is checked on the “General” tab of your config window.
  • Right click on Melee from Dolphin and click “Properties”
  • Click the “Gecko Codes” tab, click the “edit config” button
  • Copy the C2 code text from my post
  • Paste it under the “[Gecko]” tag, or any other codes you’ve already entered


  • Save the text file.
  • Make sure the code is enabled on the checklist before starting the game.

To use the C2 code on consoles, check out the spoiler at the top of this other thread.

---

DRGN DRGN I hope so! There’s a lot of stuff that needs some attention first though. Hopefully it’ll come along nicely~

At the moment, the experimental cancel in 0.20 uses a lot of lengthy logic to meticulously accomplish some things that might be handled more passively. I’m hopeful it can be chopped up and shrunken down in another pass after I’ve explored a few things.
Found out that if you up b with marth at juuuuuuuuuuuuuust the right time, HE WILL FLY LIKE A ****ING BIRD AND BE NEAR THE TOP BLASTZONE FOR MORE THAN 8 SECONDS!
LOL
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Found out that if you up b with marth at juuuuuuuuuuuuuust the right time, HE WILL FLY LIKE A ****ING BIRD AND BE NEAR THE TOP BLASTZONE FOR MORE THAN 8 SECONDS!
LOL
Haha, yeah superjumps are an interesting byproduct of “undesigned” cancels it seems. Marth is a pretty extreme example, along with Mario, Zelda, Pikachu, etc. The key is a large difference between your position of “this” and “last” frame. Try canceling a diagonal Roy recovery and compare it to Marth, lol. I believe that whatever the problem is, it’s common to Link’s hookshot boomerang cancel jump.

You can actually see a superjump in the original Melee Impossible video at the end of the Peach combo.

Other characters have interesting superjumps that you wouldn’t expect; like Bowser’s down+B from the ground. Stalls are possible with many moves too. You can basically fly or at least float/glide with most characters…

Glitches you might expect to see in older versions of Melee were extremely common and enabled artificially by this cancel. Most have been fixed along the newer versions, but superjumps remain.

---

A lot of the unexpected physics behavior might be passively handled by modifying the action state physics behavior pointer along with the cancel; but I haven’t really looked into it much. I’ve sort of made it low on my priorities list because it’s goofy and fun.
 
Last edited:

flieskiller

Smash Journeyman
Joined
Jan 3, 2013
Messages
426
the Super Boomerang Glitch is loading a certain state, but in 1.00, that state was just "disabled" by changing it to 0. The character wouldn't continue their animation after a hit if done the say way, but it would be a good start to continue based on that
 

Dr. D

Smash Rookie
Joined
May 3, 2012
Messages
10
Location
Charlotte, NC
Hello all,

I'm probably doing something wrong, but I copied the text straight from the OP and put it into its own text file in the Mods Library folder for Melee Code Manager. I then loaded a 1.02 melee iso (no mods, base iso) and I found the injection mod for impossible cancel. However, When I activate the mod and click save, the box does not stay green. When I load the iso it seems to be base melee.

Am I supposed to edit the mod any from the OP? Any help is appreciated! I can supply screenshots as well if needed.
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Hello all,

I'm probably doing something wrong, but I copied the text straight from the OP and put it into its own text file in the Mods Library folder for Melee Code Manager. I then loaded a 1.02 melee iso (no mods, base iso) and I found the injection mod for impossible cancel. However, When I activate the mod and click save, the box does not stay green. When I load the iso it seems to be base melee.

Am I supposed to edit the mod any from the OP? Any help is appreciated! I can supply screenshots as well if needed.
Hmm, did you by chance only copy the top part of the text? (the code block scrolls down a bit)

Edit: I was able to get your described scenario verbatim by truncating the code just after the injection mod. Make sure to get all of the included standalone functions beneath it when copying.

If you've got all that and it's still not working, go ahead and provide some screenshots.
 
Last edited:

Painless67sb

Smash Rookie
Joined
Jan 26, 2016
Messages
2
Can anyone help me with this,

I used the injection mod format of your tutorial and copied down the entire code. I clicked save and that worked just fine. Melee would get to the css and the stage select, but when the game and dolphin would crash every time i tried to load a match. the error message says that it is an invalid read or something. Do you think i should re-copy the code or what? This mod looks super cool and I want to try it out myself.
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
423
Can anyone help me with this,

I used the injection mod format of your tutorial and copied down the entire code. I clicked save and that worked just fine. Melee would get to the css and the stage select, but when the game and dolphin would crash every time i tried to load a match. the error message says that it is an invalid read or something. Do you think i should re-copy the code or what? This mod looks super cool and I want to try it out myself.
I gather from what you're saying that it freezes immediately when a match starts? Like, first frame--no L/R presses?

If that's the case it sounds like the hook is messing up somehow. What version of Melee are you using? Any other codes?
 

Painless67sb

Smash Rookie
Joined
Jan 26, 2016
Messages
2
I am using 1.02 with a melee netplay settings code, and dan s' widescreen hack. I'll try hackless and see if it works. Thanks for your help.

And yes, it freezes first frame.

Edit: It works, thanks!
 
Last edited:
Top Bottom