Repository: Facepunch/garrysmod
Pull request #2235: TTT: Crosshair Customisation
Author: login: figardo
Labels: name: TTT
description: The pull request is proposing changes to the TTT gamemode.
name: Addition
description: The pull request adds new functionality.
Created: 2025-03-12T03:39:37Z | Merged: 2025-03-23T11:44:53Z

Based on #1376, but with additional changes:

# Improve crosshair alignment

<img src="https://github.com/user-attachments/assets/feffec3b-004d-4fd7-a175-82278dade6f7" width=25% height=25%>

- ttt_crosshair_thickness 1 - 10
- mat_antialias 4

top-left of red dot = centre of screen

By comparison, the old PR implementation had a tendency to leave a larger gap in the bottom right than the top left when using odd thickness levels (3 here):

![ttt_misaligned](https://github.com/user-attachments/assets/e227be27-9f74-433d-866b-0e83bad84fbf)


# Ensure there's no overlap if thickness is set too high

<img src="https://github.com/user-attachments/assets/d27a87d0-3bac-4d79-8a3d-e11d727c5a54" width=50% height=50%>

- ttt_crosshair_thickness 1 (mat_antialias 1) vs 5 vs 10

When using the H.U.G.E-249, the distance between the crosshair prongs remains 18x18 no matter what thickness level is set.

Worst case scenario from the old PR (thickness 20):

![ttt_overlap](https://github.com/user-attachments/assets/5aafde87-9780-4ac2-ad9f-b393c3af9c2b)

All fixed:

![ttt_nooverlap](https://github.com/user-attachments/assets/806da139-7227-4d7f-8214-8509cef82b28)


# Use surface.DrawLine if thickness is 1 to preserve its behaviour when antialiasing is enabled

<img src="https://github.com/user-attachments/assets/1d6f04bf-ead5-4691-89a6-86bd99b5293f" width=50% height=50%>

- mat_antialias 4 vs mat_antialias 1
- ttt_crosshair_thickness 1

ttt_crosshair_outlinethickness adjusts for the extra pixel caused by antialiasing

# Remove any settings that can tighten the crosshair gap/scale

New settings section:

![image](https://github.com/user-attachments/assets/4074160e-c842-4426-a244-57f637ae8f86)



Diff:
diff --git a/garrysmod/gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua b/garrysmod/gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua
index 998d39c5d3..1b80c2ab66 100644
--- a/garrysmod/gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua
+++ b/garrysmod/gamemodes/terrortown/entities/weapons/weapon_ttt_push.lua
@@ -135,7 +135,7 @@ local CHARGE_FORCE_UP_MIN = 100
 local CHARGE_FORCE_UP_MAX = 350
 function SWEP:ChargedAttack()
    local charge = math.Clamp(self:GetCharge(), 0, 1)
-   
+
    self.IsCharging = false
    self:SetCharge(0)
 
@@ -191,7 +191,7 @@ function SWEP:Think()
          return true
       end
 
-      
+
       if SERVER and self:GetCharge() < 1 and self.NextCharge < CurTime() then
          self:SetCharge(math.min(1, self:GetCharge() + CHARGE_AMOUNT))
 
@@ -209,22 +209,17 @@ if CLIENT then
       local nxt = self:GetNextPrimaryFire()
       local charge = self.dt.charge
 
+      if nxt < CurTime() or CurTime() % 0.5 < 0.2 or charge > 0 then
+         -- draw crosshair
+         BaseClass.DrawHUD(self, true, 5)
+      end
+
       if LocalPlayer():IsTraitor() then
          surface.SetDrawColor(255, 0, 0, 255)
       else
          surface.SetDrawColor(0, 255, 0, 255)
       end
 
-      if nxt < CurTime() or CurTime() % 0.5 < 0.2 or charge > 0 then
-         local length = 10
-         local gap = 5
-
-         surface.DrawLine( x - length, y, x - gap, y )
-         surface.DrawLine( x + length, y, x + gap, y )
-         surface.DrawLine( x, y - length, x, y - gap )
-         surface.DrawLine( x, y + length, x, y + gap )
-      end
-
       if nxt > CurTime() and charge == 0 then
          local w = 40
 
@@ -234,7 +229,7 @@ if CLIENT then
          surface.DrawLine(bx, y - w, bx, y + w)
 
          bx = x - 30
-         surface.DrawLine(bx, y - w, bx, y + w) 
+         surface.DrawLine(bx, y - w, bx, y + w)
       end
 
       if charge > 0 then
diff --git a/garrysmod/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua b/garrysmod/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
index 66f0aaa0df..109091e591 100644
--- a/garrysmod/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
+++ b/garrysmod/gamemodes/terrortown/entities/weapons/weapon_tttbase.lua
@@ -133,7 +133,18 @@ if CLIENT then
    local crosshair_size = CreateConVar("ttt_crosshair_size", "1.0", FCVAR_ARCHIVE)
    local disable_crosshair = CreateConVar("ttt_disable_crosshair", "0", FCVAR_ARCHIVE)
 
-   function SWEP:DrawHUD()
+   local enable_color_crosshair = CreateConVar("ttt_crosshair_color_enable", "0", FCVAR_ARCHIVE)
+   local crosshair_color_r = CreateConVar("ttt_crosshair_color_r", "255", FCVAR_ARCHIVE)
+   local crosshair_color_g = CreateConVar("ttt_crosshair_color_g", "255", FCVAR_ARCHIVE)
+   local crosshair_color_b = CreateConVar("ttt_crosshair_color_b", "255", FCVAR_ARCHIVE)
+
+   local crosshair_opacity = CreateConVar("ttt_crosshair_opacity", "1", FCVAR_ARCHIVE)
+   local crosshair_thickness = CreateConVar("ttt_crosshair_thickness", "1", FCVAR_ARCHIVE)
+   local crosshair_outlinethickness = CreateConVar("ttt_crosshair_outlinethickness", "0", FCVAR_ARCHIVE)
+
+   local mat_antialias = GetConVar("mat_antialias")
+
+   function SWEP:DrawHUD(static, gap)
       if self.HUDHelp then
          self:DrawHelp()
       end
@@ -145,17 +156,64 @@ if CLIENT then
 
       local x = math.floor(ScrW() / 2.0)
       local y = math.floor(ScrH() / 2.0)
-      local scale = math.max(0.2,  10 * self:GetPrimaryCone())
+      local scale = math.max(0.2, 10 * self:GetPrimaryCone())
 
-      local LastShootTime = self:LastShootTime()
-      scale = scale * (2 - math.Clamp( (CurTime() - LastShootTime) * 5, 0.0, 1.0 ))
+      if not static then
+         local LastShootTime = self:LastShootTime()
+         scale = scale * (2 - math.Clamp( (CurTime() - LastShootTime) * 5, 0.0, 1.0 ))
+      end
 
-      local alpha = sights and sights_opacity:GetFloat() or 1
+      local alpha = sights and sights_opacity:GetFloat() or crosshair_opacity:GetFloat()
       local bright = crosshair_brightness:GetFloat() or 1
 
-      -- somehow it seems this can be called before my player metatable
-      -- additions have loaded
-      if client.IsTraitor and client:IsTraitor() then
+      gap = gap or math.floor(20 * scale * (sights and 0.8 or 1))
+      local length = math.floor(gap + (25 * crosshair_size:GetFloat()) * scale)
+
+      local thickness = math.max(1, crosshair_thickness:GetInt())
+      local rect = thickness > 1
+
+      -- lines are drawn with antialiasing when MSAA is enabled which makes them 1 pixel longer
+      local antialias = not rect and mat_antialias:GetInt() > 1
+
+      local offset, odd_offset = 0, 0
+      if rect then
+         offset = math.floor(thickness / 2)
+
+         -- ensures that high thickness levels don't cause the crosshair to overlap itself
+         gap = gap + offset
+         length = length + offset
+
+         -- prevents the distance between crosshair prongs from becoming uneven with odd thickness levels
+         odd_offset = thickness % 2
+      elseif not antialias then
+         odd_offset = 1
+      end
+
+      local outline = crosshair_outlinethickness:GetInt()
+      if outline > 0 then
+         surface.SetDrawColor(0, 0, 0, 255 * alpha)
+
+         local out_thick = thickness + outline * 2
+         local out_length = antialias and length + 1 or length
+         out_length = out_length - gap + outline * 2
+
+         local out_offset = offset + outline
+
+         local out_topleft = length + outline
+         local out_bottomright = gap - outline + odd_offset
+
+         surface.DrawRect( x - out_topleft, y - out_offset, out_length, out_thick )
+         surface.DrawRect( x + out_bottomright, y - out_offset, out_length, out_thick )
+         surface.DrawRect( x - out_offset, y - out_topleft, out_thick, out_length )
+         surface.DrawRect( x - out_offset, y + out_bottomright, out_thick, out_length )
+      end
+
+      if enable_color_crosshair:GetBool() then
+         surface.SetDrawColor(crosshair_color_r:GetInt() * bright,
+                              crosshair_color_g:GetInt() * bright,
+                              crosshair_color_b:GetInt() * bright,
+                              255 * alpha)
+      elseif client.IsTraitor and client:IsTraitor() then -- somehow it seems this can be called before my player metatable additions have loaded
          surface.SetDrawColor(255 * bright,
                               50 * bright,
                               50 * bright,
@@ -167,12 +225,20 @@ if CLIENT then
                               255 * alpha)
       end
 
-      local gap = math.floor(20 * scale * (sights and 0.8 or 1))
-      local length = math.floor(gap + (25 * crosshair_size:GetFloat()) * scale)
-      surface.DrawLine( x - length, y, x - gap, y )
-      surface.DrawLine( x + length, y, x + gap, y )
-      surface.DrawLine( x, y - length, x, y - gap )
-      surface.DrawLine( x, y + length, x, y + gap )
+      if rect then
+         local rect_length = length - gap
+         gap = gap + odd_offset
+
+         surface.DrawRect( x - length, y - offset, rect_length, thickness )
+         surface.DrawRect( x + gap, y - offset, rect_length, thickness )
+         surface.DrawRect( x - offset, y - length, thickness, rect_length )
+         surface.DrawRect( x - offset, y + gap, thickness, rect_length )
+      else
+         surface.DrawLine( x - length, y, x - gap, y )
+         surface.DrawLine( x + length, y, x + gap, y )
+         surface.DrawLine( x, y - length, x, y - gap )
+         surface.DrawLine( x, y + length, x, y + gap )
+      end
    end
 
    local GetPTranslation = LANG.GetParamTranslation
@@ -445,7 +511,7 @@ function SWEP:WasBought(buyer)
 end
 
 function SWEP:SetIronsights(b)
-   if (b ~= self:GetIronsights()) then
+   if (b != self:GetIronsights()) then
       self:SetIronsightsPredicted(b)
       self:SetIronsightsTime(CurTime())
       if CLIENT then
diff --git a/garrysmod/gamemodes/terrortown/gamemode/cl_help.lua b/garrysmod/gamemodes/terrortown/gamemode/cl_help.lua
index 5ce4c10d1d..12e7f1c589 100644
--- a/garrysmod/gamemodes/terrortown/gamemode/cl_help.lua
+++ b/garrysmod/gamemodes/terrortown/gamemode/cl_help.lua
@@ -67,24 +67,6 @@ function HELPSCRN:Show()
    end
    cb:SetTooltip(GetTranslation("set_startpopup_tip"))
 
-   cb = dgui:NumSlider(GetTranslation("set_cross_opacity"), "ttt_ironsights_crosshair_opacity", 0, 1, 1)
-   if cb.Label then
-      cb.Label:SetWrap(true)
-   end
-   cb:SetTooltip(GetTranslation("set_cross_opacity"))
-
-   cb = dgui:NumSlider(GetTranslation("set_cross_brightness"), "ttt_crosshair_brightness", 0, 1, 1)
-   if cb.Label then
-      cb.Label:SetWrap(true)
-   end
-
-   cb = dgui:NumSlider(GetTranslation("set_cross_size"), "ttt_crosshair_size", 0.1, 3, 1)
-   if cb.Label then
-      cb.Label:SetWrap(true)
-   end
-
-   dgui:CheckBox(GetTranslation("set_cross_disable"), "ttt_disable_crosshair")
-
    dgui:CheckBox(GetTranslation("set_minimal_id"), "ttt_minimal_targetid")
 
    dgui:CheckBox(GetTranslation("set_healthlabel"), "ttt_health_label")
@@ -102,7 +84,7 @@ function HELPSCRN:Show()
    cb:SetTooltip(GetTranslation("set_wswitch_tip"))
 
    cb = dgui:CheckBox(GetTranslation("set_cues"), "ttt_cl_soundcues")
-   
+
    cb = dgui:CheckBox(GetTranslation("set_msg_cue"), "ttt_cl_msg_soundcue")
 
    dsettings:AddItem(dgui)
@@ -149,6 +131,58 @@ function HELPSCRN:Show()
 
    dsettings:AddItem(dlanguage)
 
+   --- Crosshair area
+
+   local dcross = vgui.Create("DForm", dsettings)
+   dcross:SetName(GetTranslation("set_title_cross"))
+
+   dcross:CheckBox(GetTranslation("set_cross_disable"), "ttt_disable_crosshair")
+
+   dcross:CheckBox(GetTranslation("set_cross_color_enable"), "ttt_crosshair_color_enable")
+
+   cm = vgui.Create("DColorMixer")
+   cm:SetLabel(GetTranslation("set_cross_color"))
+   cm:SetTall(120)
+   cm:SetAlphaBar(false)
+   cm:SetPalette(false)
+   cm:SetColor(Color(255, 255, 255, 255))
+   cm:SetConVarR("ttt_crosshair_color_r")
+   cm:SetConVarG("ttt_crosshair_color_g")
+   cm:SetConVarB("ttt_crosshair_color_b")
+   dcross:AddItem(cm)
+
+   cb = dcross:NumSlider(GetTranslation("set_hip_cross_opacity"), "ttt_crosshair_opacity", 0, 1, 1)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   cb = dcross:NumSlider(GetTranslation("set_cross_opacity"), "ttt_ironsights_crosshair_opacity", 0, 1, 1)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   cb = dcross:NumSlider(GetTranslation("set_cross_brightness"), "ttt_crosshair_brightness", 0, 1, 1)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   cb = dcross:NumSlider(GetTranslation("set_cross_size"), "ttt_crosshair_size", 0.1, 3, 1)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   cb = dcross:NumSlider(GetTranslation("set_cross_thickness"), "ttt_crosshair_thickness", 1, 10, 0)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   cb = dcross:NumSlider(GetTranslation("set_cross_outlinethickness"), "ttt_crosshair_outlinethickness", 0, 4, 0)
+   if cb.Label then
+      cb.Label:SetWrap(true)
+   end
+
+   dsettings:AddItem(dcross)
+
    dtabs:AddSheet(GetTranslation("help_settings"), dsettings, "icon16/wrench.png", false, false, GetTranslation("help_settings_tip"))
 
    hook.Call("TTTSettingsTabs", GAMEMODE, dtabs)
diff --git a/garrysmod/gamemodes/terrortown/gamemode/lang/english.lua b/garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
index 5a54d87a71..8ba6ecd50c 100644
--- a/garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
+++ b/garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
@@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Iron sight crosshair opacity"
+L.set_cross_opacity   = "Opacity (iron sights)"
 L.set_cross_disable   = "Disable crosshair completely"
 L.set_minimal_id      = "Minimalist Target ID under crosshair (no karma text, hints, etc)"
 L.set_healthlabel     = "Show health status label on health bar"
@@ -1051,8 +1051,8 @@ L.set_avoid_det_tip = "Enable this to ask the server not to select you as Detect
 L.drop_no_ammo = "Insufficient ammo in your weapon's clip to drop as an ammo box."
 
 --- v31
-L.set_cross_brightness = "Crosshair brightness"
-L.set_cross_size = "Crosshair size"
+L.set_cross_brightness = "Brightness"
+L.set_cross_size = "Size"
 
 --- 2015-05-25
 L.hat_retrieve = "You picked up a Detective's hat."
@@ -1087,3 +1087,12 @@ L.sb_playervolume = "Player Volume"
 
 --- 2021-09-22
 L.tip41 = "You can adjust a player's microphone volume by right-clicking their mute icon in the scoreboard."
+
+--- 2025-03-11
+L.set_title_cross = "Crosshair settings"
+
+L.set_cross_color_enable = "Enable custom color"
+L.set_cross_color = "Custom color"
+L.set_hip_cross_opacity = "Opacity"
+L.set_cross_thickness = "Thickness"
+L.set_cross_outlinethickness = "Outline thickness"
\ No newline at end of file


Reviews:
user: login: NovaDiablox
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T04:28:54Z
user: login: robotboy655
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-18T14:30:36Z
user: login: figardo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T14:41:38Z
user: login: Tiagoquix
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T14:49:52Z
user: login: NovaDiablox
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T15:01:19Z

Review comments:
diff_hunk: @@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Ironsight crosshair opacity"
+L.set_cross_opacity   = "Ironsight opacity"
path: garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
user: login: NovaDiablox
body: "Iron sight opacity"
created_at: 2025-03-18T04:25:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Iron sight crosshair opacity"
+L.set_cross_opacity   = "Iron sight opacity"
path: garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
user: login: robotboy655
body: I feel like this is misleading now, "iron sight opacity" is a nonsensical statement. Maybe "ADS opacity"  would be better, but it could be more difficult to localize. Maybe just revert this string to what it was.
created_at: 2025-03-18T14:30:36Z
author_association: COLLABORATOR
diff_hunk: @@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Iron sight crosshair opacity"
+L.set_cross_opacity   = "Iron sight opacity"
path: garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
user: login: figardo
body: It only makes sense in the context of being located underneath crosshair settings along with the other settings (see the last image i posted), but I agree that it feels awkward when compared with the other opacity option.

Maybe swapping the order to "Opacity (iron sights)" would fit better with the other option?
created_at: 2025-03-18T14:41:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Iron sight crosshair opacity"
+L.set_cross_opacity   = "Iron sight opacity"
path: garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
user: login: Tiagoquix
body: "Opacity with iron sight" or "Opacity when using iron sights" work well.
created_at: 2025-03-18T14:49:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -244,7 +244,7 @@ L.set_tips      = "Show gameplay tips at the bottom of the screen while spectati
 L.set_startpopup = "Start of round info popup duration"
 L.set_startpopup_tip = "When the round starts, a small popup appears at the bottom of your screen for a few seconds. Change the time it displays for here."
 
-L.set_cross_opacity   = "Iron sight crosshair opacity"
+L.set_cross_opacity   = "Iron sight opacity"
path: garrysmod/gamemodes/terrortown/gamemode/lang/english.lua
user: login: NovaDiablox
body: > It only makes sense in the context of being located underneath crosshair settings along with the other settings (see the last image i posted), but I agree that it feels awkward when compared with the other opacity option.
> 
> Maybe swapping the order to "Opacity (iron sights)" would fit better with the other option?

I also agree to revert the changes in this one. Translators can use the mentioned examples when translating but it won't be consistent.
created_at: 2025-03-18T15:01:19Z
author_association: CONTRIBUTOR

PR comments:
user: login: Tiagoquix
created_at: 2025-03-16T21:52:52Z
body: I think it would be nice if you could integrate this into the default GMOD crosshair customization feature and replace instances of the TTT crosshair in the TTT game mode to use only the GMOD crosshair customization options. You could leave a separate checkbox for using role-based colors (Inno/T/DT).
author_association: CONTRIBUTOR
user: login: figardo
created_at: 2025-03-17T00:57:39Z
body: > I think it would be nice if you could integrate this into the default GMOD crosshair customization feature and replace instances of the TTT crosshair in the TTT game mode to use only the GMOD crosshair customization options. You could leave a separate checkbox for using role-based colors (Inno/T/DT).

If we used the GMod crosshair customisation settings while preserving the "no tightening the crosshair gap" rule, we'd have to ignore the settings on the Classic option for gap, dot, and maybe the T-style, as well as outright ignoring the Dot Image and HL2 options. This arrangement would just cause confusion over why the custom crosshair looks different in TTT from that of the preview in the customisation menu.

I also feel like most people would prefer to keep their sandbox crosshair settings separate from their TTT crosshair settings in general, since they are very different gamemodes.
author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T16:35:32Z
body: Thanks for your comment. It makes sense, I agree.

One suggestion: I believe you could take this opportunity and enable outline thickness by default. Helps visibility.
author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T16:50:14Z
body: One bug I noticed testing this PR in my local server is that the Newton Launcher does not follow the crosshair customization.

Exaggerated example:

![image](https://github.com/user-attachments/assets/0559835e-265e-4310-bcda-c4c71b30616d)

![image](https://github.com/user-attachments/assets/91dc851a-20b9-4e49-8e7a-191fff0f740d)

author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T16:51:17Z
body: Also, could you add an option to disable the crosshair gap/size changing when shooting?
author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T16:55:48Z
body: Another thing too:

Not sure if this is possible, but could you make it so the spectator crosshair (when not spectating anyone) matches the TTT-defined crosshair instead of using the game's crosshair?

Example of the game's crosshair being used:

![image](https://github.com/user-attachments/assets/9447a0b5-e95f-429d-a266-222a3540fbc4)

author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T19:12:10Z
body: > Also, could you add an option to disable the crosshair gap/size changing when shooting?

If you are going to make this option, please also add one to disable crosshair size being changed when using different weapons. For instance, the shotgun crosshair is very big.

i.e. make it completely static and the same for all weapons.
author_association: CONTRIBUTOR
user: login: figardo
created_at: 2025-03-17T19:13:22Z
body: > One bug I noticed testing this PR in my local server is that the Newton Launcher does not follow the crosshair customization.

Thank you, fixed now.

> One suggestion: I believe you could take this opportunity and enable outline thickness by default. Helps visibility.

While I also prefer crosshair outlines, I think it's best to keep the crosshair behaviour the same as it has been by default.

> Also, could you add an option to disable the crosshair gap/size changing when shooting?

This was one of the settings removed for tightening the crosshair gap, but I'm open to readding those settings if @svdm thinks they wouldn't mess with weapon balancing too much.

> Not sure if this is possible, but could you make it so the spectator crosshair (when not spectating anyone) matches the TTT-defined crosshair instead of using the game's crosshair?

It's possible, but it requires moving the crosshair code out of the weapon base into the gamemode files somewhere. I'll see if there's an elegant solution.
author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T19:18:18Z
body: > While I also prefer crosshair outlines, I think it's best to keep the crosshair behaviour the same as it has been by default.

In other Source games that support crosshair outlines, it is enabled by default. Most notably Counter-Strike games if I am not mistaken.

> This was one of the settings removed for tightening the crosshair gap [...]

Do you mean that what I described (not changing the gap while shooting) is now the default behavior and not toggle-able?
If so, does this also stop the crosshair changing sizes depending on the held weapon?
author_association: CONTRIBUTOR
user: login: figardo
created_at: 2025-03-17T20:10:31Z
body: > In other Source games that support crosshair outlines, it is enabled by default. Most notably Counter-Strike games if I am not mistaken.

We're adding to a gamemode that already has an established crosshair, so keeping that existing crosshair as the default would make the most sense over forcing change upon everyone after 15 years.

> Do you mean that what I described (not changing the gap while shooting) is now the default behavior and not toggle-able? If so, does this also stop the crosshair changing sizes depending on the held weapon?

If the gap isn't changing when you shoot, try testing in a multiplayer server instead of a singleplayer server, since WEAPON:LastShootTime doesn't work in singleplayer. Both gap changes still work as usual on my end.
author_association: CONTRIBUTOR
user: login: NovaDiablox
created_at: 2025-03-17T20:56:47Z
body: If Rubat agrees, the crosshair settings needs its own tab for ease of access next to the current "Settings" tab or somewhere else. I think the word "crosshair" seems repetitive. I advise something more in line with CS2 crosshair settings.
author_association: CONTRIBUTOR
user: login: Tiagoquix
created_at: 2025-03-17T21:47:48Z
body: > If the gap isn't changing when you shoot, try testing in a multiplayer server instead of a singleplayer server, since WEAPON:LastShootTime doesn't work in singleplayer. Both gap changes still work as usual on my end.

I do not mean it is not changing. It is. What I mean is that there are two things:
1. Gap/size changes depending on held weapon, even when not shooting, and;
2. gap changes when shooting.

I made a request for you to implement a way to make the crosshair completely static, without applying any gap change due to the aforementioned circumstances.

It is not clear if you intend to implement my request or not. If you do, there could be those two ConVars to control that behavior as well (they would be enabled by default, so we don't change the current behavior).
author_association: CONTRIBUTOR
user: login: figardo
created_at: 2025-03-17T23:31:33Z
body: Ah I get you now, to be clear I'm refraining from adding anything that can tighten the crosshair gap, including options to remove the gap increase when shooting or the gap increase with higher bullet spread weapons, because a tighter crosshair gap could potentially have an impact on weapon balance.

If this is determined to be a non-issue then I can re-add all of the omitted settings, including a toggle for a static crosshair.
author_association: CONTRIBUTOR
user: login: figardo
created_at: 2025-03-17T23:57:39Z
body: > If Rubat agrees, the crosshair settings needs its own tab for ease of access next to the current "Settings" tab or somewhere else.

I did consider that the new section makes the settings tab a bit long, but it feels weird to relegate new settings to a different tab just because there's a lot of them.

> I think the word "crosshair" seems repetitive. I advise something more in line with CS2 crosshair settings.

Sure thing, here's what it looks like without the repeat mention of "Crosshair" (except for disable, cause it feels weird to just say "Disable completely" imo):

![image](https://github.com/user-attachments/assets/cec5561f-d202-4651-9f23-c13f4ca5b529)

author_association: CONTRIBUTOR
user: login: svdm
created_at: 2025-03-23T11:44:39Z
body: Seems good as-is, not allowing closing of the gap is the right choice.
author_association: COLLABORATOR