Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RDY] Door alignments with TH #1163

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 44 additions & 42 deletions CorsixTH/Lua/dialogs/edit_room.lua
Expand Up @@ -1100,7 +1100,11 @@ local window_floor_blueprint_markers = {
--!param y (int) Y tile position of the door.
--!param wall (string) Name of the wall (either 'north' or 'west').
--!param has_swingdoor Whether the room has a normal door (false) or a swing door (true) as entrance.
--!return whether the door can be placed at the given position and orientation.
--!return bit flags indicating invalid tile position using 1 based power of 2 as this works with ipairs
--!values returned are the enumeration of
--! 4 = centre door in swing door or for single door the value can just be non-zero but uses the same bit of code
--! 2 (door section closer to top of screen) - smaller x or y
--! 8 (door section closer to bottom of screen) - larger x or y
local function checkDoorWalls(x, y, wall, has_swingdoor)
local th = TheApp.map.th

Expand Down Expand Up @@ -1141,43 +1145,43 @@ local function validDoorTile(xpos, ypos, player_id, world)
local th = TheApp.map.th
local tile_flags = th:getCellFlags(xpos, ypos)
-- check builable and own it
if not (tile_flags.buildable or tile_flags.owner == player_id) then return false end
if not tile_flags.buildable and tile_flags.owner ~= player_id then return false end
Copy link
Member

@TheCycoONE TheCycoONE Oct 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still pretty sure you actually want not buildable or not owned by the player here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have found a defect with this logic that I will push out.
tile_flags.buildable will be false for every door when a bench footprint 'passable'/shareable tile is in front of the door, it basically only needs to check its owned by the player, as the rest of the code would check the object footprints for built on tiles

-- any object will cause it to be blocked (ignore litter)
if not(tile_flags.thob == 0 or tile_flags.thob == 62) then return false end
if tile_flags.thob ~= 0 and tile_flags.thob ~= 62 then return false end
-- check if its passable that no object footprint blocks it
if tile_flags.passable then return world:isTileExclusivelyPassable(xpos, ypos, 1) end
return true
end

function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall)
--! Calculate position offsets and door blueprint wall values
--! param x - doors blueprint x value
--! param y - doors blueprint y value
--! param wall - original wall orientation
--! return x - updated x value
--! return y - updated y value
--! return x_mod - offest value to apply to tile count to determine relative position
--! return y_mod - offset value to apply to tile count to determine relatitve position
--! return wall - wall orientation style (only 2 styles)
local function doorWallOffsetCalculations(x, y, wall)
local x_mod
local y_mod
if wall == "south" then
y = y + 1
wall = "north"
x_mod = 2
elseif wall == "east" then
x = x + 1
wall = "west"
y_mod = 2
elseif wall == "north" then
x_mod = 2
else
y_mod = 2
end
return x, y, x_mod, y_mod, wall
--! Calculate position offsets and door blueprint wall values
--! param x - doors blueprint x value
--! param y - doors blueprint y value
--! param wall - original wall orientation
--! return x - updated x value
--! return y - updated y value
--! return x_mod - offest value to apply to tile count to determine relative position
--! return y_mod - offset value to apply to tile count to determine relatitve position
--! return wall - wall orientation style (only 2 styles)
local function doorWallOffsetCalculations(x, y, wall)
local x_mod
local y_mod
if wall == "south" then
y = y + 1
wall = "north"
x_mod = 2
elseif wall == "east" then
x = x + 1
wall = "west"
y_mod = 2
elseif wall == "north" then
x_mod = 2
else
y_mod = 2
end

return x, y, x_mod, y_mod, wall
end

function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall)
local x, y, x_mod, y_mod, wall = doorWallOffsetCalculations(orig_x, orig_y, orig_wall)
local map = TheApp.map.th

Expand Down Expand Up @@ -1252,33 +1256,31 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall)
local world = self.ui.app.world
-- invalid_tile used to select the individual blueprint that is blocked
local invalid_tile = checkDoorWalls(x, y, wall, self.room_type.swing_doors)
self.blueprint_door.valid = invalid_tile == 0
-- Ensure that the door isn't being built on top of an object
local player_id = self.ui.hospital:getPlayerIndex()
if not validDoorTile(x, y, player_id, world) or
not validDoorTile(x2, y2, player_id, world) then
self.blueprint_door.valid = false
invalid_tile = 4
invalid_tile = bitOr(invalid_tile, 4)
end
-- If we're making swing doors two more tiles need to be checked.
if self.room_type.swing_doors then
local dx = x_mod and 1 or 0
local dy = y_mod and 1 or 0
if not validDoorTile(x + dx, y + dy, player_id, world) or
not validDoorTile(x2 + dx, y2 + dy, player_id, world) then
self.blueprint_door.valid = false
invalid_tile = invalid_tile + 8
invalid_tile = bitOr(invalid_tile, 8)
end
if not validDoorTile(x - dx, y - dy, player_id, world) or
not validDoorTile(x2 - dx, y2 - dy, player_id, world) then
self.blueprint_door.valid = false
invalid_tile = invalid_tile + 2
invalid_tile = bitOr(invalid_tile, 2)
end
end


self.blueprint_door.valid = (invalid_tile == 0)

if self.room_type.swing_doors then
for i, animation in ipairs(anim) do
-- calculation here to flag blocked blueprint tiles
-- calculation here to flag blocked blueprint tiles on swing doors for each door tile
animation:setAnimation(self.anims, 126, flags + (hasBit(invalid_tile, i) and 1 or 0) * 16)
end
else
Expand All @@ -1289,8 +1291,8 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall)
local dirfix = orig_wall == "east"
flags = dirfix and flags + 1 or flags
for i = 1, 3 do
local x1 = x_mod and orig_x + (i - x_mod) or orig_x
local y1 = y_mod and orig_y + (i - y_mod) or orig_y
local x1 = x_mod and orig_x + i - x_mod or orig_x
local y1 = y_mod and orig_y + i - y_mod or orig_y
if (i == 2) then
Copy link

@ghost ghost Nov 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove the parentheses on this line.

map:setCell(x1, y1, 4, 24)
else
Expand Down
12 changes: 6 additions & 6 deletions CorsixTH/Lua/dialogs/place_objects.lua
Expand Up @@ -657,17 +657,17 @@ function UIPlaceObjects:setBlueprintCell(x, y)

-- Check 3: The footprint tile should either be buildable or passable, is it?:
if not tile.only_side and is_object_allowed then
is_object_allowed = world:isFootprintTileBuildableOrPassable(xpos, ypos, tile, object_footprint, flag, player_id)
is_object_allowed = world:isFootprintTileBuildableOrPassable(xpos, ypos, tile, object_footprint, flag, player_id)
elseif is_object_allowed then
is_object_allowed = map:getCellFlags(xpos, ypos, flags)[flag] and (player_id == 0 or flags.owner == player_id)
end

-- ignore placed object tile if it is passthrough
if not(tile.passthrough) then
-- ignore placed object tile if it is shareable
if not tile.shareable and is_object_allowed then
-- Check 4: only one object per tile allowed original TH
is_object_allowed = is_object_allowed and map:getCellFlags(xpos, ypos, flags)["thob"] == 0 and (player_id == 0 or flags.owner == player_id)
-- Check 5: only placeable if not on another objects passable footprint unless that too is a passthrough tile
is_object_allowed = is_object_allowed and world:isTileExclusivelyPassable(xpos, ypos, 10)
local objchk = map:getCellFlags(xpos, ypos, flags)["thob"];
-- can build on litter and unoccupied tiles and only placeable if not on another objects passable footprint unless that too is a shareable tile
is_object_allowed = (objchk == 0 or objchk == 62) and world:isTileExclusivelyPassable(xpos, ypos, 10)
end

-- Having checked if the tile is good set its blueprint appearance flag:
Expand Down
8 changes: 4 additions & 4 deletions CorsixTH/Lua/objects/bench.lua
Expand Up @@ -126,19 +126,19 @@ object.usage_animations = {
object.orientations = {
north = {
render_attach_position = { {0, 0}, {-1, 0}, {0, -1} },
footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true, passthrough = true} },
footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true, shareable = true} },
use_position = "passable",
},
east = {
footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true, passthrough = true} },
footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true, shareable = true} },
use_position = "passable",
},
south = {
footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true, passthrough = true} },
footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true, shareable = true} },
use_position = "passable",
},
west = {
footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, passthrough = true} },
footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, shareable = true} },
use_position = "passable",
},
}
Expand Down
42 changes: 35 additions & 7 deletions CorsixTH/Lua/utility.lua
Expand Up @@ -312,10 +312,38 @@ function rangeMapLookup(number, buckets)
assert(false) -- Should never get here.
end

--! Check bit is set
--! param value - value to check set bit of
--! param bit - 0-base index of bit to set 0 - being LSB
function hasBit(value, bit)
local p = 2 ^ bit
return value % (p + p) >= p
end


if _G._VERSION == "Lua 5.3" then
-- use builtins 5.3
function bitOr(value1, value2)
return value1 | value2
end

function hasBit(value, bit)
return (value & 2^bit) ~= 0
end
elseif _G._VERSION == "Lua 5.2" then
-- use builtins 5.2
function bitOr(value1, value2)
return bit32.bor(value1, value2)
end

function hasBit(value, bit)
return bit32.btest(value, 2^bit)
end
else
-- this is a pseudo bitwise OR operation
-- assumes value2 is always a power of 2 (limits carry errors in the addition)
-- mimics the logic of hasBit with the addition if bit not set
function bitOr(value1, value2)
return value1 % (value2 + value2) >= value2 and value1 or value1 + value2
end
--! Check bit is set
--! param value - value to check set bit of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's the cause of the error, but there should be no space between the ! and param here. See https://github.com/CorsixTH/CorsixTH/wiki/Coding-Conventions#ldocgen-syntax

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have 5.3 supported syntax for the bitwise operators in utility.lua - specifically bitOr and the value1 | value2
lua_tokenise needs a slight alteration to include them
operator = Ct(C(P".." + P"<=" + P">=" + P"==" + P"=" + P">>" + P"<<" + S"+-*/^%<>#&|") * Cc"operator"),

Travis still fails as it doesn't use lua 5.3 (yet) - luacheck on utility.lua fails for the same reason, thats not too much more work to build lua in the travis build.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into it! Those changes seem like a prerequisite for this PR, as long as you want to continue using lua 5.3 bitwise operators.

It's unfortunate that we can't continue to automatically build and test lua 5.2, as I'm sure compatibility will degrade if it's not used. That said the situations where the latest CorsixTH was available, but only lua 5.2 are likely very close to 0 these days.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see the issue now. Just my misunderstanding.

I could do something like the following for those functions and as long as 5.3 was compiled with compatability on it would use the bit32 stuff, else fall back to the old stuff or just use the old stuff (which is probably the way to go). Just that bitOr routine isn't a real Or - it Ors a single bit only effectively

bitOr = bit32 and function(value1, value2) return bit32.bor(value1, value2) end or function(value1, value2)
return value1 % (value2 + value2) >= value2 and value1 or value1 + value2
end

hasBit = bit32 and function(value, bit) return bit32.btest(value, 2^bit) end or function (value, bit)
local p = 2 ^ bit
return value % (p + p) >= p
end

--! param bit - 0-base index of bit to set 0 - being LSB
function hasBit(value, bit)
local p = 2 ^ bit
return value % (p + p) >= p
end
end
8 changes: 4 additions & 4 deletions CorsixTH/Lua/world.lua
Expand Up @@ -2711,18 +2711,18 @@ end

--[[ When placing doors and objects the passable tiles need to be checked for overlapping
passable tiles. This presents problems with objects like Bench where the passable tile
is not for exclusive use of the Bench (other objects can share that same tile)
the footprint.passthrough differentiates shareable passable tiles, and exclusive use
is not for exclusive use of the Bench (another object can share that same tile)
the footprint.shareable differentiates shareable passable tiles, and exclusive use
passable tiles (the norm for most objects)]]
--! param x - x map tile position
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly there should be no space between ! and param or ! and returns. returns should be return and the type should be in round brackets.

--! param y - y map tile position
--! param distance - searchable distance for nearby objects
--! returns noolean indicating if exclusively passable or not
--! returns boolean indicating if exclusively passable or not
function World:isTileExclusivelyPassable(x, y, distance)
for o in pairs(self:findAllObjectsNear(x, y, distance)) do
if o and o.footprint then
for _, footprint in pairs(o.footprint) do
if footprint[1] + o.tile_x == x and footprint[2] + o.tile_y == y and footprint.only_passable and not footprint.passthrough then
if footprint[1] + o.tile_x == x and footprint[2] + o.tile_y == y and footprint.only_passable and not footprint.shareable then
return false
end
end
Expand Down