Skip to content

Instantly share code, notes, and snippets.

@GermanAizek
Created October 18, 2020 03:33
Show Gist options
  • Save GermanAizek/b3f965b91096420fc2ff5e750a965fb3 to your computer and use it in GitHub Desktop.
Save GermanAizek/b3f965b91096420fc2ff5e750a965fb3 to your computer and use it in GitHub Desktop.
nutscript plugin Area
local PLUGIN = PLUGIN
PLUGIN.name = "Area"
PLUGIN.author = "Black Tea"
PLUGIN.desc = "Allows you to set area."
PLUGIN.areaTable = PLUGIN.areaTable or {}
nut.area = nut.area or {}
ALWAYS_RAISED["nut_areahelper"] = true
nut.config.add("areaFontSize", 26, "The size of the font of Area Display.",
function(oldValue, newValue)
if (CLIENT) then
hook.Run("LoadFonts", nut.config.get("font"))
end
end,
{data = {min = 1, max = 128},
category = "areaPlugin"
})
nut.config.add("areaDispSpeed", 20, "The Appearance Speed of Area Display.", nil, {
data = {min = 1, max = 40},
category = "areaPlugin"
})
local playerMeta = FindMetaTable("Player")
local PLUGIN = PLUGIN
if (SERVER) then
function nut.area.getArea(areaID)
return PLUGIN.areaTable[areaID]
end
function nut.area.getAllArea()
return PLUGIN.areaTable
end
-- This is for single check (ex: area items, checking area in commands)
function playerMeta:isInArea(areaID)
local areaData = nut.area.getArea(areaID)
if (!areaData) then
return false, "Area you specified is not valid."
end
local char = self:getChar()
if (!char) then
return false, "Your character is not valid."
end
local clientPos = self:GetPos() + self:OBBCenter()
return clientPos:WithinAABox(areaData.minVector, areaData.maxVector), areaData
end
-- This is for continous check (ex: checking gas area whatever.)
function playerMeta:getArea()
return self.curArea
end
function PLUGIN:saveAreas()
self:setData(self.areaTable)
end
function PLUGIN:LoadData()
self.areaTable = self:getData() or {}
end
function PLUGIN:PlayerLoadedChar(client, character, lastChar)
client.curArea = nil
end
function PLUGIN:PlayerDeath(client)
client.curArea = nil
end
function PLUGIN:EntityTakeDamage( client, dmg )
if client:IsPlayer() and client.curArea then
local areaData = table.Copy(nut.area.getArea(client.curArea))
if areaData.isSafe and client:isInArea(client.curArea) then
dmg:ScaleDamage(0)
end
end
end
function PLUGIN:PlayerSpawn(client)
client.curArea = nil
end
-- gets two vector and gives min and max vector for Vector:WithinAA(min, max)
local function sortVector(vector1, vector2)
local minVector = Vector(0, 0, 0)
local maxVector = Vector(0, 0, 0)
for i = 1, 3 do
if (vector1[i] >= vector2[i]) then
maxVector[i] = vector1[i]
minVector[i] = vector2[i]
else
maxVector[i] = vector2[i]
minVector[i] = vector1[i]
end
end
return minVector, maxVector
end
-- add area.
function nut.area.addArea(name, vector1, vector2, isSafe)
if (!name or !vector1 or !vector2) then
return false, "Required arguments are not provided."
end
local minVector, maxVector = sortVector(vector1, vector2)
table.insert(PLUGIN.areaTable, {
name = name,
minVector = minVector,
maxVector = maxVector,
isSafe = isSafe or 0,
})
PLUGIN:saveAreas()
end
-- Timer instead of heavy think.
timer.Create("nutAreaController", 0.33, 0, function()
for k, v in ipairs(player.GetAll()) do
local char = v:getChar()
if (char and v:Alive()) then
local area = v:getArea()
for id, areaData in pairs(nut.area.getAllArea()) do
local clientPos = v:GetPos() + v:OBBCenter()
if (clientPos:WithinAABox(areaData.minVector, areaData.maxVector)) then
if (area != id) then
v.curArea = id
hook.Run("OnPlayerAreaChanged", v, id)
end
end
end
end
end
end)
-- If area is changed, set display Area's Name to the client's screen.
function PLUGIN:OnPlayerAreaChanged(client, areaID)
local areaData = nut.area.getArea(areaID)
netstream.Start(client, "displayAreaText", tostring(areaData.name))
end
netstream.Hook("areaEdit", function(client, areaID, editData)
-- Only Admin can edit the area.
if (!client:IsAdmin()) then
return false
end
-- If area is valid, merge editData to areaData.
local areaData = table.Copy(nut.area.getArea(areaID))
if (areaData) then
client:notifyLocalized("areaModified", areaID)
PLUGIN.areaTable[areaID] = table.Merge(areaData, editData)
PLUGIN:saveAreas()
end
end)
netstream.Hook("areaTeleport", function(client, areaID, editData)
-- Only Admin can do this.
if (!client:IsAdmin()) then
return false
end
-- If area is valid, merge editData to areaData.
local areaData = table.Copy(nut.area.getArea(areaID))
if (areaData) then
local min, max = areaData.maxVector, areaData.minVector
client:SetPos(min + (max - min)/2)
end
end)
netstream.Hook("toggleSafe", function(client, areaID, editData)
-- Only Admin can edit the area.
if (!client:IsAdmin()) then
return false
end
local areaData = table.Copy(nut.area.getArea(areaID))
if (areaData) then
PLUGIN.areaTable[areaID].isSafe = !PLUGIN.areaTable[areaID].isSafe
PLUGIN:saveAreas()
end
end)
netstream.Hook("areaAdd", function(client, name, vector1, vector2, isSafe)
-- Only Admin can edit the area.
if (!client:IsAdmin() or !vector1 or !vector2 or !name) then
return false
end
nut.area.addArea(name, vector1, vector2, isSafe or 0)
end)
netstream.Hook("areaRemove", function(client, areaID, editData)
-- Only Admin can edit the area.
if (!client:IsAdmin()) then
return false
end
-- If area is valid, merge editData to areaData.
local areaData = table.Copy(nut.area.getArea(areaID))
if (areaData) then
client:notifyLocalized("areaRemoved", areaID)
PLUGIN.areaTable[areaID] = nil
PLUGIN:saveAreas()
end
end)
else
netstream.Hook("displayPosition", function(pos)
local emitter = ParticleEmitter( pos )
local bling = emitter:Add( "sprites/glow04_noz", pos )
bling:SetVelocity( Vector( 0, 0, 1 ) )
bling:SetDieTime(10)
bling:SetStartAlpha(255)
bling:SetEndAlpha(255)
bling:SetStartSize(64)
bling:SetEndSize(64)
bling:SetColor(255,186,50)
bling:SetAirResistance(300)
end)
-- area Manager.
local function addAreaPanel(frame)
local panel = frame:Add("DPanel")
panel:SetTall(30)
frame:AddItem(panel)
end
function nut.area.openAreaManager()
local frame = vgui.Create("DFrame")
frame:SetSize(400, 300)
frame:Center()
frame:MakePopup()
frame:SetTitle("Area Manager")
frame.menu = frame:Add("PanelList")
frame.menu:Dock(FILL)
frame.menu:DockMargin(5, 5, 5, 5)
frame.menu:SetSpacing(2)
frame.menu:SetPadding(2)
frame.menu:EnableVerticalScrollbar()
addAreaPanel(frame.menu)
end
netstream.Hook("areaManager", function()
--nut.area.openAreaManager()
end)
function PLUGIN:LoadFonts(font)
timer.Simple(0, function()
surface.CreateFont("nutAreaDisplay", {
font = font,
size = ScreenScale(nut.config.get("areaFontSize")),
weight = 500,
shadow = true,
})
end)
end
-- draw matrix string.
-- slow as fuck I guess?
local function drawMatrixString(str, font, x, y, scale, angle, color)
surface.SetFont(font)
local tx, ty = surface.GetTextSize(str)
local matrix = Matrix()
matrix:Translate(Vector(x, y, 1))
matrix:Rotate(angle or Angle(0, 0, 0))
matrix:Scale(scale)
cam.PushModelMatrix(matrix)
surface.SetTextPos(2, 2)
surface.SetTextColor(color or color_white)
surface.DrawText(str)
cam.PopModelMatrix()
end
-- configureable values.
local speed = 0
local targetScale = 0
local dispString = ""
local tickSound = "UI/buttonrollover.wav"
local dieTime = 5
-- non configureable values.
-- local scale = 0
local scale = 0
local flipTable = {}
local powTime = RealTime()*speed
local curChar = 0
local mathsin = math.sin
local mathcos = math.cos
local dieTrigger = false
local dieTimer = RealTime()
local dieAlpha = 0
local ft, w, h, dsx, dsy
function displayScrText(str, time)
speed = nut.config.get("areaDispSpeed")
targetScale = 1
dispString = str
dieTime = time or 5
scale = targetScale * .5
flipTable = {}
powTime = RealTime()*speed
curChar = 0
dieTrigger = false
dieTimer = RealTime()
dieAlpha = 255
end
netstream.Hook("displayAreaText", function(str)
displayScrText(str)
end)
function PLUGIN:HUDPaint()
-- values
if ((hook.Run("CanDisplayArea") == false) or (dieTrigger and dieTimer < RealTime() and dieAlpha <= 1)) then
return
end
ft = FrameTime()
w, h = ScrW(), ScrH()
dsx, dsy = 0
local strEnd = string.utf8len(dispString)
local rTime = RealTime()
surface.SetFont("Default")
local sx, sy = surface.GetTextSize(dispString)
-- Number of characters to display.
local maxDisplay = math.Round(rTime*speed - powTime)
-- resize if it's too big.
while (sx and sx*targetScale > w*.8) do
targetScale = targetScale * .9
end
-- scale lerp
scale = Lerp(ft*1, scale, targetScale)
--scale = targetScale
-- change event
if (maxDisplay != curChar and curChar < strEnd) then
curChar = maxDisplay
if (string.utf8sub(dispString, curChar, curChar) != " ") then
LocalPlayer():EmitSound(tickSound, 100, math.random(190, 200))
end
end
-- draw recursive
for i = 1, math.min(maxDisplay, strEnd) do
-- character scale/color lerp
flipTable[i] = flipTable[i] or {}
flipTable[i][1] = flipTable[i][1] or .1
--flipTable[i][1] = flipTable[i][1] or targetScale*3
flipTable[i][2] = flipTable[i][2] or 0
flipTable[i][1] = Lerp(ft*4, flipTable[i][1], scale)
flipTable[i][2] = Lerp(ft*4, flipTable[i][2], 255)
-- draw character.
local char = string.utf8sub(dispString, i, i)
local tx, ty = surface.GetTextSize(char)
drawMatrixString(char,
"zonaStalkerTitle",
math.Round(w/2 + dsx - (sx or 0)*scale/2),
math.Round(h/3*1 - (sy or 0)*scale/2),
Vector(Format("%.2f", flipTable[i][1]), Format("%.2f", scale), 1),
nil,
Color(255, 255, 255,
(dieTrigger and dieTimer < RealTime()) and dieAlpha or flipTable[i][2])
)
-- next
dsx = dsx + tx*scale
end
if (maxDisplay >= strEnd) then
if (dieTrigger != true) then
dieTrigger = true
dieTimer = RealTime() + 2
else
if (dieTimer < RealTime()) then
dieAlpha = Lerp(ft*4, dieAlpha, 0)
end
end
end
end
end
nut.command.add("areaadd", {
adminOnly = true,
syntax = "<string name>",
onRun = function(client, arguments)
local name = table.concat(arguments, " ") or "Area"
local pos = client:GetEyeTraceNoCursor().HitPos
if (!client:getNetVar("areaMin")) then
if (!name) then
nut.util.Notify(nut.lang.Get("missing_arg", 1), client)
return
end
netstream.Start(client, "displayPosition", pos)
client:setNetVar("areaMin", pos, client)
client:setNetVar("areaName", name, client)
return "@areaCommand"
else
local min = client:getNetVar("areaMin")
local max = pos
local name = client:getNetVar("areaName")
netstream.Start(client, "displayPosition", pos)
client:setNetVar("areaMin", nil, client)
client:setNetVar("areaName", nil, client)
nut.area.addArea(name, min, max)
return "@areaAdded", name
end
end
})
nut.command.add("arearemove", {
adminOnly = true,
onRun = function(client, arguments)
local areaID = client:getArea()
if (!areaID) then
return
end
local areaData = nut.area.getArea(areaID)
if (areaData) then
table.remove(PLUGIN.areaTable, areaID)
PLUGIN:saveAreas()
return "@areaRemoved", areaData.name
end
end
})
nut.command.add("areachange", {
adminOnly = true,
syntax = "<string name>",
onRun = function(client, arguments)
local name = table.concat(arguments, " ") or "Area"
local areaID = client:getArea()
if (!areaID) then
return
end
local areaData = nut.area.getArea(areaID)
if (areaData) then
areaData.name = name
PLUGIN:saveAreas()
return "@areaChanged", name, areaData.name
end
end
})
nut.command.add("areamanager", {
adminOnly = true,
onRun = function(client, arguments)
if (client:Alive()) then
netstream.Start(client, "nutAreaManager", nut.area.getAllArea())
end
end
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment