From 76a8d37edbcc96352af512e6e11f353adcc28ad3 Mon Sep 17 00:00:00 2001 From: loosewheel <76670709+loosewheel@users.noreply.github.com> Date: Tue, 15 Feb 2022 06:31:00 +1000 Subject: [PATCH] Add files via upload --- camera.lua | 447 +++++++++++++++++++++++++++++++++++++++++++++++++++ change.log | 4 + crafting.lua | 18 +++ detector.lua | 2 +- init.lua | 3 +- license.txt | 3 + readme.txt | 3 +- 7 files changed, 477 insertions(+), 3 deletions(-) create mode 100644 camera.lua diff --git a/camera.lua b/camera.lua new file mode 100644 index 0000000..18f5e71 --- /dev/null +++ b/camera.lua @@ -0,0 +1,447 @@ +local utils = ... +local S = utils.S + + + +if utils.digilines_supported then + + + +local function is_drop (obj) + if obj then + local entity = obj.get_luaentity and obj:get_luaentity () + + return (entity and entity.name and entity.name == "__builtin:item") + end + + return false +end + + + +local function get_entity_dims (obj) + local dims = { -0.5, 0, -0.5, 0.5, 2, 0.5 } + + if obj.get_luaentity then + entity = obj:get_luaentity () + + if entity and entity.name then + def = minetest.registered_entities[entity.name] + + if def and type (def.collisionbox) == "table" then + + dims = { def.collisionbox[1] or -0.5, + def.collisionbox[2] or -0.5, + def.collisionbox[3] or -0.5, + def.collisionbox[4] or 0.5, + def.collisionbox[5] or 0.5, + def.collisionbox[6] or 0.5 } + end + end + end + + local props = obj:get_properties () + if props and props.collisionbox and type (props.collisionbox) == "table" then + + dims = { props.collisionbox[1] or -0.5, + props.collisionbox[2] or -0.5, + props.collisionbox[3] or -0.5, + props.collisionbox[4] or 0.5, + props.collisionbox[5] or 0.5, + props.collisionbox[6] or 0.5 } + end + + dims[1] = math.min (dims[1], dims[3]) + dims[3] = dims[1] + dims[4] = math.max (dims[4], dims[6]) + dims[6] = dims[4] + + if (dims[3] - dims[1]) < 1 then + dims[1] = -0.5 + dims[3] = -0.5 + dims[4] = 0.5 + dims[6] = 0.5 + end + + return dims +end + + + +local function get_entity (pos) + local objects = minetest.get_objects_inside_radius (pos, 2.0) + + if #objects > 0 then + for _, obj in ipairs (objects) do + if obj.get_pos then + if obj:is_player () then + local epos = vector.round (obj:get_pos ()) + + if epos.x == pos.x and epos.z == pos.z and + (epos.y == pos.y or epos.y == pos.y - 1) then + return 1 + end + end + + if not is_drop (obj) then + local epos = vector.new (obj:get_pos ()) + local dims = get_entity_dims (obj) + + if pos.x >= (epos.x + dims[1]) and pos.x <= (epos.x + dims[4]) and + pos.y >= (epos.y + dims[2]) and pos.y <= (epos.y + dims[5]) and + pos.z >= (epos.z + dims[3]) and pos.z <= (epos.z + dims[6]) then + return 2 + end + end + end + end + end + + return nil +end + + + +local function camera_scan (pos, resolution, distance) + local node = utils.get_far_node (pos) + local image = { } + + for y = 1, resolution, 1 do + image[y] = { } + + for x = 1, resolution, 1 do + image[y][x] = "000000" + end + end + + if node then + local dir = vector.multiply (minetest.facedir_to_dir (node.param2), -1) + local last_pos = nil + local last_color = "000000" + local view = (distance * 1.414213562) / resolution + + for dist = distance, 1, -1 do + local scale = dist / distance + + for y = 1, resolution, 1 do + for x = 1, resolution, 1 do + local horz = (x - (resolution / 2)) * scale * view + local vert = (y - (resolution / 2)) * scale * view + + local tpos = nil + if dir.x ~= 0 then + tpos = vector.round ({ x = (dist * dir.x) + pos.x, y = pos.y - vert, z = horz + pos.z }) + else + tpos = vector.round ({ x = horz + pos.x, y = pos.y - vert, z = (dist * dir.z) + pos.z }) + end + + + if last_pos and vector.equals (last_pos, tpos) then + image[y][x] = last_color + else + local entity = get_entity (tpos) + + if entity == 1 then + local color = (((distance - dist) / distance) * 98) + 30 + + last_color = string.format ("00%02X00", color) + image[y][x] = last_color + last_pos = tpos + elseif entity == 2 then + local color = (((distance - dist) / distance) * 98) + 30 + + last_color = string.format ("0000%02X", color) + image[y][x] = last_color + last_pos = tpos + else + local node = utils.get_far_node (tpos) + + if node and node.name ~= "air" then + local color = (((distance - dist) / distance) * 98) + 30 + + last_color = string.format ("%02X%02X%02X", color, color, color) + image[y][x] = last_color + last_pos = tpos + else + last_pos = nil + end + end + end + end + end + end + end + + return image +end + + + +local function send_scan (pos) + local meta = minetest.get_meta (pos) + + if meta then + local channel = meta:get_string ("channel") + + if channel:len () > 0 then + local image = camera_scan (pos, + tonumber (meta:get_string ("resolution")), + tonumber (meta:get_string ("distance"))) + + utils.digilines_receptor_send (pos, + utils.digilines_default_rules, + channel, + image) + end + + + end +end + + + +local function after_place_node (pos, placer, itemstack, pointed_thing) + local meta = minetest.get_meta (pos) + local spec = + "formspec_version[3]\n".. + "size[8.5,5.5;true]\n".. + "field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]\n".. + "button[5.5,1.0;2.0,0.8;setchannel;Set]\n".. + "field[1.0,2.5;4.0,0.8;distance;Distance;${distance}]\n".. + "button[5.5,2.5;2.0,0.8;setdistance;Set]\n".. + "field[1.0,4.0;4.0,0.8;resolution;Resolution;${resolution}]\n".. + "button[5.5,4.0;2.0,0.8;setresolution;Set]\n" + + meta:set_string ("formspec", spec) + meta:set_string ("distance", "5") + meta:set_string ("resolution", "16") + + -- If return true no item is taken from itemstack + return false +end + + + +local function after_place_node_locked (pos, placer, itemstack, pointed_thing) + after_place_node (pos, placer, itemstack, pointed_thing) + + if placer and placer:is_player () then + local meta = minetest.get_meta (pos) + + meta:set_string ("owner", placer:get_player_name ()) + meta:set_string ("infotext", "Camera (owned by "..placer:get_player_name ()..")") + end + + -- If return true no item is taken from itemstack + return false +end + + + +local function on_receive_fields (pos, formname, fields, sender) + if not utils.can_interact_with_node (pos, sender) then + return + end + + if fields.setchannel then + local meta = minetest.get_meta (pos) + + if meta then + meta:set_string ("channel", fields.channel) + end + end + + if fields.setdistance then + local meta = minetest.get_meta (pos) + + if meta then + local distance = math.min (math.max (tonumber (fields.distance) or 1, 1), 16) + fields.distance = tostring (distance) + + meta:set_string ("distance", tostring (distance)) + end + end + + if fields.setresolution then + local meta = minetest.get_meta (pos) + + if meta then + local resolution = math.max (tonumber (fields.resolution) or 1, 1) + fields.resolution = tostring (resolution) + + meta:set_string ("resolution", tostring (resolution)) + end + end +end + + + +local function can_dig (pos, player) + if not utils.can_interact_with_node (pos, player) then + return false + end + + return true +end + + + +local function on_blast (pos, intensity) + local meta = minetest.get_meta (pos) + + if meta then + if intensity >= 1.0 then + minetest.remove_node (pos) + + else -- intensity < 1.0 + local node = minetest.get_node_or_nil (pos) + if node then + local items = minetest.get_node_drops (node, nil) + + if items and #items > 0 then + local stack = ItemStack (items[1]) + + if stack then + preserve_metadata (pos, node, meta, { stack }) + utils.item_drop (stack, nil, pos) + minetest.remove_node (pos) + end + end + end + end + end +end + + + +local function on_rightclick (pos, node, clicker, itemstack, pointed_thing) + if not utils.can_interact_with_node (pos, clicker) then + if clicker and clicker:is_player () then + local owner = "" + local meta = minetest.get_meta (pos) + + if meta then + owner = meta:get_string ("owner") + end + + local spec = + "formspec_version[3]".. + "size[8.0,4.0,false]".. + "label[1.0,1.0;Owned by "..minetest.formspec_escape (owner).."]".. + "button_exit[3.0,2.0;2.0,1.0;close;Close]" + + minetest.show_formspec (clicker:get_player_name (), + "lwcomponents:component_privately_owned", + spec) + end + end + + return itemstack +end + + + +local function digilines_support () + if utils.digilines_supported then + return + { + wire = + { + rules = utils.digilines_default_rules, + }, + + effector = + { + action = function (pos, node, channel, msg) + local meta = minetest.get_meta(pos) + + if meta then + local this_channel = meta:get_string ("channel") + + if this_channel ~= "" and this_channel == channel and + type (msg) == "string" then + + local m = { } + for w in string.gmatch(msg, "[^%s]+") do + m[#m + 1] = w + end + + if m[1] == "scan" then + send_scan (pos) + + elseif m[1] == "distance" then + meta:set_string ("distance", tostring (tonumber (m[2] or 5) or 5)) + + elseif m[1] == "resolution" then + meta:set_string ("resolution", tostring (tonumber (m[2] or 16) or 16)) + + end + end + end + end, + } + } + end + + return nil +end + + + +minetest.register_node("lwcomponents:camera", { + description = S("Camera"), + tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png", + "lwcamera.png", "lwcamera.png", "lwcamera_lens.png"}, + is_ground_content = false, + groups = { cracky = 3 }, + sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "facedir", + param2 = 0, + floodable = false, + drop = "lwcomponents:camera", + _digistuff_channelcopier_fieldname = "channel", + + digiline = digilines_support (), + + on_receive_fields = on_receive_fields, + can_dig = can_dig, + after_place_node = after_place_node, + on_blast = on_blast, + on_rightclick = on_rightclick +}) + + + +minetest.register_node("lwcomponents:camera_locked", { + description = S("Camera (locked)"), + tiles = { "lwcamera.png", "lwcamera.png", "lwcamera.png", + "lwcamera.png", "lwcamera.png", "lwcamera_lens.png"}, + is_ground_content = false, + groups = { cracky = 3 }, + sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "facedir", + param2 = 0, + floodable = false, + drop = "lwcomponents:camera_locked", + _digistuff_channelcopier_fieldname = "channel", + + digiline = digilines_support (), + + on_receive_fields = on_receive_fields, + can_dig = can_dig, + after_place_node = after_place_node_locked, + on_blast = on_blast, + on_rightclick = on_rightclick +}) + + + +end -- utils.digilines_supported + + + +-- diff --git a/change.log b/change.log index 1bad0f1..de3d5b3 100644 --- a/change.log +++ b/change.log @@ -98,3 +98,7 @@ v0.1.17 v0.1.18 * Added mesecons through wire. + + +v0.1.19 +* Added camera. diff --git a/crafting.lua b/crafting.lua index 0079277..e7ba70c 100644 --- a/crafting.lua +++ b/crafting.lua @@ -295,6 +295,24 @@ minetest.register_craft( { }, }) + +minetest.register_craft( { + output = "lwcomponents:camera", + recipe = { + { "default:copper_ingot", "default:iron_lump" }, + { "default:chest", "default:stone" }, + }, +}) + + +minetest.register_craft( { + output = "lwcomponents:camera_locked", + recipe = { + { "default:copper_ingot", "default:iron_lump" }, + { "default:chest_locked", "default:stone" }, + }, +}) + end -- utils.digilines_supported diff --git a/detector.lua b/detector.lua index 71bbbe7..c82658c 100644 --- a/detector.lua +++ b/detector.lua @@ -165,7 +165,7 @@ local function detect (pos) local object = minetest.get_objects_inside_radius (pos, radius + 0.5) local detected_list = { } - for i = 1, #object do + for i = 1, #object, 1 do if object[i]:is_player () then -- player diff --git a/init.lua b/init.lua index 4592fcc..966794f 100644 --- a/init.lua +++ b/init.lua @@ -1,4 +1,4 @@ -local version = "0.1.18" +local version = "0.1.19" local mod_storage = minetest.get_mod_storage () @@ -36,6 +36,7 @@ loadfile (modpath.."/cannon.lua") (utils) loadfile (modpath.."/cannon_shell.lua") (utils) loadfile (modpath.."/pistons.lua") (utils) loadfile (modpath.."/through_wire.lua") (utils) +loadfile (modpath.."/camera.lua") (utils) loadfile (modpath.."/extras.lua") (utils) loadfile (modpath.."/digiswitch.lua") (utils) loadfile (modpath.."/movefloor.lua") (utils) diff --git a/license.txt b/license.txt index df9399d..df43986 100644 --- a/license.txt +++ b/license.txt @@ -69,6 +69,9 @@ public domain. fan images derived from images from https://openclipart.org, which is public domain. +camera lens images derived from images from https://openclipart.org, which +is public domain. + player button images derived from mesecons button image. cannon firing and explosion sound from tnt (TumeniNodes/steveygos93), diff --git a/readme.txt b/readme.txt index 5e8f5d0..72b089d 100644 --- a/readme.txt +++ b/readme.txt @@ -13,7 +13,7 @@ CC BY-SA 3.0 Version ======= -0.1.18 +0.1.19 Minetest Version @@ -66,6 +66,7 @@ Various components for mesecons and digilines. * Double (optionally single) reach pistons and sticky pistons. * Digiswitch, digilines controlled mesecons power. * Movefloor, similar to vertical mesecons movestone. +* Camera, takes a representative image. * Mesecons Through Wire, transmits through 1 to 2 solid blocks. * Solid color conductor blocks, same as Solid Color Block but also mesecons and digilines conductor.