add unused port priority fix codes to external

This commit is contained in:
Jas Laferriere
2022-11-21 15:06:57 -05:00
parent ee80c69a7d
commit a6785d630b
9 changed files with 663 additions and 0 deletions

View File

@@ -0,0 +1,205 @@
################################################################################
# Address: 0x80078C04
# Tags: [affects-gameplay]
################################################################################
.set HSD_Randi, 0x80380580
.set CheckPrevHitPlayers, 0x8000ACFC
.set CompareScaleZ, 0x8007F804
.set GrabCheckOverlap, 0x80007ECC
.set LineCheckObstruct, 0x80084CE4
.set CheckNextGObj, 0x80078C4C
stfs f1,0x20(sp) #Backup this fighter's unk grab position var in stack
addi r3,r29,0 #Current victim's GObj
addi r4,r25,0 #This GObj
bl lbl_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 2,0,2 #OR cr0_lt with cr0_eq and put result in cr_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
branchl r12,HSD_Randi #HSD integer randomizer
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_EXIT #Go to injection exit
lbl_Lose:
#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
branch r12,CheckNextGObj #Go to line of code that stores grab position thingy
lbl_EXIT:
lfs f1,0x20(sp) #Load grab position thingy
b lbl_Return
.set rHitLoop, 31
.set rThisFP, 30
.set rVicFP, 29
.set rLoopHitbox, 28
.set rHit, 27
.set rThisObj, 26
.set rVicHurtbox, 25
.set rLoopHurtbox, 24
.set rReturn, 23
lbl_GrabCheckVictim:
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 r23,0x14(sp) #Backup all registers from r23 until r31
addi rThisObj,r3,0 #Store this GObj
lwz rThisFP,0x2C(rThisObj) #Get this GObjs user_data
lwz rVicFP,0x2C(r4) #Get 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
branchl r12,CheckPrevHitPlayers #Check previously hit players
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_LoopIncHitboxHurtbox #If hurtbox cannot be grabbed, check the next one
mr r3,rVicFP
branchl r12,CompreScaleZ #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 #Address of current hurtbox's data
branchl r12,GrabCheckOverlap #Check for grab overlap
cmpwi r3,0
beq- lbl_LoopIncHitboxHurtbox #If there is no overlap, check the next hurtbox
addi r3,rThisFP,0
addi r4,rVicFP,0
branchl r12,LineCheckObstruct #Check for obstructions between the two fighters
cmpwi r3,0
bne- lbl_END #If there are obstructions, exit the function with FALSE in r23
#Series of initializations from original grab logic, 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 r23
li rReturn,1 #Now, all checks have been passed; both players' grabs overlap
b lbl_END #Return with TRUE in r23
lbl_LoopIncHitboxHurtbox:
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 #Increment 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 r23,0x14(sp) #Restore all non-volatile registers and return
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 from r0 into link register
blr #Return from subroutine
lbl_Return:

View File

@@ -0,0 +1,329 @@
################################################################################
# Address: INJ_CheckLastGObj
# Tags: [affects-gameplay]
################################################################################
.include "Common/Common.s"
.include "./LedgeGrab.s"
b CODE_START
_static_vars:
blrl
.long 0, 0, 0, 1
# allocations for variables
# last word is a flag that enables/disables the code. set to 0 to disable
b _get_player_GObj_ID # xGetPlayerGObjID
_get_player_GObj_ID:
# r3 = player GObj
# returns:
# r3 = unchanged
# r4 = first player GObj
# r5 = ID
mr r4, r3
li r5, -1
# r3 = this GObj
# r4 = counted GObj
# r5 = counter
_while_first_GObj_not_counted:
lwz r0, 0xC(r4)
addi r5, r5, 1
cmpwi r0, 0
bge- _return_0
mr r4, r0
b _while_first_GObj_not_counted
# once first GObj is reached, this GObj ID will be finalized
_return_0:
blr
_recursive_cliffcatch_by_distance:
# r3 = bools (before cleared)
# r4 = first player GObj
# registers:
.set rBools, 3
.set rThis, 4
.set rRecords, 5
.set rAddr, 7
.set rQuery, 8
# loop registers, for epilog:
.set rL, 9 # Left - order of: ledge vertex ID, ECB side
.set rR, 10 # Right - order of: ledge Link ID
.set rI, 11 # Index - uses rL or rR to create index
.set rT, 3 # This - represents value from rThis index
.set rQ, 12 # Query - represents value from rQuery index
# rB clobbers rR in late part of epilog loop:
.set rB, 10 # Base
# float registers used to calculate distance for fQuery and comparing to fThis
.set fThis, 1
.set fQuery, 2
.set fVert, 3
.set fECB, 4
.set fSquare, 3
.set fSum, 0
.set fInvRoot, 4
# GObj offsets:
.set xNext, 0x8
# Player GObjData offsets:
.set xFacing, 0x2C # float, sign = TRUE if facing left; else facing right
.set xTopN, 0xB0 # XY float pair
.set xECB, 0x784 # XY float pairs left and right, 0x8-aligned
.set xLedgeLink, 0x730 # IDs left and right, 0x4-aligned
.set xECBFlags, 0x824
# stack offsets:
.set xGObjData, 0xC
.set xStackSize, 0x10
# r13 offsets:
.set xColLinks, -0x51E4 # array of 8-byte indexed structures
.set xColVerts, -0x51E8 # array of 0x18-byte indexed structures
# loop bools:
.set bInitThis, 31
_pre_recursion:
li r0, 32
mtctr r0
li rRecords, 0
# rRecords = incrementing counter tracks number of frames to compare at end
# ctr holds number of GObjs to parse for
# -- ctr loop runs simultaneously with recursion loop to check bools
# -- recursion creates a stack frame for every true bit found in bools field
_recursion:
mflr r0
stw r0, 0x4(sp)
stwu sp, -xStackSize(sp)
cmpwi rThis, 0
bge- _epilog_operation
# if given GObj exists, then continue CTR loop
_ctr_loop:
andi. r0, rBools, 1
srwi rBools, rBools, 1
bne- _iter_recursion
# /if a bool is found, it triggers an iteration in recursion
# /else, we just check for the next bool in iter_ctr
_iter_ctr:
lwz rThis, xNext(rThis)
cmpwi rThis, 0
bdnzt+ lt, _ctr_loop
b _epilog_operation
# /if bool was false
# - then load next GObj, and decrement CTR
# /if (new CTR = 0) OR (next GObj is >= 0)
# - then break from CTR loop and begin return operation
# - else, continue CTR loop
_iter_recursion:
lwz r0, 0x2C(rThis)
addi rRecords, rRecords, 1
stw r0, xGObjData(sp)
lwz rThis, xNext(rThis)
bl _recursion
# /if bool was true
# then load next GObj and create a new stack frame
_epilog_operation:
mtctr rRecords
subic. rRecords, rRecords, 1
blt _return_1
# /if rRecords-1 is negative, then skip epilog operation.
# else, CTR = rRecords before decrement
# so it is at least 1; meaning we can use it for a bdnz loop
_setup_epilog_loop:
crclr bInitThis
addi rAddr, sp, xGObjData
_epilog_loop:
lwzu rQuery, xStackSize(rAddr)
bt+ bInitThis, _this_initialized
mr. rThis, rQuery
bge- _return_1
# /if not initialized, rThis = rQuery
# /if rThis is null, then we skip this frame entirely
_this_initialized:
cmpwi rQuery, 0
bge- _epilog_iter
# /if rQuery is null (and rThis is not) then we just skip this query
_compare_ledge_side:
lbz rQ, xECBFlags(rQuery)
lbz rT, xECBFlags(rThis)
rlwinm rQ, rQ, 0, 0x3
rlwinm rT, rQ, 0, 0x3
cmpw rQ, rT
bne _epilog_iter
# /if players aren't competing for the same ledge side,
# then skip this query
_LR_index:
rlwinm rL, rQ, 31, 1
rlwinm rR, rQ, 0, 1
# Left Right
# rL = 1 0 -- for order L, R
# rR = 0 1 -- for order R, L
# (boolean index avoids need for conditional branches)
slwi rI, rR, 2
addi rI, rI, xLedgeLink
# rI = (rR<<2) + xLedgeLink
# this creates a word-alignment in rI (index) for order R, L
# -- offset xLedgeLink uses the order R, L for memorizing ledge link IDs
lwzx rT, rThis, rI # load values according to facing index modifier
lwzx rQ, rQuery, rI
cmpw rT, rQ # rThis ledge ID == rQuery Ledge ID?
bne+ _epilog_iter
# skip if players do not share the same ledge
# /else; rQuery and rThis compete for shortest ECB distance
_calculate_distance:
# calculate distance between rQuery's ECB and the ledge vertex in question, using paired singles
lwz rB, xColLinks(r13)
slwi rI, rT, 3 # index of collision link
lwzx rB, rB, rI
# rB = address of collision link data
slwi r0, rL, 1
lhzx rI, rB, r0
# rI = vertex index
lwz rB, xColVerts(r13)
mulli rI, rI, 0x18
addi rI, rI, 8
psq_lx fVert, rB, rI,0,0
# fVert = X, Y of stage vertex to measure distance from
psq_l fECB, xECB(rQuery),0,0
psq_l f0, xTopN(rQuery),0,0
ps_add fECB, fECB, f0
ps_sub f0, fECB, fVert
# f0 = delta between fECB and fVert
ps_mul fSquare, f0, f0 # square delta pair
ps_sum0 fSum, fSquare, fSquare, fSquare # add pair values together
frsqrte fInvRoot, fSum
fmuls fQuery, fInvRoot, fSum # pythag
# fQuery = square root of (A*A) + (B*B)
fcmpo cr0, fThis, fQuery
crand lt, lt, bInitThis
blt- _disqualify
fmr fThis, fQuery
mr rThis, rQuery
# /if this is the first player to be measured,
# or if fThis > fQuery (technically >=, but it's a float)
# then fThis = fQuery; continue
crnot bInitThis, lt
b _epilog_iter
# by using !lt, we're always setting bInitThis to TRUE rather than toggling it
# this is because lt is definitively FALSE for this conditional branch
_disqualify:
li r0, 0
stw r0, 0(rAddr)
# /if we've disqualified a GObj, nullify it and continue epilog loop
_epilog_iter:
bdnz+ _epilog_loop
_break_from_epilog_loop:
# /if remaining number of frames is 0, then run action change for rThis
lwz r3, 0x0(rThis)
stw rRecords, 0x8(sp)
branchl r12, 0x80081370
lwz rRecords, 0x8(sp)
# call CliffCatch action for winning player
_return_1:
addi sp, sp, xStackSize
lwz r0, 0x4(sp)
mtlr r0
blr
CODE_START:
# after collision callback event has returned
# -- if this is the final GObj being checked, then
# we select which GObjs actually get to execute cliffcatch action change
# Gate states:
.set open, 0 # when open, calling cliffcatch action change will behave normally
.set close, 1 # when closed, attempting cliffcatch will log player in xBools field
# -- closed gate will not affect player GObjs with IDs larger than bool field (32)
# r29 = this player GObj
# r30 = this player data
lwz r0, 0x8(r29)
cmpwi r0, 0
bne+ _return
# return immediately if this is not the last player GObj
_if_last_player:
mr r3, r29
bl _get_player_GObj_ID
# r4 = first player GObj ID
_update_GObj_max:
bl _static_vars
mflr r30
# r30 must now be recovered before returning
# we can use 0x2C(r29) to restore it before returning
lhz r6, xThisCount(r30)
lwz r3, xBools(r30)
cmpw cr0, r5, r6
# the new value for xThisCount is in r5
# /if it's != r6, then a player GObj has been added/destroyed in the chain
cmpwi cr1, r3, 0
crorc eq, eq+4, eq
# cr0 eq = cr1 eq | cr0 !eq
sth r5, xThisCount(r30)
li r0, open
sth r6, xPrevCount(r30)
stw r0, xGate(r30)
# open == 0; so it's also used to nullify bools
stw r0, xBools(r30)
# updated ID count in variables
# cleared bools
# r3 = bools (before cleared)
# r4 still = first player GObj
beq- _end_of_cliffcatch_update
# unlikely case where GObj chain count does not match the previous frame
# -- indicates bool index may be misaligned, so logic is delayed until they can be rechecked
bl _recursive_cliffcatch_by_distance
# fancy parse function deals with all the dirty details
_end_of_cliffcatch_update:
li r0, close
stw r0, xGate(r30)
lwz r30, 0x2C(r29)
# close cliffcatch action gate, so that bools can reaccumilate for next check
_return:
mr r3, r29

View File

@@ -0,0 +1,16 @@
.ifndef HEADER_LEDGE_GRAB
# Source: https://smashboards.com/threads/ledge-grab-port-priority-fix.463581/
# Code converted to work in Slippi by Fizzi
.set INJ_CheckLastGObj, 0x8006c3a8
.set xThisCount, 0x0
.set xPrevCount, 0x2
.set xBools, 0x4
.set xGate, 0x8 # opens/closes access to cliffcatch action changes when called
.set xEnabled, 0xC
.set xGetPlayerGObjID, 0x10
.endif
.set HEADER_LEDGE_GRAB, 1

View File

@@ -0,0 +1,64 @@
################################################################################
# Address: 0x80081388
# Tags: [affects-gameplay]
################################################################################
.include "Common/Common.s"
.include "./LedgeGrab.s"
# whenever cliffcatch action is called
# we record it in a 32-bit flag field, indexed by player GObj
# and skip the action for now, so that it can be called later on.
# -- if a GObj is 32nd or higher in the chain, it is not delayed or recorded.
.set open, 0
# r30 == r3
# r3 must be maintained if returning to function
computeBranchTargetAddress r6, INJ_CheckLastGObj
addi r6, r6, 0x8
mr r3, r30
# r3 = unchanged
# r6 = variables base address
lwz r0, xGate(r6)
lwz r7, xEnabled(r6)
cmpwi cr0, r0, open
cmpwi cr1, r7, 0
cror eq, eq, eq+4
beq- _default
# if gate is open, allow call to go through
# otherwise, prevent the call and save it for later as an indexed bool
# We also treat the code being disabled like having the gate always open.
# this will cause the bools to be blank at te end of collision measurements,
# so it will prevent the code from having any effect.
addi r7, r6, xGetPlayerGObjID
mtctr r7
bctrl
# r3 = unchanged
# r5 = player ID
# r6 = unchanged
cmpwi r5, 32
bge- _default
# also, don't bother with GObjs that we can't keep track of (32-bit field)
# if for some reason there are that many players, then they won't be affected by the gate logic
# r5 = player ID
# r6 = variables base address
li r4, 1
slw r5, r4, r5
lwz r0, 0x4(r6)
or r5, r5, r0
stw r5, 0x4(r6)
# update flagfield to include this ID
_skip:
branch r12, 0x800814ec
# /if skipping function, return to its epilog
# /else, default returns execution to prolog
_default:
lwz r3, 0x002C (r3)

View File

@@ -0,0 +1,25 @@
################################################################################
# Address: 0x8008E25C
# Tags: [affects-gameplay]
################################################################################
lwz r4,0x1198(r29) #Get thrower GObj pointer
cmplwi r4,0
beq- lbl_FrameAdvance #Run original code if NULL
lwz r4,0x2C(r4)
lbz r4,0xC(r4) #Get port ID of thrower
lbz r0,0xC(r29) #Get port ID of victim
cmpw r0,r4
bgt- lbl_Skip #If victim is lower priority, skip frame advance
lbl_FrameAdvance:
lis r12, 0x8007
subi r12, r12, 0x145C
mtlr r12
blrl
b lbl_END #Exit
lbl_Skip:
lfs f1,0x2340(r29) #Load victim's hitstun frames
lfs f0,-0x7508(rtoc) #Load 1.0F
fadds f0,f1,f0 #hitstun += 1.0F;
stfs f0,0x2340(r29) #Store fixed hitstun
lbl_END:

View File

@@ -0,0 +1,6 @@
################################################################################
# Address: 0x80132ECC
# Tags: [affects-gameplay]
################################################################################
addi r4, r29, 0x0

View File

@@ -0,0 +1,6 @@
################################################################################
# Address: 0x80133A48
# Tags: [affects-gameplay]
################################################################################
addi r4, r29, 0x0

View File

@@ -0,0 +1,6 @@
################################################################################
# Address: 0x80133B68
# Tags: [affects-gameplay]
################################################################################
addi r4, r29, 0x0

View File

@@ -0,0 +1,6 @@
################################################################################
# Address: 0x800E52E8
# Tags: [affects-gameplay]
################################################################################
addi r4, r29, 0x0