Skip to content

Instantly share code, notes, and snippets.

@YuRaNnNzZZ
Last active April 21, 2025 13:28
Show Gist options
  • Save YuRaNnNzZZ/8411ef8233714784c25b7dafd54104cb to your computer and use it in GitHub Desktop.
Save YuRaNnNzZZ/8411ef8233714784c25b7dafd54104cb to your computer and use it in GitHub Desktop.
TFA-VOX Template Collection

This is a collection of templates for TFA-VOX.

Before going through anything from here, make sure you have read through Lua basics guide for GMod here first!

List of contents:

For example custom gamemode integration, take a look at nZombies module implementation made by Zet0rz

List of community-made TFA-VOX extension modules (additional callouts/integrations)

If you have additional modules/integrations that could be useful for VOX pack makers, feel free to suggest them below!

-- TFA-VOX custom hooks reference
-- To be used with https://wiki.facepunch.com/gmod/hook.Add in your own code
-- All returns are optional, you can use hooks just to listen for events happening
-- Where state is listed as Shared, hook has to be added both on server and client to avoid any issues!
--------------
-- --
-- SPOTTING --
-- --
--------------
GM:TFAVOX_Spotting_PopulateNPCTypes()
-- Hook name: TFAVOX_Spotting_PopulateNPCTypes
-- Description: Allows to add custom spotting line types
-- State: Shared (only used serverside)
-- Arguments:
-- 1. table module - Spotting module
-- 2. table types - NPC types table (key is classname, value is key in "spot" VOX pack table)
GM:TFAVOX_SpotEntity()
-- Hook name: TFAVOX_SpotEntity
-- Description: Called when player attempts to spot an NPC/Player
-- State: Server
-- Arguments:
-- 1. Player ply - The player who attempts to spot
-- 2. Entity ent - The player/NPC who is getting spotted
-- Returns:
-- 1. boolean or Entity - Return false to prevent spotting, return an entity to override entity to be spotted (must be player/npc/nextbot)
--------------------
-- --
-- INITIALIZATION --
-- --
--------------------
GM:TFAVOX_InitializePlayer()
-- Hook name: TFAVOX_InitializePlayer
-- Description: Called when player does not a VOX table
-- State: Server
-- Arguments:
-- 1. Player ply
-- 2. boolean force
-- 3. boolean clean - VOX table was cleared after reload
GM:TFAVOX_InitializePlayerDone()
-- Hook name: TFAVOX_InitializePlayerDone
-- Description: Called after TFAVOX_InitializePlayer hook
-- State: Server
-- Arguments:
-- 1. Player ply
-- 2. boolean force
-- 3. boolean clean
GM:TFAVOX_InitializePlayerTimings()
-- Hook name: TFAVOX_InitializePlayerTimings
-- Description: Called every server tick or packs/modules reload before both TFAVOX_InitializePlayer and TFAVOX_InitializePlayerDone
-- State: Server
-- Arguments:
-- 1. Player ply
-- 2. boolean force
-- 3. boolean clean
if !MODULE then TFAVOX_Modules_Initialize() return end
MODULE.name = "Example Module" -- Module Label
MODULE.description = "Example implementation of a custom TFA-VOX module" -- Module Description
MODULE.author = "TFA" -- Module Author (optional)
MODULE.realm = "shared" -- Module Realm (client, server or shared)
MODULE.activedefault = true -- Module is active by default? (defaults to true)
MODULE.options = { -- Configurable module settings/options
["sampleopt"] = { -- Option Key/Name
["name"] = "Sample Option", -- Option Label
["description"] = "Sample option", -- Option Description
["type"] = "integer", -- Option type (int or integer)
["min"] = 0, -- Minimum value
["max"] = 100, -- Maximum value
["default"] = 100 -- Default value
},
["sampleoptfloat"] = {
["name"] = "Sample Float Option",
["description"] = "Sample option that's a float",
["type"] = "float", -- float or double
["min"] = 0,
["max"] = 100,
["default"] = 50.5
},
["sampleoptbool"] = {
["name"] = "Sample Boolean Option",
["description"] = "Sample option that's a boolean",
["type"] = "boolean", -- bool or boolean
["default"] = true
},
["sampleoptstr"] = {
["name"] = "Sample String Option",
["description"] = "Sample option that's a string",
["type"] = "string",
["default"] = "test"
},
["sampleoptcol"] = {
["name"] = "Sample Color Option",
["description"] = "Sample option that's a color",
["type"] = "color",
["default"] = Color(255, 0, 0, 255)
},
["sampleoptvec"] = {
["name"] = "Sample Vector Option",
["description"] = "Sample option that's a vector",
["type"] = "vector",
["default"] = Vector(0, 0, 0)
}
}
function MODULE:GetSampleOptBool() -- example module function to access module parameter
return self:GetOption("sampleoptbool", true) -- Arguments: module table, parameter key/name, fallback value (optional)
end
local lastprint = -999
-- Note: "self" in hooks is reserved for "MODULE" table of the module; for non-hooks usage you might want to localize "MODULE" variable
-- All module's hooks are disabled when module is not active
hook.Add("Think", "TestDH", function()
if not self:GetSampleOptBool() then return end -- calling module's function from above to access the boolean parameter
if CurTime() > lastprint + 5 then
lastprint = CurTime()
print("It works!")
end
end)
--------------------------------------
-- Custom module sounds integration --
--------------------------------------
-- First, you need to initialize the custom sounds from the pack:
hook.Add("TFAVOX_InitializePlayer", "TFAVOX_ExampleModuleInit", function(ply)
if IsValid(ply) then
local mdtbl = TFAVOX_GetPack(ply:GetModel())
if mdtbl then
ply.TFAVOX_Sounds = ply.TFAVOX_Sounds or {}
if mdtbl.examplemodule then
ply.TFAVOX_Sounds.examplemodule = ply.TFAVOX_Sounds.examplemodule or {}
ply.TFAVOX_Sounds.examplemodule.customsound = mdtbl.examplemodule.customsound
end
end
end
end)
-- In the VOX pack it would go like this:
--[[
local VOXPackTable = {
-- all base module sounds here
["examplemodule"] = {
["customsound"] = {
["sound"] = TFAVOX_GenerateSound(mdlprefix, "CustomModuleSound", {"snd1", "snd2", "snd3"})
}
}
}
]]--
-- Then, to play the sound, you need to call the sound playing function:
--[[
if SERVER and ply.TFAVOX_Sounds then
local sndtbl = ply.TFAVOX_Sounds.examplemodule
if sndtbl and sndtbl.customsound then
TFAVOX_PlayVoicePriority(ply, sndtbl.customsound, 0, false) -- Arguments: player entity, sound table, priority, interrupt
end
end
]]--
-- Click "Raw" then save the whole file (the last line is important!)
-- Then rename and put to lua/tfa_vox/packs in your addon folder
-- Path to your player model. Use forward slashes.
-- You can get the path for your current player model in Q -> Utilities -> TFA-VOX -> Debug/Development
local model = "models/player/player.mdl"
-- If you wish to use this pack with more than one playermodel, please look at the bottom of this file.
--[[ CONVENIENCE FUNCTIONS, DO NOT EDIT FROM THIS POINT UNTIL CLEAR ]]--
-- Automated prefix extraction from player name (for sound generation)
local tmptbl = string.Split(model, "/")
local mdlprefix = string.Replace(tmptbl[#tmptbl] or model, ".mdl", "")
-- OR! you can specify the prefix manually, like this:
-- local mdlprefix = "SHORT_MODEL_NAME" -- uncomment this line and comment two lines above
if model == "models/player/player.mdl" then return end
--[[ CLEAR ]]--
--[[
-- To give VOX sound paths, I recommend TFAVOX_GenerateSound.
-- TFAVOX_GenerateSound( mdlprefix, "sound_event_here", { "path/to/sound1.wav", "path/to/sound2.wav", "path/to/sound3.wav" }
-- You may have as many sounds as you want in the GenerateSound table ^^
-- Please have at least one.
-- Sound paths are relative to "sound" folder of your addon.
-- For example from above, the sounds should be placed there:
-- - garrysmod/addons/<YOUR ADDON>/sound/path/to/sound1.wav
-- - garrysmod/addons/<YOUR ADDON>/sound/path/to/sound2.wav
-- - garrysmod/addons/<YOUR ADDON>/sound/path/to/sound3.wav
-- and so on.
-- Allowed file types are: WAV, MP3 and OGG (without proper delay autocalculation.)
-- If you insist on doing things manually, ['sound'] can be a TABLE | { "sound1.wav", "sound2.wav", "sound3.wav" } | or a STRING | "snd" |
-- Manual sounds require soundscripts.
-- TFA VOX will now automatically calculate delays.
-- If you need to manually override, feed ['delay'] with a TABLE | {min,max} | or a NUMBER | 999 |
]]--
local VOXPackTable = {
['main'] = { -- subtable id
['heal'] = { -- event id
['delay'] = nil, -- delay (nil to autocalc, doesn't work with ogg)
['sound'] = TFAVOX_GenerateSound( mdlprefix, "heal", { "snd1", "snd2", "snd3" } ) -- sound path(s)
},
['healmax'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "healmax", { "snd1", "snd2", "snd3" } )
},
['crithit'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "crithit", { "snd1", "snd2", "snd3" } )
},
['crithealth'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "crithealth", { "snd1", "snd2", "snd3" } )
},
['death'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "death", { "snd1", "snd2", "snd3" } )
},
['spawn'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spawn", { "snd1", "snd2", "snd3" } )
},
['pickup'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "pickup", { "snd1", "snd2", "snd3" } )
},
['reload'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "reload", { "snd1", "snd2", "snd3" } )
},
['noammo'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "noammo", { "snd1", "snd2", "snd3" } )
},
['fall'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "fall", { "snd1", "snd2", "snd3" } )
},
['jump'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "jump", { "snd1", "snd2", "snd3" } )
},
['step'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "step", { "snd1", "snd2", "snd3" } )
}
},
['murder'] = {
['combine'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdcomb", { "snd1", "snd2", "snd3" } )
},
['cp'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdcp", { "snd1", "snd2", "snd3" } )
},
['zombie'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdzomb", { "snd1", "snd2", "snd3" } )
},
['headcrab'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdhc", { "snd1", "snd2", "snd3" } )
},
['antlion'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdant", { "snd1", "snd2", "snd3" } )
},
['barnacle'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdbarn", { "snd1", "snd2", "snd3" } )
},
['manhack'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdmh", { "snd1", "snd2", "snd3" } )
},
['scanner'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdsca", { "snd1", "snd2", "snd3" } )
},
['sniper'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdsni", { "snd1", "snd2", "snd3" } )
},
['turret'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdtur", { "snd1", "snd2", "snd3" } )
},
['ally'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdally", { "snd1", "snd2", "snd3" } )
},
-- ['npc_pigeon'] = { -- classname overrides category entry
-- ['delay'] = nil,
-- ['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdpigeon", { "snd1", "snd2", "snd3" } )
-- },
-- [HITGROUP_HEAD] = { -- last hit bodypart override; chanced (configurable); accepts enum https://wiki.facepunch.com/gmod/Enums/HITGROUP
-- ['delay'] = nil,
-- ['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdheadshot", { "snd1", "snd2", "snd3" } )
-- },
['generic'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "murdgener", { "snd1", "snd2", "snd3" } )
}
},
['spot'] = {
['combine'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotcomb", { "snd1", "snd2", "snd3" } )
},
['cp'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotcp", { "snd1", "snd2", "snd3" } )
},
['zombie'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotzom", { "snd1", "snd2", "snd3" } )
},
['headcrab'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spothc", { "snd1", "snd2", "snd3" } )
},
['antlion'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotant", { "snd1", "snd2", "snd3" } )
},
['barnacle'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotbarn", { "snd1", "snd2", "snd3" } )
},
['manhack'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotmh", { "snd1", "snd2", "snd3" } )
},
['scanner'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotsca", { "snd1", "snd2", "snd3" } )
},
['sniper'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotsni", { "snd1", "snd2", "snd3" } )
},
['turret'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spottur", { "snd1", "snd2", "snd3" } )
},
['ally'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotally", { "snd1", "snd2", "snd3" } )
},
-- ['npc_crow'] = { -- classname overrides category entry
-- ['delay'] = nil,
-- ['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotcrow", { "snd1", "snd2", "snd3" } )
-- },
['generic'] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "spotgener", { "snd1", "snd2", "snd3" } )
}
},
['taunt'] = {
[ACT_GMOD_GESTURE_AGREE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_AGREE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_GESTURE_BECON] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_BECON", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_GESTURE_BOW] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_BOW", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_GESTURE_DISAGREE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_DISAGREE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_TAUNT_SALUTE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_TAUNT_SALUTE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_GESTURE_WAVE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_WAVE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_TAUNT_PERSISTENCE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_TAUNT_PERSISTENCE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_TAUNT_MUSCLE] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_TAUNT_MUSCLE", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_TAUNT_LAUGH] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_TAUNT_LAUGH", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_GESTURE_POINT] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_GESTURE_POINT", { "snd1", "snd2", "snd3" } )
},
[ACT_GMOD_TAUNT_CHEER] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_GMOD_TAUNT_CHEER", { "snd1", "snd2", "snd3" } )
},
[ACT_SIGNAL_FORWARD] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_SIGNAL_FORWARD", { "snd1", "snd2", "snd3" } )
},
[ACT_SIGNAL_GROUP] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_SIGNAL_GROUP", { "snd1", "snd2", "snd3" } )
},
[ACT_SIGNAL_HALT] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "ACT_SIGNAL_HALT", { "snd1", "snd2", "snd3" } )
}
},
['damage'] = {
[HITGROUP_GENERIC] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_GENERIC", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_HEAD] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_HEAD", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_CHEST] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_CHEST", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_STOMACH] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_STOMACH", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_LEFTARM] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_LEFTARM", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_RIGHTARM] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_RIGHTARM", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_LEFTLEG] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_LEFTLEG", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_RIGHTLEG] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_RIGHTLEG", { "snd1", "snd2", "snd3" } )
},
[HITGROUP_GEAR] = {
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "HITGROUP_GEAR", { "snd1", "snd2", "snd3" } )
}
},
['callouts'] = {
['agree'] = { -- callout id/classname in these quotes
['name'] = "Agree",-- Callout friendly name ( what you see in the wheel )
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "Wheel_Agree", { "snd1", "snd2", "snd3" } ),
['order'] = nil, -- Sorting order index number (incremental, any entries with index will be put above others)
},
['disagree'] = { -- callout id/classname in these quotes
['name'] = "Disagree",-- Callout friendly name ( what you see in the wheel )
['delay'] = nil,
['sound'] = TFAVOX_GenerateSound( mdlprefix, "Wheel_Disagree", { "snd1", "snd2", "snd3" } ),
['order'] = nil,
}
},
['external'] = { --Completely optional, allows you to integrate with external mods
['bash'] = { -- Used by TFA Base
['sound'] = TFAVOX_GenerateSound( mdlprefix, "Bash", { "snd1", "snd2", "snd3" } )
}
}
}
TFAVOX_RegisterPack(model, VOXPackTable)
-- Manual registration for additional models with same pack:
-- TFAVOX_RegisterPack("models/player/player.mdl", VOXPackTable)

Comments are disabled for this gist.