324 lines
9 KiB
Lua
324 lines
9 KiB
Lua
-- Made by Divran 06/01/2012
|
|
WireToolSetup.setCategory( "Chips, Gates" )
|
|
WireToolSetup.open( "gates", "Gates", "gmod_wire_gate", nil, "Gates" )
|
|
|
|
WireToolSetup.SetupMax(100)
|
|
|
|
if SERVER then
|
|
ModelPlug_Register("gate")
|
|
end
|
|
|
|
if CLIENT then
|
|
----------------------------------------------------------------------------------------------------
|
|
-- Tool Info
|
|
----------------------------------------------------------------------------------------------------
|
|
|
|
language.Add( "Tool.wire_gates.name", "Gates Tool (Wire)" )
|
|
language.Add( "Tool.wire_gates.desc", "Spawns gates for use with the wire system." )
|
|
|
|
TOOL.ClientConVar["model"] = "models/jaanus/wiretool/wiretool_gate.mdl"
|
|
TOOL.ClientConVar["parent"] = 0
|
|
TOOL.ClientConVar["noclip"] = 1
|
|
TOOL.ClientConVar["angleoffset"] = 0
|
|
TOOL.ClientConVar["action"] = "+"
|
|
TOOL.ClientConVar["searchresultnum"] = 28
|
|
|
|
language.Add( "WireGatesTool_action", "Gate action" )
|
|
language.Add( "WireGatesTool_noclip", "NoCollide" )
|
|
language.Add( "WireGatesTool_parent", "Parent" )
|
|
language.Add( "WireGatesTool_angleoffset", "Spawn angle offset" )
|
|
language.Add( "sboxlimit_wire_gates", "You've hit your gates limit!" )
|
|
|
|
WireToolSetup.setToolMenuIcon( "bull/gates/gate_logic_and" )
|
|
|
|
TOOL.Information = {
|
|
{ name = "left", text = "Create/Update Gate" },
|
|
{ name = "right", text = "Copy Gate" },
|
|
{ name = "reload", text = "Increase angle offset by 45 degrees" },
|
|
{ name = "reload_shift", text = "Shift+Reload: Unparent gate (If parented)" },
|
|
}
|
|
|
|
function TOOL.BuildCPanel( panel )
|
|
----------------- GATE SELECTION & SEARCHING
|
|
|
|
-- Create panels
|
|
local searchbox = vgui.Create( "DTextEntry" )
|
|
|
|
searchbox:SetValue( "Search..." )
|
|
|
|
local oldOnGetFocus = searchbox.OnGetFocus
|
|
function searchbox:OnGetFocus()
|
|
if self:GetValue() == "Search..." then -- If "Search...", erase it
|
|
self:SetValue( "" )
|
|
end
|
|
oldOnGetFocus( self )
|
|
end
|
|
|
|
-- On lose focus
|
|
local oldOnLoseFocus = searchbox.OnLoseFocus
|
|
function searchbox:OnLoseFocus()
|
|
if self:GetValue() == "" then -- if empty, reset "Search..." text
|
|
timer.Simple( 0, function() self:SetValue( "Search..." ) end )
|
|
end
|
|
oldOnLoseFocus( self )
|
|
end
|
|
|
|
local holder = vgui.Create( "DPanel" )
|
|
holder:SetTall( 500 )
|
|
|
|
local tree = vgui.Create( "DTree", holder )
|
|
local searchlist = vgui.Create( "DListView", holder )
|
|
searchlist:AddColumn( "Gate Name" )
|
|
searchlist:AddColumn( "Category" )
|
|
|
|
local string_find = string.find
|
|
local table_SortByMember = table.SortByMember
|
|
local string_lower = string.lower
|
|
|
|
-- Searching algorithm
|
|
local function Search( text )
|
|
text = string_lower(text)
|
|
|
|
local results = {}
|
|
for action,gate in pairs( GateActions ) do
|
|
local name = gate.name
|
|
local lowname = string_lower(name)
|
|
if string_find( lowname, text, 1, true ) then -- If it has ANY match at all
|
|
results[#results+1] = { name = gate.name, group = gate.group, action = action, dist = WireLib.levenshtein( text, lowname ) }
|
|
end
|
|
end
|
|
|
|
table_SortByMember( results, "dist", true )
|
|
|
|
return results
|
|
end
|
|
|
|
-- Main searching
|
|
local searching
|
|
function searchbox:OnTextChanged()
|
|
local text = searchbox:GetValue()
|
|
if text ~= "" then
|
|
if not searching then
|
|
searching = true
|
|
local x,y = tree:GetPos()
|
|
local w,h = tree:GetSize()
|
|
searchlist:SetPos( x + w, y )
|
|
searchlist:MoveTo( x, y, 0.1, 0, 1 )
|
|
searchlist:SetSize( w, h )
|
|
searchlist:SetVisible( true )
|
|
end
|
|
local results = Search( text )
|
|
searchlist:Clear()
|
|
for i=1,#results do
|
|
local result = results[i]
|
|
|
|
local line = searchlist:AddLine( result.name, result.group )
|
|
local action = GetConVarString("wire_gates_action")
|
|
if action == result.action then
|
|
line:SetSelected( true )
|
|
end
|
|
line.action = result.action
|
|
end
|
|
else
|
|
if searching then
|
|
searching = false
|
|
local x,y = tree:GetPos()
|
|
local w,h = tree:GetSize()
|
|
searchlist:SetPos( x, y )
|
|
searchlist:MoveTo( x + w, y, 0.1, 0, 1 )
|
|
searchlist:SetSize( w, h )
|
|
timer.Create( "wire_customspawnmenu_hidesearchlist", 0.1, 1, function()
|
|
if IsValid( searchlist ) then
|
|
searchlist:SetVisible( false )
|
|
end
|
|
end )
|
|
end
|
|
searchlist:Clear()
|
|
end
|
|
end
|
|
|
|
function searchlist:OnClickLine( line )
|
|
-- Deselect old
|
|
local t = searchlist:GetSelected()
|
|
if t and next(t) then
|
|
t[1]:SetSelected(false)
|
|
end
|
|
|
|
line:SetSelected(true) -- Select new
|
|
RunConsoleCommand( "wire_gates_action", line.action )
|
|
end
|
|
|
|
function searchbox:OnEnter()
|
|
if #searchlist:GetLines() > 0 then
|
|
searchlist:OnClickLine( searchlist:GetLine( 1 ) )
|
|
end
|
|
end
|
|
|
|
panel:AddItem( searchbox )
|
|
|
|
tree:Dock( FILL )
|
|
|
|
-- Set sizes & other settings
|
|
searchlist:SetVisible( false )
|
|
searchlist:SetMultiSelect( false )
|
|
|
|
|
|
local function FillSubTree( tree, node, temp )
|
|
node.Icon:SetImage( "icon16/folder.png" )
|
|
|
|
local subtree = {}
|
|
for k,v in pairs( temp ) do
|
|
subtree[#subtree+1] = { action = k, gate = v, name = v.name }
|
|
end
|
|
|
|
table_SortByMember(subtree, "name", true )
|
|
|
|
for index=1, #subtree do
|
|
local action, gate = subtree[index].action, subtree[index].gate
|
|
local node2 = node:AddNode( gate.name or "No name found :(" )
|
|
node2.name = gate.name
|
|
node2.action = action
|
|
function node2:DoClick()
|
|
RunConsoleCommand( "wire_gates_Action", self.action )
|
|
end
|
|
node2.Icon:SetImage( "icon16/newspaper.png" )
|
|
end
|
|
tree:InvalidateLayout()
|
|
end
|
|
|
|
local CategoriesSorted = {}
|
|
|
|
for gatetype, gatefuncs in pairs( WireGatesSorted ) do
|
|
local allowed_gates = {}
|
|
local any_allowed = false
|
|
for k,v in pairs(gatefuncs) do
|
|
if not v.is_banned then
|
|
allowed_gates[k] = v
|
|
any_allowed = true
|
|
end
|
|
end
|
|
if any_allowed then
|
|
CategoriesSorted[#CategoriesSorted+1] = { gatetype = gatetype, gatefuncs = allowed_gates }
|
|
end
|
|
end
|
|
|
|
table.sort( CategoriesSorted, function( a, b ) return a.gatetype < b.gatetype end )
|
|
|
|
for i=1,#CategoriesSorted do
|
|
local gatetype = CategoriesSorted[i].gatetype
|
|
local gatefuncs = CategoriesSorted[i].gatefuncs
|
|
|
|
local node = tree:AddNode( gatetype )
|
|
node.Icon:SetImage( "icon16/folder.png" )
|
|
FillSubTree( tree, node, gatefuncs )
|
|
function node:DoClick()
|
|
self:SetExpanded( not self.m_bExpanded )
|
|
end
|
|
end
|
|
|
|
-- add it all to the main panel
|
|
panel:AddItem( holder )
|
|
|
|
|
|
-- MISCELLANEOUS PLACEMENT OPTIONS, AND MODEL
|
|
|
|
local nocollidebox = panel:CheckBox("#WireGatesTool_noclip", "wire_gates_noclip")
|
|
local parentbox = panel:CheckBox("#WireGatesTool_parent","wire_gates_parent")
|
|
|
|
panel:Help("When parenting, you should check the nocollide box, or adv duplicator might not dupe the gate.")
|
|
|
|
panel:NumSlider( "#WireGatesTool_angleoffset","wire_gates_angleoffset", 0, 360, 0 )
|
|
|
|
WireDermaExts.ModelSelect(panel, "wire_gates_model", list.Get("Wire_gate_Models"), 3, true)
|
|
|
|
function nocollidebox.Button:DoClick()
|
|
self:Toggle()
|
|
end
|
|
|
|
function parentbox.Button:DoClick() -- when you check the parent box, check the nocollide box
|
|
self:Toggle()
|
|
if (self:GetChecked() == true) then
|
|
nocollidebox:SetValue(1)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
WireToolSetup.BaseLang()
|
|
|
|
if SERVER then
|
|
function TOOL:GetConVars()
|
|
return self:GetClientInfo( "action" ), self:GetClientNumber( "noclip" ) == 1
|
|
end
|
|
|
|
function TOOL:MakeEnt( ply, model, Ang, trace )
|
|
return WireLib.MakeWireGate( ply, trace.HitPos, Ang, model, self:GetConVars() )
|
|
end
|
|
end
|
|
|
|
|
|
--------------------
|
|
-- RightClick
|
|
-- Copy gate
|
|
--------------------
|
|
function TOOL:RightClick( trace )
|
|
if CLIENT then return true end
|
|
if self:CheckHitOwnClass(trace) then
|
|
local action = GateActions[trace.Entity.action]
|
|
assert(action, "Attempted to copy gate " .. tostring(trace.Entity) .. " with no action!")
|
|
|
|
self:GetOwner():ConCommand( "wire_gates_action " .. trace.Entity.action )
|
|
self:GetOwner():ChatPrint( "Gate copied ('" .. action.name .. "')." )
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
--------------------
|
|
-- Reload
|
|
-- Increase angle offset by 45 degrees
|
|
--------------------
|
|
function TOOL:Reload( trace )
|
|
if self:GetOwner():KeyDown( IN_SPEED ) then -- Unparent
|
|
if not trace or not trace.Hit then return false end
|
|
if (CLIENT and trace.Entity) then return true end
|
|
if (trace.Entity:GetParent():IsValid()) then
|
|
|
|
-- Get its position
|
|
local pos = trace.Entity:GetPos()
|
|
|
|
-- Unparent
|
|
trace.Entity:SetParent()
|
|
|
|
-- Teleport it back to where it was before unparenting it (because unparenting causes issues which makes the gate teleport to random wierd places)
|
|
trace.Entity:SetPos( pos )
|
|
|
|
-- Wake
|
|
local phys = trace.Entity:GetPhysicsObject()
|
|
if (phys) then
|
|
phys:Wake()
|
|
end
|
|
|
|
-- Notify
|
|
self:GetOwner():ChatPrint("Entity unparented.")
|
|
return true
|
|
end
|
|
return false
|
|
else
|
|
if game.SinglePlayer() and SERVER then
|
|
self:GetOwner():ConCommand( "wire_gates_angleoffset " .. (self:GetClientNumber( "angleoffset" ) + 45) % 360 )
|
|
elseif CLIENT then
|
|
RunConsoleCommand( "wire_gates_angleoffset", (self:GetClientNumber( "angleoffset" ) + 45) % 360 )
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function TOOL:GetAngle( trace )
|
|
local ang = WireToolObj.GetAngle(self, trace)
|
|
ang:RotateAroundAxis( trace.HitNormal, self:GetClientNumber( "angleoffset" ) )
|
|
return ang
|
|
end
|