Skip to content

What is Pill Structure

Pill Structure is what we call the table, the second argument in registration via pills.register(name, {...}), which contains all the information about our Pill: model, abilities, animations, speed, sounds, etc.

All main structure parameters

The following parameters are most commonly needed in a Pill:

ParameterTypeDescription
printNamestringFull name REQUIRED
modelstringPath to the model (must start with "models/")
typestringREQUIRED AND MUST ALWAYS BE ply
hullVectorHitbox (third argument is height)
duckByfloatHow many units the Pill crouches
healthfloatMaximum health (If not specified — immortality is enabled)
jumpPowerfloatJump power
animstable[...]Model animations
soundstable[...]Sounds
moveSpeedtable[...]Movement speed
attacktable[...]Pill LMB
attack2table[...]Pill RMB
reloadfunction(ply, ent)Pill +reload bind
jumpfunction(ply, ent)Jump
landfunction(ply, ent)Landing

There are also additional parameters:

ParameterTypeDescription
cameratable[...]First-person and third-person camera settings
viewmodeltable[...]SWEP class and settings that will serve as the Pill's first-person hands
talktable[...]Settings for animatronic's mouth bone, which moves when the player talks
modelScalestringModel scale
bloodTypeintBlood type (See Enum BLOOD_COLOR)
muteStepsboolMute player footsteps?
noFallDamageboolDisable fall damage?
chaseThemestringChase theme (e.g., default)
movePoseModestringIf the model supports move_x and move_y pose parameters, enter xy. The move_yaw parameter has not been tested for functionality yet
aimtable[...]Specifies which pose parameters to use for rotating the Pill's body along with the player's camera
collisionGroupintCollision group (See Enum COLLISION_GROUP)
killConditionfunction(ply, ent)If present and returns true, draws a kill icon on the player's cursor
startFunctionfunction(ply, ent)Triggers after the player becomes the Pill
onRemovefunction(ent, formTable, ply)Triggers after the Pill is removed (i.e., the player changed Pill, or became a survivor)
onRemovePostfunction(ent, formTable, ply)Same as above
restorefunction(ent, formTable, ply)Same as above, but NOT CALLED if the player CHANGED PILL
tauntfunction(ply, ent, act)Triggers when the player uses the act command
moveModfunction(ply, ent, mv, cmd)Allows handling Pill movement inside SetupMove
animStoppedfunction(ply, ent, anim)Called after an animation ends (Not called if a layered animation ends)
animEventfunction(ply, ent, eventName, time, cycle, type, options)Called in ENT:HandleAnimEvent(...)
boneMorphstable[...]Used to change bone position, rotation, and scale

WARNING

onRemove and onRemovePost are called on both the server and the client. Also note that the arguments in the function are not what you might be used to starting with the player; here we have (ent, formTable, ply)

killCondition is called only on the client.

Parameters that are not used anywhere in the gamemode, but exist:

ParameterTypeDescription
flashlightfunction(ply, ent)Called when the flashlight is turned on (If the player turns off the flashlight — not called)
glideThinkfunction(ply, ent)Called while the player is not on the ground
diefunction(ply, ent)After the player controlling the Pill dies
visColorColorColors the Pill model with the given color
visColorRandomboolColors the Pill model with a random color
fliesboolShould the Pill fly instead of walk?
cloaktable[...]Built-in invisibility system in the database, most likely DOES NOT WORK
loadouttable[Weapon]Gives weapons from the table (MAY BE REMOVED IN FUTURE UPDATES)
ammotable[...]Gives ammo from the table (MAY BE REMOVED IN FUTURE UPDATES)

Alternative SHARED versions of attack, attack2, and reload:

ParameterTypeDescription
attack_shfunction(ply, ent)Same as attack
attack2_shfunction(ply, ent)Same as attack2
reload_shfunction(ply, ent)Same as reload
attack_sh_nolcfunction(ply, ent)Same as attack, but without Lag Compensation
attack2_sh_nolcfunction(ply, ent)Same as attack2, but without Lag Compensation
reload_sh_nolcfunction(ply, ent)Same as reload, but without Lag Compensation

Note

Instead of versions without Lag Compensation, you can simply use the SHARED versions and disable it yourself using Player:LagCompensation(false)

More about parameters

You may have noticed that many parameters require a table[...], but what is that? - These are tables with dynamic keys and values. Next, we'll take a closer look at how these tables are structured.

anims

lua
anims={
	-- Inside default are all the Pill's animations
	-- except layered ones, those will be below
	default={
		-- The following animations switch automatically
		-- On the right must be the names of the model's animations,
		-- On the left are strictly specified names
		idle = "Idle_01",
		walk = "Walking",
		run = "Running",
		jump = "Jump_1",
		glide = "Air_01", -- In air
		swim = "Swim_01", -- In water
		crouch = "Crawl",
		crouch_walk = "CrawlMovement",
		noclip = "Air_02", -- In noclip
		
		-- You can also add your own animations,
		-- which can be played using
		-- ent:PillAnim(name, freeze)
		stun = "TaserStun",
		land = "LandHard",
	},
	-- Layered animations that can be
	-- played using
	-- ent:PillGesture(name, priority, rate, blendin, blendout, startFrame)
	gestures={
		melee = "Melee_01",
		land = "LandSoft",
		taken_damage = "body_Flinch01",
	},
	-- The following values cause animations
	-- to speed up if the Pill's speed exceeds them.
	speedCap={
		walk = 160,
		run = 500,
		ducked = 90,
	},
}

sounds

lua
sounds={
	-- Left side is the sound name, right side is the path to the sound
	scream = "fnaf2/bonniescream.wav",
	melee = "fnaf2/xscream2.wav",
}
-- Can be played using
-- ent:PillSound("melee", false)

moveSpeed

lua
moveSpeed={
	walk = 160, -- Walking
	run = 500, -- Running
	ducked = 90, -- Crouching
}

attack, attack2

lua
attack={
	-- "trigger" mode means the function below triggers on a single press
	-- however there are no other modes for this parameter.
	mode="trigger",
	-- Function that triggers when the parameter activates
	-- First argument is the player wearing the Pill, second is the Pill itself
	func=function(ply,ent)
		local target = FindNearestPlayer(ent:GetPos(), 130, ply, 32)
		if not IsValid(target) then return end
		target:TakeDamage(target:Health() + 500, ply)
		
		ent:PillSound("melee",false)
	end
}

camera

lua
camera = {
	-- First-person camera offset
	offset = Vector(0, 0, 90), -- (third argument is height)
	-- Third-person camera distance from the Pill
	dist = 150
}

viewmodel

lua
viewmodel={
	weapon = "v_bear", -- SWEP class
	skin = 5, -- Skin
	bodyGroup = "Microphone", -- Bodygroup (changes its value to 1)
	func = function(wep) -- Function when given
		print("[TEST] We gave the player " .. wep:GetClass())
	end
},

talk

lua
talk = {
	jawbone="bip_lowerEndoJaw", -- Bone that will move while talking
	reversed=false, -- Reverse if jaw moves into the wrong direction
	scale=1.5, -- Scale jaw rotation
},

aim

lua
aim={
	xPose = "aim_yaw", -- Pose parameter if the Pill rotates the camera left-right
	yPose = "aim_pitch", -- Pose parameter if the Pill rotates the camera up-down
	
	xInvert = true, -- Invert left-right
	yInvert = true -- Invert up-down
},

boneMorphs

lua
boneMorphs={
	-- Left side is bone name, right side is parameters in a table
	-- Parameters can be scale, pos, and ang
	["bip_eye_R"] = {scale = Vector(0.5,0.5,0.5)},
	["bip_eye_L"] = {scale = Vector(0.5,0.5,0.5)},
	["bip_EyeLid_0_R"] = {scale = Vector(0,0,0)},
	["bip_EyeLid_1_R"] = {scale = Vector(0,0,0)},
	["bip_EyeLid_0_L"] = {scale = Vector(0,0,0)},
	["bip_EyeLid_1_L"] = {scale = Vector(0,0,0)},
},

Pill Template + Registration

Since writing out all these parameters manually can seem tedious (and it is), FH provides you with a template that contains all the main parameters!

Function:

lua
local MY_PILL = GetPillTemplate()

PrintTable(MY_PILL)

Output:

["aim"]:
		["xPose"]	=	aim_yaw
		["yPose"]	=	aim_pitch
["bloodType"]	=	3
["camera"]:
		["dist"]	=	150
		["offset"]	=	0.000000 0.000000 90.000000
["duckBy"]	=	60
["health"]	=	10000
["hull"]	=	32.000000 32.000000 86.000000
["jump"]	=	function: 0x8088097784fcdbb2
["jumpPower"]	=	250
["movePoseMode"]	=	xy
["muteSteps"]	=	true
["noFallDamage"]	=	true
["sounds"]:
		["jump"]	=	jump.mp3
		["land"]	=	land.mp3
		["melee"]	=	fnaf2/xscream2.wav
["type"]	=	ply

After using the template, you can add or modify parameters:

lua
local MY_PILL = GetPillTemplate()

MY_PILL.printName = "Super Jump Freddy"
MY_PILL.model="models/speps/pill/oldfreddy.mdl"
MY_PILL.jumpPower = 500
MY_PILL.anims={
	default={
		idle = "idle",
		crouch = "crouch",
		crouch_walk = "crouchmove",
		walk = "walk",
		run = "run",
		jump = "jump",
		glide = "air",
		land = "land",
	}
}
MY_PILL.moveSpeed={
	walk = 150,
	run = 490,
	ducked = 70,
}
MY_PILL.viewmodel={	weapon="v_freddy" }

And as the final step, we can now register our Pill at the end of our code:

lua
pills.register("super_jump_freddy", MY_PILL)

Attention

Make sure our code loads after the gamemode loads. The easiest way to do this is:

lua
hook.Add("OnGamemodeLoaded", "fh_mycustom_anim", function()
	-- make sure the server gamemode is Fazbear's Hunt
	if engine.ActiveGamemode() ~= "fazbearshunt" then return end
    
	-- Put your code here
end)

If there are no errors, then calmly join any map, then open the Admin Panel (press Q) and go to the Animatronics section. Your Pill should be in the "Unknown" category.

Next step

Go to the Registration into FH database → section to learn how to register an animatronic into the FH database.