Add land valuation
parent
3c962d0f47
commit
c577db0481
|
@ -4,6 +4,7 @@ allow_defined_top = true
|
|||
exclude_files = {
|
||||
"mods/mtg",
|
||||
"mods/libs/lib_chatcmdbuilder",
|
||||
"mods/libs/lib_utils/vector.lua",
|
||||
"mods/mechanics",
|
||||
"mods/areas",
|
||||
"mods/craftguide",
|
||||
|
@ -13,7 +14,8 @@ globals = {
|
|||
"minetest", "company",
|
||||
"areas", "sfinv",
|
||||
"shop",
|
||||
ChatCmdBuilder = {fields = {"types"}}
|
||||
ChatCmdBuilder = {fields = {"types"}},
|
||||
vector = { fields = {"sqdist"}},
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
|
|
|
@ -136,6 +136,26 @@ function land.get_by_area_id(id)
|
|||
end
|
||||
|
||||
|
||||
--- Get zone for a plot
|
||||
--
|
||||
-- Gets the base zone for a particular area
|
||||
function land.get_zone(area)
|
||||
assert(type(area) == "table")
|
||||
|
||||
local zone = area
|
||||
while zone do
|
||||
local next = areas.areas[zone.parent]
|
||||
if next and next.land_type ~= area.land_type then
|
||||
return zone
|
||||
end
|
||||
|
||||
zone = next
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Transfers a plot between two owners, after checking relevant permissions.
|
||||
--
|
||||
-- @int id
|
||||
|
@ -259,6 +279,33 @@ function land.set_price(area, pname, price)
|
|||
end
|
||||
|
||||
|
||||
--- Calculates a recommended value for the lot, based on the position and more.
|
||||
--
|
||||
-- @tparam table area
|
||||
-- @treturn number value
|
||||
function land.calc_value(area)
|
||||
assert(type(area) == "table")
|
||||
|
||||
-- Calculate a weighted metric based on volume of area
|
||||
local pos1, pos2 = vector.sort(area.pos1, area.pos2)
|
||||
local size = vector.subtract(pos2, pos1)
|
||||
local value = 200 * (size.x * size.z * 0.33 * size.y)
|
||||
|
||||
-- Find distance to zone center
|
||||
local zone = land.get_zone(area)
|
||||
if zone then
|
||||
local zone_center = zone.spawn_point or zone.pos1
|
||||
local area_center = vector.divide(vector.add(area.pos1, area.pos2), 2)
|
||||
local dist = vector.sqdist(zone_center, area_center)
|
||||
|
||||
value = value + (zone.land_value or 1000000) * 1 / (dist*0.1 + 2)
|
||||
end
|
||||
|
||||
area.land_value = value
|
||||
return value
|
||||
end
|
||||
|
||||
|
||||
--- Whether a user can buy a plot
|
||||
--
|
||||
-- @tparam table area
|
||||
|
|
|
@ -7,6 +7,9 @@ _G.audit = function()
|
|||
return { post = function() end }
|
||||
end
|
||||
|
||||
_G.vector = {}
|
||||
|
||||
require("libs/lib_utils/vector")
|
||||
require("capitalism/land/api")
|
||||
|
||||
_G.company = {}
|
||||
|
@ -153,4 +156,21 @@ describe("land", function()
|
|||
assert.is_true(suc)
|
||||
assert.equals(area.land_sale, 100)
|
||||
end)
|
||||
|
||||
it("calc_value", function()
|
||||
local function v(x, y, z)
|
||||
return { x=x, y=y, z=z }
|
||||
end
|
||||
|
||||
areas.areas = {
|
||||
{ owner="c:government", id=1, name="Root", pos1=v(0,0,0), pos2=v(100,100,100), parent=nil },
|
||||
{ owner="c:government", id=2, name="City", pos1=v(0,0,0), pos2=v(100,100,100), parent=1 },
|
||||
{ owner="c:government", id=3, name="Commercial", land_type="commercial", pos1=v(10,10,10), pos2=v(50,50,50),
|
||||
parent=2, land_value=1000000 },
|
||||
{ owner="c:test", id=4, name="Mall", land_type="commercial", pos1=v(10,10,10), pos2=v(30,30,30), parent=3 },
|
||||
{ owner="c:test", id=5, name="Shop", land_type="commercial", pos1=v(10,10,10), pos2=v(20,13,20), parent=4 },
|
||||
}
|
||||
|
||||
assert.equals(land.calc_value(areas.areas[5]), 200*(10*10*3*0.33) + 1000000 * 1 / (52.25*0.1 + 2))
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -57,3 +57,10 @@ function lib_utils.make_saveload(tab, storage, itemarraykey, registername, class
|
|||
tab.dirty = false
|
||||
end
|
||||
end
|
||||
|
||||
function vector.sqdist(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return x*x + y*y + z*z
|
||||
end
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
vector = {}
|
||||
|
||||
function vector.new(a, b, c)
|
||||
if type(a) == "table" then
|
||||
assert(a.x and a.y and a.z, "Invalid vector passed to vector.new()")
|
||||
return {x=a.x, y=a.y, z=a.z}
|
||||
elseif a then
|
||||
assert(b and c, "Invalid arguments for vector.new()")
|
||||
return {x=a, y=b, z=c}
|
||||
end
|
||||
return {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
function vector.equals(a, b)
|
||||
return a.x == b.x and
|
||||
a.y == b.y and
|
||||
a.z == b.z
|
||||
end
|
||||
|
||||
function vector.length(v)
|
||||
return math.hypot(v.x, math.hypot(v.y, v.z))
|
||||
end
|
||||
|
||||
function vector.normalize(v)
|
||||
local len = vector.length(v)
|
||||
if len == 0 then
|
||||
return {x=0, y=0, z=0}
|
||||
else
|
||||
return vector.divide(v, len)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.floor(v)
|
||||
return {
|
||||
x = math.floor(v.x),
|
||||
y = math.floor(v.y),
|
||||
z = math.floor(v.z)
|
||||
}
|
||||
end
|
||||
|
||||
function vector.round(v)
|
||||
return {
|
||||
x = math.floor(v.x + 0.5),
|
||||
y = math.floor(v.y + 0.5),
|
||||
z = math.floor(v.z + 0.5)
|
||||
}
|
||||
end
|
||||
|
||||
function vector.apply(v, func)
|
||||
return {
|
||||
x = func(v.x),
|
||||
y = func(v.y),
|
||||
z = func(v.z)
|
||||
}
|
||||
end
|
||||
|
||||
function vector.distance(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return math.hypot(x, math.hypot(y, z))
|
||||
end
|
||||
|
||||
function vector.direction(pos1, pos2)
|
||||
return vector.normalize({
|
||||
x = pos2.x - pos1.x,
|
||||
y = pos2.y - pos1.y,
|
||||
z = pos2.z - pos1.z
|
||||
})
|
||||
end
|
||||
|
||||
function vector.angle(a, b)
|
||||
local dotp = vector.dot(a, b)
|
||||
local cp = vector.cross(a, b)
|
||||
local crossplen = vector.length(cp)
|
||||
return math.atan2(crossplen, dotp)
|
||||
end
|
||||
|
||||
function vector.dot(a, b)
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||
end
|
||||
|
||||
function vector.cross(a, b)
|
||||
return {
|
||||
x = a.y * b.z - a.z * b.y,
|
||||
y = a.z * b.x - a.x * b.z,
|
||||
z = a.x * b.y - a.y * b.x
|
||||
}
|
||||
end
|
||||
|
||||
function vector.add(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x + b.x,
|
||||
y = a.y + b.y,
|
||||
z = a.z + b.z}
|
||||
else
|
||||
return {x = a.x + b,
|
||||
y = a.y + b,
|
||||
z = a.z + b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.subtract(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x - b.x,
|
||||
y = a.y - b.y,
|
||||
z = a.z - b.z}
|
||||
else
|
||||
return {x = a.x - b,
|
||||
y = a.y - b,
|
||||
z = a.z - b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.multiply(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x * b.x,
|
||||
y = a.y * b.y,
|
||||
z = a.z * b.z}
|
||||
else
|
||||
return {x = a.x * b,
|
||||
y = a.y * b,
|
||||
z = a.z * b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.divide(a, b)
|
||||
if type(b) == "table" then
|
||||
return {x = a.x / b.x,
|
||||
y = a.y / b.y,
|
||||
z = a.z / b.z}
|
||||
else
|
||||
return {x = a.x / b,
|
||||
y = a.y / b,
|
||||
z = a.z / b}
|
||||
end
|
||||
end
|
||||
|
||||
function vector.sort(a, b)
|
||||
return {x = math.min(a.x, b.x), y = math.min(a.y, b.y), z = math.min(a.z, b.z)},
|
||||
{x = math.max(a.x, b.x), y = math.max(a.y, b.y), z = math.max(a.z, b.z)}
|
||||
end
|
||||
|
||||
function vector.sqdist(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return x*x + y*y + z*z
|
||||
end
|
Loading…
Reference in New Issue