|
DefineClass.XStickToObjsBase = { |
|
__parents = { "XObjectPlacementHelper" }, |
|
|
|
InXPlaceObjectTool = true, |
|
InXSelectObjectsTool = true, |
|
AllowRotationAfterPlacement = true, |
|
HasSnapSetting = true, |
|
|
|
pivot_obj_id = false, |
|
intersection_class = "WallSlab", |
|
set_angle = true, |
|
} |
|
|
|
function XStickToObjsBase:StartMoveObjects(mouse_pos, objects) |
|
local cur_pos = GetTerrainCursor() |
|
local bestIp = false |
|
local bestId = -1 |
|
local eye = camera.GetEye() |
|
local cursor = ScreenToGame(mouse_pos) |
|
local sp = eye |
|
local ep = (cursor - eye) * 1000 + cursor |
|
self.init_move_positions = {} |
|
self.init_orientations = {} |
|
for i, o in ipairs(objects) do |
|
local hisPos = o:GetPos() |
|
if not hisPos:IsValid() then |
|
o:SetPos(cur_pos) |
|
hisPos = cur_pos |
|
end |
|
self.init_move_positions[i] = hisPos |
|
self.init_orientations[i] = { o:GetOrientation() } |
|
|
|
local ip1, ip2 = ClipSegmentWithBox3D(sp, ep, o) |
|
if ip1 and (bestId == -1 or IsCloser(sp, ip1, bestIp)) then |
|
bestIp = ip1 |
|
bestId = i |
|
end |
|
end |
|
|
|
if bestId == -1 then |
|
bestId = 1 |
|
end |
|
|
|
self.pivot_obj_id = bestId |
|
self.init_drag_position = objects[bestId]:GetPos():SetTerrainZ() |
|
end |
|
|
|
function XStickToObjsBase:MoveObjects(mouse_pos, objects) |
|
local vMove = (GetTerrainCursor() - self.init_drag_position):SetZ(0) |
|
for i, obj in ipairs(objects) do |
|
local offset = self.init_move_positions[i] - self.init_move_positions[self.pivot_obj_id] |
|
if not offset:z() then |
|
offset = offset:SetZ(0) |
|
end |
|
local eye = camera.GetEye() |
|
local cursor = ScreenToGame(mouse_pos) |
|
local sp = eye + offset |
|
local ep = (cursor - eye) * 1000 + cursor + offset |
|
local objs = IntersectObjectsOnSegment(sp, ep, 0, self.intersection_class, function(o) |
|
if not o.isVisible then |
|
return rawget(o, "wall_obj") == obj |
|
end |
|
return true |
|
end) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if objs and #objs > 0 then |
|
local closest = objs[1] |
|
local p1, p2 = ClipSegmentWithBox3D(sp, ep, closest) |
|
local ip = closest:GetPos() |
|
if p1 then |
|
ip = p1 == sp and p2 or p1 |
|
end |
|
local angle = closest:GetAngle() |
|
local x, y, z |
|
if XEditorSettings:GetSnapEnabled() then |
|
x, y, z, angle = WallWorldToVoxel(ip:x(), ip:y(), ip:z(), angle) |
|
x, y, z = WallVoxelToWorld(x, y, z, angle) |
|
else |
|
x, y, z = ip:xyz() |
|
end |
|
if IsKindOf(obj, "AlignedObj") then |
|
obj:AlignObj(point(x, y, z), self.set_angle and angle or nil) |
|
else |
|
if self.set_angle then |
|
obj:SetPosAngle(x, y, z, angle) |
|
else |
|
obj:SetPos(x, y, z) |
|
end |
|
end |
|
|
|
else |
|
local pos = (self.init_move_positions[i] + vMove):SetTerrainZ() |
|
if IsKindOf(obj, "AlignedObj") then |
|
obj:AlignObj(pos) |
|
else |
|
obj:SetPos(pos) |
|
end |
|
end |
|
|
|
end |
|
Msg("EditorCallback", "EditorCallbackMove", objects) |
|
end |
|
|
|
DefineClass.XStickToWallsHelper = { |
|
__parents = { "XStickToObjsBase" }, |
|
|
|
Title = "Stick to walls (Y)", |
|
Description = false, |
|
ActionSortKey = "6", |
|
ActionIcon = "CommonAssets/UI/Editor/Tools/StickToWall.tga", |
|
ActionShortcut = "Y", |
|
UndoOpName = "Stuck %d object(s) to wall", |
|
|
|
intersection_class = "WallSlab", |
|
set_angle = true, |
|
} |
|
|
|
DefineClass.XStickToFloorsHelper = { |
|
__parents = { "XStickToObjsBase" }, |
|
|
|
Title = "Stick to floors (U)", |
|
Description = false, |
|
ActionSortKey = "7", |
|
ActionIcon = "CommonAssets/UI/Editor/Tools/StickToFloor.tga", |
|
ActionShortcut = "U", |
|
UndoOpName = "Stuck %d object(s) to floor", |
|
|
|
intersection_class = "FloorSlab", |
|
set_angle = false, |
|
} |
|
|