local T={}T.__index=T local N=require(script.Util)local Z=require(script.Constants)local E=require(script.System)local S="\098\097\100 \097\114\103\117\109\101\110\116 \035\037\100 \116\111 \'\037\115\' \040\037\115 \101\120\112\101\099\116\101\100\044 \103\111\116 \037\115\041"local t="\098\097\100 \097\114\103\117\109\101\110\116 \035\037\100 \116\111 \'\037\115\' \040\037\115\041"function T.GetEnabled(T)return E.contains(T)end function T.SetEnabled(N,T)if T then E.add(N)else E.remove(N)end end function T.GetCFrame(T)return T.cframe end function T.SetCFrame(N,T)N.cframe=T N.changed=true end function T.GetRange(T)return T.cframe.p,T.cframe*Vector3.new(T.length,0,0)end function T.SetRange(E,T,Z)local S=Z-T if S.magnitude<.001 then S=Vector3.new(0,0,-0.001)end E.length=S.magnitude E.cframe=N.makeOrientation(T,S)E.changed=true end function T.GetColor(T)return T.color end function T.SetColor(N,T)N.color=T end function T.GetTopColor(T)return T.topColor end function T.SetTopColor(N,T)N.topColor=T end function T.GetNumArcs(T)return T.numArcs end function T.Destroy(T)E.remove(T)T.part:Destroy()T.segmentsFolder:Destroy()end function T.GetFatnessMultiplier(T)return T.fatnessMultiplier end function T.SetFatnessMultiplier(N,T)N.fatnessMultiplier=T end function T.new(g,Y,P,O,G,v,p)if g~=nil and typeof(g)~="\086\101\099\116\111\114\051"then error(S:format(1,"\110\101\119","\086\101\099\116\111\114\051",typeof(g)),2)elseif Y~=nil and typeof(Y)~="\086\101\099\116\111\114\051"then error(S:format(2,"\110\101\119","\086\101\099\116\111\114\051",typeof(Y)),2)elseif P~=nil and typeof(P)~="\067\111\108\111\114\051"then error(S:format(3,"\110\101\119","\067\111\108\111\114\051",typeof(P)),2)elseif O~=nil and typeof(O)~="\067\111\108\111\114\051"then error(S:format(4,"\110\101\119","\067\111\108\111\114\051",typeof(O)),2)elseif G~=nil and type(G)~="\110\117\109\098\101\114"then error(S:format(5,"\110\101\119","\110\117\109\098\101\114",typeof(G)),2)elseif G~=nil and G<1 then error(t:format(5,"\110\101\119","\110\117\109\098\101\114 \111\102 \097\114\099\115 \115\104\111\117\108\100 \098\101 \062\061 \049"),2)elseif v~=nil and type(v)~="\110\117\109\098\101\114"then error(S:format(6,"\110\101\119","\110\117\109\098\101\114",typeof(v)),2)elseif v~=nil and v<0 then error(t:format(6,"\110\101\119","\109\117\108\116\105\112\108\105\101\114 \115\104\111\117\108\100 \098\101 \062\061 \048"),2)elseif p~=nil and type(p)~="\098\111\111\108\101\097\110"then error(S:format(6,"\110\101\119","\098\111\111\108\101\097\110",typeof(p)),2)end g=g or Vector3.new()Y=Y or Vector3.new()P=P or Z.DEFAULT_COLOR O=O or Z.DEFAULT_TOP_COLOR G=G or Z.DEFAULT_NUM_ARCS v=v or 1 local K=setmetatable({},T)local C=Y-g K.id=N.getGlobalId()K.cframe=N.makeOrientation(g,C)K.length=C.magnitude K.color=P K.topColor=O K.arc=1 K.numArcs=G K.arcRenderAmount=0 K.fatnessMultiplier=v K.visible=true local r=Instance.new("\080\097\114\116")r.Name=Z.PART_NAME_TEMPLATE:format(K.id)r.Anchored=true r.CanCollide=false r.Locked=true r.Archivable=false r.Transparency=1 r.TopSurface=Enum.SurfaceType.Smooth r.BottomSurface=Enum.SurfaceType.Smooth r.Size=Vector3.new(.05,.05,.05)r.CFrame=K.cframe K.part=r local H=Instance.new("\065\116\116\097\099\104\109\101\110\116")H.Name="\069\109\105\116\116\101\114"H.CFrame=CFrame.new(K.length/2,0,0)H.Parent=r local F=Instance.new("\080\111\105\110\116\076\105\103\104\116")F.Name="\080\111\105\110\116\076\105\103\104\116"F.Brightness=5 F.Color=(Color3.new(0,0,0)):lerp(P,Z.LIGHT_COLOR_MODIFIER)F.Range=0 F.Shadows=true F.Enabled=Z.USE_POINTLIGHT F.Parent=H K.segments={}K.segmentsFolder=Instance.new("\070\111\108\100\101\114")K.segmentsFolder.Name=Z.SEGMENT_FOLDER_NAME_TEMPLATE:format(K.id)for T=1,G*Z.SEGMENT_PER_ARC_MAX,1 do local N=Instance.new("\073\109\097\103\101\072\097\110\100\108\101\065\100\111\114\110\109\101\110\116",K.segmentsFolder)N.Name=Z.SEGMENT_NAME_TEMPLATE:format(T)N.Image=Z.ARC_TEXTURE N.Adornee=K.part N.Size=Vector2.new(0,0)N.ZIndex=0 K.segments[T]=N end K.step={}K.amountSegments={}K.totalSteps={}K.path={}K.brightness={}K.axisKeyPoints0={}K.axisKeyPoints1={}K.pathT0={}K.pathT1={}for T=1,G,1 do K.pathT0[T]={}K.pathT1[T]={}K.step[T]=0 K.amountSegments[T]=-1 end if p or p==nil and Z.DEFAULT_ENABLED then E.add(K)end return K end function T.link(N,g,Y,P,O,G,v)if typeof(N)~="\073\110\115\116\097\110\099\101"or not N:IsA("\065\116\116\097\099\104\109\101\110\116")then error(S:format(1,"\097\116\116\097\099\104","\065\116\116\097\099\104\109\101\110\116",typeof(N)),2)elseif typeof(g)~="\073\110\115\116\097\110\099\101"or not g:IsA("\065\116\116\097\099\104\109\101\110\116")then error(S:format(2,"\097\116\116\097\099\104","\065\116\116\097\099\104\109\101\110\116",typeof(g)),2)elseif Y~=nil and typeof(Y)~="\067\111\108\111\114\051"then error(S:format(3,"\097\116\116\097\099\104","\067\111\108\111\114\051",typeof(Y)),2)elseif P~=nil and typeof(P)~="\067\111\108\111\114\051"then error(S:format(4,"\097\116\116\097\099\104","\067\111\108\111\114\051",typeof(P)),2)elseif O~=nil and type(O)~="\110\117\109\098\101\114"then error(S:format(5,"\097\116\116\097\099\104","\110\117\109\098\101\114",typeof(O)),2)elseif O~=nil and O<1 then error(t:format(5,"\097\116\116\097\099\104","\116\104\101 \110\117\109\098\101\114 \111\102 \097\114\099\115 \115\104\111\117\108\100 \098\101 \062\061 \049"),2)elseif v~=nil and type(v)~="\098\111\111\108\101\097\110"then error(S:format(6,"\097\116\116\097\099\104","\098\111\111\108\101\097\110",typeof(v)),2)end local p=T.new(N.WorldPosition,g.WorldPosition,Y,P,O,G,false)p.dynamic=true p.source=N p.drain=g if v or v==nil and Z.DEFAULT_ENABLED then E.add(p)end return p end T.New=T.new T.Link=T.link return T
--[[	Arc.lua
		Implementation of the main Arc class of this library that the user interacts.
		This module is licensed under MIT, refer to the LICENSE file or:
		https://github.com/buildthomas/ElectricArc/blob/master/LICENSE
]]

local Arc = {}
Arc.__index = Arc

local Util = require(script.Util)
local Constants = require(script.Constants)
local System = require(script.System)

-- Error format strings
local ERROR_TYPE_FORMAT = "bad argument #%d to '%s' (%s expected, got %s)"
local ERROR_BAD_ARGUMENT = "bad argument #%d to '%s' (%s)"

function Arc:GetEnabled()
	return System.contains(self)
end

function Arc:SetEnabled(value)
	if value then
		System.add(self)
	else
		System.remove(self)
	end
end

function Arc:GetCFrame()
	return self.cframe
end

function Arc:SetCFrame(cfr)
    self.cframe = cfr
    self.changed = true
end

function Arc:GetRange()
    return self.cframe.p, self.cframe * Vector3.new(self.length, 0, 0)
end

function Arc:SetRange(source, drain)
	local axis = drain - source
	if axis.magnitude < 0.001 then
		axis = Vector3.new(0, 0, -0.001)
	end
    self.length = axis.magnitude
	self.cframe = Util.makeOrientation(source, axis)
    self.changed = true
end

function Arc:GetColor()
    return self.color
end

function Arc:SetColor(color)
    self.color = color
end

function Arc:GetTopColor()
    return self.topColor
end

function Arc:SetTopColor(topColor)
    self.topColor = topColor
end

function Arc:GetNumArcs()
	return self.numArcs
end

function Arc:Destroy()
    -- Remove self from system
    System.remove(self)

    -- Destroying instances
    self.part:Destroy()
    self.segmentsFolder:Destroy()
end

function Arc:GetFatnessMultiplier()
	return self.fatnessMultiplier
end

function Arc:SetFatnessMultiplier(fatnessMultiplier)
	self.fatnessMultiplier = fatnessMultiplier
end

function Arc.new(source, drain, color, topColor, numArcs, fatnessMultiplier, enabled)
    if source ~= nil and typeof(source) ~= "Vector3" then
        error(ERROR_TYPE_FORMAT:format(1, "new", "Vector3", typeof(source)), 2)
    elseif drain ~= nil and typeof(drain) ~= "Vector3" then
        error(ERROR_TYPE_FORMAT:format(2, "new", "Vector3", typeof(drain)), 2)
    elseif color ~= nil and typeof(color) ~= "Color3" then
        error(ERROR_TYPE_FORMAT:format(3, "new", "Color3", typeof(color)), 2)
    elseif topColor ~= nil and typeof(topColor) ~= "Color3" then
        error(ERROR_TYPE_FORMAT:format(4, "new", "Color3", typeof(topColor)), 2)
    elseif numArcs ~= nil and type(numArcs) ~= "number" then
        error(ERROR_TYPE_FORMAT:format(5, "new", "number", typeof(numArcs)), 2)
    elseif numArcs ~= nil and numArcs < 1 then
		error(ERROR_BAD_ARGUMENT:format(5, "new", "number of arcs should be >= 1"), 2)
	elseif fatnessMultiplier ~= nil and type(fatnessMultiplier) ~= "number" then
        error(ERROR_TYPE_FORMAT:format(6, "new", "number", typeof(fatnessMultiplier)), 2)
    elseif fatnessMultiplier ~= nil and fatnessMultiplier < 0 then
        error(ERROR_BAD_ARGUMENT:format(6, "new", "multiplier should be >= 0"), 2)
	elseif enabled ~= nil and type(enabled) ~= "boolean" then
        error(ERROR_TYPE_FORMAT:format(6, "new", "boolean", typeof(enabled)), 2)
	end

	source = source or Vector3.new()
	drain = drain or Vector3.new()
	color = color or Constants.DEFAULT_COLOR
	topColor = topColor or Constants.DEFAULT_TOP_COLOR
	numArcs = numArcs or Constants.DEFAULT_NUM_ARCS
	fatnessMultiplier = fatnessMultiplier or 1

    local self = setmetatable({}, Arc)

    -- Helper variable, vector offset from source to drain
    local axis = (drain - source)

    self.id = Util.getGlobalId()
    self.cframe = Util.makeOrientation(source, axis) -- Orientation (rotation + position) of source of effect
    self.length = axis.magnitude -- Length of effect between its end points
    self.color = color -- Basis color of the effect
    self.topColor = topColor -- Brightest color that will appear
    self.arc = 1 -- Which arc is being animated (loops)
    self.numArcs = numArcs -- Number of arcs at any time inside the effect
	self.arcRenderAmount = 0 -- Number of arcs left to render in next heartbeat (can be a real value)
	self.fatnessMultiplier = fatnessMultiplier -- multiply the computed fatnesses by this number for this arc
    self.visible = true -- Whether effect is on-screen

	-- Part that all effects are attached to, with a light in it
	local sourcePart = Instance.new("Part")
	sourcePart.Name = Constants.PART_NAME_TEMPLATE:format(self.id)
	sourcePart.Anchored = true
	sourcePart.CanCollide = false
	sourcePart.Locked = true
	sourcePart.Archivable = false
	sourcePart.Transparency = 1
	sourcePart.TopSurface = Enum.SurfaceType.Smooth
	sourcePart.BottomSurface = Enum.SurfaceType.Smooth
	sourcePart.Size = Vector3.new(0.05, 0.05, 0.05)
    sourcePart.CFrame = self.cframe
	self.part = sourcePart

	local emitter = Instance.new("Attachment")
	emitter.Name = "Emitter"
	emitter.CFrame = CFrame.new(self.length/2, 0, 0)
	emitter.Parent = sourcePart

	local emitterLight = Instance.new("PointLight")
	emitterLight.Name = "PointLight"
	emitterLight.Brightness = 5
	emitterLight.Color = Color3.new(0, 0, 0):lerp(color, Constants.LIGHT_COLOR_MODIFIER)
	emitterLight.Range = 0
	emitterLight.Shadows = true
	emitterLight.Enabled = Constants.USE_POINTLIGHT
	emitterLight.Parent = emitter

    -- Preparing a pool of particles to be used for the effect
    self.segments = {}
    self.segmentsFolder = Instance.new("Folder")
    self.segmentsFolder.Name = Constants.SEGMENT_FOLDER_NAME_TEMPLATE:format(self.id)
    for i = 1, (numArcs * Constants.SEGMENT_PER_ARC_MAX) do
        local segment = Instance.new("ImageHandleAdornment", self.segmentsFolder)
        segment.Name = Constants.SEGMENT_NAME_TEMPLATE:format(i)
        segment.Image = Constants.ARC_TEXTURE
        segment.Adornee = self.part
        segment.Size = Vector2.new(0, 0)
        segment.ZIndex = 0
        self.segments[i] = segment
    end

    -- Initialize tables that hold the definitions of the individual (animated) arcs
    self.step = {}
    self.amountSegments = {}
    self.totalSteps = {}
    self.path = {}
	self.brightness = {}

    -- Arc paths
    self.axisKeyPoints0 = {}
    self.axisKeyPoints1 = {}
    self.pathT0 = {}
    self.pathT1 = {}
    for arc = 1, numArcs do
        self.pathT0[arc] = {} -- Starting path t=0
        self.pathT1[arc] = {} -- Ending path t=1
        self.step[arc] = 0
        self.amountSegments[arc] = -1 -- Initially the arc has no defined segment count
    end

	if enabled or (enabled == nil and Constants.DEFAULT_ENABLED) then
		-- Add to system if enabled at creation
		System.add(self)
	end

    return self
end

function Arc.link(source, drain, color, topColor, numArcs, fatnessMultiplier, enabled)
	if typeof(source) ~= "Instance" or not source:IsA("Attachment") then
        error(ERROR_TYPE_FORMAT:format(1, "attach", "Attachment", typeof(source)), 2)
    elseif typeof(drain) ~= "Instance" or not drain:IsA("Attachment") then
        error(ERROR_TYPE_FORMAT:format(2, "attach", "Attachment", typeof(drain)), 2)
    elseif color ~= nil and typeof(color) ~= "Color3" then
        error(ERROR_TYPE_FORMAT:format(3, "attach", "Color3", typeof(color)), 2)
    elseif topColor ~= nil and typeof(topColor) ~= "Color3" then
        error(ERROR_TYPE_FORMAT:format(4, "attach", "Color3", typeof(topColor)), 2)
    elseif numArcs ~= nil and type(numArcs) ~= "number" then
        error(ERROR_TYPE_FORMAT:format(5, "attach", "number", typeof(numArcs)), 2)
    elseif numArcs ~= nil and numArcs < 1 then
        error(ERROR_BAD_ARGUMENT:format(5, "attach", "the number of arcs should be >= 1"), 2)
	elseif enabled ~= nil and type(enabled) ~= "boolean" then
        error(ERROR_TYPE_FORMAT:format(6, "attach", "boolean", typeof(enabled)), 2)
	end

	local self = Arc.new(
		source.WorldPosition,
		drain.WorldPosition,
		color,
		topColor,
		numArcs,
		fatnessMultiplier,
		false
	)
	self.dynamic = true
	self.source = source
	self.drain = drain

	if enabled or (enabled == nil and Constants.DEFAULT_ENABLED) then
		-- Add to system if enabled at creation now that self.dynamic is set
		System.add(self)
	end

	return self
end

-- Aliases
Arc.New = Arc.new
Arc.Link = Arc.link

return Arc