-
Notifications
You must be signed in to change notification settings - Fork 15
/
Hit sound.lua
161 lines (140 loc) · 6.83 KB
/
Hit sound.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
--------------------------------------------------------------------------------
-- Caching common functions
--------------------------------------------------------------------------------
local ffi = require 'ffi'
local uix = require 'gamesense/uix'
local client_set_event_callback, client_unset_event_callback, client_userid_to_entindex, entity_get_local_player, ui_get, ui_new_checkbox, ui_new_combobox, ui_set_callback, ui_set_visible = client.set_event_callback, client.unset_event_callback, client.userid_to_entindex, entity.get_local_player, ui.get, ui.new_checkbox, ui.new_combobox, ui.set_callback, ui.set_visible
--------------------------------------------------------------------------------
-- FFI functions
--------------------------------------------------------------------------------
local function bind_signature(module, interface, signature, typestring)
local interface = client.create_interface(module, interface) or error("invalid interface", 2)
local instance = client.find_signature(module, signature) or error("invalid signature", 2)
local success, typeof = pcall(ffi.typeof, typestring)
if not success then
error(typeof, 2)
end
local fnptr = ffi.cast(typeof, instance) or error("invalid typecast", 2)
return function(...)
return fnptr(interface, ...)
end
end
local function vmt_entry(instance, index, type)
return ffi.cast(type, (ffi.cast("void***", instance)[0])[index])
end
local function vmt_bind(module, interface, index, typestring)
local instance = client.create_interface(module, interface) or error("invalid interface")
local success, typeof = pcall(ffi.typeof, typestring)
if not success then
error(typeof, 2)
end
local fnptr = vmt_entry(instance, index, typeof) or error("invalid vtable")
return function(...)
return fnptr(instance, ...)
end
end
--------------------------------------------------------------------------------
-- Constants, variables, and data structures
--------------------------------------------------------------------------------
local enable_ref
local head_sound_ref
local body_sound_ref
local volume_ref
local sound_names = {}
local sound_name_to_file = {}
local int_ptr = ffi.typeof("int[1]")
local char_buffer = ffi.typeof("char[?]")
local find_first = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x6A\x00\xFF\x75\x10\xFF\x75\x0C\xFF\x75\x08\xE8\xCC\xCC\xCC\xCC\x5D", "const char*(__thiscall*)(void*, const char*, const char*, int*)")
local find_next = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x83\xEC\x0C\x53\x8B\xD9\x8B\x0D\xCC\xCC\xCC\xCC", "const char*(__thiscall*)(void*, int)")
local find_close = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x53\x8B\x5D\x08\x85", "void(__thiscall*)(void*, int)")
local current_directory = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x56\x8B\x75\x08\x56\xFF\x75\x0C", "bool(__thiscall*)(void*, char*, int)")
local add_to_searchpath = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x81\xEC\xCC\xCC\xCC\xCC\x8B\x55\x08\x53\x56\x57", "void(__thiscall*)(void*, const char*, const char*, int)")
local find_is_directory = bind_signature("filesystem_stdio.dll", "VFileSystem017", "\x55\x8B\xEC\x0F\xB7\x45\x08", "bool(__thiscall*)(void*, int)")
local sndplaydelay = cvar.sndplaydelay
local native_Surface_PlaySound = vmt_bind("vguimatsurface.dll", "VGUI_Surface031", 82, "void(__thiscall*)(void*, const char*)")
--------------------------------------------------------------------------------
-- Utility functions
--------------------------------------------------------------------------------
local function collect_files()
local files = {}
local file_handle = int_ptr()
local file = find_first("*", "XGAME", file_handle)
while file ~= nil do
local file_name = ffi.string(file)
if find_is_directory(file_handle[0]) == false and (file_name:find(".mp3") or file_name:find(".wav")) then
files[#files+1] = file_name
end
file = find_next(file_handle[0])
end
find_close(file_handle[0])
return files
end
local function normalize_file_name(name)
if name:find("_") then
name = name:gsub("_", " ")
end
if name:find(".mp3") then
name = name:gsub(".mp3", "")
end
if name:find(".wav") then
name = name:gsub(".wav", "")
end
return name
end
--------------------------------------------------------------------------------
-- Callback functions
--------------------------------------------------------------------------------
local function on_player_hurt(e)
if client_userid_to_entindex(e.attacker) == entity_get_local_player() then
local sound_file = sound_name_to_file[e.hitgroup == 1 and ui_get(head_sound_ref) or ui_get(body_sound_ref)]
if sound_file then
for i=1, ui_get(volume_ref) do
native_Surface_PlaySound(sound_file)
end
end
end
end
local function on_player_blind(e)
if client_userid_to_entindex(e.attacker) == entity_get_local_player() then
local sound_file = sound_name_to_file[ui_get(body_sound_ref)]
sndplaydelay:invoke_callback(0, sound_file)
end
end
local function on_hit_sound_toggle(ref, value)
local state = value or ui_get(ref)
ui_set_visible(head_sound_ref, state)
ui_set_visible(body_sound_ref, state)
ui_set_visible(volume_ref, state)
end
--------------------------------------------------------------------------------
-- Initilization code
--------------------------------------------------------------------------------
local function init_sound(sound_name, sound_file)
sound_names[#sound_names+1] = sound_name
sound_name_to_file[sound_name] = sound_file
end
local function init()
init_sound("Wood stop", "doors/wood_stop1.wav")
init_sound("Wood strain", "physics/wood/wood_strain7.wav")
init_sound("Wood plank impact", "physics/wood/wood_plank_impact_hard4.wav")
init_sound("Warning", "resource/warning.wav")
-- Setup serach path for hitsounds
local current_path = char_buffer(128)
current_directory(current_path, ffi.sizeof(current_path))
current_path = string.format("%s\\csgo\\sound\\hitsounds", ffi.string(current_path))
add_to_searchpath(current_path, "XGAME", 0)
-- Collect sound files and add them to the hit sound list
local sound_files = collect_files()
for i=1, #sound_files do
local file_name = sound_files[i]
init_sound(normalize_file_name(file_name), string.format("hitsounds/%s", file_name))
end
enable_ref = uix.new_checkbox("LUA", "B", "Hit marker sound")
head_sound_ref = ui_new_combobox("LUA", "B", "Head shot sound", sound_names)
body_sound_ref = ui_new_combobox("LUA", "B", "Body shot sound", sound_names)
volume_ref = ui.new_slider("LUA", "B", "\nSound volume", 1, 100, 1, true, "%")
enable_ref:on("change", on_hit_sound_toggle)
enable_ref:on("player_hurt", on_player_hurt)
enable_ref:on("player_blind", on_player_blind)
end
init()