Skip to content
Snippets Groups Projects
Commit de46ba00 authored by Peter Nerlich's avatar Peter Nerlich
Browse files

spotlights: proof of concept, based of code from beacons mod

parents
No related branches found
No related tags found
No related merge requests found
README 0 → 100644
Spotlights Mod
by Peter Nerlich
Implementation inspired by Beacons and Illumination mods.
This mod adds spotlights - light sources that shine light to a spot over a long distance.
craft_image.png

8.15 KiB

default?
\ No newline at end of file
init.lua 0 → 100644
-- Maximum number of light nodes beyond spotlight
local spotlight_undiminishing_distance = tonumber(minetest.settings:get("spotlight_undiminishing_distance")) or 12
local spotlight_decaying_distance = tonumber(minetest.settings:get("spotlight_decaying_distance")) or 13
local spotlight_base_shimmer = tonumber(minetest.settings:get("spotlight_base_shimmer")) or 3
local spotlight_beam_shimmer = tonumber(minetest.settings:get("spotlight_beam_shimmer")) or 2
local spotlight_permeate_paramtype_light = minetest.settings:get_bool("spotlight_permeate_paramtype_light", true)
local perfectly_transparent_nodes = {
'default:glass', 'xpanes:pane_flat', 'doors:door_glass', 'basic_signs:sign_glass_yard',
'default:obsidian_glass', 'xpanes:obsidian_pane_flat', 'doors:door_obsidian_glass', 'basic_signs:sign_glass_yard',
'building_blocks:woodglass',
'moreblocks:clean_glass', 'moreblocks:coal_glass', 'moreblocks:iron_glass', 'moreblocks:glow_glass', 'moreblocks:super_glow_glass',
'butterflies:butterfly_red', 'butterflies:butterfly_violet', 'butterflies:butterfly_white', ' fireflies:firefly',
'elevators:rail', 'elevators:brakerail',
'farming:beanpole',
'mesecons_torch:mesecon_torch_on', 'mesecons_torch:mesecon_torch_off',
'mesecons_insulated:insulated_on', 'mesecons_insulated:insulated_off',
}
local x = nil
function toBits(num)
-- returns a table of bits, least significant first.
local t={} -- will contain the bits
while num>0 do
local rest=math.fmod(num,2)
t[#t+1]=rest
num=(num-rest)/2
end
return t
end
for x = 0, 255 do
local s = 'mesecons:wire_'
local bits = toBits(x)
bits = string.reverse(table.concat(bits))
while #bits < 8 do
bits = '0'..bits
end
--print('perfectly_transparent_nodes: inserting '..s..bits..'_...')
table.insert(perfectly_transparent_nodes, s..'_on')
table.insert(perfectly_transparent_nodes, s..'_off')
end
-- reform perfectly_transparent_nodes to be easily searchable with the form
-- name = true
local i = nil
local tmp = perfectly_transparent_nodes
perfectly_transparent_nodes = {}
for i = 1, #tmp do
perfectly_transparent_nodes[tmp[i]] = tmp[i]
end
-- end populating perfectly_transparent_nodes --
local function dump(o, indent)
if indent == nil then indent = 0 end
local function idt(n)
if n == nil then n = 0 end
return string.rep(' ', indent+n)
end
if type(o) == 'table' then
local s = '{\n' -- omit indentation on opening bracket: if nested, we are not starting a line here; if not, indent is 0 anyways
for k,v in pairs(o) do
s = s..idt(1) .. dump(k, indent+1) .. ' = ' .. dump(v, indent+1) .. ',\n'
end
return s..idt() .. '} '
elseif type(o) ~= 'number' then
return '"'..tostring(o)..'"'
else
return tostring(o)
end
end
local function merge_tables(t1, t2)
local t = table.copy(t1)
for k,v in pairs(t2) do
t[k] = v
end
return t
end
local function get_base_under_light(pos)
pos = table.copy(pos)
local y_dist = 0
local node = minetest.get_node(pos)
while minetest.get_item_group(node.name, "spotlights_base") == 0 and (spotlight_undiminishing_distance == 0 or y_dist <= spotlight_undiminishing_distance+spotlight_decaying_distance) do
pos = vector.subtract(pos, {x = 0, y = 1, z = 0})
y_dist = y_dist + 1
node = minetest.get_node(pos)
end
return pos
end
local function spotlight_on_construct(pos_this, pos_base_under_light)
local pos_above = vector.add(pos_this, {x = 0, y = 1, z = 0})
local pos_above_that = vector.add(pos_above, {x = 0, y = 1, z = 0})
local pos_below = vector.subtract(pos_this, {x = 0, y = 1, z = 0})
if pos_base_under_light == nil then pos_base_under_light = get_base_under_light(pos_this) end
local node_this = minetest.get_node(pos_this)
local node_above = minetest.get_node(pos_above)
local node_above_that = minetest.get_node(pos_above_that)
local node_below = minetest.get_node(pos_below)
local node_base_under_light = minetest.get_node(pos_base_under_light)
if node_base_under_light.name == ("spotlights:base") then
local distance = vector.distance(pos_base_under_light, pos_above)
if distance <= spotlight_undiminishing_distance + spotlight_decaying_distance then
--print('setting light at '..distance)
if distance <= spotlight_undiminishing_distance then
if node_above.name == "air" or minetest.get_item_group(node_above.name, "spotlights_beam") ~= 0 then
if node_above_that.name ~= "air" and minetest.get_item_group(node_above_that.name, "spotlights_beam") == 0 and (not spotlight_permeate_paramtype_light or not perfectly_transparent_nodes[node_above_that.name]) then
if node_above.name ~= "spotlights:beam_"..minetest.LIGHT_MAX then
print('spotlight '..distance..': lvl '..minetest.LIGHT_MAX..' (spotlight hit full force!) || '..node_above.name..', '..node_above_that.name)
minetest.set_node(pos_above, {name = "spotlights:beam_"..minetest.LIGHT_MAX})
end
else
if distance <= 2 then
if node_above.name ~= "spotlights:beam_hot" then
print('spotlight '..distance..': HOT!! || '..node_above.name)
minetest.set_node(pos_above, {name = "spotlights:beam_hot"})
end
else
if node_above.name ~= "spotlights:beam_"..spotlight_beam_shimmer then
print('spotlight '..distance..': lvl '..spotlight_beam_shimmer..' || '..node_above.name)
minetest.set_node(pos_above, {name = "spotlights:beam_"..spotlight_beam_shimmer})
end
end
end
elseif spotlight_permeate_paramtype_light and minetest.registered_nodes[node_above.name].paramtype == 'light' then
-- permeate through
print('spotlight permeating through '..node_above.name..'... ('..distance..')')
spotlight_on_construct(pos_above)
else
if node_this.name ~= "spotlights:beam_"..minetest.LIGHT_MAX then
print('spotlight '..(distance-1)..' GLITCH: should be spotlights:beam_'..minetest.LIGHT_MAX..' but is '..node_this.name)
end
end
else
local leftover_light_level = math.ceil((1 - (distance - spotlight_undiminishing_distance) / (spotlight_decaying_distance+1)) * (minetest.LIGHT_MAX-1))
if node_above.name == "air" or minetest.get_item_group(node_above.name, "spotlights_beam") ~= 0 then
if node_above_that.name ~= "air" and minetest.get_item_group(node_above_that.name, "spotlights_beam") == 0 then
if node_above.name ~= "spotlights:beam_"..leftover_light_level then
print('spotlight '..distance..': lvl '..leftover_light_level..' (spotlight hit!) || '..node_above.name..', '..node_above_that.name)
minetest.set_node(pos_above, {name = "spotlights:beam_"..leftover_light_level})
end
else
local leftover_beam = math.min(spotlight_beam_shimmer, math.ceil(leftover_light_level/2))
if node_above.name ~= "spotlights:beam_" .. leftover_beam then
print('spotlight '..distance..': lvl '..leftover_beam..' (decaying to '..leftover_light_level..') || '..node_above.name)
minetest.set_node(pos_above, {name = "spotlights:beam_" .. leftover_beam})
end
end
elseif spotlight_permeate_paramtype_light and minetest.registered_nodes[node_above.name].paramtype == 'light' then
-- permeate through
spotlight_on_construct(pos_above)
else
--[[if node_this ~= "spotlights:beam_"..leftover_light_level or node_this ~= "spotlights:beam_"..(leftover_light_level+1) then
-- checking for leftover_light_level+1 as well, as this is set on the previous node and thus we might be 1 too low now
print('spotlight '..distance..': GLITCH: should be around spotlights:beam_'..leftover_light_level..' but is '..node_this.name)
end]]--
end
end
end
end
end
local function spotlight_on_destruct(pos)
local above = vector.add(pos, {x = 0, y = 1, z = 0})
local below = vector.subtract(pos, {x = 0, y = 1, z = 0})
if minetest.get_item_group(minetest.get_node(above).name, "spotlights_beam") ~= 0 and (not spotlight_permeate_paramtype_light or minetest.registered_nodes[minetest.get_node(below).name].paramtype ~= 'light') then
minetest.remove_node(above)
end
end
local function spotlight_on_destruct_base(pos)
local above = vector.add(pos, {x = 0, y = 1, z = 0})
if minetest.get_item_group(minetest.get_node(above).name, "spotlights_beam") ~= 0 then
minetest.remove_node(above)
end
end
local function spotlight_on_timer(pos)
local pos_base_under_light = get_base_under_light(pos)
if minetest.get_node(pos_base_under_light).name ~= "spotlights:base" then
minetest.remove_node(pos)
else
spotlight_on_construct(pos, pos_base_under_light)
end
return true
end
local function make_on_construct()
return function(pos)
minetest.get_node_timer(pos):start(1)
return spotlight_on_construct(pos)
end
end
local function make_on_destruct()
return function(pos)
return spotlight_on_destruct(pos)
end
end
local function make_on_timer()
return function(pos)
return spotlight_on_timer(pos)
end
end
minetest.register_node("spotlights:base", {
description = "Spotlight",
tiles = {"beacons_base_top.png", "beacons_base_bottom.png", "beacons_base_side.png"},
groups = {spotlights_base = 1, cracky = 2},
is_ground_content = false,
paramtype = "light",
light_source = spotlight_base_shimmer,
on_rotate = function() end, -- TODO
on_construct = make_on_construct(),
on_destruct = make_on_destruct_base(),
on_timer = make_on_timer(),
})
if minetest.get_modpath("default") then
minetest.override_item("spotlights:base", {sounds = default.node_sound_metal_defaults()})
minetest.register_craft({
output = "spotlights:base",
recipe = {
{"default:steel_ingot", "default:meselamp", "default:steel_ingot",},
{"default:steel_ingot", "default:meselamp", "default:steel_ingot",},
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot",},
},
})
end
local lightPoint = {
drawtype = "airlike",
-- drawtype = "plantlike",
-- tiles = {"beacons_light.png"},
paramtype = "light",
groups = {spotlights_beam = 1, not_in_creative_inventory = 1},
sunlight_propagates = true,
can_dig = false,
walkable = false,
buildable_to = true,
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
on_blast = function() end,
on_construct = make_on_construct(),
on_destruct = make_on_destruct(),
on_timer = make_on_timer(),
}
minetest.register_node("spotlights:beam_hot", merge_tables(lightPoint, {
light_source = spotlight_base_shimmer,
damage_per_second = 1,
}))
for strength=1,minetest.LIGHT_MAX do
--print('register_node spotlights:beam_'..strength..' (max: '..minetest.LIGHT_MAX..')')
minetest.register_node("spotlights:beam_" .. strength, merge_tables(lightPoint, {
light_source = strength,
}))
--print('registered spotlights:beam_'..strength..':\n'..dump(merge_tables(lightPoint, {
-- light_source = strength,
--})))
end
name = spotlights
description = "Adds spotlights - light sources that shine light to a spot over a long distance."
\ No newline at end of file
screenshot.png

54.2 KiB

# Spotlights will carry over a certain distance without diminishing, and then decay in strength.
spotlight_undiminishing_distance (Spotlight undiminishing distance) int 12
# Spotlights will carry over a certain distance without diminishing, and then decay in strength.
spotlight_decaying_distance (Spotlight decaying distance) int 13
# The beam of the spotlight will cast a bright light when hitting a block, and only shimmer dimly before that.
spotlight_base_shimmer (Spotlight base shimmer) int 3
# The beam of the spotlight will cast a bright light when hitting a block, and only shimmer dimly before that.
spotlight_beam_shimmer (Spotlight beam shimmer) int 2
# Spotlights can continue to shine through nodes like glass, plants etc. Most still produce a bright light when hit, selected ones (like glass) do not.
spotlight_permeate_paramtype_light (Spotlight permeates through nodes of paramtype "light") bool true
\ No newline at end of file
textures/beacons_base_bottom.png

1.09 KiB

textures/beacons_base_side.png

1.12 KiB

textures/beacons_base_top.png

1.12 KiB

textures/beacons_light.png

1.1 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment