-- There's a lot of duplicated code in this file, but removing it means adding more duplicated code... so I'm just going to leave it. local function extract_dimension(pos) if exchangeclone.mtg then if minetest.get_modpath("nether") then if pos.y >= nether.DEPTH_FLOOR and pos.y <= nether.DEPTH_CEILING then return "Nether", pos else return "Overworld", pos end end return nil, pos end -- overworld if (pos.y >= mcl_vars.mg_overworld_min) and (pos.y <= mcl_vars.mg_overworld_max) then return "Overworld", pos end -- nether if (pos.y >= mcl_vars.mg_nether_min) and (pos.y <= mcl_vars.mg_nether_max) then local report_y = pos.y - mcl_vars.mg_nether_min return "Nether", {x = pos.x, y = report_y, z = pos.z} end -- end if (pos.y >= mcl_vars.mg_end_min) and (pos.y <= mcl_vars.mg_end_max) then local report_y = pos.y - mcl_vars.mg_end_min return "End", {x = pos.x, y = report_y, z = pos.z} end -- outside of scoped bounds. return "Void", pos end local function add_dimension(dimension, pos) dimension = dimension:lower() if exchangeclone.mtg then return pos end if dimension == "nether" then local report_y = pos.y + mcl_vars.mg_nether_min return {x = pos.x, y = report_y, z = pos.z} end if dimension == "end" then local report_y = pos.y + mcl_vars.mg_end_min return {x = pos.x, y = report_y, z = pos.z} end return pos end local base_formspec = { "formspec_version[3]", "size[13,10]", "button[11.5,0.5;1,0.7;add;Add]", "button[8.5,1.5;4,1;teleport;Teleport]", "button[8.5,2.75;4,1;rename;Rename]", "button[8.5,4;4,1;up;Move Up]", "button[8.5,5.25;4,1;down;Move Down]", "button[8.5,6.5;4,1;delete;Delete]", "field_close_on_enter[name;false]", "field_enter_after_edit[name;false]" } local context = {} -- player: The player to be shown the formspec -- index: The index of the location the player is currently selecting -- use_stack_data: Whether to use locations stored with the book or the player. local function show_formspec(player, index, text, use_stack_data, confirmation) local stack = player:get_wielded_item() if minetest.get_item_group(stack:get_name(), "exchangeclone_alchemical_book") < 1 then return end context[player:get_player_name()] = context[player:get_player_name()] or {} context[player:get_player_name()].using_stack_data = use_stack_data local book_data = stack:get_definition().alchemical_book_data local data = minetest.deserialize((use_stack_data and stack or player):get_meta():get_string("exchangeclone_alchemical_book")) local formspec = table.copy(base_formspec) formspec[#formspec+1] = "field[8.5,0.5;3,0.7;name;;"..minetest.formspec_escape(text or "").."]" local player_pos = player:get_pos() if type(data) ~= "table" then data = {} end if not data.locations then data.locations = {} end if #data.locations > 0 then formspec[#formspec+1] = "textlist[0.5,0.5;7,7;location_list;" for _, location in ipairs(data.locations) do formspec[#formspec+1] = minetest.formspec_escape(location.name).."," end if index then formspec[#formspec+1] = ";"..index end formspec[#formspec+1] = "]" end if index then local selected = data.locations[index] if selected then local dimension, adjusted_pos = extract_dimension(selected.pos) local player_dimension, player_adjusted_pos = extract_dimension(player_pos) local dimension_string = dimension and (" ("..dimension..")") or "" local distance = vector.distance(adjusted_pos, player_adjusted_pos) local cost = math.floor(book_data.emc_per_node*distance*20)/20 local info = minetest.formspec_escape(string.format( "%s\nPosition: %.1f, %.1f, %.1f%s\nDistance: %.1f\nCost: %s EMC", selected.name, adjusted_pos.x, adjusted_pos.y, adjusted_pos.z, dimension_string, distance, exchangeclone.format_number(cost) )) if player_dimension ~= dimension then if book_data.dimension_lock then info = info.."\nCannot teleport between dimensions." end end formspec[#formspec+1] = "textarea[0.5,8;7,1.75;;;"..info.."]" end end if confirmation then formspec[#formspec+1] = "label[8.5,8;Delete?]button[10,8;1.25,1;cancel;Cancel]button[11.25,8;1.25,1;confirm;Delete]" end minetest.show_formspec(player:get_player_name(), "exchangeclone_alchemical_book", table.concat(formspec)) end minetest.register_on_joinplayer(function(player) context[player:get_player_name()] = nil end) minetest.register_on_leaveplayer(function(player) context[player:get_player_name()] = nil end) minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "exchangeclone_alchemical_book" then return end if fields.quit then context[player:get_player_name()] = nil return end local use_stack_data = context[player:get_player_name()].using_stack_data local stack = player:get_wielded_item() if minetest.get_item_group(stack:get_name(), "exchangeclone_alchemical_book") < 1 then return end local meta = (use_stack_data and stack or player):get_meta() local data = minetest.deserialize(meta:get_string("exchangeclone_alchemical_book")) if not data then data = {} end if not data.locations then data.locations = {} end local index = context[player:get_player_name()].index local book_data = stack:get_definition().alchemical_book_data if type(data) ~= "table" then data = {} end if not data.locations then data.locations = {} end if fields.key_enter_field == "name" or fields.add or fields.rename then local name = fields.name:trim() if name == "" then return end for _, location in pairs(data.locations) do if location.name == name then minetest.chat_send_player(player:get_player_name(), "There is already a location called '"..location.name.."'") return end end if fields.rename then data.locations[index].name = name else data.locations[#data.locations+1] = {name = name, pos = player:get_pos()} end meta:set_string("exchangeclone_alchemical_book", minetest.serialize(data)) if use_stack_data then player:set_wielded_item(stack) end show_formspec(player, index, "", use_stack_data) elseif fields.teleport then if not data.locations[index] then return end local pos = data.locations[index].pos local dimension, adjusted_pos = extract_dimension(pos) local player_dimension, adjusted_player_pos = extract_dimension(player:get_pos()) if dimension ~= player_dimension then if book_data.dimension_lock then minetest.chat_send_player(player:get_player_name(), "This Alchemical Book is not powerful enough to teleport between dimensions.") show_formspec(player, index, fields.name, use_stack_data) return end end local distance = vector.distance(adjusted_player_pos, adjusted_pos) local emc_per_node = stack:get_definition().alchemical_book_data.emc_per_node local cost = distance*emc_per_node local player_emc = player:_get_emc() if player_emc < cost then minetest.chat_send_player(player:get_player_name(), "Not enough EMC to teleport.") else player:set_pos(pos) player:_add_emc(-cost) end show_formspec(player, index, fields.name, use_stack_data) elseif fields.location_list then local exploded = minetest.explode_textlist_event(fields.location_list) index = math.min(exploded.index, #data.locations) if not context[player:get_player_name()] then context[player:get_player_name()] = {} end context[player:get_player_name()].index = index if exploded.type == "DCL" then local pos = data.locations[index].pos local dimension, adjusted_pos = extract_dimension(pos) local player_dimension, adjusted_player_pos = extract_dimension(player:get_pos()) if dimension ~= player_dimension then if book_data.dimension_lock then minetest.chat_send_player(player:get_player_name(), "This Alchemical Book is not powerful enough to teleport between dimensions.") show_formspec(player, index, fields.name, use_stack_data) return end end local distance = vector.distance(adjusted_player_pos, adjusted_pos) local emc_per_node = stack:get_definition().alchemical_book_data.emc_per_node local cost = distance*emc_per_node local player_emc = player:_get_emc() if player_emc < cost then minetest.chat_send_player(player:get_player_name(), "Not enough EMC to teleport.") else player:set_pos(pos) player:_add_emc(-cost) end end show_formspec(player, index, fields.name, use_stack_data) elseif fields.up then if not data.locations[index] then return end if index > 1 then data.locations[index], data.locations[index-1] = data.locations[index-1], data.locations[index] meta:set_string("exchangeclone_alchemical_book", minetest.serialize(data)) if use_stack_data then player:set_wielded_item(stack) end index = index - 1 if not context[player:get_player_name()] then context[player:get_player_name()] = {} end context[player:get_player_name()].index = index show_formspec(player, index, fields.name, use_stack_data) end elseif fields.down then if not data.locations[index] then return end if index < #data.locations then data.locations[index], data.locations[index+1] = data.locations[index+1], data.locations[index] meta:set_string("exchangeclone_alchemical_book", minetest.serialize(data)) if use_stack_data then player:set_wielded_item(stack) end index = index + 1 if not context[player:get_player_name()] then context[player:get_player_name()] = {} end context[player:get_player_name()].index = index show_formspec(player, index, fields.name, use_stack_data) end elseif fields.delete then if not data.locations[index] then return end show_formspec(player, index, fields.name, use_stack_data, true) elseif fields.cancel then if not data.locations[index] then return end show_formspec(player, index, fields.name, use_stack_data) elseif fields.confirm then if not data.locations[index] then return end for i = index,#data.locations - 1 do data.locations[i] = data.locations[i+1] end data.locations[#data.locations] = nil index = math.min(index, #data.locations) if not context[player:get_player_name()] then context[player:get_player_name()] = {} end context[player:get_player_name()].index = index meta:set_string("exchangeclone_alchemical_book", minetest.serialize(data)) if use_stack_data then player:set_wielded_item(stack) end show_formspec(player, index, fields.name, use_stack_data) end end) local function alchemical_book_function(itemstack, player, pointed_thing) local click_test = exchangeclone.check_on_rightclick(itemstack, player, pointed_thing) if click_test ~= false then return click_test end local use_stack_data = itemstack:get_meta():get_int("exchangeclone_use_stack_data") if use_stack_data == 0 then use_stack_data = nil end if player:get_player_control().sneak then if use_stack_data then minetest.chat_send_player(player:get_player_name(), "Using player data") itemstack:get_meta():set_int("exchangeclone_use_stack_data", 0) else minetest.chat_send_player(player:get_player_name(), "Using book data") itemstack:get_meta():set_int("exchangeclone_use_stack_data", 1) end return itemstack else show_formspec(player, nil, "", use_stack_data) end end minetest.register_tool("exchangeclone:basic_alchemical_book", { description = "Basic Alchemical Book\n1000 EMC/node\nCannot travel between dimensions", inventory_image = "exchangeclone_basic_alchemical_book.png", groups = {exchangeclone_alchemical_book = 1, disable_repair = 1}, alchemical_book_data = {emc_per_node = 1000, dimension_lock = true}, on_secondary_use = alchemical_book_function, on_place = alchemical_book_function }) minetest.register_tool("exchangeclone:advanced_alchemical_book", { description = "Advanced Alchemical Book\n500 EMC/node", inventory_image = "exchangeclone_advanced_alchemical_book.png", groups = {exchangeclone_alchemical_book = 1, disable_repair = 1}, alchemical_book_data = {emc_per_node = 500}, on_secondary_use = alchemical_book_function, on_place = alchemical_book_function }) minetest.register_tool("exchangeclone:master_alchemical_book", { description = "Master Alchemical Book\n100 EMC/node.", inventory_image = "exchangeclone_master_alchemical_book.png", groups = {exchangeclone_alchemical_book = 1, disable_repair = 1}, alchemical_book_data = {emc_per_node = 100}, on_secondary_use = alchemical_book_function, on_place = alchemical_book_function }) minetest.register_tool("exchangeclone:arcane_alchemical_book", { description = "Arcane Alchemical Book\n0 EMC/node", inventory_image = "exchangeclone_arcane_alchemical_book.png", groups = {exchangeclone_alchemical_book = 1, disable_repair = 1}, alchemical_book_data = {emc_per_node = 0}, on_secondary_use = alchemical_book_function, on_place = alchemical_book_function }) local craftitem = exchangeclone.mcl and "mcl_throwing:ender_pearl" or "default:mese_crystal" minetest.register_craft({ output = "exchangeclone:basic_alchemical_book", recipe = { {"exchangeclone:low_covalence_dust","exchangeclone:red_matter", "exchangeclone:low_covalence_dust"}, {craftitem, exchangeclone.itemstrings.book, "exchangeclone:philosophers_stone"}, {"exchangeclone:low_covalence_dust","exchangeclone:red_matter", "exchangeclone:low_covalence_dust"}, } }) minetest.register_craft({ output = "exchangeclone:advanced_alchemical_book", recipe = { {"exchangeclone:medium_covalence_dust","exchangeclone:pink_matter", "exchangeclone:medium_covalence_dust"}, {craftitem, "exchangeclone:basic_alchemical_book", "exchangeclone:pink_matter"}, {"exchangeclone:medium_covalence_dust","exchangeclone:pink_matter", "exchangeclone:medium_covalence_dust"}, } }) minetest.register_craft({ output = "exchangeclone:master_alchemical_book", recipe = { {"exchangeclone:high_covalence_dust","exchangeclone:violet_matter", "exchangeclone:high_covalence_dust"}, {"exchangeclone:violet_matter", "exchangeclone:advanced_alchemical_book", "exchangeclone:violet_matter"}, {"exchangeclone:high_covalence_dust","exchangeclone:violet_matter", "exchangeclone:high_covalence_dust"}, } }) minetest.register_craft({ output = "exchangeclone:arcane_alchemical_book", recipe = { {"exchangeclone:void_ring","exchangeclone:block_cyan_matter", "exchangeclone:void_ring"}, {"exchangeclone:void_ring", "exchangeclone:master_alchemical_book", "exchangeclone:void_ring"}, {"exchangeclone:void_ring","exchangeclone:block_cyan_matter", "exchangeclone:void_ring"}, } })