From e5e1b6ab9ece3217e3dff953121df130a7828920 Mon Sep 17 00:00:00 2001 From: David G Date: Thu, 12 Mar 2020 20:38:05 -0700 Subject: [PATCH] Switch to cone of light. --- README.md | 19 ++++++++------- init.lua | 70 +++++++++++++++++++++++-------------------------------- mod.conf | 2 +- 3 files changed, 41 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index c9bb97c..061af2b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ Wand of Illumination [wand\_of\_illumination] =========================================== -Provides a wand that when used, lights up an entire room—but only for a moment. +Provides a wand that when used, lights up what's in front—but only for a moment. -Alternatively, provides a 1900-era flash-lamp, and a futuristic super-lamp for those without a sense of magic. +Alternatively, provides a 1900-era flash\_lamp and a futuristic super\_lamp, for those without a sense of magic. ![Wand of Illumination Screenshot](compare.gif "Torch vs Normal vs Extended Range") @@ -12,9 +12,10 @@ Alternatively, provides a 1900-era flash-lamp, and a futuristic super-lamp for t Features -------- -- **New:** Choice of original magic wand, 1900-era flash-lamp, or mese-powered super-lamp. -- On **left** click, places a sphere of invisible lights around the player. -- On shift-**left**-click (or aux-**left**-click), creates an extended sphere of lights. +- **New:** Now just lights up 120° in direction player is pointed. +- **New:** Choice of original magic wand, 1900-era flash\_lamp, or mese-powered super\_lamp. +- On **left** click, places a cone of invisible lights in front of the player. +- On shift-**left**-click (or aux-**left**-click), creates an extended cone of lights. - Doesn't place lights where already brightly lit. - Uses node_timers to cause these light nodes to gradually fade away. - Wear added, so all lamps will only work for a limited number of uses. @@ -23,7 +24,6 @@ Features *(Note that narrow passages, like dungeon corridors, may not light up, if they don't fall on the 4x light spacing grid.)* - WIP—Things that still need to be done. ---------------------------------- @@ -36,6 +36,9 @@ WIP—Things that still need to be done. Note about number of lights used -------------------------------- + +**Note:** *These numbers were for a full sphere. For r=40 and a 120° cone of light, only 67000 nodes are scanned, and 1044 lights are placed.* + To allow this mod to light up all the narrow twisty tunnels underground, the spacing of the lights placed needs to be as small as possible. However, I also want to minimize how many lights this mod places. With testing, a spacing of four seemed to give light coverage in most tunnels, with just a few that were too narrow to have any lights. However, with the fixed spacing I'm using, this still adds up to a large number of lights. I did some tests in the sky, which gives the worst case numbers: @@ -54,9 +57,9 @@ Here's a screenshot with r=15 and r=50 (using meselamps to make the lights visib Dependencies ------------ -- Craft recipes need default and tnt mods. - Optionally depends on Wuzzy's mana mod. -- +- Optionally depends on default and tnt mods to enable craft recipes. + Craft Recipes ------------- diff --git a/init.lua b/init.lua index cdae59f..678aec4 100644 --- a/init.lua +++ b/init.lua @@ -1,17 +1,17 @@ -- Wand of Illumination [wand_of_illumination] -- by David G (kestral246@gmail.com) --- 2020-02-14 +-- 2020-03-12 --- Provides a wand that when used lights up an entire room, but only for a moment. --- Also provides a flash-lamp and a super-lamp for those without magic. +-- Lights up what's in front, but only for a moment. +-- Provides a wand, flash_lamp, and super_lamp. --- How bright to make lights +-- How bright and wide to make lights. -- For reference, the default:torch has a brightness of 12. local brightness_value = 11 -local darken_torches = false +local light_cone = math.pi/3 -- corresponds to 120° --- Maximum number of nodes to check ((4/3)*pi*r^3). -local maxcount = 180000 -- corresponds to r_max = 35 +-- Maximum number of nodes to check (use debug to determine). +local maxcount = 100000 -- The wear, mana, and radius can now be set independently for each lamp tool. -- For extended range, all of these values are doubled. @@ -32,19 +32,6 @@ if minetest.get_modpath("mana") ~= nil then using_mana_mod = true end --- Optionally darken default torches, to make lamps more valuable. -if darken_torches then - minetest.override_item("default:torch", { - light_source = 8 - }) - minetest.override_item("default:torch_wall", { - light_source = 8 - }) - minetest.override_item("default:torch_ceiling", { - light_source = 8 - }) -end - local scanned = {} -- Set containing scanned nodes, so they don't get scanned multiple times. local tocheck = {} -- Table of nodes to check. local tolight = {} -- Table of nodes that need to be converted to fill lights. @@ -115,14 +102,12 @@ local tlength = function(T) return count end -local square = function(x) - return x * x -end - -- Scan neighboring nodes, flag for checking if air. -local scan_node = function(pname, pos, origin, maxdist2) - -- Add y to test, so make search pattern a sphere. - if square(pos.x - origin.x) + square(pos.y - origin.y) + square(pos.z - origin.z) <= maxdist2 then +local scan_node = function(pname, pos, origin, vdir, maxdist) + -- Update to send out a cone of light in direction pointed. + -- Need small sphere to get cone of light out. + local radius = vector.distance(origin, pos) + if radius <= 2 or (radius <= maxdist and vector.angle(vdir, vector.direction(origin, pos)) < light_cone) then local enc_pos = minetest.hash_node_position(pos) if scanned[pname][enc_pos] ~= true then -- hasn't been scanned local name = minetest.get_node(pos).name @@ -135,15 +120,15 @@ local scan_node = function(pname, pos, origin, maxdist2) end -- To check, scan all neighbors and determine if this node needs to be converted to light. -local check_node = function(pname, pos, origin, maxdist2) +local check_node = function(pname, pos, origin, vdir, maxdist) local enc_pos = minetest.hash_node_position(pos) local name = minetest.get_node(pos).name - scan_node(pname, vector.add(pos, {x=0,y=0,z=1}), origin, maxdist2) -- north - scan_node(pname, vector.add(pos, {x=1,y=0,z=0}), origin, maxdist2) -- east - scan_node(pname, vector.add(pos, {x=0,y=0,z=-1}), origin, maxdist2) -- south - scan_node(pname, vector.add(pos, {x=-1,y=0,z=0}), origin, maxdist2) -- west - scan_node(pname, vector.add(pos, {x=0,y=-1,z=0}), origin, maxdist2) -- down - scan_node(pname, vector.add(pos, {x=0,y=1,z=0}), origin, maxdist2) -- up + scan_node(pname, vector.add(pos, {x=0,y=0,z=1}), origin, vdir, maxdist) -- north + scan_node(pname, vector.add(pos, {x=1,y=0,z=0}), origin, vdir, maxdist) -- east + scan_node(pname, vector.add(pos, {x=0,y=0,z=-1}), origin, vdir, maxdist) -- south + scan_node(pname, vector.add(pos, {x=-1,y=0,z=0}), origin, vdir, maxdist) -- west + scan_node(pname, vector.add(pos, {x=0,y=-1,z=0}), origin, vdir, maxdist) -- down + scan_node(pname, vector.add(pos, {x=0,y=1,z=0}), origin, vdir, maxdist) -- up if name == "air" and ((pos.x%4 == 0 and pos.y%8 == 0 and pos.z%4 == 0) or (pos.x%4 == 2 and pos.y%8 == 4 and pos.z%4 == 2)) and minetest.get_node_light(pos) < brightness_value then @@ -154,12 +139,16 @@ end local use_wand = function(player, itemstack, radius, wear, mana) local pname = player:get_player_name() local pos = vector.add(vector.round(player:get_pos()), {x=0,y=1,z=0}) -- position of wand + local theta = math.fmod(player:get_look_horizontal() + math.pi/2, 2*math.pi) + local phi = player:get_look_vertical() + math.pi/2 + local vdir = vector.normalize({x=math.sin(phi)*math.cos(theta), y=math.cos(phi), z=math.sin(phi)*math.sin(theta)}) + -- For debug only. + --minetest.chat_send_player(pname, "theta = "..tostring(theta)..", phi = "..tostring(phi)..", vdir = "..tostring(minetest.serialize(vdir))) local key_stats = player:get_player_control() - local radius2 = radius * radius -- normal local wear_cost = wear local mana_cost = mana if key_stats.sneak or key_stats.aux1 then -- extended - radius2 = 3 * radius2 -- now trying 1.732x + radius = 2 * radius wear_cost = 2 * wear_cost mana_cost = 2 * mana_cost end @@ -172,11 +161,10 @@ local use_wand = function(player, itemstack, radius, wear, mana) table.insert(tocheck[pname], minetest.hash_node_position(pos)) local count = 1 while count <= table.getn(tocheck[pname]) and count <= maxcount do - check_node(pname, minetest.get_position_from_hash(tocheck[pname][count]), pos, radius2) + check_node(pname, minetest.get_position_from_hash(tocheck[pname][count]), pos, vdir, radius) count = count + 1 end count = count - 1 - local toadd = tlength(tolight[pname]) if debug then -- print statistics minetest.debug("wand_of_illumination: y = "..tostring(pos.y)..", scan = ".. tostring(tlength(scanned[pname]))..", check = "..tostring(count)..", lights = ".. @@ -206,7 +194,7 @@ minetest.register_tool("wand_of_illumination:wand", { inventory_image = "wand_of_illumination.png", stack_max = 1, on_use = function(itemstack, player, pointed_thing) - local radius = 15 -- or 26 + local radius = 15 -- or 30 local wear = math.floor(65535/25) local mana = 100 local worn_item = use_wand(player, itemstack, radius, wear, mana) @@ -219,7 +207,7 @@ minetest.register_tool("wand_of_illumination:flash_lamp", { inventory_image = "flash_lamp.png", stack_max = 1, on_use = function(itemstack, player, pointed_thing) - local radius = 10 -- or 17.3 + local radius = 10 -- or 20 local wear = math.floor(65535/15) local mana = 0 local worn_item = use_wand(player, itemstack, radius, wear, mana) @@ -232,7 +220,7 @@ minetest.register_tool("wand_of_illumination:super_lamp", { inventory_image = "super_lamp.png", stack_max = 1, on_use = function(itemstack, player, pointed_thing) - local radius = 20 -- or 34.6 + local radius = 20 -- or 40 local wear = math.floor(65535/40) local mana = 0 local worn_item = use_wand(player, itemstack, radius, wear, mana) diff --git a/mod.conf b/mod.conf index 5099a03..36cd095 100644 --- a/mod.conf +++ b/mod.conf @@ -1,3 +1,3 @@ name = wand_of_illumination -description = Light up an entire room, but only for a moment. +description = Lights up what's in front, but only for a moment. optional_depends = mana, default, tnt