From 49e018aee0b82e805660e819d7b7647d8ac9c07c Mon Sep 17 00:00:00 2001 From: Bob Blackmon Date: Sun, 2 Apr 2017 23:21:08 -0400 Subject: Changed folder --- lua/entities/ent_zone_point.lua | 132 +++++ lua/weapons/weapon_zone_designator.lua | 703 +++++++++++++++++++++++++++ lua/zones.lua | 467 ++++++++++++++++++ zones/lua/entities/ent_zone_point.lua | 132 ----- zones/lua/weapons/weapon_zone_designator.lua | 703 --------------------------- zones/lua/zones.lua | 467 ------------------ 6 files changed, 1302 insertions(+), 1302 deletions(-) create mode 100644 lua/entities/ent_zone_point.lua create mode 100644 lua/weapons/weapon_zone_designator.lua create mode 100644 lua/zones.lua delete mode 100644 zones/lua/entities/ent_zone_point.lua delete mode 100644 zones/lua/weapons/weapon_zone_designator.lua delete mode 100644 zones/lua/zones.lua diff --git a/lua/entities/ent_zone_point.lua b/lua/entities/ent_zone_point.lua new file mode 100644 index 0000000..986221a --- /dev/null +++ b/lua/entities/ent_zone_point.lua @@ -0,0 +1,132 @@ + +AddCSLuaFile() + +DEFINE_BASECLASS( "base_anim" ) + +ENT.PrintName = "Zone Point" +ENT.Author = "Bobblehead" +ENT.Information = "A point in the zone designator." +ENT.Category = "Other" + +ENT.Editable = false +ENT.Spawnable = false +ENT.AdminOnly = false +ENT.RenderGroup = RENDERGROUP_TRANSLUCENT + + +function ENT:Initialize() + self:SetModel("models/hunter/blocks/cube025x025x025.mdl") + self:SetCollisionGroup(COLLISION_GROUP_WORLD) + self:DrawShadow(false) + + if SERVER then + self:SetUseType(SIMPLE_USE) + self:PhysicsInit(SOLID_BBOX) + self:GetPhysicsObject():EnableMotion(false) + + self:GetPhysicsObject():SetMass(1) + + else + self:SetRenderBoundsWS(self:GetPos(),self:GetPos()+Vector(0,0,self:GetTall())) + end +end + +function ENT:SetupDataTables() + self:NetworkVar("Entity",0,"Next") + self:NetworkVar("Float",0,"Tall") + self:NetworkVar("Int",0,"ZoneID") + self:NetworkVar("String",0,"ZoneClass") + self:NetworkVar("Int",1,"AreaNumber") +end + +function ENT:DrawTranslucent() + local wep = LocalPlayer():GetActiveWeapon() + if wep:IsValid() and wep:GetClass() == "weapon_zone_designator" then + + if wep:GetZoneClass() == self:GetZoneClass() or GetConVarNumber("zone_filter") == 0 then + self:DrawModel() + + local p = self:GetPos() + p.z = p.z + self:GetTall() + render.Model({model=self:GetModel(),pos=p,ang=angle_zero}) + + render.SetMaterial(Material("cable/cable2")) + render.DrawBeam( self:GetPos(), p, 1, 1, 0, color_white ) + + local next = self:GetNext() + if IsValid(next) then + local class = self:GetZoneClass() + + render.DrawBeam( self:GetPos(), next:GetPos(), 1, 1, 0, color_white ) + + local n = next:GetPos() + n.z = n.z + next:GetTall() + render.DrawBeam( p, n, 1, 1, 0, color_white ) + + render.SetColorMaterial() + local col1 = table.Copy(zones.Classes[class]) + col1.a = 80 + local col2 = {a=80} + col2.r = col1.r * .5 + col2.g = col1.g * .5 + col2.b = col1.b * .5 + + render.DrawQuad(p,self:GetPos(),next:GetPos(),n,col1) + render.DrawQuad(n,next:GetPos(),self:GetPos(),p,col2) + + local id = self:GetZoneID() + local classtxt = id != -1 and class .. " (# "..id..")" or class + + local ang = (p-self:GetPos()):Cross(n-self:GetPos()):Angle() + ang:RotateAroundAxis(ang:Right(), 90) + ang:RotateAroundAxis(ang:Up(),-90) + cam.Start3D2D((n+self:GetPos())/2,ang,.2) + draw.SimpleText(classtxt,"DermaLarge",0,0,color_white,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) + cam.End3D2D() + + ang:RotateAroundAxis(Vector(0,0,1), 180) + cam.Start3D2D((n+self:GetPos())/2,ang,.2) + draw.SimpleText(classtxt,"DermaLarge",0,0,color_white,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) + cam.End3D2D() + + end + end + end +end + +function ENT:Think() + if CLIENT then + local next = self:GetNext() + if IsValid(next) and next != self.resizedto then + self:SetRenderBoundsWS(self:GetPos(),next:GetPos()+Vector(0,0,next:GetTall())) + self.resizedto = next + end + + local wep = LocalPlayer():GetActiveWeapon() + if wep:IsValid() and wep:GetClass() == "weapon_zone_designator" then + if LocalPlayer():GetEyeTrace().Entity == self then + self:SetColor(Color(255,0,0)) + elseif wep:GetCurrentPoint() == self then + self:SetColor(Color(0,0,255)) + else + self:SetColor(color_white) + end + end + else + + if IsValid(self.Resizing) then + + self:SetTall((self.Resizing:GetEyeTrace().HitPos - self:GetPos()).z) + + end + + end +end + +function ENT:OnRemove() + if SERVER then + if IsValid(self:GetNext()) then + self:GetNext():Remove() + end + end +end diff --git a/lua/weapons/weapon_zone_designator.lua b/lua/weapons/weapon_zone_designator.lua new file mode 100644 index 0000000..fd2c0c5 --- /dev/null +++ b/lua/weapons/weapon_zone_designator.lua @@ -0,0 +1,703 @@ + +if CLIENT then + CreateClientConVar("zone_tall",200,false,true) + CreateClientConVar("zone_class","",false,true) + CreateClientConVar("zone_editmode",1,false,true) + CreateClientConVar("zone_filter",0,false,true) + + surface.CreateFont( "zones_save", { + font = "Roboto", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name + size = 20, + weight = 1000, + } ) + surface.CreateFont( "zones_screen", { + font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name + size = 20, + weight = 1000, + + } ) +else + concommand.Add("zone_swep",function(p,c,a) + if p:IsAdmin() then + p:Give("weapon_zone_designator") + end + end) +end + +if engine.ActiveGamemode() == "terrortown" then + SWEP.Base = "weapon_tttbase" + SWEP.Kind = WEAPON_EQUIP2 +end + + +SWEP.NoSights = true + +SWEP.PrintName = "Zone Designator" +SWEP.Author = "Bobblehead" +SWEP.Purpose = "Creates zones. Reload for menu. Right click to remove a point/zone." + +SWEP.Slot = 5 +SWEP.SlotPos = 5 + +SWEP.Spawnable = true +SWEP.AdminOnly = true + +SWEP.HoldType = "pistol" +SWEP.ViewModelFOV = 51 +SWEP.ViewModelFlip = false +SWEP.UseHands = true +SWEP.ViewModel = "models/weapons/c_toolgun.mdl" +SWEP.WorldModel = "models/weapons/w_toolgun.mdl" +SWEP.AutoSwitchFrom = true +SWEP.AutoSwitchTo = true + +SWEP.Primary.ClipSize = -1 +SWEP.Primary.DefaultClip = -1 +SWEP.Primary.Automatic = false +SWEP.Primary.Delay = .5 +SWEP.Primary.Ammo = "none" + +SWEP.Secondary.ClipSize = -1 +SWEP.Secondary.DefaultClip = -1 +SWEP.Secondary.Automatic = false +SWEP.Secondary.Ammo = "none" + + +function SWEP:SetupDataTables() + self:NetworkVar("Float",0,"Tall") + self:NetworkVar("String",0,"ZoneClass") + self:NetworkVar("Entity",0,"CurrentPoint") + self:NetworkVar("Int",0,"Mode") + +end + +function SWEP:Initialize() + + self:SetTall(150) + self:SetMode(1) + + self:SetCurrentPoint(NULL) +end + +function SWEP:Deploy() + if SERVER then + local points = ents.FindByClass("ent_zone_point") + local ct = 0 + for k,v in pairs(zones.List) do + for k2,v2 in pairs(v.points)do + for k3, v3 in pairs(v2) do + ct = ct + 1 + end + end + end + if #points != ct then + zones.CreatePointEnts(points) + end + end +end + +function SWEP:Holster() + if SERVER then + local none = true + for k, ply in pairs(player.GetAll()) do + if ply == self.Owner then continue end + local wep = ply:GetActiveWeapon() + if IsValid(wep) and wep:GetClass() == "weapon_zone_designator" then + none = false + break + end + end + if none then + for k,v in pairs(ents.FindByClass("ent_zone_point"))do + v:Remove() + end + end + + self:SetCurrentPoint(NULL) + + return true + end +end + +function SWEP:DrawHUD() + local z,id = LocalPlayer():GetCurrentZone(GetConVarNumber("zone_filter") == 1 and self:GetZoneClass() or nil) + z = z and z.class.."(# "..id..")" or "None" + draw.SimpleText("Current Zone: "..z, "DermaLarge", 100,100) +end + +function SWEP:PrimaryAttack() + + + self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) + + if SERVER then + self.Owner:EmitSound("buttons/button15.wav") + end + + self:UpdateSettings() + local mode = self:GetMode() + + if mode == 1 then //Create + if CLIENT then return end + self:PlacePoint() + elseif mode == 2 then //Merge + if CLIENT then return end + self:MergeZones() + + elseif mode == 3 then //Edit + local curr = self:GetCurrentPoint() + + if IsValid(curr) then + if CLIENT then return end + local next = curr + repeat + + next.Resizing = nil + + next = next:GetNext() + + until ( next == curr ) + + zones.List[curr:GetZoneID()].height[curr:GetAreaNumber()] = curr:GetTall() + zones.CalcBounds(zones.List[id]) + + self:SetCurrentPoint(NULL) + + elseif CLIENT then + local tr = self.Owner:GetEyeTrace() + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + zones.ShowOptions(tr.Entity:GetZoneID()) + end + + end + + elseif mode == 4 then + if CLIENT then return end + + local curr = self:GetCurrentPoint() + local tr = self.Owner:GetEyeTrace() + + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + + self:SetCurrentPoint(tr.Entity) + + elseif IsValid(curr) then + + local id,areanum = curr:GetZoneID(), curr:GetAreaNumber() + local next = curr:GetNext() + + local new = ents.Create("ent_zone_point") + local p = curr:GetPos() + tr.HitPos.z = p.z + new:SetPos(tr.HitPos) + curr:SetNext(new) + -- self:GetCurrentPoint():DeleteOnRemove(new) + + new.LastPoint = self:GetCurrentPoint() + self:SetCurrentPoint(new) + new:SetTall(curr:GetTall()) + new:SetZoneClass(curr:GetZoneClass()) + new:SetZoneID(id) + new:SetAreaNumber(areanum) + new:Spawn() + new:SetNext(next) + next.LastPoint = new + + + local n = new + local pts = {} + repeat + pts[#pts+1] = n:GetPos() - Vector(0,0,2) + n = n:GetNext() + until (n == new) + + + zones.List[id].points[areanum] = pts + + zones.CalcBounds(zones.List[id]) + + zones.Sync() + + end + + end + +end + +function SWEP:SecondaryAttack() + self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) + + if CLIENT then return end + + self.Owner:EmitSound("buttons/button16.wav") + + local tr = self.Owner:GetEyeTrace() + local mode = self:GetMode() + + if mode == 1 then //delete + + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + local point = tr.Entity + local last = point.LastPoint + + local id = point:GetZoneID() + if id != -1 then + + if #zones.List[id].points > 1 then + id = select(2,zones.Split(id, point:GetAreaNumber())) + end + + zones.Remove(id) + + end + + point:Remove() + + self:SetCurrentPoint(last) + + elseif self:GetCurrentPoint():IsValid() then + local point, last = self:GetCurrentPoint(), self:GetCurrentPoint().LastPoint + point:Remove() + self:SetCurrentPoint(last or NULL) + end + + elseif mode == 2 then //split + + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + local point = tr.Entity + local id = point:GetZoneID() + + if #zones.List[id].points == 1 then + return + end + + local zone, newid = zones.Split(id, point:GetAreaNumber()) + + local next = point + repeat + + next:SetZoneID(newid) + next:SetAreaNumber(next:GetAreaNumber() - #zones.List[id].points) + + next = next:GetNext() + + until ( next == point ) + + end + + elseif mode == 3 then //resize + local curr = self:GetCurrentPoint() + + if IsValid(curr) then + + local next = curr + repeat + + next.Resizing = nil + + next = next:GetNext() + + until ( next == curr ) + + zones.List[curr:GetZoneID()].height[curr:GetAreaNumber()] = curr:GetTall() + zones.CalcBounds(zones.List[curr:GetZoneID()]) + + zones.Sync() + + self:SetCurrentPoint(NULL) + + else + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + local next = tr.Entity + repeat + next.Resizing = self.Owner + + next = next:GetNext() + + + until ( next == tr.Entity ) + + self:SetCurrentPoint(tr.Entity) + end + end + + elseif mode == 4 then //Remove a point + + if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" or IsValid(self:GetCurrentPoint()) then + + local hit = tr.Entity:IsValid() and tr.Entity or self:GetCurrentPoint() + local id,areanum = hit:GetZoneID(), hit:GetAreaNumber() + + if #zones.List[id].points[areanum] > 3 then + + local last = hit.LastPoint + local next = hit:GetNext() + + next.LastPoint = last + last:SetNext(next) + + hit:SetNext(NULL) + hit.LastPoint = nil + hit:Remove() + + local n = next + local pts = {} + repeat + pts[#pts+1] = n:GetPos() - Vector(0,0,2) + n = n:GetNext() + until (n == next) + + zones.List[id].points[areanum] = pts + + zones.CalcBounds(zones.List[id]) + + zones.Sync() + + self:SetCurrentPoint(last) + + end + + end + + end + + +end + +local mx,my +if CLIENT then + mx, my = ScrW()/2, ScrH()/2 +end + +function SWEP:Reload() --show menu. + + self:UpdateSettings() + if SERVER then + if game.SinglePlayer() then + self:CallOnClient("Reload") + end + return + end + + if IsValid(self.frame) then return end + + input.SetCursorPos(mx,my) + + self:OpenMenu() + +end + +function SWEP:PlacePoint() --mode == 1 + local tr = self.Owner:GetEyeTrace() + if tr.HitWorld then + + local next = ents.Create("ent_zone_point") + + if IsValid(self:GetCurrentPoint()) then + local p = self:GetCurrentPoint():GetPos() + tr.HitPos.z = p.z + next:SetPos(tr.HitPos) + self:GetCurrentPoint():SetNext(next) + -- self:GetCurrentPoint():DeleteOnRemove(next) + else + next:SetPos(tr.HitPos+Vector(0,0,1)) + end + + next.LastPoint = self:GetCurrentPoint() + self:SetCurrentPoint(next) + next:SetTall(self:GetTall()) + next:SetZoneClass(self:GetZoneClass()) + next:SetZoneID(-1) + next:SetAreaNumber(1) + next:Spawn() + + elseif tr.Entity:IsValid() and tr.Entity:GetClass() == "ent_zone_point" and tr.Entity != self:GetCurrentPoint() then + if IsValid(self:GetCurrentPoint()) then + local next = tr.Entity + if !IsValid(next.LastPoint) then + + self:GetCurrentPoint():SetNext(next) + + if IsValid(next:GetNext()) then //we've come full circle. + + next.LastPoint = self:GetCurrentPoint() + + local id = select(2,zones.CreateZoneFromPoint(self:GetCurrentPoint())) + -- self:GetCurrentPoint():DeleteOnRemove(next) + self:SetCurrentPoint(NULL) + + local o = self.Owner + timer.Simple(.1,function() -- wait for it to sync. + if IsValid(o) then + o:SendLua("zones.ShowOptions("..id..")") + end + end) + + end + + end + end + + + end +end + +function SWEP:MergeZones() + + local tr = self.Owner:GetEyeTrace() + if tr.HitWorld then + self:SetCurrentPoint(NULL) + + elseif IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then + + local curr = self:GetCurrentPoint() + local trent = tr.Entity + if not IsValid(curr) then + self:SetCurrentPoint(trent) + + else + //Merge the zones. + if curr:GetZoneID() != trent:GetZoneID() then + local cid = curr:GetZoneID() + + --Change the points. + for k,next in pairs(ents.FindByClass("ent_zone_point")) do + if next:GetZoneID() == cid then + + next:SetZoneID(trent:GetZoneID()) + next:SetAreaNumber(next:GetAreaNumber() + #zones.List[trent:GetZoneID()].points) + next:SetZoneClass(zones.List[trent:GetZoneID()].class) + + end + + end + + self:SetCurrentPoint(NULL) + + zones.Merge(cid,trent:GetZoneID()) --from, to + + else + self:SetCurrentPoint(trent) + + end + + end + + end +end + +function SWEP:UpdateSettings() + --load convars + local new_tall = SERVER and self.Owner:GetInfoNum("zone_tall",200) or GetConVarNumber("zone_tall") + local new_class = SERVER and self.Owner:GetInfo("zone_class") or GetConVarString("zone_class") + local new_mode = SERVER and self.Owner:GetInfoNum("zone_editmode",1) or GetConVarNumber("zone_editmode") + + if new_class == "" then + for k,v in pairs(zones.Classes)do + new_class = k + self.Owner:ConCommand('zone_class "'..k..'"') + break + end + end + + --If changed, remove current building area + if new_class != self:GetZoneClass() or new_tall != self:GetTall() or new_mode != self:GetMode() then + self:ResetTool() + end + assert(new_class != "", "No class is set for the zone designator! Did you call zones.RegisterClass()?\n") + + --apply convars + self:SetTall(new_tall) + self:SetZoneClass(new_class) + self:SetMode(new_mode) +end + +function SWEP:ResetTool() + + if self:GetMode() == 1 and SERVER then + local cur = self:GetCurrentPoint() + if IsValid(cur) and cur:GetZoneID() == -1 then + + while IsValid(cur) do + local last = cur.LastPoint + cur:Remove() + cur = last + end + + end + + end + self:SetCurrentPoint(NULL) +end + +function SWEP:OpenMenu() + local zc = self:GetZoneClass() + + local frame = vgui.Create("DFrame") + self.frame = frame + frame:SetSize(300,400) + frame:Center() + frame:MakePopup() + frame:ShowCloseButton(false) + frame:SetTitle("Zone Designator Options") + function frame:Think() + if not input.IsButtonDown(_G["KEY_"..input.LookupBinding("+reload"):upper()]) then + mx,my = gui.MousePos() + self:Close() + end + end + + local ztitle = vgui.Create("DLabel",frame) + ztitle:Dock(TOP) + ztitle:DockMargin(7,0,5,0) + ztitle:SetText("Zone Class:") + ztitle:SizeToContents() + + local zclass = vgui.Create("DComboBox",frame) + zclass:Dock(TOP) + zclass:DockMargin(5,0,5,0) + for k,v in pairs(zones.Classes) do + zclass:AddChoice(k,nil,k==zc) + end + function zclass:OnSelect(i,class) + RunConsoleCommand("zone_class",class) + end + + local filter = vgui.Create("DCheckBoxLabel",frame) + filter:Dock(TOP) + filter:DockMargin(6,5,5,5) + filter:SetText("Filter zones of a different class.") + filter:SizeToContents() + filter:SetConVar("zone_filter") + + local height = vgui.Create( "DNumSlider", frame ) + height:Dock(TOP) + height:DockMargin(7,0,0,0) + height:SetText( "Zone Height:" ) + height:SetMin( 0 ) + height:SetMax( 1000 ) + height:SetDecimals( 0 ) + height:SetConVar( "zone_tall" ) + + local modetitle = vgui.Create("DLabel",frame) + modetitle:Dock(TOP) + modetitle:DockMargin(7,0,5,0) + modetitle:SetText("Tool Mode:") + modetitle:SizeToContents() + + local mode = vgui.Create("DListView",frame) + mode:Dock(TOP) + mode:DockMargin(5,0,5,5) + mode:AddColumn("Mode") + mode:AddColumn("Info"):SetFixedWidth(180) + mode:SetTall(200) + mode:SetMultiSelect(false) + + mode:AddLine("Create / Delete","Create new zones") + mode:AddLine("Merge / Split","Turn two zones into one.") + mode:AddLine("Edit / Resize","Change zone properties.") + mode:AddLine("Insert / Remove","Insert points into existing zones.") + mode:SelectItem(mode:GetLine(self:GetMode())) + function mode:OnRowSelected(id) + RunConsoleCommand("zone_editmode",id) + end + + + local save = vgui.Create("DButton",frame) + save:Dock(BOTTOM) + save:DockMargin(5,0,5,5) + save:SetText("SAVE ALL ZONES") + save:SetFont("zones_save") + save:SetTextColor(color_black) + save:SetTall(50) + function save:DoClick() + Derma_Query("Are you sure you want to save? This can't be undone.", "Save Confirmation", + "Yes", function() + RunConsoleCommand("zone_save") + end, + "No", function() + end + ) + end + + + +end + +local modes = { + { --create + "Create", + "Delete" + }, + { --merge + "Merge", + "Split" + }, + { --edit + "Edit", + "Resize" + }, + { --insert + "Insert", + "Remove" + }, +} +local lmb, rmb = Material("gui/lmb.png","unlitgeneric"), Material("gui/rmb.png","unlitgeneric") +function SWEP:DrawScreen(x,y,w,h) + local mode = self:GetMode() + local txt = modes[mode] + + draw.SimpleText(txt[1], "zones_screen", x+w/4, -h/5, _, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + draw.SimpleText(txt[2], "zones_screen", w+x-w/4, -h/5, _, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + + surface.SetDrawColor(color_white) + surface.DrawRect(x+w/2-1,y+h*.125,2,h*.75) + + surface.SetMaterial(lmb) + surface.DrawTexturedRect(x+w/4-16,y+h*.55-16,32,32) + surface.SetMaterial(rmb) + surface.DrawTexturedRect(x+w*.75-16,y+h*.55-16,32,32) + +end + +local function GetBoneOrientation(self,ent) + local bone, pos, ang + bone = ent:LookupBone("Hand") + if (!bone) then return end + pos, ang = Vector(0,0,0), Angle(0,0,0) + local m = ent:GetBoneMatrix(bone) + if (m) then + pos, ang = m:GetTranslation(), m:GetAngles() + end + if (IsValid(self.Owner) and self.Owner:IsPlayer() and + ent == self.Owner:GetViewModel() and self.ViewModelFlip) then + ang.r = -ang.r // Fixes mirrored models + end + return pos, ang +end +function SWEP:ViewModelDrawn() + local vm = self.Owner:GetViewModel() + if !IsValid(vm) then return end + + local pos, ang = GetBoneOrientation(self, vm ) + local offset = Vector(.08, -5.16, 3.43) + local offsetAng = Angle(180, 0, -46) + local size = 0.0159 + local drawpos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z + ang:RotateAroundAxis(ang:Up(), offsetAng.y) + ang:RotateAroundAxis(ang:Right(), offsetAng.p) + ang:RotateAroundAxis(ang:Forward(), offsetAng.r) + + cam.Start3D2D(drawpos, ang, size) + local x,y,w,h = -72,-72 + local w,h = 2*-x, 2*-y + //Draw Background: + surface.SetDrawColor( 200, 200, 200, 255 ) + surface.SetDrawColor( 40,40,40,255 ) + surface.DrawRect( x, y, w, h ) + + //Draw foreground: + self:DrawScreen(x,y,w,h) + + cam.End3D2D() +end \ No newline at end of file diff --git a/lua/zones.lua b/lua/zones.lua new file mode 100644 index 0000000..80aaa91 --- /dev/null +++ b/lua/zones.lua @@ -0,0 +1,467 @@ + +local version = 1.1 -- Older versions will not run if a newer version is used in another script. +--[[ + ZONES - by Bobbleheadbob + WARNING: If you edit any of these files, make them use a different namespace. Multiple scripts may depend on this library so modifying it can break other scripts. + + Purpose: + For easy in-game designation of persistent polygonal zones which are used by any script. + + How to Use: + All zones are saved in zones.List; see an example below. + Zone creation is handled with weapon_zone_designator and ent_zone_point, but can be done in code as well. + When a zone is created, changed, or removed all zones are synced to clients. When clients join they are also synced. + Any extra details can be saved to a zone. Everything is written to a txt file and is persistent to the map. + + Since multiple scripts might use the zones system, don't assume that every zone is related to your script. + To register a zone class, use zones.RegisterClass(class, color); use a unique string like "Scriptname Room". + When a zone class is registered, admins can use the tool to create new ones. + When a new zone is created, the "OnZoneCreated" hook is called serverside. See the hook below for documentation. + When a player edits a zone's properties, the "ShowZoneOptions" hook is called clientside. See the hook below. + + Use zones.FindByClass() to find all zones which are of a given class. + Use ply:GetCurrentZone() to find the zone that a player is standing in. + + Installation: + This is a shared file so include it in any shared environment. Also include ent_zone_point and weapon_zone_designator as a shared ent and weapon. + You should not put this file directly in lua/autorun. + + License: + YOU MAY use/edit this however you want, as long as you give proper attribution. + YOU MAY distribute this with other scripts whether they are paid or free. + YOU MAY NOT distribute this on its own. It must accompany another script. + + Enjoy! ~Bobbleheadbob +]] + +local table, math, Vector, pairs, ipairs, ents = table, math, Vector, pairs, ipairs, ents + +if zones then + if zones.version > version then + print("A new version of zones exists. Using version "..zones.version.." instead of "..version) + return + elseif zones.version < version then + print("A new version of zones exists. Using version "..version.." instead of "..zones.version) + end +else + print("Loaded zones " ..version) +end + +zones = zones or {} +zones.version = version + +zones.Classes = zones.Classes or {} +zones.List = zones.List or {} + +//Common interface functions: + +-- Registers a zone class which can then be created using weapon_zone_designator +function zones.RegisterClass(class,color) + zones.Classes[class] = color +end + + +local plymeta = FindMetaTable("Player") +--returns one of the zones a player is found in. Also returns that zone's ID. Class is optional to filter the search. +function plymeta:GetCurrentZone(class) + return zones.GetZoneAt(self:GetPos(),class) +end + +--returns a table of zones the player is in. Class is optional to filter the search. +function plymeta:GetCurrentZones(class) + return zones.GetZonesAt(self:GetPos(),class) +end + +function zones.GetZoneAt(pos,class) --works like above, except uses any point. + for k,zone in pairs(zones.List) do + if class and class != zone.class then continue end + + for k1, points in pairs(zone.points) do + if not pos:WithinAABox(zone.bounds[k1].mins,zone.bounds[k1].maxs) then continue end + if zones.PointInPoly(pos,points) then + local z = points[1].z + if pos.z >= z and pos.z < z + zone.height[k1] then + return zone,k + end + end + end + end + return nil, -1 +end +function zones.GetZonesAt(pos,class) --works like above, except uses any point. + local tbl = {} + for k,zone in pairs(zones.List) do + if class and class != zone.class then continue end + for k1, points in pairs(zone.points) do + if not pos:WithinAABox(zone.bounds[k1].mins,zone.bounds[k1].maxs) then continue end + if zones.PointInPoly(pos,points) then + local z = points[1].z + if pos.z >= z and pos.z < z + zone.height[k1] then + tbl[k] = zone + end + end + end + end + return tbl +end + +--Gets a list of all zones which are of the specified class. +function zones.FindByClass(class) + local tbl = {} + + for k,v in pairs(zones.List) do + if v.class == class then + tbl[k] = v + end + end + + return tbl +end + +--Returns the numerical ID of a zone. +function zones.GetID(zone) + return table.KeyFromValue(zones.List,zone) +end + + +//Getting into the meat of the API: +if SERVER then + util.AddNetworkString("zones_sync") + util.AddNetworkString("zones_class") + + function zones.SaveZones() + if not file.Exists("zones","DATA") then + file.CreateDir("zones") + end + file.Write("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", util.TableToJSON(zones.List)) + end + concommand.Add("zone_save",function(ply,c,a) + if not ply:IsAdmin() then return end + zones.SaveZones() + end) + + function zones.LoadZones() + local tbl = file.Read("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", "DATA") + zones.List = tbl and util.JSONToTable(tbl) or {} + + //Update legacy files: + for k,v in pairs(zones.List)do + if not v.bounds then + zones.CalcBounds(v) + end + end + end + + local sync = false + local syncply + function zones.Sync(ply) + sync = true + syncply = ply + end + hook.Add("Tick","zones_sync",function() + if sync then + net.Start("zones_sync") + net.WriteTable(zones.List) + if syncply then + net.Send(syncply) + syncply = nil + else + net.Broadcast() + end + sync = false + end + end) + + function zones.CreateZoneFromPoint(ent) + + local zone = { + points = {{}}, --only 1 area when creating a new zone. + height = {ent:GetTall()}, + class = ent:GetZoneClass(), + bounds = {} + } + + local id = table.maxn(zones.List) + 1 + local cur = ent + repeat + local pos = cur:GetPos() - Vector(0,0,2) + zone.points[1][#zone.points[1]+1] = pos + + cur:SetZoneID(id) + cur = cur:GetNext() + + until (cur == ent) + + zones.CalcBounds(zone) + + zones.List[id] = zone + zones.Sync() + + hook.Run("OnZoneCreated",zone,zone.class,id) + + return zone, id + + end + + function zones.CalcBounds(zone) + zone.bounds = {} + for areanum,area in pairs(zone.points)do + local mins,maxs = Vector(10000000,10000000,area[1].z), Vector(-10000000,-10000000,area[1].z + zone.height[areanum]) + for k,pos in pairs(area) do + maxs.x = math.max(pos.x, maxs.x) + maxs.y = math.max(pos.y, maxs.y) + mins.x = math.min(pos.x, mins.x) + mins.y = math.min(pos.y, mins.y) + end + zone.bounds[areanum] = {mins=mins,maxs=maxs} + end + end + + function zones.Remove(id) + zones.List[id] = nil + zones.Sync() + end + + function zones.CreatePointEnts(removeThese) --removeThese is optional. + for k,v in pairs(removeThese or ents.FindByClass("ent_zone_point")) do --remove old + v:Remove() + end + + --create new + for id,zone in pairs(zones.List)do + + for k, area in pairs(zone.points) do + + local first + local curr + for k2,point in ipairs(area)do + + local next = ents.Create("ent_zone_point") + + if IsValid(curr) then + next:SetPos(point+Vector(0,0,1)) + curr:SetNext(next) + -- curr:DeleteOnRemove(next) + else + first = next + next:SetPos(point+Vector(0,0,1)) + end + + next.LastPoint = curr + curr = next + next:SetTall(zone.height[k]) + next:SetZoneClass(zone.class) + next:Spawn() + next:SetZoneID(id) + next:SetAreaNumber(k) + + end + + curr:SetNext(first) + -- curr:DeleteOnRemove(first) + first.LastPoint = curr + + end + end + + end + + function zones.Merge(from,to) + + local zfrom, zto = zones.List[from], zones.List[to] + + table.Add(zto.points, zfrom.points) + table.Add(zto.height, zfrom.height) + table.Add(zto.bounds, zfrom.bounds) + + zones.Remove(from) + + zones.Sync() + + end + + function zones.Split(id,areanum) + local zone = zones.List[id] + local pts, h, bound = zone.points[areanum], zone.height[areanum], zone.bounds[areanum] + + table.remove(zone.points,areanum) + table.remove(zone.height,areanum) + table.remove(zone.bounds,areanum) + + if #zone.points == 0 then + zones.Remove(id) + end + + local new = table.Copy(zone) + new.points = {pts} + new.height = {h} + new.bounds = {bound} + + local id = table.maxn(zones.List)+1 + zones.List[id] = new + + zones.Sync() + + return new,id + + end + + hook.Add("Initialize","claim_load",function() + zones.LoadZones() + end) + hook.Add("PlayerInitialSpawn","claim_sync",function(ply) + zones.Sync(ply) + end) + + net.Receive("zones_class",function(len,ply) + if not ply:IsAdmin() then return end + local id = net.ReadFloat() + local class = net.ReadString() + + for k,v in pairs(ents.FindByClass("ent_zone_point"))do + if v:GetZoneID() == id then + v:SetZoneClass(class) + end + end + zones.List[id].class = class + + zones.Sync() + end) + +else + net.Receive("zones_sync",function(len) + zones.List = net.ReadTable() + end) + function zones.ShowOptions(id) + + local zone = zones.List[id] + local class = zone.class + + local frame = vgui.Create("DFrame") + frame:MakePopup() + frame:SetTitle("Zone Settings") + + local ztitle = vgui.Create("DLabel",frame) + ztitle:Dock(TOP) + ztitle:DockMargin(2,0,5,5) + ztitle:SetText("Zone Class:") + ztitle:SizeToContents() + + local zclass = vgui.Create("DComboBox",frame) + zclass:Dock(TOP) + zclass:DockMargin(0,0,0,5) + for k,v in pairs(zones.Classes) do + zclass:AddChoice(k,nil,k == class) + end + function zclass:OnSelect(i,class) + net.Start("zones_class") + net.WriteFloat(id) + net.WriteString(class) + net.SendToServer() + + frame.content:Remove() + + frame.content = vgui.Create("DPanel",frame) + frame.content:Dock(FILL) + + local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) + frame:SizeTo((w or 100)+8,(h or 2)+78, .2) + frame:MoveTo(ScrW()/2-((w or 292)+8)/2,ScrH()/2-((h or 422)+78)/2, .2) + end + + frame.content = vgui.Create("DPanel",frame) + frame.content:Dock(FILL) + + local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) + frame:SetSize((w or 100)+8,(h or 2)+78) + frame:Center() + + end + +end + + + +//returns the point of intersection between two infinite lines. +local function IntersectPoint(line1, line2) + + local x1,y1,x2,y2,x3,y3,x4,y4 = line1.x1,line1.y1,line1.x2,line1.y2,line2.x1,line2.y1,line2.x2,line2.y2 + + local m1,m2 = (y1-y2)/((x1-x2)+.001),(y3-y4)/((x3-x4)+.001) --get the slopes + local yint1,yint2 = (-m1*x1)+y1,(-m2*x3)+y3 --get the y-intercepts + local x = (yint1-yint2)/(m2-m1) --calculate x pos + local y = m1*x+yint1 --plug in x pos to get y pos + + return x,y + +end +//Returns a bool if two SEGEMENTS intersect or not. +local function Intersect(line1, line2) + + local x,y = IntersectPoint(line1, line2) + local sx,sy = tostring(x), tostring(y) + if (sx == "-inf" or sx == "inf" or sx == "nan") then + return false + end + + local minx1, maxx1 = math.min(line1.x1,line1.x2)-.1, math.max(line1.x1,line1.x2)+.1 + local minx2, maxx2 = math.min(line2.x1,line2.x2)-.1, math.max(line2.x1,line2.x2)+.1 + local miny1, maxy1 = math.min(line1.y1,line1.y2)-.1, math.max(line1.y1,line1.y2)+.1 + local miny2, maxy2 = math.min(line2.y1,line2.y2)-.1, math.max(line2.y1,line2.y2)+.1 + + if (x >= minx1) and (x <= maxx1) and (x >= minx2) and (x <= maxx2) then + + if (y >= miny1) and (y <= maxy1) and (y >= miny2) and (y <= maxy2) then + + --debugoverlay.Sphere( Vector(x,y,LocalPlayer():GetPos().z), 3, FrameTime()+.01, Color(255,0,0), true) + + return true + + end + + end + + return false + +end +function zones.PointInPoly(point,poly) //True if point is within a polygon. + + //Check validity + local lines = {} + local pcount = #poly + for k1=1, pcount do + + local k2 = k1+1 + if k2 > pcount then + k2 = 1 + end + + lines[k1] = { + x1 = poly[k1].x, + y1 = poly[k1].y, + x2 = poly[k2].x, + y2 = poly[k2].y, + valid = true + } + + end + + local ray = { + x1 = point.x, + y1 = point.y, + x2 = point.x + 10000, + y2 = point.y + 10000 + } + local inside = false + + //Do ray check. + for k,v in pairs(lines)do + + if Intersect(ray,v) then + inside = !inside + end + + end + + return inside +end diff --git a/zones/lua/entities/ent_zone_point.lua b/zones/lua/entities/ent_zone_point.lua deleted file mode 100644 index 986221a..0000000 --- a/zones/lua/entities/ent_zone_point.lua +++ /dev/null @@ -1,132 +0,0 @@ - -AddCSLuaFile() - -DEFINE_BASECLASS( "base_anim" ) - -ENT.PrintName = "Zone Point" -ENT.Author = "Bobblehead" -ENT.Information = "A point in the zone designator." -ENT.Category = "Other" - -ENT.Editable = false -ENT.Spawnable = false -ENT.AdminOnly = false -ENT.RenderGroup = RENDERGROUP_TRANSLUCENT - - -function ENT:Initialize() - self:SetModel("models/hunter/blocks/cube025x025x025.mdl") - self:SetCollisionGroup(COLLISION_GROUP_WORLD) - self:DrawShadow(false) - - if SERVER then - self:SetUseType(SIMPLE_USE) - self:PhysicsInit(SOLID_BBOX) - self:GetPhysicsObject():EnableMotion(false) - - self:GetPhysicsObject():SetMass(1) - - else - self:SetRenderBoundsWS(self:GetPos(),self:GetPos()+Vector(0,0,self:GetTall())) - end -end - -function ENT:SetupDataTables() - self:NetworkVar("Entity",0,"Next") - self:NetworkVar("Float",0,"Tall") - self:NetworkVar("Int",0,"ZoneID") - self:NetworkVar("String",0,"ZoneClass") - self:NetworkVar("Int",1,"AreaNumber") -end - -function ENT:DrawTranslucent() - local wep = LocalPlayer():GetActiveWeapon() - if wep:IsValid() and wep:GetClass() == "weapon_zone_designator" then - - if wep:GetZoneClass() == self:GetZoneClass() or GetConVarNumber("zone_filter") == 0 then - self:DrawModel() - - local p = self:GetPos() - p.z = p.z + self:GetTall() - render.Model({model=self:GetModel(),pos=p,ang=angle_zero}) - - render.SetMaterial(Material("cable/cable2")) - render.DrawBeam( self:GetPos(), p, 1, 1, 0, color_white ) - - local next = self:GetNext() - if IsValid(next) then - local class = self:GetZoneClass() - - render.DrawBeam( self:GetPos(), next:GetPos(), 1, 1, 0, color_white ) - - local n = next:GetPos() - n.z = n.z + next:GetTall() - render.DrawBeam( p, n, 1, 1, 0, color_white ) - - render.SetColorMaterial() - local col1 = table.Copy(zones.Classes[class]) - col1.a = 80 - local col2 = {a=80} - col2.r = col1.r * .5 - col2.g = col1.g * .5 - col2.b = col1.b * .5 - - render.DrawQuad(p,self:GetPos(),next:GetPos(),n,col1) - render.DrawQuad(n,next:GetPos(),self:GetPos(),p,col2) - - local id = self:GetZoneID() - local classtxt = id != -1 and class .. " (# "..id..")" or class - - local ang = (p-self:GetPos()):Cross(n-self:GetPos()):Angle() - ang:RotateAroundAxis(ang:Right(), 90) - ang:RotateAroundAxis(ang:Up(),-90) - cam.Start3D2D((n+self:GetPos())/2,ang,.2) - draw.SimpleText(classtxt,"DermaLarge",0,0,color_white,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) - cam.End3D2D() - - ang:RotateAroundAxis(Vector(0,0,1), 180) - cam.Start3D2D((n+self:GetPos())/2,ang,.2) - draw.SimpleText(classtxt,"DermaLarge",0,0,color_white,TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER) - cam.End3D2D() - - end - end - end -end - -function ENT:Think() - if CLIENT then - local next = self:GetNext() - if IsValid(next) and next != self.resizedto then - self:SetRenderBoundsWS(self:GetPos(),next:GetPos()+Vector(0,0,next:GetTall())) - self.resizedto = next - end - - local wep = LocalPlayer():GetActiveWeapon() - if wep:IsValid() and wep:GetClass() == "weapon_zone_designator" then - if LocalPlayer():GetEyeTrace().Entity == self then - self:SetColor(Color(255,0,0)) - elseif wep:GetCurrentPoint() == self then - self:SetColor(Color(0,0,255)) - else - self:SetColor(color_white) - end - end - else - - if IsValid(self.Resizing) then - - self:SetTall((self.Resizing:GetEyeTrace().HitPos - self:GetPos()).z) - - end - - end -end - -function ENT:OnRemove() - if SERVER then - if IsValid(self:GetNext()) then - self:GetNext():Remove() - end - end -end diff --git a/zones/lua/weapons/weapon_zone_designator.lua b/zones/lua/weapons/weapon_zone_designator.lua deleted file mode 100644 index fd2c0c5..0000000 --- a/zones/lua/weapons/weapon_zone_designator.lua +++ /dev/null @@ -1,703 +0,0 @@ - -if CLIENT then - CreateClientConVar("zone_tall",200,false,true) - CreateClientConVar("zone_class","",false,true) - CreateClientConVar("zone_editmode",1,false,true) - CreateClientConVar("zone_filter",0,false,true) - - surface.CreateFont( "zones_save", { - font = "Roboto", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name - size = 20, - weight = 1000, - } ) - surface.CreateFont( "zones_screen", { - font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name - size = 20, - weight = 1000, - - } ) -else - concommand.Add("zone_swep",function(p,c,a) - if p:IsAdmin() then - p:Give("weapon_zone_designator") - end - end) -end - -if engine.ActiveGamemode() == "terrortown" then - SWEP.Base = "weapon_tttbase" - SWEP.Kind = WEAPON_EQUIP2 -end - - -SWEP.NoSights = true - -SWEP.PrintName = "Zone Designator" -SWEP.Author = "Bobblehead" -SWEP.Purpose = "Creates zones. Reload for menu. Right click to remove a point/zone." - -SWEP.Slot = 5 -SWEP.SlotPos = 5 - -SWEP.Spawnable = true -SWEP.AdminOnly = true - -SWEP.HoldType = "pistol" -SWEP.ViewModelFOV = 51 -SWEP.ViewModelFlip = false -SWEP.UseHands = true -SWEP.ViewModel = "models/weapons/c_toolgun.mdl" -SWEP.WorldModel = "models/weapons/w_toolgun.mdl" -SWEP.AutoSwitchFrom = true -SWEP.AutoSwitchTo = true - -SWEP.Primary.ClipSize = -1 -SWEP.Primary.DefaultClip = -1 -SWEP.Primary.Automatic = false -SWEP.Primary.Delay = .5 -SWEP.Primary.Ammo = "none" - -SWEP.Secondary.ClipSize = -1 -SWEP.Secondary.DefaultClip = -1 -SWEP.Secondary.Automatic = false -SWEP.Secondary.Ammo = "none" - - -function SWEP:SetupDataTables() - self:NetworkVar("Float",0,"Tall") - self:NetworkVar("String",0,"ZoneClass") - self:NetworkVar("Entity",0,"CurrentPoint") - self:NetworkVar("Int",0,"Mode") - -end - -function SWEP:Initialize() - - self:SetTall(150) - self:SetMode(1) - - self:SetCurrentPoint(NULL) -end - -function SWEP:Deploy() - if SERVER then - local points = ents.FindByClass("ent_zone_point") - local ct = 0 - for k,v in pairs(zones.List) do - for k2,v2 in pairs(v.points)do - for k3, v3 in pairs(v2) do - ct = ct + 1 - end - end - end - if #points != ct then - zones.CreatePointEnts(points) - end - end -end - -function SWEP:Holster() - if SERVER then - local none = true - for k, ply in pairs(player.GetAll()) do - if ply == self.Owner then continue end - local wep = ply:GetActiveWeapon() - if IsValid(wep) and wep:GetClass() == "weapon_zone_designator" then - none = false - break - end - end - if none then - for k,v in pairs(ents.FindByClass("ent_zone_point"))do - v:Remove() - end - end - - self:SetCurrentPoint(NULL) - - return true - end -end - -function SWEP:DrawHUD() - local z,id = LocalPlayer():GetCurrentZone(GetConVarNumber("zone_filter") == 1 and self:GetZoneClass() or nil) - z = z and z.class.."(# "..id..")" or "None" - draw.SimpleText("Current Zone: "..z, "DermaLarge", 100,100) -end - -function SWEP:PrimaryAttack() - - - self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) - - if SERVER then - self.Owner:EmitSound("buttons/button15.wav") - end - - self:UpdateSettings() - local mode = self:GetMode() - - if mode == 1 then //Create - if CLIENT then return end - self:PlacePoint() - elseif mode == 2 then //Merge - if CLIENT then return end - self:MergeZones() - - elseif mode == 3 then //Edit - local curr = self:GetCurrentPoint() - - if IsValid(curr) then - if CLIENT then return end - local next = curr - repeat - - next.Resizing = nil - - next = next:GetNext() - - until ( next == curr ) - - zones.List[curr:GetZoneID()].height[curr:GetAreaNumber()] = curr:GetTall() - zones.CalcBounds(zones.List[id]) - - self:SetCurrentPoint(NULL) - - elseif CLIENT then - local tr = self.Owner:GetEyeTrace() - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - zones.ShowOptions(tr.Entity:GetZoneID()) - end - - end - - elseif mode == 4 then - if CLIENT then return end - - local curr = self:GetCurrentPoint() - local tr = self.Owner:GetEyeTrace() - - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - - self:SetCurrentPoint(tr.Entity) - - elseif IsValid(curr) then - - local id,areanum = curr:GetZoneID(), curr:GetAreaNumber() - local next = curr:GetNext() - - local new = ents.Create("ent_zone_point") - local p = curr:GetPos() - tr.HitPos.z = p.z - new:SetPos(tr.HitPos) - curr:SetNext(new) - -- self:GetCurrentPoint():DeleteOnRemove(new) - - new.LastPoint = self:GetCurrentPoint() - self:SetCurrentPoint(new) - new:SetTall(curr:GetTall()) - new:SetZoneClass(curr:GetZoneClass()) - new:SetZoneID(id) - new:SetAreaNumber(areanum) - new:Spawn() - new:SetNext(next) - next.LastPoint = new - - - local n = new - local pts = {} - repeat - pts[#pts+1] = n:GetPos() - Vector(0,0,2) - n = n:GetNext() - until (n == new) - - - zones.List[id].points[areanum] = pts - - zones.CalcBounds(zones.List[id]) - - zones.Sync() - - end - - end - -end - -function SWEP:SecondaryAttack() - self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) - - if CLIENT then return end - - self.Owner:EmitSound("buttons/button16.wav") - - local tr = self.Owner:GetEyeTrace() - local mode = self:GetMode() - - if mode == 1 then //delete - - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - local point = tr.Entity - local last = point.LastPoint - - local id = point:GetZoneID() - if id != -1 then - - if #zones.List[id].points > 1 then - id = select(2,zones.Split(id, point:GetAreaNumber())) - end - - zones.Remove(id) - - end - - point:Remove() - - self:SetCurrentPoint(last) - - elseif self:GetCurrentPoint():IsValid() then - local point, last = self:GetCurrentPoint(), self:GetCurrentPoint().LastPoint - point:Remove() - self:SetCurrentPoint(last or NULL) - end - - elseif mode == 2 then //split - - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - local point = tr.Entity - local id = point:GetZoneID() - - if #zones.List[id].points == 1 then - return - end - - local zone, newid = zones.Split(id, point:GetAreaNumber()) - - local next = point - repeat - - next:SetZoneID(newid) - next:SetAreaNumber(next:GetAreaNumber() - #zones.List[id].points) - - next = next:GetNext() - - until ( next == point ) - - end - - elseif mode == 3 then //resize - local curr = self:GetCurrentPoint() - - if IsValid(curr) then - - local next = curr - repeat - - next.Resizing = nil - - next = next:GetNext() - - until ( next == curr ) - - zones.List[curr:GetZoneID()].height[curr:GetAreaNumber()] = curr:GetTall() - zones.CalcBounds(zones.List[curr:GetZoneID()]) - - zones.Sync() - - self:SetCurrentPoint(NULL) - - else - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - local next = tr.Entity - repeat - next.Resizing = self.Owner - - next = next:GetNext() - - - until ( next == tr.Entity ) - - self:SetCurrentPoint(tr.Entity) - end - end - - elseif mode == 4 then //Remove a point - - if !tr.HitWorld and IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" or IsValid(self:GetCurrentPoint()) then - - local hit = tr.Entity:IsValid() and tr.Entity or self:GetCurrentPoint() - local id,areanum = hit:GetZoneID(), hit:GetAreaNumber() - - if #zones.List[id].points[areanum] > 3 then - - local last = hit.LastPoint - local next = hit:GetNext() - - next.LastPoint = last - last:SetNext(next) - - hit:SetNext(NULL) - hit.LastPoint = nil - hit:Remove() - - local n = next - local pts = {} - repeat - pts[#pts+1] = n:GetPos() - Vector(0,0,2) - n = n:GetNext() - until (n == next) - - zones.List[id].points[areanum] = pts - - zones.CalcBounds(zones.List[id]) - - zones.Sync() - - self:SetCurrentPoint(last) - - end - - end - - end - - -end - -local mx,my -if CLIENT then - mx, my = ScrW()/2, ScrH()/2 -end - -function SWEP:Reload() --show menu. - - self:UpdateSettings() - if SERVER then - if game.SinglePlayer() then - self:CallOnClient("Reload") - end - return - end - - if IsValid(self.frame) then return end - - input.SetCursorPos(mx,my) - - self:OpenMenu() - -end - -function SWEP:PlacePoint() --mode == 1 - local tr = self.Owner:GetEyeTrace() - if tr.HitWorld then - - local next = ents.Create("ent_zone_point") - - if IsValid(self:GetCurrentPoint()) then - local p = self:GetCurrentPoint():GetPos() - tr.HitPos.z = p.z - next:SetPos(tr.HitPos) - self:GetCurrentPoint():SetNext(next) - -- self:GetCurrentPoint():DeleteOnRemove(next) - else - next:SetPos(tr.HitPos+Vector(0,0,1)) - end - - next.LastPoint = self:GetCurrentPoint() - self:SetCurrentPoint(next) - next:SetTall(self:GetTall()) - next:SetZoneClass(self:GetZoneClass()) - next:SetZoneID(-1) - next:SetAreaNumber(1) - next:Spawn() - - elseif tr.Entity:IsValid() and tr.Entity:GetClass() == "ent_zone_point" and tr.Entity != self:GetCurrentPoint() then - if IsValid(self:GetCurrentPoint()) then - local next = tr.Entity - if !IsValid(next.LastPoint) then - - self:GetCurrentPoint():SetNext(next) - - if IsValid(next:GetNext()) then //we've come full circle. - - next.LastPoint = self:GetCurrentPoint() - - local id = select(2,zones.CreateZoneFromPoint(self:GetCurrentPoint())) - -- self:GetCurrentPoint():DeleteOnRemove(next) - self:SetCurrentPoint(NULL) - - local o = self.Owner - timer.Simple(.1,function() -- wait for it to sync. - if IsValid(o) then - o:SendLua("zones.ShowOptions("..id..")") - end - end) - - end - - end - end - - - end -end - -function SWEP:MergeZones() - - local tr = self.Owner:GetEyeTrace() - if tr.HitWorld then - self:SetCurrentPoint(NULL) - - elseif IsValid(tr.Entity) and tr.Entity:GetClass() == "ent_zone_point" then - - local curr = self:GetCurrentPoint() - local trent = tr.Entity - if not IsValid(curr) then - self:SetCurrentPoint(trent) - - else - //Merge the zones. - if curr:GetZoneID() != trent:GetZoneID() then - local cid = curr:GetZoneID() - - --Change the points. - for k,next in pairs(ents.FindByClass("ent_zone_point")) do - if next:GetZoneID() == cid then - - next:SetZoneID(trent:GetZoneID()) - next:SetAreaNumber(next:GetAreaNumber() + #zones.List[trent:GetZoneID()].points) - next:SetZoneClass(zones.List[trent:GetZoneID()].class) - - end - - end - - self:SetCurrentPoint(NULL) - - zones.Merge(cid,trent:GetZoneID()) --from, to - - else - self:SetCurrentPoint(trent) - - end - - end - - end -end - -function SWEP:UpdateSettings() - --load convars - local new_tall = SERVER and self.Owner:GetInfoNum("zone_tall",200) or GetConVarNumber("zone_tall") - local new_class = SERVER and self.Owner:GetInfo("zone_class") or GetConVarString("zone_class") - local new_mode = SERVER and self.Owner:GetInfoNum("zone_editmode",1) or GetConVarNumber("zone_editmode") - - if new_class == "" then - for k,v in pairs(zones.Classes)do - new_class = k - self.Owner:ConCommand('zone_class "'..k..'"') - break - end - end - - --If changed, remove current building area - if new_class != self:GetZoneClass() or new_tall != self:GetTall() or new_mode != self:GetMode() then - self:ResetTool() - end - assert(new_class != "", "No class is set for the zone designator! Did you call zones.RegisterClass()?\n") - - --apply convars - self:SetTall(new_tall) - self:SetZoneClass(new_class) - self:SetMode(new_mode) -end - -function SWEP:ResetTool() - - if self:GetMode() == 1 and SERVER then - local cur = self:GetCurrentPoint() - if IsValid(cur) and cur:GetZoneID() == -1 then - - while IsValid(cur) do - local last = cur.LastPoint - cur:Remove() - cur = last - end - - end - - end - self:SetCurrentPoint(NULL) -end - -function SWEP:OpenMenu() - local zc = self:GetZoneClass() - - local frame = vgui.Create("DFrame") - self.frame = frame - frame:SetSize(300,400) - frame:Center() - frame:MakePopup() - frame:ShowCloseButton(false) - frame:SetTitle("Zone Designator Options") - function frame:Think() - if not input.IsButtonDown(_G["KEY_"..input.LookupBinding("+reload"):upper()]) then - mx,my = gui.MousePos() - self:Close() - end - end - - local ztitle = vgui.Create("DLabel",frame) - ztitle:Dock(TOP) - ztitle:DockMargin(7,0,5,0) - ztitle:SetText("Zone Class:") - ztitle:SizeToContents() - - local zclass = vgui.Create("DComboBox",frame) - zclass:Dock(TOP) - zclass:DockMargin(5,0,5,0) - for k,v in pairs(zones.Classes) do - zclass:AddChoice(k,nil,k==zc) - end - function zclass:OnSelect(i,class) - RunConsoleCommand("zone_class",class) - end - - local filter = vgui.Create("DCheckBoxLabel",frame) - filter:Dock(TOP) - filter:DockMargin(6,5,5,5) - filter:SetText("Filter zones of a different class.") - filter:SizeToContents() - filter:SetConVar("zone_filter") - - local height = vgui.Create( "DNumSlider", frame ) - height:Dock(TOP) - height:DockMargin(7,0,0,0) - height:SetText( "Zone Height:" ) - height:SetMin( 0 ) - height:SetMax( 1000 ) - height:SetDecimals( 0 ) - height:SetConVar( "zone_tall" ) - - local modetitle = vgui.Create("DLabel",frame) - modetitle:Dock(TOP) - modetitle:DockMargin(7,0,5,0) - modetitle:SetText("Tool Mode:") - modetitle:SizeToContents() - - local mode = vgui.Create("DListView",frame) - mode:Dock(TOP) - mode:DockMargin(5,0,5,5) - mode:AddColumn("Mode") - mode:AddColumn("Info"):SetFixedWidth(180) - mode:SetTall(200) - mode:SetMultiSelect(false) - - mode:AddLine("Create / Delete","Create new zones") - mode:AddLine("Merge / Split","Turn two zones into one.") - mode:AddLine("Edit / Resize","Change zone properties.") - mode:AddLine("Insert / Remove","Insert points into existing zones.") - mode:SelectItem(mode:GetLine(self:GetMode())) - function mode:OnRowSelected(id) - RunConsoleCommand("zone_editmode",id) - end - - - local save = vgui.Create("DButton",frame) - save:Dock(BOTTOM) - save:DockMargin(5,0,5,5) - save:SetText("SAVE ALL ZONES") - save:SetFont("zones_save") - save:SetTextColor(color_black) - save:SetTall(50) - function save:DoClick() - Derma_Query("Are you sure you want to save? This can't be undone.", "Save Confirmation", - "Yes", function() - RunConsoleCommand("zone_save") - end, - "No", function() - end - ) - end - - - -end - -local modes = { - { --create - "Create", - "Delete" - }, - { --merge - "Merge", - "Split" - }, - { --edit - "Edit", - "Resize" - }, - { --insert - "Insert", - "Remove" - }, -} -local lmb, rmb = Material("gui/lmb.png","unlitgeneric"), Material("gui/rmb.png","unlitgeneric") -function SWEP:DrawScreen(x,y,w,h) - local mode = self:GetMode() - local txt = modes[mode] - - draw.SimpleText(txt[1], "zones_screen", x+w/4, -h/5, _, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) - draw.SimpleText(txt[2], "zones_screen", w+x-w/4, -h/5, _, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) - - surface.SetDrawColor(color_white) - surface.DrawRect(x+w/2-1,y+h*.125,2,h*.75) - - surface.SetMaterial(lmb) - surface.DrawTexturedRect(x+w/4-16,y+h*.55-16,32,32) - surface.SetMaterial(rmb) - surface.DrawTexturedRect(x+w*.75-16,y+h*.55-16,32,32) - -end - -local function GetBoneOrientation(self,ent) - local bone, pos, ang - bone = ent:LookupBone("Hand") - if (!bone) then return end - pos, ang = Vector(0,0,0), Angle(0,0,0) - local m = ent:GetBoneMatrix(bone) - if (m) then - pos, ang = m:GetTranslation(), m:GetAngles() - end - if (IsValid(self.Owner) and self.Owner:IsPlayer() and - ent == self.Owner:GetViewModel() and self.ViewModelFlip) then - ang.r = -ang.r // Fixes mirrored models - end - return pos, ang -end -function SWEP:ViewModelDrawn() - local vm = self.Owner:GetViewModel() - if !IsValid(vm) then return end - - local pos, ang = GetBoneOrientation(self, vm ) - local offset = Vector(.08, -5.16, 3.43) - local offsetAng = Angle(180, 0, -46) - local size = 0.0159 - local drawpos = pos + ang:Forward() * offset.x + ang:Right() * offset.y + ang:Up() * offset.z - ang:RotateAroundAxis(ang:Up(), offsetAng.y) - ang:RotateAroundAxis(ang:Right(), offsetAng.p) - ang:RotateAroundAxis(ang:Forward(), offsetAng.r) - - cam.Start3D2D(drawpos, ang, size) - local x,y,w,h = -72,-72 - local w,h = 2*-x, 2*-y - //Draw Background: - surface.SetDrawColor( 200, 200, 200, 255 ) - surface.SetDrawColor( 40,40,40,255 ) - surface.DrawRect( x, y, w, h ) - - //Draw foreground: - self:DrawScreen(x,y,w,h) - - cam.End3D2D() -end \ No newline at end of file diff --git a/zones/lua/zones.lua b/zones/lua/zones.lua deleted file mode 100644 index 80aaa91..0000000 --- a/zones/lua/zones.lua +++ /dev/null @@ -1,467 +0,0 @@ - -local version = 1.1 -- Older versions will not run if a newer version is used in another script. ---[[ - ZONES - by Bobbleheadbob - WARNING: If you edit any of these files, make them use a different namespace. Multiple scripts may depend on this library so modifying it can break other scripts. - - Purpose: - For easy in-game designation of persistent polygonal zones which are used by any script. - - How to Use: - All zones are saved in zones.List; see an example below. - Zone creation is handled with weapon_zone_designator and ent_zone_point, but can be done in code as well. - When a zone is created, changed, or removed all zones are synced to clients. When clients join they are also synced. - Any extra details can be saved to a zone. Everything is written to a txt file and is persistent to the map. - - Since multiple scripts might use the zones system, don't assume that every zone is related to your script. - To register a zone class, use zones.RegisterClass(class, color); use a unique string like "Scriptname Room". - When a zone class is registered, admins can use the tool to create new ones. - When a new zone is created, the "OnZoneCreated" hook is called serverside. See the hook below for documentation. - When a player edits a zone's properties, the "ShowZoneOptions" hook is called clientside. See the hook below. - - Use zones.FindByClass() to find all zones which are of a given class. - Use ply:GetCurrentZone() to find the zone that a player is standing in. - - Installation: - This is a shared file so include it in any shared environment. Also include ent_zone_point and weapon_zone_designator as a shared ent and weapon. - You should not put this file directly in lua/autorun. - - License: - YOU MAY use/edit this however you want, as long as you give proper attribution. - YOU MAY distribute this with other scripts whether they are paid or free. - YOU MAY NOT distribute this on its own. It must accompany another script. - - Enjoy! ~Bobbleheadbob -]] - -local table, math, Vector, pairs, ipairs, ents = table, math, Vector, pairs, ipairs, ents - -if zones then - if zones.version > version then - print("A new version of zones exists. Using version "..zones.version.." instead of "..version) - return - elseif zones.version < version then - print("A new version of zones exists. Using version "..version.." instead of "..zones.version) - end -else - print("Loaded zones " ..version) -end - -zones = zones or {} -zones.version = version - -zones.Classes = zones.Classes or {} -zones.List = zones.List or {} - -//Common interface functions: - --- Registers a zone class which can then be created using weapon_zone_designator -function zones.RegisterClass(class,color) - zones.Classes[class] = color -end - - -local plymeta = FindMetaTable("Player") ---returns one of the zones a player is found in. Also returns that zone's ID. Class is optional to filter the search. -function plymeta:GetCurrentZone(class) - return zones.GetZoneAt(self:GetPos(),class) -end - ---returns a table of zones the player is in. Class is optional to filter the search. -function plymeta:GetCurrentZones(class) - return zones.GetZonesAt(self:GetPos(),class) -end - -function zones.GetZoneAt(pos,class) --works like above, except uses any point. - for k,zone in pairs(zones.List) do - if class and class != zone.class then continue end - - for k1, points in pairs(zone.points) do - if not pos:WithinAABox(zone.bounds[k1].mins,zone.bounds[k1].maxs) then continue end - if zones.PointInPoly(pos,points) then - local z = points[1].z - if pos.z >= z and pos.z < z + zone.height[k1] then - return zone,k - end - end - end - end - return nil, -1 -end -function zones.GetZonesAt(pos,class) --works like above, except uses any point. - local tbl = {} - for k,zone in pairs(zones.List) do - if class and class != zone.class then continue end - for k1, points in pairs(zone.points) do - if not pos:WithinAABox(zone.bounds[k1].mins,zone.bounds[k1].maxs) then continue end - if zones.PointInPoly(pos,points) then - local z = points[1].z - if pos.z >= z and pos.z < z + zone.height[k1] then - tbl[k] = zone - end - end - end - end - return tbl -end - ---Gets a list of all zones which are of the specified class. -function zones.FindByClass(class) - local tbl = {} - - for k,v in pairs(zones.List) do - if v.class == class then - tbl[k] = v - end - end - - return tbl -end - ---Returns the numerical ID of a zone. -function zones.GetID(zone) - return table.KeyFromValue(zones.List,zone) -end - - -//Getting into the meat of the API: -if SERVER then - util.AddNetworkString("zones_sync") - util.AddNetworkString("zones_class") - - function zones.SaveZones() - if not file.Exists("zones","DATA") then - file.CreateDir("zones") - end - file.Write("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", util.TableToJSON(zones.List)) - end - concommand.Add("zone_save",function(ply,c,a) - if not ply:IsAdmin() then return end - zones.SaveZones() - end) - - function zones.LoadZones() - local tbl = file.Read("zones/"..game.GetMap():gsub("_","-"):lower()..".txt", "DATA") - zones.List = tbl and util.JSONToTable(tbl) or {} - - //Update legacy files: - for k,v in pairs(zones.List)do - if not v.bounds then - zones.CalcBounds(v) - end - end - end - - local sync = false - local syncply - function zones.Sync(ply) - sync = true - syncply = ply - end - hook.Add("Tick","zones_sync",function() - if sync then - net.Start("zones_sync") - net.WriteTable(zones.List) - if syncply then - net.Send(syncply) - syncply = nil - else - net.Broadcast() - end - sync = false - end - end) - - function zones.CreateZoneFromPoint(ent) - - local zone = { - points = {{}}, --only 1 area when creating a new zone. - height = {ent:GetTall()}, - class = ent:GetZoneClass(), - bounds = {} - } - - local id = table.maxn(zones.List) + 1 - local cur = ent - repeat - local pos = cur:GetPos() - Vector(0,0,2) - zone.points[1][#zone.points[1]+1] = pos - - cur:SetZoneID(id) - cur = cur:GetNext() - - until (cur == ent) - - zones.CalcBounds(zone) - - zones.List[id] = zone - zones.Sync() - - hook.Run("OnZoneCreated",zone,zone.class,id) - - return zone, id - - end - - function zones.CalcBounds(zone) - zone.bounds = {} - for areanum,area in pairs(zone.points)do - local mins,maxs = Vector(10000000,10000000,area[1].z), Vector(-10000000,-10000000,area[1].z + zone.height[areanum]) - for k,pos in pairs(area) do - maxs.x = math.max(pos.x, maxs.x) - maxs.y = math.max(pos.y, maxs.y) - mins.x = math.min(pos.x, mins.x) - mins.y = math.min(pos.y, mins.y) - end - zone.bounds[areanum] = {mins=mins,maxs=maxs} - end - end - - function zones.Remove(id) - zones.List[id] = nil - zones.Sync() - end - - function zones.CreatePointEnts(removeThese) --removeThese is optional. - for k,v in pairs(removeThese or ents.FindByClass("ent_zone_point")) do --remove old - v:Remove() - end - - --create new - for id,zone in pairs(zones.List)do - - for k, area in pairs(zone.points) do - - local first - local curr - for k2,point in ipairs(area)do - - local next = ents.Create("ent_zone_point") - - if IsValid(curr) then - next:SetPos(point+Vector(0,0,1)) - curr:SetNext(next) - -- curr:DeleteOnRemove(next) - else - first = next - next:SetPos(point+Vector(0,0,1)) - end - - next.LastPoint = curr - curr = next - next:SetTall(zone.height[k]) - next:SetZoneClass(zone.class) - next:Spawn() - next:SetZoneID(id) - next:SetAreaNumber(k) - - end - - curr:SetNext(first) - -- curr:DeleteOnRemove(first) - first.LastPoint = curr - - end - end - - end - - function zones.Merge(from,to) - - local zfrom, zto = zones.List[from], zones.List[to] - - table.Add(zto.points, zfrom.points) - table.Add(zto.height, zfrom.height) - table.Add(zto.bounds, zfrom.bounds) - - zones.Remove(from) - - zones.Sync() - - end - - function zones.Split(id,areanum) - local zone = zones.List[id] - local pts, h, bound = zone.points[areanum], zone.height[areanum], zone.bounds[areanum] - - table.remove(zone.points,areanum) - table.remove(zone.height,areanum) - table.remove(zone.bounds,areanum) - - if #zone.points == 0 then - zones.Remove(id) - end - - local new = table.Copy(zone) - new.points = {pts} - new.height = {h} - new.bounds = {bound} - - local id = table.maxn(zones.List)+1 - zones.List[id] = new - - zones.Sync() - - return new,id - - end - - hook.Add("Initialize","claim_load",function() - zones.LoadZones() - end) - hook.Add("PlayerInitialSpawn","claim_sync",function(ply) - zones.Sync(ply) - end) - - net.Receive("zones_class",function(len,ply) - if not ply:IsAdmin() then return end - local id = net.ReadFloat() - local class = net.ReadString() - - for k,v in pairs(ents.FindByClass("ent_zone_point"))do - if v:GetZoneID() == id then - v:SetZoneClass(class) - end - end - zones.List[id].class = class - - zones.Sync() - end) - -else - net.Receive("zones_sync",function(len) - zones.List = net.ReadTable() - end) - function zones.ShowOptions(id) - - local zone = zones.List[id] - local class = zone.class - - local frame = vgui.Create("DFrame") - frame:MakePopup() - frame:SetTitle("Zone Settings") - - local ztitle = vgui.Create("DLabel",frame) - ztitle:Dock(TOP) - ztitle:DockMargin(2,0,5,5) - ztitle:SetText("Zone Class:") - ztitle:SizeToContents() - - local zclass = vgui.Create("DComboBox",frame) - zclass:Dock(TOP) - zclass:DockMargin(0,0,0,5) - for k,v in pairs(zones.Classes) do - zclass:AddChoice(k,nil,k == class) - end - function zclass:OnSelect(i,class) - net.Start("zones_class") - net.WriteFloat(id) - net.WriteString(class) - net.SendToServer() - - frame.content:Remove() - - frame.content = vgui.Create("DPanel",frame) - frame.content:Dock(FILL) - - local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) - frame:SizeTo((w or 100)+8,(h or 2)+78, .2) - frame:MoveTo(ScrW()/2-((w or 292)+8)/2,ScrH()/2-((h or 422)+78)/2, .2) - end - - frame.content = vgui.Create("DPanel",frame) - frame.content:Dock(FILL) - - local w,h = hook.Run("ShowZoneOptions",zone,class,frame.content,id,frame) - frame:SetSize((w or 100)+8,(h or 2)+78) - frame:Center() - - end - -end - - - -//returns the point of intersection between two infinite lines. -local function IntersectPoint(line1, line2) - - local x1,y1,x2,y2,x3,y3,x4,y4 = line1.x1,line1.y1,line1.x2,line1.y2,line2.x1,line2.y1,line2.x2,line2.y2 - - local m1,m2 = (y1-y2)/((x1-x2)+.001),(y3-y4)/((x3-x4)+.001) --get the slopes - local yint1,yint2 = (-m1*x1)+y1,(-m2*x3)+y3 --get the y-intercepts - local x = (yint1-yint2)/(m2-m1) --calculate x pos - local y = m1*x+yint1 --plug in x pos to get y pos - - return x,y - -end -//Returns a bool if two SEGEMENTS intersect or not. -local function Intersect(line1, line2) - - local x,y = IntersectPoint(line1, line2) - local sx,sy = tostring(x), tostring(y) - if (sx == "-inf" or sx == "inf" or sx == "nan") then - return false - end - - local minx1, maxx1 = math.min(line1.x1,line1.x2)-.1, math.max(line1.x1,line1.x2)+.1 - local minx2, maxx2 = math.min(line2.x1,line2.x2)-.1, math.max(line2.x1,line2.x2)+.1 - local miny1, maxy1 = math.min(line1.y1,line1.y2)-.1, math.max(line1.y1,line1.y2)+.1 - local miny2, maxy2 = math.min(line2.y1,line2.y2)-.1, math.max(line2.y1,line2.y2)+.1 - - if (x >= minx1) and (x <= maxx1) and (x >= minx2) and (x <= maxx2) then - - if (y >= miny1) and (y <= maxy1) and (y >= miny2) and (y <= maxy2) then - - --debugoverlay.Sphere( Vector(x,y,LocalPlayer():GetPos().z), 3, FrameTime()+.01, Color(255,0,0), true) - - return true - - end - - end - - return false - -end -function zones.PointInPoly(point,poly) //True if point is within a polygon. - - //Check validity - local lines = {} - local pcount = #poly - for k1=1, pcount do - - local k2 = k1+1 - if k2 > pcount then - k2 = 1 - end - - lines[k1] = { - x1 = poly[k1].x, - y1 = poly[k1].y, - x2 = poly[k2].x, - y2 = poly[k2].y, - valid = true - } - - end - - local ray = { - x1 = point.x, - y1 = point.y, - x2 = point.x + 10000, - y2 = point.y + 10000 - } - local inside = false - - //Do ray check. - for k,v in pairs(lines)do - - if Intersect(ray,v) then - inside = !inside - end - - end - - return inside -end -- cgit v1.2.3-70-g09d2