celevator.callbutton = {} local function makebuttontex(dir,upon,downon,inventory) local tex = "[combine:64x64:0,0=celevator_cabinet_sides.png:32,0=celevator_cabinet_sides.png:0,32=celevator_cabinet_sides.png:32,32=celevator_cabinet_sides.png:22,24=celevator_callbutton_panel.png" if inventory then tex = "[combine:32x32:5,0=celevator_callbutton_panel.png" end if dir == "up" then if inventory then tex = tex..":7,11=celevator_callbutton_up.png" else tex = tex..":24,35=celevator_callbutton_up.png" end if upon then tex = tex..":33,36=celevator_callbutton_light.png" end elseif dir == "down" then if inventory then tex = tex..":7,11=celevator_callbutton_down.png" else tex = tex..":24,35=celevator_callbutton_down.png" end if downon then tex = tex..":33,36=celevator_callbutton_light.png" end elseif dir == "both" then if inventory then tex = tex..":7,4=celevator_callbutton_up.png:7,19=celevator_callbutton_down.png" else tex = tex..":24,28=celevator_callbutton_up.png:24,43=celevator_callbutton_down.png" end if upon then tex = tex..":33,29=celevator_callbutton_light.png" end if downon then tex = tex..":33,44=celevator_callbutton_light.png" end end return(tex) end local validstates = { {"up",false,false,"Up"}, {"up",true,false,"Up"}, {"down",false,false,"Down"}, {"down",false,true,"Down"}, {"both",false,false,"Up and Down"}, {"both",true,false,"Up and Down"}, {"both",false,true,"Up and Down"}, {"both",true,true,"Up and Down"}, } function celevator.callbutton.setlight(pos,dir,newstate) local node = celevator.get_node(pos) if minetest.get_item_group(node.name,"_celevator_callbutton") ~= 1 then return end if dir == "up" then if minetest.get_item_group(node.name,"_celevator_callbutton_has_up") ~= 1 then return end local lit = minetest.get_item_group(node.name,"_celevator_callbutton_up_lit") == 1 if lit == newstate then return end local newname = "celevator:callbutton_" if minetest.get_item_group(node.name,"_celevator_callbutton_has_down") == 1 then newname = newname.."both" else newname = newname.."up" end if newstate then newname = newname.."_upon" end if minetest.get_item_group(node.name,"_celevator_callbutton_down_lit") == 1 then newname = newname.."_downon" end node.name = newname minetest.swap_node(pos,node) elseif dir == "down" then if minetest.get_item_group(node.name,"_celevator_callbutton_has_down") ~= 1 then return end local lit = minetest.get_item_group(node.name,"_celevator_callbutton_down_lit") == 1 if lit == newstate then return end local newname = "celevator:callbutton_" if minetest.get_item_group(node.name,"_celevator_callbutton_has_up") == 1 then newname = newname.."both" else newname = newname.."down" end if minetest.get_item_group(node.name,"_celevator_callbutton_up_lit") == 1 then newname = newname.."_upon" end if newstate then newname = newname.."_downon" end node.name = newname minetest.swap_node(pos,node) end end local function disambiguatedir(pos,player) if player and not player.is_fake_player then local eyepos = vector.add(player:get_pos(),vector.add(player:get_eye_offset(),vector.new(0,1.5,0))) local lookdir = player:get_look_dir() local distance = vector.distance(eyepos,pos) local endpos = vector.add(eyepos,vector.multiply(lookdir,distance+1)) local ray = minetest.raycast(eyepos,endpos,true,false) local pointed,button,hitpos repeat pointed = ray:next() if pointed and pointed.type == "node" then local node = minetest.get_node(pointed.under) if node.name and (minetest.get_item_group(node.name,"_celevator_callbutton") == 1) then button = pointed.under hitpos = vector.subtract(pointed.intersection_point,button) end end until button or not pointed if not hitpos then return end hitpos.y = -1*hitpos.y hitpos.y = math.floor((hitpos.y+0.5)*64+0.5)+1 return hitpos.y >= 40 and "down" or "up" end end for _,state in ipairs(validstates) do local boringside = "[combine:64x64:0,0=celevator_cabinet_sides.png:32,0=celevator_cabinet_sides.png:0,32=celevator_cabinet_sides.png:32,32=celevator_cabinet_sides.png" local nname = "celevator:callbutton_"..state[1] local dropname = nname local light = 0 if state[2] then nname = nname.."_upon" light = light + 5 end if state[3] then nname = nname.."_downon" light = light + 5 end local idle = not (state[2] or state[3]) local description = string.format("Elevator %s Call Button%s%s",state[4],(state[1] == "both" and "s" or ""),(idle and "" or " (on state, you hacker you!)")) minetest.register_node(nname,{ description = description, groups = { dig_immediate = 2, not_in_creative_inventory = (idle and 0 or 1), _celevator_callbutton = 1, _celevator_callbutton_has_up = (state[1] == "down" and 0 or 1), _celevator_callbutton_has_down = (state[1] == "up" and 0 or 1), _celevator_callbutton_up_lit = (state[2] and 1 or 0), _celevator_callbutton_down_lit = (state[3] and 1 or 0), }, inventory_image = makebuttontex(state[1],state[2],state[3],true), drop = dropname, tiles = { boringside, boringside, boringside, boringside, boringside, makebuttontex(state[1],state[2],state[3]) }, paramtype = "light", paramtype2 = "facedir", light_source = light, drawtype = "nodebox", node_box = { type = "fixed", fixed = { {-0.16,-0.37,0.475,0.17,0.13,0.5}, }, }, after_place_node = function(pos) local meta = minetest.get_meta(pos) meta:set_string("formspec","formspec_version[7]size[8,5]field[0.5,0.5;7,1;carid;Car ID;]field[0.5,2;7,1;landing;Landing Number;]button[3,3.5;2,1;save;Save]") end, on_receive_fields = function(pos,_,fields) if tonumber(fields.carid) and tonumber(fields.landing) then local carid = tonumber(fields.carid) local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid))) if not carinfo then return end table.insert(carinfo.callbuttons,{pos=pos,landing=tonumber(fields.landing)}) celevator.storage:set_string(string.format("car%d",carid),minetest.serialize(carinfo)) local meta = minetest.get_meta(pos) meta:set_int("carid",carid) meta:set_int("landing",tonumber(fields.landing)) meta:set_string("formspec","") end end, on_destruct = function(pos) local meta = minetest.get_meta(pos) local carid = meta:get_int("carid") if carid == 0 then return end local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid))) if not carinfo then return end for i,button in pairs(carinfo.callbuttons) do if vector.equals(pos,button.pos) then table.remove(carinfo.callbuttons,i) celevator.storage:set_string(string.format("car%d",carid),minetest.serialize(carinfo)) end end end, on_rightclick = function(pos,_,clicker) local meta = minetest.get_meta(pos) local carid = meta:get_int("carid") if carid == 0 then return end local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid))) if not carinfo then return end local controllerpos = carinfo.controllerpos or carinfo.dispatcherpos local isdispatcher = carinfo.dispatcherpos if not controllerpos then return end local controllermeta = minetest.get_meta(controllerpos) if controllermeta:get_int("carid") ~= carid then return end local landing = meta:get_int("landing") if state[1] == "up" then if isdispatcher then celevator.dispatcher.handlecallbutton(controllerpos,landing,"up") else celevator.controller.handlecallbutton(controllerpos,landing,"up") end elseif state[1] == "down" then if isdispatcher then celevator.dispatcher.handlecallbutton(controllerpos,landing,"down") else celevator.controller.handlecallbutton(controllerpos,landing,"down") end elseif state[1] == "both" then local dir = disambiguatedir(pos,clicker) if dir == "up" then if isdispatcher then celevator.dispatcher.handlecallbutton(controllerpos,landing,"up") else celevator.controller.handlecallbutton(controllerpos,landing,"up") end elseif dir == "down" then if isdispatcher then celevator.dispatcher.handlecallbutton(controllerpos,landing,"down") else celevator.controller.handlecallbutton(controllerpos,landing,"down") end end end end, }) end