Start work on redoing lux radiation logicUse a more direct, straightforward approach tolux radiation. Perhaps allow exposure to be morestochastic and less "smoothed". Offer more directand varied effects from sheilding.The end goal is to make radiation a significant force,but easily, and as intuitively as possible,manageable.

This commit is contained in:
Aaron Suen 2020-09-12 12:09:37 -04:00
parent 2d78f30c11
commit e6bd880528
2 changed files with 186 additions and 110 deletions

View File

@ -24,7 +24,7 @@ local wetdef = {
air_pass = true,
drowning = 0,
groups = {
lux_emit = 100,
lux_emit = 4,
lux_fluid = 1,
stack_as_node = 1
},

View File

@ -1,8 +1,8 @@
-- LUALOCALS < ---------------------------------------------------------
local math, minetest, nodecore, pairs
= math, minetest, nodecore, pairs
local math_exp, math_floor, math_log, math_sqrt
= math.exp, math.floor, math.log, math.sqrt
local math, minetest, nodecore, pairs, vector
= math, minetest, nodecore, pairs, vector
local math_cos, math_pi, math_random, math_sin, math_sqrt
= math.cos, math.pi, math.random, math.sin, math.sqrt
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
@ -21,111 +21,187 @@ nodecore.register_healthfx({
end
})
local luxaccum = {}
---------------------------------------------------------------
local function rademit(pos, emit)
for _, player in pairs(minetest.get_connected_players()) do
local pname = player:get_player_name()
local pp = player:get_pos()
pp.y = pp.y + 1
local dx = pp.x - pos.x
dx = dx * dx
local dy = pp.y - pos.y
dy = dy * dy
local dz = pp.z - pos.z
dz = dz * dz
local dsqr = (dx + dy + dz)
if dsqr > (32 * 32) then return end
if dsqr < 1 then
dsqr = 1
else
for pt in minetest.raycast(pos, pp, false, true) do
local pn = minetest.get_node(pt.under)
local def = minetest.registered_items[pn.name] or {groups = {}}
if def.groups.water then
dsqr = dsqr * 8
elseif pn.name ~= "air" and not def.groups.lux_emit then
dsqr = dsqr * 2
end
if dsqr > (32 * 32) then return end
end
end
luxaccum[pname] = (luxaccum[pname] or 0) + (math_log(emit) + 1) / dsqr
end
end
nodecore.register_limited_abm({
label = "lux irradiate",
interval = 1,
chance = 2,
nodenames = {"group:lux_emit"},
action = function(pos, node)
local def = minetest.registered_items[node.name]
local emit = def and def.groups and def.groups.lux_emit or 1
if emit then return rademit(pos, emit) end
end
})
nodecore.register_aism({
label = "lux stack irradiate",
interval = 1,
chance = 2,
itemnames = {"group:lux_emit"},
action = function(stack, data)
local def = minetest.registered_items[stack:get_name()]
local emit = def and def.groups and def.groups.lux_emit
if emit then return rademit(data.pos, emit) end
end
})
local avgs = {}
nodecore.interval(1, function()
for _, player in pairs(minetest.get_connected_players()) do
local meta = player:get_meta()
local rad = meta:get_float("rad") or 0
local pname = player:get_player_name()
local accum = luxaccum[pname] or 0
luxaccum[pname] = 0
local prop = math_exp(-accum / 1000)
rad = rad * prop + (1 - prop)
local redux = 0.1
local pos = player:get_pos()
local node = minetest.get_node(pos)
local def = minetest.registered_items[node.name]
if def and def.groups and def.groups.water then
redux = redux + 50
end
pos.y = pos.y + 1
node = minetest.get_node(pos)
def = minetest.registered_items[node.name]
if def and def.groups and def.groups.water then
redux = redux + 500
end
prop = math_exp(-redux / 10000)
rad = rad * prop
meta:set_float("rad", rad)
local avg = (avgs[pname] or 0) * 0.8 + accum * 0.2
avgs[pname] = avg
local img = ""
if avg > 0.75 then
local ow = math_sqrt(avg - 0.75) * 64
if ow > 255 then ow = 255 end
img = "nc_lux_radhud.png^[opacity:" .. math_floor(ow)
end
nodecore.hud_set(player, {
label = "luxrad",
hud_elem_type = "image",
position = {x = 0.5, y = 0.5},
text = img,
direction = 0,
scale = {x = -100, y = -100},
offset = {x = 0, y = 0},
quick = true
})
local rad_default = {absorb = 2/100, scatter = 2/100}
local rad_lut = {}
minetest.after(0, function()
for k, v in pairs(minetest.registered_items) do
local g = v.groups or {}
local rad = {
stack = g.visinv,
emit = g.lux_emit,
absorb = g.lux_absorb
or (v.liquidtype ~= "none" and 7/8)
or (g.cracky and 1 - 1 / (g.cracky + 2))
or (v.walkable and 1/4)
or rad_default.absorb,
scatter = g.lux_scatter
or (v.liquidtype ~= "none" and 1)
or (v.walkable and 1/8)
or rad_default.scatter
}
if rad.absorb < 1/100 then rad.absorb = 1/100 end
rad_lut[k] = rad
end
end)
local function randdir()
-- https://math.stackexchange.com/a/44691
local z = math_random() * 2 - 1
local k = math_sqrt(1 - z * z)
local theta = math_random() * math_pi * 2
return {
x = k * math_cos(theta),
y = k * math_sin(theta),
z = z
}
end
local function radscan(player)
local emit = 0
local pos = player:get_pos()
pos.y = pos.y + player:get_properties().eye_height
local dir
for _ = 1, 32 do
local nn = minetest.get_node(pos).name
if nn == "ignore" then break end
local rad = rad_lut[nn] or rad_default
if rad.emit then emit = emit + rad.emit end
if math_random() < rad.absorb then break end
if math_random() < rad.scatter then dir = randdir() end
dir = dir or randdir()
pos = vector.add(pos, vector.multiply(dir, math_random() + 0.5))
end
if emit > 0 then minetest.log(nodecore.gametime .. " " .. emit) end
end
local cost = 0
nodecore.interval(5, function()
minetest.chat_send_all("cost " .. (cost / 5000000))
cost = 0
end)
nodecore.register_playerstep({
label = "lux rad scan",
action = function(player, data, dtime)
local start = minetest.get_us_time()
data.radtime = (data.radtime or 0) + dtime
if data.radtime > 1 then data.radtime = 1 end
while data.radtime > 1/16 do
data.radtime = data.radtime - 1/16
radscan(player, data)
end
cost = cost + minetest.get_us_time() - start
end
})
---------------------------------------------------------------
-- local luxaccum = {}
-- local function rademit(pos, emit)
-- for _, player in pairs(minetest.get_connected_players()) do
-- local pname = player:get_player_name()
-- local pp = player:get_pos()
-- pp.y = pp.y + 1
-- local dx = pp.x - pos.x
-- dx = dx * dx
-- local dy = pp.y - pos.y
-- dy = dy * dy
-- local dz = pp.z - pos.z
-- dz = dz * dz
-- local dsqr = (dx + dy + dz)
-- if dsqr > (32 * 32) then return end
-- if dsqr < 1 then
-- dsqr = 1
-- else
-- for pt in minetest.raycast(pos, pp, false, true) do
-- local pn = minetest.get_node(pt.under)
-- local def = minetest.registered_items[pn.name] or {groups = {}}
-- if def.groups.water then
-- dsqr = dsqr * 8
-- else if pn.name ~= "air" and not def.groups.lux_emit then
-- dsqr = dsqr * 2
-- end
-- if dsqr > (32 * 32) then return end
-- end
-- end
-- luxaccum[pname] = (luxaccum[pname] or 0) + (math_log(emit) + 1) / dsqr
-- end
-- end
-- nodecore.register_limited_abm({
-- label = "lux irradiate",
-- interval = 1,
-- chance = 2,
-- nodenames = {"group:lux_emit"},
-- action = function(pos, node)
-- local def = minetest.registered_items[node.name]
-- local emit = def and def.groups and def.groups.lux_emit or 1
-- if emit then return rademit(pos, emit) end
-- end
-- })
-- nodecore.register_aism({
-- label = "lux stack irradiate",
-- interval = 1,
-- chance = 2,
-- itemnames = {"group:lux_emit"},
-- action = function(stack, data)
-- local def = minetest.registered_items[stack:get_name()]
-- local emit = def and def.groups and def.groups.lux_emit
-- if emit then return rademit(data.pos, emit) end
-- end
-- })
-- local avgs = {}
-- nodecore.interval(1, function()
-- for _, player in pairs(minetest.get_connected_players()) do
-- local meta = player:get_meta()
-- local rad = meta:get_float("rad") or 0
-- local pname = player:get_player_name()
-- local accum = luxaccum[pname] or 0
-- luxaccum[pname] = 0
-- local prop = math_exp(-accum / 1000)
-- rad = rad * prop + (1 - prop)
-- local redux = 0.1
-- local pos = player:get_pos()
-- local node = minetest.get_node(pos)
-- local def = minetest.registered_items[node.name]
-- if def and def.groups and def.groups.water then
-- redux = redux + 50
-- end
-- pos.y = pos.y + 1
-- node = minetest.get_node(pos)
-- def = minetest.registered_items[node.name]
-- if def and def.groups and def.groups.water then
-- redux = redux + 500
-- end
-- prop = math_exp(-redux / 10000)
-- rad = rad * prop
-- meta:set_float("rad", rad)
-- local avg = (avgs[pname] or 0) * 0.8 + accum * 0.2
-- avgs[pname] = avg
-- local img = ""
-- if avg > 0.75 then
-- local ow = math_sqrt(avg - 0.75) * 64
-- if ow > 255 then ow = 255 end
-- img = "nc_lux_radhud.png^[opacity:" .. math_floor(ow)
-- end
-- nodecore.hud_set(player, {
-- label = "luxrad",
-- hud_elem_type = "image",
-- position = {x = 0.5, y = 0.5},
-- text = img,
-- direction = 0,
-- scale = {x = -100, y = -100},
-- offset = {x = 0, y = 0},
-- quick = true
-- })
-- end
-- end)