Skip to content

Commit

Permalink
Use smallest area at given position (#79)
Browse files Browse the repository at this point in the history
When checking for permission to interact, currently the smallest id takes precedence in a situation where areas enclose other areas. This makes it complicated to set up private areas within faction areas and vice versa. Same applies for open areas within a bigger private area.

When multiple areas have the same volume, players seem to agree that the most recently protected area should also take precedence.
Since we can't guarantee that the largest id is the most recent, we still use that info as we have no other way to determine age.
  • Loading branch information
SwissalpS authored Sep 11, 2024
1 parent 9a5cdb2 commit c2e3d07
Showing 1 changed file with 39 additions and 19 deletions.
58 changes: 39 additions & 19 deletions api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,36 +95,56 @@ function areas:getAreasIntersectingArea(pos1, pos2)
return res
end

-- Checks if the area is unprotected or owned by you
-- Returns smallest area at position and its id or nil.
-- If multiple areas have the same volume, larger id takes precedence.
function areas:getSmallestAreaAtPos(pos)
local smallest_area, smallest_id, volume
local smallest_volume = math.huge
for id, area in pairs(self:getAreasAtPos(pos)) do
volume = (area.pos2.x - area.pos1.x + 1)
* (area.pos2.y - area.pos1.y + 1)
* (area.pos2.z - area.pos1.z + 1)
if smallest_volume >= volume then
smallest_area = area
smallest_id = id
smallest_volume = volume
end
end
return smallest_area, smallest_id
end

-- Checks if the area is unprotected, open, owned by player
-- or player is part of faction of smallest area at position.
function areas:canInteract(pos, name)
if minetest.check_player_privs(name, self.adminPrivs) then
return true
end
local owned = false
for _, area in pairs(self:getAreasAtPos(pos)) do
if area.owner == name or area.open then
return true
elseif areas.factions_available and area.faction_open then
if (factions.version or 0) < 2 then
local faction_name = factions.get_player_faction(name)
if faction_name then
for _, fname in ipairs(area.faction_open or {}) do
if faction_name == fname then
return true
end
end
end
else
local area = self:getSmallestAreaAtPos(pos)
-- No area, player owns it or area is open
if not area
or area.owner == name
or area.open
then
return true
elseif areas.factions_available and area.faction_open then
if (factions.version or 0) < 2 then
local faction_name = factions.get_player_faction(name)
if faction_name then
for _, fname in ipairs(area.faction_open or {}) do
if factions.player_is_in_faction(fname, name) then
if faction_name == fname then
return true
end
end
end
else
for _, fname in ipairs(area.faction_open or {}) do
if factions.player_is_in_faction(fname, name) then
return true
end
end
end
owned = true
end
return not owned
return false
end

-- Returns a table (list) of all players that own an area
Expand Down

0 comments on commit c2e3d07

Please sign in to comment.