From c8c0ea6e4689238a7fb0cd8b59df978baba9fead Mon Sep 17 00:00:00 2001 From: Malivil Date: Sat, 21 Mar 2026 10:35:29 -0400 Subject: [PATCH 1/5] Ported "Add check for checking weapon GetHeadshotMultiplier" --- RELEASE.md | 1 + gamemodes/terrortown/gamemode/player.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 940dd62bc..e7b2e652a 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -20,6 +20,7 @@ - Fixed cheat sheet getting cut off when it exceeded the height of the screen and a role pack was enabled - Fixed jester, detective, innocent, and traitor role rename ConVars not working - Fixed error in Cannibal's role weapon HUD when weapon was selected from last round (Thanks Stig!) +- Ported "Add check for checking weapon GetHeadshotMultiplier" ### Developer - Added `ROLE_STRINGS_DEFAULT` as a copy of `ROLE_STRINGS` from before role strings are changed by ConVars diff --git a/gamemodes/terrortown/gamemode/player.lua b/gamemodes/terrortown/gamemode/player.lua index 688b90354..0a00416e1 100644 --- a/gamemodes/terrortown/gamemode/player.lua +++ b/gamemodes/terrortown/gamemode/player.lua @@ -978,7 +978,7 @@ function GM:ScalePlayerDamage(ply, hitgroup, dmginfo) local wep = util.WeaponFromDamage(dmginfo) - if IsValid(wep) and not GetConVar("ttt_disable_headshots"):GetBool() then + if IsValid(wep) and wep.GetHeadshotMultiplier and not GetConVar("ttt_disable_headshots"):GetBool() then local s = wep:GetHeadshotMultiplier(ply, dmginfo) or 2 dmginfo:ScaleDamage(s) end From b3d82ea2bbb56fb8df86e3c6b51ac18ce5a09483 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sat, 21 Mar 2026 10:36:11 -0400 Subject: [PATCH 2/5] Fixed detective hats not hiding when the owning player was eaten by the Cannibal --- RELEASE.md | 1 + gamemodes/terrortown/entities/weapons/weapon_can_eater.lua | 3 +++ gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua | 3 +++ 3 files changed, 7 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index e7b2e652a..7caeb2329 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -20,6 +20,7 @@ - Fixed cheat sheet getting cut off when it exceeded the height of the screen and a role pack was enabled - Fixed jester, detective, innocent, and traitor role rename ConVars not working - Fixed error in Cannibal's role weapon HUD when weapon was selected from last round (Thanks Stig!) +- Fixed detective hats not hiding when the owning player was eaten by the Cannibal - Ported "Add check for checking weapon GetHeadshotMultiplier" ### Developer diff --git a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua index 4b4d5e770..c06fb932d 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua @@ -124,6 +124,9 @@ function SWEP:PrimaryAttack() hitEnt:SpectateEntity(owner) hitEnt:DrawViewModel(false) hitEnt:DrawWorldModel(false) + if IsValid(hitEnt.hat) then + hitEnt.hat:SetNoDraw(true) + end local sID64 = hitEnt:SteamID64() diff --git a/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua b/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua index 1b3a1b115..a3fe91b12 100644 --- a/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua +++ b/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua @@ -39,6 +39,9 @@ local function ReleaseEatenPlayers(ply, message) v:DrawViewModel(true) v:DrawWorldModel(true) v:SetNoDraw(false) + if IsValid(v.hat) then + v.hat:SetNoDraw(false) + end v:Spawn() local pos = ply:GetPos() v:SetPos(FindRespawnLocation(pos) or pos) From 851cb6f81a0433ba491052d091784903491b247e Mon Sep 17 00:00:00 2001 From: Malivil Date: Sat, 21 Mar 2026 10:36:21 -0400 Subject: [PATCH 3/5] Cleanup --- .../entities/weapons/weapon_can_eater.lua | 28 ++++++++--------- .../gamemode/roles/cannibal/cl_cannibal.lua | 31 ++++++++++++++----- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua index c06fb932d..686b28c9e 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua @@ -157,33 +157,31 @@ function SWEP:PrimaryAttack() -- Cannibal health gain if self.GainsHealthConVar:GetBool() then - local gainedhealthpercentage = self.GainedHealthPercentageConVar:GetInt() - local victimhealth = hitEnt:Health() - local cannibalhealth = owner:Health() + local gained_health_percentage = self.GainedHealthPercentageConVar:GetInt() + local victimHealth = hitEnt:Health() + local cannibalHealth = owner:Health() - local gainedhealth - if gainedhealthpercentage == 0 then - gainedhealth = 100 + local gainedHealth + if gained_health_percentage == 0 then + gainedHealth = 100 else - local gainedhealthunrounded = (gainedhealthpercentage / 100) * victimhealth - gainedhealth = math.floor(gainedhealthunrounded) + gainedHealth = math.floor((gained_health_percentage / 100) * victimHealth) end - local newcannibalhealth = cannibalhealth + gainedhealth - if newcannibalhealth > cannibalhealth then - owner:SetHealth(newcannibalhealth) + if gainedHealth > 0 then + owner:SetHealth(cannibalHealth + gainedHealth) end end -- Victim digestion if self.DigestionConVar:GetBool() then - local digestiontime = self.DigestionTimeConVar:GetInt() + local digestion_time = self.DigestionTimeConVar:GetInt() -- Ensure there's a short delay to allow time for the vars to be set first - if digestiontime == 0 then - digestiontime = 0.1 + if digestion_time == 0 then + digestion_time = 0.1 end - timer.Create("TTTCannibalDigestion_" .. sID64, digestiontime, 1, function() + timer.Create("TTTCannibalDigestion_" .. sID64, digestion_time, 1, function() if not IsPlayer(hitEnt) then return end if not IsPlayer(owner) then return end diff --git a/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua b/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua index 68b15588b..583adb885 100644 --- a/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua +++ b/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua @@ -189,17 +189,34 @@ AddHook("TTTTutorialRoleText", "Cannibal_TTTTutorialRoleText", function(role, ti local roleTeamName, roleColor = GetRoleTeamInfo(roleTeam) local html = "The " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " is a " .. roleTeamName .. " role whose goal is to eat all other players." - if GetConVar("ttt_cannibal_digestion"):GetBool() then - html = html .. "Eaten players are not immediately dead, but they are unable to do anything except talk with other eaten players and spectate the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. "." + if GetConVar("ttt_cannibal_gains_health"):GetBool() then + local gained_health_percentage = GetConVar("ttt_cannibal_gained_health_percentage"):GetInt() + local gained + if gained_health_percentage > 0 then + gained = gained_health_percentage .. "% of the victim's health" + else + gained = "100HP" + end + + html = html .. "When the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " eats a player, they gain " .. gained .. " immediately." + end - html = html .. "Eaten players are digested and killed " .. GetConVar("ttt_cannibal_digestion_time"):GetInt() .. " seconds after being eaten." + local eatenDetail = "" + local deathDetail = "" + + if GetConVar("ttt_cannibal_digestion"):GetBool() then + eatenDetail = " immediately" + deathDetail = " undigested" + end - html = html .. "If the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " dies, all undigested eaten players are freed at the position where the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " died." - else - html = html .. "Eaten players are not dead, but they are unable to do anything except talk with other eaten players and spectate the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. "." + html = html .. "Eaten players are not" .. eatenDetail .. " dead, but they are unable to do anything except talk with other eaten players and spectate the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. "." - html = html .. "If the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " dies, all eaten players are freed at the position where the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " died." + if GetConVar("ttt_cannibal_digestion"):GetBool() then + html = html .. "Eaten players are digested and killed " .. GetConVar("ttt_cannibal_digestion_time"):GetInt() .. " seconds after being eaten." end + + html = html .. "If the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " dies, all" .. deathDetail .. " eaten players are freed at the position where the " .. ROLE_STRINGS[ROLE_CANNIBAL] .. " died." + return html end end) \ No newline at end of file From 9bb201d3e4a94587f3ec024ebbd9c1fee2b6d8b4 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sat, 21 Mar 2026 10:48:11 -0400 Subject: [PATCH 4/5] Added new cannibal convars to HTML Fixed typos Adjusted default convar values --- CONVARS.md | 2 +- docs/teams/jester.html | 34 +++++++++++++++++-- .../entities/weapons/weapon_can_eater.lua | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CONVARS.md b/CONVARS.md index 4fdc60803..24d58d587 100644 --- a/CONVARS.md +++ b/CONVARS.md @@ -765,7 +765,7 @@ ttt_cannibal_damage_penalty 0 // The fraction a Canniba ttt_cannibal_can_see_jesters 0 // Whether jesters are revealed (via head icons, color/icon on the scoreboard, etc.) to the Cannibal (Only applies if ttt_cannibal_is_independent is enabled) ttt_cannibal_update_scoreboard 0 // Whether the Cannibal shows dead players as missing in action (Only applies if ttt_cannibal_is_independent is enabled) ttt_cannibal_gains_health 0 // Whether the Cannibal gains their victim's health when eating them -ttt_cannibal_gained_health_percentage 100 // What percentage of their victim's health the Cannibal gains. Set to 0 to always gain a flat 100HP (Only applies if ttt_cannibal_gains_health is enabled) +ttt_cannibal_gained_health_percentage 15 // What percentage of their victim's health the Cannibal gains. Set to 0 to always gain a flat 100HP (Only applies if ttt_cannibal_gains_health is enabled) ttt_cannibal_digestion 0 // Whether the Cannibal digests and permanently kills their victims over time ttt_cannibal_digestion_time 30 // How long in seconds a victim takes to be digested when eaten. Set to 0 for immediate digestion (Only applies if ttt_cannibal_digestion is enabled) ttt_cannibal_digestion_poop 1 // Whether the Cannibal drops poop when a victim is digested (Only applies if ttt_cannibal_digestion is enabled) diff --git a/docs/teams/jester.html b/docs/teams/jester.html index 4ffd23c2c..a8123bb40 100644 --- a/docs/teams/jester.html +++ b/docs/teams/jester.html @@ -580,7 +580,25 @@

Role Configuration:

ttt_cannibal_damage_penalty 0 Float - The fraction a Cannibal's damage will be scaled by when they are attacking. (Requires ttt_bodysnatcher_is_independent to be enabled.) + The fraction a Cannibal's damage will be scaled by when they are attacking. (Requires ttt_cannibal_is_independent to be enabled.) + + + ttt_cannibal_digestion   + 0 + Boolean + Whether the Cannibal digests and permanently kills their victims over time. + + + ttt_cannibal_digestion_poop   + 1 + Boolean + Whether the Cannibal drops poop when a victim is digested. (Requires ttt_cannibal_digestion to be enabled.) + + + ttt_cannibal_digestion_poop_sound   + 1 + Boolean + Whether the Cannibal causes a sound when poop is dropped from a digested victim. (Requires ttt_cannibal_digestion to be enabled.) ttt_cannibal_eat_cooldown @@ -588,6 +606,18 @@

Role Configuration:

Integer The amount of time in seconds between uses of the Cannibal's Cannibalizer. + + ttt_cannibal_gains_health   + 0 + Boolean + Whether the Cannibal gains their victim's health when eating them. + + + ttt_cannibal_gained_health_percentage   + 15 + Integer + What percentage of their victim's health the Cannibal gains. Set to 0 to always gain a flat 100HP (Requires ttt_cannibal_gains_health to be enabled.) + ttt_cannibal_is_independent 0 @@ -598,7 +628,7 @@

Role Configuration:

ttt_cannibal_update_scoreboard 0 Boolean - Whether the Cannibal shows dead players as missing in action. (Requires ttt_bodysnatcher_is_independent to be enabled.) + Whether the Cannibal shows dead players as missing in action. (Requires ttt_cannibal_is_independent to be enabled.) diff --git a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua index 686b28c9e..b9705de13 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua @@ -38,7 +38,7 @@ SWEP.InLoadoutForDefault = {ROLE_CANNIBAL} SWEP.DeviceCooldownConVar = CreateConVar("ttt_cannibal_eat_cooldown", "10", FCVAR_REPLICATED, "The amount of time (in seconds) between uses of the Cannibal's Cannibalizer", 0, 60) SWEP.GainsHealthConVar = CreateConVar("ttt_cannibal_gains_health", "0", FCVAR_REPLICATED, "Whether the Cannibal gains their victim's health when eating them", 0, 1) -SWEP.GainedHealthPercentageConVar = CreateConVar("ttt_cannibal_gained_health_percentage", "100", FCVAR_REPLICATED, "What percentage of their victim's health the Cannibal gains (set to 0 to always gain a flat 100HP)", 0, 500) +SWEP.GainedHealthPercentageConVar = CreateConVar("ttt_cannibal_gained_health_percentage", "15", FCVAR_REPLICATED, "What percentage of their victim's health the Cannibal gains (set to 0 to always gain a flat 100HP)", 0, 500) SWEP.DigestionConVar = CreateConVar("ttt_cannibal_digestion", "0", FCVAR_REPLICATED, "Whether the Cannibal digests and permanently kills their victims over time", 0, 1) SWEP.DigestionTimeConVar = CreateConVar("ttt_cannibal_digestion_time", "30", FCVAR_REPLICATED, "How long in seconds a victim takes to be digested when eaten (set to 0 for immediate digestion)", 0, 300) From bcb2fa605eb4a3959d1a9fe11a4fe0ee4b32c1e4 Mon Sep 17 00:00:00 2001 From: Malivil Date: Sat, 21 Mar 2026 10:51:28 -0400 Subject: [PATCH 5/5] Updated release date and number --- RELEASE.md | 4 ++-- gamemodes/terrortown/gamemode/shared.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 7caeb2329..4a19fbbcc 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,12 +1,12 @@ # Release Notes ## 2.4.4 (Beta) -**Released:** +**Released: March 21st, 2026** ### Additions - Added messages to existing twins when a player becomes a twin during an active round - Added option to allow Cannibal to gain a configurable percentage of their victims' health (disabled by default) (Thanks Joel!) -- Added option to allow Cannibal to "digest" (permamnently kill) their victims a configurable amount of time after eating them (disabled by default) (Thanks Joel!) +- Added option to allow Cannibal to "digest" (permanently kill) their victims a configurable amount of time after eating them (disabled by default) (Thanks Joel!) - Added option to allow Cannibal to drop a poop when a victim is fully digested, with or without an audible cue (enabled by default, but depends on digestion being enabled) (Thanks Joel!) ### Changes diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index 109126c82..e610042b3 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -27,7 +27,7 @@ local Utf8Sub = utf8.sub include("player_class/player_ttt.lua") -- Version string for display and function for version checks -CR_VERSION = "2.4.3" +CR_VERSION = "2.4.4" CR_BETA = true CR_WORKSHOP_ID = CR_BETA and "2404251054" or "2421039084"