Note however, there are limitations to what the game will allow. As always, when you define walls and elevations for a level in the editor those are fixed in-game. So for example, you want to move a building from one place to another. You cannot build the building with walls as defined in the editor. You have to build them with invisible walls and platforms. Because if you build them withls and move the building, the walls will remain, they will be stripped to showing nothing but they are still there. Another problem is where you are moving/copying to. Unless you specify walls and elevations beforehand in the target location, the building will move over but you can walk right thru it because its got no real walls!
Lastly, when moving structures, most of the time you have to define the target location with "void" tiles. If you do not, the floor textures may conflict with the tile textures and it looks messed up. Also, if you move an area, what is left behind may be emptiness. I gave the ability to "fill" this void by specifying the textures in the input object.
To use this, read the comments in the InputObject. This is function: createAreaMoveInputObj().
UPDATED CODE on 12-26-2014
Here is the code plus helper objects
Code: Select all
function createAreaSqrObj(x, y, width, height, levelNum)
local areaSqrObj = {
["x"] = x,
["y"] = y,
["width"] = width,
["height"] = height,
["levelNum"] = levelNum,
isXYInArea =
function(self, x, y)
if x >= self.x and x < (self.x + self.width) and y >= self.y and y < (self.y + self.height) then
return true
else
return false
end
end,
isAreaSqrIntersect =
function(self, areaSqr)
if self.levelNum == areaSqr.levelNum then
local xIntersect = false
local yIntersect = false
if self.x >= areaSqr.x and self.x <= (areaSqr.x + areaSqr.width - 1) or
(self.x + self.width - 1) >= areaSqr.x and (self.x + self.width - 1) <= (areaSqr.x + areaSqr.width - 1) then
xIntersect = true
end
if self.y >= areaSqr.y and self.y <= (areaSqr.y + areaSqr.height - 1) or
(self.y + self.height - 1) >= areaSqr.y and (self.y + self.height - 1) <= (areaSqr.y + areaSqr.height - 1) then
yIntersect = true
end
if xIntersect and yIntersect then
return true
else
return false
end
else
return false
end
end,
apply =
function(self, applyFunc)
for x = self.x, self.x + (self.width - 1) do
for y = self.y, self.y + (self.height - 1) do
applyFunc(x, y)
end
end
end
}
return areaSqrObj
end
--[[
**************************************************************************
Area Move Process
Input: AreaMoveInputObj
Output: Copy or movement of all entities in an area
**************************************************************************
]]--
-- 1st index is rotateDegree, 2nd index is facing direction. Value is new facing direction
rotateFacingTbl = {
[0] = {0, 1, 2, 3}, -- no change
[-90] = {3, 0, 1, 2}, -- counter-clockwise
[180] = {2, 3, 0, 1}, -- flip
[90] = {1, 2, 3, 0}, -- clockwise
}
rotateStartTbl = { --1st index = deltaX, 2nd = deltaY
[0] = {0, 0},
[-90] = {0, 1},
[180] = {1, 1},
[90] = {1, 0},
}
rotateXIncTbl = { --1st index = deltaX, 2nd = deltaY
[0] = {1, 0},
[-90] = {0, -1},
[180] = {-1, 0},
[90] = {0, 1},
}
rotateYIncTbl = { --1st index = deltaX, 2nd = deltaY
[0] = {0, 1},
[-90] = {1, 0},
[180] = {0, -1},
[90] = {-1, 0},
}
rototaePillarTbl = { --1st index = deltaX, 2nd = deltaY
[0] = {0, 0},
[-90] = {0, 1},
[180] = {1, 1},
[90] = {1, 0},
}
createAreaMoveInputObj =
function(areaSqr)
local inputObj = {
["areaSqr"] = areaSqr, -- x,y, width, height and level of source area is defined in this object
["deltaX"] = 0, -- Amount to move in the X axis (east west) relative to the source coordinates
["deltaY"] = 0, -- Amount to move in the Y-axis (north south) relative to the source coordinates
["deltaZ"] = 0, -- Amount to elevate (up down) relative to the source elevation
["absX"] = nil, -- Absolute X coordinate (east west) - Both absX and Y must be specified or delta is assumed
["absY"] = nil, -- Absolute Y coordinate (north south). Both absX and Y must be specified or delta is assumed
["newLevelNum"] = nil, -- Level num of where to spawn new objects. Leave nil to stay on same level as source
["rotateDegrees"] = 0, -- Rotation degrees. Valid values are: 0: no rotation, -90: counter-clockwise, 90: clockwise, 180: Flip
["copyFlag"] = "copy", -- "copy" to copy an area, leaving the source untouched.
-- "move" for using setPosition and same IDs as source (some default particles will fail to move using this mode)
-- "moveDS" - moving source to target but creating new IDs. This uses spawn and destroy (no game bugs that I am aware of)
["moveFillObjects"] = {"forest_ground_01"}, -- If moving, each voided square will get these objects spawned to fill the void
["moveFillElev"] = 0 -- The elevation at which to fill the void if moving.
}
return inputObj
end
function areaMoveProcess(inputObj)
local newLevelNum
local targetMap
local newX, newY
local success = true
local bUseAbs = false
-- Verify all the inputs first
if inputObj.absX and inputObj.absY then
bUseAbs = true
end
if inputObj.areaSqr.x < 0 or inputObj.areaSqr.x > 31 or inputObj.areaSqr.y < 0 and inputObj.areaSqr.y > 31 then
print("Area Move Fail!! Input XY out of range:", inputObj.areaSqr.x, inputObj.areaSqr.y)
return false
end
local x2, y2 = (inputObj.areaSqr.x + inputObj.areaSqr.width - 1), (inputObj.areaSqr.y + inputObj.areaSqr.height - 1)
if x2 < 0 or x2 > 31 or y2 < 0 and y2 > 31 then
print("Area Move Fail!! Input width/height out of range. X2,Y2:", x2, y2)
return false
end
if not bUseAbs then
newX, newY = (inputObj.areaSqr.x + inputObj.deltaX), (inputObj.areaSqr.y + inputObj.deltaY)
else
newX, newY = inputObj.absX, inputObj.absY
end
if newX < 0 or newX > 31 or newY < 0 or newY > 31 then
print("Area Move Fail!! Target XY out of range:", newX, newY)
return false
end
local newX2, newY2 = (newX + inputObj.areaSqr.width - 1), (newY + inputObj.areaSqr.height - 1)
if newX2 < 0 or newX2 > 31 or newY2 < 0 and newY2 > 31 then
print("Area Move Fail!! Target width/height out of range. X2,Y2:", x2, y2)
return false
end
local srcMap = Dungeon.getMap(inputObj.areaSqr.levelNum)
if not srcMap then
print("Area Move Fail!! Source map not found for level:", inputObj.areaSqr.levelNum)
return false
end
if inputObj.newLevelNum then
newLevelNum = inputObj.newLevelNum
else
--No level change
newLevelNum = inputObj.areaSqr.levelNum
end
targetMap = Dungeon.getMap(newLevelNum)
if not targetMap then
print("Area Move Fail!! Target map not found for level:", inputObj.areaSqr.levelNum)
return false
end
if not rotateFacingTbl[inputObj.rotateDegrees] then
print("Area Move Fail!! Invalid rotateDegrees specified. Use: 0, -90, 90 or 180. value specified was:", inputObj.rotateDegrees)
return false
end
local newAreaSqr = lib_scr.script.createAreaSqrObj(newX, newY, inputObj.areaSqr.width, inputObj.areaSqr.height, newLevelNum)
local bIntersect = inputObj.areaSqr:isAreaSqrIntersect(newAreaSqr)
if bIntersect then
print("Area Move Fail!! Input area and target area intersect.")
return false
end
-- OK, do it
local entTbl
local newElev
local newFacing
local startX, startY
if not bUseAbs then
startX = (inputObj.areaSqr.x + inputObj.deltaX) + (rotateStartTbl[inputObj.rotateDegrees][1] * inputObj.areaSqr.width) - rotateStartTbl[inputObj.rotateDegrees][1]
startY = (inputObj.areaSqr.y + inputObj.deltaY) + (rotateStartTbl[inputObj.rotateDegrees][2] * inputObj.areaSqr.height) - rotateStartTbl[inputObj.rotateDegrees][2]
else
startX = inputObj.absX + (rotateStartTbl[inputObj.rotateDegrees][1] * inputObj.areaSqr.width) - rotateStartTbl[inputObj.rotateDegrees][1]
startY = inputObj.absY + (rotateStartTbl[inputObj.rotateDegrees][2] * inputObj.areaSqr.height) - rotateStartTbl[inputObj.rotateDegrees][2]
end
newX = startX
newY = startY
local count = 0
for y = inputObj.areaSqr.y, (inputObj.areaSqr.y + inputObj.areaSqr.height - 1) do
for x = inputObj.areaSqr.x, (inputObj.areaSqr.x + inputObj.areaSqr.width - 1) do
entTbl = srcMap:entitiesAt(x, y)
for ent in entTbl do
newElev = ent.elevation + inputObj.deltaZ
if newElev < -7 or newElev > 7 then
print("Area Move Fail during processing!! Elevation is out of range. Source Elev, Source Elevation, XY:", ent.elevation, x, y)
return false
end
newFacing = rotateFacingTbl[inputObj.rotateDegrees][ent.facing+1]
local name = ent.name
local applyX
local applyY
if string.find(ent.name, "pillar") then
if not string.find(ent.name, "rock_pillar") then
applyX = newX + rototaePillarTbl[inputObj.rotateDegrees][1]
applyY = newY + rototaePillarTbl[inputObj.rotateDegrees][2]
else
applyX = newX
applyY = newY
end
else
applyX = newX
applyY = newY
end
--print("spawn: ",name, newLevelNum, newX, newY, newFacing, newElev)
if inputObj.copyFlag == "copy" then
spawn(ent.name, newLevelNum, applyX, applyY, newFacing, newElev)
elseif inputObj.copyFlag == "move" then
ent:setPosition(applyX, applyY, newFacing, newElev, newLevelNum)
elseif inputObj.copyFlag == "moveDS" then
ent:destroy()
spawn(name, newLevelNum, applyX, applyY, newFacing, newElev)
else
print("Invalid copyFlag value")
return false
end
--[[
if count > 5 then
print("Force abort")
success = false
break
end
]]--
count = count + 1
end
if not inputObj.copyFlag then
for i,name in ipairs(inputObj.moveFillObjects) do
spawn(name, inputObj.areaSqr.levelNum, x, y, 0, inputObj.moveFillElev)
end
end
if not success then
break
end
newX = newX + rotateXIncTbl[inputObj.rotateDegrees][1]
newY = newY + rotateXIncTbl[inputObj.rotateDegrees][2]
end
if not success then
break
end
if rotateYIncTbl[inputObj.rotateDegrees][1] == 0 then
newX = startX
else
newX = newX + rotateYIncTbl[inputObj.rotateDegrees][1]
end
if rotateYIncTbl[inputObj.rotateDegrees][2] == 0 then
newY = startY
else
newY = newY + rotateYIncTbl[inputObj.rotateDegrees][2]
end
end
-- DONE
print("Area Move completed. Number of destroy/spawns done: "..count..", success="..tostring(success))
return success
end
Code: Select all
local areaSqr = lib_scr.script.createAreaSqrObj(0, 0, 7, 7, self.go.level)
local inputObj = commonProc_scr.script.createAreaMoveInputObj(areaSqr)
inputObj.absX = 7
inputObj.absY = 21
inputObj.deltaZ = 1
inputObj.newLevelNum = 6
inputObj.rotateDegrees = 90
inputObj.copyFlag = "moveDS"
local success = commonProc_scr.script.areaMoveProcess(inputObj)
print("Level "..self.go.level.." Area Move. success=", success)