local C=coroutine.wrap local p=function() end local d={}d.__index=d local x={}x.__index=x function d.new()local C=setmetatable({_connections={};_destroyed=false;_firing=false},d)return C end function d.Fire(p,...)p._firing=true local d=p._connections for p=1,#d,1 do local x=d[p]._func;(C(x))(...)end p._firing=false end function d.Wait(C)local p,d=nil,nil local x=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116")p=C:Connect(function(...)p:Disconnect()d={...}x:Fire()end)x.Event:Wait()x:Destroy()return unpack(d)end function d.Connect(p,C)assert(not p._destroyed,"\067\097\110\110\111\116 \099\111\110\110\101\099\116 \116\111 \100\101\115\116\114\111\121\101\100 \101\118\101\110\116")assert(type(C)=="\102\117\110\099\116\105\111\110","\065\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \102\117\110\099\116\105\111\110")local d=x.new(C,p)table.insert(p._connections,d)return d end function d.DisconnectAll(C)local function d()for C,p in pairs(C._connections)do p.IsConnected=false end C._connections={}end if C._firing then for C,d in pairs(C._connections)do d._func=p end spawn(function()d()end)else d()end end function d.Disconnect(d,C)local function x()for p,x in pairs(d._connections)do if x==C then table.remove(d._connections,p)break end end end if d._firing then C._func=p spawn(x)else x()end end function d.Destroy(C)if C._destroyed then return end C._destroyed=true C:DisconnectAll()end function x.new(C,p)local d=setmetatable({Connected=true,_func=C;_event=p},x)return d end function x.Disconnect(C)if not C.Connected then return end C.Connected=false C._event:Disconnect(C)end return d
-- Event
-- Crazyman32
-- March 17, 2017

--[[
	
	event = Event.new()
	
	
	event:Fire(...)
	event:Wait()
	event:DisconnectAll()
	
	connection = event:Connect(func)
		connection.Connected
		connection:Disconnect()
	
	event:Destroy()
	
--]]



local CO_WRAP = coroutine.wrap
local BLANK_FUNC = function() end


local Event = {}
Event.__index = Event

local Connection = {}
Connection.__index = Connection


function Event.new()
	
	local self = setmetatable({
		_connections = {};
		_destroyed = false;
		_firing = false;
	}, Event)
	
	return self
	
end


function Event:Fire(...)
	self._firing = true
	local connections = self._connections
	for i = 1,#connections do
		local f = connections[i]._func
		CO_WRAP(f)(...)
	end
	self._firing = false
end


function Event:Wait()
	local c, returnArgs = nil, nil
	local be = Instance.new("BindableEvent")
	c = self:Connect(function(...)
		c:Disconnect()
		returnArgs = {...}
		be:Fire()
	end)
	be.Event:Wait()
	be:Destroy()
	return unpack(returnArgs)
end


function Event:Connect(func)
	assert(not self._destroyed, "Cannot connect to destroyed event")
	assert(type(func) == "function", "Argument must be function")
	local connection = Connection.new(func, self)
	table.insert(self._connections, connection)
	return connection
end


function Event:DisconnectAll()
	local function DisconnectAll()
		for _,c in pairs(self._connections) do
			c.IsConnected = false
		end
		self._connections = {}
	end
	if (self._firing) then
		for _,c in pairs(self._connections) do
			c._func = BLANK_FUNC
		end
		spawn(function()
			DisconnectAll()
		end)
	else
		DisconnectAll()
	end
end


function Event:Disconnect(connection)
	local function Disconnect()
		for i,c in pairs(self._connections) do
			if (c == connection) then
				table.remove(self._connections, i)
				break
			end
		end
	end
	if (self._firing) then		
		connection._func = BLANK_FUNC
		spawn(Disconnect)
	else
		Disconnect()
	end
end


function Event:Destroy()
	if (self._destroyed) then return end
	self._destroyed = true
	self:DisconnectAll()
end


function Connection.new(func, event)
	local self = setmetatable({
		Connected = true;
		_func = func;
		_event = event;
	}, Connection)
	return self
end


function Connection:Disconnect()
	if (not self.Connected) then return end
	self.Connected = false
	self._event:Disconnect(self)
end


return Event