I fixed this bug by adding a component (to player_common) which is similar to keeponland in DLC0002/DLC0003. The followings are useful code that prevent players from stucking into impassable tile:
local Drownable = Class(function(self, inst) self.inst = inst inst:AddTag("drownable") self.inst:StartUpdatingComponent(self) end) local function IsHole(x,y,z) return GetGroundTypeAtPosition(Vector3(x,y,z)) == GROUND.IMPASSABLE end local function IsWater(x,y,z) if IsDLCEnabled(CAPY_DLC) or IsDLCEnabled(PORKLAND_DLC) then return GetWorld().Map:IsWater(GetWorld().Map:GetTileAtPoint(x, y, z)) else return GetGroundTypeAtPosition(Vector3(x,y,z)) == GROUND.INVALID end end local function IsPointNearWater(x,y,z) local radius = 3 for i = -radius, radius, 1 do if IsDLCEnabled(CAPY_DLC) or IsDLCEnabled(PORKLAND_DLC) then if IsWater(x - radius, y, z + i) or IsWater(x + radius, y, z + i) then return true end end if IsHole(x - radius, y, z + i) or IsHole(x + radius, y, z + i) then return true end end for i = -(radius - 1), radius - 1, 1 do if IsDLCEnabled(CAPY_DLC) or IsDLCEnabled(PORKLAND_DLC) then if IsWater(x + i, y, z - radius) or IsWater(x + i, y, z + radius) then return true end end if IsHole(x + i, y, z - radius) or IsHole(x + i, y, z + radius) then return true end end return false end local function FindLandBetweenPoints(p0x, p0y, p1x, p1y) local map = GetWorld().Map local dx = math.abs(p1x - p0x) local dy = math.abs(p1y - p0y) local ix = p0x < p1x and TILE_SCALE or -TILE_SCALE local iy = p0y < p1y and TILE_SCALE or -TILE_SCALE local e = 0; for i = 0, dx+dy - 1 do local tile_at_point = map:GetTileAtPoint(p0x, 0, p0y) if not IsPointNearWater(p0x, 0, p0y) then return map:GetTileCenterPoint(p0x, 0, p0y) end local e1 = e + dy local e2 = e - dx if math.abs(e1) < math.abs(e2) then p0x = p0x + ix e = e1 else p0y = p0y + iy e = e2 end end return nil end local function VecUtil_LengthSq(p1_x, p1_z) return p1_x * p1_x + p1_z * p1_z end local function FindRandomPointOnShoreFromOcean(x, y, z) local nodes = {} for i, node in ipairs(GetWorld().topology.nodes) do if node.type ~= NODE_TYPE.Blank and node.type ~= NODE_TYPE.Blocker then table.insert(nodes, {n = node, distsq = VecUtil_LengthSq(x - node.x, z - node.y)}) end end table.sort(nodes, function(a, b) return a.distsq < b.distsq end) local num_rooms_to_pick = 4 local closest = {} for i = 1, num_rooms_to_pick do table.insert(closest, nodes[i]) end shuffleArray(closest) local dest_x, dest_y, dest_z for _, c in ipairs(closest) do dest_x, dest_y, dest_z = FindLandBetweenPoints(x, z, c.n.x, c.n.y) if dest_x ~= nil and TheSim:WorldPointInPoly(dest_x, dest_z, c.n.poly) then return dest_x, dest_y, dest_z end end for i = num_rooms_to_pick + 1, #nodes do local c = nodes[i] if c ~= nil then dest_x, dest_y, dest_z = FindLandBetweenPoints(x, z, c.n.x, c.n.y) if dest_x ~= nil and TheSim:WorldPointInPoly(dest_x, dest_z, c.n.poly) then return dest_x, dest_y, dest_z end end end return nil end function Drownable:OnUpdate(dt) local world = GetWorld() local function testfn(offset) local test_point = self.inst:GetPosition() + offset local tx, ty = world.Map:GetTileCoordsAtPoint(test_point.x, test_point.y, test_point.z) local actual_tile = world.Map:GetTile(tx, ty) return actual_tile ~= GROUND.IMPASSABLE end if not (self.inst.sg ~= nil and self.inst.sg:HasStateTag("busy")) and (self.inst.components.health == nil or not self.inst.components.health:IsInvincible()) then --god mode void enterable local pt = self.inst:GetPosition() local radius = 1.75 --buffer zone because the walls aren't perfecly along the visual line local result_offset = FindValidPositionByFan(0, radius, 12, testfn) local OnOcean = result_offset == nil if OnOcean then pt = self.inst:GetPosition() radius = 5 result_offset = FindValidPositionByFan(0, radius, 12, testfn) if result_offset then local moveto = pt + result_offset self.inst.Transform:SetPosition(moveto.x, moveto.y, moveto.z) else if not CHEATS_ENABLED then local px, py, pz = self.inst.Transform:GetWorldPosition() local sx, sy, sz = FindRandomPointOnShoreFromOcean(px, py, pz) if sx ~= nil then self.inst.Transform:SetPosition(sx, sy, sz) end end end end end end return Drownable
Steps to Reproduce
1. c_speed(10)
2. try to go to that impassable area
3. you will get randomly go into it
4. now you can walk on the impassable and breaks the game balance.
5. This can also happen when tent are built too near impassable tile.
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now