From d81c05bc7dde96d0483f5cf58cc63204d18ee80b Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 09:44:32 +0800 Subject: [PATCH 1/9] Add reviving progress bar to medkit. Make medkit energy (ammo1) compat with third-party HUDs --- entities/weapons/weapon_lambda_medkit.lua | 28 ++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/entities/weapons/weapon_lambda_medkit.lua b/entities/weapons/weapon_lambda_medkit.lua index dfbda64f..628b7602 100644 --- a/entities/weapons/weapon_lambda_medkit.lua +++ b/entities/weapons/weapon_lambda_medkit.lua @@ -584,6 +584,24 @@ function SWEP:Holster(ent) return true end +function SWEP:DrawHUD() + if self:GetState() ~= STATE_CHARGING then return end + + local bgColor = Color(0, 0, 0, 150) + local barColor = Color(0, 200, 0, 255) + local textColor = Color(255, 255, 255, 255) + + local progress = self:GetChargeEnergy() / REVIVE_AMOUNT + + local w, h = 600, 30 + local x = (ScrW() / 2) - (w / 2) + local y = (ScrH() * 0.8) - (h / 2) + + draw.RoundedBox(8, x, y, w, h, bgColor) + draw.RoundedBox(8, x + 2, y + 2, (w - 4) * progress, h - 4, barColor) + draw.SimpleText("Reviving...", "DermaDefault", x + (w / 2), y - 15, textColor, TEXT_ALIGN_CENTER) +end + function SWEP:DrawWorldModel() self:DrawModel() end @@ -654,7 +672,7 @@ function SWEP:PostDrawPlayerHands(hands, vm, ply, wep) end function SWEP:Ammo1() - local energy = math.Clamp(self:GetEnergy() - self:GetChargeEnergy(), 0, 100) + local energy = math.Round(math.Clamp(self:GetEnergy() - self:GetChargeEnergy(), 0, 100)) return energy end @@ -663,6 +681,14 @@ function SWEP:Ammo2() return 0 end +function SWEP:CustomAmmoDisplay() + local display = {} + display.Draw = true + display.PrimaryClip = self:Ammo1() + + return display +end + if CLIENT then surface.CreateFont("LambdaMedkitFont", { font = "HalfLife2", From cff4514c7552f1ab17a0645884a37024ffb4fd23 Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 09:45:37 +0800 Subject: [PATCH 2/9] Trigger "CreateEntityRagdoll" when creating player death ragdoll --- entities/entities/lambda_ragdollmanager.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/entities/entities/lambda_ragdollmanager.lua b/entities/entities/lambda_ragdollmanager.lua index 47904376..2d5f9529 100644 --- a/entities/entities/lambda_ragdollmanager.lua +++ b/entities/entities/lambda_ragdollmanager.lua @@ -277,6 +277,8 @@ function ENT:CreateRagdoll(dmgForce, gibPlayer, didExplode) ragdoll:Spawn() ragdoll:SetCollisionGroup(COLLISION_GROUP_DEBRIS) + hook.Run("CreateEntityRagdoll", self:GetOwner(), ragdoll) + ragdoll.GetPlayerColor = function(s) if IsValid(owner) and owner.GetPlayerColor ~= nil then return owner:GetPlayerColor() end end From 4448b5cfb8e3c709865fd77df3019eef7eb2cadd Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 09:47:29 +0800 Subject: [PATCH 3/9] Fixes a infinite loop where the entity return itself as activator --- gamemode/sh_entity_extend.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamemode/sh_entity_extend.lua b/gamemode/sh_entity_extend.lua index b62ea391..e5a50a80 100644 --- a/gamemode/sh_entity_extend.lua +++ b/gamemode/sh_entity_extend.lua @@ -41,7 +41,7 @@ end function ENTITY_META:GetActivator() -- Scripted entities don't have this field so we have to do it ourselves. - if self.LambdaLastActivator ~= nil then return self.LambdaLastActivator end + if self.LambdaLastActivator ~= nil and self ~= self.LambdaLastActivator then return self.LambdaLastActivator end -- Native entities. return self:GetInternalVariable("m_hActivator") From 1c59bf19142f7d64583b209320131282ef35b2de Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 10:06:07 +0800 Subject: [PATCH 4/9] If "gmod_suit" is 1, read / write the aux power from base game --- gamemode/cl_hud.lua | 3 +++ gamemode/sh_player_extend.lua | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/gamemode/cl_hud.lua b/gamemode/cl_hud.lua index 687462cd..36c29663 100644 --- a/gamemode/cl_hud.lua +++ b/gamemode/cl_hud.lua @@ -130,6 +130,9 @@ function GM:HUDShouldDraw(hudName) elseif hudName == "CHUDQuickInfo" then -- We make our own. return false + elseif hudName == "CHudSuitPower" then + -- We have our own AUX power display. + return false end return true diff --git a/gamemode/sh_player_extend.lua b/gamemode/sh_player_extend.lua index 41db4620..37990b8b 100644 --- a/gamemode/sh_player_extend.lua +++ b/gamemode/sh_player_extend.lua @@ -22,6 +22,8 @@ VIEWLOCK_SETTINGS_ON = 4 VIEWLOCK_SETTINGS_RELEASE = 5 VIEWLOCK_RELEASE_TIME = 1.0 -- Seconds +local gmod_suit_enabled = GetConVar("gmod_suit"):GetBool() + if SERVER then function PLAYER_META:TeleportPlayer(pos, ang, vel) local data = {} @@ -324,10 +326,18 @@ function PLAYER_META:SetInactive(state) end function PLAYER_META:SetLambdaSuitPower(val) - self:SetNW2Float("LambdaSuitPower", val) + if gmod_suit_enabled and SERVER then + self:SetSuitPower(val) + else + self:SetNW2Float("LambdaSuitPower", val) + end end function PLAYER_META:GetLambdaSuitPower() + if gmod_suit_enabled then + return self:GetSuitPower() + end + return self:GetNW2Float("LambdaSuitPower", 0.0) end From 4c543c82f12f5aedacc0444b0b821bf19bb92509 Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 10:49:42 +0800 Subject: [PATCH 5/9] Trigger "AddDeathNotice" when creating death notice, compat with killfeed replacement (likely HUD) --- gamemode/huds/hud_deathnotice.lua | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/gamemode/huds/hud_deathnotice.lua b/gamemode/huds/hud_deathnotice.lua index 61519f2e..0a26ba7e 100644 --- a/gamemode/huds/hud_deathnotice.lua +++ b/gamemode/huds/hud_deathnotice.lua @@ -94,7 +94,15 @@ local function ProcessDeathNotice(death, color1, color2) table.insert(DeathsData.Entries, death) end +local lastProceedData = {} + function GM:AddDeathNotice(attacker, attackerTeam, inflictor, victim, victimTeam) + -- Check if 'lastProceedData' has valid data from 'AddDeathNoticeFromData', if so we can skip processing and just use that data. + if lastProceedData ~= nil then + ProcessDeathNotice(lastProceedData.death, lastProceedData.color1, lastProceedData.color2) + return + end + local death = { time = CurTime(), times = 1, @@ -153,7 +161,7 @@ function GM:AddDeathNoticeFromData(data) local victim = data.victim if victim ~= nil then if victim.isPlayer then - death.right = Entity(victim.entIndex):Name() + death.right = Entity(victim.entIndex):Nick() else death.right = "#" .. victim.class end @@ -193,7 +201,16 @@ function GM:AddDeathNoticeFromData(data) local color1 = (not data.attacker or not data.attacker.team) and table.Copy(NPC_Color) or table.Copy(team.GetColor(data.attacker.team)) local color2 = (not data.victim or not data.victim.team) and table.Copy(NPC_Color) or table.Copy(team.GetColor(data.victim.team)) - ProcessDeathNotice(death, color1, color2) + lastProceedData = { + death = death, + color1 = color1, + color2 = color2 + } + + hook.Run("AddDeathNotice", death.left, data.attacker and data.attacker.team or 2, death.icon, death.right, data.victim and data.victim.team or 2) + lastProceedData = nil + + --ProcessDeathNotice(death, color1, color2) end local function ComputeDeathNoticeSize(death, bounds) From d321f6e4a619f0f4833706474bd956ac160bdd37 Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 12:53:48 +0800 Subject: [PATCH 6/9] Compat with "Enhanced PlayerModel Selector" and forks --- gamemode/huds/hud_lambda_player.lua | 79 ++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/gamemode/huds/hud_lambda_player.lua b/gamemode/huds/hud_lambda_player.lua index 184476d1..e3d371bf 100644 --- a/gamemode/huds/hud_lambda_player.lua +++ b/gamemode/huds/hud_lambda_player.lua @@ -3,6 +3,26 @@ local border_w = 5 local matHover = Material("gui/ps_hover.png", "nocull") local boxHover = GWEN.CreateTextureBorder(border, border, 64 - border * 2, 64 - border * 2, border_w, border_w, border_w, border_w, matHover) +--- Detect if the "Enhanced Playermodel Selector" is installed and enabled "Enforce your player model" for enforcing playermodels, so we can do the compat. +--- If "cl_playermodel_selector_force" and "sv_playermodel_selector_force" are both existing, we assume the user / server has it installed. +-- @param enforced boolean Check if the "Enforce your player model" option is enabled, if false, it will only check if the enhanced playermodel selector is installed. +-- @return boolean "Enhanced Playermodel Selector" is installed or not. If "enforced" is true, also check if "Enforce your player model" is enabled. +local function ThirdParty_EnhancedPlayermodelSelector(enforced) + local cl_playermodel_selector_force, sv_playermodel_selector_force = GetConVar("cl_playermodel_selector_force"), GetConVar("sv_playermodel_selector_force") + if enforced then + return cl_playermodel_selector_force and sv_playermodel_selector_force + and cl_playermodel_selector_force:GetBool() and sv_playermodel_selector_force:GetBool() + end + + return cl_playermodel_selector_force and sv_playermodel_selector_force +end + +--- Detect if the "Outfitter" is installed, so we can add it to the model selection page, as this is the only hot-reloading playermodel selector that I know of. +-- @return boolean "Outfitter" is installed or not. +local function ThirdParty_Outfitter() + return outfitter ~= nil +end + local PANEL = {} cvars.AddChangeCallback("lambda_playermdl", function() @@ -37,21 +57,50 @@ function PANEL:Init() local mdlListPanel = mdlPanel:Add("DPanelSelect") mdlListPanel:Dock(FILL) - local modelTbl = GAMEMODE:GetAvailablePlayerModels() - for name, v in pairs(modelTbl) do - local item = mdlListPanel:Add("SpawnIcon") - item:SetModel(v) - item:SetSize(64, 64) - item:SetTooltip(name) - item.plymdl = name - item.mdlPath = player_manager.TranslatePlayerModel(name) - item.PaintOver = function(this, w, h) - if this.OverlayFade > 0 then - boxHover(0, 0, w, h, Color(255, 255, 255, this.OverlayFade)) + if ThirdParty_EnhancedPlayermodelSelector() then + local enhancedPlayerSelectorbutton = mdlPanel:Add("DButton") + enhancedPlayerSelectorbutton:Dock(BOTTOM) + enhancedPlayerSelectorbutton:SetText("Open Enhanced Playermodel Selector") + enhancedPlayerSelectorbutton:SetTextColor(Color(255, 255, 255, 255)) + enhancedPlayerSelectorbutton:SetIcon("icon16/user.png") + enhancedPlayerSelectorbutton:SetConsoleCommand("playermodel_selector") + end + + if ThirdParty_EnhancedPlayermodelSelector(true) then + searchBar:SetVisible(false) + + local warningLabel = mdlListPanel:Add("DLabel") + warningLabel:Dock(TOP) + warningLabel:SetText("#LAMBDA_THIRDPARTY_EPS_WARNING") + warningLabel:SetTextColor(Color(255, 255, 255, 255)) + warningLabel:SetFont("TargetIDSmall") + warningLabel:SizeToContents() + else + local modelTbl = GAMEMODE:GetAvailablePlayerModels() + for name, v in pairs(modelTbl) do + local item = mdlListPanel:Add("SpawnIcon") + item:SetModel(v) + item:SetSize(64, 64) + item:SetTooltip(name) + item.plymdl = name + item.mdlPath = player_manager.TranslatePlayerModel(name) + item.PaintOver = function(this, w, h) + if this.OverlayFade > 0 then + boxHover(0, 0, w, h, Color(255, 255, 255, this.OverlayFade)) + end + this:DrawSelections() end - this:DrawSelections() + mdlListPanel:AddPanel(item, {lambda_playermdl = name}) end - mdlListPanel:AddPanel(item, {lambda_playermdl = name}) + end + + if ThirdParty_Outfitter() then + local outfitterButton = mdlPanel:Add("DButton") + outfitterButton:Dock(BOTTOM) + outfitterButton:SetText("Open Outfitter") + outfitterButton:SetTextColor(Color(255, 255, 255, 255)) + outfitterButton:SetIcon("icon64/outfitter.png") + outfitterButton:SetConsoleCommand("outfitter") end searchBar.OnValueChange = function(s, str) @@ -136,6 +185,10 @@ function PANEL:Init() local bgTab = sheetPanel:AddSheet("BODYGROUPS", bgPanel) + if ThirdParty_EnhancedPlayermodelSelector(true) then + bgTab.Tab:SetVisible(false) + end + local function HighlightTab(state) if state then bgTab.Tab:SetTextColor(Color(248, 128, 0, 255)) From 2113a55e2a2c38048254e1dc518a40e6d8f05075 Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 15:44:03 +0800 Subject: [PATCH 7/9] More localization & Simplified Chinese support --- entities/entities/lambda_trigger.lua | 9 +- entities/entities/lambda_vehicle_tracker.lua | 8 +- gamemode/cl_lang.lua | 3 +- gamemode/gametypes/base/cl_localisation.lua | 121 ++++++++++++++++++- gamemode/gametypes/gametype_base.lua | 18 +-- 5 files changed, 140 insertions(+), 19 deletions(-) diff --git a/entities/entities/lambda_trigger.lua b/entities/entities/lambda_trigger.lua index b0130d65..fb77d8c2 100644 --- a/entities/entities/lambda_trigger.lua +++ b/entities/entities/lambda_trigger.lua @@ -1133,7 +1133,7 @@ else -- CLIENT local _, h = 0, 0 local text = "" - local remaining = scheduledTime - GetSyncedTimestamp() + local remaining = math.Round(scheduledTime - GetSyncedTimestamp()) if remaining < 0 then remaining = 0 @@ -1149,18 +1149,19 @@ else -- CLIENT surface.SetFont("LAMBDA_2") local textY = 0 local spacing = 10 - text = "Waiting for players: " .. tostring(activePlayerCount) .. " / " .. tostring(playerCount) + text = language.GetPhrase("LAMBDA_CHECKPOINT_WAITING"):format(activePlayerCount, playerCount) draw.DrawText(text, "LAMBDA_1", x, y + textY, colorBg, TEXT_ALIGN_CENTER) draw.DrawText(text, "LAMBDA_2", x, y + textY, textColor, TEXT_ALIGN_CENTER) w, h = surface.GetTextSize(text) textY = textY + h + spacing - text = "Game will continue once all players are here" + text = language.GetPhrase("LAMBDA_CHECKPOINT_WAITING_2") + draw.DrawText(text, "LAMBDA_1", x, y + textY, colorBg, TEXT_ALIGN_CENTER) draw.DrawText(text, "LAMBDA_2", x, y + textY, textColor, TEXT_ALIGN_CENTER) textY = textY + h + spacing if scheduledTime > 0 then - text = "Timeout in " .. string.format("%.02f", remaining) .. " seconds" + text = language.GetPhrase("LAMBDA_CHECKPOINT_WAITING_3"):format(remaining) draw.DrawText(text, "LAMBDA_1", x, y + textY, colorBg, TEXT_ALIGN_CENTER) draw.DrawText(text, "LAMBDA_2", x, y + textY, textColor, TEXT_ALIGN_CENTER) textY = textY + h + spacing diff --git a/entities/entities/lambda_vehicle_tracker.lua b/entities/entities/lambda_vehicle_tracker.lua index 066c9eea..dca87abb 100644 --- a/entities/entities/lambda_vehicle_tracker.lua +++ b/entities/entities/lambda_vehicle_tracker.lua @@ -134,13 +134,13 @@ elseif CLIENT then local text = "" if belongsToUs == true then - text = "Your Vehicle" + text = "#LAMBDA_VEHICLE_OWNED" elseif isTaken == false then if haveVehicle == true then - text = "Reserved Vehicle" + text = "#LAMBDA_VEHICLE_RESERVED" alpha = alpha * 0.08 else - text = "Available Vehicle" + text = "#LAMBDA_VEHICLE_AVAILABLE" end elseif isTaken == true then local ownerName = "???" @@ -149,7 +149,7 @@ elseif CLIENT then ownerName = owner:GetName() end - text = "Vehicle belongs to " .. ownerName + text = language.GetPhrase("LAMBDA_VEHICLE_OWNED_BY_OTHERS"):format(ownerName) alpha = alpha * 0.08 end diff --git a/gamemode/cl_lang.lua b/gamemode/cl_lang.lua index 62724956..9db02a1f 100644 --- a/gamemode/cl_lang.lua +++ b/gamemode/cl_lang.lua @@ -2,11 +2,12 @@ local DbgPrint = GetLogging("Language") local SUPPORTED_LANGUAGES = { ["en"] = "english", + ["zh-cn"] = "schinese" } local function GetCurrentLanguage() local gmod_language = GetConVar("gmod_language") - local lang = gmod_language:GetString() + local lang = gmod_language:GetString():lower() local realLang = SUPPORTED_LANGUAGES[lang] if realLang == nil then DbgPrint("Language '" .. lang .. "' is not supported, falling back to 'en'") diff --git a/gamemode/gametypes/base/cl_localisation.lua b/gamemode/gametypes/base/cl_localisation.lua index a5c38760..24b4aa5e 100644 --- a/gamemode/gametypes/base/cl_localisation.lua +++ b/gamemode/gametypes/base/cl_localisation.lua @@ -1,5 +1,8 @@ if SERVER then AddCSLuaFile() end + local LOCALISATION = {} + +-- en (english) LOCALISATION["english"] = { ["World"] = "Cruel World", ["base_ai"] = "Creature", @@ -15,6 +18,12 @@ LOCALISATION["english"] = { ["Valve_Hint_CROSSBOW"] = "%+attack2% CROSSBOW ZOOM", ["GM_DIFFICULTY"] = "Difficulty level", ["GM_DIFFICULTY_DESC"] = "Set the gametype difficulty", + ["GM_DIFFICULTY_MODE_VERY_EASY"] = "Very easy", + ["GM_DIFFICULTY_MODE_EASY"] = "Easy", + ["GM_DIFFICULTY_MODE_NORMAL"] = "Normal", + ["GM_DIFFICULTY_MODE_HARD"] = "Hard", + ["GM_DIFFICULTY_MODE_VERY_HARD"] = "Very hard", + ["GM_DIFFICULTY_MODE_REALISM"] = "Realism", ["GM_WALKSPEED"] = "Walk speed", ["GM_WALKSPEED_DESC"] = "Set speed when slowly walking with ALT key", ["GM_NORMSPEED"] = "Normal speed", @@ -53,6 +62,9 @@ LOCALISATION["english"] = { ["GM_DIFFMETRICS_DESC"] = "Metrics for use by developers", ["GM_WEAPONDROP"] = "Weapon drop mode", ["GM_WEAPONDROP_DESC"] = "Change what players drop on death", + ["GM_WEAPONDROP_MODE_NONE"] = "Nothing", + ["GM_WEAPONDROP_MODE_ACTIVE"] = "Active", + ["GM_WEAPONDROP_MODE_ALL"] = "Everything", ["GM_CHANGELVLDELAY"] = "Level change delay", ["GM_CHANGELVLDELAY_DESC"] = "The amount in seconds to wait before changing to the next map", ["GM_VOICEGENDER"] = "Voice gender", @@ -79,6 +91,113 @@ LOCALISATION["english"] = { ["GM_DM_TIMELIMIT_DESC"] = "Set how long the round lasts", ["GM_DM_TEAMONLY"] = "Team based deathmatch", ["GM_DM_TEAMONLY_DESC"] = "Switch between DM or TDM", - ["LAMBDA_VEHICLE_TAKE_OVER"] = "Take over vehicle %+speed%+%+use%" + ["LAMBDA_VEHICLE_TAKE_OVER"] = "Take over vehicle %+speed%+%+use%", + ["LAMBDA_THIRDPARTY_EPS_WARNING"] = "Enhanced Playermodel Selector is installed,\nAnd \"Enforce your player model\" is enabled.\nYou must use the enhanced playermodel selector\nTo change your player model.", + ["LAMBDA_CHECKPOINT_WAITING"] = "Waiting for players: %d / %d", + ["LAMBDA_CHECKPOINT_WAITING_2"] = "Game will continue once all players are here", + ["LAMBDA_CHECKPOINT_WAITING_3"] = "Timeout in %d seconds", + ["LAMBDA_VEHICLE_OWNED"] = "Your Vehicle", + ["LAMBDA_VEHICLE_RESERVED"] = "Reserved Vehicle", + ["LAMBDA_VEHICLE_AVAILABLE"] = "Available Vehicle", + ["LAMBDA_VEHICLE_OWNED_BY_OTHERS"] = "Vehicle belongs to %s" } + +-- zh-cn (schinese) +LOCALISATION["schinese"] = { + ["World"] = "世界", + ["base_ai"] = "生物", + ["Valve_Hint_EnterVan"] = "%+use% 进入车辆", + ["Valve_Hint_ExitVan"] = "%+use% 离开车辆", + ["Valve_Hint_Crouch"] = "%+duck% 蹲下", + ["Valve_Hint_Sprint"] = "%+speed% 冲刺", + ["Valve_Hint_PushButton"] = "%+use% 按下按钮", + ["Valve_Hint_PicKUp"] = "%+use% 拾取", + ["Valve_Hint_Interact"] = "%+use% 互动", + ["Valve_Hint_GravGun"] = "%+attack% 击飞物体 %+attack2% 拉取物体", + ["Valve_Hint_CarryTurret"] = "%+use% 或重力枪拾取炮塔", + ["Valve_Hint_CROSSBOW"] = "%+attack2% 使用瞄准镜", + ["GM_DIFFICULTY"] = "难度", + ["GM_DIFFICULTY_DESC"] = "设置游戏难度", + ["GM_DIFFICULTY_MODE_VERY_EASY"] = "非常简单", + ["GM_DIFFICULTY_MODE_EASY"] = "简单", + ["GM_DIFFICULTY_MODE_NORMAL"] = "普通", + ["GM_DIFFICULTY_MODE_HARD"] = "困难", + ["GM_DIFFICULTY_MODE_VERY_HARD"] = "非常困难", + ["GM_DIFFICULTY_MODE_REALISM"] = "真实", + ["GM_WALKSPEED"] = "行走速度", + ["GM_WALKSPEED_DESC"] = "按住 ALT 键慢走时的速度", + ["GM_NORMSPEED"] = "正常速度", + ["GM_NORMSPEED_DESC"] = "设置正常行走速度", + ["GM_SPRINTSPEED"] = "冲刺速度", + ["GM_SPRINTSPEED_DESC"] = "设置奔跑速度", + ["GM_CONNECTTIMEOUT"] = "连接超时", + ["GM_CONNECTTIMEOUT_DESC"] = "设置等待玩家连接的时间", + ["GM_PLAYERCOLLISION"] = "玩家碰撞", + ["GM_PLAYERCOLLISION_DESC"] = "玩家之间存在碰撞,无法穿过其他玩家", + ["GM_FRIENDLYFIRE"] = "友军伤害", + ["GM_FRIENDLYFIRE_DESC"] = "允许对队友造成伤害", + ["GM_PREVENTITEMMOVE"] = "阻止补给品移动", + ["GM_PREVENTITEMMOVE_DESC"] = "阻止补给因玩家因素而被移动(如射击)", + ["GM_DEFAMMO"] = "启用弹药限制", + ["GM_DEFAMMO_DESC"] = "使武器备弹无法超过半条命2的默认备弹上限", + ["GM_AUTOJUMP"] = "允许自动连跳", + ["GM_AUTOJUMP_DESC"] = "允许玩家按住跳跃键自动连跳", + ["GM_RESPAWNTIME"] = "复活时间", + ["GM_RESPAWNTIME_DESC"] = "设置玩家复活等待时间", + ["GM_CHECKPOINT_RESPAWN"] = "检查点复活", + ["GM_CHECKPOINT_RESPAWN_DESC"] = "玩家必须等待新的检查点才能复活", + ["GM_RESTARTTIME"] = "重启时间", + ["GM_RESTARTTIME_DESC"] = "设置回合失败后到重新开始之间的时间", + ["GM_MAPCHANGETIME"] = "地图终点等待时间", + ["GM_MAPCHANGETIME_DESC"] = "设置玩家到达地图终点时等待其他玩家的时间", + ["GM_CHECKPOINTTIMEOUT"] = "检查点等待时间", + ["GM_CHECKPOINTTIMEOUT_DESC"] = "设置玩家到达检查点时等待其他玩家的时间", + ["GM_GODMODE"] = "无敌模式", + ["GM_GODMODE_DESC"] = "启用无敌模式,免疫所有伤害", + ["GM_PICKUPDELAY"] = "拾取物品延迟", + ["GM_PICKUPDELAY_DESC"] = "设置玩家频繁按E拿东西(如木箱等)时至少要等待的延迟", + ["GM_DIFFMETRICS"] = "NPC/玩家指标", + ["GM_DIFFMETRICS_DESC"] = "供开发者使用的指标", + ["GM_WEAPONDROP"] = "死亡武器掉落", + ["GM_WEAPONDROP_DESC"] = "玩家死亡时,是否应该掉落武器", + ["GM_WEAPONDROP_MODE_NONE"] = "不掉落", + ["GM_WEAPONDROP_MODE_ACTIVE"] = "手持武器", + ["GM_WEAPONDROP_MODE_ALL"] = "掉落全部", + ["GM_CHANGELVLDELAY"] = "关卡切换延迟", + ["GM_CHANGELVLDELAY_DESC"] = "切换至下一张地图前等待的秒数", + ["GM_VOICEGENDER"] = "语音类型", + ["GM_VOICEGENDER_DESC"] = "设置角色语音的类型", + ["GM_COCKROACHES"] = "蟑螂数量", + ["GM_COCKROACHES_DESC"] = "最多可生成的蟑螂数量,设为0以禁用", + ["GM_ABH"] = "向后连跳加速", + ["GM_ABH_DESC"] = "启用向后连跳加速,速通玩家常用的技巧以获得超高速度", + ["GM_DYNCHECKPOINT"] = "启用动态检查点", + ["GM_DYNCHECKPOINT_DESC"] = "根据玩家行为自动生成检查点", + ["GM_NPCDMG"] = "重要NPC友伤", + ["GM_NPCDMG_DESC"] = "允许玩家对重要NPC造成队友伤害", + ["GM_PLYTRACK"] = "玩家隔墙显示", + ["GM_PLYTRACK_DESC"] = "允许看见墙壁后的玩家", + ["GM_ANTLIONCOLLISION"] = "友方蚁狮碰撞", + ["GM_ANTLIONCOLLISION_DESC"] = "启用/禁用与友方蚁狮的碰撞", + ["GM_PLAYERSPEECH"] = "玩家角色语音", + ["GM_PLAYERSPEECH_DESC"] = "允许玩家根据游戏内行为自动说话(如发现敌人等)", + ["GM_PLAYERHURTSOUNDS"] = "玩家受伤语音", + ["GM_PLAYERHURTSOUNDS_DESC"] = "启用/禁用玩家根据受到的伤害自动发言", + ["GM_DM_FRAGLIMIT"] = "分数限制", + ["GM_DM_FRAGLIMIT_DESC"] = "设置结束回合的分数上限", + ["GM_DM_TIMELIMIT"] = "回合时间限制", + ["GM_DM_TIMELIMIT_DESC"] = "设置回合持续时间", + ["GM_DM_TEAMONLY"] = "团队死斗模式", + ["GM_DM_TEAMONLY_DESC"] = "切换自由死斗或团队死斗", + ["LAMBDA_VEHICLE_TAKE_OVER"] = "接管载具 %+speed%+%+use%", + ["LAMBDA_THIRDPARTY_EPS_WARNING"] = "Enhanced Playermodel Selector 已安装,\n且“强制使用选中模型”已启用。\n你必须使用增强版玩家模型选择器\n来更改你的玩家模型。", + ["LAMBDA_CHECKPOINT_WAITING"] = "等待玩家汇合: %d / %d", + ["LAMBDA_CHECKPOINT_WAITING_2"] = "流程将会在所有玩家汇合于此后继续进行", + ["LAMBDA_CHECKPOINT_WAITING_3"] = "还剩 %d 秒", + ["LAMBDA_VEHICLE_OWNED"] = "状态: 可以驾驶", + ["LAMBDA_VEHICLE_RESERVED"] = "状态: 禁止驾驶", + ["LAMBDA_VEHICLE_AVAILABLE"] = "状态: 可以驾驶", + ["LAMBDA_VEHICLE_OWNED_BY_OTHERS"] = "状态: 禁止驾驶(归属\"%s\")" +} + return LOCALISATION \ No newline at end of file diff --git a/gamemode/gametypes/gametype_base.lua b/gamemode/gametypes/gametype_base.lua index 26bb3298..345801cd 100644 --- a/gamemode/gametypes/gametype_base.lua +++ b/gamemode/gametypes/gametype_base.lua @@ -116,7 +116,7 @@ end function GAMETYPE:GetDifficultyData() return { [0] = { - Name = "Very Easy", + Name = "#GM_DIFFICULTY_MODE_VERY_EASY", Proficiency = WEAPON_PROFICIENCY_POOR, Skill = 1, NPCSpawningScale = 0.0, @@ -148,7 +148,7 @@ function GAMETYPE:GetDifficultyData() } }, [1] = { - Name = "Easy", + Name = "#GM_DIFFICULTY_MODE_EASY", Proficiency = WEAPON_PROFICIENCY_AVERAGE, Skill = 1, NPCSpawningScale = 0.2, @@ -180,7 +180,7 @@ function GAMETYPE:GetDifficultyData() } }, [2] = { - Name = "Normal", + Name = "#GM_DIFFICULTY_MODE_NORMAL", Proficiency = WEAPON_PROFICIENCY_GOOD, Skill = 2, NPCSpawningScale = 0.4, @@ -212,7 +212,7 @@ function GAMETYPE:GetDifficultyData() } }, [3] = { - Name = "Hard", + Name = "#GM_DIFFICULTY_MODE_HARD", Proficiency = WEAPON_PROFICIENCY_VERY_GOOD, Skill = 2, NPCSpawningScale = 0.7, @@ -244,7 +244,7 @@ function GAMETYPE:GetDifficultyData() } }, [4] = { - Name = "Very Hard", + Name = "#GM_DIFFICULTY_MODE_VERY_HARD", Proficiency = WEAPON_PROFICIENCY_PERFECT, Skill = 3, NPCSpawningScale = 1, @@ -276,7 +276,7 @@ function GAMETYPE:GetDifficultyData() } }, [5] = { - Name = "Realism", + Name = "#GM_DIFFICULTY_MODE_REALISM", Proficiency = WEAPON_PROFICIENCY_PERFECT, Skill = 3, NPCSpawningScale = 1, @@ -518,9 +518,9 @@ function GAMETYPE:InitSettings() Extra = { Type = "combo", Choices = { - [0] = "Nothing", - [1] = "Active", - [2] = "Everything" + [0] = "#GM_WEAPONDROP_MODE_NONE", + [1] = "#GM_WEAPONDROP_MODE_ACTIVE", + [2] = "#GM_WEAPONDROP_MODE_ALL" } } }) From 3b35c257034131d8da9ad14e70c626ba83c391be Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 15:56:13 +0800 Subject: [PATCH 8/9] Update changelog --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index fb087156..152ca2ae 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,16 @@ 0.9.30 (in development) - Improved: Enemy scaling now caps out at 20 players, doing more adds too much stress to the server. - Improved: Vehicles now temporarily disable collisions when entering a changelevel trigger, remains disabled set by settings. +- Improved: When using medkit to revive the teammate now have a progress bar. +- Improved: Compatibility with "Enhanced PlayerModel Selector" addon. +- Improved: Simplified Chinese localization. - Added: Setting to disable vehicle collisions. - Fixed: Bad lightning by forcing r_radiosity convar to 4. - Fixed: Multiple weapons dissolving when an NPC dies. - Fixed: ep1_citadel_03 disabled clip so Alyx can go through the door sooner. - Fixed: Missing default crosshair and incomplete QuickInfo crosshair. +- Fixed: Rare game freeze on community maps when it's playing a cutscene. +- Fixed: Incorrect AUX power when server have "gmod_suit 1". 0.9.29 - Improved: Use new checkpoint structure in mapscripts where possible with better positioning (first 5 chapters). From 5624b47d7fcc5da9a41692c82dbae5fc5698c04a Mon Sep 17 00:00:00 2001 From: dounai2333 <1328600509@qq.com> Date: Sun, 3 May 2026 18:24:02 +0800 Subject: [PATCH 9/9] Fixes changing "gmod_suit" doesn't update the logic --- gamemode/sh_player_extend.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/gamemode/sh_player_extend.lua b/gamemode/sh_player_extend.lua index 37990b8b..1d386a4f 100644 --- a/gamemode/sh_player_extend.lua +++ b/gamemode/sh_player_extend.lua @@ -316,6 +316,9 @@ function PLAYER_META:IsInactive() end function PLAYER_META:SetInactive(state) + -- This is bad, but currently there is no better way. + gmod_suit_enabled = GetConVar("gmod_suit"):GetBool() + self:SetNWBool("Inactive", state) if state == true then @@ -326,11 +329,16 @@ function PLAYER_META:SetInactive(state) end function PLAYER_META:SetLambdaSuitPower(val) - if gmod_suit_enabled and SERVER then - self:SetSuitPower(val) - else - self:SetNW2Float("LambdaSuitPower", val) + if gmod_suit_enabled then + -- This function does not exists in client-side. + if SERVER then + self:SetSuitPower(val) + end + + return end + + self:SetNW2Float("LambdaSuitPower", val) end function PLAYER_META:GetLambdaSuitPower()