local S = minetest.get_translator("lzr_menu") local FS = function(...) return minetest.formspec_escape(S(...)) end local SPEAKER_POS = vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_SPEAKER_OFFSET) local build_ship = function(pos) minetest.place_schematic(pos, minetest.get_modpath("lzr_menu").."/schematics/lzr_menu_ship.mts", "0", {}, true, "") minetest.set_node(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_STARTBOOK_OFFSET), {name="lzr_menu:startbook", param2=0}) minetest.set_node(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_CUSTOMBOOK_OFFSET), {name="lzr_menu:startbook_custom", param2=0}) minetest.set_node(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_EDITOR_OFFSET), {name="lzr_menu:editorbook", param2=3}) minetest.set_node(SPEAKER_POS, {name="lzr_menu:speaker", param2=2}) minetest.set_node(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_TELEVISION_OFFSET), {name="lzr_menu:television", param2=2}) end local emerge_callback = function(blockpos, action, calls_remaining, param) minetest.log("verbose", "[lzr_menu] emerge_callback() ...") if action == minetest.EMERGE_ERRORED then minetest.log("error", "[lzr_menu] Emerging error.") elseif action == minetest.EMERGE_CANCELLED then minetest.log("error", "[lzr_menu] Emerging cancelled.") elseif calls_remaining == 0 and (action == minetest.EMERGE_GENERATED or action == minetest.EMERGE_FROM_DISK or action == minetest.EMERGE_FROM_MEMORY) then build_ship(param.pos) minetest.log("action", "[lzr_menu] Ship emerged and built.") -- Now that the ship has *actually* been built, -- setting the player pos should guarantee the player -- stands on solid ground local player = minetest.get_player_by_name("singleplayer") player:set_pos(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_SPAWN_OFFSET)) end end local SHIP_SIZE = { x = 30, y = 30, z = 30 } local SPEAKER_NOTE_INTERVAL = 1.0 local emerge_ship = function(pos) minetest.emerge_area(pos, vector.add(pos, SHIP_SIZE), emerge_callback, {pos=pos, size=SHIP_SIZE}) end minetest.register_on_joinplayer(function(player) emerge_ship(lzr_globals.MENU_SHIP_POS) -- NOTE: This set_pos happens BEFORE the ship was actually built, so the -- player may fall for a moment. This set_pos is thus not reliable -- and is only made in prepatation for the future ship spawn. player:set_pos(vector.add(lzr_globals.MENU_SHIP_POS, lzr_globals.MENU_SHIP_PLAYER_SPAWN_OFFSET)) player:set_look_horizontal(0) player:set_look_vertical(0) local inv = player:get_inventory() for i=1,inv:get_size("main") do inv:set_stack("main", i, "") end end) local on_punch_start_core = function(self, node, puncher) lzr_level_select.open_dialog(puncher, "core") end local on_rightclick_start_core = function(self, node, clicker) lzr_level_select.open_dialog(clicker, "core") end local on_punch_start_custom = function(self, node, puncher) lzr_level_select.open_dialog(puncher, "custom") end local on_rightclick_start_custom = function(self, node, clicker) lzr_level_select.open_dialog(clicker, "custom") end minetest.register_node("lzr_menu:startbook", { description = S("Start Game Book"), tiles = { "lzr_menu_book_top.png", "lzr_menu_book_bottom.png", "lzr_menu_book_side.png", "lzr_menu_book_side.png", "lzr_menu_book_end.png", "lzr_menu_book_end.png" }, paramtype = "light", paramtype2 = "facedir", drawtype = "nodebox", node_box = { type = "fixed", fixed = { { -0.4375, -0.5, -0.375, 0.4375, -0.4375, 0.1875 }, { -0.375, -0.4375, -0.375, 0.375, -0.375, 0.1875 } } }, sunlight_propagates = true, on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("infotext", S("Start playing")) end, on_punch = on_punch_start_core, on_rightclick = on_rightclick_start_core, groups = { snappy = 3, not_in_creative_inventory = 1, }, }) minetest.register_node("lzr_menu:startbook_custom", { description = S("Custom Level Game Book"), tiles = { "lzr_menu_book_top.png", "lzr_menu_book_bottom.png", "lzr_menu_book_side.png", "lzr_menu_book_side.png", "lzr_menu_book_end.png", "lzr_menu_book_end.png" }, paramtype = "light", paramtype2 = "facedir", drawtype = "nodebox", node_box = { type = "fixed", fixed = { { -0.4375, -0.5, -0.375, 0.4375, -0.4375, 0.1875 }, { -0.375, -0.4375, -0.375, 0.375, -0.375, 0.1875 } } }, sunlight_propagates = true, on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("infotext", S("Play custom levels")) end, on_punch = on_punch_start_custom, on_rightclick = on_rightclick_start_custom, groups = { snappy = 3, not_in_creative_inventory = 1, }, }) local on_punch_editor = function(self, node, puncher) lzr_editor.enter_editor(puncher) end local on_rightclick_editor = function(self, node, clicker) lzr_editor.enter_editor(clicker) end minetest.register_node("lzr_menu:editorbook", { description = S("Level Editor Book"), tiles = { "lzr_menu_book_editor_top.png", "lzr_menu_book_editor_bottom.png", "lzr_menu_book_editor_side.png", "lzr_menu_book_editor_side.png", "lzr_menu_book_editor_end.png", "lzr_menu_book_editor_end.png" }, paramtype = "light", paramtype2 = "facedir", drawtype = "nodebox", node_box = { type = "fixed", fixed = { { -0.4375, -0.5, -0.375, 0.4375, -0.4375, 0.1875 }, { -0.375, -0.4375, -0.375, 0.375, -0.375, 0.1875 } } }, sunlight_propagates = true, on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("infotext", S("Enter the level editor")) end, on_punch = on_punch_editor, on_rightclick = on_rightclick_editor, groups = { snappy = 3, not_in_creative_inventory = 1, }, }) local use_speaker = function(speaker_pos, user) local state = lzr_ambience.toggle_ambience_by_player(user) if state then minetest.sound_play({name="lzr_menu_speaker_turn_on", gain=0.4}, {pos=speaker_pos}, true) else minetest.sound_play({name="lzr_menu_speaker_turn_off", gain=0.4}, {pos=speaker_pos}, true) end end local update_speaker_infotext = function(pos) if minetest.get_node(pos).name ~= "lzr_menu:speaker" then return end local meta = minetest.get_meta(pos) local infotext = S("Toggle ambience sounds") .. "\n\n" local active = lzr_ambience.is_active() local ambience_state = meta:get_int("ambience_state") -- Update infotext only if neccessary if active and ambience_state ~= 1 then infotext = infotext .. S("(Ambience is enabled)") meta:set_int("ambience_state", 1) meta:set_string("infotext", infotext) elseif not active and ambience_state ~= 2 then infotext = infotext .. S("(Ambience is disabled)") meta:set_int("ambience_state", 2) meta:set_string("infotext", infotext) end end local on_punch_speaker = function(pos, node, puncher) use_speaker(pos, puncher) update_speaker_infotext(pos) end local on_rightclick_speaker = function(pos, node, clicker) use_speaker(pos, clicker) update_speaker_infotext(pos) end minetest.register_node("lzr_menu:speaker", { description = S("Speaker"), tiles = { "lzr_menu_speaker_top.png", "lzr_menu_speaker_side.png", "lzr_menu_speaker_side.png", "lzr_menu_speaker_side.png", "lzr_menu_speaker_back.png", "lzr_menu_speaker_front.png", }, paramtype2 = "4dir", groups = { breakable = 1, rotatable = 1, not_in_creative_inventory = 1}, sounds = lzr_sounds.node_sound_wood_defaults(), is_ground_content = false, on_punch = on_punch_speaker, on_rightclick = on_rightclick_speaker, on_construct = function(pos) update_speaker_infotext(pos) local timer = minetest.get_node_timer(pos) timer:start(SPEAKER_NOTE_INTERVAL) end, on_timer = function(pos) if lzr_ambience.is_active() then local node = minetest.get_node(pos) local dir = minetest.fourdir_to_dir(node.param2) local notes = { "lzr_menu_speaker_note_quarter.png", "lzr_menu_speaker_note_eighth.png", "lzr_menu_speaker_note_eighth_2.png", } local note = notes[math.random(1, #notes)] local hue = math.random(-12, 12) * 15 note = note .. "^[hsl:"..hue..":0:0" local notepos = vector.add(pos, vector.multiply(dir, -0.65)) notepos = vector.offset(notepos, 0, -2/16, 0) minetest.add_particlespawner({ amount = 1, time = SPEAKER_NOTE_INTERVAL / 2, pos = notepos, texture = { name = note, alpha_tween = { start = 0.6, 1, 0 }, }, size = 3, exptime = 1, vel = { min = vector.new(0, 0.2, 0), max = vector.new(0, 0.6, 0), }, }) end update_speaker_infotext(pos) local timer = minetest.get_node_timer(pos) timer:start(SPEAKER_NOTE_INTERVAL) end, }) -- Instantly update the ship speaker infotext when ambience status -- was changed (could be by chat command) lzr_ambience.register_on_ambience_change(function(state) update_speaker_infotext(SPEAKER_POS) end) local graphics_settings_initial = { opaque_lasers = minetest.settings:get_bool("lzr_opaque_lasers", false), patterned_lasers = minetest.settings:get_bool("lzr_patterned_lasers", false), } local graphics_settings_state = table.copy(graphics_settings_initial) local open_graphics_settings = function(player) local form = "formspec_version[4]size[9,5.1]".. "checkbox[2.3,1;opaque_lasers;"..FS("Opaque lasers")..";"..tostring(graphics_settings_state.opaque_lasers).."]" form = form .. "box[1,0.5;1,1;#0000003f]" if graphics_settings_state.opaque_lasers then form = form .. "image[1.1,0.6;0.8,0.8;lzr_menu_settings_opaque_lasers_on.png]" else form = form .. "image[1.1,0.6;0.8,0.8;lzr_menu_settings_opaque_lasers_off.png]" end form = form .. "tooltip[opaque_lasers;"..FS("If enabled, lasers aren’t translucent. Can improve performance.").."]" if graphics_settings_state.opaque_lasers ~= graphics_settings_initial.opaque_lasers then form = form .. "label[6,1;"..minetest.formspec_escape("(*)").."]" .. "tooltip[5.92,0.8;0.4,0.4;"..S("This setting will take effect after a restart.").."]" end form = form .. "box[1,1.6;1,1;#0000003f]" if graphics_settings_state.patterned_lasers then form = form .. "image[1.1,1.7.1;0.8,0.8;lzr_menu_settings_patterned_lasers_on.png]" else form = form .. "image[1.1,1.7.1;0.8,0.8;lzr_menu_settings_patterned_lasers_off.png]" end form = form .. "checkbox[2.3,2.1;patterned_lasers;"..FS("Laser color patterns")..";"..tostring(graphics_settings_state.patterned_lasers).."]" .. "tooltip[patterned_lasers;"..FS("Special patterns will appear on the lasers, one for each color. Helps to distinguish lasers without relying on color alone.").."]" if graphics_settings_state.patterned_lasers ~= graphics_settings_initial.patterned_lasers then form = form .. "label[6,2.1;"..minetest.formspec_escape("(*)").."]" .. "tooltip[5.92,1.9;0.4,0.4;"..S("This setting will take effect after a restart.").."]" end form = form .. "button[1,3.5;3.1,0.8;apply;"..FS("Apply").."]".. "button_exit[5,3.5;3.1,0.8;cancel;"..FS("Cancel").."]" minetest.show_formspec(player:get_player_name(), "lzr_menu:graphics_settings", form) end minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() if formname == "lzr_menu:graphics_settings" then if fields.opaque_lasers == "true" then graphics_settings_state.opaque_lasers = true open_graphics_settings(player) elseif fields.opaque_lasers == "false" then graphics_settings_state.opaque_lasers = false open_graphics_settings(player) end if fields.patterned_lasers == "true" then graphics_settings_state.patterned_lasers = true open_graphics_settings(player) elseif fields.patterned_lasers == "false" then graphics_settings_state.patterned_lasers = false open_graphics_settings(player) end if fields.apply then if graphics_settings_initial.opaque_lasers == graphics_settings_state.opaque_lasers and graphics_settings_initial.patterned_lasers == graphics_settings_state.patterned_lasers then -- Nothing has changed: Nothing to do. minetest.close_formspec(pname, "lzr_menu:graphics_settings") return end minetest.settings:set_bool("lzr_opaque_lasers", graphics_settings_state.opaque_lasers) minetest.settings:set_bool("lzr_patterned_lasers", graphics_settings_state.patterned_lasers) local form = "formspec_version[4]size[10,4]".. "label[1,1;"..FS("The game needs to be restarted for the new graphics settings to take effect.").."]".. "button_exit[1,2;3,0.8;restart;"..FS("Restart").."]".. "button_exit[5,2;3,0.8;cancel;"..FS("Keep playing").."]" minetest.show_formspec(pname, "lzr_menu:confirm_restart", form) elseif fields.quit or fields.cancel then graphics_settings_state = { opaque_lasers = minetest.settings:get_bool("lzr_opaque_lasers", false), patterned_lasers = minetest.settings:get_bool("lzr_patterned_lasers", false), } end elseif formname == "lzr_menu:confirm_restart" then if fields.restart then minetest.disconnect_player(pname, S("You’ve quit the game. Start the game again for the settings to take effect.")) end end end) local function on_rightclick_television(_, _, player) open_graphics_settings(player) end local function on_punch_television(_, _, player) open_graphics_settings(player) end -- Television to update graphics settings minetest.register_node("lzr_menu:television", { description = S("Television"), tiles = { "xdecor_television_left.png^[transformR90", "xdecor_television_left.png^[transformR270", "xdecor_television_left.png", "xdecor_television_left.png^[transformR180", "xdecor_television_back.png", { name = "xdecor_television_front_animated.png", animation = { type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 1 } }, }, paramtype2 = "4dir", groups = { breakable = 1, rotatable = 1, not_in_creative_inventory = 1}, sounds = lzr_sounds.node_sound_metal_defaults(), is_ground_content = false, on_punch = on_punch_television, on_rightclick = on_rightclick_television, on_construct = function(pos) local meta = minetest.get_meta(pos) meta:set_string("infotext", S("Change graphics settings")) end, }) lzr_gamestate.register_on_enter_state(function(state) if state == lzr_gamestate.MENU then local player = minetest.get_player_by_name("singleplayer") lzr_player.set_menu_inventory(player) lzr_gui.set_menu_gui(player) lzr_ambience.set_ambience("ocean") lzr_sky.set_sky("bright_blue") lzr_weather.set_weather("clear") end end)