-
Notifications
You must be signed in to change notification settings - Fork 1
/
z-voice.lua
221 lines (199 loc) · 7.51 KB
/
z-voice.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
if incompatibleClient then return 0 end
-- localize functions to improve performance - z-voice.lua
local type,audio_sample_stop,audio_sample_load,math_random,audio_sample_play,is_game_paused,table_insert,play_character_sound = type,audio_sample_stop,audio_sample_load,math.random,audio_sample_play,is_game_paused,table.insert,play_character_sound
-- rewritten custom voice system for Character Select
-- by Agent X
-- will need some revising in the future, but this will do for now.
local SLEEP_TALK_SNORES = 8
local STARTING_SNORE = 46
local SLEEP_TALK_START = STARTING_SNORE + 49
local SLEEP_TALK_END = SLEEP_TALK_START + SLEEP_TALK_SNORES
local stallTimer = 0
local stallSayLine = 5
local TYPE_TABLE = "table"
local TYPE_USERDATA = "userdata"
local TYPE_STRING = "string"
local function check_sound_exists(sound)
if sound == nil then return false end
local soundType = type(sound)
if soundType == TYPE_USERDATA and sound._pointer ~= nil then
return true
elseif soundType == TYPE_STRING then
sound = "sound/"..sound
return (mod_file_exists(sound))
end
return false
end
local function stop_all_custom_character_sounds()
-- run through each player
for i = 0, MAX_PLAYERS - 1 do
local m = gMarioStates[i]
-- get the voice table, if there is one
local voiceTable = character_get_voice(m)
if voiceTable ~= nil then
-- run through each sample
for sound in pairs(voiceTable) do
-- if the sample is found, try to stop it
if voiceTable[sound] ~= nil and type(voiceTable[sound]) ~= "string" then
-- if there's no pointer then it must be a sound clip table
if voiceTable[sound]._pointer == nil then
for voice in pairs(voiceTable[sound]) do
if type(voiceTable[sound][voice]) == "string" then
break
end
audio_sample_stop(voiceTable[sound][voice])
end
else
audio_sample_stop(voiceTable[sound])
end
end
end
end
end
end
--[[local function stop_custom_character_sound(m, sound)
local voiceTable = character_get_voice(m)
-- if there's no pointer then it must be a sound clip table
if type(voiceTable[sound]) == "string" then return end
if voiceTable[sound]._pointer == nil then
for voice in pairs(voiceTable[sound]) do
if type(voiceTable[voice]) == "string" then
break
end
audio_sample_stop(voiceTable[sound][voice])
end
else
audio_sample_stop(voiceTable[sound])
end
end]]
local playerSample = {}
for i = 0, MAX_PLAYERS - 1 do
playerSample[i] = nil
end
--- @param m MarioState
--- @param sound CharacterSound
local function custom_character_sound(m, sound)
if m.playerIndex == 0 then
if stallTimer < stallSayLine - 1 then
return NO_SOUND
end
end
local index = m.playerIndex
if check_sound_exists(playerSample[index]) and type(playerSample[index]) ~= TYPE_STRING then
audio_sample_stop(playerSample[index])
end
if optionTable[optionTableRef.localVoices].toggle == 0 then return NO_SOUND end
-- get the voice table
local voiceTable = character_get_voice(m)
if voiceTable == nil then return end
-- load samples that haven't been loaded
for voice, name in pairs(voiceTable) do
if check_sound_exists(voiceTable[voice]) and type(voiceTable[voice]) == "string" then
local load = audio_sample_load(name)
if load ~= nil then
voiceTable[voice] = load
end
end
end
-- get the sample to play
local voice = voiceTable[sound]
if voice == nil then return NO_SOUND end
playerSample[index] = voice
-- if there's no pointer then it must be a sound clip table
if voice._pointer == nil and type(voice) ~= TYPE_STRING then
-- run through each sample and load in any samples that haven't been loaded
for i, name in pairs(voice) do
if check_sound_exists(voice[i]) and type(voice[i]) == "string" then
local load = audio_sample_load(name)
if load ~= nil then
voice[i] = load
end
end
end
if #voice ~= 0 then
-- choose a random sample
playerSample[index] = voice[math_random(#voice)]
end
end
-- Play the sample
if check_sound_exists(playerSample[index]) then
if sound == CHAR_SOUND_SNORING1 or sound == CHAR_SOUND_SNORING2 or sound == CHAR_SOUND_SNORING3 then
audio_sample_play(playerSample[index], m.pos, 0.5)
else
audio_sample_play(playerSample[index], m.pos, 1.0)
end
return NO_SOUND
end
end
--- @param m MarioState
local function custom_character_snore(m)
if is_game_paused() or optionTable[optionTableRef.localVoices].toggle == 0 then return end
if m.action ~= ACT_SLEEPING then
return
elseif m.actionState ~= 2 or (m.flags & MARIO_MARIO_SOUND_PLAYED) == 0 then
return
end
local voice = character_get_voice(m)
if voice == nil then return end
local snoreTable = voice[CHAR_SOUND_SNORING3]
if snoreTable == nil or snoreTable._pointer ~= nil then
snoreTable = {}
for i = CHAR_SOUND_SNORING1, CHAR_SOUND_SNORING3 do
if voice[i] ~= nil then
table_insert(snoreTable, voice[i])
end
end
end
local animFrame = m.marioObj.header.gfx.animInfo.animFrame
if snoreTable ~= nil and #snoreTable >= 2 then
if animFrame == 2 and m.actionTimer < SLEEP_TALK_START then
custom_character_sound(m, snoreTable[2])
elseif animFrame == 25 then
if #snoreTable >= 3 then
m.actionTimer = m.actionTimer + 1
if m.actionTimer >= SLEEP_TALK_END then
m.actionTimer = STARTING_SNORE
end
if m.actionTimer == SLEEP_TALK_START then
play_character_sound(m, CHAR_SOUND_SNORING3)
elseif m.actionTimer < SLEEP_TALK_START then
play_character_sound(m, CHAR_SOUND_SNORING1)
end
else
play_character_sound(m, CHAR_SOUND_SNORING1)
end
end
elseif animFrame == 2 then
play_character_sound(m, CHAR_SOUND_SNORING2)
elseif animFrame == 25 then
play_character_sound(m, CHAR_SOUND_SNORING1)
end
end
local function update()
if is_game_paused() then
stop_all_custom_character_sounds()
end
end
hook_event(HOOK_UPDATE, update)
hook_event(HOOK_ON_LEVEL_INIT, stop_all_custom_character_sounds)
_G.charSelect.voice = {
sound = custom_character_sound,
snore = custom_character_snore,
}
-- Must be ran on startup
local function config_character_sounds()
hook_event(HOOK_CHARACTER_SOUND, custom_character_sound)
hook_event(HOOK_MARIO_UPDATE, custom_character_snore)
end
_G.charSelect.config_character_sounds = config_character_sounds
-- Join sound
local function mario_update(m)
if m.playerIndex ~= 0 then return end
if stallTimer == stallSayLine then
play_character_sound(m, CHAR_SOUND_OKEY_DOKEY)
stallTimer = stallTimer + 1
elseif stallTimer < stallSayLine then
stallTimer = stallTimer + 1
end
end
hook_event(HOOK_MARIO_UPDATE, mario_update)