Merge pull request 'Release 5.1.6' (#196) from compatibility into production-compatible

Reviewed-on: MineClone5/MineClone5#196
This commit is contained in:
kay27 2022-02-13 02:44:06 +00:00
commit 5ad0bd21e5
29 changed files with 499 additions and 176 deletions

View File

@ -1,5 +1,4 @@
# MineClone 5
Version: 0.71.7 Release Candidate 0
MineClone 5 is a fork of MineClone 2 with different workflow:
* No Minecraft version limitation, target version is Latest Java Edition
@ -70,9 +69,8 @@ Use the `/giveme` chat command to obtain them. See the in-game help for
an explanation.
## Installation
This game requires [Minetest](http://minetest.net) to run (version 5.4.1 or
later). So you need to install Minetest first. Only stable versions of Minetest
are officially supported.
This game requires latest stable [Minetest](http://minetest.net) to run, please install
it first. Only stable versions of Minetest are officially supported.
There is no support for running MineClone 5 in development versions of Minetest.
To install MineClone 5 (if you haven't already), move this directory into the
@ -83,10 +81,8 @@ Minetest to learn more.
The MineClone 5 repository is hosted at Mesehub. To contribute or report issues, head there.
* Mesehub: <https://git.minetest.land/MineClone5/MineClone5>
* IRC: <https://web.libera.chat/#mineclone2>
* Matrix: <https://app.element.io/#/room/#mc2:matrix.org>
* Reddit: <https://www.reddit.com/r/MineClone2/>
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=16407>
* Minetest forums: <https://forum.minetest.net/viewtopic.php?f=50&t=27107>
* Semi-official Discord: <https://discord.gg/PUm5YRn7dX>
## Project description
The main goal of **MineClone 5** is to be a clone of Minecraft and to be released as free software.
@ -155,7 +151,7 @@ The following features are incomplete:
* Special minecarts
* A couple of non-trivial blocks and items
Bonus features (not found in Minecraft 1.12):
Bonus features (not found in Minecraft):
* Built-in crafting guide which shows you crafting and smelting recipes
* In-game help system containing extensive help about gameplay basics, blocks, items and more
@ -168,6 +164,7 @@ Bonus features (not found in Minecraft 1.12):
* Nether Brick Fence Gate
* Red Nether Brick Fence
* Red Nether Brick Fence Gate
* Arbitrary-shaped Nether portals
Technical differences from Minecraft:

View File

@ -4,6 +4,14 @@ mcl_vars = mcl_vars or {}
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
if not bit then
bit = {}
function bit.bxor(a, b)
-- fake! mock! speedify for now! TODO: make proper xor bitwise
return math.ceil(math.abs(math.floor(a/0.14) * b * 1.001 + b))
end
end
function math.round(x)
if x >= 0 then
return math.floor(x + 0.5)

View File

@ -0,0 +1,52 @@
# mcl_time
## by kay27 for MineClone 5
---------------------------
This mod counts time when all players sleep or some area is inactive.
It depends very much on `time_speed` configuration variable, which could be changed 'on the fly' by a chat command.
If `time_speed` set to 0, this mod logs warnings and returns zeroes.
### mcl_time.get_seconds_irl()
------------------------------
Returns: Integer value of realtime (not in-game) seconds since world creation.
Usually this value grow smoothly. But when you skip the night being in the bed, or leave some area for some time, you may experience value jumps. That's basically the idea of this mod.
### mcl_time.get_number_of_times(last_time, interval, chance)
-------------------------------------------------------------
Handy to process AMBs.
You pass `last_time` - last known value of `seconds_irl`, also ABM `interval` and ABM `chance`.
Returns:
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
* Integer value of realtime (not in-game) seconds since world creation.
### mcl_time.touch(pos)
-----------------------
This function 'toches' node at position `pos` by writing `_t` meta variable of `seconds_irl`.
### mcl_time.get_number_of_times_at_pos(pos, interval, chance)
--------------------------------------------------------------
Much more handy to call from LBM on area load, than `mcl_time.get_number_of_times()`!
It reads meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, which then pass as first argument into `mcl_time.get_number_of_times()`.
After calling this, it also 'touches' the node at `pos` by writing `seconds_irl` into meta variable `_t`.
Returns:
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
* Integer value of realtime (not in-game) seconds since world creation.
*Warning!* This function can return 0. So it's better not to use it for regular ABMs - use `mcl_time.get_number_of_times_at_pos_or_1()` instead.
### mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
-------------------------------------------------------------------
Much more handy to process ABMs than `mcl_time.get_number_of_times()` and `mcl_time.get_number_of_times_at_pos()`!
It just calls `mcl_time.get_number_of_times_at_pos()` but doesn't return 0, the minimum number it can return is 1,
which is the most suitable for regular ABM processing function.
Returns:
* Integer number of how many times ABM function should be called if the area was active all the time and you didn't skip the night.
* Integer value of realtime (not in-game) seconds since world creation.

140
mods/CORE/mcl_time/init.lua Normal file
View File

@ -0,0 +1,140 @@
mcl_time = {}
local time_update_interval = 2
local retry_on_fail_interval = 500
local default_time_speed = 72
local save_to_storage_interval = 600
local meta_name = "_t"
local current_time_update_interval = time_update_interval
local storage = minetest.get_mod_storage()
local seconds_irl_public = tonumber(storage:get_string("seconds_irl")) or -2
local last_save_seconds_irl = seconds_irl_public
local next_save_seconds_irl = last_save_seconds_irl + save_to_storage_interval
local previous_seconds_irl = -2
local function get_seconds_irl()
local time_speed = tonumber(minetest.settings:get("time_speed") or default_time_speed)
if time_speed < 1 then
minetest.log("warning", "[mcl_time] time_speed < 1 - please increase to make mcl_time api work (default: " .. default_time_speed .. ")")
return 0
end
local irl_multiplier = 86400 / time_speed
local day_count = minetest.get_day_count()
local timeofday = minetest.get_timeofday()
local seconds_irl
if not day_count or not timeofday then
seconds_irl = seconds_irl_public
else
local days_ig = 0.0 + day_count + timeofday
seconds_irl = days_ig * irl_multiplier
end
if previous_seconds_irl == seconds_irl then
current_time_update_interval = math.min(current_time_update_interval * 2, retry_on_fail_interval)
minetest.log("warning", "[mcl_time] Time doesn't change! seconds_irl=" .. tostring(seconds_irl)
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
.. " - increasing update interval to " .. tostring(current_time_update_interval))
else
previous_seconds_irl = seconds_irl
if current_time_update_interval ~= time_update_interval then
current_time_update_interval = time_update_interval
minetest.log("action", "[mcl_time] Time is changing again: seconds_irl=" .. tostring(seconds_irl)
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
.. ", update_interval=" .. tostring(current_time_update_interval))
end
end
if last_save_seconds_irl >= next_save_seconds_irl then
storage:set_string("seconds_irl", tostring(seconds_irl))
next_save_seconds_irl = seconds_irl + save_to_storage_interval
end
return seconds_irl
end
local seconds_irl_public = get_seconds_irl()
function mcl_time.get_seconds_irl()
return seconds_irl_public
end
local function time_runner()
seconds_irl_public = get_seconds_irl()
minetest.after(current_time_update_interval, time_runner)
end
function mcl_time.get_number_of_times(last_time, interval, chance)
if not last_time then return 0 end
if seconds_irl_public < 2 then return 0 end
if not interval then return 0 end
if not chance then return 0 end
if interval < 1 then return 0 end
if chance < 1 then return 0 end
local number_of_intervals = (seconds_irl_public - last_time) / interval
if number_of_intervals < 1 then return 0 end
local average_chance = (1 + chance) / 2
local number_of_times = math.floor(number_of_intervals / average_chance)
return number_of_times, seconds_irl_public
end
local get_number_of_times = mcl_time.get_number_of_times
function mcl_time.touch(pos)
local meta = minetest.get_meta(pos)
meta:set_int(meta_name, seconds_irl_public)
end
local touch = mcl_time.touch
function mcl_time.get_number_of_times_at_pos(pos, interval, chance)
if not pos then return 0 end
local meta = minetest.get_meta(pos)
local last_time = meta:get_int(meta_name)
local number_of_times = (last_time == 0) and 0 or get_number_of_times(last_time, interval, chance)
touch(pos)
return number_of_times, seconds_irl_public
end
local get_number_of_times_at_pos = mcl_time.get_number_of_times_at_pos
function mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
return math.max(get_number_of_times_at_pos(pos, interval, chance), 1), seconds_irl_public
end
function mcl_time.get_irl_seconds_passed_at_pos(pos)
if not pos then return 0 end
local meta = minetest.get_meta(pos)
local last_time = meta:get_int(meta_name)
local irl_seconds_passed = (last_time == 0) and 0 or (seconds_irl_public - last_time)
return irl_seconds_passed
end
function mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
if not pos then return 1 end
local meta = minetest.get_meta(pos)
local last_time = meta:get_int(meta_name)
local irl_seconds_passed = (last_time == 0) and 1 or (seconds_irl_public - last_time)
return irl_seconds_passed
end
function mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
if not pos then return end
local meta = minetest.get_meta(pos)
local last_time = meta:get_int(meta_name)
if last_time == 0 then return end
local delta_time = seconds_irl_public - last_time
if delta_time <= 0 then return end
return delta_time
end
time_runner()
local day_count = minetest.get_day_count()
local timeofday = minetest.get_timeofday()
minetest.log("action", "[mcl_time] time runner started, current in-real-life seconds: " .. seconds_irl_public
.. ", time_speed: " .. tostring(minetest.settings:get("time_speed"))
.. ", day_count: " .. tostring(day_count)
.. ", timeofday: " .. tostring(timeofday)
.. ", update_interval=" .. tostring(current_time_update_interval)
)

View File

@ -0,0 +1,3 @@
name = mcl_time
author = kay27
description = This mod counts time when all players sleep or some area is inactive

View File

@ -112,7 +112,9 @@ local function detach_object(obj, change_pos)
mcl_player.player_attached[obj:get_player_name()] = false
mcl_player.player_set_animation(obj, "stand" , 30)
else
obj:get_luaentity()._old_visual_size = nil
local luaentity = obj:get_luaentity()
if not luaentity then return end
luaentity._old_visual_size = nil
end
if change_pos then
obj:set_pos(vector.add(obj:get_pos(), vector.new(0, 0.2, 0)))

View File

@ -16,7 +16,11 @@ dofile(modpath .. "/api.lua")
minetest.register_globalstep(function(dtime)
for _, player in pairs(get_connected_players()) do
local storage = mcl_burning.storage[player]
if not mcl_burning.tick(player, dtime, storage or {}) and not mcl_burning.is_affected_by_rain(player) then
if not storage then
mcl_burning.init_player(player)
storage = mcl_burning.storage[player]
end
if not mcl_burning.tick(player, dtime, storage) and not mcl_burning.is_affected_by_rain(player) then
local nodes = mcl_burning.get_touching_nodes(player, {"group:puts_out_fire", "group:set_on_fire"}, storage)
local burn_time = 0

View File

@ -27,6 +27,11 @@ local mcl_item_entity = {}
local item_drop_settings = {} --settings table
item_drop_settings.dug_buffer = 0.65 -- the warm up period before a dug item can be collected
item_drop_settings.age = 1.0 --how old a dropped item (_insta_collect==false) has to be before collecting
item_drop_settings.fluid_flow_rate = 1.39 --the speed of a flowing fluid, used when computing push and drag forces of water on items; default is tuned to Minecraft
item_drop_settings.fluid_drag = 1.8 --how much drag water has on items (how quickly an item's motion will settle onto the water's flow speed)
item_drop_settings.ground_drag = 3.0 --how much friction with the ground slows items sliding on it
item_drop_settings.slippery_drag_factor = 0.25 --scales item friction with the ground on slippery floors (e.g. ice)
item_drop_settings.slippery_fluid_drag_factor = 0.4 --scales item drag with waterflow on slippery floors (e.g. ice)
item_drop_settings.radius_magnet = 2.0 --radius of item magnet. MUST BE LARGER THAN radius_collect!
item_drop_settings.xp_radius_magnet = 7.25 --radius of xp magnet. MUST BE LARGER THAN radius_collect!
item_drop_settings.radius_collect = 0.2 --radius of collection
@ -780,11 +785,35 @@ minetest.register_entity(":__builtin:item", {
-- Just to make sure we don't manipulate the speed for no reason
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
local f = 1.39
-- Set new item moving speed into the direciton of the liquid
local newv = vector.multiply(vec, f)
local f = item_drop_settings.fluid_flow_rate --1.39
-- Apply the force of the flowing liquid onto the item's velocity
local newv = vector.multiply(vec, f)
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = newv.x, y = -0.22, z = newv.z})
local oldvel = self.object:get_velocity() -- v is vector, vel is velocity
-- drag
local fluid_drag = item_drop_settings.fluid_drag
local floornn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
local floornode = floornn and minetest.registered_nodes[floornn]
if floornode and minetest.get_item_group(floornode.name, "slippery") then
-- scale fluid drag on slippery floors
fluid_drag = fluid_drag * item_drop_settings.slippery_fluid_drag_factor
end
newv.x = newv.x - (oldvel.x - newv.x) * fluid_drag * dtime
newv.y = newv.y - (oldvel.y - newv.y) * fluid_drag * dtime
newv.z = newv.z - (oldvel.z - newv.z) * fluid_drag * dtime
newv.y = newv.y + -0.22 -- (keep slight downward thrust from previous version of code)
-- NOTE: is there any particular reason we have this, anyway?
-- since fluid drag is now on, we could as well just
-- apply gravity here; drag will slow down the fall
-- realistically
self.object:set_velocity({x = oldvel.x + newv.x * dtime, y = oldvel.y + newv.y * dtime, z = oldvel.z + newv.z * dtime})
self.physical_state = true
self._flowing = true
@ -796,15 +825,17 @@ minetest.register_entity(":__builtin:item", {
elseif self._flowing == true then
-- Disable flowing physics if not on/in flowing liquid
self._flowing = false
enable_physics(self.object, self, true)
--enable_physics(self.object, self, true) -- do not reset velocity upon leaving water!
self.object:set_acceleration({x=0,y=-get_gravity(),z=0}) -- resume applying gravity
return
end
-- If node is not registered or node is walkably solid and resting on nodebox
local nn = minetest.get_node({x=p.x, y=p.y-0.5, z=p.z}).name
local v = self.object:get_velocity()
local node = nn and minetest.registered_nodes[nn]
if not minetest.registered_nodes[nn] or minetest.registered_nodes[nn].walkable and v.y == 0 then
if not node or node.walkable and v.y == 0 then
if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item
@ -817,7 +848,28 @@ minetest.register_entity(":__builtin:item", {
end
end
end
disable_physics(self.object, self)
--disable_physics(self.object, self)
-- apply ground drag
local oldvel = self.object:get_velocity()
-- ignore momentum if it's tiny
if math.abs(oldvel.x) < 0.05 and math.abs(oldvel.z) < 0.05 then
disable_physics(self.object, self)
return
end
local ground_drag = item_drop_settings.ground_drag
if node and minetest.get_item_group(node.name, "slippery") ~= 0 then
ground_drag = ground_drag * item_drop_settings.slippery_drag_factor
end
local newvel = {
x = oldvel.x - oldvel.x * ground_drag * dtime,
y = 0,
z = oldvel.z - oldvel.z * ground_drag * dtime
}
self.object:set_velocity(newvel)
end
else
if self._magnet_active == false then

View File

@ -893,6 +893,17 @@ function mobs.mob_step(self, dtime)
end
end
--water damage
if self.water_damage and self.water_damage ~= 0 then
local pos = self.object:get_pos()
local node = minetest_get_node(pos).name
if minetest_get_item_group(node, "water") ~= 0 then
mobs.smoke_effect(self)
self.health = self.health - self.water_damage
self:teleport()
end
end
--set mobs on fire when burned by sunlight
if self.ignited_by_sunlight then
local pos = self.object:get_pos()

View File

@ -147,4 +147,24 @@ mobs.breeding_effect = function(self)
vertical = false,
texture = "heart.png",
})
end
end
mobs.smoke_effect = function(self)
local pos = self.object:get_pos()
minetest.add_particlespawner({
amount = 5,
time = 0.25,
minpos = pos,
maxpos = pos,
minvel = {x = -1, y = -1, z = -1},
maxvel = {x = 1, y = 1, z = 1},
minacc = {x = 0, y = 10, z = 0},
maxacc = {x = 0, y = 10, z = 0},
minexptime = 0.1,
maxexptime = 1,
minsize = 0.5,
maxsize = 1,
collisiondetection = false,
texture = "mcl_particles_smoke.png",
})
end

View File

@ -1,2 +0,0 @@
mcl_mobs
mcl_potions

View File

@ -260,9 +260,22 @@ local dispenserdef = {
end
else
-- Drop item otherwise
minetest.add_item(droppos, dropitem)
stack:take_item()
inv:set_stack("main", stack_id, stack)
-- Drop item normally
local dropitemobj = minetest.add_item(droppos, dropitem)
stack:take_item()
inv:set_stack("main", stack_id, stack)
-- Set item velocity (overrides the default random drop direction)
local shoot_force = 1.3
local newv = minetest.facedir_to_dir(node.param2)
newv = {
x = newv.x * shoot_force,
y = newv.y * shoot_force,
z = newv.z * shoot_force
}
dropitemobj:set_velocity(newv)
end
end

View File

@ -134,9 +134,21 @@ local dropperdef = {
-- No container?
if not dropped and not dropnodedef.groups.container then
-- Drop item normally
minetest.add_item(droppos, dropitem)
local dropitemobj = minetest.add_item(droppos, dropitem)
stack:take_item()
inv:set_stack("main", stack_id, stack)
-- Set item velocity (overrides the default random drop direction)
local shoot_force = 1.3
local newv = minetest.facedir_to_dir(node.param2)
newv = {
x = -newv.x * shoot_force,
y = -newv.y * shoot_force,
z = -newv.z * shoot_force
}
dropitemobj:set_velocity(newv)
end
end
end,

View File

@ -506,6 +506,7 @@ function ARROW_ENTITY.on_activate(self, staticdata, dtime_s)
end
minetest.register_on_respawnplayer(function(player)
if not player.get_children then return end
for _, obj in pairs(player:get_children()) do
local ent = obj:get_luaentity()
if ent and ent.name and string.find(ent.name, "mcl_bows:arrow_entity") then

View File

@ -1,4 +1,6 @@
local S = minetest.get_translator(minetest.get_current_modname())
local F = minetest.formspec_escape
local C = minetest.colorize
local mod_doc = minetest.get_modpath("doc")
-- Chest Entity
@ -174,7 +176,7 @@ end]]
local function player_chest_open(player, pos, node_name, textures, param2, double, sound, mesh, shulker)
local name = player:get_player_name()
open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double, sound = sound, mesh = mesh, shulker = shulker}
if animate_chests then
if animate_chests and not string.find(node_name, "barrel") then
local dir = minetest.facedir_to_dir(param2)
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh, shulker and "shulker" or "chest", dir):open(name)
end
@ -226,6 +228,8 @@ local function chest_update_after_close(pos)
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
elseif node.name == "mcl_chests:barrel_open" then
minetest.swap_node(pos, {name = "mcl_chests:barrel", param2 = node.param2})
end
end
@ -236,7 +240,7 @@ local function player_chest_close(player)
if open_chest == nil then
return
end
if animate_chests then
if animate_chests and not string.find(open_chest.node_name, "barrel") then
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh, open_chest.shulker and "shulker" or "chest"):close(name)
end
chest_update_after_close(open_chest.pos)
@ -291,27 +295,40 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
end
end
local function drop_items_chest(pos, oldnode, oldmetadata)
local meta = minetest.get_meta(pos)
local meta2 = meta:to_table()
if oldmetadata then
meta:from_table(oldmetadata)
end
local inv = meta:get_inventory()
for i=1,inv:get_size("main") do
local stack = inv:get_stack("main", i)
if not stack:is_empty() then
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
minetest.add_item(p, stack)
end
end
meta:from_table(meta2)
local function drop_item_stack(pos, stack)
if not stack or stack:is_empty() then return end
local drop_offset = vector.new(math.random() - 0.5, 0, math.random() - 0.5)
minetest.add_item(vector.add(pos, drop_offset), stack)
end
local function on_chest_blast(pos)
local function drop_items_chest(pos, oldnode, oldmetadata, digger)
if oldmetadata and oldmetadata.inventory then
-- process after_dig_node callback
local main = oldmetadata.inventory.main
if not main then return end
for _, stack in pairs(main) do
drop_item_stack(pos, stack)
end
else
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
for i = 1, inv:get_size("main") do
drop_item_stack(pos, inv:get_stack("main", i))
end
meta:from_table()
end
end
local function on_chest_blast(pos, intensity)
local node = minetest.get_node(pos)
drop_items_chest(pos, node)
minetest.remove_node(pos)
-- drop node itself with some probability depended on explosion intensity (1 for TNT):
if math.random(1, math.floor((intensity or 1) * 2)) ~= 1 then return end
local node_def = minetest.registered_nodes[node.name]
if not node_def then return end
local node_name = node_def.drop or node_def.name
drop_item_stack(pos, ItemStack(node_name))
end
local function limit_put_list(stack, list)
@ -478,10 +495,10 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"label[0,0;"..F(C("#313131", name)).."]"..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"label[0,4.0;"..F(C("#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;]"..
@ -629,12 +646,12 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
minetest.show_formspec(clicker:get_player_name(),
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[9,11.5]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"label[0,0;"..F(C("#313131", name)).."]"..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,3.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,3.5,9,3)..
"label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"label[0,7;"..F(C("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,7.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,7.5,9,3)..
"list[current_player;main;0,10.75;9,1;]"..
@ -777,12 +794,12 @@ local function register_chest(basename, desc, longdesc, usagehelp, tt_help, tile
"mcl_chests:"..canonical_basename.."_"..pos.x.."_"..pos.y.."_"..pos.z,
"size[9,11.5]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"label[0,0;"..F(C("#313131", name)).."]"..
"list[nodemeta:"..pos_other.x..","..pos_other.y..","..pos_other.z..";main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,3.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,3.5,9,3)..
"label[0,7;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"label[0,7;"..F(C("#313131", S("Inventory"))).."]"..
"list[current_player;main;0,7.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,7.5,9,3)..
"list[current_player;main;0,10.75;9,1;]"..
@ -902,38 +919,6 @@ register_chest("trapped_chest_on",
"trapped_chest"
)
--[[local function close_if_trapped_chest(pos, player)
local node = minetest.get_node(pos)
if node.name == "mcl_chests:trapped_chest_on_small" then
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_small", param2 = node.param2})
find_or_create_entity(pos, "mcl_chests:trapped_chest_small", {"mcl_chests_trapped.png"}, node.param2, false, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_small")
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
player_chest_close(player)
elseif node.name == "mcl_chests:trapped_chest_on_left" then
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
find_or_create_entity(pos, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "left")
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_right", param2 = node.param2})
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
player_chest_close(player)
elseif node.name == "mcl_chests:trapped_chest_on_right" then
minetest.swap_node(pos, {name="mcl_chests:trapped_chest_right", param2 = node.param2})
mesecon.receptor_off(pos, trapped_chest_mesecons_rules)
local pos_other = mcl_util.get_double_container_neighbor_pos(pos, node.param2, "right")
minetest.swap_node(pos_other, {name="mcl_chests:trapped_chest_left", param2 = node.param2})
find_or_create_entity(pos_other, "mcl_chests:trapped_chest_left", {"mcl_chests_trapped_double.png"}, node.param2, true, "default_chest", "mcl_chests_chest", "chest"):reinitialize("mcl_chests:trapped_chest_left")
mesecon.receptor_off(pos_other, trapped_chest_mesecons_rules)
player_chest_close(player)
end
end]]
-- Disable chest when it has been closed
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname:find("mcl_chests:") == 1 then
@ -990,10 +975,10 @@ minetest.register_node("mcl_chests:ender_chest", {
})
local formspec_ender_chest = "size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Ender Chest"))).."]"..
"label[0,0;"..F(C("#313131", S("Ender Chest"))).."]"..
"list[current_player;enderchest;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"label[0,4.0;"..F(C("#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;]"..
@ -1125,10 +1110,10 @@ local function formspec_shulker_box(name)
name = S("Shulker Box")
end
return "size[9,8.75]"..
"label[0,0;"..minetest.formspec_escape(minetest.colorize("#313131", name)).."]"..
"label[0,0;"..F(C("#313131", name)).."]"..
"list[context;main;0,0.5;9,3;]"..
mcl_formspec.get_itemslot_bg(0,0.5,9,3)..
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
"label[0,4.0;"..F(C("#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;]"..
@ -1436,3 +1421,95 @@ minetest.register_lbm({
minetest.get_meta(pos):set_string("formspec", "")
end,
})
local function barrel_open(pos, node, clicker)
local name = minetest.get_meta(pos):get_string("name")
if name == "" then
name = S("Barrel")
end
local playername = clicker:get_player_name()
minetest.show_formspec(playername,
"mcl_chests:barrel_"..pos.x.."_"..pos.y.."_"..pos.z,
table.concat({
"size[9,8.75]",
"label[0,0;"..F(C("#313131", name)).."]",
"list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;0,0.5;9,3;]",
mcl_formspec.get_itemslot_bg(0, 0.5, 9, 3),
"label[0,4.0;"..F(C("#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),
"listring[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main]",
"listring[current_player;main]",
})
)
minetest.swap_node(pos, { name = "mcl_chests:barrel_open", param2 = node.param2 })
player_chest_open(clicker, pos, "mcl_chests:barrel")
end
minetest.register_node("mcl_chests:barrel", {
description = S("Barrel"),
_tt_help = S("27 inventory slots"),
_doc_items_longdesc = S("Barrels are containers which provide 27 inventory slots."),
_doc_items_usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."),
tiles = {"mcl_barrels_barrel_top.png", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"},
paramtype = "light",
paramtype2 = "facedir",
on_place = function(itemstack, placer, pointed_thing)
minetest.rotate_and_place(itemstack, placer, pointed_thing, minetest.is_creative_enabled(placer:get_player_name()), {}, false)
return itemstack
end,
stack_max = 64,
sounds = mcl_sounds.node_sound_wood_defaults(),
groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("main", 9*3)
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.get_meta(pos):set_string("name", itemstack:get_meta():get_string("name"))
end,
after_dig_node = drop_items_chest,
on_blast = on_blast,
on_rightclick = barrel_open,
on_destruct = close_forms,
_mcl_blast_resistance = 2.5,
_mcl_hardness = 2.5,
})
minetest.register_node("mcl_chests:barrel_open", {
description = S("Barrel Open"),
_tt_help = S("27 inventory slots"),
_doc_items_longdesc = S("Barrels are containers which provide 27 inventory slots."),
_doc_items_usagehelp = S("To access its inventory, rightclick it. When broken, the items will drop out."),
_doc_items_create_entry = false,
tiles = {"mcl_barrels_barrel_top_open.png", "mcl_barrels_barrel_bottom.png", "mcl_barrels_barrel_side.png"},
paramtype = "light",
paramtype2 = "facedir",
drop = "mcl_chests:barrel",
stack_max = 64,
sounds = mcl_sounds.node_sound_wood_defaults(),
groups = {handy = 1, axey = 1, container = 2, material_wood = 1, flammable = -1, deco_block = 1, not_in_creative_inventory = 1},
after_dig_node = drop_items_chest,
on_blast = on_blast,
on_rightclick = barrel_open,
on_destruct = close_forms,
_mcl_blast_resistance = 2.5,
_mcl_hardness = 2.5,
})
--Minecraft Java Edition craft
minetest.register_craft({
output = "mcl_chests:barrel",
recipe = {
{"group:wood", "group:wood_slab", "group:wood"},
{"group:wood", "", "group:wood"},
{"group:wood", "group:wood_slab", "group:wood"},
}
})

View File

@ -34,3 +34,5 @@ Can be combined to a large chest=Peut être combiné à un grand coffre
27 interdimensional inventory slots=27 emplacements d'inventaire interdimensionnels
Put items inside, retrieve them from any ender chest=Mettez des objets à l'intérieur, récupérez-les dans n'importe quel coffre
Emits a redstone signal when opened=Émet un signal redstone à l'ouverture
Barrel=Tonneau
Barrels are containers which provide 27 inventory slots.=Les tonneaux sont des conteneurs qui offrent 27 emplacements d'inventaire.

View File

@ -34,3 +34,5 @@ Can be combined to a large chest=Можно объединить в большо
27 interdimensional inventory slots=27 межпространственных отсеков инвентаря
Put items inside, retrieve them from any ender chest=Положите внутрь предмет и получите его из любого сундука Предела
Emits a redstone signal when opened=Подаёт сигнал редстоуна, будучи открытым
Barrel=Бочка
Barrels are containers which provide 27 inventory slots.=Бочки это хранилища, предоставляющие 27 отсеков инвентаря.

View File

@ -34,3 +34,5 @@ Can be combined to a large chest=
27 interdimensional inventory slots=
Put items inside, retrieve them from any ender chest=
Emits a redstone signal when opened=
Barrel=
Barrels are containers which provide 27 inventory slots.=

View File

@ -1,3 +1,4 @@
name = mcl_chests
author = Wuzzy, Fleckenstein, AFCMS
depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_end, mesecons
optional_depends = doc, screwdriver

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

View File

@ -655,7 +655,7 @@ mcl_enchanting.enchantments.soul_speed = {
mcl_enchanting.enchantments.unbreaking = {
name = S("Unbreaking"),
max_level = 3,
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true, pickaxe = true, shovel = true, axe = true, hoe = true, sword = true, fishing_rod = true, bow = true},
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true, crossbow = true, pickaxe = true, shovel = true, axe = true, hoe = true, sword = true, fishing_rod = true, bow = true},
secondary = {tool = true},
disallow = {non_combat_armor = true},
incompatible = {},

View File

@ -215,62 +215,11 @@ local function swap_node(pos, name)
end
end
local function furnace_reset_delta_time(pos)
local meta = minetest.get_meta(pos)
local time_speed = tonumber(minetest.settings:get("time_speed") or 72)
if (time_speed < 0.1) then
return
end
local time_multiplier = 86400 / time_speed
local current_game_time = .0 + ((minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier)
-- TODO: Change meta:get/set_string() to get/set_float() for "last_gametime".
-- In Windows *_float() works OK but under Linux it returns rounded unusable values like 449540.000000000
local last_game_time = meta:get_string("last_gametime")
if last_game_time then
last_game_time = tonumber(last_game_time)
end
if not last_game_time or last_game_time < 1 or math.abs(last_game_time - current_game_time) <= 1.5 then
return
end
meta:set_string("last_gametime", tostring(current_game_time))
end
local function furnace_get_delta_time(pos, elapsed)
local meta = minetest.get_meta(pos)
local time_speed = tonumber(minetest.settings:get("time_speed") or 72)
local current_game_time
if (time_speed < 0.1) then
return meta, elapsed
else
local time_multiplier = 86400 / time_speed
current_game_time = .0 + ((minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier)
end
local last_game_time = meta:get_string("last_gametime")
if last_game_time then
last_game_time = tonumber(last_game_time)
end
if not last_game_time or last_game_time < 1 then
last_game_time = current_game_time - 0.1
elseif last_game_time == current_game_time then
current_game_time = current_game_time + 1.0
end
local elapsed_game_time = .0 + current_game_time - last_game_time
meta:set_string("last_gametime", tostring(current_game_time))
return meta, elapsed_game_time
end
local function furnace_node_timer(pos, elapsed)
--
-- Inizialize metadata
--
local meta, elapsed_game_time = furnace_get_delta_time(pos, elapsed)
local meta = minetest.get_meta(pos)
local fuel_time = meta:get_float("fuel_time") or 0
local src_time = meta:get_float("src_time") or 0
local src_item = meta:get_string("src_item") or ""
@ -294,6 +243,7 @@ local function furnace_node_timer(pos, elapsed)
end
local update = true
local elapsed_game_time = mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos) or elapsed
while elapsed_game_time > 0.00001 and update do
--
-- Cooking
@ -489,20 +439,20 @@ minetest.register_node("mcl_furnaces:furnace", {
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
-- Reset accumulated game time when player works with furnace:
furnace_reset_delta_time(pos)
mcl_time.touch(pos)
minetest.get_node_timer(pos):start(1.0)
on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
end,
on_metadata_inventory_put = function(pos)
-- Reset accumulated game time when player works with furnace:
furnace_reset_delta_time(pos)
mcl_time.touch(pos)
-- start timer function, it will sort out whether furnace can burn or not.
minetest.get_node_timer(pos):start(1.0)
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
-- Reset accumulated game time when player works with furnace:
furnace_reset_delta_time(pos)
mcl_time.touch(pos)
-- start timer function, it will helpful if player clears dst slot
minetest.get_node_timer(pos):start(1.0)

View File

@ -1,3 +1,3 @@
name = mcl_furnaces
depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_craftguide, mcl_achievements, mcl_particles
depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_craftguide, mcl_achievements, mcl_particles, mcl_time
optional_depends = doc, screwdriver

View File

@ -1,3 +1,3 @@
name = mcl_nether
depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items, mcl_colors
depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items, mcl_colors, mcl_time
optional_depends = doc, screwdriver

View File

@ -6,21 +6,6 @@ local interval = 35
local chance = 11
local max_interval = interval * chance
local time_speed
local time_multiplier
local current_game_time
function update_timespeed()
time_speed = tonumber(minetest.settings:get("time_speed") or 72)
time_multiplier = 86400 / time_speed
current_game_time = .0 + ((minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier)
minetest.after(5, update_timespeed)
end
minetest.register_on_mods_loaded(function()
minetest.after(5, update_timespeed)
end)
minetest.register_node("mcl_nether:nether_wart_0", {
description = S("Premature Nether Wart (Stage 1)"),
_doc_items_longdesc = S("A premature nether wart has just recently been planted on soul sand. Nether wart slowly grows on soul sand in 4 stages (the second and third stages look identical). Although nether wart is home to the Nether, it grows in any dimension."),
@ -183,6 +168,9 @@ local function grow(pos, node)
new_node.param = node.param
new_node.param2 = node.param2
minetest.set_node(pos, new_node)
local meta = minetest.get_meta(pos)
meta:set_string("gametime", tostring(mcl_time:get_seconds_irl()))
end
minetest.register_abm({
@ -197,9 +185,10 @@ minetest.register_abm({
return
end
pos.y = pos.y+1
grow(pos, node)
local meta = minetest.get_meta(pos)
meta:set_string("gametime", tostring(current_game_time))
for i = 1, mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance) do
grow(pos, node)
end
end
})
@ -214,26 +203,14 @@ minetest.register_lbm({
return
end
pos.y = pos.y+1
local meta = minetest.get_meta(pos)
local last_game_time = tonumber(meta:get_string("gametime"))
if not last_game_time then return end
local real_seconds = last_game_time - current_game_time
if real_seconds < interval then return end
local threshold = math.random(interval, max_interval)
local i = 0
while real_seconds >= threshold and i < 4 do
for i = 1, mcl_time.get_number_of_times_at_pos(pos, interval, chance) do
grow(pos, node)
real_seconds = real_seconds - threshold
threshold = math.random(interval, max_interval)
i = i + 1
end
end
})
if minetest.get_modpath("doc") then
for i=1,2 do
for i=1, 2 do
doc.add_entry_alias("nodes", "mcl_nether:nether_wart_0", "nodes", "mcl_nether:nether_wart_"..i)
end
end

View File

@ -92,7 +92,6 @@ end
local function set_texture(player, index, texture)
local textures = player_textures[player:get_player_name()]
if not textures then
-- TODO: Check if minetest.register_on_joinplayer() shouldn't really work in minetest 5.1.1?
player_textures[player:get_player_name()] = {"blank.png", "blank.png", "blank.png"}
textures = player_textures[player:get_player_name()]
end