diff --git a/diff/walking_light.diff/init.lua b/diff/walking_light.diff/init.lua index 515a919..a24fb5a 100644 --- a/diff/walking_light.diff/init.lua +++ b/diff/walking_light.diff/init.lua @@ -1,125 +1,528 @@ +-- list of all players seen by minetest.register_on_joinplayer local players = {} +-- all player positions last time light was updated: {player_name : {x, y, z}} local player_positions = {} +-- all light positions of light that currently is created {player_name : {i: {x, y, z}} +local light_positions = {} +-- last item seen wielded by players local last_wielded = {} +-- toggles debug mode +local walking_light_debug = false +-- name of light node, changed by toggling debug mode +local walking_light_node = nil + +-- initialize walking light +walking_light = {} + +-- list of items that use walking light +local light_items = { + "default:torch", "walking_light:pick_mese", + "walking_light:helmet_diamond", "walking_light:megatorch" +} + +function walking_light.addLightItem(item) + for I in pairs(light_items) do + if item == light_items[I] then + minetest.log("warning", "[walking_light] \"" .. item .. "\" is already light item.") + return + end + end + + table.insert(light_items, -1, item) +end + +function walking_light.getLightItems() + return light_items +end + + +-- from http://lua-users.org/wiki/IteratorsTutorial +-- useful for removing things from a table because removing from the middle makes it skip elements otherwise +function ripairs(t) + local function ripairs_it(t,i) + i=i-1 + local v=t[i] + if v==nil then return v end + return i,v + end + return ripairs_it, t, #t+1 +end + +-- formats a vector with shorter output than dump +local function dumppos(pos) + if pos == nil then + return "nil" + end + local x = "nil" + if pos.x then + x = pos.x + end + local y = "nil" + if pos.y then + y = pos.y + end + local z = "nil" + if pos.z then + z = pos.z + end + + return "(" .. x .. "," .. y .. "," .. z .. ")" +end + +-- formats a table containing vectors with shorter output than dump +local function dumppostable(t) + if t == nil then + return "nil" + end + if #t == 0 then + return "0{}" + end + + ret = #t .. "{\n" + for i,pos in ipairs(t) do + ret = ret .. " " .. dumppos(pos) .. "\n" + end + ret = ret .. "}" + return ret +end + +function mt_get_node_or_nil(pos) + if pos == nil then + print("ERROR: walking_light.mt_get_node_or_nil(), pos is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + return minetest.get_node_or_nil(pos) +end + +function mt_add_node(pos, sometable) + if pos == nil then + print("ERROR: walking_light.mt_add_node(), pos is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + if sometable == nil then + print("ERROR: walking_light.mt_add_node(), sometable is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + minetest.add_node(pos,sometable) +end + function round(num) return math.floor(num + 0.5) end +local function poseq(pos1, pos2) + if pos1 == nil and pos2 == nil then + return true + end + if pos1 == nil or pos2 == nil then + return false + end + return pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z +end + +-- return true if the player moved since last player_positions update +local function player_moved(player) + local player_name = player:get_player_name() + local pos = player:getpos() + local rounded_pos = vector.round(pos) + local oldpos = player_positions[player_name] + if oldpos == nil or not poseq(rounded_pos, oldpos) then + -- if oldpos is nil, we assume they just logged in, so consider them moved +-- print("DEBUG: walking_light, player_moved(); moved = true; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos)) + return true + end +-- print("DEBUG: walking_light, player_moved(); moved = false; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos)) + return false +end + +-- same as table.remove(t,remove_pos), but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?) +local function table_remove_pos(t, remove_pos) +-- local DEBUG_oldsize = #t + + for i,pos in ipairs(t) do + if poseq(pos, remove_pos) then + table.remove(t, i) + break + end + end + +-- local DEBUG_newsize = #t +-- print("DEBUG: walking_light.table_remove_pos(), oldsize = " .. DEBUG_oldsize .. ", newsize = " .. DEBUG_newsize) +end + +-- same as t[remove_pos], but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?) +local function table_contains_pos(t, remove_pos) + for i,pos in ipairs(t) do + if poseq(pos, remove_pos) then + return true + end + end + return false +end + +-- same as table.insert(t,pos) but makes sure it is not duplicated +local function table_insert_pos(t, pos) + if not table_contains_pos( pos ) then + table.insert(t, pos) + end +end + +local function is_light(node) + if node ~= nil and ( node.name == "walking_light:light" or node.name == "walking_light:light_debug" ) then + return true + end + return false +end + +-- removes light at the given position +-- player is optional +local function remove_light(player, pos) + local player_name + if player then + player_name = player:get_player_name() + end + local node = mt_get_node_or_nil(pos) + if is_light(node) then + mt_add_node(pos,{type="node",name="air"}) + if player_name then + table_remove_pos(light_positions[player_name], pos) + end + else + if node ~= nil then + print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was " .. node.name) + table_remove_pos(light_positions[player_name], pos) + else + print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was nil") + end + end +end + +-- removes all light owned by a player +local function remove_light_player(player) + local player_name = player:get_player_name() + + for i,old_pos in ripairs(light_positions[player_name]) do + if old_pos then +-- print("DEBUG: walking_light.remove_light_player(), removing old light; old_pos = " .. dumppos(old_pos)) + remove_light(player, old_pos) + end + end +-- print("DEBUG: walking_light.remove_light_player(), done; light_positions = " .. dumppostable(light_positions[player_name])) +end + +local function can_add_light(pos) + local node = mt_get_node_or_nil(pos) + if node == nil or node.name == "air" then +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true") + return true + elseif is_light(node) then +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true") + return true + end +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", false") + return false +end + +-- old function returns pos instead of table, for only one position +local function pick_light_position_regular(player, pos) + if can_add_light(pos) then + return {pos} + end + + local pos2 + + -- if pos is not possible, try the old player position first, to make it more likely that it has a line of sight + local player_name = player:get_player_name() + local oldplayerpos = player_positions[player_name] + if oldplayerpos and can_add_light( vector.new(oldplayerpos.x, oldplayerpos.y + 1, oldplayerpos.z) ) then + return oldplayerpos + end + + -- if not, try all positions around the pos + pos2 = vector.new(pos.x + 1, pos.y, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x - 1, pos.y, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y, pos.z + 1) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y, pos.z - 1) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y + 1, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y - 1, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + return nil +end + +-- new function, returns table +local function pick_light_position_radius(player, pos, ret, radius) + local pos2 + local step = 4 + local unstep = 1/step + + for x = pos.x - radius, pos.x + radius, step do + for y = pos.y - radius, pos.y + radius, step do + for z = pos.z - radius, pos.z + radius, step do + pos2 = vector.new(round(x*unstep)*step, round(y*unstep)*step, round(z*unstep)*step) + distance = math.sqrt(math.pow(pos.x - x, 2) + math.pow(pos.y - y, 2) + math.pow(pos.z - z, 2)) + if distance <= radius and can_add_light( pos2 ) then + table.insert(ret, pos2) + end + end + end + end + + return ret +end + +local function pick_light_position_mega(player, pos) + local ret = {} + + if can_add_light(pos) then + table.insert(ret, pos) + end + pick_light_position_radius(player, pos, ret, 10) + + return ret +end + +local function pick_light_position(player, pos, light_item) + if light_item == "walking_light:megatorch" then + return pick_light_position_mega(player, pos) + end + return pick_light_position_regular(player, pos) +end + +-- adds light at the given position +local function add_light(player, pos) + local player_name = player:get_player_name() + local node = mt_get_node_or_nil(pos) + if node == nil then + -- don't do anything for nil blocks... they are non-loaded blocks, so we don't want to overwrite anything there +-- print("DEBUG: walking_light.add_light(), node is nil, pos = " .. dumppos(pos)) + return false + elseif node.name == "air" then + -- when the node that is already there is air, add light + mt_add_node(pos,{type="node",name=walking_light_node}) + if not table_contains_pos(light_positions[player_name], pos) then + table_insert_pos(light_positions[player_name], pos) + end + +-- if node then +-- print("DEBUG: add_light(), node.name = " .. node.name .. ", pos = " .. dumppos(pos)) +-- else +-- print("DEBUG: add_light(), node.name = nil, pos = " .. dumppos(pos)) +-- end + return true + elseif is_light(node) then + -- no point in adding light where it is already, but we should assign it to the player so it gets removed (in case it has no player) +-- print("DEBUG: add_light(), not adding; node.name = " .. node.name .. ", pos = " .. dumppos(pos)) + + if not table_contains_pos(light_positions[player_name], pos) then + table_insert_pos(light_positions[player_name], pos) + end + + return true + end +-- print("DEBUG: add_light(), not adding; node.name = " .. node.name) + return false +end + +-- updates all the light around the player, depending on what they are wielding +local function update_light_player(player) + -- if there is no player, there can be no update + if not player then + return + end + + -- figure out if they wield light; this will be nil if not + local wielded_item = get_wielded_light_item(player) + + local player_name = player:get_player_name() + local pos = player:getpos() + local rounded_pos = vector.round(pos) + + -- check for a nil node where the player is; if it is nil, we assume the block is not loaded, so we return without updating player_positions + -- that way, it should add light next step + local node = mt_get_node_or_nil(rounded_pos) + if node == nil then + return + end + + if not player_moved(player) and wielded_item == last_wielded[player_name] then + -- no update needed if the wiedled light item is the same as before (including nil), and the player didn't move + return + end + last_wielded[player_name] = wielded_item; + + local wantlightpos = nil + local wantpos = vector.new(rounded_pos.x, rounded_pos.y + 1, rounded_pos.z) + if wielded_item then + -- decide where light should be + wantlightpos = pick_light_position(player, wantpos, wielded_item) +-- print("DEBUG: walking_light update_light_player(); wantpos = " .. dumppos(wantpos) .. ", wantlightpos = " .. dumppos(wantlightpos)) + end + + if wielded_item and wantlightpos then + -- add light that isn't already there + for i,newpos in ipairs(wantlightpos) do + add_light(player, newpos) + end + end + + -- go through all light owned by the player to remove all but what should be kept + for i,oldlightpos in ripairs(light_positions[player_name]) do + if not wantlightpos or oldlightpos and oldlightpos.x and not table_contains_pos(wantlightpos, oldlightpos) then + remove_light(player, oldlightpos) + end + end + + player_positions[player_name] = vector.round(pos) + +-- print("DEBUG: walking_light.update_light_player(): wantlightpos = " .. dumppostable(wantlightpos) .. ", light_positions = " .. dumppostable(light_positions[player_name])) +end + +local function update_light_all() + -- go through all players to check + for i,player_name in ipairs(players) do + local player = minetest.get_player_by_name(player_name) + update_light_player(player) + end +end + +-- return true if item is a light item +function is_light_item(item) + for I in pairs(light_items) do + if item == light_items[I] then + return true + end + end + return false +end + +-- returns a string, the name of the item found that is a light item +function get_wielded_light_item(player) + local wielded_item = player:get_wielded_item():get_name() + if is_light_item(wielded_item) then + return wielded_item + end + + -- check equipped armor - requires unified_inventory maybe + local player_name = player:get_player_name() + if player_name then + local armor_inv = minetest.get_inventory({type="detached", name=player_name.."_armor"}) + if armor_inv then +-- print( dump(armor_inv:get_lists()) ) + local item_name = "walking_light:helmet_diamond" + local stack = ItemStack(item_name) + if armor_inv:contains_item("armor", stack) then + return item_name + end + end + end + + return nil +end + +-- return true if player is wielding a light item +function wielded_light(player) + return get_wielded_light_item(player) ~= nil +end + minetest.register_on_joinplayer(function(player) local player_name = player:get_player_name() table.insert(players, player_name) - last_wielded[player_name] = player:get_wielded_item():get_name() + last_wielded[player_name] = get_wielded_light_item(player) local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - local wielded_item = player:get_wielded_item():get_name() - if wielded_item ~= "default:torch" and wielded_item ~= "walking_light:pick_mese" then - -- Neuberechnung des Lichts erzwingen - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - end - player_positions[player_name] = {} - player_positions[player_name]["x"] = rounded_pos.x; - player_positions[player_name]["y"] = rounded_pos.y; - player_positions[player_name]["z"] = rounded_pos.z; + player_positions[player_name] = nil + light_positions[player_name] = {} + update_light_player(player) end) minetest.register_on_leaveplayer(function(player) local player_name = player:get_player_name() for i,v in ipairs(players) do - if v == player_name then + if v == player_name then table.remove(players, i) - last_wielded[player_name] = nil - -- Neuberechnung des Lichts erzwingen - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - player_positions[player_name]["x"] = nil - player_positions[player_name]["y"] = nil - player_positions[player_name]["z"] = nil - player_positions[player_name]["m"] = nil - player_positions[player_name] = nil end end + last_wielded[player_name] = false + remove_light_player(player) + player_positions[player_name]=nil end) minetest.register_globalstep(function(dtime) for i,player_name in ipairs(players) do - local player = minetest.env:get_player_by_name(player_name) - local wielded_item = player:get_wielded_item():get_name() - if wielded_item == "default:torch" or wielded_item == "walking_light:pick_mese" then - -- Fackel ist in der Hand - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - if (last_wielded[player_name] ~= "default:torch" and last_wielded[player_name] ~= "walking_light:pick_mese") or (player_positions[player_name]["x"] ~= rounded_pos.x or player_positions[player_name]["y"] ~= rounded_pos.y or player_positions[player_name]["z"] ~= rounded_pos.z) then - -- Fackel gerade in die Hand genommen oder zu neuem Node bewegt - local is_air = minetest.env:get_node_or_nil(rounded_pos) - if is_air == nil or (is_air ~= nil and (is_air.name == "air" or is_air.name == "walking_light:light")) then - -- wenn an aktueller Position "air" ist, Fackellicht setzen - minetest.env:add_node(rounded_pos,{type="node",name="walking_light:light"}) - end - if (player_positions[player_name]["x"] ~= rounded_pos.x or player_positions[player_name]["y"] ~= rounded_pos.y or player_positions[player_name]["z"] ~= rounded_pos.z) then - -- wenn Position geänder, dann altes Licht löschen - local old_pos = {x=player_positions[player_name]["x"], y=player_positions[player_name]["y"], z=player_positions[player_name]["z"]} - -- Neuberechnung des Lichts erzwingen - local is_light = minetest.env:get_node_or_nil(old_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - minetest.env:add_node(old_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(old_pos,{type="node",name="air"}) - end - end - -- gemerkte Position ist nun die gerundete neue Position - player_positions[player_name]["x"] = rounded_pos.x - player_positions[player_name]["y"] = rounded_pos.y - player_positions[player_name]["z"] = rounded_pos.z - end - - last_wielded[player_name] = wielded_item; - elseif last_wielded[player_name] == "default:torch" or last_wielded[player_name] == "walking_light:pick_mese" then - -- Fackel nicht in der Hand, aber beim letzten Durchgang war die Fackel noch in der Hand - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - repeat - local is_light = minetest.env:get_node_or_nil(rounded_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - -- minetest.env:remove_node(rounded_pos) - -- Erzwinge Neuberechnung des Lichts - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - end - until minetest.env:get_node_or_nil(rounded_pos) ~= "walking_light:light" - local old_pos = {x=player_positions[player_name]["x"], y=player_positions[player_name]["y"], z=player_positions[player_name]["z"]} - repeat - is_light = minetest.env:get_node_or_nil(old_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - -- minetest.env:remove_node(old_pos) - -- Erzwinge Neuberechnung des Lichts - minetest.env:add_node(old_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(old_pos,{type="node",name="air"}) - end - until minetest.env:get_node_or_nil(old_pos) ~= "walking_light:light" - last_wielded[player_name] = wielded_item + local player = minetest.get_player_by_name(player_name) + if player ~= nil then + update_light_player(player) + else + table.remove(players, i) end end end) -minetest.register_node("walking_light:light", { +minetest.register_node("walking_light:light_debug", { drawtype = "glasslike", - tile_images = {"walking_light.png"}, - -- tile_images = {"walking_light_debug.png"}, + tiles = {"walking_light_debug.png"}, inventory_image = minetest.inventorycube("walking_light.png"), paramtype = "light", walkable = false, is_ground_content = true, - light_propagates = true, sunlight_propagates = true, light_source = 14, selection_box = { - type = "fixed", - fixed = {0, 0, 0, 0, 0, 0}, - }, + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, }) + +minetest.register_node("walking_light:light", { + drawtype = "glasslike", + tiles = {"walking_light.png"}, + inventory_image = minetest.inventorycube("walking_light.png"), + paramtype = "light", + walkable = false, + is_ground_content = true, + sunlight_propagates = true, + light_source = 14, + selection_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, +}) + +function update_walking_light_node() + if walking_light_debug then + walking_light_node = "walking_light:light_debug" + else + walking_light_node = "walking_light:light" + end +end +update_walking_light_node() + minetest.register_tool("walking_light:pick_mese", { description = "Mese Pickaxe with light", inventory_image = "walking_light_mesepick.png", @@ -135,6 +538,65 @@ minetest.register_tool("walking_light:pick_mese", { }, }) +minetest.register_tool("walking_light:helmet_diamond", { + description = "Diamond Helmet with light", + inventory_image = "walking_light_inv_helmet_diamond.png", + wield_image = "3d_armor_inv_helmet_diamond.png", + groups = {armor_head=15, armor_heal=12, armor_use=100}, + wear = 0, +}) + +minetest.register_node("walking_light:megatorch", { + description = "Megatorch", + drawtype = "torchlike", + tiles = { + { + name = "default_torch_on_floor_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + { + name="default_torch_on_ceiling_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + { + name="default_torch_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + }, + inventory_image = "default_torch_on_floor.png", + wield_image = "default_torch_on_floor.png", + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + is_ground_content = false, + walkable = false, + light_source = 14, + selection_box = { + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, + }, + groups = {choppy=2,dig_immediate=3,flammable=1,attached_node=1}, + legacy_wallmounted = true, + --sounds = default.node_sound_defaults(), +}) + minetest.register_craft({ output = 'walking_light:pick_mese', recipe = { @@ -142,3 +604,81 @@ minetest.register_craft({ {'default:pick_mese'}, } }) + +minetest.register_craft({ + output = 'walking_light:helmet_diamond', + recipe = { + {'default:torch'}, + {'3d_armor:helmet_diamond'}, + } +}) + +minetest.register_craft({ + output = 'walking_light:megatorch', + recipe = { + {'default:torch', 'default:torch', 'default:torch'}, + {'default:torch', 'default:torch', 'default:torch'}, + {'default:torch', 'default:torch', 'default:torch'}, + } +}) + +minetest.register_chatcommand("walking_light_clear_light", { + params = "", + description = "Remove light nodes from the area", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use mapclearlight" + end + + local pos = vector.round(minetest.get_player_by_name(name):getpos()) + local size = tonumber(param) or 40 + + for i,v in ipairs({"walking_light:light", "walking_light:light_debug"}) do + point = minetest.find_node_near(pos, size/2, v) + while point do + remove_light(nil, point) + oldpoint = point + point = minetest.find_node_near(pos, size/2, v) + if poseq(oldpoint, point) then + return false, "Failed... infinite loop detected" + end + end + end + return true, "Done." + end, +}) + +minetest.register_chatcommand("walking_light_add_light", { + params = "", + description = "Add walking_light:light to a position, without a player owning it", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use mapaddlight" + end + + local pos = vector.round(minetest.get_player_by_name(name):getpos()) + pos = vector.new(pos.x, pos.y + 1, pos.z) + + if pos then + mt_add_node(pos,{type="node",name=walking_light_node}) + end + + return true, "Done." + end, +}) + +minetest.register_chatcommand("walking_light_debug", { + description = "Change to debug mode, so light blocks are visible.", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use walking_light_debug" + end + + walking_light_debug = not walking_light_debug + update_walking_light_node() + + return true, "Done." + end, +}) + +-- vim: ts=4 sw=4 softtabstop=4 smarttab noexpandtab diff --git a/diff/walking_light.diff/init.lua.diff b/diff/walking_light.diff/init.lua.diff index f62f26c..9030280 100644 --- a/diff/walking_light.diff/init.lua.diff +++ b/diff/walking_light.diff/init.lua.diff @@ -1,9 +1,12 @@ -117c117 +495c495 < light_source = 13, --- > light_source = 14, -144c144 -< }) -\ No newline at end of file +510c510 +< light_source = 13, --- -> }) +> light_source = 14, +588c588 +< light_source = 13, +--- +> light_source = 14, diff --git a/mods/walking_light/README.md b/mods/walking_light/README.md new file mode 100644 index 0000000..e79e14f --- /dev/null +++ b/mods/walking_light/README.md @@ -0,0 +1,24 @@ +minetest mod walking_light + +forked from 0.6 https://forum.minetest.net/viewtopic.php?f=11&t=2621&hilit=walking+light + +Licensing: +========== + +If not noted elsewhere: + Code: WTFPL, textures: CC BY-SA + +Some textures taken from 3d_armor mod + these files are directly from the 3d_armor mod: + textures/walking_light_helmet_diamond.png + textures/walking_light_helmet_diamond_preview.png + parts of the following files came from 3d_armor's "3d_armor_inv_helmet_diamond.png": + textures/walking_light_inv_helmet_diamond.png + textures/walking_light_inv_helmet_diamond.xcf + + License Textures: 2013 Ryan Jones - CC-BY-SA + + see 3d_armor mod here + https://forum.minetest.net/viewtopic.php?f=11&t=4654 + https://github.com/stujones11/minetest-3d_armor + diff --git a/mods/walking_light/init.lua b/mods/walking_light/init.lua index 515a919..a24fb5a 100644 --- a/mods/walking_light/init.lua +++ b/mods/walking_light/init.lua @@ -1,125 +1,528 @@ +-- list of all players seen by minetest.register_on_joinplayer local players = {} +-- all player positions last time light was updated: {player_name : {x, y, z}} local player_positions = {} +-- all light positions of light that currently is created {player_name : {i: {x, y, z}} +local light_positions = {} +-- last item seen wielded by players local last_wielded = {} +-- toggles debug mode +local walking_light_debug = false +-- name of light node, changed by toggling debug mode +local walking_light_node = nil + +-- initialize walking light +walking_light = {} + +-- list of items that use walking light +local light_items = { + "default:torch", "walking_light:pick_mese", + "walking_light:helmet_diamond", "walking_light:megatorch" +} + +function walking_light.addLightItem(item) + for I in pairs(light_items) do + if item == light_items[I] then + minetest.log("warning", "[walking_light] \"" .. item .. "\" is already light item.") + return + end + end + + table.insert(light_items, -1, item) +end + +function walking_light.getLightItems() + return light_items +end + + +-- from http://lua-users.org/wiki/IteratorsTutorial +-- useful for removing things from a table because removing from the middle makes it skip elements otherwise +function ripairs(t) + local function ripairs_it(t,i) + i=i-1 + local v=t[i] + if v==nil then return v end + return i,v + end + return ripairs_it, t, #t+1 +end + +-- formats a vector with shorter output than dump +local function dumppos(pos) + if pos == nil then + return "nil" + end + local x = "nil" + if pos.x then + x = pos.x + end + local y = "nil" + if pos.y then + y = pos.y + end + local z = "nil" + if pos.z then + z = pos.z + end + + return "(" .. x .. "," .. y .. "," .. z .. ")" +end + +-- formats a table containing vectors with shorter output than dump +local function dumppostable(t) + if t == nil then + return "nil" + end + if #t == 0 then + return "0{}" + end + + ret = #t .. "{\n" + for i,pos in ipairs(t) do + ret = ret .. " " .. dumppos(pos) .. "\n" + end + ret = ret .. "}" + return ret +end + +function mt_get_node_or_nil(pos) + if pos == nil then + print("ERROR: walking_light.mt_get_node_or_nil(), pos is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + return minetest.get_node_or_nil(pos) +end + +function mt_add_node(pos, sometable) + if pos == nil then + print("ERROR: walking_light.mt_add_node(), pos is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + if sometable == nil then + print("ERROR: walking_light.mt_add_node(), sometable is nil") + print(debug.traceback("Current Callstack:\n")) + return nil + end + minetest.add_node(pos,sometable) +end + function round(num) return math.floor(num + 0.5) end +local function poseq(pos1, pos2) + if pos1 == nil and pos2 == nil then + return true + end + if pos1 == nil or pos2 == nil then + return false + end + return pos1.x == pos2.x and pos1.y == pos2.y and pos1.z == pos2.z +end + +-- return true if the player moved since last player_positions update +local function player_moved(player) + local player_name = player:get_player_name() + local pos = player:getpos() + local rounded_pos = vector.round(pos) + local oldpos = player_positions[player_name] + if oldpos == nil or not poseq(rounded_pos, oldpos) then + -- if oldpos is nil, we assume they just logged in, so consider them moved +-- print("DEBUG: walking_light, player_moved(); moved = true; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos)) + return true + end +-- print("DEBUG: walking_light, player_moved(); moved = false; rounded_pos = " .. dumppos(rounded_pos) .. ", oldpos = " .. dumppos(oldpos)) + return false +end + +-- same as table.remove(t,remove_pos), but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?) +local function table_remove_pos(t, remove_pos) +-- local DEBUG_oldsize = #t + + for i,pos in ipairs(t) do + if poseq(pos, remove_pos) then + table.remove(t, i) + break + end + end + +-- local DEBUG_newsize = #t +-- print("DEBUG: walking_light.table_remove_pos(), oldsize = " .. DEBUG_oldsize .. ", newsize = " .. DEBUG_newsize) +end + +-- same as t[remove_pos], but uses poseq instead of comparing references (does lua have comparator support, so this isn't needed?) +local function table_contains_pos(t, remove_pos) + for i,pos in ipairs(t) do + if poseq(pos, remove_pos) then + return true + end + end + return false +end + +-- same as table.insert(t,pos) but makes sure it is not duplicated +local function table_insert_pos(t, pos) + if not table_contains_pos( pos ) then + table.insert(t, pos) + end +end + +local function is_light(node) + if node ~= nil and ( node.name == "walking_light:light" or node.name == "walking_light:light_debug" ) then + return true + end + return false +end + +-- removes light at the given position +-- player is optional +local function remove_light(player, pos) + local player_name + if player then + player_name = player:get_player_name() + end + local node = mt_get_node_or_nil(pos) + if is_light(node) then + mt_add_node(pos,{type="node",name="air"}) + if player_name then + table_remove_pos(light_positions[player_name], pos) + end + else + if node ~= nil then + print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was " .. node.name) + table_remove_pos(light_positions[player_name], pos) + else + print("WARNING: walking_light.remove_light(), pos = " .. dumppos(pos) .. ", tried to remove light but node was nil") + end + end +end + +-- removes all light owned by a player +local function remove_light_player(player) + local player_name = player:get_player_name() + + for i,old_pos in ripairs(light_positions[player_name]) do + if old_pos then +-- print("DEBUG: walking_light.remove_light_player(), removing old light; old_pos = " .. dumppos(old_pos)) + remove_light(player, old_pos) + end + end +-- print("DEBUG: walking_light.remove_light_player(), done; light_positions = " .. dumppostable(light_positions[player_name])) +end + +local function can_add_light(pos) + local node = mt_get_node_or_nil(pos) + if node == nil or node.name == "air" then +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true") + return true + elseif is_light(node) then +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", true") + return true + end +-- print("walking_light can_add_light(), pos = " .. dumppos(pos) .. ", false") + return false +end + +-- old function returns pos instead of table, for only one position +local function pick_light_position_regular(player, pos) + if can_add_light(pos) then + return {pos} + end + + local pos2 + + -- if pos is not possible, try the old player position first, to make it more likely that it has a line of sight + local player_name = player:get_player_name() + local oldplayerpos = player_positions[player_name] + if oldplayerpos and can_add_light( vector.new(oldplayerpos.x, oldplayerpos.y + 1, oldplayerpos.z) ) then + return oldplayerpos + end + + -- if not, try all positions around the pos + pos2 = vector.new(pos.x + 1, pos.y, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x - 1, pos.y, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y, pos.z + 1) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y, pos.z - 1) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y + 1, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + pos2 = vector.new(pos.x, pos.y - 1, pos.z) + if can_add_light( pos2 ) then + return {pos2} + end + + return nil +end + +-- new function, returns table +local function pick_light_position_radius(player, pos, ret, radius) + local pos2 + local step = 4 + local unstep = 1/step + + for x = pos.x - radius, pos.x + radius, step do + for y = pos.y - radius, pos.y + radius, step do + for z = pos.z - radius, pos.z + radius, step do + pos2 = vector.new(round(x*unstep)*step, round(y*unstep)*step, round(z*unstep)*step) + distance = math.sqrt(math.pow(pos.x - x, 2) + math.pow(pos.y - y, 2) + math.pow(pos.z - z, 2)) + if distance <= radius and can_add_light( pos2 ) then + table.insert(ret, pos2) + end + end + end + end + + return ret +end + +local function pick_light_position_mega(player, pos) + local ret = {} + + if can_add_light(pos) then + table.insert(ret, pos) + end + pick_light_position_radius(player, pos, ret, 10) + + return ret +end + +local function pick_light_position(player, pos, light_item) + if light_item == "walking_light:megatorch" then + return pick_light_position_mega(player, pos) + end + return pick_light_position_regular(player, pos) +end + +-- adds light at the given position +local function add_light(player, pos) + local player_name = player:get_player_name() + local node = mt_get_node_or_nil(pos) + if node == nil then + -- don't do anything for nil blocks... they are non-loaded blocks, so we don't want to overwrite anything there +-- print("DEBUG: walking_light.add_light(), node is nil, pos = " .. dumppos(pos)) + return false + elseif node.name == "air" then + -- when the node that is already there is air, add light + mt_add_node(pos,{type="node",name=walking_light_node}) + if not table_contains_pos(light_positions[player_name], pos) then + table_insert_pos(light_positions[player_name], pos) + end + +-- if node then +-- print("DEBUG: add_light(), node.name = " .. node.name .. ", pos = " .. dumppos(pos)) +-- else +-- print("DEBUG: add_light(), node.name = nil, pos = " .. dumppos(pos)) +-- end + return true + elseif is_light(node) then + -- no point in adding light where it is already, but we should assign it to the player so it gets removed (in case it has no player) +-- print("DEBUG: add_light(), not adding; node.name = " .. node.name .. ", pos = " .. dumppos(pos)) + + if not table_contains_pos(light_positions[player_name], pos) then + table_insert_pos(light_positions[player_name], pos) + end + + return true + end +-- print("DEBUG: add_light(), not adding; node.name = " .. node.name) + return false +end + +-- updates all the light around the player, depending on what they are wielding +local function update_light_player(player) + -- if there is no player, there can be no update + if not player then + return + end + + -- figure out if they wield light; this will be nil if not + local wielded_item = get_wielded_light_item(player) + + local player_name = player:get_player_name() + local pos = player:getpos() + local rounded_pos = vector.round(pos) + + -- check for a nil node where the player is; if it is nil, we assume the block is not loaded, so we return without updating player_positions + -- that way, it should add light next step + local node = mt_get_node_or_nil(rounded_pos) + if node == nil then + return + end + + if not player_moved(player) and wielded_item == last_wielded[player_name] then + -- no update needed if the wiedled light item is the same as before (including nil), and the player didn't move + return + end + last_wielded[player_name] = wielded_item; + + local wantlightpos = nil + local wantpos = vector.new(rounded_pos.x, rounded_pos.y + 1, rounded_pos.z) + if wielded_item then + -- decide where light should be + wantlightpos = pick_light_position(player, wantpos, wielded_item) +-- print("DEBUG: walking_light update_light_player(); wantpos = " .. dumppos(wantpos) .. ", wantlightpos = " .. dumppos(wantlightpos)) + end + + if wielded_item and wantlightpos then + -- add light that isn't already there + for i,newpos in ipairs(wantlightpos) do + add_light(player, newpos) + end + end + + -- go through all light owned by the player to remove all but what should be kept + for i,oldlightpos in ripairs(light_positions[player_name]) do + if not wantlightpos or oldlightpos and oldlightpos.x and not table_contains_pos(wantlightpos, oldlightpos) then + remove_light(player, oldlightpos) + end + end + + player_positions[player_name] = vector.round(pos) + +-- print("DEBUG: walking_light.update_light_player(): wantlightpos = " .. dumppostable(wantlightpos) .. ", light_positions = " .. dumppostable(light_positions[player_name])) +end + +local function update_light_all() + -- go through all players to check + for i,player_name in ipairs(players) do + local player = minetest.get_player_by_name(player_name) + update_light_player(player) + end +end + +-- return true if item is a light item +function is_light_item(item) + for I in pairs(light_items) do + if item == light_items[I] then + return true + end + end + return false +end + +-- returns a string, the name of the item found that is a light item +function get_wielded_light_item(player) + local wielded_item = player:get_wielded_item():get_name() + if is_light_item(wielded_item) then + return wielded_item + end + + -- check equipped armor - requires unified_inventory maybe + local player_name = player:get_player_name() + if player_name then + local armor_inv = minetest.get_inventory({type="detached", name=player_name.."_armor"}) + if armor_inv then +-- print( dump(armor_inv:get_lists()) ) + local item_name = "walking_light:helmet_diamond" + local stack = ItemStack(item_name) + if armor_inv:contains_item("armor", stack) then + return item_name + end + end + end + + return nil +end + +-- return true if player is wielding a light item +function wielded_light(player) + return get_wielded_light_item(player) ~= nil +end + minetest.register_on_joinplayer(function(player) local player_name = player:get_player_name() table.insert(players, player_name) - last_wielded[player_name] = player:get_wielded_item():get_name() + last_wielded[player_name] = get_wielded_light_item(player) local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - local wielded_item = player:get_wielded_item():get_name() - if wielded_item ~= "default:torch" and wielded_item ~= "walking_light:pick_mese" then - -- Neuberechnung des Lichts erzwingen - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - end - player_positions[player_name] = {} - player_positions[player_name]["x"] = rounded_pos.x; - player_positions[player_name]["y"] = rounded_pos.y; - player_positions[player_name]["z"] = rounded_pos.z; + player_positions[player_name] = nil + light_positions[player_name] = {} + update_light_player(player) end) minetest.register_on_leaveplayer(function(player) local player_name = player:get_player_name() for i,v in ipairs(players) do - if v == player_name then + if v == player_name then table.remove(players, i) - last_wielded[player_name] = nil - -- Neuberechnung des Lichts erzwingen - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - player_positions[player_name]["x"] = nil - player_positions[player_name]["y"] = nil - player_positions[player_name]["z"] = nil - player_positions[player_name]["m"] = nil - player_positions[player_name] = nil end end + last_wielded[player_name] = false + remove_light_player(player) + player_positions[player_name]=nil end) minetest.register_globalstep(function(dtime) for i,player_name in ipairs(players) do - local player = minetest.env:get_player_by_name(player_name) - local wielded_item = player:get_wielded_item():get_name() - if wielded_item == "default:torch" or wielded_item == "walking_light:pick_mese" then - -- Fackel ist in der Hand - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - if (last_wielded[player_name] ~= "default:torch" and last_wielded[player_name] ~= "walking_light:pick_mese") or (player_positions[player_name]["x"] ~= rounded_pos.x or player_positions[player_name]["y"] ~= rounded_pos.y or player_positions[player_name]["z"] ~= rounded_pos.z) then - -- Fackel gerade in die Hand genommen oder zu neuem Node bewegt - local is_air = minetest.env:get_node_or_nil(rounded_pos) - if is_air == nil or (is_air ~= nil and (is_air.name == "air" or is_air.name == "walking_light:light")) then - -- wenn an aktueller Position "air" ist, Fackellicht setzen - minetest.env:add_node(rounded_pos,{type="node",name="walking_light:light"}) - end - if (player_positions[player_name]["x"] ~= rounded_pos.x or player_positions[player_name]["y"] ~= rounded_pos.y or player_positions[player_name]["z"] ~= rounded_pos.z) then - -- wenn Position geänder, dann altes Licht löschen - local old_pos = {x=player_positions[player_name]["x"], y=player_positions[player_name]["y"], z=player_positions[player_name]["z"]} - -- Neuberechnung des Lichts erzwingen - local is_light = minetest.env:get_node_or_nil(old_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - minetest.env:add_node(old_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(old_pos,{type="node",name="air"}) - end - end - -- gemerkte Position ist nun die gerundete neue Position - player_positions[player_name]["x"] = rounded_pos.x - player_positions[player_name]["y"] = rounded_pos.y - player_positions[player_name]["z"] = rounded_pos.z - end - - last_wielded[player_name] = wielded_item; - elseif last_wielded[player_name] == "default:torch" or last_wielded[player_name] == "walking_light:pick_mese" then - -- Fackel nicht in der Hand, aber beim letzten Durchgang war die Fackel noch in der Hand - local pos = player:getpos() - local rounded_pos = {x=round(pos.x),y=round(pos.y)+1,z=round(pos.z)} - repeat - local is_light = minetest.env:get_node_or_nil(rounded_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - -- minetest.env:remove_node(rounded_pos) - -- Erzwinge Neuberechnung des Lichts - minetest.env:add_node(rounded_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(rounded_pos,{type="node",name="air"}) - end - until minetest.env:get_node_or_nil(rounded_pos) ~= "walking_light:light" - local old_pos = {x=player_positions[player_name]["x"], y=player_positions[player_name]["y"], z=player_positions[player_name]["z"]} - repeat - is_light = minetest.env:get_node_or_nil(old_pos) - if is_light ~= nil and is_light.name == "walking_light:light" then - -- minetest.env:remove_node(old_pos) - -- Erzwinge Neuberechnung des Lichts - minetest.env:add_node(old_pos,{type="node",name="default:cobble"}) - minetest.env:add_node(old_pos,{type="node",name="air"}) - end - until minetest.env:get_node_or_nil(old_pos) ~= "walking_light:light" - last_wielded[player_name] = wielded_item + local player = minetest.get_player_by_name(player_name) + if player ~= nil then + update_light_player(player) + else + table.remove(players, i) end end end) -minetest.register_node("walking_light:light", { +minetest.register_node("walking_light:light_debug", { drawtype = "glasslike", - tile_images = {"walking_light.png"}, - -- tile_images = {"walking_light_debug.png"}, + tiles = {"walking_light_debug.png"}, inventory_image = minetest.inventorycube("walking_light.png"), paramtype = "light", walkable = false, is_ground_content = true, - light_propagates = true, sunlight_propagates = true, light_source = 14, selection_box = { - type = "fixed", - fixed = {0, 0, 0, 0, 0, 0}, - }, + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, }) + +minetest.register_node("walking_light:light", { + drawtype = "glasslike", + tiles = {"walking_light.png"}, + inventory_image = minetest.inventorycube("walking_light.png"), + paramtype = "light", + walkable = false, + is_ground_content = true, + sunlight_propagates = true, + light_source = 14, + selection_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0}, + }, +}) + +function update_walking_light_node() + if walking_light_debug then + walking_light_node = "walking_light:light_debug" + else + walking_light_node = "walking_light:light" + end +end +update_walking_light_node() + minetest.register_tool("walking_light:pick_mese", { description = "Mese Pickaxe with light", inventory_image = "walking_light_mesepick.png", @@ -135,6 +538,65 @@ minetest.register_tool("walking_light:pick_mese", { }, }) +minetest.register_tool("walking_light:helmet_diamond", { + description = "Diamond Helmet with light", + inventory_image = "walking_light_inv_helmet_diamond.png", + wield_image = "3d_armor_inv_helmet_diamond.png", + groups = {armor_head=15, armor_heal=12, armor_use=100}, + wear = 0, +}) + +minetest.register_node("walking_light:megatorch", { + description = "Megatorch", + drawtype = "torchlike", + tiles = { + { + name = "default_torch_on_floor_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + { + name="default_torch_on_ceiling_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + { + name="default_torch_animated.png", + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 3.0 + }, + }, + }, + inventory_image = "default_torch_on_floor.png", + wield_image = "default_torch_on_floor.png", + paramtype = "light", + paramtype2 = "wallmounted", + sunlight_propagates = true, + is_ground_content = false, + walkable = false, + light_source = 14, + selection_box = { + type = "wallmounted", + wall_top = {-0.1, 0.5-0.6, -0.1, 0.1, 0.5, 0.1}, + wall_bottom = {-0.1, -0.5, -0.1, 0.1, -0.5+0.6, 0.1}, + wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, + }, + groups = {choppy=2,dig_immediate=3,flammable=1,attached_node=1}, + legacy_wallmounted = true, + --sounds = default.node_sound_defaults(), +}) + minetest.register_craft({ output = 'walking_light:pick_mese', recipe = { @@ -142,3 +604,81 @@ minetest.register_craft({ {'default:pick_mese'}, } }) + +minetest.register_craft({ + output = 'walking_light:helmet_diamond', + recipe = { + {'default:torch'}, + {'3d_armor:helmet_diamond'}, + } +}) + +minetest.register_craft({ + output = 'walking_light:megatorch', + recipe = { + {'default:torch', 'default:torch', 'default:torch'}, + {'default:torch', 'default:torch', 'default:torch'}, + {'default:torch', 'default:torch', 'default:torch'}, + } +}) + +minetest.register_chatcommand("walking_light_clear_light", { + params = "", + description = "Remove light nodes from the area", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use mapclearlight" + end + + local pos = vector.round(minetest.get_player_by_name(name):getpos()) + local size = tonumber(param) or 40 + + for i,v in ipairs({"walking_light:light", "walking_light:light_debug"}) do + point = minetest.find_node_near(pos, size/2, v) + while point do + remove_light(nil, point) + oldpoint = point + point = minetest.find_node_near(pos, size/2, v) + if poseq(oldpoint, point) then + return false, "Failed... infinite loop detected" + end + end + end + return true, "Done." + end, +}) + +minetest.register_chatcommand("walking_light_add_light", { + params = "", + description = "Add walking_light:light to a position, without a player owning it", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use mapaddlight" + end + + local pos = vector.round(minetest.get_player_by_name(name):getpos()) + pos = vector.new(pos.x, pos.y + 1, pos.z) + + if pos then + mt_add_node(pos,{type="node",name=walking_light_node}) + end + + return true, "Done." + end, +}) + +minetest.register_chatcommand("walking_light_debug", { + description = "Change to debug mode, so light blocks are visible.", + func = function(name, param) + if not minetest.check_player_privs(name, {server=true}) then + return false, "You need the server privilege to use walking_light_debug" + end + + walking_light_debug = not walking_light_debug + update_walking_light_node() + + return true, "Done." + end, +}) + +-- vim: ts=4 sw=4 softtabstop=4 smarttab noexpandtab diff --git a/mods/walking_light/init.lua.diff b/mods/walking_light/init.lua.diff index f62f26c..9030280 100644 --- a/mods/walking_light/init.lua.diff +++ b/mods/walking_light/init.lua.diff @@ -1,9 +1,12 @@ -117c117 +495c495 < light_source = 13, --- > light_source = 14, -144c144 -< }) -\ No newline at end of file +510c510 +< light_source = 13, --- -> }) +> light_source = 14, +588c588 +< light_source = 13, +--- +> light_source = 14, diff --git a/mods/walking_light/textures/walking_light.png b/mods/walking_light/textures/walking_light.png index 334cb07..bca3cf2 100644 Binary files a/mods/walking_light/textures/walking_light.png and b/mods/walking_light/textures/walking_light.png differ diff --git a/mods/walking_light/textures/walking_light_helmet_diamond.png b/mods/walking_light/textures/walking_light_helmet_diamond.png new file mode 100644 index 0000000..2649670 Binary files /dev/null and b/mods/walking_light/textures/walking_light_helmet_diamond.png differ diff --git a/mods/walking_light/textures/walking_light_helmet_diamond_preview.png b/mods/walking_light/textures/walking_light_helmet_diamond_preview.png new file mode 100644 index 0000000..33a273a Binary files /dev/null and b/mods/walking_light/textures/walking_light_helmet_diamond_preview.png differ diff --git a/mods/walking_light/textures/walking_light_inv_helmet_diamond.png b/mods/walking_light/textures/walking_light_inv_helmet_diamond.png new file mode 100644 index 0000000..07f5a0f Binary files /dev/null and b/mods/walking_light/textures/walking_light_inv_helmet_diamond.png differ diff --git a/mods/walking_light/textures/walking_light_inv_helmet_diamond.xcf b/mods/walking_light/textures/walking_light_inv_helmet_diamond.xcf new file mode 100644 index 0000000..a8529e5 Binary files /dev/null and b/mods/walking_light/textures/walking_light_inv_helmet_diamond.xcf differ