Need a little help with understanding and error

I tried updating the entire gamemode folder and everything but not matter what I get

[ERROR] gamemodes/terrortown/gamemode/cl_tbuttons.lua:97: attempt to call method ‘GetUsableRange’ (a nil value)

  1. Draw - gamemodes/terrortown/gamemode/cl_tbuttons.lua:97
  2. unknown - gamemodes/terrortown/gamemode/cl_hud.lua:528

spammed in console and T buttons don’t work. Any ideas on how to fix it?

Replace your files with these:

cl_tbuttons


--- Display of and interaction with ttt_traitor_button
local surface = surface
local pairs = pairs
local math = math
local abs = math.abs

TBHUD = {}
TBHUD.buttons = {}
TBHUD.buttons_count = 0

TBHUD.focus_ent = nil
TBHUD.focus_stick = 0

function TBHUD:Clear()
   self.buttons = {}
   self.buttons_count = 0

   self.focus_ent = nil
   self.focus_stick = 0
end

function TBHUD:CacheEnts()
   if IsValid(LocalPlayer()) and LocalPlayer():IsActiveTraitor() then
      self.buttons = {}
      for _, ent in pairs(ents.FindByClass("ttt_traitor_button")) do
         if IsValid(ent) then
            self.buttons[ent:EntIndex()] = ent
         end
      end
   else
      self.buttons = {}
   end

   self.buttons_count = table.Count(self.buttons)
end

function TBHUD:PlayerIsFocused()
   return IsValid(LocalPlayer()) and LocalPlayer():IsActiveTraitor() and IsValid(self.focus_ent)
end

function TBHUD:UseFocused()
   if IsValid(self.focus_ent) and self.focus_stick >= CurTime() then
      RunConsoleCommand("ttt_use_tbutton", tostring(self.focus_ent:EntIndex()))

      self.focus_ent = nil
      return true
   else
      return false
   end
end

local confirm_sound = Sound("buttons/button24.wav")
function TBHUD.ReceiveUseConfirm(um)
   surface.PlaySound(confirm_sound)

   TBHUD:CacheEnts()
end
usermessage.Hook("ttt_confirm_use_tbutton", TBHUD.ReceiveUseConfirm)

local function ComputeRangeFactor(plypos, tgtpos)
   local d = tgtpos - plypos
   d = d:DotProduct(d)
   return d / range
end

local tbut_normal = surface.GetTextureID("VGUI/ttt/tbut_hand_line")
local tbut_focus = surface.GetTextureID("VGUI/ttt/tbut_hand_filled")
local size = 32
local mid  = size / 2
local focus_range = 25

local use_key = Key("+use", "USE")

local GetTranslation = LANG.GetTranslation
local GetPTranslation = LANG.GetParamTranslation
function TBHUD:Draw(client)
   if self.buttons_count != 0 then
      surface.SetTexture(tbut_normal)

      -- we're doing slowish distance computation here, so lots of probably
      -- ineffective micro-optimization
      local plypos = client:GetPos()
      local midscreen_x = ScrW() / 2
      local midscreen_y = ScrH() / 2
      local pos, scrpos, d
      local focus_ent = nil
      local focus_d, focus_scrpos_x, focus_scrpos_y = 0, midscreen_x, midscreen_y

      -- draw icon on HUD for every button within range
      for k, but in pairs(self.buttons) do
         if IsValid(but) and but.IsUsable then
            pos = but:GetPos()
            scrpos = pos:ToScreen()

            if (not IsOffScreen(scrpos)) and but:IsUsable() then
               d = pos - plypos
               d = d:DotProduct(d) / (but:GetUsableRange() ^ 2)
               -- draw if this button is within range, with alpha based on distance
               if d < 1 then
                  surface.SetDrawColor(255, 255, 255, 200 * (1 - d))
                  surface.DrawTexturedRect(scrpos.x - mid, scrpos.y - mid, size, size)

                  if d > focus_d then
                     local x = abs(scrpos.x - midscreen_x)
                     local y = abs(scrpos.y - midscreen_y)
                     if (x < focus_range and y < focus_range and
                         x < focus_scrpos_x and y < focus_scrpos_y) then

                        -- avoid constantly switching focus every frame causing
                        -- 2+ buttons to appear in focus, instead "stick" to one
                        -- ent for a very short time to ensure consistency
                        if self.focus_stick < CurTime() or but == self.focus_ent then
                           focus_ent = but
                        end
                     end
                  end
               end
            end
         end

         -- draw extra graphics and information for button when it's in-focus
         if IsValid(focus_ent) then
            self.focus_ent = focus_ent
            self.focus_stick = CurTime() + 0.1

            local scrpos = focus_ent:GetPos():ToScreen()

            local sz = 16

            -- redraw in-focus version of icon
            surface.SetTexture(tbut_focus)
            surface.SetDrawColor(255, 255, 255, 200)
            surface.DrawTexturedRect(scrpos.x - mid, scrpos.y - mid, size, size)

            -- description
            surface.SetTextColor(255, 50, 50, 255)
            surface.SetFont("TabLarge")

            local x = scrpos.x + sz + 10
            local y = scrpos.y - sz - 3
            surface.SetTextPos(x, y)
            surface.DrawText(focus_ent:GetDescription())

            y = y + 12
            surface.SetTextPos(x, y)
            if focus_ent:GetDelay() < 0 then
               surface.DrawText(GetTranslation("tbut_single"))
            elseif focus_ent:GetDelay() == 0 then
               surface.DrawText(GetTranslation("tbut_reuse"))
            else
               surface.DrawText(GetPTranslation("tbut_retime", {num = focus_ent:GetDelay()}))
            end

            y = y + 12
            surface.SetTextPos(x, y)
            surface.DrawText(GetPTranslation("tbut_help", {key = use_key}))
         end
      end
   end
end


cl_hud


-- HUD HUD HUD

local table = table
local surface = surface
local draw = draw
local math = math
local string = string

local GetTranslation = LANG.GetTranslation
local GetPTranslation = LANG.GetParamTranslation
local GetLang = LANG.GetUnsafeLanguageTable
local interp = string.Interp

-- Fonts
surface.CreateFont("TraitorState", {font = "Trebuchet24",
                                    size = 28,
                                    weight = 1000})
surface.CreateFont("TimeLeft",     {font = "Trebuchet24",
                                    size = 24,
                                    weight = 800})
surface.CreateFont("HealthAmmo",   {font = "Trebuchet24",
                                    size = 24,
                                    weight = 750})
-- Color presets
local bg_colors = {
   background_main = Color(0, 0, 10, 200),

   noround = Color(100,100,100,200),
   traitor = Color(200, 25, 25, 200),
   innocent = Color(25, 200, 25, 200),
   detective = Color(25, 25, 200, 200)
};

local health_colors = {
   border = COLOR_WHITE,
   background = Color(100, 25, 25, 222),
   fill = Color(200, 50, 50, 250)
};

local ammo_colors = {
   border = COLOR_WHITE,
   background = Color(20, 20, 5, 222),
   fill = Color(205, 155, 0, 255)
};


-- Modified RoundedBox
local Tex_Corner8 = surface.GetTextureID( "gui/corner8" )
local function RoundedMeter( bs, x, y, w, h, color)
   surface.SetDrawColor(clr(color))

   surface.DrawRect( x+bs, y, w-bs*2, h )
   surface.DrawRect( x, y+bs, bs, h-bs*2 )

   surface.SetTexture( Tex_Corner8 )
   surface.DrawTexturedRectRotated( x + bs/2 , y + bs/2, bs, bs, 0 )
   surface.DrawTexturedRectRotated( x + bs/2 , y + h -bs/2, bs, bs, 90 )

   if w > 14 then
      surface.DrawRect( x+w-bs, y+bs, bs, h-bs*2 )
      surface.DrawTexturedRectRotated( x + w - bs/2 , y + bs/2, bs, bs, 270 )
      surface.DrawTexturedRectRotated( x + w - bs/2 , y + h - bs/2, bs, bs, 180 )
   else
      surface.DrawRect( x + math.max(w-bs, bs), y, bs/2, h )
   end

end

---- The bar painting is loosely based on:
---- http://wiki.garrysmod.com/?title=Creating_a_HUD

-- Paints a graphical meter bar
local function PaintBar(x, y, w, h, colors, value)
   -- Background
   -- slightly enlarged to make a subtle border
   draw.RoundedBox(8, x-1, y-1, w+2, h+2, colors.background)

   -- Fill
   local width = w * math.Clamp(value, 0, 1)

   if width > 0 then
      RoundedMeter(8, x, y, width, h, colors.fill)
   end
end

local roundstate_string = {
   [ROUND_WAIT]   = "round_wait",
   [ROUND_PREP]   = "round_prep",
   [ROUND_ACTIVE] = "round_active",
   [ROUND_POST]   = "round_post"
};

-- Returns player's ammo information
local function GetAmmo(ply)
   local weap = ply:GetActiveWeapon()
   if not weap or not ply:Alive() then return -1 end

   local ammo_inv = weap:Ammo1() or 0
   local ammo_clip = weap:Clip1() or 0
   local ammo_max = weap.Primary.ClipSize or 0

   return ammo_clip, ammo_max, ammo_inv
end

local function DrawBg(x, y, width, height, client)
   -- Traitor area sizes
   local th = 30
   local tw = 170

   -- Adjust for these
   y = y - th
   height = height + th

   -- main bg area, invariant
   -- encompasses entire area
   draw.RoundedBox(8, x, y, width, height, bg_colors.background_main)

   -- main border, traitor based
   local col = bg_colors.innocent
   if GAMEMODE.round_state != ROUND_ACTIVE then
      col = bg_colors.noround
   elseif client:GetTraitor() then
      col = bg_colors.traitor
   elseif client:GetDetective() then
      col = bg_colors.detective
   end

   draw.RoundedBox(8, x, y, tw, th, col)
end

local sf = surface
local dr = draw

local function ShadowedText(text, font, x, y, color, xalign, yalign)

   dr.SimpleText(text, font, x+2, y+2, COLOR_BLACK, xalign, yalign)

   dr.SimpleText(text, font, x, y, color, xalign, yalign)
end

local margin = 10

-- Paint punch-o-meter
local function PunchPaint(client)
   local L = GetLang()
   local punch = client:GetNWFloat("specpunches", 0)

   local width, height = 200, 25
   local x = ScrW() / 2 - width/2
   local y = margin/2 + height

   PaintBar(x, y, width, height, ammo_colors, punch)

   local color = bg_colors.background_main

   dr.SimpleText(L.punch_title, "HealthAmmo", ScrW() / 2, y, color, TEXT_ALIGN_CENTER)

   dr.SimpleText(L.punch_help, "TabLarge", ScrW() / 2, margin, COLOR_WHITE, TEXT_ALIGN_CENTER)

   local bonus = client:GetNWInt("bonuspunches", 0)
   if bonus != 0 then
      local text
      if bonus < 0 then
         text = interp(L.punch_bonus, {num = bonus})
      else
         text = interp(L.punch_malus, {num = bonus})
      end

      dr.SimpleText(text, "TabLarge", ScrW() / 2, y * 2, COLOR_WHITE, TEXT_ALIGN_CENTER)
   end
end

local key_params = { usekey = Key("+use", "USE") }

local function SpecHUDPaint(client)
   local L = GetLang() -- for fast direct table lookups

   -- Draw round state
   local x       = margin
   local height  = 32
   local width   = 250
   local round_y = ScrH() - height - margin

   -- move up a little on low resolutions to allow space for spectator hints
   if ScrW() < 1000 then round_y = round_y - 15 end

   local time_x = x + 170
   local time_y = round_y + 4

   draw.RoundedBox(8, x, round_y, width, height, bg_colors.background_main)
   draw.RoundedBox(8, x, round_y, time_x - x, height, bg_colors.noround)

   local text = L[ roundstate_string[GAMEMODE.round_state] ]
   ShadowedText(text, "TraitorState", x + margin, round_y, COLOR_WHITE)

   -- Draw round/prep/post time remaining
   local text = util.SimpleTime(math.max(0, GetGlobalFloat("ttt_round_end", 0) - CurTime()), "%02i:%02i")
   ShadowedText(text, "TimeLeft", time_x + margin, time_y, COLOR_WHITE)

   local tgt = client:GetObserverTarget()
   if IsValid(tgt) and tgt:IsPlayer() then
      ShadowedText(tgt:Nick(), "TimeLeft", ScrW() / 2, margin, COLOR_WHITE, TEXT_ALIGN_CENTER)

   elseif IsValid(tgt) and tgt:GetNWEntity("spec_owner", nil) == client then
      PunchPaint(client)
   else
      ShadowedText(interp(L.spec_help, key_params), "TabLarge", ScrW() / 2, margin, COLOR_WHITE, TEXT_ALIGN_CENTER)
   end
end

local ttt_health_label = CreateClientConVar("ttt_health_label", "0", true)

local function InfoPaint(client)
   local L = GetLang()

   local width = 250
   local height = 90

   local x = margin
   local y = ScrH() - margin - height

   DrawBg(x, y, width, height, client)

   local bar_height = 25
   local bar_width = width - (margin*2)

   -- Draw health
   local health = math.max(0, client:Health())
   local health_y = y + margin

   PaintBar(x + margin, health_y, bar_width, bar_height, health_colors, health/100)

   ShadowedText(tostring(health), "HealthAmmo", bar_width, health_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT)

   if ttt_health_label:GetBool() then
      local health_status = util.HealthToString(health)
      draw.SimpleText(L[health_status], "TabLarge", x + margin*2, health_y + bar_height/2, COLOR_WHITE, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
   end

   -- Draw ammo
   if client:GetActiveWeapon().Primary then
      local ammo_clip, ammo_max, ammo_inv = GetAmmo(client)
      if ammo_clip != -1 then
         local ammo_y = health_y + bar_height + margin
         PaintBar(x+margin, ammo_y, bar_width, bar_height, ammo_colors, ammo_clip/ammo_max)
         local text = string.format("%i + %02i", ammo_clip, ammo_inv)

         ShadowedText(text, "HealthAmmo", bar_width, ammo_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT)
      end
   end

   -- Draw traitor state
   local round_state = GAMEMODE.round_state

   local traitor_y = y - 30
   local text = nil
   if round_state == ROUND_ACTIVE then
      text = L[ client:GetRoleStringRaw() ]
   else
      text = L[ roundstate_string[round_state] ]
   end

   ShadowedText(text, "TraitorState", x + margin + 73, traitor_y, COLOR_WHITE, TEXT_ALIGN_CENTER)

   -- Draw round time
   local is_haste = HasteMode() and round_state == ROUND_ACTIVE
   local is_traitor = client:IsActiveTraitor()

   local endtime = GetGlobalFloat("ttt_round_end", 0) - CurTime()

   local text
   local font = "TimeLeft"
   local color = COLOR_WHITE
   local rx = x + margin + 170
   local ry = traitor_y + 3

   -- Time displays differently depending on whether haste mode is on,
   -- whether the player is traitor or not, and whether it is overtime.
   if is_haste then
      local hastetime = GetGlobalFloat("ttt_haste_end", 0) - CurTime()
      if hastetime < 0 then
         if (not is_traitor) or (math.ceil(CurTime()) % 7 <= 2) then
            -- innocent or blinking "overtime"
            text = L.overtime
            font = "Trebuchet18"

            -- need to hack the position a little because of the font switch
            ry = ry + 5
            rx = rx - 3
         else
            -- traitor and not blinking "overtime" right now, so standard endtime display
            text  = util.SimpleTime(math.max(0, endtime), "%02i:%02i")
            color = COLOR_RED
         end
      else
         -- still in starting period
         local t = hastetime
         if is_traitor and math.ceil(CurTime()) % 6 < 2 then
            t = endtime
            color = COLOR_RED
         end
         text = util.SimpleTime(math.max(0, t), "%02i:%02i")
      end
   else
      -- bog standard time when haste mode is off (or round not active)
      text = util.SimpleTime(math.max(0, endtime), "%02i:%02i")
   end

   ShadowedText(text, font, rx, ry, color)

   if is_haste then
      dr.SimpleText(L.hastemode, "TabLarge", x + margin + 165, traitor_y - 8)
   end

end

-- Paints player status HUD element in the bottom left
function GM:HUDPaint()
   local client = LocalPlayer()

   hook.Call( "HUDDrawTargetID", GAMEMODE )

   MSTACK:Draw(client)

   if (not client:Alive()) or client:Team() == TEAM_SPEC then
      SpecHUDPaint(client)

      return
   end


   RADAR:Draw(client)
   TBHUD:Draw(client)
   WSWITCH:Draw(client)

   VOICE.Draw(client)
   DISGUISE.Draw(client)

   hook.Call( "HUDDrawPickupHistory", GAMEMODE )

   -- Draw bottom left info panel
   InfoPaint(client)
end

-- Hide the standard HUD stuff
local hud = {"CHudHealth", "CHudBattery", "CHudAmmo", "CHudSecondaryAmmo"}
function GM:HUDShouldDraw(name)
   for k, v in pairs(hud) do
      if name == v then return false end
   end

   return true
end


Oddly enough it was caused by a confliction with a ULX module because my ULX was out of date. Updated ULX and solved the problem :smiley: