-- support for MT game translation. local S = default.get_translator --[[ current = pos left bottom posh = pos right bottom posv = pos left top depends where you look at ]]-- local function standarise_corners(pos1,pos2,direction) --assert(pos1.y == pos2.y) TODO: how to solve the problem of selectin not flat region local x1,x2,z1,z2,y y = pos1.y x1 = pos1.x x2 = pos2.x z1 = pos1.z z2 = pos2.z x1,x2 = math.min(x1,x2), math.max(x1,x2) z1,z2 = math.min(z1,z2), math.max(z1,z2) local p1,p2,p3,p4 p1 = { x=x1,y=y,z=z1 } p2 = { x=x2,y=y,z=z1 } p3 = { x=x1,y=y,z=z2 } p4 = { x=x2,y=y,z=z2 } if( direction.x == -1 ) then return p2,p4,p1 elseif( direction.x == 1 ) then return p3,p1,p4 elseif( direction.z == -1 ) then return p4,p3,p2 else return p1,p2,p3 end end local function iter_vectors(direction) local dx = direction.x local dz = direction.z if( direction.z == 1 ) then return {x=1,z=0},{x=0,z=1} elseif( direction.z == -1 ) then return {x=-1,z=0},{x=0,z=-1} elseif( direction.x == -1 ) then return {x=0,z=1},{x=-1,z=0} else return {x=0,z=-1},{x=1,z=0} end end function check_selection(pos1,pos2) if( pos1 == nil ) then return false end if( pos2 == nil ) then return false end return true end local function add_direct_to_pos(pos,direc) return { x = pos.x + direc.x , y = pos.y, z = pos.z + direc.z } end local function store_nodes(p1,p2,direction) local pos1,pos2 = p1,p2 local tab = {} if( check_selection(pos1,pos2) == false ) then return nil end local corner, maxh, maxv = standarise_corners(pos1,pos2,direction) local inch,incv = iter_vectors(direction) local i,k = 1,1 local cur,curv,curh = corner,corner,corner while true do i = 1 tab[k] = {} while true do tab[k][i] = minetest.get_node(cur) if( eq_pos(curh,maxh) ) then break end curh = add_direct_to_pos(curh,inch) cur = add_direct_to_pos(cur, inch) i = i + 1 end if( eq_pos(curv,maxv) ) then break end curv = add_direct_to_pos(curv,incv) cur = curv curh = corner k = k +1 end --print("["..i.."]["..k.."]="..name) --print("table = ".. dump(tab)) return tab end local function radians_to_direction_looking_forward(rad) if rad == nil then return {x=1,z=0} end local pi = math.pi if (rad>=0) and (rad<=pi/4) or (rad<=2*pi) and (rad>=(3/2+1/4)*pi) then return {x=0, z =1 } elseif (rad >= 1/4*pi) and (rad <= (1/2+1/4)*pi) then return {x=-1,z=0} elseif (rad >= (1-1/4)*pi ) and (rad <= (3/2-1/4)*pi ) then return {x=0,z=-1} else return {x=1,z=0} end end local function store_nodes_from_selection(rad) local direction = radians_to_direction_looking_forward(rad) return store_nodes(mesecons_automove.pos1, mesecons_automove.pos2,direction) end local function circuit_on_place(itemstack, user, pointed_thing) print("debug:on_plalce_circuit") end local max_text_size = 10000 local max_title_size = 80 local short_title_size = 35 minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "mesecons_autowire:circuit" then return end if( fields.save) then local stack = player:get_wielded_item() local inv = player:get_inventory() local new_stack = nil local meta = stack:get_meta() local data = meta:to_table().fields if data == nil then data = {} end data.title = fields.title or "" -- if no nodes then save nodes local nodes = minetest.deserialize(data.nodes) --if not data.nodes then if nodes == nil then local rad = player:get_look_horizontal() local tab = store_nodes_from_selection(rad) --print("tab="..dump(tab)) if( tab ) then data.nodes = minetest.serialize(tab) data.rad = rad else return end end -- print("debug.af="..dump(data)) if( stack:get_name() == "mesecons_autowire:circuit_full" ) then elseif ( stack:get_name() == "mesecons_autowire:circuit_empty" ) then local count = stack:get_count() if( count <= 0 ) then return end print("debug.count="..count) if count == 1 then --inv:remove_item("main",stack) stack:set_name("mesecons_autowire:circuit_full") else stack:set_count(count - 1) print("debug.count*="..stack:get_count() ) new_stack = ItemStack("mesecons_autowire:circuit_full") end else end if not fields.text then fields.text = "" end if not fields.title then fields.title = "" end data.title = fields.title:sub(1, max_title_size) local short_title = data.title -- Don't bother triming the title if the trailing dots would make it longer if #short_title > short_title_size + 3 then short_title = short_title:sub(1, short_title_size) .. "..." end data.description = S(short_title) data.text = fields.text:sub(1, max_text_size) data.text = data.text:gsub("\r\n", "\n"):gsub("\r", "\n") if new_stack then new_stack:get_meta():from_table({ fields = data}) if inv:room_for_item("main", new_stack) then inv:add_item("main", new_stack) else minetest.add_item(player:get_pos(), new_stack) end else print("debug.new_stack==nil") stack:get_meta():from_table( {fields = data } ) end --debug player:set_wielded_item(stack) end end) local function direction_to_number(direction) if( direction.z == 1 ) then return 1 elseif( direction.x == 1 ) then return 2 elseif(direction.z == -1 )then return 3 else return 4 end end local rotate_exceptions = { "mesecons_extrawires:crossover_off", "mesecons_extrawires:crossover_on", "mesecons_morewires:xjunction_on", "mesecons_morewires:xjunction_off" } local function is_exception(node) for _,v in ipairs(rotate_exceptions) do if( v == node.name ) then return true end end return false end local function node_to_image(node) if node == nil then return "unknown.png" end local name = node.name local param2 = node.param2 or 0 if( name == "air" ) then return "empty.png" end if (name == "mesecons_insulated:insulated_off") or (name == "mesecons_insulated:insulated_on" ) then if( param2 % 2 == 0 ) then return "wireh.png" else return "wirev.png" end end if (name == "mesecons_extrawires:crossover_off") or (name == "mesecons_extrawires:crossover_on") or (name == "mesecons_extrawires:crossover_01") or (name == "mesecons_extrawires:crossover_10" ) then return "corssover.png" end if (name == "mesecons_extrawires:corner_off" ) or (name == "mesecons_extrawires:corner_on" ) then return "corner"..param2 .. ".png" end if (name == "mesecons_extrawires:tjunction_off" ) or (name == "mesecons_extrawires:tjunction_on" ) then return "tjunction"..param2 .. ".png" end if ( name == "mesecons_morewires:xjunction_off" ) or ( name == "mesecons_morewires:xjunction_on" ) then return "xjunction.png" end if( name == "mesecons_regs:flipflop_off" ) or ( name == "mesecons_regs:flipflop_on") then return "ff"..param2..".png" end if( name == "mesecons_regs:latch_off" ) or ( name == "mesecons_regs:latch_on") then return "latch"..param2..".png" end if( name == "mesecons_gates:and_off" ) or ( name =="mesecons_gates:and_on" )then return "and".. param2 .. ".png" end if( name == "mesecons_gates:nand_off" ) or ( name =="mesecons_gates:nand_on" )then return "nand".. param2 .. ".png" end if( name == "mesecons_gates:nor_off" ) or ( name =="mesecons_gates:nor_on" )then return "nor".. param2 .. ".png" end if( name == "mesecons_gates:or_off" ) or ( name =="mesecons_gates:or_on" )then return "or".. param2 .. ".png" end if( name == "mesecons_gates:xor_off" ) or ( name =="mesecons_gates:xor_on" )then return "xor".. param2 .. ".png" end if( name == "mesecons_gates:diode_off" ) or ( name =="mesecons_gates:diode_on" )then return "diode".. param2 .. ".png" end if( name == "mesecons_gates:not_off" ) or ( name =="mesecons_gates:not_on" )then return "not".. param2 .. ".png" end return "unknown.png" end local function generate_spec(starting,nodes) if nodes == nil then return "" end local mv = #nodes local mh = #nodes[1] local str = "" local x,z for x = 1,mh do for z = 1,mv do local img = node_to_image(nodes[z][x]) --str = str .. "image[" .. 0.5*x .. "," .. 0.5*(mv-z+1) .. str = str .. "image[" .. x +starting .. "," .. (mv-z+1) .. ";1,1;"..img.."]" --";0.5,0.5;"..img.."]" end end return str end local function special_case(node,rotate) local new_node = node local applied = false if( node.name == "mesecons_extrawires:crossover_10") and (rotate % 2 == 1 ) then new_node.name = "mesecons_extrawires:crossover_01" new_node.param2 = 0 return new_node elseif (node.name == "mesecons_extrawires:crossover_10") and (rotate % 2 == 0 ) then new_node.name = "mesecons_extrawires:crossover_10" new_node.param2 = 0 return new_node elseif( node.name == "mesecons_extrawires:crossover_01" and (rotate % 2 == 1) ) then new_node.name = "mesecons_extrawires:crossover_10" new_node.param2 = 0 return new_node elseif ( node.name == "mesecons_extrawires:crossover_01" and (rotate % 2 == 0 ) ) then new_node.name = "mesecons_extrawires:crossover_01" new_node.param2 = 0 return new_node end return nil end local function rotate_node(node, saved_direction,direction) if( is_exception(node) ) then return node end local values = { {0,1,2,3}, {3,0,1,2}, {2,3,0,1}, {1,2,3,0} } local rotate = values[direction_to_number(saved_direction)][direction_to_number(direction)] local new_node = special_case(node,rotate) if( new_node ~= nil ) then return new_node end new_node = node new_node.param2 = (node.param2+rotate)%4 return new_node end local function rotate_nodes_for_window(nodes, oryginal) if nodes == nil then return nil end local mv = #nodes local mh = #nodes[1] local dir = {x=0,z=1} local tab = {} for k = 1,mv do tab[k] = {} for i = 1,mh do tab[k][i] = rotate_node(nodes[k][i],oryginal,dir) end end return tab end function is_gate(node) local gates = { "mesecons_gates:and", "mesecons_gates:or", "mesecons_gates:xor", "mesecons_gates:nand", "mesecons_gates:nor", "mesecons_gates:not", "mesecons_gates:diode", "mesecons_gates3:and3", "mesecons_gates3:or3", "mesecons_gates3:nor3", "mesecons_gates3:nand3", "mesecons_regs:flipflop", "mesecons_regs:latch" } local gates_with_states = {} for _,v in ipairs(gates) do table.insert(gates_with_states,v.."_on") table.insert(gates_with_states,v.."_off") end for _,v in ipairs(gates_with_states) do if node.name == v then print("found.gate="..v) return true end end return false end local function count_stats(tab) if tab == nil then return 0 end local block, wire, gate = 0,0,0 local h,v = #tab[1], #tab for i = 1,h do for k = 1,v do if tab[k][i].name ~= "air" then block = block + 1 end if is_wire_node(tab[k][i]) then wire = wire + 1 end if is_gate(tab[k][i]) then gate = gate + 1 end end end return block, wire, gate end local function show_dialog(itemstack,user,pointed_thing) local player_name = user:get_player_name() local formspec local esc = minetest.formspec_escape local meta = itemstack:get_meta() local data = meta:to_table().fields local title, text = data.title or "", data.text or "" local nodes_string = "empty" local nodes = minetest.deserialize(data.nodes) local hight = 0 local width = 0 if( nodes ) then -- show nodes nodes_string = "size = (".. #nodes[1] .. ","..#nodes .. ")" hight = #nodes width = #nodes[1] end if( nodes == nil ) and ( check_selection(mesecons_automove.pos1,mesecons_automove.pos2) == false ) then return end if nodes == nil then local rad = user:get_look_horizontal() local tab = store_nodes_from_selection(rad) if tab == nil then return end nodes = tab data.rad = rad hight = #nodes width = #nodes[1] end local size_w = 45 size_w = width + 10 if( size_w < 20 ) then size_w = 20 end if( size_w > 45 ) then size_w = 45 end local size_scroll = size_w - 10 local starting_point = math.max(0, (size_scroll/2) - (width/2)) local block,wire,gate = count_stats(nodes) local stats = "size : " .. width .. "x"..hight .. "(=".. width * hight .. ")\n" .. "wires : " .. wire .. "\n" .. "gates : " .. gate .. "\n" .. "other : ".. block - wire - gate .. "\n" .. "blocks: " .. block local circuitspec = generate_spec(starting_point, rotate_nodes_for_window( nodes, radians_to_direction_looking_forward( tonumber(data.rad)))) formspec = "formspec_version[3]".. --"size[45,25]" .. "size[".. size_w .. ",25]".. "field[0.5,1;8,1;title;"..S("Name")..";"..S(title).."]".. "textarea[0.5,3;8,15;text;" .. esc(S("Description:")) .. ";" .. esc(S(text)) .. "]" .. "button_exit[2.5,18;3,1;save;" .. esc(S("Save")) .. "]" .. "textarea[0.5,19;8,5;;;" .. esc(S(stats)) .. "]" .. --"label[10,0.5;"..nodes_string.."]".. --"container[8,0.5]".. "scrollbaroptions[min=0;max=".. hight -15 .. ";smallstep=2;largestep=10;arrows=show]".. --"scrollbar[44,0.5;0.6,24;vertical;scr0;0]".. "scrollbar[".. size_w - 1 .. ",0.5;0.6,24;vertical;scr0;0]".. --"scroll_container[8,0.5;36,23;scr0;vertical;1]".. "scroll_container[8,0.5;".. size_w -10 .. ",23;scr0;vertical;1]".. circuitspec .. "scroll_container_end[]".. --"container_end[]".. "" minetest.show_formspec(player_name, "mesecons_autowire:circuit", formspec) return itemstack end local function make_selection(nodes,pos,rad) if nodes == nil then return end --if check_selection(mesecons_automove.pos1,mesecons_automove.pos2) == false then return end local vsize = #nodes local hsize = #nodes[1] -- print("dump"..dump(nodes) .. "====" .. dump(pos) .. "===" .. vsize .. "=" .. hsize ) local direction = radians_to_direction_looking_forward(rad) mesecons_automove.pos1 = pos local dx,dz = 0,0 --print("dumpsirection="..dump(direction)) hsize = hsize -1 vsize = vsize -1 if direction.z == 1 then dx,dz = hsize,vsize elseif direction.z == -1 then dx,dz = -hsize,-vsize elseif direction.x == 1 then dx,dz = vsize,-hsize else --dirextion.x == -1 dx,dz = -vsize,hsize end mesecons_automove.pos2 = { x=pos.x + dx, y=pos.y, z = pos.z+dz } mesecons_automove.rad = rad --print("debug.all="..dump(mesecons_automove)) update_selection() end local function paste_nodes(nodes,saved_direction,direction) local pos1,pos2 = mesecons_automove.pos1,mesecons_automove.pos2 if( check_selection(pos1,pos2) == false ) then return nil end local corner, maxh, maxv = standarise_corners(pos1,pos2,direction) local inch,incv = iter_vectors(direction) local tab = nodes if tab == nil then return end local maxi = #nodes[1] local maxk = #nodes local i,k = 1,1 local cur,curv,curh = corner,corner,corner while true do i = 1 while true do --tab[k][i] = minetest.get_node(cur) if( i<=maxi) and (k<=maxk) then local n = rotate_node(tab[k][i],saved_direction,direction) minetest.set_node(cur,n) end if( eq_pos(curh,maxh) ) then break end curh = add_direct_to_pos(curh,inch) cur = add_direct_to_pos(cur, inch) i = i + 1 end if( eq_pos(curv,maxv) ) then break end curv = add_direct_to_pos(curv,incv) cur = curv curh = corner k = k +1 end end local function on_use_circuit(itemstack, user, pointed_thing) if( pointed_thing.type == "node" ) then -- select region local nodes = minetest.deserialize(itemstack:get_meta():to_table().fields.nodes) local sel_pos if( is_circuit_element(pointed_thing.under) ) then sel_pos = pointed_thing.under else sel_pos = pointed_thing.above end make_selection(nodes,sel_pos,user:get_look_horizontal()) else -- show dialog show_dialog(itemstack,user,pointed_thing); end end local function on_place_circuit(itemstack, user, pointed_thing) if pointed_thing.type == "node" then -- paste end if( mesecons_automove.rad == nil ) then return end local data = itemstack:get_meta():to_table() local nodes = minetest.deserialize(data.fields.nodes) local rad = tonumber( data.fields.rad ) paste_nodes(nodes,radians_to_direction_looking_forward(rad), radians_to_direction_looking_forward(mesecons_automove.rad)) end minetest.register_craftitem("mesecons_autowire:circuit_empty", { description = S("Circuit empty"), inventory_image = "circuit_empty.png", on_use = on_use_circuit }) minetest.register_craftitem("mesecons_autowire:circuit_full", { description = S("Circuit saved"), inventory_image = "circuit_full.png", groups = {not_in_creative_inventory = 1}, stack_max = 1, on_use = on_use_circuit, on_place = on_place_circuit, on_secondary_use = on_place_circuit })