mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
261 lines
6.4 KiB
Lua
261 lines
6.4 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
|
|
local PLUGIN = PLUGIN
|
|
|
|
PLUGIN.name = "Typing Indicator"
|
|
PLUGIN.description = "Shows an indicator when someone is typing."
|
|
PLUGIN.author = "`impulse"
|
|
PLUGIN.animationTime = 0.5
|
|
|
|
if (CLIENT) then
|
|
local standingOffset = Vector(0, 0, 72)
|
|
local crouchingOffset = Vector(0, 0, 38)
|
|
local boneOffset = Vector(0, 0, 10)
|
|
local textColor = Color(250, 250, 250)
|
|
local shadowColor = Color(66, 66, 66)
|
|
local currentClass
|
|
|
|
-- we can't rely on matching non-alphanumeric characters (i.e %W) due to patterns matching single bytes and not UTF-8 chars
|
|
local symbolPattern = "[~`!@#$%%%^&*()_%+%-={}%[%]|;:'\",%./<>?]"
|
|
|
|
function PLUGIN:LoadFonts(font, genericFont)
|
|
surface.CreateFont("ixTypingIndicator", {
|
|
font = genericFont,
|
|
size = 128,
|
|
extended = true,
|
|
weight = 1000
|
|
})
|
|
end
|
|
|
|
function PLUGIN:ChatTextChanged(text)
|
|
if (!IsValid(LocalPlayer())) then
|
|
return
|
|
end
|
|
|
|
local character = LocalPlayer():GetCharacter()
|
|
|
|
if (!character) then
|
|
return
|
|
end
|
|
|
|
if (text == "") then
|
|
currentClass = nil
|
|
|
|
net.Start("ixTypeClass")
|
|
net.WriteString("")
|
|
net.SendToServer()
|
|
|
|
return
|
|
end
|
|
|
|
local newClass = hook.Run("GetTypingIndicator", character, text)
|
|
|
|
if (newClass != currentClass) then
|
|
currentClass = newClass
|
|
|
|
net.Start("ixTypeClass")
|
|
net.WriteString(currentClass or "")
|
|
net.SendToServer()
|
|
end
|
|
end
|
|
|
|
function PLUGIN:FinishChat()
|
|
currentClass = nil
|
|
|
|
net.Start("ixTypeClass")
|
|
net.WriteString("")
|
|
net.SendToServer()
|
|
end
|
|
|
|
function PLUGIN:GetTypingIndicator(character, text)
|
|
local prefix = text:utf8sub(1, 1)
|
|
|
|
if (!prefix:find(symbolPattern) and text:utf8len() > 1) then
|
|
return "ic"
|
|
else
|
|
local chatType = ix.chat.Parse(nil, text)
|
|
|
|
if (chatType and chatType != "ic") then
|
|
return !ix.chat.classes[chatType].bNoIndicator and chatType or nil
|
|
end
|
|
|
|
-- some commands will have their own typing indicator, so we'll make sure we're actually typing out a command first
|
|
local start, _, commandName = text:find("/(%S+)%s")
|
|
|
|
if (start == 1) then
|
|
for uniqueID, command in pairs(ix.command.list) do
|
|
if (command.bNoIndicator) then
|
|
continue
|
|
end
|
|
|
|
if (commandName == uniqueID) then
|
|
return command.indicator and "@" .. command.indicator or "ooc"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function PLUGIN:GetTypingIndicatorPosition(client)
|
|
if !IsValid(client) then return end
|
|
|
|
local head
|
|
|
|
for i = 1, client:GetBoneCount() do
|
|
local name = client:GetBoneName(i)
|
|
|
|
if (string.find(name:lower(), "head")) then
|
|
head = i
|
|
break
|
|
end
|
|
end
|
|
|
|
local position = head and client:GetBonePosition(head) or (client:Crouching() and crouchingOffset or standingOffset)
|
|
return position + boneOffset
|
|
end
|
|
|
|
function PLUGIN:PostDrawTranslucentRenderables()
|
|
local client = LocalPlayer()
|
|
local position = client:GetPos()
|
|
|
|
for _, v in ipairs(player.GetAll()) do
|
|
if (v == client) then
|
|
continue
|
|
end
|
|
|
|
local distance = v:GetPos():DistToSqr(position)
|
|
local moveType = v:GetMoveType()
|
|
|
|
if (!IsValid(v) or !v:Alive() or
|
|
(moveType != MOVETYPE_WALK and moveType != MOVETYPE_NONE) or
|
|
!v.ixChatClassText or
|
|
distance >= v.ixChatClassRange) then
|
|
continue
|
|
end
|
|
|
|
local text = v.ixChatClassText
|
|
local range = v.ixChatClassRange
|
|
|
|
if (!text) then
|
|
continue
|
|
end
|
|
|
|
local bAnimation = !ix.option.Get("disableAnimations", false)
|
|
local fraction
|
|
|
|
if (bAnimation) then
|
|
local bComplete = v.ixChatClassTween:update(FrameTime())
|
|
|
|
if (bComplete and !v.ixChatStarted) then
|
|
v.ixChatClassText = nil
|
|
v.ixChatClassRange = nil
|
|
|
|
continue
|
|
end
|
|
|
|
fraction = v.ixChatClassAnimation
|
|
else
|
|
fraction = 1
|
|
end
|
|
|
|
local angle = EyeAngles()
|
|
angle:RotateAroundAxis(angle:Forward(), 90)
|
|
angle:RotateAroundAxis(angle:Right(), 90)
|
|
|
|
cam.Start3D2D(self:GetTypingIndicatorPosition(v), Angle(0, angle.y, 90), 0.05)
|
|
surface.SetFont("ixTypingIndicator")
|
|
|
|
local _, textHeight = surface.GetTextSize(text)
|
|
local alpha = bAnimation and ((1 - math.min(distance, range) / range) * 255 * fraction) or 255
|
|
|
|
draw.SimpleTextOutlined(text, "ixTypingIndicator", 0,
|
|
-textHeight * 0.5 * fraction,
|
|
ColorAlpha(textColor, alpha),
|
|
TEXT_ALIGN_CENTER,
|
|
TEXT_ALIGN_CENTER, 4,
|
|
ColorAlpha(shadowColor, alpha)
|
|
)
|
|
cam.End3D2D()
|
|
end
|
|
end
|
|
|
|
net.Receive("ixTypeClass", function()
|
|
local client = net.ReadEntity()
|
|
|
|
if (!IsValid(client) or client == LocalPlayer()) then
|
|
return
|
|
end
|
|
|
|
local newClass = net.ReadString()
|
|
local chatClass = ix.chat.classes[newClass]
|
|
local text
|
|
local range
|
|
|
|
if (chatClass) then
|
|
text = L(chatClass.indicator or "chatTyping")
|
|
range = chatClass.range or math.pow(ix.config.Get("chatRange", 280), 2)
|
|
elseif (newClass and newClass:sub(1, 1) == "@") then
|
|
text = L(newClass:sub(2))
|
|
range = math.pow(ix.config.Get("chatRange", 280), 2)
|
|
end
|
|
|
|
if (ix.option.Get("disableAnimations", false)) then
|
|
client.ixChatClassText = text
|
|
client.ixChatClassRange = range
|
|
else
|
|
client.ixChatClassAnimation = tonumber(client.ixChatClassAnimation) or 0
|
|
|
|
if (text and !client.ixChatStarted) then
|
|
client.ixChatClassTween = ix.tween.new(PLUGIN.animationTime, client, {ixChatClassAnimation = 1}, "outCubic")
|
|
|
|
client.ixChatClassText = text
|
|
client.ixChatClassRange = range
|
|
client.ixChatStarted = true
|
|
elseif (!text and client.ixChatStarted) then
|
|
client.ixChatClassTween = ix.tween.new(PLUGIN.animationTime, client, {ixChatClassAnimation = 0}, "inCubic")
|
|
client.ixChatStarted = nil
|
|
end
|
|
end
|
|
end)
|
|
else
|
|
util.AddNetworkString("ixTypeClass")
|
|
|
|
function PLUGIN:PlayerSpawn(client)
|
|
net.Start("ixTypeClass")
|
|
net.WriteEntity(client)
|
|
net.WriteString("")
|
|
net.Broadcast()
|
|
end
|
|
|
|
net.Receive("ixTypeClass", function(length, client)
|
|
if ((client.ixNextTypeClass or 0) > RealTime()) then
|
|
return
|
|
end
|
|
|
|
local newClass = net.ReadString()
|
|
|
|
-- send message to players in pvs only since they're the only ones who can see the indicator
|
|
-- we'll broadcast if the type class is empty because they might move out of pvs before the ending net message is sent
|
|
net.Start("ixTypeClass")
|
|
net.WriteEntity(client)
|
|
net.WriteString(newClass)
|
|
|
|
if (newClass == "") then
|
|
net.Broadcast()
|
|
else
|
|
net.SendPVS(client:GetPos())
|
|
end
|
|
|
|
client.ixNextTypeClass = RealTime() + 0.2
|
|
end)
|
|
end
|