diff --git a/lwcomponents/force_field.lua b/lwcomponents/force_field.lua new file mode 100644 index 0000000..7c0d12c --- /dev/null +++ b/lwcomponents/force_field.lua @@ -0,0 +1,1038 @@ +local utils = ... +local S = utils.S + + + +local field_pulse_interval = 0.2 + + + +local function get_bubble (pos) + local objs = minetest.get_objects_inside_radius (pos, 0.1) + + for _, obj in ipairs (objs) do + if not obj:is_player () and + obj.get_luaentity and obj:get_luaentity () and + obj:get_luaentity ().name and + obj:get_luaentity ().name == "lwcomponents:force_field_bubble" then + + return obj + end + end + + return nil +end + + + +local function spawn_glitter (pos) + local meta = minetest.get_meta (pos) + + if meta then + local radius = tonumber (meta:get_string ("radius") or 5) + + minetest.add_particlespawner ({ + amount = radius * 5, + time = 0.5, + minpos = vector.subtract (pos, radius * 0.707), + maxpos = vector.add (pos, radius * 0.707), + minvel = vector.new ({ x = -1, y = -1, z = -1 }), + maxvel = vector.new ({ x = 1, y = 1, z = 1 }), + minacc = vector.new (), + maxacc = vector.new (), + minexptime = 0.2, + maxexptime = 0.5, + minsize = 3, + maxsize = 6, + glow = 14, + texture = "lwcomponents_force_field_zap_1.png", + }) + + minetest.add_particlespawner ({ + amount = radius * 5, + time = 0.5, + minpos = vector.subtract (pos, radius * 0.707), + maxpos = vector.add (pos, radius * 0.707), + minvel = vector.new ({ x = -1, y = -1, z = -1 }), + maxvel = vector.new ({ x = 1, y = 1, z = 1 }), + minacc = vector.new (), + maxacc = vector.new (), + minexptime = 0.2, + maxexptime = 0.5, + minsize = 3, + maxsize = 6, + glow = 14, + texture = "lwcomponents_force_field_zap_2.png", + }) + end +end + + + +local function update_bubble (pos) + local meta = minetest.get_meta (pos) + local node = utils.get_far_node (pos) + + if meta and node and (node.name == "lwcomponents:force_field_on" or + node.name == "lwcomponents:force_field_locked_on") then + local radius = tonumber (meta:get_string ("radius") or 10) + local bubble = get_bubble (pos) + + if not bubble then + local staticdata = { } + + bubble = minetest.add_entity (pos, + "lwcomponents:force_field_bubble", + minetest.serialize (staticdata)) + end + + if bubble then + local props = bubble:get_properties () + props.visual_size = { x = radius * 2, y = radius * 2, z = radius * 2 } + bubble:set_properties (props) + bubble:set_armor_groups ({ immortal = 1 }) + end + end +end + + + +local function remove_bubble (pos) + local bubble = get_bubble (pos) + + if bubble then + bubble:remove () + end +end + + + +local function check_fuel (pos, used) + local meta = minetest.get_meta (pos) + + if meta then + local power = meta:get_float ("power") + + if used > power then + local inv = (meta and meta:get_inventory ()) or nil + + if inv then + while power < used do + local fuel, afterfuel = + minetest.get_craft_result ({ method = "fuel", + width = 1, + items = inv:get_list ("fuel") }) + + if fuel.time > 0 then + -- Take fuel from fuel list + inv:set_stack ("fuel", 1, afterfuel.items[1]) + power = power + fuel.time + else + -- No valid fuel in fuel list + break + end + end + end + end + + if used > power then + meta:set_float ("power", 0) + + return false + else + meta:set_float ("power", power - used) + end + end + + return true +end + + + +local function update_formspec (pos) + local meta = minetest.get_meta (pos) + + if meta then + local stopstart = minetest.get_node_timer (pos):is_started () and + "button[8.7,1.0;2.0,0.8;stop;Stop]" or + "button[8.7,1.0;2.0,0.8;start;Start]" + + local spec = + "formspec_version[3]".. + "size[11.7,12.8;true]".. + "field[1.0,1.0;4.0,0.8;channel;Channel;${channel}]".. + "button[5.0,1.0;2.0,0.8;setchannel;Set]".. + stopstart.. + "field[1.0,2.5;4.0,0.8;radius;Radius;${radius}]".. + "button[5.0,2.5;2.0,0.8;setradius;Set]".. + "textarea[1.0,4.0;6.5,2.4;exclude;Permit;${exclude}]".. + "button[7.5,4.0;2.0,0.8;setexclude;Set]".. + "list[context;fuel;9.2,2.5;1,1;]".. + "list[current_player;main;1.0,7.0;8,4;]\n".. + "listring[]" + + meta:set_string ("formspec", spec) + end +end + + + +local function turn_on (pos) + local node = utils.get_far_node (pos) + + if node then + if node.name == "lwcomponents:force_field" then + if check_fuel (pos, 0.001) then + node.name = "lwcomponents:force_field_on" + minetest.swap_node (pos, node) + minetest.get_node_timer (pos):start (field_pulse_interval) + update_formspec (pos) + update_bubble (pos) + spawn_glitter (pos) + end + + elseif node.name == "lwcomponents:force_field_locked" then + if check_fuel (pos, 0.001) then + node.name = "lwcomponents:force_field_locked_on" + minetest.swap_node (pos, node) + minetest.get_node_timer (pos):start (field_pulse_interval) + update_formspec (pos) + update_bubble (pos) + spawn_glitter (pos) + end + end + end +end + + + +local function turn_off (pos) + local node = utils.get_far_node (pos) + + if node then + if node.name == "lwcomponents:force_field_on" then + remove_bubble (pos) + node.name = "lwcomponents:force_field" + minetest.swap_node (pos, node) + minetest.get_node_timer (pos):stop () + update_formspec (pos) + spawn_glitter (pos) + + elseif node.name == "lwcomponents:force_field_locked_on" then + remove_bubble (pos) + node.name = "lwcomponents:force_field_locked" + minetest.swap_node (pos, node) + minetest.get_node_timer (pos):stop () + update_formspec (pos) + spawn_glitter (pos) + end + end +end + + + +local function run_zap (pos) + minetest.sound_play ("lwforce_field_zap", { pos = pos, max_hear_distance = 10, gain = 1.0 }) + + minetest.add_particle ({ + pos = pos, + velocity = vector.new (), + acceleration = vector.new (), + expirationtime = 0.1, + size = 10, + collisiondetection = false, + vertical = false, + texture = (math.random (10) < 6 and "lwcomponents_force_field_zap_1.png") or + "lwcomponents_force_field_zap_2.png", + glow = 14, + }) +end + + + +local function run_field (pos, elapsed) + local meta = minetest.get_meta (pos) + + if meta then + local radius = tonumber (meta:get_string ("radius") or 10) + local exclude = { } + local count = 0 + local owner = meta:get_string ("owner") + + update_bubble (pos) + + for player in string.gmatch (meta:get_string ("exclude"), "[^\n]+") do + if player and player ~= "" then + exclude[player] = true + end + end + + if owner ~= "" then + exclude[owner] = true + end + + local objs = minetest.get_objects_inside_radius (pos, radius + 1) + + for _, obj in ipairs (objs) do + local obj_pos = (obj.get_pos and obj:get_pos ()) or nil + + if obj_pos and not obj:get_armor_groups ().immortal then + if not utils.is_drop (obj) and not minetest.is_protected (obj_pos, owner) then + + if obj:is_player () then + if not exclude[obj:get_player_name ()] then + local vel = vector.multiply (vector.direction (pos, obj_pos), 30) + + obj:punch (obj, + 1.0, + { full_punch_interval = 1.0, + damage_groups = { fleshy = 1 } }, + vector.direction (pos, obj_pos)) + + obj:add_velocity (vel) + count = count + 1 + run_zap (obj_pos) + end + else + local luaent = (obj.get_luaentity and obj:get_luaentity ()) or nil + local name = obj:get_nametag_attributes () + local label = "" + + if type (name) == "table" then + label = tostring (name.text or "") + end + + name = (luaent and luaent.name) or "" + + if (name == "" and label == "") or + ((not (name ~= "" and exclude[name])) and + (not (label ~= "" and exclude[label]))) then + + local vel = vector.multiply (vector.direction (pos, obj_pos), 30) + + obj:punch (obj, + 1.0, + { full_punch_interval = 1.0, + damage_groups = { fleshy = 2 } }, + vector.direction (pos, obj_pos)) + + obj:set_velocity (vel) + count = count + 1 + run_zap (obj_pos) + end + end + end + end + end + + if not check_fuel (pos, ((radius * 0.16) * elapsed) + count) then + turn_off (pos) + + return false + end + end + + return true +end + + + +local function set_radius (pos, radius) + local meta = minetest.get_meta (pos) + + if meta then + radius = math.min (math.max (tonumber (radius) or 5, 5), 25) + + meta:set_string ("radius", tostring (radius)) + update_bubble (pos) + end +end + + + +local function add_exclude (pos, name) + local meta = minetest.get_meta (pos) + name = tostring (name or "") + + if meta and name ~= "" then + local exclude = { } + + for player in string.gmatch (meta:get_string ("exclude"), "[^\n]+") do + if player and player ~= "" then + if player == name then + return + end + + exclude[#exclude + 1] = player + end + end + + exclude[#exclude + 1] = name + + meta:set_string ("exclude", table.concat (exclude, "\n")) + end +end + + + +local function remove_exclude (pos, name) + local meta = minetest.get_meta (pos) + name = tostring (name or "") + + if meta and name ~= "" then + local exclude = { } + + for player in string.gmatch (meta:get_string ("exclude"), "[^\n]+") do + if player and player ~= "" and player ~= name then + exclude[#exclude + 1] = player + end + end + + meta:set_string ("exclude", table.concat (exclude, "\n")) + end +end + + + +local function send_status_message (pos) + if utils.digilines_supported then + local node = utils.get_far_node (pos) + local meta = minetest.get_meta (pos) + local inv = (meta and meta:get_inventory ()) or nil + + if node and meta and inv then + local channel = meta:get_string ("channel") + local state = "off" + local exclude = { } + local radius = tonumber (meta:get_string ("radius")) + local fuel = { name = "", count = 0 } + + if node.name == "lwcomponents:force_field_on" or + node.name == "lwcomponents:force_field_locked_on" then + + state = "on" + end + + for player in string.gmatch (meta:get_string ("exclude"), "[^\n]+") do + if player and player ~= "" then + exclude[#exclude + 1] = player + end + end + + local stack = inv:get_stack ("fuel", 1) + if stack and not stack:is_empty () then + fuel.name = stack:get_name () + fuel.count = stack:get_count () + end + + if channel:len () > 0 then + utils.digilines_receptor_send (pos, + utils.digilines_default_rules, + channel, + { action = "status", + state = state, + radius = radius, + permit = exclude, + fuel = fuel }) + end + end + end +end + + + +local function on_destruct (pos) + remove_bubble (pos) +end + + + +local function after_place_node (pos, placer, itemstack, pointed_thing) + local meta = minetest.get_meta (pos) + + meta:set_string ("radius", "10") + meta:set_string ("exclude", "") + meta:set_string ("inventory", "{ fuel = { } }") + update_formspec (pos) + + local inv = meta:get_inventory () + + inv:set_size ("fuel", 1) + inv:set_width ("fuel", 1) + + -- 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", "Force Field Generator (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.setradius then + local meta = minetest.get_meta (pos) + + if meta then + local radius = math.min (math.max (tonumber (fields.radius) or 5, 5), 25) + fields.radius = tostring (radius) + + meta:set_string ("radius", tostring (radius)) + update_bubble (pos) + end + end + + if fields.setexclude then + local meta = minetest.get_meta (pos) + + if meta then + meta:set_string ("exclude", fields.exclude) + end + end + + if fields.start then + turn_on (pos) + end + + if fields.stop then + turn_off (pos) + end +end + + + +local function can_dig (pos, player) + if not utils.can_interact_with_node (pos, player) then + return false + end + + local meta = minetest.get_meta (pos) + + if meta then + local inv = meta:get_inventory () + + if inv then + if not inv:is_empty ("fuel") then + return false + end + end + end + + return true +end + + + +local function on_blast (pos, intensity) + local meta = minetest.get_meta (pos) + + if meta then + if intensity >= 1.0 then + local inv = meta:get_inventory () + + if inv then + local slots = inv:get_size ("fuel") + + for slot = 1, slots do + local stack = inv:get_stack ("fuel", slot) + + if stack and not stack:is_empty () then + if math.floor (math.random (0, 5)) == 3 then + utils.item_drop (stack, nil, pos) + else + utils.on_destroy (stack) + end + end + end + end + + on_destruct (pos) + minetest.remove_node (pos) + + else -- intensity < 1.0 + local inv = meta:get_inventory () + + if inv then + local slots = inv:get_size ("fuel") + + for slot = 1, slots do + local stack = inv:get_stack ("fuel", slot) + + if stack and not stack:is_empty () then + utils.item_drop (stack, nil, pos) + end + end + end + + 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 + utils.item_drop (stack, nil, pos) + on_destruct (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 on_timer (pos, elapsed) + local result = run_field (pos, elapsed) + + return result +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 ~= "" then + if type (msg) == "string" then + local m = { } + for w in string.gmatch(msg, "[^%s]+") do + m[#m + 1] = w + end + + if this_channel == channel then + if m[1] == "start" then + turn_on (pos) + + elseif m[1] == "stop" then + turn_off (pos) + + elseif m[1] == "radius" then + set_radius (pos, m[2]) + + elseif m[1] == "add" then + add_exclude (pos, msg:sub (5, -1)) + + elseif m[1] == "remove" then + remove_exclude (pos, msg:sub (8, -1)) + + elseif m[1] == "status" then + send_status_message (pos) + + end + end + end + end + end + end, + } + } + end + + return nil +end + + + +local function mesecon_support () + if utils.mesecon_supported then + return + { + effector = + { + rules = utils.mesecon_default_rules, + + action_on = function (pos, node) + -- do something to turn the effector on + turn_on (pos) + end, + + action_off = function (pos, node) + -- do something to turn the effector off + turn_off (pos) + end, + } + } + end + + return nil +end + + + +local function pipeworks_support () + if utils.pipeworks_supported then + return + { + priority = 100, + input_inventory = "fuel", + connect_sides = { left = 1, right = 1, front = 1, back = 1, bottom = 1 }, + + insert_object = function (pos, node, stack, direction) + local meta = minetest.get_meta (pos) + local inv = (meta and meta:get_inventory ()) or nil + + if inv then + return inv:add_item ("fuel", stack) + end + + return stack + end, + + can_insert = function (pos, node, stack, direction) + local meta = minetest.get_meta (pos) + local inv = (meta and meta:get_inventory ()) or nil + + if inv then + return inv:room_for_item ("fuel", stack) + end + + return false + end, + + can_remove = function (pos, node, stack, dir) + -- returns the maximum number of items of that stack that can be removed + local meta = minetest.get_meta (pos) + local inv = (meta and meta:get_inventory ()) or nil + + if inv then + local slots = inv:get_size ("fuel") + + for i = 1, slots, 1 do + local s = inv:get_stack ("fuel", i) + + if s and not s:is_empty () and utils.is_same_item (stack, s) then + return s:get_count () + end + end + end + + return 0 + end, + + remove_items = function (pos, node, stack, dir, count) + -- removes count items and returns them + local meta = minetest.get_meta (pos) + local inv = (meta and meta:get_inventory ()) or nil + local left = count + + if inv then + local slots = inv:get_size ("fuel") + + for i = 1, slots, 1 do + local s = inv:get_stack ("fuel", i) + + if s and not s:is_empty () and utils.is_same_item (s, stack) then + if s:get_count () > left then + s:set_count (s:get_count () - left) + inv:set_stack ("fuel", i, s) + left = 0 + else + left = left - s:get_count () + inv:set_stack ("fuel", i, nil) + end + end + + if left == 0 then + break + end + end + end + + local result = ItemStack (stack) + result:set_count (count - left) + + return result + end + } + end + + return nil +end + + + +local force_field_groups = { cracky = 3, wires_connect = 1 } +if utils.pipeworks_supported then + force_field_groups.tubedevice = 1 + force_field_groups.tubedevice_receiver = 1 +end + + + +local force_field_on_groups = { cracky = 3, not_in_creative_inventory = 1, wires_connect = 1 } +if utils.pipeworks_supported then + force_field_on_groups.tubedevice = 1 + force_field_on_groups.tubedevice_receiver = 1 +end + + + +minetest.register_node("lwcomponents:force_field", { + description = S("Force Field Generator"), + tiles = { "lwcomponents_force_field.png", "lwcomponents_force_field.png", "lwcomponents_force_field.png", + "lwcomponents_force_field.png", "lwcomponents_force_field.png", "lwcomponents_force_field.png"}, + is_ground_content = false, + groups = table.copy (force_field_groups), + --sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "none", + param2 = 0, + floodable = false, + drop = "lwcomponents:force_field", + _digistuff_channelcopier_fieldname = "channel", + + mesecons = mesecon_support (), + digiline = digilines_support (), + tube = pipeworks_support (), + + on_destruct = on_destruct, + on_receive_fields = on_receive_fields, + can_dig = can_dig, + after_place_node = after_place_node, + on_blast = on_blast, + on_rightclick = on_rightclick, + on_timer = on_timer +}) + + + +minetest.register_node("lwcomponents:force_field_locked", { + description = S("Force Field Generator (locked)"), + tiles = { "lwcomponents_force_field.png", "lwcomponents_force_field.png", "lwcomponents_force_field.png", + "lwcomponents_force_field.png", "lwcomponents_force_field.png", "lwcomponents_force_field.png"}, + is_ground_content = false, + groups = table.copy (force_field_groups), + --sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "none", + param2 = 0, + floodable = false, + drop = "lwcomponents:force_field_locked", + _digistuff_channelcopier_fieldname = "channel", + + mesecons = mesecon_support (), + digiline = digilines_support (), + tube = pipeworks_support (), + + on_destruct = on_destruct, + 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, + on_timer = on_timer +}) + + + +minetest.register_node("lwcomponents:force_field_on", { + description = S("Force Field Generator"), + tiles = { "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", + "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png"}, + is_ground_content = false, + groups = table.copy (force_field_on_groups), + --sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "none", + param2 = 0, + light_source = 3, + floodable = false, + drop = "lwcomponents:force_field", + _digistuff_channelcopier_fieldname = "channel", + + mesecons = mesecon_support (), + digiline = digilines_support (), + tube = pipeworks_support (), + + on_destruct = on_destruct, + on_receive_fields = on_receive_fields, + can_dig = can_dig, + after_place_node = after_place_node, + on_blast = on_blast, + on_rightclick = on_rightclick, + on_timer = on_timer +}) + + + +minetest.register_node("lwcomponents:force_field_locked_on", { + description = S("Force Field Generator (locked)"), + tiles = { "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", + "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png", "lwcomponents_force_field_on.png"}, + is_ground_content = false, + groups = table.copy (force_field_on_groups), + --sounds = default.node_sound_stone_defaults (), + paramtype = "none", + param1 = 0, + paramtype2 = "none", + param2 = 0, + light_source = 3, + floodable = false, + drop = "lwcomponents:force_field_locked", + _digistuff_channelcopier_fieldname = "channel", + + mesecons = mesecon_support (), + digiline = digilines_support (), + tube = pipeworks_support (), + + on_destruct = on_destruct, + 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, + on_timer = on_timer +}) + + + +minetest.register_entity ("lwcomponents:force_field_bubble", { + initial_properties = { + physical = false, + collide_with_objects = false, + collisionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, + selectionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, + pointable = false, + visual = "mesh", + visual_size = { x = 1, y = 1, z = 1 }, + mesh = "lwcomponents_force_field_bubble.obj", + textures = { "lwcomponents_force_field_bubble.png" }, + use_texture_alpha = true, + is_visible = true, + makes_footstep_sound = false, + automatic_rotate = 0.35, + backface_culling = false, + damage_texture_modifier = "", + glow = 14, + static_save = true, + shaded = true, + show_on_minimap = false, + }, + + on_activate = function (self, staticdata, dtime_s) + self.staticdata = staticdata + end, + + get_staticdata = function (self) + return self.staticdata + end, + + on_step = function (self, dtime, moveresult) + end, + + on_punch = function (self, puncher, time_from_last_punch, tool_capabilities, dir) + return true + end, + + on_blast = function (self, damage) + return false, false, nil + end, +}) + + + +utils.hopper_add_container({ + {"top", "lwcomponents:force_field", "fuel"}, -- take items from above into hopper below + {"bottom", "lwcomponents:force_field", "fuel"}, -- insert items below from hopper above + {"side", "lwcomponents:force_field", "fuel"}, -- insert items from hopper at side +}) + + + +utils.hopper_add_container({ + {"top", "lwcomponents:force_field_locked", "fuel"}, -- take items from above into hopper below + {"bottom", "lwcomponents:force_field_locked", "fuel"}, -- insert items below from hopper above + {"side", "lwcomponents:force_field_locked", "fuel"}, -- insert items from hopper at side +}) + + + +utils.hopper_add_container({ + {"top", "lwcomponents:force_field_on", "fuel"}, -- take items from above into hopper below + {"bottom", "lwcomponents:force_field_on", "fuel"}, -- insert items below from hopper above + {"side", "lwcomponents:force_field_on", "fuel"}, -- insert items from hopper at side +}) + + + +utils.hopper_add_container({ + {"top", "lwcomponents:force_field_locked_on", "fuel"}, -- take items from above into hopper below + {"bottom", "lwcomponents:force_field_locked_on", "fuel"}, -- insert items below from hopper above + {"side", "lwcomponents:force_field_locked_on", "fuel"}, -- insert items from hopper at side +}) + + + +-- diff --git a/lwcomponents/hologram.lua b/lwcomponents/hologram.lua new file mode 100644 index 0000000..e333e09 --- /dev/null +++ b/lwcomponents/hologram.lua @@ -0,0 +1,423 @@ +local utils = ... +local S = utils.S + + + +if utils.digilines_supported then + + + +local hologram_block = +{ + black = { + node = "lwcomponents:hologram_black", + image = "lwhologram_black.png", + color = { a = 128, r = 0, g = 0, b = 0 } }, + orange = { + node = "lwcomponents:hologram_orange", + image = "lwhologram_orange.png", + color = { a = 128, r = 255, g = 128, b = 0 } }, + magenta = { + node = "lwcomponents:hologram_magenta", + image = "lwhologram_magenta.png", + color = { a = 128, r = 255, g = 0, b = 255 } }, + sky = { + node = "lwcomponents:hologram_sky", + image = "lwhologram_sky.png", + color = { a = 128, r = 0, g = 128, b = 255 } }, + yellow = { + node = "lwcomponents:hologram_yellow", + image = "lwhologram_yellow.png", + color = { a = 128, r = 255, g = 255, b = 0 } }, + pink = { + node = "lwcomponents:hologram_pink", + image = "lwhologram_pink.png", + color = { a = 128, r = 255, g = 128, b = 128 } }, + cyan = { + node = "lwcomponents:hologram_cyan", + image = "lwhologram_cyan.png", + color = { a = 128, r = 0, g = 255, b = 255 } }, + gray = { + node = "lwcomponents:hologram_gray", + image = "lwhologram_gray.png", + color = { a = 128, r = 128, g = 128, b = 128 } }, + silver = { + node = "lwcomponents:hologram_silver", + image = "lwhologram_silver.png", + color = { a = 128, r = 192, g = 192, b = 192 } }, + red = { + node = "lwcomponents:hologram_red", + image = "lwhologram_red.png", + color = { a = 128, r = 255, g = 0, b = 0 } }, + green = { + node = "lwcomponents:hologram_green", + image = "lwhologram_green.png", + color = { a = 128, r = 0, g = 128, b = 0 } }, + blue = { + node = "lwcomponents:hologram_blue", + image = "lwhologram_blue.png", + color = { a = 128, r = 0, g = 0, b = 255 } }, + brown = { + node = "lwcomponents:hologram_brown", + image = "lwhologram_brown.png", + color = { a = 128, r = 128, g = 64, b = 0 } }, + lime = { + node = "lwcomponents:hologram_lime", + image = "lwhologram_lime.png", + color = { a = 128, r = 0, g = 255, b = 0 } }, + purple = { + node = "lwcomponents:hologram_purple", + image = "lwhologram_purple.png", + color = { a = 128, r = 128, g = 0, b = 128 } }, + white = { + node = "lwcomponents:hologram_white", + image = "lwhologram_white.png", + color = { a = 128, r = 255, g = 255, b = 255 } }, +} + + + +local function rotate_to_dir (center, param2, point) + local base = vector.subtract (point, center) + + if param2 == 1 then + base = vector.rotate (base, { x = 0, y = (math.pi * 1.5), z = 0 }) + elseif param2 == 2 then + base = vector.rotate (base, { x = 0, y = math.pi, z = 0 }) + elseif param2 == 3 then + base = vector.rotate (base, { x = 0, y = (math.pi * 0.5), z = 0 }) + end + + return vector.add (base, center) +end + + + +local function draw_map (pos, map) + local meta = minetest.get_meta (pos) + local holonode = minetest.get_node (pos) + + if meta and holonode and type (map) == "table" then + local id = meta:get_int ("block_id") + + for y = 1, 15 do + local layer = (type (map[y]) == "table" and map[y]) or { } + + for x = 1, 15 do + local line = (type (layer[x]) == "table" and layer[x]) or { } + + for z = 1, 15 do + local map_point = { x = z + pos.x - 8, y = y + pos.y + 1, z = (16 - x) + pos.z - 8 } + local holopos = rotate_to_dir (pos, holonode.param2, map_point) + + local node = utils.get_far_node (holopos) + local draw = false + + if node and node.name ~= "air" then + if node.name:sub (1, 22) == "lwcomponents:hologram_" then + local nodemeta = minetest.get_meta (holopos) + + if nodemeta and nodemeta:get_int ("block_id") == id then + draw = true + end + end + else + draw = true + end + + if draw then + local colornode = hologram_block[line[z]] + + if node then + utils.destroy_node (holopos) + end + + if colornode then + minetest.set_node (holopos, { name = colornode.node }) + + local nodemeta = minetest.get_meta (holopos) + + if nodemeta then + nodemeta:set_int ("block_id", id) + end + end + end + end + end + end + end +end + + + +local function clear_map (pos) + draw_map (pos, { }) +end + + + +local function on_destruct (pos) + clear_map (pos) +end + + + +local function after_place_node (pos, placer, itemstack, pointed_thing) + local meta = minetest.get_meta (pos) + local spec = + "size[7.5,3]".. + "field[1,1;6,2;channel;Channel;${channel}]".. + "button_exit[2.5,2;3,1;submit;Set]" + local id = math.random (1000000) + + meta:set_string ("formspec", spec) + meta:set_int ("block_id", id) + + -- 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", "Hologram (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 + + local meta = minetest.get_meta(pos) + + if fields.submit then + meta:set_string ("channel", fields.channel) + end +end + + + +local function on_blast (pos, intensity) + local meta = minetest.get_meta (pos) + + if meta then + if intensity >= 1.0 then + + clear_map (pos) + + minetest.remove_node (pos) + + else -- intensity < 1.0 + + clear_map (pos) + + 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 + utils.item_drop (stack, nil, pos) + minetest.remove_node (pos) + end + end + end + 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_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 then + if type (msg) == "string" then + local m = { } + for w in string.gmatch(msg, "[^%s]+") do + m[#m + 1] = w + end + + if m[1] == "clear" then + clear_map (pos) + end + + elseif type (msg) == "table" then + draw_map (pos, msg) + + end + end + end + end, + } + } + end + + return nil +end + + + +minetest.register_node("lwcomponents:hologram", { + description = S("Hologram"), + tiles = { "lwhologram.png", "lwhologram.png", "lwhologram.png", + "lwhologram.png", "lwhologram.png", "lwhologram_face.png"}, + is_ground_content = false, + groups = { cracky = 3 }, + --sounds = default.node_sound_stone_defaults (), + paramtype = "light", + param1 = 0, + paramtype2 = "facedir", + param2 = 1, + floodable = false, + _digistuff_channelcopier_fieldname = "channel", + + digiline = digilines_support (), + + on_destruct = on_destruct, + after_place_node = after_place_node, + on_receive_fields = on_receive_fields, + on_blast = on_blast, + can_dig = can_dig, + on_rightclick = on_rightclick +}) + + + +minetest.register_node("lwcomponents:hologram_locked", { + description = S("Hologram (locked)"), + tiles = { "lwhologram.png", "lwhologram.png", "lwhologram.png", + "lwhologram.png", "lwhologram.png", "lwhologram_face.png"}, + is_ground_content = false, + groups = { cracky = 3 }, + --sounds = default.node_sound_stone_defaults (), + paramtype = "light", + param1 = 0, + paramtype2 = "facedir", + param2 = 1, + floodable = false, + _digistuff_channelcopier_fieldname = "channel", + + digiline = digilines_support (), + + on_destruct = on_destruct, + after_place_node = after_place_node_locked, + on_receive_fields = on_receive_fields, + on_blast = on_blast, + can_dig = can_dig, + on_rightclick = on_rightclick +}) + + + +local function register_hologram_block (block) + local bc = hologram_block[block] + + minetest.register_node(bc.node, { + description = S("Hologram "..block), + tiles = { bc.image }, + drawtype = "glasslike", + light_source = 7, + use_texture_alpha = "blend", + sunlight_propagates = true, + walkable = false, + pointable = false, + diggable = false, + climbable = false, + buildable_to = true, + floodable = true, + is_ground_content = false, + groups = { not_in_creative_inventory = 1 }, + paramtype = "light", + param1 = 255, + post_effect_color = bc.color, + }) +end + + + +register_hologram_block ("black") +register_hologram_block ("orange") +register_hologram_block ("magenta") +register_hologram_block ("sky") +register_hologram_block ("yellow") +register_hologram_block ("pink") +register_hologram_block ("cyan") +register_hologram_block ("gray") +register_hologram_block ("silver") +register_hologram_block ("red") +register_hologram_block ("green") +register_hologram_block ("blue") +register_hologram_block ("brown") +register_hologram_block ("lime") +register_hologram_block ("purple") +register_hologram_block ("white") + + + +end -- utils.digilines_supported diff --git a/lwcomponents/hopper.lua b/lwcomponents/hopper.lua new file mode 100644 index 0000000..a0f0635 --- /dev/null +++ b/lwcomponents/hopper.lua @@ -0,0 +1,459 @@ +local utils, mod_storage = ... +local S = utils.S + + + +if utils.hopper_supported then + + + +local hopper_interval = 1.0 + + + +local hopper_list = minetest.deserialize (mod_storage:get_string ("hopper_list")) +if type (hopper_list) ~= "table" then + hopper_list = {} +end + + + +local function add_hopper_to_list (pos) + hopper_list[minetest.pos_to_string (pos, 0)] = true + + mod_storage:set_string ("hopper_list", minetest.serialize (hopper_list)) +end + + + +local function remove_hopper_from_list (pos) + hopper_list[minetest.pos_to_string (pos, 0)] = nil + + mod_storage:set_string ("hopper_list", minetest.serialize (hopper_list)) +end + + + +local input_dir = +{ + [0] = { x = 0, y = 1, z = 0 }, + { x = 0, y = 0, z = 1 }, + { x = 0, y = 0, z = -1 }, + { x = 1, y = 0, z = 0 }, + { x = -1, y = 0, z = 0 }, + { x = 0, y = -1, z = 0 } +} + +local function get_input_dir (node) + return input_dir[math.floor (node.param2 / 4)] +end + + + +local function get_output_dir (node) + if node then + if node.name == "lwcomponents:hopper" then + return vector.multiply (get_input_dir (node), -1) + elseif node.name == "lwcomponents:hopper_horz" then + return minetest.facedir_to_dir (node.param2) + end + end + + return nil +end + + + +local function get_drop (pos) + local objs = minetest.get_objects_inside_radius (pos, 1) + + for _, obj in pairs (objs) do + local obj_pos = (obj.get_pos and obj:get_pos ()) + + if obj_pos and utils.is_drop (obj) then + obj_pos = vector.round (obj_pos) + + if vector.equals (pos, obj_pos) then + local stack = ItemStack (obj:get_luaentity ().itemstring) + + if stack and not stack:is_empty () then + stack:set_count (1) + + return stack, obj + end + end + end + end +end + + + +local function take_drop (obj) + if utils.is_drop (obj) then + local stack = ItemStack (obj:get_luaentity ().itemstring) + + if stack and not stack:is_empty () then + stack:set_count (stack:get_count () - 1) + + if stack:is_empty () then + obj:get_luaentity().itemstring = "" + obj:remove() + else + obj:get_luaentity().itemstring = stack:to_string () + end + end + end +end + + + +local function next_item_to_take (src_pos, src_node, src_inv_name) + if not src_inv_name or not minetest.registered_nodes[src_node.name] then + return + end + + local src_meta = minetest.get_meta (src_pos) + local src_inv = (src_meta and src_meta:get_inventory ()) or nil + + if src_inv then + local slots = src_inv:get_size (src_inv_name) + + for slot = 1, slots, 1 do + local stack = src_inv:get_stack (src_inv_name, slot) + + if stack and not stack:is_empty () then + stack:set_count (1) + + return stack, slot + end + end + end +end + + + +local function take_item (src_pos, src_inv_name, slot) + local src_meta = minetest.get_meta (src_pos) + local src_inv = (src_meta and src_meta:get_inventory ()) or nil + + if src_inv then + local stack = src_inv:get_stack (src_inv_name, slot) + + if stack and not stack:is_empty () then + stack:set_count (stack:get_count () - 1) + + src_inv:set_stack (src_inv_name, slot, stack) + end + end +end + + + +local function call_allow_metadata_inventory_put (def, pos, listname, index, stack, placer) + if def.allow_metadata_inventory_put and placer then + local result, count = pcall (def.allow_metadata_inventory_put, + pos, listname, index, stack, placer) + + if result then + return count + end + end + + return utils.settings.default_stack_max +end + + + +local function call_on_metadata_inventory_put (def, pos, listname, index, stack, placer) + if def.on_metadata_inventory_put and placer then + pcall (def.on_metadata_inventory_put, pos, listname, index, stack, placer) + end +end + + + +local function place_item (dest_pos, dest_node, dest_inv_name, stack, placer) + local dest_def = minetest.registered_nodes[dest_node.name] + + if not dest_inv_name or not dest_def then + return + end + + local dest_meta = minetest.get_meta (dest_pos) + local dest_inv = (dest_meta and dest_meta:get_inventory ()) or nil + + if dest_inv then + local slots = dest_inv:get_size (dest_inv_name) + + -- find existing stack + for slot = 1, slots, 1 do + local inv_stack = dest_inv:get_stack (dest_inv_name, slot) + + if inv_stack and not inv_stack:is_empty () and + utils.is_same_item (inv_stack, stack) and + inv_stack:get_count () < inv_stack:get_stack_max () and + (call_allow_metadata_inventory_put (dest_def, dest_pos, dest_inv_name, slot, stack, placer) > 0) then + + inv_stack:set_count (inv_stack:get_count () + 1) + dest_inv:set_stack (dest_inv_name, slot, inv_stack) + + call_on_metadata_inventory_put (dest_def, dest_pos, dest_inv_name, slot, stack, placer) + + return true + end + end + + -- find empty slot + for slot = 1, slots, 1 do + local inv_stack = dest_inv:get_stack (dest_inv_name, slot) + + if not inv_stack or inv_stack:is_empty () and + (call_allow_metadata_inventory_put (dest_def, dest_pos, dest_inv_name, slot, stack, placer) > 0) then + + dest_inv:set_stack (dest_inv_name, slot, stack) + + call_on_metadata_inventory_put (dest_def, dest_pos, dest_inv_name, slot, stack, placer) + + return true + end + end + end + + return false +end + + + +local function get_player_object (pos) + local meta = minetest.get_meta (pos) + local placer_name = "" + + if meta then + placer_name = meta:get_string ("placer_name") + local placer = minetest.get_player_by_name (placer_name) + + if placer then + return placer + end + + if placer_name == "" then + placer_name = "" + end + end + + return utils.get_dummy_player (true, placer_name) +end + + + +local function run_hopper_action (pos) + local node = utils.get_far_node (pos) + local dest_dir = get_output_dir (node) + + if dest_dir then + local dest_pos = vector.add (pos, dest_dir) + local dest_node = utils.get_far_node (dest_pos) + + if dest_node then + local registered_dest_invs = hopper.get_registered_inventories_for (dest_node.name) + + if registered_dest_invs then + local placer = get_player_object (pos) + local src_pos = vector.add (pos, get_input_dir (node)) + local drop + local stack + local slot = nil + local src_inv_name = nil + + stack, drop = get_drop (src_pos) + + if not stack then + local src_node = utils.get_far_node (src_pos) + + if src_node then + local registered_src_invs = hopper.get_registered_inventories_for (src_node.name) + + if registered_src_invs then + src_inv_name = registered_src_invs["top"] + stack, slot = next_item_to_take (src_pos, src_node, src_inv_name) + end + end + end + + if stack then + local dest_side = (node.name == "lwcomponents:hopper" and "bottom") or "side" + local dest_inv_name = registered_dest_invs[dest_side] + + if place_item (dest_pos, dest_node, dest_inv_name, stack, placer) then + if drop then + take_drop (drop) + else + take_item (src_pos, src_inv_name, slot) + end + end + end + end + end + end +end + + + +local function on_construct (pos) + add_hopper_to_list (pos) +end + + + +local function on_destruct (pos) + remove_hopper_from_list (pos) +end + + + +local function after_place_node (pos, placer, itemstack, pointed_thing) + local meta = minetest.get_meta (pos) + + meta:set_string ("placer_name", (placer and placer:get_player_name ()) or "") + + -- If return true no item is taken from itemstack + return false +end + + + +local function on_place (itemstack, placer, pointed_thing) + if pointed_thing and pointed_thing.type == "node" then + local stack = ItemStack (itemstack) + local dir = vector.direction (pointed_thing.above, pointed_thing.under) + + if dir.y == 0 then + minetest.item_place (ItemStack ("lwcomponents:hopper_horz"), placer, pointed_thing) + + if not utils.is_creative (placer) then + stack:set_count (stack:get_count () - 1) + end + + return stack + end + end + + return minetest.item_place (itemstack, placer, pointed_thing) +end + + + +minetest.register_node ("lwcomponents:hopper", { + description = S("Conduit Hopper"), + tiles = { "lwcomponents_hopper_top.png", "lwcomponents_hopper_vert_spout.png", + "lwcomponents_hopper_side.png", "lwcomponents_hopper_side.png", + "lwcomponents_hopper_side.png", "lwcomponents_hopper_side.png" }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.3125, -0.5, -0.3125, 0.3125, -0.25, 0.3125}, -- spout_vert + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, -0.3125, 0.5, 0.5}, -- funnel_1 + {-0.5, 0, 0.3125, 0.5, 0.5, 0.5}, -- funnel_2 + {-0.5, 0, -0.5, 0.5, 0.5, -0.3125}, -- funnel_3 + {0.3125, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel_4 + } + }, + selection_box = { + type = "fixed", + fixed = { + {-0.3125, -0.5, -0.3125, 0.3125, -0.25, 0.3125}, -- spout_vert + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel + } + }, + collision_box = { + type = "fixed", + fixed = { + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel + {-0.3125, -0.3125, 0.5, 0.3125, 0.3125, 0.3125}, -- spout_side + } + }, + paramtype = "light", + param1 = 0, + paramtype2 = "facedir", + param2 = 0, + drop = "lwcomponents:hopper", + groups = { cracky = 3 }, + --sounds = default.node_sound_stone_defaults (), + + on_construct = on_construct, + on_destruct = on_destruct, + after_place_node = after_place_node, + on_place = on_place, +}) + + + +minetest.register_node ("lwcomponents:hopper_horz", { + description = S("Conduit Hopper"), + tiles = { "lwcomponents_hopper_top.png", "lwcomponents_hopper_bottom.png", + "lwcomponents_hopper_side.png", "lwcomponents_hopper_side.png", + "lwcomponents_hopper_side_spout.png", "lwcomponents_hopper_side.png" }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, -0.3125, 0.5, 0.5}, -- funnel_1 + {-0.5, 0, 0.3125, 0.5, 0.5, 0.5}, -- funnel_2 + {-0.5, 0, -0.5, 0.5, 0.5, -0.3125}, -- funnel_3 + {0.3125, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel_4 + {-0.3125, -0.3125, 0.5, 0.3125, 0.3125, 0.3125}, -- spout_side + } + }, + selection_box = { + type = "fixed", + fixed = { + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel + {-0.3125, -0.3125, 0.5, 0.3125, 0.3125, 0.3125}, -- spout_side + } + }, + collision_box = { + type = "fixed", + fixed = { + {-0.375, -0.375, -0.375, 0.375, 0.3125, 0.375}, -- body + {-0.5, 0, -0.5, 0.5, 0.5, 0.5}, -- funnel + {-0.3125, -0.3125, 0.5, 0.3125, 0.3125, 0.3125}, -- spout_side + } + }, + paramtype = "light", + param1 = 0, + paramtype2 = "facedir", + param2 = 0, + drop = "lwcomponents:hopper", + groups = { cracky = 3, not_in_creative_inventory = 1 }, + --sounds = default.node_sound_stone_defaults (), + + on_construct = on_construct, + on_destruct = on_destruct, + after_place_node = after_place_node, +}) + + + +local function run_hoppers () + for spos, _ in pairs (hopper_list) do + run_hopper_action (minetest.string_to_pos (spos)) + end + + minetest.after (hopper_interval, run_hoppers) +end + + + +minetest.register_on_mods_loaded (function () + minetest.after (3.0, run_hoppers) +end) + + + +end -- utils.hopper_supported diff --git a/lwcomponents/init.lua b/lwcomponents/init.lua new file mode 100644 index 0000000..5a4dbca --- /dev/null +++ b/lwcomponents/init.lua @@ -0,0 +1,55 @@ +local version = "0.1.36" +local mod_storage = minetest.get_mod_storage () + + + +lwcomponents = { } + + + +function lwcomponents.version () + return version +end + + +local utils = { } +local modpath = minetest.get_modpath ("lwcomponents") + +loadfile (modpath.."/settings.lua") (utils) +utils.get_dummy_player = loadfile (modpath.."/dummy_player.lua") () +loadfile (modpath.."/utils.lua") (utils) +loadfile (modpath.."/long_process.lua") (utils) +loadfile (modpath.."/explode.lua") (utils) +loadfile (modpath.."/api.lua") (utils) +utils.connections = loadfile (modpath.."/connections.lua") () +loadfile (modpath.."/dropper.lua") (utils) +loadfile (modpath.."/collector.lua") (utils) +loadfile (modpath.."/dispenser.lua") (utils) +loadfile (modpath.."/detector.lua") (utils) +loadfile (modpath.."/siren.lua") (utils) +loadfile (modpath.."/puncher.lua") (utils) +loadfile (modpath.."/player_button.lua") (utils) +loadfile (modpath.."/hologram.lua") (utils) +loadfile (modpath.."/breaker.lua") (utils) +loadfile (modpath.."/deployer.lua") (utils) +loadfile (modpath.."/fan.lua") (utils) +loadfile (modpath.."/conduit.lua") (utils, mod_storage) +loadfile (modpath.."/hopper.lua") (utils, mod_storage) +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.."/storage.lua") (utils) +loadfile (modpath.."/crafter.lua") (utils) +loadfile (modpath.."/force_field.lua") (utils) +loadfile (modpath.."/destroyer.lua") (utils) +loadfile (modpath.."/extras.lua") (utils) +loadfile (modpath.."/digiswitch.lua") (utils) +loadfile (modpath.."/movefloor.lua") (utils) +loadfile (modpath.."/solid_conductor.lua") (utils) +loadfile (modpath.."/crafting.lua") (utils) + + + +-- diff --git a/lwcomponents/license.txt b/lwcomponents/license.txt new file mode 100644 index 0000000..0071bb8 --- /dev/null +++ b/lwcomponents/license.txt @@ -0,0 +1,127 @@ +Source code license +------------------- + +GNU Lesser General Public License, version 2.1 +Copyright (C) 2021 loosewheel + +This program is free software; you can redistribute it and/or modify it under the terms +of the GNU Lesser General Public License as published by the Free Software Foundation; +either version 2.1 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details: +https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html + +Mesecons through wire code was adapted from mesecons_receiver. + +Fragments of code were gleaned from tnt mod. + + + +lwsiren-buzz.ogg +---------------- +derived from https://www.freesoundslibrary.com/alarm-sound-effect/ + +License: Attribution 4.0 International (CC BY 4.0). You are allowed to use +sound effects free of charge and royalty free in your multimedia projects +for commercial or non-commercial purposes. +https://creativecommons.org/licenses/by/4.0/ + + + +lwsiren-horn.ogg +---------------- +derived from https://www.freesoundslibrary.com/ahooga-horn/ + +License: Attribution 4.0 International (CC BY 4.0). You are allowed to use +sound effects free of charge and royalty free in your multimedia projects +for commercial or non-commercial purposes. +https://creativecommons.org/licenses/by/4.0/ + + + +lwsiren-siren.ogg +------------------ +https://www.freesoundslibrary.com/cop-siren/ + +License: Attribution 4.0 International (CC BY 4.0). You are allowed to use +sound effects free of charge and royalty free in your multimedia projects +for commercial or non-commercial purposes. +https://creativecommons.org/licenses/by/4.0/ + + + +lwsiren-raid.ogg +----------------- +derived from https://www.freesoundslibrary.com/space-ship-siren-sound/ + +License: Attribution 4.0 International (CC BY 4.0). You are allowed to use +sound effects free of charge and royalty free in your multimedia projects +for commercial or non-commercial purposes. +https://creativecommons.org/licenses/by/4.0/ + + + +lwmovefloor.ogg +--------------- +https://www.freesoundslibrary.com/elevator-sound-effect-elevator-ride-doors-closing-and-opening/ + +License: Attribution 4.0 International (CC BY 4.0). You are allowed to use +sound effects free of charge and royalty free in your multimedia projects +for commercial or non-commercial purposes. + + +lwforce_field_zap.ogg +--------------------- +https://orangefreesounds.com/electricity-zap/ + +Licence: The sound effect is permitted for non-commercial use under license +Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) + + + +Media license +------------- +siren images derived from images from https://openclipart.org, which is +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. + +storage nodes 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), +released under CC0 1.0 (originally from https://freesound.org/s/80401/) + +boom image from tnt, released under CC BY-SA 3.0. + +Piston images and sounds from mesecons_pistons, released under CC-BY-SA 3.0. + +All other media, or media not covered by a licence, is licensed +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) + +You are free to: +Share — copy and redistribute the material in any medium or format. +Adapt — remix, transform, and build upon the material for any purpose, even commercially. +The licensor cannot revoke these freedoms as long as you follow the license terms. + +Under the following terms: + +Attribution — You must give appropriate credit, provide a link to the license, and +indicate if changes were made. You may do so in any reasonable manner, but not in any way +that suggests the licensor endorses you or your use. + +ShareAlike — If you remix, transform, or build upon the material, you must distribute +your contributions under the same license as the original. + +No additional restrictions — You may not apply legal terms or technological measures that +legally restrict others from doing anything the license permits. + +See http://creativecommons.org/licenses/by-sa/3.0/