• 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!

Request Announcer says different line after JV5

Akuji the Sniper

Smash Rookie
Joined
Oct 31, 2009
Messages
20
Basically, instead of the game always ending with the announcer saying "Game!", the games checks if the winner has both 0% damage and ended with the starting amount of stock. If so, the announcer uses the "Wow! Incredible!" soundclip the announcer says after beating a mode in Very Hard instead of "Game!", and maybe some cheering. There might need to be a little more delay between when the "Game!" part goes to the results screen to fit the soundclip.

I thought it would be a fun little gimmick, even if it's very hard to see happen. Maybe a version that only checks starting stock but not damage would be fine too. This would also probably not work correctly in a Team-Smash setting...
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Sweet idea. I gave this a shot, but I ran into some predictable problems. It’s something I’d like to figure out, if anyone knows more about it.

While it’s easy enough to intercept the “GAME!” sound and give it some logic to replace the SFX ID on conditions like remaining stock, number of deaths, total damage, etc--the sound “Wow, Incredible!” has to be loaded into memory in order for it to play.

The sound WILL play, but only if you’ve recently beaten the game or played the sound in the sound test menu...

To demonstrate the problem, here’s a concept code that just checks for any player that has 0 deaths and has taken 0 damage at the end of a match:

$JV Announcer 0.1 [Punkline]
C22F731C 0000000C
807E000C 3C800007
6084C855 7C032000
40A2004C 38800006
7C8903A6 3C808045
60843080 80040000
2C000000 41A2001C
80040068 2C000000
40A20010 80040D1C
2C000000 41820010
38840E90 4200FFD8
4800000C 38600000
60639C45 00000000
Code:
#JV announcer [Punkline]
#@802f731c: lwz r3,0xC (r30)    (Loads SFX ID of pending announcer sound effect)
#r0,r3,r4,r5, cr0, ctr are safe
#r30 = static BA of SFX ID values; baked into DOL
#--When announcer says "GAME!" each player block is checked
#--If a player has 0% and lost no stock, the SFX ID is replaced with "WOW, INCREDIBLE!"

lwz r3, 0xC(r30)                #loading a SFX ID for a call that (only?) plays announcer sounds
lis r4, 0x7
ori r4, r4, 0xc855              #0x7c855 is SFX ID for "GAME!"
cmpw r3, r4                     #we only want to intercept this particular ID
bne+ return

li r4, 6
mtctr r4                        #there are 6 static player blocks to check
lis r4, 0x8045
ori r4, r4, 0x3080              #r4 = player block BA

#this loops once for each block
playerBlockCheck:
lwz r0, 0(r4)
cmpwi r0, 0                     #an inactive player block will store "0" at offset 0x0
beq+ nextPlayerBlock            #so only check active players

lwz r0, 0x68(r4)                #check number of falls
cmpwi r0, 0
bne+ nextPlayerBlock            #if not 0, move on to next player

lwz r0, 0xD1C(r4)               #check total damage recieved (this is actually a float, but we only check for 0)
cmpwi r0, 0
beq- jv5                        #If no damage was taken, then a player meets jv5 conditions

nextPlayerBlock:
addi r4, r4, 0xe90              #blocks are 0xe90 in length
bdnz+ playerBlockCheck
b return                        #if all players have been checked, then nobody got jv5 conditions

jv5:

li r3, 0
ori r3, r3, 0x9c45              #0x9c45 is SFX ID for "WOW, INCREDIBLE!"

return:

If you test it, you’ll see that the “Wow, Incredible!” sound depends on whether it’s been loaded by something else. Hit the sound test and listen to the narrator say it, and then it’ll work.

---

I’m interested in how the sound test loads sounds before playing them. Does anyone have any experience with this sort of thing? It'd be cool to see this work.
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
Punkline Punkline
It seems like setting r3 to the SFX ID and then branch linking to function 80023b24 will load the SFX in RAM, if not already in, and play the sound - which is what the Sound Test menu uses. In the above function, put a breakpoint at 80023e4c when playing a SFX from the Sound Test that isn't already loaded in the RAM. You'll see that r3 is a pointer to the ASCII filepath of the sound file, and this line doesn't get hit if the SFX file is already in RAM. 80023c38 is the line that checks if the file is loaded in RAM. I think there is a table of word flags it references where 0xFFFFFFFF = file is not in RAM.

But I just did a test with playing "Failure" (SFX ID 0x9c48) in the Debug Menu using this function and it did not work...
 
Last edited:

Achilles1515

Smash Master
Joined
Jun 18, 2007
Messages
3,211
Location
Cincinnati / Columbus OH
So it actually does work (still need to investigate why not in the Debug Menu), but there is certainly lag from the processing time it takes to read the file. I tried this with the "Wow, Incredible!" SFX.

C206BE84 00000007
3CA08160 80850000
2C040000 41820020
7C832378 38800000
90850000 3CA08002
60A53B24 7CA803A6
4E800021 881F2225
60000000 00000000

Code:
# manually write the SFX ID [word] to 81600000 while in-game to play the SFX

lis r5,0x8160
lwz r4,0(r5)
cmpwi r4,0
beq- DEFAULT
mr r3,r4
li r4,0
stw r4,0(r5)
lis r5,0x8002
ori r5,r5,0x3b24
mtlr r5
blrl

DEFAULT:
lbz r0,0x2225(r31)
 

Akuji the Sniper

Smash Rookie
Joined
Oct 31, 2009
Messages
20
I don't know much about this kind of stuff, but when does the game load the GAME sound byte into memory? Maybe around whenever GAME loads it can load the other sound byte also.

Then again idk what I'm talking about lol
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
So it actually does work (still need to investigate why not in the Debug Menu), but there is certainly lag from the processing time it takes to read the file. I tried this with the "Wow, Incredible!" SFX.

C206BE84 00000007
3CA08160 80850000
2C040000 41820020
7C832378 38800000
90850000 3CA08002
60A53B24 7CA803A6
4E800021 881F2225
60000000 00000000

Code:
# manually write the SFX ID [word] to 81600000 while in-game to play the SFX

lis r5,0x8160
lwz r4,0(r5)
cmpwi r4,0
beq- DEFAULT
mr r3,r4
li r4,0
stw r4,0(r5)
lis r5,0x8002
ori r5,r5,0x3b24
mtlr r5
blrl

DEFAULT:
lbz r0,0x2225(r31)
Buried treasure? @Absolome @flieskiller @DRGN @SinsOfApathy @Tater

Achilles1515 Achilles1515 This function is a gem, and your experiment and notes were very informative. Thanks a ton for sharing this!

After a quick peek, I wasn’t really able to figure out which part(s) of this function were responsible for loading the sound. Calling it at the end of the match seems to work fine, though. I should note that I don’t have a console environment to test on atm, so I’m not sure how significant the load time really is.

When using this soundtest function while other SFX are playing, the included call to “$SFX_stopAll” sounds a bit awkward.

So I’ve tried calling it at the beginning of a match (so the slight load time is lumped in with the stage loading,) and using a separate call to $SFX_stopAll to keep the resulting sound from being played so that the only superficial effect of calling the soundtest function is loading the sound in memory. That way, when the SFX call is made like it was originally, the sound is ready to be played.

Here’s an adjustment to my earlier concept, with all this in mind:

$JV5 Announcer 0.2 [Punkline, Achilles]
C22F731C 0000000C
807E000C 3C800007
6084C855 7C032000
40A2004C 38800006
7C8903A6 3C808045
60843080 80040000
2C000000 41A2001C
80040068 2C000000
40A20010 80040D1C
2C000000 41820010
38840E90 4200FFD8
4800000C 38600000
60639C45 00000000
C21C0814 0000000A
7C0802A6 90010004
9421FF80 BC610008
38600000 60639C45
3C808002 60843B24
7C8803A6 4E800021
3C608038 6063BD6C
7C6803A6 4E800021
B8610008 38210080
80010004 7C0803A6
3FE04330 00000000
Code:
    -==-


JV5 Announcer
Announcer says "Wow, Incredible!" instead of "Game!" when a player wins without taking any damage or losing any stock.
[Punkline, Achilles]
Version -- DOL Offset ------ Hex to Replace ---------- ASM Code
1.02 ----- 0x802f731c --- 807E000C -> Branch

807E000C 3C800007
6084C855 7C032000
40A2004C 38800006
7C8903A6 3C808045
60843080 80040000
2C000000 41A2001C
80040068 2C000000
40A20010 80040D1C
2C000000 41820010
38840E90 4200FFD8
4800000C 38600000
60639C45 00000000

1.02 ----- 0x801c0814 --- 3FE04330 -> Branch

7C0802A6 90010004
9421FF80 BC610008
38600000 60639C45
bl 0x80023b24
bl 0x8038bd6c
B8610008 38210080
80010004 7C0803A6
3FE04330 00000000
Code:
#JV5 announcer [Punkline, Achilles]
#@802f731c: lwz r3,0xC (r30)    (Loads SFX ID of pending announcer sound effect)
#r0,r3,r4,r5, cr0, ctr are safe
#r30 = static BA of SFX ID values; baked into DOL
#--When announcer says "GAME!" each player block is checked
#--If a player has 0% and lost no stock, the SFX ID is replaced with "WOW, INCREDIBLE!"

lwz r3, 0xC(r30)                #loading a SFX ID for a call that (only?) plays announcer sounds
lis r4, 0x7
ori r4, r4, 0xc855              #0x7c855 is SFX ID for "GAME!"
cmpw r3, r4                     #we only want to intercept this particular ID
bne+ return

li r4, 6
mtctr r4                        #there are 6 static player blocks to check
lis r4, 0x8045
ori r4, r4, 0x3080              #r4 = player block BA

#this loops once for each block
playerBlockCheck:
lwz r0, 0(r4)
cmpwi r0, 0                     #an inactive player block will store "0" at offset 0x0
beq+ nextPlayerBlock            #so only check active players

lwz r0, 0x68(r4)                #check number of falls
cmpwi r0, 0
bne+ nextPlayerBlock            #if not 0, move on to next player

lwz r0, 0xD1C(r4)               #check total damage recieved (this is actually a float, but we only check for 0)
cmpwi r0, 0
beq- jv5                        #If no damage was taken, then a player meets jv5 conditions

nextPlayerBlock:
addi r4, r4, 0xe90              #blocks are 0xe90 in length
bdnz+ playerBlockCheck
b return                        #if all players have been checked, then nobody got jv5 conditions

jv5:
li r3, 0
ori r3, r3, 0x9c45              #0x9c45 is SFX ID for "WOW, INCREDIBLE!"
return:



#@801c0814: lis r31, 0x4330     (start of stageInitialization)
#r31,r4,r5,cr0,  are safe
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x80(sp)
stmw r3, 0x8(sp)                #keep the context safe during calls

li r3, 0
ori r3, r3, 0x9c45              #0x9c45 is SFX ID for "WOW, INCREDIBLE!"

lis r4, 0x8002
ori r4, r4, 0x3b24
mtlr r4
blrl                            #load SFX if it isn't in memory (and then play it)

lis r3, 0x8038
ori r3, r3, 0xbd6c
mtlr r3
blrl                            #stop resulting SFX from being played; just load it

lmw r3, 0x8(sp)
addi sp, sp, 0x80
lwz r0, 0x4(sp)
mtlr r0

return:
lis r31, 0x4330                 #original instruction

Edit: just removed a couple of redundant lines in the second hook.
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Actually, Achilles1515 Achilles1515 -- It looks like using this function mid-game unloads other sounds as a consequence. In the code above (and in your 0x81600000 soundtest code) the call to this function seems to cause character voices and some attack SFX to not play anymore.

I went back to your soundtest code and put a breakpoint at the beginning of $SFX_playSFX so I could watch the incoming IDs of sounds that were being called but not played after loading a new sound (like "Failure.")

Afterwards, as you might expect, loading a character voice sound with the soundtest caused all of the character voices became available again and the "Failure" sound was unloaded.
 
Last edited:
Top Bottom