local f=game:GetService("\082\117\110\083\101\114\118\105\099\101")local e=require(script.Parent.assign)local t=require(script.Parent.createSignal)local I={}I.prototype={}I.__index=I.prototype local function S(f)assert(typeof(f)=="\116\097\098\108\101")local e={}for f,t in pairs(f)do e[f]={value=t,complete=true}end local S={__goals={},__states=e,__allComplete=true;__onComplete=t();__onStep=t()}setmetatable(S,I)return S end function I.prototype.start(e)e.__connection=f.RenderStepped:Connect(function(f)e:step(f)end)end function I.prototype.stop(f)if f.__connection~=nil then f.__connection:Disconnect()end end function I.prototype.step(e,f)assert(typeof(f)=="\110\117\109\098\101\114")if e.__allComplete then return end local t=true local I={}for S,b in pairs(e.__states)do if not b.complete then local I=e.__goals[S]if I~=nil then local t=I:step(b,f)if t~=nil then b=t e.__states[S]=t end else b.complete=true end if not b.complete then t=false end end I[S]=b.value end local S=e.__allComplete e.__allComplete=t e.__onStep:fire(I)if t and not S then e.__onComplete:fire(I)end end function I.prototype.setGoal(t,f)assert(typeof(f)=="\116\097\098\108\101")t.__goals=e({},t.__goals,f)for f in pairs(f)do local e=t.__states[f]if e==nil then error(("\067\097\110\110\111\116 \115\101\116 \103\111\097\108 \102\111\114 \116\104\101 \118\097\108\117\101 \037\115 \098\101\099\097\117\115\101 \105\116 \100\111\101\115\110\'\116 \101\120\105\115\116"):format(tostring(f)),2)end e.complete=false end t.__allComplete=false end function I.prototype.onStep(e,f)assert(typeof(f)=="\102\117\110\099\116\105\111\110")return e.__onStep:subscribe(f)end function I.prototype.onComplete(e,f)assert(typeof(f)=="\102\117\110\099\116\105\111\110")return e.__onComplete:subscribe(f)end function I.prototype.destroy(f)f:stop()end return S
local RunService = game:GetService("RunService")

local assign = require(script.Parent.assign)
local createSignal = require(script.Parent.createSignal)

local GroupMotor = {}
GroupMotor.prototype = {}
GroupMotor.__index = GroupMotor.prototype

local function createGroupMotor(initialValues)
	assert(typeof(initialValues) == "table")

	local states = {}

	for key, value in pairs(initialValues) do
		states[key] = {
			value = value,
			complete = true,
		}
	end

	local self = {
		__goals = {},
		__states = states,
		__allComplete = true,
		__onComplete = createSignal(),
		__onStep = createSignal(),
	}

	setmetatable(self, GroupMotor)

	return self
end

function GroupMotor.prototype:start()
	self.__connection = RunService.RenderStepped:Connect(function(dt)
		self:step(dt)
	end)
end

function GroupMotor.prototype:stop()
	if self.__connection ~= nil then
		self.__connection:Disconnect()
	end
end

function GroupMotor.prototype:step(dt)
	assert(typeof(dt) == "number")

	if self.__allComplete then
		return
	end

	local allComplete = true
	local values = {}

	for key, state in pairs(self.__states) do
		if not state.complete then
			local goal = self.__goals[key]

			if goal ~= nil then
				local maybeNewState = goal:step(state, dt)

				if maybeNewState ~= nil then
					state = maybeNewState
					self.__states[key] = maybeNewState
				end
			else
				state.complete = true
			end

			if not state.complete then
				allComplete = false
			end
		end

		values[key] = state.value
	end

	local wasAllComplete = self.__allComplete
	self.__allComplete = allComplete

	self.__onStep:fire(values)

	if allComplete and not wasAllComplete then
		self.__onComplete:fire(values)
	end
end

function GroupMotor.prototype:setGoal(goals)
	assert(typeof(goals) == "table")

	self.__goals = assign({}, self.__goals, goals)

	for key in pairs(goals) do
		local state = self.__states[key]

		if state == nil then
			error(("Cannot set goal for the value %s because it doesn't exist"):format(tostring(key)), 2)
		end

		state.complete = false
	end

	self.__allComplete = false
end

function GroupMotor.prototype:onStep(callback)
	assert(typeof(callback) == "function")

	return self.__onStep:subscribe(callback)
end

function GroupMotor.prototype:onComplete(callback)
	assert(typeof(callback) == "function")

	return self.__onComplete:subscribe(callback)
end

function GroupMotor.prototype:destroy()
	self:stop()
end

return createGroupMotor