Completed [Game Mode] One Stock Rotations v1.1

Joined
Nov 9, 2014
Messages
632
#1
Been on a game mode kick the last 2 days. This code replaces Giant Melee with a new game mode that despawns all but the first 2 present characters, and respawns the next available despawned character upon someone dying. The surviving player currently keeps their percent upon KO'ing a player, but I'm open to changing this if I see a demand for it.

Once again, this uses a GObjProc to accomplish the logic. There are no hooks in the game engine and its handled from outside, meaning the code is entirely confined to Giant Melee!

https://gfycat.com/InsidiousOpulentBergerpicard

Code:
$One Stock Rotations v1.1 [UnclePunch]
*Replaces Giant Melee
C21B9090 00000080
808D8840 38840F98
48000011 7CA802A6
90A40044 480003E4
4E800021 7C0802A6
90010004 9421FF00
BE810008 38600016
38800017 38A00000
3D808039 618C01F0
7D8903A6 4E800421
7C7F1B78 38600040
3D808037 618CF1E4
7D8903A6 4E800421
7C7E1B78 7FC3F378
38800040 3D808000
618CC160 7D8903A6
4E800421 7FE3FB78
3880000E 3CA08037
60A5F1B0 7FC6F378
3D808039 618C0B68
7D8903A6 4E800421
7FE3FB78 48000031
7C8802A6 38A00017
3D808038 618CFD54
7D8903A6 4E800421
BA810008 80010104
38210100 7C0803A6
4E800020 4E800021
7C0802A6 90010004
9421FF00 BE810008
7C7F1B78 83DF002C
887E0000 2C030000
4182000C 2C030001
41820134 3D808016
618CB558 7D8903A6
4E800421 2C030003
4080001C 7FE3FB78
3D808039 618C0228
7D8903A6 4E800421
480002B4 3BA00000
3B800000 7FA3EB78
3D808003 618C22C0
7D8903A6 4E800421
2C030002 4082001C
387E0001 7FBC19AE
9BBE0003 3B9C0001
2C1C0002 408000B0
3BBD0001 2C1D0006
4180FFC4 7FA3EB78
3D808003 618C22C0
7D8903A6 4E800421
2C030002 40820088
7FA3EB78 3D808003
618C4110 7D8903A6
4E800421 7C7B1B78
3D80800B 618CFD04
7D8903A6 4E800421
807B002C 88632222
5460F7FF 4182002C
7FA3EB78 38800001
3D808003 618C418C
7D8903A6 4E800421
3D80800B 618CFD04
7D8903A6 4E800421
3C60804A 606310C8
1C9D0064 7C632214
88830010 38A00001
50A43E30 50A43672
98830010 3BBD0001
2C1D0006 4180FF58
38600001 987E0000
480001B4 3B800000
387E0001 7FBC18AE
7FA3EB78 3D808003
618C4110 7D8903A6
4E800421 7C7B1B78
8063002C 8883221F
548406F7 40820170
8883221D 54840739
40820164 88832219
54840673 41820158
80830010 2C04000C
4182014C 2C04000D
41820144 2C040004
41820018 2C040005
41820010 2C040006
41820008 4800001C
7F63DB78 3D80800D
618C3E40 7D8903A6
4E800421 48000110
807B002C 80832340
2C040001 41810100
6B830001 389E0001
7F2320AE 8B1E0003
7F1AC378 480000D0
7F43D378 3D808003
618C22C0 7D8903A6
4E800421 2C030002
408200B4 7C1AE800
418200AC 7C1AC800
418200A4 7F43D378
3D808003 618C3BD8
7D8903A6 4E800421
2C030000 40810088
7F43D378 3D808003
618C4110 7D8903A6
4E800421 38800001
3D80800B 618CFD9C
7D8903A6 4E800421
387E0001 7F5C19AE
9B5E0003 7F63DB78
3D80800B 618CFD04
7D8903A6 4E800421
809B002C 88642222
5460F7FF 41820048
8864000C 38800001
3D808003 618C418C
7D8903A6 4E800421
3D80800B 618CFD04
7D8903A6 4E800421
4800001C 3B5A0001
2C1A0006 41800008
3B400000 7C1AC000
4082FF20 3B9C0001
2C1C0002 4180FE5C
48000004 BA810008
80010104 38210100
7C0803A6 4E800020
38C00000 00000000
Code:
#To be inserted at 801b9090
.include "../Common.s"

#Store Pointer to onStartMelee function
  lwz    r4, -0x77C0 (r13)
  addi    r4, r4, 3992
  bl  Rotations_Init
  mflr r5
  stw r5,0x44(r4)
  b InjectionExit

#region Rotations_Init
Rotations_Init:
blrl

.set REG_GObj,31
.set REG_Data,30

.set DataSize,64

backup

#Create GObj
  li  r3,22
  li  r4,23
  li  r5,0
  branchl r12,GObj_Create
  mr  REG_GObj,r3

#Alloc Mem
  li  r3,DataSize
  branchl r12,HSD_MemAlloc
  mr  REG_Data,r3

#Zero Data
  mr  r3,REG_Data
  li  r4,DataSize
  branchl r12,ZeroAreaLength

#Attach Data
  mr  r3,REG_GObj
  li  r4,14
  load r5,HSD_Free
  mr  r6,REG_Data
  branchl r12,GObj_Initialize

#Attach Process
  mr  r3,REG_GObj
  bl  Rotations_Think
  mflr r4
  li  r5,23
  branchl r12,GObj_SchedulePerFrameFunction

Rotations_InitExit:
restore
blr

#endregion

#region Rotations_Think
Rotations_Think:
blrl

#Registers
.set REG_GObj,31
.set REG_GObjData,30

#Data Offsets
.set GameState,0x0    #byte
.set P1Slot,0x1       #byte
.set P2Slot,0x2       #byte
.set LastPlayerSpawned,0x3  #byte

#Definitions
#GameState
  .set FirstFrame,0x0
  .set InProgress,0x1

#Constants
  .set FreezeFrames, 1 * 60

backup

#Init Pointers
  mr  REG_GObj,r3
  lwz REG_GObjData,0x2C(REG_GObj)

#Check state of game
  lbz r3,GameState(REG_GObjData)
  cmpwi r3,FirstFrame
  beq Rotations_Think_FirstFrame
  cmpwi r3,InProgress
  beq Rotations_Think_InProgress

#region FirstFrame
Rotations_Think_FirstFrame:
#Ensure over 2 players are present
  branchl r12,0x8016b558
  cmpwi r3,3
  bge Rotations_Think_FirstFrameContinue
#Destroy Think Function
  mr  r3,REG_GObj
  branchl r12,0x80390228
  b Rotations_ThinkExit

Rotations_Think_FirstFrameContinue:
.set REG_LoopCount,29
.set REG_PlayerSlotIndex,28
#Init Loop
  li  REG_LoopCount,0
  li  REG_PlayerSlotIndex,0
Rotations_Think_FirstFrameLoop:
#Check Players Presence
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne Rotations_Think_FirstFrameIncLoop
#Player exists, store to data
  addi r3,REG_GObjData,P1Slot
  stbx REG_LoopCount,REG_PlayerSlotIndex,r3
#Store as last player spawned
  stb REG_LoopCount,LastPlayerSpawned(REG_GObjData)
#Now do next player
  addi REG_PlayerSlotIndex,REG_PlayerSlotIndex,1
#Check if finished doing both players
  cmpwi REG_PlayerSlotIndex,2
  bge Rotations_Think_FirstFrameSleepRemainingPlayersIncLoop
Rotations_Think_FirstFrameIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt Rotations_Think_FirstFrameLoop

#Now sleep the other players
Rotations_Think_FirstFrameSleepRemainingPlayersLoop:
.set REG_PlayerGObj,27
#Check Players Presence
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne Rotations_Think_FirstFrameSleepRemainingPlayersIncLoop
#Get players GObj
  mr  r3,REG_LoopCount
  branchl r12,0x80034110
  mr  REG_PlayerGObj,r3
#Sleep player
  branchl r12,0x800bfd04
#Check if they have a follower
  lwz r3,0x2C(REG_PlayerGObj)
  lbz r3,0x2222(r3)
  rlwinm.    r0, r3, 30, 31, 31
  beq Rotations_Think_FirstFrameSleepRemainingPlayers_DestroyHUD
#Get Follower GObj
  mr  r3,REG_LoopCount
  li  r4,1
  branchl r12,0x8003418c
#SLeep them as well
  branchl r12,0x800bfd04
Rotations_Think_FirstFrameSleepRemainingPlayers_DestroyHUD:
#Destroy their percent HUD
  load r3,0x804a10c8
  mulli r4,REG_LoopCount,100
  add r3,r3,r4
  lbz    r4, 0x0010 (r3)
  li  r5,1
  rlwimi r4,r5,7,24,24
  rlwimi r4,r5,6,25,25
  stb    r4, 0x0010 (r3)

Rotations_Think_FirstFrameSleepRemainingPlayersIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt Rotations_Think_FirstFrameSleepRemainingPlayersLoop

#Change state to every frame
  li  r3,InProgress
  stb r3,GameState(REG_GObjData)

  b Rotations_ThinkExit
#endregion

#region InProgress
Rotations_Think_InProgress:
#Check For Dead Players
.set REG_PlayerSlot,29
.set REG_PlayerSlotIndex,28
.set REG_PlayerGObj,27
#Init Loop
  li  REG_PlayerSlotIndex,0

#################################
## Check For Dead Players Loop ##
#################################
Rotations_Think_InProgressLoop:
#Get Players Slot
  addi r3,REG_GObjData,P1Slot
  lbzx  REG_PlayerSlot,REG_PlayerSlotIndex,r3
#Get Players GObj
  mr  r3,REG_PlayerSlot
  branchl r12,0x80034110
  mr  REG_PlayerGObj,r3
  lwz r3,0x2C(r3)
#Check If Player is still active (not sleep)
  lbz r4,0x221F(r3)
  rlwinm. r4,r4,0,27,27
  bne Rotations_Think_InProgressIncLoop
#Check if READY,GO is over
  lbz r4,0x221D(r3)
  rlwinm. r4,r4,0,28,28
  bne Rotations_Think_InProgressIncLoop
#Check if Blastzone code is being skipped
  lbz r4,0x2219(r3)
  rlwinm. r4,r4,0,25,25
  beq Rotations_Think_InProgressIncLoop
#Rebirth gets here too, check if NOT rebirth/rebirthWait
  lwz r4,0x10(r3)
  cmpwi r4,ASID_Rebirth
  beq Rotations_Think_InProgressIncLoop
  cmpwi r4,ASID_RebirthWait
  beq Rotations_Think_InProgressIncLoop
#If in any Star KO State, enter them into DeadUp
  cmpwi r4,ASID_DeadUpStar
  beq Rotations_Think_InProgressEnterDeadUp
  cmpwi r4,ASID_DeadUpStarIce
  beq Rotations_Think_InProgressEnterDeadUp
  cmpwi r4,ASID_DeadUpFall
  beq Rotations_Think_InProgressEnterDeadUp
  b  Rotations_Think_InProgressCheckDeadFrame
Rotations_Think_InProgressEnterDeadUp:
#Enter DeadUp
  mr  r3,REG_PlayerGObj
  branchl r12,0x800d3e40
  b Rotations_Think_InProgressIncLoop
Rotations_Think_InProgressCheckDeadFrame:
#Here we know the player is in a dead state
#Ensure he is in frame X of the dead animation
  lwz r3,0x2C(REG_PlayerGObj)
  lwz r4,0x2340(r3)
  cmpwi r4,1
  bgt Rotations_Think_InProgressIncLoop

#################################
## Search For Next Player Loop ##
#################################
Rotations_Think_InProgressSearchForNextPlayer:
.set REG_LoopCount,26
.set REG_OtherPlayerSlot,25
.set REG_LastPlayerSpawned,24

#Get other player
  xori r3,REG_PlayerSlotIndex,0x1
  addi r4,REG_GObjData,P1Slot
  lbzx REG_OtherPlayerSlot,r3,r4
#Loop starts at LastPlayerSpawned+1
  lbz REG_LastPlayerSpawned,LastPlayerSpawned(REG_GObjData)
  mr REG_LoopCount,REG_LastPlayerSpawned
  b Rotations_Think_InProgressSearchForNextPlayerIncLoop
Rotations_Think_InProgressSearchForNextPlayerLoop:
#Player who just died is in REG_PlayerSlot
#Player who is alive is in REG_OtherPlayerSlot
#Check if player is present
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne Rotations_Think_InProgressSearchForNextPlayerIncLoop
#Ensure this isnt the player who just died
  cmpw REG_LoopCount,REG_PlayerSlot
  beq Rotations_Think_InProgressSearchForNextPlayerIncLoop
#Ensure this isnt the other player
  cmpw REG_LoopCount,REG_OtherPlayerSlot
  beq Rotations_Think_InProgressSearchForNextPlayerIncLoop
#This is a unique player, check if they have stock remainings
  mr  r3,REG_LoopCount
  branchl r12,0x80033bd8
  cmpwi r3,0
  ble Rotations_Think_InProgressSearchForNextPlayerIncLoop
#Get GObj First
  mr  r3,REG_LoopCount
  branchl r12,0x80034110
#Respawn
    li r4,0x1
    branchl    r12,0x800bfd9c
#Save their slot to the GObjData
  addi r3,REG_GObjData,P1Slot
  stbx REG_LoopCount,REG_PlayerSlotIndex,r3
#Save this as the last player spawned
  stb REG_LoopCount,LastPlayerSpawned(REG_GObjData)
#Now enter the recently deceased player into perm sleep
  mr  r3,REG_PlayerGObj
  branchl r12,0x800bfd04
#Check if they have a follower
  lwz r4,0x2C(REG_PlayerGObj)
  lbz r3,0x2222(r4)
  rlwinm.    r0, r3, 30, 31, 31
  beq Rotations_Think_InProgressIncLoop
#Get Follower GObj
  lbz r3,0xC(r4)
  li  r4,1
  branchl r12,0x8003418c
#SLeep them as well
  branchl r12,0x800bfd04
  b Rotations_Think_InProgressIncLoop
Rotations_Think_InProgressSearchForNextPlayerIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt Rotations_Think_InProgressSearchForNextPlayerIncLoopCheckIfDone
#Player count is over 6, loop back to 0
  li  REG_LoopCount,0
Rotations_Think_InProgressSearchForNextPlayerIncLoopCheckIfDone:
#Now check if we did a full loop
  cmpw REG_LoopCount,REG_LastPlayerSpawned
  bne Rotations_Think_InProgressSearchForNextPlayerLoop
#If we get here, no other players are reported as alive, so do nothing for normal respawn behvior

Rotations_Think_InProgressIncLoop:
  addi REG_PlayerSlotIndex,REG_PlayerSlotIndex,1
  cmpwi REG_PlayerSlotIndex,2
  blt Rotations_Think_InProgressLoop
#Neither player is dead, exit think function
  b Rotations_ThinkExit

#endregion

Rotations_ThinkExit:
restore
blr

#endregion

InjectionExit:
  li  r6,0
 
Last edited:
Joined
Nov 9, 2014
Messages
632
#2
Updated to keep track of last spawned player and start searching for new player after that one (helps when 4+ players are present) and also be compatible with Ice Climbers (**** these guys).
 
Last edited:

flieskiller

Smash Journeyman
Joined
Jan 3, 2013
Messages
426
#3
Hello.

It is a great code, I wanted something like that for a long time, thank you for having done it.

I have one question though: Is it possible to randomize the two starting players in the rotation? Right now, it is always starting with player 1 and 2, then player 3 as the next player spawning in the game. Ideally, the order of 1-2-3-4 would be shuffled to have any two players starting, then another random as the third. If it's too much effort for something as small as this, then you can just ignore this, as it's only a small QoL.
 
Joined
Nov 9, 2014
Messages
632
#4
Hello.

It is a great code, I wanted something like that for a long time, thank you for having done it.

I have one question though: Is it possible to randomize the two starting players in the rotation? Right now, it is always starting with player 1 and 2, then player 3 as the next player spawning in the game. Ideally, the order of 1-2-3-4 would be shuffled to have any two players starting, then another random as the third. If it's too much effort for something as small as this, then you can just ignore this, as it's only a small QoL.
Thanks! I had the same idea recently, will try to implement that soon.
 
Top