Need Help with this error. Please help!

So on my TTT Server which has custom weaponry, and multiple Traitor weapons and Detective weapons, the console gets spammed with this lua error

I have no idea how to fix this and it would be nice to fix so my players don’t get spammed. This is the code.



include("weaponry_shd.lua") -- inits WEPS tbl
-- Pool all SWEP classnames, as we will be sending some over the wire regularly
for k, w in pairs(weapons.GetList()) do
   if w then
      umsg.PoolString(WEPS.GetClass(w))
   end
end
---- Weapon system, pickup limits, etc
local IsEquipment = WEPS.IsEquipment
-- Prevent players from picking up multiple weapons of the same type etc
function GM:PlayerCanPickupWeapon(ply, wep)
   if not IsValid(wep) and not IsValid(ply) then return end
   -- Disallow picking up for ammo
   if ply:HasWeapon(wep:GetClass()) then
      return false
   elseif not ply:CanCarryWeapon(wep) then
      return false
   elseif IsEquipment(wep) and wep.IsDropped and (not ply:KeyDown(IN_USE)) then
      return false
   end
   local tr = util.TraceEntity({start=wep:GetPos(), endpos=ply:GetShootPos(), mask=MASK_SOLID}, wep)
   if tr.Fraction == 1.0 or tr.Entity == ply then
      wep:SetPos(ply:GetShootPos())
   end
   return true
end
-- Cache role -> default-weapons table
local loadout_weapons = nil
local function GetLoadoutWeapons(r)
   if not loadout_weapons then
      local tbl = {
         [ROLE_INNOCENT] = {},
         [ROLE_TRAITOR]  = {},
         [ROLE_DETECTIVE]= {}
      };
      for k, w in pairs(weapons.GetList()) do
         if w and type(w.InLoadoutFor) == "table" then
            for _, wrole in pairs(w.InLoadoutFor) do
               table.insert(tbl[wrole], WEPS.GetClass(w))
            end
         end
      end
      loadout_weapons = tbl
   end
   return loadout_weapons[r]
end
-- Give player loadout weapons he should have for his role that he does not have
-- yet
local function GiveLoadoutWeapons(ply)
   local r = GetRoundState() == ROUND_PREP and ROLE_INNOCENT or ply:GetRole()
   local weps = GetLoadoutWeapons(r)
   if not weps then return end
   for _, cls in pairs(weps) do
      if not ply:HasWeapon(cls) then
         ply:Give(cls)
      end
   end
end
local function HasLoadoutWeapons(ply)
   if ply:IsSpec() then return true end
   local r = GetRoundState() == ROUND_PREP and ROLE_INNOCENT or ply:GetRole()
   local weps = GetLoadoutWeapons(r)
   if not weps then return true end

   for _, cls in pairs(weps) do
      if not ply:HasWeapon(cls) then
         return false
      end
   end
   return true
end
-- Give loadout items.
local function GiveLoadoutItems(ply)
   local items = EquipmentItems[ply:GetRole()]
   if items then
      for _, item in pairs(items) do
         if item.loadout and item.id then
            ply:GiveEquipmentItem(item.id)
         end
      end
   end
end
-- Quick hack to limit hats to models that fit them well
local Hattables = { "phoenix.mdl", "arctic.mdl", "Group01", "monk.mdl" }
local function CanWearHat(ply)
   local path = string.Explode("/", ply:GetModel())
   if #path == 1 then path = string.Explode("\\", path) end
   return table.HasValue(Hattables, path[3])
end
CreateConVar("ttt_detective_hats", "0")
-- Just hats right now
local function GiveLoadoutSpecial(ply)
   if ply:IsDetective() and GetConVar("ttt_detective_hats"):GetBool() and CanWearHat(ply) then
      if not IsValid(ply.hat) then
         local hat = ents.Create("ttt_hat_deerstalker")
         if not IsValid(hat) then return end
         hat:SetPos(ply:GetPos() + Vector(0,0,70))
         hat:SetAngles(ply:GetAngles())
         hat:SetParent(ply)
         ply.hat = hat
         hat:Spawn()
      end
   else
      SafeRemoveEntity(ply.hat)
      ply.hat = nil
   end
end
-- Sometimes, in cramped map locations, giving players weapons fails. A timer
-- calling this function is used to get them the weapons anyway as soon as
-- possible.
local function LateLoadout(id)
   local ply = player.GetByID(id)
   if not IsValid(ply) then
      timer.Destroy("lateloadout" .. id)
      return
   end
   if not HasLoadoutWeapons(ply) then
      GiveLoadoutWeapons(ply)
      if HasLoadoutWeapons(ply) then
         timer.Destroy("lateloadout" .. id)
      end
   end
end
-- Note that this is called both when a player spawns and when a round starts
function GM:PlayerLoadout( ply )
   if IsValid(ply) and (not ply:IsSpec()) then
      -- clear out equipment flags
      ply:ResetEquipment()
      -- give default items
      GiveLoadoutItems(ply)
      -- hand out weaponry
      GiveLoadoutWeapons(ply)
      GiveLoadoutSpecial(ply)
      if not HasLoadoutWeapons(ply) then
         timer.Create("lateloadout" .. ply:EntIndex(), 1, 0,
                      function() LateLoadout(ply:EntIndex()) end)
      end
   end
end
function GM:UpdatePlayerLoadouts()
   for k, v in pairs(player.GetAll()) do
      GAMEMODE:PlayerLoadout(v)
   end
end
---- Weapon switching
local function ForceWeaponSwitch(ply, cmd, args)
   -- Turns out even SelectWeapon refuses to switch to empty guns, gah.
   -- Worked around it by giving every weapon a single Clip2 round.
   -- Works because no weapon uses those.
   local wepname = args[1]
   local wep = ply:GetWeapon(wepname)
   if IsValid(wep) then
      -- Weapons apparently not guaranteed to have this
      if wep.SetClip2 then
         wep:SetClip2(1)
      end
      ply:SelectWeapon(wepname)
   end
end
concommand.Add("wepswitch", ForceWeaponSwitch)
---- Weapon dropping
function WEPS.DropNotifiedWeapon(ply, wep, death_drop)
   if IsValid(ply) and IsValid(wep) then
      -- Hack to tell the weapon it's about to be dropped and should do what it
      -- must right now
      if wep.PreDrop then
         wep:PreDrop(death_drop)
      end
      -- PreDrop might destroy weapon
      if not IsValid(wep) then return end
  
      -- Tag this weapon as dropped, so that if it's a special weapon we do not
      -- auto-pickup when nearby.
      wep.IsDropped = true
      ply:DropWeapon(wep)
      wep:PhysWake()
   
   if HasLoadoutWeapons(ply) then timer.Destroy("lateloadout" .. id) end
      -- After dropping a weapon, always switch to holstered, so that traitors
      -- will never accidentally pull out a traitor weapon
      ply:SelectWeapon("weapon_ttt_unarmed")
   end
end
local function DropActiveWeapon(ply)
   if not IsValid(ply) then return end
   local wep = ply:GetActiveWeapon()
   local max = 0
   if not IsValid(wep) then return end
   if wep.AllowDrop == false then
      return
   end
   if wep.DropOnce == true then
 if ( player.NextInvite and player.NextInvite > CurTime() ) then
  ply:PrintMessage( HUD_PRINTTALK, "Can't Drop This Right Now." )
  return
 else
  player.NextInvite = CurTime() + 120;
    end
   end
 
   local tr = util.QuickTrace(ply:GetShootPos(), ply:GetAimVector() * 32, ply)
   if tr.HitWorld then
      LANG.Msg(ply, "drop_no_room")
      return
   end
   ply:AnimPerformGesture(ACT_ITEM_PLACE)
   WEPS.DropNotifiedWeapon(ply,wep)
end
concommand.Add("ttt_dropweapon", DropActiveWeapon)
local function DropActiveAmmo(ply)
   if not IsValid(ply) then return end
   local wep = ply:GetActiveWeapon()
   if not IsValid(wep) then return end
   if not wep.AmmoEnt then return end
   local amt = wep:Clip1()
   if amt < 1 or amt <= (wep.Primary.ClipSize * 0.25) then
      LANG.Msg(ply, "drop_no_ammo")
      return
   end
   local pos, ang = ply:GetShootPos(), ply:EyeAngles()
   local dir = (ang:Forward() * 32) + (ang:Right() * 6) + (ang:Up() * -5)
   local tr = util.QuickTrace(pos, dir, ply)
   if tr.HitWorld then return end
   wep:SetClip1(0)
   ply:AnimPerformGesture(ACT_ITEM_GIVE)
   local box = ents.Create(wep.AmmoEnt)
   if not IsValid(box) then box:Remove() end
   box:SetPos(pos + dir)
   box:SetOwner(ply)
   box:Spawn()
   box:PhysWake()
   local phys = box:GetPhysicsObject()
   if IsValid(phys) then
      phys:ApplyForceCenter(ang:Forward() * 1000)
      phys:ApplyForceOffset(VectorRand(), vector_origin)
   end
   box.AmmoAmount = amt
   timer.Simple(2, function()
                      if IsValid(box) then
                         box:SetOwner(nil)
                      end
                   end)
end
concommand.Add("ttt_dropammo", DropActiveAmmo)

-- Give a weapon to a player. If the initial attempt fails due to heisenbugs in
-- the map, keep trying until the player has moved to a better spot where it
-- does work.
local function GiveEquipmentWeapon(uid, cls)
   -- Referring to players by UID because a player may disconnect while his
   -- unique timer still runs, in which case we want to be able to stop it. For
   -- that we need its name, and hence his uid.
   local ply = player.GetByUniqueID(uid)
   local tmr = "give_equipment" .. tostring(uid)
   if (not IsValid(ply)) or (not ply:IsActiveSpecial()) then
      timer.Destroy(tmr)
      return
   end
   -- giving attempt, will fail if we're in a crazy spot in the map or perhaps
   -- other glitchy cases
   local w = ply:Give(cls)
   if (not IsValid(w)) or (not ply:HasWeapon(cls)) then
      if not timer.Exists(tmr) then
         timer.Create(tmr, 1, 0, function() GiveEquipmentWeapon(uid, cls) end)
      end
      -- we will be retrying
   else
      -- can stop retrying, if we were
      timer.Destroy(tmr)
      if w.WasBought then
         -- some weapons give extra ammo after being bought, etc
         w:WasBought(ply)
      end
   end
end
local function HasPendingOrder(ply)
   return timer.Exists("give_equipment" .. tostring(ply:UniqueID()))
end
-- Equipment buying
local function OrderEquipment(ply, cmd, args)
   if not IsValid(ply) or #args != 1 then return end
   if not (ply:IsActiveTraitor() or ply:IsActiveDetective()) then return end
   -- no credits, can't happen when buying through menu as button will be off
   if ply:GetCredits() < 1 then return end
   -- it's an item if the arg is an id instead of an ent name
   local id = args[1]
   local is_item = tonumber(id)
   -- we use weapons.GetStored to save time on an unnecessary copy, we will not
   -- be modifying it
   local swep_table = (not is_item) and weapons.GetStored(id) or nil
   -- some weapons can only be bought once per player per round, this used to be
   -- defined in a table here, but is now in the SWEP's table
   if swep_table and swep_table.LimitedStock and ply:HasBought(id) then
      LANG.Msg(ply, "buy_no_stock")
      return
   end
   
   if swep_table and swep_table.VIP and not ply:IsVIP() then
   CustomMsg(ply, "You need Diamond VIP to get this!", Color(50, 150, 255, 255))
      return
   end
   local received = false
   if is_item then
      id = tonumber(id)
      -- item whitelist check
      local allowed = GetEquipmentItem(ply:GetRole(), id)
      if not allowed then
         print(ply, "tried to buy item not buyable for his class:", id)
         return
      end
      -- ownership check and finalise
      if id and EQUIP_NONE < id then
         if not ply:HasEquipmentItem(id) then
            ply:GiveEquipmentItem(id)
            received = true
         end
      end
   elseif swep_table then
      -- weapon whitelist check
      if not table.HasValue(swep_table.CanBuy, ply:GetRole()) then
         print(ply, "tried to buy weapon his role is not permitted to buy")
         return
      end
      -- if we have a pending order because we are in a confined space, don't
      -- start a new one
      if HasPendingOrder(ply) then
         LANG.Msg(ply, "buy_pending")
         return
      end
      -- no longer restricted to only WEAPON_EQUIP weapons, just anything that
      -- is whitelisted and carryable
      if ply:CanCarryWeapon(swep_table) then
         GiveEquipmentWeapon(ply:UniqueID(), id)
         received = true
      end
   end
   if received then
      ply:SubtractCredits(1)
      LANG.Msg(ply, "buy_received")
      ply:AddBought(id)
      timer.Simple(0.5,
                   function()
                      if not IsValid(ply) then return end
                      umsg.Start("bought_item", ply)
                      umsg.Bool(is_item)
                      if is_item then
                         umsg.Short(id)
                      else
                         umsg.String(id)
                      end
                      umsg.End()
                   end)
   end
end
concommand.Add("ttt_order_equipment", OrderEquipment)

local function SetDisguise(ply, cmd, args)
   if not IsValid(ply) or not ply:IsActiveTraitor() then return end
   if ply:HasEquipmentItem(EQUIP_DISGUISE) then
      local state = #args == 1 and tobool(args[1])
      ply:SetNWBool("disguised", state)
      LANG.Msg(ply, state and "disg_turned_on" or "disg_turned_off")
   end
end
concommand.Add("ttt_set_disguise", SetDisguise)
local function CheatCredits(ply)
   if cvars.Bool("sv_cheats", false) and IsValid(ply) then
      ply:AddCredits(10)
   end
end
concommand.Add("ttt_cheat_credits", CheatCredits)
local function TransferCredits(ply, cmd, args)
   if (not IsValid(ply)) or (not ply:IsActiveSpecial()) then return end
   if #args != 2 then return end
   local uid = tostring(args[1])
   local credits = tonumber(args[2])
   if uid and credits then
      local target = player.GetByUniqueID(uid)
      if (not IsValid(target)) or (not target:IsActiveSpecial()) or (target == ply) then
         LANG.Msg(ply, "xfer_no_recip")
         return
      end
      if ply:GetCredits() < credits then
         LANG.Msg(ply, "xfer_no_credits")
         return
      end
      credits = math.Clamp(credits, 0, ply:GetCredits())
      if credits == 0 then return end
      ply:SubtractCredits(credits)
      target:AddCredits(credits)
      LANG.Msg(ply, "xfer_success", {player=target:Nick()})
      LANG.Msg(target, "xfer_received", {player = ply:Nick(), num = credits})
   end
end
concommand.Add("ttt_transfer_credits", TransferCredits)
-- Protect against non-TTT weapons that may break the HUD
function GM:WeaponEquip(wep)
   if IsValid(wep) then
      -- only remove if they lack critical stuff
      if not wep.Kind then
         wep:Remove()
         ErrorNoHalt("Equipped weapon " .. wep:GetClass() .. " is not compatible with TTT
")
      end
   end
end

function WEPS.HasCustomEquipment()
   -- first look at SWEPs
   for _, wep in pairs(weapons.GetList()) do
      if wep and wep.Kind then
         local roles = nil
         if IsEquipment(wep) then
            -- this will be nil if weapon is disabled
            roles = wep.CanBuy
         else
            -- normal weapons not only buyable by a specific role, can be
            -- map-placed or spawned from a random weapon
            roles = { ROLE_NONE }
         end
         if roles then
            for _, role in pairs(roles) do
               if not table.HasValue(DefaultEquipment[role], WEPS.GetClass(wep)) then
                  return true
               end
            end
         end
      end
   end
   -- then at items
   for role, items in pairs(EquipmentItems) do
      local deq = DefaultEquipment[role]
      for _, item in pairs(items) do
         if item and item.id then
            if not table.HasValue(deq, item.id) then
               return true
            end
         end
      end
   end
   return false
end
-- non-cheat developer commands can reveal precaching the first time equipment
-- is bought, so trigger it at the start of a round instead
function WEPS.ForcePrecache()
   for k, w in pairs(weapons.GetList()) do
      if w and w.WorldModel then
         util.PrecacheModel(w.WorldModel)
      end
      if w and w.ViewModel then
         util.PrecacheModel(w.ViewModel)
      end
   end
end



Many thanks if you can help :smiley:

Here is that line for anyone too lazy to look it up.



local pos, ang = ply:GetShootPos(), ply:EyeAngles()


I’m not sure what the problem is but you could try:



local (pos, ang) = ply:GetShootPos(), ply:EyeAngles()


Looking at the code it seems the actual error is occuring on line 333 when it calls GiveEquipmentWeapon(ply:UniqueID(), id)

Try replacing id in that to tonumber(id)

That’s not line 221…

If the above post is the case then are you just running the command without arguments? id is being set to args[1] on line 286 and used in 333. It’d throw an error if there were no args.

You haven’t pasted the whole thing so line 221 in what you have pasted doesn’t match with your error message. However the message mentions ‘DropNotifiedWeapon’

This function [lua]function WEPS.DropNotifiedWeapon(ply, wep, death_drop)
if IsValid(ply) and IsValid(wep) then
– Hack to tell the weapon it’s about to be dropped and should do what it
– must right now
if wep.PreDrop then
wep:PreDrop(death_drop)
end
– PreDrop might destroy weapon
if not IsValid(wep) then return end

  -- Tag this weapon as dropped, so that if it's a special weapon we do not
  -- auto-pickup when nearby.
  wep.IsDropped = true
  ply:DropWeapon(wep)
  wep:PhysWake()

if HasLoadoutWeapons(ply) then timer.Destroy(“lateloadout” … id) end
– After dropping a weapon, always switch to holstered, so that traitors
– will never accidentally pull out a traitor weapon
ply:SelectWeapon(“weapon_ttt_unarmed”)
end
end[/lua]

This line [lua]if HasLoadoutWeapons(ply) then timer.Destroy(“lateloadout” … id) end[/lua]

It is using the variable ‘id’, but id is not set anywhere in that function code.
I suspect you could add [lua]local id = ply:EntIndex()[/lua] before that line to fix it.

This worked! Thank you kind sir!