diff --git a/GROUPS.md b/GROUPS.md index 8286b29bc6..8ff75bbdab 100644 --- a/GROUPS.md +++ b/GROUPS.md @@ -56,6 +56,7 @@ Please read to learn how digging times * `no_eat_delay=1`: Only for foodstuffs. When eating this, all eating delays are ignored. * `can_eat_when_full=1`: Only for foodstuffs. This item can be eaten when the user has a full hunger bar * `attached_node_facedir=1`: Like `attached_node`, but for facedir nodes +* `supported_node=1`: Like `attached_node`, but can be placed on any nodes that do not have the `drawtype="airlike"` attribute. * `cauldron`: Cauldron. 1: Empty. 2-4: Water height * `anvil`: Anvil. 1: No damage. 2-3: Higher damage levels * `no_rename=1`: Item cannot be renamed by anvil diff --git a/README.md b/README.md index 29f0b8ed59..fe2b85c169 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils. Developed by many people. Not developed or endorsed by Mojang AB. -Version: 0.72.0 +Version: 0.73.0 (in development) ### Gameplay You start in a randomly-generated world made entirely of cubes. You can explore @@ -66,7 +66,7 @@ Use the `/giveme` chat command to obtain them. See the in-game help for an explanation. ## Installation -This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or +This game requires [Minetest](http://minetest.net) to run (version 5.4.1 or later). So you need to install Minetest first. Only stable versions of Minetest are officially supported. There is no support for running MineClone2 in development versions of Minetest. diff --git a/mods/CORE/mcl_attached/init.lua b/mods/CORE/mcl_attached/init.lua index 4f538e104b..c4a7a3337b 100644 --- a/mods/CORE/mcl_attached/init.lua +++ b/mods/CORE/mcl_attached/init.lua @@ -1,29 +1,93 @@ +-- Overrides the builtin minetest.check_single_for_falling. +-- We need to do this in order to handle nodes in mineclone specific groups +-- "supported_node" and "attached_node_facedir". +-- +-- Nodes in group "supported_node" can be placed on any node that does not +-- have the "airlike" drawtype. Carpets are an example of this type. + local vector = vector local facedir_to_dir = minetest.facedir_to_dir local get_item_group = minetest.get_item_group local remove_node = minetest.remove_node local get_node = minetest.get_node +local get_meta = minetest.get_meta +local registered_nodes = minetest.registered_nodes +local get_node_drops = minetest.get_node_drops +local add_item = minetest.add_item +-- drop_attached_node(p) +-- +-- This function is copied verbatim from minetest/builtin/game/falling.lua +-- We need this to do the exact same dropping node handling in our override +-- minetest.check_single_for_falling() function as in the builtin function. +-- +local function drop_attached_node(p) + local n = get_node(p) + local drops = get_node_drops(n, "") + local def = registered_nodes[n.name] + if def and def.preserve_metadata then + local oldmeta = get_meta(p):to_table().fields + -- Copy pos and node because the callback can modify them. + local pos_copy = vector.new(p) + local node_copy = {name=n.name, param1=n.param1, param2=n.param2} + local drop_stacks = {} + for k, v in pairs(drops) do + drop_stacks[k] = ItemStack(v) + end + drops = drop_stacks + def.preserve_metadata(pos_copy, node_copy, oldmeta, drops) + end + if def and def.sounds and def.sounds.fall then + core.sound_play(def.sounds.fall, {pos = p}, true) + end + remove_node(p) + for _, item in pairs(drops) do + local pos = { + x = p.x + math.random()/2 - 0.25, + y = p.y + math.random()/2 - 0.25, + z = p.z + math.random()/2 - 0.25, + } + add_item(pos, item) + end +end + +-- minetest.check_single_for_falling(pos) +-- +-- * causes an unsupported `group:falling_node` node to fall and causes an +-- unattached `group:attached_node` or `group:attached_node_facedir` node +-- or unsupported `group:supported_node` node to drop. +-- * does not spread these updates to neighbours. +-- +-- Returns true if the node at has spawned a falling node or has been +-- dropped as item(s). +-- local original_function = minetest.check_single_for_falling function minetest.check_single_for_falling(pos) - local ret_o = original_function(pos) - local ret = false - local node = minetest.get_node(pos) + if original_function(pos) then + return true + end + + local node = get_node(pos) if get_item_group(node.name, "attached_node_facedir") ~= 0 then local dir = facedir_to_dir(node.param2) if dir then if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then - remove_node(pos) - local drops = minetest.get_node_drops(node.name, "") - for dr=1, #drops do - minetest.add_item(pos, drops[dr]) - end - ret = true + drop_attached_node(pos) + return true end end end - return ret_o or ret + + if get_item_group(node.name, "supported_node") ~= 0 then + local def = registered_nodes[get_node(vector.offset(pos, 0, -1, 0)).name] + if def and def.drawtype == "airlike" then + drop_attached_node(pos) + return true + end + end + + return false end diff --git a/mods/ENTITIES/mcl_burning/api.lua b/mods/ENTITIES/mcl_burning/api.lua index 8093d45f98..885875aca2 100644 --- a/mods/ENTITIES/mcl_burning/api.lua +++ b/mods/ENTITIES/mcl_burning/api.lua @@ -131,17 +131,6 @@ function mcl_burning.set_on_fire(obj, burn_time) if obj:is_player() then mcl_burning.update_hud(obj) end - - -- FIXME: does this code make sense? It removes attached fire luaentities from - -- another object that happen to be at the same position. - local fire_luaentity = fire_entity:get_luaentity() - for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do - local other_luaentity = other:get_luaentity() - if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then - other:remove() - break - end - end end function mcl_burning.extinguish(obj) diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index 62bf3f69a9..8133a1fe36 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -57,7 +57,7 @@ minetest.register_on_joinplayer(function(player) local storage = {} local burn_data = player:get_meta():get_string("mcl_burning:data") if burn_data ~= "" then - storage = minetest.deserialize(burn_data) + storage = minetest.deserialize(burn_data) or storage end mcl_burning.storage[player] = storage if storage.burn_time and storage.burn_time > 0 then @@ -98,8 +98,7 @@ minetest.register_entity("mcl_burning:fire", { glow = -1, backface_culling = false, }, - animation_frame = 0, - animation_timer = 0, + _mcl_animation_timer = 0, on_activate = function(self) self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames) end, @@ -115,9 +114,9 @@ minetest.register_entity("mcl_burning:fire", { return end if parent:is_player() then - self.animation_timer = self.animation_timer + dtime - if self.animation_timer >= 0.1 then - self.animation_timer = 0 + self._mcl_animation_timer = self._mcl_animation_timer + dtime + if self._mcl_animation_timer >= 0.1 then + self._mcl_animation_timer = 0 mcl_burning.update_hud(parent) end end diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index c38c8eafa6..ca47d4be7c 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -222,8 +222,8 @@ local collision = function(self) for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do - if object:is_player() - or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then + local ent = object:get_luaentity() + if object:is_player() or (ent and ent._cmi_is_mob and object ~= self.object) then local pos2 = object:get_pos() local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} diff --git a/mods/ENTITIES/mcl_mobs/spawning.lua b/mods/ENTITIES/mcl_mobs/spawning.lua index 210c6b9c67..2e7f523ba0 100644 --- a/mods/ENTITIES/mcl_mobs/spawning.lua +++ b/mods/ENTITIES/mcl_mobs/spawning.lua @@ -570,12 +570,22 @@ if mobs_spawn then break end - local gotten_node = get_node(spawning_position).name + local gotten_node = get_node(spawning_position) + local gotten_node_name = gotten_node.name + local gotten_node_def = minetest.registered_nodes[gotten_node_name] - if not gotten_node or gotten_node == "air" then --skip air nodes + if not gotten_node_name or not gotten_node_def or gotten_node_name == "air" then --skip air nodes break end + if gotten_node_def.use_texture_alpha and gotten_node_def.use_texture_alpha ~= "opaque" then + break + end --don't spawn on nonopaque nodes + + local leaf = minetest.get_item_group(gotten_node_name,"leaves") + if leaf ~= 0 then + break end --don't spawn on treetops + local gotten_biome = minetest.get_biome_data(spawning_position) if not gotten_biome then @@ -616,8 +626,8 @@ if mobs_spawn then break end - local is_water = get_item_group(gotten_node, "water") ~= 0 - local is_lava = get_item_group(gotten_node, "lava") ~= 0 + local is_water = get_item_group(gotten_node_name, "water") ~= 0 + local is_lava = get_item_group(gotten_node_name, "lava") ~= 0 if mob_def.type_of_spawning == "ground" and is_water then break diff --git a/mods/ENTITIES/mobs_mc/chicken.lua b/mods/ENTITIES/mobs_mc/chicken.lua index 615ec86e7f..0b43fca0dd 100644 --- a/mods/ENTITIES/mobs_mc/chicken.lua +++ b/mods/ENTITIES/mobs_mc/chicken.lua @@ -106,22 +106,42 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "flat", + "IcePlainsSpikes", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", + "ExtremeHillsM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", + "BirchForestM", + "RoofedForest", + "Savanna", + "Savanna_beach", + "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua index 62e124463d..0b9a7ec71c 100644 --- a/mods/ENTITIES/mobs_mc/cow+mooshroom.lua +++ b/mods/ENTITIES/mobs_mc/cow+mooshroom.lua @@ -151,22 +151,42 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "flat", + "IcePlainsSpikes", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", + "ExtremeHillsM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", + "BirchForestM", + "RoofedForest", + "Savanna", + "Savanna_beach", + "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index ac631f2053..5fe6055733 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -520,22 +520,42 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "flat", + "IcePlainsSpikes", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", + "ExtremeHillsM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", + "BirchForestM", + "RoofedForest", + "Savanna", + "Savanna_beach", + "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 0, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/llama.lua b/mods/ENTITIES/mobs_mc/llama.lua index 655cddfb6d..b6566059a9 100644 --- a/mods/ENTITIES/mobs_mc/llama.lua +++ b/mods/ENTITIES/mobs_mc/llama.lua @@ -223,12 +223,18 @@ mobs:spawn_specific( "overworld", "ground", { -"Mesa", -"MesaPlateauFM_grasstop", -"MesaPlateauF", -"MesaPlateauFM", -"MesaPlateauF_grasstop", -"MesaBryce", + "Mesa", + "MesaPlateauFM_grasstop", + "MesaPlateauF", + "MesaPlateauFM", + "MesaPlateauF_grasstop", + "MesaBryce", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", }, 0, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/pig.lua b/mods/ENTITIES/mobs_mc/pig.lua index b7d919cfff..837d743f0f 100644 --- a/mods/ENTITIES/mobs_mc/pig.lua +++ b/mods/ENTITIES/mobs_mc/pig.lua @@ -188,22 +188,42 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "flat", + "IcePlainsSpikes", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", + "ExtremeHillsM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", + "BirchForestM", + "RoofedForest", + "Savanna", + "Savanna_beach", + "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 9, minetest.LIGHT_MAX+1, diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 9ddc0adeec..f16b64c66f 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -309,22 +309,42 @@ mobs:spawn_specific( "overworld", "ground", { -"FlowerForest", -"Swampland", -"Taiga", -"ExtremeHills", -"BirchForest", -"MegaSpruceTaiga", -"MegaTaiga", -"ExtremeHills+", -"Forest", -"Plains", -"ColdTaiga", -"SunflowerPlains", -"RoofedForest", -"MesaPlateauFM_grasstop", -"ExtremeHillsM", -"BirchForestM", + "flat", + "IcePlainsSpikes", + "ColdTaiga", + "ColdTaiga_beach", + "ColdTaiga_beach_water", + "MegaTaiga", + "MegaSpruceTaiga", + "ExtremeHills", + "ExtremeHills_beach", + "ExtremeHillsM", + "ExtremeHills+", + "ExtremeHills+_snowtop", + "StoneBeach", + "Plains", + "Plains_beach", + "SunflowerPlains", + "Taiga", + "Taiga_beach", + "Forest", + "Forest_beach", + "FlowerForest", + "FlowerForest_beach", + "BirchForest", + "BirchForestM", + "RoofedForest", + "Savanna", + "Savanna_beach", + "SavannaM", + "Jungle", + "Jungle_shore", + "JungleM", + "JungleM_shore", + "JungleEdge", + "JungleEdgeM", + "Swampland", + "Swampland_shore" }, 0, minetest.LIGHT_MAX+1, diff --git a/mods/ITEMS/mcl_barrels/init.lua b/mods/ITEMS/mcl_barrels/init.lua index 42dbf8c18d..09b16eee39 100644 --- a/mods/ITEMS/mcl_barrels/init.lua +++ b/mods/ITEMS/mcl_barrels/init.lua @@ -14,6 +14,27 @@ local function on_blast(pos) minetest.remove_node(pos) end +-- Simple protection checking functions +local function protection_check_move(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 function protection_check_put_take(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 function barrel_open(pos, node, clicker) local name = minetest.get_meta(pos):get_string("name") @@ -82,7 +103,6 @@ minetest.register_node("mcl_barrels:barrel_closed", { tiles = {"mcl_barrels_barrel_top.png^[transformR270", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"}, paramtype = "light", paramtype2 = "facedir", - --on_place = mcl_util.rotate_axis, on_place = function(itemstack, placer, pointed_thing) minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false) return itemstack @@ -98,6 +118,21 @@ minetest.register_node("mcl_barrels:barrel_closed", { after_place_node = function(pos, placer, itemstack, pointed_thing) minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name")) 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 barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " moves stuff to barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " takes stuff from barrel at "..minetest.pos_to_string(pos)) + end, after_dig_node = drop_content, on_blast = on_blast, on_rightclick = barrel_open, @@ -119,6 +154,21 @@ minetest.register_node("mcl_barrels:barrel_open", { stack_max = 64, sounds = mcl_sounds.node_sound_wood_defaults(), groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1}, + 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 barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_put = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " moves stuff to barrel at "..minetest.pos_to_string(pos)) + end, + on_metadata_inventory_take = function(pos, listname, index, stack, player) + minetest.log("action", player:get_player_name().. + " takes stuff from barrel at "..minetest.pos_to_string(pos)) + end, after_dig_node = drop_content, on_blast = on_blast, on_rightclick = barrel_open, diff --git a/mods/ITEMS/mcl_wool/init.lua b/mods/ITEMS/mcl_wool/init.lua index c35ba9cf74..65cbb87088 100644 --- a/mods/ITEMS/mcl_wool/init.lua +++ b/mods/ITEMS/mcl_wool/init.lua @@ -75,7 +75,7 @@ for _, row in ipairs(wool.dyes) do tiles = {texture..".png"}, wield_image = texture..".png", wield_scale = { x=1, y=1, z=0.5 }, - groups = {handy=1, carpet=1,attached_node=1,flammable=1,fire_encouragement=60, fire_flammability=20, dig_by_water=1,deco_block=1,[color_group]=1}, + groups = {handy=1, carpet=1,supported_node=1,flammable=1,fire_encouragement=60, fire_flammability=20, dig_by_water=1,deco_block=1,[color_group]=1}, sounds = mcl_sounds.node_sound_wool_defaults(), paramtype = "light", sunlight_propagates = true, diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 99e9824580..1784b2e113 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -35,8 +35,8 @@ local function player_collision(player) for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do - if object and (object:is_player() - or (object:get_luaentity()._cmi_is_mob == true and object ~= player)) then + local ent = object:get_luaentity() + if (object:is_player() or (ent and ent._cmi_is_mob and object ~= player)) then local pos2 = object:get_pos() local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}