Merge branch 'master' into datapacks

This commit is contained in:
Elias Fleckenstein 2021-03-16 08:34:56 +01:00
commit c27dea59b0
46 changed files with 738 additions and 494 deletions

9
API.md

@ -39,7 +39,7 @@ A lot of things are possible by using one of the APIs in the mods. Note that not
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
## Mobs
* Mobs: `ENTITIES/mcl_mods`
* Mobs: `ENTITIES/mcl_mobs`
MineClone 2 uses its own mobs framework, called “Mobs Redo: MineClone 2 Edition” or “MRM” for short.
This is a fork of Mobs Redo [`mobs`] by TenPlus1.
@ -67,6 +67,9 @@ chances are good that it works out of the box.
* Get flowing direction of liquids: `CORE/flowlib`
* `on_walk_over` callback for nodes: `CORE/walkover`
* Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo`
* Explosion API
* Music discs API
* Flowers and flower pots
### Unstable APIs
The following APIs may be subject to change in future. You could already use these APIs but there will probably be breaking changes in the future, or the API is not as fleshed out as it should be. Use at your own risk!
@ -79,12 +82,10 @@ The following APIs may be subject to change in future. You could already use the
### Planned APIs
* Flowers
* Saplings and trees
* Custom banner patterns
* Custom dimensions
* Custom portals
* Music discs
* Dispenser and dropper support
* Proper sky and weather APIs
* Explosion API

@ -21,7 +21,7 @@ The basic digging time groups determine by which tools a node can be dug.
* `swordy=1`: Diggable by sword (any material), and this node is *not* a cobweb
* `swordy_cobweb=1`: Diggable by sword (any material), and this node is a cobweb
* `shearsy=1`: Diggable by shears, and this node is *not* wool
* `shearsy=wool=1`: Diggable by shears, and this node is wool
* `shearsy_wool=1`: Diggable by shears, and this node is wool
* `handy=1`: Breakable by hand and this node gives it useful drop when dug by hand. All nodes which are breakable by pickaxe, axe, shovel, sword or shears are also automatically breakable by hand, but not neccess
* `creative_breakable=1`: Block is breakable by hand in creative mode. This group is implied if the node belongs to any other digging group

@ -33,8 +33,7 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
keepInventory = false
# Performance settings
dedicated_server_step = 0.01
liquid_update = 0.25
dedicated_server_step = 0.001
abm_interval = 0.25
max_objects_per_block = 4096
max_packets_per_iteration = 10096

@ -1,3 +1,6 @@
local get_connected_players = minetest.get_connected_players
local clock = os.clock
controls = {}
controls.players = {}
@ -42,7 +45,7 @@ minetest.register_on_leaveplayer(function(player)
end)
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
local player_name = player:get_player_name()
local player_controls = player:get_player_control()
if controls.players[player_name] then
@ -53,15 +56,15 @@ minetest.register_globalstep(function(dtime)
for _, func in pairs(controls.registered_on_press) do
func(player, cname)
end
controls.players[player_name][cname] = {true, os.clock()}
controls.players[player_name][cname] = {true, clock()}
elseif cbool==true and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_hold) do
func(player, cname, os.clock()-controls.players[player_name][cname][2])
func(player, cname, clock()-controls.players[player_name][cname][2])
end
--Release a key
elseif cbool==false and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_release) do
func(player, cname, os.clock()-controls.players[player_name][cname][2])
func(player, cname, clock()-controls.players[player_name][cname][2])
end
controls.players[player_name][cname] = {false}
end

@ -18,6 +18,16 @@ local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
local S = minetest.get_translator("mcl_explosions")
local hash_node_position = minetest.hash_node_position
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_position_from_hash = minetest.get_position_from_hash
local get_node_drops = minetest.get_node_drops
local get_name_from_content_id = minetest.get_name_from_content_id
local get_voxel_manip = minetest.get_voxel_manip
local bulk_set_node = minetest.bulk_set_node
local check_for_falling = minetest.check_for_falling
local add_item = minetest.add_item
-- Saved sphere explosion shapes for various radiuses
local sphere_shapes = {}
@ -64,7 +74,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -79,7 +89,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -94,7 +104,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -156,7 +166,7 @@ end
-- inlined to avoid function calls and unnecessary table creation. This was
-- measured to give a significant performance increase.
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local vm = minetest.get_voxel_manip()
local vm = get_voxel_manip()
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
vector.add(pos, radius))
@ -207,7 +217,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
br = max_blast_resistance
end
local hash = minetest.hash_node_position(npos)
local hash = hash_node_position(npos)
rpos_x = rpos_x + STEP_LENGTH * rdir_x
rpos_y = rpos_y + STEP_LENGTH * rdir_y
@ -230,7 +240,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
-- Entities in radius of explosion
local punch_radius = 2 * strength
local objs = minetest.get_objects_inside_radius(pos, punch_radius)
local objs = get_objects_inside_radius(pos, punch_radius)
-- Trace rays for entity damage
for _, obj in pairs(objs) do
@ -359,46 +369,46 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local remove = true
if do_drop or on_blast ~= nil then
local npos = minetest.get_position_from_hash(hash)
local npos = get_position_from_hash(hash)
if on_blast ~= nil then
on_blast(npos, 1.0, do_drop)
remove = false
else
local name = minetest.get_name_from_content_id(data[idx])
local drop = minetest.get_node_drops(name, "")
local name = get_name_from_content_id(data[idx])
local drop = get_node_drops(name, "")
for _, item in ipairs(drop) do
if type(item) ~= "string" then
item = item:get_name() .. item:get_count()
end
minetest.add_item(npos, item)
add_item(npos, item)
end
end
end
if remove then
if mod_fire and fire and math.random(1, 3) == 1 then
table.insert(fires, minetest.get_position_from_hash(hash))
table.insert(fires, get_position_from_hash(hash))
else
table.insert(airs, minetest.get_position_from_hash(hash))
table.insert(airs, get_position_from_hash(hash))
end
end
end
-- We use bulk_set_node instead of LVM because we want to have on_destruct and
-- on_construct being called
if #airs > 0 then
minetest.bulk_set_node(airs, {name="air"})
bulk_set_node(airs, {name="air"})
end
if #fires > 0 then
minetest.bulk_set_node(fires, {name="mcl_fire:fire"})
bulk_set_node(fires, {name="mcl_fire:fire"})
end
-- Update falling nodes
for a=1, #airs do
local p = airs[a]
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
check_for_falling({x=p.x, y=p.y+1, z=p.z})
end
for f=1, #fires do
local p = fires[f]
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
check_for_falling({x=p.x, y=p.y+1, z=p.z})
end
-- Log explosion

@ -12,14 +12,15 @@ local function detach_driver(self)
if not self._driver then
return
end
if self._driver:is_player() then
mcl_player.player_attached[self._driver:get_player_name()] = nil
self._driver:set_detach()
self._driver:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
mcl_player.player_set_animation(self._driver, "stand" , 30)
end
mcl_player.player_attached[self._driver] = nil
local player = minetest.get_player_by_name(self._driver)
self._driver = nil
self._start_pos = nil
if player then
player:set_detach()
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
mcl_player.player_set_animation(player, "stand" , 30)
end
end
local function activate_tnt_minecart(self, timer)
@ -61,7 +62,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
on_rightclick = on_rightclick,
_driver = nil, -- player (or mob) who sits in and controls the minecart (only for minecart!)
_driver = nil, -- player who sits in and controls the minecart (only for minecart!)
_punched = false, -- used to re-send _velocity and position
_velocity = {x=0, y=0, z=0}, -- only used on punch
_start_pos = nil, -- Used to calculate distance for “On A Rail” achievement
@ -96,101 +97,111 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end
function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
-- Punch: Pick up minecart (unless TNT was ignited)
if self._boomtimer then return end
if self._driver then
detach_driver(self)
end
local pos = self.object:get_pos()
-- Disable detector rail
local rou_pos = vector.round(pos)
local node = minetest.get_node(rou_pos)
if node.name == "mcl_minecarts:detector_rail_on" then
local newnode = {name="mcl_minecarts:detector_rail", param2 = node.param2}
minetest.swap_node(rou_pos, newnode)
mesecon.receptor_off(rou_pos)
if not self._railtype then
local node = minetest.get_node(vector.floor(pos)).name
self._railtype = minetest.get_item_group(node, "connect_to_raillike")
end
-- Drop items and remove cart entity
if not minetest.is_creative_enabled(puncher:get_player_name()) then
for d=1, #drop do
minetest.add_item(self.object:get_pos(), drop[d])
if not puncher or not puncher:is_player() then
local cart_dir = mcl_minecarts:get_rail_direction(pos, {x=1, y=0, z=0}, nil, nil, self._railtype)
if vector.equals(cart_dir, {x=0, y=0, z=0}) then
return
end
elseif puncher and puncher:is_player() then
local inv = puncher:get_inventory()
for d=1, #drop do
if not inv:contains_item("main", drop[d]) then
inv:add_item("main", drop[d])
self._velocity = vector.multiply(cart_dir, 3)
self._old_pos = nil
self._punched = true
return
end
-- Punch+sneak: Pick up minecart (unless TNT was ignited)
if puncher:get_player_control().sneak and not self._boomtimer then
if self._driver then
if self._old_pos then
self.object:set_pos(self._old_pos)
end
detach_driver(self)
end
-- Disable detector rail
local rou_pos = vector.round(pos)
local node = minetest.get_node(rou_pos)
if node.name == "mcl_minecarts:detector_rail_on" then
local newnode = {name="mcl_minecarts:detector_rail", param2 = node.param2}
minetest.swap_node(rou_pos, newnode)
mesecon.receptor_off(rou_pos)
end
-- Drop items and remove cart entity
if not minetest.is_creative_enabled(puncher:get_player_name()) then
for d=1, #drop do
minetest.add_item(self.object:get_pos(), drop[d])
end
elseif puncher and puncher:is_player() then
local inv = puncher:get_inventory()
for d=1, #drop do
if not inv:contains_item("main", drop[d]) then
inv:add_item("main", drop[d])
end
end
end
self.object:remove()
return
end
self.object:remove()
local vel = self.object:get_velocity()
if puncher:get_player_name() == self._driver then
if math.abs(vel.x + vel.z) > 7 then
return
end
end
local punch_dir = mcl_minecarts:velocity_to_dir(puncher:get_look_dir())
punch_dir.y = 0
local cart_dir = mcl_minecarts:get_rail_direction(pos, punch_dir, nil, nil, self._railtype)
if vector.equals(cart_dir, {x=0, y=0, z=0}) then
return
end
time_from_last_punch = math.min(time_from_last_punch, tool_capabilities.full_punch_interval)
local f = 3 * (time_from_last_punch / tool_capabilities.full_punch_interval)
self._velocity = vector.multiply(cart_dir, f)
self._old_pos = nil
self._punched = true
end
cart.on_activate_by_rail = on_activate_by_rail
function cart:on_step(dtime)
local ctrl, player = nil, nil
local update = {}
local vel = self.object:get_velocity()
local pos, rou_pos, node
pos = self.object:get_pos()
rou_pos = vector.round(pos)
node = minetest.get_node(rou_pos)
local g = minetest.get_item_group(node.name, "connect_to_raillike")
if self._driver and self._driver:is_player() then
player = self._driver
ctrl = player:get_player_control()
-- player detach
if ctrl.sneak then
detach_driver(self)
return
end
if g == self._railtype then
if ctrl.right then
local c = vector.multiply(minetest.yaw_to_dir(self._driver:get_look_horizontal()-1.57), 0.2)
self.object:set_velocity(vector.add(vel, {x=c.x, y=0, z=c.z}))
end
if ctrl.left then
local c = vector.multiply(minetest.yaw_to_dir(self._driver:get_look_horizontal()+1.57), 0.2)
self.object:set_velocity(vector.add(vel, {x=c.x, y=0, z=c.z}))
end
if ctrl.up then
local c = vector.multiply(self._driver:get_look_dir(), 0.2)
self.object:set_velocity(vector.add(vel, {x=c.x, y=0, z=c.z}))
end
if ctrl.down then
local c = vector.multiply(self._driver:get_look_dir(), 0.2)
self.object:set_velocity(vector.subtract(vel, {x=c.x, y=0, z=c.z}))
if self._driver then
player = minetest.get_player_by_name(self._driver)
if player then
ctrl = player:get_player_control()
-- player detach
if ctrl.sneak then
detach_driver(self)
return
end
end
end
local vel = self.object:get_velocity()
local update = {}
if self._last_float_check == nil then
self._last_float_check = 0
else
self._last_float_check = self._last_float_check + dtime
end
local pos, rou_pos, node
-- Drop minecart if it isn't on a rail anymore
if self._last_float_check >= mcl_minecarts.check_float_time then
for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.3)) do
if object ~= self.object then
local mob = object:get_luaentity()
if mob then mob = mob._cmi_is_mob == true end
if mob and (not self._driver) and not object:get_attach() then
self._driver = object
object:set_attach(self.object, "", {x=0, y=-1.75, z=-2}, {x=0, y=0, z=0})
mobs:set_animation(self.object, "stand")
return
end
end
end
pos = self.object:get_pos()
rou_pos = vector.round(pos)
node = minetest.get_node(rou_pos)
local g = minetest.get_item_group(node.name, "connect_to_raillike")
if g ~= self._railtype and self._railtype ~= nil then
-- Detach driver
if player then
@ -289,12 +300,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end
end
if update.vel then
if self._punched then
vel = vector.add(vel, self._velocity)
if vel.x>8 then vel.x = 8 end
if vel.x<-8 then vel.x = -8 end
if vel.z>8 then vel.z = 8 end
if vel.z<-8 then vel.z = -8 end
self.object:set_velocity(vel)
self._old_dir.y = 0
elseif vector.equals(vel, {x=0, y=0, z=0}) and (not has_fuel) then
@ -619,14 +626,17 @@ register_minecart(
"mcl_minecarts_minecart_normal.png",
{"mcl_minecarts:minecart"},
function(self, clicker)
if not clicker or not clicker:is_player() then return end
if clicker == self._driver then
local name = clicker:get_player_name()
if not clicker or not clicker:is_player() then
return
end
local player_name = clicker:get_player_name()
if self._driver and player_name == self._driver then
detach_driver(self)
else
local name = clicker:get_player_name()
self._driver = clicker
elseif not self._driver then
self._driver = player_name
self._start_pos = self.object:get_pos()
mcl_player.player_attached[name] = true
mcl_player.player_attached[player_name] = true
clicker:set_attach(self.object, "", {x=0, y=-1.75, z=-2}, {x=0, y=0, z=0})
mcl_player.player_attached[name] = true
minetest.after(0.2, function(name)
@ -637,7 +647,6 @@ register_minecart(
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
end
end, name)
clicker:set_look_horizontal(self.object:get_yaw())
end
end, activate_normal_minecart
)

@ -451,6 +451,6 @@ mobs:spawn_specific("mobs_mc:donkey", mobs_mc.spawn.grassland_savanna, {"air"},
-- spawn eggs
mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
--mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

@ -11,6 +11,18 @@ of the license, or (at your option) any later version.
local S = minetest.get_translator("lightning")
local has_mcl_death_msg = minetest.get_modpath("mcl_death_messages")
local get_connected_players = minetest.get_connected_players
local line_of_sight = minetest.line_of_sight
local get_node = minetest.get_node
local set_node = minetest.set_node
local sound_play = minetest.sound_play
local add_particlespawner = minetest.add_particlespawner
local after = minetest.after
local add_entity = minetest.add_entity
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_item_group = minetest.get_item_group
lightning = {}
lightning.interval_low = 17
@ -45,7 +57,7 @@ minetest.register_globalstep(revertsky)
-- select a random strike point, midpoint
local function choose_pos(pos)
if not pos then
local playerlist = minetest.get_connected_players()
local playerlist = get_connected_players()
local playercount = table.getn(playerlist)
-- nobody on
@ -67,14 +79,14 @@ local function choose_pos(pos)
pos.z = math.floor(pos.z - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
end
local b, pos2 = minetest.line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
local b, pos2 = line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
-- nothing but air found
if b then
return nil, nil
end
local n = minetest.get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
local n = get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
if n.name == "air" or n.name == "ignore" then
return nil, nil
end
@ -87,7 +99,7 @@ end
-- * returns: bool - success if a strike happened
lightning.strike = function(pos)
if lightning.auto then
minetest.after(rng:next(lightning.interval_low, lightning.interval_high), lightning.strike)
after(rng:next(lightning.interval_low, lightning.interval_high), lightning.strike)
end
local pos2
@ -97,7 +109,7 @@ lightning.strike = function(pos)
return false
end
minetest.add_particlespawner({
add_particlespawner({
amount = 1,
time = 0.2,
-- make it hit the top of a block exactly with the bottom
@ -120,16 +132,16 @@ lightning.strike = function(pos)
glow = minetest.LIGHT_MAX,
})
minetest.sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
-- damage nearby objects, transform mobs
local objs = minetest.get_objects_inside_radius(pos2, 3.5)
local objs = get_objects_inside_radius(pos2, 3.5)
for o=1, #objs do
local obj = objs[o]
local lua = obj:get_luaentity()
if obj:is_player() then
-- Player damage
if minetest.get_modpath("mcl_death_messages") then
if has_mcl_death_msg then
mcl_death_messages.player_damage(obj, S("@1 was struck by lightning.", obj:get_player_name()))
end
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" })
@ -139,7 +151,7 @@ lightning.strike = function(pos)
if lua.name == "mobs_mc:pig" then
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:pigman")
obj = add_entity(pos2, "mobs_mc:pigman")
obj:set_yaw(rot)
-- mooshroom: toggle color red/brown (no damage)
elseif lua.name == "mobs_mc:mooshroom" then
@ -163,7 +175,7 @@ lightning.strike = function(pos)
elseif lua.name == "mobs_mc:creeper" then
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:creeper_charged")
obj = add_entity(pos2, "mobs_mc:creeper_charged")
obj:set_yaw(rot)
-- Other mobs: Just damage
else
@ -172,7 +184,7 @@ lightning.strike = function(pos)
end
end
local playerlist = minetest.get_connected_players()
local playerlist = get_connected_players()
for i = 1, #playerlist do
local player = playerlist[i]
local sky = {}
@ -197,25 +209,25 @@ lightning.strike = function(pos)
if rng:next(1,100) <= 3 then
skeleton_lightning = true
end
if minetest.get_item_group(minetest.get_node({x = pos2.x, y = pos2.y - 1, z = pos2.z}).name, "liquid") < 1 then
if minetest.get_node(pos2).name == "air" then
if get_item_group(get_node({x = pos2.x, y = pos2.y - 1, z = pos2.z}).name, "liquid") < 1 then
if get_node(pos2).name == "air" then
-- Low chance for a lightning to spawn skeleton horse + skeletons
if skeleton_lightning then
minetest.add_entity(pos2, "mobs_mc:skeleton_horse")
add_entity(pos2, "mobs_mc:skeleton_horse")
local angle, posadd
angle = math.random(0, math.pi*2)
for i=1,3 do
posadd = {x=math.cos(angle),y=0,z=math.sin(angle)}
posadd = vector.normalize(posadd)
local mob = minetest.add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
mob:set_yaw(angle-math.pi/2)
angle = angle + (math.pi*2) / 3
end
-- Cause a fire
else
minetest.set_node(pos2, {name = "mcl_fire:fire"})
set_node(pos2, {name = "mcl_fire:fire"})
end
end
end
@ -223,9 +235,9 @@ lightning.strike = function(pos)
end
-- if other mods disable auto lightning during initialization, don't trigger the first lightning.
minetest.after(5, function(dtime)
after(5, function(dtime)
if lightning.auto then
minetest.after(rng:next(lightning.interval_low,
after(rng:next(lightning.interval_low,
lightning.interval_high), lightning.strike)
end
end)

@ -1,6 +1,14 @@
local S = minetest.get_translator("mcl_void_damage")
local enable_damage = minetest.settings:get_bool("enable_damage")
local pos_to_dim = mcl_worlds.pos_to_dimension
local dim_change = mcl_worlds.dimension_change
local is_in_void = mcl_worlds.is_in_void
local get_spawn_pos = mcl_spawn.get_player_spawn_pos
local death_msg = mcl_death_messages.player_damage
local send_chat = minetest.chat_send_player
local get_connected = minetest.get_connected_players
local voidtimer = 0
local VOID_DAMAGE_FREQ = 0.5
local VOID_DAMAGE = 4
@ -33,7 +41,7 @@ minetest.register_on_mods_loaded(function()
self._void_timer = 0
local pos = obj:get_pos()
local void, void_deadly = mcl_worlds.is_in_void(pos)
local void, void_deadly = is_in_void(pos)
if void_deadly then
local ent = obj:get_luaentity()
obj:remove()
@ -51,11 +59,11 @@ minetest.register_globalstep(function(dtime)
if voidtimer > VOID_DAMAGE_FREQ then
voidtimer = 0
local enable_damage = minetest.settings:get_bool("enable_damage")
local players = minetest.get_connected_players()
local players = get_connected()
for p=1, #players do
local player = players[p]
local pos = player:get_pos()
local void, void_deadly = mcl_worlds.is_in_void(pos)
local void, void_deadly = is_in_void(pos)
if void_deadly then
local immortal_val = player:get_armor_groups().immortal
local is_immortal = false
@ -65,14 +73,14 @@ minetest.register_globalstep(function(dtime)
if is_immortal or not enable_damage then
-- If damage is disabled, we can't kill players.
-- So we just teleport the player back to spawn.
local spawn = mcl_spawn.get_player_spawn_pos(player)
local spawn = get_spawn_pos(player)
player:set_pos(spawn)
mcl_worlds.dimension_change(player, mcl_worlds.pos_to_dimension(spawn))
minetest.chat_send_player(player:get_player_name(), S("The void is off-limits to you!"))
dim_change(player, pos_to_dim(spawn))
send_chat(player:get_player_name(), S("The void is off-limits to you!"))
elseif enable_damage and not is_immortal then
-- Damage enabled, not immortal: Deal void damage (4 HP / 0.5 seconds)
if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 fell into the endless void.", player:get_player_name()))
death_msg(player, S("@1 fell into the endless void.", player:get_player_name()))
player:set_hp(player:get_hp() - VOID_DAMAGE)
end
end

@ -511,9 +511,9 @@ local function update_health(player)
end
-- update built-in HUD bars
local function update_hud(player)
local function update_hud(player, has_damage)
if not player_exists(player) then return end
if minetest.settings:get_bool("enable_damage") then
if has_damage then
if hb.settings.forceload_default_hudbars then
hb.unhide_hudbar(player, "health")
end
@ -564,10 +564,11 @@ minetest.register_globalstep(function(dtime)
if main_timer > hb.settings.tick or timer > 4 then
if main_timer > hb.settings.tick then main_timer = 0 end
-- only proceed if damage is enabled
if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then
local has_dmg = minetest.settings:get_bool("enable_damage")
if has_dmg or hb.settings.forceload_default_hudbars then
for _, player in pairs(hb.players) do
-- update all hud elements
update_hud(player)
update_hud(player, has_dmg)
end
end
end

@ -184,7 +184,7 @@ minetest.register_on_joinplayer(function(player)
hud_elem_type = "text", position = {x=0.5, y=1},
name = "xp_level", text = tostring(temp_pool.level),
number = 0x80FF20,
offset = {x = 0, y = -(48 + 24 + 24)},
offset = {x = 0, y = -(48 + 24 + 24)},
z_index = 12,
})
end)

@ -101,14 +101,14 @@ local function update_anvil_slots(meta)
end
local can_combine = mcl_enchanting.combine(input1, input2)
if can_combine then
-- Add tool health together plus a small bonus
if def1.type == "tool" and def2.type == "tool" then
local new_wear = calculate_repair(input1:get_wear(), input2:get_wear(), SAME_TOOL_REPAIR_BOOST)
input1:set_wear(new_wear)
end
name_item = input1
new_output = name_item
-- Tool + repair item
@ -318,11 +318,11 @@ local anvildef = {
_mcl_after_falling = damage_anvil_by_falling,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos)
local meta2 = meta
local meta = minetest.get_meta(pos)
local meta2 = meta:to_table()
meta:from_table(oldmetadata)
drop_anvil_items(pos, meta)
meta:from_table(meta2:to_table())
meta:from_table(meta2)
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local name = player:get_player_name()

@ -35,53 +35,13 @@ S("Arrows might get stuck on solid blocks and can be retrieved again. They are a
end,
})
-- This is a fake node, used as model for the arrow entity.
-- It's not supposed to be usable as item or real node.
-- TODO: Use a proper mesh for the arrow entity
minetest.register_node("mcl_bows:arrow_box", {
drawtype = "nodebox",
is_ground_content = false,
node_box = {
type = "fixed",
fixed = {
-- Shaft
{-6.5/17, -1.5/17, -1.5/17, -4.5/17, 1.5/17, 1.5/17},
{-4.5/17, -0.5/17, -0.5/17, 5.5/17, 0.5/17, 0.5/17},
{5.5/17, -1.5/17, -1.5/17, 6.5/17, 1.5/17, 1.5/17},
-- Tip
{-4.5/17, 2.5/17, 2.5/17, -3.5/17, -2.5/17, -2.5/17},
{-8.5/17, 0.5/17, 0.5/17, -6.5/17, -0.5/17, -0.5/17},
-- Fletching
{6.5/17, 1.5/17, 1.5/17, 7.5/17, 2.5/17, 2.5/17},
{7.5/17, -2.5/17, 2.5/17, 6.5/17, -1.5/17, 1.5/17},
{7.5/17, 2.5/17, -2.5/17, 6.5/17, 1.5/17, -1.5/17},
{6.5/17, -1.5/17, -1.5/17, 7.5/17, -2.5/17, -2.5/17},
{7.5/17, 2.5/17, 2.5/17, 8.5/17, 3.5/17, 3.5/17},
{8.5/17, -3.5/17, 3.5/17, 7.5/17, -2.5/17, 2.5/17},
{8.5/17, 3.5/17, -3.5/17, 7.5/17, 2.5/17, -2.5/17},
{7.5/17, -2.5/17, -2.5/17, 8.5/17, -3.5/17, -3.5/17},
}
},
tiles = {"mcl_bows_arrow.png^[transformFX", "mcl_bows_arrow.png^[transformFX", "mcl_bows_arrow_back.png", "mcl_bows_arrow_front.png", "mcl_bows_arrow.png", "mcl_bows_arrow.png^[transformFX"},
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false,
paramtype = "light",
paramtype2 = "facedir",
sunlight_propagates = true,
groups = {not_in_creative_inventory=1, dig_immediate=3},
drop = "",
node_placement_prediction = "",
on_construct = function(pos)
minetest.log("error", "[mcl_bows] Trying to construct mcl_bows:arrow_box at "..minetest.pos_to_string(pos))
minetest.remove_node(pos)
end,
})
local ARROW_ENTITY={
physical = true,
visual = "wielditem",
visual_size = {x=0.4, y=0.4},
textures = {"mcl_bows:arrow_box"},
pointable = false,
visual = "mesh",
mesh = "mcl_bows_arrow.obj",
visual_size = {x=-1, y=1},
textures = {"mcl_bows_arrow.png"},
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
collide_with_objects = false,
_fire_damage_resistant = true,
@ -185,6 +145,25 @@ ARROW_ENTITY.on_step = function(self, dtime)
-- Check for object "collision". Done every tick (hopefully this is not too stressing)
else
if self._damage >= 9 then
minetest.add_particlespawner({
amount = 1,
time = .001,
minpos = pos,
maxpos = pos,
minvel = vector.new(-0.1,-0.1,-0.1),
maxvel = vector.new(0.1,0.1,0.1),
minexptime = 0.5,
maxexptime = 0.5,
minsize = 2,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mobs_mc_arrow_particle.png",
glow = 1,
})
end
-- We just check for any hurtable objects nearby.
-- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often.

@ -0,0 +1,56 @@
# Blender v2.91.0 OBJ File: ''
# www.blender.org
mtllib mcl_bows_arrow.mtl
o Plane
v -3.782006 -1.443249 0.000500
v -3.782006 1.444249 0.000500
v 3.782006 1.444249 0.000500
v 3.782006 -1.443249 0.000500
v 3.331104 1.069925 1.085017
v 3.331104 -1.100076 1.085017
v 3.331104 1.069925 -1.064830
v 3.331104 -1.100076 -1.064829
v 3.782006 0.001000 1.443749
v 3.782006 0.001000 -1.443750
v -3.782006 0.001000 -1.443749
v -3.782006 0.001000 1.443750
v 3.782006 0.000000 -1.443750
v 3.782006 0.000000 1.443749
v -3.782006 0.000000 1.443750
v -3.782006 0.000000 -1.443749
v 3.782006 1.444249 -0.000500
v 3.782006 -1.443249 -0.000500
v -3.782006 -1.443249 -0.000500
v -3.782006 1.444249 -0.000500
vt 0.000000 0.300000
vt 0.000000 0.700000
vt 1.000000 0.700000
vt 1.000000 0.300000
vt -0.007553 -0.000373
vt 0.296712 -0.000373
vt 0.296712 0.298611
vt -0.007553 0.298611
vt 0.000000 0.300000
vt 1.000000 0.300000
vt 1.000000 0.700000
vt 0.000000 0.700000
vt 0.000000 0.300000
vt 1.000000 0.300000
vt 1.000000 0.700000
vt 0.000000 0.700000
vt 0.000000 0.300000
vt 0.000000 0.700000
vt 1.000000 0.700000
vt 1.000000 0.300000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
usemtl Material.002
s off
f 17/1/1 18/2/1 19/3/1 20/4/1
f 8/5/2 7/6/2 5/7/2 6/8/2
f 10/9/3 11/10/3 12/11/3 9/12/3
f 3/13/4 2/14/4 1/15/4 4/16/4
f 13/17/5 14/18/5 15/19/5 16/20/5

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 260 B

@ -0,0 +1,21 @@
# mcl_buckets
Add an API to register buckets to mcl
## mcl_buckets.register_liquid(def)
Register a new liquid
Accept folowing params:
* source_place = a string or function.
* string: name of the node to place
* function(pos): will returns name of the node to place with pos being the placement position
* source_take = table of liquid source node names to take
* itemname = itemstring of the new bucket item (or nil if liquid is not takeable)
* inventory_image = texture of the new bucket item (ignored if itemname == nil)
* name = user-visible bucket description
* longdesc = long explanatory description (for help)
* usagehelp = short usage explanation (for help)
* tt_help = very short tooltip help
* extra_check(pos, placer) = optional function(pos) which can returns false to avoid placing the liquid. Placer is object/player who is placing the liquid, can be nil.
* groups = optional list of item groups
This function can be called from any mod (which depends on this one)

@ -1,4 +1,5 @@
local S = minetest.get_translator("mcl_buckets")
local modpath = minetest.get_modpath(minetest.get_current_modname())
-- Minetest 0.4 mod: bucket
-- See README.txt for licensing and other information.
@ -45,43 +46,27 @@ local place_liquid = function(pos, itemstring)
minetest.add_node(pos, {name=itemstring, param2=fullness})
end
-- Register a new liquid
-- source_place = a string or function.
-- * string: name of the node to place
-- * function(pos): will returns name of the node to place with pos being the placement position
-- source_take = table of liquid source node names to take
-- itemname = itemstring of the new bucket item (or nil if liquid is not takeable)
-- inventory_image = texture of the new bucket item (ignored if itemname == nil)
-- name = user-visible bucket description
-- longdesc = long explanatory description (for help)
-- usagehelp = short usage explanation (for help)
-- tt_help = very short tooltip help
-- extra_check(pos, placer) = optional function(pos) which can returns false to avoid placing the liquid.
-- placer is object/player who is placing the liquid, can be nil
-- groups = optional list of item groups
--
-- This function can be called from any mod (which depends on this one)
function mcl_buckets.register_liquid(source_place, source_take, itemname, inventory_image, name, longdesc, usagehelp, tt_help, extra_check, groups)
for i=1, #source_take do
mcl_buckets.liquids[source_take[i]] = {
source_place = source_place,
source_take = source_take[i],
itemname = itemname,
function mcl_buckets.register_liquid(def)
for i=1, #def.source_take do
mcl_buckets.liquids[def.source_take[i]] = {
source_place = def.source_place,
source_take = def.source_take[i],
itemname = def.itemname,
}
if type(source_place) == "string" then
mcl_buckets.liquids[source_place] = mcl_buckets.liquids[source_take[i]]
if type(def.source_place) == "string" then
mcl_buckets.liquids[def.source_place] = mcl_buckets.liquids[def.source_take[i]]
end
end
if itemname ~= nil then
minetest.register_craftitem(itemname, {
description = name,
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usagehelp,
_tt_help = tt_help,
inventory_image = inventory_image,
if def.itemname ~= nil then
minetest.register_craftitem(def.itemname, {
description = def.name,
_doc_items_longdesc = def.longdesc,
_doc_items_usagehelp = def.usagehelp,
_tt_help = def.tt_help,
inventory_image = def.inventory_image,
stack_max = 16,
groups = groups,
groups = def.groups,
on_place = function(itemstack, user, pointed_thing)
-- Must be pointing to node
if pointed_thing.type ~= "node" then
@ -99,10 +84,10 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
end
local node_place
if type(source_place) == "function" then
node_place = source_place(place_pos)
if type(def.source_place) == "function" then
node_place = def.source_place(place_pos)
else
node_place = source_place
node_place = def.source_place
end
-- Check if pointing to a buildable node
local item = itemstack:get_name()
@ -163,17 +148,17 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
local iname = stack:get_name()
local buildable = minetest.registered_nodes[dropnode.name].buildable_to
local buildable = minetest.registered_nodes[dropnode.name].buildable_to or dropnode.name == "mcl_portals:portal"
if extra_check and extra_check(droppos, nil) == false then
if def.extra_check and def.extra_check(droppos, nil) == false then
-- Fail placement of liquid
elseif buildable then
-- buildable; replace the node
local node_place
if type(source_place) == "function" then
node_place = source_place(droppos)
if type(def.source_place) == "function" then
node_place = def.source_place(droppos)
else
node_place = source_place
node_place = def.source_place
end
place_liquid(droppos, node_place)
stack:set_name("mcl_buckets:bucket_empty")
@ -292,114 +277,4 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", {
end,
})
if mod_mcl_core then
-- Lava bucket
mcl_buckets.register_liquid(
function(pos)
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
return "mcl_nether:nether_lava_source"
else
return "mcl_core:lava_source"
end
end,
{"mcl_core:lava_source", "mcl_nether:nether_lava_source"},
"mcl_buckets:bucket_lava",
"bucket_lava.png",
S("Lava Bucket"),
S("A bucket can be used to collect and release liquids. This one is filled with hot lava, safely contained inside. Use with caution."),
S("Get in a safe distance and place the bucket to empty it and create a lava source at this spot. Don't burn yourself!"),
S("Places a lava source")
)
-- Water bucket
mcl_buckets.register_liquid(
"mcl_core:water_source",
{"mcl_core:water_source"},
"mcl_buckets:bucket_water",
"bucket_water.png",
S("Water Bucket"),
S("A bucket can be used to collect and release liquids. This one is filled with water."),
S("Place it to empty the bucket and create a water source."),
S("Places a water source"),
function(pos, placer)
-- Check protection
local placer_name = ""
if placer ~= nil then
placer_name = placer:get_player_name()
end
if placer and minetest.is_protected(pos, placer_name) then
minetest.record_protection_violation(pos, placer_name)
return false
end
local nn = minetest.get_node(pos).name
-- Pour water into cauldron
if minetest.get_item_group(nn, "cauldron") ~= 0 then
-- Put water into cauldron
if nn ~= "mcl_cauldrons:cauldron_3" then
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
end
sound_place("mcl_core:water_source", pos)
return false
-- Evaporate water if used in Nether (except on cauldron)
else
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
return false
end
end
end,
{ water_bucket = 1 }
)
end
if mod_mclx_core then
-- River water bucket
mcl_buckets.register_liquid(
"mclx_core:river_water_source",
{"mclx_core:river_water_source"},
"mcl_buckets:bucket_river_water",
"bucket_river_water.png",
S("River Water Bucket"),
S("A bucket can be used to collect and release liquids. This one is filled with river water."),
S("Place it to empty the bucket and create a river water source."),
S("Places a river water source"),
function(pos, placer)
-- Check protection
local placer_name = ""
if placer ~= nil then
placer_name = placer:get_player_name()
end
if placer and minetest.is_protected(pos, placer_name) then
minetest.record_protection_violation(pos, placer_name)
return false
end
local nn = minetest.get_node(pos).name
-- Pour into cauldron
if minetest.get_item_group(nn, "cauldron") ~= 0 then
-- Put water into cauldron
if nn ~= "mcl_cauldrons:cauldron_3r" then
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
end
sound_place("mcl_core:water_source", pos)
return false
else
-- Evaporate water if used in Nether (except on cauldron)
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
return false
end
end
end,
{ water_bucket = 1 }
)
end
minetest.register_craft({
type = "fuel",
recipe = "mcl_buckets:bucket_lava",
burntime = 1000,
replacements = {{"mcl_buckets:bucket_lava", "mcl_buckets:bucket_empty"}},
})
dofile(modpath.."/register.lua")

@ -0,0 +1,115 @@
local S = minetest.get_translator(minetest.get_current_modname())
local mod_mcl_core = minetest.get_modpath("mcl_core")
local mod_mclx_core = minetest.get_modpath("mclx_core")
if mod_mcl_core then
-- Lava bucket
mcl_buckets.register_liquid({
source_place = function(pos)
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
return "mcl_nether:nether_lava_source"
else
return "mcl_core:lava_source"
end
end,
source_take = {"mcl_core:lava_source", "mcl_nether:nether_lava_source"},
itemname = "mcl_buckets:bucket_lava",
inventory_image = "bucket_lava.png",
name = S("Lava Bucket"),
longdesc = S("A bucket can be used to collect and release liquids. This one is filled with hot lava, safely contained inside. Use with caution."),
usagehelp = S("Get in a safe distance and place the bucket to empty it and create a lava source at this spot. Don't burn yourself!"),
tt_help = S("Places a lava source")
})
-- Water bucket
mcl_buckets.register_liquid({
source_place = "mcl_core:water_source",
source_take = {"mcl_core:water_source"},
itemname = "mcl_buckets:bucket_water",
inventory_image = "bucket_water.png",
name = S("Water Bucket"),
longdesc = S("A bucket can be used to collect and release liquids. This one is filled with water."),
usagehelp = S("Place it to empty the bucket and create a water source."),
tt_help = S("Places a water source"),
extra_check = function(pos, placer)
-- Check protection
local placer_name = ""
if placer ~= nil then
placer_name = placer:get_player_name()
end
if placer and minetest.is_protected(pos, placer_name) then
minetest.record_protection_violation(pos, placer_name)
return false
end
local nn = minetest.get_node(pos).name
-- Pour water into cauldron
if minetest.get_item_group(nn, "cauldron") ~= 0 then
-- Put water into cauldron
if nn ~= "mcl_cauldrons:cauldron_3" then
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3"})
end
sound_place("mcl_core:water_source", pos)
return false
-- Evaporate water if used in Nether (except on cauldron)
else
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
return false
end
end
end,
groups = { water_bucket = 1 },
})
end
if mod_mclx_core then
-- River water bucket
mcl_buckets.register_liquid({
source_place = "mclx_core:river_water_source",
source_take = {"mclx_core:river_water_source"},
itemname = "mcl_buckets:bucket_river_water",
inventory_image = "bucket_river_water.png",
name = S("River Water Bucket"),
longdesc = S("A bucket can be used to collect and release liquids. This one is filled with river water."),
usagehelp = S("Place it to empty the bucket and create a river water source."),
tt_help = S("Places a river water source"),
extra_check = function(pos, placer)
-- Check protection
local placer_name = ""
if placer ~= nil then
placer_name = placer:get_player_name()
end
if placer and minetest.is_protected(pos, placer_name) then
minetest.record_protection_violation(pos, placer_name)
return false
end
local nn = minetest.get_node(pos).name
-- Pour into cauldron
if minetest.get_item_group(nn, "cauldron") ~= 0 then
-- Put water into cauldron
if nn ~= "mcl_cauldrons:cauldron_3r" then
minetest.set_node(pos, {name="mcl_cauldrons:cauldron_3r"})
end
sound_place("mcl_core:water_source", pos)
return false
else
-- Evaporate water if used in Nether (except on cauldron)
local dim = mcl_worlds.pos_to_dimension(pos)
if dim == "nether" then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
return false
end
end
end,
groups = { water_bucket = 1 },
})
end
minetest.register_craft({
type = "fuel",
recipe = "mcl_buckets:bucket_lava",
burntime = 1000,
replacements = {{"mcl_buckets:bucket_lava", "mcl_buckets:bucket_empty"}},
})

@ -1,7 +0,0 @@
mcl_core
mcl_sounds
mcl_hunger
mcl_buckets
mcl_farming
mcl_mobitems
doc?

@ -1 +1,4 @@
name = mcl_cake
description = Add cakes to mcl
depends = mcl_core, mcl_sounds, mcl_hunger, mcl_buckets, mcl_farming, mcl_mobitems
optional_depends = doc

@ -1,3 +0,0 @@
mcl_sounds
mcl_core
doc?

@ -1 +0,0 @@
Cocoa pods which grow at jungle trees. Does not include cocoa beans.

@ -3,10 +3,7 @@ local S = minetest.get_translator("mcl_cocoas")
mcl_cocoas = {}
-- Place cocoa
function mcl_cocoas.place(itemstack, placer, pointed_thing, plantname)
local pt = pointed_thing
function mcl_cocoas.place(itemstack, placer, pt, plantname)
-- check if pointing at a node
if not pt or pt.type ~= "node" then
return

@ -1 +1,4 @@
name = mcl_cocoas
description = Cocoa pods which grow at jungle trees. Does not include cocoa beans.
depends = mcl_sounds, mcl_core
optional_depends = doc

@ -1,3 +0,0 @@
mcl_init
mcl_formspec
mcl_sounds

@ -1 +0,0 @@
Adds a crafting table.

@ -1,5 +1,36 @@
local S = minetest.get_translator("mcl_crafting_table")
local formspec_escape = minetest.formspec_escape
local show_formspec = minetest.show_formspec
local C = minetest.colorize
local text_color = mcl_colors.BLACK or "#313131"
local itemslot_bg = mcl_formspec.get_itemslot_bg
mcl_crafting_table = {}
function mcl_crafting_table.show_crafting_form(player)
player:get_inventory():set_width("craft", 3)
player:get_inventory():set_size("craft", 9)
show_formspec(player:get_player_name(), "main",
"size[9,8.75]"..
"image[4.7,1.5;1.5,1;gui_crafting_arrow.png]"..
"label[0,4;"..formspec_escape(C(text_color, S("Inventory"))).."]".. --"#313131"
"list[current_player;main;0,4.5;9,3;9]"..
itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
itemslot_bg(0,7.74,9,1)..
"label[1.75,0;"..formspec_escape(C(text_color, S("Crafting"))).."]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
itemslot_bg(1.75,0.5,3,3)..
"list[current_player;craftpreview;6.1,1.5;1,1;]"..
itemslot_bg(6.1,1.5,1,1)..
"image_button[0.75,1.5;1,1;craftguide_book.png;__mcl_craftguide;]"..
"tooltip[__mcl_craftguide;"..formspec_escape(S("Recipe book")).."]"..
"listring[current_player;main]"..
"listring[current_player;craft]"
)
end
local show_crafting_form = mcl_crafting_table.show_crafting_form --cache function for better performances
minetest.register_node("mcl_crafting_table:crafting_table", {
description = S("Crafting Table"),
_tt_help = S("3×3 crafting grid"),
@ -12,27 +43,7 @@ minetest.register_node("mcl_crafting_table:crafting_table", {
paramtype2 = "facedir",
groups = {handy=1,axey=1, deco_block=1, material_wood=1,flammable=-1},
on_rightclick = function(pos, node, player, itemstack)
player:get_inventory():set_width("craft", 3)
player:get_inventory():set_size("craft", 9)
local form = "size[9,8.75]"..
"image[4.7,1.5;1.5,1;gui_crafting_arrow.png]"..
"label[0,4;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,4.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"label[1.75,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Crafting"))).."]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
mcl_formspec.get_itemslot_bg(1.75,0.5,3,3)..
"list[current_player;craftpreview;6.1,1.5;1,1;]"..
mcl_formspec.get_itemslot_bg(6.1,1.5,1,1)..
"image_button[0.75,1.5;1,1;craftguide_book.png;__mcl_craftguide;]"..
"tooltip[__mcl_craftguide;"..minetest.formspec_escape(S("Recipe book")).."]"..
"listring[current_player;main]"..
"listring[current_player;craft]"
minetest.show_formspec(player:get_player_name(), "main", form)
show_crafting_form(player)
end,
sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_blast_resistance = 2.5,

@ -1 +1,4 @@
name = mcl_crafting_table
description = Adds a crafting table.
depends = mcl_init, mcl_formspec, mcl_sounds
optional_depends = mcl_colors

@ -22,7 +22,7 @@ end
function mcl_enchanting.load_enchantments(itemstack, enchantments)
if not mcl_enchanting.is_book(itemstack:get_name()) then
mcl_enchanting.unload_enchantments(itemstack)
mcl_enchanting.unload_enchantments(itemstack)
for enchantment, level in pairs(enchantments or mcl_enchanting.get_enchantments(itemstack)) do
local enchantment_def = mcl_enchanting.enchantments[enchantment]
if enchantment_def.on_enchant then
@ -159,7 +159,7 @@ function mcl_enchanting.combine(itemstack, combine_with)
local itemname = itemstack:get_name()
local combine_name = combine_with:get_name()
local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname)
if enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then
if not enchanted_itemname or enchanted_itemname ~= mcl_enchanting.get_enchanted_itemstring(combine_name) and not mcl_enchanting.is_book(combine_name) then
return false
end
local enchantments = mcl_enchanting.get_enchantments(itemstack)

@ -1,5 +0,0 @@
mcl_core
mcl_worlds
mcl_sounds
mcl_particles
mcl_portals?

@ -1,5 +1,8 @@
local S = minetest.get_translator("mcl_fire")
local get_node = minetest.get_node
local add_entity = minetest.add_entity
-- Fire Charge
minetest.register_craftitem("mcl_fire:fire_charge", {
description = S("Fire Charge"),
@ -11,7 +14,7 @@ minetest.register_craftitem("mcl_fire:fire_charge", {
stack_max = 64,
on_place = function(itemstack, user, pointed_thing)
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under)
local node = get_node(pointed_thing.under)
if user and not user:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
@ -45,7 +48,7 @@ minetest.register_craftitem("mcl_fire:fire_charge", {
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Throw fire charge
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51))
local fireball = minetest.add_entity(shootpos, "mobs_mc:blaze_fireball")
local fireball = add_entity(shootpos, "mobs_mc:blaze_fireball")
local ent = fireball:get_luaentity()
ent._shot_from_dispenser = true
local v = ent.velocity or 1

@ -1,4 +1,6 @@
local S = minetest.get_translator("mcl_fire")
local get_node = minetest.get_node
local add_node = minetest.add_node
-- Flint and Steel
minetest.register_tool("mcl_fire:flint_and_steel", {
@ -12,7 +14,7 @@ minetest.register_tool("mcl_fire:flint_and_steel", {
groups = { tool = 1, },
on_place = function(itemstack, user, pointed_thing)
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under)
local node = get_node(pointed_thing.under)
if user and not user:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
@ -33,7 +35,7 @@ minetest.register_tool("mcl_fire:flint_and_steel", {
)
local used = false
if pointed_thing.type == "node" then
local nodedef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
local nodedef = minetest.registered_nodes[get_node(pointed_thing.under).name]
if nodedef and nodedef._on_ignite then
local overwrite = nodedef._on_ignite(user, pointed_thing)
if not overwrite then
@ -56,7 +58,7 @@ minetest.register_tool("mcl_fire:flint_and_steel", {
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Ignite air
if dropnode.name == "air" then
minetest.add_node(droppos, {name="mcl_fire:fire"})
add_node(droppos, {name="mcl_fire:fire"})
if not minetest.is_creative_enabled("") then
stack:add_wear(65535/65) -- 65 uses
end

@ -1,10 +1,29 @@
-- Global namespace for functions
mcl_fire = {}
local modpath = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator("mcl_fire")
local N = function(s) return s end
local has_mcl_portals = minetest.get_modpath("mcl_portals")
local set_node = minetest.set_node
local get_node = minetest.get_node
local add_node = minetest.add_node
local remove_node = minetest.remove_node
local swap_node = minetest.swap_node
local get_node_or_nil = minetest.get_node_or_nil
local find_nodes_in_area = minetest.find_nodes_in_area
local find_node_near = minetest.find_node_near
local get_item_group = minetest.get_item_group
local get_connected_players = minetest.get_connected_players
local vector = vector
local math = math
-- inverse pyramid pattern above lava source, floor 1 of 2:
local lava_fire=
{
@ -28,7 +47,72 @@ local alldirs=
{ x = 0, y = 0, z = 1}
}
-- 3 exptime variants because the animation is not tied to particle expiration time.
-- 3 colorized variants to imitate minecraft's
local smoke_pdef_base = {
amount = 0.001,
time = 0,
-- minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 }),
-- maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 }),
minvel = { x = -0.1, y = 0.3, z = -0.1 },
maxvel = { x = 0.1, y = 1.6, z = 0.1 },
-- minexptime = 3 exptime variants,
-- maxexptime = 3 exptime variants
minsize = 4.0,
maxsize = 4.5,
-- texture = "mcl_particles_smoke_anim.png^[colorize:#000000:(3 colourize variants)",
animation = {
type = "vertical_frames",
aspect_w = 8,
aspect_h = 8,
-- length = 3 exptime variants
},
collisiondetection = true,
}
local smoke_pdef_cached = {}
local spawn_smoke = function(pos)
local min = math.min
local new_minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 })
local new_maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 })
-- populate the cache
if not next(smoke_pdef_cached) then
-- the last frame plays for 1/8 * N seconds, so we can take advantage of it
-- to have varying exptime for each variant.
local exptimes = { 0.75, 1.5, 4.0 }
local colorizes = { "199", "209", "243" } -- round(78%, 82%, 90% of 256) - 1
local id = 1
for _,exptime in ipairs(exptimes) do
for _,colorize in ipairs(colorizes) do
smoke_pdef_base.minpos = new_minpos
smoke_pdef_base.maxpos = new_maxpos
smoke_pdef_base.maxexptime = exptime
smoke_pdef_base.animation.length = exptime + 0.1
-- minexptime must be set such that the last frame is actully rendered,
-- even if its very short. Larger exptime -> larger range
smoke_pdef_base.minexptime = min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1))
smoke_pdef_base.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize
smoke_pdef_cached[id] = table.copy(smoke_pdef_base)
mcl_particles.add_node_particlespawner(pos, smoke_pdef_cached[id], "high")
id = id + 1
end
end
-- cache already populated
else
for i, smoke_pdef in ipairs(smoke_pdef_cached) do
smoke_pdef.minpos = new_minpos
smoke_pdef.maxpos = new_maxpos
mcl_particles.add_node_particlespawner(pos, smoke_pdef, "high")
end
end
--[[ Old smoke pdef
local spawn_smoke = function(pos)
mcl_particles.add_node_particlespawner(pos, {
amount = 0.1,
time = 0,
@ -48,6 +132,8 @@ local spawn_smoke = function(pos)
length = 2.1,
},
}, "high")
-- ]]
end
--
@ -90,7 +176,7 @@ local fire_timer = function(pos)
end
local spawn_fire = function(pos, age)
minetest.set_node(pos, {name="mcl_fire:fire", param2 = age})
set_node(pos, {name="mcl_fire:fire", param2 = age})
minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
end
@ -120,28 +206,28 @@ minetest.register_node("mcl_fire:fire", {
groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston=1, destroys_items=1, set_on_fire=8},
floodable = true,
on_flood = function(pos, oldnode, newnode)
if minetest.get_item_group(newnode.name, "water") ~= 0 then
if get_item_group(newnode.name, "water") ~= 0 then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
local node = minetest.get_node(pos)
local node = get_node(pos)
-- Age is a number from 0 to 15 and is increased every timer step.
-- "old" fire is more likely to be extinguished
local age = node.param2
local flammables = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local below = minetest.get_node({x=pos.x, y=pos.z-1, z=pos.z})
local below_is_flammable = minetest.get_item_group(below.name, "flammable") > 0
local flammables = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local below = get_node({x=pos.x, y=pos.z-1, z=pos.z})
local below_is_flammable = get_item_group(below.name, "flammable") > 0
-- Extinguish fire
if (not fire_enabled) and (math.random(1,3) == 1) then
minetest.remove_node(pos)
remove_node(pos)
return
end
if age == 15 and not below_is_flammable then
minetest.remove_node(pos)
remove_node(pos)
return
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then
minetest.remove_node(pos)
remove_node(pos)
return
end
local age_add = 1
@ -149,14 +235,14 @@ minetest.register_node("mcl_fire:fire", {
if (not fire_enabled) then
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
return
end
-- Spawn fire to nearby flammable nodes
local is_next_to_flammable = minetest.find_node_near(pos, 2, {"group:flammable"}) ~= nil
local is_next_to_flammable = find_node_near(pos, 2, {"group:flammable"}) ~= nil
if is_next_to_flammable and math.random(1,2) == 1 then
-- The fire we spawn copies the age of this fire.
-- This prevents fire from spreading infinitely far as the fire fire dies off
@ -166,10 +252,10 @@ minetest.register_node("mcl_fire:fire", {
local burntype = math.random(1,2)
if burntype == 1 then
-- Spawn fire in air
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #nodes > 0 do
local r = math.random(1, #nodes)
if minetest.find_node_near(nodes[r], 1, {"group:flammable"}) then
if find_node_near(nodes[r], 1, {"group:flammable"}) then
spawn_fire(nodes[r], age_next)
break
else
@ -178,12 +264,12 @@ minetest.register_node("mcl_fire:fire", {
end
else
-- Burn flammable block
local nodes = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
local nodes = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"group:flammable"})
if #nodes > 0 then
local r = math.random(1, #nodes)
local nn = minetest.get_node(nodes[r]).name
local nn = get_node(nodes[r]).name
local ndef = minetest.registered_nodes[nn]
local fgroup = minetest.get_item_group(nn, "flammable")
local fgroup = get_item_group(nn, "flammable")
if ndef and ndef._on_burn then
ndef._on_burn(nodes[r])
elseif fgroup ~= -1 then
@ -195,7 +281,7 @@ minetest.register_node("mcl_fire:fire", {
-- Regular age increase
if age + age_add <= 15 then
node.param2 = age + age_add
minetest.set_node(pos, node)
set_node(pos, node)
end
-- Restart timer
fire_timer(pos)
@ -205,14 +291,14 @@ minetest.register_node("mcl_fire:fire", {
-- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer
on_construct = function(pos)
local bpos = {x=pos.x, y=pos.y-1, z=pos.z}
local under = minetest.get_node(bpos).name
local under = get_node(bpos).name
local dim = mcl_worlds.pos_to_dimension(bpos)
if under == "mcl_nether:magma" or under == "mcl_nether:netherrack" or (under == "mcl_core:bedrock" and dim == "end") then
minetest.swap_node(pos, {name = "mcl_fire:eternal_fire"})
swap_node(pos, {name = "mcl_fire:eternal_fire"})
end
if minetest.get_modpath("mcl_portals") then
if has_mcl_portals then
mcl_portals.light_nether_portal(pos)
end
@ -251,17 +337,17 @@ minetest.register_node("mcl_fire:eternal_fire", {
groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston = 1, destroys_items = 1, set_on_fire=8},
floodable = true,
on_flood = function(pos, oldnode, newnode)
if minetest.get_item_group(newnode.name, "water") ~= 0 then
if get_item_group(newnode.name, "water") ~= 0 then
minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end
end,
on_timer = function(pos)
if fire_enabled then
local airs = minetest.find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
local airs = find_nodes_in_area({x=pos.x-1, y=pos.y-1, z=pos.z-1}, {x=pos.x+1, y=pos.y+4, z=pos.z+1}, {"air"})
while #airs > 0 do
local r = math.random(1, #airs)
if minetest.find_node_near(airs[r], 1, {"group:flammable"}) then
local node = minetest.get_node(airs[r])
if find_node_near(airs[r], 1, {"group:flammable"}) then
local node = get_node(airs[r])
local age = node.param2
local age_next = math.min(15, age + math.random(0, 1))
spawn_fire(airs[r], age_next)
@ -278,7 +364,7 @@ minetest.register_node("mcl_fire:eternal_fire", {
on_construct = function(pos)
fire_timer(pos)
if minetest.get_modpath("mcl_portals") then
if has_mcl_portals then --Calling directly minetest.get_modpath consumes 4x more compute time
mcl_portals.light_nether_portal(pos)
end
spawn_smoke(pos)
@ -313,7 +399,7 @@ if flame_sound then
local ppos = player:get_pos()
local areamin = vector.subtract(ppos, radius)
local areamax = vector.add(ppos, radius)
local fpos, num = minetest.find_nodes_in_area(
local fpos, num = find_nodes_in_area(
areamin,
areamax,
{"mcl_fire:fire", "mcl_fire:eternal_fire"}
@ -384,7 +470,7 @@ if flame_sound then
end
timer = 0
local players = minetest.get_connected_players()
local players = get_connected_players()
for n = 1, #players do
mcl_fire.update_player_sound(players[n])
end
@ -416,7 +502,7 @@ minetest.register_abm({
chance = 1,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos)
remove_node(pos)
minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end,
@ -429,8 +515,8 @@ local function has_flammable(pos)
local npos, node
for n, v in ipairs(alldirs) do
npos = vector.add(pos, v)
node = minetest.get_node_or_nil(npos)
if node and node.name and minetest.get_item_group(node.name, "flammable") ~= 0 then
node = get_node_or_nil(npos)
if node and node.name and get_item_group(node.name, "flammable") ~= 0 then
return npos
end
end
@ -447,7 +533,7 @@ if not fire_enabled then
interval = 10,
chance = 10,
catch_up = false,
action = minetest.remove_node,
action = remove_node,
})
else -- Fire enabled
@ -465,12 +551,12 @@ else -- Fire enabled
i = math.random(1,9)
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
node = get_node(target)
if not node or node.name ~= "air" then
i = ((i + math.random(0,7)) % 9) + 1
dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}
node = minetest.get_node(target)
node = get_node(target)
if not node or node.name ~= "air" then
return
end
@ -480,7 +566,7 @@ else -- Fire enabled
local dir2, target2, node2
dir2 = lava_fire[i2]
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z}
node2 = minetest.get_node(target2)
node2 = get_node(target2)
if node2 and node2.name == "air" then
f = has_flammable(target2)
if f then
@ -521,9 +607,9 @@ mcl_fire.set_fire = function(pointed_thing, player, allow_on_fire)
else
pname = player:get_player_name()
end
local n = minetest.get_node(pointed_thing.above)
local nu = minetest.get_node(pointed_thing.under)
if allow_on_fire == false and minetest.get_item_group(nu.name, "fire") ~= 0 then
local n = get_node(pointed_thing.above)
local nu = get_node(pointed_thing.under)
if allow_on_fire == false and get_item_group(nu.name, "fire") ~= 0 then
return
end
if minetest.is_protected(pointed_thing.above, pname) then
@ -531,7 +617,7 @@ mcl_fire.set_fire = function(pointed_thing, player, allow_on_fire)
return
end
if n.name == "air" then
minetest.add_node(pointed_thing.above, {name="mcl_fire:fire"})
add_node(pointed_thing.above, {name="mcl_fire:fire"})
end
end
@ -549,5 +635,5 @@ minetest.register_alias("mcl_fire:basic_flame", "mcl_fire:fire")
minetest.register_alias("fire:basic_flame", "mcl_fire:fire")
minetest.register_alias("fire:permanent_flame", "mcl_fire:eternal_fire")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/flint_and_steel.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/fire_charge.lua")
dofile(modpath.."/flint_and_steel.lua")
dofile(modpath.."/fire_charge.lua")

@ -1 +1,3 @@
name = mcl_fire
depends = mcl_core, mcl_worlds, mcl_sounds, mcl_particles
optional_depends = mcl_portals

@ -233,4 +233,14 @@ mcl_jukebox.register_record("Minetest", "Jordach", "far", "mcl_jukebox_record_fa
mcl_jukebox.register_record("Credit Roll (Jordach's HD Mix)", "Junichi Masuda", "chirp", "mcl_jukebox_record_chirp.png", "mcl_jukebox_track_5")
mcl_jukebox.register_record("Winter Feeling", "Tom Peter", "strad", "mcl_jukebox_record_strad.png", "mcl_jukebox_track_6")
mcl_jukebox.register_record("Synthgroove (Jordach's Mix)", "HeroOfTheWinds", "mellohi", "mcl_jukebox_record_mellohi.png", "mcl_jukebox_track_7")
mcl_jukebox.register_record("The Clueless Frog (Jordach's Mix)", "SoundHelix", "mall", "mcl_jukebox_record_mall.png", "mcl_jukebox_track_8")
mcl_jukebox.register_record("The Clueless Frog (Jordach's Mix)", "SoundHelix", "mall", "mcl_jukebox_record_mall.png", "mcl_jukebox_track_8")
--add backward compatibility
minetest.register_alias("mcl_jukebox:record_1", "mcl_jukebox:record_13")
minetest.register_alias("mcl_jukebox:record_2", "mcl_jukebox:record_wait")
minetest.register_alias("mcl_jukebox:record_3", "mcl_jukebox:record_blocks")
minetest.register_alias("mcl_jukebox:record_4", "mcl_jukebox:record_far")
minetest.register_alias("mcl_jukebox:record_5", "mcl_jukebox:record_chirp")
minetest.register_alias("mcl_jukebox:record_6", "mcl_jukebox:record_strad")
minetest.register_alias("mcl_jukebox:record_7", "mcl_jukebox:record_mellohi")
minetest.register_alias("mcl_jukebox:record_8", "mcl_jukebox:record_mall")

@ -64,7 +64,7 @@ local function destroy_nether_portal(pos)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
local nn, orientation = node.name, node.param2
local obsidian = nn == "mcl_core:obsidian"
local obsidian = nn == "mcl_core:obsidian"
local has_meta = minetest.string_to_pos(meta:get_string("portal_frame1"))
if has_meta then
@ -138,8 +138,6 @@ minetest.register_node("mcl_portals:portal", {
sunlight_propagates = true,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "blend" or true,
walkable = false,
diggable = false,
pointable = false,
buildable_to = false,
is_ground_content = false,
drop = "",
@ -152,7 +150,8 @@ minetest.register_node("mcl_portals:portal", {
{-0.5, -0.5, -0.1, 0.5, 0.5, 0.1},
},
},
groups = {portal=1, not_in_creative_inventory = 1},
groups = { creative_breakable = 1, portal = 1, not_in_creative_inventory = 1 },
sounds = mcl_sounds.node_sound_glass_defaults(),
on_destruct = destroy_nether_portal,
_mcl_hardness = -1,
@ -583,7 +582,7 @@ local function check_and_light_shape(pos, orientation)
meta:set_string("portal_time", tostring(0))
meta:set_string("portal_target", "")
end
return true
return true
end
-- Attempts to light a Nether portal at pos
@ -842,7 +841,7 @@ minetest.override_item("mcl_core:obsidian", {
_on_ignite = function(user, pointed_thing)
local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z
-- Check empty spaces around obsidian and light all frames found:
local portals_placed =
local portals_placed =
mcl_portals.light_nether_portal({x = x - 1, y = y, z = z}) or mcl_portals.light_nether_portal({x = x + 1, y = y, z = z}) or
mcl_portals.light_nether_portal({x = x, y = y - 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y + 1, z = z}) or
mcl_portals.light_nether_portal({x = x, y = y, z = z - 1}) or mcl_portals.light_nether_portal({x = x, y = y, z = z + 1})
@ -863,4 +862,3 @@ minetest.override_item("mcl_core:obsidian", {
end
end,
})

@ -100,9 +100,10 @@ function mcl_potions.register_arrow(name, desc, color, def)
local ARROW_ENTITY={
physical = true,
visual = "wielditem",
visual_size = {x=0.4, y=0.4},
textures = {"mcl_potions:"..name.."_arrow_box"},
visual = "mesh",
mesh = "mcl_bows_arrow.obj",
visual_size = {x=1, y=1},
textures = arrow_image(color, 100),
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
collide_with_objects = false,
@ -177,6 +178,26 @@ function mcl_potions.register_arrow(name, desc, color, def)
-- Check for object "collision". Done every tick (hopefully this is not too stressing)
else
if self._damage == 10 or self._damage == 9 then
minetest.add_particlespawner({
amount = 1,
time = .001,
minpos = pos,
maxpos = pos,
minvel = vector.new(-0.1,-0.1,-0.1),
maxvel = vector.new(0.1,0.1,0.1),
minexptime = 0.5,
maxexptime = 0.5,
minsize = 2,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mobs_mc_arrow_particle.png",
glow = 1,
})
end
-- We just check for any hurtable objects nearby.
-- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often.

@ -1,2 +0,0 @@
mcl_core
doc?

@ -1 +0,0 @@
Core items not found in Minecraft

@ -1 +1,4 @@
name = mclx_core
description = Core items not found in Minecraft
depends = mcl_core
optional_depends = doc

@ -6,6 +6,16 @@ mcl_player = {}
-- Note: This is currently broken due to a bug in Irrlicht, leave at 0
local animation_blend = 0
local function get_mouse_button(player)
local controls = player:get_player_control()
local get_wielded_item_name = player:get_wielded_item():get_name()
if controls.RMB and not string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") or controls.LMB then
return true
else
return false
end
end
mcl_player.registered_player_models = { }
-- Local for speed.
@ -174,30 +184,30 @@ minetest.register_globalstep(function(dtime)
player_anim[name] = nil
player_sneak[name] = controls.sneak
end
if controls.LMB and not controls.sneak and head_in_water and is_sprinting == true then
if get_mouse_button(player) == true and not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_walk_mine", animation_speed_mod)
elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_walk", animation_speed_mod)
elseif is_sprinting == true and controls.LMB and not controls.sneak and not head_in_water then
elseif is_sprinting == true and get_mouse_button(player) == true and not controls.sneak and not head_in_water then
player_set_animation(player, "run_walk_mine", animation_speed_mod)
elseif controls.LMB and not controls.sneak then
elseif get_mouse_button(player) == true and not controls.sneak then
player_set_animation(player, "walk_mine", animation_speed_mod)
elseif controls.LMB and controls.sneak and is_sprinting ~= true then
elseif get_mouse_button(player) == true and controls.sneak and is_sprinting ~= true then
player_set_animation(player, "sneak_walk_mine", animation_speed_mod)
elseif is_sprinting == true and not controls.sneak and not head_in_water then
player_set_animation(player, "run_walk", animation_speed_mod)
elseif controls.sneak and not controls.LMB then
elseif controls.sneak and not get_mouse_button(player) == true then
player_set_animation(player, "sneak_walk", animation_speed_mod)
else
player_set_animation(player, "walk", animation_speed_mod)
end
elseif controls.LMB and not controls.sneak and head_in_water and is_sprinting == true then
elseif get_mouse_button(player) == true and not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_mine")
elseif not controls.LMB and not controls.sneak and head_in_water and is_sprinting == true then
elseif not get_mouse_button(player) == true and not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_stand")
elseif controls.LMB and not controls.sneak then
elseif get_mouse_button(player) == true and not controls.sneak then
player_set_animation(player, "mine")
elseif controls.LMB and controls.sneak then
elseif get_mouse_button(player) == true and controls.sneak then
player_set_animation(player, "sneak_mine")
elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_stand", animation_speed_mod)

@ -1,5 +1,21 @@
local S = minetest.get_translator("mcl_playerplus")
local get_connected_players = minetest.get_connected_players
local dir_to_yaw = minetest.dir_to_yaw
local get_item_group = minetest.get_item_group
local check_player_privs = minetest.check_player_privs
local find_node_near = minetest.find_node_near
local get_name_from_content_id = minetest.get_name_from_content_id
local get_voxel_manip = minetest.get_voxel_manip
local add_particle = minetest.add_particle
local add_particlespawner = minetest.add_particlespawner
local is_sprinting = mcl_sprint.is_sprinting
local exhaust = mcl_hunger.exhaust
local playerphysics = playerphysics
local vector = vector
local math = math
-- Internal player state
local mcl_playerplus_internal = {}
@ -25,7 +41,7 @@ minetest.register_globalstep(function(dtime)
-- Update jump status immediately since we need this info in real time.
-- WARNING: This section is HACKY as hell since it is all just based on heuristics.
for _,player in ipairs(minetest.get_connected_players()) do
for _,player in ipairs(get_connected_players()) do
local controls = player:get_player_control()
name = player:get_player_name()
@ -37,10 +53,10 @@ minetest.register_globalstep(function(dtime)
local player_vel_yaw = 0
if degrees(minetest.dir_to_yaw(player_velocity)) == 0 then
if degrees(dir_to_yaw(player_velocity)) == 0 then
yaw = 0
else
player_vel_yaw = degrees(minetest.dir_to_yaw(player_velocity))
player_vel_yaw = degrees(dir_to_yaw(player_velocity))
end
-- controls right and left arms pitch when shooting a bow or punching
@ -62,7 +78,7 @@ minetest.register_globalstep(function(dtime)
player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }})
-- sneaking body conrols
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0))
elseif minetest.get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and player:get_attach() == nil and mcl_sprint.is_sprinting(name) == true then
elseif get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and player:get_attach() == nil and is_sprinting(name) == true then
-- set head pitch and yaw when swimming
player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+90-degrees(dir_to_pitch(player_velocity)),yaw - player_vel_yaw * -1,0))
-- sets eye height, and nametag color accordingly
@ -127,18 +143,18 @@ minetest.register_globalstep(function(dtime)
as of 0.4.15.
]]
if minetest.get_item_group(node_feet, "liquid") == 0 and
minetest.get_item_group(node_stand, "liquid") == 0 and
if get_item_group(node_feet, "liquid") == 0 and
get_item_group(node_stand, "liquid") == 0 and
not minetest.registered_nodes[node_feet].climbable and
not minetest.registered_nodes[node_stand].climbable and
(minetest.registered_nodes[node_stand].walkable or minetest.registered_nodes[node_stand_below].walkable)
and minetest.get_item_group(node_stand, "disable_jump") == 0
and minetest.get_item_group(node_stand_below, "disable_jump") == 0 then
and get_item_group(node_stand, "disable_jump") == 0
and get_item_group(node_stand_below, "disable_jump") == 0 then
-- Cause exhaustion for jumping
if mcl_sprint.is_sprinting(name) then
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP)
if is_sprinting(name) then
exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP)
else
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_JUMP)
exhaust(name, mcl_hunger.EXHAUST_JUMP)
end
-- Reset cooldown timer
@ -157,7 +173,7 @@ minetest.register_globalstep(function(dtime)
time = 0
-- check players
for _,player in ipairs(minetest.get_connected_players()) do
for _,player in ipairs(get_connected_players()) do
-- who am I?
local name = player:get_player_name()
@ -198,7 +214,7 @@ minetest.register_globalstep(function(dtime)
end
-- Swimming? Check if boots are enchanted with depth strider
if minetest.get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then
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")
@ -220,7 +236,7 @@ minetest.register_globalstep(function(dtime)
and (ndef.groups.opaque == 1)
and (node_head ~= "ignore")
-- Check privilege, too
and (not minetest.check_player_privs(name, {noclip = true})) then
and (not check_player_privs(name, {noclip = true})) then
if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name))
player:set_hp(player:get_hp() - 1)
@ -228,9 +244,9 @@ minetest.register_globalstep(function(dtime)
end
-- Am I near a cactus?
local near = minetest.find_node_near(pos, 1, "mcl_core:cactus")
local near = find_node_near(pos, 1, "mcl_core:cactus")
if not near then
near = minetest.find_node_near({x=pos.x, y=pos.y-1, z=pos.z}, 1, "mcl_core:cactus")
near = find_node_near({x=pos.x, y=pos.y-1, z=pos.z}, 1, "mcl_core:cactus")
end
if near then
-- Am I touching the cactus? If so, it hurts
@ -247,15 +263,15 @@ minetest.register_globalstep(function(dtime)
--[[ Swimming: Cause exhaustion.
NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid!
Head alone does not count. We respect that for now. ]]
if not player:get_attach() and (minetest.get_item_group(node_feet, "liquid") ~= 0 or
minetest.get_item_group(node_stand, "liquid") ~= 0) then
if not player:get_attach() and (get_item_group(node_feet, "liquid") ~= 0 or
get_item_group(node_stand, "liquid") ~= 0) then
local lastPos = mcl_playerplus_internal[name].lastPos
if lastPos then
local dist = vector.distance(lastPos, pos)
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance + dist
if mcl_playerplus_internal[name].swimDistance >= 1 then
local superficial = math.floor(mcl_playerplus_internal[name].swimDistance)
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SWIM * superficial)
exhaust(name, mcl_hunger.EXHAUST_SWIM * superficial)
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance - superficial
end
end
@ -263,9 +279,8 @@ minetest.register_globalstep(function(dtime)
end
-- Underwater: Spawn bubble particles
if minetest.get_item_group(node_head, "water") ~= 0 then
minetest.add_particlespawner({
if get_item_group(node_head, "water") ~= 0 then
add_particlespawner({
amount = 10,
time = 0.15,
minpos = { x = -0.25, y = 0.3, z = -0.25 },
@ -288,7 +303,7 @@ minetest.register_globalstep(function(dtime)
if wi == "mcl_core:barrier" or wi == "mcl_core:realm_barrier" then
local pos = vector.round(player:get_pos())
local r = 8
local vm = minetest.get_voxel_manip()
local vm = get_voxel_manip()
local emin, emax = vm:read_from_map({x=pos.x-r, y=pos.y-r, z=pos.z-r}, {x=pos.x+r, y=pos.y+r, z=pos.z+r})
local area = VoxelArea:new{
MinEdge = emin,
@ -299,7 +314,7 @@ minetest.register_globalstep(function(dtime)
for y=pos.y-r, pos.y+r do
for z=pos.z-r, pos.z+r do
local vi = area:indexp({x=x, y=y, z=z})
local nodename = minetest.get_name_from_content_id(data[vi])
local nodename = get_name_from_content_id(data[vi])
local tex
if nodename == "mcl_core:barrier" then
tex = "mcl_core_barrier.png"
@ -307,7 +322,7 @@ minetest.register_globalstep(function(dtime)
tex = "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX"
end
if tex then
minetest.add_particle({
add_particle({
pos = {x=x, y=y, z=z},
expirationtime = 1,
size = 8,

@ -50,16 +50,27 @@ end
local function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
local player = minetest.get_player_by_name(playerName)
local controls = player:get_player_control()
if players[playerName] then
players[playerName].sprinting = sprinting
if sprinting == true then
players[playerName].fov = math.min(players[playerName].fov + 0.05, 1.2)
player:set_fov(players[playerName].fov, true, 0.15)
playerphysics.add_physics_factor(player, "speed", "mcl_sprint:sprint", mcl_sprint.SPEED)
elseif sprinting == false then
if sprinting == true or controls.RMB and string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and player:get_wielded_item():get_name() ~= "mcl_bows:bow" then
if sprinting == true then
players[playerName].fov = math.min(players[playerName].fov + 0.05, 1.2)
players[playerName].fade_time = .15
else
players[playerName].fov = .7
players[playerName].fade_time = .3
end
player:set_fov(players[playerName].fov, true, players[playerName].fade_time)
if sprinting == true then
playerphysics.add_physics_factor(player, "speed", "mcl_sprint:sprint", mcl_sprint.SPEED)
end
elseif sprinting == false and player:get_wielded_item():get_name() ~= "mcl_bows:bow_0" and player:get_wielded_item():get_name() ~= "mcl_bows:bow_1" and player:get_wielded_item():get_name() ~= "mcl_bows:bow_2" then
players[playerName].fov = math.max(players[playerName].fov - 0.05, 1.0)
player:set_fov(players[playerName].fov, true, 0.15)
playerphysics.remove_physics_factor(player, "speed", "mcl_sprint:sprint")
if sprinting == false then
playerphysics.remove_physics_factor(player, "speed", "mcl_sprint:sprint")
end
end
return true
end