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` * Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
## Mobs ## 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. 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. 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` * Get flowing direction of liquids: `CORE/flowlib`
* `on_walk_over` callback for nodes: `CORE/walkover` * `on_walk_over` callback for nodes: `CORE/walkover`
* Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo` * Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo`
* Explosion API
* Music discs API
* Flowers and flower pots
### Unstable APIs ### 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! 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 ### Planned APIs
* Flowers
* Saplings and trees * Saplings and trees
* Custom banner patterns * Custom banner patterns
* Custom dimensions * Custom dimensions
* Custom portals * Custom portals
* Music discs
* Dispenser and dropper support * Dispenser and dropper support
* Proper sky and weather APIs * 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=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 * `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=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 * `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 * `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 keepInventory = false
# Performance settings # Performance settings
dedicated_server_step = 0.01 dedicated_server_step = 0.001
liquid_update = 0.25
abm_interval = 0.25 abm_interval = 0.25
max_objects_per_block = 4096 max_objects_per_block = 4096
max_packets_per_iteration = 10096 max_packets_per_iteration = 10096

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

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

@ -12,14 +12,15 @@ local function detach_driver(self)
if not self._driver then if not self._driver then
return return
end end
if self._driver:is_player() then mcl_player.player_attached[self._driver] = nil
mcl_player.player_attached[self._driver:get_player_name()] = nil local player = minetest.get_player_by_name(self._driver)
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
self._driver = nil self._driver = nil
self._start_pos = 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 end
local function activate_tnt_minecart(self, timer) 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, 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 _punched = false, -- used to re-send _velocity and position
_velocity = {x=0, y=0, z=0}, -- only used on punch _velocity = {x=0, y=0, z=0}, -- only used on punch
_start_pos = nil, -- Used to calculate distance for “On A Rail” achievement _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 end
function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) 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() local pos = self.object:get_pos()
if not self._railtype then
-- Disable detector rail local node = minetest.get_node(vector.floor(pos)).name
local rou_pos = vector.round(pos) self._railtype = minetest.get_item_group(node, "connect_to_raillike")
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 end
-- Drop items and remove cart entity if not puncher or not puncher:is_player() then
if not minetest.is_creative_enabled(puncher:get_player_name()) then local cart_dir = mcl_minecarts:get_rail_direction(pos, {x=1, y=0, z=0}, nil, nil, self._railtype)
for d=1, #drop do if vector.equals(cart_dir, {x=0, y=0, z=0}) then
minetest.add_item(self.object:get_pos(), drop[d]) return
end end
elseif puncher and puncher:is_player() then self._velocity = vector.multiply(cart_dir, 3)
local inv = puncher:get_inventory() self._old_pos = nil
for d=1, #drop do self._punched = true
if not inv:contains_item("main", drop[d]) then return
inv:add_item("main", drop[d]) 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
end end
self.object:remove()
return
end 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 end
cart.on_activate_by_rail = on_activate_by_rail cart.on_activate_by_rail = on_activate_by_rail
function cart:on_step(dtime) function cart:on_step(dtime)
local ctrl, player = nil, nil local ctrl, player = nil, nil
local update = {} if self._driver then
local vel = self.object:get_velocity() player = minetest.get_player_by_name(self._driver)
local pos, rou_pos, node if player then
pos = self.object:get_pos() ctrl = player:get_player_control()
rou_pos = vector.round(pos) -- player detach
node = minetest.get_node(rou_pos) if ctrl.sneak then
local g = minetest.get_item_group(node.name, "connect_to_raillike") detach_driver(self)
if self._driver and self._driver:is_player() then return
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}))
end end
end end
end end
local vel = self.object:get_velocity()
local update = {}
if self._last_float_check == nil then if self._last_float_check == nil then
self._last_float_check = 0 self._last_float_check = 0
else else
self._last_float_check = self._last_float_check + dtime self._last_float_check = self._last_float_check + dtime
end end
local pos, rou_pos, node
-- Drop minecart if it isn't on a rail anymore -- Drop minecart if it isn't on a rail anymore
if self._last_float_check >= mcl_minecarts.check_float_time then if self._last_float_check >= mcl_minecarts.check_float_time then
pos = self.object:get_pos()
rou_pos = vector.round(pos)
for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.3)) do node = minetest.get_node(rou_pos)
if object ~= self.object then local g = minetest.get_item_group(node.name, "connect_to_raillike")
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
if g ~= self._railtype and self._railtype ~= nil then if g ~= self._railtype and self._railtype ~= nil then
-- Detach driver -- Detach driver
if player then if player then
@ -289,12 +300,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end end
end end
if update.vel then if self._punched then
vel = vector.add(vel, self._velocity) 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.object:set_velocity(vel)
self._old_dir.y = 0 self._old_dir.y = 0
elseif vector.equals(vel, {x=0, y=0, z=0}) and (not has_fuel) then 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_normal.png",
{"mcl_minecarts:minecart"}, {"mcl_minecarts:minecart"},
function(self, clicker) function(self, clicker)
if not clicker or not clicker:is_player() then return end local name = clicker:get_player_name()
if clicker == self._driver then 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) detach_driver(self)
else elseif not self._driver then
local name = clicker:get_player_name() self._driver = player_name
self._driver = clicker
self._start_pos = self.object:get_pos() 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}) clicker:set_attach(self.object, "", {x=0, y=-1.75, z=-2}, {x=0, y=0, z=0})
mcl_player.player_attached[name] = true mcl_player.player_attached[name] = true
minetest.after(0.2, function(name) minetest.after(0.2, function(name)
@ -637,7 +647,6 @@ register_minecart(
mcl_tmp_message.message(clicker, S("Sneak to dismount")) mcl_tmp_message.message(clicker, S("Sneak to dismount"))
end end
end, name) end, name)
clicker:set_look_horizontal(self.object:get_yaw())
end end
end, activate_normal_minecart end, activate_normal_minecart
) )

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

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

@ -511,9 +511,9 @@ local function update_health(player)
end end
-- update built-in HUD bars -- 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 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 if hb.settings.forceload_default_hudbars then
hb.unhide_hudbar(player, "health") hb.unhide_hudbar(player, "health")
end 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 or timer > 4 then
if main_timer > hb.settings.tick then main_timer = 0 end if main_timer > hb.settings.tick then main_timer = 0 end
-- only proceed if damage is enabled -- 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 for _, player in pairs(hb.players) do
-- update all hud elements -- update all hud elements
update_hud(player) update_hud(player, has_dmg)
end end
end end
end end

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

@ -101,14 +101,14 @@ local function update_anvil_slots(meta)
end end
local can_combine = mcl_enchanting.combine(input1, input2) local can_combine = mcl_enchanting.combine(input1, input2)
if can_combine then if can_combine then
-- Add tool health together plus a small bonus -- Add tool health together plus a small bonus
if def1.type == "tool" and def2.type == "tool" then if def1.type == "tool" and def2.type == "tool" then
local new_wear = calculate_repair(input1:get_wear(), input2:get_wear(), SAME_TOOL_REPAIR_BOOST) local new_wear = calculate_repair(input1:get_wear(), input2:get_wear(), SAME_TOOL_REPAIR_BOOST)
input1:set_wear(new_wear) input1:set_wear(new_wear)
end end
name_item = input1 name_item = input1
new_output = name_item new_output = name_item
-- Tool + repair item -- Tool + repair item
@ -318,11 +318,11 @@ local anvildef = {
_mcl_after_falling = damage_anvil_by_falling, _mcl_after_falling = damage_anvil_by_falling,
after_dig_node = function(pos, oldnode, oldmetadata, digger) after_dig_node = function(pos, oldnode, oldmetadata, digger)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local meta2 = meta local meta2 = meta:to_table()
meta:from_table(oldmetadata) meta:from_table(oldmetadata)
drop_anvil_items(pos, meta) drop_anvil_items(pos, meta)
meta:from_table(meta2:to_table()) meta:from_table(meta2)
end, end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player) allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local name = player:get_player_name() 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, 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={ local ARROW_ENTITY={
physical = true, physical = true,
visual = "wielditem", pointable = false,
visual_size = {x=0.4, y=0.4}, visual = "mesh",
textures = {"mcl_bows:arrow_box"}, 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}, collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
collide_with_objects = false, collide_with_objects = false,
_fire_damage_resistant = true, _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) -- Check for object "collision". Done every tick (hopefully this is not too stressing)
else 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. -- We just check for any hurtable objects nearby.
-- The radius of 3 is fairly liberal, but anything lower than than will cause -- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often. -- 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 S = minetest.get_translator("mcl_buckets")
local modpath = minetest.get_modpath(minetest.get_current_modname())
-- Minetest 0.4 mod: bucket -- Minetest 0.4 mod: bucket
-- See README.txt for licensing and other information. -- 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}) minetest.add_node(pos, {name=itemstring, param2=fullness})
end end
-- Register a new liquid function mcl_buckets.register_liquid(def)
-- source_place = a string or function. for i=1, #def.source_take do
-- * string: name of the node to place mcl_buckets.liquids[def.source_take[i]] = {
-- * function(pos): will returns name of the node to place with pos being the placement position source_place = def.source_place,
-- source_take = table of liquid source node names to take source_take = def.source_take[i],
-- itemname = itemstring of the new bucket item (or nil if liquid is not takeable) itemname = def.itemname,
-- 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,
} }
if type(source_place) == "string" then if type(def.source_place) == "string" then
mcl_buckets.liquids[source_place] = mcl_buckets.liquids[source_take[i]] mcl_buckets.liquids[def.source_place] = mcl_buckets.liquids[def.source_take[i]]
end end
end end
if itemname ~= nil then if def.itemname ~= nil then
minetest.register_craftitem(itemname, { minetest.register_craftitem(def.itemname, {
description = name, description = def.name,
_doc_items_longdesc = longdesc, _doc_items_longdesc = def.longdesc,
_doc_items_usagehelp = usagehelp, _doc_items_usagehelp = def.usagehelp,
_tt_help = tt_help, _tt_help = def.tt_help,
inventory_image = inventory_image, inventory_image = def.inventory_image,
stack_max = 16, stack_max = 16,
groups = groups, groups = def.groups,
on_place = function(itemstack, user, pointed_thing) on_place = function(itemstack, user, pointed_thing)
-- Must be pointing to node -- Must be pointing to node
if pointed_thing.type ~= "node" then if pointed_thing.type ~= "node" then
@ -99,10 +84,10 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
end end
local node_place local node_place
if type(source_place) == "function" then if type(def.source_place) == "function" then
node_place = source_place(place_pos) node_place = def.source_place(place_pos)
else else
node_place = source_place node_place = def.source_place
end end
-- Check if pointing to a buildable node -- Check if pointing to a buildable node
local item = itemstack:get_name() local item = itemstack:get_name()
@ -163,17 +148,17 @@ function mcl_buckets.register_liquid(source_place, source_take, itemname, invent
end, end,
_on_dispense = function(stack, pos, droppos, dropnode, dropdir) _on_dispense = function(stack, pos, droppos, dropnode, dropdir)
local iname = stack:get_name() 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 -- Fail placement of liquid
elseif buildable then elseif buildable then
-- buildable; replace the node -- buildable; replace the node
local node_place local node_place
if type(source_place) == "function" then if type(def.source_place) == "function" then
node_place = source_place(droppos) node_place = def.source_place(droppos)
else else
node_place = source_place node_place = def.source_place
end end
place_liquid(droppos, node_place) place_liquid(droppos, node_place)
stack:set_name("mcl_buckets:bucket_empty") stack:set_name("mcl_buckets:bucket_empty")
@ -292,114 +277,4 @@ minetest.register_craftitem("mcl_buckets:bucket_empty", {
end, end,
}) })
if mod_mcl_core then dofile(modpath.."/register.lua")
-- 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"}},
})

@ -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 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 = {} mcl_cocoas = {}
-- Place cocoa -- Place cocoa
function mcl_cocoas.place(itemstack, placer, pointed_thing, plantname) function mcl_cocoas.place(itemstack, placer, pt, plantname)
local pt = pointed_thing
-- check if pointing at a node -- check if pointing at a node
if not pt or pt.type ~= "node" then if not pt or pt.type ~= "node" then
return return

@ -1 +1,4 @@
name = mcl_cocoas 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 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", { minetest.register_node("mcl_crafting_table:crafting_table", {
description = S("Crafting Table"), description = S("Crafting Table"),
_tt_help = S("3×3 crafting grid"), _tt_help = S("3×3 crafting grid"),
@ -12,27 +43,7 @@ minetest.register_node("mcl_crafting_table:crafting_table", {
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {handy=1,axey=1, deco_block=1, material_wood=1,flammable=-1}, groups = {handy=1,axey=1, deco_block=1, material_wood=1,flammable=-1},
on_rightclick = function(pos, node, player, itemstack) on_rightclick = function(pos, node, player, itemstack)
player:get_inventory():set_width("craft", 3) show_crafting_form(player)
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)
end, end,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_blast_resistance = 2.5, _mcl_blast_resistance = 2.5,

@ -1 +1,4 @@
name = mcl_crafting_table 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) function mcl_enchanting.load_enchantments(itemstack, enchantments)
if not mcl_enchanting.is_book(itemstack:get_name()) then 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 for enchantment, level in pairs(enchantments or mcl_enchanting.get_enchantments(itemstack)) do
local enchantment_def = mcl_enchanting.enchantments[enchantment] local enchantment_def = mcl_enchanting.enchantments[enchantment]
if enchantment_def.on_enchant then if enchantment_def.on_enchant then
@ -159,7 +159,7 @@ function mcl_enchanting.combine(itemstack, combine_with)
local itemname = itemstack:get_name() local itemname = itemstack:get_name()
local combine_name = combine_with:get_name() local combine_name = combine_with:get_name()
local enchanted_itemname = mcl_enchanting.get_enchanted_itemstring(itemname) 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 return false
end end
local enchantments = mcl_enchanting.get_enchantments(itemstack) 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 S = minetest.get_translator("mcl_fire")
local get_node = minetest.get_node
local add_entity = minetest.add_entity
-- Fire Charge -- Fire Charge
minetest.register_craftitem("mcl_fire:fire_charge", { minetest.register_craftitem("mcl_fire:fire_charge", {
description = S("Fire Charge"), description = S("Fire Charge"),
@ -11,7 +14,7 @@ minetest.register_craftitem("mcl_fire:fire_charge", {
stack_max = 64, stack_max = 64,
on_place = function(itemstack, user, pointed_thing) on_place = function(itemstack, user, pointed_thing)
-- Use pointed node's on_rightclick function first, if present -- 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 user and not user:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick 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 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) _on_dispense = function(stack, pos, droppos, dropnode, dropdir)
-- Throw fire charge -- Throw fire charge
local shootpos = vector.add(pos, vector.multiply(dropdir, 0.51)) 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() local ent = fireball:get_luaentity()
ent._shot_from_dispenser = true ent._shot_from_dispenser = true
local v = ent.velocity or 1 local v = ent.velocity or 1

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

@ -1,10 +1,29 @@
-- Global namespace for functions -- Global namespace for functions
mcl_fire = {} mcl_fire = {}
local modpath = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator("mcl_fire") local S = minetest.get_translator("mcl_fire")
local N = function(s) return s end 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: -- inverse pyramid pattern above lava source, floor 1 of 2:
local lava_fire= local lava_fire=
{ {
@ -28,7 +47,72 @@ local alldirs=
{ x = 0, y = 0, z = 1} { 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 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, { mcl_particles.add_node_particlespawner(pos, {
amount = 0.1, amount = 0.1,
time = 0, time = 0,
@ -48,6 +132,8 @@ local spawn_smoke = function(pos)
length = 2.1, length = 2.1,
}, },
}, "high") }, "high")
-- ]]
end end
-- --
@ -90,7 +176,7 @@ local fire_timer = function(pos)
end end
local spawn_fire = function(pos, age) 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}) minetest.check_single_for_falling({x=pos.x, y=pos.y+1, z=pos.z})
end 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}, groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston=1, destroys_items=1, set_on_fire=8},
floodable = true, floodable = true,
on_flood = function(pos, oldnode, newnode) 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) minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end end
end, end,
on_timer = function(pos) 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. -- Age is a number from 0 to 15 and is increased every timer step.
-- "old" fire is more likely to be extinguished -- "old" fire is more likely to be extinguished
local age = node.param2 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 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 = minetest.get_node({x=pos.x, y=pos.z-1, z=pos.z}) local below = 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 below_is_flammable = get_item_group(below.name, "flammable") > 0
-- Extinguish fire -- Extinguish fire
if (not fire_enabled) and (math.random(1,3) == 1) then if (not fire_enabled) and (math.random(1,3) == 1) then
minetest.remove_node(pos) remove_node(pos)
return return
end end
if age == 15 and not below_is_flammable then if age == 15 and not below_is_flammable then
minetest.remove_node(pos) remove_node(pos)
return return
elseif age > 3 and #flammables == 0 and not below_is_flammable and math.random(1,4) == 1 then 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 return
end end
local age_add = 1 local age_add = 1
@ -149,14 +235,14 @@ minetest.register_node("mcl_fire:fire", {
if (not fire_enabled) then if (not fire_enabled) then
if age + age_add <= 15 then if age + age_add <= 15 then
node.param2 = age + age_add node.param2 = age + age_add
minetest.set_node(pos, node) set_node(pos, node)
end end
-- Restart timer -- Restart timer
fire_timer(pos) fire_timer(pos)
return return
end end
-- Spawn fire to nearby flammable nodes -- 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 if is_next_to_flammable and math.random(1,2) == 1 then
-- The fire we spawn copies the age of this fire. -- The fire we spawn copies the age of this fire.
-- This prevents fire from spreading infinitely far as the fire fire dies off -- 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) local burntype = math.random(1,2)
if burntype == 1 then if burntype == 1 then
-- Spawn fire in air -- 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 while #nodes > 0 do
local r = math.random(1, #nodes) 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) spawn_fire(nodes[r], age_next)
break break
else else
@ -178,12 +264,12 @@ minetest.register_node("mcl_fire:fire", {
end end
else else
-- Burn flammable block -- 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 if #nodes > 0 then
local r = math.random(1, #nodes) 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 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 if ndef and ndef._on_burn then
ndef._on_burn(nodes[r]) ndef._on_burn(nodes[r])
elseif fgroup ~= -1 then elseif fgroup ~= -1 then
@ -195,7 +281,7 @@ minetest.register_node("mcl_fire:fire", {
-- Regular age increase -- Regular age increase
if age + age_add <= 15 then if age + age_add <= 15 then
node.param2 = age + age_add node.param2 = age + age_add
minetest.set_node(pos, node) set_node(pos, node)
end end
-- Restart timer -- Restart timer
fire_timer(pos) 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 -- Turn into eternal fire on special blocks, light Nether portal (if possible), start burning timer
on_construct = function(pos) on_construct = function(pos)
local bpos = {x=pos.x, y=pos.y-1, z=pos.z} 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) 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 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 end
if minetest.get_modpath("mcl_portals") then if has_mcl_portals then
mcl_portals.light_nether_portal(pos) mcl_portals.light_nether_portal(pos)
end 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}, groups = {fire = 1, dig_immediate = 3, not_in_creative_inventory = 1, dig_by_piston = 1, destroys_items = 1, set_on_fire=8},
floodable = true, floodable = true,
on_flood = function(pos, oldnode, newnode) 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) minetest.sound_play("fire_extinguish_flame", {pos = pos, gain = 0.25, max_hear_distance = 16}, true)
end end
end, end,
on_timer = function(pos) on_timer = function(pos)
if fire_enabled then 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 while #airs > 0 do
local r = math.random(1, #airs) local r = math.random(1, #airs)
if minetest.find_node_near(airs[r], 1, {"group:flammable"}) then if find_node_near(airs[r], 1, {"group:flammable"}) then
local node = minetest.get_node(airs[r]) local node = get_node(airs[r])
local age = node.param2 local age = node.param2
local age_next = math.min(15, age + math.random(0, 1)) local age_next = math.min(15, age + math.random(0, 1))
spawn_fire(airs[r], age_next) spawn_fire(airs[r], age_next)
@ -278,7 +364,7 @@ minetest.register_node("mcl_fire:eternal_fire", {
on_construct = function(pos) on_construct = function(pos)
fire_timer(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) mcl_portals.light_nether_portal(pos)
end end
spawn_smoke(pos) spawn_smoke(pos)
@ -313,7 +399,7 @@ if flame_sound then
local ppos = player:get_pos() local ppos = player:get_pos()
local areamin = vector.subtract(ppos, radius) local areamin = vector.subtract(ppos, radius)
local areamax = vector.add(ppos, radius) local areamax = vector.add(ppos, radius)
local fpos, num = minetest.find_nodes_in_area( local fpos, num = find_nodes_in_area(
areamin, areamin,
areamax, areamax,
{"mcl_fire:fire", "mcl_fire:eternal_fire"} {"mcl_fire:fire", "mcl_fire:eternal_fire"}
@ -384,7 +470,7 @@ if flame_sound then
end end
timer = 0 timer = 0
local players = minetest.get_connected_players() local players = get_connected_players()
for n = 1, #players do for n = 1, #players do
mcl_fire.update_player_sound(players[n]) mcl_fire.update_player_sound(players[n])
end end
@ -416,7 +502,7 @@ minetest.register_abm({
chance = 1, chance = 1,
catch_up = false, catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
minetest.remove_node(pos) remove_node(pos)
minetest.sound_play("fire_extinguish_flame", minetest.sound_play("fire_extinguish_flame",
{pos = pos, max_hear_distance = 16, gain = 0.15}, true) {pos = pos, max_hear_distance = 16, gain = 0.15}, true)
end, end,
@ -429,8 +515,8 @@ local function has_flammable(pos)
local npos, node local npos, node
for n, v in ipairs(alldirs) do for n, v in ipairs(alldirs) do
npos = vector.add(pos, v) npos = vector.add(pos, v)
node = minetest.get_node_or_nil(npos) node = get_node_or_nil(npos)
if node and node.name and minetest.get_item_group(node.name, "flammable") ~= 0 then if node and node.name and get_item_group(node.name, "flammable") ~= 0 then
return npos return npos
end end
end end
@ -447,7 +533,7 @@ if not fire_enabled then
interval = 10, interval = 10,
chance = 10, chance = 10,
catch_up = false, catch_up = false,
action = minetest.remove_node, action = remove_node,
}) })
else -- Fire enabled else -- Fire enabled
@ -465,12 +551,12 @@ else -- Fire enabled
i = math.random(1,9) i = math.random(1,9)
dir = lava_fire[i] dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} 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 if not node or node.name ~= "air" then
i = ((i + math.random(0,7)) % 9) + 1 i = ((i + math.random(0,7)) % 9) + 1
dir = lava_fire[i] dir = lava_fire[i]
target = {x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z} 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 if not node or node.name ~= "air" then
return return
end end
@ -480,7 +566,7 @@ else -- Fire enabled
local dir2, target2, node2 local dir2, target2, node2
dir2 = lava_fire[i2] dir2 = lava_fire[i2]
target2 = {x=target.x+dir2.x, y=target.y+dir2.y, z=target.z+dir2.z} 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 if node2 and node2.name == "air" then
f = has_flammable(target2) f = has_flammable(target2)
if f then if f then
@ -521,9 +607,9 @@ mcl_fire.set_fire = function(pointed_thing, player, allow_on_fire)
else else
pname = player:get_player_name() pname = player:get_player_name()
end end
local n = minetest.get_node(pointed_thing.above) local n = get_node(pointed_thing.above)
local nu = minetest.get_node(pointed_thing.under) local nu = get_node(pointed_thing.under)
if allow_on_fire == false and minetest.get_item_group(nu.name, "fire") ~= 0 then if allow_on_fire == false and get_item_group(nu.name, "fire") ~= 0 then
return return
end end
if minetest.is_protected(pointed_thing.above, pname) then 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 return
end end
if n.name == "air" then 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
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:basic_flame", "mcl_fire:fire")
minetest.register_alias("fire:permanent_flame", "mcl_fire:eternal_fire") minetest.register_alias("fire:permanent_flame", "mcl_fire:eternal_fire")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/flint_and_steel.lua") dofile(modpath.."/flint_and_steel.lua")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/fire_charge.lua") dofile(modpath.."/fire_charge.lua")

@ -1 +1,3 @@
name = mcl_fire 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("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("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("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 meta = minetest.get_meta(pos)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
local nn, orientation = node.name, node.param2 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")) local has_meta = minetest.string_to_pos(meta:get_string("portal_frame1"))
if has_meta then if has_meta then
@ -138,8 +138,6 @@ minetest.register_node("mcl_portals:portal", {
sunlight_propagates = true, sunlight_propagates = true,
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "blend" or true, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "blend" or true,
walkable = false, walkable = false,
diggable = false,
pointable = false,
buildable_to = false, buildable_to = false,
is_ground_content = false, is_ground_content = false,
drop = "", drop = "",
@ -152,7 +150,8 @@ minetest.register_node("mcl_portals:portal", {
{-0.5, -0.5, -0.1, 0.5, 0.5, 0.1}, {-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, on_destruct = destroy_nether_portal,
_mcl_hardness = -1, _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_time", tostring(0))
meta:set_string("portal_target", "") meta:set_string("portal_target", "")
end end
return true return true
end end
-- Attempts to light a Nether portal at pos -- Attempts to light a Nether portal at pos
@ -842,7 +841,7 @@ minetest.override_item("mcl_core:obsidian", {
_on_ignite = function(user, pointed_thing) _on_ignite = function(user, pointed_thing)
local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z 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: -- 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 - 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 - 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}) 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
end, end,
}) })

@ -100,9 +100,10 @@ function mcl_potions.register_arrow(name, desc, color, def)
local ARROW_ENTITY={ local ARROW_ENTITY={
physical = true, physical = true,
visual = "wielditem", visual = "mesh",
visual_size = {x=0.4, y=0.4}, mesh = "mcl_bows_arrow.obj",
textures = {"mcl_potions:"..name.."_arrow_box"}, visual_size = {x=1, y=1},
textures = arrow_image(color, 100),
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19}, collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
collide_with_objects = false, 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) -- Check for object "collision". Done every tick (hopefully this is not too stressing)
else 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. -- We just check for any hurtable objects nearby.
-- The radius of 3 is fairly liberal, but anything lower than than will cause -- The radius of 3 is fairly liberal, but anything lower than than will cause
-- arrow to hilariously go through mobs often. -- 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 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 -- Note: This is currently broken due to a bug in Irrlicht, leave at 0
local animation_blend = 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 = { } mcl_player.registered_player_models = { }
-- Local for speed. -- Local for speed.
@ -174,30 +184,30 @@ minetest.register_globalstep(function(dtime)
player_anim[name] = nil player_anim[name] = nil
player_sneak[name] = controls.sneak player_sneak[name] = controls.sneak
end 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) player_set_animation(player, "swim_walk_mine", animation_speed_mod)
elseif not controls.sneak and head_in_water and is_sprinting == true then elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_walk", animation_speed_mod) 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) 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) 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) player_set_animation(player, "sneak_walk_mine", animation_speed_mod)
elseif is_sprinting == true and not controls.sneak and not head_in_water then elseif is_sprinting == true and not controls.sneak and not head_in_water then
player_set_animation(player, "run_walk", animation_speed_mod) 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) player_set_animation(player, "sneak_walk", animation_speed_mod)
else else
player_set_animation(player, "walk", animation_speed_mod) player_set_animation(player, "walk", animation_speed_mod)
end 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") 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") 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") 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") player_set_animation(player, "sneak_mine")
elseif not controls.sneak and head_in_water and is_sprinting == true then elseif not controls.sneak and head_in_water and is_sprinting == true then
player_set_animation(player, "swim_stand", animation_speed_mod) player_set_animation(player, "swim_stand", animation_speed_mod)

@ -1,5 +1,21 @@
local S = minetest.get_translator("mcl_playerplus") 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 -- Internal player state
local mcl_playerplus_internal = {} 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. -- 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. -- 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() local controls = player:get_player_control()
name = player:get_player_name() name = player:get_player_name()
@ -37,10 +53,10 @@ minetest.register_globalstep(function(dtime)
local player_vel_yaw = 0 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 yaw = 0
else else
player_vel_yaw = degrees(minetest.dir_to_yaw(player_velocity)) player_vel_yaw = degrees(dir_to_yaw(player_velocity))
end end
-- controls right and left arms pitch when shooting a bow or punching -- 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 }}) 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 -- sneaking body conrols
player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) 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 -- 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)) 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 -- sets eye height, and nametag color accordingly
@ -127,18 +143,18 @@ minetest.register_globalstep(function(dtime)
as of 0.4.15. as of 0.4.15.
]] ]]
if minetest.get_item_group(node_feet, "liquid") == 0 and if get_item_group(node_feet, "liquid") == 0 and
minetest.get_item_group(node_stand, "liquid") == 0 and get_item_group(node_stand, "liquid") == 0 and
not minetest.registered_nodes[node_feet].climbable and not minetest.registered_nodes[node_feet].climbable and
not minetest.registered_nodes[node_stand].climbable and not minetest.registered_nodes[node_stand].climbable and
(minetest.registered_nodes[node_stand].walkable or minetest.registered_nodes[node_stand_below].walkable) (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 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_below, "disable_jump") == 0 then
-- Cause exhaustion for jumping -- Cause exhaustion for jumping
if mcl_sprint.is_sprinting(name) then if is_sprinting(name) then
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP) exhaust(name, mcl_hunger.EXHAUST_SPRINT_JUMP)
else else
mcl_hunger.exhaust(name, mcl_hunger.EXHAUST_JUMP) exhaust(name, mcl_hunger.EXHAUST_JUMP)
end end
-- Reset cooldown timer -- Reset cooldown timer
@ -157,7 +173,7 @@ minetest.register_globalstep(function(dtime)
time = 0 time = 0
-- check players -- check players
for _,player in ipairs(minetest.get_connected_players()) do for _,player in ipairs(get_connected_players()) do
-- who am I? -- who am I?
local name = player:get_player_name() local name = player:get_player_name()
@ -198,7 +214,7 @@ minetest.register_globalstep(function(dtime)
end end
-- Swimming? Check if boots are enchanted with depth strider -- 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 boots = player:get_inventory():get_stack("armor", 5)
local depth_strider = mcl_enchanting.get_enchantment(boots, "depth_strider") 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 (ndef.groups.opaque == 1)
and (node_head ~= "ignore") and (node_head ~= "ignore")
-- Check privilege, too -- 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 if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name)) mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name))
player:set_hp(player:get_hp() - 1) player:set_hp(player:get_hp() - 1)
@ -228,9 +244,9 @@ minetest.register_globalstep(function(dtime)
end end
-- Am I near a cactus? -- 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 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 end
if near then if near then
-- Am I touching the cactus? If so, it hurts -- Am I touching the cactus? If so, it hurts
@ -247,15 +263,15 @@ minetest.register_globalstep(function(dtime)
--[[ Swimming: Cause exhaustion. --[[ Swimming: Cause exhaustion.
NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid! 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. ]] 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 if not player:get_attach() and (get_item_group(node_feet, "liquid") ~= 0 or
minetest.get_item_group(node_stand, "liquid") ~= 0) then get_item_group(node_stand, "liquid") ~= 0) then
local lastPos = mcl_playerplus_internal[name].lastPos local lastPos = mcl_playerplus_internal[name].lastPos
if lastPos then if lastPos then
local dist = vector.distance(lastPos, pos) local dist = vector.distance(lastPos, pos)
mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance + dist mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance + dist
if mcl_playerplus_internal[name].swimDistance >= 1 then if mcl_playerplus_internal[name].swimDistance >= 1 then
local superficial = math.floor(mcl_playerplus_internal[name].swimDistance) 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 mcl_playerplus_internal[name].swimDistance = mcl_playerplus_internal[name].swimDistance - superficial
end end
end end
@ -263,9 +279,8 @@ minetest.register_globalstep(function(dtime)
end end
-- Underwater: Spawn bubble particles -- Underwater: Spawn bubble particles
if minetest.get_item_group(node_head, "water") ~= 0 then if get_item_group(node_head, "water") ~= 0 then
add_particlespawner({
minetest.add_particlespawner({
amount = 10, amount = 10,
time = 0.15, time = 0.15,
minpos = { x = -0.25, y = 0.3, z = -0.25 }, 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 if wi == "mcl_core:barrier" or wi == "mcl_core:realm_barrier" then
local pos = vector.round(player:get_pos()) local pos = vector.round(player:get_pos())
local r = 8 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 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{ local area = VoxelArea:new{
MinEdge = emin, MinEdge = emin,
@ -299,7 +314,7 @@ minetest.register_globalstep(function(dtime)
for y=pos.y-r, pos.y+r do for y=pos.y-r, pos.y+r do
for z=pos.z-r, pos.z+r do for z=pos.z-r, pos.z+r do
local vi = area:indexp({x=x, y=y, z=z}) 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 local tex
if nodename == "mcl_core:barrier" then if nodename == "mcl_core:barrier" then
tex = "mcl_core_barrier.png" tex = "mcl_core_barrier.png"
@ -307,7 +322,7 @@ minetest.register_globalstep(function(dtime)
tex = "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX" tex = "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX"
end end
if tex then if tex then
minetest.add_particle({ add_particle({
pos = {x=x, y=y, z=z}, pos = {x=x, y=y, z=z},
expirationtime = 1, expirationtime = 1,
size = 8, size = 8,

@ -50,16 +50,27 @@ end
local function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting) 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 player = minetest.get_player_by_name(playerName)
local controls = player:get_player_control()
if players[playerName] then if players[playerName] then
players[playerName].sprinting = sprinting players[playerName].sprinting = sprinting
if sprinting == true 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
players[playerName].fov = math.min(players[playerName].fov + 0.05, 1.2) if sprinting == true then
player:set_fov(players[playerName].fov, true, 0.15) players[playerName].fov = math.min(players[playerName].fov + 0.05, 1.2)
playerphysics.add_physics_factor(player, "speed", "mcl_sprint:sprint", mcl_sprint.SPEED) players[playerName].fade_time = .15
elseif sprinting == false then 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) players[playerName].fov = math.max(players[playerName].fov - 0.05, 1.0)
player:set_fov(players[playerName].fov, true, 0.15) 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 end
return true return true
end end