Completed [Game Mode] Chess Melee Standalone 1.1

Joined
Nov 9, 2014
Messages
652
#1
My friends and I are huge fans of Achilles1515 Achilles1515 's Chess Melee. I recreated it using a GObj proc so it can easily be used in other mods / from a .gct. Because it is a GObj proc, the code is entirely contained to running during Super Sudden Death.

Code:
$Chess Melee Standalone [Achilles1515, UnclePunch]
*Replaces Super Sudden Death
C21B8C74 00000060 #Main.asm
808D8840 388406D8
48000011 7CA802A6
90A40044 480002E0
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
41820010 2C030001
41820144 480001DC
3BA00000 7FA3EB78
3D808003 618C22C0
7D8903A6 4E800421
2C030002 40820088
7FA3EB78 3D808003
618C4110 7D8903A6
4E800421 8063002C
8883221F 548406F7
40820064 8883221D
54840739 40820058
88832219 54840673
4182004C 80830010
2C04000C 41820040
2C04000D 41820038
2C040004 41820018
2C040005 41820010
2C040006 41820008
4800002C 80630000
3D80800D 618C3E40
7D8903A6 4E800421
48000014 3BBD0001
2C1D0006 4180FF58
48000128 3B800000
7C1CE800 40820004
7F83E378 3D808003
618C22C0 7D8903A6
4E800421 2C030002
40820044 7F83E378
3D808003 618C4110
7D8903A6 4E800421
8063002C 8883221F
548406F7 40820020
38A00001 88832219
50A4177A 98832219
38800000 9083195C
90831958 3B9C0001
2C1C0006 4180FF94
3860003C B07E0001
38600001 987E0000
480000A0 A07E0001
3863FFFF B07E0001
2C030000 4082008C
3BA00000 7FA3EB78
3D808003 618C22C0
7D8903A6 4E800421
2C030002 40820054
7FA3EB78 3D808003
618C4110 7D8903A6
4E800421 7C7C1B78
8883221F 548406F7
40820030 7F83E378
3D80800D 618C331C
7D8903A6 4E800421
7F83E378 38800001
3D80800B 618CFD9C
7D8903A6 4E800421
3BBD0001 2C1D0006
4180FF8C 38600000
987E0000 48000004
BA810008 80010104
38210100 7C0803A6
4E800020 38C00000
60000000 00000000
Code:
#To be inserted at 801b8c74
.include "../Common.s"

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

#region ChessMelee_Init
ChessMelee_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  ChessMelee_Think
  mflr r4
  li  r5,23
  branchl r12,GObj_SchedulePerFrameFunction

ChessMelee_InitExit:
restore
blr

#endregion

#region ChessMelee_Think
ChessMelee_Think:
blrl

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

#Data Offsets
.set GameState,0x0    #byte
.set FrozenTimer,0x1  #half

#Definitions
#GameState
  .set InProgress,0x0
  .set Frozen,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,InProgress
  beq ChessMelee_Think_InProgress
  cmpwi r3,Frozen
  beq ChessMelee_Think_Frozen
  b ChessMelee_ThinkExit

#region InProgress
ChessMelee_Think_InProgress:
.set REG_LoopCount,29
#Check For Dead Players
  li  REG_LoopCount,0

ChessMelee_Think_InProgressLoop:
#Check Players Presence
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne ChessMelee_Think_InProgressIncLoop
#Get Players Data
  mr  r3,REG_LoopCount
  branchl r12,0x80034110
  lwz r3,0x2C(r3)
#Check If Player is still active (not sleep)
  lbz r4,0x221F(r3)
  rlwinm. r4,r4,0,27,27
  bne ChessMelee_Think_InProgressIncLoop
#Check if READY,GO is over
  lbz r4,0x221D(r3)
  rlwinm. r4,r4,0,28,28
  bne ChessMelee_Think_InProgressIncLoop
#Check if Blastzone code is being skipped
  lbz r4,0x2219(r3)
  rlwinm. r4,r4,0,25,25
  beq ChessMelee_Think_InProgressIncLoop
#Rebirth gets here too, check if NOT rebirth/rebirthWait
  lwz r4,0x10(r3)
  cmpwi r4,ASID_Rebirth
  beq ChessMelee_Think_InProgressIncLoop
  cmpwi r4,ASID_RebirthWait
  beq ChessMelee_Think_InProgressIncLoop
#If in any Star KO State, enter them into DeadUp
  cmpwi r4,ASID_DeadUpStar
  beq ChessMelee_Think_InProgressEnterDeadUp
  cmpwi r4,ASID_DeadUpStarIce
  beq ChessMelee_Think_InProgressEnterDeadUp
  cmpwi r4,ASID_DeadUpFall
  beq ChessMelee_Think_InProgressEnterDeadUp
  b  ChessMelee_Think_FreezeOtherPlayers
ChessMelee_Think_InProgressEnterDeadUp:
#Enter DeadUp
  lwz r3,0x0(r3)
  branchl r12,0x800d3e40
  b ChessMelee_Think_FreezeOtherPlayers

ChessMelee_Think_InProgressIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt ChessMelee_Think_InProgressLoop
#No players dead, exit think function
  b ChessMelee_ThinkExit

ChessMelee_Think_FreezeOtherPlayers:
#Freeze all other players
.set REG_DeadPlayer,29
.set REG_LoopCount,28
#Check For Dead Players
  li  REG_LoopCount,0
ChessMelee_Think_FreezeOtherPlayersLoop:
#Check if this is the dead player
  cmpw REG_LoopCount,REG_DeadPlayer
  bne ChessMelee_Think_FreezeOtherPlayers_NotDeadPlayer
ChessMelee_Think_FreezeOtherPlayers_NotDeadPlayer:
#Check Players Presence
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne ChessMelee_Think_FreezeOtherPlayersIncLoop
#Get Players Data
  mr  r3,REG_LoopCount
  branchl r12,0x80034110
  lwz r3,0x2C(r3)
#Check If Player is still active (not sleep)
  lbz r4,0x221F(r3)
  rlwinm. r4,r4,0,27,27
  bne ChessMelee_Think_FreezeOtherPlayersIncLoop
#Freeze Player
  li    r5,1
  lbz    r4,0x2219(r3)
  rlwimi r4,r5,2,29,29
  stb    r4,0x2219(r3)
#Remove any hitlag
  li  r4,0
  stw r4,0x195C(r3)
  stw r4,0x1958(r3)

ChessMelee_Think_FreezeOtherPlayersIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt ChessMelee_Think_FreezeOtherPlayersLoop

#Start Frozen Timer
  li  r3,FreezeFrames
  sth r3,FrozenTimer(REG_GObjData)
#Change State
  li  r3,Frozen
  stb r3,GameState(REG_GObjData)

  b ChessMelee_ThinkExit

#endregion

#region Frozen
ChessMelee_Think_Frozen:
#Decrement timer
  lhz r3,FrozenTimer(REG_GObjData)
  subi  r3,r3,1
  sth r3,FrozenTimer(REG_GObjData)
#Check if up
  cmpwi r3,0
  bne ChessMelee_ThinkExit

#Timer up, enter everyone into rebirth
.set REG_LoopCount,29
.set REG_PlayerGObj,28
#Check For Dead Players
  li  REG_LoopCount,0
ChessMelee_Think_FrozenLoop:
#Check Players Presence
  mr  r3,REG_LoopCount
  branchl r12,0x800322c0
  cmpwi r3,0x2
  bne ChessMelee_Think_FrozenIncLoop
#Get Players GObj
  mr  r3,REG_LoopCount
  branchl r12,0x80034110
  mr  REG_PlayerGObj,r3
#Check If Player is still active (not sleep)
  lbz r4,0x221F(r3)
  rlwinm. r4,r4,0,27,27
  bne ChessMelee_Think_FrozenIncLoop
#Remove Items + Etc
  mr  r3,REG_PlayerGObj
  branchl r12,0x800d331c
#Enter into Sleep
  mr  r3,REG_PlayerGObj
    li r4,0x1
    branchl    r12,0x800bfd9c

ChessMelee_Think_FrozenIncLoop:
  addi REG_LoopCount,REG_LoopCount,1
  cmpwi REG_LoopCount,6
  blt ChessMelee_Think_FrozenLoop

#Enter InProgress Game State
  li  r3,InProgress
  stb r3,GameState(REG_GObjData)
  b ChessMelee_ThinkExit

#endregion

ChessMelee_ThinkExit:
restore
blr

#endregion

InjectionExit:
  li  r6,0
 
Last edited:

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
379
#2
Wow, nice use of GObjs! Thanks for providing the ASM, too. I’m having some trouble following it without “common.s” though.

How does this method of generating a GObjs specify a p_link and gx_link ID? Is it safe to use in all scenes, or just matches?
Also, is a “GObj proc” just a gx_link callback, or are you referencing some other callback event?
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
461
NNID
Psion312
#3
Wow, nice use of GObjs! Thanks for providing the ASM, too. I’m having some trouble following it without “common.s” though.

How does this method of generating a GObjs specify a p_link and gx_link ID? Is it safe to use in all scenes, or just matches?
Also, is a “GObj proc” just a gx_link callback, or are you referencing some other callback event?
The CreateGObj that UP uses is one at 803901F0. So it's taking the Class as 22, P_Link as 23, and P Priority as 0.

Also, the GObj_SchedulePerFrameFunction that is used (having seen UP's map vs my own naming convention) is 803901F0, I believe. So, he's setting the Think function as the render callback.
 
Joined
Nov 9, 2014
Messages
652
#4
Wow, nice use of GObjs! Thanks for providing the ASM, too. I’m having some trouble following it without “common.s” though.
Yeah sorry, here's the file https://ghostbin.com/paste/utpsq. Lots of stuff in there, some Training Mode related variables too.

How does this method of generating a GObjs specify a p_link and gx_link ID? Is it safe to use in all scenes, or just matches?
I'm not sure which aspect of the GObj is a "p_link" and "gx_link", but it is safe to use in all scenes. I use them all over the place, they are extremely useful. The only downside is how much code is required to initialize them.

Also, is a “GObj proc” just a gx_link callback, or are you referencing some other callback event?
Again, im not sure what the "gx_link" callback is, I assume it has to do with drawing something onscreen? The per-frame process is the same kind of process as the per frame player think functions (8006a360, 8006c27c etc). I'm pretty sure they are internally known as "gproc" or "gobjproc", as seen in this assertion when setting the priority beyond the maximum value.



edit:
oh i see what youre referring to as p_link. All i know about p_link is that its value is used to decide which GObj linked list it will be attached to.
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
461
NNID
Psion312
#5
I'm not sure which aspect of the GObj is a "p_link" and "gx_link", but it is safe to use in all scenes. I use them all over the place, they are extremely useful. The only downside is how much code is required to initialize them.

oh i see what youre referring to as p_link. All i know about p_link is that its value is used to decide which GObj linked list it will be attached to.
P_Link and GX_Link do the same thing, effectively. P is for the object priority linked list and will decide how objects are ordered when one is freed, GX is for the render priority linked list (which is used when calling GObjProc). These parts of GObj are something I've written extensively.

I posited to Punkline before that randomizing P Priority might be a way to randomize player priority as currently players are all given a 0 priority making them order-of-operation based, but it's not something I've put a lot of testing into.
 

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
379
#6
UnclePunch UnclePunch - thanks for posting these examples. I wanted to mention a few things, just so that you’re aware of some mechanics behind this callback event.

Even though these callbacks can be used for general purposes like this, they are actually specialized for rendering, like Sins mentioned. It’s kind of like how you can technically write any function in place of move logic callbacks.

These callbacks make up the event sequence that ends up drawing stuff for each draw frame. So this means that -- for example -- this code that allows GObj render callbacks to be toggled will also be able to toggle the callbacks that you’re using. (I think that was also part of your question, in the thread.)

I don’t think there’s any reason these can’t be exploited for general purposes like you’re doing, but it’s worth keeping in mind that these render callbacks will be a sort of “post-process” relative to other functions that the game uses to do things like updates to player action states -- executing after everything is updated. It will also probably execute each paused draw frame, like in cases where slowmo or frame advancement is used.

It’s also worth noting that all of this means that callbacks executed from a GObj like this are particularly well suited for making codes that draw geometry to gx. I may end up using this method in place of a code I had in mind for plugging in drawing-based codes with PRIM LITE!

---


P_Link and GX_Link do the same thing, effectively. P is for the object priority linked list and will decide how objects are ordered when one is freed, GX is for the render priority linked list (which is used when calling GObjProc). These parts of GObj are something I've written extensively.

I posited to Punkline before that randomizing P Priority might be a way to randomize player priority as currently players are all given a 0 priority making them order-of-operation based, but it's not something I've put a lot of testing into.

Just so that I can be sure that I understand correctly; the gx_link list serves the purpose of creating a draw order through execution of render_cb. When this code uses p_link 23, is it basically just creating a benign dummy group for collecting arbitrary objects?

And does that mean that -- since the gx_link list is independent from the p_link list -- we can potentially insert render callbacks in-between meaningfully grouped GObjs (like players and items) through careful gx_link and render_priority arguments when generating new GObjs?
 
Last edited:
Joined
Nov 9, 2014
Messages
652
#7
Even though these callbacks can be used for general purposes like this, they are actually specialized for rendering
That doesn't make much sense to me. The CSS uses these callbacks to manage player inputs and resulting menu behavior, and they're used in game to manage the animations, inputs, and collision behavior per player.

This is the blrl that they are called from,
1553632581661.png


You might be thinking of this blrl, which exclusively handles rendering/drawing (ignore the name, i named it a while ago and now im used to it)
1553632657925.png
 
Joined
Nov 9, 2014
Messages
652
#8
Also, the GObj_SchedulePerFrameFunction that is used (having seen UP's map vs my own naming convention) is 803901F0, I believe. So, he's setting the Think function as the render callback.
The function i use to attach a callback is 8038fd54, and i believe its different from the render callback. I believe the render callback is set using 8039069c.

These functions run with the game engine, and can optionally run during game pauses by using a bitflag when initializing the GObj.
 
Last edited:

Punkline

Dr. Frankenstack
Premium
Joined
May 15, 2015
Messages
379
#9
Oh, yeah, the second one is the one I was speaking of. It should still be possible to use like I mentioned, but I guess it's not what you're using. Sorry for the confusion.

So GObjProc refers to a function I have labeled as "wP_RunObjectFrameFunctions" from the old symbols map, which is actually the opposite of what I spoke of, lol. It basically does all the updating BEFORE drawing, if I understand correctly. I can see now what you meant by comparing them to the playerThink function.

So, when creating a process for a GObj like this, I'm assuming that the callback address is stored in some kind of external structure, right? Not directly local to the GObj structure, like the render callback I was confusing it with? Do you have any notes on the structure used for GObjProc callbacks?
 
Last edited:

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
461
NNID
Psion312
#10
The function i use to attach a callback is 8038fd54, and i believe its different from the render callback. I believe the render callback is set using 8039069c.

These functions run with the game engine, and can optionally run during game pauses by using a bitflag when initializing the GObj.
Ahh. Yeah, the function you're calling is one I've been trying to work out because it uses GObj_Def_2 which I think has a slightly different GObj structure. It's one that puzzled me cause it was setting the cb in a spot that's normally a different value.
 
Joined
Nov 9, 2014
Messages
652
#11
Oh, yeah, the second one is the one I was speaking of. It should still be possible to use like I mentioned, but I guess it's not what you're using. Sorry for the confusion.

So GObjProc refers to a function I have labeled as "wP_RunObjectFrameFunctions" from the old symbols map, which is actually the opposite of what I spoke of, lol. It basically does all the updating BEFORE drawing, if I understand correctly. I can see now what you meant by comparing them to the playerThink function.

So, when creating a process for a GObj like this, I'm assuming that the callback address is stored in some kind of external structure, right? Not directly local to the GObj structure, like the render callback I was confusing it with? Do you have any notes on the structure used for GObjProc callbacks?
I haven't documented the structure unfortunately, i think the GObjProc uses a linked list or something because as you know, you can have a bunch of processes tied to a single GObj.
 

SinsOfApathy

Smash Journeyman
Joined
Feb 24, 2015
Messages
461
NNID
Psion312
#12
I haven't documented the structure unfortunately, i think the GObjProc uses a linked list or something because as you know, you can have a bunch of processes tied to a single GObj.
https://github.com/PsiLupan/FRAY/blob/master/src/gobj.h#L48

Tada! Decided to look into it tonight, since the Title Menu set it for the Fog and Joint animation callbacks.

Also realized offset 0x18 of the GObj is actually the pointer to it's Proc object (which is why it has a pointer to a Player_Think function). So, updated the spreadsheet with these details as well.
 
Last edited:
Top