Так вот, у меня на данный момент несколько проблем с чатом:
Не меняется префикс при выборе его на кнопках под чатом,
Не проигрывается действие, если выбрано /do или /me,
Как указано в названии не видно то, что ты вводишь в чат.
Ниже весь код…
Основа
AquaChat = AquaChat or {
Prefixes = {
["OOC"] = { text = "OOC", color = Color(255, 255, 255) },
["Д"] = { text = "Д", color = Color(255, 105, 180) },
["Р"] = { text = "Р", color = Color(50, 255, 50) },
["Т"] = { text = "Т", color = Color(255, 165, 0) },
["М"] = { text = "М", color = Color(255, 50, 50) },
["В"] = { text = "В", color = Color(255, 50, 255) },
["R"] = { text = "RADIO", color = Color(100, 100, 255) },
["SERVER"] = { text = "СЕРВЕР", color = Color(255, 215, 0) },
["TEAM"] = { text = "TEAM", color = Color(100, 255, 100) },
["ADMIN"] = { text = "ADMIN", color = Color(255, 0, 0) },
["NOTIFY"] = { text = "", color = Color(255, 255, 255) },
["LOCAL"] = { text = "", color = Color(255, 255, 255) }
},
Background = Color(0, 0, 0, 180),
TextColor = Color(255, 255, 255),
MaxMessages = 100,
FadeInTime = 0.3,
FadeOutTime = 3,
StayTime = 8,
Font = "ChatFont",
Width = ScrW() * 0.4,
LineHeight = 18,
Messages = {},
IsOpen = false,
InputText = "",
ChatEntry = nil,
ScrollOffset = 0,
VisibleMessages = 50,
WheelScrollSpeed = 3,
ChatHistory = {},
HistoryIndex = 0,
ShowTimestamps = false,
ShowBackground = true,
DefaultChatType = "LOCAL",
ChatButtons = {},
ButtonColor = Color(70, 130, 180),
ButtonPadding = 10,
ButtonMargin = 5
}
surface.CreateFont("AquaChatFont", {
font = "Montserrat",
size = 16,
weight = 500,
antialias = true
})
-- Include other client-side components
include("aqua_chat_events.lua")
include("aqua_chat_gui.lua")
include("aqua_chat_draw.lua")
Отрисовка чата
hook.Add("HUDPaint", "AquaChat_DrawChat", function()
AquaChat.X = AquaChat.X or (ScrW() - (AquaChat.Width or ScrW() * 0.4)) / 2
AquaChat.Width = AquaChat.Width or ScrW() * 0.4
AquaChat.LineHeight = AquaChat.LineHeight or 18
local roundedCorners = 4
surface.SetFont(AquaChat.Font)
local messagesY = ScrH() * 0.7 - 10
if IsValid(AquaChat.ChatEntry) then
messagesY = AquaChat.ChatEntry:GetY() - 10
end
local maxMessagesToShow = AquaChat.IsOpen and (AquaChat.VisibleMessages or 50) or math.min(AquaChat.VisibleMessages or 50, 15)
local startIndex = math.max(1, #AquaChat.Messages - maxMessagesToShow - (AquaChat.ScrollOffset or 0) + 1)
local endIndex = math.min(#AquaChat.Messages, startIndex + maxMessagesToShow - 1)
if AquaChat.IsOpen and input.IsMouseDown(MOUSE_LEFT) then
local x, y = gui.MousePos()
if x >= AquaChat.X and x <= AquaChat.X + AquaChat.Width then
if y >= messagesY - maxMessagesToShow * AquaChat.LineHeight and y <= messagesY then
AquaChat.ScrollOffset = math.Clamp((AquaChat.ScrollOffset or 0) + input.GetMouseWheel() * (AquaChat.WheelScrollSpeed or 3),
0, math.max(0, #AquaChat.Messages - maxMessagesToShow))
end
end
end
for i = endIndex, startIndex, -1 do
local msg = AquaChat.Messages[i]
if not msg or not msg.visible then continue end
local timeAlive = CurTime() - (msg.time or CurTime())
local alpha = msg.alpha or 255
if not AquaChat.IsOpen then
if msg.fadingOut then
local fadeProgress = (CurTime() - (msg.fadeStartTime or CurTime())) / (AquaChat.FadeOutTime or 3)
alpha = 255 * (1 - fadeProgress)
if fadeProgress >= 1 then
msg.visible = false
continue
end
elseif timeAlive < (AquaChat.FadeInTime or 0.3) then
alpha = 255 * (timeAlive / (AquaChat.FadeInTime or 0.3))
elseif timeAlive > (AquaChat.StayTime or 8) then
alpha = 255 - (255 * ((timeAlive - (AquaChat.StayTime or 8)) / (AquaChat.FadeOutTime or 3)))
if alpha <= 0 then
msg.visible = false
continue
end
else
alpha = 255
end
end
msg.alpha = alpha
if alpha > 0 then
local prefixData = AquaChat.Prefixes[msg.prefix] or AquaChat.Prefixes["OOC"] or {}
local nickColor = IsValid(msg.ply) and msg.ply:IsPlayer() and team.GetColor(msg.ply:Team()) or Color(255, 255, 255, alpha)
local textColor = Color(
(AquaChat.TextColor or Color(255, 255, 255)).r,
(AquaChat.TextColor or Color(255, 255, 255)).g,
(AquaChat.TextColor or Color(255, 255, 255)).b,
alpha
)
if msg.isDead then
nickColor = Color(150, 150, 150, alpha)
end
local nick = IsValid(msg.ply) and msg.ply:IsPlayer() and msg.ply:Nick() or "Сервер"
local mskTime = os.date("!%H:%M:%S", (msg.time or CurTime()) + 3 * 3600)
local timestamp = (AquaChat.ShowTimestamps or false) and ("[" .. mskTime .. "] ") or ""
local prefixText = (prefixData.text or "") ~= "" and ((prefixData.text or "") .. " ") or ""
local nickText = msg.prefix ~= "NOTIFY" and (nick .. ": ") or ""
if AquaChat.ShowBackground then
draw.RoundedBox(roundedCorners, AquaChat.X, messagesY - (msg.height or AquaChat.LineHeight) - 2,
AquaChat.Width, (msg.height or AquaChat.LineHeight) + 4,
Color(
(AquaChat.Background or Color(0, 0, 0, 180)).r,
(AquaChat.Background or Color(0, 0, 0, 180)).g,
(AquaChat.Background or Color(0, 0, 0, 180)).b,
alpha * 0.7
)
)
end
local textY = messagesY - (msg.height or AquaChat.LineHeight)
if msg.prefix == "NOTIFY" then
draw.SimpleText(msg.text or "", AquaChat.Font, AquaChat.X + 5, textY, textColor)
else
local xPos = AquaChat.X + 5
if AquaChat.ShowTimestamps then
local timeW = surface.GetTextSize(timestamp) + 10
draw.RoundedBox(roundedCorners, xPos, textY, timeW, AquaChat.LineHeight, Color(50, 50, 50, alpha * 0.7))
draw.SimpleText(timestamp, AquaChat.Font, xPos + 5, textY, Color(200, 200, 200, alpha))
xPos = xPos + timeW + 5
end
if (prefixData.text or "") ~= "" then
local prefixW = surface.GetTextSize(prefixData.text) + 10
draw.RoundedBox(roundedCorners, xPos, textY, prefixW, AquaChat.LineHeight,
Color(
(prefixData.color or Color(255, 255, 255)).r,
(prefixData.color or Color(255, 255, 255)).g,
(prefixData.color or Color(255, 255, 255)).b,
alpha * 0.7
)
)
draw.SimpleText(prefixData.text, AquaChat.Font, xPos + 5, textY, Color(255, 255, 255, alpha))
xPos = xPos + prefixW + 5
end
draw.SimpleText(nick .. (IsValid(msg.ply) and msg.ply:IsPlayer() and ":" or ""), AquaChat.Font, xPos, textY, nickColor)
xPos = xPos + surface.GetTextSize(nick .. (IsValid(msg.ply) and msg.ply:IsPlayer() and ": " or " "))
if msg.lines and #msg.lines > 0 then
for j, line in ipairs(msg.lines) do
if j > 1 then
textY = textY + AquaChat.LineHeight + 2
end
draw.SimpleText(line, AquaChat.Font, xPos, textY, textColor)
end
end
end
messagesY = messagesY - (msg.height or AquaChat.LineHeight) - 8
end
end
if AquaChat.IsOpen and IsValid(AquaChat.ChatEntry) then
AquaChat.ChatEntry:PaintManual()
end
end)
Ивенты
local function AddMessage(prefix, ply, text, isDead)
local msg = {
prefix = prefix,
ply = IsValid(ply) and ply or Entity(0),
text = text,
time = CurTime(),
alpha = AquaChat.IsOpen and 255 or 0,
width = 0,
height = AquaChat.LineHeight,
isDead = isDead or false,
visible = true,
lines = {},
fadingOut = false
}
surface.SetFont(AquaChat.Font)
local maxWidth = AquaChat.Width - 20
local words = string.Explode(" ", text)
local currentLine = ""
for _, word in ipairs(words) do
local testLine = currentLine == "" and word or currentLine .. " " .. word
local lineWidth = surface.GetTextSize(testLine)
if lineWidth <= maxWidth then
currentLine = testLine
else
if currentLine ~= "" then
table.insert(msg.lines, currentLine)
end
currentLine = word
end
end
if currentLine ~= "" then
table.insert(msg.lines, currentLine)
end
if #msg.lines > 1 then
msg.height = AquaChat.LineHeight * #msg.lines + (#msg.lines - 1) * 2
end
table.insert(AquaChat.Messages, msg)
if #AquaChat.Messages > AquaChat.MaxMessages then
table.remove(AquaChat.Messages, 1)
end
end
net.Receive("AquaChat_AddMessage", function()
local prefix = net.ReadString()
local ply = net.ReadEntity()
local text = net.ReadString()
AddMessage(prefix, ply, text)
end)
hook.Add("OnPlayerChat", "AquaChat_HandleAllMessages", function(ply, text, isTeam, isDead)
local prefix = isTeam and "TEAM" or "OOC"
if ply == LocalPlayer() then
prefix = isTeam and "TEAM" or AquaChat.DefaultChatType
elseif not IsValid(ply) then
prefix = "SERVER"
end
AddMessage(prefix, ply, text, isDead)
end)
hook.Add("ChatText", "AquaChat_ServerMessages", function(index, name, text, type)
local prefixType = (type == "joinleave" or type == "none") and "NOTIFY" or "SERVER"
AddMessage(prefixType, Entity(0), text)
end)
hook.Add("OnChatTab", "AquaChat_SAMMessages", function(text)
AddMessage("ADMIN", Entity(0), text)
end)
hook.Add("Initialize", "AquaChat_OverrideChat", function()
function GAMEMODE:StartChat()
AquaChat.OpenChat()
return true
end
function GAMEMODE:FinishChat()
AquaChat.CloseChat()
end
end)
GUI
function AquaChat.OpenChat()
if AquaChat.IsOpen then return end
AquaChat.IsOpen = true
for _, msg in ipairs(AquaChat.Messages) do
msg.alpha = 255
msg.visible = true
msg.fadingOut = false
end
if IsValid(AquaChat.ChatEntry) then
AquaChat.ChatEntry:Remove()
end
AquaChat.X = (ScrW() - AquaChat.Width) / 2
local inputY = ScrH() * 0.7
AquaChat.ChatEntry = vgui.Create("DTextEntry")
AquaChat.ChatEntry:SetSize(AquaChat.Width, 25)
AquaChat.ChatEntry:SetPos(AquaChat.X, inputY)
AquaChat.ChatEntry:SetText("")
AquaChat.ChatEntry:SetTextColor(Color(255, 255, 255))
AquaChat.ChatEntry:SetFont("AquaChatFont")
AquaChat.ChatEntry:SetDrawLanguageID(false)
AquaChat.ChatEntry:RequestFocus()
AquaChat.ChatEntry:SetHistoryEnabled(true)
AquaChat.ChatEntry.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, Color(0, 0, 0, 200))
self:DrawTextEntryText(Color(255, 255, 255), Color(30, 130, 255), Color(255, 255, 255))
end
AquaChat.ChatEntry.OnEnter = function(self)
local text = self:GetText()
if text ~= "" then
table.insert(AquaChat.ChatHistory, 1, text)
if AquaChat.DefaultChatType ~= "LOCAL" and not string.StartWith(text, "/") then
local cmd = ({
["OOC"] = "/OOC ",
["Д"] = "/ME ",
["Р"] = "/DO ",
["Т"] = "/Т ",
["М"] = "/М ",
["В"] = "/SHOUT ",
})[AquaChat.DefaultChatType] or ""
text = cmd .. text
end
LocalPlayer():ConCommand("say " .. text)
end
AquaChat.HistoryIndex = 0
AquaChat.CloseChat()
end
AquaChat.ChatEntry.OnTextChanged = function(self)
AquaChat.InputText = self:GetText()
end
AquaChat.ChatEntry.OnKeyCodeTyped = function(self, code)
if code == KEY_UP then
if AquaChat.HistoryIndex < #AquaChat.ChatHistory then
AquaChat.HistoryIndex = AquaChat.HistoryIndex + 1
self:SetText(AquaChat.ChatHistory[AquaChat.HistoryIndex])
self:SetCaretPos(#self:GetText())
end
elseif code == KEY_DOWN then
if AquaChat.HistoryIndex > 0 then
AquaChat.HistoryIndex = AquaChat.HistoryIndex - 1
if AquaChat.HistoryIndex == 0 then
self:SetText("")
else
self:SetText(AquaChat.ChatHistory[AquaChat.HistoryIndex])
end
self:SetCaretPos(#self:GetText())
end
elseif code == KEY_TAB then
local types = {"LOCAL", "OOC", "Д", "Р", "Т", "М", "В"}
local currentIndex = table.KeyFromValue(types, AquaChat.DefaultChatType) or 1
AquaChat.DefaultChatType = types[(currentIndex % #types) + 1]
local currentText = self:GetText()
if not string.StartWith(currentText, "/") then
local cmd = ({
["OOC"] = "/ooc ",
["Д"] = "/me ",
["Р"] = "/do ",
["Т"] = "/t ",
["М"] = "/m ",
["В"] = "/shout ",
["LOCAL"] = ""
})[AquaChat.DefaultChatType] or ""
self:SetText(cmd .. currentText)
self:SetCaretPos(string.len(cmd .. currentText))
end
return true
end
end
AquaChat.CreateButtons()
end
function AquaChat.CreateButtons()
for _, btn in pairs(AquaChat.ChatButtons) do
if IsValid(btn) then
btn:Remove()
end
end
AquaChat.ChatButtons = {}
local buttonTypes = {
{type = "LOCAL", text = "Локальный", command = ""},
{type = "OOC", text = "OOC", command = "/ooc "},
{type = "Д", text = "Действие", command = "/me "},
{type = "Р", text = "Роль", command = "/do "},
{type = "Т", text = "Тихо", command = "/t "},
{type = "М", text = "МЕГАФОН", command = "/m "},
{type = "В", text = "Крик", command = "/shout "}
}
local buttonY = (AquaChat.ChatEntry and AquaChat.ChatEntry:GetY() or ScrH() * 0.7) + 30
local currentX = AquaChat.X
surface.SetFont("AquaChatFont")
for _, btnData in ipairs(buttonTypes) do
local textWidth = surface.GetTextSize(btnData.text)
local btnWidth = textWidth + AquaChat.ButtonPadding * 2
local btn = vgui.Create("DButton")
btn:SetSize(btnWidth, 25)
btn:SetPos(currentX, buttonY)
btn:SetText(btnData.text)
btn:SetTextColor(Color(255, 255, 255))
btn:SetFont("AquaChatFont")
btn.Paint = function(self, w, h)
local bgColor = Color(AquaChat.ButtonColor.r, AquaChat.ButtonColor.g, AquaChat.ButtonColor.b,
AquaChat.DefaultChatType == btnData.type and 200 or 100)
draw.RoundedBox(4, 0, 0, w, h, bgColor)
end
btn.DoClick = function()
AquaChat.DefaultChatType = btnData.type
if IsValid(AquaChat.ChatEntry) then
local currentText = AquaChat.ChatEntry:GetText()
if currentText == "" or not string.StartWith(currentText, "/") then
AquaChat.ChatEntry:SetText(btnData.command)
AquaChat.ChatEntry:SetCaretPos(string.len(btnData.command))
end
end
end
table.insert(AquaChat.ChatButtons, btn)
currentX = currentX + btnWidth + AquaChat.ButtonMargin
end
end
function AquaChat.CloseChat()
if not AquaChat.IsOpen then return end
AquaChat.IsOpen = false
local closeTime = CurTime()
for _, msg in ipairs(AquaChat.Messages) do
msg.fadingOut = true
msg.fadeStartTime = closeTime
end
if IsValid(AquaChat.ChatEntry) then
AquaChat.ChatEntry:Remove()
AquaChat.ChatEntry = nil
end
for _, btn in pairs(AquaChat.ChatButtons) do
if IsValid(btn) then
btn:Remove()
end
end
AquaChat.ChatButtons = {}
gui.HideGameUI()
end
hook.Add("PlayerBindPress", "AquaChat_MouseWheelScroll", function(ply, bind, pressed)
if not AquaChat.IsOpen then return end
if bind == "invnext" then
AquaChat.ScrollOffset = math.min(AquaChat.ScrollOffset + AquaChat.WheelScrollSpeed,
math.max(0, #AquaChat.Messages - AquaChat.VisibleMessages))
return true
elseif bind == "invprev" then
AquaChat.ScrollOffset = math.max(AquaChat.ScrollOffset - AquaChat.WheelScrollSpeed, 0)
return true
end
end)
hook.Add("GUIMousePressed", "AquaChat_CloseOnClick", function()
if AquaChat.IsOpen then
AquaChat.CloseChat()
end
end)
concommand.Add("aquachat_toggle_timestamps", function()
AquaChat.ShowTimestamps = not AquaChat.ShowTimestamps
print("Timestamps are now " .. (AquaChat.ShowTimestamps and "enabled" or "disabled"))
end)
concommand.Add("aquachat_toggle_background", function()
AquaChat.ShowBackground = not AquaChat.ShowBackground
print("Chat background is now " .. (AquaChat.ShowBackground and "enabled" or "disabled"))
end)
SV часть
if SERVER then
util.AddNetworkString("AquaChat_AddMessage")
hook.Add("PlayerSay", "AquaChat_HandleChat", function(ply, text, isTeam)
if string.StartWith(text, "/") then
local spacePos = string.find(text, " ") or (#text + 1)
local cmd = string.sub(text, 2, spacePos - 1):upper()
local msg = string.sub(text, spacePos + 1)
local prefix = ({
["OOC"] = "OOC",
["Д"] = "Д",
["Р"] = "Р",
["Т"] = "Т",
["М"] = "М",
["В"] = "В",
["R"] = "R",
["ME"] = "Д",
["DO"] = "Р",
["SHOUT"] = "В",
["К"] = "В",
["LOCAL"] = "LOCAL"
})[cmd]
if prefix then
if cmd == "ME" then
msg = "* " .. ply:Nick() .. " " .. msg
elseif cmd == "DO" then
msg = "* " .. msg .. " (" .. ply:Nick() .. ")"
end
net.Start("AquaChat_AddMessage")
net.WriteString(prefix)
net.WriteEntity(ply)
net.WriteString(msg)
net.Broadcast()
return ""
end
else
net.Start("AquaChat_AddMessage")
net.WriteString("LOCAL")
net.WriteEntity(ply)
net.WriteString(text)
net.Broadcast()
return ""
end
end)
end