From 881bb329b39e90d0f2694dd84b11aff48460663d Mon Sep 17 00:00:00 2001 From: Vitaliy Olkhin Date: Sun, 25 Feb 2024 14:41:23 +0500 Subject: [PATCH] protector-configurator mod by nikaru --- help.lua | 95 +++++++ init.lua | 6 + locale/protector_configurator.ru.tr | 22 ++ mod.conf | 3 + terminal.lua | 250 ++++++++++++++++++ ...netest_ptotector_controller_left_clear.png | Bin 0 -> 250 bytes ...inetest_ptotector_controller_top_clear.png | Bin 0 -> 218 bytes .../protector_configurator_terminal_back.png | Bin 0 -> 475 bytes .../protector_configurator_terminal_down.png | Bin 0 -> 236 bytes .../protector_configurator_terminal_front.png | Bin 0 -> 580 bytes .../protector_configurator_terminal_left.png | Bin 0 -> 288 bytes .../protector_configurator_terminal_right.png | Bin 0 -> 276 bytes .../protector_configurator_terminal_top.png | Bin 0 -> 249 bytes textures/protector_configurator_writer.png | Bin 0 -> 311 bytes writer.lua | 193 ++++++++++++++ 15 files changed, 569 insertions(+) create mode 100644 help.lua create mode 100644 init.lua create mode 100644 locale/protector_configurator.ru.tr create mode 100644 mod.conf create mode 100644 terminal.lua create mode 100644 textures/minetest_ptotector_controller_left_clear.png create mode 100644 textures/minetest_ptotector_controller_top_clear.png create mode 100644 textures/protector_configurator_terminal_back.png create mode 100644 textures/protector_configurator_terminal_down.png create mode 100644 textures/protector_configurator_terminal_front.png create mode 100644 textures/protector_configurator_terminal_left.png create mode 100644 textures/protector_configurator_terminal_right.png create mode 100644 textures/protector_configurator_terminal_top.png create mode 100644 textures/protector_configurator_writer.png create mode 100644 writer.lua diff --git a/help.lua b/help.lua new file mode 100644 index 0000000..a1f77a5 --- /dev/null +++ b/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/init.lua b/init.lua new file mode 100644 index 0000000..2a08b3d --- /dev/null +++ b/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/locale/protector_configurator.ru.tr b/locale/protector_configurator.ru.tr new file mode 100644 index 0000000..a9b88f8 --- /dev/null +++ b/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/mod.conf b/mod.conf new file mode 100644 index 0000000..8586829 --- /dev/null +++ b/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/terminal.lua b/terminal.lua new file mode 100644 index 0000000..11e53f5 --- /dev/null +++ b/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/textures/minetest_ptotector_controller_left_clear.png b/textures/minetest_ptotector_controller_left_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd8cea86b3cf7e422ce93ef494e51ed02d3ef63 GIT binary patch literal 250 zcmVPx#v`IukR0x?R&RdGYFc^T*ufIvX6ha|14mc0vD!OfFDdQSOXdX(TPNF6?&Vvg$ zaH`Yy>E#E{{$tNA-jF3P^nK6q>xkAGi7_IwBE$fIgb?@(S40G*71DJb6+$V6%kKph zW8{(UlxN}ad3ckiY1nRe_`xG>+mdqzz&VEiEP3HYVVWjno@bO+02pHsYb^jNC34P) z(u$N4bzQ%we(&MdS3OLYa-%lGYxzY+n_0KkLuc&#XH2j!n6{ SgXMwlWAJqKb6Mw<&;$TfU{!Pg literal 0 HcmV?d00001 diff --git a/textures/protector_configurator_terminal_back.png b/textures/protector_configurator_terminal_back.png new file mode 100644 index 0000000000000000000000000000000000000000..96fed7c52a6e5ed13440c8f72320a1a0fc7f0638 GIT binary patch literal 475 zcmV<10VMv3P)JP00001b5ch_0Itp) z=>Px$l}SWFR49=}klkwAKoCaHj(7EAQ4z<)DWp%+JZzq+$yK0%8e$BxS5myYGrf@O z&h`1u_c89}<;6ZfKLPOG({&xE(+LqlL*^V?;iF ze=KlTe5kHghnZ1VHL8UeBdW^7!vk`Ee@{^Z;Cwn`rvJC+3ueaGWoDjc#&N_C!+@zV z&l62k6CB_@=X2zeGPM)Bt|O&Hj1j-v?NBYKDJdl&kmiV*;{6K0@}!hdHSX^2kmK=q z+gr*Kx}=1vQdc#(WafD$=LCTCeGfoU#R;e>bzR{Qa>>_L5GSrmG2`lk5b+Z^t zL9g$wtA@I2*#Ft%`@ZM(^%p*Pa>@+DK;QQq4hPz{WxZZ=I2_pRc5Js>{sK}}_X#%= R&lvy!002ovPDHLkV1f*p-bnxe literal 0 HcmV?d00001 diff --git a/textures/protector_configurator_terminal_down.png b/textures/protector_configurator_terminal_down.png new file mode 100644 index 0000000000000000000000000000000000000000..6846b5fc74b845a6a8cd97b5174a59a836bd7866 GIT binary patch literal 236 zcmVPx#rb$FWR0x?h!J!etFcg5{KejllPTxZ m32QCZTAXvJD%Ge$a^VO4qe(Xk1!3y|0000JP00001b5ch_0Itp) z=>Px${z*hZR49>clCf(OaR7zC{O*p+K{-pVNz+m>OT}U}OF|4qkrpbX(nZk0-NChs zvy({eAK)Mau@OuycF3Zr9b!n^C1|6$sED*C!Cr$0$!V{ba|m?Gn?HE(@m?U8%lQWf z2LQ;j%llwG-fI>J8OBgX*4v8F~*uAfM0s^H(aA zDwnx%ej0#MvB>zuX=Ftr*|-jXorr^!LUvsjyfXUG0v~rj@w?GvbUcdJ^SHKoi$tPx#+DSw~R0x?x&Am#)P#A#Wx2HKa68MG#rVb9xpy(nJhjRg<2oA2j4>v~#Z^R*s z=&0ZoxD*ZegAO`a40Q;6gH;br92~rX=jjwh(W)x_#Xi%|DaKlh_nvH!VXY+!Az)0G z!NLJq3LSmlY3X|IU-qb~isPx#&PhZ;R0x?R&M`{FKp240FTXQU2!ue$tf+ns3bt>xQ( zAtETPkfv$K5K>BX?;XlH$FKh({Uxri`W-2Xf{U{|?jKH&s;USffNC+uAOJB$h)bqv zBK!Qf*%Ft$zTL9!)~KiFbB>NL@!k_cK$KQ^@5%FgHy!$c{rrFoVH`(PUDvEuFBoGe a%aVW5!dFrUP1el-0000Px#vq?ljR0x?R%b{+EmZw?4p=l5iLPx#@kvBMR5*>rlCg@yKoEw%Rr|npS_rx0B=#0|zJ<<;>8uE-UFU6RVq zLa<1YCSWay$34MZAz3ew^J!?o8S({0MTrRi5VgcK23_uu$&T*`R6)qr#cxF8P!+91v?xU@fhEAYhg`j57@>j&8YO@?>3h0Oo}002ov JPDHLkV1jl*i17db literal 0 HcmV?d00001 diff --git a/writer.lua b/writer.lua new file mode 100644 index 0000000..7fdba04 --- /dev/null +++ b/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