From 08e505218b5e45a4f62a6d9489ed257a6252c47a Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 20 Nov 2016 10:39:15 +1000 Subject: [PATCH 01/13] Door alignments with TH --- CorsixTH/Lua/dialogs/edit_room.lua | 207 +++++++++++++++++++---------- 1 file changed, 136 insertions(+), 71 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 3ecf710ed..6cb6d6b24 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -711,7 +711,13 @@ function UIEditRoom:screenToWall(x, y) -- top corner local x_, _ = self.ui:WorldToScreen(cellx, celly) if x >= x_ then - return cellx + 1 + modifier, celly, "north" + -- correctly reflects (at least origin version) of TH. + -- Swing doors in top corner to the east, actually skip another tile + if swinging then + return cellx + 2 + modifier, celly, "north" + else + return cellx + 1 + modifier, celly, "north" + end else return cellx, celly + 1 + modifier, "west" end @@ -727,7 +733,11 @@ function UIEditRoom:screenToWall(x, y) -- left corner local _, y_ = self.ui:WorldToScreen(cellx, celly) if y >= y_ + 16 then - return cellx + 1, celly, "south" + if swinging and cellx <= rect.x + 2 then + return cellx + 1 + modifier, celly, "south" + else + return cellx + 1, celly, "south" + end else return cellx, celly - 1, "west" end @@ -735,7 +745,11 @@ function UIEditRoom:screenToWall(x, y) -- right corner local _, y_ = self.ui:WorldToScreen(cellx, celly) if y >= y_ + 16 then - return cellx, celly + 1, "east" + if swinging and celly <= rect.y + 2 then + return cellx, celly + 1 + modifier, "east" + else + return cellx, celly + 1, "east" + end else return cellx - 1, celly, "north" end @@ -752,19 +766,22 @@ function UIEditRoom:screenToWall(x, y) return rect.x, celly, "west" elseif (celly == rect.y - 1 or celly == rect.y) and rect.x <= cellx and cellx < rect.x + rect.w then -- north edge - if cellx == rect.x then - cellx = rect.x + 1 + -- correctly reflects (at least origin version) of TH. + -- Swing doors in top corner to the east, actually skip another tile + if swinging and cellx <= rect.x + 2 then + cellx = rect.x + 3 + elseif cellx == rect.x then + cellx = rect.x + 1 + modifier elseif cellx == rect.x + rect.w - 1 then cellx = rect.x + rect.w - 2 end - if swinging and cellx <= rect.x + 1 then - cellx = cellx + 1 - end return cellx, rect.y, "north" elseif (cellx == rect.x + rect.w or cellx == rect.x + rect.w - 1) and rect.y <= celly and celly < rect.y + rect.h then - -- east edge - if celly == rect.y then + -- east edge + if swinging and celly <= rect.y + 1 then + celly = rect.y + 2 + elseif celly == rect.y then celly = rect.y + 1 elseif celly == rect.y + rect.h - 1 then celly = rect.y + rect.h - 2 @@ -773,7 +790,9 @@ function UIEditRoom:screenToWall(x, y) elseif (celly == rect.y + rect.h or celly == rect.y + rect.h - 1) and rect.x <= cellx and cellx < rect.x + rect.w then -- south edge - if cellx == rect.x then + if swinging and cellx <= rect.x + 1 then + cellx = rect.x + 2 + elseif cellx == rect.x then cellx = rect.x + 1 elseif cellx == rect.x + rect.w - 1 then cellx = rect.x + rect.w - 2 @@ -1053,11 +1072,20 @@ function UIEditRoom:setBlueprintRect(x, y, w, h) rect.h = h end +--25 north wall, west +--26 north wall, east +--27 east wall, south +--28 east wall, north +--29 south wall, west +--30 south wall, east +--31 west wall, south +--32 west wall, north +-- single door blue print values matching TH local door_floor_blueprint_markers = { - north = 25, - east = 28, - south = 29, - west = 32, + north = 26, + east = 27, + south = 30, + west = 31 } local window_floor_blueprint_markers = { @@ -1086,62 +1114,84 @@ local function checkDoorWalls(x, y, wall, has_swingdoor) dx = 1 dy = 0 end - + local invalid_tile = 0 if th:getCell(x, y, wall_num) % 0x100 ~= 0 then - return false + invalid_tile = 4 end -- If it is a swing door there are two more locations to check. if has_swingdoor then - if th:getCell(x - dx, y - dy, wall_num) % 0x100 ~= 0 or - th:getCell(x + dx, y + dy, wall_num) % 0x100 ~= 0 then - return false + if th:getCell(x - dx, y - dy, wall_num) % 0x100 ~= 0 then + invalid_tile = invalid_tile | 2 + end + if th:getCell(x + dx, y + dy, wall_num) % 0x100 ~= 0 then + invalid_tile = invalid_tile | 8 end end - return true + return invalid_tile end --! Check whether the given tile can function as a door entry/exit tile. --!param xpos (int) X position of the tile. --!param ypos (int) Y position of the tile. --!param player_id (int) Player id owning the hospital. ---!param flag_names (array) If set, array with two additional required properties. +--!param wall wall facing direction +--!param wall (string) wall facing direction +--!param world wall facing direction --!return Whether the tile is considered to be valid. -local function validDoorTile(xpos, ypos, player_id, flag_names) +local function validDoorTile(xpos, ypos, player_id, wall, world) local th = TheApp.map.th - local tile_flags = th:getCellFlags(xpos, ypos) - if not (tile_flags.buildable or tile_flags.passable or tile_flags.owner == player_id) then return false end - if not flag_names then return true end - return tile_flags[flag_names[1]] and tile_flags[flag_names[2]] + if not (tile_flags.buildable and tile_flags.owner == player_id) then + -- 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.passable then + -- check for any object with a passable tile built within the door footprint + -- drinks machine and reception desk in corridors for example + for o in pairs(world:findAllObjectsNear(xpos, ypos, 1)) do + if o.object_type.id ~= "bench" then + for _, xy in ipairs(o:getWalkableTiles()) do + if xy[1] == xpos and xy[2] == ypos then + return false + end + end + end + end + end + end + return (tile_flags.thob == 0 or tile_flags.thob == 62) end function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) - local x = orig_x - local y = orig_y - local wall = orig_wall - - -- Used to get the adjacent tiles when placing swing doors. - 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 + 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 + + local x, y, x_mod, y_mod, wall = doorWallOffsetCalculations(orig_x, orig_y, orig_wall) local map = TheApp.map.th if self.blueprint_door.anim then if self.room_type.swing_doors then if self.blueprint_door.anim[1] then + -- retrieve the old door position details to reset the blue print + local oldx, oldy, oldx_mod, oldy_mod, old_wall = doorWallOffsetCalculations(self.blueprint_door.floor_x, + self.blueprint_door.floor_y, + self.blueprint_door.wall) -- If we're dealing with swing doors the anim variable is actually a table with three -- identical "doors". for i, anim in ipairs(self.blueprint_door.anim) do @@ -1149,9 +1199,11 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) self.blueprint_door.old_flags[i]) anim:setTag(nil) self.blueprint_door.anim[i] = nil + oldx = oldx_mod and (self.blueprint_door.floor_x + (i - oldx_mod)) or self.blueprint_door.floor_x + oldy = oldy_mod and (self.blueprint_door.floor_y + (i - oldy_mod)) or self.blueprint_door.floor_y + map:setCell(oldx, oldy, 4, 24) end - map:setCell(self.blueprint_door.floor_x, self.blueprint_door.floor_y, 4, 24) - end + end else self.blueprint_door.anim:setAnimation(self.anims, self.blueprint_door.old_anim, self.blueprint_door.old_flags) @@ -1202,49 +1254,62 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) flags = 0 y2 = y2 - 1 end - - self.blueprint_door.valid = checkDoorWalls(x, y, wall, self.room_type.swing_doors) + 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 if self.blueprint_door.valid then -- Ensure that the door isn't being built on top of an object - local flag_names - if wall == "west" then - flag_names = {"buildableNorth", "buildableSouth"} - else - flag_names = {"buildableWest", "buildableEast"} - end local player_id = self.ui.hospital:getPlayerIndex() - - if not validDoorTile(x, y, player_id, flag_names) or - not validDoorTile(x2, y2, player_id, flag_names) then + if not validDoorTile(x, y, player_id, orig_wall, world) or + not validDoorTile(x2, y2, player_id, orig_wall, world) then self.blueprint_door.valid = false + 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, nil) or - not validDoorTile(x2 + dx, y2 + dy, player_id, nil) then + if not validDoorTile(x + dx, y + dy, player_id, orig_wall, world) or + not validDoorTile(x2 + dx, y2 + dy, player_id, orig_wall, world) then self.blueprint_door.valid = false + invalid_tile = invalid_tile | 8 end - if not validDoorTile(x - dx, y - dy, player_id, nil) or - not validDoorTile(x2 - dx, y2 - dy, player_id, nil) then + if not validDoorTile(x - dx, y - dy, player_id, orig_wall, world) or + not validDoorTile(x2 - dx, y2 - dy, player_id, orig_wall, world) then self.blueprint_door.valid = false + invalid_tile = invalid_tile | 2 end end end - if not self.blueprint_door.valid then - flags = flags + 16 -- Use red palette rather than normal palette - end if self.room_type.swing_doors then - for _, animation in ipairs(anim) do - animation:setAnimation(self.anims, 126, flags) + for i, animation in ipairs(anim) do + -- calculation here to flag blocked blueprint tiles + animation:setAnimation(self.anims, 126, flags + ((invalid_tile & 2^i)>0 and 1 or 0)*16) end else - anim:setAnimation(self.anims, 126, flags) + anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0)*16) end - if self.blueprint_door.valid then + if self.room_type.swing_doors then + flags = door_floor_blueprint_markers[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 + if (i == 2) then + map:setCell(x1, y1, 4, 24) + else + if dirfix then + map:setCell(x1, y1, 4, i < 2 and flags or flags - 1) + else + map:setCell(x1, y1, 4, i > 2 and flags or flags - 1) + end + end + end + else map:setCell(self.blueprint_door.floor_x, self.blueprint_door.floor_y, 4, - door_floor_blueprint_markers[orig_wall]) + door_floor_blueprint_markers[orig_wall]) end end From 6b58abeea5036eec907f6576c735aac447551c2e Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 20 Nov 2016 14:36:00 +1000 Subject: [PATCH 02/13] Lua 5.1 compatible logic --- CorsixTH/Lua/dialogs/edit_room.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 6cb6d6b24..fef8e5a03 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1122,10 +1122,10 @@ local function checkDoorWalls(x, y, wall, has_swingdoor) -- If it is a swing door there are two more locations to check. if has_swingdoor then if th:getCell(x - dx, y - dy, wall_num) % 0x100 ~= 0 then - invalid_tile = invalid_tile | 2 + invalid_tile = invalid_tile + 2 end if th:getCell(x + dx, y + dy, wall_num) % 0x100 ~= 0 then - invalid_tile = invalid_tile | 8 + invalid_tile = invalid_tile + 8 end end return invalid_tile @@ -1273,12 +1273,12 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) if not validDoorTile(x + dx, y + dy, player_id, orig_wall, world) or not validDoorTile(x2 + dx, y2 + dy, player_id, orig_wall, world) then self.blueprint_door.valid = false - invalid_tile = invalid_tile | 8 + invalid_tile = invalid_tile + 8 end if not validDoorTile(x - dx, y - dy, player_id, orig_wall, world) or not validDoorTile(x2 - dx, y2 - dy, player_id, orig_wall, world) then self.blueprint_door.valid = false - invalid_tile = invalid_tile | 2 + invalid_tile = invalid_tile + 2 end end end From b640551df725e7aa7348c368e8b59eb810dba31c Mon Sep 17 00:00:00 2001 From: Justin Date: Sun, 20 Nov 2016 14:58:38 +1000 Subject: [PATCH 03/13] More Lua 5.1 compatible changes --- CorsixTH/Lua/dialogs/edit_room.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index fef8e5a03..012307520 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1182,6 +1182,16 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) return x, y, x_mod, y_mod, wall end + local function BitAND(a,b)--Bitwise and + local p,c=1,0 + while a>0 and b>0 do + local ra,rb=a%2,b%2 + if ra+rb>1 then c=c+p end + a,b,p=(a-ra)/2,(b-rb)/2,p*2 + end + return c + end + local x, y, x_mod, y_mod, wall = doorWallOffsetCalculations(orig_x, orig_y, orig_wall) local map = TheApp.map.th @@ -1285,7 +1295,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) if self.room_type.swing_doors then for i, animation in ipairs(anim) do -- calculation here to flag blocked blueprint tiles - animation:setAnimation(self.anims, 126, flags + ((invalid_tile & 2^i)>0 and 1 or 0)*16) + animation:setAnimation(self.anims, 126, flags + (BitAND(invalid_tile,2^i)>0 and 1 or 0)*16) end else anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0)*16) From 5ecd54952f443cf927053f8435bf555312772e04 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 25 Nov 2016 19:30:32 +1000 Subject: [PATCH 04/13] Implemented hasbit as per lua-wiki and placed that function in utility.lua --- CorsixTH/Lua/dialogs/edit_room.lua | 14 ++------------ CorsixTH/Lua/utility.lua | 11 +++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 012307520..43832f06a 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1181,17 +1181,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) end return x, y, x_mod, y_mod, wall end - - local function BitAND(a,b)--Bitwise and - local p,c=1,0 - while a>0 and b>0 do - local ra,rb=a%2,b%2 - if ra+rb>1 then c=c+p end - a,b,p=(a-ra)/2,(b-rb)/2,p*2 - end - return c - end - + local x, y, x_mod, y_mod, wall = doorWallOffsetCalculations(orig_x, orig_y, orig_wall) local map = TheApp.map.th @@ -1295,7 +1285,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) if self.room_type.swing_doors then for i, animation in ipairs(anim) do -- calculation here to flag blocked blueprint tiles - animation:setAnimation(self.anims, 126, flags + (BitAND(invalid_tile,2^i)>0 and 1 or 0)*16) + animation:setAnimation(self.anims, 126, flags + (hasbit(invalid_tile,bit(i+1)) and 1 or 0)*16) end else anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0)*16) diff --git a/CorsixTH/Lua/utility.lua b/CorsixTH/Lua/utility.lua index 4ce9d738c..8c278daa9 100644 --- a/CorsixTH/Lua/utility.lua +++ b/CorsixTH/Lua/utility.lua @@ -311,3 +311,14 @@ function rangeMapLookup(number, buckets) end assert(false) -- Should never get here. end + +-- work around for bitwise operators +-- see http://lua-users.org/wiki/BitwiseOperators +function bit(p) + return 2 ^ (p - 1) -- 1-based indexing +end + +-- Typical call: if hasbit(x, bit(3)) then ... +function hasbit(x, p) + return x % (p + p) >= p +end \ No newline at end of file From 1b06b94bbd9280fd60338b86889ce9dd9c6e2395 Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 1 Dec 2016 16:47:55 +1000 Subject: [PATCH 05/13] Updated utility function, added refactored method to world, updated edit_room/place objects to use the updated method --- CorsixTH/Lua/dialogs/edit_room.lua | 96 ++++++++++++-------------- CorsixTH/Lua/dialogs/place_objects.lua | 8 +++ CorsixTH/Lua/objects/bench.lua | 8 +-- CorsixTH/Lua/utility.lua | 15 ++-- CorsixTH/Lua/world.lua | 29 ++++++++ 5 files changed, 92 insertions(+), 64 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 43832f06a..1d26f8aa7 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1135,34 +1135,30 @@ end --!param xpos (int) X position of the tile. --!param ypos (int) Y position of the tile. --!param player_id (int) Player id owning the hospital. ---!param wall wall facing direction ---!param wall (string) wall facing direction ---!param world wall facing direction +--!param world - reference to world object instance --!return Whether the tile is considered to be valid. -local function validDoorTile(xpos, ypos, player_id, wall, world) +local function validDoorTile(xpos, ypos, player_id, world) local th = TheApp.map.th local tile_flags = th:getCellFlags(xpos, ypos) - if not (tile_flags.buildable and tile_flags.owner == player_id) then - -- 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.passable then - -- check for any object with a passable tile built within the door footprint - -- drinks machine and reception desk in corridors for example - for o in pairs(world:findAllObjectsNear(xpos, ypos, 1)) do - if o.object_type.id ~= "bench" then - for _, xy in ipairs(o:getWalkableTiles()) do - if xy[1] == xpos and xy[2] == ypos then - return false - end - end - end - end - end - end - return (tile_flags.thob == 0 or tile_flags.thob == 62) + -- check builable and own it + if not (tile_flags.buildable or tile_flags.owner == player_id) then return false end + -- 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 + -- 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 @@ -1190,8 +1186,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) if self.blueprint_door.anim[1] then -- retrieve the old door position details to reset the blue print local oldx, oldy, oldx_mod, oldy_mod, old_wall = doorWallOffsetCalculations(self.blueprint_door.floor_x, - self.blueprint_door.floor_y, - self.blueprint_door.wall) + self.blueprint_door.floor_y, self.blueprint_door.wall) -- If we're dealing with swing doors the anim variable is actually a table with three -- identical "doors". for i, anim in ipairs(self.blueprint_door.anim) do @@ -1199,11 +1194,11 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) self.blueprint_door.old_flags[i]) anim:setTag(nil) self.blueprint_door.anim[i] = nil - oldx = oldx_mod and (self.blueprint_door.floor_x + (i - oldx_mod)) or self.blueprint_door.floor_x - oldy = oldy_mod and (self.blueprint_door.floor_y + (i - oldy_mod)) or self.blueprint_door.floor_y + oldx = oldx_mod and self.blueprint_door.floor_x + (i - oldx_mod) or self.blueprint_door.floor_x + oldy = oldy_mod and self.blueprint_door.floor_y + (i - oldy_mod) or self.blueprint_door.floor_y map:setCell(oldx, oldy, 4, 24) end - end + end else self.blueprint_door.anim:setAnimation(self.anims, self.blueprint_door.old_anim, self.blueprint_door.old_flags) @@ -1258,45 +1253,44 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) -- 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 - if self.blueprint_door.valid then - -- 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, orig_wall, world) or - not validDoorTile(x2, y2, player_id, orig_wall, world) then + -- 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 + 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 = 4 + invalid_tile = invalid_tile + 8 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, orig_wall, world) or - not validDoorTile(x2 + dx, y2 + dy, player_id, orig_wall, world) then - self.blueprint_door.valid = false - invalid_tile = invalid_tile + 8 - end - if not validDoorTile(x - dx, y - dy, player_id, orig_wall, world) or - not validDoorTile(x2 - dx, y2 - dy, player_id, orig_wall, world) then - self.blueprint_door.valid = false - invalid_tile = invalid_tile + 2 - 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 end end + if self.room_type.swing_doors then for i, animation in ipairs(anim) do -- calculation here to flag blocked blueprint tiles - animation:setAnimation(self.anims, 126, flags + (hasbit(invalid_tile,bit(i+1)) and 1 or 0)*16) + animation:setAnimation(self.anims, 126, flags + (hasBit(invalid_tile, i) and 1 or 0) * 16) end else - anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0)*16) + anim:setAnimation(self.anims, 126, flags + (invalid_tile ~= 0 and 1 or 0) * 16) end if self.room_type.swing_doors then flags = door_floor_blueprint_markers[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 map:setCell(x1, y1, 4, 24) else diff --git a/CorsixTH/Lua/dialogs/place_objects.lua b/CorsixTH/Lua/dialogs/place_objects.lua index 67f5d7f1a..a71757a16 100644 --- a/CorsixTH/Lua/dialogs/place_objects.lua +++ b/CorsixTH/Lua/dialogs/place_objects.lua @@ -662,6 +662,14 @@ function UIPlaceObjects:setBlueprintCell(x, y) 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 + -- 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) + end + -- Having checked if the tile is good set its blueprint appearance flag: if is_object_allowed then if not tile.invisible then diff --git a/CorsixTH/Lua/objects/bench.lua b/CorsixTH/Lua/objects/bench.lua index bfe405150..cbcbf5442 100644 --- a/CorsixTH/Lua/objects/bench.lua +++ b/CorsixTH/Lua/objects/bench.lua @@ -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} }, + footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = true, invisible = true, passthrough = true} }, use_position = "passable", }, east = { - footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {1, 0, only_passable = true, invisible = true, passthrough = true} }, use_position = "passable", }, south = { - footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {0, 1, only_passable = true, invisible = true, passthrough = true} }, use_position = "passable", }, west = { - footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true} }, + footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, passthrough = true} }, use_position = "passable", }, } diff --git a/CorsixTH/Lua/utility.lua b/CorsixTH/Lua/utility.lua index 8c278daa9..1d8c84fd9 100644 --- a/CorsixTH/Lua/utility.lua +++ b/CorsixTH/Lua/utility.lua @@ -312,13 +312,10 @@ function rangeMapLookup(number, buckets) assert(false) -- Should never get here. end --- work around for bitwise operators --- see http://lua-users.org/wiki/BitwiseOperators -function bit(p) - return 2 ^ (p - 1) -- 1-based indexing -end - --- Typical call: if hasbit(x, bit(3)) then ... -function hasbit(x, p) - return x % (p + p) >= p +--! 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 \ No newline at end of file diff --git a/CorsixTH/Lua/world.lua b/CorsixTH/Lua/world.lua index 857c7fd58..a050c567a 100644 --- a/CorsixTH/Lua/world.lua +++ b/CorsixTH/Lua/world.lua @@ -2708,3 +2708,32 @@ function World:resetSideObjects() end end 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 +passable tiles (the norm for most objects)]] +--! param x - x map tile position +--! param y - y map tile position +--! param distance - searchable distance for nearby objects +--! returns noolean 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 + return false + end + end + else + -- doors don't have a footprint but objects can't be built blocking them either + for _, footprint in pairs(o:getWalkableTiles()) do + if footprint[1] == x and footprint[2] == y then + return false + end + end + end + end + return true +end From cfac14450c6dff116d8d4d6bb0c8e2405355e6b8 Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 2 Oct 2017 10:30:50 +1000 Subject: [PATCH 06/13] Updates based on comments Utility - updated with support for builtins form Lua 5.3/5.2 or workaround fors 5.1 Cleaned up some conditions/checks for readability or that were redundant --- CorsixTH/Lua/dialogs/edit_room.lua | 86 +++++++++++++------------- CorsixTH/Lua/dialogs/place_objects.lua | 12 ++-- CorsixTH/Lua/objects/bench.lua | 8 +-- CorsixTH/Lua/utility.lua | 42 ++++++++++--- CorsixTH/Lua/world.lua | 8 +-- 5 files changed, 93 insertions(+), 63 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 1d26f8aa7..2ede110e0 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -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 @@ -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 -- 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 @@ -1252,13 +1256,11 @@ 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 @@ -1266,19 +1268,19 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) 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 @@ -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 map:setCell(x1, y1, 4, 24) else diff --git a/CorsixTH/Lua/dialogs/place_objects.lua b/CorsixTH/Lua/dialogs/place_objects.lua index a71757a16..9cdf6fced 100644 --- a/CorsixTH/Lua/dialogs/place_objects.lua +++ b/CorsixTH/Lua/dialogs/place_objects.lua @@ -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: diff --git a/CorsixTH/Lua/objects/bench.lua b/CorsixTH/Lua/objects/bench.lua index cbcbf5442..e973187f1 100644 --- a/CorsixTH/Lua/objects/bench.lua +++ b/CorsixTH/Lua/objects/bench.lua @@ -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", }, } diff --git a/CorsixTH/Lua/utility.lua b/CorsixTH/Lua/utility.lua index 1d8c84fd9..53e657f22 100644 --- a/CorsixTH/Lua/utility.lua +++ b/CorsixTH/Lua/utility.lua @@ -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 \ No newline at end of file + + +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 + --! 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 diff --git a/CorsixTH/Lua/world.lua b/CorsixTH/Lua/world.lua index a050c567a..774e333ac 100644 --- a/CorsixTH/Lua/world.lua +++ b/CorsixTH/Lua/world.lua @@ -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 --! 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 From be73b26aae9adae478d4eb8cc2ac867a73febfba Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 3 Oct 2017 22:58:01 +1000 Subject: [PATCH 07/13] removed some warnings from travis and fixed that one condition --- CorsixTH/Lua/dialogs/edit_room.lua | 10 +++++----- CorsixTH/Lua/utility.lua | 8 +++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 2ede110e0..102475e19 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1145,7 +1145,7 @@ 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 and tile_flags.owner ~= player_id then return false end + if not tile_flags.buildable or tile_flags.owner ~= player_id then return false end -- any object will cause it to be blocked (ignore litter) if tile_flags.thob ~= 0 and tile_flags.thob ~= 62 then return false end -- check if its passable that no object footprint blocks it @@ -1180,7 +1180,7 @@ local function doorWallOffsetCalculations(x, y, wall) 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 @@ -1275,9 +1275,9 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) 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 on swing doors for each door tile @@ -1300,7 +1300,7 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) map:setCell(x1, y1, 4, i < 2 and flags or flags - 1) else map:setCell(x1, y1, 4, i > 2 and flags or flags - 1) - end + end end end else diff --git a/CorsixTH/Lua/utility.lua b/CorsixTH/Lua/utility.lua index 53e657f22..12a761970 100644 --- a/CorsixTH/Lua/utility.lua +++ b/CorsixTH/Lua/utility.lua @@ -312,14 +312,12 @@ function rangeMapLookup(number, buckets) assert(false) -- Should never get here. 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 @@ -328,7 +326,7 @@ elseif _G._VERSION == "Lua 5.2" then function bitOr(value1, value2) return bit32.bor(value1, value2) end - + function hasBit(value, bit) return bit32.btest(value, 2^bit) end @@ -344,6 +342,6 @@ else --! 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 + return value % (p + p) >= p end end From 39d0c4375806a364ffe9df6170ad2198d5991dae Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 4 Oct 2017 22:20:49 +1000 Subject: [PATCH 08/13] Fixed some LDoc items and removed Lua 5.3 specific code --- CorsixTH/Lua/dialogs/edit_room.lua | 30 +++++++++---------- CorsixTH/Lua/utility.lua | 47 ++++++++++-------------------- CorsixTH/Lua/world.lua | 8 ++--- 3 files changed, 35 insertions(+), 50 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index 102475e19..da2662ed7 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1099,12 +1099,12 @@ local window_floor_blueprint_markers = { --!param x (int) X tile position of the door. --!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 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 +--!param has_swingdoor (boolean) Whether the room has a normal door (false) or a swing door (true) as entrance. +--!return (int) 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 @@ -1140,7 +1140,7 @@ end --!param ypos (int) Y position of the tile. --!param player_id (int) Player id owning the hospital. --!param world - reference to world object instance ---!return Whether the tile is considered to be valid. +--!return (boolean) whether the tile is considered to be valid. local function validDoorTile(xpos, ypos, player_id, world) local th = TheApp.map.th local tile_flags = th:getCellFlags(xpos, ypos) @@ -1154,14 +1154,14 @@ local function validDoorTile(xpos, ypos, player_id, world) end --! 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) +--! param x (int) doors blueprint x value +--! param y (int) doors blueprint y value +--! param wall (string) original wall orientation +--! return x (int) updated x value +--! return y (int) updated y value +--! return x_mod (int) offest value to apply to tile count to determine relative position +--! return y_mod (int) offset value to apply to tile count to determine relatitve position +--! return wall (string) wall orientation style (only 2 styles) local function doorWallOffsetCalculations(x, y, wall) local x_mod local y_mod diff --git a/CorsixTH/Lua/utility.lua b/CorsixTH/Lua/utility.lua index 12a761970..e4bb21bf2 100644 --- a/CorsixTH/Lua/utility.lua +++ b/CorsixTH/Lua/utility.lua @@ -312,36 +312,21 @@ function rangeMapLookup(number, buckets) assert(false) -- Should never get here. 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 +-- 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 +--!param value1 (int) value to check set bit of +--!param value2 (int) power of 2 value - bit enumeration +--!return (int) value1 and value2 'bitwise' or. +function bitOr(value1, value2) + return value1 % (value2 + value2) >= value2 and value1 or 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 - --! 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 +--! Check bit is set +--!param value (int) value to check set bit of +--!param bit (int) 0-base index of bit to check +--!return (boolean) true if bit is set. +function hasBit(value, bit) + local p = 2 ^ bit + return value % (p + p) >= p end diff --git a/CorsixTH/Lua/world.lua b/CorsixTH/Lua/world.lua index 774e333ac..9f65898ac 100644 --- a/CorsixTH/Lua/world.lua +++ b/CorsixTH/Lua/world.lua @@ -2714,10 +2714,10 @@ passable tiles. This presents problems with objects like Bench where the passabl 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 ---! param y - y map tile position ---! param distance - searchable distance for nearby objects ---! returns boolean indicating if exclusively passable or not +--!param x (int) x map tile position +--!param y (int) y map tile position +--!param distance (int) searchable distance for nearby objects +--!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 From b25b24c19353680df6e99ff8b52fb458adbaab97 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 4 Oct 2017 23:41:42 +1000 Subject: [PATCH 09/13] Alterations to avoid luacheck errors and luacheck (will need to be manually merged) --- .luacheckrc | 233 +++++++++++++++++++++++++++++ CorsixTH/Lua/dialogs/edit_room.lua | 3 +- CorsixTH/Lua/world.lua | 109 ++++++-------- 3 files changed, 284 insertions(+), 61 deletions(-) create mode 100644 .luacheckrc diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 000000000..ec80df3a0 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,233 @@ +--[[ Copyright (c) 2016 Albert "AlbertH" Hofkamp + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --]] + +globals = { -- Globals + "_A", "_S", + "action_queue_leave_bench", "class", "compare_tables", + "destrict", "flag_clear", "flag_isset", "flag_set", "flag_toggle", + "lfs", "list_to_set", "loadfile_envcall", "loadstring_envcall", + "permanent", "print_table", "rangeMapLookup", "rnc", + "strict_declare_global", "table_length", "unpermanent", "values", + + -- Game classes + "AIHospital", "AnimationManager", "App", "Audio", + "CallsDispatcher", "ChildClass", "Command", "Door", "DrawFlags", + "DummyRootNode", "Entity", "EntityMap", "Epidemic", "FileSystem", + "FileTreeNode", "FilteredFileTreeNode", "GameUI", "Graphics", + "GrimReaper", "Hospital", "Humanoid", "HumanoidRawWalk", + "Inspector", "LoadGame", "LoadGameFile", "Litter", "Machine", + "Map", "MoviePlayer", "NoRealClass", "Object", "ParentClass", + "Patient", "Plant", "Queue", "ResearchDepartment", "Room", + "SaveGame", "SaveGameFile", "Staff", "StaffProfile", "StaffRoom", + "Strings", "SwingDoor", "TheApp", "TreeControl", "Vip", "Window", + "World", + + -- UI + "UI", "UIAdviser", "UIAnnualReport", "UIAudio", "UIBankManager", + "UIBottomPanel", "UIBuildRoom", "UICallsDispatcher", "UICasebook", + "UICheats", "UIChooseFont", "UIConfirmDialog", "UICustomCampaign", + "UICustomGame", "UICustomise", "UIDirectoryBrowser", "UIDropdown", + "UIEditRoom", "UIFax", "UIFileBrowser", "UIFolder", "UIFullscreen", + "UIFurnishCorridor", "UIGraphs", "UIHireStaff" ,"UIInformation", + "UIJukebox", "UILoadGame", "UILoadMap", "UILuaConsole", "UIMachine", + "UIMakeDebugPatient", "UIMainMenu", "UIMapEditor", "UIMenuBar", + "UIMenuList", "UIMessage", "UINewGame", "UIOptions", "UIPatient", + "UIPlaceObjects", "UIPlaceStaff", "UIPolicy", "UIProgressReport", + "UIQueue", "UIQueuePopup", "UIResizable", "UIResearch", + "UIResolution", "UISaveGame", "UISaveMap", "UIStaff", + "UIStaffManagement", "UIStaffRise", "UITipOfTheDay", "UITownMap", + "UIUpdate", "UIWatch", + + -- Actions + "AnswerCallAction", "CallCheckPointAction", "CheckWatchAction", + "DieAction", "FallingAction", "GetUpAction", "HumanoidAction", + "IdleAction", "IdleSpawnAction", "KnockDoorAction", "MeanderAction", + "MultiUseObjectAction", "OnGroundAction", "PeeAction", + "PickupAction", "QueueAction", "SeekReceptionAction", + "SeekRoomAction", "SeekStaffRoomAction", "SeekToiletsAction", + "ShakeFistAction", "SpawnAction", "StaffReceptionAction", + "SweepFloorAction", "TapFootAction", "UseObjectAction", + "UseScreenAction", "UseStaffRoomAction", "VaccinateAction", + "VipGoToNextRoomAction", "VomitAction", "WalkAction", "YawnAction", + + -- Math extensions + "math.n_random", "math.round", "math.randomdump" + } + +-- Set standard globals +std = "lua51+lua52+lua53+luajit" +files["CorsixTH/Luatest"] = {std = "+busted"} + +codes = true -- Show warning codes +max_line_length = false -- No maximum line length + +-- Exclude files and directories +exclude_files = {"CorsixTH/Bitmap", "CorsixTH/Lua/api_version.lua", "LDocGen"} + +--! Helper function to add an ignore for a filename to 'files'. +--!param filename (str) Name of the file to add an ignore. +--!param value Ignore value to add. +local function add_ignore(filename, value) + ignores = files[filename] + if not ignores then + files[filename].ignore = {value} + else + ignores[#ignores + 1] = value + files[filename].ignore = ignores + end +end + +-- For languages, ignore +-- W111: setting non-standard global variable XYZ +-- W112: mutating non-standard global variable XYZ +-- W113: accessing undefined variable XYZ +-- W314: value assigned to field XYZ is unused +for _, lng in ipairs({"brazilian_portuguese", "czech", "danish", "developer", + "dutch", "english", "finnish", "french", "german", "hungarian", + "iberic_portuguese", "italian", "korean", "norwegian", "original_strings", + "polish", "russian", "simplified_chinese", "spanish", "swedish", + "traditional_chinese"}) do + local filename = "CorsixTH/Lua/languages/" .. lng .. ".lua" + add_ignore(filename, "111") + add_ignore(filename, "112") + add_ignore(filename, "113") + add_ignore(filename, "314") +end + +-- Ignore unused functions of save game compatibility +add_ignore("CorsixTH/Lua/app.lua", "app_confirm_quit_stub") +add_ignore("CorsixTH/Lua/dialogs/bottom_panel.lua", "stub") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/research_policy.lua", "adjust") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/research_policy.lua", "less_stub") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/research_policy.lua", "more_stub") +add_ignore("CorsixTH/Lua/dialogs/resizables/options.lua", "language_button") +add_ignore("CorsixTH/Lua/dialogs/resizables/options.lua", "width_textbox_reset") +add_ignore("CorsixTH/Lua/dialogs/resizables/options.lua", "height_textbox_reset") +add_ignore("CorsixTH/Lua/entities/machine.lua", "callbackNewRoom") +add_ignore("CorsixTH/Lua/entities/machine.lua", "repair_loop_callback") +add_ignore("CorsixTH/Lua/entities/patient.lua", "callbackNewRoom") +add_ignore("CorsixTH/Lua/entities/staff.lua", "callbackNewRoom") +add_ignore("CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua", "action_vip_go_to_next_room_end") +add_ignore("CorsixTH/Lua/rooms/operating_theatre.lua", "after_use") +add_ignore("CorsixTH/Lua/rooms/operating_theatre.lua", "wait_for_ready") + +-- W111: setting non-standard global variable XYZ +-- W113: accessing undefined variable XYZ +-- W121: setting read-only global variable XYZ +-- W122: mutating read-only global variable XYZ +-- W211: unused variable XYZ +-- W212: unused argument XYZ +-- W231: variable XYZ is never accessed +-- W512: loop is executed at most once +-- W542: empty if branch +add_ignore("CorsixTH/CorsixTH.lua", "121") +add_ignore("CorsixTH/Lua/app.lua", "122") +add_ignore("CorsixTH/Lua/app.lua", "212") +add_ignore("CorsixTH/Lua/calls_dispatcher.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/bottom_panel.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/confirm_dialog.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/edit_room.lua", "113") -- accessing hasBit and bitOr utility.lua functions +add_ignore("CorsixTH/Lua/dialogs/edit_room.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/edit_room.lua", "542") +add_ignore("CorsixTH/Lua/dialogs/fullscreen.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/bank_manager.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/graphs.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/hospital_policy.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/research_policy.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/fullscreen/staff_management.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/furnish_corridor.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/grim_reaper.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/hire_staff.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/information.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/jukebox.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/menu.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/message.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/place_objects.lua", "542") +add_ignore("CorsixTH/Lua/dialogs/queue_dialog.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/customise.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/directory_browser.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/dropdown.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/file_browser.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/lua_console.lua", "111") +add_ignore("CorsixTH/Lua/dialogs/resizables/main_menu.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/map_editor.lua", "542") +add_ignore("CorsixTH/Lua/dialogs/resizables/menu_list_dialog.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/resizables/options.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/staff_rise.lua", "212") +add_ignore("CorsixTH/Lua/dialogs/staff_rise.lua", "542") +add_ignore("CorsixTH/Lua/dialogs/tree_ctrl.lua", "212") +add_ignore("CorsixTH/Lua/entities/grim_reaper.lua", "212") +add_ignore("CorsixTH/Lua/entities/humanoid.lua", "212") +add_ignore("CorsixTH/Lua/entities/inspector.lua", "212") +add_ignore("CorsixTH/Lua/entities/machine.lua", "212") +add_ignore("CorsixTH/Lua/entities/object.lua", "212") +add_ignore("CorsixTH/Lua/entities/object.lua", "512") +add_ignore("CorsixTH/Lua/entities/patient.lua", "212") +add_ignore("CorsixTH/Lua/entities/patient.lua", "542") +add_ignore("CorsixTH/Lua/entities/staff.lua", "212") +add_ignore("CorsixTH/Lua/entities/vip.lua", "212") +add_ignore("CorsixTH/Lua/entity.lua", "212") +add_ignore("CorsixTH/Lua/epidemic.lua", "212") +add_ignore("CorsixTH/Lua/filesystem.lua", "212") +add_ignore("CorsixTH/Lua/game_ui.lua", "212") +add_ignore("CorsixTH/Lua/graphics.lua", "542") +add_ignore("CorsixTH/Lua/hospital.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_action.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/idle.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/multi_use_object.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/pickup.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/seek_reception.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/seek_reception.lua", "542") +add_ignore("CorsixTH/Lua/humanoid_actions/staff_reception.lua", "113") -- ReceptionDesk does exist +add_ignore("CorsixTH/Lua/humanoid_actions/use_object.lua", "542") +add_ignore("CorsixTH/Lua/humanoid_actions/vaccinate.lua", "212") +add_ignore("CorsixTH/Lua/humanoid_actions/vip_go_to_next_room.lua", "212") +add_ignore("CorsixTH/Lua/map.lua", "212") +add_ignore("CorsixTH/Lua/map.lua", "542") +add_ignore("CorsixTH/Lua/movie_player.lua", "542") +add_ignore("CorsixTH/Lua/objects/analyser.lua", "212") +add_ignore("CorsixTH/Lua/objects/door.lua", "212") +add_ignore("CorsixTH/Lua/objects/litter.lua", "212") +add_ignore("CorsixTH/Lua/objects/machines/operating_table.lua", "542") +add_ignore("CorsixTH/Lua/persistance.lua", "231") -- th_getupvalue assignments in lua5.2/5.3 code +add_ignore("CorsixTH/Lua/research_department.lua", "212") +add_ignore("CorsixTH/Lua/room.lua", "212") +add_ignore("CorsixTH/Lua/room.lua", "512") +add_ignore("CorsixTH/Lua/rooms/cardiogram.lua", "212") +add_ignore("CorsixTH/Lua/rooms/general_diag.lua", "212") +add_ignore("CorsixTH/Lua/rooms/psych.lua", "212") +add_ignore("CorsixTH/Lua/rooms/research.lua", "212") +add_ignore("CorsixTH/Lua/rooms/scanner_room.lua", "212") +add_ignore("CorsixTH/Lua/rooms/staff_room.lua", "212") +add_ignore("CorsixTH/Lua/rooms/staff_room.lua", "542") +add_ignore("CorsixTH/Lua/rooms/ward.lua", "212") +add_ignore("CorsixTH/Lua/sprite_viewer.lua", "212") +add_ignore("CorsixTH/Lua/strict.lua", "212") +add_ignore("CorsixTH/Lua/strings.lua", "212") +add_ignore("CorsixTH/Lua/strings.lua", "122") +add_ignore("CorsixTH/Lua/ui.lua", "111") -- _ is set in debug code +add_ignore("CorsixTH/Lua/ui.lua", "212") +add_ignore("CorsixTH/Lua/utility.lua", "111") -- defining hasBit and bitOr +add_ignore("CorsixTH/Lua/utility.lua", "121") +add_ignore("CorsixTH/Lua/window.lua", "212") +add_ignore("CorsixTH/Lua/window.lua", "542") +add_ignore("CorsixTH/Lua/world.lua", "212") +add_ignore("CorsixTH/Lua/world.lua", "542") +add_ignore("CorsixTH/Luatest/non_strict.lua", "212") diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index da2662ed7..fa3547eed 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1189,7 +1189,8 @@ function UIEditRoom:setDoorBlueprint(orig_x, orig_y, orig_wall) if self.room_type.swing_doors then if self.blueprint_door.anim[1] then -- retrieve the old door position details to reset the blue print - local oldx, oldy, oldx_mod, oldy_mod, old_wall = doorWallOffsetCalculations(self.blueprint_door.floor_x, + local oldx, oldy + local _, _, oldx_mod, oldy_mod, _ = doorWallOffsetCalculations(self.blueprint_door.floor_x, self.blueprint_door.floor_y, self.blueprint_door.wall) -- If we're dealing with swing doors the anim variable is actually a table with three -- identical "doors". diff --git a/CorsixTH/Lua/world.lua b/CorsixTH/Lua/world.lua index 9f65898ac..9c9ba4e17 100644 --- a/CorsixTH/Lua/world.lua +++ b/CorsixTH/Lua/world.lua @@ -18,7 +18,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --]] -local pathsep = package.config:sub(1, 1) local TH = require"TH" local ipairs, _G, table_remove = ipairs, _G, table.remove @@ -147,10 +146,11 @@ function World:World(app) -- TODO: Add (working) AI and/or multiplayer hospitals -- TODO: Needs to be changed for multiplayer support self.hospitals[1]:initStaff() + self.wall_id_by_block_id = {} for _, wall_type in ipairs(self.wall_types) do for _, set in ipairs({"inside_tiles", "outside_tiles", "window_tiles"}) do - for name, id in pairs(wall_type[set]) do + for _, id in pairs(wall_type[set]) do self.wall_id_by_block_id[id] = wall_type.id end end @@ -158,7 +158,7 @@ function World:World(app) self.wall_set_by_block_id = {} for _, wall_type in ipairs(self.wall_types) do for _, set in ipairs({"inside_tiles", "outside_tiles", "window_tiles"}) do - for name, id in pairs(wall_type[set]) do + for _, id in pairs(wall_type[set]) do self.wall_set_by_block_id[id] = set end end @@ -644,8 +644,6 @@ function World:tickEarthquake() local hospital = self:getLocalPlayerHospital() -- loop through the patients and allow the possibility for them to fall over for _, patient in ipairs(hospital.patients) do - local current = patient.action_queue[1] - if not patient.in_room and patient.falling_anim then -- make the patients fall @@ -910,7 +908,6 @@ function World:setSpeed(speed) if self:isCurrentSpeed(speed) then return end - local pause_state_changed = nil if speed == "Pause" then -- stop screen shaking if there was an earthquake in progress if self.next_earthquake.active then @@ -918,7 +915,6 @@ function World:setSpeed(speed) end -- By default actions are not allowed when the game is paused. self.user_actions_allowed = TheApp.config.allow_user_actions_while_paused - pause_state_changed = true elseif self:getCurrentSpeed() == "Pause" then self.user_actions_allowed = true end @@ -1044,8 +1040,8 @@ function World:onTick() end -- A patient might arrive to the player hospital. -- TODO: Multiplayer support. - if self.spawn_hours[self.hour + i-1] and self.hospitals[1].opened then - for k=1, self.spawn_hours[self.hour + i-1] do + if self.spawn_hours[self.hour + i - 1] and self.hospitals[1].opened then + for _ = 1, self.spawn_hours[self.hour + i - 1] do self:spawnPatient() end end @@ -1058,7 +1054,7 @@ function World:onTick() self.current_tick_entity = nil self.map:onTick() self.map.th:updateTemperatures(outside_temperatures[self.month], - 0.25 + self.hospitals[1].radiator_heat * 0.3) + 0.25 + self.hospitals[1].radiator_heat * 0.3) if self.ui then self.ui:onWorldTick() end @@ -1160,7 +1156,7 @@ function World:onEndDay() -- Any patients tomorrow? self.spawn_hours = {} if self.spawn_dates[self.day] then - for i = 1, self.spawn_dates[self.day] do + for _ = 1, self.spawn_dates[self.day] do local hour = math.random(1, self.hours_per_day) self.spawn_hours[hour] = self.spawn_hours[hour] and self.spawn_hours[hour] + 1 or 1 end @@ -1170,7 +1166,7 @@ function World:onEndDay() end function World:checkIfGameWon() - for i, hospital in ipairs(self.hospitals) do + for i, _ in ipairs(self.hospitals) do local res = self:checkWinningConditions(i) if res.state == "win" then self:winGame(i) @@ -1230,8 +1226,8 @@ function World:updateSpawnDates() -- Use ceil so that at least one patient arrives (unless population = 0) no_of_spawns = math.ceil(no_of_spawns*self:getLocalPlayerHospital().population) self.spawn_dates = {} - for i = 1, no_of_spawns do - -- We are interested in the coming month, pick days from it at random. + for _ = 1, no_of_spawns do + -- We are interested in the next month, pick days from it at random. local day = math.random(1, month_length[self.month % 12 + 1]) self.spawn_dates[day] = self.spawn_dates[day] and self.spawn_dates[day] + 1 or 1 end @@ -1323,8 +1319,6 @@ end -- Called when it is time to have another VIP function World:nextVip() - local current_month = (self.year - 1) * 12 + self.month - -- Support standard values for mean and variance local mean = 180 local variance = 30 @@ -1392,7 +1386,7 @@ function World:checkWinningConditions(player_no) local hospital = self.hospitals[player_no] -- Go through the goals - for i, goal in ipairs(self.goals) do + for _, goal in ipairs(self.goals) do local current_value = hospital[goal.name] -- If max_min is 1 the value must be > than the goal condition. -- If 0 it must be < than the goal condition. @@ -1562,7 +1556,7 @@ function World:onEndYear() end -- This is done here instead of in onEndMonth so that the player gets -- the chance to receive money or reputation from trophies and awards first. - for i, hospital in ipairs(self.hospitals) do + for i, _ in ipairs(self.hospitals) do local res = self:checkWinningConditions(i) if res.state == "lose" then self:loseGame(i, res.reason, res.limit) @@ -1630,24 +1624,17 @@ function World:isTileEmpty(x, y, not_in_room) return true end -local face_dir = { - [0] = "south", - [1] = "west", - [2] = "north", - [3] = "east", -} - function World:getFreeBench(x, y, distance) local bench, rx, ry, bench_distance local object_type = self.object_types.bench x, y, distance = math.floor(x), math.floor(y), math.ceil(distance) - self.pathfinder:findObject(x, y, object_type.thob, distance, function(x, y, d, dist) - local b = self:getObject(x, y, "bench") + self.pathfinder:findObject(x, y, object_type.thob, distance, function(xpos, ypos, d, dist) + local b = self:getObject(xpos, ypos, "bench") if b and not b.user and not b.reserved_for then local orientation = object_type.orientations[b.direction] if orientation.pathfind_allowed_dirs[d] then - rx = x + orientation.use_position[1] - ry = y + orientation.use_position[2] + rx = xpos + orientation.use_position[1] + ry = ypos + orientation.use_position[2] bench = b bench_distance = dist return true @@ -1695,8 +1682,8 @@ function World:findAllObjectsNear(x, y, distance, object_type_name) thob = obj_type.thob end - local callback = function(x, y, d) - local obj = self:getObject(x, y, object_type_name) + local callback = function(xpos, ypos, d) + local obj = self:getObject(xpos, ypos, object_type_name) if obj then objects[obj] = true end @@ -1748,8 +1735,8 @@ function World:findObjectNear(humanoid, object_type_name, distance, callback) if type(object_type_name) == "table" then local original_callback = callback callback = function(x, y, ...) - local obj = self:getObject(x, y, object_type_name) - if obj then + local cb_obj = self:getObject(x, y, object_type_name) + if cb_obj then return original_callback(x, y, ...) end end @@ -1819,7 +1806,7 @@ function World:findRoomNear(humanoid, room_type_id, distance, mode) distance = 2^30 end for _, r in pairs(self.rooms) do repeat - if r.built and (not room_type_id or r.room_info.id == room_type_id) and r.is_active and r.door.queue.max_size ~= 0 then + if r.built and (not room_type_id or r.room_info.id == room_type_id) and r.is_active then local x, y = r:getEntranceXY(false) local d = self:getPathDistance(humanoid.tile_x, humanoid.tile_y, x, y) if not d or d > distance then @@ -1971,12 +1958,12 @@ end -- flag's boolean value or false if the tile isn't valid. --- function World:isFootprintTileBuildableOrPassable(x, y, tile, footprint, requirement_flag, player_id) - local function isTileValid(x, y, complete_cell, flags, flag_name, need_side) + local function isTileValid(xpos, ypos, complete_cell, flags, flag_name, need_side) if complete_cell or need_side then return flags[flag_name] end - for _, tile in ipairs(footprint) do - if(tile[1] == x and tile[2] == y) then + for _, fp_tile in ipairs(footprint) do + if fp_tile[1] == xpos and fp_tile[2] == ypos then return flags[flag_name] end end @@ -2026,9 +2013,9 @@ function World:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, objec end end - local function isIsolated(x, y) + local function isIsolated(xpos, ypos) setFootprintTilesPassable(false) - local result = not self.pathfinder:isReachableFromHospital(x, y) + local result = not self.pathfinder:isReachableFromHospital(xpos, ypos) setFootprintTilesPassable(true) return result end @@ -2046,32 +2033,32 @@ function World:wouldNonSideObjectBreakPathfindingIfSpawnedAt(x, y, object, objec setFootprintTilesPassable(false) local prev_x, prev_y for _, tile in ipairs(object.orientations[objects_orientation].adjacent_to_solid_footprint) do - local x = x + tile[1] - local y = y + tile[2] + local xpos = x + tile[1] + local ypos = y + tile[2] local flags = {} - if map:getCellFlags(x, y, flags).roomId == spawn_rooms_id and flags.passable then + if map:getCellFlags(xpos, ypos, flags).roomId == spawn_rooms_id and flags.passable then if prev_x then - if not self.pathfinder:findDistance(x, y, prev_x, prev_y) then + if not self.pathfinder:findDistance(xpos, ypos, prev_x, prev_y) then -- There is no route between the two map nodes. In most cases, -- this means that connectedness has changed, though there is -- one rare situation where the above test is insufficient. If - -- (x, y) is a passable but isolated node outside the hospital + -- (xpos, ypos) is a passable but isolated node outside the hospital -- and (prev_x, prev_y) is in the corridor, then the two will -- not be connected now, but critically, neither were they -- connected before. - if not isIsolated(x, y) then + if not isIsolated(xpos, ypos) then if not isIsolated(prev_x, prev_y) then all_good = false break end else - x = prev_x - y = prev_y + xpos = prev_x + ypos = prev_y end end end - prev_x = x - prev_y = y + prev_x = xpos + prev_y = ypos end end @@ -2100,7 +2087,6 @@ function World:objectPlaced(entity, id) if id == "bench" and entity.tile_x and entity.tile_y then local notify_distance = 6 local w, h = self.map.th:size() - local tx, ty for tx = math.max(1, entity.tile_x - notify_distance), math.min(w, entity.tile_x + notify_distance) do for ty = math.max(1, entity.tile_y - notify_distance), math.min(h, entity.tile_y + notify_distance) do for _, patient in ipairs(self.entity_map:getHumanoidsAtCoordinate(tx, ty)) do @@ -2128,14 +2114,12 @@ function World:objectPlaced(entity, id) self.ui.adviser:say(_A.staff_advice.need_handyman_plants) end if id == "gates_to_hell" then - entity:playSoundsAtEntityInRandomSequence("LAVA00*.WAV", - {0,1350,1150,950,750,350}, - {0,1450,1250,1050,850,450}, - 40) + entity:playEntitySounds("LAVA00*.WAV", {0,1350,1150,950,750,350}, + {0,1450,1250,1050,850,450}, 40) entity:setTimer(entity.world:getAnimLength(2550), --[[persistable:lava_hole_spawn_animation_end]] - function(entity) - entity:setAnimation(1602) + function(anim_entity) + anim_entity:setAnimation(1602) end) entity:setAnimation(2550) end @@ -2419,7 +2403,7 @@ function World:afterLoad(old, new) plant = 0, general = 0, } - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat then @@ -2430,7 +2414,7 @@ function World:afterLoad(old, new) end if old < 43 then self.object_counts.reception_desk = 0 - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat and count_cat == "reception_desk" then @@ -2441,7 +2425,7 @@ function World:afterLoad(old, new) end if old < 47 then self.object_counts.bench = 0 - for position, obj_list in pairs(self.objects) do + for _, obj_list in pairs(self.objects) do for _, obj in ipairs(obj_list) do local count_cat = obj.object_type.count_category if count_cat and count_cat == "bench" then @@ -2460,6 +2444,7 @@ function World:afterLoad(old, new) end if old < 17 then -- Added another object + local pathsep = package.config:sub(1, 1) local _, shield = pcall(dofile, "objects" .. pathsep .. "radiation_shield") local _, shield_b = pcall(dofile, "objects" .. pathsep .. "radiation_shield_b") shield.slave_type = shield_b @@ -2683,6 +2668,10 @@ function World:afterLoad(old, new) self.next_earthquake.remaining_damage = rd self.next_earthquake.damage_timer = earthquake_damage_time self.next_earthquake.warning_timer = 0 + else + self.next_earthquake.remaining_damage = self.next_earthquake.size + self.next_earthquake.damage_timer = earthquake_damage_time + self.next_earthquake.warning_timer = earthquake_warning_period end end @@ -2717,7 +2706,7 @@ passable tiles (the norm for most objects)]] --!param x (int) x map tile position --!param y (int) y map tile position --!param distance (int) searchable distance for nearby objects ---!returns (boolean) indicating if exclusively passable or not +--!return (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 From fa38fca6b5239293e4aa4ca00b28ed02509108b3 Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 5 Oct 2017 00:44:55 +1000 Subject: [PATCH 10/13] Fixed regression with bench in front of door --- CorsixTH/Lua/dialogs/edit_room.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CorsixTH/Lua/dialogs/edit_room.lua b/CorsixTH/Lua/dialogs/edit_room.lua index fa3547eed..587161a71 100644 --- a/CorsixTH/Lua/dialogs/edit_room.lua +++ b/CorsixTH/Lua/dialogs/edit_room.lua @@ -1144,8 +1144,8 @@ end 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 + -- check own it + if tile_flags.owner ~= player_id then return false end -- any object will cause it to be blocked (ignore litter) if tile_flags.thob ~= 0 and tile_flags.thob ~= 62 then return false end -- check if its passable that no object footprint blocks it From cef1d2a36e0b9c0c4221d268f7620559286a0906 Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 23 Oct 2017 17:03:40 +1000 Subject: [PATCH 11/13] Added afterLoad checks and included Chair from GPs Office as it requires footprint change to be placed next to door --- CorsixTH/Lua/objects/bench.lua | 8 ++++++++ CorsixTH/Lua/objects/chair.lua | 25 +++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/CorsixTH/Lua/objects/bench.lua b/CorsixTH/Lua/objects/bench.lua index e973187f1..b34934f3e 100644 --- a/CorsixTH/Lua/objects/bench.lua +++ b/CorsixTH/Lua/objects/bench.lua @@ -194,4 +194,12 @@ function Bench:onDestroy() Object.onDestroy(self) end +--! This function is automatically called after loading a game and serves for compatibility. +function Bench:afterLoad(old, new) + if old < 118 then + self.footprint = object.orientations[self.direction].footprint + end + Object.afterLoad(self, old, new) +end + return object diff --git a/CorsixTH/Lua/objects/chair.lua b/CorsixTH/Lua/objects/chair.lua index 6707e229b..cd8518d23 100644 --- a/CorsixTH/Lua/objects/chair.lua +++ b/CorsixTH/Lua/objects/chair.lua @@ -136,21 +136,38 @@ object.usage_animations = { } object.orientations = { north = { - footprint = { {0, 0, complete_cell = true}, {0, -1, only_passable = 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} }, + 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} }, + 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} }, + footprint = { {0, 0, complete_cell = true}, {-1, 0, only_passable = true, invisible = true, shareable = true} }, use_position = "passable", }, } +class "Chair" (Object) + +---@type Chair +local Chair = _G["Chair"] + +function Chair:Chair(...) + self:Object(...) +end + +--! This function is automatically called after loading a game and serves for compatibility. +function Chair:afterLoad(old, new) + if old < 118 then + self.footprint = object.orientations[self.direction].footprint + end + Object.afterLoad(self, old, new) +end + return object From b9dbe1b58a8161a7a45fe23eebbd7052a0e8992b Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 3 Nov 2017 21:38:46 +1000 Subject: [PATCH 12/13] Advance save version --- CorsixTH/Lua/app.lua | 2 +- CorsixTH/Lua/objects/bench.lua | 2 +- CorsixTH/Lua/objects/chair.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CorsixTH/Lua/app.lua b/CorsixTH/Lua/app.lua index 982a5f2ba..0555528c9 100644 --- a/CorsixTH/Lua/app.lua +++ b/CorsixTH/Lua/app.lua @@ -28,7 +28,7 @@ local runDebugger = dofile "run_debugger" -- Increment each time a savegame break would occur -- and add compatibility code in afterLoad functions -local SAVEGAME_VERSION = 115 +local SAVEGAME_VERSION = 119 class "App" diff --git a/CorsixTH/Lua/objects/bench.lua b/CorsixTH/Lua/objects/bench.lua index b34934f3e..5be1373c8 100644 --- a/CorsixTH/Lua/objects/bench.lua +++ b/CorsixTH/Lua/objects/bench.lua @@ -196,7 +196,7 @@ end --! This function is automatically called after loading a game and serves for compatibility. function Bench:afterLoad(old, new) - if old < 118 then + if old < 119 then self.footprint = object.orientations[self.direction].footprint end Object.afterLoad(self, old, new) diff --git a/CorsixTH/Lua/objects/chair.lua b/CorsixTH/Lua/objects/chair.lua index cd8518d23..2fab9502d 100644 --- a/CorsixTH/Lua/objects/chair.lua +++ b/CorsixTH/Lua/objects/chair.lua @@ -164,7 +164,7 @@ end --! This function is automatically called after loading a game and serves for compatibility. function Chair:afterLoad(old, new) - if old < 118 then + if old < 119 then self.footprint = object.orientations[self.direction].footprint end Object.afterLoad(self, old, new) From a0cf7b9a53f9a5f5753cfa2fbbb34deabaf63d01 Mon Sep 17 00:00:00 2001 From: Justin Date: Thu, 9 Nov 2017 19:28:04 +1000 Subject: [PATCH 13/13] Fixed placing objects on litter and doors next to litter Bad copy paste --- CorsixTH/Lua/dialogs/place_objects.lua | 3 +-- CorsixTH/Lua/world.lua | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CorsixTH/Lua/dialogs/place_objects.lua b/CorsixTH/Lua/dialogs/place_objects.lua index 9cdf6fced..158024e1b 100644 --- a/CorsixTH/Lua/dialogs/place_objects.lua +++ b/CorsixTH/Lua/dialogs/place_objects.lua @@ -665,9 +665,8 @@ function UIPlaceObjects:setBlueprintCell(x, y) -- 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 - 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) + is_object_allowed = world:isTileExclusivelyPassable(xpos, ypos, 10) end -- Having checked if the tile is good set its blueprint appearance flag: diff --git a/CorsixTH/Lua/world.lua b/CorsixTH/Lua/world.lua index 9c9ba4e17..23e735529 100644 --- a/CorsixTH/Lua/world.lua +++ b/CorsixTH/Lua/world.lua @@ -2718,7 +2718,7 @@ function World:isTileExclusivelyPassable(x, y, distance) else -- doors don't have a footprint but objects can't be built blocking them either for _, footprint in pairs(o:getWalkableTiles()) do - if footprint[1] == x and footprint[2] == y then + if o.object_type and o.object_type.thob ~= 62 and footprint[1] == x and footprint[2] == y then return false end end