From f23fa236dd3ebfa7bf926583797579e5121fb2d7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 2 Feb 2019 00:12:57 +0100 Subject: [PATCH 001/865] Update deprecated function call in mesecons_mvps --- mods/ITEMS/REDSTONE/mesecons_mvps/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua b/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua index 2e2d0fd6..5e7da9d2 100644 --- a/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_mvps/init.lua @@ -290,7 +290,7 @@ function mesecon.mvps_move_objects(pos, dir, nodestack) end -- Move objects lying/standing on the stack (before it was pushed - oldstack) - if tonumber(minetest.setting_get("movement_gravity")) > 0 and dir.y == 0 then + if tonumber(minetest.settings:get("movement_gravity")) > 0 and dir.y == 0 then -- If gravity positive and dir horizontal, push players standing on the stack for _, n in ipairs(nodestack) do local p_above = vector.add(n.pos, {x=0, y=1, z=0}) From 4f2cd559da3999cea19ba90699e3c1374768e1f6 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Feb 2019 12:21:58 +0100 Subject: [PATCH 002/865] Rename textures that clash with MTG cactus, hotbar, some wools --- mods/HUD/mcl_inventory/init.lua | 4 +- ...ui_hotbar.png => mcl_inventory_hotbar.png} | Bin ....png => mcl_inventory_hotbar_selected.png} | Bin mods/ITEMS/mcl_core/nodes_cactuscane.lua | 2 +- ...ctus_side.png => mcl_core_cactus_side.png} | Bin ...cactus_top.png => mcl_core_cactus_top.png} | Bin mods/ITEMS/mcl_wool/init.lua | 50 +++++++++--------- ...light_blue.png => mcl_wool_light_blue.png} | Bin .../{wool_lime.png => mcl_wool_lime.png} | Bin .../{wool_green.png => wool_dark_green.png} | Bin tools/Conversion_Table.csv | 14 ++--- 11 files changed, 36 insertions(+), 34 deletions(-) rename mods/HUD/mcl_inventory/textures/{gui_hotbar.png => mcl_inventory_hotbar.png} (100%) rename mods/HUD/mcl_inventory/textures/{gui_hotbar_selected.png => mcl_inventory_hotbar_selected.png} (100%) rename mods/ITEMS/mcl_core/textures/{default_cactus_side.png => mcl_core_cactus_side.png} (100%) rename mods/ITEMS/mcl_core/textures/{default_cactus_top.png => mcl_core_cactus_top.png} (100%) rename mods/ITEMS/mcl_wool/textures/{wool_light_blue.png => mcl_wool_light_blue.png} (100%) rename mods/ITEMS/mcl_wool/textures/{wool_lime.png => mcl_wool_lime.png} (100%) rename mods/ITEMS/mcl_wool/textures/{wool_green.png => wool_dark_green.png} (100%) diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index 2833c3ac..4bd2ef80 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -135,8 +135,8 @@ minetest.register_on_joinplayer(function(player) --set hotbar size player:hud_set_hotbar_itemcount(9) --add hotbar images - player:hud_set_hotbar_image("gui_hotbar.png") - player:hud_set_hotbar_selected_image("gui_hotbar_selected.png") + player:hud_set_hotbar_image("mcl_inventory_hotbar.png") + player:hud_set_hotbar_selected_image("mcl_inventory_hotbar_selected.png") if show_armor then local set_player_armor_original = armor.set_player_armor diff --git a/mods/HUD/mcl_inventory/textures/gui_hotbar.png b/mods/HUD/mcl_inventory/textures/mcl_inventory_hotbar.png similarity index 100% rename from mods/HUD/mcl_inventory/textures/gui_hotbar.png rename to mods/HUD/mcl_inventory/textures/mcl_inventory_hotbar.png diff --git a/mods/HUD/mcl_inventory/textures/gui_hotbar_selected.png b/mods/HUD/mcl_inventory/textures/mcl_inventory_hotbar_selected.png similarity index 100% rename from mods/HUD/mcl_inventory/textures/gui_hotbar_selected.png rename to mods/HUD/mcl_inventory/textures/mcl_inventory_hotbar_selected.png diff --git a/mods/ITEMS/mcl_core/nodes_cactuscane.lua b/mods/ITEMS/mcl_core/nodes_cactuscane.lua index 3ae5807c..9b87ae6f 100644 --- a/mods/ITEMS/mcl_core/nodes_cactuscane.lua +++ b/mods/ITEMS/mcl_core/nodes_cactuscane.lua @@ -5,7 +5,7 @@ minetest.register_node("mcl_core:cactus", { _doc_items_longdesc = "This is a piece of cactus commonly found in dry areas, especially deserts. Over time, cacti will grow up to 3 blocks high on sand or red sand. A cactus hurts living beings touching it with a damage of 1 HP every half second. When a cactus block is broken, all cactus blocks connected above it will break as well.", _doc_items_usagehelp = "A cactus can only be placed on top of another cactus or any sand.", drawtype = "nodebox", - tiles = {"default_cactus_top.png", "mcl_core_cactus_bottom.png", "default_cactus_side.png","default_cactus_side.png","default_cactus_side.png","default_cactus_side.png"}, + tiles = {"mcl_core_cactus_top.png", "mcl_core_cactus_bottom.png", "mcl_core_cactus_side.png"}, is_ground_content = true, stack_max = 64, groups = {handy=1, attached_node=1, plant=1, deco_block=1, dig_by_piston=1, enderman_takable=1}, diff --git a/mods/ITEMS/mcl_core/textures/default_cactus_side.png b/mods/ITEMS/mcl_core/textures/mcl_core_cactus_side.png similarity index 100% rename from mods/ITEMS/mcl_core/textures/default_cactus_side.png rename to mods/ITEMS/mcl_core/textures/mcl_core_cactus_side.png diff --git a/mods/ITEMS/mcl_core/textures/default_cactus_top.png b/mods/ITEMS/mcl_core/textures/mcl_core_cactus_top.png similarity index 100% rename from mods/ITEMS/mcl_core/textures/default_cactus_top.png rename to mods/ITEMS/mcl_core/textures/mcl_core_cactus_top.png diff --git a/mods/ITEMS/mcl_wool/init.lua b/mods/ITEMS/mcl_wool/init.lua index e0d0e849..14e7d204 100644 --- a/mods/ITEMS/mcl_wool/init.lua +++ b/mods/ITEMS/mcl_wool/init.lua @@ -9,49 +9,51 @@ local wool = {} -- colors, and then some recipes using more specific colors for a few non-base -- colors available. When crafting, the last recipes will be checked first. wool.dyes = { - {"white", "white", "White", nil, "basecolor_white"}, - {"grey", "dark_grey", "Grey", "dark_grey", "unicolor_darkgrey"}, - {"silver", "grey", "Light Grey", "grey", "basecolor_grey"}, - {"black", "black", "Black", "black", "basecolor_black"}, - {"red", "red", "Red", "red", "basecolor_red"}, - {"yellow", "yellow", "Yellow", "yellow", "basecolor_yellow"}, - {"green", "green", "Green", "dark_green", "unicolor_dark_green"}, - {"cyan", "cyan", "Cyan", "cyan", "basecolor_cyan"}, - {"blue", "blue", "Blue", "blue", "basecolor_blue"}, - {"magenta", "magenta", "Magenta", "magenta", "basecolor_magenta"}, - {"orange", "orange", "Orange", "orange", "excolor_orange"}, - {"purple", "violet", "Purple", "violet", "excolor_violet"}, - {"brown", "brown", "Brown", "brown", "unicolor_dark_orange"}, - {"pink", "pink", "Pink", "pink", "unicolor_light_red"}, - {"lime", "lime", "Lime", "green", "basecolor_green"}, - {"light_blue", "light_blue", "Light Blue", "lightblue", "unicolor_light_blue"}, + -- name, texture, wool desc., carpet desc., dye, color_group + {"white", "wool_white", "White Wool", "White Carpet", nil, "basecolor_white"}, + {"grey", "wool_dark_grey", "Grey Wool", "Grey Carpet", "dark_grey", "unicolor_darkgrey"}, + {"silver", "wool_grey", "Light Grey Wool", "Light Grey Carpet", "grey", "basecolor_grey"}, + {"black", "wool_black", "Black Wool", "Black Carpet", "black", "basecolor_black"}, + {"red", "wool_red", "Red Wool", "Red Carpet", "red", "basecolor_red"}, + {"yellow", "wool_yellow", "Yellow Wool", "Yellow Carpet", "yellow", "basecolor_yellow"}, + {"green", "wool_dark_green", "Green Wool", "Green Carpet", "dark_green", "unicolor_dark_green"}, + {"cyan", "wool_cyan", "Cyan Wool", "Cyan Carpet", "cyan", "basecolor_cyan"}, + {"blue", "wool_blue", "Blue Wool", "Blue Carpet", "blue", "basecolor_blue"}, + {"magenta", "wool_magenta", "Magenta Wool", "Magenta Carpet", "magenta", "basecolor_magenta"}, + {"orange", "wool_orange", "Orange Wool", "Orange Carpet", "orange", "excolor_orange"}, + {"purple", "wool_violet", "Purple Wool", "Purple Carpet", "violet", "excolor_violet"}, + {"brown", "wool_brown", "Brown Wool", "Brown Carpet", "brown", "unicolor_dark_orange"}, + {"pink", "wool_pink", "Pink Wool", "Pink Carpet", "pink", "unicolor_light_red"}, + {"lime", "mcl_wool_lime", "Lime Wool", "Lime Carpet", "green", "basecolor_green"}, + {"light_blue", "mcl_wool_light_blue", "Light Blue Wool", "Light Blue Carpet", "lightblue", "unicolor_light_blue"}, } for _, row in ipairs(wool.dyes) do local name = row[1] local texture = row[2] - local desc = row[3] - local dye = row[4] - local color_group = row[5] + local desc_wool = row[3] + local desc_carpet = row[4] + local dye = row[5] + local color_group = row[6] -- Node Definition minetest.register_node("mcl_wool:"..name, { - description = desc.." Wool", + description = desc_wool, _doc_items_longdesc = "Wool is a decorational block which comes in many different colors.", stack_max = 64, is_ground_content = false, - tiles = {"wool_"..texture..".png"}, + tiles = {texture..".png"}, groups = {handy=1,shearsy_wool=1, flammable=1,wool=1,building_block=1}, sounds = mcl_sounds.node_sound_defaults(), _mcl_hardness = 0.8, _mcl_blast_resistance = 4, }) minetest.register_node("mcl_wool:"..name.."_carpet", { - description = desc.." Carpet", + description = desc_carpet, _doc_items_longdesc = "Carpets are thin floor covers which come in many different colors.", walkable = false, -- See is_ground_content = false, - tiles = {"wool_"..texture..".png"}, - wield_image = "wool_"..texture..".png", + tiles = {texture..".png"}, + wield_image = texture..".png", wield_scale = { x=1, y=1, z=0.5 }, groups = {handy=1, carpet=1,attached_node=1,dig_by_water=1,deco_block=1}, sounds = mcl_sounds.node_sound_defaults(), diff --git a/mods/ITEMS/mcl_wool/textures/wool_light_blue.png b/mods/ITEMS/mcl_wool/textures/mcl_wool_light_blue.png similarity index 100% rename from mods/ITEMS/mcl_wool/textures/wool_light_blue.png rename to mods/ITEMS/mcl_wool/textures/mcl_wool_light_blue.png diff --git a/mods/ITEMS/mcl_wool/textures/wool_lime.png b/mods/ITEMS/mcl_wool/textures/mcl_wool_lime.png similarity index 100% rename from mods/ITEMS/mcl_wool/textures/wool_lime.png rename to mods/ITEMS/mcl_wool/textures/mcl_wool_lime.png diff --git a/mods/ITEMS/mcl_wool/textures/wool_green.png b/mods/ITEMS/mcl_wool/textures/wool_dark_green.png similarity index 100% rename from mods/ITEMS/mcl_wool/textures/wool_green.png rename to mods/ITEMS/mcl_wool/textures/wool_dark_green.png diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index ad12753e..4f1992a2 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -127,8 +127,8 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,apple.png,/mods/ITEMS/mcl_core/textures,default_apple.png,,,,,,, /assets/minecraft/textures/items,apple_golden.png,/mods/ITEMS/mcl_core/textures,mcl_core_apple_golden.png,,,,,,, /assets/minecraft/textures/blocks,brick.png,/mods/ITEMS/mcl_core/textures,default_brick.png,,,,,,, -/assets/minecraft/textures/blocks,cactus_side.png,/mods/ITEMS/mcl_core/textures,default_cactus_side.png,,,,,,, -/assets/minecraft/textures/blocks,cactus_top.png,/mods/ITEMS/mcl_core/textures,default_cactus_top.png,,,,,,, +/assets/minecraft/textures/blocks,cactus_side.png,/mods/ITEMS/mcl_core/textures,mcl_core_cactus_side.png,,,,,,, +/assets/minecraft/textures/blocks,cactus_top.png,/mods/ITEMS/mcl_core/textures,mcl_core_cactus_top.png,,,,,,, /assets/minecraft/textures/blocks,cactus_bottom.png,/mods/ITEMS/mcl_core/textures,mcl_core_cactus_bottom.png,,,,,,, /assets/minecraft/textures/items,brick.png,/mods/ITEMS/mcl_core/textures,default_clay_brick.png,,,,,,, /assets/minecraft/textures/items,clay_ball.png,/mods/ITEMS/mcl_core/textures,default_clay_lump.png,,,,,,, @@ -578,10 +578,10 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/blocks,wool_colored_brown.png,/mods/ITEMS/mcl_wool/textures,wool_brown.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_cyan.png,/mods/ITEMS/mcl_wool/textures,wool_cyan.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_gray.png,/mods/ITEMS/mcl_wool/textures,wool_dark_grey.png,,,,,,, -/assets/minecraft/textures/blocks,wool_colored_green.png,/mods/ITEMS/mcl_wool/textures,wool_green.png,,,,,,, +/assets/minecraft/textures/blocks,wool_colored_green.png,/mods/ITEMS/mcl_wool/textures,wool_dark_green.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_silver.png,/mods/ITEMS/mcl_wool/textures,wool_grey.png,,,,,,, -/assets/minecraft/textures/blocks,wool_colored_light_blue.png,/mods/ITEMS/mcl_wool/textures,wool_light_blue.png,,,,,,, -/assets/minecraft/textures/blocks,wool_colored_lime.png,/mods/ITEMS/mcl_wool/textures,wool_lime.png,,,,,,, +/assets/minecraft/textures/blocks,wool_colored_light_blue.png,/mods/ITEMS/mcl_wool/textures,mcl_wool_light_blue.png,,,,,,, +/assets/minecraft/textures/blocks,wool_colored_lime.png,/mods/ITEMS/mcl_wool/textures,mcl_wool_lime.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_magenta.png,/mods/ITEMS/mcl_wool/textures,wool_magenta.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_orange.png,/mods/ITEMS/mcl_wool/textures,wool_orange.png,,,,,,, /assets/minecraft/textures/blocks,wool_colored_pink.png,/mods/ITEMS/mcl_wool/textures,wool_pink.png,,,,,,, @@ -795,8 +795,8 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/blocks,shulker_top_yellow.png,/mods/ITEMS/mcl_chests/textures,mcl_chests_yellow_shulker_box_top.png,,,,,,,y /assets/minecraft/textures/items,flower_pot.png,/mods/ITEMS/mcl_flowerpots/textures,mcl_flowerpots_flowerpot_inventory.png,,,,,,, /assets/minecraft/textures/blocks,flower_pot.png,/mods/ITEMS/mcl_flowerpots/textures,mcl_flowerpots_flowerpot.png,,,,,,,y -/assets/minecraft/textures/gui,widgets.png,/mods/HUD/mcl_inventory/textures,gui_hotbar.png,0,0,182,22,0,0,y -/assets/minecraft/textures/gui,widgets.png,/mods/HUD/mcl_inventory/textures,gui_hotbar_selected.png,0,22,24,24,0,0,y +/assets/minecraft/textures/gui,widgets.png,/mods/HUD/mcl_inventory/textures,mcl_inventory_hotbar.png,0,0,182,22,0,0,y +/assets/minecraft/textures/gui,widgets.png,/mods/HUD/mcl_inventory/textures,mcl_inventory_hotbar_selected.png,0,22,24,24,0,0,y /assets/minecraft/textures/blocks,bed_feet_end.png,/mods/ITEMS/mcl_beds/textures,mcl_beds_bed_side_bottom_red.png,,,,,,, /assets/minecraft/textures/blocks,bed_feet_side.png,/mods/ITEMS/mcl_beds/textures,mcl_beds_bed_side_bottom_r_red.png,,,,,,, /assets/minecraft/textures/blocks,bed_feet_top.png,/mods/ITEMS/mcl_beds/textures,mcl_beds_bed_top_bottom_red.png,,,,,,, From a28582798027de31f42df463d8d31aa85d914565 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Feb 2019 12:38:36 +0100 Subject: [PATCH 003/865] Change powered rail texture names to fix MTG clash --- mods/ENTITIES/mcl_minecarts/rails.lua | 2 +- ...s_rail_pwr.png => mcl_minecarts_rail_golden.png} | Bin ...r.png => mcl_minecarts_rail_golden_crossing.png} | Bin ...pwr.png => mcl_minecarts_rail_golden_curved.png} | Bin ...png => mcl_minecarts_rail_golden_t_junction.png} | Bin tools/Conversion_Table.csv | 2 +- 6 files changed, 2 insertions(+), 2 deletions(-) rename mods/ENTITIES/mcl_minecarts/textures/{carts_rail_pwr.png => mcl_minecarts_rail_golden.png} (100%) rename mods/ENTITIES/mcl_minecarts/textures/{carts_rail_crossing_pwr.png => mcl_minecarts_rail_golden_crossing.png} (100%) rename mods/ENTITIES/mcl_minecarts/textures/{carts_rail_curved_pwr.png => mcl_minecarts_rail_golden_curved.png} (100%) rename mods/ENTITIES/mcl_minecarts/textures/{carts_rail_t_junction_pwr.png => mcl_minecarts_rail_golden_t_junction.png} (100%) diff --git a/mods/ENTITIES/mcl_minecarts/rails.lua b/mods/ENTITIES/mcl_minecarts/rails.lua index 1058ba35..04f420f8 100644 --- a/mods/ENTITIES/mcl_minecarts/rails.lua +++ b/mods/ENTITIES/mcl_minecarts/rails.lua @@ -78,7 +78,7 @@ register_rail("mcl_minecarts:rail", -- Powered rail (off = brake mode) register_rail("mcl_minecarts:golden_rail", - {"carts_rail_pwr.png", "carts_rail_curved_pwr.png", "carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"}, + {"mcl_minecarts_rail_golden.png", "mcl_minecarts_rail_golden_curved.png", "mcl_minecarts_rail_golden_t_junction.png", "mcl_minecarts_rail_golden_crossing.png"}, { description = "Powered Rail", _doc_items_longdesc = "Rails can be used to build transport tracks for minecarts. Powered rails are able to accelerate and brake minecarts.", diff --git a/mods/ENTITIES/mcl_minecarts/textures/carts_rail_pwr.png b/mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden.png similarity index 100% rename from mods/ENTITIES/mcl_minecarts/textures/carts_rail_pwr.png rename to mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden.png diff --git a/mods/ENTITIES/mcl_minecarts/textures/carts_rail_crossing_pwr.png b/mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_crossing.png similarity index 100% rename from mods/ENTITIES/mcl_minecarts/textures/carts_rail_crossing_pwr.png rename to mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_crossing.png diff --git a/mods/ENTITIES/mcl_minecarts/textures/carts_rail_curved_pwr.png b/mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_curved.png similarity index 100% rename from mods/ENTITIES/mcl_minecarts/textures/carts_rail_curved_pwr.png rename to mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_curved.png diff --git a/mods/ENTITIES/mcl_minecarts/textures/carts_rail_t_junction_pwr.png b/mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_t_junction.png similarity index 100% rename from mods/ENTITIES/mcl_minecarts/textures/carts_rail_t_junction_pwr.png rename to mods/ENTITIES/mcl_minecarts/textures/mcl_minecarts_rail_golden_t_junction.png diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index 4f1992a2..5567b27f 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -448,7 +448,7 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,map_empty.png,/mods/ITEMS/mcl_maps/textures,mcl_maps_map_empty.png,,,,,,, /assets/minecraft/textures/items,map_filled_markings.png,/mods/ITEMS/mcl_maps/textures,mcl_maps_map_filled_markings.png,,,,,,, /assets/minecraft/textures/items,map_filled.png,/mods/ITEMS/mcl_maps/textures,mcl_maps_map_filled.png,,,,,,, -/assets/minecraft/textures/blocks,rail_golden.png,/mods/ENTITIES/mcl_minecarts/textures,carts_rail_pwr.png,,,,,,, +/assets/minecraft/textures/blocks,rail_golden.png,/mods/ENTITIES/mcl_minecarts/textures,mcl_minecarts_rail_golden.png,,,,,,, /assets/minecraft/textures/blocks,rail_golden_powered.png,/mods/ENTITIES/mcl_minecarts/textures,mcl_minecarts_rail_golden_powered.png,,,,,,, /assets/minecraft/textures/blocks,rail_normal_turned.png,/mods/ENTITIES/mcl_minecarts/textures,default_rail_curved.png,,,,,,, /assets/minecraft/textures/blocks,rail_normal.png,/mods/ENTITIES/mcl_minecarts/textures,default_rail.png,,,,,,, From a11f6ffaacf7d4607a03107a0da5ee8c1e2ca561 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Feb 2019 16:53:06 +0100 Subject: [PATCH 004/865] Don't respawn on bed if bed is missing or blocked --- mods/ITEMS/mcl_beds/functions.lua | 4 +++- mods/PLAYER/mcl_spawn/init.lua | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 2843bdd4..bb45a063 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -228,7 +228,9 @@ function mcl_beds.on_rightclick(pos, player) if not mcl_beds.player[name] then lay_down(player, ppos, pos) if minetest.get_modpath("mcl_spawn") then - mcl_spawn.set_spawn_pos(player, player:get_pos()) -- save respawn position when entering bed + local spos = table.copy(pos) + spos.y = spos.y + 0.1 + mcl_spawn.set_spawn_pos(player, spos) -- save respawn position when entering bed end else lay_down(player, nil, nil, false) diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index cc8463c3..65853028 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -33,8 +33,23 @@ end minetest.register_on_respawnplayer(function(player) local pos = mcl_spawn.get_spawn_pos(player) if pos then - player:set_pos(pos) - return true + -- Check if bed is still there + -- and the spawning position is free of solid or damaging blocks. + local node_bed = minetest.get_node(pos) + local node_up1 = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}) + local node_up2 = minetest.get_node({x=pos.x,y=pos.y+2,z=pos.z}) + local bgroup = minetest.get_item_group(node_bed.name, "bed") + local def1 = minetest.registered_nodes[node_up1.name] + local def2 = minetest.registered_nodes[node_up2.name] + if (bgroup == 1 or bgroup == 2) and + (not def1.walkable) and (not def2.walkable) and + (def1.damage_per_second == nil or def2.damage_per_second <= 0) and + (def1.damage_per_second == nil or def2.damage_per_second <= 0) then + player:set_pos(pos) + return true + else + minetest.chat_send_player(player:get_player_name(), "Your spawn bed was missing or blocked.") + end end end) From 6faac04f0de564a55097b4bec076ca879d7dade4 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Feb 2019 17:53:30 +0100 Subject: [PATCH 005/865] Prevent sleeping if solid or damage block over bed --- mods/ITEMS/mcl_beds/functions.lua | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index bb45a063..b1eaa85a 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -118,16 +118,28 @@ local function lay_down(player, pos, bed_pos, state, skip) -- lay down else + local yaw, param2 = get_look_yaw(bed_pos) + local dir = minetest.facedir_to_dir(param2) + local p = {x = bed_pos.x + dir.x / 4, y = bed_pos.y, z = bed_pos.z + dir.z / 4} + local n1 = minetest.get_node({x=bed_pos.x, y=bed_pos.y+1, z=bed_pos.z}) + local n2 = minetest.get_node({x=bed_pos.x, y=bed_pos.y+2, z=bed_pos.z}) + local def1 = minetest.registered_nodes[n1.name] + local def2 = minetest.registered_nodes[n2.name] + if def1.walkable or def2.walkable then + minetest.chat_send_player(name, "You can't sleep, the bed is obstructed!") + return + elseif (def1.damage_per_second ~= nil and def1.damage_per_second > 0) or (def2.damage_per_second ~= nil and def2.damage_per_second > 0) then + minetest.chat_send_player(name, "It's too dangerous to sleep here!") + return + end + mcl_beds.player[name] = 1 mcl_beds.pos[name] = pos player_in_bed = player_in_bed + 1 - -- physics, eye_offset, etc player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0}) - local yaw, param2 = get_look_yaw(bed_pos) player:set_look_horizontal(yaw) - local dir = minetest.facedir_to_dir(param2) - local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2} + player:set_attribute("mcl_beds:sleeping", "true") playerphysics.add_physics_factor(player, "speed", "mcl_beds:sleeping", 0) playerphysics.add_physics_factor(player, "jump", "mcl_beds:sleeping", 0) From 7437d3945be215ee27c6724b6a9fe707d4158483 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 00:07:39 +0100 Subject: [PATCH 006/865] Forget spawn if bed was destroyed --- mods/PLAYER/mcl_spawn/init.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 65853028..0413219b 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -48,6 +48,10 @@ minetest.register_on_respawnplayer(function(player) player:set_pos(pos) return true else + -- Forget spawn if bed was missing + if (bgroup ~= 1 and bgroup ~= 2) then + mcl_spawn.set_spawn_pos(player, nil) + end minetest.chat_send_player(player:get_player_name(), "Your spawn bed was missing or blocked.") end end From f63342ec723929769579e736bfc3f0a0ec2f81f7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 04:06:28 +0100 Subject: [PATCH 007/865] Rename seed textures --- mods/ITEMS/mcl_farming/melon.lua | 2 +- mods/ITEMS/mcl_farming/pumpkin.lua | 2 +- ...g_melon_seed.png => mcl_farming_melon_seeds.png} | Bin ...mpkin_seed.png => mcl_farming_pumpkin_seeds.png} | Bin ...g_wheat_seed.png => mcl_farming_wheat_seeds.png} | Bin mods/ITEMS/mcl_farming/wheat.lua | 2 +- tools/Conversion_Table.csv | 6 +++--- 7 files changed, 6 insertions(+), 6 deletions(-) rename mods/ITEMS/mcl_farming/textures/{farming_melon_seed.png => mcl_farming_melon_seeds.png} (100%) rename mods/ITEMS/mcl_farming/textures/{farming_pumpkin_seed.png => mcl_farming_pumpkin_seeds.png} (100%) rename mods/ITEMS/mcl_farming/textures/{farming_wheat_seed.png => mcl_farming_wheat_seeds.png} (100%) diff --git a/mods/ITEMS/mcl_farming/melon.lua b/mods/ITEMS/mcl_farming/melon.lua index 72e27a22..7e3cfa1d 100644 --- a/mods/ITEMS/mcl_farming/melon.lua +++ b/mods/ITEMS/mcl_farming/melon.lua @@ -5,7 +5,7 @@ minetest.register_craftitem("mcl_farming:melon_seeds", { _doc_items_usagehelp = "Place the melon seeds on farmland (which can be created with a hoe) to plant a melon stem. Melons grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it melon seeds.", stack_max = 64, groups = { craftitem=1 }, - inventory_image = "farming_melon_seed.png", + inventory_image = "mcl_farming_melon_seeds.png", on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:melontige_1") end, diff --git a/mods/ITEMS/mcl_farming/pumpkin.lua b/mods/ITEMS/mcl_farming/pumpkin.lua index 5df24e82..6b0d3181 100644 --- a/mods/ITEMS/mcl_farming/pumpkin.lua +++ b/mods/ITEMS/mcl_farming/pumpkin.lua @@ -4,7 +4,7 @@ minetest.register_craftitem("mcl_farming:pumpkin_seeds", { _doc_items_longdesc = "Grows into a pumpkin. Chickens like pumpkin seeds.", _doc_items_usagehelp = "Place the pumpkin seeds on farmland (which can be created with a hoe) to plant a pumpkin stem. Pumpkins grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it pumpkin seeds.", stack_max = 64, - inventory_image = "farming_pumpkin_seed.png", + inventory_image = "mcl_farming_pumpkin_seeds.png", groups = { craftitem=1 }, on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:pumpkin_1") diff --git a/mods/ITEMS/mcl_farming/textures/farming_melon_seed.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_melon_seeds.png similarity index 100% rename from mods/ITEMS/mcl_farming/textures/farming_melon_seed.png rename to mods/ITEMS/mcl_farming/textures/mcl_farming_melon_seeds.png diff --git a/mods/ITEMS/mcl_farming/textures/farming_pumpkin_seed.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_pumpkin_seeds.png similarity index 100% rename from mods/ITEMS/mcl_farming/textures/farming_pumpkin_seed.png rename to mods/ITEMS/mcl_farming/textures/mcl_farming_pumpkin_seeds.png diff --git a/mods/ITEMS/mcl_farming/textures/farming_wheat_seed.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_wheat_seeds.png similarity index 100% rename from mods/ITEMS/mcl_farming/textures/farming_wheat_seed.png rename to mods/ITEMS/mcl_farming/textures/mcl_farming_wheat_seeds.png diff --git a/mods/ITEMS/mcl_farming/wheat.lua b/mods/ITEMS/mcl_farming/wheat.lua index 7c38c06a..f7521d26 100644 --- a/mods/ITEMS/mcl_farming/wheat.lua +++ b/mods/ITEMS/mcl_farming/wheat.lua @@ -4,7 +4,7 @@ minetest.register_craftitem("mcl_farming:wheat_seeds", { _doc_items_longdesc = "Grows into a wheat plant. Chickens like wheat seeds.", _doc_items_usagehelp = "Place the wheat seeds on farmland (which can be created with a hoe) to plant a wheat plant. They grow in sunlight and grow faster on hydrated farmland. Rightclick an animal to feed it wheat seeds.", groups = { craftitem=1 }, - inventory_image = "farming_wheat_seed.png", + inventory_image = "mcl_farming_wheat_seeds.png", on_place = function(itemstack, placer, pointed_thing) return mcl_farming:place_seed(itemstack, placer, pointed_thing, "mcl_farming:wheat_1") end diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index 5567b27f..7d2e8612 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -348,7 +348,7 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,carrot.png,/mods/ITEMS/mcl_farming/textures,farming_carrot.png,,,,,,, /assets/minecraft/textures/items,cookie.png,/mods/ITEMS/mcl_farming/textures,farming_cookie.png,,,,,,, /assets/minecraft/textures/items,melon.png,/mods/ITEMS/mcl_farming/textures,farming_melon.png,,,,,,, -/assets/minecraft/textures/items,seeds_melon.png,/mods/ITEMS/mcl_farming/textures,farming_melon_seed.png,,,,,,, +/assets/minecraft/textures/items,seeds_melon.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_melon_seeds.png,,,,,,, /assets/minecraft/textures/blocks,melon_side.png,/mods/ITEMS/mcl_farming/textures,farming_melon_side.png,,,,,,, /assets/minecraft/textures/blocks,melon_top.png,/mods/ITEMS/mcl_farming/textures,farming_melon_top.png,,,,,,, /assets/minecraft/textures/items,potato_baked.png,/mods/ITEMS/mcl_farming/textures,farming_potato_baked.png,,,,,,, @@ -356,7 +356,7 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,potato_poisonous.png,/mods/ITEMS/mcl_farming/textures,farming_potato_poison.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_face_on.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_face_light.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_face_off.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_face.png,,,,,,, -/assets/minecraft/textures/items,seeds_pumpkin.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_seed.png,,,,,,, +/assets/minecraft/textures/items,seeds_pumpkin.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_pumpkin_seeds.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_side.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_side.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_top.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_top.png,,,,,,, /assets/minecraft/textures/blocks,farmland_dry.png,/mods/ITEMS/mcl_farming/textures,farming_soil.png,,,,,,, @@ -367,7 +367,7 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,stone_hoe.png,/mods/ITEMS/mcl_farming/textures,farming_tool_stonehoe.png,,,,,,, /assets/minecraft/textures/items,wood_hoe.png,/mods/ITEMS/mcl_farming/textures,farming_tool_woodhoe.png,,,,,,, /assets/minecraft/textures/items,wheat.png,/mods/ITEMS/mcl_farming/textures,farming_wheat_harvested.png,,,,,,, -/assets/minecraft/textures/items,seeds_wheat.png,/mods/ITEMS/mcl_farming/textures,farming_wheat_seed.png,,,,,,, +/assets/minecraft/textures/items,seeds_wheat.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_wheat_seeds.png,,,,,,, /assets/minecraft/textures/blocks,beetroots_stage_0.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_beetroot_0.png,,,,,,, /assets/minecraft/textures/blocks,beetroots_stage_1.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_beetroot_1.png,,,,,,, /assets/minecraft/textures/blocks,beetroots_stage_2.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_beetroot_2.png,,,,,,, From 64457b151cb9258d28873fa728a0c3eb8155f832 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 17:05:40 +0100 Subject: [PATCH 008/865] Improve free space checks on mob spawn --- mods/ENTITIES/mcl_mobs/api.lua | 58 ++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 7ff966e2..08f5f8a9 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3176,11 +3176,13 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, -- is mob actually registered? if not mobs.spawning_mobs[name] or not minetest.registered_entities[name] then + minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!") return end -- additional custom checks for spawning mob if mobs:spawn_abm_check(pos, node, name) == true then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!") return end @@ -3188,6 +3190,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if active_object_count_wider >= max_per_block or count_mobs(pos, name) >= aoc then -- too many entities + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!") return end @@ -3200,12 +3203,14 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, -- daylight, but mob wants night if day_toggle == false then -- mob needs night + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!") return end else -- night time but mob wants day if day_toggle == true then -- mob needs day + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!") return end end @@ -3221,7 +3226,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if objs[n]:is_player() then -- player too close - minetest.log("info", "Mob spawn of ".. name .. " failed, player too close") + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!") return end end @@ -3229,12 +3234,14 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, -- mobs cannot spawn in protected areas when enabled if not spawn_protected and minetest.is_protected(pos, "") then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!") return end -- are we spawning within height limits? if pos.y > max_height or pos.y < min_height then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!") return end @@ -3243,27 +3250,58 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if not light or light > max_light or light < min_light then + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!") return end - -- do we have enough height clearance to spawn mob? + -- do we have enough space to spawn mob? local ent = minetest.registered_entities[name] - local height = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) + local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1])) + local min_x, max_x + if width_x % 2 == 0 then + max_x = math.floor(width_x/2) + min_x = -(max_x-1) + else + max_x = math.floor(width_x/2) + min_x = -max_x + end - for n = 0, height do + local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3])) + local min_z, max_z + if width_z % 2 == 0 then + max_z = math.floor(width_z/2) + min_z = -(max_z-1) + else + max_z = math.floor(width_z/2) + min_z = -max_z + end - local pos2 = {x = pos.x, y = pos.y + n, z = pos.z} + local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1) - if minetest.registered_nodes[node_ok(pos2).name].walkable == true then - -- inside block - return + for y = 0, max_y do + for x = min_x, max_x do + for z = min_z, max_z do + local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z} + if minetest.registered_nodes[node_ok(pos2).name].walkable == true then + -- inside block + minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") + return + end + end end end - -- spawn mob half block higher than ground - pos.y = pos.y + 0.5 + -- spawn mob with half of its height above ground + pos.y = pos.y + ((ent.collisionbox[2] - ent.collisionbox[5]) / 2) + if width_x % 2 == 0 then + pos.x = pos.x + 0.5 + end + if width_z % 2 == 0 then + pos.z = pos.z + 0.5 + end local mob = minetest.add_entity(pos, name) + minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos)) if on_spawn then From b7a2fba1ce9568d1ba6e54f9617d2cb627a088f2 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 17:43:18 +0100 Subject: [PATCH 009/865] Fix spawn ABM check that prevented squid spawn --- mods/ENTITIES/mobs_mc/5_spawn_abm_check.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/5_spawn_abm_check.lua b/mods/ENTITIES/mobs_mc/5_spawn_abm_check.lua index 35a3c344..303feb1a 100644 --- a/mods/ENTITIES/mobs_mc/5_spawn_abm_check.lua +++ b/mods/ENTITIES/mobs_mc/5_spawn_abm_check.lua @@ -1,10 +1,11 @@ function mobs:spawn_abm_check(pos, node, name) - if (node.name == "air") then + -- Don't spawn monsters on mycelium + if (node.name == "mcl_core:mycelium" or node.name == "mcl_core:mycelium_snow") and minetest.registered_entities[name].type == "monster" then return true - elseif (node.name == "mcl_core:mycelium" or node.name == "mcl_core:mycelium_snow") and minetest.registered_entities[name].type == "monster" then - return false - elseif minetest.get_item_group(node.name, "opaque") ~= 0 then + -- Spawn on opaque or liquid nodes + elseif minetest.get_item_group(node.name, "opaque") ~= 0 or minetest.registered_nodes[node.name].liquidtype ~= "none" then return false end + -- Reject everything else return true end From cfd561554858a695c99b8b2704504b16d0b12731 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 19:12:28 +0100 Subject: [PATCH 010/865] Spawn smaller slime/magmacube if it doesn't fit --- mods/ENTITIES/mcl_mobs/api.lua | 33 ++++++++++++++-------- mods/ENTITIES/mcl_mobs/api.txt | 2 ++ mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 6 ++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 08f5f8a9..8d493cd5 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2975,6 +2975,7 @@ minetest.register_entity(name, { owner = def.owner or "", order = def.order or "", on_die = def.on_die, + spawn_small_alternative = def.spawn_small_alternative, do_custom = def.do_custom, jump_height = def.jump_height or 4, -- was 6 drawtype = def.drawtype, -- DEPRECATED, use rotate instead @@ -3162,17 +3163,10 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, end - minetest.register_abm({ - - label = name .. " spawning", - nodenames = nodes, - neighbors = neighbors, - interval = interval, - chance = max(1, (chance * mob_chance_multiplier)), - catch_up = false, - - action = function(pos, node, active_object_count, active_object_count_wider) + local spawn_action + spawn_action = function(pos, node, active_object_count, active_object_count_wider, name) + local orig_pos = table.copy(pos) -- is mob actually registered? if not mobs.spawning_mobs[name] or not minetest.registered_entities[name] then @@ -3285,6 +3279,10 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, if minetest.registered_nodes[node_ok(pos2).name].walkable == true then -- inside block minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!") + if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then + minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative) + spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative) + end return end end @@ -3309,7 +3307,20 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, on_spawn(ent, pos) end - end + end + + local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider) + spawn_action(pos, node, active_object_count, active_object_count_wider, name) + end + + minetest.register_abm({ + label = name .. " spawning", + nodenames = nodes, + neighbors = neighbors, + interval = interval, + chance = max(1, (chance * mob_chance_multiplier)), + catch_up = false, + action = spawn_abm_action, }) end diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index 9e30ca5c..c09151e9 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -213,6 +213,8 @@ functions needed for the mob to work properly which contains the following: 'rain_damage' damage per second if mob is standing in rain (default: 0) 'sunlight_damage' holds the damage per second inflicted to mobs when they are in direct sunlight + 'spawn_small_alternative': name of a smaller mob to use as replacement if + spawning fails due to space requirements Node Replacement ---------------- diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 59ed07fa..35374444 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -58,6 +58,7 @@ local slime_big = { jump_height = 5.2, jump_chance = 100, fear_height = 60, + spawn_small_alternative = "mobs_mc:slime_small", on_die = function(self, pos) local angle, posadd angle = math.random(0, math.pi*2) @@ -83,6 +84,7 @@ slime_small.reach = 2.75 slime_small.walk_velocity = 1.3 slime_small.run_velocity = 1.3 slime_small.jump_height = 4.3 +slime_small.spawn_small_alternative = "mobs_mc:slime_tiny" slime_small.on_die = function(self, pos) local angle, posadd, dir angle = math.random(0, math.pi*2) @@ -114,6 +116,7 @@ slime_tiny.drops = { slime_tiny.walk_velocity = 0.7 slime_tiny.run_velocity = 0.7 slime_tiny.jump_height = 3 +slime_tiny.spawn_small_alternative = nil slime_tiny.on_die = nil mobs:register_mob("mobs_mc:slime_tiny", slime_tiny) @@ -181,6 +184,7 @@ local magma_cube_big = { walk_chance = 0, jump_chance = 100, fear_height = 100000, + spawn_small_alternative = "mobs_mc:magma_cube_small", on_die = function(self, pos) local angle, posadd angle = math.random(0, math.pi*2) @@ -211,6 +215,7 @@ magma_cube_small.jump_height = 6 magma_cube_small.damage = 4 magma_cube_small.reach = 2.75 magma_cube_small.armor = 70 +magma_cube_small.spawn_small_alternative = "mobs_mc:magma_cube_tiny" magma_cube_small.on_die = function(self, pos) local angle, posadd, dir angle = math.random(0, math.pi*2) @@ -239,6 +244,7 @@ magma_cube_tiny.damage = 3 magma_cube_tiny.reach = 2.5 magma_cube_tiny.armor = 85 magma_cube_tiny.drops = {} +magma_cube_tiny.spawn_small_alternative = nil magma_cube_tiny.on_die = nil mobs:register_mob("mobs_mc:magma_cube_tiny", magma_cube_tiny) From 1c35828fa2b5852328319c46e4bb0fd9727109c3 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 19:24:02 +0100 Subject: [PATCH 011/865] Fix stupid mob spawn height --- mods/ENTITIES/mcl_mobs/api.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 8d493cd5..9fddda4d 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3289,8 +3289,9 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, end end - -- spawn mob with half of its height above ground - pos.y = pos.y + ((ent.collisionbox[2] - ent.collisionbox[5]) / 2) + -- spawn mob 1/2 node above ground + pos.y = pos.y + 0.5 + -- tweak X/Z spawn pos if width_x % 2 == 0 then pos.x = pos.x + 0.5 end From ca484cfa1adcbe41bd0e9614564ba8854596a0dd Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 20:19:06 +0100 Subject: [PATCH 012/865] Improve child spawn on slime/magmacube death No longer do children spawn in walls --- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 87 ++++++++++------------ 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 35374444..c419ec67 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -4,6 +4,41 @@ local MP = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(MP.."/intllib.lua") +-- Returns a function that spawns children in a circle around pos. +-- To be used as on_die callback. +-- self: mob reference +-- pos: position of "mother" mob +-- child_mod: Mob to spawn +-- children_count: Number of children to spawn +-- spawn_distance: Spawn distance from "mother" mob +-- eject_speed: Initial speed of child mob away from "mother" mob +local spawn_children_on_die = function(self, pos, child_mob, children_count, spawn_distance, eject_speed) + return function(self, pos) + local angle, posadd, newpos, dir + if not eject_speed then + eject_speed = 1 + end + local mother_stuck = minetest.registered_nodes[minetest.get_node(pos).name].walkable + angle = math.random(0, math.pi*2) + for i=1,children_count do + dir = {x=math.cos(angle),y=0,z=math.sin(angle)} + posadd = vector.multiply(vector.normalize(dir), spawn_distance) + newpos = vector.add(pos, posadd) + -- If child would end up in a wall, use position of the "mother", unless + -- the "mother" was stuck as well + local speed_penalty = 1 + if (not mother_stuck) and minetest.registered_nodes[minetest.get_node(newpos).name].walkable then + newpos = pos + speed_penalty = 0.5 + end + local mob = minetest.add_entity(newpos, child_mob) + mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) + mob:set_yaw(angle - math.pi/2) + angle = angle + (math.pi*2)/children_count + end + end +end + -- Slime local slime_big = { type = "monster", @@ -59,18 +94,7 @@ local slime_big = { jump_chance = 100, fear_height = 60, spawn_small_alternative = "mobs_mc:slime_small", - on_die = function(self, pos) - local angle, posadd - angle = math.random(0, math.pi*2) - for i=1,4 do - posadd = {x=math.cos(angle),y=0,z=math.sin(angle)} - posadd = vector.normalize(posadd) - local slime = minetest.add_entity(vector.add(pos, posadd), "mobs_mc:slime_small") - slime:setvelocity(vector.multiply(posadd, 1.5)) - slime:setyaw(angle-math.pi/2) - angle = angle + math.pi/2 - end - end, + on_die = spawn_children_on_die(self, pos, "mobs_mc:slime_small", 4, 1.0, 1.5) } mobs:register_mob("mobs_mc:slime_big", slime_big) @@ -85,18 +109,7 @@ slime_small.walk_velocity = 1.3 slime_small.run_velocity = 1.3 slime_small.jump_height = 4.3 slime_small.spawn_small_alternative = "mobs_mc:slime_tiny" -slime_small.on_die = function(self, pos) - local angle, posadd, dir - angle = math.random(0, math.pi*2) - for i=1,4 do - dir = {x=math.cos(angle),y=0,z=math.sin(angle)} - posadd = vector.multiply(vector.normalize(dir), 0.6) - local slime = minetest.add_entity(vector.add(pos, posadd), "mobs_mc:slime_tiny") - slime:setvelocity(dir) - slime:setyaw(angle-math.pi/2) - angle = angle + math.pi/2 - end -end +slime_small.on_die = spawn_children_on_die(self, pos, "mobs_mc:slime_tiny", 4, 0.6, 1.0) mobs:register_mob("mobs_mc:slime_small", slime_small) local slime_tiny = table.copy(slime_big) @@ -185,18 +198,7 @@ local magma_cube_big = { jump_chance = 100, fear_height = 100000, spawn_small_alternative = "mobs_mc:magma_cube_small", - on_die = function(self, pos) - local angle, posadd - angle = math.random(0, math.pi*2) - for i=1,3 do - posadd = {x=math.cos(angle),y=0,z=math.sin(angle)} - posadd = vector.normalize(posadd) - local mob = minetest.add_entity(vector.add(pos, posadd), "mobs_mc:magma_cube_small") - mob:setvelocity(vector.multiply(posadd, 1.5)) - mob:setyaw(angle-math.pi/2) - angle = angle + (math.pi*2) / 3 - end - end, + on_die = spawn_children_on_die(self, pos, "mobs_mc:magma_cube_small", 3, 0.8, 1.5) } mobs:register_mob("mobs_mc:magma_cube_big", magma_cube_big) @@ -216,18 +218,7 @@ magma_cube_small.damage = 4 magma_cube_small.reach = 2.75 magma_cube_small.armor = 70 magma_cube_small.spawn_small_alternative = "mobs_mc:magma_cube_tiny" -magma_cube_small.on_die = function(self, pos) - local angle, posadd, dir - angle = math.random(0, math.pi*2) - for i=1,4 do - dir = vector.normalize({x=math.cos(angle),y=0,z=math.sin(angle)}) - posadd = vector.multiply(dir, 0.6) - local mob = minetest.add_entity(vector.add(pos, posadd), "mobs_mc:magma_cube_tiny") - mob:setvelocity(dir) - mob:setyaw(angle-math.pi/2) - angle = angle + math.pi/2 - end -end +magma_cube_small.on_die = spawn_children_on_die(self, pos, "mobs_mc:magma_cube_tiny", 4, 0.6, 1.0) mobs:register_mob("mobs_mc:magma_cube_small", magma_cube_small) local magma_cube_tiny = table.copy(magma_cube_big) From 958989c80d8149a86c67d4ea2ddcd99ee70faf0c Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 20:49:34 +0100 Subject: [PATCH 013/865] If slime/mcube was killd, smaller m. att. attacker Previously, if you killed a big slime, the smaller slimes that spawn are neutral. --- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index c419ec67..5b031bbd 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -20,6 +20,7 @@ local spawn_children_on_die = function(self, pos, child_mob, children_count, spa end local mother_stuck = minetest.registered_nodes[minetest.get_node(pos).name].walkable angle = math.random(0, math.pi*2) + local children = {} for i=1,children_count do dir = {x=math.cos(angle),y=0,z=math.sin(angle)} posadd = vector.multiply(vector.normalize(dir), spawn_distance) @@ -34,8 +35,22 @@ local spawn_children_on_die = function(self, pos, child_mob, children_count, spa local mob = minetest.add_entity(newpos, child_mob) mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) mob:set_yaw(angle - math.pi/2) + table.insert(children, mob) angle = angle + (math.pi*2)/children_count end + -- If mother was murdered, children attack the killer after 1 second + if self.state == "attack" then + minetest.after(1.0, function(children, enemy) + for c=1, #children do + local child = children[c] + local le = child:get_luaentity() + if le ~= nil then + le.state = "attack" + le.attack = enemy + end + end + end, children, self.attack) + end end end From 3563b5448c18ba8125fcac66c792b45c4d988c8d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 21:02:36 +0100 Subject: [PATCH 014/865] Slime: Don't add speed if mother was stuck --- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 5b031bbd..b23a693f 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -33,7 +33,9 @@ local spawn_children_on_die = function(self, pos, child_mob, children_count, spa speed_penalty = 0.5 end local mob = minetest.add_entity(newpos, child_mob) - mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) + if (not mother_stuck) then + mob:set_velocity(vector.multiply(dir, eject_speed * speed_penalty)) + end mob:set_yaw(angle - math.pi/2) table.insert(children, mob) angle = angle + (math.pi*2)/children_count From 006850896862c3d737f467cfabdb3b2af469f758 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 21:11:37 +0100 Subject: [PATCH 015/865] Don't add weapon wear in Creative Mode --- mods/ENTITIES/mcl_mobs/api.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 9fddda4d..969d4f0c 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2383,12 +2383,13 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) if cancel then return end end - -- add weapon wear if tool_capabilities then punch_interval = tool_capabilities.full_punch_interval or 1.4 end - if weapon:get_definition() + -- add weapon wear + if minetest.settings:get_bool("creative_mode") ~= true + and weapon:get_definition() and weapon:get_definition().tool_capabilities then weapon:add_wear(floor((punch_interval / 75) * 9000)) From d9b6bae320b33a60d9fac462befd3af6116f1349 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 21:14:28 +0100 Subject: [PATCH 016/865] =?UTF-8?q?mcl=5Fhunger:=20core.*=20=E2=86=92=20mi?= =?UTF-8?q?netest.*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mods/PLAYER/mcl_hunger/hunger.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index 875d1be3..508b8b9f 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -1,6 +1,6 @@ -- wrapper for minetest.item_eat (this way we make sure other mods can't break this one) -local org_eat = core.do_item_eat -core.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing) +local org_eat = minetest.do_item_eat +minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing) -- Call on_rightclick if the pointed node defines it if pointed_thing.type == "node" then local node = minetest.get_node(pointed_thing.under) @@ -28,7 +28,7 @@ core.do_item_eat = function(hp_change, replace_with_item, itemstack, user, point -- Don't allow eating when player has full hunger bar (some exceptional items apply) if can_eat_when_full or (mcl_hunger.get_hunger(user) < 20) then itemstack = mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing) - for _, callback in pairs(core.registered_on_item_eats) do + for _, callback in pairs(minetest.registered_on_item_eats) do local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack) if result then return result @@ -63,7 +63,7 @@ function mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_t def = {} if type(hp_change) ~= "number" then hp_change = 1 - core.log("error", "Wrong on_use() definition for item '" .. item .. "'") + minetest.log("error", "Wrong on_use() definition for item '" .. item .. "'") end def.saturation = hp_change def.replace = replace_with_item From 9ed83bd1961260cf5b391cda8f702550804104ea Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 21:51:40 +0100 Subject: [PATCH 017/865] Drop food eating limits in Creative Mode --- mods/HELP/mcl_doc_basics/init.lua | 3 ++- mods/ITEMS/mcl_cake/init.lua | 6 +++--- mods/ITEMS/mcl_end/chorus_plant.lua | 2 +- mods/ITEMS/mcl_mobitems/init.lua | 2 +- mods/PLAYER/mcl_hunger/hunger.lua | 17 ++++++++++++----- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/mods/HELP/mcl_doc_basics/init.lua b/mods/HELP/mcl_doc_basics/init.lua index 3e367d6a..f4980bfe 100644 --- a/mods/HELP/mcl_doc_basics/init.lua +++ b/mods/HELP/mcl_doc_basics/init.lua @@ -770,8 +770,9 @@ S("• Creative inventory is available to obtain most items easily").."\n".. S("• Hand breaks all default blocks instantly").."\n".. S("• Greatly increased hand pointing range").."\n".. S("• Mined blocks don't drop items").."\n".. +S("• Items don't get used up").."\n".. S("• Tools don't wear off").."\n".. -S("• Bows have infinite arrows").."\n".. +S("• You can eat food whenever you want").."\n".. S("• You can always use the minimap").."\n\n".. S("Damage is not affected by Creative Mode, it needs to be disabled seperately.") diff --git a/mods/ITEMS/mcl_cake/init.lua b/mods/ITEMS/mcl_cake/init.lua index fdc11015..75542fb9 100644 --- a/mods/ITEMS/mcl_cake/init.lua +++ b/mods/ITEMS/mcl_cake/init.lua @@ -51,7 +51,7 @@ minetest.register_node("mcl_cake:cake", { on_rightclick = function(pos, node, clicker, itemstack) local newcake = minetest.do_item_eat(2, ItemStack("mcl_cake:cake_6"), ItemStack("mcl_cake:cake"), clicker, {type="nothing"}) -- Check if we were allowed to eat - if newcake:get_name() ~= "mcl_cake:cake" then + if newcake:get_name() ~= "mcl_cake:cake" or minetest.settings:get_bool("creative_mode") == true then minetest.add_node(pos,{type="node",name="mcl_cake:cake_6",param2=0}) end end, @@ -71,7 +71,7 @@ local register_slice = function(level, nodebox, desc) on_rightclick = function(pos, node, clicker, itemstack) local newcake = minetest.do_item_eat(2, ItemStack(after_eat), ItemStack(this), clicker, {type="nothing"}) -- Check if we were allowed to eat - if newcake:get_name() ~= this then + if newcake:get_name() ~= this or minetest.settings:get_bool("creative_mode") == true then minetest.add_node(pos,{type="node",name=after_eat,param2=0}) end end @@ -80,7 +80,7 @@ local register_slice = function(level, nodebox, desc) on_rightclick = function(pos, node, clicker, itemstack) local newcake = minetest.do_item_eat(2, ItemStack("mcl:cake:cake 0"), ItemStack("mcl_cake:cake_1"), clicker, {type="nothing"}) -- Check if we were allowed to eat - if newcake:get_name() ~= this then + if newcake:get_name() ~= this or minetest.settings:get_bool("creative_mode") == true then minetest.remove_node(pos) core.check_for_falling(pos) end diff --git a/mods/ITEMS/mcl_end/chorus_plant.lua b/mods/ITEMS/mcl_end/chorus_plant.lua index 882971f1..9793862e 100644 --- a/mods/ITEMS/mcl_end/chorus_plant.lua +++ b/mods/ITEMS/mcl_end/chorus_plant.lua @@ -339,7 +339,7 @@ local eat_chorus_fruit = function(itemstack, player, pointed_thing) local count = itemstack:get_count() local new_itemstack = minetest.do_item_eat(0, nil, itemstack, player, pointed_thing) local new_count = new_itemstack:get_count() - if count ~= new_count or new_itemstack:get_name() ~= "mcl_end:chorus_fruit" then + if count ~= new_count or new_itemstack:get_name() ~= "mcl_end:chorus_fruit" or (minetest.settings:get_bool("creative_mode") == true) then random_teleport(player) end return new_itemstack diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index d2c4f2b1..86fe54d1 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -135,7 +135,7 @@ minetest.register_craftitem("mcl_mobitems:cooked_rabbit", { local drink_milk = function(itemstack, player, pointed_thing) local bucket = minetest.do_item_eat(0, "mcl_buckets:bucket_empty", itemstack, player, pointed_thing) -- Check if we were allowed to drink this (eat delay check) - if bucket:get_name() ~= "mcl_mobitems:milk_bucket" and mcl_hunger.active then + if (bucket:get_name() ~= "mcl_mobitems:milk_bucket" and mcl_hunger.active) or minetest.settings:get_bool("creative_mode") == true then mcl_hunger.stop_poison(player) end return bucket diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index 508b8b9f..461c5f67 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -15,8 +15,10 @@ minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, p local name = user:get_player_name() + local creative = minetest.settings:get_bool("creative_mode") == true + -- Special foodstuffs like the cake may disable the eating delay - local no_eat_delay = minetest.get_item_group(itemstack:get_name(), "no_eat_delay") == 1 + local no_eat_delay = creative or (minetest.get_item_group(itemstack:get_name(), "no_eat_delay") == 1) -- Allow eating only after a delay of 2 seconds. This prevents eating as an excessive speed. -- FIXME: time() is not a precise timer, so the actual delay may be +- 1 second, depending on which fraction @@ -24,7 +26,7 @@ minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, p -- FIXME: In singleplayer, there's a cheat to circumvent this, simply by pausing the game between eats. -- This is because os.time() obviously does not care about the pause. A fix needs a different timer mechanism. if no_eat_delay or (mcl_hunger.last_eat[name] < 0) or (os.difftime(os.time(), mcl_hunger.last_eat[name]) >= 2) then - local can_eat_when_full = minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1 + local can_eat_when_full = creative or minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1 -- Don't allow eating when player has full hunger bar (some exceptional items apply) if can_eat_when_full or (mcl_hunger.get_hunger(user) < 20) then itemstack = mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing) @@ -136,8 +138,11 @@ local poisonrandomizer = PseudoRandom(os.time()) function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poison, exhaust, poisonchance, sound) return function(itemstack, user, pointed_thing) local itemname = itemstack:get_name() - - if itemstack:take_item() ~= nil and user ~= nil then + local creative = minetest.settings:get_bool("creative_mode") == true + if itemstack:peek_item() ~= nil and user ~= nil then + if not creative then + itemstack:take_item() + end local name = user:get_player_name() local hp = user:get_hp() @@ -242,7 +247,9 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso end --sound:eat - itemstack:add_item(replace_with_item) + if not creative then + itemstack:add_item(replace_with_item) + end end return itemstack end From 0876e76b40100dc67f536e2090f1dcf131868d38 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Feb 2019 22:05:56 +0100 Subject: [PATCH 018/865] Fix crash when using chorus fruit on cake --- mods/ITEMS/mcl_end/chorus_plant.lua | 2 +- mods/PLAYER/mcl_hunger/hunger.lua | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_end/chorus_plant.lua b/mods/ITEMS/mcl_end/chorus_plant.lua index 9793862e..41a91a47 100644 --- a/mods/ITEMS/mcl_end/chorus_plant.lua +++ b/mods/ITEMS/mcl_end/chorus_plant.lua @@ -333,7 +333,7 @@ local eat_chorus_fruit = function(itemstack, player, pointed_thing) local node_under = minetest.get_node(pointed_thing.under) -- Use pointed node's on_rightclick function first, if present if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then - return minetest.registered_nodes[node_under.name].on_rightclick(pointed_thing.under, node_under, placer, itemstack) or itemstack + return minetest.registered_nodes[node_under.name].on_rightclick(pointed_thing.under, node_under, player, itemstack) or itemstack end end local count = itemstack:get_count() diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index 461c5f67..fc200f00 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -1,6 +1,11 @@ -- wrapper for minetest.item_eat (this way we make sure other mods can't break this one) local org_eat = minetest.do_item_eat minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing) + + if not user or user:is_player() == false then + return itemstack + end + -- Call on_rightclick if the pointed node defines it if pointed_thing.type == "node" then local node = minetest.get_node(pointed_thing.under) From 6ff637ec69fae824f869dc7af97b257d65a7ecdf Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 02:02:18 +0100 Subject: [PATCH 019/865] Add more igloo generation code --- mods/MAPGEN/mcl_structures/init.lua | 124 +++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 93889604..9beb588f 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -59,18 +59,138 @@ mcl_structures.generate_desert_well = function(pos) return minetest.place_schematic(newpos, path, "0", nil, true) end +mcl_structures.generate_igloo = function(pos) + -- TODO: Check if we're allowed to destroy nodes + -- FIXME: Some nodes (water, ice) don't get overwritten by ladder + -- FIXME: Nodes at Y=0 don't get overwritten by ladder + -- TODO: Check if basement generation would not be too obvious + -- TODO: Generate basement with 50% chance only + local success, rotation = mcl_structures.generate_igloo_top(pos) + if success then + local buffer = pos.y - (mcl_vars.mg_bedrock_overworld_max + 1) + if buffer <= 19 then + return + end + local depth = math.random(19, buffer) + local bpos = {x=pos.x, y=pos.y-depth, z=pos.z} + -- trapdoor position + local tpos + local dir, tdir + if rotation == "0" then + dir = {x=-1, y=0, z=0} + tdir = {x=1, y=0, z=0} + tpos = {x=pos.x+7, y=pos.y-1, z=pos.z+3} + elseif rotation == "90" then + dir = {x=0, y=0, z=-1} + tdir = {x=0, y=0, z=-1} + tpos = {x=pos.x+3, y=pos.y-1, z=pos.z+1} + elseif rotation == "180" then + dir = {x=1, y=0, z=0} + tdir = {x=-1, y=0, z=0} + tpos = {x=pos.x+1, y=pos.y-1, z=pos.z+3} + elseif rotation == "270" then + dir = {x=0, y=0, z=1} + tdir = {x=0, y=0, z=1} + tpos = {x=pos.x+3, y=pos.y-1, z=pos.z+7} + else + return success + end + -- TODO: more reliable param2 + minetest.set_node(tpos, {name="mcl_doors:trapdoor", param2=20+minetest.dir_to_facedir(dir)}) + local set_brick = function(pos) + local c = math.random(1, 3) -- cracked chance + local m = math.random(1, 10) -- chance for monster egg + local brick + if m == 1 then + if c == 1 then + brick = "mcl_monster_eggs:monster_egg_stonebrickcracked" + else + brick = "mcl_monster_eggs:monster_egg_stonebrick" + end + else + if c == 1 then + brick = "mcl_core:stonebrickcracked" + else + brick = "mcl_core:stonebrick" + end + end + minetest.set_node(pos, {name=brick}) + end + local ladder_param2 = minetest.dir_to_wallmounted(tdir) + for y=1, depth-5 do + set_brick({x=tpos.x-1,y=tpos.y-y,z=tpos.z }) + set_brick({x=tpos.x+1,y=tpos.y-y,z=tpos.z }) + set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z-1}) + set_brick({x=tpos.x ,y=tpos.y-y,z=tpos.z+1}) + minetest.set_node({x=tpos.x,y=tpos.y-y,z=tpos.z}, {name="mcl_core:ladder", param2=ladder_param2}) + end + mcl_structures.generate_igloo_basement(bpos, rotation) + end + return success +end + mcl_structures.generate_igloo_top = function(pos) -- FIXME: This spawns bookshelf instead of furnace. Fix this! -- Furnace does ot work atm because apparently meta is not set. :-( local newpos = {x=pos.x,y=pos.y-1,z=pos.z} local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_top.mts" - return minetest.place_schematic(newpos, path, "random", nil, true) + local rotation = tostring(math.random(0,3)*90) + return minetest.place_schematic(newpos, path, rotation, nil, true), rotation end mcl_structures.generate_igloo_basement = function(pos, orientation) -- TODO: Add brewing stand + -- TODO: Spawn villager and zombie villager local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_basement.mts" - return minetest.place_schematic(pos, path, orientation, nil, true) + + local success = minetest.place_schematic(pos, path, orientation, nil, true) + if success then + local chest_offset + if orientation == "0" then + chest_offset = {x=5, y=1, z=5} + elseif orientation == "90" then + chest_offset = {x=5, y=1, z=3} + elseif orientation == "180" then + chest_offset = {x=3, y=1, z=1} + elseif orientation == "270" then + chest_offset = {x=1, y=1, z=5} + else + return success + end + -- FIXME: Use better seeding + local pr = PseudoRandom(math.random(0, 4294967295)) + local size = {x=9,y=5,z=7} + local lootitems = mcl_loot.get_multi_loot({ + { + stacks_min = 1, + stacks_max = 1, + items = { + { itemstring = "mcl_core:apple_gold", weight = 1 }, + } + }, + { + stacks_min = 2, + stacks_max = 8, + items = { + { itemstring = "mcl_core:coal_lump", weight = 15, amount_min = 1, amount_max = 4 }, + { itemstring = "mcl_core:apple", weight = 15, amount_min = 1, amount_max = 3 }, + { itemstring = "mcl_farming:wheat_item", weight = 10, amount_min = 2, amount_max = 3 }, + { itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 3 }, + { itemstring = "mcl_mobitems:rotten_flesh", weight = 10 }, + { itemstring = "mcl_tools:axe_stone", weight = 2 }, + { itemstring = "mcl_core:emerald", weight = 1 }, + } + }}, pr) + + local chest_pos = vector.add(pos, chest_offset) + local meta = minetest.get_meta(chest_pos) + local inv = meta:get_inventory() + inv:set_size("main", 9*3) + for i=1, #lootitems do + inv:add_item("main", lootitems[i]) + end + end + return success end mcl_structures.generate_boulder = function(pos) From 9105f248b40417169e695951e30526a9f5d2ca2e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 02:23:51 +0100 Subject: [PATCH 020/865] More secure igloo generation --- mods/MAPGEN/mcl_structures/init.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 9beb588f..552691bf 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -63,11 +63,12 @@ mcl_structures.generate_igloo = function(pos) -- TODO: Check if we're allowed to destroy nodes -- FIXME: Some nodes (water, ice) don't get overwritten by ladder -- FIXME: Nodes at Y=0 don't get overwritten by ladder + -- FIXME: Apply basement height limit in other dimensions -- TODO: Check if basement generation would not be too obvious -- TODO: Generate basement with 50% chance only local success, rotation = mcl_structures.generate_igloo_top(pos) if success then - local buffer = pos.y - (mcl_vars.mg_bedrock_overworld_max + 1) + local buffer = pos.y - (mcl_vars.mg_lava_overworld_max + 10) if buffer <= 19 then return end @@ -140,6 +141,7 @@ end mcl_structures.generate_igloo_basement = function(pos, orientation) -- TODO: Add brewing stand + -- TODO: Add monster eggs -- TODO: Spawn villager and zombie villager local path = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_basement.mts" From da625b569ac26f6d09bd3e9458913bb96d1f8651 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 03:00:45 +0100 Subject: [PATCH 021/865] Spawn minecarts in railcorridor chests --- mods/MAPGEN/tsm_railcorridors/gameconfig.lua | 9 +++++++++ mods/MAPGEN/tsm_railcorridors/init.lua | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mods/MAPGEN/tsm_railcorridors/gameconfig.lua b/mods/MAPGEN/tsm_railcorridors/gameconfig.lua index df86f587..b0c255ba 100644 --- a/mods/MAPGEN/tsm_railcorridors/gameconfig.lua +++ b/mods/MAPGEN/tsm_railcorridors/gameconfig.lua @@ -98,6 +98,15 @@ function tsm_railcorridors.get_treasures(pr) { itemstring = "mcl_minecarts:detector_rail", weight = 5, amount_min = 1, amount_max = 4 }, { itemstring = "mcl_minecarts:golden_rail", weight = 5, amount_min = 1, amount_max = 4 }, } + }, + -- non-MC loot: 50% chance to add a minecart, offered as alternative to spawning minecarts on rails. + -- TODO: Remove this when minecarts spawn on rails. + { + stacks_min = 0, + stacks_max = 1, + items = { + { itemstring = "mcl_minecarts:minecart", weight = 1 }, + } } } diff --git a/mods/MAPGEN/tsm_railcorridors/init.lua b/mods/MAPGEN/tsm_railcorridors/init.lua index 358b6521..57c18379 100644 --- a/mods/MAPGEN/tsm_railcorridors/init.lua +++ b/mods/MAPGEN/tsm_railcorridors/init.lua @@ -68,7 +68,8 @@ end -- Probability for every part of a corridor to contain a cart -- Disabled because cart spawning creates error message spam: -- “m_static_exists=true but static data doesn't actually exist in (x,y,z) --- TODO: Set back to 0.05 if this is fixedd. +-- TODO: Set back to 0.05 when this is fixed. +-- TODO: Remove minecarts from loot table when minecarts spawn on rails. local probability_cart = P(0) --[[ setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_cart")) From 62159b0aa02bc804a96b09ad458d8fe592175d96 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 04:32:20 +0100 Subject: [PATCH 022/865] Core mapgen: Extend some stuff to emin,emax --- mods/MAPGEN/mcl_mapgen_core/init.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 2266e886..02645d0c 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -1736,8 +1736,8 @@ minetest.register_on_generated(function(minp, maxp, seed) -- Big lava seas by replacing air below a certain height if mcl_vars.mg_lava then - lvm_used = set_layers(c_lava, c_air, mcl_vars.mg_overworld_min, mcl_vars.mg_lava_overworld_max, minp, maxp, lvm_used) - lvm_used = set_layers(c_nether_lava, c_air, mcl_vars.mg_nether_min, mcl_vars.mg_lava_nether_max, minp, maxp, lvm_used) + lvm_used = set_layers(c_lava, c_air, mcl_vars.mg_overworld_min, mcl_vars.mg_lava_overworld_max, emin, emax, lvm_used) + lvm_used = set_layers(c_nether_lava, c_air, mcl_vars.mg_nether_min, mcl_vars.mg_lava_nether_max, emin, emax, lvm_used) end -- Clay, vines, cocoas @@ -1797,12 +1797,12 @@ minetest.register_on_generated(function(minp, maxp, seed) -- Nether block fixes: -- * Replace water with Nether lava. -- * Replace stone, sand dirt in v6 so the Nether works in v6. - elseif minp.y <= mcl_vars.mg_nether_max and maxp.y >= mcl_vars.mg_nether_min then + elseif emin.y <= mcl_vars.mg_nether_max and emax.y >= mcl_vars.mg_nether_min then local nodes if mg_name == "v6" then - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) + nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) else - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source"}) + nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source"}) end for n=1, #nodes do local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z) @@ -1822,12 +1822,12 @@ minetest.register_on_generated(function(minp, maxp, seed) -- * Replace water with end stone or air (depending on height). -- * Remove stone, sand, dirt in v6 so our End map generator works in v6. -- * Generate spawn platform (End portal destination) - elseif minp.y <= mcl_vars.mg_end_max and maxp.y >= mcl_vars.mg_end_min then + elseif emin.y <= mcl_vars.mg_end_max and emax.y >= mcl_vars.mg_end_min then local nodes if mg_name == "v6" then - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) + nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) else - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source"}) + nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source"}) end for n=1, #nodes do local y = nodes[n].y From b6c21ee841bcae712c7f4ba2954b0c1c31842a97 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 08:08:51 +0100 Subject: [PATCH 023/865] Make in-water color less opaque --- mods/ITEMS/mcl_core/nodes_liquid.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_core/nodes_liquid.lua b/mods/ITEMS/mcl_core/nodes_liquid.lua index 40de3aeb..7d738690 100644 --- a/mods/ITEMS/mcl_core/nodes_liquid.lua +++ b/mods/ITEMS/mcl_core/nodes_liquid.lua @@ -37,7 +37,7 @@ minetest.register_node("mcl_core:water_flowing", { liquid_alternative_source = "mcl_core:water_source", liquid_viscosity = WATER_VISC, liquid_range = 7, - post_effect_color = {a=240, r=0x03, g=0x3C, b=0x5C}, + post_effect_color = {a=209, r=0x03, g=0x3C, b=0x5C}, groups = { water=3, liquid=3, puts_out_fire=1, not_in_creative_inventory=1, freezes=1, melt_around=1, dig_by_piston=1}, _mcl_blast_resistance = 500, -- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode @@ -80,7 +80,7 @@ Water interacts with lava in various ways: liquid_alternative_source = "mcl_core:water_source", liquid_viscosity = WATER_VISC, liquid_range = 7, - post_effect_color = {a=240, r=0x03, g=0x3C, b=0x5C}, + post_effect_color = {a=209, r=0x03, g=0x3C, b=0x5C}, stack_max = 64, groups = { water=3, liquid=3, puts_out_fire=1, freezes=1, not_in_creative_inventory=1, dig_by_piston=1}, _mcl_blast_resistance = 500, From d4fe313077b1deb73975d440f51512fba4290ce4 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 08:26:52 +0100 Subject: [PATCH 024/865] Mobs: Fix line-of-sight handling (thanks, chon!) --- mods/ENTITIES/mcl_mobs/api.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 969d4f0c..b508b23a 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -256,8 +256,7 @@ local line_of_sight = function(self, pos1, pos2, stepsize) -- It continues to advance in the line of sight in search of a real -- obstruction which counts as 'normal' nodebox. while minetest.registered_nodes[nn] - and (minetest.registered_nodes[nn].walkable == false - or minetest.registered_nodes[nn].drawtype == "nodebox") do + and minetest.registered_nodes[nn].walkable == false do -- Check if you can still move forward if td < ad + stepsize then From 37b9b6fbfc18ffeb2c2b871aa610461aac8daa9b Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 08:51:09 +0100 Subject: [PATCH 025/865] If mob jumped against wall 4 times, turn around --- mods/ENTITIES/mcl_mobs/api.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index b508b23a..3f1eeeb0 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -805,6 +805,22 @@ local do_jump = function(self) self.facing_fence = true end + -- if we jumped against a block/wall 4 times then turn + if self.object:get_velocity().x ~= 0 + and self.object:get_velocity().z ~= 0 then + + self.jump_count = (self.jump_count or 0) + 1 + + if self.jump_count == 4 then + + local yaw = self.object:get_yaw() or 0 + + yaw = set_yaw(self, yaw + 1.35, 8) + + self.jump_count = 0 + end + end + return true end From 66c99efb2ff0d70a74fc12bfaa6fc636eb447c7f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 10:57:23 +0100 Subject: [PATCH 026/865] Hide "useless" items from creative and craft guide --- mods/ENTITIES/mobs_mc/ghast.lua | 5 ++++- mods/ENTITIES/mobs_mc/rabbit.lua | 3 ++- mods/HUD/mcl_inventory/creative.lua | 26 ++++++++++++++++---------- mods/ITEMS/mcl_mobitems/init.lua | 19 +++++++++++-------- mods/ITEMS/mcl_potions/init.lua | 22 ++++++++++++++-------- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 5cb0080f..26912f43 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -43,7 +43,10 @@ mobs:register_mob("mobs_mc:ghast", { chance = 1, min = 0, max = 2,}, - {name = mobs_mc.items.ghast_tear, + -- TODO: drop tear when it's useful + -- ghast tear replaced with gunpowder + --{name = mobs_mc.items.ghast_tear, + {name = mobs_mc.items.gunpowder, chance = 1, min = 0, max = 1,}, diff --git a/mods/ENTITIES/mobs_mc/rabbit.lua b/mods/ENTITIES/mobs_mc/rabbit.lua index d0a8d849..a92c93f9 100644 --- a/mods/ENTITIES/mobs_mc/rabbit.lua +++ b/mods/ENTITIES/mobs_mc/rabbit.lua @@ -34,7 +34,8 @@ local rabbit = { drops = { {name = mobs_mc.items.rabbit_raw, chance = 1, min = 0, max = 1}, {name = mobs_mc.items.rabbit_hide, chance = 1, min = 0, max = 1}, - {name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, max = 1}, + -- TODO: Drop rabbit's foot when it's useful + --{name = mobs_mc.items.rabbit_foot, chance = 10, min = 1, max = 1}, }, water_damage = 1, lava_damage = 4, diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index aa38dbd6..65c977df 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -4,8 +4,10 @@ local players = {} -- Containing all the items for each Creative Mode tab local inventory_lists = {} +-- TODO: Brewing is disabled. Add brewing (uncommented code) when it is implemented properly + -- Create tables -local builtin_filter_ids = {"blocks","deco","redstone","rail","food","tools","combat","brew","matr","misc","all"} +local builtin_filter_ids = {"blocks","deco","redstone","rail","food","tools","combat",--[["brew",]]"matr","misc","all"} for _, f in pairs(builtin_filter_ids) do inventory_lists[f] = {} end @@ -55,10 +57,11 @@ do table.insert(inventory_lists["combat"], name) nonmisc = true end - if def.groups.brewitem then - table.insert(inventory_lists["brew"], name) - nonmisc = true - end + -- TODO: add brew + --if def.groups.brewitem then + --table.insert(inventory_lists["brew"], name) + --nonmisc = true + --end if def.groups.craftitem then table.insert(inventory_lists["matr"], name) nonmisc = true @@ -178,7 +181,7 @@ noffset_y = 8.12 next_noffset("food") next_noffset("tools") next_noffset("combat") -next_noffset("brew") +--next_noffset("brew") -- TODO: add brew next_noffset("matr") next_noffset("inv", true) @@ -197,7 +200,7 @@ hoch["default"] = "" hoch["food"] = "^[transformfy" hoch["tools"] = "^[transformfy" hoch["combat"] = "^[transformfy" -hoch["brew"] = "^[transformfy" +--hoch["brew"] = "^[transformfy" -- TODO: add brew hoch["matr"] = "^[transformfy" hoch["inv"] = "^[transformfy" @@ -213,7 +216,7 @@ local function reset_menu_item_bg() bg["food"] = dark_bg bg["tools"] = dark_bg bg["combat"] = dark_bg - bg["brew"] = dark_bg + --bg["brew"] = dark_bg -- TODO: add brew bg["matr"] = dark_bg bg["inv"] = dark_bg bg["default"] = dark_bg @@ -380,8 +383,9 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz "tooltip[tools;Tools]".. tab(name, "combat") .. "tooltip[combat;Combat]".. - tab(name, "brew") .. - "tooltip[brew;Brewing]".. + -- TODO: Add brew + --tab(name, "brew") .. + --"tooltip[brew;Brewing]".. tab(name, "matr") .. "tooltip[matr;Materials]".. tab(name, "inv") .. @@ -450,10 +454,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if players[name].page == "combat" then return end set_inv_page("combat",player) page = "combat" + --[[ TODO: add brew elseif fields.brew then if players[name].page == "brew" then return end set_inv_page("brew",player) page = "brew" + ]] elseif fields.matr then if players[name].page == "matr" then return end set_inv_page("matr",player) diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 86fe54d1..0bb5ea9c 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -198,7 +198,7 @@ minetest.register_craftitem("mcl_mobitems:blaze_powder", { _doc_items_longdesc = "This item is mainly used for crafting.", wield_image = "mcl_mobitems_blaze_powder.png", inventory_image = "mcl_mobitems_blaze_powder.png", - groups = { brewitem = 1 }, + groups = { craftitem = 1, brewitem = 1 }, stack_max = 64, }) @@ -207,25 +207,27 @@ minetest.register_craftitem("mcl_mobitems:magma_cream", { _doc_items_longdesc = "Magma cream is a crafting component.", wield_image = "mcl_mobitems_magma_cream.png", inventory_image = "mcl_mobitems_magma_cream.png", - groups = { brewitem = 1 }, + groups = { craftitem = 1, brewitem = 1 }, stack_max = 64, }) minetest.register_craftitem("mcl_mobitems:ghast_tear", { description = "Ghast Tear", - _doc_items_longdesc = "A ghast tear is dropped from dead ghasts. It has no purpose yet.", + _doc_items_longdesc = "Place this item in an item frame as decoration.", wield_image = "mcl_mobitems_ghast_tear.png", inventory_image = "mcl_mobitems_ghast_tear.png", - groups = { brewitem = 1 }, + -- TODO: Reveal item when it's useful + groups = { brewitem = 1, not_in_creative_inventory = 1 }, stack_max = 64, }) minetest.register_craftitem("mcl_mobitems:nether_star", { description = "Nether Star", - _doc_items_longdesc = "A nether star is a crafting component. It is dropped from the Wither.", + _doc_items_longdesc = "A nether star is dropped when the Wither dies. Place it in an item frame to show the world how hardcore you are! Or just as decoration.", wield_image = "mcl_mobitems_nether_star.png", inventory_image = "mcl_mobitems_nether_star.png", - groups = { craftitem = 1 }, + -- TODO: Reveal item when it's useful + groups = { craftitem = 1, not_in_creative_inventory = 1 }, stack_max = 64, }) @@ -258,10 +260,11 @@ minetest.register_craftitem("mcl_mobitems:rabbit_hide", { minetest.register_craftitem("mcl_mobitems:rabbit_foot", { description = "Rabbit's Foot", - _doc_items_longdesc = "This item currently has no purpose.", + _doc_items_longdesc = "Must be your lucky day! Place this item in an item frame for decoration.", wield_image = "mcl_mobitems_rabbit_foot.png", inventory_image = "mcl_mobitems_rabbit_foot.png", - groups = { brewitem = 1 }, + -- TODO: Reveal item when it's useful + groups = { brewitem = 1, not_in_creative_inventory = 1 }, stack_max = 64, }) diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 277267b0..fa4349c0 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -1,11 +1,12 @@ -local brewhelp = "This item currently has no purpose." +local brewhelp = "Put this item in an item frame for decoration. It's useless otherwise." minetest.register_craftitem("mcl_potions:fermented_spider_eye", { description = "Fermented Spider Eye", _doc_items_longdesc = brewhelp, wield_image = "mcl_potions_spider_eye_fermented.png", inventory_image = "mcl_potions_spider_eye_fermented.png", - groups = { brewitem = 1 }, + -- TODO: Reveal item when it's actually useful + groups = { brewitem = 1, not_in_creative_inventory = 1, not_in_craft_guide = 1 }, stack_max = 64, }) @@ -218,7 +219,8 @@ minetest.register_craftitem("mcl_potions:potion_awkward", { stack_max = 1, inventory_image = potion_image("#0000FF"), wield_image = potion_image("#0000FF"), - groups = {brewitem=1, food=3, can_eat_when_full=1}, + -- TODO: Reveal item when it's actually useful + groups = {brewitem=1, food=3, can_eat_when_full=1, not_in_creative_inventory=1}, on_place = minetest.item_eat(0, "mcl_potions:glass_bottle"), on_secondary_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), }) @@ -229,7 +231,8 @@ minetest.register_craftitem("mcl_potions:potion_mundane", { stack_max = 1, inventory_image = potion_image("#0000FF"), wield_image = potion_image("#0000FF"), - groups = {brewitem=1, food=3, can_eat_when_full=1}, + -- TODO: Reveal item when it's actually useful + groups = {brewitem=1, food=3, can_eat_when_full=1, not_in_creative_inventory=1 }, on_place = minetest.item_eat(0, "mcl_potions:glass_bottle"), on_secondary_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), }) @@ -240,16 +243,18 @@ minetest.register_craftitem("mcl_potions:potion_thick", { stack_max = 1, inventory_image = potion_image("#0000FF"), wield_image = potion_image("#0000FF"), - groups = {brewitem=1, food=3, can_eat_when_full=1}, + -- TODO: Reveal item when it's actually useful + groups = {brewitem=1, food=3, can_eat_when_full=1, not_in_creative_inventory=1 }, on_place = minetest.item_eat(0, "mcl_potions:glass_bottle"), on_secondary_use = minetest.item_eat(0, "mcl_potions:glass_bottle"), }) minetest.register_craftitem("mcl_potions:speckled_melon", { description = "Glistering Melon", - _doc_items_longdesc = brewhelp, + _doc_items_longdesc = "This shiny melon is full of tiny gold nuggets and would be nice in an item frame. It isn't edible and not useful for anything else.", stack_max = 64, - groups = { brewitem = 1 }, + -- TODO: Reveal item when it's actually useful + groups = { brewitem = 1, not_in_creative_inventory = 1, not_in_craft_guide = 1 }, inventory_image = "mcl_potions_melon_speckled.png", }) @@ -267,6 +272,7 @@ minetest.register_craftitem("mcl_potions:dragon_breath", { _doc_items_longdesc = brewhelp, wield_image = "mcl_potions_dragon_breath.png", inventory_image = "mcl_potions_dragon_breath.png", - groups = { brewitem = 1 }, + -- TODO: Reveal item when it's actually useful + groups = { brewitem = 1, not_in_creative_inventory = 1 }, stack_max = 64, }) From 27fa2c2e664cebd2e1e5445613b68d9d6c4a9a8d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 11:15:53 +0100 Subject: [PATCH 027/865] Clean up item categorization in creative inv. --- mods/ITEMS/REDSTONE/mesecons_wires/init.lua | 2 +- mods/ITEMS/mcl_beds/api.lua | 4 ++-- mods/ITEMS/mcl_core/nodes_cactuscane.lua | 2 +- mods/ITEMS/mcl_maps/init.lua | 1 + mods/ITEMS/mcl_mobitems/init.lua | 1 + mods/ITEMS/mcl_throwing/init.lua | 1 + 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_wires/init.lua b/mods/ITEMS/REDSTONE/mesecons_wires/init.lua index c66d04a5..01bf6bbb 100644 --- a/mods/ITEMS/REDSTONE/mesecons_wires/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_wires/init.lua @@ -195,7 +195,7 @@ local function register_wires() local groups_on = {dig_immediate = 3, mesecon_conductor_craftable = 1, not_in_creative_inventory = 1, attached_node = 1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1} local groups_off = {dig_immediate = 3, mesecon_conductor_craftable = 1, - attached_node = 1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1} + attached_node = 1, dig_by_water = 1,destroy_by_lava_flow=1, dig_by_piston = 1, craftitem = 1} if nodeid ~= "00000000" then groups_off["not_in_creative_inventory"] = 1 end diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 407aea97..074d847d 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -63,7 +63,7 @@ function mcl_beds.register_bed(name, def) paramtype2 = "facedir", is_ground_content = false, stack_max = 1, - groups = {handy=1, flammable = 3, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50}, + groups = {handy=1, flammable = 3, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1}, _mcl_hardness = 0.2, _mcl_blast_resistance = 1, sounds = def.sounds or default_sounds, @@ -184,7 +184,7 @@ function mcl_beds.register_bed(name, def) paramtype2 = "facedir", is_ground_content = false, -- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks! - groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50}, + groups = {handy = 1, flammable = 3, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1}, _mcl_hardness = 0.2, _mcl_blast_resistance = 1, sounds = def.sounds or default_sounds, diff --git a/mods/ITEMS/mcl_core/nodes_cactuscane.lua b/mods/ITEMS/mcl_core/nodes_cactuscane.lua index 9b87ae6f..d0c00654 100644 --- a/mods/ITEMS/mcl_core/nodes_cactuscane.lua +++ b/mods/ITEMS/mcl_core/nodes_cactuscane.lua @@ -71,7 +71,7 @@ minetest.register_node("mcl_core:reeds", { }, }, stack_max = 64, - groups = {dig_immediate=3, craftitem=1, plant=1, non_mycelium_plant=1, dig_by_piston=1}, + groups = {dig_immediate=3, craftitem=1, deco_block=1, plant=1, non_mycelium_plant=1, dig_by_piston=1}, sounds = mcl_sounds.node_sound_leaves_defaults(), node_placement_prediction = "", on_place = mcl_util.generate_on_place_plant_function(function(place_pos, place_node) diff --git a/mods/ITEMS/mcl_maps/init.lua b/mods/ITEMS/mcl_maps/init.lua index 300e1d35..2c7037bf 100644 --- a/mods/ITEMS/mcl_maps/init.lua +++ b/mods/ITEMS/mcl_maps/init.lua @@ -34,6 +34,7 @@ minetest.register_craftitem("mcl_maps:filled_map", { description = "Map", _doc_items_longdesc = "Maps show your surroundings as you explore the world. They can even show you the world like a radar. MAGIC!\nNote: Maps are subject to change in future versions of MineClone 2.", _doc_items_usagehelp = "Hold the map in any of the hotbar slots. This allows you to access the minimap by pressing the minimap key ([F9] by default).\nIn Creative Mode, you don't need this item; the minimap is always available.", + groups = { tool = 1 }, inventory_image = "mcl_maps_map_filled.png^(mcl_maps_map_filled_markings.png^[colorize:#000000)", stack_max = 1, }) diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 0bb5ea9c..29259d5d 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -274,6 +274,7 @@ minetest.register_craftitem("mcl_mobitems:saddle", { _doc_items_usagehelp = "Rightclick an animal (with the saddle in your hand) to try put on the saddle. Saddles fit on horses, mules, donkeys and pigs. Horses, mules and donkeys need to be tamed first, otherwise they'll reject the saddle. Saddled animals can be mounted by rightclicking them again.", wield_image = "mcl_mobitems_saddle.png", inventory_image = "mcl_mobitems_saddle.png", + groups = { transport = 1 }, stack_max = 1, }) diff --git a/mods/ITEMS/mcl_throwing/init.lua b/mods/ITEMS/mcl_throwing/init.lua index 731e9ce8..cd0356b7 100644 --- a/mods/ITEMS/mcl_throwing/init.lua +++ b/mods/ITEMS/mcl_throwing/init.lua @@ -295,6 +295,7 @@ minetest.register_craftitem("mcl_throwing:snowball", { _doc_items_usagehelp = how_to_throw, inventory_image = "mcl_throwing_snowball.png", stack_max = 16, + groups = { weapon_ranged = 1 }, on_use = throw_function("mcl_throwing:snowball_entity"), _on_dispense = dispense_function, }) From 069f3591e250173564e293ea1c47e91d49c213d7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 11:31:04 +0100 Subject: [PATCH 028/865] Add mobs page in creative inventory --- mods/HUD/mcl_inventory/creative.lua | 16 +++++++++++++++- .../textures/mcl_inventory_fnt_mobs.png | Bin 0 -> 158 bytes 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 mods/HUD/mcl_inventory/textures/mcl_inventory_fnt_mobs.png diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index 65c977df..7125dcb6 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -7,7 +7,7 @@ local inventory_lists = {} -- TODO: Brewing is disabled. Add brewing (uncommented code) when it is implemented properly -- Create tables -local builtin_filter_ids = {"blocks","deco","redstone","rail","food","tools","combat",--[["brew",]]"matr","misc","all"} +local builtin_filter_ids = {"blocks","deco","redstone","rail","food","tools","combat","mobs",--[["brew",]]"matr","misc","all"} for _, f in pairs(builtin_filter_ids) do inventory_lists[f] = {} end @@ -57,6 +57,10 @@ do table.insert(inventory_lists["combat"], name) nonmisc = true end + if def.groups.spawn_egg == 1 then + table.insert(inventory_lists["mobs"], name) + nonmisc = true + end -- TODO: add brew --if def.groups.brewitem then --table.insert(inventory_lists["brew"], name) @@ -181,6 +185,7 @@ noffset_y = 8.12 next_noffset("food") next_noffset("tools") next_noffset("combat") +next_noffset("mobs") --next_noffset("brew") -- TODO: add brew next_noffset("matr") next_noffset("inv", true) @@ -200,6 +205,7 @@ hoch["default"] = "" hoch["food"] = "^[transformfy" hoch["tools"] = "^[transformfy" hoch["combat"] = "^[transformfy" +hoch["mobs"] = "^[transformfy" --hoch["brew"] = "^[transformfy" -- TODO: add brew hoch["matr"] = "^[transformfy" hoch["inv"] = "^[transformfy" @@ -216,6 +222,7 @@ local function reset_menu_item_bg() bg["food"] = dark_bg bg["tools"] = dark_bg bg["combat"] = dark_bg + bg["mobs"] = dark_bg --bg["brew"] = dark_bg -- TODO: add brew bg["matr"] = dark_bg bg["inv"] = dark_bg @@ -337,6 +344,7 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz food = "mcl_core:apple", tools = "mcl_core:axe_iron", combat = "mcl_core:sword_gold", + mobs = "mobs_mc:cow", brew = "mcl_potions:potion_water", matr = "mcl_core:stick", inv = "mcl_chests:chest", @@ -383,6 +391,8 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz "tooltip[tools;Tools]".. tab(name, "combat") .. "tooltip[combat;Combat]".. + tab(name, "mobs") .. + "tooltip[mobs;Mobs]".. -- TODO: Add brew --tab(name, "brew") .. --"tooltip[brew;Brewing]".. @@ -454,6 +464,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if players[name].page == "combat" then return end set_inv_page("combat",player) page = "combat" + elseif fields.mobs then + if players[name].page == "mobs" then return end + set_inv_page("mobs",player) + page = "mobs" --[[ TODO: add brew elseif fields.brew then if players[name].page == "brew" then return end diff --git a/mods/HUD/mcl_inventory/textures/mcl_inventory_fnt_mobs.png b/mods/HUD/mcl_inventory/textures/mcl_inventory_fnt_mobs.png new file mode 100644 index 0000000000000000000000000000000000000000..26308b6163c30b129c7c81cd56531138db75cbf1 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0y~yU~Fe#U@&K7W?*2rn=A5%fq{W7z$e7@MVpzSp&{EI zF9!w&2F8*gzhDN3XE)Lq7#Q3cArulW>tT_k62660iBWG*yE|JNs3rji{RkH6b4`Yo<$JA3Lv$1N46=?n}E N44$rjF6*2UngHfYGxGod literal 0 HcmV?d00001 From 3976c7c4b921e4a2ca6823b1410f80061d23372d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 11:40:51 +0100 Subject: [PATCH 029/865] Add doors and trapdoors to decoration blocks --- mods/ITEMS/mcl_doors/api_doors.lua | 2 +- mods/ITEMS/mcl_doors/api_trapdoors.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_doors/api_doors.lua b/mods/ITEMS/mcl_doors/api_doors.lua index f17e85c8..e3e88279 100644 --- a/mods/ITEMS/mcl_doors/api_doors.lua +++ b/mods/ITEMS/mcl_doors/api_doors.lua @@ -90,7 +90,7 @@ function mcl_doors:register_door(name, def) _doc_items_usagehelp = usagehelp, inventory_image = def.inventory_image, stack_max = 64, - groups = { mesecon_conductor_craftable = 1 }, + groups = { mesecon_conductor_craftable = 1, deco_block = 1 }, on_place = function(itemstack, placer, pointed_thing) if not pointed_thing.type == "node" or not placer or not placer:is_player() then return itemstack diff --git a/mods/ITEMS/mcl_doors/api_trapdoors.lua b/mods/ITEMS/mcl_doors/api_trapdoors.lua index 89a4bef5..9e69a552 100644 --- a/mods/ITEMS/mcl_doors/api_trapdoors.lua +++ b/mods/ITEMS/mcl_doors/api_trapdoors.lua @@ -89,6 +89,7 @@ function mcl_doors:register_trapdoor(name, def) local groups_closed = groups groups_closed.trapdoor = 1 + groups_closed.deco_block = 1 minetest.register_node(name, { description = def.description, _doc_items_longdesc = longdesc, @@ -158,6 +159,7 @@ function mcl_doors:register_trapdoor(name, def) } groups_open.trapdoor = 2 + groups_open.not_in_creative_inventory = 1 minetest.register_node(name.."_open", { drawtype = "nodebox", tiles = tiles_open, From 371bc0cb7631c997423fabf00037add675e1fc0a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 12:04:58 +0100 Subject: [PATCH 030/865] Creative categories: book, chorusfruit, endpearl --- mods/ITEMS/mcl_books/init.lua | 2 +- mods/ITEMS/mcl_end/chorus_plant.lua | 2 +- mods/ITEMS/mcl_throwing/init.lua | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_books/init.lua b/mods/ITEMS/mcl_books/init.lua index 29ae2a02..de96e9e3 100644 --- a/mods/ITEMS/mcl_books/init.lua +++ b/mods/ITEMS/mcl_books/init.lua @@ -4,7 +4,7 @@ minetest.register_craftitem("mcl_books:book", { _doc_items_longdesc = "Books are used to make bookshelves and book and quills.", inventory_image = "default_book.png", stack_max = 64, - groups = { book=1 }, + groups = { book=1, craftitem = 1 }, }) if minetest.get_modpath("mcl_core") and minetest.get_modpath("mcl_mobitems") then diff --git a/mods/ITEMS/mcl_end/chorus_plant.lua b/mods/ITEMS/mcl_end/chorus_plant.lua index 41a91a47..58832b42 100644 --- a/mods/ITEMS/mcl_end/chorus_plant.lua +++ b/mods/ITEMS/mcl_end/chorus_plant.lua @@ -352,7 +352,7 @@ minetest.register_craftitem("mcl_end:chorus_fruit", { inventory_image = "mcl_end_chorus_fruit.png", on_place = eat_chorus_fruit, on_secondary_use = eat_chorus_fruit, - groups = { food = 2, eatable = 4, can_eat_when_full = 1 }, + groups = { food = 2, transport = 1, eatable = 4, can_eat_when_full = 1 }, _mcl_saturation = 2.4, stack_max = 64, }) diff --git a/mods/ITEMS/mcl_throwing/init.lua b/mods/ITEMS/mcl_throwing/init.lua index cd0356b7..ee0b4fcb 100644 --- a/mods/ITEMS/mcl_throwing/init.lua +++ b/mods/ITEMS/mcl_throwing/init.lua @@ -321,5 +321,6 @@ minetest.register_craftitem("mcl_throwing:ender_pearl", { inventory_image = "mcl_throwing_ender_pearl.png", stack_max = 16, on_use = throw_function("mcl_throwing:ender_pearl_entity"), + groups = { transport = 1 }, }) From 93c86207d9f336cf0459435565baae126fae845e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 20:04:45 +0100 Subject: [PATCH 031/865] Fix crash when using milk if damage is disabled --- mods/ITEMS/mcl_mobitems/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 29259d5d..c070c8a8 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -135,7 +135,7 @@ minetest.register_craftitem("mcl_mobitems:cooked_rabbit", { local drink_milk = function(itemstack, player, pointed_thing) local bucket = minetest.do_item_eat(0, "mcl_buckets:bucket_empty", itemstack, player, pointed_thing) -- Check if we were allowed to drink this (eat delay check) - if (bucket:get_name() ~= "mcl_mobitems:milk_bucket" and mcl_hunger.active) or minetest.settings:get_bool("creative_mode") == true then + if mcl_hunger.active and (bucket:get_name() ~= "mcl_mobitems:milk_bucket" or minetest.settings:get_bool("creative_mode") == true) then mcl_hunger.stop_poison(player) end return bucket From 4bd9be22e01dd1010fb5920b9fcc5717d843fe1f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 21:23:05 +0100 Subject: [PATCH 032/865] Apply eat effect when hunger disabled --- mods/PLAYER/mcl_hunger/API.md | 39 +++++- mods/PLAYER/mcl_hunger/api.lua | 148 ++++++++++++++++++++++ mods/PLAYER/mcl_hunger/hunger.lua | 75 ++++------- mods/PLAYER/mcl_hunger/init.lua | 131 +++++-------------- mods/PLAYER/mcl_hunger/register_foods.lua | 11 ++ mods/PLAYER/mcl_playerinfo/depends.txt | 1 - 6 files changed, 247 insertions(+), 158 deletions(-) create mode 100644 mods/PLAYER/mcl_hunger/api.lua create mode 100644 mods/PLAYER/mcl_hunger/register_foods.lua diff --git a/mods/PLAYER/mcl_hunger/API.md b/mods/PLAYER/mcl_hunger/API.md index eb7710fc..3daa6351 100644 --- a/mods/PLAYER/mcl_hunger/API.md +++ b/mods/PLAYER/mcl_hunger/API.md @@ -1,19 +1,35 @@ # API information (WIP) -This API information is WIP. The mod API is still pretty much unofficial; -this mod is mostly seen as standalone for now. +This API information is not complete yet. +The mod API is still pretty much unofficial; this mod is mostly seen +as standalone for now. + This may change in the future development of MineClone 2. Hopefully. -## Before using this mod -This mod is a no-op when the game is started with damage disabled. -Before using any of the functions, first check if global variable -“`mcl_hunger`” is present. +## Mod state +The hunger mechanic is disabled when damage is disabled +(setting `enable_damage=false`). +You can check the hunger state with `mcl_hunger.active`. If it's true, +then hunger is active. -## Hunger level +If the hunger is disabled, most of the functions are no-ops or return +default values. + +## Player values +### Hunger level The hunger level of the player is a whole number between 0 and 20 inclusive. 0 is starving and 20 is full. The hunger level is represented in the HUD by a statbar with 20 half-icons. +### Saturation +To be written ... + +### Exhaustion +To be written ... + ## Functions +This API documentation is not complete yet, more documentation will +come. + ### `mcl_hunger.get_hunger(player)` Returns the current hunger level of `player` (ObjectRef). @@ -21,6 +37,15 @@ Returns the current hunger level of `player` (ObjectRef). Sets the hunger level of `player` (ObjectRef) to `hunger` immediately. `hunger` ***must*** be between 0 and 20 inclusive. +### `mcl_hunger.exhaust(player, exhaust)` +Increase exhaustion of player by `exhaust`. + +### `mcl_hunger.stop_poison(player)` +Immediately stops all poisonings for player. + +### More functions ... +There are more functions (of less importance) available, see `api.lua`. + ## Groups Items in group `food=3` will make a drinking sound and no particles. Items in group `food` with any other rating will make an eating sound and particles, diff --git a/mods/PLAYER/mcl_hunger/api.lua b/mods/PLAYER/mcl_hunger/api.lua new file mode 100644 index 00000000..04c384f9 --- /dev/null +++ b/mods/PLAYER/mcl_hunger/api.lua @@ -0,0 +1,148 @@ +mcl_hunger.registered_foods = {} + +if mcl_hunger.active then + function mcl_hunger.get_hunger(player) + local hunger = player:get_attribute("mcl_hunger:hunger") or 20 + return tonumber(hunger) + end + + function mcl_hunger.get_saturation(player) + local saturation = player:get_attribute("mcl_hunger:saturation") or mcl_hunger.SATURATION_INIT + return tonumber(saturation) + end + + function mcl_hunger.get_exhaustion(player) + local exhaustion = player:get_attribute("mcl_hunger:exhaustion") or 0 + return tonumber(exhaustion) + end + + function mcl_hunger.set_hunger(player, hunger, update_hudbars) + hunger = math.min(20, math.max(0, hunger)) + player:set_attribute("mcl_hunger:hunger", tostring(hunger)) + if update_hudbars ~= false then + hb.change_hudbar(player, "hunger", hunger) + mcl_hunger.update_saturation_hud(player, nil, hunger) + end + return true + end + + function mcl_hunger.set_saturation(player, saturation, update_hudbar) + saturation = math.min(mcl_hunger.get_hunger(player), math.max(0, saturation)) + player:set_attribute("mcl_hunger:saturation", tostring(saturation)) + if update_hudbar ~= false then + mcl_hunger.update_saturation_hud(player, saturation) + end + return true + end + + function mcl_hunger.set_exhaustion(player, exhaustion, update_hudbar) + exhaustion = math.min(mcl_hunger.EXHAUST_LVL, math.max(0.0, exhaustion)) + player:set_attribute("mcl_hunger:exhaustion", tostring(exhaustion)) + if update_hudbar ~= false then + mcl_hunger.update_exhaustion_hud(player, exhaustion) + end + return true + end + + function mcl_hunger.exhaust(playername, increase) + local player = minetest.get_player_by_name(playername) + if not player then return false end + mcl_hunger.set_exhaustion(player, mcl_hunger.get_exhaustion(player) + increase) + if mcl_hunger.get_exhaustion(player) >= mcl_hunger.EXHAUST_LVL then + mcl_hunger.set_exhaustion(player, 0.0) + local h = nil + local satuchanged = false + local s = mcl_hunger.get_saturation(player) + if s > 0 then + mcl_hunger.set_saturation(player, math.max(s - 1.0, 0)) + satuchanged = true + elseif s <= 0.0001 then + h = mcl_hunger.get_hunger(player) + h = math.max(h-1, 0) + mcl_hunger.set_hunger(player, h) + satuchanged = true + end + if satuchanged then + if h ~= nil then h = h end + mcl_hunger.update_saturation_hud(player, mcl_hunger.get_saturation(player), h) + end + end + mcl_hunger.update_exhaustion_hud(player, mcl_hunger.get_exhaustion(player)) + return true + end + + function mcl_hunger.saturate(playername, increase, update_hudbar) + local player = minetest.get_player_by_name(playername) + local ok = mcl_hunger.set_saturation(player, math.min(mcl_hunger.get_saturation(player) + increase, mcl_hunger.get_hunger(player))) + if update_hudbar ~= false then + mcl_hunger.update_saturation_hud(player, mcl_hunger.get_saturation(player), mcl_hunger.get_hunger(player)) + end + return ok + end + + function mcl_hunger.register_food(name, hunger_change, replace_with_item, poisontime, poison, exhaust, poisonchance, sound) + if not mcl_hunger.active then + return + end + local food = mcl_hunger.registered_foods + food[name] = {} + food[name].saturation = hunger_change -- hunger points added + food[name].replace = replace_with_item -- what item is given back after eating + food[name].poisontime = poisontime -- time it is poisoning. If this is set, this item is considered poisonous, + -- otherwise the following poison/exhaust fields are ignored + food[name].poison = poison -- poison damage per tick for poisonous food + food[name].exhaust = exhaust -- exhaustion per tick for poisonous food + food[name].poisonchance = poisonchance -- chance percentage that this item poisons the player (default: 100% if poisoning is enabled) + food[name].sound = sound -- special sound that is played when eating + end + + function mcl_hunger.stop_poison(player) + if not mcl_hunger.active then + return + end + mcl_hunger.poison_damage[player:get_player_name()] = 0 + mcl_hunger.poison_hunger[player:get_player_name()] = 0 + mcl_hunger.reset_bars_poison_damage(player) + mcl_hunger.reset_bars_poison_hunger(player) + end + +else + -- When hunger is disabled, the functions are basically no-ops + + function mcl_hunger.get_hunger() + return 20 + end + + function mcl_hunger.get_saturation() + return mcl_hunger.SATURATION_INIT + end + + function mcl_hunger.get_exhaustion() + return 0 + end + + function mcl_hunger.set_hunger() + return false + end + + function mcl_hunger.set_saturation() + return false + end + + function mcl_hunger.set_exhaustion() + return false + end + + function mcl_hunger.exhaust() + return false + end + + function mcl_hunger.saturate() + return false + end + + function mcl_hunger.register_food() end + + function mcl_hunger.stop_poison() end + +end diff --git a/mods/PLAYER/mcl_hunger/hunger.lua b/mods/PLAYER/mcl_hunger/hunger.lua index fc200f00..939aeed9 100644 --- a/mods/PLAYER/mcl_hunger/hunger.lua +++ b/mods/PLAYER/mcl_hunger/hunger.lua @@ -31,7 +31,7 @@ minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, p -- FIXME: In singleplayer, there's a cheat to circumvent this, simply by pausing the game between eats. -- This is because os.time() obviously does not care about the pause. A fix needs a different timer mechanism. if no_eat_delay or (mcl_hunger.last_eat[name] < 0) or (os.difftime(os.time(), mcl_hunger.last_eat[name]) >= 2) then - local can_eat_when_full = creative or minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1 + local can_eat_when_full = creative or (mcl_hunger.active == false) or minetest.get_item_group(itemstack:get_name(), "can_eat_when_full") == 1 -- Don't allow eating when player has full hunger bar (some exceptional items apply) if can_eat_when_full or (mcl_hunger.get_hunger(user) < 20) then itemstack = mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing) @@ -48,24 +48,9 @@ minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, p return itemstack end --- food functions -local food = {} - -function mcl_hunger.register_food(name, hunger_change, replace_with_item, poisontime, poison, exhaust, poisonchance, sound) - food[name] = {} - food[name].saturation = hunger_change -- hunger points added - food[name].replace = replace_with_item -- what item is given back after eating - food[name].poisontime = poisontime -- time it is poisoning. If this is set, this item is considered poisonous, - -- otherwise the following poison/exhaust fields are ignored - food[name].poison = poison -- poison damage per tick for poisonous food - food[name].exhaust = exhaust -- exhaustion per tick for poisonous food - food[name].poisonchance = poisonchance -- chance percentage that this item poisons the player (default: 100% if poisoning is enabled) - food[name].sound = sound -- special sound that is played when eating -end - function mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing) local item = itemstack:get_name() - local def = food[item] + local def = mcl_hunger.registered_foods[item] if not def then def = {} if type(hp_change) ~= "number" then @@ -80,11 +65,11 @@ function mcl_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_t end -- Reset HUD bars after poisoning -local function reset_bars_poison_damage(player) +function mcl_hunger.reset_bars_poison_damage(player) hb.change_hudbar(player, "health", nil, nil, "hudbars_icon_health.png", nil, "hudbars_bar_health.png") end -local function reset_bars_poison_hunger(player) +function mcl_hunger.reset_bars_poison_hunger(player) hb.change_hudbar(player, "hunger", nil, nil, "hbhunger_icon.png", nil, "hbhunger_bar.png") if mcl_hunger.debug then hb.change_hudbar(player, "exhaustion", nil, nil, nil, nil, "mcl_hunger_bar_exhaustion.png") @@ -93,6 +78,9 @@ end -- Poison player local function poisonp(tick, time, time_left, damage, exhaustion, name) + if not mcl_hunger.active then + return + end local player = minetest.get_player_by_name(name) -- First check if player is still there if not player then @@ -114,10 +102,10 @@ local function poisonp(tick, time, time_left, damage, exhaustion, name) mcl_hunger.poison_hunger [name] = mcl_hunger.poison_hunger[name] - 1 end if mcl_hunger.poison_damage[name] <= 0 then - reset_bars_poison_damage(player) + mcl_hunger.reset_bars_poison_damage(player) end if mcl_hunger.poison_hunger[name] <= 0 then - reset_bars_poison_hunger(player) + mcl_hunger.reset_bars_poison_hunger(player) end end @@ -130,14 +118,6 @@ local function poisonp(tick, time, time_left, damage, exhaustion, name) end --- Immediately stop all poisonings for this player -function mcl_hunger.stop_poison(player) - mcl_hunger.poison_damage[player:get_player_name()] = 0 - mcl_hunger.poison_hunger[player:get_player_name()] = 0 - reset_bars_poison_damage(player) - reset_bars_poison_hunger(player) -end - local poisonrandomizer = PseudoRandom(os.time()) function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poison, exhaust, poisonchance, sound) @@ -202,7 +182,7 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso }) end - if hunger_change then + if mcl_hunger.active and hunger_change then -- Add saturation (must be defined in item table) local _mcl_saturation = minetest.registered_items[itemname]._mcl_saturation local saturation @@ -225,7 +205,7 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso mcl_hunger.update_saturation_hud(user, mcl_hunger.get_saturation(user), h) end -- Poison - if poisontime then + if mcl_hunger.active and poisontime then local do_poison = false if poisonchance then if poisonrandomizer:next(0,100) < poisonchance then @@ -251,7 +231,6 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso end end - --sound:eat if not creative then itemstack:add_item(replace_with_item) end @@ -260,24 +239,16 @@ function mcl_hunger.item_eat(hunger_change, replace_with_item, poisontime, poiso end end --- player-action based hunger changes -minetest.register_on_dignode(function(pos, oldnode, player) - -- is_fake_player comes from the pipeworks, we are not interested in those - if not player or not player:is_player() or player.is_fake_player == true then - return - end - local name = player:get_player_name() - -- dig event - mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_DIG) -end) +if mcl_hunger.active then + -- player-action based hunger changes + minetest.register_on_dignode(function(pos, oldnode, player) + -- is_fake_player comes from the pipeworks, we are not interested in those + if not player or not player:is_player() or player.is_fake_player == true then + return + end + local name = player:get_player_name() + -- dig event + mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_DIG) + end) +end --- Apply simple poison effect as long there are no real status effect --- TODO: Remove this when status effects are in place - -mcl_hunger.register_food("mcl_farming:potato_item_poison", 2, "", 4, 1, 0, 60) - -mcl_hunger.register_food("mcl_mobitems:rotten_flesh", 4, "", 30, 0, 100, 80) -mcl_hunger.register_food("mcl_mobitems:chicken", 2, "", 30, 0, 100, 30) -mcl_hunger.register_food("mcl_mobitems:spider_eye", 2, "", 4, 1, 0) - -mcl_hunger.register_food("mcl_fishing:pufferfish_raw", 1, "", 60, 1, 300) diff --git a/mods/PLAYER/mcl_hunger/init.lua b/mods/PLAYER/mcl_hunger/init.lua index 6fa973f7..f71dc121 100644 --- a/mods/PLAYER/mcl_hunger/init.lua +++ b/mods/PLAYER/mcl_hunger/init.lua @@ -8,13 +8,17 @@ end mcl_hunger = {} --- This variable tells you if the hunger gameplay mechanic is active. --- IMPORTANT: If damage is disabled on load time, most of the functions are NOT --- available! Check if mcl_hunger is active before using the API. -mcl_hunger.active = false - - -mcl_hunger.exhaust = function() end +--[[ This variable tells you if the hunger gameplay mechanic is active. +The state of the hunger mechanic will be determined at game start. +Hunger is enabled when damage is enabled. +If the damage setting is changed within the game, this does NOT +update the hunger mechanic, so the game must be restarted for this +to take effect. ]] +if minetest.settings:get_bool("enable_damage") == true then + mcl_hunger.active = true +else + mcl_hunger.active = false +end mcl_hunger.HUD_TICK = 0.1 @@ -31,11 +35,22 @@ mcl_hunger.EXHAUST_LVL = 4000 -- at what exhaustion player saturation gets lower mcl_hunger.SATURATION_INIT = 5 -- Initial saturation for new/respawning players -if minetest.settings:get_bool("enable_damage") then -mcl_hunger.active = true - -- Debug Mode. If enabled, saturation and exhaustion are shown as well. --- NOTE: Read-only. The setting should only be read at the beginning, this mod is not +-- NOTE: Only updated when settings are loaded. +mcl_hunger.debug = false + +-- Cooldown timers for each player, to force a short delay between consuming 2 food items +mcl_hunger.last_eat = {} + +dofile(minetest.get_modpath("mcl_hunger").."/api.lua") +dofile(minetest.get_modpath("mcl_hunger").."/hunger.lua") +dofile(minetest.get_modpath("mcl_hunger").."/register_foods.lua") + +--[[ IF HUNGER IS ENABLED ]] +if mcl_hunger.active == true then + +-- Read debug mode setting +-- The setting should only be read at the beginning, this mod is not -- prepared to change this setting later. mcl_hunger.debug = minetest.settings:get_bool("mcl_hunger_debug") if mcl_hunger.debug == nil then @@ -56,9 +71,6 @@ end mcl_hunger.poison_damage = {} -- damaging poison mcl_hunger.poison_hunger = {} -- food poisoning, increasing hunger --- Cooldown timers for each player, to force a short delay between consuming 2 food items -mcl_hunger.last_eat = {} - -- HUD item ids local hunger_hud = {} @@ -82,8 +94,6 @@ function mcl_hunger.update_exhaustion_hud(player, exhaustion) end end -dofile(minetest.get_modpath("mcl_hunger").."/hunger.lua") - -- register saturation hudbar hb.register_hudbar("hunger", 0xFFFFFF, S("Food"), { icon = "hbhunger_icon.png", bgicon = "hbhunger_bgicon.png", bar = "hbhunger_bar.png" }, 20, 20, false) if mcl_hunger.debug then @@ -91,53 +101,6 @@ if mcl_hunger.debug then hb.register_hudbar("exhaustion", 0xFFFFFF, S("Exhaust."), { icon = "mcl_hunger_icon_exhaustion.png", bgicon = "mcl_hunger_bgicon_exhaustion.png", bar = "mcl_hunger_bar_exhaustion.png" }, 0, mcl_hunger.EXHAUST_LVL, false, S("%s: %d/%d")) end --- API START -- -mcl_hunger.get_hunger = function(player) - local hunger = player:get_attribute("mcl_hunger:hunger") or 20 - return tonumber(hunger) -end - -mcl_hunger.get_saturation = function(player) - local saturation = player:get_attribute("mcl_hunger:saturation") or mcl_hunger.SATURATION_INIT - return tonumber(saturation) -end - -mcl_hunger.get_exhaustion = function(player) - local exhaustion = player:get_attribute("mcl_hunger:exhaustion") or 0 - return tonumber(exhaustion) -end - -mcl_hunger.set_hunger = function(player, hunger, update_hudbars) - hunger = math.min(20, math.max(0, hunger)) - player:set_attribute("mcl_hunger:hunger", tostring(hunger)) - if update_hudbars ~= false then - hb.change_hudbar(player, "hunger", hunger) - mcl_hunger.update_saturation_hud(player, nil, hunger) - end - return true -end - -mcl_hunger.set_saturation = function(player, saturation, update_hudbar) - saturation = math.min(mcl_hunger.get_hunger(player), math.max(0, saturation)) - player:set_attribute("mcl_hunger:saturation", tostring(saturation)) - if update_hudbar ~= false then - mcl_hunger.update_saturation_hud(player, saturation) - end - return true -end - -mcl_hunger.set_exhaustion = function(player, exhaustion, update_hudbar) - exhaustion = math.min(mcl_hunger.EXHAUST_LVL, math.max(0.0, exhaustion)) - player:set_attribute("mcl_hunger:exhaustion", tostring(exhaustion)) - if update_hudbar ~= false then - mcl_hunger.update_exhaustion_hud(player, exhaustion) - end - return true -end - - - --- END OF API -- minetest.register_on_newplayer(function(player) local name = player:get_player_name() mcl_hunger.set_hunger(player, 20, false) @@ -177,41 +140,6 @@ minetest.register_on_punchplayer(function(victim, puncher, time_from_last_punch, end end) -function mcl_hunger.exhaust(playername, increase) - local player = minetest.get_player_by_name(playername) - if not player then return false end - mcl_hunger.set_exhaustion(player, mcl_hunger.get_exhaustion(player) + increase) - if mcl_hunger.get_exhaustion(player) >= mcl_hunger.EXHAUST_LVL then - mcl_hunger.set_exhaustion(player, 0.0) - local h = nil - local satuchanged = false - local s = mcl_hunger.get_saturation(player) - if s > 0 then - mcl_hunger.set_saturation(player, math.max(s - 1.0, 0)) - satuchanged = true - elseif s <= 0.0001 then - h = mcl_hunger.get_hunger(player) - h = math.max(h-1, 0) - mcl_hunger.set_hunger(player, h) - satuchanged = true - end - if satuchanged then - if h ~= nil then h = h end - mcl_hunger.update_saturation_hud(player, mcl_hunger.get_saturation(player), h) - end - end - mcl_hunger.update_exhaustion_hud(player, mcl_hunger.get_exhaustion(player)) - return true -end - -function mcl_hunger.saturate(playername, increase, update_hudbar) - local player = minetest.get_player_by_name(playername) - mcl_hunger.set_saturation(player, math.min(mcl_hunger.get_saturation(player) + increase, mcl_hunger.get_hunger(player))) - if update_hudbar ~= false then - mcl_hunger.update_saturation_hud(player, mcl_hunger.get_saturation(player), mcl_hunger.get_hunger(player)) - end -end - local main_timer = 0 local timer = 0 -- Half second timer local timerMult = 1 -- Cycles from 0 to 7, each time when timer hits half a second @@ -255,4 +183,11 @@ minetest.register_globalstep(function(dtime) end end) +--[[ IF HUNGER IS NOT ENABLED ]] +else + +minetest.register_on_joinplayer(function(player) + mcl_hunger.last_eat[player:get_player_name()] = -1 +end) + end diff --git a/mods/PLAYER/mcl_hunger/register_foods.lua b/mods/PLAYER/mcl_hunger/register_foods.lua new file mode 100644 index 00000000..449c1c4f --- /dev/null +++ b/mods/PLAYER/mcl_hunger/register_foods.lua @@ -0,0 +1,11 @@ +-- Apply simple poison effect as long there are no real status effect +-- TODO: Remove this when status effects are in place +-- TODO: Consider moving these to the respective mods + +mcl_hunger.register_food("mcl_farming:potato_item_poison", 2, "", 4, 1, 0, 60) + +mcl_hunger.register_food("mcl_mobitems:rotten_flesh", 4, "", 30, 0, 100, 80) +mcl_hunger.register_food("mcl_mobitems:chicken", 2, "", 30, 0, 100, 30) +mcl_hunger.register_food("mcl_mobitems:spider_eye", 2, "", 4, 1, 0) + +mcl_hunger.register_food("mcl_fishing:pufferfish_raw", 1, "", 60, 1, 300) diff --git a/mods/PLAYER/mcl_playerinfo/depends.txt b/mods/PLAYER/mcl_playerinfo/depends.txt index 29155726..3fb37201 100644 --- a/mods/PLAYER/mcl_playerinfo/depends.txt +++ b/mods/PLAYER/mcl_playerinfo/depends.txt @@ -1,6 +1,5 @@ mcl_init mcl_core mcl_particles -mcl_hunger mcl_death_messages 3d_armor? From d59d789c80950d60d3a1ace79b8aecf6caefc74e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Feb 2019 21:56:52 +0100 Subject: [PATCH 033/865] Put boat/minecart in inv when punched in creative --- mods/ENTITIES/mcl_boats/init.lua | 5 +++++ mods/ENTITIES/mcl_minecarts/init.lua | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index c347efb0..a583a078 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -132,6 +132,11 @@ function boat.on_punch(self, puncher) -- Drop boat as item on the ground after punching if not minetest.settings:get_bool("creative_mode") then minetest.add_item(self.object:get_pos(), self._itemstring) + else + local inv = puncher:get_inventory() + if not inv:contains_item("main", self._itemstring) then + inv:add_item("main", self._itemstring) + end end self.object:remove() end diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index e5afcedf..6454c3ed 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -85,6 +85,13 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick) for d=1, #drop do minetest.add_item(self.object:get_pos(), drop[d]) end + elseif puncher and puncher:is_player() then + local inv = puncher:get_inventory() + for d=1, #drop do + if not inv:contains_item("main", drop[d]) then + inv:add_item("main", drop[d]) + end + end end self.object:remove() From 77709c80761fff42b1339295dfad2e23ffb4570f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 06:35:32 +0100 Subject: [PATCH 034/865] Disable fish achievement --- mods/HUD/mcl_achievements/init.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/HUD/mcl_achievements/init.lua b/mods/HUD/mcl_achievements/init.lua index 83665270..fed23ee3 100644 --- a/mods/HUD/mcl_achievements/init.lua +++ b/mods/HUD/mcl_achievements/init.lua @@ -137,11 +137,14 @@ awards.register_achievement("mcl:acquireIron", { description = S("Take an iron ingot from a furnace's output slot.\nHint: To smelt an iron ingot, put a fuel (like coal) and iron ore into a furnace."), icon = "default_steel_ingot.png", }) +--[[ +-- TODO: Re-enable when fishing rod is available awards.register_achievement("mcl:cookFish", { title = S("Delicious Fish"), description = S("Take a cooked fish from a furnace.\nHint: Use a fishing rod to catch a fish and cook it in a furnace."), icon = "mcl_fishing_fish_cooked.png", }) +]] -- Other achievements triggered outside of mcl_achievements From cfdcd63f3c8662d92be0bf1882a4ba2a3d962c69 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 07:10:10 +0100 Subject: [PATCH 035/865] Change dye texture names of "special" dyes --- mods/ITEMS/mcl_dye/init.lua | 49 +++++++++--------- .../{dye_black.png => mcl_dye_black.png} | Bin .../{dye_blue.png => mcl_dye_blue.png} | Bin .../{dye_brown.png => mcl_dye_brown.png} | Bin ...e_lightblue.png => mcl_dye_light_blue.png} | Bin .../{dye_green.png => mcl_dye_lime.png} | Bin .../{dye_white.png => mcl_dye_white.png} | Bin tools/Conversion_Table.csv | 12 ++--- 8 files changed, 31 insertions(+), 30 deletions(-) rename mods/ITEMS/mcl_dye/textures/{dye_black.png => mcl_dye_black.png} (100%) rename mods/ITEMS/mcl_dye/textures/{dye_blue.png => mcl_dye_blue.png} (100%) rename mods/ITEMS/mcl_dye/textures/{dye_brown.png => mcl_dye_brown.png} (100%) rename mods/ITEMS/mcl_dye/textures/{dye_lightblue.png => mcl_dye_light_blue.png} (100%) rename mods/ITEMS/mcl_dye/textures/{dye_green.png => mcl_dye_lime.png} (100%) rename mods/ITEMS/mcl_dye/textures/{dye_white.png => mcl_dye_white.png} (100%) diff --git a/mods/ITEMS/mcl_dye/init.lua b/mods/ITEMS/mcl_dye/init.lua index 5d0f871e..f95aa874 100644 --- a/mods/ITEMS/mcl_dye/init.lua +++ b/mods/ITEMS/mcl_dye/init.lua @@ -64,27 +64,27 @@ local dyelocal = {} -- This collection of colors is partly a historic thing, partly something else. dyelocal.dyes = { - {"white", "Bone Meal", {dye=1, craftitem=1, basecolor_white=1, excolor_white=1, unicolor_white=1}}, - {"grey", "Light Grey Dye", {dye=1, craftitem=1, basecolor_grey=1, excolor_grey=1, unicolor_grey=1}}, - {"dark_grey", "Grey Dye", {dye=1, craftitem=1, basecolor_grey=1, excolor_darkgrey=1, unicolor_darkgrey=1}}, - {"black", "Ink Sac", {dye=1, craftitem=1, basecolor_black=1, excolor_black=1, unicolor_black=1}}, - {"violet", "Purple Dye", {dye=1, craftitem=1, basecolor_magenta=1, excolor_violet=1, unicolor_violet=1}}, - {"blue", "Lapis Lazuli", {dye=1, craftitem=1, basecolor_blue=1, excolor_blue=1, unicolor_blue=1}}, - {"lightblue", "Light Blue Dye", {dye=1, craftitem=1, basecolor_blue=1, excolor_blue=1, unicolor_light_blue=1}}, - {"cyan", "Cyan Dye", {dye=1, craftitem=1, basecolor_cyan=1, excolor_cyan=1, unicolor_cyan=1}}, - {"dark_green", "Cactus Green",{dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_dark_green=1}}, - {"green", "Lime Dye", {dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_green=1}}, - {"yellow", "Dandelion Yellow", {dye=1, craftitem=1, basecolor_yellow=1, excolor_yellow=1, unicolor_yellow=1}}, - {"brown", "Cocoa Beans", {dye=1, craftitem=1, basecolor_brown=1, excolor_orange=1, unicolor_dark_orange=1}}, - {"orange", "Orange Dye", {dye=1, craftitem=1, basecolor_orange=1, excolor_orange=1, unicolor_orange=1}}, - {"red", "Rose Red", {dye=1, craftitem=1, basecolor_red=1, excolor_red=1, unicolor_red=1}}, - {"magenta", "Magenta Dye", {dye=1, craftitem=1, basecolor_magenta=1, excolor_red_violet=1,unicolor_red_violet=1}}, - {"pink", "Pink Dye", {dye=1, craftitem=1, basecolor_red=1, excolor_red=1, unicolor_light_red=1}}, + {"white", "mcl_dye_white", "Bone Meal", {dye=1, craftitem=1, basecolor_white=1, excolor_white=1, unicolor_white=1}}, + {"grey", "dye_grey", "Light Grey Dye", {dye=1, craftitem=1, basecolor_grey=1, excolor_grey=1, unicolor_grey=1}}, + {"dark_grey", "dye_dark_grey", "Grey Dye", {dye=1, craftitem=1, basecolor_grey=1, excolor_darkgrey=1, unicolor_darkgrey=1}}, + {"black", "mcl_dye_black", "Ink Sac", {dye=1, craftitem=1, basecolor_black=1, excolor_black=1, unicolor_black=1}}, + {"violet", "dye_violet", "Purple Dye", {dye=1, craftitem=1, basecolor_magenta=1, excolor_violet=1, unicolor_violet=1}}, + {"blue", "mcl_dye_blue", "Lapis Lazuli", {dye=1, craftitem=1, basecolor_blue=1, excolor_blue=1, unicolor_blue=1}}, + {"lightblue", "mcl_dye_light_blue", "Light Blue Dye", {dye=1, craftitem=1, basecolor_blue=1, excolor_blue=1, unicolor_light_blue=1}}, + {"cyan", "dye_cyan", "Cyan Dye", {dye=1, craftitem=1, basecolor_cyan=1, excolor_cyan=1, unicolor_cyan=1}}, + {"dark_green", "dye_dark_green", "Cactus Green",{dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_dark_green=1}}, + {"green", "mcl_dye_lime", "Lime Dye", {dye=1, craftitem=1, basecolor_green=1, excolor_green=1, unicolor_green=1}}, + {"yellow", "dye_yellow", "Dandelion Yellow", {dye=1, craftitem=1, basecolor_yellow=1, excolor_yellow=1, unicolor_yellow=1}}, + {"brown", "mcl_dye_brown", "Cocoa Beans", {dye=1, craftitem=1, basecolor_brown=1, excolor_orange=1, unicolor_dark_orange=1}}, + {"orange", "dye_orange", "Orange Dye", {dye=1, craftitem=1, basecolor_orange=1, excolor_orange=1, unicolor_orange=1}}, + {"red", "dye_red", "Rose Red", {dye=1, craftitem=1, basecolor_red=1, excolor_red=1, unicolor_red=1}}, + {"magenta", "dye_magenta", "Magenta Dye", {dye=1, craftitem=1, basecolor_magenta=1, excolor_red_violet=1,unicolor_red_violet=1}}, + {"pink", "dye_pink", "Pink Dye", {dye=1, craftitem=1, basecolor_red=1, excolor_red=1, unicolor_light_red=1}}, } dyelocal.unicolor_to_dye_id = {} for d=1, #dyelocal.dyes do - for k, _ in pairs(dyelocal.dyes[d][3]) do + for k, _ in pairs(dyelocal.dyes[d][4]) do if string.sub(k, 1, 9) == "unicolor_" then dyelocal.unicolor_to_dye_id[k] = dyelocal.dyes[d][1] end @@ -101,10 +101,11 @@ for _, row in ipairs(dyelocal.dyes) do local name = row[1] -- White and brown dyes are defined explicitly below if name ~= "white" and name ~= "brown" then - local description = row[2] - local groups = row[3] + local img = row[2] + local description = row[3] + local groups = row[4] local item_name = "mcl_dye:"..name - local item_image = "dye_"..name..".png" + local item_image = img..".png" minetest.register_craftitem(item_name, { inventory_image = item_image, description = description, @@ -293,12 +294,12 @@ mcl_dye.apply_bone_meal = function(pointed_thing) end minetest.register_craftitem("mcl_dye:white", { - inventory_image = "dye_white.png", + inventory_image = "mcl_dye_white.png", description = "Bone Meal", _doc_items_longdesc = "Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.", _doc_items_usagehelp = "Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.", stack_max = 64, - groups = dyelocal.dyes[1][3], + groups = dyelocal.dyes[1][4], on_place = function(itemstack, user, pointed_thing) -- Use pointed node's on_rightclick function first, if present local node = minetest.get_node(pointed_thing.under) @@ -331,12 +332,12 @@ minetest.register_craftitem("mcl_dye:white", { }) minetest.register_craftitem("mcl_dye:brown", { - inventory_image = "dye_brown.png", + inventory_image = "mcl_dye_brown.png", _doc_items_longdesc = "Cocoa beans are a brown dye and can be used to plant cocoas.", _doc_items_usagehelp = "Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.", description = "Cocoa Beans", stack_max = 64, - groups = dyelocal.dyes[12][3], + groups = dyelocal.dyes[12][4], on_place = function(itemstack, placer, pointed_thing) return mcl_cocoas.place(itemstack, placer, pointed_thing, "mcl_cocoas:cocoa_1") end, diff --git a/mods/ITEMS/mcl_dye/textures/dye_black.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_black.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_black.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_black.png diff --git a/mods/ITEMS/mcl_dye/textures/dye_blue.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_blue.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_blue.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_blue.png diff --git a/mods/ITEMS/mcl_dye/textures/dye_brown.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_brown.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_brown.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_brown.png diff --git a/mods/ITEMS/mcl_dye/textures/dye_lightblue.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_light_blue.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_lightblue.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_light_blue.png diff --git a/mods/ITEMS/mcl_dye/textures/dye_green.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_lime.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_green.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_lime.png diff --git a/mods/ITEMS/mcl_dye/textures/dye_white.png b/mods/ITEMS/mcl_dye/textures/mcl_dye_white.png similarity index 100% rename from mods/ITEMS/mcl_dye/textures/dye_white.png rename to mods/ITEMS/mcl_dye/textures/mcl_dye_white.png diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index 7d2e8612..4871c7d2 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -303,21 +303,21 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,door_spruce.png,/mods/ITEMS/mcl_doors/textures,mcl_doors_door_spruce.png,,,,,,, /assets/minecraft/textures/items,door_wood.png,/mods/ITEMS/mcl_doors/textures,doors_item_wood.png,,,,,,, /assets/minecraft/textures/items,door_iron.png,/mods/ITEMS/mcl_doors/textures,doors_item_steel.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_black.png,/mods/ITEMS/mcl_dye/textures,dye_black.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_blue.png,/mods/ITEMS/mcl_dye/textures,dye_blue.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_brown.png,/mods/ITEMS/mcl_dye/textures,dye_brown.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_black.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_black.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_blue.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_blue.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_brown.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_brown.png,,,,,,, /assets/minecraft/textures/items,dye_powder_cyan.png,/mods/ITEMS/mcl_dye/textures,dye_cyan.png,,,,,,, /assets/minecraft/textures/items,dye_powder_gray.png,/mods/ITEMS/mcl_dye/textures,dye_dark_grey.png,,,,,,, /assets/minecraft/textures/items,dye_powder_green.png,/mods/ITEMS/mcl_dye/textures,dye_dark_green.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_light_blue.png,/mods/ITEMS/mcl_dye/textures,dye_lightblue.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_lime.png,/mods/ITEMS/mcl_dye/textures,dye_green.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_light_blue.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_light_blue.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_lime.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_lime.png,,,,,,, /assets/minecraft/textures/items,dye_powder_magenta.png,/mods/ITEMS/mcl_dye/textures,dye_magenta.png,,,,,,, /assets/minecraft/textures/items,dye_powder_orange.png,/mods/ITEMS/mcl_dye/textures,dye_orange.png,,,,,,, /assets/minecraft/textures/items,dye_powder_pink.png,/mods/ITEMS/mcl_dye/textures,dye_pink.png,,,,,,, /assets/minecraft/textures/items,dye_powder_purple.png,/mods/ITEMS/mcl_dye/textures,dye_violet.png,,,,,,, /assets/minecraft/textures/items,dye_powder_red.png,/mods/ITEMS/mcl_dye/textures,dye_red.png,,,,,,, /assets/minecraft/textures/items,dye_powder_silver.png,/mods/ITEMS/mcl_dye/textures,dye_grey.png,,,,,,, -/assets/minecraft/textures/items,dye_powder_white.png,/mods/ITEMS/mcl_dye/textures,dye_white.png,,,,,,, +/assets/minecraft/textures/items,dye_powder_white.png,/mods/ITEMS/mcl_dye/textures,mcl_dye_white.png,,,,,,, /assets/minecraft/textures/items,dye_powder_yellow.png,/mods/ITEMS/mcl_dye/textures,dye_yellow.png,,,,,,, /assets/minecraft/textures/blocks,chorus_flower_dead.png,/mods/ITEMS/mcl_end/textures,mcl_end_chorus_flower_dead.png,,,,,,, /assets/minecraft/textures/blocks,chorus_flower.png,/mods/ITEMS/mcl_end/textures,mcl_end_chorus_flower.png,,,,,,, From 5897d0743533674566b882e8eb580a1732c599c3 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 19:54:12 +0100 Subject: [PATCH 036/865] Don't show bed msg if player respawns w/o bed --- mods/PLAYER/mcl_spawn/init.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 0413219b..9c9079b9 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -2,21 +2,26 @@ mcl_spawn = {} -- Returns current spawn position of player. -- If player is nil or not a player, the default spawn point is returned. +-- The second return value is true if spawn point is player-chosen, +-- false otherwise. mcl_spawn.get_spawn_pos = function(player) - local spawn + local spawn, custom_spawn if player ~= nil and player:is_player() then spawn = minetest.string_to_pos(player:get_attribute("mcl_beds:spawn")) + custom_spawn = true end if not spawn or spawn == "" then spawn = minetest.setting_get_pos("static_spawnpoint") + custom_spawn = false end if not spawn then spawn = { x=0, y=0, z=0 } if mg_name == "flat" then spawn.y = mcl_vars.mg_bedrock_overworld_max + 5 end + custom_spawn = false end - return spawn + return spawn, custom_spawn end -- Sets the player's spawn position to pos. @@ -31,8 +36,8 @@ end -- Respawn player at specified respawn position minetest.register_on_respawnplayer(function(player) - local pos = mcl_spawn.get_spawn_pos(player) - if pos then + local pos, custom_spawn = mcl_spawn.get_spawn_pos(player) + if custom_spawn then -- Check if bed is still there -- and the spawning position is free of solid or damaging blocks. local node_bed = minetest.get_node(pos) From 058cb2f1eed3eff36ad34723677c4ce8031f2012 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 20:06:02 +0100 Subject: [PATCH 037/865] Rename farmland textures because of MTG clash --- mods/ITEMS/mcl_farming/soil.lua | 4 ++-- ...arming_soil.png => mcl_farming_farmland_dry.png} | Bin ...ng_soil_wet.png => mcl_farming_farmland_wet.png} | Bin tools/Conversion_Table.csv | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename mods/ITEMS/mcl_farming/textures/{farming_soil.png => mcl_farming_farmland_dry.png} (100%) rename mods/ITEMS/mcl_farming/textures/{farming_soil_wet.png => mcl_farming_farmland_wet.png} (100%) diff --git a/mods/ITEMS/mcl_farming/soil.lua b/mods/ITEMS/mcl_farming/soil.lua index b89ae402..0b38a5ed 100644 --- a/mods/ITEMS/mcl_farming/soil.lua +++ b/mods/ITEMS/mcl_farming/soil.lua @@ -1,5 +1,5 @@ minetest.register_node("mcl_farming:soil", { - tiles = {"farming_soil.png", "default_dirt.png", "default_dirt.png", "default_dirt.png", "default_dirt.png", "default_dirt.png"}, + tiles = {"mcl_farming_farmland_dry.png", "default_dirt.png"}, description = "Farmland", _doc_items_longdesc = "Farmland is used for farming, a necessary surface to plant crops. It is created when a hoe is used on dirt or a similar block. Plants are able to grow on farmland, but slowly. Farmland will become hydrated farmland (on which plants grow faster) when it rains or a water source is nearby. This block will turn back to dirt when a solid block appears above it or a piston arm extends above it.", drop = "mcl_core:dirt", @@ -23,7 +23,7 @@ minetest.register_node("mcl_farming:soil", { }) minetest.register_node("mcl_farming:soil_wet", { - tiles = {"farming_soil_wet.png", "default_dirt.png", "default_dirt.png", "default_dirt.png", "default_dirt.png", "default_dirt.png"}, + tiles = {"mcl_farming_farmland_wet.png", "default_dirt.png"}, description = "Hydrated Farmland", _doc_items_longdesc = "Hydrated farmland is used in farming, this is where you can plant and grow some plants. It is created when farmlands is under rain or near water. Without water, this block will dry out eventually. This block will turn back to dirt when a solid block appears above it or a piston arm extends above it.", drop = "mcl_core:dirt", diff --git a/mods/ITEMS/mcl_farming/textures/farming_soil.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_farmland_dry.png similarity index 100% rename from mods/ITEMS/mcl_farming/textures/farming_soil.png rename to mods/ITEMS/mcl_farming/textures/mcl_farming_farmland_dry.png diff --git a/mods/ITEMS/mcl_farming/textures/farming_soil_wet.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_farmland_wet.png similarity index 100% rename from mods/ITEMS/mcl_farming/textures/farming_soil_wet.png rename to mods/ITEMS/mcl_farming/textures/mcl_farming_farmland_wet.png diff --git a/tools/Conversion_Table.csv b/tools/Conversion_Table.csv index 4871c7d2..a01d38f2 100644 --- a/tools/Conversion_Table.csv +++ b/tools/Conversion_Table.csv @@ -359,8 +359,8 @@ Source path,Source file,Target path,Target file,xs,ys,xl,yl,xt,yt,Blacklisted? /assets/minecraft/textures/items,seeds_pumpkin.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_pumpkin_seeds.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_side.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_side.png,,,,,,, /assets/minecraft/textures/blocks,pumpkin_top.png,/mods/ITEMS/mcl_farming/textures,farming_pumpkin_top.png,,,,,,, -/assets/minecraft/textures/blocks,farmland_dry.png,/mods/ITEMS/mcl_farming/textures,farming_soil.png,,,,,,, -/assets/minecraft/textures/blocks,farmland_wet.png,/mods/ITEMS/mcl_farming/textures,farming_soil_wet.png,,,,,,, +/assets/minecraft/textures/blocks,farmland_dry.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_farmland_dry.png,,,,,,, +/assets/minecraft/textures/blocks,farmland_wet.png,/mods/ITEMS/mcl_farming/textures,mcl_farming_farmland_wet.png,,,,,,, /assets/minecraft/textures/items,diamond_hoe.png,/mods/ITEMS/mcl_farming/textures,farming_tool_diamondhoe.png,,,,,,, /assets/minecraft/textures/items,gold_hoe.png,/mods/ITEMS/mcl_farming/textures,farming_tool_goldhoe.png,,,,,,, /assets/minecraft/textures/items,iron_hoe.png,/mods/ITEMS/mcl_farming/textures,farming_tool_steelhoe.png,,,,,,, From 729c176ff499ee1c749d54bd38de214eafb511d9 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 21:24:19 +0100 Subject: [PATCH 038/865] Texture Converter: Add description.txt --- tools/Texture_Converter.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/Texture_Converter.py b/tools/Texture_Converter.py index 6cb6cdb4..d89a5718 100755 --- a/tools/Texture_Converter.py +++ b/tools/Texture_Converter.py @@ -375,6 +375,11 @@ def convert_textures(): colorize(GRASS, tex_dir+"/blocks/grass_top.png", o[0], str(PXSIZE), target_dir("/mods/ITEMS/mcl_core/textures")+"/default_"+o[2]+".png") colorize_alpha(GRASS, tex_dir+"/blocks/grass_side_overlay.png", o[0], str(PXSIZE), target_dir("/mods/ITEMS/mcl_core/textures")+"/default_"+o[2]+"_side.png") + # Create description file + description = "Automatically converted Minecraft texture pack from MineClone 2 Texture Converter.\nSize: "+str(PXSIZE)+"px×"+str(PXSIZE)+"px" + description_file = open(target_dir("/") + "/description.txt", "w") + description_file.write(description) + description_file.close() print("Textures conversion COMPLETE!") if failed_conversions > 0: From 36060dfb6a5009cd397eba11784e9b491fd37f89 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 7 Feb 2019 22:22:07 +0100 Subject: [PATCH 039/865] Converter: Add preview image, use proper folder name --- tools/Texture_Converter.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tools/Texture_Converter.py b/tools/Texture_Converter.py index d89a5718..257e9389 100755 --- a/tools/Texture_Converter.py +++ b/tools/Texture_Converter.py @@ -14,7 +14,6 @@ import shutil, csv, os, tempfile, sys, getopt home = os.environ["HOME"] mineclone2_path = home + "/.minetest/games/mineclone2" working_dir = os.getcwd() -output_dir_name = "New_MineClone_2_Texture_Pack" appname = "Texture_Converter.py" ### SETTINGS ### @@ -100,6 +99,16 @@ For the full help, use: tex_dir = base_dir + "/assets/minecraft/textures" +# Get texture pack name (from directory name) +bdir_split = base_dir.split("/") +output_dir_name = bdir_split[-1] +if len(output_dir_name) == 0: + if len(bdir_split) >= 2: + output_dir_name = base_dir.split("/")[-2] + else: + # Fallback + output_dir_name = "New_MineClone_2_Texture_Pack" + # FUNCTION DEFINITIONS def colorize(colormap, source, colormap_pixel, texture_size, destination): os.system("convert "+colormap+" -crop 1x1+"+colormap_pixel+" -depth 8 -resize "+texture_size+"x"+texture_size+" "+tempfile1.name) @@ -375,11 +384,17 @@ def convert_textures(): colorize(GRASS, tex_dir+"/blocks/grass_top.png", o[0], str(PXSIZE), target_dir("/mods/ITEMS/mcl_core/textures")+"/default_"+o[2]+".png") colorize_alpha(GRASS, tex_dir+"/blocks/grass_side_overlay.png", o[0], str(PXSIZE), target_dir("/mods/ITEMS/mcl_core/textures")+"/default_"+o[2]+"_side.png") - # Create description file - description = "Automatically converted Minecraft texture pack from MineClone 2 Texture Converter.\nSize: "+str(PXSIZE)+"px×"+str(PXSIZE)+"px" - description_file = open(target_dir("/") + "/description.txt", "w") - description_file.write(description) - description_file.close() + # Metadata + if make_texture_pack: + # Create description file + description = "Texture pack for MineClone 2. Automatically converted from a Minecraft resource pack by the MineClone 2 Texture Converter. Size: "+str(PXSIZE)+"×"+str(PXSIZE) + description_file = open(target_dir("/") + "/description.txt", "w") + description_file.write(description) + description_file.close() + + # Create preview image (screenshot.png) + os.system("convert -size 300x200 canvas:transparent "+target_dir("/") + "/screenshot.png") + os.system("composite "+base_dir+"/pack.png "+target_dir("/") + "/screenshot.png -gravity center "+target_dir("/") + "/screenshot.png") print("Textures conversion COMPLETE!") if failed_conversions > 0: From 7d0c647e8b2c1d9e57773e1eed3805a936227d38 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 05:30:05 +0100 Subject: [PATCH 040/865] Comment on beetroot seed probability --- mods/ITEMS/mcl_farming/beetroot.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mods/ITEMS/mcl_farming/beetroot.lua b/mods/ITEMS/mcl_farming/beetroot.lua index d88633d9..8fe69358 100644 --- a/mods/ITEMS/mcl_farming/beetroot.lua +++ b/mods/ITEMS/mcl_farming/beetroot.lua @@ -94,6 +94,12 @@ minetest.register_node("mcl_farming:beetroot", { walkable = false, drawtype = "plantlike", drop = { + --[[ drops 1 beetroot guaranteed. + drops 0-3 beetroot seeds: + 0 seeds: 42.18% + 1 seed: 14.06% + 2 seeds: 18.75% + 3 seeds: 25% ]] max_items = 2, items = { { items = {"mcl_farming:beetroot_item"}, rarity = 1 }, From cb8e3fcf82af500bcea04f1e0f7be1c6f9b7adee Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 05:36:43 +0100 Subject: [PATCH 041/865] Fix bone meal failing to grow crops when it's dark --- mods/ITEMS/mcl_dye/init.lua | 12 ++++++------ mods/ITEMS/mcl_farming/shared_functions.lua | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/mods/ITEMS/mcl_dye/init.lua b/mods/ITEMS/mcl_dye/init.lua index f95aa874..c347a900 100644 --- a/mods/ITEMS/mcl_dye/init.lua +++ b/mods/ITEMS/mcl_dye/init.lua @@ -203,24 +203,24 @@ mcl_dye.apply_bone_meal = function(pointed_thing) -- Wheat, Potato, Carrot, Pumpkin Stem, Melon Stem: Advance by 2-5 stages elseif string.find(n.name, "mcl_farming:wheat_") ~= nil then local stages = math.random(2, 5) - return mcl_farming:grow_plant("plant_wheat", pos, n, stages) + return mcl_farming:grow_plant("plant_wheat", pos, n, stages, true) elseif string.find(n.name, "mcl_farming:potato_") ~= nil then local stages = math.random(2, 5) - return mcl_farming:grow_plant("plant_potato", pos, n, stages) + return mcl_farming:grow_plant("plant_potato", pos, n, stages, true) elseif string.find(n.name, "mcl_farming:carrot_") ~= nil then local stages = math.random(2, 5) - return mcl_farming:grow_plant("plant_carrot", pos, n, stages) + return mcl_farming:grow_plant("plant_carrot", pos, n, stages, true) elseif string.find(n.name, "mcl_farming:pumpkin_") ~= nil then local stages = math.random(2, 5) - return mcl_farming:grow_plant("plant_pumpkin_stem", pos, n, stages) + return mcl_farming:grow_plant("plant_pumpkin_stem", pos, n, stages, true) elseif string.find(n.name, "mcl_farming:melontige_") ~= nil then local stages = math.random(2, 5) - return mcl_farming:grow_plant("plant_melon_stem", pos, n, stages) + return mcl_farming:grow_plant("plant_melon_stem", pos, n, stages, true) elseif string.find(n.name, "mcl_farming:beetroot_") ~= nil then -- Beetroot: 75% chance to advance to next stage if math.random(1,100) <= 75 then - return mcl_farming:grow_plant("plant_beetroot", pos, n) + return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true) end elseif n.name == "mcl_cocoas:cocoa_1" or n.name == "mcl_cocoas:cocoa_2" then -- Cocoa: Advance by 1 stage diff --git a/mods/ITEMS/mcl_farming/shared_functions.lua b/mods/ITEMS/mcl_farming/shared_functions.lua index 0b201ca6..9844dd43 100644 --- a/mods/ITEMS/mcl_farming/shared_functions.lua +++ b/mods/ITEMS/mcl_farming/shared_functions.lua @@ -24,14 +24,15 @@ end -- pos: Position -- node: Node table -- stages: Number of stages to advance (optional, defaults to 1) +-- ignore_light: if true, ignore light requirements for growing -- Returns true if plant has been grown by 1 or more stages. -- Returns false if nothing changed. -function mcl_farming:grow_plant(identifier, pos, node, stages) - if not minetest.get_node_light(pos) then +function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light) + if not minetest.get_node_light(pos) and not ignore_light then return false end - if minetest.get_node_light(pos) < 10 then + if minetest.get_node_light(pos) < 10 and not ignore_light then return false end From bcf7125f9da75895e3fc284c0489a29852c7110a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 17:55:14 +0100 Subject: [PATCH 042/865] Fix mob items not working without maphack priv --- mods/ENTITIES/mcl_mobs/api.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 3f1eeeb0..ebe977e9 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3576,11 +3576,11 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) local name = placer:get_player_name() local privs = minetest.get_player_privs(name) - if not privs.maphack then - minetest.chat_send_player(name, "You need the “maphack” privilege to change the mob spawner.") - return itemstack - end if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then + if not privs.maphack then + minetest.chat_send_player(name, "You need the “maphack” privilege to change the mob spawner.") + return itemstack + end mcl_mobspawners.setup_spawner(pointed_thing.under, itemstack:get_name()) if not minetest.settings:get_bool("creative_mode") then itemstack:take_item() From 312b17a958ff93c6e398ee922c8c33da0a279181 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 21:59:01 +0100 Subject: [PATCH 043/865] Check protection for most nodes --- mods/ITEMS/REDSTONE/mcl_comparators/init.lua | 7 ++- mods/ITEMS/REDSTONE/mcl_dispensers/init.lua | 27 ++++++++++ mods/ITEMS/REDSTONE/mcl_droppers/init.lua | 27 ++++++++++ .../REDSTONE/mesecons_commandblock/init.lua | 11 ++-- mods/ITEMS/REDSTONE/mesecons_delayer/init.lua | 14 ++++- .../REDSTONE/mesecons_noteblock/init.lua | 7 ++- .../REDSTONE/mesecons_solarpanel/init.lua | 20 +++++++ mods/ITEMS/mcl_anvils/init.lua | 21 +++++++- mods/ITEMS/mcl_buckets/init.lua | 39 +++++++++++--- mods/ITEMS/mcl_cake/init.lua | 16 ++++++ mods/ITEMS/mcl_chests/init.lua | 54 ++++++++++++++++--- mods/ITEMS/mcl_flowerpots/init.lua | 18 +++++++ mods/ITEMS/mcl_furnaces/init.lua | 8 ++- mods/ITEMS/mcl_hoppers/init.lua | 54 +++++++++++++++++++ mods/ITEMS/mcl_itemframes/init.lua | 32 +++++++++++ mods/ITEMS/mcl_jukebox/init.lua | 32 ++++++++++- mods/ITEMS/mcl_portals/portal_end.lua | 5 ++ .../minetest-3d_armor/3d_armor_stand/init.lua | 23 +++++++- 18 files changed, 389 insertions(+), 26 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua index 58097213..1feb8889 100644 --- a/mods/ITEMS/REDSTONE/mcl_comparators/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_comparators/init.lua @@ -153,7 +153,12 @@ end local make_rightclick_handler = function(state, mode) local newnodename = "mcl_comparators:comparator_"..state.."_"..flipmode(mode) - return function (pos, node) + return function (pos, node, clicker) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end minetest.swap_node(pos, {name = newnodename, param2 = node.param2 }) end end diff --git a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua index 0642f7f1..2c3c6b78 100644 --- a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua @@ -50,6 +50,33 @@ end local dispenserdef = { is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, after_dig_node = function(pos, oldnode, oldmetadata, digger) local meta = minetest.get_meta(pos) local meta2 = meta diff --git a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua index f67cfc4b..be42e79a 100644 --- a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua @@ -63,6 +63,33 @@ local dropperdef = { end meta:from_table(meta2:to_table()) end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, _mcl_blast_resistance = 17.5, _mcl_hardness = 3.5, mesecons = {effector = { diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index 4047a926..acb1a9d0 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -131,9 +131,14 @@ local on_rightclick = function(pos, node, player, itemstack, pointed_thing) if not minetest.settings:get_bool("creative_mode") then return end - local privs = minetest.get_player_privs(player:get_player_name()) + local pname = player:get_player_name() + if minetest.is_protected(pos, pname) then + minetest.record_protection_violation(pos, pname) + return + end + local privs = minetest.get_player_privs(pname) if not privs.maphack then - minetest.chat_send_player(player:get_player_name(), "Access denied. You need the “maphack” privilege to edit command blocks.") + minetest.chat_send_player(pname, "Access denied. You need the “maphack” privilege to edit command blocks.") return end @@ -152,7 +157,7 @@ local on_rightclick = function(pos, node, player, itemstack, pointed_thing) "image_button[8,4.5;1,1;doc_button_icon_lores.png;doc;]" .. "label[0,4;"..minetest.formspec_escape(commanderstr).."]" .. "tooltip[doc;Help]" - minetest.show_formspec(player:get_player_name(), "commandblock_"..pos.x.."_"..pos.y.."_"..pos.z, formspec) + minetest.show_formspec(pname, "commandblock_"..pos.x.."_"..pos.y.."_"..pos.z, formspec) end local on_place = function(itemstack, placer, pointed_thing) diff --git a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua index d6c1f95b..ea463844 100644 --- a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua @@ -254,7 +254,12 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), { sunlight_propagates = false, is_ground_content = false, drop = 'mesecons_delayer:delayer_off_1', - on_rightclick = function (pos, node) + on_rightclick = function (pos, node, clicker) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.report_protection_violation(pos, protname) + return + end if node.name=="mesecons_delayer:delayer_off_1" then minetest.set_node(pos, {name="mesecons_delayer:delayer_off_2", param2=node.param2}) elseif node.name=="mesecons_delayer:delayer_off_2" then @@ -317,7 +322,12 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), { sunlight_propagates = false, is_ground_content = false, drop = 'mesecons_delayer:delayer_off_1', - on_rightclick = function (pos, node) + on_rightclick = function (pos, node, clicker) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.report_protection_violation(pos, protname) + return + end if node.name=="mesecons_delayer:delayer_on_1" then minetest.set_node(pos, {name="mesecons_delayer:delayer_on_2",param2=node.param2}) elseif node.name=="mesecons_delayer:delayer_on_2" then diff --git a/mods/ITEMS/REDSTONE/mesecons_noteblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_noteblock/init.lua index 191c4436..9d1737ac 100644 --- a/mods/ITEMS/REDSTONE/mesecons_noteblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_noteblock/init.lua @@ -14,7 +14,12 @@ The note block will only play a note when it is below air, otherwise, it stays s groups = {handy=1,axey=1, material_wood=1}, is_ground_content = false, place_param2 = 0, - on_rightclick = function (pos, node) -- change sound when rightclicked + on_rightclick = function (pos, node, clicker) -- change sound when rightclicked + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end node.param2 = (node.param2+1)%24 mesecon.noteblock_play(pos, node.param2) minetest.set_node(pos, node) diff --git a/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua b/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua index 1c66b619..0bd0b737 100644 --- a/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_solarpanel/init.lua @@ -27,6 +27,11 @@ minetest.register_node("mesecons_solarpanel:solar_panel_on", { rules = mesecon.rules.pplate, }}, on_rightclick = function(pos, node, clicker, pointed_thing) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end minetest.swap_node(pos, {name = "mesecons_solarpanel:solar_panel_inverted_off"}) mesecon.receptor_off(pos, mesecon.rules.pplate) end, @@ -60,6 +65,11 @@ minetest.register_node("mesecons_solarpanel:solar_panel_off", { rules = mesecon.rules.pplate, }}, on_rightclick = function(pos, node, clicker, pointed_thing) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end minetest.swap_node(pos, {name = "mesecons_solarpanel:solar_panel_inverted_on"}) mesecon.receptor_on(pos, mesecon.rules.pplate) end, @@ -134,6 +144,11 @@ minetest.register_node("mesecons_solarpanel:solar_panel_inverted_on", { rules = mesecon.rules.pplate, }}, on_rightclick = function(pos, node, clicker, pointed_thing) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end minetest.swap_node(pos, {name = "mesecons_solarpanel:solar_panel_off"}) mesecon.receptor_off(pos, mesecon.rules.pplate) end, @@ -168,6 +183,11 @@ minetest.register_node("mesecons_solarpanel:solar_panel_inverted_off", { rules = mesecon.rules.pplate, }}, on_rightclick = function(pos, node, clicker, pointed_thing) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end minetest.swap_node(pos, {name = "mesecons_solarpanel:solar_panel_on"}) mesecon.receptor_on(pos, mesecon.rules.pplate) end, diff --git a/mods/ITEMS/mcl_anvils/init.lua b/mods/ITEMS/mcl_anvils/init.lua index 78db3ba9..3863583f 100644 --- a/mods/ITEMS/mcl_anvils/init.lua +++ b/mods/ITEMS/mcl_anvils/init.lua @@ -277,15 +277,32 @@ local anvildef = { drop_anvil_items(pos, meta) meta:from_table(meta2:to_table()) end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, allow_metadata_inventory_put = function(pos, listname, index, stack, player) - if listname == "output" then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + elseif listname == "output" then return 0 else return stack:get_count() end end, allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - if to_list == "output" then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + elseif to_list == "output" then return 0 elseif from_list == "output" and to_list == "input" then local meta = minetest.get_meta(pos) diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index 5eac32ef..f53cad4c 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -53,7 +53,8 @@ end -- name = user-visible bucket description -- longdesc = long explanatory description (for help) -- usagehelp = short usage explanation (for help) --- extra_check = optional function(pos) which can returns false to avoid placing the liquid +-- extra_check(pos, placer) = optional function(pos) which can returns false to avoid placing the liquid. +-- placer is object/player who is placing the liquid, can be nil -- groups = optional list of item groups -- -- This function can be called from any mod (which depends on this one) @@ -103,12 +104,13 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent -- Check if pointing to a buildable node local item = itemstack:get_name() - if extra_check and extra_check(place_pos) == false then + if extra_check and extra_check(place_pos, user) == false then -- Fail placement of liquid elseif minetest.registered_nodes[nn] and minetest.registered_nodes[nn].buildable_to then -- buildable; replace the node local pns = user:get_player_name() if minetest.is_protected(place_pos, pns) then + minetest.record_protection_violation(place_pos, pns) return itemstack end place_liquid(place_pos, node_place) @@ -122,6 +124,7 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent if minetest.registered_nodes[abovenode.name] and minetest.registered_nodes[abovenode.name].buildable_to then local pn = user:get_player_name() if minetest.is_protected(pointed_thing.above, pn) then + minetest.record_protection_violation(pointed_thing.above, pn) return itemstack end place_liquid(pointed_thing.above, node_place) @@ -159,11 +162,12 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent local iname = stack:get_name() local buildable = minetest.registered_nodes[dropnode.name].buildable_to - if extra_check and extra_check(droppos) == false then + if extra_check and extra_check(droppos, nil) == false then -- Fail placement of liquid elseif buildable then -- buildable; replace the node if minetest.is_protected(droppos, "") then + minetest.record_protection_violation(droppos, "") return stack end local node_place @@ -192,7 +196,7 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { on_place = function(itemstack, user, pointed_thing) -- Must be pointing to node if pointed_thing.type ~= "node" then - return + return itemstack end -- Call on_rightclick if the pointed node defines it @@ -204,6 +208,12 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { end end + -- Can't steal liquids + if minetest.is_protected(pointed_thing.above, pointed_thing.under) then + minetest.record_protection_violation(pointed_thing.under, user:get_player_name()) + return itemstack + end + -- Check if pointing to a liquid source local liquiddef = mcl_buckets.liquids[nn] local new_bucket @@ -257,6 +267,11 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { end end, _on_dispense = function(stack, pos, droppos, dropnode, dropdir) + if minetest.is_protected(droppos, "") then + minetest.record_protection_violation(droppos, "") + return stack + end + -- Fill empty bucket with liquid or drop bucket if no liquid local collect_liquid = false @@ -310,7 +325,13 @@ if mod_mcl_core then "Water Bucket", "A bucket can be used to collect and release liquids. This one is filled with water.", "Right-click on any block to empty the bucket and put a water source on this spot.", - function(pos) + function(pos, placer) + -- Check protection + local placer_name = placer:get_player_name() + if minetest.is_protected(pos, placer_name) then + minetest.record_protection_violation(pos, placer_name) + return false + end local nn = minetest.get_node(pos).name -- Pour water into cauldron if minetest.get_item_group(nn, "cauldron") ~= 0 then @@ -343,7 +364,13 @@ if mod_mclx_core then "River Water Bucket", "A bucket can be used to collect and release liquids. This one is filled with river water.", "Right-click on any block to empty the bucket and put a river water source on this spot.", - function(pos) + function(pos, placer) + -- Check protection + local placer_name = placer:get_player_name() + if minetest.is_protected(pos, placer_name) then + minetest.record_protection_violation(pos, placer_name) + return false + end local nn = minetest.get_node(pos).name -- Pour into cauldron if minetest.get_item_group(nn, "cauldron") ~= 0 then diff --git a/mods/ITEMS/mcl_cake/init.lua b/mods/ITEMS/mcl_cake/init.lua index 75542fb9..ca6f7a55 100644 --- a/mods/ITEMS/mcl_cake/init.lua +++ b/mods/ITEMS/mcl_cake/init.lua @@ -49,6 +49,12 @@ minetest.register_node("mcl_cake:cake", { groups = {handy=1, cake=7, food=2,no_eat_delay=1, attached_node=1, dig_by_piston=1, comparator_signal=14}, drop = '', on_rightclick = function(pos, node, clicker, itemstack) + -- Cake is subject to protection + local name = clicker:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end local newcake = minetest.do_item_eat(2, ItemStack("mcl_cake:cake_6"), ItemStack("mcl_cake:cake"), clicker, {type="nothing"}) -- Check if we were allowed to eat if newcake:get_name() ~= "mcl_cake:cake" or minetest.settings:get_bool("creative_mode") == true then @@ -69,6 +75,11 @@ local register_slice = function(level, nodebox, desc) local on_rightclick if level > 1 then on_rightclick = function(pos, node, clicker, itemstack) + local name = clicker:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end local newcake = minetest.do_item_eat(2, ItemStack(after_eat), ItemStack(this), clicker, {type="nothing"}) -- Check if we were allowed to eat if newcake:get_name() ~= this or minetest.settings:get_bool("creative_mode") == true then @@ -78,6 +89,11 @@ local register_slice = function(level, nodebox, desc) else -- Last slice on_rightclick = function(pos, node, clicker, itemstack) + local name = clicker:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end local newcake = minetest.do_item_eat(2, ItemStack("mcl:cake:cake 0"), ItemStack("mcl_cake:cake_1"), clicker, {type="nothing"}) -- Check if we were allowed to eat if newcake:get_name() ~= this or minetest.settings:get_bool("creative_mode") == true then diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index e17dcd59..57c991ce 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -15,6 +15,26 @@ local player_chest_open = function(player, pos) open_chests[player:get_player_name()] = { pos = pos } end +-- Simple protection checking functions +local protection_check_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end +end +local protection_check_put_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end +end + local trapped_chest_mesecons_rules = mesecon.rules.pplate -- To be called if a player closed a chest @@ -122,6 +142,9 @@ minetest.register_node("mcl_chests:"..basename, { end meta:from_table(meta2:to_table()) end, + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, + allow_metadata_inventory_put = protection_check_put_take, on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) minetest.log("action", player:get_player_name().. " moves stuff in chest at "..minetest.pos_to_string(pos)) @@ -211,9 +234,15 @@ minetest.register_node("mcl_chests:"..basename.."_left", { end meta:from_table(meta2:to_table()) end, - -- BEGIN OF LISTRING WORKAROUND + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, allow_metadata_inventory_put = function(pos, listname, index, stack, player) - if listname == "input" then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + -- BEGIN OF LISTRING WORKAROUND + elseif listname == "input" then local inv = minetest.get_inventory({type="node", pos=pos}) if inv:room_for_item("main", stack) then return -1 @@ -226,11 +255,11 @@ minetest.register_node("mcl_chests:"..basename.."_left", { return 0 end end + -- END OF LISTRING WORKAROUND else return stack:get_count() end end, - -- END OF LISTRING WORKAROUND on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) minetest.log("action", player:get_player_name().. " moves stuff in chest at "..minetest.pos_to_string(pos)) @@ -326,9 +355,15 @@ minetest.register_node("mcl_chests:"..basename.."_right", { end meta:from_table(meta2:to_table()) end, - -- BEGIN OF LISTRING WORKAROUND + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, allow_metadata_inventory_put = function(pos, listname, index, stack, player) - if listname == "input" then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + -- BEGIN OF LISTRING WORKAROUND + elseif listname == "input" then local other_pos = mcl_util.get_double_container_neighbor_pos(pos, minetest.get_node(pos).param2, "right") local other_inv = minetest.get_inventory({type="node", pos=other_pos}) if other_inv:room_for_item("main", stack) then @@ -341,11 +376,11 @@ minetest.register_node("mcl_chests:"..basename.."_right", { return 0 end end + -- END OF LISTRING WORKAROUND else return stack:get_count() end end, - -- END OF LISTRING WORKAROUND on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) minetest.log("action", player:get_player_name().. " moves stuff in chest at "..minetest.pos_to_string(pos)) @@ -738,7 +773,14 @@ for color, desc in pairs(boxtypes) do minetest.add_item(pos, boxitem) end end, + allow_metadata_inventory_move = protection_check_move, + allow_metadata_inventory_take = protection_check_put_take, allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + end -- Do not allow to place shulker boxes into shulker boxes local group = minetest.get_item_group(stack:get_name(), "shulker_box") if group == 0 or group == nil then diff --git a/mods/ITEMS/mcl_flowerpots/init.lua b/mods/ITEMS/mcl_flowerpots/init.lua index c9187eed..e4df4459 100644 --- a/mods/ITEMS/mcl_flowerpots/init.lua +++ b/mods/ITEMS/mcl_flowerpots/init.lua @@ -53,6 +53,11 @@ minetest.register_node("mcl_flowerpots:flower_pot", { groups = {dig_immediate=3, deco_block=1, attached_node=1, dig_by_piston=1, flower_pot=1}, sounds = mcl_sounds.node_sound_stone_defaults(), on_rightclick = function(pos, node, clicker, itemstack) + local name = clicker:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end local item = clicker:get_wielded_item():get_name() for _, row in ipairs(flowers) do local flower = row[1] @@ -120,6 +125,11 @@ minetest.register_node("mcl_flowerpots:flower_pot_"..flower, { groups = {dig_immediate=3, attached_node=1, dig_by_piston=1, not_in_creative_inventory=1, flower_pot=2}, sounds = mcl_sounds.node_sound_stone_defaults(), on_rightclick = function(pos, item, clicker) + local name = clicker:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end minetest.add_item({x=pos.x, y=pos.y+0.5, z=pos.z}, flower_node) minetest.set_node(pos, {name="mcl_flowerpots:flower_pot"}) end, @@ -163,6 +173,14 @@ minetest.register_node("mcl_flowerpots:flower_pot_"..flower, { groups = {dig_immediate=3, attached_node=1, dig_by_piston=1, not_in_creative_inventory=1, flower_pot=2}, sounds = mcl_sounds.node_sound_stone_defaults(), on_rightclick = function(pos, item, clicker) + local name = "" + if clicker:is_player() then + name = clicker:get_player_name() + end + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return + end minetest.add_item({x=pos.x, y=pos.y+0.5, z=pos.z}, flower_node) minetest.set_node(pos, {name="mcl_flowerpots:flower_pot"}) end, diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index e409bd30..9a8804fd 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -60,7 +60,9 @@ end -- local function allow_metadata_inventory_put(pos, listname, index, stack, player) - if minetest.is_protected(pos, player:get_player_name()) then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) return 0 end local meta = minetest.get_meta(pos) @@ -111,7 +113,9 @@ local function allow_metadata_inventory_move(pos, from_list, from_index, to_list end local function allow_metadata_inventory_take(pos, listname, index, stack, player) - if minetest.is_protected(pos, player:get_player_name()) then + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) return 0 end return stack:get_count() diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index a05646b7..c7f7b0b9 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -71,6 +71,33 @@ local def_hopper = { end meta:from_table(meta2:to_table()) end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) minetest.log("action", player:get_player_name().. " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos)) @@ -230,6 +257,33 @@ local def_hopper_side = { end meta:from_table(meta2:to_table()) end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) minetest.log("action", player:get_player_name().. " moves stuff in mcl_hoppers at "..minetest.pos_to_string(pos)) diff --git a/mods/ITEMS/mcl_itemframes/init.lua b/mods/ITEMS/mcl_itemframes/init.lua index b674a1cd..14170e3b 100644 --- a/mods/ITEMS/mcl_itemframes/init.lua +++ b/mods/ITEMS/mcl_itemframes/init.lua @@ -125,6 +125,11 @@ minetest.register_node("mcl_itemframes:item_frame",{ if not itemstack then return end + local pname = clicker:get_player_name() + if minetest.is_protected(pos, pname) then + minetest.record_protection_violation(pos, pname) + return + end local meta = minetest.get_meta(pos) drop_item(pos, node, meta) local inv = meta:get_inventory() @@ -150,6 +155,33 @@ minetest.register_node("mcl_itemframes:item_frame",{ end return itemstack end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, on_destruct = function(pos) local meta = minetest.get_meta(pos) local node = minetest.get_node(pos) diff --git a/mods/ITEMS/mcl_jukebox/init.lua b/mods/ITEMS/mcl_jukebox/init.lua index 2ee8f8c1..efa29399 100644 --- a/mods/ITEMS/mcl_jukebox/init.lua +++ b/mods/ITEMS/mcl_jukebox/init.lua @@ -138,7 +138,10 @@ minetest.register_node("mcl_jukebox:jukebox", { on_rightclick= function(pos, node, clicker, itemstack, pointed_thing) if not clicker then return end local cname = clicker:get_player_name() - + if minetest.is_protected(pos, cname) then + minetest.record_protection_violation(pos, cname) + return + end local meta = minetest.get_meta(pos) local inv = meta:get_inventory() if not inv:is_empty("main") then @@ -172,6 +175,33 @@ minetest.register_node("mcl_jukebox:jukebox", { end return itemstack end, + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return count + end + end, + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, after_dig_node = function(pos, oldnode, oldmetadata, digger) local name = digger:get_player_name() local meta = minetest.get_meta(pos) diff --git a/mods/ITEMS/mcl_portals/portal_end.lua b/mods/ITEMS/mcl_portals/portal_end.lua index c172eacf..bca803dc 100644 --- a/mods/ITEMS/mcl_portals/portal_end.lua +++ b/mods/ITEMS/mcl_portals/portal_end.lua @@ -376,6 +376,11 @@ minetest.override_item("mcl_end:ender_eye", { -- Place eye of ender into end portal frame if pointed_thing.under and node.name == "mcl_portals:end_portal_frame" then + local protname = user:get_player_name() + if minetest.is_protected(pointed_thing.under, protname) then + minetest.record_protection_violation(pointed_thing.under, protname) + return itemstack + end minetest.set_node(pointed_thing.under, { name = "mcl_portals:end_portal_frame_eye", param2 = node.param2 }) if minetest.get_modpath("doc") then diff --git a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua index d6212e37..75a050e7 100644 --- a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua +++ b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua @@ -120,6 +120,11 @@ minetest.register_node("3d_armor_stand:armor_stand", { on_destruct = drop_armor, -- Put piece of armor on armor stand, or take one away on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local protname = clicker:get_player_name() + if minetest.is_protected(pos, protname) then + minetest.record_protection_violation(pos, protname) + return + end -- Check if player wields armor local name = itemstack:get_name() local list @@ -177,7 +182,21 @@ minetest.register_node("3d_armor_stand:armor_stand", { after_place_node = function(pos) minetest.add_entity(pos, "3d_armor_stand:armor_entity") end, - allow_metadata_inventory_put = function(pos, listname, index, stack) + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + else + return stack:get_count() + end + end, + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + minetest.record_protection_violation(pos, name) + return 0 + end local def = stack:get_definition() or {} local groups = def.groups or {} if groups[listname] then @@ -185,7 +204,7 @@ minetest.register_node("3d_armor_stand:armor_stand", { end return 0 end, - allow_metadata_inventory_move = function(pos) + allow_metadata_inventory_move = function() return 0 end, on_metadata_inventory_put = function(pos) From 9a3c6a3fd7b88f1f65b208b1b1c4f2b5f95e708d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 22:17:51 +0100 Subject: [PATCH 044/865] Protect: add bottles, mobspawner, fix repeater --- mods/ENTITIES/mcl_mobs/api.lua | 4 ++ mods/ITEMS/REDSTONE/mesecons_delayer/init.lua | 4 +- mods/ITEMS/mcl_potions/init.lua | 63 ++++++++++++------- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index ebe977e9..a75a6e39 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3577,6 +3577,10 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative) local name = placer:get_player_name() local privs = minetest.get_player_privs(name) if mod_mobspawners and under.name == "mcl_mobspawners:spawner" then + if minetest.is_protected(pointed_thing.under, name) then + minetest.record_protection_violation(pointed_thing.under, name) + return itemstack + end if not privs.maphack then minetest.chat_send_player(name, "You need the “maphack” privilege to change the mob spawner.") return itemstack diff --git a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua index ea463844..a17dd7f5 100644 --- a/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_delayer/init.lua @@ -257,7 +257,7 @@ minetest.register_node("mesecons_delayer:delayer_off_"..tostring(i), { on_rightclick = function (pos, node, clicker) local protname = clicker:get_player_name() if minetest.is_protected(pos, protname) then - minetest.report_protection_violation(pos, protname) + minetest.record_protection_violation(pos, protname) return end if node.name=="mesecons_delayer:delayer_off_1" then @@ -325,7 +325,7 @@ minetest.register_node("mesecons_delayer:delayer_on_"..tostring(i), { on_rightclick = function (pos, node, clicker) local protname = clicker:get_player_name() if minetest.is_protected(pos, protname) then - minetest.report_protection_violation(pos, protname) + minetest.record_protection_violation(pos, protname) return end if node.name=="mesecons_delayer:delayer_on_1" then diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index fa4349c0..2920cfdd 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -46,27 +46,34 @@ minetest.register_craftitem("mcl_potions:glass_bottle", { get_water = true river_water = node.name == "mclx_core:river_water_source" -- Or reduce water level of cauldron by 1 - elseif node.name == "mcl_cauldrons:cauldron_3" then - get_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_2"}) - elseif node.name == "mcl_cauldrons:cauldron_2" then - get_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_1"}) - elseif node.name == "mcl_cauldrons:cauldron_1" then - get_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) - elseif node.name == "mcl_cauldrons:cauldron_3r" then - get_water = true - river_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_2r"}) - elseif node.name == "mcl_cauldrons:cauldron_2r" then - get_water = true - river_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_1r"}) - elseif node.name == "mcl_cauldrons:cauldron_1r" then - get_water = true - river_water = true - minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) + elseif string.sub(node.name, 1, 14) == "mcl_cauldrons:" then + local pname = placer:get_player_name() + if minetest.is_protected(pointed_thing.under, pname) then + minetest.record_protection_violation(pointed_thing.under, pname) + return itemstack + end + if node.name == "mcl_cauldrons:cauldron_3" then + get_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_2"}) + elseif node.name == "mcl_cauldrons:cauldron_2" then + get_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_1"}) + elseif node.name == "mcl_cauldrons:cauldron_1" then + get_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) + elseif node.name == "mcl_cauldrons:cauldron_3r" then + get_water = true + river_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_2r"}) + elseif node.name == "mcl_cauldrons:cauldron_2r" then + get_water = true + river_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron_1r"}) + elseif node.name == "mcl_cauldrons:cauldron_1r" then + get_water = true + river_water = true + minetest.set_node(pointed_thing.under, {name="mcl_cauldrons:cauldron"}) + end end if get_water then -- Replace with water bottle, if possible, otherwise @@ -160,7 +167,12 @@ minetest.register_craftitem("mcl_potions:potion_water", { local cauldron = fill_cauldron(node.name, "mcl_core:water_source") if cauldron then - -- Increase water level of cauldron by 1 + local pname = placer:get_player_name() + if minetest.is_protected(pointed_thing.under, pname) then + minetest.record_protection_violation(pointed_thing.under, pname) + return itemstack + end + -- Increase water level of cauldron by 1 minetest.set_node(pointed_thing.under, {name=cauldron}) minetest.sound_play("mcl_potions_bottle_pour", {pos=pointed_thing.under, gain=0.5, max_hear_range=16}) return "mcl_potions:glass_bottle" @@ -195,7 +207,12 @@ minetest.register_craftitem("mcl_potions:potion_river_water", { local cauldron = fill_cauldron(node.name, "mclx_core:river_water_source") if cauldron then - -- Increase water level of cauldron by 1 + local pname = placer:get_player_name() + if minetest.is_protected(pointed_thing.under, pname) then + minetest.record_protection_violation(pointed_thing.under, pname) + return itemstack + end + -- Increase water level of cauldron by 1 minetest.set_node(pointed_thing.under, {name=cauldron}) minetest.sound_play("mcl_potions_bottle_pour", {pos=pointed_thing.under, gain=0.5, max_hear_range=16}) return "mcl_potions:glass_bottle" From c141f4ece57fee557de1fe88450e057d5f1be9fb Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 22:20:58 +0100 Subject: [PATCH 045/865] Mobspawners: Remove unused function --- mods/ITEMS/mcl_mobspawners/init.lua | 36 ----------------------------- 1 file changed, 36 deletions(-) diff --git a/mods/ITEMS/mcl_mobspawners/init.lua b/mods/ITEMS/mcl_mobspawners/init.lua index 1eb9005a..46cf74c7 100644 --- a/mods/ITEMS/mcl_mobspawners/init.lua +++ b/mods/ITEMS/mcl_mobspawners/init.lua @@ -290,42 +290,6 @@ minetest.register_node("mcl_mobspawners:spawner", { on_timer = spawn_mobs, - on_receive_fields = function(pos, formname, fields, sender) - - if not fields.text or fields.text == "" then - return - end - - local meta = minetest.get_meta(pos) - local comm = fields.text:split(" ") - local name = sender:get_player_name() - - if minetest.is_protected(pos, name) then - minetest.record_protection_violation(pos, name) - return - end - - local mob = comm[1] -- mob to spawn - local mlig = tonumber(comm[2]) -- min light - local xlig = tonumber(comm[3]) -- max light - local num = tonumber(comm[4]) -- total mobs in area - local pla = tonumber(comm[5]) -- player distance (0 to disable) - local yof = tonumber(comm[6]) or 0 -- Y offset to spawn mob - - if mob and mob ~= "" and mobs.spawning_mobs[mob] == true - and num and num >= 0 and num <= 10 - and mlig and mlig >= 0 and mlig <= 15 - and xlig and xlig >= 0 and xlig <= 15 - and pla and pla >=0 and pla <= 20 - and yof and yof > -10 and yof < 10 then - - mcl_mobspawners.setup_spawner(pos, mob, mlig, xlig, num, pla, yof) - else - minetest.chat_send_player(name, S("Mob Spawner settings failed!")) - minetest.chat_send_player(name, - S("Syntax: name min_light[0-14] max_light[0-14] max_mobs_in_area[0 to disable] distance[1-20] y_offset[-10 to 10]")) - end - end, sounds = mcl_sounds.node_sound_metal_defaults(), _mcl_blast_resistance = 25, From 79e5a6dfa3895c762a7a6317e788003069126079 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 22:23:26 +0100 Subject: [PATCH 046/865] Fix typo in 3d_armor_stand --- mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua index 75a050e7..76dcec55 100644 --- a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua +++ b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua @@ -123,7 +123,7 @@ minetest.register_node("3d_armor_stand:armor_stand", { local protname = clicker:get_player_name() if minetest.is_protected(pos, protname) then minetest.record_protection_violation(pos, protname) - return + return itemstack end -- Check if player wields armor local name = itemstack:get_name() @@ -139,7 +139,7 @@ minetest.register_node("3d_armor_stand:armor_stand", { -- If player wields armor, put it on armor stand local inv = minetest.get_inventory({type = "node", pos = pos}) local wielditem = clicker:get_wielded_item() - if not inv then return end + if not inv then return itemstack end if list then -- ... but only if the slot is free local single_item = ItemStack(itemstack) @@ -148,7 +148,7 @@ minetest.register_node("3d_armor_stand:armor_stand", { inv:add_item(list, single_item) update_entity(pos) itemstack:take_item() - return itmstack + return itemstack end end From fb3db5077c23307c9b0367bd8a3ca34ab7a76f3e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 22:27:45 +0100 Subject: [PATCH 047/865] Fix slime code using nil arguments --- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index b23a693f..2c21dcfa 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -12,7 +12,7 @@ local S, NS = dofile(MP.."/intllib.lua") -- children_count: Number of children to spawn -- spawn_distance: Spawn distance from "mother" mob -- eject_speed: Initial speed of child mob away from "mother" mob -local spawn_children_on_die = function(self, pos, child_mob, children_count, spawn_distance, eject_speed) +local spawn_children_on_die = function(child_mob, children_count, spawn_distance, eject_speed) return function(self, pos) local angle, posadd, newpos, dir if not eject_speed then @@ -111,7 +111,7 @@ local slime_big = { jump_chance = 100, fear_height = 60, spawn_small_alternative = "mobs_mc:slime_small", - on_die = spawn_children_on_die(self, pos, "mobs_mc:slime_small", 4, 1.0, 1.5) + on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5) } mobs:register_mob("mobs_mc:slime_big", slime_big) @@ -126,7 +126,7 @@ slime_small.walk_velocity = 1.3 slime_small.run_velocity = 1.3 slime_small.jump_height = 4.3 slime_small.spawn_small_alternative = "mobs_mc:slime_tiny" -slime_small.on_die = spawn_children_on_die(self, pos, "mobs_mc:slime_tiny", 4, 0.6, 1.0) +slime_small.on_die = spawn_children_on_die("mobs_mc:slime_tiny", 4, 0.6, 1.0) mobs:register_mob("mobs_mc:slime_small", slime_small) local slime_tiny = table.copy(slime_big) @@ -215,7 +215,7 @@ local magma_cube_big = { jump_chance = 100, fear_height = 100000, spawn_small_alternative = "mobs_mc:magma_cube_small", - on_die = spawn_children_on_die(self, pos, "mobs_mc:magma_cube_small", 3, 0.8, 1.5) + on_die = spawn_children_on_die("mobs_mc:magma_cube_small", 3, 0.8, 1.5) } mobs:register_mob("mobs_mc:magma_cube_big", magma_cube_big) @@ -235,7 +235,7 @@ magma_cube_small.damage = 4 magma_cube_small.reach = 2.75 magma_cube_small.armor = 70 magma_cube_small.spawn_small_alternative = "mobs_mc:magma_cube_tiny" -magma_cube_small.on_die = spawn_children_on_die(self, pos, "mobs_mc:magma_cube_tiny", 4, 0.6, 1.0) +magma_cube_small.on_die = spawn_children_on_die("mobs_mc:magma_cube_tiny", 4, 0.6, 1.0) mobs:register_mob("mobs_mc:magma_cube_small", magma_cube_small) local magma_cube_tiny = table.copy(magma_cube_big) From a7d429a017570a3c55de25360614f6cdc4f1c2d7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 22:44:26 +0100 Subject: [PATCH 048/865] Fix several "undeclared global" errors --- mods/ENTITIES/mcl_mobs/api.txt | 2 +- mods/ENTITIES/mobs_mc/wither.lua | 6 +++--- mods/ITEMS/mcl_flowers/init.lua | 3 +-- mods/PLAYER/mcl_spawn/init.lua | 2 ++ 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.txt b/mods/ENTITIES/mcl_mobs/api.txt index c09151e9..157370d0 100644 --- a/mods/ENTITIES/mcl_mobs/api.txt +++ b/mods/ENTITIES/mcl_mobs/api.txt @@ -395,7 +395,7 @@ This function registers a arrow for mobs with the attack type shoot. (self, player) 'hit_mob' a function that is called when the arrow hits a mob; this function should hurt the mob, the parameters are - (self, player) + (self, mob) 'hit_node' a function that is called when the arrow hits a node, the parameters are (self, pos, node) 'tail' when set to 1 adds a trail or tail to mob arrows diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index a52fbdf6..9602d5a5 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -132,7 +132,7 @@ mobs:register_arrow(":mobs_mc:fireball", { -- direct hit, no fire... just plenty of pain hit_player = function(self, player) - minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 16}) + minetest.sound_play("tnt_explode", {pos = player:get_pos(), gain = 1.5, max_hear_distance = 16}) player:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 8}, @@ -140,8 +140,8 @@ mobs:register_arrow(":mobs_mc:fireball", { end, - hit_mob = function(self, player) - minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5,max_hear_distance = 16}) + hit_mob = function(self, mob) + minetest.sound_play("tnt_explode", {pos = mob:get_pos(), gain = 1.5,max_hear_distance = 16}) player:punch(self.object, 1.0, { full_punch_interval = 0.5, damage_groups = {fleshy = 8}, diff --git a/mods/ITEMS/mcl_flowers/init.lua b/mods/ITEMS/mcl_flowers/init.lua index 337a5495..ac575e12 100644 --- a/mods/ITEMS/mcl_flowers/init.lua +++ b/mods/ITEMS/mcl_flowers/init.lua @@ -398,14 +398,13 @@ minetest.register_node("mcl_flowers:waterlily", { local idef = itemstack:get_definition() if idef.sounds and idef.sounds.place then - minetest.sound_play(idef.sounds.place, {pos=above, gain=1}) + minetest.sound_play(idef.sounds.place, {pos=pointed_thing.above, gain=1}) end if not minetest.settings:get_bool("creative_mode") then itemstack:take_item() end else - minetest.chat_send_player(player_name, "Node is protected") minetest.record_protection_violation(pos, player_name) end end diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 9c9079b9..d5391f7d 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -1,5 +1,7 @@ mcl_spawn = {} +local mg_name = minetest.get_mapgen_setting("mg_name") + -- Returns current spawn position of player. -- If player is nil or not a player, the default spawn point is returned. -- The second return value is true if spawn point is player-chosen, From 9817b389045d83f1353bebb77a4ba1dfa2907cba Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 23:17:08 +0100 Subject: [PATCH 049/865] Fix bucket crash --- mods/ITEMS/mcl_buckets/init.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index f53cad4c..5840346b 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -327,7 +327,10 @@ if mod_mcl_core then "Right-click on any block to empty the bucket and put a water source on this spot.", function(pos, placer) -- Check protection - local placer_name = placer:get_player_name() + local placer_name = "" + if placer ~= nil then + placer_name = placer:get_player_name() + end if minetest.is_protected(pos, placer_name) then minetest.record_protection_violation(pos, placer_name) return false @@ -366,7 +369,10 @@ if mod_mclx_core then "Right-click on any block to empty the bucket and put a river water source on this spot.", function(pos, placer) -- Check protection - local placer_name = placer:get_player_name() + local placer_name = "" + if placer ~= nil then + placer_name = placer:get_player_name() + end if minetest.is_protected(pos, placer_name) then minetest.record_protection_violation(pos, placer_name) return false From b729ffc604e350b22ef75e0a6e501315ded37543 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 23:17:20 +0100 Subject: [PATCH 050/865] Spawning fire now respects protection --- mods/ITEMS/mcl_fire/fire_charge.lua | 7 +++++++ mods/ITEMS/mcl_fire/flint_and_steel.lua | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/mods/ITEMS/mcl_fire/fire_charge.lua b/mods/ITEMS/mcl_fire/fire_charge.lua index 144d1959..26259e04 100644 --- a/mods/ITEMS/mcl_fire/fire_charge.lua +++ b/mods/ITEMS/mcl_fire/fire_charge.lua @@ -15,6 +15,13 @@ minetest.register_craftitem("mcl_fire:fire_charge", { end end + -- Check protection + local protname = user:get_player_name() + if minetest.is_protected(pointed_thing.under, protname) then + minetest.record_protection_violation(pointed_thing.under, protname) + return itemstack + end + -- Ignite/light fire if pointed_thing.type == "node" then local nodedef = minetest.registered_nodes[node.name] diff --git a/mods/ITEMS/mcl_fire/flint_and_steel.lua b/mods/ITEMS/mcl_fire/flint_and_steel.lua index 3b6861f5..0ab4043f 100644 --- a/mods/ITEMS/mcl_fire/flint_and_steel.lua +++ b/mods/ITEMS/mcl_fire/flint_and_steel.lua @@ -15,6 +15,12 @@ minetest.register_tool("mcl_fire:flint_and_steel", { return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack end end + -- Check protection + local protname = user:get_player_name() + if minetest.is_protected(pointed_thing.under, protname) then + minetest.record_protection_violation(pointed_thing.under, protname) + return itemstack + end local idef = itemstack:get_definition() minetest.sound_play( @@ -44,11 +50,13 @@ minetest.register_tool("mcl_fire:flint_and_steel", { end, _dispense_into_walkable = true, _on_dispense = function(stack, pos, droppos, dropnode, dropdir) + -- Ignite air if dropnode.name == "air" then minetest.add_node(droppos, {name="mcl_fire:fire"}) if not minetest.settings:get_bool("creative_mode") then stack:add_wear(65535/65) -- 65 uses end + -- Ignite TNT elseif dropnode.name == "mcl_tnt:tnt" then tnt.ignite(droppos) if not minetest.settings:get_bool("creative_mode") then From 46c7413337204ef03db5fcf5833fb0f36cbc2f4a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 23:29:12 +0100 Subject: [PATCH 051/865] Bucket dispensers now ignore protection Otherwise, it bucket dispensers would not work on your own property. --- mods/ITEMS/mcl_buckets/init.lua | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index 5840346b..f05d725c 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -166,10 +166,6 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent -- Fail placement of liquid elseif buildable then -- buildable; replace the node - if minetest.is_protected(droppos, "") then - minetest.record_protection_violation(droppos, "") - return stack - end local node_place if type(source_place) == "function" then node_place = source_place(droppos) @@ -267,11 +263,6 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { end end, _on_dispense = function(stack, pos, droppos, dropnode, dropdir) - if minetest.is_protected(droppos, "") then - minetest.record_protection_violation(droppos, "") - return stack - end - -- Fill empty bucket with liquid or drop bucket if no liquid local collect_liquid = false @@ -331,7 +322,7 @@ if mod_mcl_core then if placer ~= nil then placer_name = placer:get_player_name() end - if minetest.is_protected(pos, placer_name) then + if placer and minetest.is_protected(pos, placer_name) then minetest.record_protection_violation(pos, placer_name) return false end @@ -373,7 +364,7 @@ if mod_mclx_core then if placer ~= nil then placer_name = placer:get_player_name() end - if minetest.is_protected(pos, placer_name) then + if placer and minetest.is_protected(pos, placer_name) then minetest.record_protection_violation(pos, placer_name) return false end From 5b0945b88c159df529e72cd67774c5c921a551e9 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 8 Feb 2019 23:55:49 +0100 Subject: [PATCH 052/865] Don't change water bottles when using in creative --- mods/ITEMS/mcl_potions/init.lua | 50 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 2920cfdd..9932ed93 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -76,26 +76,28 @@ minetest.register_craftitem("mcl_potions:glass_bottle", { end end if get_water then - -- Replace with water bottle, if possible, otherwise - -- place the water potion at a place where's space - local water_bottle - if river_water then - water_bottle = ItemStack("mcl_potions:potion_river_water") - else - water_bottle = ItemStack("mcl_potions:potion_water") + if minetest.settings:get_bool("creative_mode") ~= true then + -- Replace with water bottle, if possible, otherwise + -- place the water potion at a place where's space + local water_bottle + if river_water then + water_bottle = ItemStack("mcl_potions:potion_river_water") + else + water_bottle = ItemStack("mcl_potions:potion_water") + end + if itemstack:get_count() == 1 then + return water_bottle + else + local inv = placer:get_inventory() + if inv:room_for_item("main", water_bottle) then + inv:add_item("main", water_bottle) + else + minetest.add_item(placer:get_pos(), water_bottle) + end + itemstack:take_item() + end end minetest.sound_play("mcl_potions_bottle_fill", {pos=pointed_thing.under, gain=0.5, max_hear_range=16}) - if itemstack:get_count() == 1 then - return water_bottle - else - local inv = placer:get_inventory() - if inv:room_for_item("main", water_bottle) then - inv:add_item("main", water_bottle) - else - minetest.add_item(placer:get_pos(), water_bottle) - end - itemstack:take_item() - end end end return itemstack @@ -175,7 +177,11 @@ minetest.register_craftitem("mcl_potions:potion_water", { -- Increase water level of cauldron by 1 minetest.set_node(pointed_thing.under, {name=cauldron}) minetest.sound_play("mcl_potions_bottle_pour", {pos=pointed_thing.under, gain=0.5, max_hear_range=16}) - return "mcl_potions:glass_bottle" + if minetest.settings:get_bool("creative_mode") == true then + return itemstack + else + return "mcl_potions:glass_bottle" + end end end @@ -215,7 +221,11 @@ minetest.register_craftitem("mcl_potions:potion_river_water", { -- Increase water level of cauldron by 1 minetest.set_node(pointed_thing.under, {name=cauldron}) minetest.sound_play("mcl_potions_bottle_pour", {pos=pointed_thing.under, gain=0.5, max_hear_range=16}) - return "mcl_potions:glass_bottle" + if minetest.settings:get_bool("creative_mode") == true then + return itemstack + else + return "mcl_potions:glass_bottle" + end end end From 986871f2b55d7da3ec7a562b0f3dd2c2ffa617eb Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 00:05:00 +0100 Subject: [PATCH 053/865] No replace empty bottle if used on src in creative --- mods/ITEMS/mcl_potions/init.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_potions/init.lua b/mods/ITEMS/mcl_potions/init.lua index 9932ed93..ea859127 100644 --- a/mods/ITEMS/mcl_potions/init.lua +++ b/mods/ITEMS/mcl_potions/init.lua @@ -38,12 +38,14 @@ minetest.register_craftitem("mcl_potions:glass_bottle", { -- Try to fill glass bottle with water local get_water = false + local from_liquid_source = false local river_water = false if not def then -- Unknown node: no-op elseif def.groups and def.groups.water and def.liquidtype == "source" then -- Water source get_water = true + from_liquid_source = true river_water = node.name == "mclx_core:river_water_source" -- Or reduce water level of cauldron by 1 elseif string.sub(node.name, 1, 14) == "mcl_cauldrons:" then @@ -76,7 +78,8 @@ minetest.register_craftitem("mcl_potions:glass_bottle", { end end if get_water then - if minetest.settings:get_bool("creative_mode") ~= true then + local creative = minetest.settings:get_bool("creative_mode") == true + if from_liquid_source or creative then -- Replace with water bottle, if possible, otherwise -- place the water potion at a place where's space local water_bottle @@ -85,10 +88,15 @@ minetest.register_craftitem("mcl_potions:glass_bottle", { else water_bottle = ItemStack("mcl_potions:potion_water") end - if itemstack:get_count() == 1 then + local inv = placer:get_inventory() + if creative then + -- Don't replace empty bottle in creative for convenience reasons + if not inv:contains_item("main", water_bottle) then + inv:add_item("main", water_bottle) + end + elseif itemstack:get_count() == 1 then return water_bottle else - local inv = placer:get_inventory() if inv:room_for_item("main", water_bottle) then inv:add_item("main", water_bottle) else From 3ba4aabbcff6c4682a88df0cf099e55fc26d5844 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 00:17:25 +0100 Subject: [PATCH 054/865] Check for protection when using anvil formspec --- mods/ITEMS/mcl_anvils/init.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/ITEMS/mcl_anvils/init.lua b/mods/ITEMS/mcl_anvils/init.lua index 3863583f..8b3717a3 100644 --- a/mods/ITEMS/mcl_anvils/init.lua +++ b/mods/ITEMS/mcl_anvils/init.lua @@ -407,6 +407,11 @@ local anvildef = { meta:set_string("formspec", form) end, on_receive_fields = function(pos, formname, fields, sender) + local sender_name = sender:get_player_name() + if minetest.is_protected(pos, sender_name) then + minetest.record_protection_violation(pos, sender_name) + return + end if fields.name_button or fields.name then local set_name if fields.name == nil then From 3ec79149626a3a39d4593d95faefef3696ad5159 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 02:42:11 +0100 Subject: [PATCH 055/865] Allow to use Minetest's original flat mapgen again --- mods/CORE/mcl_init/init.lua | 29 ++++++++++++++++-------- mods/ITEMS/mcl_portals/portal_nether.lua | 12 ++++++++-- mods/MAPGEN/mcl_biomes/init.lua | 7 ++++-- mods/MAPGEN/mcl_mapgen_core/init.lua | 29 ++++++------------------ settingtypes.txt | 25 ++++++++++++-------- 5 files changed, 57 insertions(+), 45 deletions(-) diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index d239c8d9..de50bf00 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -11,7 +11,10 @@ mcl_vars.inventory_header = mcl_vars.gui_slots .. mcl_vars.gui_bg -- Mapgen variables local mg_name = minetest.get_mapgen_setting("mg_name") local minecraft_height_limit = 256 -if mg_name ~= "flat" then +local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" + +if not superflat then + -- Normal mode --[[ Realm stacking (h is for height) - Overworld (h>=256) - Void (h>=1000) @@ -32,17 +35,13 @@ if mg_name ~= "flat" then mcl_vars.mg_bedrock_is_rough = true else + -- Classic superflat local ground = minetest.get_mapgen_setting("mgflat_ground_level") ground = tonumber(ground) if not ground then ground = 8 end - -- 1 perfectly flat bedrock layer - if minetest.get_mapgen_setting("mcl_superflat_classic") == "false" then - mcl_vars.mg_overworld_min = -30912 - else - mcl_vars.mg_overworld_min = ground - 3 - end + mcl_vars.mg_overworld_min = ground - 3 mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min @@ -58,14 +57,24 @@ mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128 mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max -mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31 -if mg_name ~= "flat" then +if not superflat then mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4 mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4 + mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31 else - -- Thin bedrock in flat mapgen + -- Thin bedrock in classic superflat mapgen mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max + mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2 +end +if mg_name == "flat" then + if superflat then + mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4 + mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52 + else + mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4 + mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52 + end end -- The End (surface at ca. Y = -27000) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index d08bddef..64de52ba 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -13,6 +13,7 @@ local TELEPORT_DELAY = 3 -- seconds before teleporting in Nether portal local TELEPORT_COOLOFF = 4 -- after object was teleported, for this many seconds it won't teleported again local mg_name = minetest.get_mapgen_setting("mg_name") +local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" -- 3D noise local np_cave = { @@ -187,7 +188,7 @@ end local function find_nether_target_y(target_x, target_z) if mg_name == "flat" then - return mcl_vars.mg_bedrock_nether_bottom_max + 5 + return mcl_vars.mg_flat_nether_floor + 1 end local start_y = math.random(mcl_vars.mg_lava_nether_max + 1, mcl_vars.mg_bedrock_nether_top_min - 5) -- Search start if not nobj_cave then @@ -330,8 +331,15 @@ function mcl_portals.light_nether_portal(pos) local target = {x = p1.x, y = p1.y, z = p1.z} target.x = target.x + 1 if target.y < mcl_vars.mg_nether_max and target.y > mcl_vars.mg_nether_min then - if mg_name == "flat" then + if superflat then target.y = mcl_vars.mg_bedrock_overworld_max + 5 + elseif mg_name == "flat" then + local ground = minetest.get_mapgen_setting("mgflat_ground_level") + ground = tonumber(ground) + if not ground then + ground = 8 + end + target.y = ground + 2 else target.y = math.random(mcl_vars.mg_overworld_min + 40, mcl_vars.mg_overworld_min + 96) end diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index 20a08664..f37929c4 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -2,6 +2,7 @@ local mg_name = minetest.get_mapgen_setting("mg_name") -- Some mapgen settings local imitate = minetest.settings:get("mcl_imitation_mode") +local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" local generate_fallen_logs = false @@ -3209,7 +3210,7 @@ end -- Detect mapgen to select functions -- if mg_name ~= "singlenode" then - if mg_name ~= "flat" then + if not superflat then if mg_name ~= "v6" then register_biomes() register_biomelike_ores() @@ -3219,7 +3220,9 @@ if mg_name ~= "singlenode" then register_decorations() end else - -- Implementation of Minecraft's Superflat mapgen, classic style + -- Implementation of Minecraft's Superflat mapgen, classic style: + -- * Perfectly flat land, 1 grass biome, no decorations, no caves + -- * 4 layers, from top to bottom: grass block, dirt, dirt, bedrock minetest.clear_registered_biomes() minetest.clear_registered_decorations() minetest.clear_registered_schematics() diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 02645d0c..0586404d 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -44,6 +44,7 @@ minetest.register_alias("mapgen_stair_sandstone_block", "mcl_stairs:stair_sandst minetest.register_alias("mapgen_stair_desert_stone", "mcl_stairs:stair_sandstone") local mg_name = minetest.get_mapgen_setting("mg_name") +local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" local WITCH_HUT_HEIGHT = 3 -- Exact Y level to spawn witch huts at. This height refers to the height of the floor @@ -550,8 +551,7 @@ minetest.register_ore({ y_max = mcl_worlds.layer_to_y(32), }) -if mg_name ~= "flat" then - +if not superflat then -- Water and lava springs (single blocks of lava/water source) -- Water appears at nearly every height, but not near the bottom minetest.register_ore({ @@ -622,13 +622,8 @@ minetest.register_ore({ y_min = mcl_worlds.layer_to_y(62), y_max = mcl_worlds.layer_to_y(127), }) - end - - - - local function register_mgv6_decorations() -- Cacti @@ -951,20 +946,10 @@ end if mg_name == "v6" then register_mgv6_decorations() minetest.set_mapgen_setting("mg_flags", "caves,nodungeons,decorations,light", true) -elseif mg_name == "flat" then - local classic = minetest.get_mapgen_setting("mcl_superflat_classic") - if classic == nil then - classic = minetest.settings:get_bool("mcl_superflat_classic") - minetest.set_mapgen_setting("mcl_superflat_classic", "true", true) - end - if classic ~= "false" then - -- Enforce superflat-like mapgen: No hills, lakes or caves - minetest.set_mapgen_setting("mg_flags", "nocaves,nodungeons,nodecorations,light", true) - minetest.set_mapgen_setting("mgflat_spflags", "nolakes,nohills", true) - else - -- If superflat mode is disabled, mapgen is way more liberal - minetest.set_mapgen_setting("mg_flags", "caves,nodungeons,nodecorations,light", true) - end +elseif superflat then + -- Enforce superflat-like mapgen: No hills, lakes or caves + minetest.set_mapgen_setting("mg_flags", "nocaves,nodungeons,nodecorations,light", true) + minetest.set_mapgen_setting("mgflat_spflags", "nolakes,nohills", true) else minetest.set_mapgen_setting("mg_flags", "caves,nodungeons,decorations,light", true) end @@ -1731,7 +1716,7 @@ minetest.register_on_generated(function(minp, maxp, seed) -- Flat Nether if mg_name == "flat" then - lvm_used = set_layers(c_air, nil, mcl_vars.mg_bedrock_nether_bottom_max + 4, mcl_vars.mg_bedrock_nether_bottom_max + 52, minp, maxp, lvm_used) + lvm_used = set_layers(c_air, nil, mcl_vars.mg_flat_nether_floor, mcl_vars.mg_flat_nether_ceiling, minp, maxp, lvm_used) end -- Big lava seas by replacing air below a certain height diff --git a/settingtypes.txt b/settingtypes.txt index 7409690d..1290c25c 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -95,17 +95,24 @@ flame_sound (Flame sound) bool true # Feedback is appreciated. craftguide_progressive_mode (Enable recipe book progressive mode) bool false -# If enabled, the “flat” map generator generates a “classic” superflat map: -# Completely flat, 1 layer of grass blocks on top of 2 layers of dirt on -# top of a final layer of bedrock. -# Note if this is enabled, the setting “mgflat_flags” is ignored. To -# customize the “flat” map generator, you must disable this setting. -# Warning: Disabling this setting is currently EXPERIMENTAL! The generated map -# may not be that pretty. -mcl_superflat_classic (Classic superflat map generation) bool true - # Mobs difficulty. This is a number that will affect the initial and maximum # health and the amount of damage that mobs deal. Health and damage will # be multiplied with this number. # This feature is not finished yet! mob_difficulty (Mob difficulty factor) float 1.0 0.0 + +# If enabled, the “flat” map generator generates a Classic Superflat world: +# Completely flat, 1 layer of grass blocks on top of 2 layers of dirt on +# top of a final layer of bedrock. No caves, trees or plants. +# Also, if enabled, the setting “mgflat_flags” is ignored. +# If disabled, Minetest's default flat map generator is used, that is, trees, +# caves, and a deeper underground can be generated. +# +# Caution: Change this setting with care! +# If you change this setting, then play on an existing flat world +# that started with a different setting (e.g. you changed from superflat +# from “enabled” to “disabled”), there will be continuity errors when players +# reach new areas. Most importantly, the void is much higher in Superflat than +# in “normal” Flat. +# But creating new flat worlds after changing this setting should be safe. +mcl_superflat_classic (Classic superflat map generation) bool true From d50ff261182be04c61be52062b108810e9a5ae26 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 03:11:15 +0100 Subject: [PATCH 056/865] =?UTF-8?q?Rename=20setting:=20mob=5Fspawn=5Fmulti?= =?UTF-8?q?plier=20=E2=86=92=20mobs=5Fspawn=5Fchance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mods/ENTITIES/mcl_mobs/api.lua | 4 ++-- settingtypes.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index a75a6e39..0f7057df 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -65,7 +65,7 @@ local remove_far = false local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0 local show_health = false local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99) -local mob_chance_multiplier = tonumber(minetest.settings:get("mob_chance_multiplier") or 1) +local mobs_spawn_chance = tonumber(minetest.settings:get("mobs_spawn_chance") or 1) -- Peaceful mode message so players will know there are no monsters if peaceful_only then @@ -3335,7 +3335,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, nodenames = nodes, neighbors = neighbors, interval = interval, - chance = max(1, (chance * mob_chance_multiplier)), + chance = max(1, (chance * mobs_spawn_chance)), catch_up = false, action = spawn_abm_action, }) diff --git a/settingtypes.txt b/settingtypes.txt index 1290c25c..69a51081 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -62,7 +62,7 @@ mobs_spawn (Spawn mobs naturally) bool true # Controls the overall amount of mobs that spawn. The higher the number, # the less often mobs will spawn. This does not affect mob spawners. -mob_chance_multiplier (Mob spawn multiplier) float 1.0 0.0 +mobs_spawn_chance (Mob spawn chance) float 1.0 0.0 # If enabled, only peaceful mobs will appear naturally. This does not # affect mob spawners. From e89a01630bb673365d182ebcebd1b947d01dfa12 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 04:32:55 +0100 Subject: [PATCH 057/865] Remove misunderstood replacements from decorations I thought it would replace nodes on the map, but it turned it it replaces nodes from the schematic definition. --- mods/MAPGEN/mcl_biomes/init.lua | 6 ------ mods/MAPGEN/mcl_mapgen_core/init.lua | 6 ------ 2 files changed, 12 deletions(-) diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index f37929c4..93945354 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -2473,9 +2473,6 @@ local function register_decorations() { name = "mcl_flowers:double_grass_top", param1=255, param2=param2 }, }, }, - replacements = { - ["mcl_flowers:tallgrass"] = "mcl_flowers:double_grass", - }, place_on = {"group:grass_block_no_snow"}, sidelen = 16, noise_params = { @@ -2508,9 +2505,6 @@ local function register_decorations() { name = "mcl_flowers:double_fern_top", param1=255, }, }, }, - replacements = { - ["mcl_flowers:fern"] = "mcl_flowers:double_fern" - }, place_on = {"group:grass_block_no_snow", "mcl_core:podzol"}, sidelen = 16, noise_params = { diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 0586404d..eb9caa63 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -679,9 +679,6 @@ local function register_mgv6_decorations() { name = "mcl_flowers:double_grass_top", param1 = 255, }, }, }, - replacements = { - ["mcl_flowers:tallgrass"] = "mcl_flowers:double_grass" - }, place_on = {"group:grass_block_no_snow"}, sidelen = 8, noise_params = { @@ -707,9 +704,6 @@ local function register_mgv6_decorations() { name = "mcl_flowers:double_fern_top", param1=255, }, }, }, - replacements = { - ["mcl_flowers:fern"] = "mcl_flowers:double_fern" - }, -- v6 hack: This makes sure large ferns only appear in jungles spawn_by = { "mcl_core:jungletree", "mcl_flowers:fern" }, num_spawn_by = 1, From e28f213f9aff61e51ff5fa9d7932d540d8a90d3f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 05:58:40 +0100 Subject: [PATCH 058/865] Add workaround to fix broken double plants in v6 --- mods/MAPGEN/mcl_mapgen_core/init.lua | 35 +++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index eb9caa63..9a979d43 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -1729,12 +1729,13 @@ minetest.register_on_generated(function(minp, maxp, seed) ----- The section to perform basic block overrides of the core mapgen generated world. ----- -- Snow and sand fixes. This code implements snow consistency - -- and fixes floating sand. + -- and fixes floating sand and cut plants. -- A snowy grass block must be below a top snow or snow block at all times. - if minp.y <= mcl_vars.mg_overworld_max and maxp.y >= mcl_vars.mg_overworld_min then + if emin.y <= mcl_vars.mg_overworld_max and emax.y >= mcl_vars.mg_overworld_min then -- v6 mapgen: -- Put top snow on snowy grass blocks. The mapgen does not generate the top snow on its own. if mg_name == "v6" then + -- FIXME: Cavegen and mudflow might screw this up and cause floating top snow to appear local snowdirt = minetest.find_nodes_in_area_under_air(minp, maxp, "mcl_core:dirt_with_grass_snow") for n = 1, #snowdirt do -- CHECKME: What happens at chunk borders? @@ -1743,10 +1744,38 @@ minetest.register_on_generated(function(minp, maxp, seed) data[p_pos] = c_top_snow end end - if #snowdirt > 1 then + if #snowdirt > 0 then lvm_used = true end + --[[ Remove broken double plants caused by v6 weirdness. + v6 might break the bottom part of double plants because of how it works. + There are 3 possibilities: + 1) Jungle: Top part is placed on top of a jungle tree or fern (=v6 jungle grass). + This is because the schematic might be placed even if some nodes of it + could not be placed because the destination was already occupied. + TODO: A better fix for this would be if schematics could abort placement + altogether if ANY of their nodes could not be placed. + 2) Cavegen: Removes the bottom part, the upper part floats + 3) Mudflow: Same as 2) ]] + local plants = minetest.find_nodes_in_area(emin, emax, "group:double_plant") + for n = 1, #plants do + local node = vm:get_node_at(plants[n]) + local is_top = minetest.get_item_group(node.name, "double_plant") == 2 + if is_top then + local p_pos = area:index(plants[n].x, plants[n].y-1, plants[n].z) + if p_pos then + node = vm:get_node_at({x=plants[n].x, y=plants[n].y-1, z=plants[n].z}) + local is_bottom = minetest.get_item_group(node.name, "double_plant") == 1 + if not is_bottom then + p_pos = area:index(plants[n].x, plants[n].y, plants[n].z) + data[p_pos] = c_air + lvm_used = true + end + end + end + end + -- Non-v6 mapgens: -- Clear snowy grass blocks without snow above to ensure consistency. From 9e578289585c4911bfabfcc62c8b8d2fb1de84fc Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 9 Feb 2019 21:28:53 +0100 Subject: [PATCH 059/865] Add tileable_vertical to covered dirt nodes --- mods/ITEMS/mcl_core/functions.lua | 2 +- mods/ITEMS/mcl_core/nodes_base.lua | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mods/ITEMS/mcl_core/functions.lua b/mods/ITEMS/mcl_core/functions.lua index 58182053..c040ce7e 100644 --- a/mods/ITEMS/mcl_core/functions.lua +++ b/mods/ITEMS/mcl_core/functions.lua @@ -1226,7 +1226,7 @@ mcl_core.register_snowed_node = function(itemstring_snowed, itemstring_clear, ti -- Note: _mcl_snowed must be added to the clear node manually! if not tiles then - def.tiles = {"default_snow.png", "default_dirt.png", "mcl_core_grass_side_snowed.png"} + def.tiles = {"default_snow.png", "default_dirt.png", {name="mcl_core_grass_side_snowed.png", tileable_vertical=false}} else def.tiles = tiles end diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index 10739109..f2299e07 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -310,7 +310,7 @@ minetest.register_node("mcl_core:dirt_with_grass", { description = "Grass Block", _doc_items_longdesc = "A grass block is dirt with a grass cover. Grass blocks are resourceful blocks which allow the growth of all sorts of plants. They can be turned into farmland with a hoe and turned into grass paths with a shovel. In light, the grass slowly spreads onto dirt nearby. Under an opaque block or a liquid, a grass block may turn back to dirt.", _doc_items_hidden = false, - tiles = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, + tiles = {"default_grass.png", "default_dirt.png", {name="default_dirt.png^default_grass_side.png", tileable_vertical=false}}, is_ground_content = true, stack_max = 64, groups = {handy=1,shovely=1, grass_block=1, grass_block_no_snow=1, soil=1, soil_sapling=2, soil_sugarcane=1, cultivatable=2, spreading_dirt_type=1, enderman_takable=1, building_block=1}, @@ -344,7 +344,7 @@ mcl_core.register_snowed_node("mcl_core:dirt_with_grass_snow", "mcl_core:dirt_wi -- Grass Block variant for dry biomes minetest.register_node("mcl_core:dirt_with_dry_grass", { _doc_items_create_entry = false, - tiles = {"default_dry_grass.png", "default_dirt.png", "default_dirt.png^default_dry_grass_side.png"}, + tiles = {"default_dry_grass.png", "default_dirt.png", {name="default_dirt.png^default_dry_grass_side.png", tileable_vertical=false}}, is_ground_content = true, stack_max = 64, groups = {handy=1,shovely=1, grass_block=1, grass_block_no_snow=1, soil=1, soil_sapling=2, soil_sugarcane=1, cultivatable=2, spreading_dirt_type=1, enderman_takable=1, building_block=1, not_in_creative_inventory=1}, @@ -392,7 +392,7 @@ minetest.register_node("mcl_core:grass_path", { minetest.register_node("mcl_core:mycelium", { description = "Mycelium", _doc_items_longdesc = "Mycelium is a type of dirt and the ideal soil for mushrooms. Unlike other dirt-type blocks, it can not be turned into farmland with a hoe. In light, mycelium slowly spreads over nearby dirt. Under an opaque block or a liquid, it eventually turns back into dirt.", - tiles = {"mcl_core_mycelium_top.png", "default_dirt.png", "mcl_core_mycelium_side.png"}, + tiles = {"mcl_core_mycelium_top.png", "default_dirt.png", {name="mcl_core_mycelium_side.png", tileable_vertical=false}}, is_ground_content = true, stack_max = 64, groups = {handy=1,shovely=1, spreading_dirt_type=1, building_block=1}, @@ -411,7 +411,7 @@ mcl_core.register_snowed_node("mcl_core:mycelium_snow", "mcl_core:mycelium") minetest.register_node("mcl_core:podzol", { description = "Podzol", _doc_items_longdesc = "Podzol is a type of dirt found in taiga forests. Only a few plants are able to survive on it.", - tiles = {"mcl_core_dirt_podzol_top.png", "default_dirt.png", "mcl_core_dirt_podzol_side.png"}, + tiles = {"mcl_core_dirt_podzol_top.png", "default_dirt.png", {name="mcl_core_dirt_podzol_side.png", tileable_vertical=false}}, is_ground_content = true, stack_max = 64, groups = {handy=1,shovely=3, soil=1, soil_sapling=2, soil_sugarcane=1, enderman_takable=1, building_block=1}, From 5a7952bf9251bdf549863a1e5731ab728ab2e3d8 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 15:49:36 +0100 Subject: [PATCH 060/865] Set mob spawn chance to 2.5 and fix player respawn msg --- mods/ENTITIES/mcl_mobs/api.lua | 4 ++-- mods/PLAYER/mcl_spawn/init.lua | 30 ++++++++++++++++++------------ settingtypes.txt | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 0f7057df..30b8a582 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -65,7 +65,7 @@ local remove_far = false local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0 local show_health = false local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99) -local mobs_spawn_chance = tonumber(minetest.settings:get("mobs_spawn_chance") or 1) +local mobs_spawn_chance = tonumber(minetest.settings:get("mobs_spawn_chance") or 2.5) -- Peaceful mode message so players will know there are no monsters if peaceful_only then @@ -3335,7 +3335,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, nodenames = nodes, neighbors = neighbors, interval = interval, - chance = max(1, (chance * mobs_spawn_chance)), + chance = floor(max(1, chance * mobs_spawn_chance)), catch_up = false, action = spawn_abm_action, }) diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index d5391f7d..f97f1700 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -2,33 +2,37 @@ mcl_spawn = {} local mg_name = minetest.get_mapgen_setting("mg_name") --- Returns current spawn position of player. +-- Returns current custom spawn position of player. +-- Returns nil if player has no custom spawn position. -- If player is nil or not a player, the default spawn point is returned. -- The second return value is true if spawn point is player-chosen, -- false otherwise. mcl_spawn.get_spawn_pos = function(player) - local spawn, custom_spawn + local spawn, custom_spawn = nil, false if player ~= nil and player:is_player() then - spawn = minetest.string_to_pos(player:get_attribute("mcl_beds:spawn")) - custom_spawn = true + local attr = player:get_attribute("mcl_beds:spawn") + if attr ~= nil and attr ~= "" then + spawn = minetest.string_to_pos(attr) + custom_spawn = true + end end if not spawn or spawn == "" then spawn = minetest.setting_get_pos("static_spawnpoint") custom_spawn = false end - if not spawn then - spawn = { x=0, y=0, z=0 } - if mg_name == "flat" then - spawn.y = mcl_vars.mg_bedrock_overworld_max + 5 + if not spawn or spawn == "" then + local attr = player:get_attribute("mcl_spawn:first_spawn") + if attr ~= nil and attr ~= "" then + spawn = minetest.string_to_pos(attr) + custom_spawn = false end - custom_spawn = false end return spawn, custom_spawn end -- Sets the player's spawn position to pos. -- Set pos to nil to clear the spawn position. -mcl_spawn.set_spawn_pos = function(player, pos) +mcl_spawn.set_spawn_pos = function(player, pos, type) if pos == nil then player:set_attribute("mcl_beds:spawn", "") else @@ -39,7 +43,7 @@ end -- Respawn player at specified respawn position minetest.register_on_respawnplayer(function(player) local pos, custom_spawn = mcl_spawn.get_spawn_pos(player) - if custom_spawn then + if pos and custom_spawn then -- Check if bed is still there -- and the spawning position is free of solid or damaging blocks. local node_bed = minetest.get_node(pos) @@ -65,5 +69,7 @@ minetest.register_on_respawnplayer(function(player) end) minetest.register_on_newplayer(function(player) - mcl_spawn.set_spawn_pos(player, player:get_pos()) + -- Remember where the player spawned first + player:set_attribute("mcl_spawn:first_spawn", minetest.pos_to_string(player:get_pos())) end) + diff --git a/settingtypes.txt b/settingtypes.txt index 69a51081..1adfec3f 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -62,7 +62,7 @@ mobs_spawn (Spawn mobs naturally) bool true # Controls the overall amount of mobs that spawn. The higher the number, # the less often mobs will spawn. This does not affect mob spawners. -mobs_spawn_chance (Mob spawn chance) float 1.0 0.0 +mobs_spawn_chance (Mob spawn chance) float 2.5 0.0 # If enabled, only peaceful mobs will appear naturally. This does not # affect mob spawners. From 49949e2f36b8eff7d50aecd79e919e2d24d92837 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 16:14:08 +0100 Subject: [PATCH 061/865] Don't allow to go to bed while player moves --- mods/ITEMS/mcl_beds/functions.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index b1eaa85a..f763a23c 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -71,6 +71,14 @@ local function lay_down(player, pos, bed_pos, state, skip) return end + -- No sleeping while moving. This is a workaround. + -- TODO: Ideally, the player speed should be force-set to 0, + -- but this is not possible in Minetest 0.4.17. + if vector.length(player:get_player_velocity()) > 0.001 then + minetest.chat_send_player(name, "You have to stop moving before going to bed!") + return + end + -- No sleeping if monsters nearby. -- The exceptions above apply. -- Zombie pigmen only prevent sleep while they are hostle. From 1cbbe8f4b13c7782dc6fca6f9def5e2364ce3c26 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 17:45:42 +0100 Subject: [PATCH 062/865] Refactor playerphysics init --- mods/PLAYER/playerphysics/init.lua | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/mods/PLAYER/playerphysics/init.lua b/mods/PLAYER/playerphysics/init.lua index 0b9420b1..2b7d7df0 100644 --- a/mods/PLAYER/playerphysics/init.lua +++ b/mods/PLAYER/playerphysics/init.lua @@ -1,43 +1,43 @@ playerphysics = {} -local function calculate_physic_product(player, physic) +local function calculate_attribute_product(player, attribute) local a = minetest.deserialize(player:get_attribute("playerphysics:physics")) local product = 1 - if a == nil or a[physic] == nil then + if a == nil or a[attribute] == nil then return product end - local factors = a[physic] + local factors = a[attribute] if type(factors) == "table" then - for id, factor in pairs(factors) do + for _, factor in pairs(factors) do product = product * factor end end return product end -function playerphysics.add_physics_factor(player, physic, id, value) +function playerphysics.add_physics_factor(player, attribute, id, value) local a = minetest.deserialize(player:get_attribute("playerphysics:physics")) if a == nil then - a = { [physic] = { [id] = value } } - elseif a[physic] == nil then - a[physic] = { [id] = value } + a = { [attribute] = { [id] = value } } + elseif a[attribute] == nil then + a[attribute] = { [id] = value } else - a[physic][id] = value + a[attribute][id] = value end player:set_attribute("playerphysics:physics", minetest.serialize(a)) - local raw_value = calculate_physic_product(player, physic) - player:set_physics_override({[physic] = raw_value}) + local raw_value = calculate_attribute_product(player, attribute) + player:set_physics_override({[attribute] = raw_value}) end -function playerphysics.remove_physics_factor(player, physic, id) +function playerphysics.remove_physics_factor(player, attribute, id) local a = minetest.deserialize(player:get_attribute("playerphysics:physics")) - if a == nil or a[physic] == nil then + if a == nil or a[attribute] == nil then -- Nothing to remove return else - a[physic][id] = nil + a[attribute][id] = nil end player:set_attribute("playerphysics:physics", minetest.serialize(a)) - local raw_value = calculate_physic_product(player, physic) - player:set_physics_override({[physic] = raw_value}) + local raw_value = calculate_attribute_product(player, attribute) + player:set_physics_override({[attribute] = raw_value}) end From 2ffd16377bc9a5f05d15beee81f080d519785952 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 17:48:49 +0100 Subject: [PATCH 063/865] Update playerphysics README --- mods/PLAYER/playerphysics/README.md | 68 +++++++++---- mods/PLAYER/playerphysics/README.md.bak | 116 ++++++++++++++++++++++ mods/PLAYER/playerphysics/description.txt | 2 +- 3 files changed, 168 insertions(+), 18 deletions(-) create mode 100644 mods/PLAYER/playerphysics/README.md.bak diff --git a/mods/PLAYER/playerphysics/README.md b/mods/PLAYER/playerphysics/README.md index 5a522878..303213fb 100644 --- a/mods/PLAYER/playerphysics/README.md +++ b/mods/PLAYER/playerphysics/README.md @@ -2,39 +2,73 @@ Version: 1.0.0 -This mod simplifies the modification of player physics (speed, jumping height, gravity). +This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict. -The problem with `set_physics_override` is that is sets a raw value. -As soon as two independent mods want to mess with player physics, this is a problem. +## Introduction +### For players +Mods and games in Minetest can set physical attributes of players, such as speed and jump strength. For example, player speed could be set to 200%. But the way this works makes it difficult for multiple mods to *modify* physical attributes without leading to conflicts, problems and hilarious bugs, like speed that changes often to nonsense values. -This has a different approach in that you add and remove an arbitrary number of factors for each attribute. -The actual player attribute will be the product of all factors which have been added. +The Player Physics API aims to resolve this conflict by providing a “common ground” for mods to work together in this regard. -## Preconditions +This mod does nothing on its own, you will only need to install it as dependency of other mods. + +When you browse for mods that somehow mess with player physics (namely: speed, jump strength or gravity) and want to use more than one of them, check out if they support the Player Physics API. If they don't, it's very likely these mods will break as soon you activate more than one of them, for example, if two mods try to set the player speed. If you found such a “hilarious bug”, please report it to the developers of the mods (or games) and point them to the Player Physics API. + +Of course, not all mods need the Player Physics API. Mods that don't touch player physics at all won't need this mod. + +The rest of this document is directed at developers. + +### For developers +The function `set_physics_override` from the Minetest Lua API allows mod authors to override physical attributes of players, such as speed or jump strength. + +This function works fine as long there is only one mod that sets a particular physical attribute at a time. However, as soon as at least two different mods (that do not know each other) try to change the same player physics attribute using only this function, there will be conflicts as each mod will undo the change of the other mod, as the function sets a raw value. A classic race condition occurs. This is the case because the mods fail to communicate with each other. + +This mod solves the problem of conflicts. It bans the concept of “setting the raw value directly” and replaces it with the concept of factors that mods can add and remove for each attribute. The real physical player attribute will be the product of all active factors. + +## Quick start +Let's say you have a mod `example` and want to double the speed of the player (i.e. multiply it by a factor of 2), but you also don't want to break other mods that might touch the speed. + +Previously, you might have written something like this: + +`player:set_physics_override({speed=2})` + +However, your mod broke down as soon the mod `example2` came along, which wanted to increase the speed by 50%. In the real game, the player speed randomly switched from 50% and 200% which was a very annoying bug. + +In your `example` mod, you can replace the code with this: + +`playerphysics.add_physics_factor(player, "speed", "my_double_speed", 2)` + +Where `"my_double_speed` is an unique ID for your speed factor. + +Now your `example` mod is interoperable! And now, of course, the `example2` mod has to be updated in a similar fashion. + +## Precondition There is only one precondition to using this mod, but it is important: -Mods *MUST NOT* call `set_physics_override` directly! Instead, to modify player physics, use this API. + +Mods *MUST NOT* call `set_physics_override` directly for numerical values. Instead, to modify player physics, all mods that touch player physics have to use this API. ## Functions -### `playerphysics.add_physics_factor(player, physic, id, value)` -Adds a factor for a player physic and updates the player physics immeiately. +### `playerphysics.add_physics_factor(player, attribute, id, value)` +Adds a factor for a player physic and updates the player physics immediately. #### Parameters * `player`: Player object -* `physic`: Type of player physic to change. Any of the numeric values of `set_physics_override` (e.g. `"speed"`, `"jump"`, `"gravity"`) -* `id`: Unique identifier for this factor. Identifiers are stored on a per-player per-physics type basis +* `attribute`: Which of the physical attributes to change. Any of the numeric values of `set_physics_override` (e.g. `"speed"`, `"jump"`, `"gravity"`) +* `id`: Unique identifier for this factor. Identifiers are stored on a per-player per-attribute type basis * `value`: The factor to add to the list of products -### `playerphysics.remove_physics_factor(player, physic, id)` +If a factor for the same player, attribute and `id` already existed, it will be overwritten. + +### `playerphysics.remove_physics_factor(player, attribute, id)` Removes the physics factor of the given ID and updates the player's physics. #### Parameters -* `player`: Player object -* `physic`: Type of player physic to change. Any of the numeric values of `set_physics_override` (e.g. `"speed"`, `"jump"`, `"gravity"`) -* `id`: Unique identifier for the factor to remove +Same as in `playerphysics.add_physics_factor`, except there is no `value` argument. ## Examples ### Speed changes -Let's assume this mod is used by multiple different mods all trying to change the speed. +Let's assume this mod is used by 3 different mods all trying to change the speed: +Potions, Exhaustion and Electrocution. Here's what it could look like: Potions mod: @@ -79,4 +113,4 @@ playerphysics.add_physics_factor(player, "speed", "sleeping", 0) playerphysics.add_physics_factor(player, "jump", "sleeping", 0) ``` -This works regardless of the other factors because mathematics tell us that the factor 0 forces the product to be 0. +This works regardless of the other factors because 0 times anything equals 0. diff --git a/mods/PLAYER/playerphysics/README.md.bak b/mods/PLAYER/playerphysics/README.md.bak new file mode 100644 index 00000000..abd48bb6 --- /dev/null +++ b/mods/PLAYER/playerphysics/README.md.bak @@ -0,0 +1,116 @@ +# Player Physics API. + +Version: 1.0.0 + +This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict. + +## Introduction +### For players +Mods and games in Minetest can set physical attributes of players, such as speed and jump strength. For example, player speed could be set to 200%. But the way this works makes it difficult for multiple mods to *modify* physical attributes without leading to conflicts, problems and hilarious bugs, like speed that changes often to nonsense values. + +The Player Physics API aims to resolve this conflict by providing a “common ground” for mods to work together in this regard. + +This mod does nothing on its own, you will only need to install it as dependency of other mods. + +When you browse for mods that somehow mess with player physics (namely: speed, jump strength or gravity) and want to use more than one of them, check out if they support the Player Physics API. If they don't, it's very likely these mods will break as soon you activate more than one of them, for example, if two mods try to set the player speed. If you found such a “hilarious bug”, please report it to the developers of the mods (or games) and point them to the Player Physics API. + +Of course, not all mods need the Player Physics API. Mods that don't touch player physics at all won't need this mod. + +The rest of this document is directed at developers. + +### For developers +The function `set_physics_override` from the Minetest Lua API allows mod authors to override physical attributes of players, such as speed or jump strength. + +This function works fine as long there is only one mod that sets a particular physical attribute at a time. However, as soon as at least two different mods (that do not know each other) try to change the same player physics attribute using only this function, there will be conflicts as each mod will undo the change of the other mod, as the function sets a raw value. A classic race condition occurs. This is the case because the mods fail to communicate with each other. + +This mod solves the problem of conflicts. It bans the concept of “setting the raw value directly” and replaces it with the concept of factors that mods can add and remove for each attribute. The real phyisical player attribute will be the product of all active factors. + +## Quick start +Let's say you have a mod `example` and want to double the speed of the player (i.e. multiply it by a factor of 2), but you also don't want to break other mods that might touch the speed. + +Previously, you might have written something like this: + +`player:set_physics_override({speed=2})` + +However, your mod broke down as soon the mod `example2` came along, which wanted to increase the speed by 50%. In the real game, the player speed randomly switched from 50% and 200% which was a very annoying bug. + +In your `example` mod, you can replace the code with this: + +`playerphysics.add_physics_factor(player, "speed", "my_double_speed", 2)` + +Where `"my_double_speed` is an unique ID for your speed factor. + +Now your `example` mod is interoperable! And now, of course, the `example2` mod has to be updated in a similar fashion. + +## Precondition +There is only one precondition to using this mod, but it is important: + +Mods *MUST NOT* call `set_physics_override` directly for numerical values. Instead, to modify player physics, all mods that touch player physics have to use this API. + +## Functions +### `playerphysics.add_physics_factor(player, attribute, id, value)` +Adds a factor for a player physic and updates the player physics immediately. + +#### Parameters +* `player`: Player object +* `attribute`: Which of the physical attributes to change. Any of the numeric values of `set_physics_override` (e.g. `"speed"`, `"jump"`, `"gravity"`) +* `id`: Unique identifier for this factor. Identifiers are stored on a per-player per-attribute type basis +* `value`: The factor to add to the list of products + +If a factor for the same player, attribute and `id` already existed, it will be overwritten. + +### `playerphysics.remove_physics_factor(player, attribute, id)` +Removes the physics factor of the given ID and updates the player's physics. + +#### Parameters +Same as in `playerphysics.add_physics_factor`, except there is no `value` argument. + +## Examples +### Speed changes +Let's assume this mod is used by 3 different mods all trying to change the speed: +Potions, Exhaustion and Electrocution. +Here's what it could look like: + +Potions mod: +``` +playerphysics.add_physics_factor(player, "speed", "run_potion", 2) +``` + +Exhaustion mod: +``` +playerphysics.add_physics_factor(player, "jump", "exhausted", 0.75) +``` + +Electrocution mod: +``` +playerphysics.add_physics_factor(player, "jump", "shocked", 0.9) +``` + +When the 3 mods have done their change, the real player speed is simply the product of all factors, that is: + +2 * 0.75 * 0.9 = 1.35 + +The final player speed is thus 135%. + +### Speed changes, part 2 + +Let's take the example above. +Now if the Electrocution mod is done with shocking the player, it just needs to call: + +``` +playerphysics.remove_physics_factor(player, "jump", "shocked") +``` + +The effect is now gone, so the new player speed will be: + +2 * 0.75 = 1.5 + +### Sleeping +To simulate sleeping by preventing all player movement, this can be done with this easy trick: + +``` +playerphysics.add_physics_factor(player, "speed", "sleeping", 0) +playerphysics.add_physics_factor(player, "jump", "sleeping", 0) +``` + +This works regardless of the other factors because 0 times anything equals 0. diff --git a/mods/PLAYER/playerphysics/description.txt b/mods/PLAYER/playerphysics/description.txt index 57ee96ff..c692c5cd 100644 --- a/mods/PLAYER/playerphysics/description.txt +++ b/mods/PLAYER/playerphysics/description.txt @@ -1 +1 @@ -This mod simplifies the modification of player physics (speed, jumping height, gravity) by adding factors to the base values. +This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict. From 2d721a98cb7a31db699b258d8d0de81bcc80e606 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 18:55:48 +0100 Subject: [PATCH 064/865] Call on_drop for dropped items on player death Fixes charged bow dropping on death --- mods/PLAYER/mcl_death_drop/init.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mods/PLAYER/mcl_death_drop/init.lua b/mods/PLAYER/mcl_death_drop/init.lua index 1b033bae..5f4b1ddb 100644 --- a/mods/PLAYER/mcl_death_drop/init.lua +++ b/mods/PLAYER/mcl_death_drop/init.lua @@ -24,13 +24,16 @@ minetest.register_on_dieplayer(function(player) pos.x = pos.x + x pos.z = pos.z + z if not void_deadly and drop then + local def = minetest.registered_items[stack:get_name()] + if def and def.on_drop then + stack = def.on_drop(stack, player, pos) + end minetest.add_item(pos, stack) end - stack:clear() - inv:set_stack(listname, i, stack) pos.x = pos.x - x pos.z = pos.z - z end + inv:set_list(listname, {}) end end armor:set_player_armor(player) From f985aab19136f3e5fb47fc24d9352e6f668c0fd1 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 18:58:14 +0100 Subject: [PATCH 065/865] Version 0.45.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06df675b..f3e4b05c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by daredevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.44.0 +Version: 0.45.0 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From 0f134426e85520bc96efed3068279490f3aff0aa Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 20:03:56 +0100 Subject: [PATCH 066/865] Fix protection-related crash when taking liquid --- mods/ITEMS/mcl_buckets/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index f05d725c..c5b45c4d 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -205,7 +205,7 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { end -- Can't steal liquids - if minetest.is_protected(pointed_thing.above, pointed_thing.under) then + if minetest.is_protected(pointed_thing.above, user:get_player_name()) then minetest.record_protection_violation(pointed_thing.under, user:get_player_name()) return itemstack end From dee5f3bda6c15fa2646c476129a6e8527cde1111 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 20:04:30 +0100 Subject: [PATCH 067/865] Version 0.45.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3e4b05c..10aa7bcf 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by daredevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.45.0 +Version: 0.45.1 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From aa3739528b638bb8e6544119714a8a620bd9e889 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 11 Feb 2019 21:27:17 +0100 Subject: [PATCH 068/865] Fix weird arguments given to is_protected --- mods/ITEMS/mcl_core/nodes_base.lua | 6 +++++- mods/ITEMS/mcl_fire/fire_charge.lua | 4 ++-- mods/ITEMS/mcl_fire/flint_and_steel.lua | 4 ++-- mods/ITEMS/mcl_fire/init.lua | 18 +++++++++++++++--- mods/ITEMS/mcl_nether/init.lua | 7 ++++++- mods/ITEMS/mcl_tnt/init.lua | 2 +- 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index f2299e07..237eff39 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -652,7 +652,11 @@ minetest.register_node("mcl_core:bedrock", { local dim = mcl_worlds.pos_to_dimension(pos) local flame_pos = {x = pos.x, y = pos.y + 1, z = pos.z} local fn = minetest.get_node(flame_pos) - if dim == "end" and fn.name == "air" and not minetest.is_protected(flame_pos, "fire") and pointed_thing.under.y < pointed_thing.above.y then + local pname = player:get_player_name() + if minetest.is_protected(flame_pos, pname) then + return minetest.record_protection_violation(flame_pos, pname) + end + if dim == "end" and fn.name == "air" and pointed_thing.under.y < pointed_thing.above.y then minetest.set_node(flame_pos, {name = "mcl_fire:eternal_fire"}) return true else diff --git a/mods/ITEMS/mcl_fire/fire_charge.lua b/mods/ITEMS/mcl_fire/fire_charge.lua index 26259e04..d35ffae9 100644 --- a/mods/ITEMS/mcl_fire/fire_charge.lua +++ b/mods/ITEMS/mcl_fire/fire_charge.lua @@ -28,10 +28,10 @@ minetest.register_craftitem("mcl_fire:fire_charge", { if nodedef and nodedef._on_ignite then local overwrite = nodedef._on_ignite(user, pointed_thing) if not overwrite then - mcl_fire.set_fire(pointed_thing) + mcl_fire.set_fire(pointed_thing, user) end else - mcl_fire.set_fire(pointed_thing) + mcl_fire.set_fire(pointed_thing, user) end if not minetest.settings:get_bool("creative_mode") then itemstack:take_item() diff --git a/mods/ITEMS/mcl_fire/flint_and_steel.lua b/mods/ITEMS/mcl_fire/flint_and_steel.lua index 0ab4043f..7cb114ad 100644 --- a/mods/ITEMS/mcl_fire/flint_and_steel.lua +++ b/mods/ITEMS/mcl_fire/flint_and_steel.lua @@ -33,10 +33,10 @@ minetest.register_tool("mcl_fire:flint_and_steel", { if nodedef and nodedef._on_ignite then local overwrite = nodedef._on_ignite(user, pointed_thing) if not overwrite then - mcl_fire.set_fire(pointed_thing) + mcl_fire.set_fire(pointed_thing, user) end else - mcl_fire.set_fire(pointed_thing) + mcl_fire.set_fire(pointed_thing, user) end used = true end diff --git a/mods/ITEMS/mcl_fire/init.lua b/mods/ITEMS/mcl_fire/init.lua index 665b13de..7743d30d 100644 --- a/mods/ITEMS/mcl_fire/init.lua +++ b/mods/ITEMS/mcl_fire/init.lua @@ -393,10 +393,22 @@ else -- Fire enabled end --- Set pointed_thing on (normal) fire -mcl_fire.set_fire = function(pointed_thing) +-- Set pointed_thing on (normal) fire. +-- * pointed_thing: Pointed thing to ignite +-- * player: Player who sets fire or nil if nobody +mcl_fire.set_fire = function(pointed_thing, player) + local pname + if player == nil then + pname = "" + else + pname = player:get_player_name() + end local n = minetest.get_node(pointed_thing.above) - if n.name == "air" and not minetest.is_protected(pointed_thing.above, "fire") then + if minetest.is_protected(pointed_thing.above, pname) then + minetest.record_protection_violation(pointed_thing.above, pname) + return + end + if n.name == "air" then minetest.add_node(pointed_thing.above, {name="mcl_fire:fire"}) end end diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index b0bb771a..4fc36a8b 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -46,7 +46,12 @@ local eternal_on_ignite = function(player, pointed_thing) local pos = pointed_thing.under local flame_pos = {x = pos.x, y = pos.y + 1, z = pos.z} local fn = minetest.get_node(flame_pos) - if fn.name == "air" and not minetest.is_protected(flame_pos, "fire") and pointed_thing.under.y < pointed_thing.above.y then + local pname = player:get_player_name() + if minetest.is_protected(flame_pos, pname) then + minetest.record_protection_violation(flame_pos, pname) + return + end + if fn.name == "air" and pointed_thing.under.y < pointed_thing.above.y then minetest.set_node(flame_pos, {name = "mcl_fire:eternal_fire"}) return true else diff --git a/mods/ITEMS/mcl_tnt/init.lua b/mods/ITEMS/mcl_tnt/init.lua index 39df3848..dd6ebc66 100644 --- a/mods/ITEMS/mcl_tnt/init.lua +++ b/mods/ITEMS/mcl_tnt/init.lua @@ -204,7 +204,7 @@ tnt.boom = function(pos, info) end minetest.sound_play(sound, {pos = pos,gain = 1.0,max_hear_distance = 16,}) local node = minetest.get_node(pos) - if minetest.get_item_group("water") == 1 or minetest.get_item_group("lava") == 1 or minetest.is_protected(pos, "tnt") then + if minetest.get_item_group("water") == 1 or minetest.get_item_group("lava") == 1 then -- Cancel the Explosion return end From 46a6d9bb8e616ddeae42c6ccc0dc30fb1ed1df11 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 20:14:30 +0100 Subject: [PATCH 069/865] Signs: Remove dead code --- mods/ITEMS/mcl_signs/init.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mods/ITEMS/mcl_signs/init.lua b/mods/ITEMS/mcl_signs/init.lua index 29c23f52..541e8114 100644 --- a/mods/ITEMS/mcl_signs/init.lua +++ b/mods/ITEMS/mcl_signs/init.lua @@ -361,9 +361,6 @@ minetest.register_node("mcl_signs:wall_sign", { return itemstack end, on_destruct = destruct_sign, - on_receive_fields = function(pos, formname, fields, sender) - update_sign(pos, fields, sender) - end, on_punch = function(pos, node, puncher) update_sign(pos) end, @@ -398,9 +395,6 @@ local ssign = { sounds = node_sounds, on_destruct = destruct_sign, - on_receive_fields = function(pos, formname, fields, sender) - update_sign(pos, fields, sender) - end, on_punch = function(pos, node, puncher) update_sign(pos) end, From d0e38623562b56cfa7913ea78eb39b372700bc92 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 20:52:44 +0100 Subject: [PATCH 070/865] Fix bad wall sign text update after punch --- mods/ITEMS/mcl_signs/init.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_signs/init.lua b/mods/ITEMS/mcl_signs/init.lua index 541e8114..608d1922 100644 --- a/mods/ITEMS/mcl_signs/init.lua +++ b/mods/ITEMS/mcl_signs/init.lua @@ -157,6 +157,19 @@ local function get_rotation_level(facedir, nodename) return rl end +local function get_wall_signtext_info(param2, nodename) + local dir = minetest.wallmounted_to_dir(param2) + if dir.x > 0 then + return 2 + elseif dir.z > 0 then + return 1 + elseif dir.x < 0 then + return 4 + else + return 3 + end +end + local sign_groups = {handy=1,axey=1, flammable=1, deco_block=1, material_wood=1, attached_node=1} local destruct_sign = function(pos) @@ -186,7 +199,7 @@ local update_sign = function(pos, fields, sender) for _, v in ipairs(objects) do local ent = v:get_luaentity() if ent and ent.name == "mcl_signs:text" then - v:set_properties({textures={generate_texture(create_lines(text), v:get_luaentity()._signnodename)}}) + v:set_properties({textures={generate_texture(create_lines(text), ent._signnodename)}}) return end end @@ -198,7 +211,7 @@ local update_sign = function(pos, fields, sender) if nn == "mcl_signs:standing_sign" or nn == "mcl_signs:standing_sign22_5" or nn == "mcl_signs:standing_sign45" or nn == "mcl_signs:standing_sign67_5" then sign_info = signtext_info_standing[get_rotation_level(n.param2, nn) + 1] elseif nn == "mcl_signs:wall_sign" then - sign_info = signtext_info_wall[n.param2 + 1] + sign_info = signtext_info_wall[get_wall_signtext_info(n.param2)] end if sign_info == nil then return @@ -215,6 +228,7 @@ local update_sign = function(pos, fields, sender) sign_info.yaw = sign_info.yaw + 3 * (math.pi / 8) end text_entity:get_luaentity()._signnodename = nn + text_entity:set_properties({textures={generate_texture(create_lines(text), nn)}}) text_entity:setyaw(sign_info.yaw) end From 37b9a8f6bf70ab3fad990b02e468530726c7262b Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 20:59:25 +0100 Subject: [PATCH 071/865] Fix incorrect text rotation when sign text updates --- mods/ITEMS/mcl_signs/init.lua | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mods/ITEMS/mcl_signs/init.lua b/mods/ITEMS/mcl_signs/init.lua index 608d1922..1b1ede29 100644 --- a/mods/ITEMS/mcl_signs/init.lua +++ b/mods/ITEMS/mcl_signs/init.lua @@ -220,13 +220,6 @@ local update_sign = function(pos, fields, sender) x = pos.x + sign_info.delta.x, y = pos.y + sign_info.delta.y, z = pos.z + sign_info.delta.z}, "mcl_signs:text") - if nn == "mcl_signs:standing_sign22_5" then - sign_info.yaw = sign_info.yaw + math.pi / 8 - elseif nn == "mcl_signs:standing_sign45" then - sign_info.yaw = sign_info.yaw + 2 * (math.pi / 8) - elseif nn == "mcl_signs:standing_sign67_5" then - sign_info.yaw = sign_info.yaw + 3 * (math.pi / 8) - end text_entity:get_luaentity()._signnodename = nn text_entity:set_properties({textures={generate_texture(create_lines(text), nn)}}) From 198adcc7404725138d19c7f1f20889392abc8f36 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 21:29:11 +0100 Subject: [PATCH 072/865] Respawn sign text on load --- mods/ITEMS/mcl_signs/init.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_signs/init.lua b/mods/ITEMS/mcl_signs/init.lua index 1b1ede29..c9763379 100644 --- a/mods/ITEMS/mcl_signs/init.lua +++ b/mods/ITEMS/mcl_signs/init.lua @@ -427,7 +427,7 @@ local ssign67 = table.copy(ssign) ssign67.mesh = "mcl_signs_sign67.5.obj" minetest.register_node("mcl_signs:standing_sign67_5", ssign67) - +-- FIXME: Prevent entity destruction by /clearobjects minetest.register_entity("mcl_signs:text", { collisionbox = { 0, 0, 0, 0, 0, 0 }, visual = "upright_sprite", @@ -484,6 +484,15 @@ end minetest.register_alias("signs:sign_wall", "mcl_signs:wall_sign") minetest.register_alias("signs:sign_yard", "mcl_signs:standing_sign") +minetest.register_lbm({ + name = "mcl_signs:respawn_entities", + label = "Respawn sign text entities", + run_at_every_load = true, + nodenames = { "mcl_signs:wall_sign", "mcl_signs:standing_sign", "mcl_signs:standing_sign22_5", "mcl_signs:standing_sign45", "mcl_signs:standing_sign67_5" }, + action = function(pos, node) + update_sign(pos) + end, +}) if minetest.settings:get_bool("log_mods") then minetest.log("action", "[mcl_signs] loaded") From eb7c8371ac07c8c3de3bb4abea1f1910e8f873e5 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 21:58:31 +0100 Subject: [PATCH 073/865] Respawn itemframe entities on load --- mods/ITEMS/mcl_itemframes/init.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mods/ITEMS/mcl_itemframes/init.lua b/mods/ITEMS/mcl_itemframes/init.lua index 14170e3b..d4d39ab8 100644 --- a/mods/ITEMS/mcl_itemframes/init.lua +++ b/mods/ITEMS/mcl_itemframes/init.lua @@ -221,4 +221,14 @@ minetest.register_lbm({ end, }) +minetest.register_lbm({ + label = "Respawn item frame item entities", + name = "mcl_itemframes:respawn_entities", + nodenames = {"mcl_itemframes:item_frame"}, + run_at_every_load = true, + action = function(pos, node) + update_item_entity(pos, node) + end, +}) + minetest.register_alias("itemframes:frame", "mcl_itemframes:item_frame") From 267a697fab032188d2ff7f9947a1da5e95b117da Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 23:32:18 +0100 Subject: [PATCH 074/865] Banners: Respawn entity if it got lost Entity is respawned on load (in an LBM) or when the banner node is punched. Also, the banner drop is now handled in the node instead of the entity. --- mods/ITEMS/mcl_banners/init.lua | 192 ++++++++++++++++++++++---------- 1 file changed, 134 insertions(+), 58 deletions(-) diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index 71f0ac02..5bab2ed7 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -32,6 +32,11 @@ mcl_banners.colors = { ["unicolor_light_blue"] = {"light_blue", "Light Blue Banner", "mcl_wool:light_blue", "#4040CF", "mcl_dye:lightblue", "Light Blue" }, } +local colors_reverse = {} +for k,v in pairs(mcl_banners.colors) do + colors_reverse["mcl_banners:banner_item_"..v[1]] = k +end + -- Add pattern/emblazoning crafting recipes dofile(minetest.get_modpath("mcl_banners").."/patterncraft.lua") @@ -42,28 +47,40 @@ local layer_ratio = 255 local standing_banner_entity_offset = { x=0, y=-0.499, z=0 } local hanging_banner_entity_offset = { x=0, y=-1.7, z=0 } -local on_destruct_standing_banner = function(pos) +local on_destruct_banner = function(pos, hanging) + local offset, nodename + if hanging then + offset = hanging_banner_entity_offset + nodename = "mcl_banners:hanging_banner" + else + offset = standing_banner_entity_offset + nodename = "mcl_banners:standing_banner" + end -- Find this node's banner entity and make it drop as an item - local checkpos = vector.add(pos, standing_banner_entity_offset) + local checkpos = vector.add(pos, offset) local objects = minetest.get_objects_inside_radius(checkpos, 0.5) for _, v in ipairs(objects) do local ent = v:get_luaentity() - if ent and ent.name == "mcl_banners:standing_banner" then - v:get_luaentity():_drop() + if ent and ent.name == nodename then + v:remove() end end + -- Drop item + local meta = minetest.get_meta(pos) + local item = meta:get_inventory():get_stack("banner", 1) + if not item:is_empty() then + minetest.add_item(pos, item) + else + minetest.add_item(pos, "mcl_banners:banner_item_white") + end +end + +local on_destruct_standing_banner = function(pos) + return on_destruct_banner(pos, false) end local on_destruct_hanging_banner = function(pos) - -- Find this node's banner entity and make it drop as an item - local checkpos = vector.add(pos, hanging_banner_entity_offset) - local objects = minetest.get_objects_inside_radius(checkpos, 0.5) - for _, v in ipairs(objects) do - local ent = v:get_luaentity() - if ent and ent.name == "mcl_banners:hanging_banner" then - v:get_luaentity():_drop() - end - end + return on_destruct_banner(pos, true) end local make_banner_texture = function(base_color, layers) @@ -96,6 +113,59 @@ local make_banner_texture = function(base_color, layers) end end +local spawn_banner_entity = function(pos, hanging, itemstack) + local banner + if hanging then + banner = minetest.add_entity(pos, "mcl_banners:hanging_banner") + else + banner = minetest.add_entity(pos, "mcl_banners:standing_banner") + end + if banner == nil then + return banner + end + local imeta = itemstack:get_meta() + local layers_raw = imeta:get_string("layers") + local layers = minetest.deserialize(layers_raw) + local colorid = colors_reverse[itemstack:get_name()] + banner:get_luaentity():_set_textures(colorid, layers) + local mname = imeta:get_string("name") + if mname ~= nil and mname ~= "" then + banner:get_luaentity()._item_name = mname + banner:get_luaentity()._item_description = imeta:get_string("description") + end + + return banner +end + +local respawn_banner_entity = function(pos, node) + local hanging = node.name == "mcl_banners:hanging_banner" + local offset + if hanging then + offset = hanging_banner_entity_offset + else + offset = standing_banner_entity_offset + end + -- Check if a banner entity already exists + local bpos = vector.add(pos, offset) + local objects = minetest.get_objects_inside_radius(bpos, 0.5) + for _, v in ipairs(objects) do + local ent = v:get_luaentity() + if ent and (ent.name == "mcl_banners:standing_banner" or ent.name == "mcl_banners:hanging_banner") then + return + end + end + -- Spawn new entity + local meta = minetest.get_meta(pos) + local banner_item = meta:get_inventory():get_stack("banner", 1) + local banner_entity = spawn_banner_entity(bpos, hanging, banner_item) + + -- Set rotation + local final_yaw + local rotation_level = meta:get_int("rotation_level") + final_yaw = (rotation_level * (math.pi/8)) + math.pi + banner_entity:set_yaw(final_yaw) +end + local on_rotate if minetest.get_modpath("screwdriver") then on_rotate = screwdriver.disallow @@ -138,6 +208,9 @@ minetest.register_node("mcl_banners:standing_banner", { drop = "", -- Item drops are handled in entity code on_destruct = on_destruct_standing_banner, + on_punch = function(pos, node) + respawn_banner_entity(pos, node) + end, _mcl_hardness = 1, _mcl_blast_resistance = 5, }) @@ -166,6 +239,9 @@ minetest.register_node("mcl_banners:hanging_banner", { drop = "", -- Item drops are handled in entity code on_destruct = on_destruct_hanging_banner, + on_punch = function(pos, node) + respawn_banner_entity(pos, node) + end, _mcl_hardness = 1, _mcl_blast_resistance = 5, on_rotate = on_rotate, @@ -269,48 +345,61 @@ for colorid, colortab in pairs(mcl_banners.colors) do end hanging = true end - local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end - if hanging then - place_pos = vector.add(place_pos, hanging_banner_entity_offset) - else - place_pos = vector.add(place_pos, standing_banner_entity_offset) + local bnode = minetest.get_node(place_pos) + if bnode.name ~= "mcl_banners:standing_banner" and bnode.name ~= "mcl_banners:hanging_banner" then + minetest.log("error", "[mcl_banners] The placed banner node is not what the mod expected!") + return itemstack end + local meta = minetest.get_meta(place_pos) + local inv = meta:get_inventory() + inv:set_size("banner", 1) + local store_stack = ItemStack(itemstack) + store_stack:set_count(1) + inv:set_stack("banner", 1, store_stack) - local banner + -- Spawn entity + local entity_place_pos if hanging then - banner = minetest.add_entity(place_pos, "mcl_banners:hanging_banner") + entity_place_pos = vector.add(place_pos, hanging_banner_entity_offset) else - banner = minetest.add_entity(place_pos, "mcl_banners:standing_banner") + entity_place_pos = vector.add(place_pos, standing_banner_entity_offset) end - local imeta = itemstack:get_meta() - local layers_raw = imeta:get_string("layers") - local layers = minetest.deserialize(layers_raw) - banner:get_luaentity():_set_textures(colorid, layers) - local mname = imeta:get_string("name") - if mname ~= nil and mname ~= "" then - banner:get_luaentity()._item_name = mname - banner:get_luaentity()._item_description = imeta:get_string("description") - end - + local banner_entity = spawn_banner_entity(entity_place_pos, hanging, itemstack) -- Set rotation - local final_yaw + local final_yaw, rotation_level if hanging then local pdir = vector.direction(pointed_thing.under, pointed_thing.above) final_yaw = minetest.dir_to_yaw(pdir) + if pdir.x > 0 then + rotation_level = 4 + elseif pdir.z > 0 then + rotation_level = 8 + elseif pdir.x < 0 then + rotation_level = 12 + else + rotation_level = 0 + end else -- Determine the rotation based on player's yaw local yaw = placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) - local rotation_level = round((yaw / (math.pi*2)) * 16) + rotation_level = round((yaw / (math.pi*2)) * 16) + if rotation_level >= 16 then + rotation_level = 0 + end final_yaw = (rotation_level * (math.pi/8)) + math.pi end - banner:set_yaw(final_yaw) + meta:set_int("rotation_level", rotation_level) + + if banner_entity ~= nil then + banner_entity:set_yaw(final_yaw) + end if not minetest.settings:get_bool("creative_mode") then itemstack:take_item() @@ -392,30 +481,6 @@ local entity_standing = { self.object:set_armor_groups({immortal=1}) end, - -- This is a custom function which causes the banner to be dropped as item and destroys the entity. - _drop = function(self) - local pos = self.object:get_pos() - pos.y = pos.y + 1 - - if not minetest.settings:get_bool("creative_mode") and self._base_color then - -- Spawn item - local banner = ItemStack("mcl_banners:banner_item_"..mcl_banners.colors[self._base_color][1]) - local meta = banner:get_meta() - meta:set_string("layers", minetest.serialize(self._layers)) - if self._item_name ~= nil and self._item_name ~= "" then - meta:set_string("description", self._item_description) - meta:set_string("name", self._item_name) - else - meta:set_string("description", mcl_banners.make_advanced_banner_description(banner:get_definition().description, self._layers)) - end - - minetest.add_item(pos, banner) - end - - -- Destroy entity - self.object:remove() - end, - -- Set the banner textures. This function can be used by external mods. -- Meaning of parameters: -- * self: Lua entity reference to entity. @@ -436,6 +501,17 @@ local entity_hanging = table.copy(entity_standing) entity_hanging.mesh = "amc_banner_hanging.b3d" minetest.register_entity("mcl_banners:hanging_banner", entity_hanging) +-- FIXME: Prevent entity destruction by /clearobjects +minetest.register_lbm({ + label = "Respawn banner entities", + name = "mcl_banners:respawn_entities", + run_at_every_load = true, + nodenames = {"mcl_banners:standing_banner", "mcl_banners:hanging_banner"}, + action = function(pos, node) + respawn_banner_entity(pos, node) + end, +}) + minetest.register_craft({ type = "fuel", recipe = "group:banner", From e332c64d2ada9aa5c09f8bb591c7adf17b1632c6 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 18 Feb 2019 23:55:18 +0100 Subject: [PATCH 075/865] Respawn armor entity of armor stand on load --- .../minetest-3d_armor/3d_armor_stand/init.lua | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua index 76dcec55..02eb0bcb 100644 --- a/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua +++ b/mods/ITEMS/minetest-3d_armor/3d_armor_stand/init.lua @@ -125,6 +125,12 @@ minetest.register_node("3d_armor_stand:armor_stand", { minetest.record_protection_violation(pos, protname) return itemstack end + + local inv = minetest.get_inventory({type = "node", pos = pos}) + if not inv then + return itemstack + end + -- Check if player wields armor local name = itemstack:get_name() local list @@ -135,11 +141,8 @@ minetest.register_node("3d_armor_stand:armor_stand", { break end end - -- If player wields armor, put it on armor stand - local inv = minetest.get_inventory({type = "node", pos = pos}) local wielditem = clicker:get_wielded_item() - if not inv then return itemstack end if list then -- ... but only if the slot is free local single_item = ItemStack(itemstack) @@ -172,11 +175,12 @@ minetest.register_node("3d_armor_stand:armor_stand", { if taken then stand_armor:take_item() inv:set_stack("armor_" .. elements[e], 1, stand_armor) - update_entity(pos) end + update_entity(pos) return clicker:get_wielded_item() end end + update_entity(pos) return itemstack end, after_place_node = function(pos) @@ -264,6 +268,17 @@ minetest.register_entity("3d_armor_stand:armor_entity", { end, }) +-- FIXME: Armor helper entity can get destroyed by /clearobjects +minetest.register_lbm({ + label = "Respawn armor stand entities", + name = "3d_armor_stand:respawn_entities", + nodenames = {"3d_armor_stand:armor_stand"}, + run_at_every_load = true, + action = function(pos, node) + update_entity(pos, node) + end, +}) + if minetest.get_modpath("doc_identifier") ~= nil then doc.sub.identifier.register_object("3d_armor_stand:armor_entity", "nodes", "3d_armor_stand:armor_stand") end From e5c78973b008e7f35323b4039546d36102352f7d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 19 Feb 2019 00:06:14 +0100 Subject: [PATCH 076/865] Respawn mobspawner doll on load, if gone mobspawner doll on load, if gone mobspawner doll on load, if gone mobspawner doll on load, if gone --- mods/ITEMS/mcl_mobspawners/init.lua | 31 +++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_mobspawners/init.lua b/mods/ITEMS/mcl_mobspawners/init.lua index 46cf74c7..58ec364c 100644 --- a/mods/ITEMS/mcl_mobspawners/init.lua +++ b/mods/ITEMS/mcl_mobspawners/init.lua @@ -66,6 +66,20 @@ local function set_doll_properties(doll, mob) doll:get_luaentity()._mob = mob end +local function respawn_doll(pos) + local meta = minetest.get_meta(pos) + local mob = meta:get_string("Mob") + local doll + if mob and mob ~= "" then + doll = find_doll(pos) + if not doll then + doll = spawn_doll(pos) + set_doll_properties(doll, mob) + end + end + return doll +end + --[[ Public function: Setup the spawner at pos. This function blindly assumes there's actually a spawner at pos. If not, then the results are undefined. @@ -288,6 +302,10 @@ minetest.register_node("mcl_mobspawners:spawner", { end end, + on_punch = function(pos) + respawn_doll(pos) + end, + on_timer = spawn_mobs, sounds = mcl_sounds.node_sound_metal_defaults(), @@ -328,7 +346,7 @@ end doll_def.on_step = function(self, dtime) -- Check if spawner is still present. If not, delete the entity - self.timer = self.timer + 0.01 + self.timer = self.timer + dtime local n = minetest.get_node_or_nil(self.object:get_pos()) if self.timer > 1 then if n and n.name and n.name ~= "mcl_mobspawners:spawner" then @@ -341,5 +359,14 @@ doll_def.on_punch = function(self, hitter) end minetest.register_entity("mcl_mobspawners:doll", doll_def) - +-- FIXME: Doll can get destroyed by /clearobjects +minetest.register_lbm({ + label = "Respawn mob spawner dolls", + name = "mcl_mobspawners:respawn_entities", + nodenames = { "mcl_mobspawners:spawner" }, + run_at_every_load = true, + action = function(pos, node) + respawn_doll(pos) + end, +}) From a1ce94eee5eefec7af84c79b1f6f4bcb7a4833b1 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 19 Feb 2019 00:06:47 +0100 Subject: [PATCH 077/865] Add comment to mcl_itemframes --- mods/ITEMS/mcl_itemframes/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/ITEMS/mcl_itemframes/init.lua b/mods/ITEMS/mcl_itemframes/init.lua index d4d39ab8..2d2fffb3 100644 --- a/mods/ITEMS/mcl_itemframes/init.lua +++ b/mods/ITEMS/mcl_itemframes/init.lua @@ -221,6 +221,7 @@ minetest.register_lbm({ end, }) +-- FIXME: Item entities can get destroyed by /clearobjects minetest.register_lbm({ label = "Respawn item frame item entities", name = "mcl_itemframes:respawn_entities", From c1bc7a8fae9ff108021e6b0ca076f7d978459d4d Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 19 Feb 2019 03:42:50 +0100 Subject: [PATCH 078/865] Chorus fruit keeps u safe from damaging blocks --- mods/ITEMS/mcl_end/chorus_plant.lua | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/mods/ITEMS/mcl_end/chorus_plant.lua b/mods/ITEMS/mcl_end/chorus_plant.lua index 58832b42..5c48654d 100644 --- a/mods/ITEMS/mcl_end/chorus_plant.lua +++ b/mods/ITEMS/mcl_end/chorus_plant.lua @@ -17,6 +17,12 @@ local chorus_flower_box = { } } +-- Helper function +local function round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end + minetest.register_node("mcl_end:chorus_flower", { description = "Chorus Flower", _doc_items_longdesc = "A chorus flower is the living part of a chorus plant. It can grow into a tall chorus plant, step by step. When it grows, it may die on old age eventually. It also dies when it is unable to grow.", @@ -282,16 +288,16 @@ local random_teleport = function(player) for a=1, 16 do -- Teleportation box local x,y,z - x = math.random(pos.x-8, pos.x+8) + x = math.random(round(pos.x)-8, round(pos.x)+8) y = math.random(math.ceil(pos.y)-8, math.ceil(pos.y)+8) - z = math.random(pos.z-8, pos.z+8) + z = math.random(round(pos.z)-8, round(pos.z)+8) local node_cache = {} local ground_level = false -- Scan nodes from selected position until we hit ground for t=0, 16 do local tpos = {x=x, y=y-t, z=z} local tnode = minetest.get_node(tpos) - if tnode.name == "mcl_core:void" then + if tnode.name == "mcl_core:void" or tnode.name == "ignore" then break end local tdef = minetest.registered_nodes[tnode.name] @@ -304,16 +310,20 @@ local random_teleport = function(player) -- Ground found? Then let's check if the player has enough room if ground_level and #node_cache >= 1 then local streak = 0 + local last_was_walkable = true for c=#node_cache, 1, -1 do local tpos = node_cache[c].pos local tnode = node_cache[c].node local tdef = minetest.registered_nodes[tnode.name] - -- Player needs a space of 2 nodes on top of each other - if not tdef.walkable and tdef.liquidtype == "none" then - streak = streak + 1 + -- Player needs a space of 2 safe non-liquid nodes on top of a walkable node + if not tdef.walkable and tdef.liquidtype == "none" and tdef.damage_per_second <= 0 then + if (streak == 0 and last_was_walkable) or (streak > 0) then + streak = streak + 1 + end else streak = 0 end + last_was_walkable = tdef.walkable if streak >= 2 then -- JACKPOT! Now we can teleport. local goal = {x=tpos.x, y=tpos.y-1.5, z=tpos.z} @@ -347,7 +357,7 @@ end minetest.register_craftitem("mcl_end:chorus_fruit", { description = "Chorus Fruit", - _doc_items_longdesc = "A chorus fruit is an edible fruit from the chorus plant which is home to the End. Eating it teleports you to the top of a random solid block nearby, provided you won't end up inside a liquid or some solid blocks. Teleportation might fail if there are very few or no places to teleport to.", + _doc_items_longdesc = "A chorus fruit is an edible fruit from the chorus plant which is home to the End. Eating it teleports you to the top of a random solid block nearby, provided you won't end up inside a liquid, solid or harmful blocks. Teleportation might fail if there are very few or no places to teleport to.", wield_image = "mcl_end_chorus_fruit.png", inventory_image = "mcl_end_chorus_fruit.png", on_place = eat_chorus_fruit, From 38f6804a799b23706fd525a1dbd9c6e96e3317d2 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 19 Feb 2019 20:16:12 +0100 Subject: [PATCH 079/865] Update tsm_railcorridors to 0.14.0 --- mods/MAPGEN/tsm_railcorridors/README.md | 13 +- mods/MAPGEN/tsm_railcorridors/init.lua | 789 ++++++++++++------ .../MAPGEN/tsm_railcorridors/settingtypes.txt | 19 +- 3 files changed, 557 insertions(+), 264 deletions(-) diff --git a/mods/MAPGEN/tsm_railcorridors/README.md b/mods/MAPGEN/tsm_railcorridors/README.md index 9b2b745b..de9df489 100644 --- a/mods/MAPGEN/tsm_railcorridors/README.md +++ b/mods/MAPGEN/tsm_railcorridors/README.md @@ -1,11 +1,10 @@ # Railway corridors [`tsm_railcorridors`] MineClone 2 adaption. NO TREASURER SUPPORT! -* Current version 0.12.0 +* Current version 0.14.0 -Minetest mod for adding underground corridors with rails and wood constructions with -a few treasure chests now and then. Optional Treasurer support is available for adding -treasures from various mods. +Minetest mod for adding underground corridors with rails and wood constructions with a few treasure chests now and then. +Optional support for the Treasurer mod is available for adding treasures from various mods. Cobwebs are added if the `mobs_monster` mod is found. Use the advanced settings to finetune the railway corridors. @@ -13,6 +12,6 @@ Use the advanced settings to finetune the railway corridors. * Forum thread: https://forum.minetest.net/viewtopic.php?t=10339 * License: MIT License. -## Info for modders -Want to include this mod in a game, but you hate the dependencies? -You can edit the node names in gameconfig.lua to fit your needs. :-) +## Info for game makers +Want to include this mod in a game, but you have problems with the dependencies? +Edit `gameconfig.lua` to fit your needs. :-) diff --git a/mods/MAPGEN/tsm_railcorridors/init.lua b/mods/MAPGEN/tsm_railcorridors/init.lua index 57c18379..d6de8198 100644 --- a/mods/MAPGEN/tsm_railcorridors/init.lua +++ b/mods/MAPGEN/tsm_railcorridors/init.lua @@ -12,15 +12,13 @@ local P = function (float) return math.floor(32767 * float) end --- Wahrscheinlichkeit für jeden Chunk, solche Gänge mit Schienen zu bekommen --- Probability for every newly generated chunk to get corridors -local probability_railcaves_in_chunk = P(0.3) -setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_chunk")) +-- Probability for every newly generated mapchunk to get corridors +local probability_railcaves_in_mapchunk = P(0.33333) +setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_mapchunk")) if setting then - probability_railcaves_in_chunk = P(setting) + probability_railcaves_in_mapchunk = P(setting) end --- Innerhalb welcher Parameter soll sich die Pfadlänge bewegen? (Forks heben den Maximalwert auf) -- Minimal and maximal value of path length (forks don't look up this value) local way_min = 4; local way_max = 7; @@ -33,7 +31,6 @@ if setting then way_max = setting end --- Wahrsch. für jeden geraden Teil eines Korridors, Fackeln zu bekommen -- Probability for every horizontal part of a corridor to be with torches local probability_torches_in_segment = P(0.5) setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_torches_in_segment")) @@ -41,7 +38,6 @@ if setting then probability_torches_in_segment = P(setting) end --- Wahrsch. für jeden Teil eines Korridors, nach oben oder nach unten zu gehen -- Probability for every part of a corridor to go up or down local probability_up_or_down = P(0.2) setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_up_or_down")) @@ -49,7 +45,6 @@ if setting then probability_up_or_down = P(setting) end --- Wahrscheinlichkeit für jeden Teil eines Korridors, sich zu verzweigen – vorsicht, wenn fast jeder Gang sich verzweigt, kann der Algorithums unlösbar werden und MT hängt sich auf -- Probability for every part of a corridor to fork – caution, too high values may cause MT to hang on. local probability_fork = P(0.04) setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_fork")) @@ -57,7 +52,6 @@ if setting then probability_fork = P(setting) end --- Wahrscheinlichkeit für jeden geraden Teil eines Korridors eine Kiste zu enthalten -- Probability for every part of a corridor to contain a chest local probability_chest = P(0.05) setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_chest")) @@ -66,17 +60,11 @@ if setting then end -- Probability for every part of a corridor to contain a cart --- Disabled because cart spawning creates error message spam: --- “m_static_exists=true but static data doesn't actually exist in (x,y,z) --- TODO: Set back to 0.05 when this is fixed. --- TODO: Remove minecarts from loot table when minecarts spawn on rails. -local probability_cart = P(0) ---[[ +local probability_cart = P(0.05) setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_cart")) if setting then probability_cart = P(setting) end -]] -- Probability for a rail corridor system to be damaged local probability_damage = P(1.0) @@ -111,27 +99,50 @@ local height_max = mcl_worlds.layer_to_y(60) -- Chaos Mode: If enabled, rail corridors don't stop generating when hitting obstacles local chaos_mode = minetest.settings:get_bool("tsm_railcorridors_chaos") or false --- Parameter Ende +-- End of parameters --- Random generators -local pr, webperlin_major, webperlin_minor -local pr_initialized = false +if not tsm_railcorridors.nodes.corridor_woods_function then + local accumulated_chance = 0 + for w=1, #tsm_railcorridors.nodes.corridor_woods do + accumulated_chance = accumulated_chance + tsm_railcorridors.nodes.corridor_woods[w].chance + end + assert(accumulated_chance == 1000, "Rail corridor wood chances add up to "..accumulated_chance.." per mille! (should be 1000 per mille)") +end + +-- Random Perlin noise generators +local pr, pr_carts, pr_treasures, pr_deco, webperlin_major, webperlin_minor local function InitRandomizer(seed) -- Mostly used for corridor gen. pr = PseudoRandom(seed) + -- Dirt room decorations + pr_deco = PseudoRandom(seed+25) + -- Separate randomizer for carts because spawning carts is very timing-dependent + pr_carts = PseudoRandom(seed-654) + -- Chest contents randomizer + pr_treasures = PseudoRandom(seed+777) -- Used for cobweb generation, both noises have to reach a high value for cobwebs to appear webperlin_major = PerlinNoise(934, 3, 0.6, 500) webperlin_minor = PerlinNoise(834, 3, 0.6, 50) - pr_initialized = true + pr_inited = true end +local carts_table = {} + +local dirt_room_coords + +-- Returns true if pos is inside the dirt room of the current corridor system +local function IsInDirtRoom(pos) + local min = dirt_room_coords.min + local max = dirt_room_coords.max + return pos.x >= min.x and pos.x <= max.x and pos.y >= min.y and pos.y <= max.y and pos.z >= min.z and pos.z <= max.z +end -- Checks if the mapgen is allowed to carve through this structure and only sets -- the node if it is allowed. Does never build in liquids. -- If check_above is true, don't build if the node above is attached (e.g. rail) -- or a liquid. -local function SetNodeIfCanBuild(pos, node, check_above) +local function SetNodeIfCanBuild(pos, node, check_above, can_replace_rail) if check_above then local abovename = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}).name local abovedef = minetest.registered_nodes[abovename] @@ -144,8 +155,13 @@ local function SetNodeIfCanBuild(pos, node, check_above) end local name = minetest.get_node(pos).name local def = minetest.registered_nodes[name] - if name ~= "unknown" and name ~= "ignore" and def.is_ground_content and - (def.liquidtype == "none" or name == tsm_railcorridors.nodes.cobweb) then + if name ~= "unknown" and name ~= "ignore" and + ((def.is_ground_content and def.liquidtype == "none") or + name == tsm_railcorridors.nodes.cobweb or + name == tsm_railcorridors.nodes.torch_wall or + name == tsm_railcorridors.nodes.torch_floor or + (can_replace_rail and name == tsm_railcorridors.nodes.rail) + ) then minetest.set_node(pos, node) return true else @@ -175,8 +191,9 @@ end -- Returns true if rails are allowed to be placed on top of this node local function IsRailSurface(pos) local nodename = minetest.get_node(pos).name + local nodename_above = minetest.get_node({x=pos.x,y=pos.y+2,z=pos.z}).name local nodedef = minetest.registered_nodes[nodename] - return nodename ~= "unknown" and nodename ~= "ignore" and nodedef.walkable and (nodedef.node_box == nil or nodedef.node_box.type == "regular") + return nodename ~= "unknown" and nodename ~= "ignore" and nodedef.walkable and (nodedef.node_box == nil or nodedef.node_box.type == "regular") and nodename_above ~= tsm_railcorridors.nodes.rail end -- Checks if the node is empty space which requires to be filled by a platform @@ -184,36 +201,91 @@ local function NeedsPlatform(pos) local node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}) local node2 = minetest.get_node({x=pos.x,y=pos.y-2,z=pos.z}) local nodedef = minetest.registered_nodes[node.name] - return node.name ~= "ignore" and node.name ~= "unknown" and nodedef.is_ground_content and ((nodedef.walkable == false and node2.name ~= tsm_railcorridors.nodes.dirt) or (nodedef.groups and nodedef.groups.falling_node)) + local falling = minetest.get_item_group(node.name, "falling_node") == 1 + return + -- Node can be replaced if ground content or rail + (node.name ~= "ignore" and node.name ~= "unknown" and nodedef.is_ground_content) and + -- Node needs platform if node below is not walkable. + -- Unless 2 nodes below there is dirt: This is a special case for the starter cube. + ((nodedef.walkable == false and node2.name ~= tsm_railcorridors.nodes.dirt) or + -- Falling nodes always need to be replaced by a platform, we want a solid and safe ground + falling), + -- second return value + falling end -- Create a cube filled with the specified nodes -- Specialties: --- * Avoids floating rails for non-solid nodes like air +-- * Avoids floating rails +-- * May cut into wood structures of the corridors (alongside with their torches) +-- Arguments: +-- * p: Center position +-- * radius: How many nodes from the center the cube will extend +-- * node: Node to set +-- * replace_air_only: If true, only air can be replaced +-- * wood, post: Wood and post nodes of the railway corridor to cut into (optional) + -- Returns true if all nodes could be set -- Returns false if setting one or more nodes failed -local function Cube(p, radius, node, replace_air_only) +local function Cube(p, radius, node, replace_air_only, wood, post) local y_top = p.y+radius local nodedef = minetest.registered_nodes[node.name] local solid = nodedef.walkable and (nodedef.node_box == nil or nodedef.node_box.type == "regular") and nodedef.liquidtype == "none" -- Check if all the nodes could be set local built_all = true - for zi = p.z-radius, p.z+radius do - for yi = y_top, p.y-radius, -1 do - for xi = p.x-radius, p.x+radius do + + -- If wood has been removed, remod + local cleanup_torches = {} + for xi = p.x-radius, p.x+radius do + for zi = p.z-radius, p.z+radius do + local column_last_attached = nil + for yi = y_top, p.y-radius, -1 do local ok = false - if not solid and yi == y_top then - local topdef = minetest.registered_nodes[minetest.get_node({x=xi,y=yi+1,z=zi}).name] - if not (topdef.groups and topdef.groups.attached_node) and topdef.liquidtype == "none" then + local thisnode = minetest.get_node({x=xi,y=yi,z=zi}) + if not solid then + if yi == y_top then + local topnode = minetest.get_node({x=xi,y=yi+1,z=zi}) + local topdef = minetest.registered_nodes[topnode.name] + if minetest.get_item_group(topnode.name, "attached_node") ~= 1 and topdef.liquidtype == "none" then + ok = true + end + elseif column_last_attached and yi == column_last_attached - 1 then + ok = false + else ok = true end + if minetest.get_item_group(thisnode.name, "attached_node") == 1 then + column_last_attached = yi + end else ok = true end local built = false if ok then if replace_air_only ~= true then - built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, node) + -- Cut into wood structures (post/wood) + if post and (xi == p.x or zi == p.z) and thisnode.name == post then + minetest.set_node({x=xi,y=yi,z=zi}, node) + built = true + elseif wood and (xi == p.x or zi == p.z) and thisnode.name == wood then + local topnode = minetest.get_node({x=xi,y=yi+1,z=zi}) + local topdef = minetest.registered_nodes[topnode.name] + if topdef.walkable and topnode.name ~= wood then + minetest.set_node({x=xi,y=yi,z=zi}, node) + -- Check for torches around the wood and schedule them + -- for removal + if node.name == "air" then + table.insert(cleanup_torches, {x=xi+1,y=yi,z=zi}) + table.insert(cleanup_torches, {x=xi-1,y=yi,z=zi}) + table.insert(cleanup_torches, {x=xi,y=yi,z=zi+1}) + table.insert(cleanup_torches, {x=xi,y=yi,z=zi-1}) + end + built = true + end + -- Set node normally + else + built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, node) + end else if minetest.get_node({x=xi,y=yi,z=zi}).name == "air" then built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, node) @@ -226,15 +298,74 @@ local function Cube(p, radius, node, replace_air_only) end end end + -- Remove torches we have detected before + for c=1, #cleanup_torches do + local check = minetest.get_node(cleanup_torches[c]) + if check.name == tsm_railcorridors.nodes.torch_wall or check.name == tsm_railcorridors.nodes.torch_floor then + minetest.set_node(cleanup_torches[c], node) + end + end return built_all end -local function Platform(p, radius, node) +local function DirtRoom(p, radius, height, dirt_mode, decorations_mode) + local y_bottom = p.y + local y_top = y_bottom + height + 1 + dirt_room_coords = { + min = { x = p.x-radius, y = y_bottom, z = p.z-radius }, + max = { x = p.x+radius, y = y_top, z = p.z+radius }, + } + local built_all = true + for xi = p.x-radius, p.x+radius do + for zi = p.z-radius, p.z+radius do + for yi = y_top, y_bottom, -1 do + local thisnode = minetest.get_node({x=xi,y=yi,z=zi}) + local built = false + if xi == p.x-radius or xi == p.x+radius or zi == p.z-radius or zi == p.z+radius or yi == y_bottom or yi == y_top then + if dirt_mode == 1 or yi == y_bottom then + built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, {name=tsm_railcorridors.nodes.dirt}) + elseif (dirt_mode == 2 or dirt_mode == 3) and yi == y_top then + if minetest.get_item_group(thisnode.name, "falling_node") == 1 then + built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, {name=tsm_railcorridors.nodes.dirt}) + end + end + else + if yi == y_bottom + 1 then + -- crazy rails + if decorations_mode == 1 then + local r = pr_deco:next(1,3) + if r == 2 then + built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, {name=tsm_railcorridors.nodes.rail}) + end + end + end + if not built then + built = SetNodeIfCanBuild({x=xi,y=yi,z=zi}, {name="air"}) + end + end + if not built then + built_all = false + end + end + end + end + return built_all +end + +local function Platform(p, radius, node, node2) + -- node2 is secondary platform material for replacing falling nodes + if not node2 then + node2 = { name = tsm_railcorridors.nodes.dirt } + end for zi = p.z-radius, p.z+radius do for xi = p.x-radius, p.x+radius do - local np = NeedsPlatform({x=xi,y=p.y,z=zi}) + local np, np2 = NeedsPlatform({x=xi,y=p.y,z=zi}) if np then - minetest.set_node({x=xi,y=p.y-1,z=zi}, node) + if np2 then + minetest.set_node({x=xi,y=p.y-1,z=zi}, node2) + else + minetest.set_node({x=xi,y=p.y-1,z=zi}, node) + end end end end @@ -253,36 +384,24 @@ local function PlaceChest(pos, param2) end -- This function checks if a cart has ACTUALLY been spawned. --- If not, it tries to spawn it again, and again, until it succeeded or --- it failed too often. -- To be calld by minetest.after. --- This is a HORRIBLE workaround thanks to the fact that minetest.add_entity is unreliable as fuck +-- This is a workaround thanks to the fact that minetest.add_entity is unreliable as fuck -- See: https://github.com/minetest/minetest/issues/4759 -- FIXME: Kill this horrible hack with fire as soon you can. local function RecheckCartHack(params) local pos = params[1] local cart_id = params[2] - local tries = params[3] - tries = tries - 1 -- Find cart for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do if obj ~= nil and obj:get_luaentity().name == cart_id then -- Cart found! We can now safely call the callback func. -- (calling it earlier has the danger of failing) + minetest.log("info", "[tsm_railcorridors] Cart spawn succeeded: "..minetest.pos_to_string(pos)) tsm_railcorridors.on_construct_cart(pos, obj) return end end - if tries <= 0 then - -- Abort if too many tries to avoid excessive function calls - return - end - -- No cart found! :-( Try again … - if minetest.get_node(pos).name == tsm_railcorridors.nodes.rail then - minetest.add_entity(pos, cart_id) - minetest.after(5, RecheckCartHack, {pos, cart_id, tries}) - end - -- The rail may have been destroyed in the meantime, that's why the node is checked. + minetest.log("info", "[tsm_railcorridors] Cart spawn FAILED: "..minetest.pos_to_string(pos)) end -- Try to place a cobweb. @@ -321,27 +440,108 @@ local function TryPlaceCobweb(pos, needs_check, side_vector) return false end end - -local function WoodBulk(pos, wood) - SetNodeIfCanBuild({x=pos.x+1, y=pos.y, z=pos.z+1}, {name=wood}) - SetNodeIfCanBuild({x=pos.x-1, y=pos.y, z=pos.z+1}, {name=wood}) - SetNodeIfCanBuild({x=pos.x+1, y=pos.y, z=pos.z-1}, {name=wood}) - SetNodeIfCanBuild({x=pos.x-1, y=pos.y, z=pos.z-1}, {name=wood}) + +-- 4 wooden pillars around pos at height +local function WoodBulk(pos, height, wood) + for y=0, height-1 do + SetNodeIfCanBuild({x=pos.x+1, y=pos.y+y, z=pos.z+1}, {name=wood}, false, true) + SetNodeIfCanBuild({x=pos.x-1, y=pos.y+y, z=pos.z+1}, {name=wood}, false, true) + SetNodeIfCanBuild({x=pos.x+1, y=pos.y+y, z=pos.z-1}, {name=wood}, false, true) + SetNodeIfCanBuild({x=pos.x-1, y=pos.y+y, z=pos.z-1}, {name=wood}, false, true) + end end --- Gänge mit Schienen --- Corridors with rails +-- Build a wooden support frame +local function WoodSupport(p, wood, post, torches, dir, torchdir) + local node_wood = {name=wood} + local node_fence = {name=post} + + local calc = { + p.x+dir[1], p.z+dir[2], -- X and Z, added by direction + p.x-dir[1], p.z-dir[2], -- subtracted + p.x+dir[2], p.z+dir[1], -- orthogonal + p.x-dir[2], p.z-dir[1], -- orthogonal, the other way + } + --[[ Shape: + WWW + P.P + PrP + pfp + W = wood + P = post (above floor level) + p = post (in floor level, only placed if no floor) + + From previous generation (for reference): + f = floor + r = rail + . = air + ]] + + -- Don't place those wood structs below open air + if not (minetest.get_node({x=calc[1], y=p.y+2, z=calc[2]}).name == "air" and + minetest.get_node({x=calc[3], y=p.y+2, z=calc[4]}).name == "air" and + minetest.get_node({x=p.x, y=p.y+2, z=p.z}).name == "air") then + + -- Left post and planks + local left_ok + left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y-1, z=calc[2]}, node_fence) + if left_ok then left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y , z=calc[2]}, node_fence) end + if left_ok then left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y+1, z=calc[2]}, node_wood, false, true) end + + -- Right post and planks + local right_ok + right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y-1, z=calc[4]}, node_fence) + if right_ok then right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y , z=calc[4]}, node_fence) end + if right_ok then right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y+1, z=calc[4]}, node_wood, false, true) end + + -- Middle planks + local top_planks_ok = false + if left_ok and right_ok then top_planks_ok = SetNodeIfCanBuild({x=p.x, y=p.y+1, z=p.z}, node_wood) end + + if minetest.get_node({x=p.x,y=p.y-2,z=p.z}).name=="air" then + if left_ok then SetNodeIfCanBuild({x=calc[1], y=p.y-2, z=calc[2]}, node_fence) end + if right_ok then SetNodeIfCanBuild({x=calc[3], y=p.y-2, z=calc[4]}, node_fence) end + end + -- Torches on the middle planks + if torches and top_planks_ok then + -- Place torches at horizontal sides + SetNodeIfCanBuild({x=calc[5], y=p.y+1, z=calc[6]}, {name=tsm_railcorridors.nodes.torch_wall, param2=torchdir[1]}, true) + SetNodeIfCanBuild({x=calc[7], y=p.y+1, z=calc[8]}, {name=tsm_railcorridors.nodes.torch_wall, param2=torchdir[2]}, true) + end + elseif torches then + -- Try to build torches instead of the wood structs + local node = {name=tsm_railcorridors.nodes.torch_floor, param2=minetest.dir_to_wallmounted({x=0,y=-1,z=0})} + + -- Try two different height levels + local pos1 = {x=calc[1], y=p.y-2, z=calc[2]} + local pos2 = {x=calc[3], y=p.y-2, z=calc[4]} + local nodedef1 = minetest.registered_nodes[minetest.get_node(pos1).name] + local nodedef2 = minetest.registered_nodes[minetest.get_node(pos2).name] + + if nodedef1.walkable then + pos1.y = pos1.y + 1 + end + SetNodeIfCanBuild(pos1, node, true) + + if nodedef2.walkable then + pos2.y = pos2.y + 1 + end + SetNodeIfCanBuild(pos2, node, true) + + end +end + +-- Dig out a single corridor section and place wooden structures and torches -- Returns , -- success: true if corridor could be placed entirely -- segments: Number of segments successfully placed -local function corridor_part(start_point, segment_vector, segment_count, wood, post, first_or_final, up_or_down_prev) +local function dig_corridor_section(start_point, segment_vector, segment_count, wood, post, up_or_down_prev) local p = {x=start_point.x, y=start_point.y, z=start_point.z} local torches = pr:next() < probability_torches_in_segment local dir = {0, 0} local torchdir = {1, 1} local node_wood = {name=wood} - local node_fence = {name=post} if segment_vector.x == 0 and segment_vector.z ~= 0 then dir = {1, 0} torchdir = {5, 4} @@ -350,7 +550,12 @@ local function corridor_part(start_point, segment_vector, segment_count, wood, p torchdir = {3, 2} end for segmentindex = 0, segment_count-1 do - local dug = Cube(p, 1, {name="air"}) + local dug + if segment_vector.y == 0 then + dug = Cube(p, 1, {name="air"}, false, wood, post) + else + dug = Cube(p, 1, {name="air"}, false) + end if not chaos_mode and segmentindex > 0 and not dug then return false, segmentindex end -- Add wooden platform, if neccessary. To avoid floating rails if segment_vector.y == 0 then @@ -364,92 +569,27 @@ local function corridor_part(start_point, segment_vector, segment_count, wood, p -- Normal 3×3 platform Platform({x=p.x, y=p.y-1, z=p.z}, 1, node_wood) end + else + -- Sloped bridge + Platform({x=p.x-dir[1], y=p.y-2, z=p.z-dir[2]}, 0, node_wood) + Platform({x=p.x, y=p.y-2, z=p.z}, 0, node_wood) + Platform({x=p.x+dir[1], y=p.y-2, z=p.z+dir[2]}, 0, node_wood) end - -- Diese komischen Holz-Konstruktionen - -- These strange wood structs if segmentindex % 2 == 1 and segment_vector.y == 0 then - local calc = { - p.x+dir[1], p.z+dir[2], -- X and Z, added by direction - p.x-dir[1], p.z-dir[2], -- subtracted - p.x+dir[2], p.z+dir[1], -- orthogonal - p.x-dir[2], p.z-dir[1], -- orthogonal, the other way - } - --[[ Shape: - WWW - P.P - PrP - pfp - W = wood - P = post (above floor level) - p = post (in floor level, only placed if no floor) - - From previous generation (for reference): - f = floor - r = rail - . = air - ]] - - -- Don't place those wood structs below open air - if not (minetest.get_node({x=calc[1], y=p.y+2, z=calc[2]}).name == "air" and - minetest.get_node({x=calc[3], y=p.y+2, z=calc[4]}).name == "air" and - minetest.get_node({x=p.x, y=p.y+2, z=p.z}).name == "air") then - - -- Left post and planks - local left_ok = true - left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y-1, z=calc[2]}, node_fence) - if left_ok then left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y , z=calc[2]}, node_fence) end - if left_ok then left_ok = SetNodeIfCanBuild({x=calc[1], y=p.y+1, z=calc[2]}, node_wood) end - - -- Right post and planks - local right_ok = true - right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y-1, z=calc[4]}, node_fence) - if right_ok then right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y , z=calc[4]}, node_fence) end - if right_ok then right_ok = SetNodeIfCanBuild({x=calc[3], y=p.y+1, z=calc[4]}, node_wood) end - - -- Middle planks - local top_planks_ok = false - if left_ok and right_ok then top_planks_ok = SetNodeIfCanBuild({x=p.x, y=p.y+1, z=p.z}, node_wood) end - - if minetest.get_node({x=p.x,y=p.y-2,z=p.z}).name=="air" then - if left_ok then SetNodeIfCanBuild({x=calc[1], y=p.y-2, z=calc[2]}, node_fence) end - if right_ok then SetNodeIfCanBuild({x=calc[3], y=p.y-2, z=calc[4]}, node_fence) end - end - -- Torches on the middle planks - if torches and top_planks_ok then - -- Place torches at horizontal sides - SetNodeIfCanBuild({x=calc[5], y=p.y+1, z=calc[6]}, {name=tsm_railcorridors.nodes.torch_wall, param2=torchdir[1]}, true) - SetNodeIfCanBuild({x=calc[7], y=p.y+1, z=calc[8]}, {name=tsm_railcorridors.nodes.torch_wall, param2=torchdir[2]}, true) - end - elseif torches then - -- Try to build torches instead of the wood structs - local node = {name=tsm_railcorridors.nodes.torch_floor, param2=minetest.dir_to_wallmounted({x=0,y=-1,z=0})} - - -- Try two different height levels - local pos1 = {x=calc[1], y=p.y-2, z=calc[2]} - local pos2 = {x=calc[3], y=p.y-2, z=calc[4]} - local nodedef1 = minetest.registered_nodes[minetest.get_node(pos1).name] - local nodedef2 = minetest.registered_nodes[minetest.get_node(pos2).name] - - if nodedef1.walkable then - pos1.y = pos1.y + 1 - end - SetNodeIfCanBuild(pos1, node, true) - - if nodedef2.walkable then - pos2.y = pos2.y + 1 - end - SetNodeIfCanBuild(pos2, node, true) - - end + WoodSupport(p, wood, post, torches, dir, torchdir) end - - -- nächster Punkt durch Vektoraddition - -- next way point + + -- Next way point p = vector.add(p, segment_vector) end -- End of the corridor segment; create the final piece - local dug = Cube(p, 1, {name="air"}) + local dug + if segment_vector.y == 0 then + dug = Cube(p, 1, {name="air"}, false, wood, post) + else + dug = Cube(p, 1, {name="air"}, false) + end if not chaos_mode and not dug then return false, segment_count end if segment_vector.y == 0 then Platform({x=p.x, y=p.y-1, z=p.z}, 1, node_wood) @@ -457,7 +597,11 @@ local function corridor_part(start_point, segment_vector, segment_count, wood, p return true, segment_count end -local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, up_or_down_prev, up, wood, post, first_or_final, damage, no_spawner) +-- Generate a corridor section. Corridor sections are part of a corridor line. +-- This is one short part of a corridor line. It can be one straight section or it goes up or down. +-- It digs out the corridor and places wood structs and torches using the helper function dig_corridor_function, +-- then it places rails, chests, and other goodies. +local function create_corridor_section(waypoint, axis, sign, up_or_down, up_or_down_next, up_or_down_prev, up, wood, post, first_or_final, damage, no_spawner) local segamount = 3 if up_or_down then segamount = 1 @@ -467,12 +611,12 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, end local vek = {x=0,y=0,z=0}; local start = table.copy(waypoint) - if coord == "x" then + if axis == "x" then vek.x=segamount if up_or_down and up == false then start.x=start.x+segamount end - elseif coord == "z" then + elseif axis == "z" then vek.z=segamount if up_or_down and up == false then start.z=start.z+segamount @@ -487,20 +631,19 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, end local segcount = pr:next(4,6) if up_or_down and up == false then - Cube(waypoint, 1, {name="air"}) + Cube(waypoint, 1, {name="air"}, false) end - local corridor_dug, corridor_segments_dug = corridor_part(start, vek, segcount, wood, post, first_or_final, up_or_down_prev) + local corridor_dug, corridor_segments_dug = dig_corridor_section(start, vek, segcount, wood, post, up_or_down_prev) local corridor_vek = {x=vek.x*segcount, y=vek.y*segcount, z=vek.z*segcount} - -- nachträglich Schienen legen - -- after this: rails + -- After this: rails segamount = 1 if sign then segamount = 0-segamount end - if coord == "x" then + if axis == "x" then vek.x=segamount - elseif coord == "z" then + elseif axis == "z" then vek.z=segamount end if up_or_down then @@ -541,7 +684,7 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, -- Randomly returns either the left or right side of the main rail. -- Also returns offset as second return value. local left_or_right = function(pos, vek) - local off, facedir + local off if pr:next(1, 2) == 1 then -- left off = {x = -vek.z, y= 0, z = vek.x} @@ -565,32 +708,30 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, -- Chest if i == chestplace then local cpos, offset = left_or_right(p, vek) - if minetest.get_node(cpos).name == post then + if minetest.get_node(cpos).name == post or IsInDirtRoom(p) then chestplace = chestplace + 1 else PlaceChest(cpos, minetest.dir_to_facedir(offset)) end end - -- Rail and cart - if i == cartplace then + -- A rail at the side of the track to put a cart on + if i == cartplace and #tsm_railcorridors.carts > 0 then local cpos = left_or_right(p, vek) if minetest.get_node(cpos).name == post then cartplace = cartplace + 1 else - local placed = PlaceRail(cpos, damage) + local placed + if IsRailSurface({x=cpos.x, y=cpos.y-1, z=cpos.z}) then + placed = PlaceRail(cpos, damage) + else + placed = false + end if placed then - local cart_type = pr:next(1, #tsm_railcorridors.carts) - -- FIXME: The cart sometimes fails to spawn - -- See - local cart_id = tsm_railcorridors.carts[cart_type] - local cart = minetest.add_entity(cpos, cart_id) - - -- This checks if the cart is actually spawned, it's a giant hack! - -- Note that the callback function is also called there. - -- TODO: Move callback function to this position when the - -- minetest.add_entity bug has been fixed. - minetest.after(2, RecheckCartHack, {cpos, cart_id, 10}) + -- We don't put on a cart yet, we put it in the carts table + -- for later placement + local cart_type = pr_carts:next(1, #tsm_railcorridors.carts) + table.insert(carts_table, {pos = cpos, cart_type = cart_type}) end end end @@ -649,7 +790,7 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, end end - + local offset = table.copy(corridor_vek) local final_point = vector.add(waypoint, offset) if up_or_down then @@ -657,12 +798,13 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, offset.y = offset.y - 1 final_point = vector.add(waypoint, offset) else - offset[coord] = offset[coord] + segamount + offset[axis] = offset[axis] + segamount final_point = vector.add(waypoint, offset) - -- After going up or down, 1 missing rail piece must be added - if IsRailSurface({x=final_point.x,y=final_point.y-2,z=final_point.z}) then - PlaceRail({x=final_point.x,y=final_point.y-1,z=final_point.z}, damage) - end + end + -- After going up or down, 1 missing rail piece must be added + Platform({x=final_point.x,y=final_point.y-1,z=final_point.z}, 0, {name=wood}) + if IsRailSurface({x=final_point.x,y=final_point.y-2,z=final_point.z}) then + PlaceRail({x=final_point.x,y=final_point.y-1,z=final_point.z}, damage) end end if not corridor_dug then @@ -672,34 +814,46 @@ local function corridor_func(waypoint, coord, sign, up_or_down, up_or_down_next, end end -local function start_corridor(waypoint, coord, sign, length, psra, wood, post, damage, no_spawner) +-- Generate a line of corridors. +-- The corridor can go up/down, take turns and it can branch off, creating more corridor lines. +local function create_corridor_line(waypoint, axis, sign, length, wood, post, damage, no_spawner) local wp = waypoint - local c = coord + local a = axis local s = sign - local ud = false -- up or down - local udn = false -- up or down is next - local udp = false -- up or down was previous - local up + local ud = false -- Up or down + local udn = false -- Up or down is next + local udp = false -- Up or down was previous + local up = false -- true if going up + local upp = false -- true if was going up previously for i=1,length do - local needs_platform -- Update previous up/down status udp = ud + -- Can't go up/down if a platform is needed at waypoint + local needs_platform = NeedsPlatform({x=wp.x,y=wp.y-2,z=wp.z}) -- Update current up/down status - if udn then - needs_platform = NeedsPlatform(wp) - if needs_platform then - ud = false - end + if udn and not needs_platform then ud = true -- Force direction near the height limits if wp.y >= height_max - 12 then + if udp then + ud = false + end up = false elseif wp.y <= height_min + 12 then + if udp then + ud = false + end up = true else - -- Chose random direction in between - up = pr:next(0, 2) < 1 + -- If previous was up/down, keep the vertical direction + if udp and not chaos_mode then + up = upp + else + -- Chose random direction + up = pr:next(1, 2) == 1 + end end + upp = up else ud = false end @@ -709,71 +863,141 @@ local function start_corridor(waypoint, coord, sign, length, psra, wood, post, d elseif udn and not needs_platform then udn = false end - -- Make corridor / Korridor graben + -- Make corridor local first_or_final if i == length then first_or_final = "final" elseif i == 1 then first_or_final = "first" end - wp, no_spawner = corridor_func(wp,c,s, ud, udn, udp, up, wood, post, first_or_final, damage, no_spawner) + wp, no_spawner = create_corridor_section(wp,a,s, ud, udn, udp, up, wood, post, first_or_final, damage, no_spawner) if wp == false then return end - -- Verzweigung? - -- Fork? + -- Fork in the road? If so, starts 2-3 new corridor lines and terminates the current one. if pr:next() < probability_fork then + -- 75% chance to fork off in 3 directions (making a crossing) + -- 25% chance to fork off in 2 directions (making a t-junction) + local is_crossing = pr:next(0, 3) < 3 + local forks = 2 + if is_crossing then + forks = 3 + end local p = {x=wp.x, y=wp.y, z=wp.z} - start_corridor(wp, c, s, pr:next(way_min,way_max), psra, wood, post, damage, no_spawner) - if c == "x" then c="z" else c="x" end - start_corridor(wp, c, s, pr:next(way_min,way_max), psra, wood, post, damage, no_spawner) - start_corridor(wp, c, not s, pr:next(way_min,way_max), psra, wood, post, damage, no_spawner) - WoodBulk({x=p.x, y=p.y-1, z=p.z}, wood) - WoodBulk({x=p.x, y=p.y, z=p.z}, wood) - WoodBulk({x=p.x, y=p.y+1, z=p.z}, wood) - WoodBulk({x=p.x, y=p.y+2, z=p.z}, wood) + local a2 + if a == "x" then + a2="z" + else + a2="x" + end + local fork_dirs = { + {a2, s}, -- to the side + {a2, not s}, -- to the other side + {a, s}, -- straight ahead + } + for f=1, forks do + local r = pr:next(1, #fork_dirs) + create_corridor_line(wp, fork_dirs[r][1], fork_dirs[r][2], pr:next(way_min,way_max), wood, post, damage, no_spawner) + table.remove(fork_dirs, r) + end + if is_crossing and not IsInDirtRoom(p) then + -- 4 large wooden pillars around the center rail + WoodBulk({x=p.x, y=p.y-1, z=p.z}, 4, wood) + end return end - -- coord und sign verändern - -- randomly change sign and coord - if c=="x" then - c="z" - elseif c=="z" then - c="x" + -- Randomly change sign, toggle axis. + -- In other words, take a turn. + if a=="x" then + a="z" + elseif a=="z" then + a="x" end; - s = pr:next(0, 2) < 1 + s = pr:next(1, 2) == 1 end end -local function place_corridors(main_cave_coords, psra) - --[[ ALWAYS start building in the ground. Prevents corridors starting - in mid-air or in liquids. ]] - if not IsGround(main_cave_coords) then - return +-- Spawns all carts in the carts table and clears the carts table afterwards +local function spawn_carts() + for c=1, #carts_table do + local cpos = carts_table[c].pos + local cart_type = carts_table[c].cart_type + local node = minetest.get_node(cpos) + if node.name == tsm_railcorridors.nodes.rail then + -- FIXME: The cart sometimes fails to spawn + -- See + local cart_id = tsm_railcorridors.carts[cart_type] + minetest.log("info", "[tsm_railcorridors] Cart spawn attempt: "..minetest.pos_to_string(cpos)) + minetest.add_entity(cpos, cart_id) + + -- This checks if the cart is actually spawned, it's a giant hack! + -- Note that the callback function is also called there. + -- TODO: Move callback function to this position when the + -- minetest.add_entity bug has been fixed. + minetest.after(3, RecheckCartHack, {cpos, cart_id}) + end end + carts_table = {} +end + +-- Start generation of a rail corridor system +-- main_cave_coords is the center of the floor of the dirt room, from which +-- all corridors expand. +local function create_corridor_system(main_cave_coords) + + -- Dirt room size + local maxsize = 6 + if chaos_mode then + maxsize = 9 + end + local size = pr:next(3, maxsize) + + --[[ Only build if starter coords are in the ground. + Prevents corridors starting in mid-air or in liquids. ]] + local check_coords = { + -- Center of the room, on the floor + {x=0,y=0,z=0}, + -- Also check near the 4 bottom corners of the dirt room + {x= size-1, y=0, z=size-1}, + {x=-size+1, y=0, z=size-1}, + {x= size-1, y=0, z=-size+1}, + {x=-size+1, y=0, z=-size+1}, + } + for c=1, #check_coords do + if not IsGround(vector.add(main_cave_coords, check_coords[c])) then + return false + end + end + local center_node = minetest.get_node(main_cave_coords) + local height = pr:next(4, 7) + if height > size then + height = size + end + local floor_diff = 1 + if pr:next(0, 100) < 50 then + floor_diff = 0 + end + local dirt_mode = pr:next(1,2) + local rnd = pr:next(1,1000) + -- Small chance to fill dirt room with random rails + local decorations_mode = 0 + if rnd == 1000 then + decorations_mode = 1 + end + + --[[ Starting point: A big hollow dirt cube from which the corridors will extend. + Corridor generation starts here. ]] + DirtRoom(main_cave_coords, size, height, dirt_mode, decorations_mode) + main_cave_coords.y = main_cave_coords.y + 2 + floor_diff + -- Determine if this corridor system is “damaged” (some rails removed) and to which extent local damage = 0 if pr:next() < probability_damage then damage = pr:next(10, 50) end - --[[ Starter cube: A big hollow dirt cube from which the corridors will extend. - Corridor generation starts here. ]] - if pr:next(0, 100) < 50 then - Cube(main_cave_coords, 4, {name=tsm_railcorridors.nodes.dirt}) - Cube(main_cave_coords, 3, {name="air"}) - -- Center rail - PlaceRail({x=main_cave_coords.x, y=main_cave_coords.y-3, z=main_cave_coords.z}, damage) - main_cave_coords.y =main_cave_coords.y - 1 - else - Cube(main_cave_coords, 3, {name=tsm_railcorridors.nodes.dirt}) - Cube(main_cave_coords, 2, {name="air"}) - -- Center rail - PlaceRail({x=main_cave_coords.x, y=main_cave_coords.y-2, z=main_cave_coords.z}, damage) - end - local xs = pr:next(0, 2) < 1 - local zs = pr:next(0, 2) < 1; -- Get wood and fence post types, using gameconfig. + local wood, post if tsm_railcorridors.nodes.corridor_woods_function then -- Get wood type by gameconfig function @@ -787,10 +1011,6 @@ local function place_corridors(main_cave_coords, psra) for w=1, #tsm_railcorridors.nodes.corridor_woods do local woodtable = tsm_railcorridors.nodes.corridor_woods[w] accumulated_chance = accumulated_chance + woodtable.chance - if accumulated_chance > 1000 then - minetest.log("warning", "[tsm_railcorridors] Warning: Wood chances add up to over 100%!") - break - end if rnd <= accumulated_chance then woodtype = w break @@ -800,31 +1020,98 @@ local function place_corridors(main_cave_coords, psra) post = tsm_railcorridors.nodes.corridor_woods[woodtype].post end - start_corridor(main_cave_coords, "x", xs, pr:next(way_min,way_max), psra, wood, post, damage, false) - start_corridor(main_cave_coords, "z", zs, pr:next(way_min,way_max), psra, wood, post, damage, false) - -- Auch mal die andere Richtung? - -- Try the other direction? - if pr:next(0, 100) < 70 then - start_corridor(main_cave_coords, "x", not xs, pr:next(way_min,way_max), psra, wood, post, damage, false) + -- Start 2-4 corridors in each direction + local dirs = { + {axis="x", axis2="z", sign=false}, + {axis="x", axis2="z", sign=true}, + {axis="z", axis2="x", sign=false}, + {axis="z", axis2="x", sign=true}, + } + local first_corridor + local corridors = 2 + for _=1, 2 do + if pr:next(0,100) < 70 then + corridors = corridors + 1 + end end - if pr:next(0, 100) < 70 then - start_corridor(main_cave_coords, "z", not zs, pr:next(way_min,way_max), psra, wood, post, damage, false) + -- Chance for 5th corridor in Chaos Mode + if chaos_mode and size > 4 then + if pr:next(0,100) < 50 then + corridors = corridors + 1 + end end + local centered_crossing = false + if corridors <= 4 and pr:next(1, 20) >= 11 then + centered_crossing = true + end + -- This moves the start of the corridors in the dirt room back and forth + local d_max = 3 + if floor_diff == 1 and height <= 4 then + d_max = d_max + 1 + end + local from_center_base = size - pr:next(1,d_max) + for i=1, math.min(4, corridors) do + local d = pr:next(1, #dirs) + local dir = dirs[d] + local side_offset = 0 + if not centered_crossing and size > 3 then + if i==1 and corridors == 5 then + side_offset = pr:next(2, size-2) + if pr:next(1,2) == 1 then + side_offset = -side_offset + end + else + side_offset = pr:next(-size+2, size-2) + end + end + local from_center = from_center_base + if dir.sign then + from_center = -from_center + end + if i == 1 then + first_corridor = {sign=dir.sign, axis=dir.axis, axis2=dir.axis2, side_offset=side_offset, from_center=from_center} + end + local coords = vector.add(main_cave_coords, {[dir.axis] = from_center, y=0, [dir.axis2] = side_offset}) + create_corridor_line(coords, dir.axis, dir.sign, pr:next(way_min,way_max), wood, post, damage, false) + table.remove(dirs, d) + end + if corridors == 5 then + local special_coords = vector.add(main_cave_coords, {[first_corridor.axis2] = -first_corridor.side_offset, y=0, [first_corridor.axis] = first_corridor.from_center}) + create_corridor_line(special_coords, first_corridor.axis, first_corridor.sign, pr:next(way_min,way_max), wood, post, damage, false) + end + + -- At this point, all corridors were generated and all nodes were set. + -- We spawn the carts now + spawn_carts() + + return true end +-- The rail corridor algorithm starts here minetest.register_on_generated(function(minp, maxp, blockseed) + -- We re-init the randomizer for every mapchunk as we start generating in the middle of each mapchunk. + -- We can't use the mapgen seed as this would make the algorithm depending on the order the mapchunk generate. InitRandomizer(blockseed) - if minp.y < height_max and maxp.y > height_min and pr:next() < probability_railcaves_in_chunk then - -- Get semi-random height in chunk - + if minp.y < height_max and maxp.y > height_min and pr:next() < probability_railcaves_in_mapchunk then + -- Keep some distance from the upper/lower mapchunk limits local buffer = 5 - local y = pr:next(minp.y + buffer, maxp.y - buffer) - y = math.floor(math.max(height_min + buffer, math.min(height_max - buffer, y))) - -- Mid point of the chunk - local p = {x=minp.x+math.floor((maxp.x-minp.x)/2), y=y, z=minp.z+math.floor((maxp.z-minp.z)/2)} - -- Haupthöhle und alle weiteren - -- Corridors; starting with main cave out of dirt - place_corridors(p, pr) + -- Do up to 10 tries to start a corridor system + for t=1,10 do + -- Get semi-random height in mapchunk + local y = pr:next(minp.y + buffer, maxp.y - buffer) + y = math.floor(math.max(height_min + buffer, math.min(height_max - buffer, y))) + + -- Mid point of the mapchunk + local p = {x=minp.x+math.floor((maxp.x-minp.x)/2), y=y, z=minp.z+math.floor((maxp.z-minp.z)/2)} + -- Start corridor system at p. Might fail if p is in open air + minetest.log("verbose", "[tsm_railcorridors] Attempting to start rail corridor system at "..minetest.pos_to_string(p)) + if create_corridor_system(p, pr) then + minetest.log("info", "[tsm_railcorridors] Generated rail corridor system at "..minetest.pos_to_string(p)) + break + else + minetest.log("info", "[tsm_railcorridors] Rail corridor system generation attempt failed at "..minetest.pos_to_string(p).. " (try "..t..")") + end + end end end) diff --git a/mods/MAPGEN/tsm_railcorridors/settingtypes.txt b/mods/MAPGEN/tsm_railcorridors/settingtypes.txt index b21662c6..a2896290 100644 --- a/mods/MAPGEN/tsm_railcorridors/settingtypes.txt +++ b/mods/MAPGEN/tsm_railcorridors/settingtypes.txt @@ -1,5 +1,5 @@ -#Probability (0.0 to 1.0) for every newly generated chunk to get rail corridors. -tsm_railcorridors_probability_railcaves_in_chunk (Rail corridor probability) float 0.3 0.0 1.0 +#Probability (0.0 to 1.0) for every newly generated mapchunk to get rail corridors. +tsm_railcorridors_probability_railcaves_in_mapchunk (Rail corridor probability) float 0.33333 0.0 1.0 #Minimum rail corridor path length (excludes forks). tsm_railcorridors_way_min (Minimum rail corridor length) int 4 1 @@ -20,6 +20,17 @@ tsm_railcorridors_probability_fork (Fork probability) float 0.04 0.0 1.0 #Probability (0.0 to 1.0) for every part of a rail corridor to contain a treasure chest. tsm_railcorridors_probability_chest (Chest probability) float 0.05 0.0 1.0 +#Probability (0.0 to 1.0) for every part of a rail corridor to include a cart. +#Note: The rail may still be subject to rail damage, so the probability +#of finding a cart in rail corridors with high rail damage will be lower. +#NOTE: Due to a bug in Minetest +#carts often fail to spawn even if they should. +tsm_railcorridors_probability_cart (Cart probability) float 0.0 0.0 1.0 + +#If enabled, cobwebs may be placed in some corridors. +#Currently, cobwebs are only supported with the Mobs Redo mod. +tsm_railcorridors_place_cobwebs (Cobwebs) bool true + #Probability (0.0 to 1.0) for a rail corridor system to have damaged/incomplete railways tsm_railcorridors_probability_damage (Damaged railway probability) float 1.0 0.0 1.0 @@ -28,7 +39,3 @@ tsm_railcorridors_probability_damage (Damaged railway probability) float 1.0 0.0 #to pretty chaotic rail corridors, but they are also more free to spread. #If disabled, rail corridors spread in a orderly fashion. tsm_railcorridors_chaos (Chaos Mode) bool false - -#If enabled, cobwebs may be placed in some corridors. -#Currently, cobwebs are only supported with the Mobs Redo mod. -tsm_railcorridors_place_cobwebs (Cobwebs) bool true From 8982e368ecb1e4146a74d75508eea5c593388f60 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 16:09:39 +0100 Subject: [PATCH 080/865] Abort sleep if taking damage --- mods/ITEMS/mcl_beds/functions.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index f763a23c..495927a1 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -194,6 +194,7 @@ function mcl_beds.sleep() end end +-- Throw all players out of bed function mcl_beds.kick_players() for name, _ in pairs(mcl_beds.player) do local player = minetest.get_player_by_name(name) @@ -201,6 +202,14 @@ function mcl_beds.kick_players() end end +-- Throw a player out of bed +function mcl_beds.kick_player(player) + local name = player:get_player_name() + if mcl_beds.player[name] ~= nil then + lay_down(player, nil, nil, false) + end +end + function mcl_beds.skip_night() minetest.set_timeofday(0.25) -- tod = 6000 end @@ -305,3 +314,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) mcl_beds.sleep() end end) + +minetest.register_on_player_hpchange(function(player, hp_change) + if hp_change < 0 then + mcl_beds.kick_player(player) + end +end) From 3b8fe6039e8238b0c5d5a335fbfcfbe7d21c9743 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 16:18:13 +0100 Subject: [PATCH 081/865] Don't skip night if not all players are asleep --- mods/ITEMS/mcl_beds/functions.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 495927a1..e57d5822 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -161,15 +161,18 @@ local function lay_down(player, pos, bed_pos, state, skip) end local function update_formspecs(finished) + if is_sp then + return + end local ges = #minetest.get_connected_players() local form_n local all_in_bed = ges == player_in_bed if finished then - form_n = mcl_beds.formspec .. "label[2.7,11; Good morning.]" + form_n = mcl_beds.formspec .. "label[2.7,11;Good morning.]" else form_n = mcl_beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) .. - " of " .. tostring(ges) .. " players are in bed]" + " of " .. tostring(ges) .. " players are in bed]" end for name,_ in pairs(mcl_beds.player) do @@ -272,10 +275,10 @@ function mcl_beds.on_rightclick(pos, player) -- skip the night and let all players stand up if check_in_beds() then minetest.after(5, function() - if not is_sp then + if check_in_beds() then update_formspecs(is_night_skip_enabled()) + mcl_beds.sleep() end - mcl_beds.sleep() end) end end @@ -294,8 +297,10 @@ minetest.register_on_leaveplayer(function(player) mcl_beds.player[name] = nil if check_in_beds() then minetest.after(5, function() - update_formspecs(is_night_skip_enabled()) - mcl_beds.sleep() + if check_in_beds() then + update_formspecs(is_night_skip_enabled()) + mcl_beds.sleep() + end end) end end) From cb2978470cea010bc7b96d2eacff7e34432d5308 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 17:04:38 +0100 Subject: [PATCH 082/865] Improve bed formspec --- mods/ITEMS/mcl_beds/functions.lua | 35 ++++++++++++++++++++++--------- mods/ITEMS/mcl_beds/init.lua | 4 ---- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index e57d5822..357d8bd2 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -161,18 +161,32 @@ local function lay_down(player, pos, bed_pos, state, skip) end local function update_formspecs(finished) - if is_sp then - return - end local ges = #minetest.get_connected_players() - local form_n + local form_n = "size[8,15;true]" + local all_in_bed = ges == player_in_bed if finished then - form_n = mcl_beds.formspec .. "label[2.7,11;Good morning.]" + for name,_ in pairs(mcl_beds.player) do + minetest.close_formspec(name, "mcl_beds_form") + end + return + elseif not is_sp then + local text = string.format("%d of %d player(s) are in bed.", player_in_bed, ges) + if all_in_bed then + text = text .. "\n" .. "You're sleeping." + form_n = form_n .. "bgcolor[#000000FF; true]" + form_n = form_n .. "button_exit[2,12;4,0.75;leave;Abort sleep]" + else + text = text .. "\n" .. "Sleep will commence when all players are in bed." + form_n = form_n .. "bgcolor[#808080BB; true]" + form_n = form_n .. "button_exit[2,12;4,0.75;leave;Leave bed]" + end + form_n = form_n .. "label[2.2,7.5;"..minetest.formspec_escape(text).."]" else - form_n = mcl_beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) .. - " of " .. tostring(ges) .. " players are in bed]" + form_n = form_n .. "label[2.2,7.5;You're sleeping.]" + form_n = form_n .. "button_exit[2,12;4,0.75;leave;Abort sleep]" + form_n = form_n .. "bgcolor[#000000FF; true]" end for name,_ in pairs(mcl_beds.player) do @@ -203,6 +217,7 @@ function mcl_beds.kick_players() local player = minetest.get_player_by_name(name) lay_down(player, nil, nil, false) end + update_formspecs(false) end -- Throw a player out of bed @@ -210,6 +225,8 @@ function mcl_beds.kick_player(player) local name = player:get_player_name() if mcl_beds.player[name] ~= nil then lay_down(player, nil, nil, false) + update_formspecs(false) + minetest.close_formspec(name, "mcl_beds_form") end end @@ -268,9 +285,7 @@ function mcl_beds.on_rightclick(pos, player) lay_down(player, nil, nil, false) end - if not is_sp then - update_formspecs(false) - end + update_formspecs(false) -- skip the night and let all players stand up if check_in_beds() then diff --git a/mods/ITEMS/mcl_beds/init.lua b/mods/ITEMS/mcl_beds/init.lua index 72bfb347..8f60cb54 100644 --- a/mods/ITEMS/mcl_beds/init.lua +++ b/mods/ITEMS/mcl_beds/init.lua @@ -2,10 +2,6 @@ mcl_beds = {} mcl_beds.player = {} mcl_beds.pos = {} -mcl_beds.formspec = "size[8,15;true]" .. - "bgcolor[#080808BB; true]" .. - "button_exit[2,12;4,0.75;leave;Leave Bed]" - local modpath = minetest.get_modpath("mcl_beds") -- Load files From b481eadafd08d3dcc79a0619db36a546edc0fd25 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 17:32:22 +0100 Subject: [PATCH 083/865] Beds: Show message when night skip is disabled --- mods/ITEMS/mcl_beds/functions.lua | 34 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 357d8bd2..6b35000b 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -163,8 +163,12 @@ end local function update_formspecs(finished) local ges = #minetest.get_connected_players() local form_n = "size[8,15;true]" - local all_in_bed = ges == player_in_bed + local night_skip = is_night_skip_enabled() + local button_leave = "button_exit[2,12;4,0.75;leave;Leave bed]" + local button_abort = "button_exit[2,12;4,0.75;leave;Abort sleep]" + local bg_presleep = "bgcolor[#00000080;true]" + local bg_sleep = "bgcolor[#000000FF;true]" if finished then for name,_ in pairs(mcl_beds.player) do @@ -173,20 +177,32 @@ local function update_formspecs(finished) return elseif not is_sp then local text = string.format("%d of %d player(s) are in bed.", player_in_bed, ges) - if all_in_bed then + if not night_skip then + text = text .. "\n" .. "You're in bed." .. "\n" .. "Note: Night skip is disabled." + form_n = form_n .. bg_presleep + form_n = form_n .. button_leave + elseif all_in_bed then text = text .. "\n" .. "You're sleeping." - form_n = form_n .. "bgcolor[#000000FF; true]" - form_n = form_n .. "button_exit[2,12;4,0.75;leave;Abort sleep]" + form_n = form_n .. bg_sleep + form_n = form_n .. button_abort else text = text .. "\n" .. "Sleep will commence when all players are in bed." - form_n = form_n .. "bgcolor[#808080BB; true]" - form_n = form_n .. "button_exit[2,12;4,0.75;leave;Leave bed]" + form_n = form_n .. bg_presleep + form_n = form_n .. button_leave end form_n = form_n .. "label[2.2,7.5;"..minetest.formspec_escape(text).."]" else - form_n = form_n .. "label[2.2,7.5;You're sleeping.]" - form_n = form_n .. "button_exit[2,12;4,0.75;leave;Abort sleep]" - form_n = form_n .. "bgcolor[#000000FF; true]" + local text + if night_skip then + text = "You're sleeping." + form_n = form_n .. bg_sleep + form_n = form_n .. button_abort + else + text = "You're in bed." .. "\n" .. "Note: Night skip is disabled." + form_n = form_n .. bg_presleep + form_n = form_n .. button_leave + end + form_n = form_n .. "label[2.2,7.5;"..minetest.formspec_escape(text).."]" end for name,_ in pairs(mcl_beds.player) do From 942b9468ffadb7f3451583b909b096e8a8c8c9c2 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 17:38:19 +0100 Subject: [PATCH 084/865] Simplify bed help a bit --- mods/ITEMS/mcl_beds/api.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 074d847d..5d473245 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -23,16 +23,16 @@ local function destruct_bed(pos, n) end local beddesc = "Beds allow you to sleep at night and make the time pass faster." -local beduse = "Right-click on the bed to sleep in it. This only works when the sun sets, at night or during a thunderstorm." +local beduse = "To use a bed, stand close to it and right-click the bed to sleep in it. Sleeping only works when the sun sets, at night or during a thunderstorm. The bed must also be clear of any danger." if minetest.settings:get_bool("enable_bed_respawn") == false then - beddesc = beddesc .. "\n" .. "In local folklore, legends are told of other worlds where setting the start point for your next would be possible. But this world is not one of them." + beddesc = beddesc .. "\n" .. "In local folklore, legends are told of other worlds where setting the start point for your next life would be possible. But this world is not one of them." else - beddesc = beddesc .. "\n" .. "By sleeping in a bed, you set the starting point for your next life." + beddesc = beddesc .. "\n" .. "By sleeping in a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed." end if minetest.settings:get_bool("enable_bed_night_skip") == false then beddesc = beddesc .. "\n" .. "In this strange world, going to bed won't skip the night, but you can skip thunderstorms." else - beddesc = beddesc .. "\n" .. "Sleeping allows you to skip the night if you're the only player in this world. If you're not alone, the night is skipped when all players in this world went to sleep. Thunderstorms can be skipped in the same manner." + beddesc = beddesc .. "\n" .. "Sleeping allows you to skip the night. The night is skipped when all players in this world went to sleep. The night is skipped after sleeping for a few seconds. Thunderstorms can be skipped in the same manner." end local default_sounds From f18b1bd52ae158f05e096324f33df44d2956b1c4 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 18:01:21 +0100 Subject: [PATCH 085/865] Kick player out of bed when bed destroyed --- mods/ITEMS/mcl_beds/api.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 5d473245..5675b50a 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -22,6 +22,18 @@ local function destruct_bed(pos, n) end end +local function kick_player_after_destruct(pos) + for name, _ in pairs(mcl_beds.pos) do + if vector.equals(pos, mcl_beds.pos) then + local player = minetest.get_player_by_name(name) + if player and player:is_player() then + mcl_beds.kick_player(player) + break + end + end + end +end + local beddesc = "Beds allow you to sleep at night and make the time pass faster." local beduse = "To use a bed, stand close to it and right-click the bed to sleep in it. Sleeping only works when the sun sets, at night or during a thunderstorm. The bed must also be clear of any danger." if minetest.settings:get_bool("enable_bed_respawn") == false then @@ -125,6 +137,7 @@ function mcl_beds.register_bed(name, def) on_destruct = function(pos) destruct_bed(pos, 1) + kick_player_after_destruct(pos) end, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) @@ -199,6 +212,7 @@ function mcl_beds.register_bed(name, def) on_rotate = false, on_destruct = function(pos) destruct_bed(pos, 2) + kick_player_after_destruct(pos) end, }) From 0cc8962258a522ce787fb5b2df0c16e3e412d82e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 18:17:44 +0100 Subject: [PATCH 086/865] Fix stuck player if server shuts down during sleep --- mods/ITEMS/mcl_beds/functions.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 6b35000b..27faef23 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -318,8 +318,11 @@ end -- Callbacks minetest.register_on_joinplayer(function(player) if player:get_attribute("mcl_beds:sleeping") == "true" then + -- Make player awake on joining server player:set_attribute("mcl_beds:sleeping", "false") end + playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping") + playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping") end) minetest.register_on_leaveplayer(function(player) From ec53db93529de46cfc14692701bfdd9b9554c908 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 19:22:24 +0100 Subject: [PATCH 087/865] Beds can save spawn pos at daytime, too --- mods/ITEMS/mcl_beds/api.lua | 18 +++++----- mods/ITEMS/mcl_beds/functions.lua | 58 ++++++++++++++++++------------- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 5675b50a..708f529c 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -1,15 +1,13 @@ local reverse = true -local function destruct_bed(pos, n) +local function destruct_bed(pos, is_top) local node = minetest.get_node(pos) local other - - if n == 2 then - local dir = minetest.facedir_to_dir(node.param2) + local dir = minetest.facedir_to_dir(node.param2) + if is_top then other = vector.subtract(pos, dir) - elseif n == 1 then - local dir = minetest.facedir_to_dir(node.param2) + else other = vector.add(pos, dir) end @@ -136,12 +134,12 @@ function mcl_beds.register_bed(name, def) end, on_destruct = function(pos) - destruct_bed(pos, 1) + destruct_bed(pos, false) kick_player_after_destruct(pos) end, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) - mcl_beds.on_rightclick(pos, clicker) + mcl_beds.on_rightclick(pos, clicker, false) return itemstack end, @@ -206,12 +204,12 @@ function mcl_beds.register_bed(name, def) selection_box = selection_box_top, collision_box = collision_box_top, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) - mcl_beds.on_rightclick(pos, clicker) + mcl_beds.on_rightclick(pos, clicker, true) return itemstack end, on_rotate = false, on_destruct = function(pos) - destruct_bed(pos, 2) + destruct_bed(pos, true) kick_player_after_destruct(pos) end, }) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 27faef23..2232f6da 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -61,14 +61,14 @@ local function lay_down(player, pos, bed_pos, state, skip) local hud_flags = player:hud_get_flags() if not player or not name then - return + return false end if bed_pos then -- No sleeping if too far away if vector.distance(bed_pos, pos) > 2 then minetest.chat_send_player(name, "You can't sleep, the bed's too far away!") - return + return false end -- No sleeping while moving. This is a workaround. @@ -76,7 +76,7 @@ local function lay_down(player, pos, bed_pos, state, skip) -- but this is not possible in Minetest 0.4.17. if vector.length(player:get_player_velocity()) > 0.001 then minetest.chat_send_player(name, "You have to stop moving before going to bed!") - return + return false end -- No sleeping if monsters nearby. @@ -93,7 +93,7 @@ local function lay_down(player, pos, bed_pos, state, skip) if math.abs(bed_pos.y - obj:get_pos().y) <= 5 then minetest.chat_send_player(name, "You can't sleep now, monsters are nearby!") end - return + return false end end end @@ -108,7 +108,7 @@ local function lay_down(player, pos, bed_pos, state, skip) end -- skip here to prevent sending player specific changes (used for leaving players) if skip then - return + return false end if p then player:setpos(p) @@ -116,7 +116,9 @@ local function lay_down(player, pos, bed_pos, state, skip) -- physics, eye_offset, etc player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0}) - player:set_look_horizontal(math.random(1, 180) / 100) + if player:get_look_vertical() > 0 then + player:set_look_vertical(0) + end mcl_player.player_attached[name] = false playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping") playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping") @@ -135,10 +137,24 @@ local function lay_down(player, pos, bed_pos, state, skip) local def2 = minetest.registered_nodes[n2.name] if def1.walkable or def2.walkable then minetest.chat_send_player(name, "You can't sleep, the bed is obstructed!") - return + return false elseif (def1.damage_per_second ~= nil and def1.damage_per_second > 0) or (def2.damage_per_second ~= nil and def2.damage_per_second > 0) then minetest.chat_send_player(name, "It's too dangerous to sleep here!") - return + return false + end + + if minetest.get_modpath("mcl_spawn") then + local spos = table.copy(bed_pos) + spos.y = spos.y + 0.1 + mcl_spawn.set_spawn_pos(player, spos) -- save respawn position when entering bed + end + + -- Check day of time and weather + local tod = minetest.get_timeofday() * 24000 + -- Values taken from Minecraft Wiki with offset of +6000 + if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then + minetest.chat_send_player(name, "You can only sleep at night or during a thunderstorm.") + return false end mcl_beds.player[name] = 1 @@ -147,6 +163,7 @@ local function lay_down(player, pos, bed_pos, state, skip) -- physics, eye_offset, etc player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0}) player:set_look_horizontal(yaw) + player:set_look_vertical(0) player:set_attribute("mcl_beds:sleeping", "true") playerphysics.add_physics_factor(player, "speed", "mcl_beds:sleeping", 0) @@ -158,6 +175,7 @@ local function lay_down(player, pos, bed_pos, state, skip) end player:hud_set_flags(hud_flags) + return true end local function update_formspecs(finished) @@ -260,7 +278,7 @@ function mcl_beds.skip_thunderstorm() return false end -function mcl_beds.on_rightclick(pos, player) +function mcl_beds.on_rightclick(pos, player, is_top) -- Anti-Inception: Don't allow to sleep while you're sleeping if player:get_attribute("mcl_beds:sleeping") == "true" then return @@ -278,24 +296,16 @@ function mcl_beds.on_rightclick(pos, player) end local name = player:get_player_name() local ppos = player:get_pos() - local tod = minetest.get_timeofday() * 24000 - - -- Values taken from Minecraft Wiki with offset of +6000 - if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then - if mcl_beds.player[name] then - lay_down(player, nil, nil, false) - end - minetest.chat_send_player(name, "You can only sleep at night or during a thunderstorm.") - return - end -- move to bed if not mcl_beds.player[name] then - lay_down(player, ppos, pos) - if minetest.get_modpath("mcl_spawn") then - local spos = table.copy(pos) - spos.y = spos.y + 0.1 - mcl_spawn.set_spawn_pos(player, spos) -- save respawn position when entering bed + if is_top then + lay_down(player, ppos, pos) + else + local node = minetest.get_node(pos) + local dir = minetest.facedir_to_dir(node.param2) + local other = vector.add(pos, dir) + lay_down(player, ppos, other) end else lay_down(player, nil, nil, false) From 079b09c80f1a01d8ac0a4041c9c83e3963be4c2e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 19:39:12 +0100 Subject: [PATCH 088/865] Explicit msgs when respawn pos changed due to bed --- mods/ITEMS/mcl_beds/api.lua | 2 +- mods/ITEMS/mcl_beds/functions.lua | 12 ++++++++++-- mods/PLAYER/mcl_spawn/init.lua | 22 +++++++++++++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index 708f529c..b6f18ea4 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -37,7 +37,7 @@ local beduse = "To use a bed, stand close to it and right-click the bed to sleep if minetest.settings:get_bool("enable_bed_respawn") == false then beddesc = beddesc .. "\n" .. "In local folklore, legends are told of other worlds where setting the start point for your next life would be possible. But this world is not one of them." else - beddesc = beddesc .. "\n" .. "By sleeping in a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed." + beddesc = beddesc .. "\n" .. "By using a bed, you set the starting point for your next life. If you die, you will start your next life at this bed, unless it is obstructed or destroyed." end if minetest.settings:get_bool("enable_bed_night_skip") == false then beddesc = beddesc .. "\n" .. "In this strange world, going to bed won't skip the night, but you can skip thunderstorms." diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 2232f6da..e20bb8c5 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -143,19 +143,27 @@ local function lay_down(player, pos, bed_pos, state, skip) return false end + local spawn_changed = false if minetest.get_modpath("mcl_spawn") then local spos = table.copy(bed_pos) spos.y = spos.y + 0.1 - mcl_spawn.set_spawn_pos(player, spos) -- save respawn position when entering bed + spawn_changed = mcl_spawn.set_spawn_pos(player, spos) -- save respawn position when entering bed end -- Check day of time and weather local tod = minetest.get_timeofday() * 24000 -- Values taken from Minecraft Wiki with offset of +6000 if tod < 18541 and tod > 5458 and (not weather_mod or (mcl_weather.get_weather() ~= "thunder")) then - minetest.chat_send_player(name, "You can only sleep at night or during a thunderstorm.") + if spawn_changed then + minetest.chat_send_player(name, "New respawn position set! But you can only sleep at night or during a thunderstorm.") + else + minetest.chat_send_player(name, "You can only sleep at night or during a thunderstorm.") + end return false end + if spawn_changed then + minetest.chat_send_player(name, "New respawn position set!") + end mcl_beds.player[name] = 1 mcl_beds.pos[name] = pos diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index f97f1700..5c8a797e 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -32,12 +32,32 @@ end -- Sets the player's spawn position to pos. -- Set pos to nil to clear the spawn position. -mcl_spawn.set_spawn_pos = function(player, pos, type) +-- If message is set, informs the player with a chat message when the spawn position +-- changed. +mcl_spawn.set_spawn_pos = function(player, pos, message) + local spawn_changed = false if pos == nil then + if player:get_attribute("mcl_beds:spawn") ~= "" then + spawn_changed = true + if message then + minetest.chat_send_player(player:get_player_name(), "Respawn position cleared!") + end + end player:set_attribute("mcl_beds:spawn", "") else + local oldpos = minetest.string_to_pos(player:get_attribute("mcl_beds:spawn")) + if oldpos then + -- We don't bother sending a message if the new spawn pos is basically the same + if vector.distance(pos, oldpos) > 0.1 then + spawn_changed = true + if message then + minetest.chat_send_player(player:get_player_name(), "New respawn position set!") + end + end + end player:set_attribute("mcl_beds:spawn", minetest.pos_to_string(pos)) end + return spawn_changed end -- Respawn player at specified respawn position From 88872c8ce253f49f73222a469f3daa056c377f46 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 20:40:06 +0100 Subject: [PATCH 089/865] Can't sleep in occupied beds --- mods/ITEMS/mcl_beds/functions.lua | 14 ++++++++++++-- mods/ITEMS/mcl_beds/init.lua | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index e20bb8c5..5f24f7ba 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -71,6 +71,13 @@ local function lay_down(player, pos, bed_pos, state, skip) return false end + for _, other_pos in pairs(mcl_beds.bed_pos) do + if vector.distance(bed_pos, other_pos) < 0.1 then + minetest.chat_send_player(name, "This bed is already occupied!") + return false + end + end + -- No sleeping while moving. This is a workaround. -- TODO: Ideally, the player speed should be force-set to 0, -- but this is not possible in Minetest 0.4.17. @@ -111,7 +118,7 @@ local function lay_down(player, pos, bed_pos, state, skip) return false end if p then - player:setpos(p) + player:set_pos(p) end -- physics, eye_offset, etc @@ -125,6 +132,8 @@ local function lay_down(player, pos, bed_pos, state, skip) player:set_attribute("mcl_beds:sleeping", "false") hud_flags.wielditem = true mcl_player.player_set_animation(player, "stand" , 30) + mcl_beds.pos[name] = nil + mcl_beds.bed_pos[name] = nil -- lay down else @@ -167,6 +176,7 @@ local function lay_down(player, pos, bed_pos, state, skip) mcl_beds.player[name] = 1 mcl_beds.pos[name] = pos + mcl_beds.bed_pos[name] = bed_pos player_in_bed = player_in_bed + 1 -- physics, eye_offset, etc player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0}) @@ -176,7 +186,7 @@ local function lay_down(player, pos, bed_pos, state, skip) player:set_attribute("mcl_beds:sleeping", "true") playerphysics.add_physics_factor(player, "speed", "mcl_beds:sleeping", 0) playerphysics.add_physics_factor(player, "jump", "mcl_beds:sleeping", 0) - player:setpos(p) + player:set_pos(p) mcl_player.player_attached[name] = true hud_flags.wielditem = false mcl_player.player_set_animation(player, "lay" , 0) diff --git a/mods/ITEMS/mcl_beds/init.lua b/mods/ITEMS/mcl_beds/init.lua index 8f60cb54..4c25b539 100644 --- a/mods/ITEMS/mcl_beds/init.lua +++ b/mods/ITEMS/mcl_beds/init.lua @@ -1,6 +1,7 @@ mcl_beds = {} mcl_beds.player = {} mcl_beds.pos = {} +mcl_beds.bed_pos = {} local modpath = minetest.get_modpath("mcl_beds") From 8c672fa3b22a686e07b6b15a75c1bb3b90e3cb86 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 20:45:55 +0100 Subject: [PATCH 090/865] Tweak messages in mcl_beds --- mods/ITEMS/mcl_beds/functions.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 5f24f7ba..67382dfb 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -78,9 +78,7 @@ local function lay_down(player, pos, bed_pos, state, skip) end end - -- No sleeping while moving. This is a workaround. - -- TODO: Ideally, the player speed should be force-set to 0, - -- but this is not possible in Minetest 0.4.17. + -- No sleeping while moving. Slightly different behaviour than in MC. if vector.length(player:get_player_velocity()) > 0.001 then minetest.chat_send_player(name, "You have to stop moving before going to bed!") return false @@ -214,7 +212,7 @@ local function update_formspecs(finished) elseif not is_sp then local text = string.format("%d of %d player(s) are in bed.", player_in_bed, ges) if not night_skip then - text = text .. "\n" .. "You're in bed." .. "\n" .. "Note: Night skip is disabled." + text = text .. "\n" .. "Note: Night skip is disabled." form_n = form_n .. bg_presleep form_n = form_n .. button_leave elseif all_in_bed then @@ -222,7 +220,7 @@ local function update_formspecs(finished) form_n = form_n .. bg_sleep form_n = form_n .. button_abort else - text = text .. "\n" .. "Sleep will commence when all players are in bed." + text = text .. "\n" .. "You will fall asleep when all players are in bed." form_n = form_n .. bg_presleep form_n = form_n .. button_leave end From 7678a1a95fefdf742f39bd39ff11aa249ac12ad5 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 20:52:06 +0100 Subject: [PATCH 091/865] Beds: Fix kick_players_afeter_destruct --- mods/ITEMS/mcl_beds/api.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index b6f18ea4..4fbbe55e 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -20,9 +20,9 @@ local function destruct_bed(pos, is_top) end end -local function kick_player_after_destruct(pos) - for name, _ in pairs(mcl_beds.pos) do - if vector.equals(pos, mcl_beds.pos) then +local function kick_player_after_destruct(destruct_pos) + for name, player_bed_pos in pairs(mcl_beds.bed_pos) do + if vector.distance(destruct_pos, player_bed_pos) < 0.1 then local player = minetest.get_player_by_name(name) if player and player:is_player() then mcl_beds.kick_player(player) From 686b575f81f36471e6ccb6b5e845b0b9300409e7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 20:59:01 +0100 Subject: [PATCH 092/865] Beds: Fix player model offset when laying down --- mods/ITEMS/mcl_beds/functions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 67382dfb..6824cabe 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -137,7 +137,7 @@ local function lay_down(player, pos, bed_pos, state, skip) else local yaw, param2 = get_look_yaw(bed_pos) local dir = minetest.facedir_to_dir(param2) - local p = {x = bed_pos.x + dir.x / 4, y = bed_pos.y, z = bed_pos.z + dir.z / 4} + local p = {x = bed_pos.x - dir.x/2, y = bed_pos.y, z = bed_pos.z - dir.z/2} local n1 = minetest.get_node({x=bed_pos.x, y=bed_pos.y+1, z=bed_pos.z}) local n2 = minetest.get_node({x=bed_pos.x, y=bed_pos.y+2, z=bed_pos.z}) local def1 = minetest.registered_nodes[n1.name] From 99741f3d2a7b2a0a0323b55ab53d5d4033242291 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 21:03:25 +0100 Subject: [PATCH 093/865] Beds: Update formspecs when player leaves/joins --- mods/ITEMS/mcl_beds/functions.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 6824cabe..018cf74f 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -349,6 +349,7 @@ minetest.register_on_joinplayer(function(player) end playerphysics.remove_physics_factor(player, "speed", "mcl_beds:sleeping") playerphysics.remove_physics_factor(player, "jump", "mcl_beds:sleeping") + update_formspecs(false) end) minetest.register_on_leaveplayer(function(player) @@ -363,6 +364,7 @@ minetest.register_on_leaveplayer(function(player) end end) end + update_formspecs(false) end) minetest.register_on_player_receive_fields(function(player, formname, fields) From 00851220287becbd83186f2a2ea3b2aac76eb85a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 20 Feb 2019 21:09:04 +0100 Subject: [PATCH 094/865] Slightly rewrite a bed formspec string --- mods/ITEMS/mcl_beds/functions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_beds/functions.lua b/mods/ITEMS/mcl_beds/functions.lua index 018cf74f..02f72ff5 100644 --- a/mods/ITEMS/mcl_beds/functions.lua +++ b/mods/ITEMS/mcl_beds/functions.lua @@ -210,7 +210,7 @@ local function update_formspecs(finished) end return elseif not is_sp then - local text = string.format("%d of %d player(s) are in bed.", player_in_bed, ges) + local text = string.format("Players in bed: %d/%d", player_in_bed, ges) if not night_skip then text = text .. "\n" .. "Note: Night skip is disabled." form_n = form_n .. bg_presleep From 31668cdde516a955bea9e49cfbd6a287fa11f61c Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 21 Feb 2019 02:37:13 +0100 Subject: [PATCH 095/865] Add brown mooshroom --- mods/ENTITIES/mobs_mc/LICENSE-media.md | 5 ++++- mods/ENTITIES/mobs_mc/cow+mooshroom.lua | 9 +++++++-- .../mobs_mc/textures/mobs_mc_mooshroom_brown.png | Bin 0 -> 1048 bytes .../mobs_mc/textures/mobs_mc_mushroom_brown.png | Bin 0 -> 374 bytes mods/ENTITIES/mobs_mc_gameconfig/init.lua | 1 + mods/ENVIRONMENT/lightning/init.lua | 8 ++++++++ 6 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_mooshroom_brown.png create mode 100644 mods/ENTITIES/mobs_mc/textures/mobs_mc_mushroom_brown.png diff --git a/mods/ENTITIES/mobs_mc/LICENSE-media.md b/mods/ENTITIES/mobs_mc/LICENSE-media.md index fe5c41e7..7cad2241 100644 --- a/mods/ENTITIES/mobs_mc/LICENSE-media.md +++ b/mods/ENTITIES/mobs_mc/LICENSE-media.md @@ -70,6 +70,9 @@ Origin of those models: * `mobs_mc_wither.png` * `mobs_mc_wither_skeleton.png` * `mobs_mc_TEMP_wither_projectile.png` + * Gerold55 + * `mobs_mc_mooshroom_brown.png` (CC0) + * `mobs_mc_mushroom_brown.png` (CC0) * “Spawn egg” textures (`mobs_mc_spawn_icon_*`) by 22i * Any other texture not mentioned here are licensed under the MIT License @@ -183,4 +186,4 @@ Origin of those models: Note: Many of these sounds have been more or less modified to fit the game. -Sounds not mentioned here are licensed under CC0. +Sounds not mentioned hre are licensed under CC0. diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index bf1f9c1d..48a6aac7 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -80,7 +80,7 @@ mobs:register_mob("mobs_mc:cow", cow_def) local mooshroom_def = table.copy(cow_def) mooshroom_def.mesh = "mobs_mc_cow.b3d" -mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, } +mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } } mooshroom_def.on_rightclick = function(self, clicker) if mobs:feed_tame(self, clicker, 1, true, true) then return end if mobs:protect(self, clicker) then return end @@ -93,7 +93,12 @@ mooshroom_def.on_rightclick = function(self, clicker) if item:get_name() == mobs_mc.items.shears then local pos = self.object:get_pos() minetest.sound_play("shears", {pos = pos}) - minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, mobs_mc.items.mushroom_red .. " 5") + + if self.base_texture[1] == "mobs_mc_mooshroom_brown.png" then + minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, mobs_mc.items.mushroom_brown .. " 5") + else + minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, mobs_mc.items.mushroom_red .. " 5") + end local oldyaw = self.object:getyaw() self.object:remove() diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_mooshroom_brown.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_mooshroom_brown.png new file mode 100644 index 0000000000000000000000000000000000000000..115416a53c8a5e525b8f245dac8f40f6f8be1f19 GIT binary patch literal 1048 zcmeAS@N?(olHy`uVBq!ia0y~yU~phyU{K&-V_;xdG`FsWfq{V~-O<;Pfnj4m_n$;o z1_lPs0*}aI1_r)EAj~ML;nl#vz#viL8c`CQpH@<#W5tq`R@_NM(i(&pCYze_Muk^5os`_25V-z{ezIdb(%Re8-8!R7k%-ZlI`yZN|y z*`gUH`)V!kcC3BCczyZx^^#z*VO&bYM-?C+tcY{bF}x=tlUxE@JGbw*2 zH+}P`E!ICSoTykd=MCq}Z%vB{KpmvtJpm8#rE5dr&RA* zx3xxbS?u(J!iC)be*H-7&goC>{kEpu=)KXNWAY5UPp{3^jh`!EXLsut7x&HJ`9d{$ z*7LUWU)jaiKcVhz>Ds5lfAy12P}Q) z^RuKy$L9S@FVIvip1^)$$9It@ojs|0j_sSrE-=qIIH&*YL(|yUZz}qK`7BM#{xhhQ zZd{Vm#xC$=$GxCfu#_@b>f2A|2S=7Q{=V~m%9(@m3tqd=d-15LqWACj`j$P4ydNyz zO^!9%{)o{gF8RCt*Ubl#Jx|_Q!TuttX~&9&t-WRVcnd*;~tlJo_{kQRO>%*Uu-DfXu|IWU@ zh}G%e@rnFw_qKf2P4v@#DW@3NS9E@P+}b+k+mahu4|}iHU|?Wi@O1TaS?83{1OTaz B0l)wN literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_mushroom_brown.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_mushroom_brown.png new file mode 100644 index 0000000000000000000000000000000000000000..fac0f56ef0c934a782294a77e9a780e77c75ca6b GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&C3 z=y_ah~ zEDEYF<7H!Dh^m-1D|X)9olI9w+Oa7(g&khkYPj_sYryiF$#xE0#z&31&+fTy#`W6o z-Vt{v28NewKB#0#mdoE`@MUKxdHC6CvaeKRz}u^JQ%)$pzb)XvgTe~DWM4fnB$Ju literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc_gameconfig/init.lua b/mods/ENTITIES/mobs_mc_gameconfig/init.lua index ff02ccfd..f24952e9 100644 --- a/mods/ENTITIES/mobs_mc_gameconfig/init.lua +++ b/mods/ENTITIES/mobs_mc_gameconfig/init.lua @@ -44,6 +44,7 @@ mobs_mc.override.items = { shears = "mcl_tools:shears", mushroom_red = "mcl_mushrooms:mushroom_red", + mushroom_brown = "mcl_mushrooms:mushroom_brown", bucket = "mcl_buckets:bucket_empty", grass_block = "mcl_core:dirt_with_grass", string = "mcl_mobitems:string", diff --git a/mods/ENVIRONMENT/lightning/init.lua b/mods/ENVIRONMENT/lightning/init.lua index dfcfe014..207c4d1a 100644 --- a/mods/ENVIRONMENT/lightning/init.lua +++ b/mods/ENVIRONMENT/lightning/init.lua @@ -189,6 +189,14 @@ lightning.strike = function(pos) obj:remove() obj = minetest.add_entity(pos2, "mobs_mc:pigman") obj:set_yaw(rot) + -- mooshroom: toggle color red/brown + elseif lua.name == "mobs_mc:mooshroom" then + if lua.base_texture[1] == "mobs_mc_mooshroom.png" then + lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } + else + lua.base_texture = { "mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png" } + end + obj:set_properties({textures = lua.base_texture}) -- villager → witch elseif lua.name == "mobs_mc:villager" then -- Witches are incomplete, this code is unused From 93c087997fe4140aee12c4c42232669008bce45f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 21 Feb 2019 03:36:02 +0100 Subject: [PATCH 096/865] Add /lightning command --- mods/ENVIRONMENT/lightning/init.lua | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mods/ENVIRONMENT/lightning/init.lua b/mods/ENVIRONMENT/lightning/init.lua index 207c4d1a..e3792f7e 100644 --- a/mods/ENVIRONMENT/lightning/init.lua +++ b/mods/ENVIRONMENT/lightning/init.lua @@ -230,3 +230,33 @@ minetest.after(5, function(dtime) lightning.interval_high), lightning.strike) end end) + +minetest.register_chatcommand("lightning", { + params = "[ ]", + description = "Let lightning strike at the specified position or yourself", + privs = { maphack = true }, + func = function(name, param) + local pos = {} + pos.x, pos.y, pos.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") + pos.x = tonumber(pos.x) + pos.y = tonumber(pos.y) + pos.z = tonumber(pos.z) + if not (pos.x and pos.y and pos.z) then + pos = nil + end + if name == "" and pos == nil then + return false, "No position specified and unknown player" + end + if pos then + lightning.strike(pos) + else + local player = minetest.get_player_by_name(name) + if player then + lightning.strike(player:get_pos()) + else + return false, "No position specified and unknown player" + end + end + return true + end, +}) From 236ef99359ee930f1c1604d006efcd9288200668 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 21 Feb 2019 18:08:30 +0100 Subject: [PATCH 097/865] Add hard limits to book title and book text length --- mods/ITEMS/mcl_books/init.lua | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/mods/ITEMS/mcl_books/init.lua b/mods/ITEMS/mcl_books/init.lua index de96e9e3..a2627c77 100644 --- a/mods/ITEMS/mcl_books/init.lua +++ b/mods/ITEMS/mcl_books/init.lua @@ -1,3 +1,6 @@ +local max_text_length = 4500 -- TODO: Increase to 12800 when scroll bar was added to written book +local max_title_length = 64 + -- Book minetest.register_craftitem("mcl_books:book", { description = "Book", @@ -59,6 +62,10 @@ local make_description = function(title, author, generation) return desc end +local cap_text_length = function(text, max_length) + return string.sub(text, 1, max_length) +end + local write = function(itemstack, user, pointed_thing) -- Call on_rightclick if the pointed node defines it if pointed_thing.type == "node" then @@ -102,7 +109,8 @@ end minetest.register_craftitem("mcl_books:writable_book", { description = "Book and Quill", _doc_items_longdesc = "This item can be used to write down some notes.", - _doc_items_usagehelp = "Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.", + _doc_items_usagehelp = "Hold it in the hand, then rightclick to read the current notes and edit then. You can edit the text as often as you like. You can also sign the book which turns it into a written book which you can stack, but it can't be edited anymore.".."\n".. + "A book can hold up to 4500 characters. The title length is limited to 64 characters.", inventory_image = "mcl_books_book_writable.png", groups = { book=1 }, stack_max = 1, @@ -115,11 +123,12 @@ minetest.register_on_player_receive_fields(function ( player, formname, fields ) local stack = player:get_wielded_item() if (stack:get_name() and (stack:get_name() == "mcl_books:writable_book")) then local meta = stack:get_meta() + local text = cap_text_length(fields.text, max_text_length) if fields.ok then - meta:set_string("text", fields.text) + meta:set_string("text", text) player:set_wielded_item(stack) elseif fields.sign then - meta:set_string("text", fields.text) + meta:set_string("text", text) player:set_wielded_item(stack) local name = player:get_player_name() @@ -138,15 +147,17 @@ minetest.register_on_player_receive_fields(function ( player, formname, fields ) local book = player:get_wielded_item() local name = player:get_player_name() if book:get_name() == "mcl_books:writable_book" then - if fields.title == "" then - fields.title = "Nameless Book" + local title = fields.title + if string.len(title) == 0 then + title = "Nameless Book" end + title = cap_text_length(title, max_title_length) local meta = newbook:get_meta() - local text = get_text(book) - meta:set_string("title", fields.title) + local text = cap_text_length(get_text(book), max_text_length) + meta:set_string("title", title) meta:set_string("author", name) meta:set_string("text", text) - meta:set_string("description", make_description(fields.title, name, 0)) + meta:set_string("description", make_description(title, name, 0)) -- The book copy counter. 0 = original, 1 = copy of original, 2 = copy of copy of original, … meta:set_int("generation", 0) @@ -235,7 +246,7 @@ minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craf -- Valid copy. Let's update the description field of the result item -- so it is properly displayed in the crafting grid. local imeta = itemstack:get_meta() - local title = ometa:get_string("title") + local title = cap_text_length(ometa:get_string("title"), max_title_length) local author = ometa:get_string("author") -- Increase book generation and update description @@ -283,11 +294,11 @@ minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv -- Copy metadata local imeta = itemstack:get_meta() - local title = ometa:get_string("title") + local title = cap_text_length(ometa:get_string("title"), max_title_length) local author = ometa:get_string("author") imeta:set_string("title", title) imeta:set_string("author", author) - imeta:set_string("text", text) + imeta:set_string("text", cap_text_length(text, max_text_length)) -- Increase book generation and update description generation = generation + 1 From e614f9228a806184a5132cf998fe437daa9abcf3 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 21 Feb 2019 23:08:51 +0100 Subject: [PATCH 098/865] Version 0.46.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10aa7bcf..9654821f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by daredevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.45.1 +Version: 0.46.0 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From 2028ef40cb61d0e6e1fa99d50f6e803b1ed40720 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 22 Feb 2019 05:29:17 +0100 Subject: [PATCH 099/865] Add screwdriver --- mods/ITEMS/screwdriver/README.txt | 13 ++ mods/ITEMS/screwdriver/init.lua | 170 ++++++++++++++++++ mods/ITEMS/screwdriver/license.txt | 50 ++++++ .../screwdriver/textures/screwdriver.png | Bin 0 -> 182 bytes 4 files changed, 233 insertions(+) create mode 100644 mods/ITEMS/screwdriver/README.txt create mode 100644 mods/ITEMS/screwdriver/init.lua create mode 100644 mods/ITEMS/screwdriver/license.txt create mode 100644 mods/ITEMS/screwdriver/textures/screwdriver.png diff --git a/mods/ITEMS/screwdriver/README.txt b/mods/ITEMS/screwdriver/README.txt new file mode 100644 index 00000000..9d39c58c --- /dev/null +++ b/mods/ITEMS/screwdriver/README.txt @@ -0,0 +1,13 @@ +Minetest Game mod: screwdriver +============================== +See license.txt for license information. + +License of source code +---------------------- +Originally by RealBadAngel, Maciej Kasatkin (LGPL 2.1) +Various Minetest developers and contributors (LGPL 2.1) + +License of media (textures) +--------------------------- +Created by Gambit (CC BY-SA 3.0): + screwdriver.png diff --git a/mods/ITEMS/screwdriver/init.lua b/mods/ITEMS/screwdriver/init.lua new file mode 100644 index 00000000..4d38bbc2 --- /dev/null +++ b/mods/ITEMS/screwdriver/init.lua @@ -0,0 +1,170 @@ +screwdriver = {} + +screwdriver.ROTATE_FACE = 1 +screwdriver.ROTATE_AXIS = 2 +screwdriver.disallow = function(pos, node, user, mode, new_param2) + return false +end +screwdriver.rotate_simple = function(pos, node, user, mode, new_param2) + if mode ~= screwdriver.ROTATE_FACE then + return false + end +end + +-- For attached wallmounted nodes: returns true if rotation is valid +-- simplified version of minetest:builtin/game/falling.lua#L148. +local function check_attached_node(pos, rotation) + local d = minetest.wallmounted_to_dir(rotation) + local p2 = vector.add(pos, d) + local n = minetest.get_node(p2).name + local def2 = minetest.registered_nodes[n] + if def2 and not def2.walkable then + return false + end + return true +end + +screwdriver.rotate = {} + +local facedir_tbl = { + [screwdriver.ROTATE_FACE] = { + [0] = 1, [1] = 2, [2] = 3, [3] = 0, + [4] = 5, [5] = 6, [6] = 7, [7] = 4, + [8] = 9, [9] = 10, [10] = 11, [11] = 8, + [12] = 13, [13] = 14, [14] = 15, [15] = 12, + [16] = 17, [17] = 18, [18] = 19, [19] = 16, + [20] = 21, [21] = 22, [22] = 23, [23] = 20, + }, + [screwdriver.ROTATE_AXIS] = { + [0] = 4, [1] = 4, [2] = 4, [3] = 4, + [4] = 8, [5] = 8, [6] = 8, [7] = 8, + [8] = 12, [9] = 12, [10] = 12, [11] = 12, + [12] = 16, [13] = 16, [14] = 16, [15] = 16, + [16] = 20, [17] = 20, [18] = 20, [19] = 20, + [20] = 0, [21] = 0, [22] = 0, [23] = 0, + }, +} + +screwdriver.rotate.facedir = function(pos, node, mode) + local rotation = node.param2 % 32 -- get first 5 bits + local other = node.param2 - rotation + rotation = facedir_tbl[mode][rotation] or 0 + return rotation + other +end + +screwdriver.rotate.colorfacedir = screwdriver.rotate.facedir + +local wallmounted_tbl = { + [screwdriver.ROTATE_FACE] = {[2] = 5, [3] = 4, [4] = 2, [5] = 3, [1] = 0, [0] = 1}, + [screwdriver.ROTATE_AXIS] = {[2] = 5, [3] = 4, [4] = 2, [5] = 1, [1] = 0, [0] = 3} +} + +screwdriver.rotate.wallmounted = function(pos, node, mode) + local rotation = node.param2 % 8 -- get first 3 bits + local other = node.param2 - rotation + rotation = wallmounted_tbl[mode][rotation] or 0 + if minetest.get_item_group(node.name, "attached_node") ~= 0 then + -- find an acceptable orientation + for i = 1, 5 do + if not check_attached_node(pos, rotation) then + rotation = wallmounted_tbl[mode][rotation] or 0 + else + break + end + end + end + return rotation + other +end + +screwdriver.rotate.colorwallmounted = screwdriver.rotate.wallmounted + +-- Handles rotation +screwdriver.handler = function(itemstack, user, pointed_thing, mode, uses) + if pointed_thing.type ~= "node" then + return + end + + local pos = pointed_thing.under + local player_name = user and user:get_player_name() or "" + + if minetest.is_protected(pos, player_name) then + minetest.record_protection_violation(pos, player_name) + return + end + + local node = minetest.get_node(pos) + local ndef = minetest.registered_nodes[node.name] + if not ndef then + return itemstack + end + -- can we rotate this paramtype2? + local fn = screwdriver.rotate[ndef.paramtype2] + if not fn and not ndef.on_rotate then + return itemstack + end + + local should_rotate = true + local new_param2 + if fn then + new_param2 = fn(pos, node, mode) + else + new_param2 = node.param2 + end + + -- Node provides a handler, so let the handler decide instead if the node can be rotated + if ndef.on_rotate then + -- Copy pos and node because callback can modify it + local result = ndef.on_rotate(vector.new(pos), + {name = node.name, param1 = node.param1, param2 = node.param2}, + user, mode, new_param2) + if result == false then -- Disallow rotation + return itemstack + elseif result == true then + should_rotate = false + end + elseif ndef.on_rotate == false then + return itemstack + elseif ndef.can_dig and not ndef.can_dig(pos, user) then + return itemstack + end + + if should_rotate and new_param2 ~= node.param2 then + node.param2 = new_param2 + minetest.swap_node(pos, node) + minetest.check_for_falling(pos) + end + + if not (minetest.settings:get_bool("creative_mode")) then + itemstack:add_wear(65535 / ((uses or 200) - 1)) + end + + return itemstack +end + +-- Screwdriver +minetest.register_tool("screwdriver:screwdriver", { + description = "Screwdriver", + inventory_image = "screwdriver.png", + on_use = function(itemstack, user, pointed_thing) + screwdriver.handler(itemstack, user, pointed_thing, screwdriver.ROTATE_FACE, 200) + return itemstack + end, + on_place = function(itemstack, user, pointed_thing) + screwdriver.handler(itemstack, user, pointed_thing, screwdriver.ROTATE_AXIS, 200) + return itemstack + end, +}) + + +minetest.register_craft({ + output = "screwdriver:screwdriver", + recipe = { + {"mcl_core:iron_ingot"}, + {"mcl_core:stick"} + } +}) + +minetest.register_alias("screwdriver:screwdriver1", "screwdriver:screwdriver") +minetest.register_alias("screwdriver:screwdriver2", "screwdriver:screwdriver") +minetest.register_alias("screwdriver:screwdriver3", "screwdriver:screwdriver") +minetest.register_alias("screwdriver:screwdriver4", "screwdriver:screwdriver") diff --git a/mods/ITEMS/screwdriver/license.txt b/mods/ITEMS/screwdriver/license.txt new file mode 100644 index 00000000..d9b721bb --- /dev/null +++ b/mods/ITEMS/screwdriver/license.txt @@ -0,0 +1,50 @@ +License of source code +---------------------- + +GNU Lesser General Public License, version 2.1 +Copyright (C) 2013-2016 RealBadAngel, Maciej Kasatkin +Copyright (C) 2013-2016 Various Minetest developers and contributors + +This program is free software; you can redistribute it and/or modify it under the terms +of the GNU Lesser General Public License as published by the Free Software Foundation; +either version 2.1 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details: +https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html + + +Licenses of media (textures) +---------------------------- + +Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +Copyright (C) 2013-2016 Gambit + +You are free to: +Share — copy and redistribute the material in any medium or format. +Adapt — remix, transform, and build upon the material for any purpose, even commercially. +The licensor cannot revoke these freedoms as long as you follow the license terms. + +Under the following terms: + +Attribution — You must give appropriate credit, provide a link to the license, and +indicate if changes were made. You may do so in any reasonable manner, but not in any way +that suggests the licensor endorses you or your use. + +ShareAlike — If you remix, transform, or build upon the material, you must distribute +your contributions under the same license as the original. + +No additional restrictions — You may not apply legal terms or technological measures that +legally restrict others from doing anything the license permits. + +Notices: + +You do not have to comply with the license for elements of the material in the public +domain or where your use is permitted by an applicable exception or limitation. +No warranties are given. The license may not give you all of the permissions necessary +for your intended use. For example, other rights such as publicity, privacy, or moral +rights may limit how you use the material. + +For more details: +http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/mods/ITEMS/screwdriver/textures/screwdriver.png b/mods/ITEMS/screwdriver/textures/screwdriver.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a56d558b34392a3275da443c0ba32a3b4db340 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdq5|d_r7(G7EiF`7$#yc628s z7z)39`EqWWSx=l*xtH3CQum7&FUG~i<>uyAR#xuYw{K^Hk@fK_H)R%)Y32O5POM=Q-*yMdNzVclr=>h< gNl@c3I>5*vUczopr0RG23A^-pY literal 0 HcmV?d00001 From 6e8be2a2c386b79b984927217e120fc50fcf4dae Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 22 Feb 2019 06:08:48 +0100 Subject: [PATCH 100/865] Fix vine not dropping all vines when dug w/ shears --- mods/ITEMS/mcl_core/nodes_climb.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_core/nodes_climb.lua b/mods/ITEMS/mcl_core/nodes_climb.lua index 52818695..25f8cdb5 100644 --- a/mods/ITEMS/mcl_core/nodes_climb.lua +++ b/mods/ITEMS/mcl_core/nodes_climb.lua @@ -141,13 +141,14 @@ minetest.register_node("mcl_core:vine", { return itemstack end, - -- If destroyed, also a “dependant” vine below it. + -- If dug, also dig a “dependant” vine below it. -- A vine is dependant if it hangs from this node and has no supporting block. - after_destruct = function(pos, oldnode) + on_dig = function(pos, node, digger) local below = {x=pos.x, y=pos.y-1, z=pos.z} local belownode = minetest.get_node(below) - if belownode.name == oldnode.name and (not mcl_core.check_vines_supported(below, belownode)) then - minetest.remove_node(below) + minetest.node_dig(pos, node, digger) + if belownode.name == node.name and (not mcl_core.check_vines_supported(below, belownode)) then + minetest.registered_nodes[node.name].on_dig(below, node, digger) end end, From 1556e6cb3e046a28ac3f29cf54418cf4e6943042 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 22 Feb 2019 06:13:31 +0100 Subject: [PATCH 101/865] Ice: Use after_dig_node instead of after_destruct --- mods/ITEMS/mcl_core/nodes_base.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index 237eff39..81395010 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -786,7 +786,7 @@ minetest.register_node("mcl_core:ice", { groups = {handy=1,pickaxey=1, slippery=3, building_block=1}, drop = "", sounds = mcl_sounds.node_sound_glass_defaults(), - after_destruct = function(pos, oldnode) + after_dig_node = function(pos, oldnode) -- Create a water source if ice is destroyed and there was something below it local below = {x=pos.x, y=pos.y-1, z=pos.z} local belownode = minetest.get_node(below) From 1044e9690954ac5c45b0878303d8d0eb639e6f4e Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 25 Feb 2019 17:46:13 +0100 Subject: [PATCH 102/865] Add tool groups (pickaxe, shovel, ...) --- GROUPS.md | 7 +++++++ mods/ITEMS/mcl_farming/hoes.lua | 10 +++++----- mods/ITEMS/mcl_tools/init.lua | 32 ++++++++++++++++---------------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/GROUPS.md b/GROUPS.md index 57c90eb4..70f61247 100644 --- a/GROUPS.md +++ b/GROUPS.md @@ -166,6 +166,13 @@ These groups are used mostly for informational purposes * `plant=1`: Plant or part of a plant * `double_plant`: Part of a double-sized plant. 1 = lower part, 2 = upper part +* `pickaxe=1`: Pickaxe +* `shovel=1`: Shovel +* `axe=1`: Axe +* `sword=1`: Sword +* `hoe=1`: Hoe (farming tool) +* `shears=1`: Shears + * `weapon=1`: Item is primarily (!) a weapon * `tool=1`: Item is primarily (!) a tool * `craftitem=1`: Item is primarily (!) used for crafting diff --git a/mods/ITEMS/mcl_farming/hoes.lua b/mods/ITEMS/mcl_farming/hoes.lua index bc048f57..1d8e9411 100644 --- a/mods/ITEMS/mcl_farming/hoes.lua +++ b/mods/ITEMS/mcl_farming/hoes.lua @@ -48,7 +48,7 @@ minetest.register_tool("mcl_farming:hoe_wood", { return itemstack end end, - groups = { tool=1 }, + groups = { tool=1, hoe=1 }, tool_capabilities = { full_punch_interval = 1, damage_groups = { fleshy = 1, } @@ -99,7 +99,7 @@ minetest.register_tool("mcl_farming:hoe_stone", { return itemstack end end, - groups = { tool=1 }, + groups = { tool=1, hoe=1 }, tool_capabilities = { full_punch_interval = 0.5, damage_groups = { fleshy = 1, } @@ -145,7 +145,7 @@ minetest.register_tool("mcl_farming:hoe_iron", { return itemstack end end, - groups = { tool=1 }, + groups = { tool=1, hoe=1 }, tool_capabilities = { -- 1/3 full_punch_interval = 0.33333333, @@ -199,7 +199,7 @@ minetest.register_tool("mcl_farming:hoe_gold", { return itemstack end end, - groups = { tool=1 }, + groups = { tool=1, hoe=1 }, tool_capabilities = { full_punch_interval = 1, damage_groups = { fleshy = 1, } @@ -254,7 +254,7 @@ minetest.register_tool("mcl_farming:hoe_diamond", { return itemstack end end, - groups = { tool=1 }, + groups = { tool=1, hoe=1 }, tool_capabilities = { full_punch_interval = 0.25, damage_groups = { fleshy = 1, } diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index c60aafe1..b5f8b303 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -64,7 +64,7 @@ minetest.register_tool("mcl_tools:pick_wood", { _doc_items_longdesc = pickaxe_longdesc, _doc_items_hidden = false, inventory_image = "default_tool_woodpick.png", - groups = { tool=1 }, + groups = { tool=1, pickaxe=1 }, tool_capabilities = { -- 1/1.2 full_punch_interval = 0.83333333, @@ -81,7 +81,7 @@ minetest.register_tool("mcl_tools:pick_stone", { description = "Stone Pickaxe", _doc_items_longdesc = pickaxe_longdesc, inventory_image = "default_tool_stonepick.png", - groups = { tool=1 }, + groups = { tool=1, pickaxe=1 }, tool_capabilities = { -- 1/1.2 full_punch_interval = 0.83333333, @@ -98,7 +98,7 @@ minetest.register_tool("mcl_tools:pick_iron", { description = "Iron Pickaxe", _doc_items_longdesc = pickaxe_longdesc, inventory_image = "default_tool_steelpick.png", - groups = { tool=1 }, + groups = { tool=1, pickaxe=1 }, tool_capabilities = { -- 1/1.2 full_punch_interval = 0.83333333, @@ -115,7 +115,7 @@ minetest.register_tool("mcl_tools:pick_gold", { description = "Golden Pickaxe", _doc_items_longdesc = pickaxe_longdesc, inventory_image = "default_tool_goldpick.png", - groups = { tool=1 }, + groups = { tool=1, pickaxe=1 }, tool_capabilities = { -- 1/1.2 full_punch_interval = 0.83333333, @@ -132,7 +132,7 @@ minetest.register_tool("mcl_tools:pick_diamond", { description = "Diamond Pickaxe", _doc_items_longdesc = pickaxe_longdesc, inventory_image = "default_tool_diamondpick.png", - groups = { tool=1 }, + groups = { tool=1, pickaxe=1 }, tool_capabilities = { -- 1/1.2 full_punch_interval = 0.83333333, @@ -244,7 +244,7 @@ minetest.register_tool("mcl_tools:shovel_wood", { _doc_items_hidden = false, inventory_image = "default_tool_woodshovel.png", wield_image = "default_tool_woodshovel.png^[transformR90", - groups = { tool=1 }, + groups = { tool=1, shovel=1 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=1, @@ -263,7 +263,7 @@ minetest.register_tool("mcl_tools:shovel_stone", { _doc_items_usagehelp = shovel_use, inventory_image = "default_tool_stoneshovel.png", wield_image = "default_tool_stoneshovel.png^[transformR90", - groups = { tool=1 }, + groups = { tool=1, shovel=1 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=3, @@ -282,7 +282,7 @@ minetest.register_tool("mcl_tools:shovel_iron", { _doc_items_usagehelp = shovel_use, inventory_image = "default_tool_steelshovel.png", wield_image = "default_tool_steelshovel.png^[transformR90", - groups = { tool=1 }, + groups = { tool=1, shovel=1 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=4, @@ -301,7 +301,7 @@ minetest.register_tool("mcl_tools:shovel_gold", { _doc_items_usagehelp = shovel_use, inventory_image = "default_tool_goldshovel.png", wield_image = "default_tool_goldshovel.png^[transformR90", - groups = { tool=1 }, + groups = { tool=1, shovel=1 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=2, @@ -320,7 +320,7 @@ minetest.register_tool("mcl_tools:shovel_diamond", { _doc_items_usagehelp = shovel_use, inventory_image = "default_tool_diamondshovel.png", wield_image = "default_tool_diamondshovel.png^[transformR90", - groups = { tool=1 }, + groups = { tool=1, shovel=1 }, tool_capabilities = { full_punch_interval = 1, max_drop_level=5, @@ -340,7 +340,7 @@ minetest.register_tool("mcl_tools:axe_wood", { _doc_items_longdesc = axe_longdesc, _doc_items_hidden = false, inventory_image = "default_tool_woodaxe.png", - groups = { tool=1 }, + groups = { tool=1, axe=1 }, tool_capabilities = { full_punch_interval = 1.25, max_drop_level=1, @@ -356,7 +356,7 @@ minetest.register_tool("mcl_tools:axe_stone", { description = "Stone Axe", _doc_items_longdesc = axe_longdesc, inventory_image = "default_tool_stoneaxe.png", - groups = { tool=1 }, + groups = { tool=1, axe=1 }, tool_capabilities = { full_punch_interval = 1.25, max_drop_level=3, @@ -372,7 +372,7 @@ minetest.register_tool("mcl_tools:axe_iron", { description = "Iron Axe", _doc_items_longdesc = axe_longdesc, inventory_image = "default_tool_steelaxe.png", - groups = { tool=1 }, + groups = { tool=1, axe=1 }, tool_capabilities = { -- 1/0.9 full_punch_interval = 1.11111111, @@ -389,7 +389,7 @@ minetest.register_tool("mcl_tools:axe_gold", { description = "Golden Axe", _doc_items_longdesc = axe_longdesc, inventory_image = "default_tool_goldaxe.png", - groups = { tool=1 }, + groups = { tool=1, axe=1 }, tool_capabilities = { full_punch_interval = 1.0, max_drop_level=2, @@ -405,7 +405,7 @@ minetest.register_tool("mcl_tools:axe_diamond", { description = "Diamond Axe", _doc_items_longdesc = axe_longdesc, inventory_image = "default_tool_diamondaxe.png", - groups = { tool=1 }, + groups = { tool=1, axe=1 }, tool_capabilities = { full_punch_interval = 1.0, max_drop_level=5, @@ -514,7 +514,7 @@ minetest.register_tool("mcl_tools:shears", { inventory_image = "default_tool_shears.png", wield_image = "default_tool_shears.png", stack_max = 1, - groups = { tool=1 }, + groups = { tool=1, shears=1 }, tool_capabilities = { full_punch_interval = 0.5, max_drop_level=1, From 6497916adec46519df18230acaca52b196980ed0 Mon Sep 17 00:00:00 2001 From: nickolas360 Date: Thu, 28 Feb 2019 15:35:18 +0100 Subject: [PATCH 103/865] Fix spawning at bed when chunk is unloaded --- mods/PLAYER/mcl_spawn/init.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 5c8a797e..bf8c1344 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -60,15 +60,24 @@ mcl_spawn.set_spawn_pos = function(player, pos, message) return spawn_changed end +local function get_far_node(pos) + local node = minetest.get_node(pos) + if node.name ~= "ignore" then + return node + end + minetest.get_voxel_manip():read_from_map(pos, pos) + return minetest.get_node(pos) +end + -- Respawn player at specified respawn position minetest.register_on_respawnplayer(function(player) local pos, custom_spawn = mcl_spawn.get_spawn_pos(player) if pos and custom_spawn then -- Check if bed is still there -- and the spawning position is free of solid or damaging blocks. - local node_bed = minetest.get_node(pos) - local node_up1 = minetest.get_node({x=pos.x,y=pos.y+1,z=pos.z}) - local node_up2 = minetest.get_node({x=pos.x,y=pos.y+2,z=pos.z}) + local node_bed = get_far_node(pos) + local node_up1 = get_far_node({x=pos.x,y=pos.y+1,z=pos.z}) + local node_up2 = get_far_node({x=pos.x,y=pos.y+2,z=pos.z}) local bgroup = minetest.get_item_group(node_bed.name, "bed") local def1 = minetest.registered_nodes[node_up1.name] local def2 = minetest.registered_nodes[node_up2.name] From 7851cee45e639294b5dc35beb731b28a0310d3a7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 28 Feb 2019 16:43:52 +0100 Subject: [PATCH 104/865] Fix exhauston for attacking and taking dmg --- mods/ENTITIES/mcl_falling_nodes/init.lua | 4 ---- mods/ENTITIES/mcl_mobs/api.lua | 8 +++++++- mods/ENTITIES/mcl_mobs/depends.txt | 1 + mods/ITEMS/mcl_bows/arrow.lua | 4 ---- mods/ITEMS/mcl_bows/depends.txt | 1 - mods/ITEMS/mcl_tnt/depends.txt | 1 - mods/ITEMS/mcl_tnt/init.lua | 4 ---- mods/PLAYER/mcl_hunger/init.lua | 13 ++++++++++--- mods/PLAYER/mcl_playerplus/init.lua | 1 - 9 files changed, 18 insertions(+), 19 deletions(-) diff --git a/mods/ENTITIES/mcl_falling_nodes/init.lua b/mods/ENTITIES/mcl_falling_nodes/init.lua index 92cca703..5f54f58d 100644 --- a/mods/ENTITIES/mcl_falling_nodes/init.lua +++ b/mods/ENTITIES/mcl_falling_nodes/init.lua @@ -1,5 +1,4 @@ local dmes = minetest.get_modpath("mcl_death_messages") ~= nil -local hung = minetest.get_modpath("mcl_hunger") ~= nil local get_falling_depth = function(self) if not self._startpos then @@ -56,9 +55,6 @@ local deal_falling_damage = function(self, dtime) if dmes then mcl_death_messages.player_damage(v, string.format(msg, v:get_player_name())) end - if hung then - mcl_hunger.exhaust(v:get_player_name(), mcl_hunger.EXHAUST_DAMAGE) - end end v:set_hp(hp) end diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 30b8a582..337deeb0 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -96,6 +96,7 @@ mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dir local mod_weather = minetest.get_modpath("mcl_weather") ~= nil local mod_tnt = minetest.get_modpath("mcl_tnt") ~= nil local mod_mobspawners = minetest.get_modpath("mcl_mobspawners") ~= nil +local mod_hunger = minetest.get_modpath("mcl_hunger") ~= nil -- play sound local mob_sound = function(self, sound, is_opinion) @@ -2342,10 +2343,15 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir) end - -- weapon wear + -- punch interval local weapon = hitter:get_wielded_item() local punch_interval = 1.4 + -- exhaust attacker + if mod_hunger and hitter:is_player() then + mcl_hunger.exhaust(hitter:get_player_name(), mcl_hunger.EXHAUST_ATTACK) + end + -- calculate mob damage local damage = 0 local armor = self.object:get_armor_groups() or {} diff --git a/mods/ENTITIES/mcl_mobs/depends.txt b/mods/ENTITIES/mcl_mobs/depends.txt index a1d9c9aa..eb3eb2aa 100644 --- a/mods/ENTITIES/mcl_mobs/depends.txt +++ b/mods/ENTITIES/mcl_mobs/depends.txt @@ -1,6 +1,7 @@ mcl_core mcl_weather? mcl_tnt? +mcl_hunger? invisibility? intllib? lucky_block? diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 52a857a0..a3c8fb4a 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -7,7 +7,6 @@ local GRAVITY = 9.81 local YAW_OFFSET = -math.pi/2 -local mod_mcl_hunger = minetest.get_modpath("mcl_hunger") local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements") local mod_button = minetest.get_modpath("mesecons_button") @@ -193,9 +192,6 @@ ARROW_ENTITY.on_step = function(self, dtime) -- “Ding” sound for hitting another player minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter}) end - if mod_mcl_hunger then - mcl_hunger.exhaust(obj:get_player_name(), mcl_hunger.EXHAUST_DAMAGE) - end end if lua then diff --git a/mods/ITEMS/mcl_bows/depends.txt b/mods/ITEMS/mcl_bows/depends.txt index 736cd117..08132ddb 100644 --- a/mods/ITEMS/mcl_bows/depends.txt +++ b/mods/ITEMS/mcl_bows/depends.txt @@ -1,7 +1,6 @@ controls awards? mcl_achievements? -mcl_hunger? mcl_core? mcl_mobitems? playerphysics? diff --git a/mods/ITEMS/mcl_tnt/depends.txt b/mods/ITEMS/mcl_tnt/depends.txt index 0f49dddd..f02d2b05 100644 --- a/mods/ITEMS/mcl_tnt/depends.txt +++ b/mods/ITEMS/mcl_tnt/depends.txt @@ -1,5 +1,4 @@ mcl_sounds? mcl_mobitems? -mcl_hunger? mcl_death_messages? doc_identifier? diff --git a/mods/ITEMS/mcl_tnt/init.lua b/mods/ITEMS/mcl_tnt/init.lua index dd6ebc66..fbe82c1c 100644 --- a/mods/ITEMS/mcl_tnt/init.lua +++ b/mods/ITEMS/mcl_tnt/init.lua @@ -1,5 +1,4 @@ local mod_death_messages = minetest.get_modpath("mcl_death_messages") -local mod_hunger = minetest.get_modpath("mcl_hunger") local function spawn_tnt(pos, entname) minetest.sound_play("tnt_ignite", {pos = pos,gain = 1.0,max_hear_distance = 15,}) @@ -33,9 +32,6 @@ local function do_tnt_physics(tnt_np,tntr) if mod_death_messages then mcl_death_messages.player_damage(obj, string.format("%s was caught in an explosion.", obj:get_player_name())) end - if mod_hunger then - mcl_hunger.exhaust(obj:get_player_name(), mcl_hunger.EXHAUST_DAMAGE) - end end obj:set_hp(obj:get_hp() - damage) end diff --git a/mods/PLAYER/mcl_hunger/init.lua b/mods/PLAYER/mcl_hunger/init.lua index f71dc121..5df787e7 100644 --- a/mods/PLAYER/mcl_hunger/init.lua +++ b/mods/PLAYER/mcl_hunger/init.lua @@ -29,7 +29,7 @@ mcl_hunger.EXHAUST_SPRINT_JUMP = 200 -- jump while sprinting mcl_hunger.EXHAUST_ATTACK = 100 -- hit an enemy mcl_hunger.EXHAUST_SWIM = 10 -- player movement in water mcl_hunger.EXHAUST_SPRINT = 100 -- sprint (per node) -mcl_hunger.EXHAUST_DAMAGE = 100 -- TODO (mostly done): taking damage (protected by armor) +mcl_hunger.EXHAUST_DAMAGE = 100 -- taking damage (protected by armor) mcl_hunger.EXHAUST_REGEN = 6000 -- Regenerate 1 HP mcl_hunger.EXHAUST_LVL = 4000 -- at what exhaustion player saturation gets lowered @@ -134,12 +134,19 @@ end) -- PvP combat exhaustion minetest.register_on_punchplayer(function(victim, puncher, time_from_last_punch, tool_capabilities, dir, damage) - if victim:is_player() and puncher:is_player() then - mcl_hunger.exhaust(victim:get_player_name(), mcl_hunger.EXHAUST_DAMAGE) + if puncher:is_player() then mcl_hunger.exhaust(puncher:get_player_name(), mcl_hunger.EXHAUST_ATTACK) end end) +-- Exhaust on taking damage +minetest.register_on_player_hpchange(function(player, hp_change) + if hp_change < 0 then + local name = player:get_player_name() + mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_DAMAGE) + end +end) + local main_timer = 0 local timer = 0 -- Half second timer local timerMult = 1 -- Cycles from 0 to 7, each time when timer hits half a second diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index f9022a3b..17074ea9 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -135,7 +135,6 @@ minetest.register_globalstep(function(dtime) if dist < 1.1 or dist_feet < 1.1 then if player:get_hp() > 0 then mcl_death_messages.player_damage(player, string.format("%s was prickled by a cactus.", name)) - mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_DAMAGE) player:set_hp(player:get_hp() - 1) end end From 1daf9b7a590c905f932eef020924152178278015 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 28 Feb 2019 18:00:17 +0100 Subject: [PATCH 105/865] Put treasure loot into random inventory slots --- mods/CORE/mcl_loot/init.lua | 54 ++++++++++++++++++++++++++ mods/MAPGEN/mcl_dungeons/init.lua | 4 +- mods/MAPGEN/mcl_structures/init.lua | 8 +--- mods/MAPGEN/tsm_railcorridors/init.lua | 4 +- 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/mods/CORE/mcl_loot/init.lua b/mods/CORE/mcl_loot/init.lua index f7eff3f6..3b52e365 100644 --- a/mods/CORE/mcl_loot/init.lua +++ b/mods/CORE/mcl_loot/init.lua @@ -98,3 +98,57 @@ function mcl_loot.get_multi_loot(multi_loot_definitions, pr) end return items end + +--[[ +Returns a table of length `max_slot` and all natural numbers between 1 and `max_slot` +in a random order. +]] +local function get_random_slots(max_slot) + local slots = {} + for s=1, max_slot do + slots[s] = s + end + local slots_out = {} + while #slots > 0 do + local r = math.random(1, #slots) + table.insert(slots_out, slots[r]) + table.remove(slots, r) + end + for s=1, #slots_out do + print(slots_out[s]) + end + return slots_out +end + +--[[ +Puts items in an inventory list into random slots. +* inv: InvRef +* listname: Inventory list name +* items: table of items to add + +Items will be added from start of the table to end. +If the inventory already has occupied slots, or is +too small, placement of some items might fail. +]] +function mcl_loot.fill_inventory(inv, listname, items) + local size = inv:get_size(listname) + local slots = get_random_slots(size) + local leftovers = {} + -- 1st pass: Add items into random slots + for i=1, math.min(#items, size) do + local item = items[i] + local slot = slots[i] + local old_item = inv:get_stack(listname, slot) + local leftover = old_item:add_item(item) + inv:set_stack(listname, slot, old_item) + if not leftover:is_empty() then + table.insert(leftovers, item) + end + end + -- 2nd pass: If some items couldn't be added in first pass, + -- try again in a non-random fashion + for l=1, math.min(#leftovers, size) do + inv:add_item(listname, leftovers[l]) + end + -- If there are still items left, tough luck! +end diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index f23c33bf..dc19a6e1 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -366,9 +366,7 @@ minetest.register_on_generated(function(minp, maxp) local meta = minetest.get_meta(cpos) local inv = meta:get_inventory() local items = get_loot() - for i=1, math.min(#items, inv:get_size("main")) do - inv:set_stack("main", i, ItemStack(items[i])) - end + mcl_loot.fill_inventory(inv, "main", items) end -- Mob spawners are placed seperately, too diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 552691bf..e98dedda 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -188,9 +188,7 @@ mcl_structures.generate_igloo_basement = function(pos, orientation) local meta = minetest.get_meta(chest_pos) local inv = meta:get_inventory() inv:set_size("main", 9*3) - for i=1, #lootitems do - inv:add_item("main", lootitems[i]) - end + mcl_loot.fill_inventory(inv, "main", lootitems) end return success end @@ -401,9 +399,7 @@ mcl_structures.generate_desert_temple = function(pos) local meta = minetest.get_meta(chests[c]) local inv = meta:get_inventory() inv:set_size("main", 9*3) - for i=1, #lootitems do - inv:add_item("main", lootitems[i]) - end + mcl_loot.fill_inventory(inv, "main", lootitems) end -- Initialize pressure plates and randomly remove up to 5 plates diff --git a/mods/MAPGEN/tsm_railcorridors/init.lua b/mods/MAPGEN/tsm_railcorridors/init.lua index d6de8198..6812125e 100644 --- a/mods/MAPGEN/tsm_railcorridors/init.lua +++ b/mods/MAPGEN/tsm_railcorridors/init.lua @@ -377,9 +377,7 @@ local function PlaceChest(pos, param2) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() local items = tsm_railcorridors.get_treasures(pr) - for i=1, math.min(#items, inv:get_size("main")) do - inv:set_stack("main", i, ItemStack(items[i])) - end + mcl_loot.fill_inventory(inv, "main", items) end end From 19b1cf5986916d4e2c75a9acd88f1a2ba3cfd322 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Thu, 28 Feb 2019 18:19:57 +0100 Subject: [PATCH 106/865] More robust initialization of chests of structs --- mods/MAPGEN/mcl_structures/init.lua | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index e98dedda..fa233682 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -15,6 +15,18 @@ mcl_structures.get_struct = function(file) return allnode end +-- Call on_construct on pos. +-- Useful to init chests from formspec. +local init_node_construct = function(pos) + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + if def and def.on_construct then + def.on_construct(pos) + return true + end + return false +end + -- The call of Struct mcl_structures.call_struct = function(pos, struct_style, rotation) if not rotation then @@ -185,9 +197,9 @@ mcl_structures.generate_igloo_basement = function(pos, orientation) }}, pr) local chest_pos = vector.add(pos, chest_offset) + init_node_construct(chest_pos) local meta = minetest.get_meta(chest_pos) local inv = meta:get_inventory() - inv:set_size("main", 9*3) mcl_loot.fill_inventory(inv, "main", lootitems) end return success @@ -396,9 +408,10 @@ mcl_structures.generate_desert_temple = function(pos) } }}, pr) + local meta = minetest.get_meta(chests[c]) + init_node_construct(chests[c]) local meta = minetest.get_meta(chests[c]) local inv = meta:get_inventory() - inv:set_size("main", 9*3) mcl_loot.fill_inventory(inv, "main", lootitems) end From a711c7bdb7b8ac006d5d71b5a64f753a132745fb Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 17:30:21 +0100 Subject: [PATCH 107/865] handle_node_drops no longer destroys metadata --- mods/ENTITIES/mcl_item_entity/init.lua | 10 +++++----- mods/HUD/mcl_inventory/creative.lua | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index d1c502fc..4b10cdac 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -245,16 +245,16 @@ function minetest.handle_node_drops(pos, drops, digger) end for _,item in ipairs(drops) do - local count, name + local count if type(item) == "string" then - count = 1 - name = item + count = ItemStack(item):get_count() else count = item:get_count() - name = item:get_name() end + local drop_item = ItemStack(item) + drop_item:set_count(1) for i=1,count do - local obj = core.add_item(pos, name) + local obj = core.add_item(pos, drop_item) if obj ~= nil then local x = math.random(1, 5) if math.random(1,2) == 1 then diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index 7125dcb6..dd5d0bd8 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -555,8 +555,7 @@ if minetest.settings:get_bool("creative_mode") then local inv = digger:get_inventory() if inv then for _,item in ipairs(drops) do - item = ItemStack(item):get_name() - if not inv:contains_item("main", item) then + if not inv:contains_item("main", item, true) then inv:add_item("main", item) end end From c6111039ab18f17537d037594fd1f5f62860a491 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 17:31:31 +0100 Subject: [PATCH 108/865] Fix annoying drops when digging banner in creative --- mods/ITEMS/mcl_banners/init.lua | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index 5bab2ed7..541a69c9 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -47,6 +47,25 @@ local layer_ratio = 255 local standing_banner_entity_offset = { x=0, y=-0.499, z=0 } local hanging_banner_entity_offset = { x=0, y=-1.7, z=0 } +local on_dig_banner = function(pos, node, digger) + -- Check protection + local name = digger:get_player_name() + if minetest.is_protected(pos, name) then + minetest.register_protection_violation(pos, name) + return + end + -- Drop item + local meta = minetest.get_meta(pos) + local item = meta:get_inventory():get_stack("banner", 1) + if not item:is_empty() then + minetest.handle_node_drops(pos, {item:to_string()}, digger) + else + minetest.handle_node_drops(pos, {"mcl_bannes:banner_item_white"}, digger) + end + -- Remove node + minetest.remove_node(pos) +end + local on_destruct_banner = function(pos, hanging) local offset, nodename if hanging then @@ -56,7 +75,7 @@ local on_destruct_banner = function(pos, hanging) offset = standing_banner_entity_offset nodename = "mcl_banners:standing_banner" end - -- Find this node's banner entity and make it drop as an item + -- Find this node's banner entity and remove it local checkpos = vector.add(pos, offset) local objects = minetest.get_objects_inside_radius(checkpos, 0.5) for _, v in ipairs(objects) do @@ -65,14 +84,6 @@ local on_destruct_banner = function(pos, hanging) v:remove() end end - -- Drop item - local meta = minetest.get_meta(pos) - local item = meta:get_inventory():get_stack("banner", 1) - if not item:is_empty() then - minetest.add_item(pos, item) - else - minetest.add_item(pos, "mcl_banners:banner_item_white") - end end local on_destruct_standing_banner = function(pos) @@ -207,6 +218,7 @@ minetest.register_node("mcl_banners:standing_banner", { sounds = node_sounds, drop = "", -- Item drops are handled in entity code + on_dig = on_dig_banner, on_destruct = on_destruct_standing_banner, on_punch = function(pos, node) respawn_banner_entity(pos, node) @@ -238,6 +250,7 @@ minetest.register_node("mcl_banners:hanging_banner", { sounds = node_sounds, drop = "", -- Item drops are handled in entity code + on_dig = on_dig_banner, on_destruct = on_destruct_hanging_banner, on_punch = function(pos, node) respawn_banner_entity(pos, node) From dca095171c573bd8b4ecae91b09fd32f3310a610 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 17:48:00 +0100 Subject: [PATCH 109/865] Restrict banner layers to 3 if has a gradient --- mods/ITEMS/mcl_banners/init.lua | 3 ++- mods/ITEMS/mcl_banners/patterncraft.lua | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index 541a69c9..49af2de6 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -193,7 +193,8 @@ minetest.register_node("mcl_banners:standing_banner", { _doc_items_entry_name = "Banner", _doc_items_image = "mcl_banners_item_base.png^mcl_banners_item_overlay.png", _doc_items_longdesc = "Banners are tall colorful decorative blocks. They can be placed on the floor and at walls. Banners can be emblazoned with a variety of patterns using a lot of dye in crafting.", - _doc_items_usagehelp = "Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 6 layers on a banner that way. You can copy the pattern of a banner by placing two banners of the same color in the crafting grid—one needs to be emblazoned, the other one must be clean. Finally, you can use a banner on a cauldron with water to wash off its top-most layer.", + _doc_items_usagehelp = [[Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 6 layers on a banner that way. If the banner includes a gradient, only 3 layers are possible. +You can copy the pattern of a banner by placing two banners of the same color in the crafting grid—one needs to be emblazoned, the other one must be clean. Finally, you can use a banner on a cauldron with water to wash off its top-most layer.]], walkable = false, is_ground_content = false, paramtype = "light", diff --git a/mods/ITEMS/mcl_banners/patterncraft.lua b/mods/ITEMS/mcl_banners/patterncraft.lua index 8d202c78..2858b3d2 100644 --- a/mods/ITEMS/mcl_banners/patterncraft.lua +++ b/mods/ITEMS/mcl_banners/patterncraft.lua @@ -5,6 +5,9 @@ -- Maximum number of layers which can be put on a banner by crafting. local max_layers_crafting = 6 +-- Maximum number of layers when banner includes a gradient (workaround, see below). +local max_layers_gradient = 3 + -- Max. number lines in the descriptions for the banner layers. -- This is done to avoid huge tooltips. local max_layer_lines = 6 @@ -386,6 +389,16 @@ local banner_pattern_craft = function(itemstack, player, old_craft_grid, craft_i if #layers >= max_layers_crafting then return ItemStack("") end + -- Lower layer limit when banner includes any gradient. + -- Workaround to circumvent bug #340 (gradients are likely to cause transparent pixels). + -- FIXME: Remove this restriction when bug #340 is fixed. + if #layers >= max_layers_gradient then + for l=1, #layers do + if layers[l].pattern == "gradient" or layers[l].pattern == "gradient_up" then + return ItemStack("") + end + end + end local matching_pattern local max_i = player:get_inventory():get_size("craft") From ab919713985fddf90e502bdec4f958cdb3606417 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 17:53:21 +0100 Subject: [PATCH 110/865] Increase pattern layer limit to 12 --- mods/ITEMS/mcl_banners/init.lua | 2 +- mods/ITEMS/mcl_banners/patterncraft.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index 49af2de6..bfe7832a 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -193,7 +193,7 @@ minetest.register_node("mcl_banners:standing_banner", { _doc_items_entry_name = "Banner", _doc_items_image = "mcl_banners_item_base.png^mcl_banners_item_overlay.png", _doc_items_longdesc = "Banners are tall colorful decorative blocks. They can be placed on the floor and at walls. Banners can be emblazoned with a variety of patterns using a lot of dye in crafting.", - _doc_items_usagehelp = [[Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 6 layers on a banner that way. If the banner includes a gradient, only 3 layers are possible. + _doc_items_usagehelp = [[Use crafting to draw a pattern on top of the banner. Emblazoned banners can be emblazoned again to combine various patterns. You can draw up to 12 layers on a banner that way. If the banner includes a gradient, only 3 layers are possible. You can copy the pattern of a banner by placing two banners of the same color in the crafting grid—one needs to be emblazoned, the other one must be clean. Finally, you can use a banner on a cauldron with water to wash off its top-most layer.]], walkable = false, is_ground_content = false, diff --git a/mods/ITEMS/mcl_banners/patterncraft.lua b/mods/ITEMS/mcl_banners/patterncraft.lua index 2858b3d2..4639b7a9 100644 --- a/mods/ITEMS/mcl_banners/patterncraft.lua +++ b/mods/ITEMS/mcl_banners/patterncraft.lua @@ -1,9 +1,9 @@ -- Pattern crafting. This file contains the code for crafting all the -- emblazonings you can put on the banners. It's quite complicated; --- normal 08/15 crafting won't work here. +-- run-of-the-mill crafting won't work here. -- Maximum number of layers which can be put on a banner by crafting. -local max_layers_crafting = 6 +local max_layers_crafting = 12 -- Maximum number of layers when banner includes a gradient (workaround, see below). local max_layers_gradient = 3 From 03c6beb9718bceb7be1cebb58293c251f72faaf2 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 18:01:29 +0100 Subject: [PATCH 111/865] Remove mcl_imitation_mode --- .../mcl_core_jungle_bush_jungle_leaves.mts | Bin 129 -> 0 bytes mods/MAPGEN/mcl_biomes/init.lua | 8 +------- settingtypes.txt | 14 -------------- 3 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 mods/ITEMS/mcl_core/schematics/mcl_core_jungle_bush_jungle_leaves.mts diff --git a/mods/ITEMS/mcl_core/schematics/mcl_core_jungle_bush_jungle_leaves.mts b/mods/ITEMS/mcl_core/schematics/mcl_core_jungle_bush_jungle_leaves.mts deleted file mode 100644 index d2df30e888e54a2658c9c97456acb35442e8eaa3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129 zcmeYb3HD`RVPFN}dgl6i24)84#LOZF(cI*m_~iVeRI9Agy!4#ZoYcg!)M5r z)YOVO$q5IzBo0mxNN929;Afk0AwogaC!q9)&#_dw%y+BTuRpHDBE-_&-1%Q&<9`Rk TkfSGFeVFNP&A_l Date: Fri, 1 Mar 2019 18:08:28 +0100 Subject: [PATCH 112/865] Add experimental setting: fallen logs --- mods/MAPGEN/mcl_biomes/init.lua | 3 +-- settingtypes.txt | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mods/MAPGEN/mcl_biomes/init.lua b/mods/MAPGEN/mcl_biomes/init.lua index a046c174..26efcee6 100644 --- a/mods/MAPGEN/mcl_biomes/init.lua +++ b/mods/MAPGEN/mcl_biomes/init.lua @@ -1,10 +1,9 @@ local mg_name = minetest.get_mapgen_setting("mg_name") -- Some mapgen settings -local imitate = minetest.settings:get("mcl_imitation_mode") local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true" -local generate_fallen_logs = false +local generate_fallen_logs = minetest.settings:get_bool("mcl_generate_fallen_logs") or false -- Jungle bush schematic. In PC/Java Edition it's Jungle Wood + Oak Leaves local jungle_bush_schematic = minetest.get_modpath("mcl_core").."/schematics/mcl_core_jungle_bush_oak_leaves.mts" diff --git a/settingtypes.txt b/settingtypes.txt index 3d65971e..ba0db568 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -87,6 +87,10 @@ craftguide_progressive_mode (Enable recipe book progressive mode) bool false # This feature is not finished yet! mob_difficulty (Mob difficulty factor) float 1.0 0.0 +# Whether to generate fallen logs in some biomes. +# They might not always look pretty and have strange overhangs. +mcl_generate_fallen_logs (Generate fallen logs) bool false + # If enabled, the “flat” map generator generates a Classic Superflat world: # Completely flat, 1 layer of grass blocks on top of 2 layers of dirt on # top of a final layer of bedrock. No caves, trees or plants. From d367a8dbad79befe9e0e3d5d01ee5b14a839a40a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 18:32:10 +0100 Subject: [PATCH 113/865] Update banner comment --- mods/ITEMS/mcl_banners/patterncraft.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_banners/patterncraft.lua b/mods/ITEMS/mcl_banners/patterncraft.lua index 4639b7a9..f60d5678 100644 --- a/mods/ITEMS/mcl_banners/patterncraft.lua +++ b/mods/ITEMS/mcl_banners/patterncraft.lua @@ -390,8 +390,8 @@ local banner_pattern_craft = function(itemstack, player, old_craft_grid, craft_i return ItemStack("") end -- Lower layer limit when banner includes any gradient. - -- Workaround to circumvent bug #340 (gradients are likely to cause transparent pixels). - -- FIXME: Remove this restriction when bug #340 is fixed. + -- Workaround to circumvent Minetest bug (https://github.com/minetest/minetest/issues/6210) + -- TODO: Remove this restriction when bug #6210 is fixed. if #layers >= max_layers_gradient then for l=1, #layers do if layers[l].pattern == "gradient" or layers[l].pattern == "gradient_up" then From 47389902bc76cd798a9d29b10ac191bdff2dbb88 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Mar 2019 18:33:56 +0100 Subject: [PATCH 114/865] Version 0.47.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9654821f..ed7be27b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by daredevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.46.0 +Version: 0.47.0 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From 94591c8b527eb60b46ae13c9c891f34da9eac96b Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Mar 2019 06:07:44 +0100 Subject: [PATCH 115/865] Fix crash when dig banner in protected area --- mods/ITEMS/mcl_banners/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_banners/init.lua b/mods/ITEMS/mcl_banners/init.lua index bfe7832a..a04d88ed 100644 --- a/mods/ITEMS/mcl_banners/init.lua +++ b/mods/ITEMS/mcl_banners/init.lua @@ -51,7 +51,7 @@ local on_dig_banner = function(pos, node, digger) -- Check protection local name = digger:get_player_name() if minetest.is_protected(pos, name) then - minetest.register_protection_violation(pos, name) + minetest.record_protection_violation(pos, name) return end -- Drop item From c19e3f455cd4c1e29e37d3e4d031953e8f107baa Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Mon, 4 Mar 2019 06:08:44 +0100 Subject: [PATCH 116/865] Version 0.47.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed7be27b..9a35de3e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by daredevils. Developed by Wuzzy and contributors. Not developed or endorsed by Mojang AB. -Version: 0.47.0 +Version: 0.47.1 ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore From 62e3a8b9ff665a46ec2160d9b0cf72f7d4f2fdfa Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 00:11:43 +0100 Subject: [PATCH 117/865] Add player skin support, add female skin --- mods/PLAYER/simple_skins/depends.txt | 3 + mods/PLAYER/simple_skins/description.txt | 1 + mods/PLAYER/simple_skins/init.lua | 148 ++++++++++++++++++ mods/PLAYER/simple_skins/intllib.lua | 45 ++++++ mods/PLAYER/simple_skins/license.txt | 21 +++ mods/PLAYER/simple_skins/locale/fr.po | 51 ++++++ mods/PLAYER/simple_skins/locale/it.po | 52 ++++++ mods/PLAYER/simple_skins/locale/ms.po | 51 ++++++ mods/PLAYER/simple_skins/locale/template.pot | 50 ++++++ mods/PLAYER/simple_skins/meta/character.txt | 3 + mods/PLAYER/simple_skins/meta/character_1.txt | 3 + mods/PLAYER/simple_skins/mod.conf | 1 + mods/PLAYER/simple_skins/readme.md | 7 + .../simple_skins/textures/character_1.png | Bin 0 -> 5505 bytes .../textures/inventory_plus_skins.png | Bin 0 -> 2182 bytes 15 files changed, 436 insertions(+) create mode 100644 mods/PLAYER/simple_skins/depends.txt create mode 100644 mods/PLAYER/simple_skins/description.txt create mode 100644 mods/PLAYER/simple_skins/init.lua create mode 100644 mods/PLAYER/simple_skins/intllib.lua create mode 100644 mods/PLAYER/simple_skins/license.txt create mode 100644 mods/PLAYER/simple_skins/locale/fr.po create mode 100644 mods/PLAYER/simple_skins/locale/it.po create mode 100644 mods/PLAYER/simple_skins/locale/ms.po create mode 100644 mods/PLAYER/simple_skins/locale/template.pot create mode 100644 mods/PLAYER/simple_skins/meta/character.txt create mode 100644 mods/PLAYER/simple_skins/meta/character_1.txt create mode 100644 mods/PLAYER/simple_skins/mod.conf create mode 100644 mods/PLAYER/simple_skins/readme.md create mode 100644 mods/PLAYER/simple_skins/textures/character_1.png create mode 100644 mods/PLAYER/simple_skins/textures/inventory_plus_skins.png diff --git a/mods/PLAYER/simple_skins/depends.txt b/mods/PLAYER/simple_skins/depends.txt new file mode 100644 index 00000000..1927ce89 --- /dev/null +++ b/mods/PLAYER/simple_skins/depends.txt @@ -0,0 +1,3 @@ +mcl_player +intllib? +3d_armor? diff --git a/mods/PLAYER/simple_skins/description.txt b/mods/PLAYER/simple_skins/description.txt new file mode 100644 index 00000000..61c7bff6 --- /dev/null +++ b/mods/PLAYER/simple_skins/description.txt @@ -0,0 +1 @@ +Mod that allows players to set their individual skins. \ No newline at end of file diff --git a/mods/PLAYER/simple_skins/init.lua b/mods/PLAYER/simple_skins/init.lua new file mode 100644 index 00000000..3a41490f --- /dev/null +++ b/mods/PLAYER/simple_skins/init.lua @@ -0,0 +1,148 @@ +-- Simple Skins mod for Minetest (MineClone 2 Edition) + +-- Released by TenPlus1 and based on Zeg9's code under MIT license + +skins = { + skins = {}, meta = {}, + modpath = minetest.get_modpath("simple_skins"), + skin_count = 0, -- counter of _custom_ skins (all skins except character.png) +} + + +-- Load support for intllib. +local S, NS = dofile(skins.modpath .. "/intllib.lua") + + +-- load skin list and metadata +local id, f, data, skin = 1 + +while true do + + skin = "character_" .. id + + -- does skin file exist ? + f = io.open(skins.modpath .. "/textures/" .. skin .. ".png") + + -- escape loop if not found and remove last entry + if not f then + id = id - 1 + break + end + + f:close() + + -- does metadata exist for that skin file ? + f = io.open(skins.modpath .. "/meta/" .. skin .. ".txt") + + if f then + data = minetest.deserialize("return {" .. f:read('*all') .. "}") + f:close() + end + + -- add metadata to list + skins.meta[skin] = { + name = data and data.name or "", + author = data and data.author or "", + } + + id = id + 1 + skins.skin_count = skins.skin_count + 1 +end + +skins.set_player_skin = function(player, skin) + if not player then + return + end + local playername = player:get_player_name() + skins.skins[playername] = skin + player:set_attribute("simple_skins:skin", skins.skins[playername]) + skins.update_player_skin(player) + if minetest.get_modpath("3d_armor") then + armor.textures[playername].skin = skin .. ".png" + armor:update_player_visuals(player) + end +end + +skins.update_player_skin = function(player) + if not player then + return + end + local playername = player:get_player_name() + mcl_player.player_set_textures(player, { skins.skins[playername] .. ".png" }) +end + +-- load player skin on join +minetest.register_on_joinplayer(function(player) + + local name = player:get_player_name() + local skin = player:get_attribute("simple_skins:skin") + local set_skin + -- do we already have a skin in player attributes? + if skin then + set_skin = skin + + -- otherwise use random skin if not set + else + local r = math.random(0, skins.skin_count) + if r == 0 then + set_skin = "character" + else + set_skin = "character_" .. r + end + end + if set_skin then + skins.set_player_skin(player, set_skin) + end +end) + +-- command to set player skin (usually for custom skins) +minetest.register_chatcommand("setskin", { + params = "[] ", + description = S("Select player skin of yourself or another player"), + privs = {}, + func = function(name, param) + + local playername, skin_id = string.match(param, "([^ ]+) (%d+)") + if not playername or not skin_id then + skin_id = string.match(param, "(%d+)") + if not skin_id then + return false, S("Insufficient or wrong parameters") + end + playername = name + end + skin_id = tonumber(skin_id) + + local player = minetest.get_player_by_name(playername) + + if not player then + return false, S("Player @1 not online!", playername) + end + if name ~= playername then + local privs = minetest.get_player_privs(name) + if not privs.server then + return false, S("You need the “server” privilege to change the skin of other players!") + end + end + + local skin + if skin_id == nil or skin_id > skins.skin_count or skin_id < 0 then + return false, S("Invalid skin number! Valid numbers: 0 to @1", skins.skin_count) + elseif skin_id == 0 then + skin = "character" + else + skin = "character_" .. tostring(skin_id) + end + + skins.set_player_skin(player, skin) + local skinfile = skin..".png" + + local your_msg = S("Your skin has been set to: @1", skinfile) + if name == playername then + return true, your_msg + else + minetest.chat_send_player(playername, your_msg) + return true, S("Skin of @1 set to: @2", playername, skinfile) + end + + end, +}) diff --git a/mods/PLAYER/simple_skins/intllib.lua b/mods/PLAYER/simple_skins/intllib.lua new file mode 100644 index 00000000..6669d720 --- /dev/null +++ b/mods/PLAYER/simple_skins/intllib.lua @@ -0,0 +1,45 @@ + +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- Get the latest version of this file at: +-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua + +local function format(str, ...) + local args = { ... } + local function repl(escape, open, num, close) + if escape == "" then + local replacement = tostring(args[tonumber(num)]) + if open == "" then + replacement = replacement..close + end + return replacement + else + return "@"..open..num..close + end + end + return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl)) +end + +local gettext, ngettext +if minetest.get_modpath("intllib") then + if intllib.make_gettext_pair then + -- New method using gettext. + gettext, ngettext = intllib.make_gettext_pair() + else + -- Old method using text files. + gettext = intllib.Getter() + end +end + +-- Fill in missing functions. + +gettext = gettext or function(msgid, ...) + return format(msgid, ...) +end + +ngettext = ngettext or function(msgid, msgid_plural, n, ...) + return format(n==1 and msgid or msgid_plural, ...) +end + +return gettext, ngettext diff --git a/mods/PLAYER/simple_skins/license.txt b/mods/PLAYER/simple_skins/license.txt new file mode 100644 index 00000000..fec6f6aa --- /dev/null +++ b/mods/PLAYER/simple_skins/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 TenPlus1 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/mods/PLAYER/simple_skins/locale/fr.po b/mods/PLAYER/simple_skins/locale/fr.po new file mode 100644 index 00000000..30d8e36e --- /dev/null +++ b/mods/PLAYER/simple_skins/locale/fr.po @@ -0,0 +1,51 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-07-29 07:11+0200\n" +"PO-Revision-Date: 2017-07-29 07:17+0200\n" +"Last-Translator: fat115 \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.12\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: init.lua +msgid "Select Player Skin:" +msgstr "Sélectionner l'apparence du joueur :" + +#: init.lua +msgid "Name: " +msgstr "Nom : " + +#: init.lua +msgid "Author: " +msgstr "Auteur : " + +#: init.lua +msgid "Admin command to set player skin" +msgstr "Commande admin pour définir l'apparence du joueur" + +#: init.lua +msgid "'s skin set to" +msgstr ", apparence définie pour" + +#: init.lua +msgid "Set player skin" +msgstr "Définir l'apparence du joueur" + +#: init.lua +msgid "Close" +msgstr "Fermer" + +#: init.lua +msgid "[MOD] Simple Skins loaded" +msgstr "[MOD] Simple Skins chargé" diff --git a/mods/PLAYER/simple_skins/locale/it.po b/mods/PLAYER/simple_skins/locale/it.po new file mode 100644 index 00000000..d4701316 --- /dev/null +++ b/mods/PLAYER/simple_skins/locale/it.po @@ -0,0 +1,52 @@ +# simple_skin . +# Copyright (C) 2018 +# This file is distributed under the same license as the PACKAGE package. +# Stefano Peris , 2018. +# Github: +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-21 07:29+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Stefano Peris \n" +"Language-Team: \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.12\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: init.lua +msgid "Select Player Skin:" +msgstr "Seleziona la skin del giocatore" + +#: init.lua +msgid "Name: " +msgstr "Nome" + +#: init.lua +msgid "Author: " +msgstr "Autore" + +#: init.lua +msgid "Admin command to set player skin" +msgstr "Comando di admin per impostare la skin del giocatore" + +#: init.lua +msgid "'s skin set to" +msgstr ", la skin è impostata su" + +#: init.lua +msgid "Set player skin" +msgstr "Imposta la skin del giocatore" + +#: init.lua +msgid "Close" +msgstr "Chiudi" + +#: init.lua +msgid "[MOD] Simple Skins loaded" +msgstr "[MOD] Skins semplici caricate" diff --git a/mods/PLAYER/simple_skins/locale/ms.po b/mods/PLAYER/simple_skins/locale/ms.po new file mode 100644 index 00000000..bba5982d --- /dev/null +++ b/mods/PLAYER/simple_skins/locale/ms.po @@ -0,0 +1,51 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-07-29 07:11+0200\n" +"PO-Revision-Date: 2018-02-14 01:23+0800\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.6\n" +"Last-Translator: MuhdNurHidayat (MNH48) \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Language: ms\n" + +#: init.lua +msgid "Select Player Skin:" +msgstr "Pilih Kulit Pemain:" + +#: init.lua +msgid "Name: " +msgstr "Nama: " + +#: init.lua +msgid "Author: " +msgstr "Pencipta: " + +#: init.lua +msgid "Admin command to set player skin" +msgstr "Perintah pentadbir untuk menetapkan kulit pemain" + +#: init.lua +msgid "'s skin set to" +msgstr " telah ditukarkan kulitnya kepada" + +#: init.lua +msgid "Set player skin" +msgstr "Tetapkan kulit pemain" + +#: init.lua +msgid "Close" +msgstr "Tutup" + +#: init.lua +msgid "[MOD] Simple Skins loaded" +msgstr "[MODS] Simple Skins telah dimuatkan" diff --git a/mods/PLAYER/simple_skins/locale/template.pot b/mods/PLAYER/simple_skins/locale/template.pot new file mode 100644 index 00000000..36282e43 --- /dev/null +++ b/mods/PLAYER/simple_skins/locale/template.pot @@ -0,0 +1,50 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-07-29 07:11+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: init.lua +msgid "Select Player Skin:" +msgstr "" + +#: init.lua +msgid "Name: " +msgstr "" + +#: init.lua +msgid "Author: " +msgstr "" + +#: init.lua +msgid "Admin command to set player skin" +msgstr "" + +#: init.lua +msgid "'s skin set to" +msgstr "" + +#: init.lua +msgid "Set player skin" +msgstr "" + +#: init.lua +msgid "Close" +msgstr "" + +#: init.lua +msgid "[MOD] Simple Skins loaded" +msgstr "" diff --git a/mods/PLAYER/simple_skins/meta/character.txt b/mods/PLAYER/simple_skins/meta/character.txt new file mode 100644 index 00000000..5a07db19 --- /dev/null +++ b/mods/PLAYER/simple_skins/meta/character.txt @@ -0,0 +1,3 @@ +name = "Steve", +author = "(Texture pack author)", +description = "The default male skin.", diff --git a/mods/PLAYER/simple_skins/meta/character_1.txt b/mods/PLAYER/simple_skins/meta/character_1.txt new file mode 100644 index 00000000..ec438955 --- /dev/null +++ b/mods/PLAYER/simple_skins/meta/character_1.txt @@ -0,0 +1,3 @@ +name = "Alex", +author = "(Texture pack author)", +description = "The default female skin.", diff --git a/mods/PLAYER/simple_skins/mod.conf b/mods/PLAYER/simple_skins/mod.conf new file mode 100644 index 00000000..aff90aab --- /dev/null +++ b/mods/PLAYER/simple_skins/mod.conf @@ -0,0 +1 @@ +name = simple_skins diff --git a/mods/PLAYER/simple_skins/readme.md b/mods/PLAYER/simple_skins/readme.md new file mode 100644 index 00000000..0c6980bb --- /dev/null +++ b/mods/PLAYER/simple_skins/readme.md @@ -0,0 +1,7 @@ +Simple Skins, MineClone 2 Edition + +Simple Skins mod to allow players to select a skin. +Use the chat command /setskin to change skin. + +Original mod: +https://forum.minetest.net/viewtopic.php?id=9100 diff --git a/mods/PLAYER/simple_skins/textures/character_1.png b/mods/PLAYER/simple_skins/textures/character_1.png new file mode 100644 index 0000000000000000000000000000000000000000..71f02471dc622249681a511a66087b803e97dbdf GIT binary patch literal 5505 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 CAYT6f literal 0 HcmV?d00001 diff --git a/mods/PLAYER/simple_skins/textures/inventory_plus_skins.png b/mods/PLAYER/simple_skins/textures/inventory_plus_skins.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc97759cd8c906632a0ff2712b647c23abc2278 GIT binary patch literal 2182 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orHh?5jc|N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsHU}kKDwp&hzKFh$U0f^}>kNMa?qyyq9{Wr|9qC+Ba>{QZr0&+m7<*3nnr#V<54%WVJB zHu09`zMFq-d#lsm&ieV3HGKBl&(Aq`Z*_~zKJ_Zg!$C_j_R7{N#qE8(0l$oO9-jK) zcISDq;kqW(G6S;%X@{@!8d@&ct8rn0SNF3_>(Um9J0+59i|_tS*0!@Q`#VACo9pS+ z3&uVA35%Oe_gC&rUTCa8|EHDc85<5;*@KdaNBU3K82y|6x@^lezgVT{yfp&TZ(H^n zm=*sP-|N7kd(=d(=6veBPsi*8Umr}cF%Z|;a7#@uYKeQ^&%>MD_h&S3++?c3U&_#7 zQ0`*zOklt+d1fiMtA$5A=TLd?K>_`LP*3%hz}NotYpe zAXxiJ@=5}8;~D{_PwMSWGOI2gPe|&~d={Z}d{zyY=CUb8x1>ThpI1CSr|6t&@w%ha z1Cl&drw8o_DSM-sI8iwLaO=$Mqf12BX}g7gS+RBJv*?VCOQ%I=-pO+R_2ojczwP%+ zJFh=%lfUs#xi`m6(&p8Y&X8G&$7ZI@OZ~Kld*`-4T-xileA4O;-y0bm79Y9T{8?Rk z@06`)BP{-YYBrrwyf5a$w8=XxnUnPdB+k!fRM~QS&P^x99cS-6JM(GU>K6y3j{2Tk za8^QsXL3wTN%8lDcj5PZc>Z^pfA6*2yz;mG4CC2WsqfVD*}=EQRNMKCr0`?IqJ`I%$hVxi z`q;>_Kk+x8(bD96`F^`+@4logDRDP_+}Y**K5o&WX?Z%ERo}n0iETG+>?^$f!atee z!A2$1yB4+!?`}Tj<8xCcRvkZc>8isEIYrx6`=$r^>*w9K`c~G{!BO#Y$x^3B=W=gLX&$U~GE_ykl0>fATbuk}cCU&!8obd;b^7V=w(e6czgZ^F%8r@x_5I{2A7*^GJ$=z3 zy>qiC$zObvaOU%_d2hG^--g9SS2ur?o3TaBX5mkdh)9KZZWC|6{PSbtjq__OPySdJ zbN=DPsey8{_P#S%nfCttwLMZIt1i6la=vzRx%|8B5lc+x$N#WPdA^pRltbKa|CVQu zxjQE1sJ)&Ru;pr$1kbtii)L?R@lk2sCigKYW!d}Jk3Bm1J|%<)$;+hu=lXV@HSR%p z{4cIGD|8n;+r8`lW#?Sq>9&TM`_~x7el)+l&qK-Sa%I)YCvz&)nwTp$+00z#x#_pj zxp^_0FRyX?xnnBB#1mP&T?2RgI9uB>@RGV?>#s#a*8c~yR!9p!KV|mpR`_X z%lf;bU+6=yTb$9OY4(4Z1FABYebVdu#Fv?0sAchp-!S%L(AwCo`&XS?8gwJ`tln;u z!1O1w8*U1S>6}*u@f4~+MCeTg@8{v!7Ys})7w$X;K6)>{1Ijud7FyK|y9Un#D7P``8)&p(-X#kM6| zjh?S?wK{t|Qe{Q(_U2IE?2gb?k)`fL2$v|<&zm07&r?&B8wRq^pruEv0|xx z83O|Ydx@v7EBj++7BMaM+N2du3=E7XJY5_^G|uNva`X@hlsH~*%pP*K4J*O_S`~I#AyqUF1diuGi zm&&pwj_RLQeeiDbbEj(V=koU??H|so-kYR1MeUGAoQAK;-H=PZw){$`V^3&B$xG*p Date: Tue, 5 Mar 2019 00:15:20 +0100 Subject: [PATCH 118/865] Replace damage sound to something gender-neutral --- mods/CORE/mcl_sounds/README.txt | 5 ++++- mods/CORE/mcl_sounds/sounds/player_damage.ogg | Bin 5775 -> 6176 bytes 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mods/CORE/mcl_sounds/README.txt b/mods/CORE/mcl_sounds/README.txt index 54eeab60..43e6cf30 100644 --- a/mods/CORE/mcl_sounds/README.txt +++ b/mods/CORE/mcl_sounds/README.txt @@ -67,10 +67,13 @@ blukotek (CC0 1.0) https://www.freesound.org/people/blukotek/sounds/251660/ default_dig_snappy.ogg +sonictechtonic (CC BY 3.0) +https://www.freesound.org/people/sonictechtonic/sounds/241872/ + player_damage.ogg + Voxelands project (CC BY-SA 3.0) mcl_sounds_place_node_water.ogg mcl_sounds_dug_water.ogg - player_damage.ogg (Note: Artists from the Voxelands project include: sdzen, darkrose, sapier, Tom Peter, Telaron, juskiddink) diff --git a/mods/CORE/mcl_sounds/sounds/player_damage.ogg b/mods/CORE/mcl_sounds/sounds/player_damage.ogg index 063e6c08c4da5cd7600b06c9f19edf7592537da3..788808710c1923c9ae797b7534b66a97dd18dd6d 100644 GIT binary patch literal 6176 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 z zO)%hANfGQWlKQZZ=fEQAXD?=}OBIUAAFbi?%009 z`ocLkznfdy8TRQWZ(DjUZQt5Nt|wm#JZ%`xNWYWZ;~vDo&>+lE(vZx+!0@lF&%EYUOUjAlZ_6xkSfCQ>~pY8hFMZz~Kx zH2n{rrK2}JEIn`OGiHWEbF++u;#e8>wd(w1OsWa=sn=@XCA$8%Vp0%m=51BW00xG2 z{7suJ55L`X%II%OR>7+iKknb*oBVP`?$p29x($m=8*(50TlVr<%e4a2rfU{Y&(3B^ z*tx=ydy0Hz75l^uTh$(v?EQOf*0Qt%5t{<0Gcg~C@n>aF@Rx4*Q^b^4&BAc6_0RmB zpJMKpEB}>vy7K;=1hq}eDtg;E9XhyYNHA~+GB7Yy^WNCY%pjM0?y`quSth92aAAr& z!z-baFFj6X&1PVzXJwdn;og7MMf?m;yc-xF{Fh~z*ZSwXkInD2nL4*!urBQwMpUIqpRpTx2>Q!_n7Q$0fiBam`=1_p-IyyX0p)FNA-#Ij_N zq_Li%fq_C!W)egnBP)bfa&iu1WN=_$P$`zsa$8y~)*>L~6d?In#_3%48%ZZ0!6q3a zpXk%7#S;{lEO6?G)@ZyiA(R26q1~}Uq@~M|L$O8GHeynLG_zU0 zkZC!jqtVrL#9)V53yY~nPty~F6IYtKojPVUdz$``YDssj5QEsE;^;A}!lT;!nse;k7&Q&_6H-V86Si1)ULqH&pYoQ1` zSYHYQ1IGf3uB8!OOEbEjcl2?zw5?%cXkcJqVPFt2aSpa|pW<>pB=q{W+}lVfdRnR^ zSi1uQgTSTCw3Tcf2F#Ld;CSF*U}zBRGC0xz3*-g~FTO>bYc223dAuN!Z`o0EuYUhvLKQR!cyN@d100oNUZSO%Y-?C z$1I=EQCnL%VOH-}%ja`g*Jk$3^4@6qe2&M?%AncaAhBYQQDEZL(U&rFghAXDdv{Ko zec`C(^Ev*3N2Nn_!ZZ(M!kgFAO-Pn&&vZ zy7(ev$rLLN)v1L+Ug}_4S^)`81yIy5F!+CxxhN=$Kp$n!3#tYRsRjz^UN$nl9PAoentFX& zY2^0W=o_uE-)rxFuf6-DG%;dYY9tDRc%6xXL7_#!31nT6hvqSf;xm>nRHg{Pyvf19 zz)&FK4o+{Ln^e3nshqu}$vSubbK(^>^q!XN-r0xDFxmQ{4Etms-%(f6WbQpU__D^||ZKDF%4u63^o zA#QL2S7Bf%QE@L)aSu{)4N`G00*7t`4=8kH4jZbt7U`V6WCHQyMPb{^!LH#YkU|3* z0SpX0CpUqSh$=p_c6y)Vi#5|v zXe?Q9-OuvblIv$Qn&vzgFif6tJjl?Q=h!sImMN@G&S5MJfeZ`{h9?Y<$P}IPe5K-g z&QeQu=`l<9m5Z+gdTm@5W$m?eTS)ffIg76Zp3+zv<-J;VX-M{}jSLJ84D1XI4BQJZ zOb}&s5Mf|wLG~dvzspm~{Z-#{46$`z(Ej9XEZTPg( zyT-mZL0sR^t)=19N@KU>-klCND)f3t=xwvmtJ_QiOJV~D?F7&JWGoOfGN9y&PJ4wTfA$%b zltyQ~-nH?}zI8Uc3rpJUm>3w?WEdEjd^DI_+tzR}JYr#xXqn^e~*cF#f z^72t#D&efPaq5&L9nGURqH=Z~ol&f@^ynn79Mz=}(LR>jB#Qe$maBs;U%E9YD0^yg zkQIk!Dxa5@=Ftc*FT-L#kWqY2UaCtag1t7j1|?~0UXAd|+IVzEvA5y1fS_*Gr4rs= zhT9~H^EN)c=9raj^)y&%hbcOH`{_S^V$ zR@9oEM{i{3?)*Bd_`=GqQNcbtL9W`#8d>~qZ}WvHjipBeyn5Ddjf(EEY=>Ijwe{$X z;_Qvz0=#-umqvJdnQoKF?lb*1D{A%DqcgIzHa?qG{NC`{jo@t4?Go938=poMzuWul zS~4R812Z231EboMMknVmCQ!a-QS>roTjQFV`IO&1e%6kElrL5ZX0M48d@3~`K|VH2v}rW zYrIKlcxi0pwAA|%u^=_uN~0yhu7X5zqs`l*ub1Ba-kNA>wLS0kuJ^wWeY8H#!0>^E zonZl!beOw^rWCgh*j0=S4ie2196c191%f;jmkI=VaWXJS6fiJw7%b!wk=i80(80vO zz%en%OS5+hsGbC|mQE3Zx6Qx}G)#h(;fKEk!w>r#3p6)cI4o4uW^5>6U^pPLbVd=6 z6{n_Yk0sl}DN};7)+Y8Cax7hPCCYnhv4EH7%B?q&*34-R2=ZEcR4SQWap|?FH5;$Z zvgXiSDwe&*@`j98rtYzb;&XeyPYB93ycSjbe(&^aNo!1>-)R;&v_&L&-Og_hs^4pF zi^@K0`$M56VB^)O;t!z4WVhk>JIx<#ITT}hET7A@d^pIS$iPtE%*^1@)N8y(Wv*x+ zn>fg~9Gnaa0!dwl&*wA?IB`r2>alz-(<0!cp&A4h<8$IrO@WCmozeqQ$GLRMB&fQj zQ-X}1FK8BU;#@i<$P28O1H^g>7t;haYQeIasx44;noC;*yfi@SG?z{ha00bPKur=M zCz#kIxL8mSOf1L?V#?AfQ-VBM85m?N7#LV29MvU5#S#~Dipw>C)2{;qgUFGv;Lf>@ zXAILN3>*Rsm>GEZ z1nk%y)g219FfwpBrL=jN=&-c2Ph}7^6lG9R(|E$<(0bJM)=}0H$p=k(@2muz1eyen zJYwMTIB<~D+~#AO`ke2p0@c*lDg6G2PL(6`O zmtD@vzplBr-TQy@zU4f#JFjdKd@L~KhSiLnoq^w@ zHmm$+_SH?^`WZ<@svSzx8U> zzrNh}%~w5hIrjM_o%tV*_bF&tJ?D|Rx+c8x-`>9qf}8jjO%{J&opdE&x(|=dKEKIJ z-fP*)Nvr>iKdTZtdtT}H#r~6KFK|9N;evDgwU8F$872>FjM`quo>?EjQ@ixE@wZ(( zKGA~H9(>!@wZ)kwTlT;?>6^~{r#EY9oru|=9czC6YvvZYKHc&y_kE2RZ6ezy9!Pi| zE0Dop(CN88LVc~u8J&9(vgSJHxP77@eA)H?s~v|1!w*?2=P18kYi*eyrB9dgDF}tc z$4y=EaDV(H6$Xh(VINpL#}8 z;MNlSfPg-lcTjo#MyPr;+ zsxQQAbK7jfnQPJ`rks3dSHrzm`ohVJasIE`83cCi4mXgT{@->BS!8vI@RdLD|K$_y19Rde)-y1C5d6Y8n_+gt^@D2}wOk4e4C+N5C?30E&m6Fr zT=;L( zD$L-(ru+H5=%LiL-w$uhX_(r(!-(O))9q)N?zYZRo5R4UAX)c$OY^^Vj0_B$-)?Dl zco(75kjZp={}Cpi1BMTF+RciJ;F4vCvo@QtY-{tw=kc2+XGzbie78<|?qY#8ZURay z&0*zF>Xy~tiR?RmpFJ_6|M-P1Tlac3hIV}k@NwX1`Ly{!lgC2gKvC)9yFpe4KKA)5 znD#Xt>tbjN`Ps+AP~g5;cER+Ahn6&Ov_z$L3vTw#`1JNw#Y3JmVXJ2?D9kS1x|n~< z_w}0l{a!Q3DKs3Dcfb3|NQ!aZtg8Z=z1)F2yVV2w-%byod(f@?t^>21euT4t083Nk z+{?YSXNA7+{r)dfdw*Fjcisx=4QXEg%3c*(_#JRooXyj4a*D(!hR;h+9DX%PPdj|S z#;xeNt&7V#6)S)5;b+>?l2>$*fzh&l^K;H(Mf1s~-VCxz-0#F5oZk3Rmes)X#O6EG z+M<}WLYPd?FxBlUZ3t1bdGK$$?NQCxdn?`F+%{cP#9T1>fu%hMpPGPx&x%cgKHSf5 zTNkoxT>NROH0M80U;Oo`N6-JQ3an;lTlMqnl9vUC-xf1Q==L;f@6TjN_%XvNLFv)M z)KzzH>NdlmCqtT48xjY3d_DunA zw+S$~Wi#B%%$*b>qu=#AT{`O4(H+9I#-+9n8AernDh-YTOrPCL`_^ar?R*~b|DK}b z<0Zz9-2y$I=hRCuF@38~da=c{>X}YLLxa2h;o=*D4YDeGcBF0Jh#21Q^j+tl!MuoZ z-t!!VHn|2)-*5&7V+IDP1o00^QVS;>>|<#7XD%A()f42)nz{5!1aIik!|kn$tXzXv zA9q_jHKo|#_~g%mqDSK_str3_)-0{FW1pb)z52kJ!nyJCYpsLAtJa7bf7FZ5Se33= z&RKSoySMmK(Vx7Po2`W7T{AZ2iT&t#(~wf+TfX#TE8mVLJ(l*G7k55wjd@io`#GYk zUCgUSQZ?V`TFDxwd)s0%PI4aPX3pxm-(Yy=;?9fahh-Q}Oi|z1lCUiQw{D#6^5?t$ zJkPv5$7*fmGR}{xxviy3T6e6Urn3Iu@8qJJS&`yQ-X?83u;m%8U_4_h0uGsX4!60RVDWkz@b> From 2c5038ad058cff4219b09ce5b6c7c113e7d43fe7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 01:50:51 +0100 Subject: [PATCH 119/865] Player skins: Adjust inventory preview image, too --- mods/HUD/mcl_inventory/creative.lua | 14 ++++-- mods/HUD/mcl_inventory/depends.txt | 1 + mods/HUD/mcl_inventory/init.lua | 15 ++++-- mods/PLAYER/mcl_player/init.lua | 14 +++++- mods/PLAYER/simple_skins/init.lua | 47 +++++++++--------- .../PLAYER/simple_skins/textures/player_1.png | Bin 0 -> 2625 bytes 6 files changed, 59 insertions(+), 32 deletions(-) create mode 100644 mods/PLAYER/simple_skins/textures/player_1.png diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index dd5d0bd8..f2afb964 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -4,6 +4,9 @@ local players = {} -- Containing all the items for each Creative Mode tab local inventory_lists = {} +local show_armor = minetest.get_modpath("3d_armor") ~= nil +local mod_player = minetest.get_modpath("mcl_player") ~= nil + -- TODO: Brewing is disabled. Add brewing (uncommented code) when it is implemented properly -- Create tables @@ -271,15 +274,20 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz inv_bg = "crafting_inventory_creative_survival.png" -- Show armor and player image - local show_armor = minetest.get_modpath("3d_armor") - local img = "player.png" + local img, img_player + if mod_player then + img_player = mcl_player.player_get_preview(player) + else + img_player = "player.png" + end + img = img_player local player_preview = "image[3.9,1.4;1.2333,2.4666;"..img.."]" if show_armor and armor.textures[playername] and armor.textures[playername].preview then img = armor.textures[playername].preview local s1 = img:find("character_preview") if s1 ~= nil then s1 = img:sub(s1+21) - img = "player.png"..s1 + img = img_player..s1 end player_preview = "image[3.9,1.4;1.2333,2.4666;"..img.."]" end diff --git a/mods/HUD/mcl_inventory/depends.txt b/mods/HUD/mcl_inventory/depends.txt index a174c0ee..46d93c42 100644 --- a/mods/HUD/mcl_inventory/depends.txt +++ b/mods/HUD/mcl_inventory/depends.txt @@ -1,3 +1,4 @@ mcl_init +mcl_player? _mcl_autogroup? 3d_armor? diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index 4bd2ef80..3989af19 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -1,8 +1,7 @@ mcl_inventory = {} -local show_armor = false -if minetest.get_modpath("3d_armor") ~= nil then show_armor = true end - +local show_armor = minetest.get_modpath("3d_armor") ~= nil +local mod_player = minetest.get_modpath("mcl_player") ~= nil -- Returns a single itemstack in the given inventory to the main inventory, or drop it when there's no space left local function return_item(itemstack, dropper, pos, inv) @@ -59,14 +58,20 @@ local function set_inventory(player, armor_change_only) local player_name = player:get_player_name() -- Show armor and player image - local img = "player.png" + local img, img_player + if mod_player then + img_player = mcl_player.player_get_preview(player) + else + img_player = "player.png" + end + img = img_player local player_preview = "image[0.6,0.2;2,4;"..img.."]" if show_armor and armor.textures[player_name] and armor.textures[player_name].preview then img = armor.textures[player_name].preview local s1 = img:find("character_preview") if s1 ~= nil then s1 = img:sub(s1+21) - img = "player.png"..s1 + img = img_player..s1 end player_preview = "image[1.1,0.2;2,4;"..img.."]" end diff --git a/mods/PLAYER/mcl_player/init.lua b/mods/PLAYER/mcl_player/init.lua index 599acd65..b01c0b4d 100644 --- a/mods/PLAYER/mcl_player/init.lua +++ b/mods/PLAYER/mcl_player/init.lua @@ -70,10 +70,22 @@ function mcl_player.player_set_model(player, model_name) player_model[name] = model_name end -function mcl_player.player_set_textures(player, textures) +function mcl_player.player_set_textures(player, textures, preview) local name = player:get_player_name() player_textures[name] = textures player:set_properties({textures = textures,}) + if preview then + player:set_attribute("mcl_player:preview", preview) + end +end + +function mcl_player.player_get_preview(player) + local preview = player:get_attribute("mcl_player:preview") + if not preview then + return "player.png" + else + return preview + end end function mcl_player.player_set_animation(player, anim_name, speed) diff --git a/mods/PLAYER/simple_skins/init.lua b/mods/PLAYER/simple_skins/init.lua index 3a41490f..077278b7 100644 --- a/mods/PLAYER/simple_skins/init.lua +++ b/mods/PLAYER/simple_skins/init.lua @@ -3,7 +3,7 @@ -- Released by TenPlus1 and based on Zeg9's code under MIT license skins = { - skins = {}, meta = {}, + skins = {}, previews = {}, meta = {}, modpath = minetest.get_modpath("simple_skins"), skin_count = 0, -- counter of _custom_ skins (all skins except character.png) } @@ -49,18 +49,30 @@ while true do skins.skin_count = skins.skin_count + 1 end -skins.set_player_skin = function(player, skin) +skins.set_player_skin = function(player, skin_id) if not player then - return + return false end local playername = player:get_player_name() + local skin, preview + if skin_id == nil or type(skin_id) ~= "number" or skin_id < 0 or skin_id > skins.skin_count then + return false + elseif skin_id == 0 then + skin = "character" + preview = "player" + else + skin = "character_" .. tostring(skin_id) + preview = "player_" .. tostring(skin_id) + end skins.skins[playername] = skin - player:set_attribute("simple_skins:skin", skins.skins[playername]) + skins.previews[playername] = preview + player:set_attribute("simple_skins:skin_id", skin_id) skins.update_player_skin(player) if minetest.get_modpath("3d_armor") then armor.textures[playername].skin = skin .. ".png" armor:update_player_visuals(player) end + return true end skins.update_player_skin = function(player) @@ -68,27 +80,21 @@ skins.update_player_skin = function(player) return end local playername = player:get_player_name() - mcl_player.player_set_textures(player, { skins.skins[playername] .. ".png" }) + mcl_player.player_set_textures(player, { skins.skins[playername] .. ".png" }, skins.previews[playername] .. ".png" ) end -- load player skin on join minetest.register_on_joinplayer(function(player) local name = player:get_player_name() - local skin = player:get_attribute("simple_skins:skin") + local skin_id = player:get_attribute("simple_skins:skin_id") local set_skin -- do we already have a skin in player attributes? - if skin then - set_skin = skin - + if skin_id then + set_skin = tonumber(skin_id) -- otherwise use random skin if not set else - local r = math.random(0, skins.skin_count) - if r == 0 then - set_skin = "character" - else - set_skin = "character_" .. r - end + set_skin = math.random(0, skins.skin_count) end if set_skin then skins.set_player_skin(player, set_skin) @@ -125,16 +131,11 @@ minetest.register_chatcommand("setskin", { end local skin - if skin_id == nil or skin_id > skins.skin_count or skin_id < 0 then + local ok = skins.set_player_skin(player, skin_id) + if not ok then return false, S("Invalid skin number! Valid numbers: 0 to @1", skins.skin_count) - elseif skin_id == 0 then - skin = "character" - else - skin = "character_" .. tostring(skin_id) end - - skins.set_player_skin(player, skin) - local skinfile = skin..".png" + local skinfile = "Skin #"..skin_id local your_msg = S("Your skin has been set to: @1", skinfile) if name == playername then diff --git a/mods/PLAYER/simple_skins/textures/player_1.png b/mods/PLAYER/simple_skins/textures/player_1.png new file mode 100644 index 0000000000000000000000000000000000000000..3d7af2a980c2412be1f72e39fd6d7ffeda8f7fb3 GIT binary patch literal 2625 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 K=d#Wzp$Pz}JO2~_ literal 0 HcmV?d00001 From e47bd634d4a35a087d342c10629fc7af9cb90612 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:29:49 +0100 Subject: [PATCH 120/865] Player skins: Update inventory preview (part 2) --- mods/HUD/mcl_inventory/creative.lua | 32 ++++++++++++++++++++++++++++ mods/HUD/mcl_inventory/init.lua | 6 ++++++ mods/PLAYER/simple_skins/depends.txt | 1 + mods/PLAYER/simple_skins/init.lua | 3 +++ 4 files changed, 42 insertions(+) diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index f2afb964..d9ad2e94 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -570,6 +570,38 @@ if minetest.settings:get_bool("creative_mode") then end end + mcl_inventory.update_inventory_formspec = function(player) + local page = nil + + local name = player:get_player_name() + + if players[name].page then + page = players[name].page + else + page = "nix" + end + + -- Figure out current scroll bar from formspec + local formspec = player:get_inventory_formspec() + local start_i = players[name].start_i + + local inv_size + if page == "nix" then + local inv = minetest.get_inventory({type="detached", name="creative_"..name}) + inv_size = inv:get_size("main") + elseif page ~= nil and page ~= "inv" then + inv_size = #(inventory_lists[page]) + else + inv_size = 0 + end + + local filter = players[name].filter + if filter == nil then + filter = "" + end + + mcl_inventory.set_creative_formspec(player, start_i, start_i / (9*5) + 1, inv_size, false, page, filter) + end end minetest.register_on_joinplayer(function(player) diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index 3989af19..415c3075 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -127,6 +127,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) +if not minetest.settings:get_bool("creative_mode") then + mcl_inventory.update_inventory_formspec = function(player) + set_inventory(player) + end +end + -- Drop crafting grid items on leaving minetest.register_on_leaveplayer(function(player) return_fields(player, "craft") diff --git a/mods/PLAYER/simple_skins/depends.txt b/mods/PLAYER/simple_skins/depends.txt index 1927ce89..e0804a6f 100644 --- a/mods/PLAYER/simple_skins/depends.txt +++ b/mods/PLAYER/simple_skins/depends.txt @@ -1,3 +1,4 @@ mcl_player +mcl_inventory? intllib? 3d_armor? diff --git a/mods/PLAYER/simple_skins/init.lua b/mods/PLAYER/simple_skins/init.lua index 077278b7..98d3e7e8 100644 --- a/mods/PLAYER/simple_skins/init.lua +++ b/mods/PLAYER/simple_skins/init.lua @@ -72,6 +72,9 @@ skins.set_player_skin = function(player, skin_id) armor.textures[playername].skin = skin .. ".png" armor:update_player_visuals(player) end + if minetest.get_modpath("mcl_inventory") then + mcl_inventory.update_inventory_formspec(player) + end return true end From aae30bba3964437830a0793aac64df5eda4743a7 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:36:53 +0100 Subject: [PATCH 121/865] Rename simple_skins to mcl_skins --- .../minetest-3d_armor/3d_armor/armor.lua | 15 ++++++-- .../{simple_skins => mcl_skins}/depends.txt | 0 .../description.txt | 0 .../{simple_skins => mcl_skins}/init.lua | 36 +++++++++--------- .../{simple_skins => mcl_skins}/intllib.lua | 0 .../{simple_skins => mcl_skins}/license.txt | 0 .../{simple_skins => mcl_skins}/locale/fr.po | 0 .../{simple_skins => mcl_skins}/locale/it.po | 0 .../{simple_skins => mcl_skins}/locale/ms.po | 0 .../locale/template.pot | 0 .../meta/character.txt | 0 .../meta/character_1.txt | 0 mods/PLAYER/mcl_skins/mod.conf | 1 + .../{simple_skins => mcl_skins}/readme.md | 0 .../textures/character_1.png | Bin .../textures/inventory_plus_skins.png | Bin .../textures/player_1.png | Bin mods/PLAYER/simple_skins/mod.conf | 1 - 18 files changed, 31 insertions(+), 22 deletions(-) rename mods/PLAYER/{simple_skins => mcl_skins}/depends.txt (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/description.txt (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/init.lua (78%) rename mods/PLAYER/{simple_skins => mcl_skins}/intllib.lua (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/license.txt (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/locale/fr.po (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/locale/it.po (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/locale/ms.po (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/locale/template.pot (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/meta/character.txt (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/meta/character_1.txt (100%) create mode 100644 mods/PLAYER/mcl_skins/mod.conf rename mods/PLAYER/{simple_skins => mcl_skins}/readme.md (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/textures/character_1.png (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/textures/inventory_plus_skins.png (100%) rename mods/PLAYER/{simple_skins => mcl_skins}/textures/player_1.png (100%) delete mode 100644 mods/PLAYER/simple_skins/mod.conf diff --git a/mods/ITEMS/minetest-3d_armor/3d_armor/armor.lua b/mods/ITEMS/minetest-3d_armor/3d_armor/armor.lua index 0b07fb14..ae9799f9 100644 --- a/mods/ITEMS/minetest-3d_armor/3d_armor/armor.lua +++ b/mods/ITEMS/minetest-3d_armor/3d_armor/armor.lua @@ -66,7 +66,9 @@ armor = { version = "0.4.6", } -if minetest.get_modpath("skins") then +if minetest.get_modpath("mcl_skins") then + skin_mod = "mcl_skins" +elseif minetest.get_modpath("skins") then skin_mod = "skins" elseif minetest.get_modpath("simple_skins") then skin_mod = "simple_skins" @@ -197,7 +199,9 @@ end armor.get_player_skin = function(self, name) local skin = nil - if skin_mod == "skins" or skin_mod == "simple_skins" then + if skin_mod == "mcl_skins" then + skin = mcl_skins.skins[name] + elseif skin_mod == "skins" or skin_mod == "simple_skins" then skin = skins.skins[name] elseif skin_mod == "u_skins" then skin = u_skins.u_skins[name] @@ -380,7 +384,12 @@ minetest.register_on_joinplayer(function(player) wielditem = "3d_armor_trans.png", preview = armor.default_skin.."_preview.png", } - if skin_mod == "skins" then + if skin_mod == "mcl_skins" then + local skin = mcl_skins.skins[name] + if skin then + armor.textures[name].skin = skin..".png" + end + elseif skin_mod == "skins" then local skin = skins.skins[name] if skin and skins.get_type(skin) == skins.type.MODEL then armor.textures[name].skin = skin..".png" diff --git a/mods/PLAYER/simple_skins/depends.txt b/mods/PLAYER/mcl_skins/depends.txt similarity index 100% rename from mods/PLAYER/simple_skins/depends.txt rename to mods/PLAYER/mcl_skins/depends.txt diff --git a/mods/PLAYER/simple_skins/description.txt b/mods/PLAYER/mcl_skins/description.txt similarity index 100% rename from mods/PLAYER/simple_skins/description.txt rename to mods/PLAYER/mcl_skins/description.txt diff --git a/mods/PLAYER/simple_skins/init.lua b/mods/PLAYER/mcl_skins/init.lua similarity index 78% rename from mods/PLAYER/simple_skins/init.lua rename to mods/PLAYER/mcl_skins/init.lua index 98d3e7e8..fc892471 100644 --- a/mods/PLAYER/simple_skins/init.lua +++ b/mods/PLAYER/mcl_skins/init.lua @@ -2,15 +2,15 @@ -- Released by TenPlus1 and based on Zeg9's code under MIT license -skins = { +mcl_skins = { skins = {}, previews = {}, meta = {}, - modpath = minetest.get_modpath("simple_skins"), + modpath = minetest.get_modpath("mcl_skins"), skin_count = 0, -- counter of _custom_ skins (all skins except character.png) } -- Load support for intllib. -local S, NS = dofile(skins.modpath .. "/intllib.lua") +local S, NS = dofile(mcl_skins.modpath .. "/intllib.lua") -- load skin list and metadata @@ -21,7 +21,7 @@ while true do skin = "character_" .. id -- does skin file exist ? - f = io.open(skins.modpath .. "/textures/" .. skin .. ".png") + f = io.open(mcl_skins.modpath .. "/textures/" .. skin .. ".png") -- escape loop if not found and remove last entry if not f then @@ -32,7 +32,7 @@ while true do f:close() -- does metadata exist for that skin file ? - f = io.open(skins.modpath .. "/meta/" .. skin .. ".txt") + f = io.open(mcl_skins.modpath .. "/meta/" .. skin .. ".txt") if f then data = minetest.deserialize("return {" .. f:read('*all') .. "}") @@ -40,22 +40,22 @@ while true do end -- add metadata to list - skins.meta[skin] = { + mcl_skins.meta[skin] = { name = data and data.name or "", author = data and data.author or "", } id = id + 1 - skins.skin_count = skins.skin_count + 1 + mcl_skins.skin_count = mcl_skins.skin_count + 1 end -skins.set_player_skin = function(player, skin_id) +mcl_skins.set_player_skin = function(player, skin_id) if not player then return false end local playername = player:get_player_name() local skin, preview - if skin_id == nil or type(skin_id) ~= "number" or skin_id < 0 or skin_id > skins.skin_count then + if skin_id == nil or type(skin_id) ~= "number" or skin_id < 0 or skin_id > mcl_skins.skin_count then return false elseif skin_id == 0 then skin = "character" @@ -64,10 +64,10 @@ skins.set_player_skin = function(player, skin_id) skin = "character_" .. tostring(skin_id) preview = "player_" .. tostring(skin_id) end - skins.skins[playername] = skin - skins.previews[playername] = preview + mcl_skins.skins[playername] = skin + mcl_skins.previews[playername] = preview player:set_attribute("simple_skins:skin_id", skin_id) - skins.update_player_skin(player) + mcl_skins.update_player_skin(player) if minetest.get_modpath("3d_armor") then armor.textures[playername].skin = skin .. ".png" armor:update_player_visuals(player) @@ -78,12 +78,12 @@ skins.set_player_skin = function(player, skin_id) return true end -skins.update_player_skin = function(player) +mcl_skins.update_player_skin = function(player) if not player then return end local playername = player:get_player_name() - mcl_player.player_set_textures(player, { skins.skins[playername] .. ".png" }, skins.previews[playername] .. ".png" ) + mcl_player.player_set_textures(player, { mcl_skins.skins[playername] .. ".png" }, mcl_skins.previews[playername] .. ".png" ) end -- load player skin on join @@ -97,10 +97,10 @@ minetest.register_on_joinplayer(function(player) set_skin = tonumber(skin_id) -- otherwise use random skin if not set else - set_skin = math.random(0, skins.skin_count) + set_skin = math.random(0, mcl_skins.skin_count) end if set_skin then - skins.set_player_skin(player, set_skin) + mcl_skins.set_player_skin(player, set_skin) end end) @@ -134,9 +134,9 @@ minetest.register_chatcommand("setskin", { end local skin - local ok = skins.set_player_skin(player, skin_id) + local ok = mcl_skins.set_player_skin(player, skin_id) if not ok then - return false, S("Invalid skin number! Valid numbers: 0 to @1", skins.skin_count) + return false, S("Invalid skin number! Valid numbers: 0 to @1", mcl_skins.skin_count) end local skinfile = "Skin #"..skin_id diff --git a/mods/PLAYER/simple_skins/intllib.lua b/mods/PLAYER/mcl_skins/intllib.lua similarity index 100% rename from mods/PLAYER/simple_skins/intllib.lua rename to mods/PLAYER/mcl_skins/intllib.lua diff --git a/mods/PLAYER/simple_skins/license.txt b/mods/PLAYER/mcl_skins/license.txt similarity index 100% rename from mods/PLAYER/simple_skins/license.txt rename to mods/PLAYER/mcl_skins/license.txt diff --git a/mods/PLAYER/simple_skins/locale/fr.po b/mods/PLAYER/mcl_skins/locale/fr.po similarity index 100% rename from mods/PLAYER/simple_skins/locale/fr.po rename to mods/PLAYER/mcl_skins/locale/fr.po diff --git a/mods/PLAYER/simple_skins/locale/it.po b/mods/PLAYER/mcl_skins/locale/it.po similarity index 100% rename from mods/PLAYER/simple_skins/locale/it.po rename to mods/PLAYER/mcl_skins/locale/it.po diff --git a/mods/PLAYER/simple_skins/locale/ms.po b/mods/PLAYER/mcl_skins/locale/ms.po similarity index 100% rename from mods/PLAYER/simple_skins/locale/ms.po rename to mods/PLAYER/mcl_skins/locale/ms.po diff --git a/mods/PLAYER/simple_skins/locale/template.pot b/mods/PLAYER/mcl_skins/locale/template.pot similarity index 100% rename from mods/PLAYER/simple_skins/locale/template.pot rename to mods/PLAYER/mcl_skins/locale/template.pot diff --git a/mods/PLAYER/simple_skins/meta/character.txt b/mods/PLAYER/mcl_skins/meta/character.txt similarity index 100% rename from mods/PLAYER/simple_skins/meta/character.txt rename to mods/PLAYER/mcl_skins/meta/character.txt diff --git a/mods/PLAYER/simple_skins/meta/character_1.txt b/mods/PLAYER/mcl_skins/meta/character_1.txt similarity index 100% rename from mods/PLAYER/simple_skins/meta/character_1.txt rename to mods/PLAYER/mcl_skins/meta/character_1.txt diff --git a/mods/PLAYER/mcl_skins/mod.conf b/mods/PLAYER/mcl_skins/mod.conf new file mode 100644 index 00000000..96f82764 --- /dev/null +++ b/mods/PLAYER/mcl_skins/mod.conf @@ -0,0 +1 @@ +name = mcl_skins diff --git a/mods/PLAYER/simple_skins/readme.md b/mods/PLAYER/mcl_skins/readme.md similarity index 100% rename from mods/PLAYER/simple_skins/readme.md rename to mods/PLAYER/mcl_skins/readme.md diff --git a/mods/PLAYER/simple_skins/textures/character_1.png b/mods/PLAYER/mcl_skins/textures/character_1.png similarity index 100% rename from mods/PLAYER/simple_skins/textures/character_1.png rename to mods/PLAYER/mcl_skins/textures/character_1.png diff --git a/mods/PLAYER/simple_skins/textures/inventory_plus_skins.png b/mods/PLAYER/mcl_skins/textures/inventory_plus_skins.png similarity index 100% rename from mods/PLAYER/simple_skins/textures/inventory_plus_skins.png rename to mods/PLAYER/mcl_skins/textures/inventory_plus_skins.png diff --git a/mods/PLAYER/simple_skins/textures/player_1.png b/mods/PLAYER/mcl_skins/textures/player_1.png similarity index 100% rename from mods/PLAYER/simple_skins/textures/player_1.png rename to mods/PLAYER/mcl_skins/textures/player_1.png diff --git a/mods/PLAYER/simple_skins/mod.conf b/mods/PLAYER/simple_skins/mod.conf deleted file mode 100644 index aff90aab..00000000 --- a/mods/PLAYER/simple_skins/mod.conf +++ /dev/null @@ -1 +0,0 @@ -name = simple_skins From 788ecbf178fc471ae310c9086f07750205224800 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:40:37 +0100 Subject: [PATCH 122/865] Update mcl_skins readme --- mods/PLAYER/mcl_skins/init.lua | 4 +--- mods/PLAYER/mcl_skins/readme.md | 12 +++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mods/PLAYER/mcl_skins/init.lua b/mods/PLAYER/mcl_skins/init.lua index fc892471..99228f58 100644 --- a/mods/PLAYER/mcl_skins/init.lua +++ b/mods/PLAYER/mcl_skins/init.lua @@ -1,6 +1,4 @@ --- Simple Skins mod for Minetest (MineClone 2 Edition) - --- Released by TenPlus1 and based on Zeg9's code under MIT license +-- Skins for MineClone 2 mcl_skins = { skins = {}, previews = {}, meta = {}, diff --git a/mods/PLAYER/mcl_skins/readme.md b/mods/PLAYER/mcl_skins/readme.md index 0c6980bb..bbe5309a 100644 --- a/mods/PLAYER/mcl_skins/readme.md +++ b/mods/PLAYER/mcl_skins/readme.md @@ -1,7 +1,13 @@ -Simple Skins, MineClone 2 Edition += Skins for MineClone 2 = -Simple Skins mod to allow players to select a skin. +Simple mod to allow players to select a skin. Use the chat command /setskin to change skin. -Original mod: +Forked from Simple Skins by TenPlus1. https://forum.minetest.net/viewtopic.php?id=9100 + +== License == +Code under MIT license +Origial authors: +- TenPlus1 +- Zeg9 From b2c19d9ec60ee1e9c88b89685922b3decdf2e326 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:41:57 +0100 Subject: [PATCH 123/865] mcl_skins: Fix attribute name --- mods/PLAYER/mcl_skins/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/PLAYER/mcl_skins/init.lua b/mods/PLAYER/mcl_skins/init.lua index 99228f58..b584130c 100644 --- a/mods/PLAYER/mcl_skins/init.lua +++ b/mods/PLAYER/mcl_skins/init.lua @@ -64,7 +64,7 @@ mcl_skins.set_player_skin = function(player, skin_id) end mcl_skins.skins[playername] = skin mcl_skins.previews[playername] = preview - player:set_attribute("simple_skins:skin_id", skin_id) + player:set_attribute("mcl_skins:skin_id", tostring(skin_id)) mcl_skins.update_player_skin(player) if minetest.get_modpath("3d_armor") then armor.textures[playername].skin = skin .. ".png" @@ -88,7 +88,7 @@ end minetest.register_on_joinplayer(function(player) local name = player:get_player_name() - local skin_id = player:get_attribute("simple_skins:skin_id") + local skin_id = player:get_attribute("mcl_skins:skin_id") local set_skin -- do we already have a skin in player attributes? if skin_id then From 5601f8e0b79fab373b871bde2f5413b2cfd11fad Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:45:14 +0100 Subject: [PATCH 124/865] Rename some files --- mods/PLAYER/mcl_skins/{license.txt => LICENSE.txt} | 0 mods/PLAYER/mcl_skins/{readme.md => README.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename mods/PLAYER/mcl_skins/{license.txt => LICENSE.txt} (100%) rename mods/PLAYER/mcl_skins/{readme.md => README.md} (100%) diff --git a/mods/PLAYER/mcl_skins/license.txt b/mods/PLAYER/mcl_skins/LICENSE.txt similarity index 100% rename from mods/PLAYER/mcl_skins/license.txt rename to mods/PLAYER/mcl_skins/LICENSE.txt diff --git a/mods/PLAYER/mcl_skins/readme.md b/mods/PLAYER/mcl_skins/README.md similarity index 100% rename from mods/PLAYER/mcl_skins/readme.md rename to mods/PLAYER/mcl_skins/README.md From 62eaf60938e4b1f7c28db6b76143498911b82ea0 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 10:57:57 +0100 Subject: [PATCH 125/865] mcl_skins: Add fallback code if skin was missing --- mods/PLAYER/mcl_skins/init.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mods/PLAYER/mcl_skins/init.lua b/mods/PLAYER/mcl_skins/init.lua index b584130c..a822218d 100644 --- a/mods/PLAYER/mcl_skins/init.lua +++ b/mods/PLAYER/mcl_skins/init.lua @@ -73,6 +73,7 @@ mcl_skins.set_player_skin = function(player, skin_id) if minetest.get_modpath("mcl_inventory") then mcl_inventory.update_inventory_formspec(player) end + minetest.log("action", "[mcl_skins] Player skin for "..playername.." set to skin #"..skin_id) return true end @@ -98,7 +99,12 @@ minetest.register_on_joinplayer(function(player) set_skin = math.random(0, mcl_skins.skin_count) end if set_skin then - mcl_skins.set_player_skin(player, set_skin) + local ok = mcl_skins.set_player_skin(player, set_skin) + if not ok then + set_skin = math.random(0, mcl_skins.skin_count) + minetest.log("warning", "[mcl_skins] Player skin for "..name.." not found, falling back to skin #"..set_skin) + mcl_skins.set_player_skin(player, set_skin) + end end end) @@ -148,3 +154,5 @@ minetest.register_chatcommand("setskin", { end, }) + +minetest.log("action", "[mcl_skins] Mod initialized with "..mcl_skins.skin_count.." custom skin(s)") From 9a54383a23e50580d2cca242b27e8d8864067b6f Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Tue, 5 Mar 2019 11:43:09 +0100 Subject: [PATCH 126/865] Add mesh hand --- mods/PLAYER/mcl_meshhand/README.md | 9 ++++ mods/PLAYER/mcl_meshhand/depends.txt | 1 + mods/PLAYER/mcl_meshhand/description.txt | 1 + mods/PLAYER/mcl_meshhand/init.lua | 47 ++++++++++++++++++ mods/PLAYER/mcl_meshhand/mod.conf | 1 + .../mcl_meshhand/models/mcl_meshhand.b3d | Bin 0 -> 1023 bytes .../mcl_meshhand/models/mcl_meshhand.blend | Bin 0 -> 554856 bytes mods/PLAYER/mcl_skins/init.lua | 20 ++++++-- 8 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 mods/PLAYER/mcl_meshhand/README.md create mode 100644 mods/PLAYER/mcl_meshhand/depends.txt create mode 100644 mods/PLAYER/mcl_meshhand/description.txt create mode 100644 mods/PLAYER/mcl_meshhand/init.lua create mode 100644 mods/PLAYER/mcl_meshhand/mod.conf create mode 100644 mods/PLAYER/mcl_meshhand/models/mcl_meshhand.b3d create mode 100644 mods/PLAYER/mcl_meshhand/models/mcl_meshhand.blend diff --git a/mods/PLAYER/mcl_meshhand/README.md b/mods/PLAYER/mcl_meshhand/README.md new file mode 100644 index 00000000..2c796ff3 --- /dev/null +++ b/mods/PLAYER/mcl_meshhand/README.md @@ -0,0 +1,9 @@ +Mesh hand mod for MineClone 2. + +This mod uses a better-looking mesh for the wieldhand and applies the player skin texture to it. + +== Credits == +Based on 3D Hand [newhand] mod by jordan4ibanez. +https://forum.minetest.net/viewtopic.php?t=16435 + +License: CC0 diff --git a/mods/PLAYER/mcl_meshhand/depends.txt b/mods/PLAYER/mcl_meshhand/depends.txt new file mode 100644 index 00000000..f8be59ba --- /dev/null +++ b/mods/PLAYER/mcl_meshhand/depends.txt @@ -0,0 +1 @@ +mcl_skins? diff --git a/mods/PLAYER/mcl_meshhand/description.txt b/mods/PLAYER/mcl_meshhand/description.txt new file mode 100644 index 00000000..7a4daae5 --- /dev/null +++ b/mods/PLAYER/mcl_meshhand/description.txt @@ -0,0 +1 @@ +Applies the player skin texture to the hand. diff --git a/mods/PLAYER/mcl_meshhand/init.lua b/mods/PLAYER/mcl_meshhand/init.lua new file mode 100644 index 00000000..1e318a5b --- /dev/null +++ b/mods/PLAYER/mcl_meshhand/init.lua @@ -0,0 +1,47 @@ +local has_mcl_skins = minetest.get_modpath("mcl_skins") ~= nil + +-- mcl_skins is enabled +if has_mcl_skins == true then + --generate a node for every skin + for _,texture in pairs(mcl_skins.list) do + minetest.register_node("mcl_meshhand:"..texture, { + description = "", + tiles = {texture..".png"}, + inventory_image = "blank.png", + visual_scale = 1, + wield_scale = {x=1,y=1,z=1}, + paramtype = "light", + drawtype = "mesh", + mesh = "mcl_meshhand.b3d", + node_placement_prediction = "", + }) + end + --change the player's hand to their skin + minetest.register_on_joinplayer(function(player) + local skin = mcl_skins.skins[player:get_player_name()] + player:get_inventory():set_stack("hand", 1, "mcl_meshhand:"..skin) + end) + + mcl_skins.register_on_set_skin(function(player, skin) + local name = player:get_player_name() + player:get_inventory():set_stack("hand", 1, "mcl_meshhand:"..skin) + end) + +--do default skin if no skin mod installed +else + minetest.register_node("mcl_meshhand:hand", { + description = "", + tiles = {"character.png"}, + inventory_image = "blank.png", + visual_scale = 1, + wield_scale = {x=1,y=1,z=1}, + paramtype = "light", + drawtype = "mesh", + mesh = "mcl_meshhand.b3d", + node_placement_prediction = "", + }) + + minetest.register_on_joinplayer(function(player) + player:get_inventory():set_stack("hand", 1, "mcl_meshhand:hand") + end) +end diff --git a/mods/PLAYER/mcl_meshhand/mod.conf b/mods/PLAYER/mcl_meshhand/mod.conf new file mode 100644 index 00000000..6b57f4a4 --- /dev/null +++ b/mods/PLAYER/mcl_meshhand/mod.conf @@ -0,0 +1 @@ +name = mcl_meshhand diff --git a/mods/PLAYER/mcl_meshhand/models/mcl_meshhand.b3d b/mods/PLAYER/mcl_meshhand/models/mcl_meshhand.b3d new file mode 100644 index 0000000000000000000000000000000000000000..a38124c60799c4b19b9260a94c712be38bfd7628 GIT binary patch literal 1023 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 z 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

lw zEG$7&1?GZX1ZD+8#tmT(0E;nzNr=VZXmkND!v%|mq~;dn7bWJvG~{OHp&5~znTM_@ z8|qzf)=SDP0n>@4DVg~YGeHwoU~VvI+CCK_?UY#pu^TK4??gj*Am2kA3FbQ?n;Q={ zn4v5)B{e@jDYFEe(ZI^kc)6JsNOGXvHF>Ey#S9Ropm2n+AO$N!dVT?<30{;8nv;kJ zYXz|rE8uL<0>soJh_c+$iueN1Hl7j$AFKyvEqJa8k{9y9E!?~mhLrq*f}GSMQ04&j zY(cpXR2PD)b?|UwNjzvIwg|N3K?}Ur55WfwU{!%TP#{)nMRE>k2}Dj}C8%M+07}m;%mo)^1v!bJ4KRh!vKqEblOeUD2pZhU znR%)CdEjAK1}M8cBeNtG#!1RaOwNXJ(i3xY6B)7!j3DYk3|OS4mV*W?AzKBNv$nv(+>-%rhBr~tKE7%IUesE-6@fGWPsB(RaG@!%=})N)RR z6t^jvxv6;|e}k42LY5R&Wafg)`+~$2Glq)dC||5;|wNHTvAk;44$>l zPX;aD2QBo3EH4CW%r8!4NGk#j8bU$?v>3QJF)g*Ek^wrX3vvdi=mrfmfto0Z$t9re z0J%vyrA6Sv8&m{WBo-GiRDuYoVe#OhwDiQ%V$e8BPJU5*Zh8qMRTbnHmp~F4hy~iR z0HTW%OBhlz!DTyhKoup(Ct!V`LI%tLE%JsA8iV--i7AE*1)0gvUL$ymAE;8#Er