Punkline
Dr. Frankenstack
- Joined
- May 15, 2015
- Messages
- 423
Stormghetti
requested a code that plays unused fanfare BGM when triggering the announcer voice at the end of stadium games, event matches, and other mini games.
Announcer Fanfares 2.0:
uses mytoc blocks 155, 158, and 341
---
This code allows users to pair BGM IDs with announcer SFX IDs to create triggers for playing a fanfare. The default configuration includes:
00009C46 00000012 # “Complete!” = FF_GOOD
0007C85E 00000012 # “Success!” = FF_GOOD
00009C40 0000001C # “A New Record!” = FF_STEP3
00009C48 0000000C # “Failure” = FF_BAD
Here's a list of BGM IDs, for reference. These were acquired by observing the index starting at 803BBDDC:
---
To customize what fanfare plays, modify the list inside either the DOL mod or the Gecko Code to use music from the above index:
---
Update notes:
Announcer Fanfares 2.0:
uses mytoc blocks 155, 158, and 341
Code:
-==-
Announcer Fanfares 2.0
Pair announcer SFX IDs with a fanfare BGM ID.
Default configuration triggers unused fanfares:
"Complete!" - plays FF_GOOD.hps
"Success!" - plays FF_GOOD.hps
"New Record!" - plays FF_STEP3.hps
"Failure" - plays FF_BAD.hps
[Punkline]
1.02 ----- 802F7358 --- C822E0D0 -> C8228000
1.02 ----- 802F72D0 --- C822E0D0 -> C8228000
1.02 ----- 8017F398 --- CBC2AAB0 -> CBC280A0
1.02 ----- 8017C3D8 --- C862AA50 -> C86280A0
1.02 ----- 80023864 --- 38210008 -> 38210030
1.02 ----- 80023860 --- 8001000c -> 80010034
1.02 ----- 804DA430 --- 43300000 -> branch
4E800021 # start list
# modify these to change triggers, or the resulting fanfares
00009C46 00000012 # "Complete!" SFX ID, FF_GOOD.hps
0007C85E 00000012 # "Success!" SFX ID, FF_GOOD.hps
00009C40 0000001C # "New Record!" SFX ID, FF_STEP3.hps ID
00009C48 0000000C # "Failure" SFX ID, FF_BAD.hps
FFFFFFFF # end of list
1.02 ----- 804DA490 --- 43300000 -> branch
7C0802A6 90010004 9421FFF0 8062AAB4 2C030000 40810010
bl 0x80023f28
38600000 9062AAB4 38210010 80010004 7C0803A6 4E800020 00000000
1.02 ----- 804DA434 --- 80000000 -> branch
7C0802A6 90010004 9421FFF8 38C2AA50 7CC803A6 4E800021 7CC802A6 80E60000 7C071800 40A2001C 80E60004 90E2AAB4 9062E0D4 3902AAB0 9102E0D0 48000010 84E60008 2C070000 4181FFD8 38210008 80010004 7C0803A6 4E800020 00000000
1.02 ----- 800237bc --- 9421fff8 -> branch
9421FFD0 7C000026 90010020 80C2E0D0 80E2E0D4 39000000 9102E0D0 9102E0D4 2C060000 40A00028 7C071800 40A20020 38E10010 7C6765AA 7CE33B78 7CC803A6 4E800021 38610010 7C6364AA 80010020 7C0FF120 00000000
1.02 ----- 802f72e8 --- 4c411382 -> branch
4C411382 7C600026 90610018 40A20028 807E0020 2C030000 41810010 807E000C 2C030000 40810010 3802AA54 7C0803A6 4E800021 80610018 7C6FF120 00000000
1.02 ----- 802f6ecc --- 281e0000 -> branch
3862AA54 7C6803A6 7FA3EB78 4E800021 281E0000 00000000
1.02 ----- 80180d14 --- 981e0000 -> branch
981E0000 7C000026 90010018 800DAF34 2C000000 40A20044 807E0004 5463103A 7C63F214 80030014 7C1D0000 4181002C 38000001 900DAF34 3C600001 38639C48 3882AA54 7C8803A6 4E800021 3880007F 38A00040
bl 0x800237a8
80010018 7C0FF120 00000000
1.02 ----- 80180e94 --- 3880007f -> branch
3882AA54 7C8803A6 4E800021 3880007F 00000000
$Announcer Fanfares 2.0 [Punkline]
042F7358 C8228000
042F72D0 C8228000
0417F398 CBC280A0
0417C3D8 C86280A0
04023864 38210030
04023860 80010034
C24DA430 00000006
60000000 4E800021
00009C46 00000012
0007C85E 00000012
00009C40 0000001C
00009C48 0000000C
FFFFFFFF 00000000
C24DA490 00000009
7C0802A6 90010004
9421FFF0 8062AAB4
2C030000 4081001C
3D808002 618C3F28
7D8803A6 4E800021
38600000 9062AAB4
38210010 80010004
7C0803A6 4E800020
60000000 00000000
C24DA434 0000000C
7C0802A6 90010004
9421FFF8 38C2AA50
7CC803A6 4E800021
7CC802A6 80E60000
7C071800 40A2001C
80E60004 90E2AAB4
9062E0D4 3902AAB0
9102E0D0 48000010
84E60008 2C070000
4181FFD8 38210008
80010004 7C0803A6
4E800020 00000000
C20237BC 0000000B
9421FFD0 7C000026
90010020 80C2E0D0
80E2E0D4 39000000
9102E0D0 9102E0D4
2C060000 40A00028
7C071800 40A20020
38E10010 7C6765AA
7CE33B78 7CC803A6
4E800021 38610010
7C6364AA 80010020
7C0FF120 00000000
C22F72E8 00000008
4C411382 7C600026
90610018 40A20028
807E0020 2C030000
41810010 807E000C
2C030000 40810010
3802AA54 7C0803A6
4E800021 80610018
7C6FF120 00000000
C22F6ECC 00000003
3862AA54 7C6803A6
7FA3EB78 4E800021
281E0000 00000000
C2180D14 0000000E
981E0000 7C000026
90010018 800DAF34
2C000000 40A20050
807E0004 5463103A
7C63F214 80030014
7C1D0000 41810038
38000001 900DAF34
3C600001 38639C48
3882AA54 7C8803A6
4E800021 3880007F
38A00040 3D808002
618C37A8 7D8803A6
4E800021 80010018
7C0FF120 00000000
C2180E94 00000003
3882AA54 7C8803A6
4E800021 3880007F
60000000 00000000
042F7358 C8228000
042F72D0 C8228000
0417F398 CBC280A0
0417C3D8 C86280A0
04023864 38210030
04023860 80010034
C24DA430 00000006
60000000 4E800021
00009C46 00000012
0007C85E 00000012
00009C40 0000001C
00009C48 0000000C
FFFFFFFF 00000000
C24DA490 00000009
7C0802A6 90010004
9421FFF0 8062AAB4
2C030000 4081001C
3D808002 618C3F28
7D8803A6 4E800021
38600000 9062AAB4
38210010 80010004
7C0803A6 4E800020
60000000 00000000
C24DA434 0000000C
7C0802A6 90010004
9421FFF8 38C2AA50
7CC803A6 4E800021
7CC802A6 80E60000
7C071800 40A2001C
80E60004 90E2AAB4
9062E0D4 3902AAB0
9102E0D0 48000010
84E60008 2C070000
4181FFD8 38210008
80010004 7C0803A6
4E800020 00000000
C20237BC 0000000B
9421FFD0 7C000026
90010020 80C2E0D0
80E2E0D4 39000000
9102E0D0 9102E0D4
2C060000 40A00028
7C071800 40A20020
38E10010 7C6765AA
7CE33B78 7CC803A6
4E800021 38610010
7C6364AA 80010020
7C0FF120 00000000
C22F72E8 00000008
4C411382 7C600026
90610018 40A20028
807E0020 2C030000
41810010 807E000C
2C030000 40810010
3802AA54 7C0803A6
4E800021 80610018
7C6FF120 00000000
C22F6ECC 00000003
3862AA54 7C6803A6
7FA3EB78 4E800021
281E0000 00000000
C2180D14 0000000E
981E0000 7C000026
90010018 800DAF34
2C000000 40A20050
807E0004 5463103A
7C63F214 80030014
7C1D0000 41810038
38000001 900DAF34
3C600001 38639C48
3882AA54 7C8803A6
4E800021 3880007F
38A00040 3D808002
618C37A8 7D8803A6
4E800021 80010018
7C0FF120 00000000
C2180E94 00000003
3882AA54 7C8803A6
4E800021 3880007F
60000000 00000000
Code:
-==-
!
ASM Gecko - Fanfare on New Records 2.0
Announcer Fanfares 2.0
Pair announcer SFX IDs with a fanfare BGM ID to play it when the announcer speaks.
Default configuration uses unused hps files:
"Complete!" plays FF_GOOD.hps
"Success!" plays FF_GOOD.hps
"New Record!" plays FF_STEP3.hps
"Failure" plays FF_BAD.hps
[Punkline]
1.02 ----- 802F7358 --- C822E0D0 -> C8228000
1.02 ----- 802F72D0 --- C822E0D0 -> C8228000
# mytoc -0x1F30(rtoc), -0x1F2C(rtoc)
1.02 ----- 8017F398 --- CBC2AAB0 -> CBC280A0
# mytoc -0x5550(rtoc), -0x554C(rtoc)
1.02 ----- 8017C3D8 --- C862AA50 -> C86280A0
# mytoc -0x55B0(rtoc), -0x55AC(rtoc)
1.02 ----- 80023864 --- 38210008 -> 38210030
1.02 ----- 80023860 --- 8001000c -> 80010034
# alters stack epilog for SFX function
1.02 ----- 804DA430 --- 43300000 -> branch
# this is branched to from rtoc - 0x55B0
# it handles storing globals for the fanfare pairings
blrl
.long 0x9C46, 0x12 # "Complete!" SFX ID, FF_GOOD.hps
.long 0x7c85e, 0x12 # "Success!" SFX ID, FF_GOOD.hps
.long 0x9C40, 0x1C # "New Record!" SFX ID, FF_STEP3.hps ID
.long 0x9c48, 0x0C # "Failure" SFX ID, FF_BAD.hps
.long -1 # terminate list
1.02 ----- 804DA490 --- 43300000 -> branch
# this is branched to from rtoc - 0x5550
# it is not an injection, but rather a branch to a callback function
# it handles playing a fanfare when recognizing a SFX ID
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x10(sp)
.set mytoc_fanfare_BGM_ID, -0x554C
lwz r3, mytoc_fanfare_BGM_ID(rtoc)
cmpwi r3, 0
ble- _return
# bl 0x80023f28
lis r12, 0x8002
ori r12, r12, 0x3F28
mtlr r12
blrl
li r3, 0
stw r3, mytoc_fanfare_BGM_ID(rtoc)
_return:
addi sp, sp, 0x10
lwz r0, 0x4(sp)
mtlr r0
blr
# .long 0
1.02 ----- 804DA434 --- 80000000 -> branch
# this function is branched to from rtoc - 0x55AC
# it handles checking the default fanfare pairings
# r3 = SFX ID (key for lookup)
# returns r3, r4, r5 unchanged
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x8(sp)
.set mytoc_SFX_event_pointer, -0x1F30
.set mytoc_SFX_ID, -0x1F2C
.set mytoc_fanfare_callback, -0x5550
.set mytoc_fanfare_BGM_ID, -0x554C
.set mytoc_fanfare_defaults, -0x55B0
addi r6, rtoc, mytoc_fanfare_defaults
mtlr r6
blrl
mflr r6
# r6 now = base address of default SFX/BGM pairings
lwz r7, 0(r6)
_loop:
cmpw r7, r3
bne+ _iterate_loop
_exit_loop:
lwz r7, 4(r6)
stw r7, mytoc_fanfare_BGM_ID(rtoc)
stw r3, mytoc_SFX_ID(rtoc)
addi r8, rtoc, mytoc_fanfare_callback
stw r8, mytoc_SFX_event_pointer(rtoc)
b _return
_iterate_loop:
lwzu r7, 8(r6)
cmpwi r7, 0
bgt+ _loop
_return:
addi sp, sp, 0x8
lwz r0, 0x4(sp)
mtlr r0
blr
1.02 ----- 800237bc --- 9421fff8 -> branch
# this injection sets up a callback event inside of a SFX func
# the SFX func is a prefunction that seems to be used only for a
# limited range of SFX IDs, but it includes announcer SFX
stwu sp, -0x0030(sp)
mfcr r0
stw r0, 0x20(sp)
.set mytoc_SFX_event_pointer, -0x1F30
.set mytoc_SFX_ID, -0x1F2C
lwz r6, mytoc_SFX_event_pointer(rtoc)
lwz r7, mytoc_SFX_ID(rtoc)
li r8, 0
stw r8, mytoc_SFX_event_pointer(rtoc)
stw r8, mytoc_SFX_ID(rtoc)
cmpwi r6, 0
bge+ _return # check r6 for address
cmpw r7, r3
bne+ _return # make sure IDs match
# original instruction activates stack frame
# we alter the offset to include more space
_callback_event:
addi r7, sp, 0x10
stswi r3, r7, 0xC
# now args are stored in stack:
# r3 = SFX ID
# r4 = volume
# r5 = stereo mix
# we'll pass this string to the callback,
# so that it may optionally alter the SFX behavior
mr r3, r7
mtlr r6
blrl # callback
addi r3, sp, 0x10
lswi r3, r3, 0xC
# arguments are restored for opening of SFX func
_return:
lwz r0, 0x20(sp)
mtcr r0
# .long 0
1.02 ----- 802f72e8 --- 4c411382 -> branch
# this injection sets up a callback for the previous event
# it only includes the scope of SFX tied to an 000E entity type
# includes "Ready..." "GO!" "Failer" etc
# r31 = JObj root belonging to graphic (?)
# f31 = some float derived from r31 (likely an AObj timer)
# r30 = SFX structure
# 0xC = SFX ID for normal announcer voice
# 0x10 = timer byte 1 (for announcer)
# 0x11 = timer byte 2 (for crowd SFX?)
# 0x12 = flags byte (bit 80 seems to signify SFX played)
# 0x20 = SFX ID for special announcer (New Record!)
# 0x24 = SFX ID for crowd SFX
# -- if any SFX IDs are null, they are skipped
_code_start:
cror cr2, cr1, cr2
mfcr r3
stw r3, 0x18(sp)
# hold CR in stack for safe branch
# we'll be using what's currently in cr0 to determine
# which offset to look at from r30
bne+ _return
lwz r3, 0x20(r30)
cmpwi r3, 0
bgt- _set_fanfare_callback
_normal_announcer:
lwz r3, 0xC(r30)
cmpwi r3, 0
ble _return
_set_fanfare_callback:
.set mytoc_fanfare_assign_default, -0x55AC
addi r0, rtoc, mytoc_fanfare_assign_default
mtlr r0
blrl
_return:
lwz r3, 0x18(sp)
mtcr r3
# .long 0
1.02 ----- 802f6ecc --- 281e0000 -> branch
# r29 = incoming SFX ID for announcer call on trophy stage
.set mytoc_fanfare_assign_default, -0x55AC
.set rSFXID, 29
# .set trophy_stageID, 0x26
# lis r3, 0x804A
# lwz r3, -0x18B0(r3) # r3 = current stage ID (internal)
# cmpwi r3, trophy_stageID
# bne+ _return
# _if_trophy_stage_exit:
addi r3, rtoc, mytoc_fanfare_assign_default
mtlr r3
mr r3, rSFXID
blrl # assign BGM ID if pending SFX ID matches a default def
cmplwi r30, 0 # original instruction
# .long 0
1.02 ----- 80180d14 --- 981e0000 -> branch
# add artificial announcer SFX to HRC
.set mytoc_fanfare_assign_default, -0x55AC
stb r0, 0 (r30) # original instruction
mfcr r0
stw r0, 0x18(sp) # store CR for return
lwz r0, -0x50CC(r13) # flag word indicates sound has been played
cmpwi r0, 0
bne+ _return
lwz r3, 0x4(r30)
slwi r3, r3, 2
add r3, r3, r30
lwz r0, 0x14(r3)
cmpw r29, r0 # r29 = current distance
bgt- _return
# if distance <= record, then play "Failure" SFX and flag -0x50CC(r13)
li r0, 1
stw r0, -0x50CC(r13)
lis r3, 1
addi r3, r3, -0x63B8 # load ID for Failure SFX
addi r4, rtoc, mytoc_fanfare_assign_default
mtlr r4
blrl # prime fanfare
li r4, 127
li r5, 64
# bl 0x800237a8 # call SFX
lis r12, 0x8002
ori r12, r12, 0x37A8
mtlr r12
blrl
_return:
lwz r0, 0x18(sp)
mtcr r0
# .long 0
1.02 ----- 80180e94 --- 3880007f -> branch
# fanfare for HRC New record
.set mytoc_fanfare_assign_default, -0x55AC
addi r4, rtoc, mytoc_fanfare_assign_default
mtlr r4
blrl # prime fanfare
li r4, 127
# .long 0
---
This code allows users to pair BGM IDs with announcer SFX IDs to create triggers for playing a fanfare. The default configuration includes:
00009C46 00000012 # “Complete!” = FF_GOOD
0007C85E 00000012 # “Success!” = FF_GOOD
00009C40 0000001C # “A New Record!” = FF_STEP3
00009C48 0000000C # “Failure” = FF_BAD
Here's a list of BGM IDs, for reference. These were acquired by observing the index starting at 803BBDDC:
Code:
ID - Music:
00 - 1p_qk.hps
01 - akaneia.hps
02 - baloon.hps
03 - bigblue.hps
04 - castle.hps
05 - continue.hps
06 - corneria.hps
07 - docmari.hps
08 - ending.hps
09 - famidemo.hps
0A - ff_1p01.hps
0B - ff_1p02.hps
0C - ff_bad.hps
0D - ff_dk.hps
0E - ff_emb.hps
0F - ff_flat.hps
10 - ff_fox.hps
11 - ff_fzero.hps
12 - ff_good.hps
13 - ff_ice.hps
14 - ff_kirby.hps
15 - ff_link.hps
16 - ff_mario.hps
17 - ff_nes.hps
18 - ff_poke.hps
19 - ff_samus.hps
1A - ff_step1.hps
1B - ff_step2.hps
1C - ff_step3.hps
1D - ff_yoshi.hps
1E - flatzone.hps
1F - fourside.hps
20 - gameover.hps
21 - garden.hps
22 - greatbay.hps
23 - greens.hps
24 - howto.hps
25 - howto_s.hps
26 - hyaku.hps
27 - hyaku2.hps
28 - icemt.hps
29 - inis1_01.hps
2A - inis1_02.hps
2B - inis2_01.hps
2C - inis2_02.hps
2D - intro_es.hps
2E - intro_nm.hps
2F - item_h.hps
30 - item_s.hps
31 - izumi.hps
32 - kongo.hps
33 - kraid.hps
34 - menu01.hps
35 - menu02.hps
36 - menu3.hps
37 - mrider.hps
38 - mutecity.hps
39 - old_dk.hps
3A - old_kb.hps
3B - old_ys.hps
3C - onetto.hps
3D - onetto2.hps
3E - opening.hps
3F - pokesta.hps
40 - pstadium.hps
41 - pura.hps
42 - rcruise.hps
43 - s_info1.hps
44 - s_info2.hps
45 - s_info3.hps
46 - s_new1.hps
47 - s_new2.hps
48 - s_newcom.hps
49 - s_select.hps
4A - saria.hps
4B - shrine.hps
4C - siren.hps
4D - smari3.hps
4E - sp_end.hps
4F - sp_giga.hps
50 - sp_metal.hps
51 - sp_zako.hps
52 - swm_15min.hps
53 - target.hps
54 - venom.hps
55 - vl_battle.hps
56 - vl_castle.hps
57 - vl_corneria.hps
58 - vl_cosmos.hps
59 - vl_figure1.hps
5A - vl_figure2.hps
5B - vl_fzero.hps
5C - vl_last_v2.hps
5D - vs_hyou1.hps
5E - vs_hyou2.hps
5F - yorster.hps
60 - ystory.hps
61 - zebes.hps
62 - testnz.hps
---
To customize what fanfare plays, modify the list inside either the DOL mod or the Gecko Code to use music from the above index:
---
Update notes:
As of 3/28/2018, this code has been completely rewritten to include some new features:
- Reusable move-logic-like callback pointer allows (the next) SFX call made from 800237A8 to execute additional code before playing a sound.
- Fanfare mechanic uses callback pointer from a higher level function used only for applying SFX that correspond with the animation timing of announcer .
- Default fanfares for “Failure” and “Success” announcements have been added to configuration.
- Default SFX/BGM ID pairings may be given custom definitions with code installation.
- Default SFX/BGM ID pairings may be modified procedurally by other codes for conditional fanfares.
- non-default SFX/BGM IDs may be assigned manually via injection code triggers.
- Fanfare mechanic has been extended to include classic/adventure mode races.
- Fanfare mechanic has been extended to include a scene transition function used by the Trophy collection mini game.
- HRC scene function has been given artificial “Failure” SFX call conditions for unbroken records and no distance.
- Reusable move-logic-like callback pointer allows (the next) SFX call made from 800237A8 to execute additional code before playing a sound.
- Fanfare mechanic uses callback pointer from a higher level function used only for applying SFX that correspond with the animation timing of announcer .
- Default fanfares for “Failure” and “Success” announcements have been added to configuration.
- Default SFX/BGM ID pairings may be given custom definitions with code installation.
- Default SFX/BGM ID pairings may be modified procedurally by other codes for conditional fanfares.
- non-default SFX/BGM IDs may be assigned manually via injection code triggers.
- Fanfare mechanic has been extended to include classic/adventure mode races.
- Fanfare mechanic has been extended to include a scene transition function used by the Trophy collection mini game.
- HRC scene function has been given artificial “Failure” SFX call conditions for unbroken records and no distance.
Edit 3/18/2018 : New code version (1.1) fixes instances where breaking records would mess up the event trigger:
- Added the FF_STEP3.hps fanfare when setting a new record. These should trigger on Target Test and Event matches.
- Added injection to include fanfare in Home Run Contest new records.
- rtoc event pointer is now reset in case of new records.
Thanks Stormghetti and @tauKhan for helping me troubleshoot this!
- Added the FF_STEP3.hps fanfare when setting a new record. These should trigger on Target Test and Event matches.
- Added injection to include fanfare in Home Run Contest new records.
- rtoc event pointer is now reset in case of new records.
Thanks Stormghetti and @tauKhan for helping me troubleshoot this!
Last edited: