• 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 Grab Port-Priority Fix - Award Grab to Lower Damage Player

PKFreeZZy

Smash Cadet
Joined
Aug 21, 2016
Messages
60
Location
Hungary
Slippi.gg
VETR#758
Down below is a code meant as an attempt to fix grabs being based on port-priority, currently WIP before it can be implemented on Slippi Nintendont!

This is to remedy the need for players having to play Rock-Paper-Scissors to decide on which port they use.

We figured that this is a less disruptive and rage-inducing method than one which involves both players suffering a forced release; this makes grab priority predictable, and it also makes sense from a design perspective: the player who's more fresh has the edge, like how mashing out at lower %s is much easier than at high damage.

In the extreme case that both players are at the exact same % (including the hidden decimal point), the grab winner is decided by a 50/50 RNG check.

Code:
$Grab Port-Priority Fix - Award Grab to Lower % Player [PKFreeZZy]
*Fixes port-priority on grabs by awarding it to the player with less damage, should they occur at the same time. If both players have the exact same damage, the winner is decided by a 50/50 random roll.
C2078C04 00000040
D0210020 387C0000
389E0000 48000065
2C030000 4182003C
C03E1830 C01C1830
FC010040 4C401382
40820030 FC010000
40820020 38600002
3D808038 398C0580
7D8803A6 4E800021
2C030000 4182000C
801C0000 48000014
3D808008 398C8C4C
7D8803A6 4E800020
C0210020 48000190
7C0802A6 90010004
9421FFC0 DBE10038
BF010018 3BC30000
3BA40000 3B800000
C0028930 D01E216C
3BFE0000 3B000000
C3E28900 387F0914
801E0914 3B630000
2C000000 4182011C
80030030 28000008
40820110 88030040
5400DFFF 41820010
801D00E0 2C000001
4182001C 88030040
5400E7FF 418200EC
801D00E0 2C000000
408200E0 387D0000
389B0000 3D808001
398CACFC 7D8803A6
4E800021 2C030000
408200C0 3B5D0000
3B200000 480000A8
801A11E8 2C000000
41820094 7FA3EB78
3D808008 398CF804
7D8803A6 4E800021
C03E0038 7C651B78
C05D0038 7F63DB78
C07D00B8 389A11A0
3D808000 398C7ECC
7D8803A6 4E800021
2C030000 41820050
387E0000 389D0000
3D808008 398C4CE4
7D8803A6 4E800021
2C030000 40820054
C03D00B0 C01E00B0
EC210028 FC01F840
40800008 FC200850
C01E216C FC010040
40800030 3B000001
48000028 3B5A004C
3B390001 881D119E
7C190040 4180FF54
3B9C0001 281C0004
3BFF0138 4180FEC8
7F03C378 BB010018
80010044 CBE10038
38210040 7C0803A6
4E800020 00000000

Code:
Grab Port-Priority Fix - Award Grab to Lower Damage Player
Fixes Port-Priority by letting the "fresher" player win grab interaction; 50/50 chance if both players have the exact same damage
[PKFreeZZy]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x80078C04 ---- 801C0000 -> Branch

stfs f1,0x20(sp) #Backup result of fighter grab position calculation in stack

addi r3,r28,0 #Current victim's user_data
addi r4,r30,0 #This user_data
bl <GrabCheckVictim>

cmpwi r3,0 #Check if victim is also grabbing this fighter
beq- lbl_Win #If victim is not feeling touchy, this fighter wins the interaction

lfs f1,0x1830(r30) #This fighter's damage
lfs f0,0x1830(r28) #Victim's damage

fcmpo cr0,f1,f0 #Compare this fighter's % to victim's
cror eq,lt,eq #OR cr0_lt with cr0_eq and put result in cr0_eq to dodge NaN edge cases
bne- lbl_Lose #If this fighter has a higher % than the victim, lose the interaction

fcmpu cr0,f1,f0 #Check if both %s are equal
bne- lbl_Win #If this fighter REALLY has less damage than the victim, win the grab

li r3,2 #Load 2 into randomizer to get a 50/50 chance to beat victim if %s are equal
bl 0x80380580 #HSD_Randi
cmpwi r3,0
beq- lbl_Lose #If result is 0, lose the interaction

lbl_Win:
lwz r0,0(r28) #Get victim's GObj pointer
b lbl_END #Go to injection exit

lbl_Lose:
#The code down below is not required, so it is commented out until proven otherwise
#Documentation on 0x1A58 and 0x1A5C is conflicting, not entirely sure what their
#true purpose is, but they are both related to attacker/victim logic

#li r0,0 #Set r0 to NULL
#stw r0,0x1A5C(r30) #Store NULL pointer to this fighter's hitlag partner pointer?
#stw r0,0x1A58(r30) #Store NULL pointer to this fighter's victim pointer?
#lbz r3,0x221B(r30) #Load flags at 0x221B
#rlwimi r3,r0,2,29,29 #Move r0 over bit 29 of r3
#stb r3,0x221B(r30) #Grab bool is now false
#lfs f1,0x20(sp) #Load grab position thingy
#b 0x80078C20 #Go to line of code that stores grab position thingy

b 0x80078C4C #Go to next GObj
lbl_END:
lfs f1,0x20(sp) #Load grab position thingy
.long 0 #Return from injection

<GrabCheckVictim> NTSC 1.02
.set rHitLoop, 31
.set rThisFP, 30
.set rVicFP, 29
.set rLoopHitbox, 28
.set rHit, 27
.set rVicHurtbox, 26
.set rLoopHurtbox, 25
.set rReturn, 24

mflr r0 #Get return pointer from link register
stw r0,0x4(sp) #Store link register at top of current stack position
stwu sp,-0x40(sp) #Make space for 0x40 bytes in the stack
stfd f31,0x38(sp) #Backup f31 so we can store 0.0F to it
stmw r24,0x18(sp) #Backup all registers from r24 until r31
addi rThisFP,r3,0 #Move this fighter's user_data
addi rVicFP,r4,0  #Move victim's user_data
li rLoopHitbox,0 #Init loop counter
lfs f0,-0x76D0(rtoc)
stfs f0,0x216C(rThisFP) #Get and store maximum single-precision float limit
addi rHitLoop,rThisFP,0 #Move this fighter's data to temporary hitbox loop register
li rReturn,0 #Init return value, this stays at "false" unless all checks are passed
lfs f31,-0x7700(rtoc) #Load 0.0F

lbl_LoopHitboxStart:
addi r3,rHitLoop,0x914 #Get address of the start of this fighter's hitbox array
lwz r0,0x914(rThisFP) #Load hitbox state
addi rHit,r3,0 #Move hitbox struct address to reserved hitbox register
cmpwi r0,0 #Check if hitbox state is "disabled"
beq- lbl_LoopIncHitbox #If hitbox is disabled, check for the next one

lwz r0,0x30(r3) #Get hitbox element
cmplwi r0,8 #Check if hitbox's element is "grab"
bne- lbl_LoopIncHitbox #If we're not dealing with a grabbox, check next hitbox

lbz r0,0x40(r3) #Get hitbox flags
rlwinm. r0,r0,27,31,31 #Check to ignore airborne fighters
beq- lbl_CheckFlagNext
lwz r0,0xE0(rVicFP) #Get ground_or_air
cmpwi r0,1 #Check if fighter is airborne
beq- lbl_SkipToCheckPrevHit
lbl_CheckFlagNext:
lbz r0,0x40(r3) #Get hitbox flags
rlwinm. r0,r0,28,31,31 #Check if fighter is grounded
beq- lbl_LoopIncHitbox
lwz r0,0xE0(rVicFP) #Get grorund_or_air
cmpwi r0,0 #Check if fighter is grounded
bne- lbl_LoopIncHitbox #Check next hitbox if airborne

lbl_SkipToCheckPrevHit:
addi r3,rVicFP,0
addi r4,rHit,0
bl 0x8000ACFC #CheckPrevHitPlayers

cmpwi r3,0
bne- lbl_LoopIncHitbox #Check next hitbox if victim has already been hit by this one

addi rVicHurtbox,rVicFP,0 #Move victim's user_data to temporary hurtbox register
li rLoopHurtbox,0 #Init hurtbox loop
b lbl_LoopHurtboxCheck #Go to hurtbox loop count

lbl_LoopHurtboxStart:
lwz r0,0x11E8(rVicHurtbox) #Get hurtbox's grab enable bool?
cmpwi r0,0
beq- lbl_LoopIncHurtbox #If hurtbox cannot be grabbed, check the next one

mr r3,rVicFP
bl 0x8007F804 #Compare victim's Z-scale to 0.0F

lfs f1,0x38(rThisFP) #Get this fighter's Y-scale
mr r5,r3 #Move float* address of Z-scale?
lfs f2,0x38(rVicFP) #Get victim's Y-scale
mr r3,rHit
lfs f3,0xB8(rVicFP) #Get victim's current Z-position
addi r4,rVicHurtbox,4512 #Move address of current hurtbox's data into r4
bl 0x80007ECC #Check for grab overlap

cmpwi r3,0
beq- lbl_LoopIncHurtbox #If there is no overlap, check the next hurtbox

addi r3,rThisFP,0
addi r4,rVicFP,0
bl 0x80084CE4 #Check for obstructions between the two fighters

cmpwi r3,0
bne- lbl_END #If there are obstructions, exit the function with FALSE in rReturn

#This series of initializations is to flag the victim as if we've attacked them
#We don't want that in this case, so this block is commented out
#addi r3,rThisFP,0
#addi r4,rHit,0
#addi r6,rVicFP,0
#li r5,0
#li r7,0
#bl 0x80076808

lfs f1,0xB0(rVicFP) #Get victim's X-position
lfs f0,0xB0(rThisFP) #Get this fighter's X-position

fsubs f1,f1,f0 #Subtract this fighter's X-pos from victim's X-pos

fcmpo cr0,f1,f31 #Compare to 0.0F
bge- lbl_SkipNeg #If positive, value is already absolute

fneg f1,f1 #Otherwise, flip the sign bit of the negative result (fabs)

lbl_SkipNeg:
lfs f0,0x216C(rThisFP) #Get this fighter's grab distance threshold?
fcmpo cr0,f1,f0 #Compare position to 0x216C
bge- lbl_END #Return with FALSE in rReturn
li rReturn,1 #Now, all checks have been passed; both players' grabs overlap
b lbl_END #Return with TRUE in rReturn

lbl_LoopIncHurtbox:
addi rVicHurtbox, rVicHurtbox, 76 #Get address of next hurtbox struct
addi rLoopHurtbox, rLoopHurtbox, 1 #Incremennt hurtbox loop counter

lbl_LoopHurtboxCheck:
lbz r0,0x119E(rVicFP) #Get victim's hurtbox count
cmplw rLoopHurtbox,r0 #Check if hurtbox loop count has exceeded victim's number of hurtboxes
blt+ lbl_LoopHurtboxStart

lbl_LoopIncHitbox:
addi rLoopHitbox,rLoopHitbox,1 #Incremeent hitbox loop count
cmplwi rLoopHitbox,4 #Check if all four hitboxes have been compared
addi rHitLoop, rHitLoop, 0x138 #Add size of hurtbox struct to temporary hitbox register
blt+ lbl_LoopHitboxStart

lbl_END:
mr r3,rReturn #Return isOverlap bool
lmw r24,0x18(sp) #Restore all non-volatile registers
lwz r0,0x44(sp) #Load return pointer into r0
lfd f31,0x38(sp) #Restore f31
addi sp,sp,0x40 #Restore stack position
mtlr r0 #Move return pointer into link register
blr #Return from subroutine
 
Last edited:
Top Bottom