TOOL.Category = "Constraints"
TOOL.Name = "Präzision"
TOOL.ClientConVar["mode"] = "1"
TOOL.ClientConVar["user"] = "1"
TOOL.ClientConVar["freeze"] = "1"
TOOL.ClientConVar["nocollide"] = "1"
TOOL.ClientConVar["nocollideall"]	= "0"
TOOL.ClientConVar["rotation"] = "15"
TOOL.ClientConVar["rotate"] = "1"
TOOL.ClientConVar["offset"] = "0"
TOOL.ClientConVar["forcelimit"] = "0"
TOOL.ClientConVar["torquelimit"] = "0"
TOOL.ClientConVar["friction"]	= "0"
TOOL.ClientConVar["width"] = "1"
TOOL.ClientConVar["offsetpercent"] = "1"
TOOL.ClientConVar["removal"] = "0"
TOOL.ClientConVar["move"] = "1"
TOOL.ClientConVar["physdisable"] = "0"
TOOL.ClientConVar["shadowdisable"] = "0"
TOOL.ClientConVar["allowphysgun"] = "0"
TOOL.ClientConVar["autorotate"] = "0"
TOOL.ClientConVar["entirecontrap"] = "0"
TOOL.ClientConVar["nudge"] = "25"
TOOL.ClientConVar["nudgepercent"] = "1"
TOOL.ClientConVar["disablesliderfix"] = "0"
TOOL.ClientConVar["XRotMin"] = "-180"
TOOL.ClientConVar["XRotMax"] = "180"
TOOL.ClientConVar["YRotMin"] = "-180"
TOOL.ClientConVar["YRotMax"] = "180"
TOOL.ClientConVar["ZRotMin"] = "-180"
TOOL.ClientConVar["ZRotMax"] = "180"
TOOL.ClientConVar["XRotFric"] = "0"
TOOL.ClientConVar["YRotFric"] = "0"
TOOL.ClientConVar["ZRotFric"] = "0"
TOOL.ClientConVar["freemove"] = "0"
TOOL.ClientConVar["removal_nocollide"] = "1"
TOOL.ClientConVar["removal_weld"] = "1"
TOOL.ClientConVar["removal_axis"] = "1"
TOOL.ClientConVar["removal_ballsocket"] = "1"
TOOL.ClientConVar["removal_advballsocket"] = "1"
TOOL.ClientConVar["removal_slider"] = "1"
TOOL.ClientConVar["removal_parent"] = "1"
TOOL.ClientConVar["removal_other"] = "1"
TOOL.ClientConVar["enablefeedback"] = "1"
TOOL.ClientConVar["chatfeedback"] = "1"
TOOL.ClientConVar["nudgeundo"] = "0"
TOOL.ClientConVar["moveundo"]	= "1"
TOOL.ClientConVar["rotateundo"] = "1"

TOOL.Information = {
	{name = "left", stage = 0},
	{name = "left_1", stage = 1},
	{name = "left_2", stage = 2},
	{name = "right"},
	{name = "reload"}
}

local function GetAllEnts(Ent, OrderedEntList, EntsTab, ConstsTab)
	if !SERVER then return end
	if IsValid(Ent) and !EntsTab[Ent:EntIndex()] then
		EntsTab[Ent:EntIndex()] = Ent
		table.insert(OrderedEntList, Ent)
		if !constraint.HasConstraints(Ent) then return OrderedEntList end
		for key, ConstraintEntity in pairs(Ent.Constraints) do
			if !ConstsTab[ConstraintEntity] then
				ConstsTab[ConstraintEntity] = true
				local ConstTable = ConstraintEntity:GetTable()
				for i=1, 6 do
					local e = ConstTable["Ent"..i]
					if IsValid(e) and !EntsTab[e:EntIndex()] then
						GetAllEnts(e, OrderedEntList, EntsTab, ConstsTab)
					end
				end
			end
		end
	end
	return OrderedEntList
end

function TOOL:DoParent(Ent1, Ent2)
	local TempEnt = Ent2
	if !(IsValid(Ent1) and Ent1:EntIndex() != 0) then
		self:SendMessage("Erstes Prop ist ungültig.")
		return false
	end
	if !(IsValid(Ent2) and Ent2:EntIndex() != 0) then
		self:SendMessage("Zweites Prop ist ungültig.")
		return false
	end
	if Ent1 == Ent2 then
		self:SendMessage("Gleiches Prop ausgewählt.")
		return false
	end
	constraint.RemoveAll(Ent1)
	Ent1.MG_Disabled = true
	Ent1:SetMoveType(MOVETYPE_NONE)
	Ent1:SetCollisionGroup(COLLISION_GROUP_WORLD)
	Ent1.PhysgunDisabled = disablephysgun
	Ent1:SetUnFreezable(disablephysgun)
	Ent1.CanTool = function()
		return false
	end
	local Phys1 = Ent1:GetPhysicsObject()
	while true do
		if !IsValid(TempEnt:GetParent()) then
			Ent1:SetParent(Ent2)
			if IsValid(Phys1) then
				Phys1:Wake()
			end
			break
		elseif (TempEnt:GetParent() == Ent1) then
			self:UndoParent(TempEnt)
			timer.Simple(0.1, function()
				if !IsValid(Ent1) or !IsValid(Ent2) then return end
				Ent1:SetParent(Ent2)
			end)
			self:SendMessage("Geschlossene Vereinungsschleife erkannt. Schleife unterbrochen und Objekt vereint.")
			break
		else
			TempEnt = TempEnt:GetParent()
		end
	end
	Phys1:Wake()
	undo.Create("Präzision: Vereinen")
		undo.SetPlayer(self:GetOwner())
		undo.AddFunction(self.UndoParent, Ent1)
	undo.Finish()
	return true
end

function TOOL:UndoParent(Ent1)
	if !IsValid(Ent1) then return end
	Ent1.MG_Disabled = nil
	Ent1:SetParent()
	Ent1:SetMoveType(MOVETYPE_VPHYSICS)
	Ent1:SetCollisionGroup(COLLISION_GROUP_NONE)
	Ent1.PhysgunDisabled = false
	Ent1:SetUnFreezable(false)
	Ent1.CanTool = nil
	local Phys1 = Ent1:GetPhysicsObject()
	if IsValid(Phys1) then
		Phys1:Wake()
	end
	if MG and MG.EnableAntiPropMinge then
		MG.DisableProtectionMode(Ent1)
		MG.EnableProtectionMode(Ent1)
	end
end

function TOOL:DoApply(CurrentEnt, FirstEnt, autorotate, nocollideall, shadowdisable, physdis, disablephysgun)
	local CurrentPhys = CurrentEnt:GetPhysicsObject()
	if autorotate then
		if CurrentEnt == FirstEnt then
			local angle = CurrentPhys:RotateAroundAxis(Vector(0, 0, 1), 0)
			self.anglechange = Vector(angle.p - (math.Round(angle.p / 45)) * 45, angle.r - (math.Round(angle.r / 45)) * 45, angle.y - (math.Round(angle.y / 45)) * 45)
			if table.Count(self.TaggedEnts) == 1 then
				angle.p = (math.Round(angle.p / 45)) * 45
				angle.r = (math.Round(angle.r / 45)) * 45
			end
			angle.y = (math.Round(angle.y / 45)) * 45
			CurrentPhys:SetAngles(angle)
		else
			local distance = math.sqrt(math.pow((CurrentEnt:GetPos().X - FirstEnt:GetPos().X),2) + math.pow((CurrentEnt:GetPos().Y - FirstEnt:GetPos().Y), 2))
			local theta = math.atan((CurrentEnt:GetPos().Y - FirstEnt:GetPos().Y) / (CurrentEnt:GetPos().X - FirstEnt:GetPos().X)) - math.rad(self.anglechange.Z)
			if CurrentEnt:GetPos().X - FirstEnt:GetPos().X < 0 then
				CurrentEnt:SetPos(Vector(FirstEnt:GetPos().X - (distance * (math.cos(theta))), FirstEnt:GetPos().Y - (distance * (math.sin(theta))), CurrentEnt:GetPos().Z))
			else
				CurrentEnt:SetPos(Vector(FirstEnt:GetPos().X + (distance * (math.cos(theta))), FirstEnt:GetPos().Y + (distance * (math.sin(theta))), CurrentEnt:GetPos().Z))
			end
			CurrentPhys:SetAngles(CurrentPhys:RotateAroundAxis(Vector(0, 0, -1), self.anglechange.Z))
		end
	end
	CurrentPhys:EnableCollisions(!nocollideall)
	CurrentEnt:DrawShadow(!shadowdisable)
	if physdis then
		CurrentEnt:SetMoveType(MOVETYPE_NONE)
		CurrentEnt.PhysgunDisabled = disablephysgun
		CurrentEnt:SetUnFreezable(disablephysgun)
	else
		local pos = CurrentEnt:GetPos()
		CurrentEnt:SetMoveType(MOVETYPE_VPHYSICS)
		CurrentEnt.PhysgunDisabled = false
		CurrentEnt:SetUnFreezable(false)
		local phys = CurrentEnt:GetPhysicsObject()
		if IsValid(phys) then
			phys:SetPos(pos)
		end
	end
end

function TOOL:CreateUndo(constraint, undoname)
	if constraint then
		undo.Create(undoname)
			undo.AddEntity(constraint)
			undo.SetPlayer(self:GetOwner())
		undo.Finish()
		self:GetOwner():AddCleanup("constraints", constraint)
	end
end

function TOOL:DoConstraint(mode)
	self:SetStage(0)
	local Ent1, Ent2 = self:GetEnt(1),	self:GetEnt(2)
	if (!IsValid(Ent1) or CLIENT) then
		self:ClearObjects()
		return false
	end
	local print_text = true
	local forcelimit = self:GetClientNumber("forcelimit", 0)
	local freeze = util.tobool(self:GetClientNumber("freeze", 1))
	local nocollide	= self:GetClientNumber("nocollide", 0)
	local nocollideall = util.tobool(self:GetClientNumber("nocollideall", 0))
	local torquelimit = self:GetClientNumber("torquelimit", 0)
	local width	= self:GetClientNumber("width", 1)
	local friction = self:GetClientNumber("friction", 0)
	local physdis = util.tobool(self:GetClientNumber("physdisable", 0))
	local disablephysgun = self:GetClientNumber("allowphysgun") == 0
	local shadowdisable = util.tobool(self:GetClientNumber("shadowdisable", 0))
	local autorotate = util.tobool(self:GetClientNumber("autorotate",1))
	local removal_nocollide = util.tobool(self:GetClientNumber("removal_nocollide",1))
	local removal_weld = util.tobool(self:GetClientNumber("removal_weld",1))
	local removal_axis = util.tobool(self:GetClientNumber("removal_axis",1))
	local removal_ballsocket = util.tobool(self:GetClientNumber("removal_ballsocket",1))
	local removal_advballsocket = util.tobool(self:GetClientNumber("removal_advballsocket",1))
	local removal_slider = util.tobool(self:GetClientNumber("removal_slider",1))
	local removal_parent = util.tobool(self:GetClientNumber("removal_parent",1))
	local removal_other = util.tobool(self:GetClientNumber("removal_other",1))
	local Bone1 = self:GetBone(1)
	local LPos1 = self:GetLocalPos(1)
	local Bone2
	local LPos2
	if (IsValid(Ent2) or Ent2:IsWorld()) then
		Bone2 = self:GetBone(2)
		LPos2 = self:GetLocalPos(2)
	end
	local Phys1 = self:GetPhys(1)
	local NumApp = 0
	for key, CurrentEnt in pairs(self.TaggedEnts) do
		if IsValid(CurrentEnt) then
			if (CurrentEnt != Ent2) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if (IsValid(CurrentPhys) and !IsValid(CurrentEnt:GetParent())) then
					if (CurrentEnt:GetPhysicsObjectCount() < 2) then
						if (util.tobool(nocollide) and (mode == 1 or mode == 3)) then
							constraint.NoCollide(CurrentEnt, Ent2, 0, Bone2)
						end
						if (mode == 1) then
							self:DoApply(CurrentEnt, Ent1, autorotate, nocollideall, shadowdisable, physdis, disablephysgun)
						elseif (mode == 4) then
							local constr = constraint.Weld(CurrentEnt, Ent2, 0, Bone2, forcelimit,  util.tobool(nocollide))
							self:CreateUndo(constr, "Präzision: Verbinden")
						elseif (mode == 5) then
							local constr = constraint.Axis(CurrentEnt, Ent2, Bone1, Bone2, LPos1, LPos2, forcelimit, torquelimit, friction, nocollide)
							self:CreateUndo(constr, "Präzision: Achse")
						elseif (mode == 6) then
							local constr = constraint.Ballsocket(CurrentEnt, Ent2, 0, Bone2, LPos2, forcelimit, torquelimit, nocollide)
							self:CreateUndo(constr, "Präzision: Ballsocket")
						elseif (mode == 7) then
							local constr = constraint.AdvBallsocket(CurrentEnt, Ent2, 0, Bone2, LPos1, LPos2, forcelimit, torquelimit, self:GetClientNumber("XRotMin", -180), self:GetClientNumber("YRotMin", -180), self:GetClientNumber("ZRotMin", -180), self:GetClientNumber("XRotMax", 180), self:GetClientNumber("YRotMax", 180), self:GetClientNumber("ZRotMax", 180), self:GetClientNumber("XRotFric", 0), self:GetClientNumber("YRotFric", 0), self:GetClientNumber("ZRotFric", 0), self:GetClientNumber("freemove", 0), nocollide)
							self:CreateUndo(constr, "Präzision: Erweiterter Ballsocket")
						elseif (mode == 8) then
							local constraint0 = constraint.Slider(CurrentEnt, Ent2, 0, Bone2, LPos1, LPos2, width)
							if constraint0 then
								undo.Create("Präzision: Schiene")
									if (self:GetClientNumber("disablesliderfix") == 0) then
										local constraint2 = constraint.AdvBallsocket(Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0, 0, 0, -180, -180, 0, 180, 180, 50, 0, 0, 1, 0)
										if constraint2 then
											undo.AddEntity(constraint2)
										end
										local constraint3 = constraint.AdvBallsocket(Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0, 0, -180, 0, -180, 180, 0, 180, 0, 50, 0, 1, 0)
										if constraint3 then
											undo.AddEntity(constraint3)
										end
										local constraint4 = constraint.AdvBallsocket(Ent1, Ent2, Bone1, Bone2, LPos1, LPos2, 0, 0, -180, -180, 0, 180, 180, 0, 0, 0, 50, 1, 0)
										if constraint4 then
											undo.AddEntity(constraint4)
										end
									end
									undo.AddEntity(constraint0)
									undo.SetPlayer(self:GetOwner())
								undo.Finish()
								self:GetOwner():AddCleanup("constraints", constraint0)
							end
						elseif (mode == 9) then
							print_text = self:DoParent(CurrentEnt, Ent2)
						elseif (mode == 10) then
							if CLIENT then return true end
							if removal_nocollide then
								constraint.RemoveConstraints(CurrentEnt, "NoCollide")
								CurrentPhys:EnableCollisions(true)
							end
							if removal_weld then
								constraint.RemoveConstraints(CurrentEnt, "Weld")
							end
							if removal_axis then
								constraint.RemoveConstraints(CurrentEnt, "Axis")
							end
							if removal_ballsocket then
								constraint.RemoveConstraints(CurrentEnt, "Ballsocket")
							end
							if removal_slider then
								constraint.RemoveConstraints(CurrentEnt, "Slider")
							end
							if removal_parent then
								if IsValid(CurrentEnt:GetParent()) then
									self:UndoParent(CurrentEnt)
								end
							end
							if removal_other then
								constraint.RemoveConstraints(CurrentEnt, "Elastic")
								constraint.RemoveConstraints(CurrentEnt, "Hydraulic")
								constraint.RemoveConstraints(CurrentEnt, "Keepupright")
								constraint.RemoveConstraints(CurrentEnt, "Motor")
								constraint.RemoveConstraints(CurrentEnt, "Muscle")
								constraint.RemoveConstraints(CurrentEnt, "Pulley")
								constraint.RemoveConstraints(CurrentEnt, "Rope")
								constraint.RemoveConstraints(CurrentEnt, "Winch")
							end
						end
						if (mode <= 8) then
							if freeze then
								CurrentPhys:EnableMotion(false)
							end
						end
					else
						self:SendMessage("Das ist kein Prop.")
						print_text = false
					end
				else
					self:SendMessage("Kein Physikobjekt.")
					print_text = false
				end
			else
				self:SendMessage("Gleiches Prop ausgewählt.")
				print_text = false
			end
		else
			self:SendMessage("Prop nicht mehr gültig.")
			print_text = false
		end
		NumApp = NumApp + 1
	end
	if print_text then
		if (mode == 1) then
			self:SendMessage(NumApp.." Prop(s) angewendet.")
		elseif (mode == 2) then
			self:SendMessage(NumApp.." Prop(s) rotiert.")
		elseif (mode == 3) then
			self:SendMessage(NumApp.." Prop(s) verschoben.")
		elseif (mode == 4) then
			self:SendMessage(NumApp.." Prop(s) verbunden.")
		elseif (mode == 5) then
			self:SendMessage("Bei "..NumApp.." Prop(s) eine Achse erstellt.")
		elseif (mode == 6) then
			self:SendMessage("Bei "..NumApp.." Prop(s) einen Ballsocket erstellt.")
		elseif (mode == 7) then
			self:SendMessage("Bei "..NumApp.." Prop(s) einen erweiterten Ballsocket erstellt.")
		elseif (mode == 8) then
			self:SendMessage("Bei "..NumApp.." Prop(s) einen Schiene erstellt.")
		elseif (mode == 9) then
			self:SendMessage(NumApp.." Prop(s) vereint.")
		elseif (mode == 10) then
			self:SendMessage(NumApp.." Prop(s) gesäubert.")
		end
	end
	self:ClearSelection()
	self:ClearObjects()
end

function TOOL:SendMessage(message)
	if (self:GetClientNumber("enablefeedback") == 0) then return end
	if (self:GetClientNumber("chatfeedback") == 1) then
		self:GetOwner():PrintMessage(HUD_PRINTTALK, "Präzision: "..message)
	else
		self:GetOwner():PrintMessage(HUD_PRINTCENTER, message)
	end
end

function TOOL:TargetValidity(trace, phys)
	local ent = trace.Entity
	if (SERVER and (!util.IsValidPhysicsObject(ent, trace.PhysicsBone) or !IsValid(phys))) then
		local mode = self:GetClientNumber("mode")
		if IsValid(ent:GetParent()) then
			return 2
		else
			return 0
		end
	elseif ent:IsPlayer() then
		return 0
	elseif trace.HitWorld then
		return 1
	else
		return 3
	end
end

function TOOL:StartRotate()
	if !IsValid(self:GetEnt(1)) or !IsValid(self:GetPhys(1)) then return end
	local Ent = self:GetEnt(1)
	local Phys = self:GetPhys(1)
	local oldposu = Ent:GetPos()
	local oldangles = Ent:GetAngles()
	local function MoveUndo(Undo, Entity, oldposu, oldangles)
		if IsValid(Entity) then
			Entity:SetAngles(oldangles)
			Entity:SetPos(oldposu)
			if MG and MG.EnableAntiPropMinge and MG.CheckForStuckingPlayers(Entity) then
				if !MG.IsProtected(Entity) then
					MG.EnableProtectionMode(Entity)
					MG.SetProtected(Entity, true)
				end
			end
		end
	end
	if self:GetClientNumber("rotateundo") then
		if SERVER then
			undo.Create("Präzision: Rotieren")
				undo.SetPlayer(self:GetOwner())
				undo.AddFunction(MoveUndo, Ent, oldposu, oldangles)
			undo.Finish()
		end
	end
	if !IsValid(Phys) then return end
	Phys:EnableMotion(false)
	local rotation = self:GetClientNumber("rotation")
	if (rotation < 0.02) then rotation = 0.02 end
	self.axis = self:GetNormal(1)
	self.axisY = self.axis:Cross(Ent:GetUp())
	if self:WithinABit(self.axisY, Vector(0,0,0)) then
		self.axisY = self.axis:Cross(Ent:GetForward())
	end
	self.axisZ = self.axisY:Cross(self.axis)
	self.realdegrees = 0
	self.lastdegrees = -((rotation / 2) % rotation)
	self.realdegreesY = 0
	self.lastdegreesY = -((rotation / 2) % rotation)
	self.realdegreesZ = 0
	self.lastdegreesZ = -((rotation / 2) % rotation)
	self.OldPos = self:GetPos(1)
end

function TOOL:DoMove()
	if !IsValid(self:GetEnt(1)) then return end
	local Norm1, Norm2 = self:GetNormal(1), self:GetNormal(2)
	local Phys1, Phys2 = self:GetPhys(1), self:GetPhys(2)
	if !IsValid(Phys1) or !IsValid(Phys2) then return end
	local Ang1, Ang2 = Norm1:Angle(), (Norm2 * -1):Angle()
	if self:GetClientNumber("autorotate") == 1 then
		Ang2.p = math.Round(Ang2.p / 45) * 45
		Ang2.r = math.Round(Ang2.r / 45) * 45
		Ang2.y = math.Round(Ang2.y / 45) * 45
		Norm2 = Ang2:Forward() * -1
	end
	local oldposu = self:GetEnt(1):GetPos()
	local oldangles = self:GetEnt(1):GetAngles()
	local function MoveUndo(Undo, Entity, oldposu, oldangles)
		if IsValid(Entity) then
			Entity:SetAngles(oldangles)
			Entity:SetPos(oldposu)
			if MG and MG.EnableAntiPropMinge and MG.CheckForStuckingPlayers(Entity) then
				if !MG.IsProtected(Entity) then
					MG.EnableProtectionMode(Entity)
					MG.SetProtected(Entity, true)
				end
			end
		end
	end
	if self:GetClientNumber("moveundo") == 1 then
		undo.Create("Präzision: Bewegung")
			undo.SetPlayer(self:GetOwner())
			undo.AddFunction(MoveUndo, self:GetEnt(1), oldposu, oldangles)
		undo.Finish()
	end
	local rotation = self:GetClientNumber("rotation")
	if rotation < 0.02 then
		rotation = 0.02
	end
	if ((self:GetClientNumber("rotate") == 1 and mode != 1) or mode == 2) then
		self.axis = Norm2
		self.axisY = self.axis:Cross(Vector(0, 1, 0))
		if self:WithinABit(self.axisY, Vector(0, 0, 0)) then
			self.axisY = self.axis:Cross(Vector(0, 0, 1))
		end
		self.axisY:Normalize()
		self.axisZ = self.axisY:Cross(self.axis)
		self.axisZ:Normalize()
		self.realdegrees = 0
		self.lastdegrees = -((rotation / 2) % rotation)
		self.realdegreesY = 0
		self.lastdegreesY = -((rotation / 2) % rotation)
		self.realdegreesZ = 0
		self.lastdegreesZ = -((rotation / 2) % rotation)
	else
		self.axis = Norm2
		self.axisY = self.axis:Cross(Vector(0, 1, 0))
		if self:WithinABit(self.axisY, Vector(0, 0, 0)) then
			self.axisY = self.axis:Cross(Vector(0, 0, 1))
		end
		self.axisY:Normalize()
		self.axisZ = self.axisY:Cross(self.axis)
		self.axisZ:Normalize()
	end
	local TargetAngle = Phys1:AlignAngles(Ang1, Ang2)
	if self:GetClientNumber("autorotate") == 1 then
		TargetAngle.p = math.Round(TargetAngle.p / 45) * 45
		TargetAngle.r = math.Round(TargetAngle.r / 45) * 45
		TargetAngle.y = math.Round(TargetAngle.y / 45) * 45
	end
	Phys1:SetAngles(TargetAngle)
	local NewOffset = math.Clamp(self:GetClientNumber("offset"), -5000, 5000)
	local offsetpercent	= self:GetClientNumber("offsetpercent") == 1
	if offsetpercent then
		local Ent2 = self:GetEnt(2)
		local glower = Ent2:OBBMins()
		local gupper = Ent2:OBBMaxs()
		local height = math.abs(gupper.z - glower.z) - 0.5
		if self:WithinABit(Norm2, Ent2:GetForward()) then
			height = math.abs(gupper.x - glower.x) - 0.5
		elseif self:WithinABit(Norm2, Ent2:GetRight()) then
			height = math.abs(gupper.y - glower.y) - 0.5
		end
		NewOffset = NewOffset / 100
		NewOffset = NewOffset * height
	end
	Norm2 = Norm2 * (-0.0625 + NewOffset)
	local TargetPos = self:GetPos(2) + (Phys1:GetPos() - self:GetPos(1)) + Norm2
	Phys1:SetPos(TargetPos)
	Phys1:EnableMotion(false)
	Phys1:Wake()
end

function TOOL:ToggleColor(CurrentEnt)
	color = CurrentEnt:GetColor()
	color["a"] = color["a"] - 128
	if color["a"] < 0 then
		color["a"] = color["a"] + 256
	end
	color["r"] = color["r"] - 128
	if color["r"] < 0 then
		color["r"] = color["r"] + 256
	end
	color["g"] = color["g"] - 128
	if color["g"] < 0 then
		color["g"] = color["g"] + 256
	end
	color["b"] = color["b"] - 128
	if color["b"] < 0 then
		color["b"] = color["b"] + 256
	end
	CurrentEnt:SetColor(color)
	if color["a"] == 255 then
		CurrentEnt:SetRenderMode(RENDERMODE_NORMAL)
	else
		CurrentEnt:SetRenderMode(RENDERMODE_TRANSCOLOR)
	end
end

function TOOL:ClearSelection()
	if self.TaggedEnts then
		local color
		for key, CurrentEnt in pairs(self.TaggedEnts) do
			if IsValid(CurrentEnt) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if IsValid(CurrentPhys) then
					self:ToggleColor(CurrentEnt)
				end
			end
		end
	end
	self.TaggedEnts = {}
end

function TOOL:SelectEnts(StartEnt, AllConnected)
	self:ClearSelection()
	if !SERVER then return end
	if AllConnected == 1 then
		local NumApp = 0
		local EntsTab = {}
		local ConstsTab = {}
		GetAllEnts(StartEnt, self.TaggedEnts, EntsTab, ConstsTab)
		for key, CurrentEnt in pairs(self.TaggedEnts) do
			if IsValid(CurrentEnt) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if IsValid(CurrentPhys) then
					self:ToggleColor(CurrentEnt)
				end
			end
			NumApp = NumApp + 1
		end
		self:SendMessage(NumApp.." Objekt(e) ausgewählt.")
	else
		if IsValid(StartEnt) then
			local CurrentPhys = StartEnt:GetPhysicsObject()
			if IsValid(CurrentPhys) then
				table.insert(self.TaggedEnts, StartEnt)
				self:ToggleColor(StartEnt)
			end
		end
	end
end

function TOOL:LeftClick(trace)
	local stage = self:GetStage()
	local mode = self:GetClientNumber("mode")
	local moving = (mode == 3 or (self:GetClientNumber("move") == 1 and mode >= 3 and mode <= 8))
	local rotating = self:GetClientNumber("rotate") == 1
	if !trace.PhysicsBone then self:GetOwner():ChatPrint("Kein Physikobjekt.") return false end
	local ent = trace.Entity
	local phys = ent:GetPhysicsObjectNum(trace.PhysicsBone)
	if stage == 0 then
		if mode != 1 and self:TargetValidity(trace, phys) <= 1 then
			if SERVER then
				self:GetOwner():ChatPrint("Ungültiges Prop.")
			end
			return false
		end
		self:SetObject(1, ent, trace.HitPos, phys, trace.PhysicsBone, trace.HitNormal)
		if self:GetClientNumber("entirecontrap") == 1 and mode != 1 and mode != 2 and mode != 3 and mode != 5 and mode != 6 and mode != 7 and mode != 8 then
			self:SelectEnts(ent, 1)
		else
			self:SelectEnts(ent, 0)
		end
		if mode == 1 or mode == 10 then
			self:DoConstraint(mode)
		else
			if mode == 9 then
				self:SetStage(1)
			else
				if moving then
					self:StartGhostEntity(ent)
					self:SetStage(1)
				elseif mode == 2 then
					self:StartRotate()
					self:SetStage(2)
				else
					self:SetStage(1)
				end
			end
		end
	elseif stage == 1 then
		self:SetObject(2, ent, trace.HitPos, phys, trace.PhysicsBone, trace.HitNormal)
		if self:GetEnt(1) == self:GetEnt(2) then
			SavedPos = self:GetPos(2)
		end
		if mode == 9 then
			self:DoConstraint(mode)
		else
			if moving then
				if CLIENT then
					self:ReleaseGhostEntity()
					return true
				end
				if SERVER and !game.SinglePlayer() then
					self:ReleaseGhostEntity()
				end
				self:DoMove()
			end
			if rotating then
				self:StartRotate()
				self:SetStage(2)
			else
				self:DoConstraint(mode)
			end
		end
	elseif stage == 2 then
		self:DoConstraint(mode)
	end
	return true
end

function TOOL:WithinABit(v1, v2)
	local tol = 0.1
	local da = v1.x-v2.x
	local db = v1.y-v2.y
	local dc = v1.z-v2.z
	if da < tol and da > -tol and db < tol and db > -tol and dc < tol and dc > -tol then
		return true
	else
		da = v1.x+v2.x
		db = v1.y+v2.y
		dc = v1.z+v2.z
		if da < tol and da > -tol and db < tol and db > -tol and dc < tol and dc > -tol then
			return true
		else
			return false
		end
	end
end

function TOOL:UpdateCustomGhost(ghost, player, offset)
	if ghost == nil then return end
	if !IsValid(ghost) then ghost = nil return end
	local tr = util.GetPlayerTrace(player, player:GetAimVector())
	local trace = util.TraceLine(tr)
	if !trace.Hit then return end
	local Ang1, Ang2 = self:GetNormal(1):Angle(), (trace.HitNormal * -1):Angle()
	local TargetAngle = self:GetEnt(1):AlignAngles(Ang1, Ang2)
	self.GhostEntity:SetPos(self:GetEnt(1):GetPos())
	if self:GetClientNumber("autorotate") == 1 then
		TargetAngle.p = (math.Round(TargetAngle.p / 45)) * 45
		TargetAngle.r = (math.Round(TargetAngle.r / 45)) * 45
		TargetAngle.y = (math.Round(TargetAngle.y / 45)) * 45
	end
	self.GhostEntity:SetAngles(TargetAngle)
	local TraceNormal = trace.HitNormal
	local offsetpercent	= self:GetClientNumber("offsetpercent") == 1
	local NewOffset = offset
	if offsetpercent then
		local ent = trace.Entity
		local glower = ent:OBBMins()
		local gupper = ent:OBBMaxs()
		local height = math.abs(gupper.z - glower.z) -0.5
		if self:WithinABit(TraceNormal, ent:GetForward()) then
			height = math.abs(gupper.x - glower.x) -0.5
		elseif self:WithinABit(TraceNormal, ent:GetRight()) then
			height = math.abs(gupper.y - glower.y) -0.5
		end
		NewOffset = NewOffset / 100
		NewOffset = NewOffset * height
	end
	local TranslatedPos = ghost:LocalToWorld(self:GetLocalPos(1))
	local TargetPos = trace.HitPos + (self:GetEnt(1):GetPos() - TranslatedPos) + (TraceNormal*NewOffset)
	self.GhostEntity:SetPos(TargetPos)
end

function TOOL:Think()
	local ply = self:GetOwner()
	local wep = ply:GetActiveWeapon()
	if !wep:IsValid() or wep:GetClass() != "gmod_tool" or ply:GetInfo("gmod_toolmode") != "precision" then return end
	if self:NumObjects() < 1 then return end
	local Ent1 = self:GetEnt(1)
	if SERVER then
		if !IsValid(Ent1) then
			self:ClearObjects()
			return
		end
	end
	local mode = self:GetClientNumber("mode")
	if self:NumObjects() == 1 and mode != 2 then
		if ((self:GetClientNumber("move") == 1 and mode >= 3) or mode == 3) then
			if mode <= 8 then
				local offset = math.Clamp(self:GetClientNumber("offset"), -5000, 5000)
				self:UpdateCustomGhost(self.GhostEntity, self:GetOwner(), offset)
			end
		end
	else
		local rotate = (self:GetClientNumber("rotate") == 1 and mode != 1) or mode == 2
		if (SERVER and rotate and mode <= 8 and self.realdegrees) then
			local offset = math.Clamp(self:GetClientNumber("offset"), -5000, 5000)
			local Phys1 = self:GetPhys(1)
			if !IsValid(Phys1) then return end
			local cmd = self:GetOwner():GetCurrentCommand()
			local rotation = self:GetClientNumber("rotation")
			if (rotation < 0.02) then rotation = 0.02 end
			local degrees = cmd:GetMouseX() * 0.02
			local newdegrees = 0
			local changedegrees = 0
			local angle = 0
			if self:GetOwner():KeyDown(IN_RELOAD) then
				self.realdegreesY = self.realdegreesY + degrees
				newdegrees =  self.realdegreesY - ((self.realdegreesY + (rotation/2)) % rotation)
				changedegrees = self.lastdegreesY - newdegrees
				self.lastdegreesY = newdegrees
				angle = Phys1:RotateAroundAxis(self.axisY , changedegrees)
			elseif self:GetOwner():KeyDown(IN_ATTACK2) then
				self.realdegreesZ = self.realdegreesZ + degrees
				newdegrees =  self.realdegreesZ - ((self.realdegreesZ + (rotation/2)) % rotation)
				changedegrees = self.lastdegreesZ - newdegrees
				self.lastdegreesZ = newdegrees
				angle = Phys1:RotateAroundAxis(self.axisZ , changedegrees)
			else
				self.realdegrees = self.realdegrees + degrees
				newdegrees =  self.realdegrees - ((self.realdegrees + (rotation/2)) % rotation)
				changedegrees = self.lastdegrees - newdegrees
				self.lastdegrees = newdegrees
				angle = Phys1:RotateAroundAxis(self.axis , changedegrees)
			end
			Phys1:SetAngles(angle)
			if ((self:GetClientNumber("move") == 1 and mode >= 3) or mode == 3) then
				local WPos2 = self:GetPos(2)
				local Ent2 = self:GetEnt(2)
				local Norm2 = self:GetNormal(2)
				local NewOffset = offset
				local offsetpercent	= self:GetClientNumber("offsetpercent") == 1
				if offsetpercent then
					local glower = Ent2:OBBMins()
					local gupper = Ent2:OBBMaxs()
					local height = math.abs(gupper.z - glower.z) -0.5
					if self:WithinABit(Norm2, Ent2:GetForward()) then
						height = math.abs(gupper.x - glower.x) -0.5
					elseif self:WithinABit(Norm2, Ent2:GetRight()) then
						height = math.abs(gupper.y - glower.y) -0.5
					end
					NewOffset = NewOffset / 100
					NewOffset = NewOffset * height
				end
				Norm2 = Norm2 * (-0.0625 + NewOffset)
				local TargetPos = Vector(0, 0, 0)
				if (self:GetEnt(1) == self:GetEnt(2)) then
					TargetPos = SavedPos + (Phys1:GetPos() - self:GetPos(1)) + (Norm2)
				else
					TargetPos = WPos2 + (Phys1:GetPos() - self:GetPos(1)) + (Norm2)
				end
				Phys1:SetPos(TargetPos)
			else
				local TargetPos = (Phys1:GetPos() - self:GetPos(1)) + self.OldPos
				Phys1:SetPos(TargetPos)
			end
			Phys1:Wake()
		end
	end
end

function TOOL:Nudge(trace, direction)
	local ent = trace.Entity
	if !IsValid(ent) or ent:IsPlayer() then return false end
	if CLIENT then return true end
	if !trace.PhysicsBone then return end
	local Phys1 = ent:GetPhysicsObjectNum(trace.PhysicsBone)
	if !IsValid(Phys1) then return end
	local offsetpercent	= self:GetClientNumber("nudgepercent") == 1
	local offset = self:GetClientNumber("nudge", 100)
	local max = 100
	if offsetpercent != 1 then
		if offset > max then
			offset = max
		elseif offset < -max then
			offset = -max
		end
	end
	local NewOffset = offset
	if offsetpercent then
		local glower = ent:OBBMins()
		local gupper = ent:OBBMaxs()
		local height = math.abs(gupper.z - glower.z) - 0.5
		if self:WithinABit(trace.HitNormal, ent:GetForward()) then
			height = math.abs(gupper.x - glower.x) - 0.5
		elseif self:WithinABit(trace.HitNormal, ent:GetRight()) then
			height = math.abs(gupper.y - glower.y) - 0.5
		end
		NewOffset = NewOffset / 100
		local cap = math.floor(max / height)
		if NewOffset > cap then
			NewOffset = cap
		elseif NewOffset < -cap then
			NewOffset = -cap
		end
		NewOffset = NewOffset * height
	end
	if self:GetClientNumber("entirecontrap") == 1 then
		local NumApp = 0
		local TargetEnts = {}
		local EntsTab = {}
		local ConstsTab = {}
		GetAllEnts(ent, TargetEnts, EntsTab, ConstsTab)
		for key, CurrentEnt in pairs(TargetEnts) do
			if IsValid(CurrentEnt) then
				local CurrentPhys = CurrentEnt:GetPhysicsObject()
				if IsValid(CurrentPhys) then
					local TargetPos = CurrentPhys:GetPos() + trace.HitNormal * NewOffset * direction
					CurrentPhys:SetPos(TargetPos)
					CurrentPhys:Wake()
				elseif CurrentEnt:GetMoveType() == MOVETYPE_NONE then
					local TargetPos = CurrentEnt:GetPos() + trace.HitNormal * NewOffset * direction
					CurrentEnt:SetPos(TargetPos)
				end
			end
			NumApp = NumApp + 1
		end
		self:SendMessage(NumApp.." Prop(s) bewegt.")
	else
		if self:GetClientNumber("nudgeundo") == 1 then
			local oldpos = Phys1:GetPos()
			local function NudgeUndo(Undo, Entity, oldpos)
				if IsValid(Entity) then
					Entity:SetPos(oldpos)
					if MG and MG.EnableAntiPropMinge and MG.CheckForStuckingPlayers(Entity) then
						if !MG.IsProtected(Entity) then
							MG.EnableProtectionMode(Entity)
							MG.SetProtected(Entity, true)
						end
					end
				end
			end
			undo.Create("Präzision: Bewegung")
				undo.SetPlayer(self:GetOwner())
				undo.AddFunction(NudgeUndo, ent, oldpos)
			undo.Finish()
		end
		local TargetPos = Phys1:GetPos() + trace.HitNormal * NewOffset * direction
		if IsValid(Phys1) then
			Phys1:SetPos(TargetPos)
			Phys1:Wake()
		end
		if ent:GetMoveType() == MOVETYPE_NONE then
			ent:SetPos(TargetPos)
		end
		self:SendMessage("Prop bewegt.")
	end
	return true
end

function TOOL:RightClick(trace)
	local rotate = self:GetClientNumber("rotate") == 1
	local mode = self:GetClientNumber("mode")
	if ((mode == 2 and self:NumObjects() == 1) or (rotate and self:NumObjects() == 2)) then
		if CLIENT then return false end
	else
		return self:Nudge(trace, -1)
	end
end

function TOOL:Reload(trace)
	local rotate = self:GetClientNumber("rotate") == 1
	local mode = self:GetClientNumber("mode")
	if ((mode == 2 and self:NumObjects() == 1) or (rotate and self:NumObjects() == 2)) then
		if CLIENT then return false end
	else
		return self:Nudge(trace, 1)
	end
end

if CLIENT then
	language.Add("tool.precision.name", "Präzisionswerkzeug")
	language.Add("tool.precision.desc", "Bewegt/Schränkt Props.")

	language.Add("tool.precision.left", "Bewegen/Anwenden")
	language.Add("tool.precision.right", "Drücken")
	language.Add("tool.precision.reload", "Ziehen")
	language.Add("tool.precision.left_1", "Wähle das zweite Element aus. Bei Aktivierung wird das erste Element, das Zweite bewegen können. (Waffe wechseln um diese Aktion rückgängig zu machen)")
	language.Add("tool.precision.left_2", "Rotation aktiviert: Biege deinen Blick nach links/rechts, um das Prop zu drehen. (Rechtsklick oder Nachladen halten, um die Drehrichtung zu ändern)")

	language.Add("Undone_Präzision: Verbinden", "Undone Präzision: Verbinden")
	language.Add("Undone_Präzision: Schiene", "Undone Präzision: Schiene")
	language.Add("Undone_Präzision: Rotieren", "Undone Präzision: Rotieren")
	language.Add("Undone_Präzision: Bewegung", "Undone Präzision: Bewegung")
	language.Add("Undone_Präzision: Vereinen", "Undone Präzision: Vereinen")
	language.Add("Undone_Präzision: Achse", "Undone Präzision: Achse")
	language.Add("Undone_Präzision: Ballsocket", "Undone Präzision: Ballsocket")
	language.Add("Undone_Präzision: Erweiterter Ballsocket", "Undone Präzision: Erweiterter Ballsocket")

	language.Add("tool.precision.nudge", "Drück/Zieh-Distanz")

	language.Add("tool.precision.nudgepercent", "Drücken/Ziehen als Prozentsatz(%) der Zieltiefe")
	language.Add("tool.precision.nudgepercent.help", "Ausgewählt = Benutze Prozente der Breite des ausgewählten Props beim Drücken/Ziehen\n\nNicht ausgewählt = Verwende exakte Einheiten beim Drücken/Ziehen")

	language.Add("tool.precision.move", "Prop bewegen")
	language.Add("tool.precision.move.help", "Deaktiviere diese Option, um das ausgewählte Prop nicht zu verschieben.")

	language.Add("tool.precision.rotate", "Prop rotieren (Rotation nach Bewegung)")
	language.Add("tool.precision.rotate.help", "Deaktiviere diese Option, um das ausgewählte Prop nicht zu rotieren.")

	language.Add("tool.precision.offset", "Schnappdistanz")
	language.Add("tool.precision.offset.help", "Distanzvorlauf zwischen verbundenen Props. Negative Werte eingeben für Einsatz bei Bewegung.")

	language.Add("tool.precision.rotation", "Schnapprotierung (Maß)")
	language.Add("tool.precision.rotation.help", "Dreht das Prop zu bestimmten Maßen(Grad).")

	language.Add("tool.precision.nocollide", "Kollision des Props deaktivieren")
	language.Add("tool.precision.nocollide.help", "Deaktiviert die Kollision für Paare von Props.\n\nEs gibt derzeitig keinen Weg, dies rückgängig zu machen.")

	language.Add("tool.precision.autorotate", "Automatisch nach Welt ausrichten (45 Grad-Winkel)")
	language.Add("tool.precision.autorotate.help", "Dreht das erste ausgewählte Prop auf die nächste Weltachse.\n\nÄhnlich wie beim Halten der Sprinttaste, während man mit der Physics Gun ein Prop rotiert")

	language.Add("tool.precision.nocollideall", "Nur mit Spielern kollidieren")
	language.Add("tool.precision.nocollideall.help", "Das Prop kollidiert ausschließlich nur noch mit Spielern.\n\nAchtung: Lasse das Prop nicht durch die Welt fallen!")

	language.Add("tool.precision.physdisable", "Physik des Props deaktivieren")
	language.Add("tool.precision.physdisable.help", "Deaktiviert die Physik des Props\nSchwerkraft und Treffbarkeit nicht betroffen.")

	language.Add("tool.precision.allowphysgun", "Physics Gun-Benutzung auf physikdeaktivierten Props erlauben")
	language.Add("tool.precision.allowphysgun.help", "Standardmäßig deaktiviert um Unfälle zu vermeiden.\n\nAktiviere diese Option um Props nach Physikdeaktivierung mit der Physics Gun verschieben zu können.\n(Könnte Schaden an Konstruktionen anrichten)")

	language.Add("tool.precision.allowphysgun2", "Erweitert: Physics Gun-Benutzung auf vereinte Props erlauben")
	language.Add("tool.precision.allowphysgun2.help", "Standardmäßig deaktiviert um Unfälle zu vermeiden.\n\nNutze dies um mit der Vereinungshierarchie rumzuspielen.")

	language.Add("tool.precision.freemove", "Freie Bewegung")
	language.Add("tool.precision.freemove.help", "Nur relative Position festigen.")

	language.Add("tool.precision.entirecontrap", "Alle Physikobjekte von Prop auswählen")
	language.Add("tool.precision.entirecontrap.help", "Das Prop wird mit all seinen Verbindungen ausgewählt.\nFunktioniert nur mit Anwenden und Drücken/Ziehen\nNicht rückgängig machbar.")

	language.Add("tool.precision.forcelimit", "Maximale Stärke")
	language.Add("tool.precision.forcelimit.help", "Die Verbindung löst sich, wenn die Kräftewirkung den eingestellen Wert überschreiten.\n\nSetze den Wert auf 0, um die Verbindung unzerstörbar zu machen.")

	language.Add("tool.precision.torquelimit", "Maximaler Drehmoment")
	language.Add("tool.precision.torquelimit.help", "Die Verbindung löst sich, wenn der Drehmoment den eingestellen Wert überschreiten.\n\nSetze den Wert auf 0, um die Verbindung unzerstörbar zu machen.")

	language.Add("tool.precision.sliderfix", "Schienenstabilisierung deaktivieren")
	language.Add("tool.precision.sliderfix.help", "Das Deaktivieren dieser Funktion kann zu ungewünschten Nebeneffekten führen.\nBenutzung auf eigene Gefahr!")

	local showgenmenu = 0
	local ConVarsDefault = TOOL:BuildConVarList()
	local function AddDefControls(Panel)
		timer.Simple(0, function()
			local ply = LocalPlayer()
			if !IsValid(ply) then
				timer.Simple(0.1, function()
					AddDefControls(Panel)
				end)
				return
			end
			Panel:ClearControls()
			Panel:AddControl("Header", {Description = "#tool.precision.desc"})
			Panel:AddControl("ComboBox", {Label = "#Presets", MenuButton = 1, Folder = "precision", Options = {["#preset.default"] = ConVarsDefault}, CVars = table.GetKeys(ConVarsDefault)})
			Panel:AddControl("Slider", {Label = "#tool.precision.nudge",
			Type = "Float",
			Min	= 1,
			Max	= 100,
			Command = "precision_nudge"}):SetDecimals(4)
			Panel:AddControl("Checkbox", {Label = "#tool.precision.nudgepercent", Command = "precision_nudgepercent", Help = true})
			local user = ply:GetInfoNum("precision_user", 0)
			local mode = ply:GetInfoNum("precision_mode", 0)
			local list = vgui.Create("DListView")
			local height = 187
			if user < 2 then
				height = 135
			elseif user < 3 then
				height = 170
			end
			list:SetSize(30, height)
			list:AddColumn("Werkzeug-Modi")
			list:SetMultiSelect(false)
			function list:OnRowSelected(id, line)
				if !(mode == id) then
					RunConsoleCommand("precision_setmode", id)
				end
			end
			if mode == 1 then
				list:AddLine(" 1 ->Anwenden<- (Konfig. direkt beim Prop anwenden)")
			else
				list:AddLine(" 1   Anwenden   (Konfig. direkt beim Prop anwenden)")
			end
			if mode == 2 then
				list:AddLine(" 2 ->Rotieren<- (Rotiere ein Prop ohne es zu bewegen)")
			else
				list:AddLine(" 2   Rotieren   (Rotiere ein Prop ohne es zu bewegen)")
			end
			if mode == 3 then
				list:AddLine(" 3 ->Bewegen<- (Bewege Props näher zueinander)")
			else
				list:AddLine(" 3   Bewegen   (Bewege Props näher zueinander)")
			end
			if mode == 4 then
				list:AddLine(" 4 ->Verbinden<-")
			else
				list:AddLine(" 4   Verbinden")
			end
			if mode == 5 then
				list:AddLine(" 5 ->Achse<-")
			else
				list:AddLine(" 5   Achse")
			end
			if mode == 6 then
				list:AddLine(" 6 ->Ballsocket<-")
			else
				list:AddLine(" 6   Ballsocket")
			end
			if user >= 2 then
				if mode == 7 then
					list:AddLine(" 7 ->Erweiterter Ballsocket<-")
				else
					list:AddLine(" 7   Erweiterter Ballsocket")
				end
				if mode == 8 then
					list:AddLine(" 8 ->Schiene<-")
				else
					list:AddLine(" 8   Schiene")
				end
			end
			if user >= 3 then
				if mode == 9 then
					list:AddLine(" 9 ->Vereinen<- (Wie Verbinden, aber ohne Kollision)")
				else
					list:AddLine(" 9   Vereinen   (Wie Verbinden, aber ohne Kollision)")
				end
			end
			if mode == 10 then
				list:AddLine("10 ->Säuberung<- (Entfernt Verbindungen & Co.)")
			else
				list:AddLine("10   Säuberung   (Entfernt Verbindungen & Co.)")
			end
			list:SortByColumn(1)
			Panel:AddItem(list)
			if mode >= 4 and mode <= 8 then
				Panel:AddControl("Checkbox", {Label = "#tool.precision.move", Command = "precision_move", Help = true})
			end
			if mode >= 3 and mode <= 8 then
				Panel:AddControl("Checkbox", {Label = "#tool.precision.rotate", Command = "precision_rotate", Help = true})
				Panel:AddControl("Slider", {Label = "#tool.precision.offset",
				Type = "Float",
				Min	= 0,
				Max	= 10,
				Command = "precision_offset",
				Help = true})
				Panel:AddControl("Checkbox", {Label = "Schnappdistanz als Prozentsatz(%) der Zieltiefe", Command = "precision_offsetpercent"})
			end
			if mode >= 2 and mode <= 8 then
				Panel:AddControl("Slider", {Label = "#tool.precision.rotation",
				Type = "Float",
				Min = 0.02,
				Max	= 90,
				Command = "precision_rotation",
				Help = true}):SetDecimals(4)
			end
			if user >= 2 or mode == 1 then
				if (mode >= 3 and mode <= 8) or mode == 1 then
					Panel:AddControl("Checkbox", {Label = "#tool.precision.autorotate", Command = "precision_autorotate", Help = true})
				end
				if mode == 1 then
					Panel:AddControl("Checkbox", {Label = "Prop-Schatten deaktivieren", Command = "precision_shadowdisable"})
				end
			end
			if mode <= 8 then
				Panel:AddControl("Checkbox", {Label = "Prop einfrieren", Command = "precision_freeze"})
				if mode >= 3 and mode <= 8 then
					Panel:AddControl("Checkbox", {Label = "#tool.precision.nocollide", Command = "precision_nocollide", Help = true})
				end
			end
			if user >= 3 then
				if mode == 1 then
					Panel:AddControl("Checkbox", {Label = "#tool.precision.nocollideall", Command = "precision_nocollideall", Help = true})
					Panel:AddControl("Checkbox", {Label = "#tool.precision.physdisable", Command = "precision_physdisable", Help = true})
					Panel:AddControl("Checkbox", {Label = "#tool.precision.allowphysgun", Command = "precision_allowphysgun", Help = true})
				end
				if mode == 9 then
					Panel:AddControl("Checkbox", {Label = "#tool.precision.allowphysgun2", Command = "precision_allowphysgun", Help = true})
				end
			end
			if user >= 2 then
				if (mode >= 4 and mode <= 7) then
					Panel:AddControl("Slider", {Label = "#tool.precision.forcelimit",
					Type = "Float",
					Min	= 0,
					Max	= 5000,
					Command = "precision_forcelimit",
					Help = true})
				end
				if mode == 5 or mode == 6 or mode == 7 then
					Panel:AddControl("Slider", {Label = "#tool.precision.torquelimit",
					Type = "Float",
					Min	= 0,
					Max	= 5000,
					Command = "precision_torquelimit",
					Help = true})
				end
			end
			if mode == 5 then
				Panel:AddControl("Slider", {Label = "Achsenreibung",
				Type = "Float",
				Min	= 0,
				Max	= 100,
				Command = "precision_friction"})
			end
			if mode == 7 then
				Panel:AddControl("Slider", {Label = "X-Rotation Minimum",
				Type = "Float",
				Min	= -180,
				Max	= 180,
				Command = "precision_XRotMin"})
				Panel:AddControl("Slider", {Label = "X-Rotation Maximum",
				Type = "Float",
				Min	= -180,
				Max	= 180,
				Command = "precision_XRotMax"})
				Panel:AddControl("Slider", {Label = "Y-Rotation Minimum",
				Type = "Float",
				Min	= -180,
				Max	= 180,
				Command = "precision_YRotMin"})
				Panel:AddControl("Slider", {Label = "Y-Rotation Maximum",
				Type = "Float",
				Min	= -180,
				Max	= 180,
				Command = "precision_YRotMax"})
				Panel:AddControl("Slider", {Label = "Z-Rotation Minimum",
				Type = "Float",
				Min	= -180,
				Max	= 180,
				Command = "precision_ZRotMin"})
				Panel:AddControl("Slider", {Label = "Z-Rotation Maximum",
				Type = "Float",
				Min = -180,
				Max = 180,
				Command = "precision_ZRotMax"})
				Panel:AddControl("Slider", {Label = "X-Rotation Reibung",
				Type = "Float",
				Min	= 0,
				Max	= 100,
				Command = "precision_XRotFric"})
				Panel:AddControl("Slider", {Label = "Y-Rotation Reibung",
				Type = "Float",
				Min	= 0,
				Max	= 100,
				Command = "precision_YRotFric"})
				Panel:AddControl("Slider", {Label = "Z-Rotation Reibung",
				Type = "Float",
				Min	= 0,
				Max	= 100,
				Command = "precision_ZRotFric"})
				Panel:AddControl("Checkbox", {Label = "#tool.precision.freemove", Command = "precision_freemove", Help = true})
			end
			if mode == 8 then
				Panel:AddControl("Slider", {Label = "Schienenbreite",
				Type = "Float",
				Min	= 0,
				Max	= 10,
				Command = "precision_width"})
				Panel:AddControl("Checkbox", {Label = "#tool.precision.sliderfix", Command = "precision_disablesliderfix", Help = true})
			end
			if mode == 10 then
				Panel:AddControl("Label", {Text = "Dieser Modus wird Folgendes entfernen:"})
				Panel:AddControl("Checkbox", {Label = "Kollisionen", Command = "precision_removal_nocollide"})
				Panel:AddControl("Checkbox", {Label = "Verbindungen", Command = "precision_removal_weld"})
				Panel:AddControl("Checkbox", {Label = "Achsen", Command = "precision_removal_axis"})
				Panel:AddControl("Checkbox", {Label = "Ballsockets", Command = "precision_removal_ballsocket"})
				Panel:AddControl("Checkbox", {Label = "Erweiterte Ballsockets", Command = "precision_removal_advballsocket"})
				Panel:AddControl("Checkbox", {Label = "Schienen", Command = "precision_removal_slider"})
				Panel:AddControl("Checkbox", {Label = "Vereinte Props", Command = "precision_removal_parent"})
				Panel:AddControl("Checkbox", {Label = "Weiteres", Command = "precision_removal_other"})
				Panel:AddControl("Label", {Text = "(Weiteres = Seile, Windungen, Hydraulik, Motoren)"})
				Panel:AddControl("Button", {Label = "Alle auswählen", Command = "precision_removal_all"})
				Panel:AddControl("Button", {Label = "Nichts auswählen", Command = "precision_removal_none"})
			end
			if user >= 2 then
				Panel:AddControl("Checkbox", {Label = "#tool.precision.entirecontrap", Command = "precision_entirecontrap", Help = true})
			end
			if showgenmenu == 1 then
				Panel:AddControl("Button", {Label = "\\/ Erweiterte Werkzeugseinstellungen \\/", Command = "precision_generalmenu"})
				local params = {Label = "Nutzerlevel", MenuButton = "0", Height = 67, Options = {}}
				if user == 1 then
					params.Options[" 1 ->Normal<-"] = {precision_setuser = "1"}
				else
					params.Options[" 1   Normal"] = {precision_setuser = "1"}
				end
				if user == 2 then
					params.Options[" 2 ->Erweitert<-"] = {precision_setuser = "2"}
				else
					params.Options[" 2   Erweitert"] = {precision_setuser = "2"}
				end
				if user == 3 then
					params.Options[" 3 ->Experimentell<-"] = {precision_setuser = "3"}
				else
					params.Options[" 3   Experimentell"] = {precision_setuser = "3"}
				end
				Panel:AddControl("ListBox", params)
				Panel:AddControl("Checkbox", {Label = "Werkzeugbenachrichtigungen erlauben", Command = "precision_enablefeedback"})
				Panel:AddControl("Checkbox", {Label = "Chat/Bildschirm-Benachrichtigungen erlauben", Command = "precision_chatfeedback"})
				Panel:AddControl("Checkbox", {Label = "Drücken/Ziehen rückgängig machbar", Command = "precision_nudgeundo"})
				Panel:AddControl("Checkbox", {Label = "Bewegen rückgängig machbar", Command = "precision_moveundo"})
				Panel:AddControl("Checkbox", {Label = "Rotieren rückgängig machbar", Command = "precision_rotateundo"})
				Panel:AddControl("Button", {Label = "Konfiguration für ausgewählten Modus zurücksetzen", Command = "precision_defaultrestore"})
			else
				Panel:AddControl("Button", {Label = "-- Erweiterte Werkzeugseinstellungen --", Command = "precision_generalmenu"})
				if user == 1 then
					Panel:AddControl("Label", {Text = "Für erweiterte Nutzungsmöglichkeiten, klicke auf den Knopf über diesem Text."})
				end
			end
		end)
	end

	local function precision_defaults()
		local mode = LocalPlayer():GetInfoNum("precision_mode", 3)
		if mode == 1 then
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_autorotate", 1)
			RunConsoleCommand("precision_shadowdisable", 0)
			RunConsoleCommand("precision_nocollideall", 0)
			RunConsoleCommand("precision_physdisable", 0)
			RunConsoleCommand("precision_allowphysgun", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
		elseif mode == 2 then
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_entirecontrap", 0)
		elseif mode == 3 then
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 1)
			RunConsoleCommand("precision_autorotate", 1)
			RunConsoleCommand("precision_entirecontrap", 0)
		elseif mode == 4 then
			RunConsoleCommand("precision_move", 1)
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 1)
			RunConsoleCommand("precision_autorotate", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
			RunConsoleCommand("precision_forcelimit", 0)
		elseif mode == 5 then
			RunConsoleCommand("precision_move", 1)
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 1)
			RunConsoleCommand("precision_autorotate", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
			RunConsoleCommand("precision_forcelimit", 0)
			RunConsoleCommand("precision_torquelimit", 0)
			RunConsoleCommand("precision_friction", 0)
		elseif mode == 6 then
			RunConsoleCommand("precision_move", 1)
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 1)
			RunConsoleCommand("precision_autorotate", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
			RunConsoleCommand("precision_forcelimit", 0)
			RunConsoleCommand("precision_torquelimit", 0)
		elseif mode == 7 then
			RunConsoleCommand("precision_move", 0)
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 1)
			RunConsoleCommand("precision_autorotate", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
			RunConsoleCommand("precision_forcelimit", 0)
			RunConsoleCommand("precision_torquelimit", 0)
			RunConsoleCommand("precision_XRotMin", 0)
			RunConsoleCommand("precision_XRotMax", 0)
			RunConsoleCommand("precision_YRotMin", 0)
			RunConsoleCommand("precision_YRotMax", 0)
			RunConsoleCommand("precision_ZRotMin", 0)
			RunConsoleCommand("precision_ZRotMax", 0)
			RunConsoleCommand("precision_XRotFric", 0)
			RunConsoleCommand("precision_YRotFric", 0)
			RunConsoleCommand("precision_ZRotFric", 0)
			RunConsoleCommand("precision_freemove", 1)
		elseif mode == 8 then
			RunConsoleCommand("precision_move", 1)
			RunConsoleCommand("precision_rotate", 1)
			RunConsoleCommand("precision_offset", 0)
			RunConsoleCommand("precision_offsetpercent", 1)
			RunConsoleCommand("precision_rotation", 15)
			RunConsoleCommand("precision_freeze", 1)
			RunConsoleCommand("precision_nocollide", 0)
			RunConsoleCommand("precision_autorotate", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
			RunConsoleCommand("precision_width", 1)
			RunConsoleCommand("precision_disablesliderfix", 0)
		elseif mode == 9 then
			RunConsoleCommand("precision_allowphysgun", 0)
			RunConsoleCommand("precision_entirecontrap", 0)
		end
		precision_updatecpanel()
	end
	concommand.Add("precision_defaultrestore", precision_defaults)

	local function precision_genmenu()
		if (showgenmenu == 1) then
			showgenmenu = 0
		else
			showgenmenu = 1
		end
		precision_updatecpanel()
	end
	concommand.Add("precision_generalmenu", precision_genmenu)

	local function precision_setmode(player, tool, args)
		local ply = LocalPlayer()
		local num = tonumber(args[1])
		if num and ply:GetInfoNum("precision_mode", 3) != num then
			num = math.Round(num)
			RunConsoleCommand("precision_mode", num)
			precision_updatecpanel()
		end
	end
	concommand.Add("precision_setmode", precision_setmode)

	local function precision_setuser(player, tool, args)
		local ply = LocalPlayer()
		local num = tonumber(args[1])
		if num and ply:GetInfoNum("precision_user", 3) != num then
			num = math.Round(num)
			local mode = ply:GetInfoNum("precision_mode", 3)
			local new_mode
			if num == 1 and (mode == 7 or mode == 8) then
				new_mode = 10
			end
			if num == 2 and (mode == 7 or mode == 8 or mode == 9) then
				new_mode = 10
			end
			if new_mode then
				RunConsoleCommand("precision_mode", new_mode)
			end
			RunConsoleCommand("precision_user", num)
			precision_updatecpanel()
		end
	end
	concommand.Add("precision_setuser", precision_setuser)

	function precision_updatecpanel()
		local panel = controlpanel.Get("precision")
		if !panel then return end
		AddDefControls(panel)
	end
	concommand.Add("precision_updatecpanel", precision_updatecpanel)

	function TOOL:BuildCPanel()
		AddDefControls(self)
	end

	local function precision_removalall()
		RunConsoleCommand("precision_removal_nocollide", 1)
		RunConsoleCommand("precision_removal_weld", 1)
		RunConsoleCommand("precision_removal_axis", 1)
		RunConsoleCommand("precision_removal_ballsocket", 1)
		RunConsoleCommand("precision_removal_advballsocket", 1)
		RunConsoleCommand("precision_removal_slider", 1)
		RunConsoleCommand("precision_removal_parent", 1)
		RunConsoleCommand("precision_removal_other", 1)
		precision_updatecpanel()
	end
	concommand.Add("precision_removal_all", precision_removalall)

	local function precision_removalnone()
		RunConsoleCommand("precision_removal_nocollide", 0)
		RunConsoleCommand("precision_removal_weld", 0)
		RunConsoleCommand("precision_removal_axis", 0)
		RunConsoleCommand("precision_removal_ballsocket", 0)
		RunConsoleCommand("precision_removal_advballsocket", 0)
		RunConsoleCommand("precision_removal_slider", 0)
		RunConsoleCommand("precision_removal_parent", 0)
		RunConsoleCommand("precision_removal_other", 0)
		precision_updatecpanel()
	end
	concommand.Add("precision_removal_none", precision_removalnone)

	function TOOL:FreezeMovement()
		local stage = self:GetStage()
		if stage == 2 then
			return true
		end
		return false
	end
end

function TOOL:Holster()
	self:ClearObjects()
	self:SetStage(0)
	self:ClearSelection()
end