mirror of
https://github.com/project-slippi/slippi-ssbm-asm.git
synced 2025-10-05 23:52:43 +02:00
add unused port priority fix codes to external
This commit is contained in:
205
External/PortPriority/FighterGrab/FighterGrab.asm
vendored
Normal file
205
External/PortPriority/FighterGrab/FighterGrab.asm
vendored
Normal 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:
|
329
External/PortPriority/LedgeGrab/CheckLastGObj.asm
vendored
Normal file
329
External/PortPriority/LedgeGrab/CheckLastGObj.asm
vendored
Normal 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
|
16
External/PortPriority/LedgeGrab/LedgeGrab.s
vendored
Normal file
16
External/PortPriority/LedgeGrab/LedgeGrab.s
vendored
Normal 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
|
64
External/PortPriority/LedgeGrab/SkipAction.asm
vendored
Normal file
64
External/PortPriority/LedgeGrab/SkipAction.asm
vendored
Normal 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)
|
25
External/PortPriority/ThrowHitstun/FixThrowHitstun.asm
vendored
Normal file
25
External/PortPriority/ThrowHitstun/FixThrowHitstun.asm
vendored
Normal 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:
|
6
External/PortPriority/ThrowHitstun/SetPtrBowser1.asm
vendored
Normal file
6
External/PortPriority/ThrowHitstun/SetPtrBowser1.asm
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
################################################################################
|
||||
# Address: 0x80132ECC
|
||||
# Tags: [affects-gameplay]
|
||||
################################################################################
|
||||
|
||||
addi r4, r29, 0x0
|
6
External/PortPriority/ThrowHitstun/SetPtrBowser2.asm
vendored
Normal file
6
External/PortPriority/ThrowHitstun/SetPtrBowser2.asm
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
################################################################################
|
||||
# Address: 0x80133A48
|
||||
# Tags: [affects-gameplay]
|
||||
################################################################################
|
||||
|
||||
addi r4, r29, 0x0
|
6
External/PortPriority/ThrowHitstun/SetPtrBowser3.asm
vendored
Normal file
6
External/PortPriority/ThrowHitstun/SetPtrBowser3.asm
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
################################################################################
|
||||
# Address: 0x80133B68
|
||||
# Tags: [affects-gameplay]
|
||||
################################################################################
|
||||
|
||||
addi r4, r29, 0x0
|
6
External/PortPriority/ThrowHitstun/SetPtrFalconGanon.asm
vendored
Normal file
6
External/PortPriority/ThrowHitstun/SetPtrFalconGanon.asm
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
################################################################################
|
||||
# Address: 0x800E52E8
|
||||
# Tags: [affects-gameplay]
|
||||
################################################################################
|
||||
|
||||
addi r4, r29, 0x0
|
Reference in New Issue
Block a user