163 lines
4.3 KiB
Lua
163 lines
4.3 KiB
Lua
|
|
local player_lights = {}
|
|
|
|
local function can_replace(pos)
|
|
local nn = minetest.get_node(pos).name
|
|
return nn == "air" or minetest.get_item_group(nn, "illumination_light") > 0
|
|
end
|
|
|
|
local function remove_light(pos)
|
|
if pos and can_replace(pos) then
|
|
minetest.set_node(pos, {name = "air"})
|
|
end
|
|
end
|
|
|
|
local function get_light_node(player)
|
|
local light = 0
|
|
-- Light from wielded item/tool/node
|
|
local item = player:get_wielded_item():get_name()
|
|
local def = minetest.registered_items[item]
|
|
if def and def.light_source then
|
|
light = def.light_source
|
|
end
|
|
-- Light from armor or other worn items
|
|
local name = player:get_player_name()
|
|
local armor_light = player_lights[name].armor_light
|
|
if armor_light and armor_light > light then
|
|
light = armor_light
|
|
end
|
|
if light >= 14 then
|
|
return "illumination:light_14"
|
|
elseif light < 1 then
|
|
return nil
|
|
end
|
|
return "illumination:light_"..light
|
|
end
|
|
|
|
local function find_light_pos(pos)
|
|
-- Check feet and head positions first
|
|
if can_replace(pos) then
|
|
return pos
|
|
end
|
|
pos.y = pos.y + 1
|
|
if can_replace(pos) then
|
|
return pos
|
|
end
|
|
-- Otherwise look around player's head
|
|
return minetest.find_node_near(pos, 1, {"air", "group:illumination_light"})
|
|
end
|
|
|
|
local function update_illumination(player)
|
|
local name = player:get_player_name()
|
|
if not player_lights[name] then
|
|
return -- Player has just joined/left
|
|
end
|
|
local pos = vector.round(player:get_pos())
|
|
local old_pos = player_lights[name].pos
|
|
local player_pos = player_lights[name].player_pos
|
|
local node = get_light_node(player)
|
|
-- Check if illumination needs updating
|
|
if old_pos and player_pos then
|
|
if node == minetest.get_node(old_pos).name and vector.equals(pos, player_pos) then
|
|
return -- Already has illumination
|
|
end
|
|
end
|
|
-- Update illumination
|
|
player_lights[name].player_pos = pos
|
|
if node then
|
|
local new_pos = find_light_pos(pos)
|
|
if new_pos then
|
|
minetest.set_node(new_pos, {name = node})
|
|
if old_pos and not vector.equals(old_pos, new_pos) then
|
|
remove_light(old_pos)
|
|
end
|
|
player_lights[name].pos = new_pos
|
|
return
|
|
end
|
|
end
|
|
-- No illumination
|
|
remove_light(old_pos)
|
|
player_lights[name].pos = nil
|
|
end
|
|
|
|
minetest.register_globalstep(function()
|
|
for _, player in pairs(minetest.get_connected_players()) do
|
|
update_illumination(player)
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
local name = player:get_player_name()
|
|
if not player_lights[name] then
|
|
player_lights[name] = {}
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
local name = player:get_player_name()
|
|
if player_lights[name] then
|
|
remove_light(player_lights[name].pos)
|
|
end
|
|
player_lights[name] = nil
|
|
end)
|
|
|
|
-- Support for luminescent armor
|
|
if minetest.get_modpath("3d_armor") then
|
|
armor:register_on_update(function(player)
|
|
local name, inv = armor:get_valid_player(player)
|
|
if name then
|
|
local light = 0
|
|
for i=1, inv:get_size("armor") do
|
|
local item = inv:get_stack("armor", i):get_name()
|
|
local def = minetest.registered_items[item]
|
|
if def and def.light_source and def.light_source > light then
|
|
light = def.light_source
|
|
end
|
|
end
|
|
if player_lights[name] then
|
|
player_lights[name].armor_light = light
|
|
else
|
|
-- Armor updated before illumination
|
|
player_lights[name] = {armor_light = light}
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Light node for every light level
|
|
for n = 1, 14 do
|
|
minetest.register_node("illumination:light_"..n, {
|
|
drawtype = "airlike",
|
|
paramtype = "light",
|
|
light_source = n,
|
|
sunlight_propagates = true,
|
|
walkable = false,
|
|
pointable = false,
|
|
buildable_to = true,
|
|
air_equivalent = true,
|
|
groups = {
|
|
not_in_creative_inventory = 1,
|
|
not_blocking_trains = 1,
|
|
illumination_light = 1,
|
|
},
|
|
drop = "",
|
|
})
|
|
end
|
|
|
|
-- Cleanup for leftover and player-placed illumination lights
|
|
minetest.register_lbm({
|
|
label = "Illumination light cleanup",
|
|
name = "illumination:light_cleanup",
|
|
nodenames = {"group:illumination_light"},
|
|
run_at_every_load = true,
|
|
action = function(pos)
|
|
minetest.set_node(pos, {name = "air"})
|
|
end,
|
|
})
|
|
|
|
-- Aliases for old illumination lights
|
|
minetest.register_alias("illumination:light_faint", "illumination:light_4")
|
|
minetest.register_alias("illumination:light_dim", "illumination:light_8")
|
|
minetest.register_alias("illumination:light_mid", "illumination:light_12")
|
|
minetest.register_alias("illumination:light_full", "illumination:light_14")
|