Add 'exchange' command to the door controller
This commit is contained in:
parent
b178801acb
commit
e12262172b
@ -997,10 +997,18 @@ techage.manual_DE.aText = {
|
|||||||
"\n"..
|
"\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
"\n",
|
"\n",
|
||||||
"Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen\\, muss der \"Aufzeichnen\" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden\\, die Teil der Tür / des Tores sein sollen. Danach muss der \"Fertig\" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert. Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n"..
|
"Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen\\, muss der \"Aufzeichnen\" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden\\, die Teil der Tür / des Tores sein sollen. Danach muss der \"Fertig\" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert.\n"..
|
||||||
|
"\n"..
|
||||||
|
" Über die Tasten \"Entfernen\" bzw. \"Setzen\" kann die Funktion des Controllers von Hand getestet werden.\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
"Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n"..
|
"Wird ein 'on' / 'off' Kommando an den Tür Controller II gesendet\\, entfernt bzw. setzt er die Blöcke ebenfalls.\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
|
"Über ein 'exchange' Kommando können einzelne Böcke gesetzt\\, entfernt\\, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden\\, also:\n"..
|
||||||
|
"\n"..
|
||||||
|
" $send_cmnd(node_number\\, \"exchange\"\\, 2)\n"..
|
||||||
|
"\n"..
|
||||||
|
"Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.\n"..
|
||||||
|
"\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
"\n",
|
"\n",
|
||||||
"Der Mesecons Umsetzer dient zur Umwandlung von Techage on/off Kommandos in Mesecons Signale und umgekehrt.\n"..
|
"Der Mesecons Umsetzer dient zur Umwandlung von Techage on/off Kommandos in Mesecons Signale und umgekehrt.\n"..
|
||||||
|
@ -988,6 +988,12 @@ techage.manual_EN.aText = {
|
|||||||
"\n",
|
"\n",
|
||||||
"The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n"..
|
"The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II\\, the \"Record\" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the \"Done\" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the \"Remove\" or \"Set\" buttons. If an 'on' /'off' command is sent to the Door Controller II\\, it removes or sets the blocks as well.\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
|
"Individual blocks can be set\\, removed or replaced by other blocks via an 'exchange' command. The slot number of the inventory (1 .. 16) must be transferred as payload\\, i.e.:\n"..
|
||||||
|
"\n"..
|
||||||
|
" $send_cmnd(node_number\\, \"exchange\"\\, 2)\n"..
|
||||||
|
"\n"..
|
||||||
|
"This can also be used to simulate extendable stairs and the like. \n"..
|
||||||
|
"\n"..
|
||||||
"\n"..
|
"\n"..
|
||||||
"\n",
|
"\n",
|
||||||
"The Mesecons converter is used to convert Techage on/off commands into Mesecons signals and vice versa.\n"..
|
"The Mesecons converter is used to convert Techage on/off commands into Mesecons signals and vice versa.\n"..
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
TechAge
|
TechAge
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Copyright (C) 2020 Joachim Stolberg
|
Copyright (C) 2020-2021 Joachim Stolberg
|
||||||
|
|
||||||
AGPL v3
|
AGPL v3
|
||||||
See LICENSE.txt for more information
|
See LICENSE.txt for more information
|
||||||
@ -19,23 +19,43 @@ local S = techage.S
|
|||||||
|
|
||||||
local logic = techage.logic
|
local logic = techage.logic
|
||||||
|
|
||||||
local MarkedNodes = {} -- t[player][hash] = entity
|
local MarkedNodes = {} -- t[player] = {{entity, pos},...}
|
||||||
local CurrentPos -- to mark punched entities
|
local CurrentPos -- to mark punched entities
|
||||||
|
local RegisteredNodes = {} -- to be checked before removed/placed
|
||||||
|
|
||||||
|
local function is_simple_node(name)
|
||||||
|
-- special handling
|
||||||
|
if RegisteredNodes[name] ~= nil then
|
||||||
|
return RegisteredNodes[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
local ndef = minetest.registered_nodes[name]
|
||||||
|
if not ndef or name == "air" then return true end
|
||||||
|
if ndef.groups and ndef.groups.techage_door == 1 then return true end
|
||||||
|
|
||||||
|
-- don't remove nodes with some intelligence or undiggable nodes
|
||||||
|
if ndef.drop == "" then return false end
|
||||||
|
if ndef.diggable == false then return false end
|
||||||
|
if ndef.after_dig_node then return false end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local function unmark_position(name, pos)
|
local function unmark_position(name, pos)
|
||||||
MarkedNodes[name] = MarkedNodes[name] or {}
|
|
||||||
pos = vector.round(pos)
|
pos = vector.round(pos)
|
||||||
local hash = minetest.hash_node_position(pos)
|
for idx,item in ipairs(MarkedNodes[name] or {}) do
|
||||||
if MarkedNodes[name][hash] then
|
if vector.equals(pos, item.pos) then
|
||||||
MarkedNodes[name][hash]:remove()
|
item.entity:remove()
|
||||||
MarkedNodes[name][hash] = nil
|
table.remove(MarkedNodes[name], idx)
|
||||||
CurrentPos = hash
|
CurrentPos = pos
|
||||||
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function unmark_all(name)
|
local function unmark_all(name)
|
||||||
for _,entity in pairs(MarkedNodes[name] or {}) do
|
for _,item in ipairs(MarkedNodes[name] or {}) do
|
||||||
entity:remove()
|
item.entity:remove()
|
||||||
end
|
end
|
||||||
MarkedNodes[name] = nil
|
MarkedNodes[name] = nil
|
||||||
end
|
end
|
||||||
@ -43,12 +63,11 @@ end
|
|||||||
local function mark_position(name, pos)
|
local function mark_position(name, pos)
|
||||||
MarkedNodes[name] = MarkedNodes[name] or {}
|
MarkedNodes[name] = MarkedNodes[name] or {}
|
||||||
pos = vector.round(pos)
|
pos = vector.round(pos)
|
||||||
local hash = minetest.hash_node_position(pos)
|
if not CurrentPos or not vector.equals(pos, CurrentPos) then -- entity not punched?
|
||||||
if hash ~= CurrentPos then -- entity not punched?
|
|
||||||
local entity = minetest.add_entity(pos, "techage:marker")
|
local entity = minetest.add_entity(pos, "techage:marker")
|
||||||
if entity ~= nil then
|
if entity ~= nil then
|
||||||
entity:get_luaentity().player_name = name
|
entity:get_luaentity().player_name = name
|
||||||
MarkedNodes[name][hash] = entity
|
table.insert(MarkedNodes[name], {pos = pos, entity = entity})
|
||||||
end
|
end
|
||||||
CurrentPos = nil
|
CurrentPos = nil
|
||||||
return true
|
return true
|
||||||
@ -56,11 +75,10 @@ local function mark_position(name, pos)
|
|||||||
CurrentPos = nil
|
CurrentPos = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function table_to_poslist(name)
|
local function get_poslist(name)
|
||||||
local lst = {}
|
local lst = {}
|
||||||
for hash,_ in pairs(MarkedNodes[name] or {}) do
|
for _,item in ipairs(MarkedNodes[name] or {}) do
|
||||||
local pos = minetest.get_position_from_hash(hash)
|
table.insert(lst, item.pos)
|
||||||
table.insert(lst, pos)
|
|
||||||
end
|
end
|
||||||
return lst
|
return lst
|
||||||
end
|
end
|
||||||
@ -100,21 +118,25 @@ minetest.register_entity(":techage:marker", {
|
|||||||
|
|
||||||
local function formspec1(meta)
|
local function formspec1(meta)
|
||||||
local status = meta:get_string("status")
|
local status = meta:get_string("status")
|
||||||
return "size[8,6.5]"..
|
return "size[8,7]"..
|
||||||
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]"..
|
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";1;;true]"..
|
||||||
"button[0.7,0;3,1;record;"..S("Record").."]"..
|
"button[0.7,0.5;3,1;record;"..S("Record").."]"..
|
||||||
"button[4.3,0;3,1;ready;"..S("Done").."]"..
|
"button[4.3,0.5;3,1;ready;"..S("Done").."]"..
|
||||||
"button[0.7,1;3,1;show;"..S("Set").."]"..
|
"button[0.7,1.5;3,1;show;"..S("Set").."]"..
|
||||||
"button[4.3,1;3,1;hide;"..S("Remove").."]"..
|
"button[4.3,1.5;3,1;hide;"..S("Remove").."]"..
|
||||||
"label[0.5,2;"..status.."]"..
|
"label[0.5,2.5;"..status.."]"..
|
||||||
"list[current_player;main;0,2.8;8,4;]"
|
"list[current_player;main;0,3.3;8,4;]"
|
||||||
end
|
end
|
||||||
|
|
||||||
local function formspec2()
|
local function formspec2()
|
||||||
return "size[8,6.5]"..
|
return "size[8,7]"..
|
||||||
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
|
"tabheader[0,0;tab;"..S("Ctrl,Inv")..";2;;true]"..
|
||||||
"list[context;main;0,0;8,2;]"..
|
"label[0.3,0.0;1]"..
|
||||||
"list[current_player;main;0,2.8;8,4;]"..
|
"label[7.3,0.0;8]"..
|
||||||
|
"label[0.3,2.4;9]"..
|
||||||
|
"label[7.3,2.4;16]"..
|
||||||
|
"list[context;main;0,0.5;8,2;]"..
|
||||||
|
"list[current_player;main;0,3.3;8,4;]"..
|
||||||
"listring[context;main]"..
|
"listring[context;main]"..
|
||||||
"listring[current_player;main]"
|
"listring[current_player;main]"
|
||||||
end
|
end
|
||||||
@ -128,22 +150,22 @@ end
|
|||||||
|
|
||||||
local function exchange_node(pos, item, param2)
|
local function exchange_node(pos, item, param2)
|
||||||
local node = minetest.get_node_or_nil(pos)
|
local node = minetest.get_node_or_nil(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
if node and is_simple_node(node.name) then
|
||||||
if node and (not meta or not next((meta:to_table()).fields)) or
|
if item and item:get_name() ~= "" then
|
||||||
minetest.get_item_group(node.name, "techage_door") then
|
|
||||||
if item and item:get_name() ~= "" and param2 then
|
|
||||||
minetest.swap_node(pos, {name = item:get_name(), param2 = param2})
|
minetest.swap_node(pos, {name = item:get_name(), param2 = param2})
|
||||||
else
|
else
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
end
|
end
|
||||||
if node.name ~= "air" then
|
if node.name ~= "air" then
|
||||||
return ItemStack(node.name), node.param2
|
return ItemStack(node.name), node.param2
|
||||||
|
else
|
||||||
|
return ItemStack(), nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return ItemStack(), nil
|
return item, param2
|
||||||
end
|
end
|
||||||
|
|
||||||
local function exchange_nodes(pos, nvm)
|
local function exchange_nodes(pos, nvm, slot)
|
||||||
local meta = M(pos)
|
local meta = M(pos)
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
|
|
||||||
@ -153,7 +175,7 @@ local function exchange_nodes(pos, nvm)
|
|||||||
nvm.pos_list = nvm.pos_list or {}
|
nvm.pos_list = nvm.pos_list or {}
|
||||||
nvm.param2_list = nvm.param2_list or {}
|
nvm.param2_list = nvm.param2_list or {}
|
||||||
|
|
||||||
for idx = 1, 16 do
|
for idx = (slot or 1), (slot or 16) do
|
||||||
local pos = nvm.pos_list[idx]
|
local pos = nvm.pos_list[idx]
|
||||||
if pos and not minetest.is_protected(pos, owner) then
|
if pos and not minetest.is_protected(pos, owner) then
|
||||||
item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item_list[idx], nvm.param2_list[idx])
|
item_list[idx], nvm.param2_list[idx] = exchange_node(pos, item_list[idx], nvm.param2_list[idx])
|
||||||
@ -213,22 +235,18 @@ minetest.register_node("techage:ta3_doorcontroller2", {
|
|||||||
return
|
return
|
||||||
elseif fields.record then
|
elseif fields.record then
|
||||||
local inv = meta:get_inventory()
|
local inv = meta:get_inventory()
|
||||||
if not inv:is_empty("main") then
|
local nvm = techage.get_nvm(pos)
|
||||||
meta:set_string("status", S("Error: Inventory already in use"))
|
nvm.pos_list = nil
|
||||||
else
|
nvm.is_on = false
|
||||||
local nvm = techage.get_nvm(pos)
|
meta:set_string("status", S("Recording..."))
|
||||||
nvm.pos_list = nil
|
local name = player:get_player_name()
|
||||||
nvm.is_on = false
|
minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
|
||||||
meta:set_string("status", S("Recording..."))
|
MarkedNodes[name] = {}
|
||||||
local name = player:get_player_name()
|
|
||||||
minetest.chat_send_player(name, S("Click on all the blocks that are part of the door/gate"))
|
|
||||||
MarkedNodes[name] = {}
|
|
||||||
end
|
|
||||||
meta:set_string("formspec", formspec1(meta))
|
meta:set_string("formspec", formspec1(meta))
|
||||||
elseif fields.ready then
|
elseif fields.ready then
|
||||||
local nvm = techage.get_nvm(pos)
|
local nvm = techage.get_nvm(pos)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local pos_list = table_to_poslist(name)
|
local pos_list = get_poslist(name)
|
||||||
local text = #pos_list.." "..S("block positions are stored.")
|
local text = #pos_list.." "..S("block positions are stored.")
|
||||||
meta:set_string("status", text)
|
meta:set_string("status", text)
|
||||||
nvm.pos_list = pos_list
|
nvm.pos_list = pos_list
|
||||||
@ -258,7 +276,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
|
|||||||
if minetest.is_protected(pos, player:get_player_name()) then
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
return 0
|
return 1
|
||||||
end,
|
end,
|
||||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
if minetest.is_protected(pos, player:get_player_name()) then
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
@ -270,10 +288,7 @@ minetest.register_node("techage:ta3_doorcontroller2", {
|
|||||||
if minetest.is_protected(pos, player:get_player_name()) then
|
if minetest.is_protected(pos, player:get_player_name()) then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
if is_simple_node(stack:get_name()) then
|
||||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
|
||||||
local pos_list = minetest.deserialize(M(pos):get_string("pos_list")) or {}
|
|
||||||
if pos_list[index] and inv:get_stack(listname, index):get_count() == 0 then
|
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
return 0
|
return 0
|
||||||
@ -301,9 +316,12 @@ minetest.register_node("techage:ta3_doorcontroller2", {
|
|||||||
techage.register_node({"techage:ta3_doorcontroller2"}, {
|
techage.register_node({"techage:ta3_doorcontroller2"}, {
|
||||||
on_recv_message = function(pos, src, topic, payload)
|
on_recv_message = function(pos, src, topic, payload)
|
||||||
if topic == "on" then
|
if topic == "on" then
|
||||||
return hide_nodes(pos, nil)
|
return hide_nodes(pos)
|
||||||
elseif topic == "off" then
|
elseif topic == "off" then
|
||||||
return show_nodes(pos)
|
return show_nodes(pos)
|
||||||
|
elseif topic == "exchange" then
|
||||||
|
local nvm = techage.get_nvm(pos)
|
||||||
|
return exchange_nodes(pos, nvm, tonumber(payload))
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end,
|
end,
|
||||||
@ -345,4 +363,4 @@ minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
|
|||||||
|
|
||||||
mark_position(name, pointed_thing.under)
|
mark_position(name, pointed_thing.under)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -636,10 +636,20 @@ Der Tür Controller dient zur Ansteuerung der TA3 Tür/Tor Blöcke. Beim Tür Co
|
|||||||
|
|
||||||
### TA3 Tür Controller II / Door Controller II
|
### TA3 Tür Controller II / Door Controller II
|
||||||
|
|
||||||
Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen, muss der "Aufzeichnen" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden, die Teil der Tür / des Tores sein sollen. Danach muss der "Fertig" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert. Über die Tasten "Entfernen" bzw. "Setzen" kann die Funktion des Controllers von Hand getestet werden.
|
Der Tür Controller II kann alle Arten von Blöcken entfernen und wieder setzen. Um den Tür Controller II anzulernen, muss der "Aufzeichnen" Button gedrückt werden. Dann müssen alle Blöcke angeklickt werden, die Teil der Tür / des Tores sein sollen. Danach muss der "Fertig" Button gedrückt werden. Es können bis zu 16 Blöcke ausgewählt werden. Die entfernten Blöcke werden im Inventar des Controllers gespeichert.
|
||||||
|
|
||||||
|
Über die Tasten "Entfernen" bzw. "Setzen" kann die Funktion des Controllers von Hand getestet werden.
|
||||||
|
|
||||||
Wird ein `on` / `off` Kommando an den Tür Controller II gesendet, entfernt bzw. setzt er die Blöcke ebenfalls.
|
Wird ein `on` / `off` Kommando an den Tür Controller II gesendet, entfernt bzw. setzt er die Blöcke ebenfalls.
|
||||||
|
|
||||||
|
Über ein `exchange` Kommando können einzelne Böcke gesetzt, entfernt, bzw. durch andere Blöcke ersetzt werden. Die Slot-Nummer des Inventars (1 .. 16) muss als payload übergeben werden, also:
|
||||||
|
|
||||||
|
```
|
||||||
|
$send_cmnd(node_number, "exchange", 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
Damit lassen sich auch ausfahrbare Treppen und ähnliches simulieren.
|
||||||
|
|
||||||
[ta3_doorcontroller|image]
|
[ta3_doorcontroller|image]
|
||||||
|
|
||||||
### TA3 Mesecons Umsetzer / TA3 Mesecons Converter
|
### TA3 Mesecons Umsetzer / TA3 Mesecons Converter
|
||||||
|
@ -621,7 +621,15 @@ The door controller is used to control the TA3 door/gate blocks. With the door c
|
|||||||
|
|
||||||
### TA3 Door Controller II
|
### TA3 Door Controller II
|
||||||
|
|
||||||
The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II, the "Record" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the "Done" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the "Remove" or "Set" buttons. If an `on` /` off` command is sent to the Door Controller II, it removes or sets the blocks as well.
|
The Door Controller II can remove and set all types of blocks. To teach in the Door Controller II, the "Record" button must be pressed. Then all blocks that should be part of the door / gate must be clicked. Then the "Done" button must be pressed. Up to 16 blocks can be selected. The removed blocks are saved in the controller's inventory. The function of the controller can be tested manually using the "Remove" or "Set" buttons. If an `on` /`off` command is sent to the Door Controller II, it removes or sets the blocks as well.
|
||||||
|
|
||||||
|
Individual blocks can be set, removed or replaced by other blocks via an `exchange` command. The slot number of the inventory (1 .. 16) must be transferred as payload, i.e.:
|
||||||
|
|
||||||
|
```
|
||||||
|
$send_cmnd(node_number, "exchange", 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be used to simulate extendable stairs and the like.
|
||||||
|
|
||||||
[ta3_doorcontroller|image]
|
[ta3_doorcontroller|image]
|
||||||
|
|
||||||
|
@ -390,6 +390,7 @@ Please note, that this is not a technical distinction, only a logical.
|
|||||||
| "reset" | nil | Reset the item counter of the TA4 Item Detector block |
|
| "reset" | nil | Reset the item counter of the TA4 Item Detector block |
|
||||||
| "pull" | item string | Start the TA4 pusher to pull/push items.<br /> Example: `default:dirt 8` |
|
| "pull" | item string | Start the TA4 pusher to pull/push items.<br /> Example: `default:dirt 8` |
|
||||||
| "config" | item string | Configure the TA4 pusher.<br />Example: `wool:blue` |
|
| "config" | item string | Configure the TA4 pusher.<br />Example: `wool:blue` |
|
||||||
|
| "exchange" | inventory slot number | place/remove/exchange an block by means of the TA3 Door Controller II (techage:ta3_doorcontroller2) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user