8a74b34907
Using Oblomov's proposed sinusoidal brightness profile, making the bright and dim extremes of the lantern's range shorter, and stretching the middle. Also nerfed the total useful lifetime of lanterns since we no longer have to inflate it by as large of a "useless" range at the bottom end.
113 lines
3.3 KiB
Lua
113 lines
3.3 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local math, minetest, nodecore, string
|
|
= math, minetest, nodecore, string
|
|
local math_asin, math_ceil, math_pi, math_sin, string_format
|
|
= math.asin, math.ceil, math.pi, math.sin, string.format
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local modname = minetest.get_current_modname()
|
|
|
|
local discharge_rate = 20
|
|
local max_charge = discharge_rate * 2400
|
|
|
|
local function charge_to_level(charge)
|
|
local i = math_ceil(4 * (1 + 2 * math_asin(charge * 2 / max_charge - 1) / math_pi))
|
|
return i > 7 and 7 or i
|
|
end
|
|
local function level_to_charge(level)
|
|
return (math_sin((level / 4 - 1) / 2 * math_pi) / 2 + 0.5) * max_charge
|
|
end
|
|
|
|
local fluid_water = nodecore.group_expand("group:water", true)
|
|
local fluid_flux = nodecore.group_expand("group:lux_fluid", true)
|
|
local function influid(pos)
|
|
local n = minetest.get_node(pos).name
|
|
if fluid_water[n] then return fluid_water end
|
|
if fluid_flux[n] then return fluid_flux end
|
|
pos = {x = pos.x, y = pos.y + 1, z = pos.z}
|
|
n = minetest.get_node(pos).name
|
|
if fluid_water[n] then return fluid_water end
|
|
if fluid_flux[n] then return fluid_flux end
|
|
end
|
|
|
|
local function floateq(a, b)
|
|
if not (a and b) then return true end
|
|
if a == 0 and b == 0 then return a == b end
|
|
local ratio = a / b
|
|
return ratio > 0.999 and ratio < 1.001
|
|
end
|
|
local function floatrpt(a, b)
|
|
if floateq(a, b) then return string_format("%0.2f", a) end
|
|
return string_format("%0.2f -> %0.2f", a, b)
|
|
end
|
|
|
|
local function getlevel(name)
|
|
return minetest.get_item_group(name, modname) - 1
|
|
end
|
|
|
|
local function chargecalc(pos, oldname, meta)
|
|
local fluid = influid(pos)
|
|
local rate = (nodecore.lux_soak_rate(pos) or 0)
|
|
- discharge_rate * ((fluid == fluid_water) and 2 or 1)
|
|
if rate < 0 and fluid == fluid_flux then rate = 0 end
|
|
|
|
local oldrate = meta:get_float("rate")
|
|
local oldqty = meta:get_float("qty")
|
|
local oldtime = meta:get_float("time")
|
|
|
|
local now = nodecore.gametime
|
|
local qty = (oldtime == 0)
|
|
and level_to_charge(getlevel(oldname))
|
|
or (oldqty + oldrate * (now - oldtime))
|
|
if qty <= 0 then
|
|
qty = 0
|
|
if rate < 0 then rate = 0 end
|
|
end
|
|
if qty >= max_charge then
|
|
qty = max_charge
|
|
if rate > 0 then rate = 0 end
|
|
end
|
|
local level = charge_to_level(qty)
|
|
local name = modname .. ":lamp" .. level
|
|
|
|
if name == oldname and floateq(rate, oldrate) then return end
|
|
|
|
nodecore.log("action", string_format("lantern level %s rate %s charge %s at %s",
|
|
floatrpt(getlevel(oldname), level),
|
|
floatrpt(oldrate, rate), floatrpt(oldqty, qty),
|
|
minetest.pos_to_string(pos, 0)))
|
|
|
|
meta:set_float("rate", rate)
|
|
meta:set_float("qty", qty)
|
|
meta:set_float("time", now)
|
|
return name
|
|
end
|
|
|
|
nodecore.register_aism({
|
|
label = "lantern charge",
|
|
interval = 2,
|
|
arealoaded = 14,
|
|
itemnames = "group:" .. modname,
|
|
action = function(stack, data)
|
|
local pos = data.pos or data.player and data.player:get_pos()
|
|
local name = chargecalc(pos, stack:get_name(), stack:get_meta())
|
|
if name then
|
|
stack:set_name(name)
|
|
return stack
|
|
end
|
|
end
|
|
})
|
|
nodecore.register_abm({
|
|
label = "lantern charge",
|
|
interval = 2,
|
|
arealoaded = 14,
|
|
nodenames = {"group:" .. modname},
|
|
action = function(pos, node)
|
|
local name = chargecalc(pos, node.name, minetest.get_meta(pos))
|
|
if name then
|
|
node.name = name
|
|
return minetest.swap_node(pos, node)
|
|
end
|
|
end
|
|
})
|