Punkline
Dr. Frankenstack
- Joined
- May 15, 2015
- Messages
- 423
This code varies the voice sound effects used for jump/death actions, and prevents voice clips from being cut off when a character resets their position on the stage (like the “rebirth” action.) It was requested by
Stormghetti
, who wanted a means of making the jump sound effects less monotonous.
SFX IDs for the pool of voice clips are generated by selecting a random indexed callback function. Each indexed function can be toggled for individual characters in a bitmask kept in the <extended_voice_masks> data table. More details about configuration below.
By default, these masks and SFX routines are configured to provide silent short hops, like in Brawl. It also makes the majority of characters’ aerial jumps silent, with exceptions for characters with unique doublejump animations/SFX. For characters with suitable voiceclips, the sound played for a full jump will randomly select silence, or either of the two jump sounds used by that character.
Death voices now have a chance to be silenced, or play the “ledge teeter” or “screen hit (on updeath)” voices instead of the normal death voice.
Developers may modify the callback pointers included at the end of the voice masks array to change the behavior of each randomly selected voice. In the future, the character mask size may be extended to support additional slots for random voices, or possibly new actions.
This code requires Melee Code Manager version 4.1+
Extended Jump/Death Voice Logic:
---
NOTE: Not all jump sounds are generated from the game code.
Many come from subaction event data, and will need to be configured with programs like Crazy Hand:
Additionally, several characters have “silent” jumps that will end up being silent when logically toggled for random selection. By default, most of these have been masked out in the character mask array.
---
Each character has a special 16-bit mask in the <extended_voice_masks> data table.
The nibbles each represent a type of jump, or the death action:
Short hop:
8000 - SFX silence
4000 - SFX ground jump
2000 - SFX aerial jump
Normal jump:
0800 - SFX silence
0400 - SFX ground jump
0200 - SFX aerial jump
Double jump:
0080 - SFX silence
0040 - SFX ground jump
0020 - SFX aerial jump
Death:
0008 - SFX silence
0004 - SFX normal death
0002 - SFX hit screen on updeath
0001 - SFX ledge teeter
The <extended_voice_masks> data table has been formatted using named symbols for these flags:
By using | to add sounds together, and - to remove them; you may reference these voiceclip names from inside of expressions that define each character’s voice logic. If no sounds are flagged for a given action’s bitfield, then the default sounds will be played instead.
Expressions made like this can also be packed into new symbols by using the .set pseudo-op, and then used in other expressions:
In the above screenshot, the “default” symbol represents a configuration that can be used in any character to apply the following logic:
In contrast, the “mixjump” symbol represents this logic:
---
When these symbols are used to define character masks, the default settings make several individual exceptions through slight modifications. For example, Yoshi has been given mask that ensures his double jump sound only plays on a double jump:
If you wanted to make it so that Yoshi remains silent on his doublejump, then you can modify it like so:
Another example; we can make Ganondorf say “TECH” only on shorthops by using this configuration:
---
Feel free to ask questions, report bugs, or give any other feedback.
SFX IDs for the pool of voice clips are generated by selecting a random indexed callback function. Each indexed function can be toggled for individual characters in a bitmask kept in the <extended_voice_masks> data table. More details about configuration below.
By default, these masks and SFX routines are configured to provide silent short hops, like in Brawl. It also makes the majority of characters’ aerial jumps silent, with exceptions for characters with unique doublejump animations/SFX. For characters with suitable voiceclips, the sound played for a full jump will randomly select silence, or either of the two jump sounds used by that character.
Death voices now have a chance to be silenced, or play the “ledge teeter” or “screen hit (on updeath)” voices instead of the normal death voice.
Developers may modify the callback pointers included at the end of the voice masks array to change the behavior of each randomly selected voice. In the future, the character mask size may be extended to support additional slots for random voices, or possibly new actions.
This code requires Melee Code Manager version 4.1+
Extended Jump/Death Voice Logic:
Code:
-==-
Extended Jump/Death Voice Logic
Varies Jump and Death voice clip logic.
Prevents cutting off voices on respawn.
Edit <extended_voice_masks> to configure SFX logic, and callback routines.
[Punkline]
<extended_voice_masks>
# data pointers:
.long <<extended_voice_masks>> + _jump_sound_routines
.long <<extended_voice_masks>> + _death_sound_routines
# mask symbols:
.set hopNONE, 0x8000 # SFX - silence
.set hopNORM, 0x4000 # SFX - ground jump voice
.set hopALT, 0x2000 # SFX - aerial jump voice
.set jmpNONE, 0x0800 # SFX - silence
.set jmpNORM, 0x0400 # SFX - ground jump voice
.set jmpALT, 0x0200 # SFX - aerial jump voice
.set djmpNONE, 0x0080 # SFX - silence
.set djmpALT, 0x0040 # SFX - ground jump voice
.set djmpNORM, 0x0020 # SFX - aerial jump voice
.set dthNONE, 0x0008 # SFX - silence
.set dthNORM, 0x0004 # SFX - normal death voice
.set dthSCRN, 0x0002 # SFX - screen hit voice
.set dthLDGE, 0x0001 # SFX - ledge teeter voice
# These named flags can be combined to create logic for sounds.
# | can be used to add new flags to a flagfield.
# - can be used to remove flags from a flagfield.
# default field values:
.set hop, hopNONE
.set jmp, jmpNONE | jmpNORM
.set djmp, djmpNONE | djmpNORM
.set dth, dthNONE | dthNORM | dthSCRN | dthLDGE
# each nibble represents an action
.set default, hop | jmp | djmp | dth
# "default" summarizes all of the default flags
.set mixjump, hop | jmp | jmpALT | djmpNONE | dth
# "mixjump" is used for characters who have SFX suitable for both air or ground animations
# - the doubljump is made silent to prevent the same sound from playing in both ground/air jumps
# The following hwords will set each described character's sound pool:
# mario:
.hword mixjump
# fox:
.hword mixjump - jmpNORM
# cfalcon:
.hword mixjump - jmpNORM
# dkong:
.hword mixjump
# kirby:
.hword default
# subaction event makes flying sound, not game code
# bowser:
.hword mixjump
# link:
.hword mixjump
# sheik:
.hword mixjump - jmpALT
# ness:
.hword default
# subaction event makes levitate sound, not game code
# peach:
.hword default
# subaction event makes twirl sound, not game code
# popo:
.hword mixjump
# nana:
.hword mixjump
# subaction event makes IC jump sound, not game code
# pika:
.hword mixjump
# samus:
.hword hop | dth - dthLDGE
# only use jump/spin sounds with corresponding animations
# remove silent teeter death sound
# yoshi:
.hword default - djmpNONE
# only use yoshi djump sound with its corresponding animation
# remove possibility of silent doublejumps
# jpuff:
.hword mixjump
# mewtwo:
.hword default - dthLDGE
# only use levitate sound with corresponding animation
# remove silent teeter death sound
# luigi:
.hword mixjump
# marth:
.hword mixjump - jmpALT
# remove silent djump sount
# zelda:
.hword mixjump
# ylink:
.hword mixjump
# doc:
.hword mixjump
# falco:
.hword mixjump - jmpNORM
# pichu:
.hword mixjump
# gaw:
.hword mixjump
# gdorf:
.hword mixjump - jmpALT
# roy:
.hword mixjump
.align 2
# The following lists are used to create an index for each mask nibble.
# Each type of jump shares the jump_sound_routines index:
_jump_sound_routines:
.long <<SFX_player_silent_voice>>
.long <<SFX_player_groundjump_voice>>
.long <<SFX_player_aerialjump_voice>>
_death_sound_routines:
.long <<SFX_player_silent_voice>>
.long <<SFX_player_death_voice>>
.long <<SFX_player_screenhit_voice>>
.long <<SFX_player_ledgeteeter_voice>>
# callbacks are given the following arguments:
# r3 = player data table
# r4 = player -> 0x10C -> 0x4C base address
# callbacks return:
# r3 = unchanged
# r4 = special SFX ID for voiceclip argument
<SFX_player_silent_voice>
li r4, -1
blr
<SFX_player_groundjump_voice>
lwz r4, 0x10(r4)
blr
<SFX_player_aerialjump_voice>
lwz r4, 0x14(r4)
blr
<SFX_player_death_voice>
lwz r4, 0x4(r4)
blr
<SFX_player_screenhit_voice>
lwz r4, 0x20(r4)
lwz r4, 0x4(r4)
lwz r4, 0x0(r4)
blr
<SFX_player_ledgeteeter_voice>
lwz r4, 0x18(r4)
blr
<get_extended_voice_mask>
# r3 = player data
# r4 = selection mask
# returns:
# r3 = unchanged
# r4 = shifted mask
# r5 = base of callback index
# r6 = base of mask array
# r7 = internal character ID
lis r0, (<<extended_voice_masks>>+8)@h
lwz r7, 0x4(r3)
ori r6, r0, (<<extended_voice_masks>>+8)@l
slwi r8, r7, 1
lhzx r8, r6, r8
cntlzw r0, r4
and r4, r8, r4
slw r4, r4, r0
cmpwi r0, 28
lwz r5, -0x8(r6)
bltlr+
lwz r5, -0x4(r6)
blr
# r3 = unchanged
# r4 = shifted mask
# r5 = base of callback index
# r6 = base of mask array
# r7 = internal character ID
<random_bit_from_mask>
7C641B79 38A00000 38C00000 40A20014 38A0FFFF 38C0FFFF 38E00000 4E800020 7C0802A6 9421FFE0 90010024 38A50001 7C870034 7CE63A14 38C70001 7C643031 90E1001C 40A20038 38E10008 7C6785AA 7CA32B78
bl 0x80380580
80E10010 7C661B78 3C808000 54602834 38A1001C 80610008 7CA5002E 7C842C30 48000008 4BFFFFA5 80010024 38210020 7C0803A6 4E800020
<extended_voice_event>
7C0802A6 9421FFE0 90010024 BFC10010 7C7F1B78
bl <get_extended_voice_mask>
7C832378 2C07001B 3880FFFE 7CBE2B78 40800030
bl <random_bit_from_mask>
2C05FFFF 3880FFFE 40810020 54A0103A 7CBE002E 7CA803A6 807F010C 8083004C 7FE3FB78 4E800021 BBC10010 80010024 38210020 7C0803A6 4E800020
1.02 ------ 80068440 --- 48020611 -> 60000000
1.02 ------ 800cb17c --- 2c000000 -> Branch
2C000000 7C000026 9001001C 00000000
1.02 ------ 800cb214 --- 80840010 -> Branch
8101001C 38E10010 7D080120 80840010 7C6785AA 38800E00 41A20008 54842036 7FE3FB78
bl <extended_voice_event>
2C04FFFE 38E10010 40810008 90810014 7C6784AA 00000000
1.02 ------ 80088354 --- 88032225 -> Branch
80FF010C 8107004C 80080014 7C00F000 40820018 388000E0
bl <extended_voice_event>
2C04FFFE 40810008 7C9E2378 881F2225 00000000
1.02 ------ 800d38cc --- 93e10014 -> Branch
8103010C 38E10008 8108004C 80080004 7C002000 40820028 7C6765AA 3880000F
bl <extended_voice_event>
2C04FFFE 38E10008 40810008 9081000C 7C6764AA 38C00040 93E10014 00000000
Code:
-==-
ASM - Extended Jump/Death Voice Logic
Varies Jump and Death voice clip logic.
Prevents cutting off voices on respawn.
Edit <extended_voice_masks> to configure SFX logic, and callback routines.
[Punkline]
<extended_voice_masks>
# data pointers:
.long <<extended_voice_masks>> + _jump_sound_routines
.long <<extended_voice_masks>> + _death_sound_routines
# mask symbols:
.set hopNONE, 0x8000 # SFX - silence
.set hopNORM, 0x4000 # SFX - ground jump voice
.set hopALT, 0x2000 # SFX - aerial jump voice
.set jmpNONE, 0x0800 # SFX - silence
.set jmpNORM, 0x0400 # SFX - ground jump voice
.set jmpALT, 0x0200 # SFX - aerial jump voice
.set djmpNONE, 0x0080 # SFX - silence
.set djmpALT, 0x0040 # SFX - ground jump voice
.set djmpNORM, 0x0020 # SFX - aerial jump voice
.set dthNONE, 0x0008 # SFX - silence
.set dthNORM, 0x0004 # SFX - normal death voice
.set dthSCRN, 0x0002 # SFX - screen hit voice
.set dthLDGE, 0x0001 # SFX - ledge teeter voice
# These named flags can be combined to create logic for sounds.
# | can be used to add new flags to a flagfield.
# - can be used to remove flags from a flagfield.
# default field values:
.set hop, hopNONE
.set jmp, jmpNONE | jmpNORM
.set djmp, djmpNONE | djmpNORM
.set dth, dthNONE | dthNORM | dthSCRN | dthLDGE
# each nibble represents an action
.set default, hop | jmp | djmp | dth
# "default" summarizes all of the default flags
.set mixjump, hop | jmp | jmpALT | djmpNONE | dth
# "mixjump" is used for characters who have SFX suitable for both air or ground animations
# - the doubljump is made silent to prevent the same sound from playing in both ground/air jumps
# The following hwords will set each described character's sound pool:
# mario:
.hword mixjump
# fox:
.hword mixjump - jmpNORM
# cfalcon:
.hword mixjump - jmpNORM
# dkong:
.hword mixjump
# kirby:
.hword default
# subaction event makes flying sound, not game code
# bowser:
.hword mixjump
# link:
.hword mixjump
# sheik:
.hword mixjump - jmpALT
# ness:
.hword default
# subaction event makes levitate sound, not game code
# peach:
.hword default
# subaction event makes twirl sound, not game code
# popo:
.hword mixjump
# nana:
.hword mixjump
# subaction event makes IC jump sound, not game code
# pika:
.hword mixjump
# samus:
.hword hop | dth - dthLDGE
# only use jump/spin sounds with corresponding animations
# remove silent teeter death sound
# yoshi:
.hword default - djmpNONE
# only use yoshi djump sound with its corresponding animation
# remove possibility of silent doublejumps
# jpuff:
.hword mixjump
# mewtwo:
.hword default - dthLDGE
# only use levitate sound with corresponding animation
# remove silent teeter death sound
# luigi:
.hword mixjump
# marth:
.hword mixjump - jmpALT
# remove silent djump sount
# zelda:
.hword mixjump
# ylink:
.hword mixjump
# doc:
.hword mixjump
# falco:
.hword mixjump - jmpNORM
# pichu:
.hword mixjump
# gaw:
.hword mixjump
# gdorf:
.hword mixjump - jmpALT
# roy:
.hword mixjump
.align 2
# The following lists are used to create an index for each mask nibble.
# Each type of jump shares the jump_sound_routines index:
_jump_sound_routines:
.long <<SFX_player_silent_voice>>
.long <<SFX_player_groundjump_voice>>
.long <<SFX_player_aerialjump_voice>>
_death_sound_routines:
.long <<SFX_player_silent_voice>>
.long <<SFX_player_death_voice>>
.long <<SFX_player_screenhit_voice>>
.long <<SFX_player_ledgeteeter_voice>>
# callbacks are given the following arguments:
# r3 = player data table
# r4 = player -> 0x10C -> 0x4C base address
# callbacks return:
# r3 = unchanged
# r4 = special SFX ID for voiceclip argument
<SFX_player_silent_voice>
li r4, -1
blr
<SFX_player_groundjump_voice>
lwz r4, 0x10(r4)
blr
<SFX_player_aerialjump_voice>
lwz r4, 0x14(r4)
blr
<SFX_player_death_voice>
lwz r4, 0x4(r4)
blr
<SFX_player_screenhit_voice>
lwz r4, 0x20(r4)
lwz r4, 0x4(r4)
lwz r4, 0x0(r4)
blr
<SFX_player_ledgeteeter_voice>
lwz r4, 0x18(r4)
blr
<get_extended_voice_mask>
# r3 = player data
# r4 = selection mask
# returns:
# r3 = unchanged
# r4 = shifted mask
# r5 = base of callback index
# r6 = base of mask array
# r7 = internal character ID
lis r0, (<<extended_voice_masks>>+8)@h
lwz r7, 0x4(r3)
ori r6, r0, (<<extended_voice_masks>>+8)@l
slwi r8, r7, 1
lhzx r8, r6, r8
cntlzw r0, r4
and r4, r8, r4
slw r4, r4, r0
cmpwi r0, 28
lwz r5, -0x8(r6)
bltlr+
lwz r5, -0x4(r6)
blr
# r3 = unchanged
# r4 = shifted mask
# r5 = base of callback index
# r6 = base of mask array
# r7 = internal character ID
<random_bit_from_mask>
# r3 = mask
# count number of TRUE bits
# - return rand(n)th TRUE bit from given mask
# returns:
# r3 = unchanged
# r4 = randomly selected true bit (mask)
# r5 = index of randomly selected bit (0...31)
# r6 = index of randomly selected true bit (0...r7-1)
# r7 = number of true bits
.set rMask, 3
.set rRemaining, 4
.set rTrueCTR, 5
.set rNext, 6
.set rThis, 7
.set xThis, 0x1C
.set xMask, 0x8
.set xTrueCTR, 0x10
_setup:
mr. rRemaining, rMask
li rTrueCTR, 0
li rNext, 0
bne+ _while_true_bit_exists
_abort:
li r5, -1
li r6, -1
li r7, 0
blr
# return error values if mask is empty
_while_true_bit_exists:
# rMask, rRemaining, rTrueCTR, rNext = arguments r3...r6
# It is guaranteed at this point that at least 1 true bit exists in rRemaining
mflr r0
stwu sp, -0x20(sp)
stw r0, 0x24(sp)
# create stack frame for storing index of rThis true bit
# frame is also used to save return values when calling rng func
# - each true bit generates a new frame
addi rTrueCTR, rTrueCTR, 1
cntlzw rThis, rRemaining
add rThis, rNext, rThis
addi rNext, rThis, 1
slw. rRemaining, rMask, rNext
stw rThis, xThis(sp)
bne+ _recursive_call
# we use this conditional branch to separate the exit condition from the LR destination
_exit:
# exit handle will select random record, and begin collapsing frames
addi r7, sp, 0x8
stswi r3, r7, 0x10
# store working registers temporarily as string r3...r6
mr r3, rTrueCTR
bl 0x80380580
# r3 = random number between 0 and TrueCTR-1
lwz r7, xTrueCTR(sp)
mr r6, r3
lis r4, 0x8000
slwi r0, r3, 5
addi r5, sp, xThis
lwz r3, xMask(sp)
lwzx r5, r5, r0
srw r4, r4, r5
# returns:
# r3 = unchanged
# r4 = randomly selected true bit (mask)
# r5 = index of randomly selected bit (0...31)
# r6 = index of randomly selected true bit (0...r7-1)
# r7 = number of true bits
b _collapse
_recursive_call:
bl _while_true_bit_exists
# if not exiting, then store rThis in stack frame
# pass rMask, rRemaining, rTrueCTR, rNext to recursive call
_collapse:
lwz r0, 0x24(sp)
addi sp, sp, 0x20
mtlr r0
blr
<extended_voice_event>
# r3 = player data
# r4 = mask filter
mflr r0
stwu sp, -0x20(sp)
stw r0, 0x24(sp)
stmw r30, 0x10(sp)
mr r31, r3
bl <get_extended_voice_mask>
# r4 = shifted mask
# r5 = base of callback index
# r6 = base of mask array
# r7 = internal character ID
mr r3, r4
cmpwi r7, 0x1B
li r4, -2
mr r30, r5
bge- _return
# abort if not a playable character
# return r4 = -2 if aborting
# else, callback index has been saved in stack frame
_execute_random_voiceclip_routine:
bl <random_bit_from_mask>
# r3 = unchanged
# r4 = randomly selected true bit (mask)
# r5 = index of randomly selected bit (0...31)
# r6 = index of randomly selected true bit (0...r7-1)
# r7 = number of true bits
cmpwi r5, -1
li r4, -2
ble- _return
slwi r0, r5, 2
lwzx r5, r30, r0
mtlr r5
lwz r3, 0x10C(r31)
lwz r4, 0x4C(r3)
mr r3, r31
# setup and execute callback routine:
# r3 = player data
# r4 = in-file SFX ID index
# r5 = address of self
blrl
# r3 = player data
# r4 = selected voiceclip ID (-1 if invalid character)
_return:
lmw r30, 0x10(sp)
lwz r0, 0x24(sp)
addi sp, sp, 0x20
mtlr r0
blr
1.02 ------ 80068440 --- 48020611 -> 60000000
# allows death SFX to continue beyond character death
1.02 ------ 800cb17c --- 2c000000 -> Branch
# this lets us use the jump injection for both hops and jumps
cmpwi r0, 0
mfcr r0
stw r0, 0x1C(sp)
.long 0
# store shorthop threshold comparison in stack frame
1.02 ------ 800cb214 --- 80840010 -> Branch
# This injection takes care of shorthop and jump actions
# a variable stored in 0x1C(sp) helps us differentiate
.set bFull, 2 # cr bool holds information about jump type
lwz r8, 0x1C(sp)
addi r7, sp, 0x10
mtcrf 0x80, r8
lwz r4, 0x0010(r4)
stswi r3, r7, 0x10
# argument string has been stored temporarily
# shorthop variable has been loaded into cr
li r4, 0x0E00
# select shorthop mask if not bFull
bt+ bFull, _jump_event
slwi r4, r4, 4
# select jump mask if bFull
_jump_event:
mr r3, r31
bl <extended_voice_event>
cmpwi r4, -2
addi r7, sp, 0x10
ble- _return
stw r4, 0x14(sp)
_return:
lswi r3, r7, 0x10
.long 0
1.02 ------ 80088354 --- 88032225 -> Branch
# This injection takes care of the doublejump action
# r31 = player data
# r30 = given ID
# r29 = given volume (7F, usually)
# r28 = given stereo balance (40, usually)
lwz r7, 0x10C(r31)
lwz r8, 0x4C(r7)
lwz r0, 0x14(r8)
cmpw r0, r30
bne- _return
# abort if this is not a doublejump sound call
li r4, 0xE0
bl <extended_voice_event>
cmpwi r4, -2
ble- _return
# if ID is -2, then use given ID instead
mr r30, r4
# else clobber given voiceclip ID with returned ID
_return:
lbz r0, 0x2225 (r31)
.long 0
1.02 ------ 800d38cc --- 93e10014 -> Branch
# This injection takes care of the death action
lwz r8, 0x10C(r3)
addi r7, sp, 0x8
lwz r8, 0x4C(r8)
lwz r0, 0x4(r8)
cmpw r0, r4
bne- _return
stswi r3, r7, 0xC
li r4, 0xF
bl <extended_voice_event>
cmpwi r4, -2
addi r7, sp, 0x8
ble- _restore_arguments
stw r4, 0xC(sp)
_restore_arguments:
lswi r3, r7, 0xC
li r6, 0x40
_return:
stw r31, 0x0014 (sp)
.long 0
---
NOTE: Not all jump sounds are generated from the game code.
Many come from subaction event data, and will need to be configured with programs like Crazy Hand:
Peach - double jump twirl
Ness - double jump levitate
Ice Climbers - jump and double jump sounds
Kirby - all flying jumps
Mewtwo - double jump levitate
Ness - double jump levitate
Ice Climbers - jump and double jump sounds
Kirby - all flying jumps
Mewtwo - double jump levitate
Additionally, several characters have “silent” jumps that will end up being silent when logically toggled for random selection. By default, most of these have been masked out in the character mask array.
---
Each character has a special 16-bit mask in the <extended_voice_masks> data table.
The nibbles each represent a type of jump, or the death action:
Short hop:
8000 - SFX silence
4000 - SFX ground jump
2000 - SFX aerial jump
Normal jump:
0800 - SFX silence
0400 - SFX ground jump
0200 - SFX aerial jump
Double jump:
0080 - SFX silence
0040 - SFX ground jump
0020 - SFX aerial jump
Death:
0008 - SFX silence
0004 - SFX normal death
0002 - SFX hit screen on updeath
0001 - SFX ledge teeter
The <extended_voice_masks> data table has been formatted using named symbols for these flags:
By using | to add sounds together, and - to remove them; you may reference these voiceclip names from inside of expressions that define each character’s voice logic. If no sounds are flagged for a given action’s bitfield, then the default sounds will be played instead.
Expressions made like this can also be packed into new symbols by using the .set pseudo-op, and then used in other expressions:
In the above screenshot, the “default” symbol represents a configuration that can be used in any character to apply the following logic:
- always silent shorthops
- normal full jumps, with chance for silence
- normal double jumps, with chance for silence
- varying death sounds
In contrast, the “mixjump” symbol represents this logic:
- silent shorthop
- varying full jump sounds, with chance for silence
- silent double jump
- varying death sounds
---
When these symbols are used to define character masks, the default settings make several individual exceptions through slight modifications. For example, Yoshi has been given mask that ensures his double jump sound only plays on a double jump:
If you wanted to make it so that Yoshi remains silent on his doublejump, then you can modify it like so:
Another example; we can make Ganondorf say “TECH” only on shorthops by using this configuration:
---
Feel free to ask questions, report bugs, or give any other feedback.
Last edited: