diff --git a/mods/CORE/_mcl_autogroup/init.lua b/mods/CORE/_mcl_autogroup/init.lua index 345bfd302..c8475d0bd 100644 --- a/mods/CORE/_mcl_autogroup/init.lua +++ b/mods/CORE/_mcl_autogroup/init.lua @@ -6,7 +6,7 @@ block has a hardness and the actual Minecraft digging time is determined by this: 1) The block's hardness -2) The tool being used (the tool_multiplier and its efficiency level) +2) The tool being used (the tool speed and its efficiency level) 3) Whether the tool is considered as "eligible" for the block (e.g. only diamond pick eligible for obsidian) @@ -43,13 +43,13 @@ this field is a table which defines which groups the tool can dig and how efficiently. _mcl_diggroups = { - handy = { tool_multiplier = 1, level = 1, uses = 0 }, - pickaxey = { tool_multiplier = 1, level = 0, uses = 0 }, + handy = { speed = 1, level = 1, uses = 0 }, + pickaxey = { speed = 1, level = 0, uses = 0 }, } The "uses" field indicate how many uses (0 for infinite) a tool has when used on -the specified digging group. The "tool_multiplier" field is a multiplier to the -dig speed on that digging group. +the specified digging group. The "speed" field is a multiplier to the dig speed +on that digging group. The "level" field indicates which levels of the group the tool can harvest. A level of 0 means that the tool cannot harvest blocks of that node. A level of 1 @@ -69,6 +69,8 @@ This also means that it is very important that no mod adds _mcl_autogroup as a dependency. --]] +assert(minetest.get_modpath("mcl_autogroup"), "This mod requires the mod mcl_autogroup to function") + -- Returns a table containing the unique "_mcl_hardness" for nodes belonging to -- each diggroup. local function get_hardness_values_for_groups() @@ -135,19 +137,18 @@ end -- Parameters: -- group - the group which it is digging -- can_harvest - if the tool can harvest the block --- tool_multiplier - dig speed multiplier for tool (default 1) +-- speed - dig speed multiplier for tool (default 1) -- efficiency - efficiency level for the tool if applicable -local function get_digtimes(group, can_harvest, tool_multiplier, efficiency) - tool_multiplier = tool_multiplier or 1 - local speed_multiplier = tool_multiplier +local function get_digtimes(group, can_harvest, speed, efficiency) + local speed = speed or 1 if efficiency then - speed_multiplier = speed_multiplier + efficiency * efficiency + 1 + speed = speed + efficiency * efficiency + 1 end local digtimes = {} for index, hardness in pairs(hardness_values[group]) do - local digtime = (hardness or 0) / speed_multiplier + local digtime = (hardness or 0) / speed if can_harvest then digtime = digtime * 1.5 else @@ -177,8 +178,12 @@ end -- Add the groupcaps from a field in "_mcl_diggroups" to the groupcaps of a -- tool. local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency) + if not groupcaps_def then + return + end + for g, capsdef in pairs(groupcaps_def) do - local mult = capsdef.tool_multiplier or 1 + local mult = capsdef.speed or 1 local uses = capsdef.uses local def = mcl_autogroup.registered_diggroups[g] local max_level = def.levels and #def.levels or 1 @@ -195,7 +200,6 @@ local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency) groupcaps[g .. "_dig"] = get_groupcap(g, level > 0, mult, efficiency, uses) end end - return groupcaps end -- Checks if the given node would drop its useful drop if dug by a given tool. @@ -209,7 +213,7 @@ function mcl_autogroup.can_harvest(nodename, toolname) -- Check if it can be dug by tool local tdef = minetest.registered_tools[toolname] - if tdef then + if tdef and tdef._mcl_diggroups then for g, gdef in pairs(tdef._mcl_diggroups) do if ndef.groups[g] then if ndef.groups[g] <= gdef.level then diff --git a/mods/CORE/mcl_autogroup/init.lua b/mods/CORE/mcl_autogroup/init.lua index 09894dd84..16dd831c0 100644 --- a/mods/CORE/mcl_autogroup/init.lua +++ b/mods/CORE/mcl_autogroup/init.lua @@ -12,6 +12,8 @@ as possible. Minetest loads mods in reverse alphabetical order. mcl_autogroup = {} mcl_autogroup.registered_diggroups = {} +assert(minetest.get_modpath("_mcl_autogroup"), "This mod requires the mod _mcl_autogroup to function") + -- Register a group as a digging group. -- -- Parameters: diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index 884ebfae1..014a30d1e 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -33,25 +33,26 @@ mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16) mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2) -local chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE +mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE +mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE -local central_chunk_max_pos = central_chunk_min_pos + chunk_size_in_nodes - 1 +local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1 local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE) local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1 -local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk -local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. -mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes -mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes +local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk +local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. +mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes +mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes local function coordinate_to_block(x) return math.floor(x / mcl_vars.MAP_BLOCKSIZE) end local function coordinate_to_chunk(x) - return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize) + return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize) end function mcl_vars.pos_to_block(pos) @@ -70,7 +71,7 @@ function mcl_vars.pos_to_chunk(pos) } end -local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes) +local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes) local k_positive_z = k_positive * 2 local k_positive_y = k_positive_z * k_positive_z @@ -174,3 +175,86 @@ minetest.craftitemdef_default.stack_max = 64 -- Set random seed for all other mods (Remember to make sure no other mod calls this function) math.randomseed(os.time()) +local chunks = {} -- intervals of chunks generated +function mcl_vars.add_chunk(pos) + local n = mcl_vars.get_chunk_number(pos) -- unsigned int + local prev + for i, d in pairs(chunks) do + if n <= d[2] then -- we've found it + if (n == d[2]) or (n >= d[1]) then return end -- already here + if n == d[1]-1 then -- right before: + if prev and (prev[2] == n-1) then + prev[2] = d[2] + table.remove(chunks, i) + return + end + d[1] = n + return + end + if prev and (prev[2] == n-1) then --join to previous + prev[2] = n + return + end + table.insert(chunks, i, {n, n}) -- insert new interval before i + return + end + prev = d + end + chunks[#chunks+1] = {n, n} +end +function mcl_vars.is_generated(pos) + local n = mcl_vars.get_chunk_number(pos) -- unsigned int + for i, d in pairs(chunks) do + if n <= d[2] then + return (n >= d[1]) + end + end + return false +end + +-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does. +-- p: Position, if it's wrong, {name="error"} node will return. +-- force: optional (default: false) - Do the maximum to still read the node within us_timeout. +-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job. +-- +-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}. +function mcl_vars.get_node(p, force, us_timeout) + -- check initial circumstances + if not p or not p.x or not p.y or not p.z then return {name="error"} end + + -- try common way + local node = minetest.get_node(p) + if node.name ~= "ignore" then + return node + end + + -- copy table to get sure it won't changed by other threads + local pos = {x=p.x,y=p.y,z=p.z} + + -- try LVM + minetest.get_voxel_manip():read_from_map(pos, pos) + node = minetest.get_node(pos) + if node.name ~= "ignore" or not force then + return node + end + + -- all ways failed - need to emerge (or forceload if generated) + local us_timeout = us_timeout or 244 + if mcl_vars.is_generated(pos) then + minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!") + minetest.forceload_block(pos) + else + minetest.emerge_area(pos, pos) + end + + local t = minetest.get_us_time() + + node = minetest.get_node(pos) + + while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do + node = minetest.get_node(pos) + end + + return node + -- it still can return "ignore", LOL, even if force = true, but only after time out +end diff --git a/mods/CORE/mcl_worlds/init.lua b/mods/CORE/mcl_worlds/init.lua index 35549ffad..6cdeaab7e 100644 --- a/mods/CORE/mcl_worlds/init.lua +++ b/mods/CORE/mcl_worlds/init.lua @@ -6,7 +6,7 @@ mcl_worlds = {} function mcl_worlds.is_in_void(pos) local void = not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or - (pos.y < mcl_vars.mg_nether_max and pos.y > mcl_vars.mg_nether_min) or + (pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or (pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min)) local void_deadly = false @@ -15,11 +15,11 @@ function mcl_worlds.is_in_void(pos) -- Overworld → Void → End → Void → Nether → Void if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance - elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max then + elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then -- The void between End and Nether. Like usual, but here, the void -- *above* the Nether also has a small tolerance area, so player -- can fly above the Nether without getting hurt instantly. - void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max + deadly_tolerance) + void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance) elseif pos.y < mcl_vars.mg_nether_min then void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance end @@ -35,7 +35,7 @@ end function mcl_worlds.y_to_layer(y) if y >= mcl_vars.mg_overworld_min then return y - mcl_vars.mg_overworld_min, "overworld" - elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max then + elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then return y - mcl_vars.mg_nether_min, "nether" elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then return y - mcl_vars.mg_end_min, "end" @@ -73,7 +73,7 @@ end -- Takes a position and returns true if this position can have Nether dust function mcl_worlds.has_dust(pos) -- Weather in the Overworld and the high part of the void below - return pos.y <= mcl_vars.mg_nether_max + 64 and pos.y >= mcl_vars.mg_nether_min - 64 + return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10 end -- Takes a position (pos) and returns true if compasses are working here diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index 9a9b65cc9..38e73565b 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -1,6 +1,6 @@ local S = minetest.get_translator("mcl_boats") -local boat_visual_size = {x = 3, y = 3, z = 3} +local boat_visual_size = {x = 1, y = 1, z = 1} local paddling_speed = 22 local boat_y_offset = 0.35 local boat_y_offset_ground = boat_y_offset + 0.6 @@ -12,9 +12,7 @@ local function is_group(pos, group) return minetest.get_item_group(nn, group) ~= 0 end -local function is_water(pos) - return is_group(pos, "water") -end +local is_water = flowlib.is_water local function is_ice(pos) return is_group(pos, "ice") @@ -247,7 +245,7 @@ function boat.on_step(self, dtime, moveresult) else local ctrl = self._passenger:get_player_control() if ctrl and ctrl.sneak then - detach_player(self._passenger, true) + detach_object(self._passenger, true) self._passenger = nil end end diff --git a/mods/ENTITIES/mcl_boats/mod.conf b/mods/ENTITIES/mcl_boats/mod.conf index 251459186..a5d6cc8cb 100644 --- a/mods/ENTITIES/mcl_boats/mod.conf +++ b/mods/ENTITIES/mcl_boats/mod.conf @@ -1,7 +1,7 @@ name = mcl_boats author = PilzAdam description = Adds drivable boats. -depends = mcl_player +depends = mcl_player, flowlib optional_depends = mcl_core, doc_identifier diff --git a/mods/ENTITIES/mcl_boats/models/mcl_boats_boat.b3d b/mods/ENTITIES/mcl_boats/models/mcl_boats_boat.b3d index e53bc4129..6c9c31469 100644 Binary files a/mods/ENTITIES/mcl_boats/models/mcl_boats_boat.b3d and b/mods/ENTITIES/mcl_boats/models/mcl_boats_boat.b3d differ diff --git a/mods/ENTITIES/mcl_burning/api.lua b/mods/ENTITIES/mcl_burning/api.lua index 4eac333a2..b08a0fb70 100644 --- a/mods/ENTITIES/mcl_burning/api.lua +++ b/mods/ENTITIES/mcl_burning/api.lua @@ -167,7 +167,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason) hud_elem_type = "image", position = {x = 0.5, y = 0.5}, scale = {x = -100, y = -100}, - text = "mcl_burning_hud_flame_animated.png", + text = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. 1, z_index = 1000, }) + 1 end diff --git a/mods/ENTITIES/mcl_falling_nodes/init.lua b/mods/ENTITIES/mcl_falling_nodes/init.lua index 1ffc87b34..6e69f8911 100644 --- a/mods/ENTITIES/mcl_falling_nodes/init.lua +++ b/mods/ENTITIES/mcl_falling_nodes/init.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator("mcl_falling_nodes") local dmes = minetest.get_modpath("mcl_death_messages") ~= nil +local has_mcl_armor = minetest.get_modpath("mcl_armor") + +local is_creative_enabled = minetest.is_creative_enabled local get_falling_depth = function(self) if not self._startpos then @@ -13,9 +16,8 @@ local deal_falling_damage = function(self, dtime) if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then return end - -- Cause damage to any player it hits. + -- Cause damage to any entity it hits. -- Algorithm based on MC anvils. - -- TODO: Support smashing other objects, too. local pos = self.object:get_pos() if not self._startpos then -- Fallback @@ -23,30 +25,39 @@ local deal_falling_damage = function(self, dtime) end local objs = minetest.get_objects_inside_radius(pos, 1) for _,v in ipairs(objs) do - local hp = v:get_hp() - if v:is_player() and hp ~= 0 then - if not self._hit_players then - self._hit_players = {} - end + if v:is_player() then + local hp = v:get_hp() local name = v:get_player_name() - local hit = false - for _,v in ipairs(self._hit_players) do - if name == v then - hit = true + if hp ~= 0 then + if not self._hit_players then + self._hit_players = {} end - end - if not hit then - table.insert(self._hit_players, name) - local way = self._startpos.y - pos.y - local damage = (way - 1) * 2 - damage = math.min(40, math.max(0, damage)) - if damage >= 1 then - hp = hp - damage - if hp < 0 then - hp = 0 + local hit = false + for _,v in ipairs(self._hit_players) do + if name == v then + hit = true end - if v:is_player() then - -- TODO: Reduce damage if wearing a helmet + end + if not hit then + table.insert(self._hit_players, name) + local way = self._startpos.y - pos.y + local damage = (way - 1) * 2 + damage = math.min(40, math.max(0, damage)) + if damage >= 1 then + hp = hp - damage + if hp < 0 then + hp = 0 + end + -- Reduce damage if wearing a helmet + local inv = v:get_inventory() + local helmet = inv:get_stack("armor", 2) + if has_mcl_armor and not helmet:is_empty() then + hp = hp/4*3 + if not is_creative_enabled(name) then + helmet:add_wear(65535/helmet:get_definition().groups.mcl_armor_uses) --TODO: be sure damage is exactly like mc (informations are missing in the mc wiki) + inv:set_stack("armor", 2, helmet) + end + end local msg if minetest.get_item_group(self.node.name, "anvil") ~= 0 then msg = S("@1 was smashed by a falling anvil.", v:get_player_name()) @@ -56,8 +67,35 @@ local deal_falling_damage = function(self, dtime) if dmes then mcl_death_messages.player_damage(v, msg) end + v:set_hp(hp, { type = "punch", from = "mod" }) + end + end + end + else + local hp = v:get_luaentity().health + if hp and hp ~= 0 then + if not self._hit_mobs then + self._hit_mobs = {} + end + local hit = false + for _,mob in ipairs(self._hit_mobs) do + if v == mob then + hit = true + end + end + --TODO: reduce damage for mobs then they will be able to wear armor + if not hit then + table.insert(self._hit_mobs, v) + local way = self._startpos.y - pos.y + local damage = (way - 1) * 2 + damage = math.min(40, math.max(0, damage)) + if damage >= 1 then + hp = hp - damage + if hp < 0 then + hp = 0 + end + v:get_luaentity().health = hp end - v:set_hp(hp, { type = "punch", from = "mod" }) end end end diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 7cea5a91c..95b90e546 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -1,3 +1,7 @@ +local has_awards = minetest.get_modpath("awards") + +mcl_item_entity = {} + --basic settings local item_drop_settings = {} --settings table item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting @@ -16,16 +20,33 @@ local get_gravity = function() return tonumber(minetest.settings:get("movement_gravity")) or 9.81 end +local registered_pickup_achievement = {} + +--TODO: remove limitation of 1 award per itemname +function mcl_item_entity.register_pickup_achievement(itemname, award) + if not has_awards then + minetest.log("warning", "[mcl_item_entity] Trying to register pickup achievement ["..award.."] for ["..itemname.."] while awards missing") + elseif registered_pickup_achievement[itemname] then + minetest.log("error", "[mcl_item_entity] Trying to register already existing pickup achievement ["..award.."] for ["..itemname.."]") + else + registered_pickup_achievement[itemname] = award + end +end + +mcl_item_entity.register_pickup_achievement("tree", "mcl:mineWood") +mcl_item_entity.register_pickup_achievement("mcl_mobitems:blaze_rod", "mcl:blazeRod") +mcl_item_entity.register_pickup_achievement("mcl_mobitems:leather", "mcl:killCow") +mcl_item_entity.register_pickup_achievement("mcl_core:diamond", "mcl:diamonds") + local check_pickup_achievements = function(object, player) - local itemname = ItemStack(object:get_luaentity().itemstring):get_name() - if minetest.get_item_group(itemname, "tree") ~= 0 then - awards.unlock(player:get_player_name(), "mcl:mineWood") - elseif itemname == "mcl_mobitems:blaze_rod" then - awards.unlock(player:get_player_name(), "mcl:blazeRod") - elseif itemname == "mcl_mobitems:leather" then - awards.unlock(player:get_player_name(), "mcl:killCow") - elseif itemname == "mcl_core:diamond" then - awards.unlock(player:get_player_name(), "mcl:diamonds") + if has_awards then + local itemname = ItemStack(object:get_luaentity().itemstring):get_name() + local playername = player:get_player_name() + for name,award in pairs(registered_pickup_achievement) do + if itemname == name or minetest.get_item_group(itemname, name) ~= 0 then + awards.unlock(playername, award) + end + end end end @@ -165,10 +186,6 @@ minetest.register_globalstep(function(dtime) end end) -local minigroups = { "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" } -local basegroups = { "pickaxey", "axey", "shovely" } -local materials = { "wood", "gold", "stone", "iron", "diamond" } - -- Stupid workaround to get drops from a drop table: -- Create a temporary table in minetest.registered_nodes that contains the proper drops, -- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 9c61fa5ed..70bf16477 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -1,5 +1,7 @@ local S = minetest.get_translator("mcl_minecarts") +local has_mcl_wip = minetest.get_modpath("mcl_wip") + mcl_minecarts = {} mcl_minecarts.modpath = minetest.get_modpath("mcl_minecarts") mcl_minecarts.speed_max = 10 @@ -662,8 +664,6 @@ register_minecart( "mcl_minecarts_minecart_chest.png", {"mcl_minecarts:minecart", "mcl_chests:chest"}, nil, nil, false) - -mcl_wip.register_wip_item("mcl_minecarts:chest_minecart") -- Minecart with Furnace register_minecart( @@ -719,8 +719,6 @@ register_minecart( end, nil, false ) -mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart") - -- Minecart with Command Block register_minecart( "mcl_minecarts:command_block_minecart", @@ -742,8 +740,6 @@ register_minecart( nil, nil, false ) -mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart") - -- Minecart with Hopper register_minecart( "mcl_minecarts:hopper_minecart", @@ -762,8 +758,6 @@ register_minecart( nil, nil, false ) -mcl_wip.register_wip_item("mcl_minecarts:hopper_minecart") - -- Minecart with TNT register_minecart( "mcl_minecarts:tnt_minecart", @@ -824,29 +818,34 @@ minetest.register_craft({ -- TODO: Re-enable crafting of special minecarts when they have been implemented if false then + minetest.register_craft({ + output = "mcl_minecarts:furnace_minecart", + recipe = { + {"mcl_furnaces:furnace"}, + {"mcl_minecarts:minecart"}, + }, + }) -minetest.register_craft({ - output = "mcl_minecarts:furnace_minecart", - recipe = { - {"mcl_furnaces:furnace"}, - {"mcl_minecarts:minecart"}, - }, -}) - -minetest.register_craft({ - output = "mcl_minecarts:hopper_minecart", - recipe = { - {"mcl_hoppers:hopper"}, - {"mcl_minecarts:minecart"}, - }, -}) - -minetest.register_craft({ - output = "mcl_minecarts:chest_minecart", - recipe = { - {"mcl_chests:chest"}, - {"mcl_minecarts:minecart"}, - }, -}) + minetest.register_craft({ + output = "mcl_minecarts:hopper_minecart", + recipe = { + {"mcl_hoppers:hopper"}, + {"mcl_minecarts:minecart"}, + }, + }) + minetest.register_craft({ + output = "mcl_minecarts:chest_minecart", + recipe = { + {"mcl_chests:chest"}, + {"mcl_minecarts:minecart"}, + }, + }) end + +if has_mcl_wip then + mcl_wip.register_wip_item("mcl_minecarts:chest_minecart") + mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart") + mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart") + mcl_wip.register_wip_item("mcl_minecarts:hopper_minecart") +end \ No newline at end of file diff --git a/mods/ENTITIES/mcl_minecarts/mod.conf b/mods/ENTITIES/mcl_minecarts/mod.conf index 138fd18e6..9fff9175d 100644 --- a/mods/ENTITIES/mcl_minecarts/mod.conf +++ b/mods/ENTITIES/mcl_minecarts/mod.conf @@ -1,6 +1,6 @@ name = mcl_minecarts author = Krock description = Minecarts are vehicles to move players quickly on rails. -depends = mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons, mcl_wip -optional_depends = doc_identifier +depends = mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons +optional_depends = doc_identifier, mcl_wip diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 3b929a119..f1df87e8b 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -283,6 +283,33 @@ local get_velocity = function(self) return 0 end +local function update_roll(self) + local is_Fleckenstein = self.nametag == "Fleckenstein" + local was_Fleckenstein = false + + local rot = self.object:get_rotation() + rot.z = is_Fleckenstein and pi or 0 + self.object:set_rotation(rot) + + local cbox = table.copy(self.collisionbox) + local acbox = self.object:get_properties().collisionbox + + if math.abs(cbox[2] - acbox[2]) > 0.1 then + was_Fleckenstein = true + end + + if is_Fleckenstein ~= was_Fleckenstein then + local pos = self.object:get_pos() + pos.y = pos.y + (acbox[2] + acbox[5]) + self.object:set_pos(pos) + end + + if is_Fleckenstein then + cbox[2], cbox[5] = -cbox[5], -cbox[2] + end + + self.object:set_properties({collisionbox = cbox}) +end -- set and return valid yaw local set_yaw = function(self, yaw, delay, dtime) @@ -298,6 +325,7 @@ local set_yaw = function(self, yaw, delay, dtime) yaw = yaw + (math.random() * 2 - 1) * 5 * dtime end self.object:set_yaw(yaw) + update_roll(self) return yaw end @@ -645,9 +673,9 @@ local update_tag = function(self) nametag = tag, }) + update_roll(self) end - -- drop items local item_drop = function(self, cooked, looting_level) @@ -2826,7 +2854,7 @@ local falling = function(self, pos) end if mcl_portals ~= nil then - if mcl_portals.nether_portal_cooloff[self.object] then + if mcl_portals.nether_portal_cooloff(self.object) then return false -- mob has teleported through Nether portal - it's 99% not falling end end @@ -2856,6 +2884,18 @@ local falling = function(self, pos) self.object:set_acceleration({x = 0, y = 0, z = 0}) end + if minetest.registered_nodes[node_ok(pos).name].groups.lava then + + if self.floats_on_lava == 1 then + + self.object:set_acceleration({ + x = 0, + y = -self.fall_speed / (max(1, v.y) ^ 2), + z = 0 + }) + end + end + -- in water then float up if minetest.registered_nodes[node_ok(pos).name].groups.water then @@ -3475,6 +3515,7 @@ local mob_step = function(self, dtime) yaw = yaw + (math.random() * 2 - 1) * 5 * dtime end self.object:set_yaw(yaw) + update_roll(self) end -- end rotation @@ -3773,6 +3814,7 @@ minetest.register_entity(name, { knock_back = def.knock_back ~= false, shoot_offset = def.shoot_offset or 0, floats = def.floats or 1, -- floats in water by default + floats_on_lava = def.floats_on_lava or 0, replace_rate = def.replace_rate, replace_what = def.replace_what, replace_with = def.replace_with, diff --git a/mods/ENTITIES/mobs_mc/1_items_default.lua b/mods/ENTITIES/mobs_mc/1_items_default.lua index ddcc290c7..b4abd4f9c 100644 --- a/mods/ENTITIES/mobs_mc/1_items_default.lua +++ b/mods/ENTITIES/mobs_mc/1_items_default.lua @@ -521,7 +521,7 @@ if c("totem") then -- Totem of Undying minetest.register_craftitem("mobs_mc:totem", { description = S("Totem of Undying"), - _tt_help = minetest.colorize("#00FF00", S("Protects you from death while wielding it")), + _tt_help = minetest.colorize(mcl_colors.GREEN, S("Protects you from death while wielding it")), _doc_items_longdesc = S("A totem of undying is a rare artifact which may safe you from certain death."), _doc_items_usagehelp = S("The totem only works while you hold it in your hand. If you receive fatal damage, you are saved from death and you get a second chance with 1 HP. The totem is destroyed in the process, however."), inventory_image = "mcl_totems_totem.png", diff --git a/mods/ENTITIES/mobs_mc/mod.conf b/mods/ENTITIES/mobs_mc/mod.conf index 98f48b388..a3057faff 100644 --- a/mods/ENTITIES/mobs_mc/mod.conf +++ b/mods/ENTITIES/mobs_mc/mod.conf @@ -1,6 +1,6 @@ name = mobs_mc author = maikerumine description = Adds Minecraft-like monsters and animals. -depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip +depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip, mcl_colors optional_depends = default, mcl_tnt, mcl_bows, mcl_throwing, mcl_fishing, bones, mesecons_materials, mobs_mc_gameconfig, doc_items diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 681c68e1b..84650b4dd 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -25,6 +25,19 @@ local colors = { unicolor_black = { mobs_mc.items.wool_black, "#000000D0" }, } +local rainbow_colors = { + "unicolor_light_red", + "unicolor_red", + "unicolor_orange", + "unicolor_yellow", + "unicolor_green", + "unicolor_dark_green", + "unicolor_light_blue", + "unicolor_blue", + "unicolor_violet", + "unicolor_red_violet" +} + if minetest.get_modpath("mcl_wool") ~= nil then colors["unicolor_light_blue"] = { mobs_mc.items.wool_light_blue, "#5050FFD0" } end @@ -112,7 +125,7 @@ mobs:register_mob("mobs_mc:sheep", { end, -- Set random color on spawn - do_custom = function(self) + do_custom = function(self, dtime) if not self.initial_color_set then local r = math.random(0,100000) local textures @@ -149,8 +162,35 @@ mobs:register_mob("mobs_mc:sheep", { } self.initial_color_set = true end + + local is_kay27 = self.nametag == "kay27" + + if self.color_change_timer then + local old_color = self.color + if is_kay27 then + self.color_change_timer = self.color_change_timer - dtime + if self.color_change_timer < 0 then + self.color_change_timer = 0.5 + self.color_index = (self.color_index + 1) % #rainbow_colors + self.color = rainbow_colors[self.color_index + 1] + end + else + self.color_change_timer = nil + self.color_index = nil + self.color = self.initial_color + end + + if old_color ~= self.color then + self.base_texture = sheep_texture(self.color) + self.object:set_properties({textures = self.base_texture}) + end + elseif is_kay27 then + self.initial_color = self.color + self.color_change_timer = 0 + self.color_index = -1 + end end, - + on_rightclick = function(self, clicker) local item = clicker:get_wielded_item() diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 54269b46e..7c21fb812 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -109,7 +109,6 @@ local slime_big = { fear_height = 0, spawn_small_alternative = "mobs_mc:slime_small", on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5), - fire_resistant = true, use_texture_alpha = true, } mobs:register_mob("mobs_mc:slime_big", slime_big) diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg new file mode 100644 index 000000000..9c56b0f65 Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg new file mode 100644 index 000000000..bafc77b7e Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.3.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.3.ogg new file mode 100644 index 000000000..9e5c79b6d Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.3.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg new file mode 100644 index 000000000..5c9ee492b Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg new file mode 100644 index 000000000..acb236445 Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg new file mode 100644 index 000000000..1ef7a5227 Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg differ diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg new file mode 100644 index 000000000..c2743fbcc Binary files /dev/null and b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg differ diff --git a/mods/ENTITIES/mobs_mc/textures/mobs_mc_wither_half_health.png b/mods/ENTITIES/mobs_mc/textures/mobs_mc_wither_half_health.png new file mode 100644 index 000000000..f6353400c Binary files /dev/null and b/mods/ENTITIES/mobs_mc/textures/mobs_mc_wither_half_health.png differ diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index a38c78719..68644266f 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -516,7 +516,7 @@ local function show_trade_formspec(playername, trader, tradenum) "size[9,8.75]" .."background[-0.19,-0.25;9.41,9.49;mobs_mc_trading_formspec_bg.png]" ..disabled_img - .."label[4,0;"..F(minetest.colorize("#313131", S(profession))).."]" + .."label[4,0;"..F(minetest.colorize(mcl_colors.DARK_GRAY, S(profession))).."]" .."list[current_player;main;0,4.5;9,3;9]" .."list[current_player;main;0,7.74;9,1;]" ..b_prev..b_next @@ -967,6 +967,10 @@ mobs:register_mob("mobs_mc:villager", { drops = {}, can_despawn = false, -- TODO: sounds + sounds = { + random = "mobs_mc_villager", + distance = 10, + }, animation = { stand_speed = 25, stand_start = 40, diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index 3fbf65955..caf5a248d 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -16,7 +16,7 @@ mobs:register_mob("mobs_mc:wither", { hp_min = 300, xp_min = 50, xp_max = 50, - armor = {undead = 80, fleshy = 80}, + armor = {undead = 80, fleshy = 100}, -- This deviates from MC Wiki's size, which makes no sense collisionbox = {-0.9, 0.4, -0.9, 0.9, 2.45, 0.9}, visual = "mesh", @@ -66,6 +66,14 @@ mobs:register_mob("mobs_mc:wither", { run_start = 0, run_end = 20, }, harmed_by_heal = true, + do_custom = function(self) + if self.health < (self.hp_max / 2) then + self.base_texture = "mobs_mc_wither_half_health.png" + self.fly = false + self.object:set_properties({textures={self.base_texture}}) + self.armor = {undead = 80, fleshy = 80} + end + end, on_spawn = function(self) minetest.sound_play("mobs_mc_wither_spawn", {object=self.object, gain=1.0, max_hear_distance=64}) end, diff --git a/mods/ENVIRONMENT/mcl_weather/weather_core.lua b/mods/ENVIRONMENT/mcl_weather/weather_core.lua index 365f6e549..d3772dc7e 100644 --- a/mods/ENVIRONMENT/mcl_weather/weather_core.lua +++ b/mods/ENVIRONMENT/mcl_weather/weather_core.lua @@ -38,6 +38,7 @@ mcl_weather.reg_weathers["none"] = { local storage = minetest.get_mod_storage() -- Save weather into mod storage, so it can be loaded after restarting the server local save_weather = function() + if not mcl_weather.end_time then return end storage:set_string("mcl_weather_state", mcl_weather.state) storage:set_int("mcl_weather_end_time", mcl_weather.end_time) minetest.log("verbose", "[mcl_weather] Weather data saved: state="..mcl_weather.state.." end_time="..mcl_weather.end_time) diff --git a/mods/HELP/doc/doc/init.lua b/mods/HELP/doc/doc/init.lua index 360cc149c..9057cda8e 100644 --- a/mods/HELP/doc/doc/init.lua +++ b/mods/HELP/doc/doc/init.lua @@ -1,13 +1,7 @@ local S = minetest.get_translator("doc") local F = function(f) return minetest.formspec_escape(S(f)) end --- Compability for 0.4.14 or earlier -local colorize -if minetest.colorize then - colorize = minetest.colorize -else - colorize = function(color, text) return text end -end +local colorize = minetest.colorize doc = {} @@ -41,10 +35,10 @@ doc.FORMSPEC.ENTRY_HEIGHT = doc.FORMSPEC.ENTRY_END_Y - doc.FORMSPEC.ENTRY_START_ -- Internal helper variables local DOC_INTRO = S("This is the help.") -local COLOR_NOT_VIEWED = "#00FFFF" -- cyan -local COLOR_VIEWED = "#FFFFFF" -- white -local COLOR_HIDDEN = "#999999" -- gray -local COLOR_ERROR = "#FF0000" -- red +local COLOR_NOT_VIEWED = mcl_colors.AQUA +local COLOR_VIEWED = mcl_colors.WHITE +local COLOR_HIDDEN = mcl_colors.GRAY +local COLOR_ERROR = mcl_colors.RED local CATEGORYFIELDSIZE = { WIDTH = math.ceil(doc.FORMSPEC.WIDTH / 4), @@ -776,7 +770,7 @@ function doc.generate_entry_list(cid, playername) if name == nil or name == "" then name = S("Nameless entry (@1)", eid) if doc.entry_viewed(playername, cid, eid) then - viewedprefix = "#FF4444" + viewedprefix = mcl_colors.RED else viewedprefix = COLOR_ERROR end diff --git a/mods/HELP/doc/doc/mod.conf b/mods/HELP/doc/doc/mod.conf index 0f65ddff7..54064551b 100644 --- a/mods/HELP/doc/doc/mod.conf +++ b/mods/HELP/doc/doc/mod.conf @@ -2,3 +2,4 @@ name = doc author = Wuzzy description = A simple in-game documentation system which enables mods to add help entries based on templates. optional_depends = unified_inventory, sfinv_buttons, central_message, inventory_plus +depends = mcl_colors diff --git a/mods/HELP/mcl_craftguide/init.lua b/mods/HELP/mcl_craftguide/init.lua index eb98bcce0..829fc4181 100644 --- a/mods/HELP/mcl_craftguide/init.lua +++ b/mods/HELP/mcl_craftguide/init.lua @@ -410,7 +410,7 @@ local function get_tooltip(item, groups, cooktime, burntime) local tooltip if groups then - local gcol = "#FFAAFF" + local gcol = mcl_colors.LIGHT_PURPLE if #groups == 1 then local g = group_names[groups[1]] local groupstr @@ -446,12 +446,12 @@ local function get_tooltip(item, groups, cooktime, burntime) if not groups and cooktime then tooltip = tooltip .. "\n" .. - S("Cooking time: @1", colorize("yellow", cooktime)) + S("Cooking time: @1", colorize(mcl_colors.YELLOW, cooktime)) end if not groups and burntime then tooltip = tooltip .. "\n" .. - S("Burning time: @1", colorize("yellow", burntime)) + S("Burning time: @1", colorize(mcl_colors.YELLOW, burntime)) end return fmt(FMT.tooltip, item, ESC(tooltip)) @@ -668,7 +668,7 @@ local function make_formspec(name) fs[#fs + 1] = fmt("label[%f,%f;%s]", sfinv_only and 6.3 or data.iX - 2.2, 0.22, - ESC(colorize("#383838", fmt("%s / %u", data.pagenum, data.pagemax)))) + ESC(colorize(mcl_colors.DARK_GRAY, fmt("%s / %u", data.pagenum, data.pagemax)))) fs[#fs + 1] = fmt([[ image_button[%f,0.12;0.8,0.8;craftguide_prev_icon.png;prev;] diff --git a/mods/HELP/mcl_craftguide/mod.conf b/mods/HELP/mcl_craftguide/mod.conf index b7ab8882c..ce99c0e32 100644 --- a/mods/HELP/mcl_craftguide/mod.conf +++ b/mods/HELP/mcl_craftguide/mod.conf @@ -1,5 +1,5 @@ name = mcl_craftguide author = kilbith description = The most comprehensive Crafting Guide on Minetest. -depends = mcl_core, mcl_compass, mcl_clock, doc +depends = mcl_core, mcl_compass, mcl_clock, doc, mcl_colors optional_depends = sfinv, sfinv_buttons diff --git a/mods/HELP/mcl_tt/mod.conf b/mods/HELP/mcl_tt/mod.conf index 3a33b70dc..e442e1320 100644 --- a/mods/HELP/mcl_tt/mod.conf +++ b/mods/HELP/mcl_tt/mod.conf @@ -1,4 +1,4 @@ name = mcl_tt author = Wuzzy description = Add MCL2 tooltips -depends = tt, mcl_enchanting +depends = tt, mcl_enchanting, mcl_colors diff --git a/mods/HELP/mcl_tt/snippets_mcl.lua b/mods/HELP/mcl_tt/snippets_mcl.lua index 6e2803502..3d13df751 100644 --- a/mods/HELP/mcl_tt/snippets_mcl.lua +++ b/mods/HELP/mcl_tt/snippets_mcl.lua @@ -77,7 +77,7 @@ end) tt.register_snippet(function(itemstring) local def = minetest.registered_items[itemstring] if minetest.get_item_group(itemstring, "crush_after_fall") == 1 then - return S("Deals damage when falling"), "#FFFF00" + return S("Deals damage when falling"), mcl_colors.YELLOW end end) diff --git a/mods/HELP/tt/init.lua b/mods/HELP/tt/init.lua index f23778b6c..afc421e4f 100644 --- a/mods/HELP/tt/init.lua +++ b/mods/HELP/tt/init.lua @@ -1,7 +1,8 @@ tt = {} -tt.COLOR_DEFAULT = "#d0ffd0" -tt.COLOR_DANGER = "#ffff00" -tt.COLOR_GOOD = "#00ff00" +tt.COLOR_DEFAULT = mcl_colors.GREEN +tt.COLOR_DANGER = mcl_colors.YELLOW +tt.COLOR_GOOD = mcl_colors.GREEN +tt.NAME_COLOR = mcl_colors.YELLOW -- API tt.registered_snippets = {} @@ -63,12 +64,15 @@ tt.reload_itemstack_description = function(itemstack) local meta = itemstack:get_meta() if def and def._mcl_generate_description then def._mcl_generate_description(itemstack) - elseif should_change(itemstring, def) and meta:get_string("name") == "" then + elseif should_change(itemstring, def) then local toolcaps if def.tool_capabilities then toolcaps = itemstack:get_tool_capabilities() end local orig_desc = def._tt_original_description or def.description + if meta:get_string("name") ~= "" then + orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name")) + end local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack) if desc ~= orig_desc then meta:set_string("description", desc) diff --git a/mods/HELP/tt/mod.conf b/mods/HELP/tt/mod.conf index 23ce15369..2a260772d 100644 --- a/mods/HELP/tt/mod.conf +++ b/mods/HELP/tt/mod.conf @@ -1,3 +1,4 @@ name = tt author = Wuzzy description = Support for custom tooltip extensions for items +depends = mcl_colors diff --git a/mods/HUD/awards/api.lua b/mods/HUD/awards/api.lua index 9b0261b65..6601dd626 100644 --- a/mods/HUD/awards/api.lua +++ b/mods/HUD/awards/api.lua @@ -214,7 +214,7 @@ function awards.unlock(name, award) -- Get award minetest.log("action", name.." has gotten award "..award) - minetest.chat_send_all(S("@1 has made the achievement @2", name, minetest.colorize("#51EF4E", "[" .. (awdef.title or award) .. "]"))) + minetest.chat_send_all(S("@1 has made the achievement @2", name, minetest.colorize(mcl_colors.GREEN, "[" .. (awdef.title or award) .. "]"))) data.unlocked[award] = award awards.save() @@ -447,7 +447,7 @@ function awards.getFormspec(name, to, sid) first = false if def.secret and not award.got then - formspec = formspec .. "#707070"..minetest.formspec_escape(S("(Secret Award)")) + formspec = formspec .. mcl_colors.DARK_GRAY..minetest.formspec_escape(S("(Secret Award)")) else local title = award.name if def and def.title then @@ -456,7 +456,7 @@ function awards.getFormspec(name, to, sid) if award.got then formspec = formspec .. minetest.formspec_escape(title) else - formspec = formspec .. "#ACACAC".. minetest.formspec_escape(title) + formspec = formspec .. mcl_colors.GRAY.. minetest.formspec_escape(title) end end end diff --git a/mods/HUD/awards/mod.conf b/mods/HUD/awards/mod.conf index 8b1534692..1657323e2 100644 --- a/mods/HUD/awards/mod.conf +++ b/mods/HUD/awards/mod.conf @@ -6,3 +6,4 @@ license = LGPL 2.1 or later forum = https://forum.minetest.net/viewtopic.php?t=4870 version = 2.3.0 optional_depends = sfinv, unified_inventory +depends = mcl_colors diff --git a/mods/HUD/mcl_achievements/init.lua b/mods/HUD/mcl_achievements/init.lua index 7473568d2..2f1db1fe6 100644 --- a/mods/HUD/mcl_achievements/init.lua +++ b/mods/HUD/mcl_achievements/init.lua @@ -238,3 +238,20 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) awards.show_to(name, name, nil, false) end end) + + +awards.register_achievement("mcl:stoneAge", { + title = S("Stone Age"), + description = S("Mine a stone with new pickaxe."), + icon = "default_cobble.png", +}) +awards.register_achievement("mcl:hotStuff", { + title = S("Hot Stuff"), + description = S("Put lava in a bucket."), + icon = "bucket_lava.png", +}) +awards.register_achievement("mcl:obsidian", { + title = S("Ice Bucket Challenge"), + description = S("Obtain an obsidian block."), + icon = "default_obsidian.png", +}) diff --git a/mods/HUD/mcl_death_messages/init.lua b/mods/HUD/mcl_death_messages/init.lua index b2c656ac4..8ca686701 100644 --- a/mods/HUD/mcl_death_messages/init.lua +++ b/mods/HUD/mcl_death_messages/init.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator("mcl_death_messages") local N = function(s) return s end +local C = minetest.colorize + +local color_skyblue = mcl_colors.AQUA local function get_tool_name(item) local name = item:get_meta():get_string("name") @@ -41,6 +44,9 @@ local msgs = { ["murder"] = { N("@1 was slain by @2 using [@3]"), }, + ["murder_hand"] = { + N("@1 was slain by @2"), + }, ["murder_any"] = { N("@1 was killed."), }, @@ -131,7 +137,7 @@ local last_damages = { } minetest.register_on_dieplayer(function(player, reason) -- Death message - local message = minetest.settings:get_bool("mcl_showDeathMessages") + local message = minetest.settings:get_bool("mcl_showDeathMessages") --Maybe cache the setting? if message == nil then message = true end @@ -201,7 +207,11 @@ minetest.register_on_dieplayer(function(player, reason) elseif hitter:is_player() then hittername = hitter:get_player_name() if hittername ~= nil then - msg = dmsg("murder", name, hittername, minetest.colorize("#00FFFF", hitter_toolname)) + if hitter_toolname == "" then + msg = dmsg("murder_hand", name, hittername) + else + msg = dmsg("murder", name, hittername, C(color_skyblue, hitter_toolname)) + end else msg = dmsg("murder_any", name) end @@ -229,7 +239,7 @@ minetest.register_on_dieplayer(function(player, reason) if shooter == nil then msg = dmsg("arrow", name) elseif shooter:is_player() then - msg = dmsg("arrow_name", name, shooter:get_player_name(), minetest.colorize("#00FFFF", get_tool_name(shooter:get_wielded_item()))) + msg = dmsg("arrow_name", name, shooter:get_player_name(), C(color_skyblue, get_tool_name(shooter:get_wielded_item()))) elseif s_ent and s_ent._cmi_is_mob then if s_ent.nametag ~= "" then msg = dmsg("arrow_name", name, shooter:get_player_name(), get_tool_name(shooter:get_wielded_item())) diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr index b9ef6680d..ffb567b8b 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Ein Ghast hat @1 zu Tode erschrocken. @1 was killed by a baby husk.=@1 wurde von einem Wüstenzombiebaby getötet. @1 was killed by a zombie pigman.=@1 wurde von einem Schweinezombie getötet. @1 was killed by a baby zombie pigman.=@1 wurde von einem Schweinezombiebaby getötet. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr index 6ed106db8..a56199e00 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr @@ -55,3 +55,4 @@ A ghast scared @1 to death.=Se ha asustado @1 hasta morir. @1 was killed by a baby husk.=@1 fue asesinado por un bebé husk. @1 was killed by a zombie pigman.=@1 fue asesinado por un cerdo zombie. @1 was killed by a baby zombie pigman.=@1 fue asesinado por un bebé cerdo zombie. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr index 6d0a5115c..05cf99976 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Un ghast a éffrayé @1 à mort. @1 was killed by a baby husk.=@1 a été tué par un bébé zombie momie. @1 was killed by a zombie pigman.=@1 a été tué par un zombie-couchon. @1 was killed by a baby zombie pigman.=@1 a été tué par un bébé zombie-couchon +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr index f9f164dd3..d5b6ec396 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Гаст напугал @1 до смерти. @1 was killed by a baby husk.=@1 был(а) убит(а) машылом-кадавром. @1 was killed by a zombie pigman.=@1 был(а) убит(а) зомби-свиночеловеком. @1 was killed by a baby zombie pigman.=@1 был(а) убит(а) малышом-зомби-свиночеловеком. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/template.txt b/mods/HUD/mcl_death_messages/locale/template.txt index db074f756..d1e3b832b 100644 --- a/mods/HUD/mcl_death_messages/locale/template.txt +++ b/mods/HUD/mcl_death_messages/locale/template.txt @@ -56,3 +56,4 @@ A ghast scared @1 to death.= @1 was killed by a baby husk.= @1 was killed by a zombie pigman.= @1 was killed by a baby zombie pigman.= +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/mod.conf b/mods/HUD/mcl_death_messages/mod.conf index 23d2852e7..a634e16de 100644 --- a/mods/HUD/mcl_death_messages/mod.conf +++ b/mods/HUD/mcl_death_messages/mod.conf @@ -1,3 +1,4 @@ name = mcl_death_messages author = 4Evergreen4 description = Shows messages in chat when a player dies. +depends = mcl_colors diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index 1cebed0cd..a69fcef5b 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -442,7 +442,7 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz end local caption = "" if name ~= "inv" and filtername[name] then - caption = "label[0,1.2;"..F(minetest.colorize("#313131", filtername[name])).."]" + caption = "label[0,1.2;"..F(minetest.colorize(mcl_colors.DARK_GRAY, filtername[name])).."]" end formspec = "size[10,9.3]".. @@ -489,8 +489,8 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz if filter == nil then filter = "" end - formspec = formspec .. "field[5.3,1.34;4,0.75;suche;;"..minetest.formspec_escape(filter).."]" - formspec = formspec .. "field_close_on_enter[suche;false]" + formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]" + formspec = formspec .. "field_close_on_enter[search;false]" end if pagenum ~= nil then formspec = formspec .. "p"..tostring(pagenum) end @@ -561,11 +561,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) elseif fields.inv then if players[name].page == "inv" then return end page = "inv" - elseif fields.suche == "" and not fields.creative_next and not fields.creative_prev then + elseif fields.search == "" and not fields.creative_next and not fields.creative_prev then set_inv_page("all", player) page = "nix" - elseif fields.suche ~= nil and not fields.creative_next and not fields.creative_prev then - set_inv_search(string.lower(fields.suche),player) + elseif fields.search ~= nil and not fields.creative_next and not fields.creative_prev then + set_inv_search(string.lower(fields.search),player) page = "nix" end @@ -612,8 +612,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) players[name].start_i = start_i local filter = "" - if not fields.nix and fields.suche ~= nil and fields.suche ~= "" then - filter = fields.suche + if not fields.nix and fields.search ~= nil and fields.search ~= "" then + filter = fields.search players[name].filter = filter end diff --git a/mods/HUD/mcl_inventory/init.lua b/mods/HUD/mcl_inventory/init.lua index 054424051..e9da9486e 100644 --- a/mods/HUD/mcl_inventory/init.lua +++ b/mods/HUD/mcl_inventory/init.lua @@ -109,10 +109,10 @@ local function set_inventory(player, armor_change_only) mcl_formspec.get_itemslot_bg(0,3,1,1).. armor_slot_imgs.. -- craft and inventory - "label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4;"..F(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. "list[current_player;main;0,7.74;9,1;]".. - "label[4,0.5;"..F(minetest.colorize("#313131", S("Crafting"))).."]".. + "label[4,0.5;"..F(minetest.colorize(mcl_colors.DARK_GRAY, S("Crafting"))).."]".. "list[current_player;craft;4,1;2,2]".. "list[current_player;craftpreview;7,1.5;1,1;]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. diff --git a/mods/HUD/mcl_inventory/mod.conf b/mods/HUD/mcl_inventory/mod.conf index fa6b2c2f4..edd6343c7 100644 --- a/mods/HUD/mcl_inventory/mod.conf +++ b/mods/HUD/mcl_inventory/mod.conf @@ -1,6 +1,6 @@ name = mcl_inventory author = BlockMen description = Adds the player inventory and creative inventory. -depends = mcl_init, mcl_formspec +depends = mcl_init, mcl_formspec, mcl_colors optional_depends = mcl_player, _mcl_autogroup, mcl_armor, mcl_brewing, mcl_potions, mcl_enchanting diff --git a/mods/HUD/mcl_tmp_message/API.md b/mods/HUD/mcl_tmp_message/API.md new file mode 100644 index 000000000..0a3fc06a3 --- /dev/null +++ b/mods/HUD/mcl_tmp_message/API.md @@ -0,0 +1,7 @@ +# mcl_temp_message + +Allow mods to show short messages in the hud of players. + +## mcl_tmp_message.message(player, message) + +Show above the hotbar a hud message to player . \ No newline at end of file diff --git a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua index b6d0d2ef6..1fd63cb4d 100644 --- a/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_dispensers/init.lua @@ -13,12 +13,12 @@ local S = minetest.get_translator("mcl_dispensers") local setup_dispenser = function(pos) -- Set formspec and inventory local form = "size[9,8.75]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg(0,7.74,9,1).. - "label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dispenser"))).."]".. + "label[3,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Dispenser"))).."]".. "list[current_name;main;3,0.5;3,3;]".. mcl_formspec.get_itemslot_bg(3,0.5,3,3).. "listring[current_name;main]".. diff --git a/mods/ITEMS/REDSTONE/mcl_dispensers/mod.conf b/mods/ITEMS/REDSTONE/mcl_dispensers/mod.conf index 13cdb5f5a..ac1b56c7d 100644 --- a/mods/ITEMS/REDSTONE/mcl_dispensers/mod.conf +++ b/mods/ITEMS/REDSTONE/mcl_dispensers/mod.conf @@ -1,3 +1,3 @@ name = mcl_dispensers -depends = mcl_init, mcl_formspec, mesecons, mcl_sounds, mcl_tnt, mcl_worlds, mcl_core, mcl_nether, mcl_armor_stand, mcl_armor +depends = mcl_init, mcl_formspec, mesecons, mcl_sounds, mcl_tnt, mcl_worlds, mcl_core, mcl_nether, mcl_armor_stand, mcl_armor, mcl_colors optional_depends = doc, screwdriver diff --git a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua index 715a85f3d..0d41c3552 100644 --- a/mods/ITEMS/REDSTONE/mcl_droppers/init.lua +++ b/mods/ITEMS/REDSTONE/mcl_droppers/init.lua @@ -14,12 +14,12 @@ local S = minetest.get_translator("mcl_droppers") local setup_dropper = function(pos) -- Set formspec and inventory local form = "size[9,8.75]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg(0,7.74,9,1).. - "label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dropper"))).."]".. + "label[3,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Dropper"))).."]".. "list[current_name;main;3,0.5;3,3;]".. mcl_formspec.get_itemslot_bg(3,0.5,3,3).. "listring[current_name;main]".. diff --git a/mods/ITEMS/REDSTONE/mcl_droppers/init_new.lua b/mods/ITEMS/REDSTONE/mcl_droppers/init_new.lua index 1bf968a82..b41d9c2fe 100644 --- a/mods/ITEMS/REDSTONE/mcl_droppers/init_new.lua +++ b/mods/ITEMS/REDSTONE/mcl_droppers/init_new.lua @@ -15,10 +15,10 @@ local setup_dropper = function(pos) -- Set formspec and inventory local form = "size[9,8.75]".. "background[-0.19,-0.25;9.41,9.49;crafting_inventory_9_slots.png]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. "list[current_player;main;0,7.74;9,1;]".. - "label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dropper"))).."]".. + "label[3,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Dropper"))).."]".. "list[current_name;main;3,0.5;3,3;]".. "listring[current_name;main]".. "listring[current_player;main]" diff --git a/mods/ITEMS/REDSTONE/mcl_droppers/mod.conf b/mods/ITEMS/REDSTONE/mcl_droppers/mod.conf index bbb1c19f2..b5cf8f0b7 100644 --- a/mods/ITEMS/REDSTONE/mcl_droppers/mod.conf +++ b/mods/ITEMS/REDSTONE/mcl_droppers/mod.conf @@ -1,3 +1,3 @@ name = mcl_droppers -depends = mcl_init, mcl_formspec, mesecons, mcl_util +depends = mcl_init, mcl_formspec, mesecons, mcl_util, mcl_colors optional_depends = doc, screwdriver diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index c5c3b3dc8..1928f809c 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -1,6 +1,11 @@ local S = minetest.get_translator("mesecons_commandblock") local F = minetest.formspec_escape +local color_red = mcl_colors.RED + +local command_blocks_activated = minetest.settings:get_bool("mcl_enable_commandblocks", true) +local msg_not_activated = S("Command blocks are not enabled on this server") + local function construct(pos) local meta = minetest.get_meta(pos) @@ -78,7 +83,7 @@ local function check_commands(commands, player_name) if string.sub(cmd, 1, 1) == "/" then msg = S("Error: The command “@1” does not exist; your command block has not been changed. Use the “help” chat command for a list of available commands. Hint: Try to remove the leading slash.", cmd) end - return false, minetest.colorize("#FF0000", msg) + return false, minetest.colorize(color_red, msg) end if player_name then local player_privs = minetest.get_player_privs(player_name) @@ -86,7 +91,7 @@ local function check_commands(commands, player_name) for cmd_priv, _ in pairs(cmddef.privs) do if player_privs[cmd_priv] ~= true then local msg = S("Error: You have insufficient privileges to use the command “@1” (missing privilege: @2)! The command block has not been changed.", cmd, cmd_priv) - return false, minetest.colorize("#FF0000", msg) + return false, minetest.colorize(color_red, msg) end end end @@ -98,10 +103,15 @@ local function commandblock_action_on(pos, node) if node.name ~= "mesecons_commandblock:commandblock_off" then return end - - minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) - + local meta = minetest.get_meta(pos) + local commander = meta:get_string("commander") + + if not command_blocks_activated then + --minetest.chat_send_player(commander, msg_not_activated) + return + end + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) local commands = resolve_commands(meta:get_string("commands"), pos) for _, command in pairs(commands:split("\n")) do @@ -117,7 +127,6 @@ local function commandblock_action_on(pos, node) return end -- Execute command in the name of commander - local commander = meta:get_string("commander") cmddef.func(commander, param) end end @@ -129,6 +138,10 @@ local function commandblock_action_off(pos, node) end local on_rightclick = function(pos, node, player, itemstack, pointed_thing) + if not command_blocks_activated then + minetest.chat_send_player(player:get_player_name(), msg_not_activated) + return + end local can_edit = true -- Only allow write access in Creative Mode if not minetest.is_creative_enabled(player:get_player_name()) then diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr index 9c9b1df1d..a149feef9 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=Zugr Editing the command block has failed! You can only change the command block in Creative Mode!=Bearbeitung des Befehlsblocks fehlgeschlagen! Sie können den Befehlsblock nur im Kreativmodus ändern! Editing the command block has failed! The command block is gone.=Bearbeiten des Befehlsblocks fehlgeschlagen! Der Befehlsblock ist verschwunden. Executes server commands when powered by redstone power=Führt Serverbefehle aus, wenn mit Redstoneenergie versorgt +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr index 8826ab9a6..938c710b9 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr @@ -28,3 +28,4 @@ Example 2:@n give @@n mcl_core:apple 5@nGives the nearest player 5 apples=2. Access denied. You need the “maphack” privilege to edit command blocks.=Acceso denegado. Necesita el privilegio "maphack" para editar bloques de comandos. Editing the command block has failed! You can only change the command block in Creative Mode!=¡La edición del bloque de comando ha fallado! ¡Solo puede cambiar el bloque de comandos en modo creativo! Editing the command block has failed! The command block is gone.=¡La edición del bloque de comando ha fallado! El bloque de comando se ha ido. +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr index 061ac08a0..b397c979c 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=Acc Editing the command block has failed! You can only change the command block in Creative Mode!=La modification du bloc de commandes a échoué! Vous ne pouvez modifier le bloc de commandes qu'en mode créatif! Editing the command block has failed! The command block is gone.=La modification du bloc de commandes a échoué! Le bloc de commande a disparu. Executes server commands when powered by redstone power=Exécute les commandes du serveur lorsqu'il est alimenté par l'alimentation Redstone +Command blocks are not enabled on this server=Les blocks de commandes ne sont pas activés sur ce serveur diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr index 8671099c7..85bed4b95 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=До Editing the command block has failed! You can only change the command block in Creative Mode!=Попытка редактирования командного блока потерпела неудачу. Вы можете изменять командные блоки только в творческом режиме! Editing the command block has failed! The command block is gone.=Попытка редактирования командного блока потерпела неудачу. Командный блок исчез. Executes server commands when powered by redstone power=При подаче энергии редстоуна выполняет серверные команды +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt index 0e0c3caa5..49e98ef2b 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.= Editing the command block has failed! You can only change the command block in Creative Mode!= Editing the command block has failed! The command block is gone.= Executes server commands when powered by redstone power= +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf b/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf index 4a743406c..a35c425f5 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf @@ -1,3 +1,3 @@ name = mesecons_commandblock -depends = mesecons +depends = mesecons, mcl_colors optional_depends = doc, doc_items diff --git a/mods/ITEMS/mcl_anvils/init.lua b/mods/ITEMS/mcl_anvils/init.lua index f95ddabac..1845ed776 100644 --- a/mods/ITEMS/mcl_anvils/init.lua +++ b/mods/ITEMS/mcl_anvils/init.lua @@ -9,7 +9,6 @@ local MATERIAL_TOOL_REPAIR_BOOST = { math.ceil(MAX_WEAR * 0.75), -- 75% MAX_WEAR, -- 100% } -local NAME_COLOR = "#FFFF4C" local function get_anvil_formspec(set_name) if not set_name then @@ -17,7 +16,7 @@ local function get_anvil_formspec(set_name) end return "size[9,8.75]".. "background[-0.19,-0.25;9.41,9.49;mcl_anvils_inventory.png]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. @@ -28,7 +27,7 @@ local function get_anvil_formspec(set_name) mcl_formspec.get_itemslot_bg(4,2.5,1,1).. "list[context;output;8,2.5;1,1;]".. mcl_formspec.get_itemslot_bg(8,2.5,1,1).. - "label[3,0.1;"..minetest.formspec_escape(minetest.colorize("#313131", S("Repair and Name"))).."]".. + "label[3,0.1;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Repair and Name"))).."]".. "field[3.25,1;4,1;name;;"..minetest.formspec_escape(set_name).."]".. "field_close_on_enter[name;false]".. "button[7,0.7;2,1;name_button;"..minetest.formspec_escape(S("Set Name")).."]".. @@ -172,14 +171,8 @@ local function update_anvil_slots(meta) if new_name ~= old_name then -- Save the raw name internally meta:set_string("name", new_name) - -- Rename item - if new_name == "" then - tt.reload_itemstack_description(name_item) - else - -- Custom name set. Colorize it! - -- This makes the name visually different from unnamed items - meta:set_string("description", minetest.colorize(NAME_COLOR, new_name)) - end + -- Rename item handled by tt + tt.reload_itemstack_description(name_item) new_output = name_item elseif just_rename then new_output = "" @@ -495,7 +488,6 @@ S("The anvil has limited durability and 3 damage levels: undamaged, slightly dam local anvildef1 = table.copy(anvildef) anvildef1.description = S("Slightly Damaged Anvil") anvildef1._doc_items_create_entry = false -anvildef1.groups.not_in_creative_inventory = 1 anvildef1.groups.anvil = 2 anvildef1._doc_items_create_entry = false anvildef1.tiles = {"mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} @@ -503,7 +495,6 @@ anvildef1.tiles = {"mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvi local anvildef2 = table.copy(anvildef) anvildef2.description = S("Very Damaged Anvil") anvildef2._doc_items_create_entry = false -anvildef2.groups.not_in_creative_inventory = 1 anvildef2.groups.anvil = 3 anvildef2._doc_items_create_entry = false anvildef2.tiles = {"mcl_anvils_anvil_top_damaged_2.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} diff --git a/mods/ITEMS/mcl_anvils/mod.conf b/mods/ITEMS/mcl_anvils/mod.conf index cd4fa02a8..cbb5dc223 100644 --- a/mods/ITEMS/mcl_anvils/mod.conf +++ b/mods/ITEMS/mcl_anvils/mod.conf @@ -1,5 +1,5 @@ name = mcl_anvils author = Wuzzy description = Anvils mods for MCL2 -depends = mcl_init, mcl_formspec, mcl_sounds, tt, mcl_enchanting +depends = mcl_init, mcl_formspec, mcl_sounds, tt, mcl_enchanting, mcl_colors optional_depends = mcl_core, screwdriver diff --git a/mods/ITEMS/mcl_armor/armor.lua b/mods/ITEMS/mcl_armor/armor.lua index a879f7240..05a020016 100644 --- a/mods/ITEMS/mcl_armor/armor.lua +++ b/mods/ITEMS/mcl_armor/armor.lua @@ -367,6 +367,7 @@ mcl_player.player_register_model("mcl_armor_character.b3d", { run_walk = {x=440, y=459}, run_walk_mine = {x=461, y=480}, sit_mount = {x=484, y=484}, + die = {x=498, y=498}, }, }) diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d b/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d index c6a1274c5..a658f753c 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d and b/mods/ITEMS/mcl_armor/models/mcl_armor_character.b3d differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend b/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend index 88db35cf5..12869b59d 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend and b/mods/ITEMS/mcl_armor/models/mcl_armor_character.blend differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d index cd2fca988..44494d1ec 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d and b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.b3d differ diff --git a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend index 098417b42..c854a49e5 100644 Binary files a/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend and b/mods/ITEMS/mcl_armor/models/mcl_armor_character_female.blend differ diff --git a/mods/ITEMS/mcl_banners/mod.conf b/mods/ITEMS/mcl_banners/mod.conf index cee7bace7..8c3117206 100644 --- a/mods/ITEMS/mcl_banners/mod.conf +++ b/mods/ITEMS/mcl_banners/mod.conf @@ -1,4 +1,5 @@ name = mcl_banners author = 22i description = Adds decorative banners in different colors which can be emblazoned with patterns, offering a countless number of combinations. +depends = mcl_colors optional_depends = mcl_sounds, mcl_core, mcl_wool, mcl_cauldrons, doc, screwdriver diff --git a/mods/ITEMS/mcl_banners/patterncraft.lua b/mods/ITEMS/mcl_banners/patterncraft.lua index e1f05ff11..31782a42b 100644 --- a/mods/ITEMS/mcl_banners/patterncraft.lua +++ b/mods/ITEMS/mcl_banners/patterncraft.lua @@ -281,7 +281,7 @@ mcl_banners.make_advanced_banner_description = function(description, layers) -- Final string concatenations: Just a list of strings local append = table.concat(layerstrings, "\n") - description = description .. "\n" .. minetest.colorize("#8F8F8F", append) + description = description .. "\n" .. minetest.colorize(mcl_colors.GRAY, append) return description end end diff --git a/mods/ITEMS/mcl_beds/api.lua b/mods/ITEMS/mcl_beds/api.lua index c274a29a0..a2df1bdf3 100644 --- a/mods/ITEMS/mcl_beds/api.lua +++ b/mods/ITEMS/mcl_beds/api.lua @@ -89,6 +89,7 @@ function mcl_beds.register_bed(name, def) selection_box = selection_box_bottom, collision_box = collision_box_bottom, drop = "", + node_placement_prediction = "", on_place = function(itemstack, placer, pointed_thing) local under = pointed_thing.under diff --git a/mods/ITEMS/mcl_books/init.lua b/mods/ITEMS/mcl_books/init.lua index 45208c413..5101994e9 100644 --- a/mods/ITEMS/mcl_books/init.lua +++ b/mods/ITEMS/mcl_books/init.lua @@ -1,4 +1,4 @@ -local S =minetest.get_translator("mcl_books") +local S = minetest.get_translator("mcl_books") local max_text_length = 4500 -- TODO: Increase to 12800 when scroll bar was added to written book local max_title_length = 64 @@ -67,7 +67,7 @@ local make_description = function(title, author, generation) else desc = S("Tattered Book") end - desc = desc .. "\n" .. minetest.colorize("#AAAAAA", S("by @1", author)) + desc = desc .. "\n" .. minetest.colorize(mcl_colors.GRAY, S("by @1", author)) return desc end @@ -147,8 +147,8 @@ minetest.register_on_player_receive_fields(function ( player, formname, fields ) local formspec = "size[8,9]".. header.. "background[-0.5,-0.5;9,10;mcl_books_book_bg.png]".. - "field[0.75,1;7.25,1;title;"..minetest.formspec_escape(minetest.colorize("#000000", S("Enter book title:")))..";]".. - "label[0.75,1.5;"..minetest.formspec_escape(minetest.colorize("#404040", S("by @1", name))).."]".. + "field[0.75,1;7.25,1;title;"..minetest.formspec_escape(minetest.colorize(mcl_colors.BLACK, S("Enter book title:")))..";]".. + "label[0.75,1.5;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("by @1", name))).."]".. "button_exit[0.75,7.95;3,1;sign;"..minetest.formspec_escape(S("Sign and Close")).."]".. "tooltip[sign;"..minetest.formspec_escape(S("Note: The book will no longer be editable after signing")).."]".. "button[4.25,7.95;3,1;cancel;"..minetest.formspec_escape(S("Cancel")).."]" diff --git a/mods/ITEMS/mcl_books/mod.conf b/mods/ITEMS/mcl_books/mod.conf index 7c4513b00..cea9a5dd8 100644 --- a/mods/ITEMS/mcl_books/mod.conf +++ b/mods/ITEMS/mcl_books/mod.conf @@ -1,4 +1,4 @@ name = mcl_books author = celeron55 description = Books mod for MCL2 -optional_depends = mcl_init, mcl_core, mcl_sounds, mcl_mobitems, mcl_dye +optional_depends = mcl_init, mcl_core, mcl_sounds, mcl_mobitems, mcl_dye, mcl_colors diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 1b7d63c13..cddae0869 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -16,23 +16,17 @@ local dir_to_pitch = function(dir) end local random_arrow_positions = function(positions, placement) - local min = 0 - local max = 0 if positions == 'x' then - min = -4 - max = 4 + return math.random(-4, 4) elseif positions == 'y' then - min = 0 - max = 10 + return math.random(0, 10) end if placement == 'front' and positions == 'z' then - min = 3 - max = 3 + return 3 elseif placement == 'back' and positions == 'z' then - min = -3 - max = -3 + return -3 end - return math.random(max, min) + return 0 end local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements") @@ -304,8 +298,8 @@ ARROW_ENTITY.on_step = function(self, dtime) else self._attach_parent = 'Body' end - self._z_rotation = math.random(30, -30) - self._y_rotation = math.random(30, -30) + self._z_rotation = math.random(-30, 30) + self._y_rotation = math.random( -30, 30) self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions('z', placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation}) minetest.after(150, function() self.object:remove() diff --git a/mods/ITEMS/mcl_brewing/init.lua b/mods/ITEMS/mcl_brewing/init.lua index 617929ff7..78ccd8ed9 100644 --- a/mods/ITEMS/mcl_brewing/init.lua +++ b/mods/ITEMS/mcl_brewing/init.lua @@ -4,8 +4,8 @@ local function active_brewing_formspec(fuel_percent, brew_percent) return "size[9,8.75]".. "background[-0.19,-0.25;9.5,9.5;mcl_brewing_inventory.png]".. - "label[4,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Brewing Stand"))).."]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[4,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Brewing Stand"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.75;9,1;]".. @@ -35,8 +35,8 @@ end local brewing_formspec = "size[9,8.75]".. "background[-0.19,-0.25;9.5,9.5;mcl_brewing_inventory.png]".. - "label[4,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Brewing Stand"))).."]".. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[4,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Brewing Stand"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.75;9,1;]".. diff --git a/mods/ITEMS/mcl_brewing/mod.conf b/mods/ITEMS/mcl_brewing/mod.conf index 2c27c979e..160319c93 100644 --- a/mods/ITEMS/mcl_brewing/mod.conf +++ b/mods/ITEMS/mcl_brewing/mod.conf @@ -1,4 +1,4 @@ name = mcl_brewing author = bzoss -depends = mcl_init, mcl_formspec, mcl_sounds, mcl_potions, mcl_mobitems +depends = mcl_init, mcl_formspec, mcl_sounds, mcl_potions, mcl_mobitems, mcl_colors optional_depends = mcl_core, doc, screwdriver diff --git a/mods/ITEMS/mcl_buckets/API.md b/mods/ITEMS/mcl_buckets/API.md index 69ee4b21d..53f7d3698 100644 --- a/mods/ITEMS/mcl_buckets/API.md +++ b/mods/ITEMS/mcl_buckets/API.md @@ -5,17 +5,17 @@ Add an API to register buckets to mcl Register a new liquid Accept folowing params: -* source_place = a string or function. +* source_place: a string or function. * string: name of the node to place * function(pos): will returns name of the node to place with pos being the placement position -* source_take = table of liquid source node names to take -* itemname = itemstring of the new bucket item (or nil if liquid is not takeable) -* inventory_image = texture of the new bucket item (ignored if itemname == nil) -* name = user-visible bucket description -* longdesc = long explanatory description (for help) -* usagehelp = short usage explanation (for help) -* tt_help = very short tooltip help -* 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 +* source_take: table of liquid source node names to take +* itemname: itemstring of the new bucket item (or nil if liquid is not takeable) +* inventory_image: texture of the new bucket item (ignored if itemname == nil) +* name: user-visible bucket description +* longdesc: long explanatory description (for help) +* usagehelp: short usage explanation (for help) +* tt_help: very short tooltip help +* 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) \ No newline at end of file diff --git a/mods/ITEMS/mcl_buckets/init.lua b/mods/ITEMS/mcl_buckets/init.lua index 30e4075c8..0ba68b723 100644 --- a/mods/ITEMS/mcl_buckets/init.lua +++ b/mods/ITEMS/mcl_buckets/init.lua @@ -207,6 +207,9 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", { -- Fill bucket, but not in Creative Mode if not minetest.is_creative_enabled(user:get_player_name()) then new_bucket = ItemStack({name = liquiddef.itemname}) + if liquiddef.itemname == "mcl_buckets:bucket_lava" and awards and awards.unlock and user and user:is_player() then + awards.unlock(user:get_player_name(), "mcl:hotStuff") + end end minetest.add_node(pointed_thing.under, {name="air"}) diff --git a/mods/ITEMS/mcl_chests/init.lua b/mods/ITEMS/mcl_chests/init.lua index fb8c59f28..1f3f518a4 100644 --- a/mods/ITEMS/mcl_chests/init.lua +++ b/mods/ITEMS/mcl_chests/init.lua @@ -475,10 +475,10 @@ minetest.register_node(small_name, { minetest.show_formspec(clicker:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, "size[9,8.75]".. - "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. + "label[0,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, name)).."]".. "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,0.5,9,3).. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. @@ -624,12 +624,12 @@ minetest.register_node(left_name, { minetest.show_formspec(clicker:get_player_name(), "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, "size[9,11.5]".. - "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. + "label[0,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, name)).."]".. "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,0.5,9,3).. "list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,3.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,3.5,9,3).. - "label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,7;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,7.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,7.5,9,3).. "list[current_player;main;0,10.75;9,1;]".. @@ -773,12 +773,12 @@ minetest.register_node("mcl_chests:"..basename.."_right", { "mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z, "size[9,11.5]".. - "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. + "label[0,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, name)).."]".. "list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,0.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,0.5,9,3).. "list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,3.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,3.5,9,3).. - "label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,7;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,7.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,7.5,9,3).. "list[current_player;main;0,10.75;9,1;]".. @@ -986,10 +986,10 @@ minetest.register_node("mcl_chests:ender_chest", { }) local formspec_ender_chest = "size[9,8.75]".. - "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]".. + "label[0,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Ender Chest"))).."]".. "list[current_player;enderchest;0,0.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,0.5,9,3).. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. @@ -1104,10 +1104,10 @@ local function formspec_shulker_box(name) name = S("Shulker Box") end return "size[9,8.75]".. - "label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]".. + "label[0,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, name)).."]".. "list[current_name;main;0,0.5;9,3;]".. mcl_formspec.get_itemslot_bg(0,0.5,9,3).. - "label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4.0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. diff --git a/mods/ITEMS/mcl_chests/mod.conf b/mods/ITEMS/mcl_chests/mod.conf index 0ff5129ca..609b1fff9 100644 --- a/mods/ITEMS/mcl_chests/mod.conf +++ b/mods/ITEMS/mcl_chests/mod.conf @@ -1,3 +1,3 @@ name = mcl_chests -depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_end, mesecons +depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_end, mesecons, mcl_colors optional_depends = doc, screwdriver diff --git a/mods/ITEMS/mcl_core/init.lua b/mods/ITEMS/mcl_core/init.lua index aae6abe9a..897382e01 100644 --- a/mods/ITEMS/mcl_core/init.lua +++ b/mods/ITEMS/mcl_core/init.lua @@ -14,7 +14,7 @@ mcl_autogroup.register_diggroup("shearsy_wool") mcl_autogroup.register_diggroup("shearsy_cobweb") mcl_autogroup.register_diggroup("swordy") mcl_autogroup.register_diggroup("swordy_cobweb") -mcl_autogroup.register_diggroup("creative_breakable") +mcl_autogroup.register_diggroup("hoey") -- Load files local modpath = minetest.get_modpath("mcl_core") diff --git a/mods/ITEMS/mcl_core/mod.conf b/mods/ITEMS/mcl_core/mod.conf index e204ace84..45018df75 100644 --- a/mods/ITEMS/mcl_core/mod.conf +++ b/mods/ITEMS/mcl_core/mod.conf @@ -1,4 +1,4 @@ name = mcl_core description = Core items of MineClone 2: Basic biome blocks (dirt, sand, stones, etc.), derived items, glass, sugar cane, cactus, barrier, mining tools, hand, craftitems, and misc. items which don't really fit anywhere else. -depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting +depends = mcl_autogroup, mcl_init, mcl_sounds, mcl_particles, mcl_util, mcl_worlds, doc_items, mcl_enchanting, mcl_colors optional_depends = doc diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index cc6a0e6ae..4477f0377 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -33,6 +33,11 @@ minetest.register_node("mcl_core:stone", { _mcl_blast_resistance = 6, _mcl_hardness = 1.5, _mcl_silk_touch_drop = true, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + if awards and awards.unlock and digger and digger:is_player() then + awards.unlock(digger:get_player_name(), "mcl:stoneAge") + end + end, }) minetest.register_node("mcl_core:stone_with_coal", { @@ -808,12 +813,17 @@ minetest.register_node("mcl_core:obsidian", { description = S("Obsidian"), _doc_items_longdesc = S("Obsidian is an extremely hard mineral with an enourmous blast-resistance. Obsidian is formed when water meets lava."), tiles = {"default_obsidian.png"}, - is_ground_content = true, + is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), stack_max = 64, groups = {pickaxey=5, building_block=1, material_stone=1}, _mcl_blast_resistance = 1200, _mcl_hardness = 50, + after_dig_node = function(pos, oldnode, oldmetadata, digger) + if awards and awards.unlock and digger and digger:is_player() then + awards.unlock(digger:get_player_name(), "mcl:obsidian") + end + end, }) minetest.register_node("mcl_core:ice", { diff --git a/mods/ITEMS/mcl_core/nodes_cactuscane.lua b/mods/ITEMS/mcl_core/nodes_cactuscane.lua index d1bcac011..4ec005170 100644 --- a/mods/ITEMS/mcl_core/nodes_cactuscane.lua +++ b/mods/ITEMS/mcl_core/nodes_cactuscane.lua @@ -4,7 +4,7 @@ local S = minetest.get_translator("mcl_core") minetest.register_node("mcl_core:cactus", { description = S("Cactus"), - _tt_help = S("Grows on sand").."\n"..minetest.colorize("#FFFF00", S("Contact damage: @1 per half second", 1)), + _tt_help = S("Grows on sand").."\n"..minetest.colorize(mcl_colors.YELLOW, S("Contact damage: @1 per half second", 1)), _doc_items_longdesc = S("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 = S("A cactus can only be placed on top of another cactus or any sand."), drawtype = "nodebox", diff --git a/mods/ITEMS/mcl_core/nodes_misc.lua b/mods/ITEMS/mcl_core/nodes_misc.lua index 083aa0b85..8b36f0696 100644 --- a/mods/ITEMS/mcl_core/nodes_misc.lua +++ b/mods/ITEMS/mcl_core/nodes_misc.lua @@ -236,7 +236,7 @@ minetest.register_node("mcl_core:realm_barrier", { -- Prevent placement to protect player from screwing up the world, because the node is not pointable and hard to get rid of. node_placement_prediction = "", on_place = function(pos, placer, itemstack, pointed_thing) - minetest.chat_send_player(placer:get_player_name(), minetest.colorize("#FF0000", "You can't just place a realm barrier by hand!")) + minetest.chat_send_player(placer:get_player_name(), minetest.colorize(mcl_colors.RED, "You can't just place a realm barrier by hand!")) return end, }) @@ -266,7 +266,7 @@ minetest.register_node("mcl_core:void", { -- Prevent placement to protect player from screwing up the world, because the node is not pointable and hard to get rid of. node_placement_prediction = "", on_place = function(pos, placer, itemstack, pointed_thing) - minetest.chat_send_player(placer:get_player_name(), minetest.colorize("#FF0000", "You can't just place the void by hand!")) + minetest.chat_send_player(placer:get_player_name(), minetest.colorize(mcl_colors.RED, "You can't just place the void by hand!")) return end, drop = "", diff --git a/mods/ITEMS/mcl_core/nodes_trees.lua b/mods/ITEMS/mcl_core/nodes_trees.lua index 3a8aef8d0..197846ebc 100644 --- a/mods/ITEMS/mcl_core/nodes_trees.lua +++ b/mods/ITEMS/mcl_core/nodes_trees.lua @@ -108,7 +108,19 @@ local register_leaves = function(subname, description, longdesc, tiles, sapling, tiles = tiles, paramtype = "light", stack_max = 64, - groups = {handy=1,shearsy=1,swordy=1, leafdecay=leafdecay_distance, flammable=2, leaves=1, deco_block=1, dig_by_piston=1, fire_encouragement=30, fire_flammability=60}, + groups = { + handy=1, + hoey=1, + shearsy=1, + swordy=1, + leafdecay=leafdecay_distance, + flammable=2, + leaves=1, + deco_block=1, + dig_by_piston=1, + fire_encouragement=30, + fire_flammability=60 + }, drop = get_drops(0), _mcl_shears_drop = true, sounds = mcl_sounds.node_sound_leaves_defaults(), diff --git a/mods/ITEMS/mcl_crafting_table/API.md b/mods/ITEMS/mcl_crafting_table/API.md new file mode 100644 index 000000000..45aa0c9ce --- /dev/null +++ b/mods/ITEMS/mcl_crafting_table/API.md @@ -0,0 +1,6 @@ +# mcl_crafting_table +Add a node which allow players to craft more complex things. + +## mcl_crafting_table.show_crafting_form(player) +Show the crafting form to a player. +Used in the node registration, but can be used by external mods. \ No newline at end of file diff --git a/mods/ITEMS/mcl_crafting_table/init.lua b/mods/ITEMS/mcl_crafting_table/init.lua index 4ad581774..6df4c2544 100644 --- a/mods/ITEMS/mcl_crafting_table/init.lua +++ b/mods/ITEMS/mcl_crafting_table/init.lua @@ -2,7 +2,7 @@ local S = minetest.get_translator("mcl_crafting_table") local formspec_escape = minetest.formspec_escape local show_formspec = minetest.show_formspec local C = minetest.colorize -local text_color = mcl_colors.BLACK or "#313131" +local text_color = mcl_colors.DARK_GRAY local itemslot_bg = mcl_formspec.get_itemslot_bg mcl_crafting_table = {} @@ -13,7 +13,7 @@ function mcl_crafting_table.show_crafting_form(player) show_formspec(player:get_player_name(), "main", "size[9,8.75]".. "image[4.7,1.5;1.5,1;gui_crafting_arrow.png]".. - "label[0,4;"..formspec_escape(C(text_color, S("Inventory"))).."]".. --"#313131" + "label[0,4;"..formspec_escape(C(text_color, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. diff --git a/mods/ITEMS/mcl_crafting_table/mod.conf b/mods/ITEMS/mcl_crafting_table/mod.conf index 03b3174ab..149d1c982 100644 --- a/mods/ITEMS/mcl_crafting_table/mod.conf +++ b/mods/ITEMS/mcl_crafting_table/mod.conf @@ -1,4 +1,3 @@ name = mcl_crafting_table description = Adds a crafting table. -depends = mcl_init, mcl_formspec, mcl_sounds -optional_depends = mcl_colors +depends = mcl_init, mcl_formspec, mcl_sounds, mcl_colors diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 83149862a..ea69d1868 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -52,7 +52,7 @@ function mcl_enchanting.get_enchantment_description(enchantment, level) end function mcl_enchanting.get_colorized_enchantment_description(enchantment, level) - return minetest.colorize(mcl_enchanting.enchantments[enchantment].curse and "#FC5454" or "#A8A8A8", mcl_enchanting.get_enchantment_description(enchantment, level)) + return minetest.colorize(mcl_enchanting.enchantments[enchantment].curse and mcl_colors.RED or mcl_colors.GRAY, mcl_enchanting.get_enchantment_description(enchantment, level)) end function mcl_enchanting.get_enchanted_itemstring(itemname) @@ -468,13 +468,13 @@ function mcl_enchanting.show_enchanting_formspec(player) local formspec = "" .. "size[9.07,8.6;]" .. "formspec_version[3]" - .. "label[0,0;" .. C("#313131") .. F(table_name) .. "]" + .. "label[0,0;" .. C(mcl_colors.DARK_GRAY) .. F(table_name) .. "]" .. mcl_formspec.get_itemslot_bg(0.2, 2.4, 1, 1) .. "list[current_player;enchanting_item;0.2,2.4;1,1]" .. mcl_formspec.get_itemslot_bg(1.1, 2.4, 1, 1) .. "image[1.1,2.4;1,1;mcl_enchanting_lapis_background.png]" .. "list[current_player;enchanting_lapis;1.1,2.4;1,1]" - .. "label[0,4;" .. C("#313131") .. F(S("Inventory")).."]" + .. "label[0,4;" .. C(mcl_colors.DARK_GRAY) .. F(S("Inventory")).."]" .. mcl_formspec.get_itemslot_bg(0, 4.5, 9, 3) .. mcl_formspec.get_itemslot_bg(0, 7.74, 9, 1) .. "list[current_player;main;0,4.5;9,3;9]" @@ -501,11 +501,11 @@ function mcl_enchanting.show_enchanting_formspec(player) local hover_ending = (can_enchant and "_hovered" or "_off") formspec = formspec .. "container[3.2," .. y .. "]" - .. (slot and "tooltip[button_" .. i .. ";" .. C("#818181") .. F(slot.description) .. " " .. C("#FFFFFF") .. " . . . ?\n\n" .. (enough_levels and C(enough_lapis and "#818181" or "#FC5454") .. F(S("@1 Lapis Lazuli", i)) .. "\n" .. C("#818181") .. F(S("@1 Enchantment Levels", i)) or C("#FC5454") .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "") + .. (slot and "tooltip[button_" .. i .. ";" .. C(mcl_colors.GRAY) .. F(slot.description) .. " " .. C(mcl_colors.WHITE) .. " . . . ?\n\n" .. (enough_levels and C(enough_lapis and mcl_colors.GRAY or mcl_colors.RED) .. F(S("@1 Lapis Lazuli", i)) .. "\n" .. C(mcl_colors.GRAY) .. F(S("@1 Enchantment Levels", i)) or C(mcl_colors.RED) .. F(S("Level requirement: @1", slot.level_requirement))) .. "]" or "") .. "style[button_" .. i .. ";bgimg=mcl_enchanting_button" .. ending .. ".png;bgimg_hovered=mcl_enchanting_button" .. hover_ending .. ".png;bgimg_pressed=mcl_enchanting_button" .. hover_ending .. ".png]" .. "button[0,0;7.5,1.3;button_" .. i .. ";]" .. (slot and "image[0,0;1.3,1.3;mcl_enchanting_number_" .. i .. ending .. ".png]" or "") - .. (slot and "label[7.2,1.1;" .. C(can_enchant and "#80FF20" or "#407F10") .. slot.level_requirement .. "]" or "") + .. (slot and "label[7.2,1.1;" .. C(can_enchant and mcl_colors.GREEN or mcl_colors.DARK_GREEN) .. slot.level_requirement .. "]" or "") .. (slot and slot.glyphs or "") .. "container_end[]" y = y + 1.35 @@ -582,7 +582,12 @@ function mcl_enchanting.allow_inventory_action(player, action, inventory, invent local listname = inventory_info.to_list local stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) if stack:get_name() == "mcl_dye:blue" and listname ~= "enchanting_item" then - return math.min(inventory:get_stack("enchanting_lapis", 1):get_free_space(), stack:get_count()) + local count = stack:get_count() + local old_stack = inventory:get_stack("enchanting_lapis", 1) + if old_stack:get_name() ~= "" then + count = math.min(count, old_stack:get_free_space()) + end + return count elseif inventory:get_stack("enchanting_item", 1):get_count() == 0 and listname ~= "enchanting_lapis" then return 1 else diff --git a/mods/ITEMS/mcl_enchanting/groupcaps.lua b/mods/ITEMS/mcl_enchanting/groupcaps.lua index 3060000db..375029547 100644 --- a/mods/ITEMS/mcl_enchanting/groupcaps.lua +++ b/mods/ITEMS/mcl_enchanting/groupcaps.lua @@ -45,6 +45,10 @@ end -- To make it more efficient it will first check a hash value to determine if -- the tool needs to be updated. function mcl_enchanting.update_groupcaps(itemstack) + if not itemstack:get_meta():get("tool_capabilities") then + return + end + local name = itemstack:get_name() local level = mcl_enchanting.get_enchantment(itemstack, "efficiency") local groupcaps = get_efficiency_groupcaps(name, level) diff --git a/mods/ITEMS/mcl_enchanting/mod.conf b/mods/ITEMS/mcl_enchanting/mod.conf index ac4dad644..4d4741fb8 100644 --- a/mods/ITEMS/mcl_enchanting/mod.conf +++ b/mods/ITEMS/mcl_enchanting/mod.conf @@ -1,5 +1,5 @@ name = mcl_enchanting description = Enchanting for MineClone2 -depends = tt, walkover, mcl_sounds +depends = tt, walkover, mcl_sounds, mcl_colors optional_depends = screwdriver author = Fleckenstein diff --git a/mods/ITEMS/mcl_end/eye_of_ender.lua b/mods/ITEMS/mcl_end/eye_of_ender.lua index 16f1c906b..afac9ebfc 100644 --- a/mods/ITEMS/mcl_end/eye_of_ender.lua +++ b/mods/ITEMS/mcl_end/eye_of_ender.lua @@ -29,7 +29,7 @@ minetest.register_entity("mcl_end:ender_eye", { if self._age >= 3 then -- End of life local r = math.random(1,5) - if r == 1 or minetest.is_creative_enabled("") then + if r == 1 then -- 20% chance to get destroyed completely. -- 100% if in Creative Mode self.object:remove() diff --git a/mods/ITEMS/mcl_farming/hoes.lua b/mods/ITEMS/mcl_farming/hoes.lua index 5a383d78a..a45b382ed 100644 --- a/mods/ITEMS/mcl_farming/hoes.lua +++ b/mods/ITEMS/mcl_farming/hoes.lua @@ -78,6 +78,9 @@ minetest.register_tool("mcl_farming:hoe_wood", { }, _repair_material = "group:wood", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 2, level = 1, uses = 60 } + }, }) minetest.register_craft({ @@ -118,6 +121,9 @@ minetest.register_tool("mcl_farming:hoe_stone", { }, _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 4, level = 3, uses = 132 } + }, }) minetest.register_craft({ @@ -154,6 +160,9 @@ minetest.register_tool("mcl_farming:hoe_iron", { }, _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 6, level = 4, uses = 251 } + }, }) minetest.register_craft({ @@ -196,6 +205,9 @@ minetest.register_tool("mcl_farming:hoe_gold", { }, _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 12, level = 2, uses = 33 } + }, }) minetest.register_craft({ @@ -240,6 +252,9 @@ minetest.register_tool("mcl_farming:hoe_diamond", { }, _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 8, level = 5, uses = 1562 } + }, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_farming/mod.conf b/mods/ITEMS/mcl_farming/mod.conf index 73627923e..9ab36c39f 100644 --- a/mods/ITEMS/mcl_farming/mod.conf +++ b/mods/ITEMS/mcl_farming/mod.conf @@ -1,3 +1,3 @@ name = mcl_farming -depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc +depends = mcl_core, mcl_sounds, mcl_wool, mcl_torches, mcl_weather, mobs_mc, mcl_colors optional_depends = mcl_armor, doc diff --git a/mods/ITEMS/mcl_farming/potatoes.lua b/mods/ITEMS/mcl_farming/potatoes.lua index 871d67963..a7f5a7084 100644 --- a/mods/ITEMS/mcl_farming/potatoes.lua +++ b/mods/ITEMS/mcl_farming/potatoes.lua @@ -118,7 +118,7 @@ minetest.register_craftitem("mcl_farming:potato_item_baked", { minetest.register_craftitem("mcl_farming:potato_item_poison", { description = S("Poisonous Potato"), - _tt_help = minetest.colorize("#FFFF00", S("60% chance of poisoning")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("60% chance of poisoning")), _doc_items_longdesc = S("This potato doesn't look too healthy. You can eat it to restore hunger points, but there's a 60% chance it will poison you briefly."), stack_max = 64, inventory_image = "farming_potato_poison.png", diff --git a/mods/ITEMS/mcl_farming/wheat.lua b/mods/ITEMS/mcl_farming/wheat.lua index 9a8a9f65e..e3ee79ead 100644 --- a/mods/ITEMS/mcl_farming/wheat.lua +++ b/mods/ITEMS/mcl_farming/wheat.lua @@ -146,7 +146,7 @@ minetest.register_node("mcl_farming:hay_block", { paramtype2 = "facedir", is_ground_content = false, on_place = mcl_util.rotate_axis, - groups = {handy=1, flammable=2, fire_encouragement=60, fire_flammability=20, building_block=1, fall_damage_add_percent=-80}, + groups = {handy=1, hoey=1, flammable=2, fire_encouragement=60, fire_flammability=20, building_block=1, fall_damage_add_percent=-80}, sounds = mcl_sounds.node_sound_leaves_defaults(), on_rotate = on_rotate, _mcl_blast_resistance = 0.5, diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 1ff56c277..228d490ea 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -173,7 +173,7 @@ local fish = function(itemstack, player, pointed_thing) if noent == true then local playerpos = player:get_pos() local dir = player:get_look_dir() - local obj = mcl_throwing.throw("mcl_throwing:flying_bobber", {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, 15, player:get_player_name()) + local obj = mcl_throwing.throw("mcl_fishing:flying_bobber", {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, 15, player:get_player_name()) end end @@ -295,6 +295,52 @@ bobber_ENTITY.on_step = bobber_on_step minetest.register_entity("mcl_fishing:bobber_entity", bobber_ENTITY) +local flying_bobber_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_fishing_bobber.png"}, --FIXME: Replace with correct texture. + visual_size = {x=0.5, y=0.5}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + + _lastpos={}, + _thrower = nil, + objtype="fishing", +} + +-- Movement function of flying bobber +local flying_bobber_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + --local player = minetest.get_player_by_name(self._thrower) + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + if (def and (def.walkable or def.liquidtype == "flowing" or def.liquidtype == "source")) or not def then + local make_child= function(object) + local ent = object:get_luaentity() + ent.player = self._thrower + ent.child = true + end + make_child(minetest.add_entity(self._lastpos, "mcl_fishing:bobber_entity")) + self.object:remove() + return + end + end + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +flying_bobber_ENTITY.on_step = flying_bobber_on_step + +minetest.register_entity("mcl_fishing:flying_bobber_entity", flying_bobber_ENTITY) + +mcl_throwing.register_throwable_object("mcl_fishing:flying_bobber", "mcl_fishing:flying_bobber_entity", 5) + -- If player leaves area, remove bobber. minetest.register_on_leaveplayer(function(player) local objs = minetest.get_objects_inside_radius(player:get_pos(), 250) @@ -449,7 +495,7 @@ minetest.register_craftitem("mcl_fishing:clownfish_raw", { minetest.register_craftitem("mcl_fishing:pufferfish_raw", { description = S("Pufferfish"), - _tt_help = minetest.colorize("#FFFF00", S("Very poisonous")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("Very poisonous")), _doc_items_longdesc = S("Pufferfish are a common species of fish and can be obtained by fishing. They can technically be eaten, but they are very bad for humans. Eating a pufferfish only restores 1 hunger point and will poison you very badly (which drains your health non-fatally) and causes serious food poisoning (which increases your hunger)."), inventory_image = "mcl_fishing_pufferfish_raw.png", on_place = minetest.item_eat(1), diff --git a/mods/ITEMS/mcl_fishing/mod.conf b/mods/ITEMS/mcl_fishing/mod.conf index 56a3305a0..c4e5f5f2e 100644 --- a/mods/ITEMS/mcl_fishing/mod.conf +++ b/mods/ITEMS/mcl_fishing/mod.conf @@ -1,3 +1,3 @@ name = mcl_fishing description = Adds fish and fishing poles to go fishing. -depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting +depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing, mcl_colors diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index d3877d90b..1d1ecc031 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -9,12 +9,12 @@ local LIGHT_ACTIVE_FURNACE = 13 local function active_formspec(fuel_percent, item_percent) return "size[9,8.75]".. - "label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg(0,7.74,9,1).. - "label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]".. + "label[2.75,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Furnace"))).."]".. "list[current_name;src;2.75,0.5;1,1;]".. mcl_formspec.get_itemslot_bg(2.75,0.5,1,1).. "list[current_name;fuel;2.75,2.5;1,1;]".. @@ -38,12 +38,12 @@ local function active_formspec(fuel_percent, item_percent) end local inactive_formspec = "size[9,8.75]".. - "label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,4;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,4.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,4.5,9,3).. "list[current_player;main;0,7.74;9,1;]".. mcl_formspec.get_itemslot_bg(0,7.74,9,1).. - "label[2.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Furnace"))).."]".. + "label[2.75,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Furnace"))).."]".. "list[current_name;src;2.75,0.5;1,1;]".. mcl_formspec.get_itemslot_bg(2.75,0.5,1,1).. "list[current_name;fuel;2.75,2.5;1,1;]".. @@ -161,6 +161,12 @@ local function on_metadata_inventory_take(pos, listname, index, stack, player) end end +local function on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + if from_list == "dst" then + give_xp(pos, player) + end +end + local function spawn_flames(pos, param2) local minrelpos, maxrelpos local dir = minetest.facedir_to_dir(param2) @@ -477,10 +483,12 @@ minetest.register_node("mcl_furnaces:furnace", { give_xp(pos) end, - on_metadata_inventory_move = function(pos) + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) -- Reset accumulated game time when player works with furnace: furnace_reset_delta_time(pos) minetest.get_node_timer(pos):start(1.0) + + on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) end, on_metadata_inventory_put = function(pos) -- Reset accumulated game time when player works with furnace: @@ -494,9 +502,7 @@ minetest.register_node("mcl_furnaces:furnace", { -- start timer function, it will helpful if player clears dst slot minetest.get_node_timer(pos):start(1.0) - if listname == "dst" then - give_xp(pos, player) - end + on_metadata_inventory_take(pos, listname, index, stack, player) end, allow_metadata_inventory_put = allow_metadata_inventory_put, @@ -552,6 +558,7 @@ minetest.register_node("mcl_furnaces:furnace_active", { allow_metadata_inventory_put = allow_metadata_inventory_put, allow_metadata_inventory_move = allow_metadata_inventory_move, allow_metadata_inventory_take = allow_metadata_inventory_take, + on_metadata_inventory_move = on_metadata_inventory_move, on_metadata_inventory_take = on_metadata_inventory_take, on_receive_fields = receive_fields, _mcl_blast_resistance = 3.5, diff --git a/mods/ITEMS/mcl_furnaces/mod.conf b/mods/ITEMS/mcl_furnaces/mod.conf index fe0b9c208..99a1ad0bf 100644 --- a/mods/ITEMS/mcl_furnaces/mod.conf +++ b/mods/ITEMS/mcl_furnaces/mod.conf @@ -1,3 +1,3 @@ name = mcl_furnaces -depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_craftguide, mcl_achievements, mcl_particles +depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_craftguide, mcl_achievements, mcl_particles, mcl_colors optional_depends = doc, screwdriver diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index 3ff549e4f..e9b3f75e0 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -4,10 +4,10 @@ local S = minetest.get_translator("mcl_hoppers") local mcl_hoppers_formspec = "size[9,7]".. - "label[2,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Hopper"))).."]".. + "label[2,0;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Hopper"))).."]".. "list[current_name;main;2,0.5;5,1;]".. mcl_formspec.get_itemslot_bg(2,0.5,5,1).. - "label[0,2;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]".. + "label[0,2;"..minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Inventory"))).."]".. "list[current_player;main;0,2.5;9,3;9]".. mcl_formspec.get_itemslot_bg(0,2.5,9,3).. "list[current_player;main;0,5.74;9,1;]".. diff --git a/mods/ITEMS/mcl_hoppers/mod.conf b/mods/ITEMS/mcl_hoppers/mod.conf index c89292f6b..53f514f39 100644 --- a/mods/ITEMS/mcl_hoppers/mod.conf +++ b/mods/ITEMS/mcl_hoppers/mod.conf @@ -1,4 +1,4 @@ name = mcl_hoppers description = It's just a clone of Minecraft hoppers, functions nearly identical to them minus mesecons making them stop and the way they're placed. -depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util +depends = mcl_core, mcl_formspec, mcl_sounds, mcl_util, mcl_colors optional_depends = doc, screwdriver diff --git a/mods/ITEMS/mcl_jukebox/init.lua b/mods/ITEMS/mcl_jukebox/init.lua index c5bd3d268..067848f50 100644 --- a/mods/ITEMS/mcl_jukebox/init.lua +++ b/mods/ITEMS/mcl_jukebox/init.lua @@ -20,8 +20,8 @@ function mcl_jukebox.register_record(title, author, identifier, image, sound) local usagehelp = S("Place a music disc into an empty jukebox to play the music. Use the jukebox again to retrieve the music disc. The music can only be heard by you, not by other players.") minetest.register_craftitem(":mcl_jukebox:record_"..identifier, { description = - core.colorize("#55FFFF", S("Music Disc")) .. "\n" .. - core.colorize("#989898", S("@1—@2", author, title)), + core.colorize(mcl_colors.AQUA, S("Music Disc")) .. "\n" .. + core.colorize(mcl_colors.GRAY, S("@1—@2", author, title)), _doc_items_create_entry = true, _doc_items_entry_name = entryname, _doc_items_longdesc = longdesc, diff --git a/mods/ITEMS/mcl_jukebox/mod.conf b/mods/ITEMS/mcl_jukebox/mod.conf index ad1f8c06a..9046ff7d3 100644 --- a/mods/ITEMS/mcl_jukebox/mod.conf +++ b/mods/ITEMS/mcl_jukebox/mod.conf @@ -1,3 +1,3 @@ name = mcl_jukebox description = Jukebox and music discs are used to play background music on a per-player basis. -depends = mcl_core, mcl_sounds +depends = mcl_core, mcl_sounds, mcl_colors diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 650e40ac3..1b7929722 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -2,7 +2,7 @@ local S = minetest.get_translator("mcl_mobitems") minetest.register_craftitem("mcl_mobitems:rotten_flesh", { description = S("Rotten Flesh"), - _tt_help = minetest.colorize("#FFFF00", S("80% chance of food poisoning")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("80% chance of food poisoning")), _doc_items_longdesc = S("Yuck! This piece of flesh clearly has seen better days. If you're really desperate, you can eat it to restore a few hunger points, but there's a 80% chance it causes food poisoning, which increases your hunger for a while."), inventory_image = "mcl_mobitems_rotten_flesh.png", wield_image = "mcl_mobitems_rotten_flesh.png", @@ -63,7 +63,7 @@ minetest.register_craftitem("mcl_mobitems:cooked_beef", { minetest.register_craftitem("mcl_mobitems:chicken", { description = S("Raw Chicken"), - _tt_help = minetest.colorize("#FFFF00", S("30% chance of food poisoning")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("30% chance of food poisoning")), _doc_items_longdesc = S("Raw chicken is a food item which is not safe to consume. You can eat it to restore a few hunger points, but there's a 30% chance to suffer from food poisoning, which increases your hunger rate for a while. Cooking raw chicken will make it safe to eat and increases its nutritional value."), inventory_image = "mcl_mobitems_chicken_raw.png", wield_image = "mcl_mobitems_chicken_raw.png", @@ -147,7 +147,7 @@ end minetest.register_craftitem("mcl_mobitems:milk_bucket", { description = S("Milk"), - _tt_help = minetest.colorize("#00FF00", S("Removes all status effects")), + _tt_help = minetest.colorize(mcl_colors.GREEN, S("Removes all status effects")), _doc_items_longdesc = S("Milk is very refreshing and can be obtained by using a bucket on a cow. Drinking it will remove all status effects, but restores no hunger points."), _doc_items_usagehelp = S("Use the placement key to drink the milk."), inventory_image = "mcl_mobitems_bucket_milk.png", @@ -160,7 +160,7 @@ minetest.register_craftitem("mcl_mobitems:milk_bucket", { minetest.register_craftitem("mcl_mobitems:spider_eye", { description = S("Spider Eye"), - _tt_help = minetest.colorize("#FFFF00", S("Poisonous")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("Poisonous")), _doc_items_longdesc = S("Spider eyes are used mainly in crafting. If you're really desperate, you can eat a spider eye, but it will poison you briefly."), inventory_image = "mcl_mobitems_spider_eye.png", wield_image = "mcl_mobitems_spider_eye.png", diff --git a/mods/ITEMS/mcl_mobitems/mod.conf b/mods/ITEMS/mcl_mobitems/mod.conf index dc85b6b01..e9604036e 100644 --- a/mods/ITEMS/mcl_mobitems/mod.conf +++ b/mods/ITEMS/mcl_mobitems/mod.conf @@ -1,2 +1,2 @@ name = mcl_mobitems -depends = mcl_core, mcl_hunger +depends = mcl_core, mcl_hunger, mcl_colors diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index 7c8dd56a5..467054767 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -95,7 +95,7 @@ minetest.register_node("mcl_nether:netherrack", { minetest.register_node("mcl_nether:magma", { description = S("Magma Block"), - _tt_help = minetest.colorize("#FFFF00", S("Burns your feet")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("Burns your feet")), _doc_items_longdesc = S("Magma blocks are hot solid blocks which hurt anyone standing on it, unless they have fire resistance. Starting a fire on this block will create an eternal fire."), stack_max = 64, tiles = {{name="mcl_nether_magma.png", animation={type="vertical_frames", aspect_w=32, aspect_h=32, length=1.5}}}, @@ -176,7 +176,7 @@ minetest.register_node("mcl_nether:nether_wart_block", { stack_max = 64, tiles = {"mcl_nether_nether_wart_block.png"}, is_ground_content = false, - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, sounds = mcl_sounds.node_sound_leaves_defaults( { footstep={name="default_dirt_footstep", gain=0.7}, diff --git a/mods/ITEMS/mcl_nether/mod.conf b/mods/ITEMS/mcl_nether/mod.conf index 807bf311e..8bef6c6c9 100644 --- a/mods/ITEMS/mcl_nether/mod.conf +++ b/mods/ITEMS/mcl_nether/mod.conf @@ -1,3 +1,3 @@ name = mcl_nether -depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items +depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items, mcl_colors optional_depends = mcl_death_messages, doc, screwdriver diff --git a/mods/ITEMS/mcl_ocean/kelp.lua b/mods/ITEMS/mcl_ocean/kelp.lua index 291a69520..c33303977 100644 --- a/mods/ITEMS/mcl_ocean/kelp.lua +++ b/mods/ITEMS/mcl_ocean/kelp.lua @@ -783,7 +783,7 @@ minetest.register_node("mcl_ocean:dried_kelp_block", { description = S("Dried Kelp Block"), _doc_items_longdesc = S("A decorative block that serves as a great furnace fuel."), tiles = { "mcl_ocean_dried_kelp_top.png", "mcl_ocean_dried_kelp_bottom.png", "mcl_ocean_dried_kelp_side.png" }, - groups = { handy = 1, building_block = 1, flammable = 2, fire_encouragement = 30, fire_flammability = 60 }, + groups = { handy = 1, hoey = 1, building_block = 1, flammable = 2, fire_encouragement = 30, fire_flammability = 60 }, sounds = mcl_sounds.node_sound_leaves_defaults(), paramtype2 = "facedir", on_place = mcl_util.rotate_axis, diff --git a/mods/ITEMS/mcl_portals/mod.conf b/mods/ITEMS/mcl_portals/mod.conf index b25ab391f..d99344a76 100644 --- a/mods/ITEMS/mcl_portals/mod.conf +++ b/mods/ITEMS/mcl_portals/mod.conf @@ -1,4 +1,4 @@ name = mcl_portals description = Adds buildable portals to the Nether and End dimensions. -depends = mcl_init, mcl_worlds, mcl_core, mcl_nether, mcl_end, mcl_particles, mcl_spawn +depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn optional_depends = awards, doc diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index ff9df2b4d..e842edf81 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -1,83 +1,206 @@ local S = minetest.get_translator("mcl_portals") --- Parameters +-- Localize functions for better performance +local abs = math.abs +local ceil = math.ceil +local floor = math.floor +local max = math.max +local min = math.min +local random = math.random +local dist = vector.distance +local add = vector.add +local mul = vector.multiply +local sub = vector.subtract -local OVERWORLD_TO_NETHER_SCALE = 8 -local LIMIT = math.min(math.abs(mcl_vars.mapgen_edge_min), math.abs(mcl_vars.mapgen_edge_max)) +-- Setup +local W_MIN, W_MAX = 4, 23 +local H_MIN, H_MAX = 5, 23 +local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2) +local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 1, 8 +local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max +local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again +local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds +local CHATTER_US = TOUCH_CHATTER_TIME * 1000000 +local DELAY = 3 -- seconds before teleporting in Nether portal in Survival mode (4 minus ABM interval time) +local DISTANCE_MAX = 128 +local PORTAL = "mcl_portals:portal" +local OBSIDIAN = "mcl_core:obsidian" +local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max_official, 2048) +local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max +local O_DY, N_DY = O_Y_MAX - O_Y_MIN + 1, N_Y_MAX - N_Y_MIN + 1 --- Portal frame sizes -local FRAME_SIZE_X_MIN = 4 -local FRAME_SIZE_Y_MIN = 5 -local FRAME_SIZE_X_MAX = 23 -local FRAME_SIZE_Y_MAX = 23 - -local PORTAL_NODES_MIN = 5 -local PORTAL_NODES_MAX = (FRAME_SIZE_X_MAX - 2) * (FRAME_SIZE_Y_MAX - 2) - -local TELEPORT_COOLOFF = 3 -- after player was teleported, for this many seconds they won't teleported again -local MOB_TELEPORT_COOLOFF = 14 -- after mob was teleported, for this many seconds they won't teleported again -local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds -local TOUCH_CHATTER_TIME_US = TOUCH_CHATTER_TIME * 1000000 -local TELEPORT_DELAY = 3 -- seconds before teleporting in Nether portal (4 minus ABM interval time) -local DESTINATION_EXPIRES = 60 * 1000000 -- cached destination expires after this number of microseconds have passed without using the same origin portal - -local PORTAL_SEARCH_HALF_CHUNK = 40 -- greater values may slow down the teleportation -local PORTAL_SEARCH_ALTITUDE = 128 - -local PORTAL_ALPHA = 192 -if minetest.features.use_texture_alpha_string_modes then - PORTAL_ALPHA = nil -end +-- Alpha and particles +local ALPHA = minetest.features.use_texture_alpha_string_modes and 192 +local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none" +local node_particles_levels = { none=0, low=1, medium=2, high=3 } +local PARTICLES = node_particles_levels[node_particles_allowed] -- Table of objects (including players) which recently teleported by a -- Nether portal. Those objects have a brief cooloff period before they -- can teleport again. This prevents annoying back-and-forth teleportation. -mcl_portals.nether_portal_cooloff = {} -local touch_chatter_prevention = {} +local cooloff = {} +function mcl_portals.nether_portal_cooloff(object) + return cooloff[object] +end -local overworld_ymin = math.max(mcl_vars.mg_overworld_min, -31) -local overworld_ymax = math.min(mcl_vars.mg_overworld_max_official, 63) -local nether_ymin = mcl_vars.mg_bedrock_nether_bottom_min -local nether_ymax = mcl_vars.mg_bedrock_nether_top_max -local overworld_dy = overworld_ymax - overworld_ymin + 1 -local nether_dy = nether_ymax - nether_ymin + 1 +local chatter = {} -local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none" -local node_particles_levels = { - high = 3, - medium = 2, - low = 1, - none = 0, +local queue = {} +local chunks = {} + +local storage = minetest.get_mod_storage() +local exits = {} +local keys = minetest.deserialize(storage:get_string("nether_exits_keys") or "return {}") or {} +for _, key in pairs(keys) do + local n = tonumber(key) + if n then + exits[key] = minetest.deserialize(storage:get_string("nether_exits_"..key) or "return {}") or {} + end +end +minetest.register_on_shutdown(function() + local keys={} + for key, data in pairs(exits) do + storage:set_string("nether_exits_"..tostring(key), minetest.serialize(data)) + keys[#keys+1] = key + end + storage:set_string("nether_exits_keys", minetest.serialize(keys)) +end) + +local get_node = mcl_vars.get_node +local set_node = minetest.set_node +local registered_nodes = minetest.registered_nodes +local is_protected = minetest.is_protected +local find_nodes_in_area = minetest.find_nodes_in_area +local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air +local log = minetest.log +local pos_to_string = minetest.pos_to_string +local is_area_protected = minetest.is_area_protected +local get_us_time = minetest.get_us_time + +local limits = { + nether = { + pmin = {x=LIM_MIN, y = N_Y_MIN, z = LIM_MIN}, + pmax = {x=LIM_MAX, y = N_Y_MAX, z = LIM_MAX}, + }, + overworld = { + pmin = {x=LIM_MIN, y = O_Y_MIN, z = LIM_MIN}, + pmax = {x=LIM_MAX, y = O_Y_MAX, z = LIM_MAX}, + }, } -local node_particles_allowed_level = node_particles_levels[node_particles_allowed] + +-- This function registers exits from Nether portals. +-- Incoming verification performed: two nodes must be portal nodes, and an obsidian below them. +-- If the verification passes - position adds to the table and saves to mod storage on exit. +local function add_exit(p) + if not p or not p.y or not p.z or not p.x then return end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local p = {x = x, y = y, z = z} + if get_node({x=x,y=y-1,z=z}).name ~= OBSIDIAN or get_node(p).name ~= PORTAL or get_node({x=x,y=y+1,z=z}).name ~= PORTAL then return end + local k = floor(z/256) * 256 + floor(x/256) + if not exits[k] then + exits[k]={} + end + local e = exits[k] + for i = 1, #e do + local t = e[i] + if t and t.x == p.x and t.y == p.y and t.z == p.z then + return + end + end + e[#e+1] = p + log("action", "[mcl_portals] Exit added at " .. pos_to_string(p)) +end + +-- This function removes Nether portals exits. +local function remove_exit(p) + if not p or not p.y or not p.z or not p.x then return end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local k = floor(z/256) * 256 + floor(x/256) + if not exits[k] then return end + local p = {x = x, y = y, z = z} + local e = exits[k] + if e then + for i, t in pairs(e) do + if t and t.x == x and t.y == y and t.z == z then + e[i] = nil + log("action", "[mcl_portals] Nether portal removed from " .. pos_to_string(p)) + return + end + end + end +end + +-- This functon searches Nether portal nodes whitin distance specified +local function find_exit(p, dx, dy, dz) + if not p or not p.y or not p.z or not p.x then return end + local dx, dy, dz = dx or DISTANCE_MAX, dy or DISTANCE_MAX, dz or DISTANCE_MAX + if dx < 1 or dy < 1 or dz < 1 then return false end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local x1, y1, z1, x2, y2, z2 = x-dx+1, y-dy+1, z-dz+1, x+dx-1, y+dy-1, z+dz-1 + local k1x, k2x = floor(x1/256), floor(x2/256) + local k1z, k2z = floor(z1/256), floor(z2/256) + + local t, d + for kx = k1x, k2x do for kz = k1z, k2z do + local k = kz*256 + kx + local e = exits[k] + if e then + for _, t0 in pairs(e) do + local d0 = dist(p, t0) + if not d or d>d0 then + d = d0 + t = t0 + if d==0 then return t end + end + end + end + end end + + if t and abs(t.x-p.x) <= dx and abs(t.y-p.y) <= dy and abs(t.z-p.z) <= dz then + return t + end +end --- Functions +-- Ping-Pong the coordinate for Fast Travelling, https://git.minetest.land/Wuzzy/MineClone2/issues/795#issuecomment-11058 +local function ping_pong(x, m, l1, l2) + if x < 0 then + return l1 + abs(((x*m+l1) % (l1*4)) - (l1*2)), floor(x*m/l1/2) + ((ceil(x*m/l1)+1)%2) * ((x*m)%l1)/l1 + end + return l2 - abs(((x*m+l2) % (l2*4)) - (l2*2)), floor(x*m/l2/2) + (floor(x*m/l2)%2) * ((x*m)%l2)/l2 +end --- Ping-Pong fast travel, https://git.minetest.land/Wuzzy/MineClone2/issues/795#issuecomment-11058 -local function nether_to_overworld(x) - return LIMIT - math.abs(((x * OVERWORLD_TO_NETHER_SCALE + LIMIT) % (LIMIT*4)) - (LIMIT*2)) +local function get_target(p) + if p and p.y and p.x and p.z then + local x, z = p.x, p.z + local y, d = mcl_worlds.y_to_layer(p.y) + local o1, o2 -- y offset + if y then + if d=="nether" then + x, o1 = ping_pong(x, TRAVEL_X, LIM_MIN, LIM_MAX) + z, o2 = ping_pong(z, TRAVEL_Z, LIM_MIN, LIM_MAX) + y = floor(y * TRAVEL_Y + (o1+o2) / 16 * LIM_MAX) + y = min(max(y + mcl_vars.mg_overworld_min, mcl_vars.mg_overworld_min), mcl_vars.mg_overworld_max) + elseif d=="overworld" then + x, y, z = floor(x / TRAVEL_X + 0.5), floor(y / TRAVEL_Y + 0.5), floor(z / TRAVEL_Z + 0.5) + y = min(max(y + mcl_vars.mg_nether_min, mcl_vars.mg_nether_min), mcl_vars.mg_nether_max) + end + return {x=x, y=y, z=z}, d + end + end end -- Destroy portal if pos (portal frame or portal node) got destroyed -local function destroy_nether_portal(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) +local function destroy_nether_portal(pos, node) + if not node then return end local nn, orientation = node.name, node.param2 - local obsidian = nn == "mcl_core:obsidian" + local obsidian = nn == OBSIDIAN - local has_meta = minetest.string_to_pos(meta:get_string("portal_frame1")) - if has_meta then - meta:set_string("portal_frame1", "") - meta:set_string("portal_frame2", "") - meta:set_string("portal_target", "") - meta:set_string("portal_time", "") - end local check_remove = function(pos, orientation) - local node = minetest.get_node(pos) - if node and (node.name == "mcl_portals:portal" and (orientation == nil or (node.param2 == orientation))) then - minetest.log("action", "[mcl_portal] Destroying Nether portal at " .. minetest.pos_to_string(pos)) - return minetest.remove_node(pos) + local node = get_node(pos) + if node and (node.name == PORTAL and (orientation == nil or (node.param2 == orientation))) then + minetest.remove_node(pos) + remove_exit(pos) end end if obsidian then -- check each of 6 sides of it and destroy every portal: @@ -89,9 +212,6 @@ local function destroy_nether_portal(pos) check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) return end - if not has_meta then -- no meta means repeated call: function calls on every node destruction - return - end if orientation == 0 then check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0) check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0) @@ -103,7 +223,7 @@ local function destroy_nether_portal(pos) check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) end -minetest.register_node("mcl_portals:portal", { +minetest.register_node(PORTAL, { description = S("Nether Portal"), _doc_items_longdesc = S("A Nether portal teleports creatures and objects to the hot and dangerous Nether dimension (and back!). Enter at your own risk!"), _doc_items_usagehelp = S("Stand in the portal for a moment to activate the teleportation. Entering a Nether portal for the first time will also create a new portal in the other dimension. If a Nether portal has been built in the Nether, it will lead to the Overworld. A Nether portal is destroyed if the any of the obsidian which surrounds it is destroyed, or if it was caught in an explosion."), @@ -143,7 +263,7 @@ minetest.register_node("mcl_portals:portal", { drop = "", light_source = 11, post_effect_color = {a = 180, r = 51, g = 7, b = 89}, - alpha = PORTAL_ALPHA, + alpha = ALPHA, node_box = { type = "fixed", fixed = { @@ -152,398 +272,293 @@ minetest.register_node("mcl_portals:portal", { }, groups = { creative_breakable = 1, portal = 1, not_in_creative_inventory = 1 }, sounds = mcl_sounds.node_sound_glass_defaults(), - on_destruct = destroy_nether_portal, + after_destruct = destroy_nether_portal, _mcl_hardness = -1, _mcl_blast_resistance = 0, }) -local function find_target_y(x, y, z, y_min, y_max) - local y_org = math.max(math.min(y, y_max), y_min) - local node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - return y_org +local function light_frame(x1, y1, z1, x2, y2, z2, name, node, node_frame) + local orientation = 0 + if x1 == x2 then + orientation = 1 end - while node.name ~= "air" and y < y_max do - y = y + 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - break - end - end - if node then - if node.name ~= "air" then - y = y_org - end - end - while node == nil and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - end - if y == y_max and node ~= nil then -- try reverse direction who knows what they built there... - while node.name ~= "air" and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - break - end - end - end - if node == nil then - return y_org - end - while node.name == "air" and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - while node == nil and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - end - if node == nil then - return y_org - end - end - if y == y_min then - return y_org - end - return math.max(math.min(y, y_max), y_min) -end - -local function find_nether_target_y(x, y, z) - local target_y = find_target_y(x, y, z, nether_ymin + 4, nether_ymax - 25) + 1 - minetest.log("verbose", "[mcl_portal] Found Nether target altitude: " .. tostring(target_y) .. " for pos. " .. minetest.pos_to_string({x = x, y = y, z = z})) - return target_y -end - -local function find_overworld_target_y(x, y, z) - local target_y = find_target_y(x, y, z, overworld_ymin + 4, overworld_ymax - 25) + 1 - local node = minetest.get_node({x = x, y = target_y - 1, z = z}) - if not node then - return target_y - end - local nn = node.name - if nn ~= "air" and minetest.get_item_group(nn, "water") == 0 then - target_y = target_y + 1 - end - minetest.log("verbose", "[mcl_portal] Found Overworld target altitude: " .. tostring(target_y) .. " for pos. " .. minetest.pos_to_string({x = x, y = y, z = z})) - return target_y -end - - -local function update_target(pos, target, time_str) - local stack = {{x = pos.x, y = pos.y, z = pos.z}} - while #stack > 0 do - local i = #stack - local meta = minetest.get_meta(stack[i]) - if meta:get_string("portal_time") == time_str then - stack[i] = nil -- Already updated, skip it - else - local node = minetest.get_node(stack[i]) - local portal = node.name == "mcl_portals:portal" - if not portal then - stack[i] = nil - else - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", time_str) - meta:set_string("portal_target", target) - stack[i].y = y - 1 - stack[i + 1] = {x = x, y = y + 1, z = z} - if node.param2 == 0 then - stack[i + 2] = {x = x - 1, y = y, z = z} - stack[i + 3] = {x = x + 1, y = y, z = z} + local pos = {} + local node = node or {name = PORTAL, param2 = orientation} + local node_frame = node_frame or {name = OBSIDIAN} + for x = x1 - 1 + orientation, x2 + 1 - orientation do + pos.x = x + for z = z1 - orientation, z2 + orientation do + pos.z = z + for y = y1 - 1, y2 + 1 do + pos.y = y + local frame = (x < x1) or (x > x2) or (y < y1) or (y > y2) or (z < z1) or (z > z2) + if frame then + set_node(pos, node_frame) else - stack[i + 2] = {x = x, y = y, z = z - 1} - stack[i + 3] = {x = x, y = y, z = z + 1} + set_node(pos, node) + add_exit({x=pos.x, y=pos.y-1, z=pos.z}) end end end end end -local function ecb_setup_target_portal(blockpos, action, calls_remaining, param) - -- param.: srcx, srcy, srcz, dstx, dsty, dstz, srcdim, ax1, ay1, az1, ax2, ay2, az2 +--Build arrival portal +function build_nether_portal(pos, width, height, orientation, name, clear_before_build) + local width, height, orientation = width or W_MIN - 2, height or H_MIN - 2, orientation or random(0, 1) - local portal_search = function(target, p1, p2) - local portal_nodes = minetest.find_nodes_in_area(p1, p2, "mcl_portals:portal") - local portal_pos = false - if portal_nodes and #portal_nodes > 0 then - -- Found some portal(s), use nearest: - portal_pos = {x = portal_nodes[1].x, y = portal_nodes[1].y, z = portal_nodes[1].z} - local nearest_distance = vector.distance(target, portal_pos) - for n = 2, #portal_nodes do - local distance = vector.distance(target, portal_nodes[n]) - if distance < nearest_distance then - portal_pos = {x = portal_nodes[n].x, y = portal_nodes[n].y, z = portal_nodes[n].z} - nearest_distance = distance - end - end - end -- here we have the best portal_pos - return portal_pos + if clear_before_build then + light_frame(pos.x, pos.y, pos.z, pos.x + (1 - orientation) * (width - 1), pos.y + height - 1, pos.z + orientation * (width - 1), name, {name="air"}, {name="air"}) end + light_frame(pos.x, pos.y, pos.z, pos.x + (1 - orientation) * (width - 1), pos.y + height - 1, pos.z + orientation * (width - 1), name) - if calls_remaining <= 0 then - minetest.log("action", "[mcl_portal] Area for destination Nether portal emerged!") - local src_pos = {x = param.srcx, y = param.srcy, z = param.srcz} - local dst_pos = {x = param.dstx, y = param.dsty, z = param.dstz} - local meta = minetest.get_meta(src_pos) - local portal_pos = portal_search(dst_pos, {x = param.ax1, y = param.ay1, z = param.az1}, {x = param.ax2, y = param.ay2, z = param.az2}) - - if portal_pos == false then - minetest.log("verbose", "[mcl_portal] No portal in area " .. minetest.pos_to_string({x = param.ax1, y = param.ay1, z = param.az1}) .. "-" .. minetest.pos_to_string({x = param.ax2, y = param.ay2, z = param.az2})) - -- Need to build arrival portal: - local org_dst_y = dst_pos.y - if param.srcdim == "overworld" then - dst_pos.y = find_nether_target_y(dst_pos.x, dst_pos.y, dst_pos.z) - else - dst_pos.y = find_overworld_target_y(dst_pos.x, dst_pos.y, dst_pos.z) - end - if math.abs(org_dst_y - dst_pos.y) >= PORTAL_SEARCH_ALTITUDE / 2 then - portal_pos = portal_search(dst_pos, - {x = dst_pos.x - PORTAL_SEARCH_HALF_CHUNK, y = math.floor(dst_pos.y - PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z - PORTAL_SEARCH_HALF_CHUNK}, - {x = dst_pos.x + PORTAL_SEARCH_HALF_CHUNK, y = math.ceil(dst_pos.y + PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z + PORTAL_SEARCH_HALF_CHUNK} - ) - end - if portal_pos == false then - minetest.log("verbose", "[mcl_portal] 2nd attempt: No portal in area " .. minetest.pos_to_string({x = dst_pos.x - PORTAL_SEARCH_HALF_CHUNK, y = math.floor(dst_pos.y - PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z - PORTAL_SEARCH_HALF_CHUNK}) .. "-" .. minetest.pos_to_string({x = dst_pos.x + PORTAL_SEARCH_HALF_CHUNK, y = math.ceil(dst_pos.y + PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z + PORTAL_SEARCH_HALF_CHUNK})) - local width, height = 2, 3 - portal_pos = mcl_portals.build_nether_portal(dst_pos, width, height) + -- Build obsidian platform: + for x = pos.x - orientation, pos.x + orientation + (width - 1) * (1 - orientation), 1 + orientation do + for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width - 1) * orientation, 2 - orientation do + local pp = {x = x, y = pos.y - 1, z = z} + local pp_1 = {x = x, y = pos.y - 2, z = z} + local nn = get_node(pp).name + local nn_1 = get_node(pp_1).name + if ((nn=="air" and nn_1 == "air") or not registered_nodes[nn].is_ground_content) and not is_protected(pp, name) then + set_node(pp, {name = OBSIDIAN}) end end + end - local target_meta = minetest.get_meta(portal_pos) - local p3 = minetest.string_to_pos(target_meta:get_string("portal_frame1")) - local p4 = minetest.string_to_pos(target_meta:get_string("portal_frame2")) - if p3 and p4 then - portal_pos = vector.divide(vector.add(p3, p4), 2.0) - portal_pos.y = math.min(p3.y, p4.y) - portal_pos = vector.round(portal_pos) - local node = minetest.get_node(portal_pos) - if node and node.name ~= "mcl_portals:portal" then - portal_pos = {x = p3.x, y = p3.y, z = p3.z} - if minetest.get_node(portal_pos).name == "mcl_core:obsidian" then - -- Old-version portal: - if p4.z == p3.z then - portal_pos = {x = p3.x + 1, y = p3.y + 1, z = p3.z} - else - portal_pos = {x = p3.x, y = p3.y + 1, z = p3.z + 1} + log("action", "[mcl_portals] Destination Nether portal generated at "..pos_to_string(pos).."!") + + return pos +end + +function mcl_portals.spawn_nether_portal(pos, rot, pr, name) + if not pos then return end + local o = 0 + if rot then + if rot == "270" or rot=="90" then + o = 1 + elseif rot == "random" then + o = random(0,1) + end + end + build_nether_portal(pos, nil, nil, o, name, true) +end + +-- Teleportation cooloff for some seconds, to prevent back-and-forth teleportation +local function stop_teleport_cooloff(o) + cooloff[o] = nil + chatter[o] = nil +end + +local function teleport_cooloff(obj) + cooloff[obj] = true + if obj:is_player() then + minetest.after(PLAYER_COOLOFF, stop_teleport_cooloff, obj) + else + minetest.after(MOB_COOLOFF, stop_teleport_cooloff, obj) + end +end + +local function finalize_teleport(obj, exit) + if not obj or not exit or not exit.x or not exit.y or not exit.z then return end + + local objpos = obj:get_pos() + if not objpos then return end + + local is_player = obj:is_player() + local name + if is_player then + name = obj:get_player_name() + end + local y, dim = mcl_worlds.y_to_layer(exit.y) + + + -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y + objpos = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + if get_node(objpos).name ~= PORTAL then return end + + -- THIS IS A TEMPORATY CODE SECTION FOR COMPATIBILITY REASONS -- 1 of 2 -- TODO: Remove -- + -- Old worlds have no exits indexed - adding the exit to return here: + add_exit(objpos) + -- TEMPORATY CODE SECTION ENDS HERE -- + + + -- Enable teleportation cooloff for some seconds, to prevent back-and-forth teleportation + teleport_cooloff(obj) + + -- Teleport + obj:set_pos(exit) + + if is_player then + mcl_worlds.dimension_change(obj, dim) + minetest.sound_play("mcl_portals_teleport", {pos=exit, gain=0.5, max_hear_distance = 16}, true) + log("action", "[mcl_portals] player "..name.." teleported to Nether portal at "..pos_to_string(exit)..".") + else + log("action", "[mcl_portals] entity teleported to Nether portal at "..pos_to_string(exit)..".") + end +end + +local function create_portal_2(pos1, name, obj) + local orientation = 0 + local pos2 = {x = pos1.x + 3, y = pos1.y + 3, z = pos1.z + 3} + local nodes = find_nodes_in_area(pos1, pos2, {"air"}) + if #nodes == 64 then + orientation = random(0,1) + else + pos2.x = pos2.x - 1 + nodes = find_nodes_in_area(pos1, pos2, {"air"}) + if #nodes == 48 then + orientation = 1 + end + end + local exit = build_nether_portal(pos1, W_MIN-2, H_MIN-2, orientation, name) + finalize_teleport(obj, exit) + local cn = mcl_vars.get_chunk_number(pos1) + chunks[cn] = nil + if queue[cn] then + for next_obj, _ in pairs(queue[cn]) do + if next_obj ~= obj then + finalize_teleport(next_obj, exit) + end + end + queue[cn] = nil + end +end + +local function get_lava_level(pos, pos1, pos2) + if pos.y > -1000 then + return max(min(mcl_vars.mg_lava_overworld_max, pos2.y-1), pos1.y+1) + end + return max(min(mcl_vars.mg_lava_nether_max, pos2.y-1), pos1.y+1) +end + +local function ecb_scan_area_2(blockpos, action, calls_remaining, param) + if calls_remaining and calls_remaining > 0 then return end + local pos, pos1, pos2, name, obj = param.pos, param.pos1, param.pos2, param.name or "", param.obj + local pos0, distance + local lava = get_lava_level(pos, pos1, pos2) + + -- THIS IS A TEMPORATY CODE SECTION FOR COMPATIBILITY REASONS -- 2 of 2 -- TODO: Remove -- + -- Find portals for old worlds (new worlds keep them all in the table): + local portals = find_nodes_in_area(pos1, pos2, {PORTAL}) + if portals and #portals>0 then + for _, p in pairs(portals) do + add_exit(p) + end + local exit = find_exit(pos) + if exit then + finalize_teleport(obj, exit) + end + return + end + -- TEMPORATY CODE SECTION ENDS HERE -- + + + local nodes = find_nodes_in_area_under_air(pos1, pos2, {"group:building_block"}) + if nodes then + local nc = #nodes + if nc > 0 then + log("action", "[mcl_portals] Area for destination Nether portal emerged! Found " .. tostring(nc) .. " nodes under the air around "..pos_to_string(pos)) + for i=1,nc do + local node = nodes[i] + local node1 = {x=node.x, y=node.y+1, z=node.z } + local node2 = {x=node.x+2, y=node.y+3, z=node.z+2} + local nodes2 = find_nodes_in_area(node1, node2, {"air"}) + if nodes2 then + local nc2 = #nodes2 + if nc2 == 27 and not is_area_protected(node, node2, name) then + local distance0 = dist(pos, node) + if distance0 < 2 then + log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") + create_portal_2(node1, name, obj) + return + end + if not distance or (distance0 < distance) or (distance0 < distance-1 and node.y > lava and pos0.y < lava) then + log("action", "[mcl_portals] found distance "..tostring(distance0).." at pos "..pos_to_string(node)) + distance = distance0 + pos0 = {x=node1.x, y=node1.y, z=node1.z} + end end end end end - local time_str = tostring(minetest.get_us_time()) - local target = minetest.pos_to_string(portal_pos) - - update_target(src_pos, target, time_str) end -end - -local function nether_portal_get_target_position(src_pos) - local _, current_dimension = mcl_worlds.y_to_layer(src_pos.y) - local x, y, z, y_min, y_max = 0, 0, 0, 0, 0 - if current_dimension == "nether" then - x = math.floor(nether_to_overworld(src_pos.x) + 0.5) - z = math.floor(nether_to_overworld(src_pos.z) + 0.5) - y = math.floor((math.min(math.max(src_pos.y, nether_ymin), nether_ymax) - nether_ymin) / nether_dy * overworld_dy + overworld_ymin + 0.5) - y_min = overworld_ymin - y_max = overworld_ymax - else -- overworld: - x = math.floor(src_pos.x / OVERWORLD_TO_NETHER_SCALE + 0.5) - z = math.floor(src_pos.z / OVERWORLD_TO_NETHER_SCALE + 0.5) - y = math.floor((math.min(math.max(src_pos.y, overworld_ymin), overworld_ymax) - overworld_ymin) / overworld_dy * nether_dy + nether_ymin + 0.5) - y_min = nether_ymin - y_max = nether_ymax + if distance then -- several nodes of air might be better than lava lake, right? + log("action", "[mcl_portals] using backup pos "..pos_to_string(pos0).." to create a portal") + create_portal_2(pos0, name, obj) + return end - return x, y, z, current_dimension, y_min, y_max -end - -local function find_or_create_portal(src_pos) - local x, y, z, cdim, y_min, y_max = nether_portal_get_target_position(src_pos) - local pos1 = {x = x - PORTAL_SEARCH_HALF_CHUNK, y = math.max(y_min, math.floor(y - PORTAL_SEARCH_ALTITUDE / 2)), z = z - PORTAL_SEARCH_HALF_CHUNK} - local pos2 = {x = x + PORTAL_SEARCH_HALF_CHUNK, y = math.min(y_max, math.ceil(y + PORTAL_SEARCH_ALTITUDE / 2)), z = z + PORTAL_SEARCH_HALF_CHUNK} - if pos1.y == y_min then - pos2.y = math.min(y_max, pos1.y + PORTAL_SEARCH_ALTITUDE) + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") + if pos.y < lava then + pos.y = lava + 1 else - if pos2.y == y_max then - pos1.y = math.max(y_min, pos2.y - PORTAL_SEARCH_ALTITUDE) - end + pos.y = pos.y + 1 end - minetest.emerge_area(pos1, pos2, ecb_setup_target_portal, {srcx=src_pos.x, srcy=src_pos.y, srcz=src_pos.z, dstx=x, dsty=y, dstz=z, srcdim=cdim, ax1=pos1.x, ay1=pos1.y, az1=pos1.z, ax2=pos2.x, ay2=pos2.y, az2=pos2.z}) + create_portal_2(pos, name, obj) end -local function emerge_target_area(src_pos) - local x, y, z, cdim, y_min, y_max = nether_portal_get_target_position(src_pos) - local pos1 = {x = x - PORTAL_SEARCH_HALF_CHUNK, y = math.max(y_min + 2, math.floor(y - PORTAL_SEARCH_ALTITUDE / 2)), z = z - PORTAL_SEARCH_HALF_CHUNK} - local pos2 = {x = x + PORTAL_SEARCH_HALF_CHUNK, y = math.min(y_max - 2, math.ceil(y + PORTAL_SEARCH_ALTITUDE / 2)), z = z + PORTAL_SEARCH_HALF_CHUNK} - minetest.emerge_area(pos1, pos2) - pos1 = {x = x - 1, y = y_min, z = z - 1} - pos2 = {x = x + 1, y = y_max, z = z + 1} - minetest.emerge_area(pos1, pos2) +local function create_portal(pos, limit1, limit2, name, obj) + local cn = mcl_vars.get_chunk_number(pos) + if chunks[cn] then + local q = queue[cn] or {} + q[obj] = true + queue[cn] = q + return + end + chunks[cn] = true + + -- we need to emerge the area here, but currently (mt5.4/mcl20.71) map generation is slow + -- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum + + local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) + local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + + if limit1 and limit1.x and limit1.y and limit1.z then + pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)} + end + if limit2 and limit2.x and limit2.y and limit2.z then + pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)} + end + + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) end local function available_for_nether_portal(p) - local nn = minetest.get_node(p).name - local obsidian = nn == "mcl_core:obsidian" + local nn = get_node(p).name + local obsidian = nn == OBSIDIAN if nn ~= "air" and minetest.get_item_group(nn, "fire") ~= 1 then return false, obsidian end return true, obsidian end -local function light_frame(x1, y1, z1, x2, y2, z2, build_frame) - local build_frame = build_frame or false - local orientation = 0 - if x1 == x2 then - orientation = 1 - end - local disperse = 50 - local pass = 1 - while true do - local protection = false - - for x = x1 - 1 + orientation, x2 + 1 - orientation do - for z = z1 - orientation, z2 + orientation do - for y = y1 - 1, y2 + 1 do - local frame = (x < x1) or (x > x2) or (y < y1) or (y > y2) or (z < z1) or (z > z2) - if frame then - if build_frame then - if pass == 1 then - if minetest.is_protected({x = x, y = y, z = z}, "") then - protection = true - local offset_x = math.random(-disperse, disperse) - local offset_z = math.random(-disperse, disperse) - disperse = disperse + math.random(25, 177) - if disperse > 5000 then - return nil - end - x1, z1 = x1 + offset_x, z1 + offset_z - x2, z2 = x2 + offset_x, z2 + offset_z - local _, dimension = mcl_worlds.y_to_layer(y1) - local height = math.abs(y2 - y1) - y1 = (y1 + y2) / 2 - if dimension == "nether" then - y1 = find_nether_target_y(math.min(x1, x2), y1, math.min(z1, z2)) - else - y1 = find_overworld_target_y(math.min(x1, x2), y1, math.min(z1, z2)) - end - y2 = y1 + height - break - end - else - minetest.set_node({x = x, y = y, z = z}, {name = "mcl_core:obsidian"}) - end - end - else - if not build_frame or pass == 2 then - local node = minetest.get_node({x = x, y = y, z = z}) - minetest.set_node({x = x, y = y, z = z}, {name = "mcl_portals:portal", param2 = orientation}) - end - end - if not frame and pass == 2 then - local meta = minetest.get_meta({x = x, y = y, z = z}) - -- Portal frame corners - meta:set_string("portal_frame1", minetest.pos_to_string({x = x1, y = y1, z = z1})) - meta:set_string("portal_frame2", minetest.pos_to_string({x = x2, y = y2, z = z2})) - -- Portal target coordinates - meta:set_string("portal_target", "") - -- Portal last teleportation time - meta:set_string("portal_time", tostring(0)) - end - end - if protection then - break - end - end - if protection then - break - end - end - if build_frame == false or pass == 2 then - break - end - if build_frame and not protection and pass == 1 then - pass = 2 - end - end - emerge_target_area({x = x1, y = y1, z = z1}) - return {x = x1, y = y1, z = z1} -end - ---Build arrival portal -function mcl_portals.build_nether_portal(pos, width, height, orientation) - local height = height or FRAME_SIZE_Y_MIN - 2 - local width = width or FRAME_SIZE_X_MIN - 2 - local orientation = orientation or math.random(0, 1) - - if orientation == 0 then - minetest.load_area({x = pos.x - 3, y = pos.y - 1, z = pos.z - width * 2}, {x = pos.x + width + 2, y = pos.y + height + 2, z = pos.z + width * 2}) - else - minetest.load_area({x = pos.x - width * 2, y = pos.y - 1, z = pos.z - 3}, {x = pos.x + width * 2, y = pos.y + height + 2, z = pos.z + width + 2}) - end - - pos = light_frame(pos.x, pos.y, pos.z, pos.x + (1 - orientation) * (width - 1), pos.y + height - 1, pos.z + orientation * (width - 1), true) - - -- Clear some space around: - for x = pos.x - math.random(2 + (width-2)*( orientation), 5 + (2*width-5)*( orientation)), pos.x + width*(1-orientation) + math.random(2+(width-2)*( orientation), 4 + (2*width-4)*( orientation)) do - for z = pos.z - math.random(2 + (width-2)*(1-orientation), 5 + (2*width-5)*(1-orientation)), pos.z + width*( orientation) + math.random(2+(width-2)*(1-orientation), 4 + (2*width-4)*(1-orientation)) do - for y = pos.y - 1, pos.y + height + math.random(1,6) do - local nn = minetest.get_node({x = x, y = y, z = z}).name - if nn ~= "mcl_core:obsidian" and nn ~= "mcl_portals:portal" and minetest.registered_nodes[nn].is_ground_content and not minetest.is_protected({x = x, y = y, z = z}, "") then - minetest.remove_node({x = x, y = y, z = z}) - end - end - end - end - - -- Build obsidian platform: - for x = pos.x - orientation, pos.x + orientation + (width - 1) * (1 - orientation), 1 + orientation do - for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width - 1) * orientation, 2 - orientation do - local pp = {x = x, y = pos.y - 1, z = z} - local nn = minetest.get_node(pp).name - if not minetest.registered_nodes[nn].is_ground_content and not minetest.is_protected(pp, "") then - minetest.set_node(pp, {name = "mcl_core:obsidian"}) - end - end - end - - minetest.log("action", "[mcl_portal] Destination Nether portal generated at "..minetest.pos_to_string(pos).."!") - - return pos -end - local function check_and_light_shape(pos, orientation) local stack = {{x = pos.x, y = pos.y, z = pos.z}} local node_list = {} + local index_list = {} local node_counter = 0 -- Search most low node from the left (pos1) and most right node from the top (pos2) local pos1 = {x = pos.x, y = pos.y, z = pos.z} local pos2 = {x = pos.x, y = pos.y, z = pos.z} - local wrong_portal_nodes_clean_up = function(node_list) - for i = 1, #node_list do - local meta = minetest.get_meta(node_list[i]) - meta:set_string("portal_time", "") - end - return false - end - + local kx, ky, kz = pos.x - 1999, pos.y - 1999, pos.z - 1999 while #stack > 0 do local i = #stack - local meta = minetest.get_meta(stack[i]) - local target = meta:get_string("portal_time") - if target and target == "-2" then + local x, y, z = stack[i].x, stack[i].y, stack[i].z + local k = (x-kx)*16000000 + (y-ky)*4000 + z-kz + if index_list[k] then stack[i] = nil -- Already checked, skip it else local good, obsidian = available_for_nether_portal(stack[i]) if obsidian then stack[i] = nil else - if (not good) or (node_counter >= PORTAL_NODES_MAX) then - return wrong_portal_nodes_clean_up(node_list) + if (not good) or (node_counter >= N_MAX) then + return false end - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", "-2") node_counter = node_counter + 1 node_list[node_counter] = {x = x, y = y, z = z} + index_list[k] = true stack[i].y = y - 1 stack[i + 1] = {x = x, y = y + 1, z = z} if orientation == 0 then @@ -563,24 +578,19 @@ local function check_and_light_shape(pos, orientation) end end - if node_counter < PORTAL_NODES_MIN then - return wrong_portal_nodes_clean_up(node_list) + if node_counter < N_MIN then + return false end -- Limit rectangles width and height - if math.abs(pos2.x - pos1.x + pos2.z - pos1.z) + 3 > FRAME_SIZE_X_MAX or math.abs(pos2.y - pos1.y) + 3 > FRAME_SIZE_Y_MAX then - return wrong_portal_nodes_clean_up(node_list) + if abs(pos2.x - pos1.x + pos2.z - pos1.z) + 3 > W_MAX or abs(pos2.y - pos1.y) + 3 > H_MAX then + return false end for i = 1, node_counter do local node_pos = node_list[i] - local node = minetest.get_node(node_pos) - minetest.set_node(node_pos, {name = "mcl_portals:portal", param2 = orientation}) - local meta = minetest.get_meta(node_pos) - meta:set_string("portal_frame1", minetest.pos_to_string(pos1)) - meta:set_string("portal_frame2", minetest.pos_to_string(pos2)) - meta:set_string("portal_time", tostring(0)) - meta:set_string("portal_target", "") + minetest.set_node(node_pos, {name = PORTAL, param2 = orientation}) + add_exit(node_pos) end return true end @@ -596,9 +606,14 @@ function mcl_portals.light_nether_portal(pos) if dim ~= "overworld" and dim ~= "nether" then return false end - local orientation = math.random(0, 1) + local orientation = random(0, 1) for orientation_iteration = 1, 2 do if check_and_light_shape(pos, orientation) then + minetest.after(0.2, function(pos) -- generate target map chunk + local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) + local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + minetest.emerge_area(pos1, pos2) + end, vector.new(pos)) return true end orientation = 1 - orientation @@ -606,126 +621,50 @@ function mcl_portals.light_nether_portal(pos) return false end -local function update_portal_time(pos, time_str) - local stack = {{x = pos.x, y = pos.y, z = pos.z}} - while #stack > 0 do - local i = #stack - local meta = minetest.get_meta(stack[i]) - if meta:get_string("portal_time") == time_str then - stack[i] = nil -- Already updated, skip it - else - local node = minetest.get_node(stack[i]) - local portal = node.name == "mcl_portals:portal" - if not portal then - stack[i] = nil - else - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", time_str) - stack[i].y = y - 1 - stack[i + 1] = {x = x, y = y + 1, z = z} - if node.param2 == 0 then - stack[i + 2] = {x = x - 1, y = y, z = z} - stack[i + 3] = {x = x + 1, y = y, z = z} - else - stack[i + 2] = {x = x, y = y, z = z - 1} - stack[i + 3] = {x = x, y = y, z = z + 1} - end - end - end - end -end - -local function prepare_target(pos) - local meta, us_time = minetest.get_meta(pos), minetest.get_us_time() - local portal_time = tonumber(meta:get_string("portal_time")) or 0 - local delta_time_us = us_time - portal_time - local pos1, pos2 = minetest.string_to_pos(meta:get_string("portal_frame1")), minetest.string_to_pos(meta:get_string("portal_frame2")) - if delta_time_us <= DESTINATION_EXPIRES then - -- Destination point must be still cached according to https://minecraft.gamepedia.com/Nether_portal - return update_portal_time(pos, tostring(us_time)) - end - -- No cached destination point - find_or_create_portal(pos) -end - --- Teleportation cooloff for some seconds, to prevent back-and-forth teleportation -local function stop_teleport_cooloff(o) - mcl_portals.nether_portal_cooloff[o] = false - touch_chatter_prevention[o] = nil -end - -local function teleport_cooloff(obj) - if obj:is_player() then - minetest.after(TELEPORT_COOLOFF, stop_teleport_cooloff, obj) - else - minetest.after(MOB_TELEPORT_COOLOFF, stop_teleport_cooloff, obj) - end -end - -- Teleport function local function teleport_no_delay(obj, pos) local is_player = obj:is_player() - if (not obj:get_luaentity()) and (not is_player) then - return - end + if (not is_player and not obj:get_luaentity()) or cooloff[obj] then return end local objpos = obj:get_pos() - if objpos == nil then - return - end + if not objpos then return end - if mcl_portals.nether_portal_cooloff[obj] then - return - end - -- If player stands, player is at ca. something+0.5 - -- which might cause precision problems, so we used ceil. - objpos.y = math.ceil(objpos.y) + -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y + objpos = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + if get_node(objpos).name ~= PORTAL then return end - if minetest.get_node(objpos).name ~= "mcl_portals:portal" then - return - end - - local meta = minetest.get_meta(pos) - local delta_time = minetest.get_us_time() - (tonumber(meta:get_string("portal_time")) or 0) - local target = minetest.string_to_pos(meta:get_string("portal_target")) - if delta_time > DESTINATION_EXPIRES or target == nil then - -- Area not ready yet - retry after a second - return minetest.after(1, teleport_no_delay, obj, pos) - end - - -- Enable teleportation cooloff for some seconds, to prevent back-and-forth teleportation - teleport_cooloff(obj) - mcl_portals.nether_portal_cooloff[obj] = true - - -- Teleport - obj:set_pos(target) + local target, dim = get_target(objpos) + if not target then return end + local name if is_player then - mcl_worlds.dimension_change(obj, mcl_worlds.pos_to_dimension(target)) - minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16}, true) - local name = obj:get_player_name() - minetest.log("action", "[mcl_portal] "..name.." teleported to Nether portal at "..minetest.pos_to_string(target)..".") + name = obj:get_player_name() + end + + local exit = find_exit(target) + if exit then + finalize_teleport(obj, exit) + else + -- need to create arrival portal + create_portal(target, limits[dim].pmin, limits[dim].pmax, name, obj) end end local function prevent_portal_chatter(obj) - local time_us = minetest.get_us_time() - local chatter = touch_chatter_prevention[obj] or 0 - touch_chatter_prevention[obj] = time_us + local time_us = get_us_time() + local ch = chatter[obj] or 0 + chatter[obj] = time_us minetest.after(TOUCH_CHATTER_TIME, function(o) - if not o or not touch_chatter_prevention[o] then - return - end - if minetest.get_us_time() - touch_chatter_prevention[o] >= TOUCH_CHATTER_TIME_US then - touch_chatter_prevention[o] = nil + if o and chatter[o] and get_us_time() - chatter[o] >= CHATTER_US then + chatter[o] = nil end end, obj) - return time_us - chatter > TOUCH_CHATTER_TIME_US + return time_us - ch > CHATTER_US end local function animation(player, playername) - local chatter = touch_chatter_prevention[player] or 0 - if mcl_portals.nether_portal_cooloff[player] or minetest.get_us_time() - chatter < TOUCH_CHATTER_TIME_US then + local ch = chatter[player] or 0 + if cooloff[player] or get_us_time() - ch < CHATTER_US then local pos = player:get_pos() if not pos then return @@ -756,36 +695,35 @@ local function teleport(obj, portal_pos) name = obj:get_player_name() animation(obj, name) end - -- Call prepare_target() first because it might take a long - prepare_target(portal_pos) - -- Prevent quick back-and-forth teleportation - if not mcl_portals.nether_portal_cooloff[obj] then - local creative_enabled = minetest.is_creative_enabled(name) - if creative_enabled then - return teleport_no_delay(obj, portal_pos) - end - minetest.after(TELEPORT_DELAY, teleport_no_delay, obj, portal_pos) + + if cooloff[obj] then return end + + if minetest.is_creative_enabled(name) then + teleport_no_delay(obj, portal_pos) + return end + + minetest.after(DELAY, teleport_no_delay, obj, portal_pos) end minetest.register_abm({ label = "Nether portal teleportation and particles", - nodenames = {"mcl_portals:portal"}, + nodenames = {PORTAL}, interval = 1, chance = 1, action = function(pos, node) local o = node.param2 -- orientation - local d = math.random(0, 1) -- direction - local time = math.random() * 1.9 + 0.5 + local d = random(0, 1) -- direction + local time = random() * 1.9 + 0.5 local velocity, acceleration if o == 1 then - velocity = {x = math.random() * 0.7 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5} - acceleration = {x = math.random() * 1.1 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5} + velocity = {x = random() * 0.7 + 0.3, y = random() - 0.5, z = random() - 0.5} + acceleration = {x = random() * 1.1 + 0.3, y = random() - 0.5, z = random() - 0.5} else - velocity = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 0.7 + 0.3} - acceleration = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 1.1 + 0.3} + velocity = {x = random() - 0.5, y = random() - 0.5, z = random() * 0.7 + 0.3} + acceleration = {x = random() - 0.5, y = random() - 0.5, z = random() * 1.1 + 0.3} end - local distance = vector.add(vector.multiply(velocity, time), vector.multiply(acceleration, time * time / 2)) + local distance = add(mul(velocity, time), mul(acceleration, time * time / 2)) if d == 1 then if o == 1 then distance.x = -distance.x @@ -797,11 +735,11 @@ minetest.register_abm({ acceleration.z = -acceleration.z end end - distance = vector.subtract(pos, distance) + distance = sub(pos, distance) for _, obj in pairs(minetest.get_objects_inside_radius(pos, 15)) do if obj:is_player() then minetest.add_particlespawner({ - amount = node_particles_allowed_level + 1, + amount = PARTICLES + 1, minpos = distance, maxpos = distance, minvel = velocity, @@ -830,14 +768,14 @@ minetest.register_abm({ --[[ ITEM OVERRIDES ]] -local longdesc = minetest.registered_nodes["mcl_core:obsidian"]._doc_items_longdesc +local longdesc = registered_nodes[OBSIDIAN]._doc_items_longdesc longdesc = longdesc .. "\n" .. S("Obsidian is also used as the frame of Nether portals.") local usagehelp = S("To open a Nether portal, place an upright frame of obsidian with a width of at least 4 blocks and a height of 5 blocks, leaving only air in the center. After placing this frame, light a fire in the obsidian frame. Nether portals only work in the Overworld and the Nether.") -minetest.override_item("mcl_core:obsidian", { +minetest.override_item(OBSIDIAN, { _doc_items_longdesc = longdesc, _doc_items_usagehelp = usagehelp, - on_destruct = destroy_nether_portal, + after_destruct = destroy_nether_portal, _on_ignite = function(user, pointed_thing) local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z -- Check empty spaces around obsidian and light all frames found: @@ -846,9 +784,9 @@ minetest.override_item("mcl_core:obsidian", { mcl_portals.light_nether_portal({x = x, y = y - 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y + 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y, z = z - 1}) or mcl_portals.light_nether_portal({x = x, y = y, z = z + 1}) if portals_placed then - minetest.log("action", "[mcl_portal] Nether portal activated at "..minetest.pos_to_string({x=x,y=y,z=z})..".") + log("action", "[mcl_portals] Nether portal activated at "..pos_to_string({x=x,y=y,z=z})..".") if minetest.get_modpath("doc") then - doc.mark_entry_as_revealed(user:get_player_name(), "nodes", "mcl_portals:portal") + doc.mark_entry_as_revealed(user:get_player_name(), "nodes", PORTAL) -- Achievement for finishing a Nether portal TO the Nether local dim = mcl_worlds.pos_to_dimension({x=x, y=y, z=z}) diff --git a/mods/ITEMS/mcl_sponges/init.lua b/mods/ITEMS/mcl_sponges/init.lua index 4a2107f88..b832c01c6 100644 --- a/mods/ITEMS/mcl_sponges/init.lua +++ b/mods/ITEMS/mcl_sponges/init.lua @@ -48,7 +48,7 @@ minetest.register_node("mcl_sponges:sponge", { buildable_to = false, stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, on_place = function(itemstack, placer, pointed_thing) local pn = placer:get_player_name() if pointed_thing.type ~= "node" then @@ -107,7 +107,7 @@ minetest.register_node("mcl_sponges:sponge_wet", { buildable_to = false, stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, _mcl_blast_resistance = 0.6, _mcl_hardness = 0.6, }) diff --git a/mods/ITEMS/mcl_throwing/API.md b/mods/ITEMS/mcl_throwing/API.md new file mode 100644 index 000000000..f2b1c7374 --- /dev/null +++ b/mods/ITEMS/mcl_throwing/API.md @@ -0,0 +1,35 @@ +# mcl_throwing + +## mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) +Throw a throwable item. + +* throw_item: itemstring of the throwable item +* pos: initial position of the entity +* dir: direction where the throwable item will be thrown +* velocity: (optional) will overide the default velocity value (can be nil) +* thrower: (optional) player/entity who throw the object (can be nil) + +## mcl_throwing.register_throwable_object(name, entity, velocity) +Register a throwable item. + +* name: itemname of the throwable object +* entity: entity thrown +* velocity: initial velocity of the entity + +## mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode, dropdir) +Throw throwable item from dispencer. + +Shouldn't be called directly. + +Must be used in item definition: + +`_on_dispense = mcl_throwing.dispense_function,` + +## mcl_throwing.get_player_throw_function(entity_name, velocity) + +Return a function who handle item throwing (to be used in item definition) + +Handle creative mode, and throw params. + +* entity_name: the name of the entity to throw +* velocity: (optional) velocity overide (can be nil) diff --git a/mods/ITEMS/mcl_throwing/init.lua b/mods/ITEMS/mcl_throwing/init.lua index 5fe34b45e..4d6dcfe5c 100644 --- a/mods/ITEMS/mcl_throwing/init.lua +++ b/mods/ITEMS/mcl_throwing/init.lua @@ -2,7 +2,7 @@ mcl_throwing = {} local S = minetest.get_translator("mcl_throwing") local mod_death_messages = minetest.get_modpath("mcl_death_messages") -local mod_fishing = minetest.get_modpath("mcl_fishing") +local modpath = minetest.get_modpath(minetest.get_current_modname()) -- -- Snowballs and other throwable items @@ -10,21 +10,15 @@ local mod_fishing = minetest.get_modpath("mcl_fishing") local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) -local entity_mapping = { - ["mcl_throwing:flying_bobber"] = "mcl_throwing:flying_bobber_entity", - ["mcl_throwing:snowball"] = "mcl_throwing:snowball_entity", - ["mcl_throwing:egg"] = "mcl_throwing:egg_entity", - ["mcl_throwing:ender_pearl"] = "mcl_throwing:ender_pearl_entity", -} +local entity_mapping = {} +local velocities = {} -local velocities = { - ["mcl_throwing:flying_bobber_entity"] = 5, - ["mcl_throwing:snowball_entity"] = 22, - ["mcl_throwing:egg_entity"] = 22, - ["mcl_throwing:ender_pearl_entity"] = 22, -} +function mcl_throwing.register_throwable_object(name, entity, velocity) + entity_mapping[name] = entity + velocities[name] = velocity +end -mcl_throwing.throw = function(throw_item, pos, dir, velocity, thrower) +function mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) if velocity == nil then velocity = velocities[throw_item] end @@ -44,7 +38,7 @@ mcl_throwing.throw = function(throw_item, pos, dir, velocity, thrower) end -- Throw item -local player_throw_function = function(entity_name, velocity) +function mcl_throwing.get_player_throw_function(entity_name, velocity) local func = function(item, player, pointed_thing) local playerpos = player:get_pos() local dir = player:get_look_dir() @@ -57,7 +51,7 @@ local player_throw_function = function(entity_name, velocity) return func end -local dispense_function = function(stack, dispenserpos, droppos, dropnode, dropdir) +function mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode, dropdir) -- Launch throwable item local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) mcl_throwing.throw(stack:get_name(), shootpos, dropdir) @@ -85,374 +79,4 @@ local on_activate = function(self, staticdata, dtime_s) end end --- The snowball entity -local snowball_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_snowball.png"}, - visual_size = {x=0.5, y=0.5}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - _thrower = nil, - - _lastpos={}, -} -local egg_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_egg.png"}, - visual_size = {x=0.45, y=0.45}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - _thrower = nil, - - _lastpos={}, -} --- Ender pearl entity -local pearl_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_ender_pearl.png"}, - visual_size = {x=0.9, y=0.9}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - - _lastpos={}, - _thrower = nil, -- Player ObjectRef of the player who threw the ender pearl -} - -local flying_bobber_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_fishing_bobber.png"}, --FIXME: Replace with correct texture. - visual_size = {x=0.5, y=0.5}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - - _lastpos={}, - _thrower = nil, - objtype="fishing", -} - -local check_object_hit = function(self, pos, dmg) - for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do - - local entity = object:get_luaentity() - - if entity - and entity.name ~= self.object:get_luaentity().name then - - if object:is_player() and self._thrower ~= object:get_player_name() then - -- TODO: Deal knockback - self.object:remove() - return true - elseif (entity._cmi_is_mob == true or entity._hittable_by_projectile) and (self._thrower ~= object) then - -- FIXME: Knockback is broken - object:punch(self.object, 1.0, { - full_punch_interval = 1.0, - damage_groups = dmg, - }, nil) - return true - end - end - end - return false -end - -local snowball_particles = function(pos, vel) - local vel = vector.normalize(vector.multiply(vel, -1)) - minetest.add_particlespawner({ - amount = 20, - time = 0.001, - minpos = pos, - maxpos = pos, - minvel = vector.add({x=-2, y=3, z=-2}, vel), - maxvel = vector.add({x=2, y=5, z=2}, vel), - minacc = {x=0, y=-9.81, z=0}, - maxacc = {x=0, y=-9.81, z=0}, - minexptime = 1, - maxexptime = 3, - minsize = 0.7, - maxsize = 0.7, - collisiondetection = true, - collision_removal = true, - object_collision = false, - texture = "weather_pack_snow_snowflake"..math.random(1,2)..".png", - }) -end - --- Snowball on_step()--> called when snowball is moving. -local snowball_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local vel = self.object:get_velocity() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - if (def and def.walkable) or not def then - minetest.sound_play("mcl_throwing_snowball_impact_hard", { pos = pos, max_hear_distance=16, gain=0.7 }, true) - snowball_particles(self._lastpos, vel) - self.object:remove() - return - end - end - - if check_object_hit(self, pos, {snowball_vulnerable = 3}) then - minetest.sound_play("mcl_throwing_snowball_impact_soft", { pos = pos, max_hear_distance=16, gain=0.7 }, true) - snowball_particles(pos, vel) - self.object:remove() - return - end - - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set _lastpos-->Node will be added at last pos outside the node -end - --- Movement function of egg -local egg_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - - -- Destroy when hitting a solid node with chance to spawn chicks - if self._lastpos.x~=nil then - if (def and def.walkable) or not def then - -- 1/8 chance to spawn a chick - -- FIXME: Chicks have a quite good chance to spawn in walls - local r = math.random(1,8) - - -- Turn given object into a child - local make_child= function(object) - local ent = object:get_luaentity() - object:set_properties({ - visual_size = { x = ent.base_size.x/2, y = ent.base_size.y/2 }, - collisionbox = { - ent.base_colbox[1]/2, - ent.base_colbox[2]/2, - ent.base_colbox[3]/2, - ent.base_colbox[4]/2, - ent.base_colbox[5]/2, - ent.base_colbox[6]/2, - } - }) - ent.child = true - end - if r == 1 then - make_child(minetest.add_entity(self._lastpos, "mobs_mc:chicken")) - - -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks - local r = math.random(1,32) - if r == 1 then - local offsets = { - { x=0.7, y=0, z=0 }, - { x=-0.7, y=0, z=-0.7 }, - { x=-0.7, y=0, z=0.7 }, - } - for o=1, 3 do - local pos = vector.add(self._lastpos, offsets[o]) - make_child(minetest.add_entity(pos, "mobs_mc:chicken")) - end - end - end - minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) - self.object:remove() - return - end - end - - -- Destroy when hitting a mob or player (no chick spawning) - if check_object_hit(self, pos) then - minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) - self.object:remove() - return - end - - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - --- Movement function of ender pearl -local pearl_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - pos.y = math.floor(pos.y) - local node = minetest.get_node(pos) - local nn = node.name - local def = minetest.registered_nodes[node.name] - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - local walkable = (def and def.walkable) - - -- No teleport for hitting ignore for now. Otherwise the player could get stuck. - -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas - if node.name == "ignore" then - self.object:remove() - -- Activate when hitting a solid node or a plant - elseif walkable or nn == "mcl_core:vine" or nn == "mcl_core:deadbush" or minetest.get_item_group(nn, "flower") ~= 0 or minetest.get_item_group(nn, "sapling") ~= 0 or minetest.get_item_group(nn, "plant") ~= 0 or minetest.get_item_group(nn, "mushroom") ~= 0 or not def then - local player = minetest.get_player_by_name(self._thrower) - if player then - -- Teleport and hurt player - - -- First determine good teleport position - local dir = {x=0, y=0, z=0} - - local v = self.object:get_velocity() - if walkable then - local vc = table.copy(v) -- vector for calculating - -- Node is walkable, we have to find a place somewhere outside of that node - vc = vector.normalize(vc) - - -- Zero-out the two axes with a lower absolute value than - -- the axis with the strongest force - local lv, ld - lv, ld = math.abs(vc.y), "y" - if math.abs(vc.x) > lv then - lv, ld = math.abs(vc.x), "x" - end - if math.abs(vc.z) > lv then - lv, ld = math.abs(vc.z), "z" - end - if ld ~= "x" then vc.x = 0 end - if ld ~= "y" then vc.y = 0 end - if ld ~= "z" then vc.z = 0 end - - -- Final tweaks to the teleporting pos, based on direction - -- Impact from the side - dir.x = vc.x * -1 - dir.z = vc.z * -1 - - -- Special case: top or bottom of node - if vc.y > 0 then - -- We need more space when impact is from below - dir.y = -2.3 - elseif vc.y < 0 then - -- Standing on top - dir.y = 0.5 - end - end - -- If node was not walkable, no modification to pos is made. - - -- Final teleportation position - local telepos = vector.add(pos, dir) - local telenode = minetest.get_node(telepos) - - --[[ It may be possible that telepos is walkable due to the algorithm. - Especially when the ender pearl is faster horizontally than vertical. - This applies final fixing, just to be sure we're not in a walkable node ]] - if not minetest.registered_nodes[telenode.name] or minetest.registered_nodes[telenode.name].walkable then - if v.y < 0 then - telepos.y = telepos.y + 0.5 - else - telepos.y = telepos.y - 2.3 - end - end - - local oldpos = player:get_pos() - -- Teleport and hurt player - player:set_pos(telepos) - player:set_hp(player:get_hp() - 5, { type = "fall", from = "mod" }) - - -- 5% chance to spawn endermite at the player's origin - local r = math.random(1,20) - if r == 1 then - minetest.add_entity(oldpos, "mobs_mc:endermite") - end - - end - self.object:remove() - return - end - end - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - --- Movement function of flying bobber -local flying_bobber_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - --local player = minetest.get_player_by_name(self._thrower) - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - if (def and (def.walkable or def.liquidtype == "flowing" or def.liquidtype == "source")) or not def then - local make_child= function(object) - local ent = object:get_luaentity() - ent.player = self._thrower - ent.child = true - end - make_child(minetest.add_entity(self._lastpos, "mcl_fishing:bobber_entity")) - self.object:remove() - return - end - end - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - -snowball_ENTITY.on_step = snowball_on_step -egg_ENTITY.on_step = egg_on_step -pearl_ENTITY.on_step = pearl_on_step -flying_bobber_ENTITY.on_step = flying_bobber_on_step - -minetest.register_entity("mcl_throwing:snowball_entity", snowball_ENTITY) -minetest.register_entity("mcl_throwing:egg_entity", egg_ENTITY) -minetest.register_entity("mcl_throwing:ender_pearl_entity", pearl_ENTITY) -minetest.register_entity("mcl_throwing:flying_bobber_entity", flying_bobber_ENTITY) - -local how_to_throw = S("Use the punch key to throw.") - --- Snowball -minetest.register_craftitem("mcl_throwing:snowball", { - description = S("Snowball"), - _tt_help = S("Throwable"), - _doc_items_longdesc = S("Snowballs can be thrown or launched from a dispenser for fun. Hitting something with a snowball does nothing."), - _doc_items_usagehelp = how_to_throw, - inventory_image = "mcl_throwing_snowball.png", - stack_max = 16, - groups = { weapon_ranged = 1 }, - on_use = player_throw_function("mcl_throwing:snowball_entity"), - _on_dispense = dispense_function, -}) - --- Egg -minetest.register_craftitem("mcl_throwing:egg", { - description = S("Egg"), - _tt_help = S("Throwable").."\n"..S("Chance to hatch chicks when broken"), - _doc_items_longdesc = S("Eggs can be thrown or launched from a dispenser and breaks on impact. There is a small chance that 1 or even 4 chicks will pop out of the egg."), - _doc_items_usagehelp = how_to_throw, - inventory_image = "mcl_throwing_egg.png", - stack_max = 16, - on_use = player_throw_function("mcl_throwing:egg_entity"), - _on_dispense = dispense_function, - groups = { craftitem = 1 }, -}) - --- Ender Pearl -minetest.register_craftitem("mcl_throwing:ender_pearl", { - description = S("Ender Pearl"), - _tt_help = S("Throwable").."\n"..minetest.colorize("#FFFF00", S("Teleports you on impact for cost of 5 HP")), - _doc_items_longdesc = S("An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points."), - _doc_items_usagehelp = how_to_throw, - wield_image = "mcl_throwing_ender_pearl.png", - inventory_image = "mcl_throwing_ender_pearl.png", - stack_max = 16, - on_use = player_throw_function("mcl_throwing:ender_pearl_entity"), - groups = { transport = 1 }, -}) - +dofile(modpath.."/register.lua") \ No newline at end of file diff --git a/mods/ITEMS/mcl_throwing/mod.conf b/mods/ITEMS/mcl_throwing/mod.conf index 4bfc2efb5..60d3e31a7 100644 --- a/mods/ITEMS/mcl_throwing/mod.conf +++ b/mods/ITEMS/mcl_throwing/mod.conf @@ -1,3 +1,3 @@ name = mcl_throwing -depends = mcl_fishing +depends = mcl_colors optional_depends = mcl_core, mcl_mobitems, doc diff --git a/mods/ITEMS/mcl_throwing/register.lua b/mods/ITEMS/mcl_throwing/register.lua new file mode 100644 index 000000000..027ff4e93 --- /dev/null +++ b/mods/ITEMS/mcl_throwing/register.lua @@ -0,0 +1,335 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- The snowball entity +local snowball_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_snowball.png"}, + visual_size = {x=0.5, y=0.5}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + _thrower = nil, + + _lastpos={}, +} +local egg_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_egg.png"}, + visual_size = {x=0.45, y=0.45}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + _thrower = nil, + + _lastpos={}, +} +-- Ender pearl entity +local pearl_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_ender_pearl.png"}, + visual_size = {x=0.9, y=0.9}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + + _lastpos={}, + _thrower = nil, -- Player ObjectRef of the player who threw the ender pearl +} + +local check_object_hit = function(self, pos, dmg) + for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do + + local entity = object:get_luaentity() + + if entity + and entity.name ~= self.object:get_luaentity().name then + + if object:is_player() and self._thrower ~= object:get_player_name() then + -- TODO: Deal knockback + self.object:remove() + return true + elseif (entity._cmi_is_mob == true or entity._hittable_by_projectile) and (self._thrower ~= object) then + -- FIXME: Knockback is broken + object:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = dmg, + }, nil) + return true + end + end + end + return false +end + +local snowball_particles = function(pos, vel) + local vel = vector.normalize(vector.multiply(vel, -1)) + minetest.add_particlespawner({ + amount = 20, + time = 0.001, + minpos = pos, + maxpos = pos, + minvel = vector.add({x=-2, y=3, z=-2}, vel), + maxvel = vector.add({x=2, y=5, z=2}, vel), + minacc = {x=0, y=-9.81, z=0}, + maxacc = {x=0, y=-9.81, z=0}, + minexptime = 1, + maxexptime = 3, + minsize = 0.7, + maxsize = 0.7, + collisiondetection = true, + collision_removal = true, + object_collision = false, + texture = "weather_pack_snow_snowflake"..math.random(1,2)..".png", + }) +end + +-- Snowball on_step()--> called when snowball is moving. +local snowball_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local vel = self.object:get_velocity() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + if (def and def.walkable) or not def then + minetest.sound_play("mcl_throwing_snowball_impact_hard", { pos = pos, max_hear_distance=16, gain=0.7 }, true) + snowball_particles(self._lastpos, vel) + self.object:remove() + return + end + end + + if check_object_hit(self, pos, {snowball_vulnerable = 3}) then + minetest.sound_play("mcl_throwing_snowball_impact_soft", { pos = pos, max_hear_distance=16, gain=0.7 }, true) + snowball_particles(pos, vel) + self.object:remove() + return + end + + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set _lastpos-->Node will be added at last pos outside the node +end + +-- Movement function of egg +local egg_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + + -- Destroy when hitting a solid node with chance to spawn chicks + if self._lastpos.x~=nil then + if (def and def.walkable) or not def then + -- 1/8 chance to spawn a chick + -- FIXME: Chicks have a quite good chance to spawn in walls + local r = math.random(1,8) + + -- Turn given object into a child + local make_child= function(object) + local ent = object:get_luaentity() + object:set_properties({ + visual_size = { x = ent.base_size.x/2, y = ent.base_size.y/2 }, + collisionbox = { + ent.base_colbox[1]/2, + ent.base_colbox[2]/2, + ent.base_colbox[3]/2, + ent.base_colbox[4]/2, + ent.base_colbox[5]/2, + ent.base_colbox[6]/2, + } + }) + ent.child = true + end + if r == 1 then + make_child(minetest.add_entity(self._lastpos, "mobs_mc:chicken")) + + -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks + local r = math.random(1,32) + if r == 1 then + local offsets = { + { x=0.7, y=0, z=0 }, + { x=-0.7, y=0, z=-0.7 }, + { x=-0.7, y=0, z=0.7 }, + } + for o=1, 3 do + local pos = vector.add(self._lastpos, offsets[o]) + make_child(minetest.add_entity(pos, "mobs_mc:chicken")) + end + end + end + minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) + self.object:remove() + return + end + end + + -- Destroy when hitting a mob or player (no chick spawning) + if check_object_hit(self, pos) then + minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) + self.object:remove() + return + end + + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +-- Movement function of ender pearl +local pearl_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + pos.y = math.floor(pos.y) + local node = minetest.get_node(pos) + local nn = node.name + local def = minetest.registered_nodes[node.name] + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + local walkable = (def and def.walkable) + + -- No teleport for hitting ignore for now. Otherwise the player could get stuck. + -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas + if node.name == "ignore" then + self.object:remove() + -- Activate when hitting a solid node or a plant + elseif walkable or nn == "mcl_core:vine" or nn == "mcl_core:deadbush" or minetest.get_item_group(nn, "flower") ~= 0 or minetest.get_item_group(nn, "sapling") ~= 0 or minetest.get_item_group(nn, "plant") ~= 0 or minetest.get_item_group(nn, "mushroom") ~= 0 or not def then + local player = minetest.get_player_by_name(self._thrower) + if player then + -- Teleport and hurt player + + -- First determine good teleport position + local dir = {x=0, y=0, z=0} + + local v = self.object:get_velocity() + if walkable then + local vc = table.copy(v) -- vector for calculating + -- Node is walkable, we have to find a place somewhere outside of that node + vc = vector.normalize(vc) + + -- Zero-out the two axes with a lower absolute value than + -- the axis with the strongest force + local lv, ld + lv, ld = math.abs(vc.y), "y" + if math.abs(vc.x) > lv then + lv, ld = math.abs(vc.x), "x" + end + if math.abs(vc.z) > lv then + lv, ld = math.abs(vc.z), "z" + end + if ld ~= "x" then vc.x = 0 end + if ld ~= "y" then vc.y = 0 end + if ld ~= "z" then vc.z = 0 end + + -- Final tweaks to the teleporting pos, based on direction + -- Impact from the side + dir.x = vc.x * -1 + dir.z = vc.z * -1 + + -- Special case: top or bottom of node + if vc.y > 0 then + -- We need more space when impact is from below + dir.y = -2.3 + elseif vc.y < 0 then + -- Standing on top + dir.y = 0.5 + end + end + -- If node was not walkable, no modification to pos is made. + + -- Final teleportation position + local telepos = vector.add(pos, dir) + local telenode = minetest.get_node(telepos) + + --[[ It may be possible that telepos is walkable due to the algorithm. + Especially when the ender pearl is faster horizontally than vertical. + This applies final fixing, just to be sure we're not in a walkable node ]] + if not minetest.registered_nodes[telenode.name] or minetest.registered_nodes[telenode.name].walkable then + if v.y < 0 then + telepos.y = telepos.y + 0.5 + else + telepos.y = telepos.y - 2.3 + end + end + + local oldpos = player:get_pos() + -- Teleport and hurt player + player:set_pos(telepos) + player:set_hp(player:get_hp() - 5, { type = "fall", from = "mod" }) + + -- 5% chance to spawn endermite at the player's origin + local r = math.random(1,20) + if r == 1 then + minetest.add_entity(oldpos, "mobs_mc:endermite") + end + + end + self.object:remove() + return + end + end + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +snowball_ENTITY.on_step = snowball_on_step +egg_ENTITY.on_step = egg_on_step +pearl_ENTITY.on_step = pearl_on_step + +minetest.register_entity("mcl_throwing:snowball_entity", snowball_ENTITY) +minetest.register_entity("mcl_throwing:egg_entity", egg_ENTITY) +minetest.register_entity("mcl_throwing:ender_pearl_entity", pearl_ENTITY) + + +local how_to_throw = S("Use the punch key to throw.") + +-- Snowball +minetest.register_craftitem("mcl_throwing:snowball", { + description = S("Snowball"), + _tt_help = S("Throwable"), + _doc_items_longdesc = S("Snowballs can be thrown or launched from a dispenser for fun. Hitting something with a snowball does nothing."), + _doc_items_usagehelp = how_to_throw, + inventory_image = "mcl_throwing_snowball.png", + stack_max = 16, + groups = { weapon_ranged = 1 }, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:snowball_entity"), + _on_dispense = mcl_throwing.dispense_function, +}) + +-- Egg +minetest.register_craftitem("mcl_throwing:egg", { + description = S("Egg"), + _tt_help = S("Throwable").."\n"..S("Chance to hatch chicks when broken"), + _doc_items_longdesc = S("Eggs can be thrown or launched from a dispenser and breaks on impact. There is a small chance that 1 or even 4 chicks will pop out of the egg."), + _doc_items_usagehelp = how_to_throw, + inventory_image = "mcl_throwing_egg.png", + stack_max = 16, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:egg_entity"), + _on_dispense = mcl_throwing.dispense_function, + groups = { craftitem = 1 }, +}) + +-- Ender Pearl +minetest.register_craftitem("mcl_throwing:ender_pearl", { + description = S("Ender Pearl"), + _tt_help = S("Throwable").."\n"..minetest.colorize(mcl_colors.YELLOW, S("Teleports you on impact for cost of 5 HP")), + _doc_items_longdesc = S("An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points."), + _doc_items_usagehelp = how_to_throw, + wield_image = "mcl_throwing_ender_pearl.png", + inventory_image = "mcl_throwing_ender_pearl.png", + stack_max = 16, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:ender_pearl_entity"), + groups = { transport = 1 }, +}) + +mcl_throwing.register_throwable_object("mcl_throwing:snowball", "mcl_throwing:snowball_entity", 22) +mcl_throwing.register_throwable_object("mcl_throwing:egg", "mcl_throwing:egg_entity", 22) +mcl_throwing.register_throwable_object("mcl_throwing:ender_pearl", "mcl_throwing:ender_pearl_entity", 22) diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 3004a8305..bc6bed09f 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -48,15 +48,16 @@ minetest.register_tool(":", { }, groups = hand_groups, _mcl_diggroups = { - handy = { tool_multiplier = 1, level = 1, uses = 0 }, - axey = { tool_multiplier = 1, level = 1, uses = 0 }, - shovely = { tool_multiplier = 1, level = 1, uses = 0 }, - pickaxey = { tool_multiplier = 1, level = 0, uses = 0 }, - swordy = { tool_multiplier = 1, level = 0, uses = 0 }, - swordy_cobweb = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy_wool = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy_cobweb = { tool_multiplier = 1, level = 0, uses = 0 }, + handy = { speed = 1, level = 1, uses = 0 }, + axey = { speed = 1, level = 1, uses = 0 }, + shovely = { speed = 1, level = 1, uses = 0 }, + hoey = { speed = 1, level = 1, uses = 0 }, + pickaxey = { speed = 1, level = 0, uses = 0 }, + swordy = { speed = 1, level = 0, uses = 0 }, + swordy_cobweb = { speed = 1, level = 0, uses = 0 }, + shearsy = { speed = 1, level = 0, uses = 0 }, + shearsy_wool = { speed = 1, level = 0, uses = 0 }, + shearsy_cobweb = { speed = 1, level = 0, uses = 0 }, } }) @@ -90,7 +91,7 @@ minetest.register_tool("mcl_tools:pick_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 2, level = 1, uses = 60 } + pickaxey = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:pick_stone", { @@ -110,7 +111,7 @@ minetest.register_tool("mcl_tools:pick_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 4, level = 3, uses = 132 } + pickaxey = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:pick_iron", { @@ -130,7 +131,7 @@ minetest.register_tool("mcl_tools:pick_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 6, level = 4, uses = 251 } + pickaxey = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:pick_gold", { @@ -150,7 +151,7 @@ minetest.register_tool("mcl_tools:pick_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 12, level = 2, uses = 33 } + pickaxey = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:pick_diamond", { @@ -170,7 +171,7 @@ minetest.register_tool("mcl_tools:pick_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 8, level = 5, uses = 1562 } + pickaxey = { speed = 8, level = 5, uses = 1562 } }, }) @@ -262,7 +263,7 @@ minetest.register_tool("mcl_tools:shovel_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 2, level = 1, uses = 60 } + shovely = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:shovel_stone", { @@ -283,7 +284,7 @@ minetest.register_tool("mcl_tools:shovel_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 4, level = 3, uses = 132 } + shovely = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:shovel_iron", { @@ -304,7 +305,7 @@ minetest.register_tool("mcl_tools:shovel_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 6, level = 4, uses = 251 } + shovely = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:shovel_gold", { @@ -325,7 +326,7 @@ minetest.register_tool("mcl_tools:shovel_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 12, level = 2, uses = 33 } + shovely = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:shovel_diamond", { @@ -346,7 +347,7 @@ minetest.register_tool("mcl_tools:shovel_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 8, level = 5, uses = 1562 } + shovely = { speed = 8, level = 5, uses = 1562 } }, }) @@ -368,7 +369,7 @@ minetest.register_tool("mcl_tools:axe_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 2, level = 1, uses = 60 } + axey = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:axe_stone", { @@ -387,7 +388,7 @@ minetest.register_tool("mcl_tools:axe_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 4, level = 3, uses = 132 } + axey = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:axe_iron", { @@ -407,7 +408,7 @@ minetest.register_tool("mcl_tools:axe_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 6, level = 4, uses = 251 } + axey = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:axe_gold", { @@ -426,7 +427,7 @@ minetest.register_tool("mcl_tools:axe_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 12, level = 2, uses = 33 } + axey = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:axe_diamond", { @@ -445,7 +446,7 @@ minetest.register_tool("mcl_tools:axe_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 8, level = 5, uses = 1562 } + axey = { speed = 8, level = 5, uses = 1562 } }, }) @@ -467,8 +468,8 @@ minetest.register_tool("mcl_tools:sword_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 2, level = 1, uses = 60 }, - swordy_cobweb = { tool_multiplier = 2, level = 1, uses = 60 } + swordy = { speed = 2, level = 1, uses = 60 }, + swordy_cobweb = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:sword_stone", { @@ -487,8 +488,8 @@ minetest.register_tool("mcl_tools:sword_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 4, level = 3, uses = 132 }, - swordy_cobweb = { tool_multiplier = 4, level = 3, uses = 132 } + swordy = { speed = 4, level = 3, uses = 132 }, + swordy_cobweb = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:sword_iron", { @@ -507,8 +508,8 @@ minetest.register_tool("mcl_tools:sword_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 6, level = 4, uses = 251 }, - swordy_cobweb = { tool_multiplier = 6, level = 4, uses = 251 } + swordy = { speed = 6, level = 4, uses = 251 }, + swordy_cobweb = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:sword_gold", { @@ -527,8 +528,8 @@ minetest.register_tool("mcl_tools:sword_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 12, level = 2, uses = 33 }, - swordy_cobweb = { tool_multiplier = 12, level = 2, uses = 33 } + swordy = { speed = 12, level = 2, uses = 33 }, + swordy_cobweb = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:sword_diamond", { @@ -547,8 +548,8 @@ minetest.register_tool("mcl_tools:sword_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 8, level = 5, uses = 1562 }, - swordy_cobweb = { tool_multiplier = 8, level = 5, uses = 1562 } + swordy = { speed = 8, level = 5, uses = 1562 }, + swordy_cobweb = { speed = 8, level = 5, uses = 1562 } }, }) @@ -569,9 +570,9 @@ minetest.register_tool("mcl_tools:shears", { sound = { breaks = "default_tool_breaks" }, _mcl_toollike_wield = true, _mcl_diggroups = { - shearsy = { tool_multiplier = 1.5, level = 1, uses = 238 }, - shearsy_wool = { tool_multiplier = 5, level = 1, uses = 238 }, - shearsy_cobweb = { tool_multiplier = 15, level = 1, uses = 238 } + shearsy = { speed = 1.5, level = 1, uses = 238 }, + shearsy_wool = { speed = 5, level = 1, uses = 238 }, + shearsy_cobweb = { speed = 15, level = 1, uses = 238 } }, }) diff --git a/mods/MAPGEN/mcl_dungeons/init.lua b/mods/MAPGEN/mcl_dungeons/init.lua index 05d82c3e9..dc9c6d619 100644 --- a/mods/MAPGEN/mcl_dungeons/init.lua +++ b/mods/MAPGEN/mcl_dungeons/init.lua @@ -12,6 +12,8 @@ end local min_y = math.max(mcl_vars.mg_overworld_min, mcl_vars.mg_bedrock_overworld_max) + 1 local max_y = mcl_vars.mg_overworld_max - 1 +local get_node = mcl_vars.get_node + -- Calculate the number of dungeon spawn attempts -- In Minecraft, there 8 dungeon spawn attempts Minecraft chunk (16*256*16 = 65536 blocks). -- Minetest chunks don't have this size, so scale the number accordingly. @@ -49,8 +51,8 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) local y_floor = y local y_ceiling = y + dim.y + 1 if check then for tx = x+1, x+dim.x do for tz = z+1, z+dim.z do - if not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_floor , z = tz}).name].walkable - or not minetest.registered_nodes[mcl_mapgen_core.get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end + if not minetest.registered_nodes[get_node({x = tx, y = y_floor , z = tz}).name].walkable + or not minetest.registered_nodes[get_node({x = tx, y = y_ceiling, z = tz}).name].walkable then return false end end end end -- Check for air openings (2 stacked air at ground level) in wall positions @@ -63,25 +65,25 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) local x2,z2 = x+dim.x+1, z+dim.z+1 - if mcl_mapgen_core.get_node({x=x, y=y+1, z=z}).name == "air" and mcl_mapgen_core.get_node({x=x, y=y+2, z=z}).name == "air" then + if get_node({x=x, y=y+1, z=z}).name == "air" and get_node({x=x, y=y+2, z=z}).name == "air" then openings_counter = openings_counter + 1 if not openings[x] then openings[x]={} end openings[x][z] = true table.insert(corners, {x=x, z=z}) end - if mcl_mapgen_core.get_node({x=x2, y=y+1, z=z}).name == "air" and mcl_mapgen_core.get_node({x=x2, y=y+2, z=z}).name == "air" then + if get_node({x=x2, y=y+1, z=z}).name == "air" and get_node({x=x2, y=y+2, z=z}).name == "air" then openings_counter = openings_counter + 1 if not openings[x2] then openings[x2]={} end openings[x2][z] = true table.insert(corners, {x=x2, z=z}) end - if mcl_mapgen_core.get_node({x=x, y=y+1, z=z2}).name == "air" and mcl_mapgen_core.get_node({x=x, y=y+2, z=z2}).name == "air" then + if get_node({x=x, y=y+1, z=z2}).name == "air" and get_node({x=x, y=y+2, z=z2}).name == "air" then openings_counter = openings_counter + 1 if not openings[x] then openings[x]={} end openings[x][z2] = true table.insert(corners, {x=x, z=z2}) end - if mcl_mapgen_core.get_node({x=x2, y=y+1, z=z2}).name == "air" and mcl_mapgen_core.get_node({x=x2, y=y+2, z=z2}).name == "air" then + if get_node({x=x2, y=y+1, z=z2}).name == "air" and get_node({x=x2, y=y+2, z=z2}).name == "air" then openings_counter = openings_counter + 1 if not openings[x2] then openings[x2]={} end openings[x2][z2] = true @@ -89,13 +91,13 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) end for wx = x+1, x+dim.x do - if mcl_mapgen_core.get_node({x=wx, y=y+1, z=z}).name == "air" and mcl_mapgen_core.get_node({x=wx, y=y+2, z=z}).name == "air" then + if get_node({x=wx, y=y+1, z=z}).name == "air" and get_node({x=wx, y=y+2, z=z}).name == "air" then openings_counter = openings_counter + 1 if check and openings_counter > 5 then return end if not openings[wx] then openings[wx]={} end openings[wx][z] = true end - if mcl_mapgen_core.get_node({x=wx, y=y+1, z=z2}).name == "air" and mcl_mapgen_core.get_node({x=wx, y=y+2, z=z2}).name == "air" then + if get_node({x=wx, y=y+1, z=z2}).name == "air" and get_node({x=wx, y=y+2, z=z2}).name == "air" then openings_counter = openings_counter + 1 if check and openings_counter > 5 then return end if not openings[wx] then openings[wx]={} end @@ -103,13 +105,13 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) end end for wz = z+1, z+dim.z do - if mcl_mapgen_core.get_node({x=x, y=y+1, z=wz}).name == "air" and mcl_mapgen_core.get_node({x=x, y=y+2, z=wz}).name == "air" then + if get_node({x=x, y=y+1, z=wz}).name == "air" and get_node({x=x, y=y+2, z=wz}).name == "air" then openings_counter = openings_counter + 1 if check and openings_counter > 5 then return end if not openings[x] then openings[x]={} end openings[x][wz] = true end - if mcl_mapgen_core.get_node({x=x2, y=y+1, z=wz}).name == "air" and mcl_mapgen_core.get_node({x=x2, y=y+2, z=wz}).name == "air" then + if get_node({x=x2, y=y+1, z=wz}).name == "air" and get_node({x=x2, y=y+2, z=wz}).name == "air" then openings_counter = openings_counter + 1 if check and openings_counter > 5 then return end if not openings[x2] then openings[x2]={} end @@ -185,7 +187,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) -- Calculate the mob spawner position, to be re-used for later local sp = {x = x + math.ceil(dim.x/2), y = y+1, z = z + math.ceil(dim.z/2)} - local rn = minetest.registered_nodes[mcl_mapgen_core.get_node(sp).name] + local rn = minetest.registered_nodes[get_node(sp).name] if rn and rn.is_ground_content then table.insert(spawner_posses, sp) end @@ -200,7 +202,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) -- Do not overwrite nodes with is_ground_content == false (e.g. bedrock) -- Exceptions: cobblestone and mossy cobblestone so neighborings dungeons nicely connect to each other - local name = mcl_mapgen_core.get_node(p).name + local name = get_node(p).name if minetest.registered_nodes[name].is_ground_content or name == "mcl_core:cobble" or name == "mcl_core:mossycobble" then -- Floor if ty == y then @@ -245,7 +247,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) if forChest and (currentChest < totalChests + 1) and (chestSlots[currentChest] == chestSlotCounter) then currentChest = currentChest + 1 table.insert(chests, {x=tx, y=ty, z=tz}) - else + -- else --minetest.swap_node(p, {name = "air"}) end if forChest then @@ -263,8 +265,8 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) -- Detect the 4 horizontal neighbors local spos = vector.add(pos, surround_vectors[s]) local wpos = vector.subtract(pos, surround_vectors[s]) - local nodename = minetest.get_node(spos).name - local nodename2 = minetest.get_node(wpos).name + local nodename = get_node(spos).name + local nodename2 = get_node(wpos).name local nodedef = minetest.registered_nodes[nodename] local nodedef2 = minetest.registered_nodes[nodename2] -- The chest needs an open space in front of it and a walkable node (except chest) behind it @@ -345,6 +347,7 @@ local function ecb_spawn_dungeon(blockpos, action, calls_remaining, param) }) end + minetest.log("action", "[mcl_dungeons] Filling chest " .. tostring(c) .. " at " .. minetest.pos_to_string(pos)) mcl_loot.fill_inventory(meta:get_inventory(), "main", mcl_loot.get_multi_loot(loottable, pr), pr) end diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 2986664f6..e08b55ba3 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -1,45 +1,8 @@ mcl_mapgen_core = {} -mcl_mapgen_core.registered_generators = {} +local registered_generators = {} local lvm, nodes, param2 = 0, 0, 0 - -local generating = {} -- generating chunks -local chunks = {} -- intervals of chunks generated -local function add_chunk(pos) - local n = mcl_vars.get_chunk_number(pos) -- unsigned int - local prev - for i, d in pairs(chunks) do - if n <= d[2] then -- we've found it - if (n == d[2]) or (n >= d[1]) then return end -- already here - if n == d[1]-1 then -- right before: - if prev and (prev[2] == n-1) then - prev[2] = d[2] - table.remove(chunks, i) - return - end - d[1] = n - return - end - if prev and (prev[2] == n-1) then --join to previous - prev[2] = n - return - end - table.insert(chunks, i, {n, n}) -- insert new interval before i - return - end - prev = d - end - chunks[#chunks] = {n, n} -end -function mcl_mapgen_core.is_generated(pos) - local n = mcl_vars.get_chunk_number(pos) -- unsigned int - for i, d in pairs(chunks) do - if n <= d[2] then - return (n >= d[1]) - end - end - return false -end +local lvm_buffer = {} -- -- Aliases for map generator outputs @@ -1790,6 +1753,8 @@ local generate_nether_decorations = function(minp, maxp, seed) return end + minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp)) + -- TODO: Generate everything based on Perlin noise instead of PseudoRandom local bpos @@ -1847,24 +1812,23 @@ local generate_nether_decorations = function(minp, maxp, seed) end minetest.register_on_generated(function(minp, maxp, blockseed) - add_chunk(minp) + minetest.log("action", "[mcl_mapgen_core] Generating chunk " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp)) local p1, p2 = {x=minp.x, y=minp.y, z=minp.z}, {x=maxp.x, y=maxp.y, z=maxp.z} if lvm > 0 then local lvm_used, shadow = false, false - local lb = {} -- buffer local lb2 = {} -- param2 local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local e1, e2 = {x=emin.x, y=emin.y, z=emin.z}, {x=emax.x, y=emax.y, z=emax.z} local data2 - local data = vm:get_data(lb) + local data = vm:get_data(lvm_buffer) if param2 > 0 then data2 = vm:get_param2_data(lb2) end local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2}) - for _, rec in pairs(mcl_mapgen_core.registered_generators) do + for _, rec in pairs(registered_generators) do if rec.vf then - local lvm_used0, shadow0 = rec.vf(vm, data, data2, p1, p2, area, p1, p2, blockseed) + local lvm_used0, shadow0 = rec.vf(vm, data, data2, e1, e2, area, p1, p2, blockseed) if lvm_used0 then lvm_used = true end @@ -1887,18 +1851,18 @@ minetest.register_on_generated(function(minp, maxp, blockseed) end if nodes > 0 then - for _, rec in pairs(mcl_mapgen_core.registered_generators) do + for _, rec in pairs(registered_generators) do if rec.nf then rec.nf(p1, p2, blockseed) end end end --- add_chunk(minp) + mcl_vars.add_chunk(minp) end) minetest.register_on_generated=function(node_function) - mcl_mapgen_core.register_generator("mod_"..tostring(#mcl_mapgen_core.registered_generators+1), nil, node_function) + mcl_mapgen_core.register_generator("mod_"..tostring(#registered_generators+1), nil, node_function) end function mcl_mapgen_core.register_generator(id, lvm_function, node_function, priority, needs_param2) @@ -1917,18 +1881,18 @@ function mcl_mapgen_core.register_generator(id, lvm_function, node_function, pri needs_param2 = needs_param2, } - mcl_mapgen_core.registered_generators[id] = new_record + registered_generators[id] = new_record table.sort( - mcl_mapgen_core.registered_generators, + registered_generators, function(a, b) return (a.i < b.i) or ((a.i == b.i) and (a.vf ~= nil) and (b.vf == nil)) end) end function mcl_mapgen_core.unregister_generator(id) - if not mcl_mapgen_core.registered_generators[id] then return end - local rec = mcl_mapgen_core.registered_generators[id] - mcl_mapgen_core.registered_generators[id] = nil + if not registered_generators[id] then return end + local rec = registered_generators[id] + registered_generators[id] = nil if rec.vf then lvm = lvm - 1 end if rev.nf then nodes = nodes - 1 end if rec.needs_param2 then param2 = param2 - 1 end @@ -2131,24 +2095,26 @@ local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed) -- 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 - local nodes + elseif emin.y <= mcl_vars.mg_nether_max and emax.y >= mcl_vars.mg_nether_min then 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"}) + local nodes = minetest.find_nodes_in_area(emin, emax, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) + for n=1, #nodes do + local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z) + if data[p_pos] == c_water then + data[p_pos] = c_nether_lava + lvm_used = true + elseif data[p_pos] == c_stone then + data[p_pos] = c_netherrack + lvm_used = true + elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then + data[p_pos] = c_soul_sand + lvm_used = true + end + end else - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source"}) - end - for n=1, #nodes do - local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z) - if data[p_pos] == c_water then - data[p_pos] = c_nether_lava - lvm_used = true - elseif data[p_pos] == c_stone then - data[p_pos] = c_netherrack - lvm_used = true - elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then - data[p_pos] = c_soul_sand - lvm_used = true + local nodes = minetest.find_nodes_in_area(emin, emax, {"group:water"}) + for _, n in pairs(nodes) do + data[area:index(n.x, n.y, n.z)] = c_nether_lava end end @@ -2157,17 +2123,16 @@ local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed) -- * 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 - local nodes, node + local nodes, n 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 if #nodes > 0 then lvm_used = true - for n=1, #nodes do - node = nodes[n] - data[area:index(node.x, node.y, node.z)] = c_air + for _, n in pairs(nodes) do + data[area:index(n.x, n.y, n.z)] = c_air end end @@ -2220,48 +2185,3 @@ end mcl_mapgen_core.register_generator("main", basic, nil, 1, true) --- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like 5.3.0 does. --- p: Position, if it's wrong, {name="error"} node will return. --- force: optional (default: false) - Do the maximum to still read the node within us_timeout. --- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job. --- --- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}. -function mcl_mapgen_core.get_node(p, force, us_timeout) - -- check initial circumstances - if not p or not p.x or not p.y or not p.z then return {name="error"} end - - -- try common way - local node = minetest.get_node(p) - if node.name ~= "ignore" then - return node - end - - -- copy table to get sure it won't changed by other threads - local pos = {x=p.x,y=p.y,z=p.z} - - -- try LVM - minetest.get_voxel_manip():read_from_map(pos, pos) - node = minetest.get_node(pos) - if node.name ~= "ignore" or not force then - return node - end - - -- all ways failed - need to emerge (or forceload if generated) - local us_timeout = us_timeout or 244 - if mcl_mapgen_core.is_generated(pos) then - minetest.forceload_block(pos) - else - minetest.emerge_area(pos, pos) - end - - local t = minetest.get_us_time() - - node = minetest.get_node(pos) - - while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do - node = minetest.get_node(pos) - end - - return node - -- it still can return "ignore", LOL, even if force = true, but only after time out -end diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 96c620c99..f6317bdeb 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -272,7 +272,7 @@ local function hut_placement_callback(p1, p2, size, orientation, pr) if not p1 or not p2 then return end local legs = minetest.find_nodes_in_area(p1, p2, "mcl_core:tree") for i = 1, #legs do - while minetest.get_item_group(mcl_mapgen_core.get_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do + while minetest.get_item_group(mcl_vars.get_node({x=legs[i].x, y=legs[i].y-1, z=legs[i].z}, true, 333333).name, "water") ~= 0 do legs[i].y = legs[i].y - 1 minetest.swap_node(legs[i], {name = "mcl_core:tree", param2 = 2}) end @@ -534,7 +534,7 @@ end -- Debug command minetest.register_chatcommand("spawnstruct", { - params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | dungeon", + params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | nether_portal | dungeon", description = S("Generate a pre-defined structure near your position."), privs = {debug = true}, func = function(name, param) @@ -570,6 +570,8 @@ minetest.register_chatcommand("spawnstruct", { mcl_structures.generate_end_portal_shrine(pos, rot, pr) elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then mcl_dungeons.spawn_dungeon(pos, rot, pr) + elseif param == "nether_portal" and mcl_portals and mcl_portals.spawn_nether_portal then + mcl_portals.spawn_nether_portal(pos, rot, pr, name) elseif param == "" then message = S("Error: No structure type given. Please use “/spawnstruct ”.") errord = true diff --git a/mods/MAPGEN/mcl_villages/buildings.lua b/mods/MAPGEN/mcl_villages/buildings.lua index 18d6c1e0b..e43db6d98 100644 --- a/mods/MAPGEN/mcl_villages/buildings.lua +++ b/mods/MAPGEN/mcl_villages/buildings.lua @@ -4,7 +4,7 @@ ------------------------------------------------------------------------------- function settlements.build_schematic(vm, data, va, pos, building, replace_wall, name) -- get building node material for better integration to surrounding - local platform_material = mcl_mapgen_core.get_node(pos) + local platform_material = mcl_vars.get_node(pos) if not platform_material or (platform_material.name == "air" or platform_material.name == "ignore") then return end diff --git a/mods/MAPGEN/mcl_villages/foundation.lua b/mods/MAPGEN/mcl_villages/foundation.lua index 67a2385f7..038a2f202 100644 --- a/mods/MAPGEN/mcl_villages/foundation.lua +++ b/mods/MAPGEN/mcl_villages/foundation.lua @@ -52,7 +52,7 @@ function settlements.terraform(settlement_info, pr) else -- write ground -- local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi} --- local node = mcl_mapgen_core.get_node(p) +-- local node = mcl_vars.get_node(p) -- if node and node.name ~= "air" then -- minetest.swap_node(p,{name="air"}) -- end diff --git a/mods/MAPGEN/mcl_villages/utils.lua b/mods/MAPGEN/mcl_villages/utils.lua index 2d96ba26f..d7617541d 100644 --- a/mods/MAPGEN/mcl_villages/utils.lua +++ b/mods/MAPGEN/mcl_villages/utils.lua @@ -1,28 +1,5 @@ -local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass") -local c_dirt_with_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow") ---local c_dirt_with_dry_grass = minetest.get_content_id("mcl_core:dirt_with_dry_grass") -local c_podzol = minetest.get_content_id("mcl_core:podzol") -local c_sand = minetest.get_content_id("mcl_core:sand") -local c_desert_sand = minetest.get_content_id("mcl_core:redsand") ---local c_silver_sand = minetest.get_content_id("mcl_core:silver_sand") --- -local c_air = minetest.get_content_id("air") -local c_snow = minetest.get_content_id("mcl_core:snow") -local c_fern_1 = minetest.get_content_id("mcl_flowers:fern") -local c_fern_2 = minetest.get_content_id("mcl_flowers:fern") -local c_fern_3 = minetest.get_content_id("mcl_flowers:fern") -local c_rose = minetest.get_content_id("mcl_flowers:poppy") -local c_viola = minetest.get_content_id("mcl_flowers:blue_orchid") -local c_geranium = minetest.get_content_id("mcl_flowers:allium") -local c_tulip = minetest.get_content_id("mcl_flowers:tulip_orange") -local c_dandelion_y = minetest.get_content_id("mcl_flowers:dandelion") -local c_dandelion_w = minetest.get_content_id("mcl_flowers:oxeye_daisy") -local c_bush_leaves = minetest.get_content_id("mcl_core:leaves") -local c_bush_stem = minetest.get_content_id("mcl_core:tree") -local c_a_bush_leaves = minetest.get_content_id("mcl_core:acacialeaves") -local c_a_bush_stem = minetest.get_content_id("mcl_core:acaciatree") -local c_water_source = minetest.get_content_id("mcl_core:water_source") -local c_water_flowing = minetest.get_content_id("mcl_core:water_flowing") +local get_node = mcl_vars.get_node + ------------------------------------------------------------------------------- -- function to copy tables ------------------------------------------------------------------------------- @@ -53,9 +30,9 @@ function settlements.find_surface(pos, wait) -- check, in which direction to look for surface local surface_node if wait then - surface_node = mcl_mapgen_core.get_node(p6, true, 10000000) + surface_node = get_node(p6, true, 10000000) else - surface_node = mcl_mapgen_core.get_node(p6) + surface_node = get_node(p6) end if surface_node.name=="air" or surface_node.name=="ignore" then itter = -1 @@ -65,7 +42,7 @@ function settlements.find_surface(pos, wait) -- Check Surface_node and Node above -- if settlements.surface_mat[surface_node.name] then - local surface_node_plus_1 = mcl_mapgen_core.get_node({ x=p6.x, y=p6.y+1, z=p6.z}) + local surface_node_plus_1 = get_node({ x=p6.x, y=p6.y+1, z=p6.z}) if surface_node_plus_1 and surface_node and (string.find(surface_node_plus_1.name,"air") or string.find(surface_node_plus_1.name,"snow") or @@ -90,7 +67,7 @@ function settlements.find_surface(pos, wait) return nil end cnt = cnt+1 - surface_node = mcl_mapgen_core.get_node(p6) + surface_node = get_node(p6) end settlements.debug("find_surface5: cnt_max overflow") return nil diff --git a/mods/MISC/mcl_wip/API.md b/mods/MISC/mcl_wip/API.md new file mode 100644 index 000000000..e3439af77 --- /dev/null +++ b/mods/MISC/mcl_wip/API.md @@ -0,0 +1,16 @@ +# mcl_wip +Used to mark items or nodes as WIP. + +## mcl_wip.register_wip_item(itemname) +Register as a WIP item. +If isn't a valid itemname, an error will be shown after mods loaded. + +## mcl_wip.register_experimental_item(itemname) +Register as a experimental item. +If isn't a valid itemname, an error will be shown after mods loaded. + +## mcl_wip.registered_wip_items +Table containing WIP items names. + +## mcl_wip.registered_experimental_items +Table containing experimental items names. \ No newline at end of file diff --git a/mods/PLAYER/mcl_death_drop/API.md b/mods/PLAYER/mcl_death_drop/API.md new file mode 100644 index 000000000..b19e2fd7c --- /dev/null +++ b/mods/PLAYER/mcl_death_drop/API.md @@ -0,0 +1,14 @@ +# mcl_death_drop +Drop registered inventories on player death. + +## mcl_death_drop.register_dropped_list(inv, listname, drop) +* inv: can be: + * "PLAYER": will be interpreted like player inventory (to avoid multiple calling to get_inventory()) + * function(player): must return inventory +* listname: string +* drop: bool + * true: the entire list will be dropped + * false: items with curse_of_vanishing enchantement will be broken. + +## mcl_death_drop.registered_dropped_lists +Table containing dropped list inventory, name and drop state. \ No newline at end of file diff --git a/mods/PLAYER/mcl_death_drop/init.lua b/mods/PLAYER/mcl_death_drop/init.lua index 56e6ea522..7c54334a9 100644 --- a/mods/PLAYER/mcl_death_drop/init.lua +++ b/mods/PLAYER/mcl_death_drop/init.lua @@ -1,26 +1,40 @@ +local random = math.random + +mcl_death_drop = {} + +mcl_death_drop.registered_dropped_lists = {} + +function mcl_death_drop.register_dropped_list(inv, listname, drop) + table.insert(mcl_death_drop.registered_dropped_lists, {inv=inv, listname=listname, drop=drop}) +end + +mcl_death_drop.register_dropped_list("PLAYER", "main", true) +mcl_death_drop.register_dropped_list("PLAYER", "craft", true) +mcl_death_drop.register_dropped_list("PLAYER", "armor", true) +mcl_death_drop.register_dropped_list(function(player) return select(3, armor:get_valid_player(player)) end , "armor", false) + minetest.register_on_dieplayer(function(player) local keep = minetest.settings:get_bool("mcl_keepInventory", false) if keep == false then -- Drop inventory, crafting grid and armor - local inv = player:get_inventory() + local playerinv = player:get_inventory() local pos = player:get_pos() - local name, player_armor_inv, armor_armor_inv, pos = armor:get_valid_player(player, "[on_dieplayer]") -- No item drop if in deep void local void, void_deadly = mcl_worlds.is_in_void(pos) - local lists = { - { inv = inv, listname = "main", drop = true }, - { inv = inv, listname = "craft", drop = true }, - { inv = player_armor_inv, listname = "armor", drop = true }, - { inv = armor_armor_inv, listname = "armor", drop = false }, - } - for l=1,#lists do - local inv = lists[l].inv - local listname = lists[l].listname - local drop = lists[l].drop + + for l=1,#mcl_death_drop.registered_dropped_lists do + local inv = mcl_death_drop.registered_dropped_lists[l].inv + if inv == "PLAYER" then + inv = playerinv + elseif type(inv) == "function" then + inv = inv(player) + end + local listname = mcl_death_drop.registered_dropped_lists[l].listname + local drop = mcl_death_drop.registered_dropped_lists[l].drop if inv ~= nil then for i, stack in ipairs(inv:get_list(listname)) do - local x = math.random(0, 9)/3 - local z = math.random(0, 9)/3 + local x = random(0, 9)/3 + local z = random(0, 9)/3 pos.x = pos.x + x pos.z = pos.z + z if not void_deadly and drop and not mcl_enchanting.has_enchantment(stack, "curse_of_vanishing") then diff --git a/mods/PLAYER/mcl_player/init.lua b/mods/PLAYER/mcl_player/init.lua index 9e6790ea0..210e2d19f 100644 --- a/mods/PLAYER/mcl_player/init.lua +++ b/mods/PLAYER/mcl_player/init.lua @@ -178,7 +178,7 @@ minetest.register_globalstep(function(dtime) -- Apply animations based on what the player is doing if player:get_hp() == 0 then - player_set_animation(player, "lay") + player_set_animation(player, "die") elseif walking and velocity.x > 0.35 or walking and velocity.x < -0.35 or walking and velocity.z > 0.35 or walking and velocity.z < -0.35 then if player_sneak[name] ~= controls.sneak then player_anim[name] = nil @@ -253,3 +253,28 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason) end return hp_change end, true) + +minetest.register_on_respawnplayer(function(player) + local pos = player:get_pos() + minetest.add_particlespawner({ + amount = 50, + time = 0.001, + minpos = vector.add(pos, 0), + maxpos = vector.add(pos, 0), + minvel = vector.new(-5,-5,-5), + maxvel = vector.new(5,5,5), + minexptime = 1.1, + maxexptime = 1.5, + minsize = 1, + maxsize = 2, + collisiondetection = false, + vertical = false, + texture = "mcl_particles_mob_death.png^[colorize:#000000:255", + }) + + minetest.sound_play("mcl_mobs_mob_poof", { + pos = pos, + gain = 1.0, + max_hear_distance = 8, + }, true) +end) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 7122cc894..767b275e4 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -252,13 +252,7 @@ minetest.register_globalstep(function(dtime) playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.4) end end - else - -- Reset speed decrease - playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface") - end - - -- Swimming? Check if boots are enchanted with depth strider - if get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then + elseif get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then local boots = player:get_inventory():get_stack("armor", 5) local depth_strider = mcl_enchanting.get_enchantment(boots, "depth_strider") diff --git a/mods/PLAYER/mcl_skins/init.lua b/mods/PLAYER/mcl_skins/init.lua index ac770f8f5..5956aab7c 100644 --- a/mods/PLAYER/mcl_skins/init.lua +++ b/mods/PLAYER/mcl_skins/init.lua @@ -227,6 +227,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if mcl_skins.skin_count <= 6 then -- Change skin immediately if there are not many skins mcl_skins.cycle_skin(player) + if player:get_attach() ~= nil then + mcl_player.player_set_animation(player, "sit") + end else -- Show skin selection formspec otherwise mcl_skins.show_formspec(player:get_player_name()) @@ -237,7 +240,7 @@ end) mcl_skins.show_formspec = function(playername) local formspec = "size[7,8.5]" - formspec = formspec .. "label[2,2;" .. minetest.formspec_escape(minetest.colorize("#383838", S("Select player skin:"))) .. "]" + formspec = formspec .. "label[2,2;" .. minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Select player skin:"))) .. "]" .. "textlist[0,2.5;6.8,6;skins_set;" local meta @@ -265,7 +268,7 @@ mcl_skins.show_formspec = function(playername) if meta then if meta.name and meta.name ~= "" then - formspec = formspec .. "label[2,0.5;" .. minetest.formspec_escape(minetest.colorize("#383838", S("Name: @1", meta.name))) .. "]" + formspec = formspec .. "label[2,0.5;" .. minetest.formspec_escape(minetest.colorize(mcl_colors.DARK_GRAY, S("Name: @1", meta.name))) .. "]" end end @@ -294,4 +297,3 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end) minetest.log("action", "[mcl_skins] Mod initialized with "..mcl_skins.skin_count.." custom skin(s)") - diff --git a/mods/PLAYER/mcl_spawn/init.lua b/mods/PLAYER/mcl_spawn/init.lua index 6a3d543d3..fe88cf3de 100644 --- a/mods/PLAYER/mcl_spawn/init.lua +++ b/mods/PLAYER/mcl_spawn/init.lua @@ -81,13 +81,7 @@ local dir_step = storage:get_int("mcl_spawn_dir_step") or 0 local dir_ind = storage:get_int("mcl_spawn_dir_ind") or 1 local emerge_pos1, emerge_pos2 --- Get world 'mapgen_limit' and 'chunksize' to calculate 'spawn_limit'. --- This accounts for how mapchunks are not generated if they or their shell exceed --- 'mapgen_limit'. - -local mapgen_limit = tonumber(minetest.get_mapgen_setting("mapgen_limit")) -local chunksize = tonumber(minetest.get_mapgen_setting("chunksize")) -local spawn_limit = math.max(mapgen_limit - (chunksize + 1) * 16, 0) +local spawn_limit = mcl_vars.mapgen_edge_max --Functions @@ -503,10 +497,17 @@ function mcl_spawn.shadow_worker() mcl_spawn.search() minetest.log("action", "[mcl_spawn] Started world spawn point search") end - if success and ((not good_for_respawn(wsp)) or (not can_find_tree(wsp))) then - success = false - minetest.log("action", "[mcl_spawn] World spawn position isn't safe anymore: "..minetest.pos_to_string(wsp)) - mcl_spawn.search() + + if success then + local wsp_node = minetest.get_node(wsp) + if wsp_node and wsp_node.name == "ignore" then + -- special case - respawn area unloaded from memory - it's okay, skip for now + + elseif ((not good_for_respawn(wsp)) or ((no_trees_area_counter >= 0) and not can_find_tree(wsp))) then + success = false + minetest.log("action", "[mcl_spawn] World spawn position isn't safe anymore: "..minetest.pos_to_string(wsp)) + mcl_spawn.search() + end end minetest.after(respawn_search_interval, mcl_spawn.shadow_worker) diff --git a/settingtypes.txt b/settingtypes.txt index af0e18d85..67e686d1e 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -129,6 +129,9 @@ mcl_superflat_classic (Classic superflat map generation) bool false # If disabled, no ores will be generated. mcl_generate_ores (Generate Ores) bool true +# If disabled, command blocks will be unusuable (but still present). +mcl_enable_commandblocks (Enable Command Blocks) bool true + # Make some blocks emit decorative particles like flames. This setting # specifies the detail level of particles, with higher levels being # more CPU demanding.