0
0
Fork 0

Merge branch 'master' into master

This commit is contained in:
ninjum 2024-08-18 21:33:09 +02:00
commit 52a6583b46
69 changed files with 2591 additions and 2122 deletions

View File

@ -46,6 +46,9 @@ Armor trim models were created by Aeonix_Aeon
Source: <https://www.curseforge.com/minecraft/texture-packs/ozocraft-remix>
License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
Charcoal block texture was created by [blitzdoughnuts](https://gitlab.com/ApplemunchFromDaDead), based on the Pixel Perfection coal block.
License: [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)
The main menu images are released under: [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
All other files, unless mentioned otherwise, fall under:

View File

@ -83,7 +83,7 @@ The VoxeLibre repository is hosted at Mesehub. To contribute or report issues, h
* Discord: <https://discord.gg/xE4z8EEpDC>
* YouTube: <https://www.youtube.com/channel/UClI_YcsXMF3KNeJtoBfnk9A>
* ContentDB: <https://content.minetest.net/packages/wuzzy/mineclone2/>
* OpenCollective: <https://opencollective.com/mineclone2>
* OpenCollective: <https://opencollective.com/voxelibre>
* Mastodon: <https://fosstodon.org/@VoxeLibre>
* Lemmy: <https://lemm.ee/c/voxelibre>
* Matrix space: <https://app.element.io/#/room/#voxelibre:matrix.org>

View File

@ -136,6 +136,7 @@ local function try_object_pickup(player, inv, object, checkpos)
-- Destroy entity
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
le.target = checkpos
le.itemstring = ""
le._removed = true
-- Stop the object
@ -957,6 +958,7 @@ minetest.register_entity(":__builtin:item", {
self.random_velocity = 0
self:set_item(own_stack:to_string())
entity.itemstring = ""
entity._removed = true
object:remove()
return true

View File

@ -18,7 +18,7 @@ mcl_mobs.invis = {}
local remove_far = true
local mobs_debug = minetest.settings:get_bool("mobs_debug", false) -- Shows helpful debug info above each mob
local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn", false)
local MAPGEN_LIMIT = mcl_vars.mapgen_limit
local MAPGEN_MOB_LIMIT = MAPGEN_LIMIT - 90

View File

@ -258,6 +258,18 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end
end
-- Stop!
local s = get_sign(entity.v)
entity.v = entity.v - 0.02 * s
if s ~= get_sign(entity.v) then
entity.object:set_velocity({x = 0, y = 0, z = 0})
entity.v = 0
return
end
-- if not moving then set animation and return
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
@ -273,18 +285,6 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
mcl_mobs:set_animation(entity, moving_anim)
end
-- Stop!
local s = get_sign(entity.v)
entity.v = entity.v - 0.02 * s
if s ~= get_sign(entity.v) then
entity.object:set_velocity({x = 0, y = 0, z = 0})
entity.v = 0
return
end
-- enforce speed limit forward and reverse
local max_spd = entity.max_speed_reverse

View File

@ -17,12 +17,13 @@ local mt_get_biome_name = minetest.get_biome_name
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_connected_players = minetest.get_connected_players
local math_min = math.min
local math_max = math.max
local math_random = math.random
local math_floor = math.floor
local math_ceil = math.ceil
local math_cos = math.cos
local math_sin = math.sin
local math_round = function(x) return (x > 0) and math_floor(x + 0.5) or math_ceil(x - 0.5) end
local math_sqrt = math.sqrt
local vector_distance = vector.distance
@ -33,9 +34,9 @@ local table_copy = table.copy
local table_remove = table.remove
local pairs = pairs
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_spawning", false)
local logging = minetest.settings:get_bool("mcl_logging_mobs_spawn", false)
local function mcl_log (message, property)
if LOGGING_ON then
if logging then
if property then
message = message .. ": " .. dump(property)
end
@ -54,8 +55,10 @@ local FIND_SPAWN_POS_RETRIES = 16
local FIND_SPAWN_POS_RETRIES_SUCCESS_RESPIN = 8
local MOB_SPAWN_ZONE_INNER = 24
local MOB_SPAWN_ZONE_INNER_SQ = MOB_SPAWN_ZONE_INNER^2 -- squared
local MOB_SPAWN_ZONE_MIDDLE = 32
local MOB_SPAWN_ZONE_OUTER = 128
local MOB_SPAWN_ZONE_OUTER_SQ = MOB_SPAWN_ZONE_OUTER^2 -- squared
-- range for mob count
local MOB_CAP_INNER_RADIUS = 32
@ -95,7 +98,6 @@ mcl_log("Percentage of hostile spawns are group: " .. hostile_group_percentage_s
--do mobs spawn?
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
local logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true)
-- THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
-- Also used for missing parameter
@ -601,71 +603,40 @@ function mcl_mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_
spawn_dictionary[key]["check_position"] = check_position
end
-- Calculate the inverse of a piecewise linear function f(x). Line segments are represented as two
-- adjacent points specified as { x, f(x) }. At least 2 points are required. If there are most solutions,
-- the one with a lower x value will be chosen.
local function inverse_pwl(fx, f)
if fx < f[1][2] then
return f[1][1]
end
for i=2,#f do
local x0,fx0 = unpack(f[i-1])
local x1,fx1 = unpack(f[i ])
if fx < fx1 then
return (fx - fx0) * (x1 - x0) / (fx1 - fx0) + x0
end
end
return f[#f][1]
end
local SPAWN_DISTANCE_CDF_PWL = {
{0.000,0.00},
{0.083,0.40},
{0.416,0.75},
{1.000,1.00},
}
local two_pi = 2 * math.pi
local function get_next_mob_spawn_pos(pos)
-- Select a distance such that distances closer to the player are selected much more often than
-- those further away from the player.
local fx = (math_random(1,10000)-1) / 10000
local x = inverse_pwl(fx, SPAWN_DISTANCE_CDF_PWL)
local distance = x * (MOB_SPAWN_ZONE_OUTER - MOB_SPAWN_ZONE_INNER) + MOB_SPAWN_ZONE_INNER
-- those further away from the player. This does produce a concentration at INNER (24 blocks)
local distance = math_random()^2 * (MOB_SPAWN_ZONE_OUTER - MOB_SPAWN_ZONE_INNER) + MOB_SPAWN_ZONE_INNER
--print("Using spawn distance of "..tostring(distance).." fx="..tostring(fx)..",x="..tostring(x))
-- TODO Floor xoff and zoff and add 0.5 so it tries to spawn in the middle of the square. Less failed attempts.
-- Use spherical coordinates https://en.wikipedia.org/wiki/Spherical_coordinate_system#Cartesian_coordinates
local theta = math_random() * two_pi
local phi = math_random() * two_pi
local xoff = math_round(distance * math_sin(theta) * math_cos(phi))
local yoff = math_round(distance * math_cos(theta))
local zoff = math_round(distance * math_sin(theta) * math_sin(phi))
-- Choose a random direction. Rejection sampling is simple and fast (1-2 tries usually)
local xoff, yoff, zoff, dd
repeat
xoff, yoff, zoff = math_random() * 2 - 1, math_random() * 2 - 1, math_random() * 2 - 1
dd = xoff*xoff + yoff*yoff + zoff*zoff
until (dd <= 1 and dd >= 1e-6) -- outside of uniform ball, retry
dd = distance / math_sqrt(dd) -- distance scaling factor
xoff, yoff, zoff = xoff * dd, yoff * dd, zoff * dd
local goal_pos = vector.offset(pos, xoff, yoff, zoff)
if not ( math.abs(goal_pos.x) <= SPAWN_MAPGEN_LIMIT and math.abs(pos.y) <= SPAWN_MAPGEN_LIMIT and math.abs(goal_pos.z) <= SPAWN_MAPGEN_LIMIT ) then
if not ( math.abs(goal_pos.x) <= SPAWN_MAPGEN_LIMIT and math.abs(goal_pos.y) <= SPAWN_MAPGEN_LIMIT and math.abs(goal_pos.z) <= SPAWN_MAPGEN_LIMIT ) then
mcl_log("Pos outside mapgen limits: " .. minetest.pos_to_string(goal_pos))
return nil
end
-- Calculate upper/lower y limits
local R1 = MOB_SPAWN_ZONE_OUTER
local d = vector_distance( pos, vector.new( goal_pos.x, pos.y, goal_pos.z ) ) -- distance from player to projected point on horizontal plane
local y1 = math_sqrt( R1*R1 - d*d ) -- absolue value of distance to outer sphere
local d2 = xoff*xoff + zoff*zoff -- squared distance in x,z plane only
local y1 = math_sqrt( MOB_SPAWN_ZONE_OUTER_SQ - d2 ) -- absolue value of distance to outer sphere
local y_min
local y_max
if d >= MOB_SPAWN_ZONE_INNER then
local y_min, y_max
if d2 >= MOB_SPAWN_ZONE_INNER_SQ then
-- Outer region, y range has both ends on the outer sphere
y_min = pos.y - y1
y_max = pos.y + y1
else
-- Inner region, y range spans between inner and outer spheres
local R2 = MOB_SPAWN_ZONE_INNER
local y2 = math_sqrt( R2*R2 - d*d )
if goal_pos.y > pos. y then
local y2 = math_sqrt( MOB_SPAWN_ZONE_INNER_SQ - d2 )
if goal_pos.y > pos.y then
-- Upper hemisphere
y_min = pos.y + y2
y_max = pos.y + y1
@ -675,16 +646,9 @@ local function get_next_mob_spawn_pos(pos)
y_max = pos.y - y2
end
end
y_min = math_round(y_min)
y_max = math_round(y_max)
-- Limit total range of check to 32 nodes (maximum of 3 map blocks)
if y_max > goal_pos.y + 16 then
y_max = goal_pos.y + 16
end
if y_min < goal_pos.y - 16 then
y_min = goal_pos.y - 16
end
y_min = math_max(math_floor(y_min), goal_pos.y - 16)
y_max = math_min(math_ceil(y_max), goal_pos.y + 16)
-- Ask engine for valid spawn locations
local spawning_position_list = find_nodes_in_area_under_air(
@ -997,7 +961,7 @@ if mobs_spawn then
mob_total_wide = 0
end
local cap_space_wide = math.max(type_cap - mob_total_wide, 0)
local cap_space_wide = math_max(type_cap - mob_total_wide, 0)
mcl_log("mob_type", mob_type)
mcl_log("cap_space_wide", cap_space_wide)
@ -1005,10 +969,10 @@ if mobs_spawn then
local cap_space_available = 0
if mob_type == "hostile" then
mcl_log("cap_space_global", cap_space_hostile)
cap_space_available = math.min(cap_space_hostile, cap_space_wide)
cap_space_available = math_min(cap_space_hostile, cap_space_wide)
else
mcl_log("cap_space_global", cap_space_non_hostile)
cap_space_available = math.min(cap_space_non_hostile, cap_space_wide)
cap_space_available = math_min(cap_space_non_hostile, cap_space_wide)
end
local mob_total_close = mob_counts_close[mob_type]
@ -1017,8 +981,8 @@ if mobs_spawn then
mob_total_close = 0
end
local cap_space_close = math.max(close_zone_cap - mob_total_close, 0)
cap_space_available = math.min(cap_space_available, cap_space_close)
local cap_space_close = math_max(close_zone_cap - mob_total_close, 0)
cap_space_available = math_min(cap_space_available, cap_space_close)
mcl_log("cap_space_close", cap_space_close)
mcl_log("cap_space_available", cap_space_available)
@ -1145,7 +1109,7 @@ if mobs_spawn then
local amount_to_spawn = math.random(group_min, spawn_in_group)
mcl_log("Spawning quantity: " .. amount_to_spawn)
amount_to_spawn = math.min(amount_to_spawn, cap_space_available)
amount_to_spawn = math_min(amount_to_spawn, cap_space_available)
mcl_log("throttled spawning quantity: " .. amount_to_spawn)
if logging then
@ -1196,8 +1160,8 @@ if mobs_spawn then
local players = get_connected_players()
local total_mobs, total_non_hostile, total_hostile = count_mobs_total_cap()
local cap_space_hostile = math.max(mob_cap.global_hostile - total_hostile, 0)
local cap_space_non_hostile = math.max(mob_cap.global_non_hostile - total_non_hostile, 0)
local cap_space_hostile = math_max(mob_cap.global_hostile - total_hostile, 0)
local cap_space_non_hostile = math_max(mob_cap.global_non_hostile - total_non_hostile, 0)
mcl_log("global cap_space_hostile", cap_space_hostile)
mcl_log("global cap_space_non_hostile", cap_space_non_hostile)

View File

@ -4,21 +4,17 @@
local S = minetest.get_translator("mobs_mc")
local BEAM_CHECK_FREQUENCY = 2
local BEAM_CHECK_FREQUENCY = 1
local POS_CHECK_FREQUENCY = 15
local HEAL_AMMOUNT = 37
local HEAL_INTERVAL = 1
local HEAL_AMOUNT = 2
local function heal(self)
local o = self.object
self.health = math.min(self.hp_max,self.health + HEAL_AMMOUNT)
end
local function check_beam(self)
for _, obj in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 80)) do
local luaentity = obj:get_luaentity()
if luaentity and luaentity.name == "mcl_end:crystal" then
if luaentity.beam then
if luaentity.beam == self.beam then
heal(self)
break
end
else
@ -106,7 +102,6 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
},
ignores_nametag = true,
do_custom = function(self,dtime)
mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple")
if self._pos_timer == nil or self._pos_timer > POS_CHECK_FREQUENCY then
self._pos_timer = 0
check_pos(self)
@ -115,8 +110,20 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", {
self._beam_timer = 0
check_beam(self)
end
self._beam_timer = self._beam_timer + dtime
self._pos_timer = self._pos_timer + dtime
if self.beam ~= nil then
-- heal
self._heal_timer = (self._heal_timer or 0) + dtime
if self._heal_timer > HEAL_INTERVAL then
self.health = math.min(self.hp_max,self.health + HEAL_AMOUNT)
self._heal_timer = self._heal_timer - HEAL_INTERVAL
end
end
mcl_bossbars.update_boss(self.object, "Ender Dragon", "light_purple")
end,
on_die = function(self, pos, cmi_cause)
if self._portal_pos then

View File

@ -83,8 +83,8 @@ mcl_mobs.register_mob("mobs_mc:iron_golem", {
stand_speed = 15, walk_speed = 15, run_speed = 25, punch_speed = 15,
stand_start = 0, stand_end = 0,
walk_start = 0, walk_end = 40,
run_start = 0, run_end = 40,
punch_start = 40, punch_end = 50,
run_start = 40, run_end = 80,
punch_start = 80, punch_end = 90,
},
jump = true,
do_custom = function(self, dtime)

View File

@ -10,6 +10,10 @@ mcl_weather.thunder = {
init_done = false,
}
lightning.register_on_strike(function(pos, pos2, objects)
if not mcl_weather.has_rain(pos) then return nil, true end
end)
minetest.register_globalstep(function(dtime)
if mcl_weather.get_weather() ~= "thunder" then
return false

View File

@ -330,9 +330,16 @@ function hb.change_hudbar(player, identifier, new_value, new_max_value, new_icon
local name = player:get_player_name()
local hudtable = hb.get_hudtable(identifier)
-- hb.change_hudbar may be called with a non-existing hudbar like hunger.
if hudtable == nil then
return false
end
if not hudtable.hudstate[name] then
return false
end
local value_changed, max_changed = false, false
if new_value then

View File

@ -1,7 +1,12 @@
local size_min, size_max = 20, 59
local delta_size = size_max - size_min
-- Constants
local size_min = 20 / 100 -- minimum size, prescaled
local size_max = 59 / 100 -- maximum size, prescaled
local delta_size = (size_max - size_min) / 10 -- Size change for each XP size level
local max_orb_age = 300 -- seconds
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
local size_to_xp = {
-- min and max XP amount for a given size
{-32768, 2}, -- 1
{ 3, 6}, -- 2
{ 7, 16}, -- 3
@ -16,24 +21,20 @@ local size_to_xp = {
}
local function xp_to_size(xp)
local i, l = 1, #size_to_xp
xp = xp or 0
while xp > size_to_xp[i][1] and i < l do
i = i + 1
-- Find the size for the xp amount
for i=1,11 do
local bucket = size_to_xp[i]
if xp >= bucket[1] and xp <= bucket[2] then
return (i - 1) * delta_size + size_min
end
end
return ((i - 1) / (l - 1) * delta_size + size_min) / 100
-- Fallback is the minimum size
return size_min
end
local max_orb_age = 300 -- seconds
local gravity = vector.new(0, -((tonumber(minetest.settings:get("movement_gravity"))) or 9.81), 0)
local collector, pos, pos2
local direction, distance, player_velocity, goal
local currentvel, acceleration, multiplier, velocity
local node, vel, def
local is_moving, is_slippery, slippery, slip_factor
local size
local function xp_step(self, dtime)
--if item set to be collected then only execute go to player
if self.collected == true then
@ -41,33 +42,32 @@ local function xp_step(self, dtime)
self.collected = false
return
end
collector = minetest.get_player_by_name(self.collector)
local collector = minetest.get_player_by_name(self.collector)
if collector and collector:get_hp() > 0 and vector.distance(self.object:get_pos(),collector:get_pos()) < 7.25 then
self.object:set_acceleration(vector.new(0,0,0))
self.disable_physics(self)
--get the variables
pos = self.object:get_pos()
pos2 = collector:get_pos()
local pos = self.object:get_pos()
local pos2 = collector:get_pos()
player_velocity = collector:get_velocity() or collector:get_player_velocity()
local player_velocity = collector:get_velocity() or collector:get_player_velocity()
pos2.y = pos2.y + 0.8
direction = vector.direction(pos,pos2)
distance = vector.distance(pos2,pos)
multiplier = distance
local direction = vector.direction(pos,pos2)
local distance = vector.distance(pos2,pos)
local multiplier = distance
if multiplier < 1 then
multiplier = 1
end
goal = vector.multiply(direction,multiplier)
currentvel = self.object:get_velocity()
local currentvel = self.object:get_velocity()
if distance > 1 then
multiplier = 20 - distance
velocity = vector.multiply(direction,multiplier)
goal = velocity
acceleration = vector.new(goal.x-currentvel.x,goal.y-currentvel.y,goal.z-currentvel.z)
self.object:add_velocity(vector.add(acceleration,player_velocity))
local velocity = vector.multiply(direction, multiplier)
local acceleration = vector.new(velocity.x - currentvel.x, velocity.y - currentvel.y, velocity.z - currentvel.z)
self.object:add_velocity(vector.add(acceleration, player_velocity))
elseif distance < 0.8 then
mcl_experience.add_xp(collector, self._xp)
self.object:remove()
@ -75,28 +75,26 @@ local function xp_step(self, dtime)
return
else
self.collector = nil
self.enable_physics(self)
self:enable_physics()
end
end
-- Age orbs
self.age = self.age + dtime
if self.age > max_orb_age then
self.object:remove()
return
end
pos = self.object:get_pos()
local pos = self.object:get_pos()
if not pos then return end
if pos then
node = minetest.get_node_or_nil({
x = pos.x,
y = pos.y -0.25,
z = pos.z
})
else
return
end
-- Get the node directly below the XP orb
local node = minetest.get_node_or_nil({
x = pos.x,
y = pos.y - 0.25, -- Orb collision box is +/-0.2, so go a bit below that
z = pos.z
})
-- Remove nodes in 'ignore'
if node and node.name == "ignore" then
@ -109,18 +107,18 @@ local function xp_step(self, dtime)
end
-- Slide on slippery nodes
vel = self.object:get_velocity()
def = node and minetest.registered_nodes[node.name]
is_moving = (def and not def.walkable) or
local vel = self.object:get_velocity()
local def = node and minetest.registered_nodes[node.name]
local is_moving = (def and not def.walkable) or
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
is_slippery = false
local is_slippery = false
if def and def.walkable then
slippery = minetest.get_item_group(node.name, "slippery")
local slippery = minetest.get_item_group(node.name, "slippery")
is_slippery = slippery ~= 0
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
-- Horizontal deceleration
slip_factor = 4.0 / (slippery + 4)
local slip_factor = 4.0 / (slippery + 4)
self.object:set_acceleration({
x = -vel.x * slip_factor,
y = 0,
@ -160,7 +158,6 @@ minetest.register_entity("mcl_experience:orb", {
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
pointable = false,
static_save = false,
},
moving_state = true,
slippery_state = false,
@ -191,7 +188,7 @@ minetest.register_entity("mcl_experience:orb", {
-- This was a minetest bug for a while: https://github.com/minetest/minetest/issues/14420
local xp = tonumber(staticdata) or 0
self._xp = xp
size = xp_to_size(xp)
local size = xp_to_size(xp)
self.object:set_properties({
visual_size = {x = size, y = size},
@ -199,6 +196,9 @@ minetest.register_entity("mcl_experience:orb", {
})
self.object:set_sprite({x=1,y=math.random(1,14)}, 14, 0.05, false)
end,
get_staticdata = function(self)
return tostring(self._xp or 0)
end,
enable_physics = function(self)
if not self.physical_state then

View File

@ -113,8 +113,8 @@ mesecon.register_node("mcl_observers:observer", {
sounds = mcl_sounds.node_sound_stone_defaults(),
paramtype2 = "facedir",
on_rotate = false,
_mcl_blast_resistance = 3.5,
_mcl_hardness = 3.5,
_mcl_blast_resistance = 3,
_mcl_hardness = 3,
}, {
description = S("Observer"),
_tt_help = S("Emits redstone pulse when block in front changes"),
@ -172,8 +172,8 @@ mesecon.register_node("mcl_observers:observer_down", {
sounds = mcl_sounds.node_sound_stone_defaults(),
groups = {pickaxey=1, material_stone=1, not_opaque=1, not_in_creative_inventory=1 },
on_rotate = false,
_mcl_blast_resistance = 3.5,
_mcl_hardness = 3.5,
_mcl_blast_resistance = 3,
_mcl_hardness = 3,
drop = "mcl_observers:observer_off",
}, {
tiles = {
@ -224,8 +224,8 @@ mesecon.register_node("mcl_observers:observer_up", {
sounds = mcl_sounds.node_sound_stone_defaults(),
groups = {pickaxey=1, material_stone=1, not_opaque=1, not_in_creative_inventory=1 },
on_rotate = false,
_mcl_blast_resistance = 3.5,
_mcl_hardness = 3.5,
_mcl_blast_resistance = 3,
_mcl_hardness = 3,
drop = "mcl_observers:observer_off",
}, {
tiles = {

View File

@ -218,7 +218,7 @@ minetest.register_node("mesecons_pistons:piston_normal_off", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_up_normal_off"})
@ -255,7 +255,7 @@ minetest.register_node("mesecons_pistons:piston_normal_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})
@ -326,7 +326,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_off", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_up_sticky_off"})
@ -363,7 +363,7 @@ minetest.register_node("mesecons_pistons:piston_sticky_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})
@ -449,7 +449,7 @@ minetest.register_node("mesecons_pistons:piston_up_normal_off", {
footstep = mcl_sounds.node_sound_wood_defaults().footstep
}),
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_down_normal_off"})
@ -487,7 +487,7 @@ minetest.register_node("mesecons_pistons:piston_up_normal_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})
@ -556,7 +556,7 @@ minetest.register_node("mesecons_pistons:piston_up_sticky_off", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_down_sticky_off"})
@ -594,7 +594,7 @@ minetest.register_node("mesecons_pistons:piston_up_sticky_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})
@ -680,7 +680,7 @@ minetest.register_node("mesecons_pistons:piston_down_normal_off", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_normal_off"})
@ -718,7 +718,7 @@ minetest.register_node("mesecons_pistons:piston_down_normal_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})
@ -782,7 +782,7 @@ minetest.register_node("mesecons_pistons:piston_down_sticky_off", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_AXIS then
minetest.set_node(pos, {name="mesecons_pistons:piston_sticky_off"})
@ -820,7 +820,7 @@ minetest.register_node("mesecons_pistons:piston_down_sticky_on", {
},
},
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_hardness = 1.5,
on_rotate = false,
})

View File

@ -62,7 +62,7 @@ local bamboo_def = {
inventory_image = "mcl_bamboo_bamboo_shoot.png",
wield_image = "mcl_bamboo_bamboo_shoot.png",
_mcl_blast_resistance = 1,
_mcl_hardness = 1.5,
_mcl_hardness = 1,
node_box = {
type = "fixed",
fixed = {
@ -277,7 +277,7 @@ local bamboo_block_def = {
sounds = node_sound,
paramtype2 = "facedir",
drops = "mcl_bamboo:bamboo_block",
_mcl_blast_resistance = 3,
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_stripped_variant = "mcl_bamboo:bamboo_block_stripped", -- this allows us to use the built in Axe's strip block.
on_place = mcl_util.rotate_axis,

View File

@ -208,7 +208,7 @@ if minetest.get_modpath("mcl_fences") then
wood_groups,
minetest.registered_nodes["mcl_core:wood"]._mcl_hardness,
minetest.registered_nodes["mcl_core:wood"]._mcl_blast_resistance,
node_sound) -- note: about missing params.. will use defaults.
node_sound)
mcl_bamboo.mcl_log(dump(fence_id))
mcl_bamboo.mcl_log(dump(gate_id))

View File

@ -210,7 +210,7 @@ function mcl_beds.register_bed(name, def)
stack_max = 1,
groups = {handy=1, bed = 1, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, deco_block = 1, flammable=-1},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
_mcl_blast_resistance = 0.2,
sounds = def.sounds or default_sounds,
selection_box = common_box,
collision_box = common_box,
@ -286,10 +286,9 @@ function mcl_beds.register_bed(name, def)
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
-- FIXME: Should be bouncy=66, but this would be a higher bounciness than slime blocks!
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=33, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
groups = {handy = 1, flammable = -1, bed = 2, dig_by_piston=1, bouncy=66, fall_damage_add_percent=-50, not_in_creative_inventory = 1},
_mcl_hardness = 0.2,
_mcl_blast_resistance = 1,
_mcl_blast_resistance = 0.2,
sounds = def.sounds or default_sounds,
drop = "",
selection_box = common_box,

View File

@ -33,8 +33,8 @@ minetest.register_node("mcl_blackstone:blackstone_gilded", {
{items = {"mcl_blackstone:blackstone_gilded"}, rarity = 1},
}
},
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_blast_resistance = 6,
_mcl_hardness = 1.5,
_mcl_silk_touch_drop = true,
_mcl_fortune_drop = {
discrete_uniform_distribution = true,
@ -226,18 +226,7 @@ mcl_stairs.register_stair_and_slab("blackstone_brick_polished", "mcl_blackstone:
S("Double Polished Blackstone Brick Slab"), nil)
--Wall
mcl_walls.register_wall(
"mcl_blackstone:wall",
S("Blackstone Wall"),
"mcl_blackstone:blackstone",
{
"mcl_blackstone_top.png",
"mcl_blackstone_top.png",
"mcl_blackstone_side.png"
},
"",
{ cracky=3, pickaxey=1, material_stone=1 }
)
mcl_walls.register_wall("mcl_blackstone:wall", S("Blackstone Wall"), "mcl_blackstone:blackstone")
--lavacooling

View File

@ -456,8 +456,8 @@ minetest.register_node("mcl_brewing:stand_000", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -537,8 +537,8 @@ minetest.register_node("mcl_brewing:stand_100", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -617,8 +617,8 @@ minetest.register_node("mcl_brewing:stand_010", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -692,8 +692,8 @@ minetest.register_node("mcl_brewing:stand_001", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -777,8 +777,8 @@ minetest.register_node("mcl_brewing:stand_110", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -858,8 +858,8 @@ minetest.register_node("mcl_brewing:stand_101", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -939,8 +939,8 @@ minetest.register_node("mcl_brewing:stand_011", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,
@ -1027,8 +1027,8 @@ minetest.register_node("mcl_brewing:stand_111", {
}
},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 1,
_mcl_hardness = 1,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
on_destruct = on_destruct,
allow_metadata_inventory_take = allow_take,
allow_metadata_inventory_put = allow_put,

View File

@ -19,6 +19,6 @@ Cherry Slab=Dalle en cerisier
Double Cherry Slab=Double Dalle en cerisier
Cherry Sign=Panneau de cerisier
Cherry Fence=Barrière en cerisier
Cherry Gate=Portillion en cerisier
Cherry Fence Gate=Portillion en cerisier
Cherry Pressure Plate=Plaque de pression en cerisier
Cherry Button=Bouton de Cerisier

View File

@ -19,6 +19,6 @@ Cherry Slab=Laje de Cerejeira
Double Cherry Slab=Laje Dupla de Cerejeira
Cherry Sign=Placa de Cerejeira
Cherry Fence=Cerca de Cerejeira
Cherry Gate=Portão de Cerejeira
Cherry Fence Gate=Portão de Cerejeira
Cherry Pressure Plate=Placa de Pressão de Cerejeira
Cherry Button=Botão de Cerejeira

View File

@ -19,6 +19,6 @@ Cherry Slab=Вишнёвая плита
Double Cherry Slab=Двойная вишнёвая плита
Cherry Sign=Вишнёвая табличка
Cherry Fence=Вишнёвый забор
Cherry Gate=Вишнёвая калитка
Cherry Fence Gate=Вишнёвая калитка
Cherry Pressure Plate=Вишнёвая нажимная плита
Cherry Button=Вишнёвая кнопка

View File

@ -19,6 +19,6 @@ Cherry Slab=
Double Cherry Slab=
Cherry Sign=
Cherry Fence=
Cherry Gate=
Cherry Fence Gate=
Cherry Pressure Plate=
Cherry Button=

View File

@ -51,13 +51,13 @@ mcl_stairs.register_stair("cherrywood", "mcl_cherry_blossom:cherrywood",
{handy=1,axey=1, flammable=3,wood_stairs=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{"mcl_cherry_blossom_planks.png"},
S("Cherry Stairs"),
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
"woodlike")
mcl_stairs.register_slab("cherrywood", "mcl_cherry_blossom:cherrywood",
{handy=1,axey=1, flammable=3,wood_slab=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{"mcl_cherry_blossom_planks.png"},
S("Cherry Slab"),
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
S("Double Cherry Slab"))
-- Signs
@ -69,7 +69,7 @@ mcl_signs.register_sign_custom("mcl_cherry_blossom", "_cherrywood",
mcl_fences.register_fence_and_fence_gate(
"cherry_fence",
S("Cherry Fence"),
S("Cherry Gate"),
S("Cherry Fence Gate"),
"mcl_cherry_blossom_planks.png",
{handy=1, axey=1, flammable=2, fence_wood=1, fire_encouragement=5, fire_flammability=20},
minetest.registered_nodes["mcl_core:wood"]._mcl_hardness,

View File

@ -0,0 +1,233 @@
# `mcl_chests` API
When reading through this documentation, please keep in mind that the chest
animations are achieved by giving each chest node an entity, as Minetest (as of
5.8.1) doesn't support giving nodes animated meshes, only static ones.
Because of that, a lot of parameters passed through the exposed functions are
be related to nodes and entities.
Please refer to [Minetest documentation](http://api.minetest.net/) and the code
comments in `api.lua`.
## `mcl_chests.register_chest(basename, definition)`
This function allows for simple chest registration, used by both regular and
trapped chests.
* `basename` is a string that will be concatenated to form full nodenames for
chests, for example `"mcl_chests:basename_small"`.
* `definition` is a key-value table, with the following fields:
```lua
{
desc = S("Stone Chest"),
-- Equivalent to `description` field of Item/Node definition.
-- Will be shown as chest's name in the inventory.
title = {
small = S("Stone Chest") -- the same as `desc` if not specified
double = S("Large Stone Chest") -- defaults to `"Large " .. desc`
}
-- These will be shown when opening the chest (in formspecs).
longdesc = S(
"Stone Chests are containers which provide 27 inventory slots. Stone Chests can be turned into" ..
"large stone chests with double the capacity by placing two stone chests next to each other."
),
usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."),
tt_help = S("27 inventory slots") .. "\n" .. S("Can be combined to a large stone chest"),
-- Equivalent to `_doc_items_longdesc`, `_doc_items_usagehelp` and
-- `_tt_help` fields of Item/Node definition. Shown in the tooltip and wiki.
tiles = {
small = { "vl_stone_chests_small.png" },
double = { "vl_stone_chests_double.png" },
inv = {
"vl_stone_chests_top.png",
"vl_stone_chests_bottom.png",
"vl_stone_chests_right.png",
"vl_stone_chests_left.png",
"vl_stone_chests_back.png",
"vl_stone_chests_front.png"
},
},
-- `small` and `double` fields contain the textures that will be applied to
-- chest entities.
-- `inv` field contains table of textures (6 in total, for each cube side),
-- that will be used to render the chest "node" in the inventory.
groups = {
pickaxey = 1,
stone = 1,
material_stone = 1,
},
-- Equivalent to `groups` field of Item/Node definition. There is some table
-- merging occuring internally, but it is purely for entity rendering.
sounds = {
mcl_sounds.node_sound_stone_defaults(), -- defaults to `nil`
"vl_stone_chests_sound" -- defaults to `"default_chest"`
},
-- First value is equivalent to `sounds` field of Item/Node definition.
-- Second value is a sound prefix, from which the actual sounds will be
-- concatenated (e.g. `vl_stone_chests_sound_open.ogg`). See `api.lua`.
hardness = 4.0,
-- Equivalent to `_mcl_blast_resistance` and `_mcl_hardness` fields of
-- Item/Node definition. They are always equal for chests.
hidden = false,
-- Equivalent to `_doc_items_hidden` field of Item/Node definition.
mesecons = {
receptor = {
state = mesecon.state.on,
rules = mesecon.rules.pplate,
},
},
-- Equivalent to `mesecons` field of Item/Node definition.
on_rightclick = function(pos, node, clicker)
mcl_util.deal_damage(clicker, 2)
end,
-- If provided, will be executed at the end of the actual `on_rightclick`
-- function of the chest node.
-- If `on_rightclick_left` or `on_rightclick_right` are not provided, this
-- will also be what is executed for left and right double chest nodes,
-- respectively.
drop = "chest",
-- If provided, the chest will not drop itself, but the item of the chest
-- with that basename.
canonical_basename = "chest",
-- If provided, the chest will turn into chest with that basename in
-- `on_construct`.
}
```
For usage examples, see `chests.lua` and `example.lua`.
## `mcl_chests.create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos)`
This function creates a chest entity based on the parameters:
* `pos` is the position vector.
* `node_name` is a string used in initialization data for the entity.
* `textures` is the entity textures.
* `param2` is a node param2, which then will be converted to entity direction.
* `double` is a boolean value for whether the chest is double or not.
* `sound_prefix` is a string, from which the actual sounds for the entity will
be concatenated.
* `mesh_prefix` is the same thing as `sound_prefix`, but for meshes.
* `animation_type` is a string that will be used in `set_animation` method of
chest entity.
* `dir` and `entity_pos` are number and vector values used to get entity info.
Returned value is either a luaentity, or `nil` if failed (in which case a
warning message gets written into the console).
## `mcl_chests.find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir, entity_pos)`
This function finds an existing entity, or creates one if failed. Parameters:
* `pos` is the position vector.
* `node_name` is a string used in initialization data for the entity.
* `textures` is the entity textures.
* `param2` is a node param2, which then will be converted to entity direction.
* `double` is a boolean value for whether the chest is double or not.
* `sound_prefix` is a string, from which the actual sounds for the entity will
be concatenated.
* `mesh_prefix` is the same thing as `sound_prefix`, but for meshes.
* `animation_type` is a string that will be used in `set_animation` method of
chest entity.
* `dir` and `entity_pos` are number and vector values used to get entity info.
Returned value is either a luaentity, or `nil` if failed (in which case a
warning message gets written into the console).
## `mcl_chests.select_and_spawn_entity(pos, node)`
This function is a simple wrapper for `mcl_chests.find_or_create_entity`,
getting most of the fields from node definition.
* `pos` is the position vector.
* `node` is a NodeRef.
Returned value is either a luaentity, or `nil` if failed (in which case a
warning message gets written into the console).
## `mcl_chests.no_rotate`
This function is equivalent to `screwdriver.disallow` and is used when a chest
can't be rotated, and is applied in `on_rotate` field of Node definition.
## `mcl_chests.simple_rotate(pos, node, user, mode, new_param2)`
This function allows for simple rotation with the entity being affected as well,
and is applied in `on_rotate` field of Node definition.
## `mcl_chests.open_chests`
This table contains all currently open chests, indexed by player name.
`nil` if player is not using a chest, and `{ pos = <chest node position> }`
otherwise (where position is a vector value).
## `mcl_chests.protection_check_move(pos, from_list, from_index, to_list, to_index, count, player)`
This function is called in `allow_metadata_inventory_move` field of Node
definition.
## `mcl_chests.protection_check_put_take(pos, listname, index, stack, player)`
This function is called in `allow_metadata_inventory_put` and
`allow_metadata_inventory_take` fields of Node definition.
## `mcl_chests.player_chest_open(player, pos, node_name, textures, param2, double, sound, mesh, shulker)`
This function opens a chest based on the parameters:
* `player` is an ObjectRef.
* `pos` is the position vector.
* `node_name` is a string used in initialization data for the entity.
* `textures` is the entity textures.
* `param2` is a node param2, which then will be converted to entity direction.
* `double` is a boolean value for whether the chest is double or not.
* `sound` is a prefix string, from which the actual sounds for the entity will
be concatenated.
* `mesh` is the same thing as `sound`, but for meshes.
* `shulker` is a boolean value for whether the chest is a shulker or not.
## `mcl_chests.player_chest_close(player)`
This function has to be called when a player closes a chest.
* `player` is an ObjectRef.
## `mcl_chests.chest_update_after_close(pos)`
This function is called when a chest is closed by `player_chest_close`.
* `pos` is the chest's position vector.
## `mcl_chests.is_not_shulker_box(stack)`
This function checks for whether `stack` is a shulker box, and returns `false`
if it is. Used internally to disallow putting shulker boxes into shulker boxes.
* `stack` is an ItemStack.

View File

@ -0,0 +1,19 @@
# `mcl_chests`
This mod adds normal and large chests, trapped chests, ender chests and
shulkers, providing an API for mods to register their own chests.
The API is documented in `API.md`.
## License of source code
Copyright (C) 2011-2012 celeron55, Perttu Ahola <celeron55@gmail.com>\
Copyright (C) 2024 rudzik8, Mikita Wiśniewski <rudzik8@protonmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
http://www.gnu.org/licenses/lgpl-2.1.html

View File

@ -0,0 +1,966 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local get_double_container_neighbor_pos = mcl_util.get_double_container_neighbor_pos
local string = string
local table = table
local sf = string.format
-- Recursively merge tables with eachother
local function table_merge(tbl, ...)
local t = table.copy(tbl)
for k,v in pairs(...) do
if type(t[k]) == "table" and type(v) == "table" then
table_merge(t[k], v)
else
t[k] = v
end
end
return t
end
-- Chest Entity
-- ------------
-- This is necessary to show the chest as an animated mesh, as Minetest doesn't support assigning animated meshes to
-- nodes directly. We're bypassing this limitation by giving each chest its own entity, and making the chest node
-- itself fully transparent.
local animated_chests = (minetest.settings:get_bool("animated_chests") ~= false)
local entity_animations = {
shulker = {
speed = 50,
open = { x = 45, y = 95 },
close = { x = 95, y = 145 },
},
chest = {
speed = 25,
open = { x = 0, y = 7 },
close = { x = 13, y = 20 },
},
}
minetest.register_entity("mcl_chests:chest", {
initial_properties = {
visual = "mesh",
pointable = false,
physical = false,
static_save = false,
},
set_animation = function(self, animname)
local anim_table = entity_animations[self.animation_type]
local anim = anim_table[animname]
if not anim then return end
self.object:set_animation(anim, anim_table.speed, 0, false)
end,
open = function(self, playername)
self.players[playername] = true
if not self.is_open then
self:set_animation("open")
minetest.sound_play(self.sound_prefix .. "_open", { pos = self.node_pos, gain = 0.5, max_hear_distance = 16 },
true)
self.is_open = true
end
end,
close = function(self, playername)
local playerlist = self.players
playerlist[playername] = nil
if self.is_open then
if next(playerlist) then
return
end
self:set_animation("close")
minetest.sound_play(self.sound_prefix .. "_close",
{ pos = self.node_pos, gain = 0.3, max_hear_distance = 16 },
true)
self.is_open = false
end
end,
initialize = function(self, node_pos, node_name, textures, dir, double, sound_prefix, mesh_prefix, animation_type)
self.node_pos = node_pos
self.node_name = node_name
self.sound_prefix = sound_prefix
self.animation_type = animation_type
local obj = self.object
obj:set_armor_groups({ immortal = 1 })
obj:set_properties({
textures = textures,
mesh = mesh_prefix .. (double and "_double" or "") .. ".b3d",
})
self:set_yaw(dir)
self.players = {}
end,
reinitialize = function(self, node_name)
self.node_name = node_name
end,
set_yaw = function(self, dir)
self.object:set_yaw(minetest.dir_to_yaw(dir))
end,
check = function(self)
local node_pos, node_name = self.node_pos, self.node_name
if not node_pos or not node_name then
return false
end
local node = minetest.get_node(node_pos)
if node.name ~= node_name then
return false
end
return true
end,
on_activate = function(self, initialization_data)
if initialization_data and initialization_data:find("\"###mcl_chests:chest###\"") then
self:initialize(unpack(minetest.deserialize(initialization_data)))
else
minetest.log("warning",
"[mcl_chests] on_activate called without proper initialization_data ... removing entity")
self.object:remove()
end
end,
on_step = function(self, dtime)
if not self:check() then
self.object:remove()
end
end
})
local function get_entity_pos(pos, dir, double)
pos = vector.copy(pos)
if double then
local add, mul, vec, cross = vector.add, vector.multiply, vector.new, vector.cross
pos = add(pos, mul(cross(dir, vec(0, 1, 0)), -0.5))
end
return pos
end
local function find_entity(pos)
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 0)) do
local luaentity = obj:get_luaentity()
if luaentity and luaentity.name == "mcl_chests:chest" then
return luaentity
end
end
end
local function get_entity_info(pos, param2, double, dir, entity_pos)
dir = dir or minetest.facedir_to_dir(param2)
return dir, get_entity_pos(pos, dir, double)
end
local function create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir,
entity_pos)
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
local initialization_data = minetest.serialize({pos, node_name, textures, dir, double, sound_prefix,
mesh_prefix, animation_type, "###mcl_chests:chest###"})
local obj = minetest.add_entity(entity_pos, "mcl_chests:chest", initialization_data)
if obj and obj:get_pos() then
return obj:get_luaentity()
else
minetest.log("warning", "[mcl_chests] Failed to create entity at " ..
(entity_pos and minetest.pos_to_string(entity_pos, 1) or "nil"))
end
end
mcl_chests.create_entity = create_entity
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix,
animation_type, dir, entity_pos)
dir, entity_pos = get_entity_info(pos, param2, double, dir, entity_pos)
return find_entity(entity_pos) or
create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, animation_type, dir,
entity_pos)
end
mcl_chests.find_or_create_entity = find_or_create_entity
local function select_and_spawn_entity(pos, node)
local node_name = node.name
local node_def = minetest.registered_nodes[node_name]
local double_chest = minetest.get_item_group(node_name, "double_chest") > 0
find_or_create_entity(pos, node_name, node_def._chest_entity_textures, node.param2, double_chest,
node_def._chest_entity_sound, node_def._chest_entity_mesh, node_def._chest_entity_animation_type)
end
mcl_chests.select_and_spawn_entity = select_and_spawn_entity
local no_rotate, simple_rotate
if screwdriver then
no_rotate = screwdriver.disallow
simple_rotate = function(pos, node, user, mode, new_param2)
if screwdriver.rotate_simple(pos, node, user, mode, new_param2) ~= false then
local nodename = node.name
local nodedef = minetest.registered_nodes[nodename]
local dir = minetest.facedir_to_dir(new_param2)
find_or_create_entity(pos, nodename, nodedef._chest_entity_textures, new_param2, false,
nodedef._chest_entity_sound,
nodedef._chest_entity_mesh, nodedef._chest_entity_animation_type, dir):set_yaw(dir)
else
return false
end
end
end
mcl_chests.no_rotate, mcl_chests.simple_rotate = no_rotate, simple_rotate
-- List of open chests
-- -------------------
-- Key: Player name
-- Value:
-- If player is using a chest: { pos = <chest node position> }
-- Otherwise: nil
local open_chests = {}
mcl_chests.open_chests = open_chests
-- To be called if a player opened a chest
local function player_chest_open(player, pos, node_name, textures, param2, double, sound, mesh, shulker)
local name = player:get_player_name()
open_chests[name] = {
pos = pos,
node_name = node_name,
textures = textures,
param2 = param2,
double = double,
sound = sound,
mesh = mesh,
shulker = shulker
}
if animated_chests then
local dir = minetest.facedir_to_dir(param2)
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh,
shulker and "shulker" or "chest", dir):open(name)
end
end
mcl_chests.player_chest_open = player_chest_open
-- Simple protection checking functions
local function protection_check_move(pos, from_list, from_index, to_list, to_index, count, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
else
return count
end
end
mcl_chests.protection_check_move = protection_check_move
local function protection_check_take(pos, listname, index, stack, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
else
return stack:get_count()
end
end
mcl_chests.protection_check_put_take = protection_check_take
-- Logging functions
local function log_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
minetest.log("action", player:get_player_name() ..
" moves stuff to chest at " .. minetest.pos_to_string(pos))
end
local function log_inventory_put(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name() ..
" moves stuff to chest at " .. minetest.pos_to_string(pos))
-- BEGIN OF LISTRING WORKAROUND
if listname == "input" then
local inv = minetest.get_inventory({ type = "node", pos = pos })
inv:add_item("main", stack)
end
-- END OF LISTRING WORKAROUND
end
local function log_inventory_take(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name() ..
" takes stuff from chest at " .. minetest.pos_to_string(pos))
end
-- To be called when a chest is closed (only relevant for trapped chest atm)
local function chest_update_after_close(pos)
local node = minetest.get_node(pos)
if node.name == "mcl_chests:trapped_chest_on_small" then
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_small", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_small", { "mcl_chests_trapped.png" }, node.param2, false,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small")
mesecon.receptor_off(pos, mesecon.rules.pplate)
elseif node.name == "mcl_chests:trapped_chest_on_left" then
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 })
find_or_create_entity(pos, "mcl_chests:trapped_chest_left", mcl_chests.tiles.chest_trapped_double, node.param2, true,
"default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos, mesecon.rules.pplate)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "left")
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_right", param2 = node.param2 })
mesecon.receptor_off(pos_other, mesecon.rules.pplate)
elseif node.name == "mcl_chests:trapped_chest_on_right" then
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_right", param2 = node.param2 })
mesecon.receptor_off(pos, mesecon.rules.pplate)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "right")
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_left", param2 = node.param2 })
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", mcl_chests.tiles.chest_trapped_double,
node.param2, true, "default_chest", "mcl_chests_chest", "chest")
:reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos_other, mesecon.rules.pplate)
end
end
mcl_chests.chest_update_after_close = chest_update_after_close
-- To be called if a player closed a chest
local function player_chest_close(player)
local name = player:get_player_name()
local open_chest = open_chests[name]
if open_chest == nil then
return
end
if animated_chests then
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2,
open_chest.double, open_chest.sound, open_chest.mesh, open_chest.shulker and "shulker" or "chest")
:close(name)
end
chest_update_after_close(open_chest.pos)
open_chests[name] = nil
end
mcl_chests.player_chest_close = player_chest_close
local function double_chest_add_item(top_inv, bottom_inv, listname, stack)
if not stack or stack:is_empty() then return end
local name = stack:get_name()
local function top_off(inv, stack)
for c, chest_stack in ipairs(inv:get_list(listname)) do
if stack:is_empty() then
break
end
if chest_stack:get_name() == name and chest_stack:get_free_space() > 0 then
stack = chest_stack:add_item(stack)
inv:set_stack(listname, c, chest_stack)
end
end
return stack
end
stack = top_off(top_inv, stack)
stack = top_off(bottom_inv, stack)
if not stack:is_empty() then
stack = top_inv:add_item(listname, stack)
if not stack:is_empty() then
bottom_inv:add_item(listname, stack)
end
end
end
local function on_chest_blast(pos)
local node = minetest.get_node(pos)
local drop_items_chest = mcl_util.drop_items_from_meta_container("main")
drop_items_chest(pos, node)
minetest.remove_node(pos)
end
local function limit_put_list(stack, list)
for _, other in ipairs(list) do
stack = other:add_item(stack)
if stack:is_empty() then
break
end
end
return stack
end
local function limit_put(stack, top_inv, bottom_inv)
local leftover = ItemStack(stack)
leftover = limit_put_list(leftover, top_inv:get_list("main"))
leftover = limit_put_list(leftover, bottom_inv:get_list("main"))
return stack:get_count() - leftover:get_count()
end
local function close_forms(canonical_basename, pos)
local players = minetest.get_connected_players()
for p = 1, #players do
if vector.distance(players[p]:get_pos(), pos) <= 30 then
minetest.close_formspec(players[p]:get_player_name(),
"mcl_chests:" .. canonical_basename .. "_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z)
end
end
end
local function get_chest_inventories(pos, side)
local inv = minetest.get_inventory({ type = "node", pos = pos })
local node = minetest.get_node(pos)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, side)
local inv_other = minetest.get_inventory({ type = "node", pos = pos_other })
local top_inv, bottom_inv
if side == "left" then
top_inv = inv
bottom_inv = inv_other
else
top_inv = inv_other
bottom_inv = inv
end
return top_inv, bottom_inv
end
-- Functions used in double chest registration code
-- ------------------------------------------------
-- The `return function` wrapping is necessary to avoid stacking up parameters.
-- `side` is either "left" or "right".
local function hopper_pull_double(side) return function(pos, hop_pos, hop_inv, hop_list)
local top_inv, bottom_inv = get_chest_inventories(pos, side)
local stack_id = mcl_util.select_stack(top_inv, "main", hop_inv, hop_list)
if stack_id ~= nil then
return top_inv, "main", stack_id
end
stack_id = mcl_util.select_stack(bottom_inv, "main", hop_inv, hop_list)
return bottom_inv, "main", stack_id
end end
local function hopper_push_double(side) return function(pos, hop_pos, hop_inv, hop_list)
local top_inv, bottom_inv = get_chest_inventories(pos, side)
local stack_id = mcl_util.select_stack(hop_inv, hop_list, top_inv, "main", nil, 1)
if stack_id ~= nil then
return top_inv, "main", stack_id
end
stack_id = mcl_util.select_stack(hop_inv, hop_list, bottom_inv, "main", nil, 1)
return bottom_inv, "main", stack_id
end end
local function construct_double_chest(side, names) return function(pos)
local n = minetest.get_node(pos)
local param2 = n.param2
local p = get_double_container_neighbor_pos(pos, param2, side)
-- Turn into a small chest if the neighbor is gone
if not p or minetest.get_node(p).name ~= names[side].cr then
n.name = names.small.a
minetest.swap_node(pos, n)
end
end end
local function destruct_double_chest(side, names, canonical_basename, small_textures, sound_prefix) return function(pos)
local n = minetest.get_node(pos)
if n.name == names.small.a then
return
end
close_forms(canonical_basename, pos)
local param2 = n.param2
local p = get_double_container_neighbor_pos(pos, param2, side)
if not p or minetest.get_node(p).name ~= names[side].r then
return
end
close_forms(canonical_basename, p)
minetest.swap_node(p, { name = names.small.a, param2 = param2 })
create_entity(p, names.small.a, small_textures, param2, false, sound_prefix, "mcl_chests_chest", "chest")
end end
-- Small chests use `protection_check_take` for both put and take actions.
local function protection_check_put(side) return function(pos, listname, index, stack, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
-- BEGIN OF LISTRING WORKAROUND
elseif listname == "input" then
local top_inv, bottom_inv = get_chest_inventories(pos, side)
return limit_put(stack, top_inv, bottom_inv)
-- END OF LISTRING WORKAROUND
else
return stack:get_count()
end
end end
local function log_inventory_put_double(side) return function(pos, listname, index, stack, player)
minetest.log("action", player:get_player_name() ..
" moves stuff to chest at " .. minetest.pos_to_string(pos))
-- BEGIN OF LISTRING WORKAROUND
if listname == "input" then
local top_inv, bottom_inv = get_chest_inventories(pos, side)
top_inv:set_stack("input", 1, nil)
bottom_inv:set_stack("input", 1, nil)
double_chest_add_item(top_inv, bottom_inv, "main", stack)
end
-- END OF LISTRING WORKAROUND
end end
-- This is a helper function to register regular chests (both small and double variants).
-- Some parameters here are only utilized by trapped chests.
function mcl_chests.register_chest(basename, d)
-- If this passes without crash, we know for a fact that d = {...}
assert((d and type(d) == "table"), "Second argument to mcl_chests.register_chest must be a table")
-- Fallback for when there is no `title` field
if not d.title then d.title = {} end
d.title.small = d.title.small or d.desc
d.title.double = d.title.double or ("Large " .. d.title.small)
if not d.drop then
d.drop = "mcl_chests:" .. basename
else
d.drop = "mcl_chests:" .. d.drop
end
local drop_items_chest = mcl_util.drop_items_from_meta_container("main")
if not d.groups then d.groups = {} end
if not d.on_rightclick_left then
d.on_rightclick_left = d.on_rightclick
end
if not d.on_rightclick_right then
d.on_rightclick_right = d.on_rightclick
end
--[[local on_rightclick_side = {
left = d.on_rightclick_left or d.on_rightclick,
right = d.on_rightclick_right or d.on_rightclick,
}]]
if not d.sounds or type(d.sounds) ~= "table" then
d.sounds = { nil, "default_chest" }
end
if not d.sounds[2] then
d.sounds[2] = "default_chest"
end
-- The basename of the "canonical" version of the node, if set (e.g.: trapped_chest_on → trapped_chest).
-- Used to get a shared formspec ID and to swap the node back to the canonical version in on_construct.
if not d.canonical_basename then
d.canonical_basename = basename
end
-- Names table
-- -----------
-- Accessed through names["kind"].x (names.kind.x), where x can be:
-- a = "actual"
-- c = canonical
-- r = reverse (only for double chests)
-- cr = canonical, reverse (only for double chests)
local names = {
small = {
a = "mcl_chests:" .. basename .. "_small",
c = "mcl_chests:" .. d.canonical_basename .. "_small",
},
left = {
a = "mcl_chests:" .. basename .. "_left",
c = "mcl_chests:" .. d.canonical_basename .. "_left",
},
right = {
a = "mcl_chests:" .. basename .. "_right",
c = "mcl_chests:" .. d.canonical_basename .. "_right",
},
}
names.left.r = names.right.a
names.right.r = names.left.a
names.left.cr = names.right.c
names.right.cr = names.left.c
local small_textures = d.tiles.small
local double_textures = d.tiles.double
-- Construct groups
local groups_inv = table_merge({ deco_block = 1 }, d.groups)
local groups_small = table_merge(groups_inv, {
container = 2,
deco_block = 1,
chest_entity = 1,
not_in_creative_inventory = 1
}, d.groups)
local groups_left = table_merge(groups_small, {
double_chest = 1
}, d.groups)
local groups_right = table_merge(groups_small, {
-- In a double chest, the entity is assigned to the left side, but not the right one.
chest_entity = 0,
double_chest = 2
}, d.groups)
-- Dummy inventory node
-- Will turn into names.small.a when placed down
minetest.register_node("mcl_chests:" .. basename, {
description = d.desc,
_tt_help = d.tt_help,
_doc_items_longdesc = d.longdesc,
_doc_items_usagehelp = d.usagehelp,
_doc_items_hidden = d.hidden,
drawtype = "mesh",
mesh = "mcl_chests_chest.b3d",
tiles = small_textures,
use_texture_alpha = "opaque",
paramtype = "light",
paramtype2 = "facedir",
sounds = d.sounds[1],
groups = groups_inv,
on_construct = function(pos, node)
local node = minetest.get_node(pos)
node.name = names.small.a
minetest.set_node(pos, node)
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
end,
})
minetest.register_node(names.small.a, {
description = d.desc,
_tt_help = d.tt_help,
_doc_items_longdesc = d.longdesc,
_doc_items_usagehelp = d.usagehelp,
_doc_items_hidden = d.hidden,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = small_textures,
_chest_entity_sound = d.sounds[2],
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
paramtype = "light",
paramtype2 = "facedir",
drop = d.drop,
groups = groups_small,
is_ground_content = false,
sounds = d.sounds[1],
on_construct = function(pos)
local param2 = minetest.get_node(pos).param2
local meta = minetest.get_meta(pos)
--[[ This is a workaround for Minetest issue 5894
<https://github.com/minetest/minetest/issues/5894>.
Apparently if we don't do this, large chests initially don't work when
placed at chunk borders, and some chests randomly don't work after
placing. ]]
-- FIXME: Remove this workaround when the bug has been fixed.
-- BEGIN OF WORKAROUND --
meta:set_string("workaround", "ignore_me")
meta:set_string("workaround", "") -- Done to keep metadata clean
-- END OF WORKAROUND --
local inv = meta:get_inventory()
inv:set_size("main", 9 * 3)
--[[ The "input" list is *another* workaround (hahahaha!) around the fact that Minetest
does not support listrings to put items into an alternative list if the first one
happens to be full. See <https://github.com/minetest/minetest/issues/5343>.
This list is a hidden input-only list and immediately puts items into the appropriate chest.
It is only used for listrings and hoppers. This workaround is not that bad because it only
requires a simple inventory allows check for large chests.]]
-- FIXME: Refactor the listrings as soon Minetest supports alternative listrings
-- BEGIN OF LISTRING WORKAROUND
inv:set_size("input", 1)
-- END OF LISTRING WORKAROUND
-- Combine into a double chest if neighbouring another small chest
if minetest.get_node(get_double_container_neighbor_pos(pos, param2, "right")).name ==
names.small.a then
minetest.swap_node(pos, { name = names.right.a, param2 = param2 })
local p = get_double_container_neighbor_pos(pos, param2, "right")
minetest.swap_node(p, { name = names.left.a, param2 = param2 })
create_entity(p, names.left.a, double_textures, param2, true, d.sounds[2],
"mcl_chests_chest", "chest")
elseif minetest.get_node(get_double_container_neighbor_pos(pos, param2, "left")).name ==
names.small.a then
minetest.swap_node(pos, { name = names.left.a, param2 = param2 })
create_entity(pos, names.left.a, double_textures, param2, true, d.sounds[2],
"mcl_chests_chest", "chest")
local p = get_double_container_neighbor_pos(pos, param2, "left")
minetest.swap_node(p, { name = names.right.a, param2 = param2 })
else
minetest.swap_node(pos, { name = names.small.a, param2 = param2 })
create_entity(pos, names.small.a, small_textures, param2, false, d.sounds[2],
"mcl_chests_chest", "chest")
end
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
end,
after_dig_node = drop_items_chest,
on_blast = on_chest_blast,
allow_metadata_inventory_move = protection_check_move,
allow_metadata_inventory_take = protection_check_take,
allow_metadata_inventory_put = protection_check_take,
on_metadata_inventory_move = log_inventory_move,
on_metadata_inventory_put = log_inventory_put,
on_metadata_inventory_take = log_inventory_take,
_mcl_blast_resistance = d.hardness,
_mcl_hardness = d.hardness,
on_rightclick = function(pos, node, clicker)
local topnode = minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z })
if topnode and topnode.name and minetest.registered_nodes[topnode.name] then
if minetest.registered_nodes[topnode.name].groups.opaque == 1 then
-- won't open if there is no space from the top
return false
end
end
local name = minetest.get_meta(pos):get_string("name")
if name == "" then
name = d.title.small
end
minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
})
)
if d.on_rightclick then
d.on_rightclick(pos, node, clicker)
end
player_chest_open(clicker, pos, names.small.a, small_textures, node.param2, false, d.sounds[2],
"mcl_chests_chest")
end,
on_destruct = function(pos)
close_forms(d.canonical_basename, pos)
end,
mesecons = d.mesecons,
on_rotate = simple_rotate,
})
minetest.register_node(names.left.a, {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = { -0.4375, -0.5, -0.4375, 0.5, 0.375, 0.4375 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = double_textures,
_chest_entity_sound = d.sounds[2],
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
paramtype = "light",
paramtype2 = "facedir",
groups = groups_left,
drop = d.drop,
is_ground_content = false,
sounds = d.sounds[1],
on_construct = construct_double_chest("left", names),
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
end,
on_destruct = destruct_double_chest("left", names, d.canonical_basename, small_textures, d.sounds[2]),
after_dig_node = drop_items_chest,
on_blast = on_chest_blast,
allow_metadata_inventory_move = protection_check_move,
allow_metadata_inventory_take = protection_check_take,
allow_metadata_inventory_put = protection_check_put("left"),
on_metadata_inventory_move = log_inventory_move,
on_metadata_inventory_put = log_inventory_put_double("left"),
on_metadata_inventory_take = log_inventory_take,
_mcl_blast_resistance = d.hardness,
_mcl_hardness = d.hardness,
on_rightclick = function(pos, node, clicker)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "left")
local above_def = minetest.registered_nodes[
minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z }).name
]
local above_def_other = minetest.registered_nodes[
minetest.get_node({ x = pos_other.x, y = pos_other.y + 1, z = pos_other.z }).name
]
if (not above_def or above_def.groups.opaque == 1 or not above_def_other
or above_def_other.groups.opaque == 1) then
-- won't open if there is no space from the top
return false
end
local name = minetest.get_meta(pos):get_string("name")
if name == "" then -- if empty after that ^
name = minetest.get_meta(pos_other):get_string("name")
end if name == "" then -- if STILL empty after that ^
name = d.title.double
end
minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos.x, pos.y, pos.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos_other.x, pos_other.y, pos_other.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
})
)
if d.on_rightclick_left then
d.on_rightclick_left(pos, node, clicker)
end
player_chest_open(clicker, pos, names.left.a, double_textures, node.param2, true, d.sounds[2],
"mcl_chests_chest")
end,
mesecons = d.mesecons,
on_rotate = no_rotate,
_mcl_hoppers_on_try_pull = hopper_pull_double("left"),
_mcl_hoppers_on_try_push = hopper_push_double("left"),
})
minetest.register_node(names.right.a, {
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
node_box = {
type = "fixed",
fixed = { -0.5, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
groups = groups_right,
drop = d.drop,
is_ground_content = false,
sounds = d.sounds[1],
on_construct = construct_double_chest("right", names),
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
end,
on_destruct = destruct_double_chest("right", names, d.canonical_basename, small_textures, d.sounds[2]),
after_dig_node = drop_items_chest,
on_blast = on_chest_blast,
allow_metadata_inventory_move = protection_check_move,
allow_metadata_inventory_take = protection_check_take,
allow_metadata_inventory_put = protection_check_put("right"),
on_metadata_inventory_move = log_inventory_move,
on_metadata_inventory_put = log_inventory_put_double("right"),
on_metadata_inventory_take = log_inventory_take,
_mcl_blast_resistance = d.hardness,
_mcl_hardness = d.hardness,
on_rightclick = function(pos, node, clicker)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "right")
local above_def = minetest.registered_nodes[
minetest.get_node({ x = pos.x, y = pos.y + 1, z = pos.z }).name
]
local above_def_other = minetest.registered_nodes[
minetest.get_node({ x = pos_other.x, y = pos_other.y + 1, z = pos_other.z }).name
]
if (not above_def or above_def.groups.opaque == 1 or not above_def_other
or above_def_other.groups.opaque == 1) then
-- won't open if there is no space from the top
return false
end
local name = minetest.get_meta(pos):get_string("name")
if name == "" then -- if empty after that ^
name = minetest.get_meta(pos_other):get_string("name")
end if name == "" then -- if STILL empty after that ^
name = d.title.double
end
minetest.show_formspec(clicker:get_player_name(),
sf("mcl_chests:%s_%s_%s_%s", d.canonical_basename, pos.x, pos.y, pos.z),
table.concat({
"formspec_version[4]",
"size[11.75,14.15]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,0.75;9,3;]", pos_other.x, pos_other.y, pos_other.z),
mcl_formspec.get_itemslot_bg_v4(0.375, 4.5, 9, 3),
sf("list[nodemeta:%s,%s,%s;main;0.375,4.5;9,3;]", pos.x, pos.y, pos.z),
"label[0.375,8.45;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 8.825, 9, 3),
"list[current_player;main;0.375,8.825;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 12.775, 9, 1),
"list[current_player;main;0.375,12.775;9,1;]",
--BEGIN OF LISTRING WORKAROUND
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;input]", pos.x, pos.y, pos.z),
--END OF LISTRING WORKAROUND
"listring[current_player;main]" ..
sf("listring[nodemeta:%s,%s,%s;main]", pos_other.x, pos_other.y, pos_other.z),
"listring[current_player;main]",
sf("listring[nodemeta:%s,%s,%s;main]", pos.x, pos.y, pos.z),
})
)
if d.on_rightclick_right then
d.on_rightclick_right(pos, node, clicker)
end
player_chest_open(clicker, pos_other, names.left.a, double_textures, node.param2, true, d.sounds[2],
"mcl_chests_chest")
end,
mesecons = d.mesecons,
on_rotate = no_rotate,
_mcl_hoppers_on_try_pull = hopper_pull_double("right"),
_mcl_hoppers_on_try_push = hopper_push_double("right"),
})
if doc then
doc.add_entry_alias("nodes", names.small.a, "nodes", names.left.a)
doc.add_entry_alias("nodes", names.small.a, "nodes", names.right.a)
end
end
-- Returns false if itemstack is a shulker box
function mcl_chests.is_not_shulker_box(stack)
local g = minetest.get_item_group(stack:get_name(), "shulker_box")
return g == 0 or g == nil
end

View File

@ -0,0 +1,165 @@
local S = minetest.get_translator(minetest.get_current_modname())
local get_double_container_neighbor_pos = mcl_util.get_double_container_neighbor_pos
local chestusage = S("To access its inventory, rightclick it. When broken, the items will drop out.")
mcl_chests.register_chest("chest", {
desc = S("Chest"),
longdesc = S(
"Chests are containers which provide 27 inventory slots. Chests can be turned into large chests with " ..
"double the capacity by placing two chests next to each other."
),
usagehelp = chestusage,
tt_help = S("27 inventory slots") .. "\n" .. S("Can be combined to a large chest"),
tiles = {
small = mcl_chests.tiles.chest_normal_small,
double = mcl_chests.tiles.chest_normal_double,
inv = { "default_chest_top.png", "mcl_chests_chest_bottom.png",
"mcl_chests_chest_right.png", "mcl_chests_chest_left.png",
"mcl_chests_chest_back.png", "default_chest_front.png" },
},
groups = {
handy = 1,
axey = 1,
material_wood = 1,
flammable = -1,
},
sounds = { mcl_sounds.node_sound_wood_defaults() },
hardness = 2.5,
hidden = false,
})
local traptiles = {
small = mcl_chests.tiles.chest_trapped_small,
double = mcl_chests.tiles.chest_trapped_double,
}
mcl_chests.register_chest("trapped_chest", {
desc = S("Trapped Chest"),
title = {
small = S("Chest"),
double = S("Large Chest")
},
longdesc = S(
"A trapped chest is a container which provides 27 inventory slots. When it is opened, it sends a redstone " ..
"signal to its adjacent blocks as long it stays open. Trapped chests can be turned into large trapped " ..
"chests with double the capacity by placing two trapped chests next to each other."
),
usagehelp = chestusage,
tt_help = S("27 inventory slots") ..
"\n" .. S("Can be combined to a large chest") .. "\n" .. S("Emits a redstone signal when opened"),
tiles = traptiles,
groups = {
handy = 1,
axey = 1,
material_wood = 1,
flammable = -1,
mesecon = 2,
},
sounds = { mcl_sounds.node_sound_wood_defaults() },
hardness = 2.5,
hidden = false,
mesecons = {
receptor = {
state = mesecon.state.off,
rules = mesecon.rules.pplate,
},
},
on_rightclick = function(pos, node, clicker)
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_small", param2 = node.param2 })
mcl_chests.find_or_create_entity(pos, "mcl_chests:trapped_chest_on_small", { "mcl_chests_trapped.png" },
node.param2, false, "default_chest", "mcl_chests_chest", "chest")
:reinitialize("mcl_chests:trapped_chest_on_small")
mesecon.receptor_on(pos, mesecon.rules.pplate)
end,
on_rightclick_left = function(pos, node, clicker)
local meta = minetest.get_meta(pos)
meta:set_int("players", 1)
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 })
mcl_chests.find_or_create_entity(pos, "mcl_chests:trapped_chest_on_left",
mcl_chests.tiles.chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest",
"chest"):reinitialize("mcl_chests:trapped_chest_on_left")
mesecon.receptor_on(pos, mesecon.rules.pplate)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "left")
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_on_right", param2 = node.param2 })
mesecon.receptor_on(pos_other, mesecon.rules.pplate)
end,
on_rightclick_right = function(pos, node, clicker)
local pos_other = get_double_container_neighbor_pos(pos, node.param2, "right")
minetest.swap_node(pos, { name = "mcl_chests:trapped_chest_on_right", param2 = node.param2 })
mesecon.receptor_on(pos, mesecon.rules.pplate)
minetest.swap_node(pos_other, { name = "mcl_chests:trapped_chest_on_left", param2 = node.param2 })
mcl_chests.find_or_create_entity(pos_other, "mcl_chests:trapped_chest_on_left",
mcl_chests.tiles.chest_trapped_double, node.param2, true, "default_chest", "mcl_chests_chest",
"chest"):reinitialize("mcl_chests:trapped_chest_on_left")
mesecon.receptor_on(pos_other, mesecon.rules.pplate)
end
})
mcl_chests.register_chest("trapped_chest_on", {
title = {
small = S("Chest"),
double = S("Large Chest")
},
tiles = traptiles,
groups = {
handy = 1,
axey = 1,
material_wood = 1,
flammable = -1,
mesecon = 2,
},
sounds = { mcl_sounds.node_sound_wood_defaults() },
hardness = 2.5,
hidden = true,
mesecons = {
receptor = {
state = mesecon.state.on,
rules = mesecon.rules.pplate,
},
},
drop = "trapped_chest",
canonical_basename = "trapped_chest"
})
minetest.register_craft({
output = "mcl_chests:chest",
recipe = {
{ "group:wood", "group:wood", "group:wood" },
{ "group:wood", "", "group:wood" },
{ "group:wood", "group:wood", "group:wood" },
},
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_chests:chest",
burntime = 15,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_chests:trapped_chest",
burntime = 15,
})
-- Disable active/open trapped chests when loaded because nobody could have them open at loading time.
-- Fixes redstone weirdness.
minetest.register_lbm({
label = "Disable active trapped chests",
name = "mcl_chests:reset_trapped_chests",
nodenames = {
"mcl_chests:trapped_chest_on_small",
"mcl_chests:trapped_chest_on_left",
"mcl_chests:trapped_chest_on_right"
},
run_at_every_load = true,
action = function(pos, node)
minetest.log("action", "[mcl_chests] Disabled active trapped chest on load: " .. minetest.pos_to_string(pos))
mcl_chests.chest_update_after_close(pos)
end,
})

View File

@ -0,0 +1,138 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local longdesc = S(
"Ender chests grant you access to a single personal interdimensional inventory with 27 slots. This " ..
"inventory is the same no matter from which ender chest you access it from. If you put one item into one " ..
"ender chest, you will find it in all other ender chests. Each player will only see their own items, but " ..
"not the items of other players."
)
minetest.register_node("mcl_chests:ender_chest", {
description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") ..
"\n" .. S("Put items inside, retrieve them from any ender chest"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "mesh",
mesh = "mcl_chests_chest.b3d",
tiles = mcl_chests.tiles.chest_ender_small,
use_texture_alpha = "opaque",
paramtype = "light",
paramtype2 = "facedir",
groups = { deco_block = 1 },
sounds = mcl_sounds.node_sound_stone_defaults(),
on_construct = function(pos)
local node = minetest.get_node(pos)
node.name = "mcl_chests:ender_chest_small"
minetest.set_node(pos, node)
end,
})
local formspec_ender_chest = table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, S("Ender Chest"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[current_player;enderchest;0.375,0.75;9,3;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[current_player;enderchest]",
"listring[current_player;main]",
})
minetest.register_node("mcl_chests:ender_chest_small", {
description = S("Ender Chest"),
_tt_help = S("27 interdimensional inventory slots") ..
"\n" .. S("Put items inside, retrieve them from any ender chest"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = S("Rightclick the ender chest to access your personal interdimensional inventory."),
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = { -0.4375, -0.5, -0.4375, 0.4375, 0.375, 0.4375 },
},
_chest_entity_textures = mcl_chests.tiles.ender_chest_texture,
_chest_entity_sound = "mcl_chests_enderchest",
_chest_entity_mesh = "mcl_chests_chest",
_chest_entity_animation_type = "chest",
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
-- Note: The “container” group is missing here because the ender chest does not
-- have an inventory on its own
groups = { pickaxey = 1, deco_block = 1, material_stone = 1, chest_entity = 1, not_in_creative_inventory = 1 },
is_ground_content = false,
paramtype = "light",
light_source = 7,
paramtype2 = "facedir",
sounds = mcl_sounds.node_sound_stone_defaults(),
drop = "mcl_core:obsidian 8",
on_construct = function(pos)
mcl_chests.create_entity(pos, "mcl_chests:ender_chest_small", mcl_chests.tiles.ender_chest_texture,
minetest.get_node(pos).param2, false, "mcl_chests_enderchest", "mcl_chests_chest", "chest")
end,
on_rightclick = function(pos, node, clicker)
if minetest.registered_nodes[minetest.get_node(vector.offset(pos, 0, 1, 0)).name].groups.opaque == 1 then
-- won't open if there is no space from the top
return false
end
minetest.show_formspec(clicker:get_player_name(), "mcl_chests:ender_chest_" .. clicker:get_player_name(),
formspec_ender_chest)
mcl_chests.player_chest_open(clicker, pos, "mcl_chests:ender_chest_small",
mcl_chests.tiles.ender_chest_texture, node.param2, false, "mcl_chests_enderchest",
"mcl_chests_chest")
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then
mcl_chests.player_chest_close(sender)
end
end,
_mcl_blast_resistance = 600,
_mcl_hardness = 22.5,
_mcl_silk_touch_drop = { "mcl_chests:ender_chest" },
on_rotate = mcl_chests.simple_rotate,
})
minetest.register_on_joinplayer(function(player)
local inv = player:get_inventory()
inv:set_size("enderchest", 9 * 3)
end)
minetest.register_allow_player_inventory_action(function(player, action, inv, info)
if inv:get_location().type == "player" and (
action == "move" and (info.from_list == "enderchest" or info.to_list == "enderchest")
or action == "put" and info.listname == "enderchest"
or action == "take" and info.listname == "enderchest") then
local def = player:get_wielded_item():get_definition()
local range = (def and def.range or player:get_inventory():get_stack("hand", 1):get_definition().range) + 1
if not minetest.find_node_near(player:get_pos(), range, "mcl_chests:ender_chest_small", true) then
return 0
end
end
end)
minetest.register_craft({
output = "mcl_chests:ender_chest",
recipe = {
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_end:ender_eye", "mcl_core:obsidian" },
{ "mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian" },
},
})
minetest.register_lbm({
label = "Upgrade old ender chest formspec",
name = "mcl_chests:replace_old_ender_form",
nodenames = { "mcl_chests:ender_chest_small" },
run_at_every_load = false,
action = function(pos, node)
minetest.get_meta(pos):set_string("formspec", "")
end,
})

View File

@ -0,0 +1,50 @@
local S = minetest.get_translator(minetest.get_current_modname())
mcl_chests.register_chest("stone_chest", {
desc = S("Stone Chest"),
title = {
small = S("Stone Chest"),
double = S("Large Stone Chest")
},
longdesc = S(
"Stone Chests are containers which provide 27 inventory slots. Stone Chests can be turned into" ..
"large stone chests with double the capacity by placing two stone chests next to each other."
),
usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."),
tt_help = S("27 inventory slots") .. "\n" .. S("Can be combined to a large stone chest"),
tiles = {
small = { mcl_chests.tiles.chest_normal_small[1] .. "^[hsl:-15:-80:-20" },
double = { mcl_chests.tiles.chest_normal_double[1] .. "^[hsl:-15:-80:-20" },
inv = { "default_chest_top.png^[hsl:-15:-80:-20",
"mcl_chests_chest_bottom.png^[hsl:-15:-80:-20",
"mcl_chests_chest_right.png^[hsl:-15:-80:-20",
"mcl_chests_chest_left.png^[hsl:-15:-80:-20",
"mcl_chests_chest_back.png^[hsl:-15:-80:-20",
"default_chest_front.png^[hsl:-15:-80:-20"
},
},
groups = {
pickaxey = 1,
stone = 1,
material_stone = 1,
},
sounds = {
mcl_sounds.node_sound_stone_defaults(),
"mcl_chests_enderchest"
},
hardness = 4.0,
hidden = false,
-- It bites!
on_rightclick = function(pos, node, clicker)
mcl_util.deal_damage(clicker, 2)
end,
})
minetest.register_craft({
output = "mcl_chests:stone_chest",
recipe = {
{ "mcl_core:stone", "mcl_core:stone", "mcl_core:stone" },
{ "mcl_core:stone", "", "mcl_core:stone" },
{ "mcl_core:stone", "mcl_core:stone", "mcl_core:stone" },
},
})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,358 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
-- Shulker boxes
local boxtypes = {
white = S("White Shulker Box"),
grey = S("Light Grey Shulker Box"),
orange = S("Orange Shulker Box"),
cyan = S("Cyan Shulker Box"),
magenta = S("Magenta Shulker Box"),
violet = S("Purple Shulker Box"),
lightblue = S("Light Blue Shulker Box"),
blue = S("Blue Shulker Box"),
yellow = S("Yellow Shulker Box"),
brown = S("Brown Shulker Box"),
green = S("Lime Shulker Box"),
dark_green = S("Green Shulker Box"),
pink = S("Pink Shulker Box"),
red = S("Red Shulker Box"),
dark_grey = S("Grey Shulker Box"),
black = S("Black Shulker Box"),
}
local shulker_mob_textures = {
white = "mobs_mc_shulker_white.png",
grey = "mobs_mc_shulker_silver.png",
orange = "mobs_mc_shulker_orange.png",
cyan = "mobs_mc_shulker_cyan.png",
magenta = "mobs_mc_shulker_magenta.png",
violet = "mobs_mc_shulker_purple.png",
lightblue = "mobs_mc_shulker_light_blue.png",
blue = "mobs_mc_shulker_blue.png",
yellow = "mobs_mc_shulker_yellow.png",
brown = "mobs_mc_shulker_brown.png",
green = "mobs_mc_shulker_lime.png",
dark_green = "mobs_mc_shulker_green.png",
pink = "mobs_mc_shulker_pink.png",
red = "mobs_mc_shulker_red.png",
dark_grey = "mobs_mc_shulker_gray.png",
black = "mobs_mc_shulker_black.png",
}
local canonical_shulker_color = "violet"
local normal_canonical_name = "mcl_chests:" .. canonical_shulker_color .. "_shulker_box"
local small_canonical_name = normal_canonical_name .. "_small"
--WARNING: after formspec v4 update, old shulker boxes will need to be placed again to get the new formspec
local function formspec_shulker_box(name)
if not name or name == "" then
name = S("Shulker Box")
end
return table.concat({
"formspec_version[4]",
"size[11.75,10.425]",
"label[0.375,0.375;" .. F(C(mcl_formspec.label_color, name)) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 0.75, 9, 3),
"list[context;main;0.375,0.75;9,3;]",
"label[0.375,4.7;" .. F(C(mcl_formspec.label_color, S("Inventory"))) .. "]",
mcl_formspec.get_itemslot_bg_v4(0.375, 5.1, 9, 3),
"list[current_player;main;0.375,5.1;9,3;9]",
mcl_formspec.get_itemslot_bg_v4(0.375, 9.05, 9, 1),
"list[current_player;main;0.375,9.05;9,1;]",
"listring[context;main]",
"listring[current_player;main]",
})
end
local function set_shulkerbox_meta(nmeta, imeta)
local name = imeta:get_string("name")
nmeta:set_string("description", imeta:get_string("description"))
nmeta:set_string("name", name)
nmeta:set_string("formspec", formspec_shulker_box(name))
end
for color, desc in pairs(boxtypes) do
local mob_texture = shulker_mob_textures[color]
local is_canonical = color == canonical_shulker_color
local longdesc, usagehelp, create_entry, entry_name
if doc then
if is_canonical then
longdesc = S(
"A shulker box is a portable container which provides 27 inventory slots for any item " ..
"except shulker boxes. Shulker boxes keep their inventory when broken, so shulker boxes " ..
"as well as their contents can be taken as a single item. Shulker boxes come in many " ..
"different colors."
)
usagehelp = S(
"To access the inventory of a shulker box, place and right-click it. To take a shulker " ..
"box and its contents with you, just break and collect it, the items will not fall out. " ..
"Place the shulker box again to be able to retrieve its contents."
)
entry_name = S("Shulker Box")
else
create_entry = false
end
end
local normal_name = "mcl_chests:" .. color .. "_shulker_box"
local small_name = normal_name .. "_small"
minetest.register_node(normal_name, {
description = desc,
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
_doc_items_create_entry = create_entry,
_doc_items_entry_name = entry_name,
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
tiles = { mob_texture },
use_texture_alpha = "opaque",
drawtype = "mesh",
mesh = "mcl_chests_shulker.b3d",
groups = {
handy = 1,
pickaxey = 1,
container = 2,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
old_shulker_box_node = 1
},
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1,
drop = "",
paramtype = "light",
paramtype2 = "facedir",
on_construct = function(pos)
local node = minetest.get_node(pos)
node.name = small_name
minetest.set_node(pos, node)
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
local imeta = itemstack:get_meta()
-- Convert old itemstacks to not use get_metadata()
if not imeta:contains("inv") and
(itemstack:get_metadata() ~= "") then
imeta:set_string("inv", itemstack:get_metadata())
itemstack:set_metadata("") -- clear
end
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
local ninv = nmeta:get_inventory()
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(nmeta, imeta)
if minetest.is_creative_enabled(placer:get_player_name()) then
if not ninv:is_empty("main") then
return nil
else
return itemstack
end
else
return nil
end
end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Place shulker box as node
if minetest.registered_nodes[dropnode.name].buildable_to then
minetest.set_node(droppos, { name = small_name, param2 = minetest.dir_to_facedir(dropdir) })
local ninv = minetest.get_inventory({ type = "node", pos = droppos })
local imeta = stack:get_meta()
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(minetest.get_meta(droppos), imeta)
stack:take_item()
end
return stack
end,
})
minetest.register_node(small_name, {
description = desc,
_tt_help = S("27 inventory slots") .. "\n" .. S("Can be carried around with its contents"),
_doc_items_create_entry = create_entry,
_doc_items_entry_name = entry_name,
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = { -0.48, -0.5, -0.48, 0.48, 0.489, 0.48 },
},
tiles = { "blank.png^[resize:16x16" },
use_texture_alpha = "clip",
_chest_entity_textures = { mob_texture },
_chest_entity_sound = "mcl_chests_shulker",
_chest_entity_mesh = "mcl_chests_shulker",
_chest_entity_animation_type = "shulker",
groups = {
handy = 1,
pickaxey = 1,
container = 2,
deco_block = 1,
dig_by_piston = 1,
shulker_box = 1,
chest_entity = 1,
not_in_creative_inventory = 1
},
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
stack_max = 1,
drop = "",
paramtype = "light",
paramtype2 = "facedir",
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec_shulker_box(nil))
local inv = meta:get_inventory()
inv:set_size("main", 9 * 3)
mcl_chests.create_entity(pos, small_name, { mob_texture }, minetest.get_node(pos).param2, false,
"mcl_chests_shulker", "mcl_chests_shulker", "shulker")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
local nmeta = minetest.get_meta(pos)
local imeta = itemstack:get_meta()
-- Convert old itemstacks to not use get_metadata()
if not imeta:contains("inv") and
(itemstack:get_metadata() ~= "") then
imeta:set_string("inv", itemstack:get_metadata())
itemstack:set_metadata("") -- clear
end
local iinv_main = minetest.deserialize(imeta:get_string("inv"))
local ninv = nmeta:get_inventory()
ninv:set_list("main", iinv_main)
ninv:set_size("main", 9 * 3)
set_shulkerbox_meta(nmeta, imeta)
if minetest.is_creative_enabled(placer:get_player_name()) then
if not ninv:is_empty("main") then
return nil
else
return itemstack
end
else
return nil
end
end,
on_rightclick = function(pos, node, clicker)
mcl_chests.player_chest_open(clicker, pos, small_name, { mob_texture }, node.param2, false,
"mcl_chests_shulker", "mcl_chests_shulker", true)
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then
mcl_chests.player_chest_close(sender)
end
end,
on_destruct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local items = {}
for i = 1, inv:get_size("main") do
local stack = inv:get_stack("main", i)
items[i] = stack:to_string()
end
local data = minetest.serialize(items)
local boxitem = ItemStack("mcl_chests:" .. color .. "_shulker_box")
local boxitem_meta = boxitem:get_meta()
boxitem_meta:set_string("description", meta:get_string("description"))
boxitem_meta:set_string("name", meta:get_string("name"))
boxitem_meta:set_string("inv", data)
if minetest.is_creative_enabled("") then
if not inv:is_empty("main") then
minetest.add_item(pos, boxitem)
end
else
minetest.add_item(pos, boxitem)
end
end,
allow_metadata_inventory_move = mcl_chests.protection_check_move,
allow_metadata_inventory_take = mcl_chests.protection_check_put_take,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
minetest.record_protection_violation(pos, name)
return 0
end
-- Do not allow to place shulker boxes into shulker boxes
local group = minetest.get_item_group(stack:get_name(), "shulker_box")
if group == 0 or group == nil then
return stack:get_count()
else
return 0
end
end,
on_rotate = mcl_chests.simple_rotate,
_mcl_blast_resistance = 2,
_mcl_hardness = 2,
_mcl_hoppers_on_try_push = function(pos, hop_pos, hop_inv, hop_list)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv, "main",
mcl_util.select_stack(hop_inv, hop_list, inv, "main", mcl_chests.is_not_shulker_box, 1)
end,
})
if doc and not is_canonical then
doc.add_entry_alias("nodes", normal_canonical_name, "nodes", normal_name)
doc.add_entry_alias("nodes", small_canonical_name, "nodes", small_name)
end
minetest.register_craft({
type = "shapeless",
output = normal_name,
recipe = { "group:shulker_box", "mcl_dye:" .. color },
})
end
minetest.register_craft({
output = "mcl_chests:violet_shulker_box",
recipe = {
{ "mcl_mobitems:shulker_shell" },
{ "mcl_chests:chest" },
{ "mcl_mobitems:shulker_shell" },
},
})
-- Save metadata of shulker box when used in crafting
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if minetest.get_item_group(itemstack:get_name(), "shulker_box") ~= 1 then return end
local original
for i = 1, #old_craft_grid do
local item = old_craft_grid[i]:get_name()
if minetest.get_item_group(item, "shulker_box") == 1 then
original = old_craft_grid[i]
break
end
end
if original then
local ometa = original:get_meta():to_table()
local nmeta = itemstack:get_meta()
nmeta:from_table(ometa)
return itemstack
end
end)
minetest.register_lbm({
label = "Update shulker box formspecs (0.72.0)",
name = "mcl_chests:update_shulker_box_formspecs_0_72_0",
nodenames = { "group:shulker_box" },
run_at_every_load = false,
action = function(pos, node)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", formspec_shulker_box(meta:get_string("name")))
end,
})

View File

@ -162,7 +162,7 @@ for _, row in ipairs(block.dyes) do
stack_max = 64,
is_ground_content = false,
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 4.2,
_mcl_blast_resistance = 1.4,
_mcl_hardness = 1.4,
on_rotate = on_rotate,
})

View File

@ -312,8 +312,8 @@ minetest.register_node("mcl_compass:lodestone",{
"lodestone_side4.png"
},
groups = {pickaxey=1, material_stone=1},
_mcl_hardness = 1.5,
_mcl_blast_resistance = 6,
_mcl_hardness = 3.5,
_mcl_blast_resistance = 3.5,
sounds = mcl_sounds.node_sound_stone_defaults()
})

View File

@ -58,7 +58,7 @@ minetest.register_node("mcl_copper:block_exposed", {
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_oxidized_variant = "mcl_copper:block_weathered",
_mcl_waxed_variant = "mcl_copper:waxed_block_exposed",
_mcl_stripped_variant = "mcl_copper:block",
@ -72,7 +72,7 @@ minetest.register_node("mcl_copper:waxed_block_exposed", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_exposed",
})
@ -84,7 +84,7 @@ minetest.register_node("mcl_copper:block_weathered", {
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_oxidized_variant = "mcl_copper:block_oxidized",
_mcl_waxed_variant = "mcl_copper:waxed_block_weathered",
_mcl_stripped_variant = "mcl_copper:block_exposed",
@ -98,7 +98,7 @@ minetest.register_node("mcl_copper:waxed_block_weathered", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_weathered",
})
@ -110,7 +110,7 @@ minetest.register_node("mcl_copper:block_oxidized", {
groups = {pickaxey = 2, building_block = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_waxed_variant = "mcl_copper:waxed_block_oxidized",
_mcl_stripped_variant = "mcl_copper:block_weathered",
})
@ -123,7 +123,7 @@ minetest.register_node("mcl_copper:waxed_block_oxidized", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_oxidized",
})
@ -135,7 +135,7 @@ minetest.register_node("mcl_copper:block_cut", {
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_oxidized_variant = "mcl_copper:block_exposed_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_cut",
})
@ -148,7 +148,7 @@ minetest.register_node("mcl_copper:waxed_block_cut", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_cut",
})
@ -160,7 +160,7 @@ minetest.register_node("mcl_copper:block_exposed_cut", {
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_waxed_variant = "mcl_copper:waxed_block_exposed_cut",
_mcl_oxidized_variant = "mcl_copper:block_weathered_cut",
_mcl_stripped_variant = "mcl_copper:block_cut",
@ -174,7 +174,7 @@ minetest.register_node("mcl_copper:waxed_block_exposed_cut", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_exposed_cut",
})
@ -186,7 +186,7 @@ minetest.register_node("mcl_copper:block_weathered_cut", {
groups = {pickaxey = 2, building_block = 1, oxidizable = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_exposed_cut",
_mcl_oxidized_variant = "mcl_copper:block_oxidized_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_weathered_cut",
@ -200,7 +200,7 @@ minetest.register_node("mcl_copper:waxed_block_weathered_cut", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_weathered_cut",
})
@ -212,7 +212,7 @@ minetest.register_node("mcl_copper:block_oxidized_cut", {
groups = {pickaxey = 2, building_block = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_weathered_cut",
_mcl_waxed_variant = "mcl_copper:waxed_block_oxidized_cut",
})
@ -225,7 +225,7 @@ minetest.register_node("mcl_copper:waxed_block_oxidized_cut", {
groups = {pickaxey = 2, building_block = 1, waxed = 1},
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
_mcl_hardness = 3,
_mcl_stripped_variant = "mcl_copper:block_oxidized_cut",
})
@ -289,54 +289,54 @@ mcl_stairs.register_stair("copper_cut", "mcl_copper:block_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Stairs of Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_cut", "mcl_copper:waxed_block_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png", "mcl_copper_block_cut.png"},
S("Waxed Stairs of Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("copper_exposed_cut", "mcl_copper:block_exposed_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Stairs of Exposed Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_exposed_cut", "mcl_copper:waxed_block_exposed_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png", "mcl_copper_exposed_cut.png"},
S("Waxed Stairs of Exposed Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("copper_weathered_cut", "mcl_copper:block_weathered_cut",
{pickaxey = 2, oxidizable = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Stairs of Weathered Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_weathered_cut", "mcl_copper:waxed_block_weathered_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png", "mcl_copper_weathered_cut.png"},
S("Waxed Stairs of Weathered Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("copper_oxidized_cut", "mcl_copper:block_oxidized_cut",
{pickaxey = 2},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Stairs of Oxidized Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("waxed_copper_oxidized_cut", "mcl_copper:waxed_block_oxidized_cut",
{pickaxey = 2, waxed = 1},
{"mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png", "mcl_copper_oxidized_cut.png"},
S("Waxed Stairs of Oxidized Cut Copper"),
nil, 6, nil,
nil, nil, nil,
"woodlike")

View File

@ -165,6 +165,22 @@ minetest.register_craft({
}
})
minetest.register_craft({
output = "mcl_core:charcoalblock",
recipe = {
{"mcl_core:charcoal_lump", "mcl_core:charcoal_lump", "mcl_core:charcoal_lump"},
{"mcl_core:charcoal_lump", "mcl_core:charcoal_lump", "mcl_core:charcoal_lump"},
{"mcl_core:charcoal_lump", "mcl_core:charcoal_lump", "mcl_core:charcoal_lump"},
}
})
minetest.register_craft({
output = "mcl_core:charcoal_lump 9",
recipe = {
{"mcl_core:charcoalblock"},
}
})
minetest.register_craft({
output = "mcl_core:ironblock",
recipe = {
@ -497,6 +513,12 @@ minetest.register_craft({
burntime = 800,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_core:charcoalblock",
burntime = 800,
})
minetest.register_craft({
type = "fuel",
recipe = "mcl_core:coal_lump",

View File

@ -1451,6 +1451,22 @@ minetest.register_abm({
end
})
-- Freeze water
minetest.register_abm({
label = "Freeze water in cold areas",
nodenames = {"mcl_core:water_source", "mclx_core:river_water_source"},
interval = 32,
chance = 8,
action = function(pos, node)
if mcl_weather.has_snow(pos)
and minetest.get_natural_light(vector.offset(pos,0,1,0), 0.5) == minetest.LIGHT_MAX + 1
and minetest.get_artificial_light(minetest.get_node(pos).param1) < 10 then
node.name = "mcl_core:ice"
minetest.swap_node(pos, node)
end
end
})
--[[ Call this for vines nodes only.
Given the pos and node of a vines node, this returns true if the vines are supported
and false if the vines are currently floating.
@ -1642,32 +1658,30 @@ end
-- Obsidian crying
local crobby_particle = {
velocity = vector.new(0,0,0),
size = math.random(1.3,2.5),
velocity = vector.zero(),
acceleration = vector.zero(),
texture = "mcl_core_crying_obsidian_tear.png",
collisiondetection = false,
collision_removal = false,
}
minetest.register_abm({
label = "Obsidian cries",
nodenames = {"mcl_core:crying_obsidian"},
interval = 5,
chance = 10,
action = function(pos, node)
minetest.after(math.random(0.1,1.5),function()
minetest.after(0.1 + math.random() * 1.4, function()
local pt = table.copy(crobby_particle)
pt.acceleration = vector.new(0,0,0)
pt.collisiondetection = false
pt.expirationtime = math.random(0.5,1.5)
pt.pos = vector.offset(pos,math.random(-0.5,0.5),-0.51,math.random(-0.5,0.5))
pt.size = 1.3 + math.random() * 1.2
pt.expirationtime = 0.5 + math.random()
pt.pos = vector.offset(pos, math.random() - 0.5, -0.51, math.random() - 0.5)
minetest.add_particle(pt)
minetest.after(pt.expirationtime,function()
pt.acceleration = vector.new(0,-9,0)
minetest.after(pt.expirationtime, function()
pt.acceleration = vector.new(0, -9, 0)
pt.collisiondetection = true
pt.expirationtime = math.random(1.2,4.5)
pt.expirationtime = 1.2 + math.random() * 3.3
minetest.add_particle(pt)
end)
end)

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Birkenholzplanken
Birch leaves are grown from birch trees.=Birkenblätter wachsen an Birken.
Black Stained Glass=Schwarzes Buntglas
Block of Coal=Kohleblock
Block of Charcoal=
Block of Diamond=Diamantblock
Block of Emerald=Smaragdblock
Block of Gold=Goldblock
Block of Iron=Eisenblock
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Kohleblöcke sind für eine kompakte Aufbewahrung von Kohle nützlich und sehr nützlich als Ofenbrennstoff. Ein Kohleblock ist so effizient wie 10 mal Kohle.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=Blaues Buntglas
Bone Block=Knochenblock
Bone blocks are decorative blocks and a compact storage of bone meal.=Knochenblöcke sind Deko-Blöcke und geeignet zur kompakten Aufbewahrung von Knochenmehl.

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Madera de abedul
Birch leaves are grown from birch trees.=Las hojas de abedul se cultivan a partir de abedules.
Black Stained Glass=Cristal negro
Block of Coal=Bloque de carbón
Block of Charcoal=
Block of Diamond=Bloque de diamante
Block of Emerald=Bloque de esmeralda
Block of Gold=Bloque de oro
Block of Iron=Bloque de hierro
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Los bloques de carbón son útiles como almacenamiento compacto de carbón y son muy útiles como combustible de horno. Un bloque de carbón es tan eficiente como 10 de carbón.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=Cristal azul
Bone Block=Bloque de hueso
Bone blocks are decorative blocks and a compact storage of bone meal.=Los bloques óseos son bloques decorativos y un almacenamiento compacto de harina de huesos.

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Planches de bouleau
Birch leaves are grown from birch trees.=Les feuilles de bouleau poussent sur les bouleaux.
Black Stained Glass=Verre noir
Block of Coal=Bloc de charbon
Block of Charcoal=
Block of Diamond=Bloc de diamant
Block of Emerald=Bloc d'émeraude
Block of Gold=Bloc d'or
Block of Iron=Bloc de fer
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Les blocs de charbon sont utiles pour stocker du charbon et très utiles comme combustible de four. Un bloc de charbon est aussi efficace que 10 charbon.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=Verre bleu
Bone Block=Bloc d'os
Bone blocks are decorative blocks and a compact storage of bone meal.=Les blocs d'os sont des blocs décoratifs et servent à stocker la poudre d'os.

View File

@ -35,11 +35,13 @@ Birch Wood Planks=シラカバの板材
Birch leaves are grown from birch trees.=シラカバの葉は、シラカバの木から育ちます。
Black Stained Glass=黒色ガラス
Block of Coal=石炭ブロック
Block of Charcoal=
Block of Diamond=ダイヤモンドブロック
Block of Emerald=エメラルドブロック
Block of Gold=金ブロック
Block of Iron=鉄ブロック
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=石炭ブロックは、石炭をコンパクトに保管でき、炉の燃料として非常に便利です。1個の石炭ブロックは、10個の石炭と同じ効率です。
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=青色ガラス
Bone Block=骨ブロック
Bone blocks are decorative blocks and a compact storage of bone meal.=骨ブロックは装飾用ブロックで、骨粉をコンパクトに保管できます。
@ -283,4 +285,4 @@ Grows on sand or dirt next to water=水辺の砂や土の上に生育
Stackable=スタック可能
Crying Obsidian=泣く黒曜石
Crying obsidian is a luminous obsidian that can generate as part of ruined portals.=泣く黒曜石は、廃墟のポータルの一部として生成可能な、発光する黒曜石です。
Enchanted Golden Apple=エンチャントされた金のリンゴ
Enchanted Golden Apple=エンチャントされた金のリンゴ

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Brzozowe deski
Birch leaves are grown from birch trees.=Brzozowe liście rosną na brzozach.
Black Stained Glass=Czarne szkło
Block of Coal=Blok węgla
Block of Charcoal=
Block of Diamond=Blok diamentu
Block of Emerald=Blok szmaragdu
Block of Gold=Blok złota
Block of Iron=Blok żelaza
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Bloki węgla są użyteczne do kompaktowego przechowywania diamentów i bardzo użyteczne jako paliwo do pieca.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=Niebieskie szkło
Bone Block=Blok kości
Bone blocks are decorative blocks and a compact storage of bone meal.=Bloki kości są blokami dekoracyjnymi i są użyteczne do kompaktowego przechowywania mączki kostnej.

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Tábuas de Bétula
Birch leaves are grown from birch trees.=Folhas de bétula crescem a partir de árvores de bétula.
Black Stained Glass=Vidro Tingido de Preto
Block of Coal=Bloco de Carvão
Block of Charcoal=
Block of Diamond=Bloco de Diamante
Block of Emerald=Bloco de Esmeralda
Block of Gold=Bloco de Ouro
Block of Iron=Bloco de Ferro
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Blocos de carvão são úteis para armzenad carvão de forma compacta e muito úteis como combustível de fornalas. Um bloco de carvão é tão eficiente quanto 10 carvões.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=Vidro Tingido de Azul
Bone Block=Bloco de Osso
Bone blocks are decorative blocks and a compact storage of bone meal.=Blocos de osso são blocos decorativos e uma forma compacta de armazenar farinha de osso.

View File

@ -35,11 +35,13 @@ Birch Wood Planks=Берёзовые доски
Birch leaves are grown from birch trees.=Листва берёзы произрастает на берёзах.
Black Stained Glass=Чёрное стекло
Block of Coal=Угольный блок
Block of Charcoal=Блок древесного угля
Block of Diamond=Алмазный блок
Block of Emerald=Изумрудный блок
Block of Gold=Золотой блок
Block of Iron=Железный блок
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=Угольный блок удобен для компактного хранения угля, а также полезен как топливо для печи.
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=Блок древесного угля удобен для компактного хранения древесного угля, а также полезен как топливо для печи.
Blue Stained Glass=Синее стекло
Bone Block=Костный блок
Bone blocks are decorative blocks and a compact storage of bone meal.=Костные блоки это декоративные блоки, а также способ компактного хранения костной муки.

View File

@ -34,11 +34,13 @@ Birch Wood Planks=白樺樹木材
Birch leaves are grown from birch trees.=白樺樹葉是由白樺樹樹生長出來的。
Black Stained Glass=黑色玻璃
Block of Coal=煤炭磚
Block of Charcoal=
Block of Diamond=鑽石磚
Block of Emerald=綠寶石磚
Block of Gold=金磚
Block of Iron=鐵磚
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=煤炭磚作為煤炭的省位存儲方式作為熔爐燃料非常有用。一個煤炭磚的燃燒時間相當於10塊煤炭。
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=藍色玻璃
Bone Block=骨塊
Bone blocks are decorative blocks and a compact storage of bone meal.=骨粉塊是一個裝飾方塊,也是骨粉的省位存儲方式。

View File

@ -35,11 +35,13 @@ Birch Wood Planks=
Birch leaves are grown from birch trees.=
Black Stained Glass=
Block of Coal=
Block of Charcoal=
Block of Diamond=
Block of Emerald=
Block of Gold=
Block of Iron=
Blocks of coal are useful as a compact storage of coal and very useful as a furnace fuel. A block of coal is as efficient as 10 coal.=
Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal.=
Blue Stained Glass=
Bone Block=
Bone blocks are decorative blocks and a compact storage of bone meal.=

View File

@ -288,7 +288,7 @@ minetest.register_node("mcl_core:stone_smooth", {
sounds = mcl_sounds.node_sound_stone_defaults(),
is_ground_content = false,
_mcl_blast_resistance = 6,
_mcl_hardness = 1.5,
_mcl_hardness = 2,
})
minetest.register_node("mcl_core:granite", {
@ -424,7 +424,7 @@ minetest.register_node("mcl_core:grass_path", {
footstep = {name="default_grass_footstep", gain=0.1},
}),
_mcl_blast_resistance = 0.65,
_mcl_hardness = 0.6,
_mcl_hardness = 0.65,
})
-- TODO: Add particles
@ -497,8 +497,8 @@ minetest.register_node("mcl_core:podzol", {
sounds = mcl_sounds.node_sound_dirt_defaults(),
on_construct = mcl_core.on_snowable_construct,
_mcl_snowed = "mcl_core:podzol_snow",
_mcl_blast_resistance = 0.8,
_mcl_hardness = 0.8,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_silk_touch_drop = true,
})
mcl_core.register_snowed_node("mcl_core:podzol_snow", "mcl_core:podzol", nil, nil, false, S("Podzol with Snow"))
@ -600,8 +600,8 @@ minetest.register_node("mcl_core:sandstonesmooth", {
stack_max = 64,
groups = {pickaxey=1, sandstone=1, normal_sandstone=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 2,
_mcl_blast_resistance = 0.8,
_mcl_hardness = 0.8,
})
minetest.register_node("mcl_core:sandstonecarved", {
@ -687,8 +687,8 @@ minetest.register_node("mcl_core:redsandstonesmooth2", {
stack_max = 64,
groups = {pickaxey=1, sandstone=1, red_sandstone=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 0.8,
_mcl_hardness = 0.8,
_mcl_blast_resistance = 6,
_mcl_hardness = 2,
})
---
@ -798,6 +798,18 @@ minetest.register_node("mcl_core:coalblock", {
_mcl_hardness = 5,
})
minetest.register_node("mcl_core:charcoalblock", {
description = S("Block of Charcoal"),
_doc_items_longdesc = S("Blocks of charcoal are useful as a compact storage of charcoal and very useful as a furnace fuel. A block of charcoal is as efficient as 10 charcoal."),
tiles = {"mcl_core_charcoal_block.png"},
is_ground_content = false,
stack_max = 64,
groups = {pickaxey=1, flammable=1, building_block=1, material_stone=1, fire_encouragement=5, fire_flammability=5},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 6,
_mcl_hardness = 5,
})
minetest.register_node("mcl_core:ironblock", {
description = S("Block of Iron"),
_doc_items_longdesc = S("A block of iron is mostly a decorative block but also useful as a compact storage of iron ingots."),
@ -1051,7 +1063,15 @@ for i=1,8 do
local itemstring = itemstack:get_name()
local itemcount = itemstack:get_count()
local fakestack = ItemStack(itemstring.." "..itemcount)
fakestack:set_name("mcl_core:snow_"..math.min(8, (i+g)))
if i+g < 8 then
fakestack:set_name("mcl_core:snow_"..(i+g))
else
-- To stack `mcl_core:snow_8', just replacing it with `mcl_core:snowblock' Issue#4483
if i+g == 9 then
fakestack:set_count(itemcount + 1)
end
fakestack:set_name("mcl_core:snowblock")
end
itemstack = minetest.item_place(fakestack, placer, pointed_thing)
minetest.sound_play(mcl_sounds.node_sound_snow_defaults().place, {pos = pointed_thing.under}, true)
itemstack:set_name(itemstring)
@ -1119,8 +1139,8 @@ minetest.register_node("mcl_core:snowblock", {
on_construct = mcl_core.on_snow_construct,
after_destruct = mcl_core.after_snow_destruct,
drop = "mcl_throwing:snowball 4",
_mcl_blast_resistance = 0.1,
_mcl_hardness = 0.1,
_mcl_blast_resistance = 0.2,
_mcl_hardness = 0.2,
_mcl_silk_touch_drop = true,
})

View File

@ -40,7 +40,7 @@ end
minetest.register_node("mcl_core:ladder", {
description = S("Ladder"),
_doc_items_longdesc = S(
"A piece of ladder which allows you to climb vertically. Ladders can only be placed on the side of solid blocks and not on glass, leaves, ice, slabs, glowstone, nor sea lanterns."),
"A piece of ladder which allows you to climb vertically. Ladders can only be placed on the side of solid blocks."),
drawtype = "signlike",
is_ground_content = false,
tiles = { "default_ladder.png" },
@ -85,9 +85,8 @@ minetest.register_node("mcl_core:ladder", {
end
local groups = def.groups
-- Don't allow to place the ladder at particular nodes
if (groups and (groups.glass or groups.leaves or groups.slab)) or
node.name == "mcl_core:ladder" or node.name == "mcl_core:ice" or node.name == "mcl_nether:glowstone" or node.name == "mcl_ocean:sea_lantern" then
-- Don't allow to place the ladder at non-solid nodes
if (groups and (not groups.solid)) then
return itemstack
end
@ -105,9 +104,10 @@ minetest.register_node("mcl_core:ladder", {
return itemstack
end
local idef = itemstack:get_definition()
local success = minetest.item_place_node(itemstack, placer, pointed_thing)
local itemstack, pos = minetest.item_place_node(itemstack, placer, pointed_thing)
if success then
-- A non-nil pos indicates the node was placed in a valid position.
if pos then
if idef.sounds and idef.sounds.place then
minetest.sound_play(idef.sounds.place, { pos = above, gain = 1 }, true)
end

View File

@ -191,8 +191,7 @@ minetest.register_node("mcl_crimson:twisting_vines", {
"mcl_crimson:twisting_vines",
"mcl_crimson:twisting_vines",
},
_mcl_blast_resistance = 0.2,
_mcl_hardness = 0.2,
_mcl_blast_resistance = 0,
})
minetest.register_node("mcl_crimson:weeping_vines", {
@ -281,8 +280,7 @@ minetest.register_node("mcl_crimson:weeping_vines", {
"mcl_crimson:weeping_vines",
"mcl_crimson:weeping_vines",
},
_mcl_blast_resistance = 0.2,
_mcl_hardness = 0.2,
_mcl_blast_resistance = 0,
})
minetest.register_node("mcl_crimson:nether_sprouts", {
@ -465,6 +463,7 @@ minetest.register_node("mcl_crimson:warped_hyphae_wood", {
tiles = {"mcl_crimson_warped_hyphae_wood.png"},
groups = {handy = 5,axey = 1, wood=1,building_block = 1, material_wood = 1},
sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_blast_resistance = 3,
_mcl_hardness = 2,
})
@ -662,6 +661,7 @@ minetest.register_node("mcl_crimson:crimson_hyphae_wood", {
tiles = {"mcl_crimson_crimson_hyphae_wood.png"},
groups = {handy = 5, axey = 1, wood = 1, building_block = 1, material_wood = 1},
sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_blast_resistance = 3,
_mcl_hardness = 2,
})

View File

@ -38,8 +38,8 @@ minetest.register_node("mcl_deepslate:infested_deepslate", {
drop = "",
sounds = mcl_sounds.node_sound_stone_defaults(),
after_dig_node = spawn_silverfish,
_mcl_hardness = 0,
_mcl_blast_resistance = 0.5,
_mcl_hardness = 1.5,
_mcl_blast_resistance = 0.75,
})
minetest.register_node("mcl_deepslate:tuff", {
@ -218,10 +218,7 @@ local function register_deepslate_variant(item, desc, longdesc)
end
if item ~= "chiseled" then
mcl_stairs.register_stair_and_slab_simple("deepslate_"..item, "mcl_deepslate:deepslate_"..item, S(desc.." Stairs"), S(desc.." Slab"), S("Double "..desc.." Slab"))
mcl_walls.register_wall(
"mcl_deepslate:deepslate"..item.."wall",
S(desc.." Wall"),
"mcl_deepslate:deepslate_"..item)
mcl_walls.register_wall("mcl_deepslate:deepslate"..item.."wall", S(desc.." Wall"), "mcl_deepslate:deepslate_"..item)
end
end

View File

@ -230,7 +230,7 @@ minetest.register_node("mcl_end:chorus_flower_dead", {
groups = {handy=1,axey=1, deco_block = 1, dig_by_piston = 1, destroy_by_lava_flow = 1,chorus_plant = 1, not_in_creative_inventory=1},
after_dig_node = mcl_end.check_detach_chorus_plant,
on_blast = mcl_end.check_blast_chorus_plant,
_mcl_blast_resistance = 2,
_mcl_blast_resistance = 0.4,
_mcl_hardness = 0.4,
})
@ -309,7 +309,7 @@ minetest.register_node("mcl_end:chorus_plant", {
end,
after_dig_node = mcl_end.check_detach_chorus_plant,
on_blast = mcl_end.check_blast_chorus_plant,
_mcl_blast_resistance = 2,
_mcl_blast_resistance = 0.4,
_mcl_hardness = 0.4,
})

View File

@ -44,7 +44,7 @@ minetest.register_node("mcl_farming:soil_wet", {
end,
groups = {handy=1,shovely=1, not_in_creative_inventory=1, dirtifies_below_solid=1, dirtifier=1, soil=3, soil_sapling=1 },
sounds = mcl_sounds.node_sound_dirt_defaults(),
_mcl_blast_resistance = 0.5,
_mcl_blast_resistance = 0.6,
_mcl_hardness = 0.6,
})

View File

@ -31,8 +31,8 @@ local lectern_def = {
walkable = true,
is_ground_content = false,
node_placement_prediction = "",
_mcl_blast_resistance = 3,
_mcl_hardness = 2,
_mcl_blast_resistance = 2.5,
_mcl_hardness = 2.5,
selection_box = {
type = "fixed",
fixed = {

View File

@ -60,7 +60,8 @@ local rod_def = {
return minetest.item_place(itemstack, placer, pointed_thing, param2)
end,
_mcl_blast_resistance = 0,
_mcl_blast_resistance = 6,
_mcl_hardness = 3,
}
minetest.register_node("mcl_lightning_rods:rod", rod_def)

View File

@ -322,14 +322,14 @@ mcl_stairs.register_stair("mangrove_wood", "mcl_mangrove:mangrove_wood",
{handy=1,axey=1, flammable=3,wood_stairs=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{"mcl_mangrove_planks.png"},
S("Mangrove Wood Stairs"),
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
"woodlike")
mcl_stairs.register_slab("mangrove_wood", "mcl_mangrove:mangrove_wood",
{handy=1,axey=1, flammable=3,wood_slab=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{"mcl_mangrove_planks.png"},
S("Mangrove Wood Slab"),
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
S("Double Mangrove Wood Slab"))
minetest.register_craft({

View File

@ -10,10 +10,15 @@ local function spawn_silverfish(pos, oldnode, oldmetadata, digger)
end
-- Template function for registering monster egg blocks
local function register_block(subname, description, tiles, is_ground_content)
local function register_block(subname, description, tiles, is_ground_content, hardness_override)
if is_ground_content == nil then
is_ground_content = false
end
-- Default hardness matches for stone and stone brick variants; cobble has 1.0
local hardness = 0.75
if hardness_override then
hardness = hardness_override
end
minetest.register_node("mcl_monster_eggs:monster_egg_"..subname, {
description = description,
tiles = tiles,
@ -24,14 +29,14 @@ local function register_block(subname, description, tiles, is_ground_content)
after_dig_node = spawn_silverfish,
_tt_help = S("Hides a silverfish"),
_doc_items_longdesc = S("An infested block is a block from which a silverfish will pop out when it is broken. It looks identical to its normal counterpart."),
_mcl_hardness = 0,
_mcl_blast_resistance = 0.5,
_mcl_hardness = hardness,
_mcl_blast_resistance = 0.75,
})
end
-- Register all the monster egg blocks
register_block("stone", S("Infested Stone"), {"default_stone.png"}, true)
register_block("cobble", S("Infested Cobblestone"), {"default_cobble.png"})
register_block("cobble", S("Infested Cobblestone"), {"default_cobble.png"}, nil, 1.0)
register_block("stonebrick", S("Infested Stone Bricks"), {"default_stone_brick.png"})
register_block("stonebrickcracked", S("Infested Cracked Stone Bricks"), {"mcl_core_stonebrick_cracked.png"})
register_block("stonebrickmossy", S("Infested Mossy Stone Bricks"), {"mcl_core_stonebrick_mossy.png"})

View File

@ -259,8 +259,8 @@ minetest.register_node("mcl_nether:quartz_smooth", {
tiles = {"mcl_nether_quartz_block_bottom.png"},
groups = {pickaxey=1, quartz_block=1,building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 0.8,
_mcl_hardness = 0.8,
_mcl_blast_resistance = 6,
_mcl_hardness = 2,
})
minetest.register_craftitem("mcl_nether:glowstone_dust", {

View File

@ -1260,7 +1260,11 @@ local function potions_init_icons(player)
})
table.insert(icon_ids[name], id)
end
hb.init_hudbar(player, "absorption")
-- Absorption bar in damage disabled server is unneccessary
if minetest.settings:get_bool("enable_damage") == true then
hb.init_hudbar(player, "absorption")
end
end
local function potions_set_icons(player)

View File

@ -194,7 +194,7 @@ minetest.register_node("mcl_sculk:sculk", {
is_ground_content = false,
on_destruct = sculk_on_destruct,
_mcl_blast_resistance = 0.2,
_mcl_hardness = 0.6,
_mcl_hardness = 0.2,
_mcl_silk_touch_drop = true,
})

View File

@ -11,7 +11,8 @@ mcl_stairs.register_stair_and_slab_simple("platinum", "example:platinum", "Plati
```
## `mcl_stairs.register_stair_and_slab_simple(subname, sourcenode, desc_stair, desc_slab, double_description, corner_stair_texture_override)`
Register a simple stair and a slab. The stair and slab will inherit all attributes from `sourcenode`. The `sourcenode` is also used as the item for crafting recipes.
Register a simple stair and a slab. The stair and slab will inherit all attributes from `sourcenode`. The `sourcenode` is also used as the item for crafting recipes. If multiple nodes should craft into the same stairs/slab, see
`mcl_stairs.register_craft_stairs` or `mcl_stairs.register_craft_slab`
This function is meant for simple nodes; if you need more flexibility, use one of the other functions instead.
@ -44,7 +45,7 @@ The itemstrings for the registered nodes will be of the form:
### Parameters
* `subname`: Name fragment for node itemstrings (see above)
* `recipeitem`: Item for crafting recipe. Use `group:` prefix to use a group instead
* `recipeitem`: Item for crafting recipe and attribute inheritance. Do not use `group:` prefix here, alternative recipes can be registered using `mcl_stairs.register_craft_stairs(subname, recipeitem_or_group)`.
* `groups`: Groups used for stair
* `images`: Textures
* `description`: Stair description/tooltip
@ -81,3 +82,35 @@ The itemstrings for the registered nodes will be of the form:
* `double_description`: Node description/tooltip for double slab
* Other parameters: Same as for `register_stair`
## `mcl_stairs.register_craft_stairs(subname, recipeitem)`
Just registers a recipe for `mcl_stairs:stair_<subname>`.
Useful if a node variant should craft the same stairs as the base node, since the above functions use the same
parameter for crafting material and attribute inheritance.
e.g. 6 Purpur Pillar -> 4 Purpur Stairs is an alternate recipe.
Creates staircase recipes with 6 input items, both left-facing and right-facing. Outputs 4 stairs.
The itemstring for the output node will be of the form:
* `mcl_stairs:stair_<subname>`: Normal stair
### Parameters
* `subname`: Name fragment for node itemstring (see above)
* `recipeitem`: Item for crafting recipe. Use `group:` prefix to use a group instead
## `mcl_stairs.register_craft_slab(subname, recipeitem)`
Just registers a recipe for `mcl_stairs:slab_<subname>`.
Useful if a node variant should craft the same stairs as the base node, since the above functions use the same
parameter for crafting material and attribute inheritance.
e.g. 3 Quartz Pillar -> 6 Quartz Slab is an alternate recipe.
Creates slab recipe with 3 input items in any horizontal line. Outputs 6 slabs.
The itemstring for the output node will be of the form:
* `mcl_stairs:slab_<subname>`: Slab
### Parameters
* `subname`: Name fragment for node itemstring (see above)
* `recipeitem`: Item for crafting recipe. Use `group:` prefix to use a group instead

View File

@ -237,30 +237,43 @@ function mcl_stairs.register_slab(subname, recipeitem, groups, images, descripti
fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
},
on_place = function(itemstack, placer, pointed_thing)
local under = minetest.get_node(pointed_thing.under)
if not placer then return end
local above = pointed_thing.above
local under = pointed_thing.under
local anode = minetest.get_node(above)
local unode = minetest.get_node(under)
local adefs = minetest.registered_nodes[anode.name]
local udefs = minetest.registered_nodes[unode.name]
local wield_item = itemstack:get_name()
local creative_enabled = minetest.is_creative_enabled(placer:get_player_name())
local player_name = placer:get_player_name()
local creative_enabled = minetest.is_creative_enabled(player_name)
-- place slab using under node orientation
local dir = vector.subtract(pointed_thing.above, pointed_thing.under)
local dir = vector.subtract(above, under)
local p2 = unode.param2
local p2 = under.param2
if minetest.is_protected(under, player_name) and not
minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(under, player_name)
return
end
-- combine two slabs if possible
-- Requirements: Same slab material, must be placed on top of lower slab, or on bottom of upper slab
if (wield_item == under.name or (minetest.registered_nodes[under.name] and wield_item == minetest.registered_nodes[under.name]._mcl_other_slab_half)) and
not ((dir.y >= 0 and minetest.get_item_group(under.name, "slab_top") == 1) or
(dir.y <= 0 and minetest.get_item_group(under.name, "slab_top") == 0)) then
if (wield_item == unode.name or (udefs and wield_item == udefs._mcl_other_slab_half)) and
not ((dir.y >= 0 and minetest.get_item_group(unode.name, "slab_top") == 1) or
(dir.y <= 0 and minetest.get_item_group(unode.name, "slab_top") == 0)) then
local player_name = placer:get_player_name()
if minetest.is_protected(pointed_thing.under, player_name) and not
minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(pointed_thing.under,
player_name)
return
minetest.set_node(under, {name = double_slab, param2 = p2})
if not creative_enabled then
itemstack:take_item()
end
local newnode = double_slab
minetest.set_node(pointed_thing.under, {name = newnode, param2 = p2})
return itemstack
elseif (wield_item == anode.name or (adefs and wield_item == adefs._mcl_other_slab_half)) then
minetest.set_node(above, {name = double_slab, param2 = p2})
if not creative_enabled then
itemstack:take_item()
end

View File

@ -1,10 +1,39 @@
-- Register all Minecraft stairs and slabs
-- Note about hardness: For some reason, the hardness of slabs and stairs don't always match nicely, so that some
-- slabs actually take slightly longer to be dug than their stair counterparts.
-- Note sure if it is a good idea to preserve this oddity.
local S = minetest.get_translator(minetest.get_current_modname())
-- Cut Sandstone Stairs do not exist, and register_stair_and_slab does not allow multiple recipes
-- (e.g. using group:node) if we try to copy the properties of the node at the same parameter.
-- The missing recipes can be added separately via these:
function mcl_stairs.register_craft_stairs(subname, recipeitem)
minetest.register_craft({
output = "mcl_stairs:stair_" .. subname .. " 4",
recipe = {
{recipeitem, "", ""},
{recipeitem, recipeitem, ""},
{recipeitem, recipeitem, recipeitem},
},
})
-- Flipped recipe
minetest.register_craft({
output = "mcl_stairs:stair_" .. subname .. " 4",
recipe = {
{"", "", recipeitem},
{"", recipeitem, recipeitem},
{recipeitem, recipeitem, recipeitem},
},
})
end
function mcl_stairs.register_craft_slab(subname, recipeitem)
minetest.register_craft({
output = "mcl_stairs:slab_" .. subname .. " 6",
recipe = {
{recipeitem, recipeitem, recipeitem},
},
})
end
local woods = {
{ "wood", "default_wood.png", S("Oak Wood Stairs"), S("Oak Wood Slab"), S("Double Oak Wood Slab") },
{ "junglewood", "default_junglewood.png", S("Jungle Wood Stairs"), S("Jungle Wood Slab"), S("Double Jungle Wood Slab") },
@ -20,13 +49,13 @@ for w=1, #woods do
{handy=1,axey=1, flammable=3,wood_stairs=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{wood[2]},
wood[3],
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
"woodlike")
mcl_stairs.register_slab(wood[1], "mcl_core:"..wood[1],
{handy=1,axey=1, flammable=3,wood_slab=1, material_wood=1, fire_encouragement=5, fire_flammability=20},
{wood[2]},
wood[4],
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
wood[5])
end
@ -47,7 +76,7 @@ mcl_stairs.register_slab("stone", "mcl_core:stone_smooth",
{pickaxey=1, material_stone=1},
{"mcl_stairs_stone_slab_top.png", "mcl_stairs_stone_slab_top.png", "mcl_stairs_stone_slab_side.png"},
S("Polished Stone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Polished Stone Slab"))
mcl_stairs.register_stair("andesite", "mcl_core:andesite",
@ -86,118 +115,95 @@ mcl_stairs.register_slab("diorite", "mcl_core:diorite",
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Diorite Slab"))
mcl_stairs.register_stair("cobble", "mcl_core:cobble",
mcl_stairs.register_stair_and_slab("cobble", "mcl_core:cobble",
{pickaxey=1, material_stone=1},
{"default_cobble.png"},
S("Cobblestone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8)
mcl_stairs.register_slab("cobble", "mcl_core:cobble",
{pickaxey=1, material_stone=1},
{"default_cobble.png"},
S("Cobblestone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Cobblestone Slab"))
mcl_stairs.register_stair("mossycobble", "mcl_core:mossycobble",
mcl_stairs.register_stair_and_slab("mossycobble", "mcl_core:mossycobble",
{pickaxey=1, material_stone=1},
{"default_mossycobble.png"},
S("Mossy Cobblestone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8)
mcl_stairs.register_slab("mossycobble", "mcl_core:mossycobble",
{pickaxey=1, material_stone=1},
{"default_mossycobble.png"},
S("Mossy Cobblestone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Mossy Cobblestone Slab"))
mcl_stairs.register_stair("brick_block", "mcl_core:brick_block",
mcl_stairs.register_stair_and_slab("brick_block", "mcl_core:brick_block",
{pickaxey=1, material_stone=1},
{"default_brick.png"},
S("Brick Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8)
mcl_stairs.register_slab("brick_block", "mcl_core:brick_block",
{pickaxey=1, material_stone=1},
{"default_brick.png"},
S("Brick Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Brick Slab"))
mcl_stairs.register_stair("sandstone", "mcl_core:sandstone",
mcl_stairs.register_stair_and_slab("sandstone", "mcl_core:sandstone",
{pickaxey=1, material_stone=1},
{"mcl_core_sandstone_top.png", "mcl_core_sandstone_bottom.png", "mcl_core_sandstone_normal.png"},
S("Sandstone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8,
nil, "mcl_core:sandstone") --fixme: extra parameter from previous release
mcl_stairs.register_slab("sandstone", "mcl_core:sandstone",
{pickaxey=1, material_stone=1},
{"mcl_core_sandstone_top.png", "mcl_core_sandstone_bottom.png", "mcl_core_sandstone_normal.png"},
S("Sandstone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Sandstone Slab"), "mcl_core:sandstone") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Sandstone Slab"))
mcl_stairs.register_craft_stairs("sandstone", "mcl_core:sandstonesmooth") -- Comment this line out if Cut Sandstone Stairs are implemented
mcl_stairs.register_craft_stairs("sandstone", "mcl_core:sandstonecarved")
mcl_stairs.register_craft_slab("sandstone", "mcl_core:sandstonecarved")
mcl_stairs.register_stair("sandstonesmooth2", "mcl_core:sandstonesmooth2",
{pickaxey=1, material_stone=1},
{"mcl_core_sandstone_top.png"},
S("Smooth Sandstone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8)
mcl_stairs.register_slab("sandstonesmooth2", "mcl_core:sandstonesmooth2",
{pickaxey=1, material_stone=1},
{"mcl_core_sandstone_top.png"},
S("Smooth Sandstone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Smooth Sandstone Slab"))
-- mcl_stairs.register_stair_and_slab("sandstonesmooth", "mcl_core:sandstonesmooth",
-- {pickaxey=1, material_stone=1},
-- {"mcl_core_sandstone_top.png", "mcl_core_sandstone_bottom.png", "mcl_core_sandstone_smooth.png"},
-- S("Cut Sandstone Stairs"), S("Cut Sandstone Slab"),
-- mcl_sounds.node_sound_stone_defaults(), nil, nil,
-- S("Double Cut Sandstone Slab"))
mcl_stairs.register_stair("redsandstone", "mcl_core:redsandstone",
mcl_stairs.register_stair_and_slab_simple("sandstonesmooth2", "mcl_core:sandstonesmooth2", S("Smooth Sandstone Stairs"), S("Smooth Sandstone Slab"), S("Double Smooth Sandstone Slab"))
mcl_stairs.register_stair_and_slab("redsandstone", "mcl_core:redsandstone",
{pickaxey=1, material_stone=1},
{"mcl_core_red_sandstone_top.png", "mcl_core_red_sandstone_bottom.png", "mcl_core_red_sandstone_normal.png"},
S("Red Sandstone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8,
nil, "mcl_core:redsandstone") --fixme: extra parameter from previous release
mcl_stairs.register_slab("redsandstone", "mcl_core:redsandstone",
{pickaxey=1, material_stone=1},
{"mcl_core_red_sandstone_top.png", "mcl_core_red_sandstone_bottom.png", "mcl_core_red_sandstone_normal.png"},
S("Red Sandstone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Red Sandstone Slab"), "mcl_core:redsandstone") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Red Sandstone Slab"))
mcl_stairs.register_craft_stairs("redsandstone", "mcl_core:redsandstonesmooth") -- Comment this line out if Cut Red Sandstone Stairs are implemented
mcl_stairs.register_craft_stairs("redsandstone", "mcl_core:redsandstonecarved")
mcl_stairs.register_craft_slab("redsandstone", "mcl_core:redsandstonecarved")
mcl_stairs.register_stair("redsandstonesmooth2", "mcl_core:redsandstonesmooth2",
{pickaxey=1, material_stone=1},
{"mcl_core_red_sandstone_top.png"},
S("Smooth Red Sandstone Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8)
mcl_stairs.register_slab("redsandstonesmooth2", "mcl_core:redsandstonesmooth2",
{pickaxey=1, material_stone=1},
{"mcl_core_red_sandstone_top.png"},
S("Smooth Red Sandstone Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Smooth Red Sandstone Slab"))
-- mcl_stairs.register_stair_and_slab("redsandstonesmooth", "mcl_core:redsandstonesmooth",
-- {pickaxey=1, material_stone=1},
-- {"mcl_core_red_sandstone_top.png", "mcl_core_red_sandstone_bottom.png", "mcl_core_red_sandstone_smooth.png"},
-- S("Cut Red Sandstone Stairs"), S("Cut Red Sandstone Slab"),
-- mcl_sounds.node_sound_stone_defaults(), nil, nil,
-- S("Double Cut Red Sandstone Slab"))
mcl_stairs.register_stair_and_slab_simple("redsandstonesmooth2", "mcl_core:redsandstonesmooth2", S("Smooth Red Sandstone Stairs"), S("Smooth Red Sandstone Slab"), S("Double Smooth Red Sandstone Slab"))
-- Intentionally not group:stonebrick because of mclx_stairs
mcl_stairs.register_stair("stonebrick", "mcl_core:stonebrick",
{pickaxey=1, material_stone=1},
{"default_stone_brick.png"},
S("Stone Bricks Stairs"),
mcl_sounds.node_sound_stone_defaults(), 6, 1.5,
nil, "mcl_core:stonebrick") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
nil)
mcl_stairs.register_slab("stonebrick", "mcl_core:stonebrick",
{pickaxey=1, material_stone=1},
{"default_stone_brick.png"},
S("Stone Bricks Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Stone Bricks Slab"), "mcl_core:stonebrick") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Stone Bricks Slab"))
mcl_stairs.register_stair("quartzblock", "mcl_nether:quartz_block",
mcl_stairs.register_stair_and_slab("quartzblock", "mcl_nether:quartz_block",
{pickaxey=1, material_stone=1},
{"mcl_nether_quartz_block_top.png", "mcl_nether_quartz_block_bottom.png", "mcl_nether_quartz_block_side.png"},
S("Quartz Stairs"),
mcl_sounds.node_sound_stone_defaults(), 0.8, 0.8,
nil, "mcl_nether:quartz_block") --fixme: extra parameter from previous release
mcl_stairs.register_slab("quartzblock", "mcl_nether:quartz_block",
{pickaxey=1, material_stone=1},
{"mcl_nether_quartz_block_top.png", "mcl_nether_quartz_block_bottom.png", "mcl_nether_quartz_block_side.png"},
S("Quartz Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Quartz Slab"), "mcl_nether:quartz_block") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Quartz Slab"))
mcl_stairs.register_craft_stairs("quartzblock", "mcl_nether:quartz_pillar")
mcl_stairs.register_craft_stairs("quartzblock", "mcl_nether:quartz_chiseled")
mcl_stairs.register_craft_slab("quartzblock", "mcl_nether:quartz_pillar")
mcl_stairs.register_craft_slab("quartzblock", "mcl_nether:quartz_chiseled")
mcl_stairs.register_stair("quartz_smooth", "mcl_nether:quartz_smooth",
{pickaxey=1, material_stone=1},
@ -216,14 +222,14 @@ mcl_stairs.register_stair_and_slab("nether_brick", "mcl_nether:nether_brick",
{"mcl_nether_nether_brick.png"},
S("Nether Brick Stairs"),
S("Nether Brick Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Nether Brick Slab"), nil)
mcl_stairs.register_stair_and_slab("red_nether_brick", "mcl_nether:red_nether_brick",
{pickaxey=1, material_stone=1},
{"mcl_nether_red_nether_brick.png"},
S("Red Nether Brick Stairs"),
S("Red Nether Brick Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Red Nether Brick Slab"), nil)
mcl_stairs.register_stair_and_slab("end_bricks", "mcl_end:end_bricks",
@ -234,18 +240,15 @@ mcl_stairs.register_stair_and_slab("end_bricks", "mcl_end:end_bricks",
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double End Stone Brick Slab"), nil)
mcl_stairs.register_stair("purpur_block", "mcl_end:purpur_block",
mcl_stairs.register_stair_and_slab("purpur_block", "mcl_end:purpur_block",
{pickaxey=1, material_stone=1},
{"mcl_end_purpur_block.png"},
S("Purpur Stairs"),
mcl_sounds.node_sound_stone_defaults(), 6, 1.5,
nil)
mcl_stairs.register_slab("purpur_block", "mcl_end:purpur_block",
{pickaxey=1, material_stone=1},
{"mcl_end_purpur_block.png"},
S("Purpur Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Purpur Slab"))
mcl_stairs.register_craft_stairs("purpur_block", "mcl_end:purpur_pillar")
mcl_stairs.register_craft_slab("purpur_block", "mcl_end:purpur_pillar")
mcl_stairs.register_stair("prismarine", "mcl_ocean:prismarine",
{pickaxey=1, material_stone=1},
@ -298,52 +301,52 @@ mcl_stairs.register_slab("andesite_smooth", "mcl_core:andesite_smooth",
{pickaxey=1},
{"mcl_core_andesite_smooth.png", "mcl_core_andesite_smooth.png", "mcl_stairs_andesite_smooth_slab.png"},
S("Polished Andesite Slab"),
nil, 6, nil,
nil, nil, nil,
S("Double Polished Andesite Slab"))
mcl_stairs.register_stair("andesite_smooth", "mcl_core:andesite_smooth",
{pickaxey=1},
{"mcl_stairs_andesite_smooth_slab.png", "mcl_core_andesite_smooth.png", "mcl_core_andesite_smooth.png", "mcl_core_andesite_smooth.png", "mcl_core_andesite_smooth.png", "mcl_stairs_andesite_smooth_slab.png"},
S("Polished Andesite Stairs"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_slab("granite_smooth", "mcl_core:granite_smooth",
{pickaxey=1},
{"mcl_core_granite_smooth.png", "mcl_core_granite_smooth.png", "mcl_stairs_granite_smooth_slab.png"},
S("Polished Granite Slab"),
nil, 6, nil,
nil, nil, nil,
S("Double Polished Granite Slab"))
mcl_stairs.register_stair("granite_smooth", "mcl_core:granite_smooth",
{pickaxey=1},
{"mcl_stairs_granite_smooth_slab.png", "mcl_core_granite_smooth.png", "mcl_core_granite_smooth.png", "mcl_core_granite_smooth.png", "mcl_core_granite_smooth.png", "mcl_stairs_granite_smooth_slab.png"},
S("Polished Granite Stairs"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_slab("diorite_smooth", "mcl_core:diorite_smooth",
{pickaxey=1},
{"mcl_core_diorite_smooth.png", "mcl_core_diorite_smooth.png", "mcl_stairs_diorite_smooth_slab.png"},
S("Polished Diorite Slab"),
nil, 6, nil,
nil, nil, nil,
S("Double Polished Diorite Slab"))
mcl_stairs.register_stair("diorite_smooth", "mcl_core:diorite_smooth",
{pickaxey=1},
{"mcl_stairs_diorite_smooth_slab.png", "mcl_core_diorite_smooth.png", "mcl_core_diorite_smooth.png", "mcl_core_diorite_smooth.png", "mcl_core_diorite_smooth.png", "mcl_stairs_diorite_smooth_slab.png"},
S("Polished Diorite Stairs"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("stonebrickmossy", "mcl_core:stonebrickmossy",
{pickaxey=1},
{"mcl_core_stonebrick_mossy.png"},
S("Mossy Stone Brick Stairs"),
mcl_sounds.node_sound_stone_defaults(), 6, 1.5,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
nil)
mcl_stairs.register_slab("stonebrickmossy", "mcl_core:stonebrickmossy",
{pickaxey=1},
{"mcl_core_stonebrick_mossy.png"},
S("Mossy Stone Brick Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
S("Double Mossy Stone Brick Slab"), "mcl_core:stonebrickmossy") --fixme: extra parameter from previous release
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Mossy Stone Brick Slab"))

View File

@ -123,7 +123,7 @@ local function snowball_on_step(self, dtime)
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
self._lastpos = pos -- Set _lastpos-->Node will be added at last pos outside the node
end
-- Movement function of egg
@ -133,47 +133,39 @@ local function egg_on_step(self, dtime)
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 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)
-- Destroy when hitting a solid node or entity, with chance to spawn chicks
if (def and def.walkable) or not def or check_object_hit(self, pos, 0) then
-- If egg has just been thrown, use current position
if not self._lastpos.x then
self._lastpos = pos
end
-- 1/8 chance to spawn a chick
-- FIXME: Chicks have a quite good chance to spawn in walls
if math.random(1,8) == 1 then
mcl_mobs.spawn_child(self._lastpos, "mobs_mc:chicken")
if r == 1 then
mcl_mobs.spawn_child(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])
mcl_mobs.spawn_child(pos, "mobs_mc:chicken")
end
-- BONUS ROUND: 1/32 chance to spawn 3 additional chicks
if math.random(1,32) == 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])
mcl_mobs.spawn_child(pos, "mobs_mc:chicken")
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()
if mod_target and node.name == "mcl_target:target_off" then
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
end
return
end
end
-- Destroy when hitting a mob or player (no chick spawning)
if check_object_hit(self, pos, 0) then
minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true)
self.object:remove()
if mod_target and node.name == "mcl_target:target_off" then
mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks
end
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
self._lastpos = pos -- Set lastpos-->Node will be added at last pos outside the node
end
-- Movement function of ender pearl
@ -272,7 +264,7 @@ local function pearl_on_step(self, dtime)
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
self._lastpos = pos -- Set lastpos-->Node will be added at last pos outside the node
end
snowball_ENTITY.on_step = snowball_on_step

View File

@ -116,6 +116,7 @@ minetest.register_node("mcl_tnt:tnt", {
local TNT = {
-- Static definition
physical = true, -- Collides with things
collide_with_objects = false,
--weight = -100,
collisionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
visual = "cube",

View File

@ -22,13 +22,13 @@ for b=1, #barks do
{handy=1,axey=1, flammable=3, bark_stairs=1, material_wood=1, fire_encouragement=5, fire_flammability=5},
{minetest.registered_nodes[id].tiles[3]},
bark[2],
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
"woodlike")
mcl_stairs.register_slab(sub, id,
{handy=1,axey=1, flammable=3, bark_slab=1, material_wood=1, fire_encouragement=5, fire_flammability=5},
{minetest.registered_nodes[id].tiles[3]},
bark[3],
mcl_sounds.node_sound_wood_defaults(), 3, 2,
mcl_sounds.node_sound_wood_defaults(), nil, nil,
bark[4])
end
@ -42,7 +42,7 @@ mcl_stairs.register_stair("lapisblock", "mcl_core:lapisblock",
{pickaxey=3},
{"mcl_stairs_lapis_block_slab.png", "mcl_core_lapis_block.png", "mcl_core_lapis_block.png", "mcl_core_lapis_block.png", "mcl_core_lapis_block.png", "mcl_stairs_lapis_block_slab.png"},
S("Lapis Lazuli Stairs"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_slab("goldblock", "mcl_core:goldblock",
@ -55,7 +55,7 @@ mcl_stairs.register_stair("goldblock", "mcl_core:goldblock",
{pickaxey=4},
{"mcl_stairs_gold_block_slab.png", "default_gold_block.png", "default_gold_block.png", "default_gold_block.png", "default_gold_block.png", "mcl_stairs_gold_block_slab.png"},
S("Stairs of Gold"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_slab("ironblock", "mcl_core:ironblock",
@ -68,21 +68,21 @@ mcl_stairs.register_stair("ironblock", "mcl_core:ironblock",
{pickaxey=2},
{"mcl_stairs_iron_block_slab.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "default_steel_block.png", "mcl_stairs_iron_block_slab.png"},
S("Stairs of Iron"),
nil, 6, nil,
nil, nil, nil,
"woodlike")
mcl_stairs.register_stair("stonebrickcracked", "mcl_core:stonebrickcracked",
{pickaxey=1},
{"mcl_core_stonebrick_cracked.png"},
S("Cracked Stone Brick Stairs"),
mcl_sounds.node_sound_stone_defaults(), 6, 1.5,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
"woodlike")
mcl_stairs.register_slab("stonebrickcracked", "mcl_core:stonebrickcracked",
{pickaxey=1},
{"mcl_core_stonebrick_cracked.png"},
S("Cracked Stone Brick Slab"),
mcl_sounds.node_sound_stone_defaults(), 6, 2,
mcl_sounds.node_sound_stone_defaults(), nil, nil,
S("Double Cracked Stone Brick Slab"))
local block = {}

View File

@ -4027,7 +4027,7 @@ local function register_decorations()
rotation = "random",
})
minetest.register_decoration({
name = "mcl_biomes:mangrove_tree_4",
name = "mcl_biomes:mangrove_tree_5",
deco_type = "schematic",
place_on = {"mcl_mud:mud"},
sidelen = 80,
@ -4040,6 +4040,7 @@ local function register_decorations()
rotation = "random",
})
minetest.register_decoration({
name = "mcl_biomes:mangrove_bee_nest",
deco_type = "schematic",
place_on = {"mcl_mud:mud"},
sidelen = 80,
@ -6099,6 +6100,9 @@ if mg_name ~= "singlenode" then
minetest.get_decoration_id("mcl_biomes:mangrove_tree_1"),
minetest.get_decoration_id("mcl_biomes:mangrove_tree_2"),
minetest.get_decoration_id("mcl_biomes:mangrove_tree_3"),
minetest.get_decoration_id("mcl_biomes:mangrove_tree_4"),
minetest.get_decoration_id("mcl_biomes:mangrove_tree_5"),
minetest.get_decoration_id("mcl_biomes:mangrove_bee_nest"),
}
for _, f in pairs(deco_ids_fungus) do
minetest.set_gen_notify({decoration = true}, {f})
@ -6158,29 +6162,20 @@ if mg_name ~= "singlenode" then
if not (maxp.y < mcl_vars.mg_overworld_min or minp.y > mcl_vars.mg_overworld_max) then
local biomemap = minetest.get_mapgen_object("biomemap")
--minetest.log("mangrove stuff: " .. dump(biomemap))
local swamp_biome_id = minetest.get_biome_id("MangroveSwamp")
local swamp_shore_id = minetest.get_biome_id("MangroveSwamp_shore")
local is_swamp = table.indexof(biomemap, swamp_biome_id) ~= -1
local is_swamp_shore = table.indexof(biomemap, swamp_shore_id) ~= -1
if is_swamp or is_swamp_shore then
--minetest.log("Mangrove swamp biomes...")
--minetest.log("is_swamp: " .. dump(is_swamp))
--minetest.log("is_swamp_shore: " .. dump(is_swamp_shore))
mangrove_roots_gen(gennotify, pr)
else
--minetest.log("is not mangrove swamp biomes...")
end
end
if not (maxp.y < mcl_vars.mg_end_min or minp.y > mcl_vars.mg_end_max) then
--minetest.log("chorus stuff")
chorus_gen(gennotify, pr)
end
if not (maxp.y < mcl_vars.mg_nether_min or minp.y > mcl_vars.mg_nether_max) then
--minetest.log("nether stuff")
crimson_warped_gen(gennotify)
end
end)

View File

@ -116,57 +116,58 @@ mcl_structures.register_structure("shipwreck",{
y_offset = function(pr) return pr:next(-4,-2) end,
loot = {
["mcl_chests:chest_small"] = {
stacks_min = 3,
stacks_max = 10,
items = {
{ itemstring = "mcl_sus_stew:stew", weight = 10, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:paper", weight = 8, amount_min = 1, amount_max = 12 },
{ itemstring = "mcl_farming:wheat_item", weight = 7, amount_min = 8, amount_max = 21 },
{ itemstring = "mcl_farming:carrot_item", weight = 7, amount_min = 4, amount_max = 8 },
{ itemstring = "mcl_farming:potato_item_poison", weight = 7, amount_min = 2, amount_max = 6 },
{ itemstring = "mcl_farming:potato_item", weight = 7, amount_min = 2, amount_max = 6 },
--{ itemstring = "TODO:moss_block", weight = 7, amount_min = 1, amount_max = 4 },
{ itemstring = "mcl_core:coal_lump", weight = 6, amount_min = 2, amount_max = 8 },
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 5, amount_min = 5, amount_max = 24 },
{ itemstring = "mcl_farming:potato_item", weight = 3, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_armor:helmet_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:chestplate_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:leggings_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:boots_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
--{ itemstring = "TODO:bamboo", weight = 2, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_farming:pumpkin", weight = 2, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_tnt:tnt", weight = 1, amount_min = 1, amount_max = 2 },
{
stacks_min = 3,
stacks_max = 10,
items = {
{ itemstring = "mcl_sus_stew:stew", weight = 10, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:paper", weight = 8, amount_min = 1, amount_max = 12 },
{ itemstring = "mcl_farming:wheat_item", weight = 7, amount_min = 8, amount_max = 21 },
{ itemstring = "mcl_farming:carrot_item", weight = 7, amount_min = 4, amount_max = 8 },
{ itemstring = "mcl_farming:potato_item_poison", weight = 7, amount_min = 2, amount_max = 6 },
{ itemstring = "mcl_farming:potato_item", weight = 7, amount_min = 2, amount_max = 6 },
--{ itemstring = "TODO:moss_block", weight = 7, amount_min = 1, amount_max = 4 },
{ itemstring = "mcl_core:coal_lump", weight = 6, amount_min = 2, amount_max = 8 },
{ itemstring = "mcl_mobitems:rotten_flesh", weight = 5, amount_min = 5, amount_max = 24 },
{ itemstring = "mcl_farming:potato_item", weight = 3, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_armor:helmet_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:chestplate_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:leggings_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_armor:boots_leather_enchanted", weight = 3, func = function(stack, pr)
mcl_enchanting.enchant_uniform_randomly(stack, {"soul_speed"}) end },
{ itemstring = "mcl_bamboo:bamboo", weight = 2, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_farming:pumpkin", weight = 2, amount_min = 1, amount_max = 3 },
{ itemstring = "mcl_tnt:tnt", weight = 1, amount_min = 1, amount_max = 2 },
}
},
{
stacks_min = 2,
stacks_max = 6,
items = {
{ itemstring = "mcl_core:iron_ingot", weight = 90, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:iron_nugget", weight = 50, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_core:emerald", weight = 40, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:lapis", weight = 20, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_core:gold_ingot", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_experience:bottle", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 1 },
stacks_min = 2,
stacks_max = 6,
items = {
{ itemstring = "mcl_core:iron_ingot", weight = 90, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:iron_nugget", weight = 50, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_core:emerald", weight = 40, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:lapis", weight = 20, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_core:gold_ingot", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:gold_nugget", weight = 10, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_experience:bottle", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 1 },
}
},{
stacks_min = 3,
stacks_max = 3,
items = {
--{ itemstring = "FIXME TREASURE MAP", weight = 8, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:paper", weight = 20, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_mobitems:feather", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_books:book", weight = 5, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_clock:clock", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_compass:compass", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_maps:empty_map", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_armor:coast", weight = 20, amount_min = 2, amount_max = 2},
stacks_min = 3,
stacks_max = 3,
items = {
--{ itemstring = "FIXME TREASURE MAP", weight = 8, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:paper", weight = 20, amount_min = 1, amount_max = 10 },
{ itemstring = "mcl_mobitems:feather", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_books:book", weight = 5, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_clock:clock", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_compass:compass", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_maps:empty_map", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_armor:coast", weight = 20, amount_min = 2, amount_max = 2},
}
},
}
@ -207,35 +208,37 @@ mcl_structures.register_structure("ocean_temple",{
end,
loot = {
["mcl_chests:chest_small"] = {
stacks_min = 3,
stacks_max = 10,
items = {
{ itemstring = "mcl_sus_stew:stew", weight = 10, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:paper", weight = 8, amount_min = 1, amount_max = 12 },
{ itemstring = "mcl_fishing:fish_raw", weight = 5, amount_min = 8, amount_max = 21 },
{ itemstring = "mcl_fishing:salmon_raw", weight = 7, amount_min = 4, amount_max = 8 },
{ itemstring = "mcl_tnt:tnt", weight = 1, amount_min = 1, amount_max = 2 },
},
{
stacks_min = 2,
stacks_max = 6,
items = {
{ itemstring = "mcl_core:iron_ingot", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:goldblock", weight = 1, amount_min = 1, amount_max = 2 },
{ itemstring = "mcl_experience:bottle", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_fishing:fishing_rod", weight = 1, amount_min = 1, amount_max = 1 },
stacks_min = 3,
stacks_max = 10,
items = {
{ itemstring = "mcl_sus_stew:stew", weight = 10, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:paper", weight = 8, amount_min = 1, amount_max = 12 },
{ itemstring = "mcl_fishing:fish_raw", weight = 5, amount_min = 8, amount_max = 21 },
{ itemstring = "mcl_fishing:salmon_raw", weight = 7, amount_min = 4, amount_max = 8 },
{ itemstring = "mcl_tnt:tnt", weight = 1, amount_min = 1, amount_max = 2 },
}
},
{
stacks_min = 4,
stacks_max = 4,
items = {
--{ itemstring = "FIXME TREASURE MAP", weight = 8, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_books:book", weight = 1, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_clock:clock", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_compass:compass", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_maps:empty_map", weight = 1, amount_min = 1, amount_max = 1 },
stacks_min = 2,
stacks_max = 6,
items = {
{ itemstring = "mcl_core:iron_ingot", weight = 10, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_core:goldblock", weight = 1, amount_min = 1, amount_max = 2 },
{ itemstring = "mcl_experience:bottle", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_core:diamond", weight = 5, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_fishing:fishing_rod", weight = 1, amount_min = 1, amount_max = 1 },
}
},
{
stacks_min = 4,
stacks_max = 4,
items = {
--{ itemstring = "FIXME TREASURE MAP", weight = 8, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_books:book", weight = 1, amount_min = 1, amount_max = 5 },
{ itemstring = "mcl_clock:clock", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_compass:compass", weight = 1, amount_min = 1, amount_max = 1 },
{ itemstring = "mcl_maps:empty_map", weight = 1, amount_min = 1, amount_max = 1 },
}
},
}

View File

@ -512,23 +512,27 @@ minetest.register_globalstep(function(dtime)
local boots = player:get_inventory():get_stack("armor", 5)
local soul_speed = mcl_enchanting.get_enchantment(boots, "soul_speed")
if soul_speed > 0 then
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", soul_speed * 0.105 + 1.3)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:soul_speed", soul_speed * 0.105 + 1.3)
else
if node_stand_below == "mcl_core:ice" or node_stand_below == "mcl_core:packed_ice" or node_stand_below == "mcl_core:slimeblock" or node_stand_below == "mcl_core:water_source" then
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.1)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:soul_speed", 0.1)
else
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.4)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:soul_speed", 0.4)
end
end
elseif get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then
else
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:soul_speed")
end
if 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")
if depth_strider > 0 then
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", (depth_strider / 3) + 0.75)
playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:depth_strider", (depth_strider / 3) + 0.75)
else
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:depth_strider")
end
else
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface")
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:depth_strider")
end
-- Is player suffocating inside node? (Only for solid full opaque cube type nodes
@ -679,6 +683,8 @@ minetest.register_on_joinplayer(function(player)
player:respawn()
minetest.log("warning", name .. " joined the game with 0 hp and has been forced to respawn")
end
playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface")
end)
-- clear when player leaves

View File

@ -329,13 +329,13 @@ give_starting_inv (Player Starter Pack) bool false
mcl_item_id_debug (Item ID Debug) bool false
#Log mob spawning and despawning events
mcl_logging_mobs_spawn (Log Mob Spawning) bool true
mcl_logging_mobs_spawn (Log Mob Spawning) bool false
# If enabled mapgen timings will be dumped to log
mcl_logging_mapgen (Chunk generation logging) bool false
# If enabled generated structures will be logged
mcl_logging_structures (Structure generation logging) bool true
mcl_logging_structures (Structure generation logging) bool false
#Complete debug logging for mcl_signs events. Use this if you have issues with signs.
mcl_logging_mcl_signs (Complete debug logging for mcl_signs) bool false

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B