1220 lines
32 KiB
Lua
1220 lines
32 KiB
Lua
local pl = FindMetaTable("Player")
|
|
|
|
util.AddNetworkString("COD.HitMarkEnemy")
|
|
util.AddNetworkString("COD.HitMarkEnemy2")
|
|
util.AddNetworkString("COD.ScoreMarkEnemy")
|
|
util.AddNetworkString("COD.KillstreaksHUD")
|
|
util.AddNetworkString("COD.EndingHUD")
|
|
util.AddNetworkString("COD.StartMatchHUD")
|
|
util.AddNetworkString("COD.PickupCarePackage")
|
|
util.AddNetworkString("COD.KillNick")
|
|
util.AddNetworkString("COD.KillstreakChoose")
|
|
util.AddNetworkString("COD.PerksShow")
|
|
util.AddNetworkString("COD.PerksChoose")
|
|
util.AddNetworkString("COD.Killfeed")
|
|
util.AddNetworkString("COD.Cutscene")
|
|
util.AddNetworkString("COD.SendData")
|
|
util.AddNetworkString("COD.TimerShow")
|
|
util.AddNetworkString("COD.OtherKillstreak")
|
|
util.AddNetworkString("COD.ShowAnnouncment")
|
|
util.AddNetworkString("COD.SendAdminStatus")
|
|
util.AddNetworkString("COD.GameStartedStatus")
|
|
util.AddNetworkString("COD.RequestGameStatus")
|
|
|
|
COD.TimeBeforeEnd = 0
|
|
COD.TimeBefore1PerkUnlock = 0
|
|
COD.Perk1Unlocked = false
|
|
COD.TimeBefore2PerkUnlock = 0
|
|
COD.Perk2Unlocked = false
|
|
COD.Ending = false
|
|
COD.GameStarted = false
|
|
COD.EnabledDynamicSpawnPoints = false
|
|
COD.DisableSpawn = false
|
|
COD.TimeBeforeStart = 0
|
|
COD.DisableEndGameByNoTeam = false
|
|
|
|
local KillstreakTeamEntities = {
|
|
["tdm_ah64"] = true,
|
|
["tdm_mi24"] = true,
|
|
["tdm_sentry"] = true,
|
|
["tdm_harrier"] = true,
|
|
["tdm_drone"] = true,
|
|
}
|
|
|
|
net.Receive("COD.KillstreakChoose", function(len, ply)
|
|
local tab = net.ReadTable()
|
|
local mw = net.ReadString()
|
|
local sw = net.ReadString()
|
|
ply.KillstreakFuture = tab
|
|
ply.WeaponData = {mw, sw}
|
|
end)
|
|
|
|
net.Receive("COD.PerksChoose", function(len, ply)
|
|
local p1 = net.ReadFloat()
|
|
local p2 = net.ReadFloat()
|
|
ply.Perk1Choosed = p1
|
|
ply.Perk2Choosed = p2
|
|
end)
|
|
|
|
hook.Add("CanPlayerSuicide", "AllowOwnerSuicide", function( ply )
|
|
return false
|
|
end)
|
|
|
|
function COD:AddFragsToData(team, count)
|
|
if team == 1 then
|
|
COD.DataTable["Team1_Kills"] = COD.DataTable["Team1_Kills"]+count
|
|
elseif team == 2 then
|
|
COD.DataTable["Team2_Kills"] = COD.DataTable["Team2_Kills"]+count
|
|
end
|
|
BroadcastLua([[
|
|
COD.DataTable["Team2_Kills"] = ]]..COD.DataTable["Team2_Kills"]..[[
|
|
COD.DataTable["Team1_Kills"] = ]]..COD.DataTable["Team1_Kills"]..[[
|
|
]])
|
|
end
|
|
|
|
function COD:GetInfoData(ply)
|
|
local tab = COD.DataTable
|
|
|
|
if ply != "all" and IsValid(ply) then
|
|
net.Start("COD.SendData")
|
|
net.WriteTable(tab)
|
|
net.Send(ply)
|
|
end
|
|
|
|
if ply == "all" then
|
|
net.Start("COD.SendData")
|
|
net.WriteTable(tab)
|
|
net.Broadcast()
|
|
end
|
|
end
|
|
|
|
function COD:ShowAnnouncment(type)
|
|
net.Start("COD.ShowAnnouncment")
|
|
net.WriteFloat(type)
|
|
net.Broadcast()
|
|
end
|
|
|
|
function COD:ShowEndScreen()
|
|
local t1, t2 = COD.DataTable["Team1_Kills"], COD.DataTable["Team2_Kills"]
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if ply:Team() == 1 and t1 > t2 then
|
|
net.Start("COD.EndingHUD")
|
|
net.WriteBool(true)
|
|
net.Send(ply)
|
|
elseif ply:Team() == 2 and t2 > t1 then
|
|
net.Start("COD.EndingHUD")
|
|
net.WriteBool(true)
|
|
net.Send(ply)
|
|
else
|
|
net.Start("COD.EndingHUD")
|
|
net.WriteBool(false)
|
|
net.Send(ply)
|
|
end
|
|
end
|
|
end
|
|
|
|
function COD:CountTeamPlayers(team)
|
|
local tab = {}
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if ply:Team() == team then
|
|
table.insert(tab, ply)
|
|
end
|
|
end
|
|
return #tab
|
|
end
|
|
|
|
function COD:SpawnPlayerAtSafePosition(ply)
|
|
if !IsValid(ply) then return end
|
|
|
|
local enemy_players = player.GetAll()
|
|
if ply:Team() == 1 then
|
|
enemy_players = team.GetPlayers(2)
|
|
elseif ply:Team() == 2 then
|
|
enemy_players = team.GetPlayers(1)
|
|
end
|
|
|
|
local positions = {}
|
|
for _, pos in ipairs(COD.DataTable["simple_Spawns"]) do
|
|
local can = true
|
|
local gdist = 0
|
|
for _, en in ipairs(enemy_players) do
|
|
local dist = en:GetPos():DistToSqr(pos)
|
|
if en:IsLineOfSightClear(pos) or dist < 50000 then
|
|
can = false
|
|
end
|
|
if dist > gdist then
|
|
gdist = dist
|
|
end
|
|
end
|
|
if can then
|
|
table.insert(positions, {vec = pos, dist = gdist})
|
|
end
|
|
end
|
|
if #positions > 0 then
|
|
local position, dist = Vector(), 0
|
|
for _, p in ipairs(positions) do
|
|
if p.dist > dist then
|
|
dist = p.dist
|
|
position = p.vec
|
|
end
|
|
end
|
|
ply:SetPos(position)
|
|
else
|
|
ply:SetPos(table.Random(COD.DataTable["simple_Spawns"]))
|
|
end
|
|
end
|
|
|
|
function COD:KillstreakAddOther(ply, removing, number)
|
|
local tab = ply.KillstreakOthers
|
|
if removing then
|
|
if number == -1 then
|
|
ply.KillstreakOthers = {}
|
|
tab = {}
|
|
else
|
|
table.remove(tab, #tab)
|
|
end
|
|
else
|
|
table.insert(tab, number)
|
|
end
|
|
net.Start("COD.OtherKillstreak")
|
|
net.WriteTable(tab)
|
|
net.Send(ply)
|
|
end
|
|
|
|
hook.Add("Think", "TDMGmodStartMatch", function()
|
|
local count = player.GetCount()
|
|
if count > 1 then
|
|
if not COD.GameStarted then
|
|
if COD.TimeBeforeStart < CurTime() then
|
|
COD:ChangeState(true)
|
|
end
|
|
else
|
|
if (#team.GetPlayers(1) == 0 or #team.GetPlayers(2) == 0) and not COD.DisableEndGameByNoTeam then
|
|
COD:ChangeState(false)
|
|
COD.TimeBeforeStart = CurTime()+COD.DataTable["Delay_Before_Start"]
|
|
end
|
|
if ( COD.TimeBeforeEnd-CurTime() <= 0 or COD.DataTable["Team1_Kills"] >= COD.DataTable["MaxKills"] or COD.DataTable["Team2_Kills"] >= COD.DataTable["MaxKills"] ) and not COD.Ending then
|
|
COD.Ending = true
|
|
COD:ShowEndScreen()
|
|
if COD.LastKillData.length > 0 then
|
|
COD:ShowLastKillCam(6)
|
|
COD.LastKillData = {
|
|
length = 0,
|
|
data = ""
|
|
}
|
|
end
|
|
timer.Simple(12, function()
|
|
COD:ChangeState(false)
|
|
end)
|
|
end
|
|
if COD.Ending then
|
|
COD:RemoveAllPlayers()
|
|
end
|
|
if COD.TimeBefore1PerkUnlock < CurTime() and not COD.Perk1Unlocked then
|
|
COD.Perk1Unlocked = true
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
ply:UnlockPerks(1)
|
|
end
|
|
end
|
|
if COD.TimeBefore2PerkUnlock < CurTime() and not COD.Perk2Unlocked then
|
|
COD.Perk2Unlocked = true
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
ply:UnlockPerks(2)
|
|
end
|
|
end
|
|
end
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
if ply:Health() >= 100 or not ply:Alive() then
|
|
ply.HealCooldown = CurTime() + 8
|
|
if ply:GetNWFloat('Perk2') == 1 then
|
|
ply.HealCooldown = CurTime() + 3
|
|
end
|
|
else
|
|
if ply.HealCooldown < CurTime() and not ply:IsDowned() then
|
|
ply:SetHealth(math.Clamp(ply:Health()+1, 1, 100))
|
|
end
|
|
end
|
|
if ply:GetNWFloat('Perk1') == 4 then
|
|
if ply.CooldownPerkEquip < CurTime() then
|
|
ply.CooldownPerkEquip = CurTime()+30
|
|
local wep = ply:GetActiveWeapon()
|
|
if IsValid(wep) then
|
|
local at = wep:GetPrimaryAmmoType()
|
|
local clip = wep:GetMaxClip1()
|
|
ply:GiveAmmo(clip, at, true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
COD.TimeBeforeStart = CurTime()+COD.DataTable["Delay_Before_Start"]
|
|
if COD.GameStarted then
|
|
COD:ChangeState(false)
|
|
end
|
|
end
|
|
end)
|
|
|
|
function COD:ChangeState(bool)
|
|
game.CleanUpMap()
|
|
COD.DataTable["Team1_Kills"] = 0
|
|
COD.DataTable["Team2_Kills"] = 0
|
|
if bool then
|
|
COD.DataTable["MaxKills"] = COD.GamemodeSettings[COD.DataTable["Gamemode"]]["MaxKills"]
|
|
COD.EnabledDynamicSpawnPoints = false
|
|
COD.TimeBeforeEnd = CurTime()+COD.GamemodeSettings[COD.DataTable["Gamemode"]]["MaxTime"]+COD.DataTable["Delay_Before_Start"]
|
|
COD.TimeBefore1PerkUnlock = CurTime()+90
|
|
COD.TimeBefore2PerkUnlock = CurTime()+180
|
|
COD.Perk1Unlocked = false
|
|
COD.Perk2Unlocked = false
|
|
COD.GameStarted = true
|
|
COD.Ending = false
|
|
net.Start("COD.GameStartedStatus")
|
|
net.WriteBool(true)
|
|
net.Broadcast()
|
|
COD.LastKillData = {
|
|
length = 0,
|
|
data = ""
|
|
}
|
|
BroadcastLua([[
|
|
COD.DataTable["Team2_Kills"] = ]]..COD.DataTable["Team2_Kills"]..[[
|
|
COD.DataTable["Team1_Kills"] = ]]..COD.DataTable["Team1_Kills"]..[[
|
|
COD.DataTable["MaxKills"] = ]]..COD.DataTable["MaxKills"]..[[
|
|
COD.TimeMatch = ]]..COD.TimeBeforeEnd..[[
|
|
]])
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
ply:ResetParametrsCOD()
|
|
end
|
|
COD:AutoTeamMix()
|
|
net.Start("COD.StartMatchHUD")
|
|
net.Broadcast()
|
|
COD.EnabledDynamicSpawnPoints = true
|
|
COD.DisableEndGameByNoTeam = false
|
|
else
|
|
COD.TimeBefore1PerkUnlock = math.huge
|
|
COD.TimeBefore2PerkUnlock = math.huge
|
|
COD.TimeBeforeEnd = 0
|
|
COD.GameStarted = false
|
|
COD.Ending = false
|
|
net.Start("COD.GameStartedStatus")
|
|
net.WriteBool(false)
|
|
net.Broadcast()
|
|
COD.EnabledDynamicSpawnPoints = false
|
|
if COD.DataTable["Enable_RandomGamemode"] then
|
|
COD.DataTable["Gamemode"] = math.random(1,5)
|
|
COD:GetInfoData("all")
|
|
end
|
|
COD:RemoveAllPlayers()
|
|
BroadcastLua([[
|
|
COD.DataTable["Team2_Kills"] = 0
|
|
COD.DataTable["Team1_Kills"] = 0
|
|
COD.TimeMatch = 0
|
|
]])
|
|
end
|
|
hook.Run("COD.ChangeState", bool)
|
|
end
|
|
|
|
function COD:RemoveAllPlayers()
|
|
local players = player.GetAll()
|
|
for k, ply in ipairs(players) do
|
|
if ply:Alive() then
|
|
ply:KillSilent()
|
|
end
|
|
end
|
|
end
|
|
|
|
function COD:AutoTeamMix()
|
|
local players = player.GetAll()
|
|
table.Shuffle(players)
|
|
local plcount = math.floor(player.GetCount()/2)
|
|
local teambool = tobool(math.random(0,1))
|
|
for k, ply in ipairs(players) do
|
|
if plcount > 0 then
|
|
plcount = plcount - 1
|
|
if teambool then
|
|
ply:SetTeam(1)
|
|
else
|
|
ply:SetTeam(2)
|
|
end
|
|
else
|
|
if teambool then
|
|
ply:SetTeam(2)
|
|
else
|
|
ply:SetTeam(1)
|
|
end
|
|
end
|
|
ply:KillSilent()
|
|
ply:Spawn()
|
|
end
|
|
end
|
|
|
|
function pl:ChangeScore(float, reset)
|
|
self:SetNWFloat('Score', self:GetNWFloat('Score')+float)
|
|
if reset then
|
|
self:SetNWFloat('Score', 0)
|
|
end
|
|
end
|
|
|
|
function pl:ResetParametrsCOD()
|
|
self:ChangeScore(0, true)
|
|
self:SetFrags(0)
|
|
self:SetDeaths(0)
|
|
self:SetNWFloat('KillsP', 0)
|
|
self:SetNWString('KillStreak_Other', '')
|
|
self:SetNWBool('KillStreak1_Used', false)
|
|
self:SetNWBool('KillStreak2_Used', false)
|
|
self:SetNWBool('KillStreak3_Used', false)
|
|
self:SetNWBool('KillStreak1_Gave', false)
|
|
self:SetNWBool('KillStreak2_Gave', false)
|
|
self:SetNWBool('KillStreak3_Gave', false)
|
|
COD:KillstreakAddOther(self, true, -1)
|
|
self:UnlockPerks(0)
|
|
local tab = self.KillstreakFuture
|
|
if tab then
|
|
self:SetNWFloat('KillStreak1', tab[1])
|
|
self:SetNWFloat('KillStreak2', tab[2])
|
|
self:SetNWFloat('KillStreak3', tab[3])
|
|
else
|
|
self:SelectKillstreaksRandom()
|
|
end
|
|
end
|
|
|
|
function pl:ThrowFrag()
|
|
if self.Knifing or self:GetNWFloat('FragGrenades') <= 0 then return end
|
|
|
|
local wep = self:Give('tdm_grenade')
|
|
local aw = self:GetActiveWeapon()
|
|
if IsValid(aw) then
|
|
self.FastKnifeBeforeWep = aw:GetClass()
|
|
else
|
|
self.FastKnifeBeforeWep = ""
|
|
end
|
|
|
|
self:SetNWFloat('FragGrenades', self:GetNWFloat('FragGrenades')-1)
|
|
|
|
self.Knifing = true
|
|
self:SetActiveWeapon(nil)
|
|
self:SelectWeapon(wep)
|
|
wep:Throw()
|
|
|
|
timer.Simple(1, function()
|
|
if !IsValid(self) then return end
|
|
self.Knifing = false
|
|
end)
|
|
end
|
|
|
|
function pl:ThrowFlash()
|
|
if self.Knifing or self:GetNWFloat('FlashGrenades') <= 0 then return end
|
|
|
|
local wep = self:Give('tdm_grenade')
|
|
wep.IsFlash = true
|
|
local aw = self:GetActiveWeapon()
|
|
if IsValid(aw) then
|
|
self.FastKnifeBeforeWep = aw:GetClass()
|
|
else
|
|
self.FastKnifeBeforeWep = ""
|
|
end
|
|
|
|
self:SetNWFloat('FlashGrenades', self:GetNWFloat('FlashGrenades')-1)
|
|
|
|
self.Knifing = true
|
|
self:SetActiveWeapon(nil)
|
|
self:SelectWeapon(wep)
|
|
wep:Throw()
|
|
|
|
timer.Simple(1, function()
|
|
if !IsValid(self) then return end
|
|
self.Knifing = false
|
|
end)
|
|
end
|
|
|
|
function pl:FastKnife()
|
|
if self.Knifing then return end
|
|
|
|
local wep = self:Give('tdm_knife')
|
|
local aw = self:GetActiveWeapon()
|
|
if IsValid(aw) then
|
|
self.FastKnifeBeforeWep = aw:GetClass()
|
|
else
|
|
self.FastKnifeBeforeWep = ""
|
|
end
|
|
|
|
self.Knifing = true
|
|
self:SetActiveWeapon(nil)
|
|
self:SelectWeapon(wep)
|
|
wep:Knifing()
|
|
|
|
timer.Simple(0.5, function()
|
|
if !IsValid(self) then return end
|
|
self.Knifing = false
|
|
end)
|
|
end
|
|
|
|
function pl:SetPrimaryWep(class)
|
|
if not class or class == "" then
|
|
local tab = {}
|
|
|
|
table.Merge(tab, COD.Loadout["SMGs"])
|
|
table.Merge(tab, COD.Loadout["LMGs"])
|
|
table.Merge(tab, COD.Loadout["Assault Rifles"])
|
|
table.Merge(tab, COD.Loadout["Sniper Rifles"])
|
|
table.Merge(tab, COD.Loadout["Marksman Rifles"])
|
|
table.Merge(tab, COD.Loadout["Shotguns"])
|
|
|
|
local tab2 = {}
|
|
for k, v in pairs(tab) do
|
|
table.insert(tab2, v.class)
|
|
end
|
|
|
|
class = tab2[math.random(1,#tab2)]
|
|
end
|
|
local wep = self:Give(class)
|
|
self:SetNWString('MainWep', class)
|
|
if IsValid(wep) then
|
|
self:GiveAmmo(wep:GetMaxClip1()*6, wep:GetPrimaryAmmoType(), true)
|
|
end
|
|
end
|
|
|
|
function pl:SetSecondaryWep(class)
|
|
if not class or class == "" then
|
|
local tab = {}
|
|
table.Merge(tab, COD.Loadout["Pistols"])
|
|
table.Merge(tab, COD.Loadout["Others"])
|
|
|
|
local tab2 = {}
|
|
for k, v in pairs(tab) do
|
|
table.insert(tab2, v.class)
|
|
end
|
|
|
|
class = tab2[math.random(1,#tab2)]
|
|
end
|
|
local wep = self:Give(class)
|
|
self:SetNWString('SecWep', class)
|
|
if IsValid(wep) then
|
|
self:GiveAmmo(wep:GetMaxClip1()*3, wep:GetPrimaryAmmoType(), true)
|
|
end
|
|
end
|
|
|
|
function pl:UnlockPerks(type)
|
|
if type == 1 then
|
|
self:SetNWFloat('Perk1', self:GetNWFloat('Perk1_Choose'))
|
|
if self:GetNWFloat('Perk1_Choose') == 3 and self:Alive() then
|
|
self:SetNWFloat('KillsP', self:GetNWFloat('KillsP')+1)
|
|
self:CheckKillstreaks()
|
|
end
|
|
elseif type == 2 then
|
|
self:SetNWFloat('Perk2', self:GetNWFloat('Perk2_Choose'))
|
|
else
|
|
self:SetNWFloat('Perk1', 0)
|
|
self:SetNWFloat('Perk2', 0)
|
|
end
|
|
net.Start("COD.PerksShow")
|
|
net.WriteFloat(type)
|
|
net.Send(self)
|
|
end
|
|
|
|
hook.Add("PlayerButtonDown", "TDMGUseAbilities", function(ply, but)
|
|
if ply:Alive() and not ply:IsTyping() and not ply.ControllingKillstreak then
|
|
if but == KEY_7 then
|
|
ply:UseKillstreak(1)
|
|
elseif but == KEY_8 then
|
|
ply:UseKillstreak(2)
|
|
elseif but == KEY_9 then
|
|
ply:UseKillstreak(3)
|
|
elseif but == KEY_0 then
|
|
ply:UseKillstreak(4)
|
|
elseif but == KEY_V then
|
|
ply:FastKnife()
|
|
elseif but == KEY_G then
|
|
ply:ThrowFrag()
|
|
elseif but == KEY_Q then
|
|
ply:ThrowFlash()
|
|
end
|
|
end
|
|
if but == KEY_F1 then
|
|
ply:ConCommand("open_choose_menu")
|
|
end
|
|
end)
|
|
|
|
hook.Add("PlayerInitialSpawn", "TDMPlayer", function(ply)
|
|
ply:SetNWString('TakedownAnim', '02')
|
|
ply:SetNWFloat('Perk1', 0)
|
|
ply:SetNWFloat('Perk2', 0)
|
|
ply:SetNWFloat('Perk1_Choose', 1)
|
|
ply:SetNWFloat('Perk2_Choose', 1)
|
|
COD:GetInfoData(ply)
|
|
ply.KillstreakOthers = {}
|
|
ply.Perk1Choosed = 1
|
|
ply.Perk2Choosed = 1
|
|
|
|
timer.Simple(1, function()
|
|
if not IsValid(ply) then return end
|
|
net.Start("COD.SendAdminStatus")
|
|
net.WriteBool(ply:IsAdmin())
|
|
net.Send(ply)
|
|
|
|
net.Start("COD.GameStartedStatus")
|
|
net.WriteBool(COD.GameStarted)
|
|
net.Send(ply)
|
|
end)
|
|
|
|
net.Receive("COD.RequestGameStatus", function(_, ply)
|
|
net.Start("COD.GameStartedStatus")
|
|
net.WriteBool(COD.GameStarted)
|
|
net.Send(ply)
|
|
end)
|
|
if COD.GameStarted then
|
|
timer.Simple(1, function()
|
|
if !IsValid(ply) then return end
|
|
if COD.DataTable["Gamemode"] != 4 then
|
|
local t1c = COD:CountTeamPlayers(1)
|
|
local t2c = COD:CountTeamPlayers(2)
|
|
if t1c == t2c then
|
|
ply:SetTeam(math.random(1,2))
|
|
elseif t1c > t2c then
|
|
ply:SetTeam(2)
|
|
elseif t1c < t2c then
|
|
ply:SetTeam(1)
|
|
end
|
|
else
|
|
ply:SetTeam(1)
|
|
end
|
|
ply:ResetParametrsCOD()
|
|
ply:Spawn()
|
|
end)
|
|
end
|
|
end)
|
|
|
|
hook.Add("SetupPlayerVisibility", "AddPlayersOnCameraTDM", function()
|
|
for _, plys in ipairs(player.GetAll()) do
|
|
AddOriginToPVS(plys:GetPos())
|
|
end
|
|
end)
|
|
|
|
hook.Add("PlayerDeathThink", "TDMPlayer", function(ply)
|
|
if not COD.GameStarted or COD.Ending or COD.DisableSpawn then
|
|
ply:Spectate(6)
|
|
end
|
|
if COD.GameStarted then
|
|
if ply:Team() != 1 and ply:Team() != 2 then
|
|
ply:Spectate(6)
|
|
end
|
|
if ply.DeathTime > CurTime() or ply.ControllingKillstreak then
|
|
return false
|
|
end
|
|
end
|
|
end)
|
|
|
|
hook.Add("PlayerSpawn", "TDMPlayerSpawn", function(ply)
|
|
if not COD.GameStarted or COD.DisableSpawn then
|
|
ply:KillSilent()
|
|
else
|
|
if ply:Team() != 1 and ply:Team() != 2 then
|
|
ply:KillSilent()
|
|
end
|
|
end
|
|
if ply:Team() == 1 then
|
|
ply:SetModel("models/tdmg/pm/specgru_milsim_"..math.random(1,4).."_1_pm.mdl")
|
|
ply:SetPos(table.Random(COD.DataTable["Team1_Spawns"]))
|
|
ply.VJ_NPC_Class = {"CLASS_SPECGRU"}
|
|
elseif ply:Team() == 2 then
|
|
ply:SetModel("models/tdmg/pm/kortac_1_"..math.random(1,4).."_pm.mdl")
|
|
ply:SetPos(table.Random(COD.DataTable["Team2_Spawns"]))
|
|
ply.VJ_NPC_Class = {"CLASS_KORTAC"}
|
|
end
|
|
ply.HeadBlow = false
|
|
if COD.EnabledDynamicSpawnPoints then
|
|
COD:SpawnPlayerAtSafePosition(ply)
|
|
end
|
|
ply:GodEnable()
|
|
timer.Simple(2, function()
|
|
if IsValid(ply) then
|
|
ply:GodDisable()
|
|
end
|
|
end)
|
|
ply:SetNWBool('Downed', false)
|
|
ply:SetupHands()
|
|
ply:SetWalkSpeed(160)
|
|
ply:SetRunSpeed(280)
|
|
ply:SetJumpPower(128)
|
|
ply:UnSpectate()
|
|
ply:SetNWFloat('KillsP', 0)
|
|
ply.DeathTime = 0
|
|
|
|
if COD.Perk1Unlocked then
|
|
ply:SetNWFloat('Perk1', ply.Perk1Choosed)
|
|
end
|
|
|
|
if COD.Perk2Unlocked then
|
|
ply:SetNWFloat('Perk2', ply.Perk2Choosed)
|
|
end
|
|
|
|
ply:SetNWFloat('Perk1_Choose', ply.Perk1Choosed)
|
|
ply:SetNWFloat('Perk2_Choose', ply.Perk2Choosed)
|
|
|
|
ply.CooldownPerkEquip = CurTime()+15
|
|
if ply:GetNWFloat('Perk1') == 3 then
|
|
ply:SetNWFloat('KillsP', 1)
|
|
end
|
|
ply:SetNoCollideWithTeammates(true)
|
|
local wdata = ply.WeaponData
|
|
if wdata and wdata[1] != "" then
|
|
ply:SetPrimaryWep(wdata[1])
|
|
else
|
|
ply:SetPrimaryWep()
|
|
end
|
|
if wdata and wdata[2] != "" then
|
|
ply:SetSecondaryWep(wdata[2])
|
|
else
|
|
ply:SetSecondaryWep()
|
|
end
|
|
ply:SetNWFloat('FragGrenades', 2)
|
|
ply:SetNWFloat('FlashGrenades', 2)
|
|
ply:SetNWBool('jugger', false)
|
|
ply:SetNWBool('KillStreak1_Used', false)
|
|
ply:SetNWBool('KillStreak2_Used', false)
|
|
ply:SetNWBool('KillStreak3_Used', false)
|
|
if ply:Alive() then
|
|
net.Start("COD.PerksShow")
|
|
net.Send(ply)
|
|
end
|
|
end)
|
|
|
|
function COD:GiveMessageCenter(plytab, type)
|
|
if istable(plytab) and #plytab > 0 or IsEntity(plytab) then
|
|
net.Start("COD.ScoreMarkEnemy")
|
|
net.WriteFloat(type)
|
|
net.Send(plytab)
|
|
end
|
|
end
|
|
|
|
hook.Add("InitPostEntity", "TDMLoadCommands", function()
|
|
RunConsoleCommand("sbox_playershurtplayers", 1)
|
|
RunConsoleCommand("mp_falldamage", 1)
|
|
end)
|
|
|
|
hook.Add("PlayerDeathSound", "TDMSilent", function()
|
|
return true
|
|
end)
|
|
|
|
hook.Add("PlayerDeath", "!TDMHook", function(ply, inf, att)
|
|
ply.DeathTime = CurTime()+3
|
|
local name = "default"
|
|
local att2 = att
|
|
if IsValid(inf) then
|
|
name = inf:GetClass()
|
|
if name == "env_explosion" or name == "tdm_ah64_rocket1" or name == "tdm_ah64_rocket2" then
|
|
if IsValid(inf:GetCreator()) then
|
|
att2 = inf:GetCreator()
|
|
end
|
|
name = "explosion"
|
|
end
|
|
if name == "tdm_knife" or name == "tdm_infection_knife" then
|
|
name = "knife"
|
|
end
|
|
if name == "player" then
|
|
if IsValid(att:GetActiveWeapon()) then
|
|
name = att:GetActiveWeapon():GetClass()
|
|
end
|
|
end
|
|
end
|
|
if ply.Takedowning and att.Takedowning then
|
|
name = "takedown"
|
|
end
|
|
net.Start("COD.Killfeed")
|
|
net.WriteTable({
|
|
attacker = att2,
|
|
inflictor = name,
|
|
target = ply,
|
|
})
|
|
net.Broadcast()
|
|
|
|
local rag = ply:GetRagdollEntity()
|
|
if IsValid(rag) then
|
|
rag:Remove()
|
|
|
|
local ent = ents.Create("tdm_deathanim")
|
|
ent:SetModel(ply:GetModel())
|
|
ent:SetPos(ply:GetPos())
|
|
ent:SetAngles(ply:GetAngles())
|
|
if !ply:OnGround() or ply:IsDowned() then
|
|
ent.Transform = ply
|
|
end
|
|
ent:Spawn()
|
|
end
|
|
if att:IsPlayer() and ply != att then
|
|
net.Start("COD.HitMarkEnemy")
|
|
net.WriteBool(true)
|
|
net.WriteBool(false)
|
|
net.Send(att)
|
|
att:SetNWFloat('KillsP', att:GetNWFloat('KillsP')+1)
|
|
|
|
net.Start("COD.KillNick")
|
|
net.WriteEntity(ply)
|
|
net.Send(att)
|
|
|
|
if att.Takedowning then
|
|
att:ChangeScore(150)
|
|
COD:GiveMessageCenter(att, 2)
|
|
elseif ply.HeadKill then
|
|
att:ChangeScore(110)
|
|
COD:GiveMessageCenter(att, 1)
|
|
elseif IsValid(inf) and inf:GetClass() == "tdm_knife" then
|
|
att:ChangeScore(125)
|
|
COD:GiveMessageCenter(att, 4)
|
|
else
|
|
att:ChangeScore(100)
|
|
COD:GiveMessageCenter(att, 0)
|
|
end
|
|
att:CheckKillstreaks()
|
|
end
|
|
if ply != att then
|
|
timer.Simple(1, function()
|
|
if !IsValid(ply) or !IsValid(att) then return end
|
|
COD:ShowKillCam(ply, att)
|
|
end)
|
|
end
|
|
if ply:Team() == 1 then
|
|
COD:AddFragsToData(2, 1)
|
|
elseif ply:Team() == 2 then
|
|
COD:AddFragsToData(1, 1)
|
|
end
|
|
ply:SetNWBool('jugger', false)
|
|
ply.AttackerPlayer = att
|
|
end)
|
|
|
|
hook.Add("EntityTakeDamage", "TDMHook", function(ply, dmg)
|
|
local att = dmg:GetAttacker()
|
|
|
|
if ply:IsPlayer() and ply:GetNWFloat('Perk1') == 1 and dmg:IsExplosionDamage() then
|
|
dmg:ScaleDamage(0.4)
|
|
end
|
|
if ply:IsPlayer() and dmg:IsBulletDamage() then
|
|
dmg:ScaleDamage(0.8)
|
|
end
|
|
|
|
if att:IsPlayer() and ply != att and ply:IsPlayer() then
|
|
if att:Team() == ply:Team() then return true end
|
|
net.Start("COD.HitMarkEnemy")
|
|
net.WriteBool(false)
|
|
net.WriteBool(false)
|
|
net.Send(att)
|
|
if ply:Armor() > 0 then
|
|
net.Start("COD.HitMarkEnemy2")
|
|
net.WriteBool(ply:Armor()<=dmg:GetDamage())
|
|
net.WriteBool(false)
|
|
net.Send(att)
|
|
end
|
|
end
|
|
|
|
if ply:IsPlayer() and dmg:GetDamage() >= ply:Health()+ply:Armor() and ply:GetNWFloat('Perk2') == 2 and not dmg:IsExplosionDamage() and not ply.AlreadyWasDowned and not ply.Takedowning then
|
|
dmg:ScaleDamage(0)
|
|
ply:Down()
|
|
|
|
if att:IsPlayer() then
|
|
net.Start("COD.HitMarkEnemy2")
|
|
net.WriteBool(false)
|
|
net.WriteBool(true)
|
|
net.Send(att)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
if att:IsPlayer() and (ply:IsNPC() or KillstreakTeamEntities[ply:GetClass()]) then
|
|
if ply.Team == att:Team() then
|
|
return true
|
|
else
|
|
net.Start("COD.HitMarkEnemy")
|
|
net.WriteBool(false)
|
|
net.WriteBool(false)
|
|
net.Send(att)
|
|
if dmg:GetDamage() >= ply:Health() and not ply.AlreadyHaveDeathMark then
|
|
if ply:IsNPC() or ply:GetClass() == "tdm_drone" or ply:GetClass() == "tdm_sentry" then
|
|
COD:GiveMessageCenter(att, 3)
|
|
att:ChangeScore(50)
|
|
else
|
|
COD:GiveMessageCenter(att, 6)
|
|
att:ChangeScore(250)
|
|
end
|
|
ply.AlreadyHaveDeathMark = true
|
|
end
|
|
end
|
|
end
|
|
if ply:IsPlayer() then
|
|
net.Start("COD.HitMarkEnemy")
|
|
net.WriteBool(false)
|
|
net.WriteBool(true)
|
|
net.Send(ply)
|
|
ply.HealCooldown = CurTime() + 8
|
|
if ply:GetNWFloat('Perk2') == 1 then
|
|
ply.HealCooldown = CurTime() + 3
|
|
end
|
|
if ply:Armor() > 0 then
|
|
local dmgs = dmg:GetDamage()
|
|
ply:SetArmor(math.max(ply:Armor()-dmgs, 0))
|
|
return true
|
|
end
|
|
end
|
|
if ply:IsPlayer() and att.Team == ply:Team() then return true end
|
|
end)
|
|
|
|
hook.Add("ScalePlayerDamage", "TDMHook", function(ply, hit, dmg)
|
|
if hit == HITGROUP_HEAD then
|
|
ply.HeadKill = true
|
|
timer.Create("HeadshotFalseTDM"..ply:EntIndex(), 0.01, 1, function()
|
|
if !IsValid(ply) then return end
|
|
ply.HeadKill = false
|
|
end)
|
|
end
|
|
end)
|
|
|
|
concommand.Add("cod_changegamemode", function(ply, cmd, args)
|
|
if ply:IsSuperAdmin() then
|
|
local arg1 = args[1]
|
|
if not arg1 then
|
|
arg1 = COD.DataTable["Gamemode"]
|
|
end
|
|
local num = math.floor(tonumber(arg1))
|
|
if num >= 1 and num <= 5 then
|
|
COD.DataTable["Gamemode"] = num
|
|
COD:GetInfoData("all")
|
|
COD:ChangeState(true)
|
|
end
|
|
end
|
|
end)
|
|
|
|
concommand.Add("cod_givekillstreak", function(ply, cmd, args)
|
|
if ply:IsSuperAdmin() then
|
|
if args[1] then
|
|
local num = math.floor(tonumber(args[1]))
|
|
if num >= 1 and num <= 22 then
|
|
COD:KillstreakAddOther(ply, false, num)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
local function CanSeeEnt(ent1, ent2)
|
|
local pos1 = ent1:GetPos()
|
|
local pos2 = ent2:GetPos()
|
|
local tr = util.TraceLine( {
|
|
start = pos1,
|
|
endpos = pos2,
|
|
filter = function(ent)
|
|
if ent:IsWorld() or string.match(ent:GetClass(), "prop_") then
|
|
return true
|
|
end
|
|
end,
|
|
})
|
|
local pos3 = pos2 - pos1
|
|
local diff = ent1:GetAimVector():Dot(pos3)
|
|
return !tr.Hit and diff > 0.2
|
|
end
|
|
|
|
timer.Simple(1, function()
|
|
if LeadBot then
|
|
local delay = CurTime()+2
|
|
hook.Add("Think", "BrainBotTDM", function()
|
|
if delay < CurTime() then
|
|
delay = CurTime()+2
|
|
for _, bot in ipairs(player.GetBots()) do
|
|
bot:UseKillstreak(math.random(1,3))
|
|
end
|
|
end
|
|
end)
|
|
|
|
hook.Add("PlayerSpawn", "BrainBotTDM2", function(ply)
|
|
if ply:IsBot() then
|
|
ply.Perk1Choosed = math.random(1,4)
|
|
ply.Perk2Choosed = math.random(1,4)
|
|
end
|
|
end)
|
|
|
|
function LeadBot.StartCommand(bot, cmd)
|
|
if COD.TimeBeforeEnd > CurTime()+COD.GamemodeSettings[COD.DataTable["Gamemode"]]["MaxTime"] then return end
|
|
|
|
local buttons = IN_SPEED
|
|
local botWeapon = bot:GetActiveWeapon()
|
|
local controller = bot.ControllerBot
|
|
local target = controller.Target
|
|
local val = IsValid(target)
|
|
|
|
if !IsValid(controller) then return end
|
|
|
|
if LeadBot.NoSprint or bot.DelaySprint and bot.DelaySprint > CurTime() then
|
|
buttons = 0
|
|
end
|
|
|
|
if val then
|
|
if bot.StopDelayTime < CurTime() then
|
|
bot.StopDelayTime = CurTime()+math.random(1,5)
|
|
bot.StopWalkingTarget = !bot.StopWalkingTarget
|
|
end
|
|
else
|
|
bot.StopDelayTime = CurTime()+math.random(1,3)
|
|
bot.StopWalkingTarget = false
|
|
end
|
|
|
|
if val and math.random(2) == 1 and not bot.ReadyToTakedown then
|
|
buttons = buttons + IN_ATTACK
|
|
bot.DelaySprint = CurTime()+math.Rand(2,8)
|
|
end
|
|
|
|
if IsValid(botWeapon) and (botWeapon:Clip1() == 0 or !val and botWeapon:Clip1() <= botWeapon:GetMaxClip1() / 2) then
|
|
timer.Simple(3, function()
|
|
if IsValid(botWeapon) and botWeapon:Clip1() == 0 then
|
|
botWeapon:SetClip1(botWeapon:GetMaxClip1())
|
|
end
|
|
end)
|
|
end
|
|
|
|
if bot:GetMoveType() == MOVETYPE_LADDER then
|
|
local pos = controller.goalPos
|
|
local ang = ((pos + bot:GetCurrentViewOffset()) - bot:GetShootPos()):Angle()
|
|
|
|
if pos.z > controller:GetPos().z then
|
|
controller.LookAt = Angle(-30, ang.y, 0)
|
|
else
|
|
controller.LookAt = Angle(30, ang.y, 0)
|
|
end
|
|
|
|
controller.LookAtTime = CurTime() + 0.1
|
|
controller.NextJump = -1
|
|
if not bot.StopWalkingTarget then
|
|
buttons = buttons + IN_FORWARD
|
|
end
|
|
end
|
|
|
|
if controller.NextDuck > CurTime() then
|
|
buttons = buttons + IN_DUCK
|
|
elseif controller.NextJump == 0 and not bot.Takedowning then
|
|
controller.NextJump = CurTime() + 1
|
|
buttons = buttons + IN_JUMP
|
|
end
|
|
|
|
if bot.Takedowning then
|
|
controller.NextJump = CurTime() + 1
|
|
end
|
|
|
|
if !bot:IsOnGround() and controller.NextJump > CurTime() then
|
|
buttons = buttons + IN_DUCK
|
|
end
|
|
|
|
if bot:IsDowned() then
|
|
if bot.ReviveTimeDelay < CurTime() then
|
|
buttons = IN_USE
|
|
end
|
|
else
|
|
bot.ReviveTimeDelay = CurTime()+math.Rand(0,15)
|
|
end
|
|
|
|
|
|
if val and not bot:IsDowned() and bot:IsAtBack(controller.Target) and bot:GetPos():DistToSqr(controller.Target:GetPos()) < 100000 then
|
|
bot.ReadyToTakedown = true
|
|
else
|
|
bot.ReadyToTakedown = false
|
|
end
|
|
|
|
if bot.ReadyToTakedown then
|
|
if bot:GetPos():DistToSqr(controller.Target:GetPos()) < 4000 then
|
|
bot:Takedown(controller.Target)
|
|
end
|
|
end
|
|
|
|
cmd:ClearButtons()
|
|
cmd:ClearMovement()
|
|
cmd:SetButtons(buttons)
|
|
end
|
|
|
|
function LeadBot.PlayerMove(bot, cmd, mv)
|
|
if COD.TimeBeforeEnd > CurTime()+COD.DataTable["MaxTime"] then return end
|
|
|
|
local controller = bot.ControllerBot
|
|
local botWeapon = bot:GetActiveWeapon()
|
|
local havemelee = false
|
|
if not bot.FlagDelay then
|
|
bot.FlagDelay = CurTime()+0.2
|
|
end
|
|
|
|
if IsValid(botWeapon) then
|
|
if botWeapon:GetMaxClip1() <= 0 then
|
|
havemelee = true
|
|
bot.StopWalkingTarget = false
|
|
bot.DelaySprint = 0
|
|
end
|
|
end
|
|
|
|
if COD.DataTable["Gamemode"] == 5 and !IsValid(controller.Target) and bot.FlagDelay < CurTime() then
|
|
bot.FlagDelay = CurTime()+0.2
|
|
local pos, mindist = nil, math.huge
|
|
for k, v in ipairs(ents.FindByClass("tdm_domination_flag")) do
|
|
local vpos = v:GetPos()
|
|
local vdist = vpos:DistToSqr(bot:GetPos())
|
|
if v:GetNWFloat('Team') != bot:Team() and vdist < mindist then
|
|
mindist = vdist
|
|
pos = vpos
|
|
end
|
|
end
|
|
if isvector(pos) then
|
|
controller.PosGen = pos
|
|
end
|
|
end
|
|
|
|
if !IsValid(controller) then
|
|
bot.ControllerBot = ents.Create("leadbot_navigator")
|
|
bot.ControllerBot:Spawn()
|
|
bot.ControllerBot:SetOwner(bot)
|
|
controller = bot.ControllerBot
|
|
end
|
|
|
|
if controller.PosGen and controller.P and controller.TPos ~= controller.PosGen then
|
|
controller.TPos = controller.PosGen
|
|
controller.P:Compute(controller, controller.PosGen)
|
|
end
|
|
|
|
mv:SetForwardSpeed(1200)
|
|
|
|
if controller:GetPos() ~= bot:GetPos() then
|
|
controller:SetPos(bot:GetPos())
|
|
end
|
|
|
|
if controller:GetAngles() ~= bot:EyeAngles() then
|
|
controller:SetAngles(bot:EyeAngles())
|
|
end
|
|
|
|
if (bot.NextSpawnTime and bot.NextSpawnTime + 1 > CurTime()) or !IsValid(controller.Target) or controller.ForgetTarget < CurTime() or controller.Target:Health() < 1 then
|
|
if IsValid(controller.Target) then
|
|
controller.PosGen = controller.Target:GetPos()
|
|
controller.LastSegmented = CurTime() + 30
|
|
end
|
|
controller.Target = nil
|
|
end
|
|
if !IsValid(controller.Target) then
|
|
for _, ply in ipairs(ents.GetAll()) do
|
|
if ply ~= bot and ((ply:IsPlayer() and (!LeadBot.TeamPlay or (LeadBot.TeamPlay and (ply:Team() ~= bot:Team()))))) and ply:GetPos():DistToSqr(bot:GetPos()) < 2250000 then
|
|
if ply:Alive() and not ply:IsDowned() and CanSeeEnt(bot, ply) then
|
|
controller.Target = ply
|
|
controller.ForgetTarget = CurTime() + 2
|
|
end
|
|
if ply:Alive() and ply:IsDowned() and not ply.Takedowning and ply:GetPos():DistToSqr(bot:GetPos()) < 250000 and bot:IsAtBack(ply) then
|
|
controller.Target = ply
|
|
controller.ForgetTarget = CurTime() + 1
|
|
end
|
|
end
|
|
if ply ~= bot and ( ply:IsNPC() and ply.Team and ply.Team != bot:Team() or KillstreakTeamEntities[ply:GetClass()] and ply.Team != bot:Team() ) and CanSeeEnt(bot, ply) then
|
|
controller.Target = ply
|
|
controller.ForgetTarget = CurTime() + 2
|
|
end
|
|
end
|
|
elseif controller.ForgetTarget < CurTime() and CanSeeEnt(bot, controller.Target) then
|
|
controller.ForgetTarget = CurTime() + 2
|
|
end
|
|
|
|
local dt = util.QuickTrace(bot:EyePos(), bot:GetForward() * 45, bot)
|
|
|
|
if IsValid(dt.Entity) and dt.Entity:GetClass() == "prop_door_rotating" then
|
|
dt.Entity:Fire("OpenAwayFrom", bot, 0)
|
|
end
|
|
|
|
if !IsValid(controller.Target) and (!controller.PosGen or bot:GetPos():DistToSqr(controller.PosGen) < 32 or controller.LastSegmented < CurTime()) then
|
|
controller.PosGen = controller:FindSpot("random", {radius = 12500})
|
|
controller.LastSegmented = CurTime() + 10
|
|
elseif IsValid(controller.Target) then
|
|
local distance = controller.Target:GetPos():DistToSqr(bot:GetPos())
|
|
controller.PosGen = controller.Target:GetPos()
|
|
|
|
if distance <= 90000 and not bot.ReadyToTakedown and not havemelee then
|
|
mv:SetForwardSpeed(-1200)
|
|
end
|
|
end
|
|
|
|
if !controller.P then
|
|
return
|
|
end
|
|
|
|
local segments = controller.P:GetAllSegments()
|
|
|
|
if !segments then return end
|
|
|
|
local cur_segment = controller.cur_segment
|
|
local curgoal = segments[cur_segment]
|
|
|
|
if !curgoal then
|
|
mv:SetForwardSpeed(0)
|
|
return
|
|
end
|
|
|
|
if segments[cur_segment + 1] and Vector(bot:GetPos().x, bot:GetPos().y, 0):DistToSqr(Vector(curgoal.pos.x, curgoal.pos.y)) < 100 then
|
|
controller.cur_segment = controller.cur_segment + 1
|
|
curgoal = segments[controller.cur_segment]
|
|
end
|
|
|
|
local goalpos = curgoal.pos
|
|
|
|
if bot:GetVelocity():Length2DSqr() <= 225 then
|
|
if controller.NextCenter < CurTime() then
|
|
controller.strafeAngle = ((controller.strafeAngle == 1 and 2) or 1)
|
|
controller.NextCenter = CurTime() + math.Rand(0.3, 0.65)
|
|
elseif controller.nextStuckJump < CurTime() then
|
|
if !bot:Crouching() then
|
|
controller.NextJump = 0
|
|
end
|
|
controller.nextStuckJump = CurTime() + math.Rand(1, 2)
|
|
end
|
|
end
|
|
|
|
if controller.NextCenter > CurTime() and not bot.StopWalkingTarget then
|
|
if controller.strafeAngle == 1 then
|
|
mv:SetSideSpeed(1500)
|
|
elseif controller.strafeAngle == 2 then
|
|
mv:SetSideSpeed(-1500)
|
|
else
|
|
mv:SetForwardSpeed(-1500)
|
|
end
|
|
end
|
|
|
|
if controller.NextJump ~= 0 and curgoal.type > 1 and controller.NextJump < CurTime() then
|
|
controller.NextJump = 0
|
|
end
|
|
|
|
if curgoal.area:GetAttributes() == NAV_MESH_CROUCH then
|
|
controller.NextDuck = CurTime() + 0.1
|
|
end
|
|
|
|
controller.goalPos = goalpos
|
|
|
|
if GetConVar("developer"):GetBool() then
|
|
controller.P:Draw()
|
|
end
|
|
|
|
local lerp = FrameTime() * math.random(8, 10)
|
|
local lerpc = FrameTime() * 8
|
|
|
|
if !LeadBot.LerpAim then
|
|
lerp = 1
|
|
lerpc = 1
|
|
end
|
|
|
|
local mva = ((goalpos + bot:GetCurrentViewOffset()) - bot:GetShootPos()):Angle()
|
|
|
|
mv:SetMoveAngles(mva)
|
|
|
|
if IsValid(controller.Target) then
|
|
if not bot.Takedowning then
|
|
bot:SetEyeAngles(LerpAngle(lerp, bot:EyeAngles(), (controller.Target:EyePos() - bot:GetShootPos()):Angle()))
|
|
end
|
|
return
|
|
else
|
|
if not bot.Takedowning then
|
|
if controller.LookAtTime > CurTime() then
|
|
local ang = LerpAngle(lerpc, bot:EyeAngles(), controller.LookAt)
|
|
bot:SetEyeAngles(Angle(ang.p, ang.y, 0))
|
|
else
|
|
local ang = LerpAngle(lerpc, bot:EyeAngles(), mva)
|
|
bot:SetEyeAngles(Angle(ang.p, ang.y, 0))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end) |