Revision Difference
GM:StartCommand#547184
<function name="StartCommand" parent="GM" type="hook">
<ishook>yes</ishook>
<description>
Allows you to change the players inputs before they are processed by the server.
This is basically a shared version of <page>GM:CreateMove</page>.
<note>This function is also called for bots, making it the best solution to control them so far</note>
<note>This hook is predicted, but not by usual means, this hook is called when a <page>CUserCmd</page> is generated on the client, and on the server when it is received, so it is necessary for this hook to be called clientside even on singleplayer</note>
</description>
<realm>Shared</realm>
<predicted>Yes</predicted>
<hidepredictionwarning>Disable automatic prediction warning</hidepredictionwarning>
<args>
<arg name="ply" type="Player">The player</arg>
<arg name="ucmd" type="CUserCmd">The usercommand</arg>
</args>
</function>
<example>
<description>
Example of how you'd control a bot using this hook.
The example causes all bots to go kill any players they can get to with crowbars.
</description>
<code>
hook.Add( "StartCommand", "StartCommandExample", function( ply, cmd )
-- If the player is not a bot or the bot is dead, do not do anything
-- TODO: Maybe spawn the bot manually here if the bot is dead
if ( !ply:IsBot() or !ply:Alive() ) then return end
-- Clear any default movement or actions
cmd:ClearMovement()
cmd:ClearButtons()
-- Bot has no enemy, try to find one
if ( !IsValid( ply.CustomEnemy ) ) then
-- Scan through all players and select one not dead
for id, pl in ipairs( player.GetAll() ) do
if ( !pl:Alive() or pl == ply ) then continue end -- Don't select dead players or self as enemies
ply.CustomEnemy = pl
end
-- TODO: Maybe add a Line Of Sight check so bots won't walk into walls to try to get to their target
-- Or add path finding so bots can find their way to enemies
end
-- We failed to find an enemy, don't do anything
if ( !IsValid( ply.CustomEnemy ) ) then return end
-- Move forwards at the bots normal walking speed
cmd:SetForwardMove( ply:GetWalkSpeed() )
-- Aim at our enemy
if ( ply.CustomEnemy:IsPlayer() ) then
cmd:SetViewAngles( ( ply.CustomEnemy:GetShootPos() - ply:GetShootPos() ):GetNormalized():Angle() )
ply:SetEyeAngles( ( ply.CustomEnemy:GetShootPos() - ply:GetShootPos() ):GetNormalized():Angle() )⤶
else
cmd:SetViewAngles( ( ply.CustomEnemy:GetPos() - ply:GetShootPos() ):GetNormalized():Angle() )
ply:SetEyeAngles( ( ply.CustomEnemy:GetPos() - ply:GetShootPos() ):GetNormalized():Angle() )⤶
end
-- Give the bot a crowbar if the bot doesn't have one yet
if ( SERVER and !ply:HasWeapon( "weapon_crowbar" ) ) then ply:Give( "weapon_crowbar" ) end
-- Select the crowbar
cmd:SelectWeapon( ply:GetWeapon( "weapon_crowbar" ) )
-- Hold Mouse 1 to cause the bot to attack
cmd:SetButtons( IN_ATTACK )
-- Enemy is dead, clear our enemy so that we may acquire a new one
if ( !ply.CustomEnemy:Alive() ) then
ply.CustomEnemy = nil
end
end )
</code>
</example>