local m=EasyConfiguration.MakeEasyConfiguration(script)m.AddValue("\073\110\116\086\097\108\117\101",{Name="\077\097\120\083\104\105\112\072\101\097\108\116\104";Value=10000})m.AddValue("\073\110\116\086\097\108\117\101",{Name="\083\104\105\112\072\101\097\108\116\104",Value=m.MaxShipHealth})local O=WaitForChild(script,"\068\097\109\097\103\101\083\104\105\112")function O.OnInvoke(O)if tonumber(O)then m.ShipHealth=m.ShipHealth-O else warn("\091\083\104\105\112\083\099\114\105\112\116\093 - \068\101\114\112 \097 \104\101\114\112 \103\105\118\101 \109\101 \097 \110\117\109\098\101\114 \121\111\117 \105\100\105\111\116")end end local n={}do n.Sinking=false local m={}local function O(m)return m.X,m.Y,m.Z end local P={}local function g(m)for m,O in pairs(m:GetChildren())do if O:IsA("\077\111\100\101\108")then if O:FindFirstChild("\113\067\097\110\110\111\110\077\097\110\097\103\101\114")then P[O]=true else g(O)end end end end g(BoatModel)local function x(m)for O,n in pairs(P)do if m:IsDescendantOf(O)then return true end end return false end function n.SetRandomPartsOnFire(g,P)local L=Seat.CFrame.lookVector n.TallestPart=P[1]for P,g in pairs(P)do local L=math.max(O(g.Size))local D=(Seat.CFrame:toObjectSpace(g.CFrame)).p.Y+10 if g.Position.Y>n.TallestPart.Position.Y then n.TallestPart=g end if L<=30 and(not g:FindFirstChild("\070\108\097\109\101\070\114\111\109\083\105\110\107")and(g.Transparency<1 and(not x(g)and g~=PhysicsManager.CenterPart)))then if math.random()>.5 then delay(D/15+(math.random()-.5)*2,function()local O=Instance.new("\070\105\114\101",g)O.Size=L+5 O.Name="\070\108\097\109\101\070\114\111\109\083\105\110\107"O.Archivable=false O.Heat=0 local n=#m+1 local P={Fire=O;Part=g}if math.random()>.5 then local m=Instance.new("\083\109\111\107\101",g)m.Name="\083\109\111\107\101"m.Archivable=false m.RiseVelocity=10 local O=.5+math.random()*.3 m.Color=Color3.new(O,O,O)m.Size=L+5 m.Opacity=.1 P.Smoke=m end m[n]=P end)end end end end local function L(m)m:BreakJoints()m.CanCollide=false local O=m:getMass()local n=Make("\066\111\100\121\080\111\115\105\116\105\111\110",{Parent=m;maxForce=Vector3.new(0,((O*9.81)*20)*(1+Configuration.PercentExtraCargo),0);position=Vector3.new(0,Configuration.WaterLevel,0);Archivable=false})PhysicsManager:ReduceGravity(O)Debris:AddItem(n,5)end function n.StartManagingFire(O)spawn(function()while n.Sinking do local O=1 while O<=#m do local n=m[O]if n.Part.Position.Y<=Configuration.WaterLevel then n.Fire:Destroy()if n.Smoke then n.Smoke:Destroy()end table.remove(m,O)else O=O+1 if math.random()<=.05 and n.Part.Material.Name~="\070\097\098\114\105\099"then L(n.Part)end end end wait(.1)if n.TallestPart.Position.Y<=Configuration.WaterLevel-25 then n:CleanUp()end end end)end function n.CleanUp(m)print("\067\108\101\097\110\105\110\103")n.Sinking=false PhysicsManager:Destroy()ControlManager:Destroy()BoatModel:Destroy()end function n.Sink(m)if not n.Sinking then n.Sinking=true n:SetRandomPartsOnFire(PhysicsManager.Parts)PhysicsManager:Sink()n:StartManagingFire()end end end;(m.Get("\083\104\105\112\072\101\097\108\116\104")).Changed:connect(function()if m.ShipHealth<=0 then n:Sink()end end)PhysicsManager={}do PhysicsManager.Active=true local m={}PhysicsManager.Parts=m PhysicsManager.RotateGyro=CFrame.new()PhysicsManager.TotalForceReductionInBodyPosition=1 CallOnChildren(BoatModel,function(O)if O:IsA("\066\097\115\101\080\097\114\116")then m[#m+1]=O end end)local O,n=GetCenterOfMass(m)local P=Instance.new("\080\097\114\116",BoatModel)P.Anchored=true P.Name="\067\101\110\116\101\114\080\097\114\116"P.CanCollide=false P.Archivable=false P.FormFactor="\067\117\115\116\111\109"P.Size=Vector3.new(.2,.2,.2)P.Transparency=1 P.CFrame=GetRotationInXZPlane(Seat.CFrame-Seat.CFrame.p)+O PhysicsManager.CenterPart=P n=n+P:GetMass()local g=Instance.new("\066\111\100\121\080\111\115\105\116\105\111\110")g.P=0 g.D=0 g.maxForce=Vector3.new(0,(((1*n)*(1+Configuration.PercentExtraCargo))*9.81)*20,0)g.Parent=P g.position=P.Position g.Archivable=false local x=Instance.new("\066\111\100\121\071\121\114\111")x.D=100 x.P=1000 x.maxTorque=Vector3.new(1,0,1)*Configuration.MaxRotationCorrectionAcceleration x.Parent=P x.cframe=P.CFrame x.Archivable=false local L=Instance.new("\066\111\100\121\086\101\108\111\099\105\116\121")L.maxForce=Vector3.new(1,0,1)*(n*Configuration.Acceleration)L.P=100 L.Parent=P local D=Instance.new("\066\111\100\121\065\110\103\117\108\097\114\086\101\108\111\099\105\116\121")D.maxTorque=Vector3.new(0,(1*n)*Configuration.TurnAccelerationFactor,0)D.P=100 D.Parent=P D.angularvelocity=Vector3.new()local v=coroutine.create(function()local m=g.position local O=tick()%100000 while PhysicsManager.Active do local m=coroutine.yield()O=O+.1*m local n=GetRotationInXZPlane(P.CFrame)local g=(P.RotVelocity.Y/Configuration.MaxSpeed)/Configuration.TiltRatioFactor local L=P.Velocity.magnitude/Configuration.MaxSpeed local D=g*L local v=math.max(0,math.min(1,math.abs(D)))*Sign(D)local z=math.max(0,math.min(1,L))local Z=Configuration.AddedYawOnSpeed*z local u=(math.sin(O)*Configuration.MaxShipYawInRadians)*(1-z)+Z local e=CFrame.Angles(u,0,0)local N=CFrame.Angles(0,0,Configuration.MaxShipTiltInRadians*v)x.cframe=((n*N)*e)*PhysicsManager.RotateGyro end end)local z=coroutine.create(function()local m=g.position local O=tick()%100000 while PhysicsManager.Active do local n=coroutine.yield()O=O+.1*n local x=P.Velocity.magnitude/Configuration.MaxSpeed local L=math.max(0,math.min(1,x))local D=Configuration.AmplitudeOfWaves*L local v=(math.sin(O)*Configuration.AmplitudeOfWaves)*(1-L)+D g.position=m+Vector3.new(0,v,0)end end)spawn(function()local m=.1 while PhysicsManager.Active do assert(coroutine.resume(v,m))assert(coroutine.resume(z,m))m=wait(.1)end end)function PhysicsManager.ReduceGravity(O,m)g.maxForce=g.maxForce-Vector3.new(0,(((m*(1+Configuration.PercentExtraCargo))*9.81)*20)*PhysicsManager.TotalForceReductionInBodyPosition,0)end function PhysicsManager.ControlUpdate(n,m,O)m=m or 0 O=O or 0 L.velocity=(P.CFrame.lookVector*m)*Configuration.MaxSpeed D.angularvelocity=Vector3.new(0,Configuration.MaxTurnSpeed*O,0)end function PhysicsManager.StopControlUpdate(m)L.velocity=Vector3.new()D.angularvelocity=Vector3.new()end function PhysicsManager.Sink(m)spawn(function()local m=(math.random()*math.pi)/720 local O=(math.random()*math.pi)/720 local n=.999 local P=.999 while PhysicsManager.Active do PhysicsManager.TotalForceReductionInBodyPosition=PhysicsManager.TotalForceReductionInBodyPosition*n g.maxForce=g.maxForce*n n=1-(1-n)*.95 D.maxTorque=D.maxTorque*P L.maxForce=L.maxForce*P x.maxTorque=x.maxTorque*n m=m*.99 O=O*.99 PhysicsManager.RotateGyro=PhysicsManager.RotateGyro*CFrame.Angles(m,0,O)wait()end end)end function PhysicsManager.Destroy(m)PhysicsManager.Active=false D:Destroy()x:Destroy()L:Destroy()g:Destroy()P:Destroy()end end SeatManager={}do SeatManager.PlayerChanged=Signal.new()local m=WaitForChild(script,"\067\111\110\116\114\111\108\069\110\100\101\100")local O=WaitForChild(script,"\113\083\104\105\112\077\097\110\097\103\101\114\076\111\099\097\108")SeatManager.Seat=Seat local n function SeatManager.GetActivePlayer(m)return n and n.Player or nil end local function P()if n then n:Destroy()n=nil end end function SeatManager.GetActivePlayer(m)if n then return n.Player else return nil end end local function g(g,x)BoatModel.Parent=workspace SeatManager.PlayerChanged:fire()P()local L={}L.Player=x L.Weld=g local D=O:Clone()D.Archivable=false local v=MakeMaid()L.Maid=v Make("\079\098\106\101\099\116\086\097\108\117\101",{Name="\080\097\114\101\110\116\083\099\114\105\112\116";Value=script;Archivable=false;Parent=D})L.Script=D v:GiveTask(function()if x:IsDescendantOf(game)then m:FireClient(x)D.Name="\095\068\101\097\100\083\099\114\105\112\116"D:Destroy()end end)D.Parent=x.PlayerGui D.Disabled=false print("\078\101\119 \112\108\097\121\101\114 -",x)function L.Destroy(m)v:DoCleaning()v=nil end n=L end Seat.ChildAdded:connect(function(m)if m:IsA("\087\101\108\100")then local O=m.Part1 if O then local n,P=GetCharacter(O)if P and(CheckCharacter(P)and n.Humanoid.Health>0)then g(m,P)end end end end)Seat.ChildRemoved:connect(function(m)if n and n.Weld==m then P()SeatManager.PlayerChanged:fire()end end)end ControlManager={}do ControlManager.Active=true local m=WaitForChild(script,"\077\111\118\101")local O=WaitForChild(script,"\083\116\111\112")local n local P local g=false local x=coroutine.create(function()while ControlManager.Active do local m=wait()while(n or P)and SeatManager:GetActivePlayer()do PhysicsManager:ControlUpdate(n,P)m=wait()end PhysicsManager:StopControlUpdate()g=false coroutine.yield()end end)assert(coroutine.resume(x))local function L()if not g and ControlManager.Active then g=true assert(coroutine.resume(x))end end m.OnServerEvent:connect(function(m,O)if m==SeatManager:GetActivePlayer()then if O=="\070\111\114\119\097\114\100\115"then n=1 elseif O=="\066\097\099\107\119\097\114\100\115"then n=-1 elseif O=="\076\101\102\116"then P=1 elseif O=="\082\105\103\104\116"then P=-1 else warn("\085\110\097\098\108\101 \116\111 \104\097\110\100\108\101 \109\111\118\101 \101\118\101\110\116 \119\105\116\104 \116\121\112\101 \096"..(tostring(O).."\096"))end else warn("\073\110\118\097\108\105\100 \099\108\105\101\110\116\044 \099\097\110\110\111\116 \109\111\118\101")end end)O.OnServerEvent:connect(function(m,O)if m==SeatManager:GetActivePlayer()then if O=="\070\111\114\119\097\114\100\115"or O=="\066\097\099\107\119\097\114\100\115"then n=nil elseif O=="\076\101\102\116"or O=="\082\105\103\104\116"then P=nil else warn("\085\110\097\098\108\101 \116\111 \104\097\110\100\108\101 \109\111\118\101 \101\118\101\110\116 \119\105\116\104 \116\121\112\101 \096"..(tostring(O).."\096"))end else warn("\073\110\118\097\108\105\100 \099\108\105\101\110\116\044 \099\097\110\110\111\116 \109\111\118\101")end end)function ControlManager.Destroy(m)ControlManager.Active=false end end local P={}do local m=GetBricks(BoatModel)WeldParts(m,PhysicsManager.CenterPart,"\077\097\110\117\097\108\087\101\108\100")end


local ShipData = EasyConfiguration.MakeEasyConfiguration(script)


ShipData.AddValue("IntValue", {
	Name = "MaxShipHealth";
	Value = 10000;
})

ShipData.AddValue("IntValue", {
	Name = "ShipHealth";
	Value = ShipData.MaxShipHealth;
})

local DamageShipFunction = WaitForChild(script, "DamageShip")
function DamageShipFunction.OnInvoke(Damage)
	if tonumber(Damage) then
		ShipData.ShipHealth = ShipData.ShipHealth - Damage
	else
		warn("[ShipScript] - Derp a herp give me a number you idiot")
	end
end

local ShipSinkingManager = {} do
	ShipSinkingManager.Sinking = false
	
	local FireList = {}
	
	local function DecomposeVector3(Vector)
		return Vector.X, Vector.Y, Vector.Z
	end
	
	local CannonSets = {}
	local function GetCannonSets(Model)
		for _, Item in pairs(Model:GetChildren()) do
			if Item:IsA("Model") then
				if Item:FindFirstChild("qCannonManager") then
					CannonSets[Item] = true
					--print("Cannon set found", Item)
				else
					GetCannonSets(Item)
				end
			end
		end
	end
	GetCannonSets(BoatModel)
	
	local function IsChildOfCannonSet(Child)
		for CannonSet, _ in pairs(CannonSets) do
			if Child:IsDescendantOf(CannonSet) then
				return true
			end
		end
		
		return false
	end
	
	function ShipSinkingManager:SetRandomPartsOnFire(PartList)
		local RelativeLookVector = Seat.CFrame.lookVector
		ShipSinkingManager.TallestPart = PartList[1]
		
		for _, Item in pairs(PartList) do
			local LargestSize = math.max(DecomposeVector3(Item.Size))
			local RelativeYHeight = Seat.CFrame:toObjectSpace(Item.CFrame).p.Y + 10
			
			if Item.Position.Y > ShipSinkingManager.TallestPart.Position.Y then
				ShipSinkingManager.TallestPart = Item
			end
			
			if LargestSize <= 30 and not Item:FindFirstChild("FlameFromSink") and Item.Transparency < 1 and not IsChildOfCannonSet(Item) and Item ~= PhysicsManager.CenterPart then
				if math.random() > 0.5 then
					delay(RelativeYHeight/15 + (math.random() - 0.5)*2, function()
						local Fire = Instance.new("Fire", Item)
						Fire.Size = LargestSize + 5
						Fire.Name = "FlameFromSink"
						Fire.Archivable = false
						Fire.Heat = 0
						
						local Index = #FireList+1
						local NewFire = {
							Fire = Fire;
							Part = Item;
						}
						if math.random() > 0.5 then
							local Smoke = Instance.new("Smoke", Item)
							Smoke.Name = "Smoke"
							Smoke.Archivable = false
							Smoke.RiseVelocity = 10;
							
							local SmokeColorPercent = 0.5 + math.random()*0.3
							Smoke.Color = Color3.new(SmokeColorPercent, SmokeColorPercent, SmokeColorPercent)
							Smoke.Size = LargestSize + 5
							Smoke.Opacity = 0.1
							
							NewFire.Smoke = Smoke
						end
						
						FireList[Index] = NewFire
					end)
				end
			end
		end
	end
	
	local function BreakOffPart(Part)
		Part:BreakJoints()
		Part.CanCollide = false
		
		local Mass = Part:getMass()
		local Floater = Make("BodyPosition", {
			Parent = Part;
			maxForce = Vector3.new(0, Mass * 9.81 * 20 * (1+Configuration.PercentExtraCargo), 0);
			position = Vector3.new(0, Configuration.WaterLevel, 0);
			Archivable = false;
		})
		
		PhysicsManager:ReduceGravity(Mass)
		Debris:AddItem(Floater, 5)
	end
	
	function ShipSinkingManager:StartManagingFire()
		spawn(function()
			while ShipSinkingManager.Sinking do
				local Index = 1
				while Index <= #FireList do
					local Fire = FireList[Index]
					--print(Index, Fire)
					if Fire.Part.Position.Y <= Configuration.WaterLevel then
						--print("Removing ", Index)
						Fire.Fire:Destroy()
						
						if Fire.Smoke then
							Fire.Smoke:Destroy()
						end
						
						table.remove(FireList, Index)
					else
						Index = Index + 1
						
						if math.random() <= 0.05 and Fire.Part.Material.Name ~= "Fabric" then
							BreakOffPart(Fire.Part)
						end
					end
				end
				wait(0.1)
				if ShipSinkingManager.TallestPart.Position.Y <= Configuration.WaterLevel - 25 then
					ShipSinkingManager:CleanUp()
				end
			end
		end)
	end
	
	function ShipSinkingManager:CleanUp()
		print("Cleaning")
		
		ShipSinkingManager.Sinking = false
		PhysicsManager:Destroy()
		ControlManager:Destroy()
		
		BoatModel:Destroy()
	end
	
	function ShipSinkingManager:Sink()
		if not ShipSinkingManager.Sinking then
			ShipSinkingManager.Sinking = true
			ShipSinkingManager:SetRandomPartsOnFire(PhysicsManager.Parts)
			PhysicsManager:Sink()
			ShipSinkingManager:StartManagingFire()
		end
	end
end

ShipData.Get("ShipHealth").Changed:connect(function()
	if ShipData.ShipHealth <= 0 then
		ShipSinkingManager:Sink()
	end
end)


PhysicsManager = {} do
	PhysicsManager.Active = true
	local Parts = {}
	PhysicsManager.Parts = Parts
	PhysicsManager.RotateGyro = CFrame.new() -- Used by sinking
	PhysicsManager.TotalForceReductionInBodyPosition = 1 -- Er... not a total, but a uh... running percentage? 
	
	CallOnChildren(BoatModel, function(Part)
		if Part:IsA("BasePart") then
			Parts[#Parts+1] = Part
		end
	end)
	 -- Force = Mass * Acceleration 
	
	local CenterOfMass, TotalMass = GetCenterOfMass(Parts)
	
	local CenterPart        = Instance.new("Part", BoatModel)
	CenterPart.Anchored     = true;
	CenterPart.Name         = "CenterPart";
	CenterPart.CanCollide   = false;
	CenterPart.Archivable   = false;
	CenterPart.FormFactor   = "Custom";
	CenterPart.Size         = Vector3.new(0.2, 0.2, 0.2)
	CenterPart.Transparency = 1
	CenterPart.CFrame       = GetRotationInXZPlane(Seat.CFrame - Seat.CFrame.p) + CenterOfMass
	PhysicsManager.CenterPart = CenterPart
	
	TotalMass = TotalMass + CenterPart:GetMass()
	
	local BodyPosition      = Instance.new("BodyPosition")
	BodyPosition.P          = 0 --10000000
	BodyPosition.D          = 0 --10000000
	BodyPosition.maxForce   = Vector3.new(0, 1 * TotalMass*(1+Configuration.PercentExtraCargo) * 9.81 * 20, 0) --Vector3.new(0, 100000000, 0)
	BodyPosition.Parent     = CenterPart
	BodyPosition.position   = CenterPart.Position--]]
	BodyPosition.Archivable = false
	
	local BodyGyro = Instance.new("BodyGyro")
	BodyGyro.D = 100
	BodyGyro.P = 1000
	BodyGyro.maxTorque = Vector3.new(1, 0, 1) * (Configuration.MaxRotationCorrectionAcceleration) --Vector3.new(8999999488, 0, 8999999488)
	BodyGyro.Parent = CenterPart
	BodyGyro.cframe = CenterPart.CFrame
	BodyGyro.Archivable = false
	
	local BodyVelocity = Instance.new("BodyVelocity")
	BodyVelocity.maxForce = Vector3.new(1, 0, 1) * (TotalMass * Configuration.Acceleration) --Vector3.new(1000000, 0, 1000000)
	BodyVelocity.P = 100
	BodyVelocity.Parent = CenterPart

	local BodyAngularVelocity = Instance.new("BodyAngularVelocity")
	BodyAngularVelocity.maxTorque = Vector3.new(0, 1*TotalMass * Configuration.TurnAccelerationFactor, 0)
	BodyAngularVelocity.P = 100
	BodyAngularVelocity.Parent = CenterPart
	BodyAngularVelocity.angularvelocity = Vector3.new()
	
	local TiltCoroutine = coroutine.create(function()
		local BasePosition = BodyPosition.position
		local Count = tick()%100000
		
		while PhysicsManager.Active do
			local Delta = coroutine.yield()
			Count = Count + 0.1*Delta
			
			local YRotation   = GetRotationInXZPlane(CenterPart.CFrame)
			local UndoctoredPercentTilt = CenterPart.RotVelocity.Y/Configuration.MaxSpeed/Configuration.TiltRatioFactor -- Because apparently bodyangularvelocity's never get close to the true value. 
			local UndoctoredPercentSpeed = CenterPart.Velocity.magnitude/Configuration.MaxSpeed
			
			local UndoctoredPercent = UndoctoredPercentTilt*UndoctoredPercentSpeed
			
			local PercentTilt = math.max(0, math.min(1, math.abs(UndoctoredPercent)))*Sign(UndoctoredPercent)
			
			
			local PercentSpeed = math.max(0, math.min(1, UndoctoredPercentSpeed))
			
			local AddedYaw = Configuration.AddedYawOnSpeed * PercentSpeed
			local NewYawAmount = math.sin(Count)*Configuration.MaxShipYawInRadians*(1-PercentSpeed)+AddedYaw
			local Yaw = CFrame.Angles(NewYawAmount, 0, 0)
			
			local Tilt = CFrame.Angles(0, 0, Configuration.MaxShipTiltInRadians * PercentTilt) 
			BodyGyro.cframe = YRotation * Tilt * Yaw * PhysicsManager.RotateGyro
		end
	end)
	
	local WaveCoroutine = coroutine.create(function()
		local BasePosition = BodyPosition.position
		local Count = tick()%100000
		
		while PhysicsManager.Active do
			local Delta = coroutine.yield()
			Count = Count + 0.1*Delta
			
			local UndoctoredPercentSpeed = CenterPart.Velocity.magnitude/Configuration.MaxSpeed
			local PercentSpeed = math.max(0, math.min(1, UndoctoredPercentSpeed))
			
			--print("PercentSpeed", PercentSpeed)
			
			local AddedHeightFromSpeed = Configuration.AmplitudeOfWaves * PercentSpeed
			local WaveHeight = math.sin(Count)*Configuration.AmplitudeOfWaves*(1-PercentSpeed) + AddedHeightFromSpeed -- waves don't effect ships moving fast. 
			
			BodyPosition.position = BasePosition + Vector3.new(0, WaveHeight, 0)
		end
	end)
	
	spawn(function()	
		local Delta = 0.1

		while PhysicsManager.Active do		
			assert(coroutine.resume(TiltCoroutine, Delta))
			assert(coroutine.resume(WaveCoroutine, Delta))
			
			Delta = wait(0.1)
		end
	end)
	
	function PhysicsManager:ReduceGravity(Mass)
		BodyPosition.maxForce = BodyPosition.maxForce - Vector3.new(0, 
			Mass*(1+Configuration.PercentExtraCargo) * 9.81 * 20 * PhysicsManager.TotalForceReductionInBodyPosition, 
			0)
	end
	
	function PhysicsManager:ControlUpdate(Forwards, Turn)
		Forwards = Forwards or 0
		Turn = Turn or 0
		
		BodyVelocity.velocity = CenterPart.CFrame.lookVector * Forwards * Configuration.MaxSpeed
		BodyAngularVelocity.angularvelocity = Vector3.new(0, Configuration.MaxTurnSpeed * Turn, 0)
	end
	
	function PhysicsManager:StopControlUpdate()
		BodyVelocity.velocity = Vector3.new()
		BodyAngularVelocity.angularvelocity = Vector3.new()
	end
	
	function PhysicsManager:Sink()
		
		spawn(function()
			local ChangeInRotationOnSinkX = math.random() * math.pi/720
			local ChangeInRotationOnSinkZ = math.random() * math.pi/720
			local ChangeInForce        = 0.999
			local ControlChangeInForce = 0.999
			
			while PhysicsManager.Active do
				PhysicsManager.TotalForceReductionInBodyPosition = PhysicsManager.TotalForceReductionInBodyPosition * ChangeInForce
				BodyPosition.maxForce = BodyPosition.maxForce * ChangeInForce
				ChangeInForce = 1-((1 - ChangeInForce)*0.95)
				
				BodyAngularVelocity.maxTorque = BodyAngularVelocity.maxTorque * ControlChangeInForce
				BodyVelocity.maxForce = BodyVelocity.maxForce * ControlChangeInForce
				
				
				BodyGyro.maxTorque = BodyGyro.maxTorque * ChangeInForce
				ChangeInRotationOnSinkX = ChangeInRotationOnSinkX * 0.99
				ChangeInRotationOnSinkZ = ChangeInRotationOnSinkZ * 0.99
				PhysicsManager.RotateGyro = PhysicsManager.RotateGyro * CFrame.Angles(ChangeInRotationOnSinkX, 0, ChangeInRotationOnSinkZ)
				wait()
			end
		end)
	end
	
	function PhysicsManager:Destroy()
		PhysicsManager.Active = false
		
		BodyAngularVelocity:Destroy()
		BodyGyro:Destroy()
		BodyVelocity:Destroy()
		BodyPosition:Destroy()
		CenterPart:Destroy()
	end
end

SeatManager = {} do
	SeatManager.PlayerChanged = Signal.new()
	
	local ControlEndedEvent = WaitForChild(script, "ControlEnded");
	local qShipManagerLocal = WaitForChild(script, "qShipManagerLocal")
	SeatManager.Seat = Seat
	
	local ActivePlayerData
	
	function SeatManager:GetActivePlayer()
		return ActivePlayerData and ActivePlayerData.Player or nil
	end
	
	local function DeactivateActivePlayer()
		if ActivePlayerData then
			ActivePlayerData:Destroy()
			ActivePlayerData = nil
		end
	end
	
	function SeatManager:GetActivePlayer()
		if ActivePlayerData then
			return ActivePlayerData.Player
		else
			return nil
		end
	end
	
	local function HandleNewPlayer(Weld, Player)
		BoatModel.Parent = workspace
		SeatManager.PlayerChanged:fire()
		DeactivateActivePlayer()
		
		local NewData = {}
		NewData.Player = Player
		NewData.Weld = Weld
		
		local Script = qShipManagerLocal:Clone()
		Script.Archivable = false;
		
		local Maid = MakeMaid()
		NewData.Maid = Maid


		Make("ObjectValue", {
			Name = "ParentScript";
			Value = script;
			Archivable = false;
			Parent = Script;
		})
		NewData.Script = Script
		
		Maid:GiveTask(function()
			if Player:IsDescendantOf(game) then
				ControlEndedEvent:FireClient(Player)
				Script.Name = "_DeadScript";--]]
				Script:Destroy()
			end
		end)--]]
		
		Script.Parent = Player.PlayerGui
		Script.Disabled = false
		
		print("New player -", Player)

		function NewData:Destroy()
			Maid:DoCleaning()
			Maid = nil
		end
		
		ActivePlayerData = NewData
	end
	
	Seat.ChildAdded:connect(function(Weld)
		if Weld:IsA("Weld") then
			local Torso = Weld.Part1
			
			if Torso then
				local Character, Player = GetCharacter(Torso)
				if Player and CheckCharacter(Player) and Character.Humanoid.Health > 0 then
					HandleNewPlayer(Weld, Player)
				end
			end
		end
	end)
	
	Seat.ChildRemoved:connect(function(Child)
		if ActivePlayerData and ActivePlayerData.Weld == Child then
			--ActivePlayerData.Player.PlayerGui
			DeactivateActivePlayer()
			SeatManager.PlayerChanged:fire()
		end
	end)
end

ControlManager = {} do
	ControlManager.Active = true
	local MoveEvent = WaitForChild(script, "Move");
	local StopEvent = WaitForChild(script, "Stop");
	local Forwards
	local Turn
	
	local Updating = false
	local UpdateCoroutine = coroutine.create(function()
		while ControlManager.Active do
			local Delta = wait()
			while (Forwards or Turn) and SeatManager:GetActivePlayer() do
				--[[if Forwards then
					PhysicsManager:Forwards(Delta, Forwards)
				else
					PhysicsManager:Forwards(Delta, nil)
				end
				
				if Turn then
					PhysicsManager:Turn(Delta, Turn)
				else
					PhysicsManager:Turn(Delta, Turn)
				end--]]
				PhysicsManager:ControlUpdate(Forwards, Turn)
				
				Delta = wait()
			end
			
			PhysicsManager:StopControlUpdate()
			
			Updating = false
			coroutine.yield()
		end
	end)
	assert(coroutine.resume(UpdateCoroutine))
	
	local function StartUpdate()
		if not Updating and ControlManager.Active then
			Updating = true
			assert(coroutine.resume(UpdateCoroutine))
		end
	end
	
	MoveEvent.OnServerEvent:connect(function(Client, Type)
		if Client == SeatManager:GetActivePlayer() then
			if Type == "Forwards" then
				Forwards = 1
			elseif Type == "Backwards" then
				Forwards = -1
			elseif Type == "Left" then
				Turn = 1
			elseif Type == "Right" then
				Turn = -1
			else
				warn("Unable to handle move event with type `" .. tostring(Type) .. "`")
			end
		else
			warn("Invalid client, cannot move")
		end
	end)
	
	StopEvent.OnServerEvent:connect(function(Client, Type)
		if Client == SeatManager:GetActivePlayer() then
			if Type == "Forwards" or Type == "Backwards" then
				Forwards = nil
			elseif Type == "Left" or Type == "Right" then
				Turn = nil
			else
				warn("Unable to handle move event with type `" .. tostring(Type) .. "`")
			end
		else
			warn("Invalid client, cannot move")
		end
	end)
	
	function ControlManager:Destroy()
		ControlManager.Active = false
	end
end

local WeldManager = {} do
	local Parts = GetBricks(BoatModel)
	WeldParts(Parts, PhysicsManager.CenterPart, "ManualWeld")
end
