diff --git a/protector-configurator/help.lua b/protector-configurator/help.lua new file mode 100644 index 0000000..a1f77a5 --- /dev/null +++ b/protector-configurator/help.lua @@ -0,0 +1,95 @@ +local modname = "protector_configurator" +local S = minetest.get_translator(modname) + + +protector_configurator = {} + + +function protector_configurator:get_cords(meta) + local cords = meta:get_string("cords") + if cords == "" then + return nil + end + local cords_t = {} + for i, cord in pairs(cords:split(" ")) do + local pos = minetest.string_to_pos(cord) + if pos then table.insert(cords_t, pos) end + end + return cords_t +end + + +function protector_configurator:check_owner(username, pos) + local meta = minetest.get_meta(pos) + if meta:get_string("owner") ~= username then + return false + end + return true +end + + +function protector_configurator:cords2strings(cords) + local cords_t = {} + for i, cord in pairs(cords) do + local cord = minetest.pos_to_string(cord) + if cord then table.insert(cords_t, cord) end + end + return cords_t +end + + +function protector_configurator:add_cord(meta, cord) + local cords = self:get_cords(meta) + if not cords then + cords = {} + end + for i, cord_ in pairs(cords) do + if cord_ == cord then return end + end + table.insert(cords, cord) + meta:set_string("cords", table.concat(self:cords2strings(cords), " ")) +end + + +function protector_configurator:add_cords(meta, new_cords) + local cords = self:get_cords(meta) + if not cords or #cords == 0 then + meta:set_string("cords", table.concat(self:cords2strings(new_cords), " ")) + return + end + local max_idx = #cords + + for i, new_cord in pairs(new_cords) do + local f = false + for i, cord in pairs(cords) do + if new_cord == cord then f = true break end + end + if not f then table.insert(cords, new_cord) end + end + meta:set_string("cords", table.concat(self:cords2strings(cords), " ")) +end + + +function protector_configurator:del_cord_by_index(meta, index) + local cords = self:get_cords(meta) + if not cords then return end + if index > #cords then return end + table.remove(cords, index) + meta:set_string("cords", table.concat(self:cords2strings(cords), " ")) +end + + +function protector_configurator:list2textlist(list, x, y, w, h, name) + if x then x = tostring(x) else x = 1 end + if y then y = tostring(y) else y = 0 end + if w then w = tostring(w) else w = 5 end + if h then h = tostring(h) else h = 7 end + if name then name = tostring(name) else name = "text_list" end + + local str = string.format('textlist[%s,%s;%s,%s;%s;', x, y, w, h, name) + for i, elem in pairs(list) do + str = str .. minetest.formspec_escape(tostring(elem)) .. ',' + end + local str = str:sub(1, #str - 1) .. ";1]" + return str +end \ No newline at end of file diff --git a/protector-configurator/init.lua b/protector-configurator/init.lua new file mode 100644 index 0000000..2a08b3d --- /dev/null +++ b/protector-configurator/init.lua @@ -0,0 +1,6 @@ +local modname = "protector_configurator" +local modpath = minetest.get_modpath(modname) + +dofile(modpath .. "/help.lua") +dofile(modpath .. "/terminal.lua") +dofile(modpath .. "/writer.lua") \ No newline at end of file diff --git a/protector-configurator/locale/protector_configurator.ru.tr b/protector-configurator/locale/protector_configurator.ru.tr new file mode 100644 index 0000000..a9b88f8 --- /dev/null +++ b/protector-configurator/locale/protector_configurator.ru.tr @@ -0,0 +1,22 @@ +# textdomain: protector_configurator + +protect writer=записыватель защиты +LMB on the terminal to insert coordinates from the protect writer into the terminal=ЛКМ по терминалу для вставки коородинат из записывателя защиты в терминал +or=или +LMB on the protector block to add coordinates to the protect writer’s list=ЛКМ по блоку защиты для добавления координат в список записывателя защиты +and=и +shift + RMB to copy coordinates from the terminal to protect writer=shift + ПКМ для копирования координат из терминала в записыватель защиты +no coordinates have been set=не установлено ни одной координаты +clear all=очистить все +delete=удалить +add=добавить +you can't add this protector!=вы не можете добавить этот блок защиты! +you do not own this terminal!=вы не являетесь владельцем этого терминала! +added coordinates:=добавлены координаты: +coordinates added to terminal=координаты добавлены в терминал +no players have been set=не установлен ни один игрок +set members=установить участников +add members=добавить участников +protector terminal=терминал защиты +coordinates copied to writer=координаты скопированы в записыватель защиты +exit=выход \ No newline at end of file diff --git a/protector-configurator/mod.conf b/protector-configurator/mod.conf new file mode 100644 index 0000000..8586829 --- /dev/null +++ b/protector-configurator/mod.conf @@ -0,0 +1,3 @@ +name = protector_configurator +description = Add protector configurator for Protector Redo +depends = default \ No newline at end of file diff --git a/protector-configurator/terminal.lua b/protector-configurator/terminal.lua new file mode 100644 index 0000000..11e53f5 --- /dev/null +++ b/protector-configurator/terminal.lua @@ -0,0 +1,250 @@ +modname = "protector_configurator" +local S = minetest.get_translator(modname) + +local context_cords = {} +local context_players = {} + + +function protector_configurator:terminal_formspec(meta) + + local cords = protector_configurator:get_cords(meta) + if cords then + cords = protector_configurator:cords2strings(cords) + else + cords = {S("no coordinates have been set")} + end + + local players = meta:get_string("players") + if players ~= "" then + players = players:split(" ") + else + players = {S("no players have been set")} + end + + local cordslist = protector_configurator:list2textlist(cords, 11, 0, 5, 7, "cords") + + local playerslist = protector_configurator:list2textlist(players, 0, 0, 5, 7, "players") + + local formspec = "size[16,8]" + .. cordslist + .. "button[11,7;2,1;delete_cord;" .. S("delete") .. "]" + .. "button[13,7;3,1;clear_cords;" .. S("clear all") .. "]" + .. playerslist + .. "button[0,7;2,1;delete_player;" .. S("delete") .. "]" + .. "button[2,7;3,1;clear_players;" .. S("clear all") .. "]" + .. "field[5.5,0.5;3,1;input_name;add player(s):;]" + .. "field_close_on_enter[input_name;false]" + .. "button[8.5,0.2;2,1;add;" .. S("add") .. "]" + .. "button[6,3;4.5,1;set_members;" .. S("set members") .."(=)]" + .. "button[6,4;4.5,1;add_members;" .. S("add members") .."(+)]" + .. "field_enter_after_edit[input_name;true]" + + return formspec +end + + +local function check_can_configure(pos, owner) + local nodename = minetest.get_node(pos).name + if nodename == "ignore" then return "ignore" end + if nodename ~= "protector:protect" and nodename ~= "protector:protect2" then return "cant" end + + local protect_owner = minetest.get_meta(pos):get_string("owner") + + if protect_owner ~= owner then return "cant" end + return "can" +end + + +local function update_cords(meta, cords, to_del) + for i, del_cord in pairs(to_del) do + for j, cord in pairs(cords) do + if cord == del_cord then table.remove(cords, j) break end + end + end + meta:set_string("cords", table.concat(protector_configurator:cords2strings(cords), " ")) +end + + +local function xor_add(list1, list2) + for i, elem2 in pairs(list2) do + local f = false + for j, elem1 in pairs(list1) do + if elem1 == elem2 then f = true break end + end + if not f then table.insert(list1, elem2) end + end + return list1 +end + + +local function set_members(meta, mode) + local mode = mode or "set" + local players = meta:get_string("players") + local cords = protector_configurator:get_cords(meta) + if not cords then return end + + local owner = meta:get_string("owner") + local to_del = {} + + for i, cord in pairs(cords) do + local result = check_can_configure(cord, owner) + + if result == "cant" then -- remove coordinates from the list if the block is not available to this player or is deleted + table.insert(to_del, cord) + elseif result == "can" then + + local protector_meta = minetest.get_meta(cord) + + if mode == "set" then -- if set members + protector_meta:set_string("members", players) + elseif mode == "add" then -- if you add members to those already added earlier + local members = protector_meta:get_string("members") + if members == "" then members = players + else members = table.concat(xor_add(members:split(" "), players:split(" ")), " ") end + protector_meta:set_string("members", members) + end + + end + end + + update_cords(meta, cords, to_del) +end + + +local function add_player(meta, name) + local players = meta:get_string("players") + + if players == "" then + players = {} + else + players = players:split(" ") + end + + for i, name in pairs(name:split(" ")) do + local f = false + for i, player in pairs(players) do + if player == name then f = true break end + end + if not f then table.insert(players, minetest.formspec_escape(name)) end + end + meta:set_string("players", table.concat(players, " ")) +end + +----for formspec---- +local function context_work(name, field, context) + local t = field:split(":") + if t[1] ~= "CHG" then return end + context[name] = tonumber(t[2]) +end + + +local function delete_cord(name, meta) + local idx = context_cords[name] + if not idx then idx = 1 end + + protector_configurator:del_cord_by_index(meta, idx) + + context_cords[name] = nil +end + +local function delete_player(name, meta) + local idx = context_players[name] + if not idx then idx = 1 end + + local players = meta:get_string("players") + if players == "" then + return + else + players = players:split(" ") + end + if idx > #players then return end + + table.remove(players, idx) + + meta:set_string("players", table.concat(players, " ")) + context_players[name] = nil +end + + +local function on_receive_fields(pos, formname, fields, player) + if not player then return end + if not protector_configurator:check_owner(player:get_player_name(), pos) then return end + + local name = player:get_player_name() + local meta = minetest.get_meta(pos) + + --input_name should be processed later by set_members and add_members + if fields.cords then context_work(name, fields.cords, context_cords) + elseif fields.players then context_work(name, fields.players, context_players) + elseif fields.delete_cord then delete_cord(name, meta) + elseif fields.delete_player then delete_player(name, meta) + elseif fields.clear_cords then meta:set_string("cords", "") + elseif fields.clear_players then meta:set_string("players", "") + elseif fields.set_members then set_members(meta) + elseif fields.add_members then set_members(meta, "add") + elseif fields.input_name then add_player(meta, fields.input_name) end + + meta:set_string("formspec", protector_configurator:terminal_formspec(meta)) +end + + +minetest.register_node(modname .. ":terminal", { + description = S("protector terminal"), + + stack_max = 1, + + drawtype = "nodebox", + + groups = {cracky=3, stone=1}, + + paramtype2 = "facedir", + + tiles = { + "protector_configurator_terminal_top.png", + "protector_configurator_terminal_down.png", + "protector_configurator_terminal_right.png", + "protector_configurator_terminal_left.png", + "protector_configurator_terminal_back.png", + "protector_configurator_terminal_front.png" + }, + + node_box = { + type = "fixed", + fixed = {-0.375, -0.5, 0.5, 0.375, 0.375, 0.25} + --12 / 14 / 2 = 0.375, + --4 / 16 = 0.25, + }, + + after_place_node = function(pos, placer, itemstack, pointed_thing) + local meta = minetest.get_meta(pos) + local item_meta = itemstack:get_meta() + meta:set_string("owner", placer:get_player_name()) + + meta:set_string("cords", item_meta:get_string("cords")) + meta:set_string("players", item_meta:get_string("players")) + + meta:set_string("formspec", protector_configurator:terminal_formspec(meta)) + end, + + preserve_metadata = function(pos, oldnode, oldmeta, drops) + if #drops < 1 then return end + + local item_meta = drops[1]:get_meta() + + if oldmeta.cords then item_meta:set_string("cords", oldmeta.cords) end + if oldmeta.players then item_meta:set_string("players", oldmeta.players) end + end, + + on_receive_fields = on_receive_fields +}) + +minetest.register_craft({ + output = modname .. ":terminal", + + recipe = { + {"default:steelblock", "", "default:steelblock"}, + {"default:mese_crystal", "default:steel_ingot", "default:mese_crystal"}, + {"default:steelblock", "default:gold_ingot", "default:steelblock"} + } +}) + diff --git a/protector-configurator/textures/minetest_ptotector_controller_left_clear.png b/protector-configurator/textures/minetest_ptotector_controller_left_clear.png new file mode 100644 index 0000000..7dd8cea Binary files /dev/null and b/protector-configurator/textures/minetest_ptotector_controller_left_clear.png differ diff --git a/protector-configurator/textures/minetest_ptotector_controller_top_clear.png b/protector-configurator/textures/minetest_ptotector_controller_top_clear.png new file mode 100644 index 0000000..2ea7538 Binary files /dev/null and b/protector-configurator/textures/minetest_ptotector_controller_top_clear.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_back.png b/protector-configurator/textures/protector_configurator_terminal_back.png new file mode 100644 index 0000000..96fed7c Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_back.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_down.png b/protector-configurator/textures/protector_configurator_terminal_down.png new file mode 100644 index 0000000..6846b5f Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_down.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_front.png b/protector-configurator/textures/protector_configurator_terminal_front.png new file mode 100644 index 0000000..6e15834 Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_front.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_left.png b/protector-configurator/textures/protector_configurator_terminal_left.png new file mode 100644 index 0000000..1089999 Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_left.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_right.png b/protector-configurator/textures/protector_configurator_terminal_right.png new file mode 100644 index 0000000..a868624 Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_right.png differ diff --git a/protector-configurator/textures/protector_configurator_terminal_top.png b/protector-configurator/textures/protector_configurator_terminal_top.png new file mode 100644 index 0000000..d77149a Binary files /dev/null and b/protector-configurator/textures/protector_configurator_terminal_top.png differ diff --git a/protector-configurator/textures/protector_configurator_writer.png b/protector-configurator/textures/protector_configurator_writer.png new file mode 100644 index 0000000..f9c26b9 Binary files /dev/null and b/protector-configurator/textures/protector_configurator_writer.png differ diff --git a/protector-configurator/writer.lua b/protector-configurator/writer.lua new file mode 100644 index 0000000..7fdba04 --- /dev/null +++ b/protector-configurator/writer.lua @@ -0,0 +1,193 @@ +local modname = "protector_configurator" +local S = minetest.get_translator(modname) + +local context = {} + + +local writer_formspec = function(itemstack, player) + if not player then + return + end + local player = player:get_player_name() + if not player then + return + end + + local meta = itemstack:get_meta() + + local cords = protector_configurator:get_cords(meta) + + -- if coordinates are not set, we will display information about this instead of coordinates + local textlist = "" + if not cords then + textlist = protector_configurator:list2textlist({S("no coordinates have been set")}) + else + textlist = protector_configurator:list2textlist(protector_configurator:cords2strings(cords)) + end + + local formspec = 'size[8,8]' + .. textlist + .. "button[1,7;2,1;delete;" .. S("delete") .. "]" + .. "button[3,7;3,1;clear;" .. S("clear all") .. "]" + .. "button_exit[6,7;2,1;exit;" .. S("exit") .. "]" + + minetest.show_formspec(player, modname .. ":writer_formspec", formspec) +end + + +local function use_with_protecotr(itemstack, username, pos) + local meta = itemstack:get_meta() + protector_configurator:add_cord(meta, pos) + + minetest.chat_send_player(username, S("added coordinates:") .. " " + .. minetest.pos_to_string(pos)) + + return itemstack +end + + +local function use_with_terminal(itemstack, username, pos) + local terminal_meta = minetest.get_meta(pos) + local writer_meta = itemstack:get_meta() + + local writer_cords = protector_configurator:get_cords(writer_meta) + if not writer_cords then return end + + protector_configurator:add_cords(terminal_meta, writer_cords) + + minetest.chat_send_player(username, S("coordinates added to terminal") ) + + terminal_meta:set_string("formspec", protector_configurator:terminal_formspec(terminal_meta)) + return itemstack +end + + +local function on_use_writer(itemstack, user, pointed_thing) + if not user or pointed_thing.type ~= "node" then + return + end + local username = user:get_player_name() + if not username then + return + end + + local pos = pointed_thing.under + local nodename = minetest.get_node(pos).name + + if nodename == "protector:protect" or nodename == "protector:protect2" then + if protector_configurator:check_owner(username, pos) then -- add protector cords + return use_with_protecotr(itemstack, username, pos) + else -- cant add protector + minetest.chat_send_player(username, S("you can't add this protector!")) + end + elseif nodename == modname .. ":terminal" then + if protector_configurator:check_owner(username, pos) then -- add cords to terminal + return use_with_terminal(itemstack, username, pos) + else -- cant add cords to terminal + minetest.chat_send_player(username, S("you do not own this terminal!")) + end + end +end + + +local function copy_to_writer(pos, itemstack) + local terminal_meta = minetest.get_meta(pos) + local writer_meta = itemstack:get_meta() + + writer_meta:set_string("cords", terminal_meta:get_string("cords")) + return itemstack +end + + +local function on_place(itemstack, placer, pointed_thing) + if not placer then return end + local name = placer:get_player_name() + + if pointed_thing.type == "node" then + local node = minetest.get_node(pointed_thing.under).name + print("node") + print(node) + if node ~= modname .. ":terminal" then + writer_formspec(itemstack, placer) + return + end + if protector_configurator:check_owner(name, pointed_thing.under) then + minetest.chat_send_player(name, S("coordinates copied to writer")) + return copy_to_writer(pointed_thing.under, itemstack) + else + minetest.chat_send_player(name, S("you do not own this terminal!")) + end + end +end + + +minetest.register_craftitem(modname .. ":writer", { + + description = S("protect writer") .. "\n" + .. S("LMB on the protector block to add coordinates to the protect writer’s list") .. "\n" + .. S("or") .. " " .. S("LMB on the terminal to insert coordinates from the protect writer into the terminal") .. "\n" + .. S("and") .. " " .. S("shift + RMB to copy coordinates from the terminal to protect writer"), + + stack_max = 1, + + inventory_image = modname .. "_writer.png", + + on_place = on_place, + + on_secondary_use = writer_formspec, + + on_use = on_use_writer +}) + +-----for formspec----- + +local function clear_writer(player, item) + if not player then return end + local meta = item:get_meta() + meta:set_string("cords", "") + player:set_wielded_item(item) +end + +local function textlist_work(player, field) + if not player then return end + local t = field:split(":") + if t[1] ~= "CHG" then return end + context[player:get_player_name()] = tonumber(t[2]) +end + +local function delete(player, item) + if not player or not item then return end + local name = player:get_player_name() + + local idx = context[name] + if not idx then idx = 1 end + + local meta = item:get_meta() + protector_configurator:del_cord_by_index(meta, idx) + + player:set_wielded_item(item) + context[name] = nil +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "protector_configurator:writer_formspec" then return end + local item = player:get_wielded_item() + if not item then return end + if item:get_name() ~= modname .. ":writer" then return end + + if fields.clear then clear_writer(player, item) + elseif fields.text_list then textlist_work(player, fields.text_list) + elseif fields.delete then delete(player, item) end + + if not fields.exit then writer_formspec(item, player) end +end) + +minetest.register_craft({ + output = modname .. ":writer", + + recipe = { + {"default:mese_crystal"}, + {"default:steel_ingot"}, + {"default:stick"} + } +}) \ No newline at end of file