diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f40449606..4b5ef26d5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,5 +17,7 @@ - [ ] ConVars added to ULX list - [ ] `plymeta:IsRoleAbilityDisabled` used - Otherwise: - - [ ] CONVARS.md updated, if applicable + - [ ] Documentation + - [ ] CONVARS.md + - [ ] Website (changes marked with "beta only" notation if applicable) - [ ] ULX updated (either added to list of convars for a role, or PR created in [ULX](https://github.com/Custom-Roles-for-TTT/TTT-Custom-Roles-ULX) repo \[Add link below\]) diff --git a/API/HOOKS.md b/API/HOOKS.md index 704990c6e..f0b56c274 100644 --- a/API/HOOKS.md +++ b/API/HOOKS.md @@ -319,7 +319,7 @@ Called when someone uses a fake cure on a player.\ *Parameters:* - *ply* - The target player who is being "cured" -### TTTHUDInfoPaint(client, labelX, labelY, activeLabels) +### TTTHUDInfoPaint(client, labelX, labelY, activeLabels, x, y) Called after player information such as role, health, and ammo and equipment information such as radar cooldown and disguiser activation are drawn on the screen. Used to write additional persistent text on the screen for player reference.\ *Realm:* Client\ *Added in:* 1.3.1\ @@ -328,6 +328,21 @@ Called after player information such as role, health, and ammo and equipment inf - *labelX* - The X value representing the correct indentation from the left side of the screen to add information - *labelY* - The Y value representing the first clear space to add information - *activeLabels* - The list of current active additional labels. Used to determine the labelY offset to use via: `labelY = labelY + (20 * #activeLabels)`. Be sure to insert an entry when you add your own label so other addons can space appropriately. *(Added in 1.6.11)* +- *x* - The X value representing the left edge of the player information HUD *(Added in 2.5.2)* +- *y* - The Y value representing the top edge of the player information HUD *(Added in 2.5.2)* + +### TTTHUDInfoPositionOverride(client, x, y, width, height) +Allows overriding the position of the player information HUD (role, health, ammo etc.).\ +*Realm:* Client\ +*Added in:* 2.5.2\ +*Parameters:* +- *client* - The local player +- *x* - The X position value of the top left corner of the element +- *y* - The Y position value of the top left corner of the element +- *width* - The element's width +- *height* - The element's height + +*Return:* The new x and y positions for the element (e.g. `return newX, newY`) ### TTTHUDRoleColorOverride(client, colorType) Allows overriding the color to use in place of the given player's normal role color.\ diff --git a/CONVARS.md b/CONVARS.md index f6cb8f00d..5601cfd2e 100644 --- a/CONVARS.md +++ b/CONVARS.md @@ -740,6 +740,8 @@ ttt_sponge_device_for_beggar 0 // Whether the Beggar sho ttt_sponge_device_for_beggar_heal 0 // Whether the Beggar should be fully healed when using the spongifier ttt_sponge_device_for_bodysnatcher 0 // Whether the Bodysnatcher should get the spongifier ttt_sponge_device_for_bodysnatcher_heal 0 // Whether the Bodysnatcher be fully healed when using the spongifier +ttt_sponge_device_for_cannibal 0 // Whether the Cannibal should get the spongifier +ttt_sponge_device_for_cannibal_heal 0 // Whether the Cannibal should be fully healed when using the spongifier ttt_sponge_device_for_clown 0 // Whether the Clown should get the spongifier ttt_sponge_device_for_clown_heal 0 // Whether the Clown should be fully healed when using the spongifier ttt_sponge_device_for_cupid 0 // Whether the Cupid should get the spongifier @@ -754,6 +756,7 @@ ttt_sponge_device_for_shadow 0 // Whether the Shadow sho ttt_sponge_device_for_shadow_heal 0 // Whether the Shadow should be fully healed when using the spongifier (only created and used when "ttt_shadow_is_jester" is enabled) ttt_sponge_device_for_swapper 0 // Whether the Swapper should get the spongifier ttt_sponge_device_for_swapper_heal 0 // Whether the Swapper should be fully healed when using the spongifier +ttt_sponge_win_ends_round 1 // Whether the round should end when the Sponge wins // Guesser ttt_guesser_can_guess_detectives 0 // Whether the Guesser is allowed to guess detectives @@ -775,6 +778,7 @@ ttt_cannibal_notify_killer 1 // Whether to notify a Ca ttt_cannibal_notify_sound 0 // Whether to play a cheering sound when a Cannibal is killed ttt_cannibal_notify_confetti 0 // Whether to throw confetti when a Cannibal is a killed ttt_cannibal_eat_cooldown 10 // The amount of time (in seconds) between uses of the Cannibal's Cannibalizer +ttt_cannibal_eat_sound_level 100 // The sound level (volume) to play the Cannibal's eat sound (set to 0 to disable) ttt_cannibal_damage_penalty 0 // The fraction a Cannibal's damage will be scaled by when they are attacking (Only applies if ttt_cannibal_is_independent is enabled) 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) @@ -784,6 +788,7 @@ ttt_cannibal_digestion 0 // Whether the Cannibal d 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) ttt_cannibal_digestion_poop_sound 1 // Whether the Cannibal causes a sound when poop is dropped from a digested victim (Only applies if ttt_cannibal_digestion is enabled) +ttt_cannibal_digestion_poop_sound_level 100 // The sound level (volume) to play the Cannibal's digestion poop sound (set to 0 to disable). (Only applies if ttt_cannibal_digestion is enabled) // ---------------------------------------- @@ -1419,6 +1424,8 @@ ttt_tracker_minimap_offset_y 14 // The screen offset from // Misc. // ---------------------------------------- ttt_distance_unit 1 // What unit to use when displaying distance. 0 - None (Source). 1 - Meters. 2 - Feet +ttt_infohud_offset_x 0 // The X (horizontal) offset of the player information HUD element +ttt_infohud_offset_y 0 // The Y (vertical) offset of the player information HUD element ``` ## Role Weapon Shop diff --git a/RELEASE.md b/RELEASE.md index e2f6a7337..4d938ae40 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,25 @@ # Release Notes +## 2.5.2 +**Released: August 8th, 2026** + +### Additions +- Added the new role that a player gets by being deputized by a Marshal to the event log message +- Added ability to control whether killing the Sponge ends the round (enabled by default) +- Added ability to adjust the Cannibal's eat and digestion poop sound volumes +- Added `ttt_infohud_offset_x` and `ttt_infohud_offset_y` client convars to allow players to reposition the player information HUD (role, health, ammo etc.) + +### Changes +- Ported "Optimize player spawn queue randomization in TTT" from base TTT + +### Fixes +- Fixed players swallowed by the Cannibal still being able to trigger traitor traps +- Fixed various roles erroring about unsupported hook 'TTTUpdateRoleState' + +### Developer +- Added `TTTHUDInfoPositionOverride` hook to override the position of the player information HUD (role, health, ammo etc.) +- Added new `x` and `y` parameters to `TTTHUDInfoPaint` hook which provide the raw position of the player information HUD (i.e. agnostic of any existing labels) + ## 2.5.1 **Released: July 25th, 2026** diff --git a/docs/api/hooks.html b/docs/api/hooks.html index 7416b5749..02ac5ce9a 100644 --- a/docs/api/hooks.html +++ b/docs/api/hooks.html @@ -507,8 +507,28 @@

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

+

+ Allows overriding the position of the player information HUD (role, health, ammo etc.).
+ Realm: Client
+ Added in: 2.5.2
+ Parameters: +

+ +

+ Return: The new x and y positions for the element (e.g. return newX, newY) +

+

TTTHUDRoleColorOverride(client, colorType)

Allows overriding the color to use in place of the given player's normal role color.
diff --git a/docs/teams/jester.html b/docs/teams/jester.html index 8b9977253..3f1833116 100644 --- a/docs/teams/jester.html +++ b/docs/teams/jester.html @@ -600,12 +600,24 @@

Role Configuration:

Boolean Whether the Cannibal causes a sound when poop is dropped from a digested victim. (Requires ttt_cannibal_digestion to be enabled.) + + ttt_cannibal_digestion_poop_sound_level + 100 + Integer + The sound level (volume) to play the Cannibal's digestion poop sound (set to 0 to disable). (Requires ttt_cannibal_digestion to be enabled.) + ttt_cannibal_eat_cooldown 10 Integer The amount of time in seconds between uses of the Cannibal's Cannibalizer. + + ttt_cannibal_eat_sound_level + 100 + Integer + The sound level (volume) to play the Cannibal's eat sound (set to 0 to disable). + ttt_cannibal_gains_health 0 @@ -1205,6 +1217,12 @@

Role Configuration:

Boolean Whether a specific jester role should be fully healed when using the spongifier. Replace * with the name of the jester role you want to configure without spaces or capital letters. + + ttt_sponge_win_ends_round + 1 + Boolean + Whether the round should end when the Sponge wins. +

A list of ConVars shared by every role and instructions for using ConVars can be found on the Configuring ConVars tutorial page.

diff --git a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua index 148934175..e7af2f61a 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_can_eater.lua @@ -43,8 +43,10 @@ SWEP.DigestionConVar = CreateConVar("ttt_cannibal_digestion", "0", FCVAR_REPLICA 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) if SERVER then + SWEP.EatSoundLevelConVar = CreateConVar("ttt_cannibal_eat_sound_level", "100", FCVAR_NONE, "The sound level (volume) to play the Cannibal's eat sound (set to 0 to disable)", 0, 511) SWEP.DigestionPoopConVar = CreateConVar("ttt_cannibal_digestion_poop", "1", FCVAR_NONE, "Whether the Cannibal drops poop when a victim is digested", 0, 1) - SWEP.DigestionPoopSoundConVar = CreateConVar("ttt_cannibal_digestion_poop_sound", "1", FCVAR_NONE, "Whether the Cannibal causes a sound when poop is dropped from a digested victim.", 0, 1) + SWEP.DigestionPoopSoundConVar = CreateConVar("ttt_cannibal_digestion_poop_sound", "1", FCVAR_NONE, "Whether the Cannibal causes a sound when poop is dropped from a digested victim", 0, 1) + SWEP.DigestionPoopSoundLevelConVar = CreateConVar("ttt_cannibal_digestion_poop_sound_level", "100", FCVAR_NONE, "The sound level (volume) to play the Cannibal's digestion poop sound (set to 0 to disable)", 0, 511) end local eatSounds = { @@ -148,7 +150,10 @@ function SWEP:PrimaryAttack() hitEnt:SetProperty("TTTCannibalEaten", owner:SteamID64()) hitEnt:QueueMessage(MSG_PRINTBOTH, "You have been eaten by " .. owner:Nick() .. "!") - owner:EmitSound(eatSounds[math.random(1, #eatSounds)], 100) + local soundLevel = self.EatSoundLevelConVar:GetInt() + if soundLevel > 0 then + owner:EmitSound(eatSounds[math.random(1, #eatSounds)], soundLevel) + end local cooldown = self.DeviceCooldownConVar:GetInt() if cooldown > 0 then @@ -214,8 +219,9 @@ function SWEP:PrimaryAttack() poop:SetCollisionGroup(COLLISION_GROUP_WEAPON) poop.fingerprints = fingerprints - if self.DigestionPoopSoundConVar:GetBool()then - owner:EmitSound(poopSounds[math.random(#poopSounds)], 100) + soundLevel = self.DigestionPoopSoundLevelConVar:GetInt() + if self.DigestionPoopSoundConVar:GetBool() and soundLevel > 0 then + owner:EmitSound(poopSounds[math.random(#poopSounds)], soundLevel) end end end diff --git a/gamemodes/terrortown/entities/weapons/weapon_kil_crowbar.lua b/gamemodes/terrortown/entities/weapons/weapon_kil_crowbar.lua index 7892509d1..174775fc9 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_kil_crowbar.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_kil_crowbar.lua @@ -41,7 +41,6 @@ SWEP.Secondary.Delay = 1 SWEP.IsGrenade = false SWEP.Kind = WEAPON_MELEE -SWEP.WeaponID = AMMO_CROWBAR SWEP.NoSights = true SWEP.IsSilent = true diff --git a/gamemodes/terrortown/entities/weapons/weapon_kil_knife.lua b/gamemodes/terrortown/entities/weapons/weapon_kil_knife.lua index a5327d997..2a29d15aa 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_kil_knife.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_kil_knife.lua @@ -44,7 +44,6 @@ SWEP.Secondary.Ammo = "none" SWEP.Secondary.Delay = 12 SWEP.Kind = WEAPON_NONE -SWEP.WeaponID = AMMO_CROWBAR SWEP.IsSilent = true diff --git a/gamemodes/terrortown/entities/weapons/weapon_qua_bomb_station.lua b/gamemodes/terrortown/entities/weapons/weapon_qua_bomb_station.lua index 03bc44d1d..2fcc18eed 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_qua_bomb_station.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_qua_bomb_station.lua @@ -46,7 +46,6 @@ SWEP.Secondary.Delay = 1.0 SWEP.Kind = WEAPON_EQUIP SWEP.CanBuy = { ROLE_QUACK } SWEP.LimitedStock = true -SWEP.WeaponID = AMMO_HEALTHSTATION SWEP.AllowDrop = false SWEP.NoSights = true diff --git a/gamemodes/terrortown/entities/weapons/weapon_qua_station_bomb.lua b/gamemodes/terrortown/entities/weapons/weapon_qua_station_bomb.lua index f2a7604c2..65bcf0fdf 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_qua_station_bomb.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_qua_station_bomb.lua @@ -27,7 +27,6 @@ SWEP.Category = WEAPON_CATEGORY_ROLE SWEP.CanBuy = { ROLE_QUACK } -- This is special equipment SWEP.Kind = WEAPON_EQUIP2 -SWEP.WeaponID = AMMO_STATIONBOMB SWEP.BlockShopRandomization = true diff --git a/gamemodes/terrortown/entities/weapons/weapon_spy_flaregun.lua b/gamemodes/terrortown/entities/weapons/weapon_spy_flaregun.lua index 241e297a6..791808d61 100644 --- a/gamemodes/terrortown/entities/weapons/weapon_spy_flaregun.lua +++ b/gamemodes/terrortown/entities/weapons/weapon_spy_flaregun.lua @@ -41,7 +41,6 @@ SWEP.Kind = WEAPON_ROLE SWEP.CanBuy = {} -- only traitors can buy SWEP.LimitedStock = true -- only buyable once SWEP.AllowDrop = false -SWEP.WeaponID = AMMO_FLARE SWEP.Tracer = "AR2Tracer" diff --git a/gamemodes/terrortown/gamemode/cl_disguise.lua b/gamemodes/terrortown/gamemode/cl_disguise.lua index 5697df393..6c595a885 100644 --- a/gamemodes/terrortown/gamemode/cl_disguise.lua +++ b/gamemodes/terrortown/gamemode/cl_disguise.lua @@ -15,8 +15,8 @@ function DISGUISE.CreateMenu(parent) local owned = LocalPlayer():HasEquipmentItem(EQUIP_DISGUISE) if not owned then - dform:Help(T("disg_not_owned")) - return dform + dform:Help(T("disg_not_owned")) + return dform end local dcheck = vgui.Create("DCheckBoxLabel", dform) @@ -24,8 +24,8 @@ function DISGUISE.CreateMenu(parent) dcheck:SetIndent(5) dcheck:SetValue(LocalPlayer():GetNWBool("disguised", false)) dcheck.OnChange = function(s, val) - RunConsoleCommand("ttt_set_disguise", val and "1" or "0") - end + RunConsoleCommand("ttt_set_disguise", val and "1" or "0") + end dform:AddItem(dcheck) dform:Help(T("disg_help1")) @@ -37,6 +37,23 @@ function DISGUISE.CreateMenu(parent) return dform end +local labelX = 0 +local labelY = 0 + +function DISGUISE.Bought(is_item, id) + if is_item and id == EQUIP_DISGUISE then + hook.Add("TTTHUDInfoPaint", "DisguiseLabelPos", function(client, label_left, label_top, _) + labelX = label_left + labelY = ScrH() - label_top + 20 + + if not client:HasEquipmentItem(EQUIP_DISGUISE) then + hook.Remove("TTTHUDInfoPaint", "DisguiseLabelPos") + end + end) + end +end +hook.Add("TTTBoughtItem", "DisguiseBoughtItem", DISGUISE.Bought) + function DISGUISE.Draw(client) if (not client) or not client:HasEquipmentItem(EQUIP_DISGUISE) then return end if not client:GetNWBool("disguised", false) then return end @@ -47,11 +64,7 @@ function DISGUISE.Draw(client) local text = T("disg_hud") local _, h = surface.GetTextSize(text) - local label_top = 140 - if client:HasEquipmentItem(EQUIP_RADAR) then - label_top = label_top + 20 - end - surface.SetTextPos(36, ScrH() - label_top - h) + surface.SetTextPos(labelX, labelY - h) surface.DrawText(text) end diff --git a/gamemodes/terrortown/gamemode/cl_help.lua b/gamemodes/terrortown/gamemode/cl_help.lua index 16d2cde87..fe76f575c 100644 --- a/gamemodes/terrortown/gamemode/cl_help.lua +++ b/gamemodes/terrortown/gamemode/cl_help.lua @@ -757,6 +757,12 @@ function HELPSCRN:CreateConfig(dsettings) cb = dgui:CheckBox(GetTranslation("set_hide_ammo"), "ttt_hide_ammo") cb:SetTooltip(GetTranslation("set_hide_ammo_tip")) + cb = dgui:NumSlider(GetTranslation("set_infohud_offset_x"), "ttt_infohud_offset_x", 0, GetConVar("ttt_infohud_offset_x"):GetMax(), 0) + cb:SetTooltip(GetTranslation("set_infohud_offset_x_tip")) + + cb = dgui:NumSlider(GetTranslation("set_infohud_offset_y"), "ttt_infohud_offset_y", 0, GetConVar("ttt_infohud_offset_y"):GetMax(), 0) + cb:SetTooltip(GetTranslation("set_infohud_offset_y_tip")) + cb = dgui:TextEntry(GetTranslation("set_radio_button"), "ttt_radio_button") cb:SetTooltip(GetTranslation("set_radio_button_tip")) diff --git a/gamemodes/terrortown/gamemode/cl_hud.lua b/gamemodes/terrortown/gamemode/cl_hud.lua index dee35373b..0a1a0a137 100644 --- a/gamemodes/terrortown/gamemode/cl_hud.lua +++ b/gamemodes/terrortown/gamemode/cl_hud.lua @@ -372,24 +372,27 @@ local function GetAmmo(ply) return ammo_clip, ammo_max, ammo_inv end +local roleAreaHeight = 30 +local roleAreaWidth = 170 + local function DrawBg(x, y, width, height, client) if not hide_role then hide_role = GetConVar("ttt_hide_role") end - -- Traitor area sizes - local th = 30 - local tw = 170 + -- Role area sizes + local rh = roleAreaHeight + local rw = roleAreaWidth -- Adjust for these - y = y - th - height = height + th + y = y - rh + height = height + rh -- main bg area, invariant -- encompasses entire area draw.RoundedBox(8, x, y, width, height, bg_colors.background_main) - -- main border, traitor based + -- main border, role based local col = ROLE_COLORS[client:GetDisplayedRole()] if GAMEMODE.round_state ~= ROUND_ACTIVE then col = bg_colors.noround @@ -400,7 +403,7 @@ local function DrawBg(x, y, width, height, client) if new_col then col = new_col end end - draw.RoundedBoxEx(8, x, y, tw, th, col, true, false, false, true) + draw.RoundedBoxEx(8, x, y, rw, rh, col, true, false, false, true) end function CRHUD:ShadowedText(text, font, x, y, color, xalign, yalign) @@ -480,6 +483,14 @@ end local ttt_health_label = CreateClientConVar("ttt_health_label", "0", true) +local infoWidth = 250 +local infoHeight = 94 + +local infohud_offset_max_x = ScrW() - infoWidth - (margin * 2) +local infohud_offset_max_y = ScrH() - infoHeight - (margin * 2) - roleAreaHeight +local ttt_infohud_offset_x = CreateClientConVar("ttt_infohud_offset_x", "0", true, false, "The X (horizontal) offset of the player information HUD element", 0, infohud_offset_max_x) +local ttt_infohud_offset_y = CreateClientConVar("ttt_infohud_offset_y", "0", true, false, "The Y (vertical) offset of the player information HUD element", 0, infohud_offset_max_y) + local armor_tex = surface.GetTextureID("vgui/ttt/equip/armor") local drown_start = nil -- Found in the "Drowning Indicator for TTT" addon which in turn found it "in Sourceā„¢ Code" @@ -487,11 +498,18 @@ local MAX_AIR_TIME_SECONDS = 8 local function InfoPaint(client) local L = GetLang() - local width = 250 - local height = 94 + local width = infoWidth + local height = infoHeight - local x = margin - local y = ScrH() - margin - height + local defaultX = margin + local defaultY = ScrH() - margin - height + + local x = defaultX + ttt_infohud_offset_x:GetInt() + local y = defaultY - ttt_infohud_offset_y:GetInt() + + local overrideX, overrideY = CallHook("TTTHUDInfoPositionOverride", nil, client, x, y - roleAreaHeight, width, height + roleAreaHeight) + if overrideX then x = overrideX end + if overrideY then y = overrideY + roleAreaHeight end DrawBg(x, y, width, height, client) @@ -508,7 +526,7 @@ local function InfoPaint(client) CRHUD:PaintBar(8, x + margin, health_y, bar_width, bar_height, overhealth_colors, MathMax(0, health - maxHealth) / maxHealth) CRHUD:PaintBar(8, x + margin, health_y, bar_width, bar_height, extraoverhealth_colors, MathMax(0, health - (2 * maxHealth)) / maxHealth) - CRHUD:ShadowedText(tostring(health), "HealthAmmo", bar_width, health_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT) + CRHUD:ShadowedText(tostring(health), "HealthAmmo", x + bar_width - margin, health_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT) local health_offset = 0 if client:HasEquipmentItem(EQUIP_ARMOR) then @@ -533,7 +551,7 @@ local function InfoPaint(client) CRHUD:PaintBar(8, x + margin, ammo_y, bar_width, bar_height, ammo_colors, ammo_clip / ammo_max) local text = format("%i + %02i", ammo_clip, ammo_inv) - CRHUD:ShadowedText(text, "HealthAmmo", bar_width, ammo_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT) + CRHUD:ShadowedText(text, "HealthAmmo", x + bar_width - margin, ammo_y, COLOR_WHITE, TEXT_ALIGN_RIGHT, TEXT_ALIGN_RIGHT) end end @@ -558,10 +576,10 @@ local function InfoPaint(client) drown_start = nil end - -- Draw traitor state + -- Draw role state local round_state = GAMEMODE.round_state - local traitor_y = y - 30 + local role_y = y - roleAreaHeight local text if round_state == ROUND_ACTIVE then if hide_role:GetBool() then @@ -583,9 +601,9 @@ local function InfoPaint(client) if text then if #text > 10 then - CRHUD:ShadowedText(text, "TraitorStateSmall", x + margin + 74, traitor_y + 2, COLOR_WHITE, TEXT_ALIGN_CENTER) + CRHUD:ShadowedText(text, "TraitorStateSmall", x + margin + 74, role_y + 2, COLOR_WHITE, TEXT_ALIGN_CENTER) else - CRHUD:ShadowedText(text, "TraitorState", x + margin + 74, traitor_y, COLOR_WHITE, TEXT_ALIGN_CENTER) + CRHUD:ShadowedText(text, "TraitorState", x + margin + 74, role_y, COLOR_WHITE, TEXT_ALIGN_CENTER) end end @@ -598,7 +616,7 @@ local function InfoPaint(client) local font = "TimeLeft" local color = COLOR_WHITE local rx = x + margin + 170 - local ry = traitor_y + 3 + local ry = role_y + 3 -- Time displays differently depending on whether haste mode is on, -- whether the player is traitor or not, and whether it is overtime. @@ -634,8 +652,9 @@ local function InfoPaint(client) CRHUD:ShadowedText(text, font, rx, ry, color) - local label_top = 140 - local label_left = 36 + local label_top = ScrH() - y + roleAreaHeight + 6 + local label_left = x + if client:HasEquipmentItem(EQUIP_RADAR) and RADAR.enable then label_top = label_top + 20 end @@ -645,7 +664,7 @@ local function InfoPaint(client) -- Allow other addons to add stuff to the player info HUD local active_labels = {} - CallHook("TTTHUDInfoPaint", nil, client, label_left, label_top, active_labels) + CallHook("TTTHUDInfoPaint", nil, client, label_left, label_top, active_labels, x, y - roleAreaHeight) end -- Paints player status HUD element in the bottom left diff --git a/gamemodes/terrortown/gamemode/cl_radar.lua b/gamemodes/terrortown/gamemode/cl_radar.lua index cd283512d..397fe555c 100644 --- a/gamemodes/terrortown/gamemode/cl_radar.lua +++ b/gamemodes/terrortown/gamemode/cl_radar.lua @@ -28,6 +28,11 @@ RADAR.teleport_marks = {} local detectives_corpse_call_expiration = GetConVar("ttt_detectives_corpse_call_expiration") +local labelX = 0 +local labelY = 0 + +hook.Remove("TTTHUDInfoPaint", "RadarTimeRemainingPos") + function RADAR:EndScan() self.enable = false self.endtime = CurTime() @@ -76,6 +81,15 @@ end function RADAR.Bought(is_item, id) if is_item and id == EQUIP_RADAR then RunConsoleCommand("ttt_radar_scan") + + hook.Add("TTTHUDInfoPaint", "RadarTimeRemainingPos", function(client, label_left, label_top, _) + labelX = label_left + labelY = ScrH() - label_top + 20 + + if not client:HasEquipmentItem(EQUIP_RADAR) then + hook.Remove("TTTHUDInfoPaint", "RadarTimeRemainingPos") + end + end) end end hook.Add("TTTBoughtItem", "RadarBoughtItem", RADAR.Bought) @@ -294,7 +308,10 @@ function RADAR:Draw(client) local text = GetPTranslation("radar_hud", { time = FormatTime(remaining, "%02i:%02i") }) local _, h = surface.GetTextSize(text) - surface.SetTextPos(36, ScrH() - 140 - h) + if client:HasEquipmentItem(EQUIP_DISGUISE) and client:GetNWBool("disguised", false) then + labelY = labelY + 20 + end + surface.SetTextPos(labelX, labelY - h) surface.DrawText(text) end diff --git a/gamemodes/terrortown/gamemode/init.lua b/gamemodes/terrortown/gamemode/init.lua index b99323d76..a6aa80f94 100644 --- a/gamemodes/terrortown/gamemode/init.lua +++ b/gamemodes/terrortown/gamemode/init.lua @@ -100,12 +100,12 @@ local util = util local CallHook = hook.Call local RunHook = hook.Run -local GetAllPlayers = player.GetAll local PlayerIterator = player.Iterator local MathRand = math.Rand local StringFormat = string.format local StringLower = string.lower local StringUpper = string.upper +local TableShuffle = table.Shuffle -- Round times CreateConVar("ttt_roundtime_minutes", "10", FCVAR_NOTIFY) @@ -743,13 +743,16 @@ function SpawnWillingPlayers(dead_only) local num_spawns = #GetSpawnEnts() local to_spawn = {} - for _, ply in RandomPairs(GetAllPlayers()) do + for _, ply in PlayerIterator() do if IsValid(ply) and ply:ShouldSpawn() then table.insert(to_spawn, ply) GAMEMODE:PlayerSpawnAsSpectator(ply) end end + -- Shuffle the table of queued players to randomize the spawn order + TableShuffle(to_spawn) + local sfn = function() local c = 0 -- fill the available spawnpoints with players that need @@ -1222,7 +1225,7 @@ function SelectRoles() end end - table.Shuffle(choices) + TableShuffle(choices) local choice_count = #choices -- special spawning cvars @@ -1349,7 +1352,7 @@ function SelectRoles() end end end - table.Shuffle(groupRoles) + TableShuffle(groupRoles) local chosenRole = groupRoles[1] for _, role in ipairs(groupRoles) do if role ~= chosenRole then diff --git a/gamemodes/terrortown/gamemode/lang/english.lua b/gamemodes/terrortown/gamemode/lang/english.lua index 362160b2d..c1097b90b 100644 --- a/gamemodes/terrortown/gamemode/lang/english.lua +++ b/gamemodes/terrortown/gamemode/lang/english.lua @@ -292,6 +292,10 @@ L.set_hide_role = "Hide your role in the HUD" L.set_hide_role_tip = "By default your role will appear in the bottom left of the HUD. Turn this on to prevent screen cheating." L.set_hide_ammo = "Hide your weapon ammo in the HUD" L.set_hide_ammo_tip = "By default your weapon ammo will appear in the bottom left of the HUD. Turn this on if you have another addon that does that for you." +L.set_infohud_offset_x = "Info HUD X (horizontal) offset" +L.set_infohud_offset_x_tip = "The horizontal offset (in pixels) of the player info HUD (role, health, ammo etc.)" +L.set_infohud_offset_y = "Info HUD Y (vertical) offset" +L.set_infohud_offset_y_tip = "The vertical offset (in pixels) of the player info HUD (role, health, ammo etc.)" L.set_radio_button = "Radio menu button" L.set_radio_button_tip = "What button to press to open/close the radio menu" L.set_bypass_culling = "Bypass map culling" diff --git a/gamemodes/terrortown/gamemode/roles/assassin/cl_assassin.lua b/gamemodes/terrortown/gamemode/roles/assassin/cl_assassin.lua index b07edd302..f898048b0 100644 --- a/gamemodes/terrortown/gamemode/roles/assassin/cl_assassin.lua +++ b/gamemodes/terrortown/gamemode/roles/assassin/cl_assassin.lua @@ -175,7 +175,7 @@ local function EnableAssassinTargetHighlights() end) end -local function Assassin_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Assassin_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() assassin_target_vision = assassin_target_vision_enabled:GetBool() @@ -184,7 +184,7 @@ local function Assassin_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Assassin_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Assassin_Highlight_Think() @@ -379,8 +379,7 @@ ROLE_REGISTERED_HOOKS[ROLE_ASSASSIN] = { ["TTTScoreboardPlayerRole"] = Assassin_TTTScoreboardPlayerRole, ["TTTScoringWinTitle"] = Assassin_TTTScoringWinTitle, ["TTTTargetIDPlayerTargetIcon"] = Assassin_TTTTargetIDPlayerTargetIcon, - ["TTTTargetIDPlayerText"] = Assassin_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Assassin_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Assassin_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Assassin_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua b/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua index c7e4be3ab..e0220e6f3 100644 --- a/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua +++ b/gamemodes/terrortown/gamemode/roles/cannibal/cannibal.lua @@ -114,6 +114,7 @@ local function Cannibal_TTTOnRoleAbilityDisabled(ply) ReleaseEatenPlayers(ply, ply:Nick() .. " felt unwell and spat you out!") end + ------------------------- -- EATEN PLAYER BLOCKS -- ------------------------- @@ -124,6 +125,12 @@ local function Cannibal_PlayerCanPickupWeapon(ply, wep) if ply.TTTCannibalEaten then return false end end +local function Cannibal_TTTCanUseTraitorButton(ent, ply) + if not IsValid(ply) then return end + + if ply.TTTCannibalEaten then return false end +end + local function ShouldBlockCommunications(listener, speaker) if not speaker.TTTCannibalEaten then return false end if listener.TTTCannibalEaten and listener.TTTCannibalEaten == speaker.TTTCannibalEaten then return false end @@ -235,6 +242,7 @@ ROLE_REGISTERED_HOOKS[ROLE_CANNIBAL] = { ["PlayerDeath"] = Cannibal_PlayerDeath, ["PlayerDisconnected"] = Cannibal_PlayerDisconnected, ["ScalePlayerDamage"] = Cannibal_ScalePlayerDamage, + ["TTTCanUseTraitorButton"] = Cannibal_TTTCanUseTraitorButton, ["TTTCheckForWin"] = Cannibal_TTTCheckForWin, ["TTTEndRound"] = Cannibal_TTTEndRound, ["TTTOnRoleAbilityDisabled"] = Cannibal_TTTOnRoleAbilityDisabled, diff --git a/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua b/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua index 1f0a019e2..6893a8291 100644 --- a/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua +++ b/gamemodes/terrortown/gamemode/roles/cannibal/cl_cannibal.lua @@ -164,12 +164,8 @@ end -- HUD -- --------- -local function Cannibal_HUDDrawScoreBoard() - if not IsPlayer(client) then - client = LocalPlayer() - end - - if not client.TTTCannibalEaten then return end +local function Cannibal_TTTHUDInfoPaint(cli, label_left, label_top, active_labels, x, y) + if not cli.TTTCannibalEaten then return end local bar_colors = { border = COLOR_WHITE, @@ -177,8 +173,10 @@ local function Cannibal_HUDDrawScoreBoard() fill = ROLE_COLORS[ROLE_CANNIBAL] } - CRHUD:PaintBar(8, 20, ScrH() - 59, 230, 25, bar_colors, 1) - draw.SimpleText(LANG.GetTranslation("cannibal_swallowed"), "HealthAmmo", 135, ScrH() - 59, Color(255, 255, 255, 200), TEXT_ALIGN_CENTER) + local barX = x + 10 + local barY = y + 75 + CRHUD:PaintBar(8, barX, barY, 230, 25, bar_colors, 1) + draw.SimpleText(LANG.GetTranslation("cannibal_swallowed"), "HealthAmmo", x + 125, barY, Color(255, 255, 255, 200), TEXT_ALIGN_CENTER) end -------------- @@ -228,9 +226,9 @@ end) ------------------ ROLE_REGISTERED_HOOKS[ROLE_CANNIBAL] = { - ["HUDDrawScoreBoard"] = Cannibal_HUDDrawScoreBoard, ["TTTEventFinishIconText"] = Cannibal_TTTEventFinishIconText, ["TTTEventFinishText"] = Cannibal_TTTEventFinishText, + ["TTTHUDInfoPaint"] = Cannibal_TTTHUDInfoPaint, ["TTTScoreGroup"] = Cannibal_TTTScoreGroup, ["TTTScoreboardPlayerName"] = Cannibal_TTTScoreboardPlayerName, ["TTTScoreboardPlayerRole"] = Cannibal_TTTScoreboardPlayerRole, diff --git a/gamemodes/terrortown/gamemode/roles/cannibal/shared.lua b/gamemodes/terrortown/gamemode/roles/cannibal/shared.lua index e1c6ec45f..224ea75cc 100644 --- a/gamemodes/terrortown/gamemode/roles/cannibal/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/cannibal/shared.lua @@ -40,6 +40,11 @@ ROLE_CONVARS[ROLE_CANNIBAL] = { type = ROLE_CONVAR_TYPE_NUM, decimal = 0 }, + { + cvar = "ttt_cannibal_eat_sound_level", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 + }, { cvar = "ttt_cannibal_damage_penalty", type = ROLE_CONVAR_TYPE_NUM, @@ -76,6 +81,11 @@ ROLE_CONVARS[ROLE_CANNIBAL] = { { cvar = "ttt_cannibal_digestion_poop_sound", type = ROLE_CONVAR_TYPE_BOOL + }, + { + cvar = "ttt_cannibal_digestion_poop_sound_level", + type = ROLE_CONVAR_TYPE_NUM, + decimal = 0 } } diff --git a/gamemodes/terrortown/gamemode/roles/cupid/cl_cupid.lua b/gamemodes/terrortown/gamemode/roles/cupid/cl_cupid.lua index a4464df2a..ec371d5f1 100644 --- a/gamemodes/terrortown/gamemode/roles/cupid/cl_cupid.lua +++ b/gamemodes/terrortown/gamemode/roles/cupid/cl_cupid.lua @@ -302,7 +302,7 @@ local function EnableLoverHighlights() end) end -local function Cupid_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Cupid_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() lover_vision = cupid_lover_vision_enabled:GetBool() @@ -311,7 +311,7 @@ local function Cupid_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Cupid_Highlight_PreDrawHalos") vision_enabled = false end -end +end) local function Cupid_Highlight_Think() if not IsPlayer(client) or not client:Alive() or client:IsSpec() then return end @@ -447,8 +447,7 @@ ROLE_REGISTERED_HOOKS[ROLE_CUPID] = { ["TTTTargetIDPlayerRing"] = Cupid_TTTTargetIDPlayerRing, ["TTTTargetIDPlayerRoleIcon"] = Cupid_TTTTargetIDPlayerRoleIcon, ["TTTTargetIDPlayerTargetIcon"] = Cupid_TTTTargetIDPlayerTargetIcon, - ["TTTTargetIDPlayerText"] = Cupid_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Cupid_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Cupid_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Cupid_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/guesser/cl_guesser.lua b/gamemodes/terrortown/gamemode/roles/guesser/cl_guesser.lua index a963f3210..9eb92513d 100644 --- a/gamemodes/terrortown/gamemode/roles/guesser/cl_guesser.lua +++ b/gamemodes/terrortown/gamemode/roles/guesser/cl_guesser.lua @@ -358,7 +358,7 @@ local function EnableGuesserTargetHighlights() end) end -local function Guesser_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Guesser_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() -- Disable highlights on role change @@ -366,7 +366,7 @@ local function Guesser_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Guesser_Highlight_PreDrawHalos") vision_enabled = false end -end +end) local function Guesser_Highlight_Think() if not IsPlayer(client) or not client:Alive() or client:IsSpec() then return end @@ -451,8 +451,7 @@ ROLE_REGISTERED_HOOKS[ROLE_GUESSER] = { ["TTTScoringSummaryRender"] = Guesser_TTTScoringSummaryRender, ["TTTTargetIDPlayerRing"] = Guesser_TTTTargetIDPlayerRing, ["TTTTargetIDPlayerRoleIcon"] = Guesser_TTTTargetIDPlayerRoleIcon, - ["TTTTargetIDPlayerText"] = Guesser_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Guesser_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Guesser_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Guesser_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/hivemind/cl_hivemind.lua b/gamemodes/terrortown/gamemode/roles/hivemind/cl_hivemind.lua index 5c958826e..883ac15db 100644 --- a/gamemodes/terrortown/gamemode/roles/hivemind/cl_hivemind.lua +++ b/gamemodes/terrortown/gamemode/roles/hivemind/cl_hivemind.lua @@ -131,7 +131,7 @@ local function EnableHiveMindHighlights() end) end -local function HiveMind_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "HiveMind_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() hivemind_vision = hivemind_vision_enabled:GetBool() @@ -140,7 +140,7 @@ local function HiveMind_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "HiveMind_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function HiveMind_Highlight_Think() @@ -249,8 +249,7 @@ ROLE_REGISTERED_HOOKS[ROLE_HIVEMIND] = { ["TTTScoringWinTitle"] = HiveMind_TTTScoringWinTitle, ["TTTTargetIDPlayerRing"] = HiveMind_TTTTargetIDPlayerRing, ["TTTTargetIDPlayerRoleIcon"] = HiveMind_TTTTargetIDPlayerRoleIcon, - ["TTTTargetIDPlayerText"] = HiveMind_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = HiveMind_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = HiveMind_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "HiveMind_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/killer/cl_killer.lua b/gamemodes/terrortown/gamemode/roles/killer/cl_killer.lua index 02888d4e1..f17a05296 100644 --- a/gamemodes/terrortown/gamemode/roles/killer/cl_killer.lua +++ b/gamemodes/terrortown/gamemode/roles/killer/cl_killer.lua @@ -76,7 +76,7 @@ local function EnableKillerHighlights() end) end -local function Killer_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Killer_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() killer_vision = killer_vision_enabled:GetBool() can_see_jesters = killer_can_see_jesters:GetBool() @@ -86,7 +86,7 @@ local function Killer_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Killer_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Killer_Highlight_Think() @@ -214,8 +214,7 @@ ROLE_REGISTERED_HOOKS[ROLE_KILLER] = { ["TTTEventFinishText"] = Killer_TTTEventFinishText, ["TTTScoringWinTitle"] = Killer_TTTScoringWinTitle, ["TTTShouldPlayerSmoke"] = Killer_TTTShouldPlayerSmoke, - ["TTTTargetIDPlayerTargetIcon"] = Killer_TTTTargetIDPlayerTargetIcon, - ["TTTUpdateRoleState"] = Killer_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerTargetIcon"] = Killer_TTTTargetIDPlayerTargetIcon } AddHook("TTTPrepareRound", "Killer_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/marshal/cl_marshal.lua b/gamemodes/terrortown/gamemode/roles/marshal/cl_marshal.lua index c5e25d25b..ea2ad56a2 100644 --- a/gamemodes/terrortown/gamemode/roles/marshal/cl_marshal.lua +++ b/gamemodes/terrortown/gamemode/roles/marshal/cl_marshal.lua @@ -22,7 +22,7 @@ AddHook("Initialize", "Marshal_Translations_Initialize", function() LANG.AddToLanguage("english", "marshalbadge_help_sec", "The target player will become " .. ROLE_STRINGS_EXT[ROLE_DEPUTY] .. " or " .. ROLE_STRINGS[ROLE_IMPERSONATOR]) -- Event - LANG.AddToLanguage("english", "ev_marshal_deputize", "{target} was deputized by {marshal}") + LANG.AddToLanguage("english", "ev_marshal_deputize", "{target} was deputized by {marshal}, converting them into {role}") -- Announcement LANG.AddToLanguage("english", "marshal_deputize_announce", "{amarshal} has promoted {target} to be {adeputy}") @@ -55,7 +55,7 @@ AddHook("Initialize", "Marshal_Scoring_Initialize", function() local PT = LANG.GetParamTranslation Event(EVENT_DEPUTIZED, { text = function(e) - return PT("ev_marshal_deputize", {target = e.tar, marshal = e.ply}) + return PT("ev_marshal_deputize", {target = e.tar, marshal = e.ply, role = e.rol}) end, icon = function(e) return traitor_icon, "Deputized" @@ -66,9 +66,17 @@ net.Receive("TTT_Deputized", function(len) local marshalname = net.ReadString() local targetname = net.ReadString() local targetsid = net.ReadString() + + local targetply = player.GetBySteamID64(targetsid) + local targetrole = "" + if IsValid(targetply) then + targetrole = ROLE_STRINGS_EXT[targetply:GetRole()] + end + CLSCORE:AddEvent({ id = EVENT_DEPUTIZED, tar = targetname, + rol = targetrole, ply = marshalname, sid64 = targetsid, bonus = 1 diff --git a/gamemodes/terrortown/gamemode/roles/medium/cl_medium.lua b/gamemodes/terrortown/gamemode/roles/medium/cl_medium.lua index 0e3b16298..fb62e1eb6 100644 --- a/gamemodes/terrortown/gamemode/roles/medium/cl_medium.lua +++ b/gamemodes/terrortown/gamemode/roles/medium/cl_medium.lua @@ -54,9 +54,9 @@ end) ------------------ local spirit_vision = true -local function Medium_RoleFeature_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Medium_RoleFeature_TTTUpdateRoleState", function() spirit_vision = medium_spirit_vision:GetBool() -end +end) local cacheTime = CurTime() local cacheLength = 5 @@ -380,6 +380,5 @@ ROLE_REGISTERED_HOOKS[ROLE_MEDIUM] = { ["PostDrawTranslucentRenderables"] = Medium_PostDrawTranslucentRenderables, ["Think"] = Medium_RoleFeature_Think, ["TTTScoreboardPlayerRole"] = Medium_TTTScoreboardPlayerRole, - ["TTTScoreGroup"] = Medium_TTTScoreGroup, - ["TTTUpdateRoleState"] = Medium_RoleFeature_TTTUpdateRoleState + ["TTTScoreGroup"] = Medium_TTTScoreGroup } \ No newline at end of file diff --git a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua index fa7923e88..4081701c3 100644 --- a/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua +++ b/gamemodes/terrortown/gamemode/roles/shadow/cl_shadow.lua @@ -256,7 +256,7 @@ local function EnableShadowTargetHighlights() end) end -local function Shadow_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Shadow_Highlight_TTTUpdateRoleState", function() client = client or LocalPlayer() -- Disable highlights on role change @@ -264,7 +264,7 @@ local function Shadow_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Shadow_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Shadow_Highlight_Think() @@ -675,8 +675,7 @@ ROLE_REGISTERED_HOOKS[ROLE_SHADOW] = { ["TTTTargetIDPlayerRing"] = Shadow_TTTTargetIDPlayerRing, ["TTTTargetIDPlayerRoleIcon"] = Shadow_TTTTargetIDPlayerRoleIcon, ["TTTTargetIDPlayerTargetIcon"] = Shadow_TTTTargetIDPlayerTargetIcon, - ["TTTTargetIDPlayerText"] = Shadow_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Shadow_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Shadow_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Shadow_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua b/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua index ece808b25..2c4bc6ead 100644 --- a/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua +++ b/gamemodes/terrortown/gamemode/roles/sponge/cl_sponge.lua @@ -1,12 +1,14 @@ local hook = hook local math = math local player = player +local table = table local AddHook = hook.Add local MathCos = math.cos local MathSin = math.sin -local StringUpper = string.upper local PlayerIterator = player.Iterator +local StringUpper = string.upper +local TableInsert = table.insert ------------- -- CONVARS -- @@ -217,6 +219,21 @@ local function Sponge_TTTScoringWinTitle(wintype, wintitles, title, secondary_wi end end +local sponge_wins = false +local function Sponge_TTTScoringSecondaryWins(wintype, secondary_wins) + if sponge_wins then + TableInsert(secondary_wins, ROLE_SPONGE) + end +end + +net.Receive("TTT_SpongeWin", function() + sponge_wins = true +end) + +AddHook("TTTPrepareRound", "Sponge_TTTPrepareRound", function() + sponge_wins = false +end) + ------------ -- EVENTS -- ------------ @@ -291,6 +308,7 @@ ROLE_REGISTERED_HOOKS[ROLE_SPONGE] = { ["TTTEventFinishText"] = Sponge_TTTEventFinishText, ["TTTPlayerAliveClientThink"] = Sponge_RoleFeatures_TTTPlayerAliveClientThink, ["TTTScoreboardPlayerRole"] = Sponge_TTTScoreboardPlayerRole, + ["TTTScoringSecondaryWins"] = Sponge_TTTScoringSecondaryWins, ["TTTScoringSummaryRender"] = Sponge_TTTScoringSummaryRender, ["TTTScoringWinTitle"] = Sponge_TTTScoringWinTitle, ["TTTTargetIDPlayerRing"] = Sponge_TTTTargetIDPlayerRing, diff --git a/gamemodes/terrortown/gamemode/roles/sponge/shared.lua b/gamemodes/terrortown/gamemode/roles/sponge/shared.lua index dfc41c919..3b3da7d82 100644 --- a/gamemodes/terrortown/gamemode/roles/sponge/shared.lua +++ b/gamemodes/terrortown/gamemode/roles/sponge/shared.lua @@ -33,6 +33,10 @@ TableInsert(ROLE_CONVARS[ROLE_SPONGE], { type = ROLE_CONVAR_TYPE_NUM, decimal = 0 }) +TableInsert(ROLE_CONVARS[ROLE_SPONGE], { + cvar = "ttt_sponge_win_ends_round", + type = ROLE_CONVAR_TYPE_BOOL +}) TableInsert(ROLE_CONVARS[ROLE_SPONGE], { cvar = "ttt_sponge_notify_mode", type = ROLE_CONVAR_TYPE_DROPDOWN, diff --git a/gamemodes/terrortown/gamemode/roles/sponge/sponge.lua b/gamemodes/terrortown/gamemode/roles/sponge/sponge.lua index c78aab07a..a018ac002 100644 --- a/gamemodes/terrortown/gamemode/roles/sponge/sponge.lua +++ b/gamemodes/terrortown/gamemode/roles/sponge/sponge.lua @@ -8,6 +8,8 @@ local timer = timer local AddHook = hook.Add local PlayerIterator = player.Iterator +util.AddNetworkString("TTT_SpongeWin") + ------------- -- CONVARS -- ------------- @@ -16,6 +18,7 @@ CreateConVar("ttt_sponge_notify_mode", "0", FCVAR_NONE, "The logic to use when n CreateConVar("ttt_sponge_notify_killer", "1", FCVAR_NONE, "Whether to notify a sponge's killer", 0, 1) CreateConVar("ttt_sponge_notify_sound", "0", FCVAR_NONE, "Whether to play a cheering sound when a sponge is killed", 0, 1) CreateConVar("ttt_sponge_notify_confetti", "0", FCVAR_NONE, "Whether to throw confetti when a sponge is a killed", 0, 1) +local sponge_win_ends_round = CreateConVar("ttt_sponge_win_ends_round", "1", FCVAR_NONE, "Whether the round should end when the sponge wins", 0, 1) local sponge_aura_float_time = CreateConVar("ttt_sponge_aura_float_time", "0", FCVAR_NONE, "The amount of time (in seconds) a player can spend outside the Sponge's aura before they are no longer considered inside", 0, 10) local sponge_aura_radius = GetConVar("ttt_sponge_aura_radius") @@ -201,6 +204,12 @@ local function Sponge_WinCheck_PlayerDeath(victim, infl, attacker) SpongeKilledNotification(attacker, victim) victim:SetNWString("SpongeKiller", attacker:Nick()) + if not sponge_win_ends_round:GetBool() then + net.Start("TTT_SpongeWin") + net.Broadcast() + return + end + -- If we're debugging, don't end the round if GetConVar("ttt_debug_preventwin"):GetBool() then return diff --git a/gamemodes/terrortown/gamemode/roles/vampire/cl_vampire.lua b/gamemodes/terrortown/gamemode/roles/vampire/cl_vampire.lua index b7afa9c8d..99a6a95d3 100644 --- a/gamemodes/terrortown/gamemode/roles/vampire/cl_vampire.lua +++ b/gamemodes/terrortown/gamemode/roles/vampire/cl_vampire.lua @@ -207,7 +207,7 @@ local function EnableVampireHighlights() end) end -local function Vampire_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Vampire_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() vampire_vision = vampire_vision_enabled:GetBool() jesters_visible_to_traitors = GetConVar("ttt_jesters_visible_to_traitors"):GetBool() @@ -219,7 +219,7 @@ local function Vampire_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Vampire_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Vampire_Highlight_Think() @@ -329,8 +329,7 @@ ROLE_REGISTERED_HOOKS[ROLE_VAMPIRE] = { ["TTTRolePopupParams"] = Vampire_TTTRolePopupParams, ["TTTScoringSummaryRender"] = Vampire_TTTScoringSummaryRender, ["TTTScoringWinTitle"] = Vampire_TTTScoringWinTitle, - ["TTTTargetIDPlayerTargetIcon"] = Vampire_TTTTargetIDPlayerTargetIcon, - ["TTTUpdateRoleState"] = Vampire_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerTargetIcon"] = Vampire_TTTTargetIDPlayerTargetIcon } AddHook("TTTPrepareRound", "Vampire_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/vindicator/cl_vindicator.lua b/gamemodes/terrortown/gamemode/roles/vindicator/cl_vindicator.lua index 9166de105..c720a4445 100644 --- a/gamemodes/terrortown/gamemode/roles/vindicator/cl_vindicator.lua +++ b/gamemodes/terrortown/gamemode/roles/vindicator/cl_vindicator.lua @@ -126,7 +126,7 @@ local function EnableVindicatorTargetHighlights() end) end -local function Vindicator_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Vindicator_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() -- Disable highlights on role change @@ -134,7 +134,7 @@ local function Vindicator_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Vindicator_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Vindicator_Highlight_Think() @@ -350,8 +350,7 @@ ROLE_REGISTERED_HOOKS[ROLE_VINDICATOR] = { ["TTTScoringSummaryRender"] = Vindicator_TTTScoringSummaryRender, ["TTTScoringWinTitle"] = Vindicator_TTTScoringWinTitle, ["TTTTargetIDPlayerTargetIcon"] = Vindicator_TTTTargetIDPlayerTargetIcon, - ["TTTTargetIDPlayerText"] = Vindicator_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Vindicator_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Vindicator_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Vindicator_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/roles/zombie/cl_zombie.lua b/gamemodes/terrortown/gamemode/roles/zombie/cl_zombie.lua index 2a1b230a8..f1ebe12c2 100644 --- a/gamemodes/terrortown/gamemode/roles/zombie/cl_zombie.lua +++ b/gamemodes/terrortown/gamemode/roles/zombie/cl_zombie.lua @@ -257,7 +257,7 @@ local function EnableZombieHighlights() end) end -local function Zombie_Highlight_TTTUpdateRoleState() +AddHook("TTTUpdateRoleState", "Zombie_Highlight_TTTUpdateRoleState", function() client = LocalPlayer() zombie_vision = zombie_vision_enabled:GetBool() jesters_visible_to_traitors = GetConVar("ttt_jesters_visible_to_traitors"):GetBool() @@ -269,7 +269,7 @@ local function Zombie_Highlight_TTTUpdateRoleState() RemoveHook("PreDrawHalos", "Zombie_Highlight_PreDrawHalos") vision_enabled = false end -end +end) -- Handle enabling and disabling of highlighting local function Zombie_Highlight_Think() @@ -381,8 +381,7 @@ ROLE_REGISTERED_HOOKS[ROLE_ZOMBIE] = { ["TTTTargetIDPlayerRing"] = Zombie_TTTTargetIDPlayerRing, ["TTTTargetIDPlayerRoleIcon"] = Zombie_TTTTargetIDPlayerRoleIcon, ["TTTTargetIDPlayerTargetIcon"] = Zombie_TTTTargetIDPlayerTargetIcon, - ["TTTTargetIDPlayerText"] = Zombie_TTTTargetIDPlayerText, - ["TTTUpdateRoleState"] = Zombie_Highlight_TTTUpdateRoleState + ["TTTTargetIDPlayerText"] = Zombie_TTTTargetIDPlayerText } AddHook("TTTPrepareRound", "Zombie_TTTPrepareRound", function() diff --git a/gamemodes/terrortown/gamemode/shared.lua b/gamemodes/terrortown/gamemode/shared.lua index 2a8c86788..bf332badc 100644 --- a/gamemodes/terrortown/gamemode/shared.lua +++ b/gamemodes/terrortown/gamemode/shared.lua @@ -32,8 +32,8 @@ local TableInsert = table.insert include("player_class/player_ttt.lua") -- Version string for display and function for version checks -CR_VERSION = "2.5.1" -CR_BETA = false +CR_VERSION = "2.5.2" +CR_BETA = true CR_WORKSHOP_ID = CR_BETA and "2404251054" or "2421039084" function CRVersion(version) diff --git a/scripts/specspirits.lua b/scripts/specspirits.lua new file mode 100644 index 000000000..3cf6e2abc --- /dev/null +++ b/scripts/specspirits.lua @@ -0,0 +1,114 @@ +AddCSLuaFile() + +local ents = ents +local hook = hook + +if SERVER then + local player = player + local timer = timer + + local CreateEntity = ents.Create + local PlayerIterator = player.Iterator + + local defaultColor = Vector(1, 1, 1) + local function CreateSpectatorSpirit(ply) + if IsValid(ply.SpiritEnt) then return end + if IsValid(ply.SpecSpiritEnt) then return end + if ply:Alive() or not ply:IsSpec() then return end + if ply:GetRole() == ROLE_NONE then return end + + local spirit = CreateEntity("npc_kleiner") + spirit:SetPos(ply:GetPos()) + spirit:SetRenderMode(RENDERMODE_NONE) + spirit:SetNotSolid(true) + spirit:DrawShadow(false) + spirit:AddFlags(FL_NOTARGET) + spirit:SetNWString("SpecSpiritOwner", ply:SteamID64()) + spirit:SetNWVector("SpecSpiritColor", ply:GetNWVector("PlayerColor", defaultColor)) + spirit:Spawn() + + ply.SpecSpiritEnt = spirit + end + + hook.Add("PlayerDeath", "SpecSpirits_PlayerDeath", function(victim, infl, attacker) + -- Wait so the Medium logic has a chance to run first + timer.Simple(0, function() + if not IsPlayer(victim) then return end + print("[SpecSpirits] Creating spirit for " .. victim:Nick()) + CreateSpectatorSpirit(victim) + end) + end) + + hook.Add("FinishMove", "SpecSpirits_FinishMove", function(ply, mv) + if not IsValid(ply) or not ply:IsSpec() then return end + if not IsValid(ply.SpecSpiritEnt) then return end + + ply.SpecSpiritEnt:SetPos(ply:GetPos()) + + local show = ply:GetObserverMode() == OBS_MODE_ROAMING + ply.SpecSpiritEnt:SetProperty("SpecSpiritVisible", show) + end) + + hook.Add("TTTPrepareRound", "SpecSpirits_TTTPrepareRound", function() + for _, p in PlayerIterator() do + SafeRemoveEntity(p.SpecSpiritEnt) + p.SpecSpiritEnt = nil + end + end) +end + +if CLIENT then + local math = math + + local EntsFindByClass = ents.FindByClass + local MathRand = math.Rand + local MathRandom = math.random + + local client + local wispOffset = Vector(0, 0, 64) + local wispVelocity = Vector(0, 0, 30) + local wispColor = Vector(1, 1, 1) + hook.Add("Think", "SpecSpirits_Think", function() + if GetRoundState() ~= ROUND_ACTIVE then return end + + if not client then + client = LocalPlayer() + end + if client:Alive() or not client:IsSpec() then return end + + for _, ent in ipairs(EntsFindByClass("npc_kleiner")) do + if ent.SpecSpiritVisible then + local curTime = CurTime() + + ent:SetNoDraw(true) + ent:SetRenderMode(RENDERMODE_NONE) + ent:SetNotSolid(true) + ent:DrawShadow(false) + if not ent.SpecSpiritEmitter then ent.SpecSpiritEmitter = ParticleEmitter(ent:GetPos()) end + if not ent.SpecSpiritNextPart then ent.SpecSpiritNextPart = curTime end + local pos = ent:GetPos() + wispOffset + -- Use DistToSqr as it's more efficient and this is called very frequently + -- 9000000 = 3000^2 + if ent.SpecSpiritNextPart < curTime and client:GetPos():DistToSqr(pos) <= 9000000 then + ent.SpecSpiritEmitter:SetPos(pos) + ent.SpecSpiritNextPart = curTime + MathRand(0.003, 0.01) + local particle = ent.SpecSpiritEmitter:Add("particle/wisp.vmt", pos) + particle:SetVelocity(wispVelocity) + particle:SetDieTime(1) + particle:SetStartAlpha(MathRandom(150, 220)) + particle:SetEndAlpha(0) + local size = MathRandom(4, 7) + particle:SetStartSize(size) + particle:SetEndSize(1) + particle:SetRoll(MathRand(0, math.pi)) + particle:SetRollDelta(0) + local col = ent:GetNWVector("SpecSpiritColor", wispColor) + particle:SetColor(col.x * 255, col.y * 255, col.z * 255) + end + elseif ent.SpecSpiritEmitter then + ent.SpecSpiritEmitter:Finish() + ent.SpecSpiritEmitter = nil + end + end + end) +end \ No newline at end of file