This commit is contained in:
Elias Fleckenstein 2021-04-04 12:01:59 +02:00
commit ff538d51bd
41 changed files with 1127 additions and 375 deletions

@ -1,5 +1,8 @@
# This is a game specific minetest.conf file, do not edit
# If any of these settings are set in your minetest.conf file in ~/.minetest (Linux) or in the root directory of the game (Run in place/Windows)
# They will override these settings
# Basic game rules
time_speed = 72
@ -33,7 +36,7 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
keepInventory = false
# Performance settings
# dedicated_server_step = 0.001
dedicated_server_step = 0.05 #tick rate
# abm_interval = 0.25
# max_objects_per_block = 4096
# max_packets_per_iteration = 10096

23
mods/CORE/controls/API.md Normal file

@ -0,0 +1,23 @@
# controls
## controls.players
Table containing player controls at runtime.
WARNING: Never use this table in writing
## controls.register_on_press(func)
Register a function that will be executed with (player, keyname) every time a player press a key.
## controls.registered_on_press
Table containing functions registered with controls.register_on_press().
## controls.register_on_release(func)
Register a function that will be executed with (player, keyname, clock_from_last_press) every time a player release a key.
## controls.registered_on_release
Table containing functions registered with controls.register_on_release().
## controls.register_on_hold(func)
Register a function that will be executed with (player, keyname, clock_from_start_hold) every time a player hold a key.
## controls.registered_on_hold
Table containing functions registered with controls.register_on_hold().

45
mods/CORE/flowlib/API.md Normal file

@ -0,0 +1,45 @@
# flowlib
Simple flow functions.
## flowlib.is_touching(realpos, nodepos, radius)
Return true if a sphere of <radius> at <realpos> collide with node at <nodepos>.
* realpos: position
* nodepos: position
* radius: number
## flowlib.is_water(pos)
Return true if node at <pos> is water, false overwise.
* pos: position
## flowlib.node_is_water(node)
Return true if <node> is water, false overwise.
* node: node
## flowlib.is_lava(pos)
Return true if node at <pos> is lava, false overwise.
* pos: position
## flowlib.node_is_lava(node)
Return true if <node> is lava, false overwise.
* node: node
## flowlib.is_liquid(pos)
Return true if node at <pos> is liquid, false overwise.
* pos: position
## flowlib.node_is_liquid(node)
Return true if <node> is liquid, false overwise.
* node: node
## flowlib.quick_flow(pos, node)
Return direction where the water is flowing (to be use to push mobs, items...).
* pos: position
* node: node
## flowlib.move_centre(pos, realpos, node, radius)
Return the pos of the nearest not water block near from <pos> in a sphere of <radius> at <realpos>.
WARNING: This function is never used in mcl2, use at your own risk. The informations described here may be wrong.
* pos: position
* realpos: position, position of the entity
* node: node
* radius: number

@ -0,0 +1,27 @@
# mcl_autogroup
This mod emulate digging times from mc.
## mcl_autogroup.can_harvest(nodename, toolname)
Return true if <nodename> can be dig with <toolname>.
* nodename: string, valid nodename
* toolname: (optional) string, valid toolname
## mcl_autogroup.get_groupcaps(toolname, efficiency)
This function is used to calculate diggroups for tools.
WARNING: This function can only be called after mod initialization.
* toolname: string, name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
* efficiency: (optional) integer, the efficiency level the tool is enchanted with (default 0)
## mcl_autogroup.get_wear(toolname, diggroup)
Return the max wear of <toolname> with <diggroup>
WARNING: This function can only be called after mod initialization.
* toolname: string, name of the tool used
* diggroup: string, the name of the diggroup the tool is used on
## mcl_autogroup.register_diggroup(group, def)
* group: string, name of the group to register as a digging group
* def: (optional) table, table with information about the diggroup (defaults to {} if unspecified)
* level: (optional) string, if specified it is an array containing the names of the different digging levels the digging group supports
## mcl_autogroup.registered_diggroups
List of registered diggroups, indexed by name.

@ -0,0 +1,8 @@
# mcl_colors
Mod providing global table containing legacity minecraft colors to be used in mods.
## mcl_colors.*
Colors by upper name, in hex value.
## mcl_colors.background.*
Background colors by upper name, in hex value.

@ -0,0 +1,15 @@
# mcl_explosions
This mod provide helper functions to create explosions.
## mcl_explosions.explode(pos, strength, info, puncher)
* pos: position, initial position of the explosion
* strenght: number, radius of the explosion
* info: table, explosion informations:
* drop_chance: number, if specified becomes the drop chance of all nodes in the explosion (default: 1.0 / strength)
* max_blast_resistance: int, if specified the explosion will treat all non-indestructible nodes as having a blast resistance of no more than this value
* sound: bool, if true, the explosion will play a sound (default: true)
* particles: bool, if true, the explosion will create particles (default: true)
* fire: bool, if true, 1/3 nodes become fire (default: false)
* griefing: bool, if true, the explosion will destroy nodes (default: true)
* grief_protected: bool, if true, the explosion will also destroy nodes which have been protected (default: false)
* puncher: (optional) entity, will be used as source for damage done by the explosion

@ -0,0 +1,80 @@
# mcl_worlds
This mod provides utility functions about positions and dimensions.
## mcl_worlds.is_in_void(pos)
This function returns:
* true, true: if pos is in deep void (deadly)
* true, false: if the pos is in void (non deadly)
* false, false: owerwise
Params:
* pos: position
## mcl_worlds.y_to_layer(y)
This function is used to calculate the minetest y layer and dimension of the given <y> minecraft layer.
Mainly used for ore generation.
Takes an Y coordinate as input and returns:
* The corresponding Minecraft layer (can be nil if void)
* The corresponding Minecraft dimension ("overworld", "nether" or "end") or "void" if <y> is in the void
If the Y coordinate is not located in any dimension, it will return: nil, "void"
Params:
* y: int
## mcl_worlds.pos_to_dimension(pos)
This function return the Minecraft dimension of <pos> ("overworld", "nether" or "end") or "void" if <y> is in the void.
* pos: position
## mcl_worlds.layer_to_y(layer, mc_dimension)
Takes a Minecraft layer and a “dimension” name and returns the corresponding Y coordinate for MineClone 2.
mc_dimension can be "overworld", "nether", "end" (default: "overworld").
* layer: int
* mc_dimension: string
## mcl_worlds.has_weather(pos)
Returns true if <pos> can have weather, false owerwise.
Weather can be only in the overworld.
* pos: position
## mcl_worlds.has_dust(pos)
Returns true if <pos> can have nether dust, false owerwise.
Nether dust can be only in the nether.
* pos: position
## mcl_worlds.compass_works(pos)
Returns true if compasses are working at <pos>, false owerwise.
In mc, you cant use compass in the nether and the end.
* pos: position
## mcl_worlds.compass_works(pos)
Returns true if clock are working at <pos>, false owerwise.
In mc, you cant use clock in the nether and the end.
* pos: position
## mcl_worlds.register_on_dimension_change(function(player, dimension))
Register a callback function func(player, dimension).
It will be called whenever a player changes between dimensions.
The void counts as dimension.
* player: player, the player who changed the dimension
* dimension: position, The new dimension of the player ("overworld", "nether", "end", "void").
## mcl_worlds.registered_on_dimension_change
Table containing all function registered with mcl_worlds.register_on_dimension_change()
## mcl_worlds.dimension_change(player, dimension)
Notify this mod of a dimmension change of <player> to <dimension>
* player: player, player who changed the dimension
* dimension: string, new dimension ("overworld", "nether", "end", "void")

@ -1,6 +1,6 @@
local S = minetest.get_translator("mcl_boats")
local boat_visual_size = {x = 3, y = 3, z = 3}
local boat_visual_size = {x = 1, y = 1, z = 1}
local paddling_speed = 22
local boat_y_offset = 0.35
local boat_y_offset_ground = boat_y_offset + 0.6

@ -1,14 +1,36 @@
--these are lua locals, used for higher performance
local minetest,math,vector,ipairs = minetest,math,vector,ipairs
--this is used for the player pool in the sound buffer
local pool = {}
local tick = false
minetest.register_on_joinplayer(function(player)
local name
name = player:get_player_name()
pool[name] = 0
end)
minetest.register_on_leaveplayer(function(player)
local name
name = player:get_player_name()
pool[name] = nil
end)
local has_awards = minetest.get_modpath("awards")
mcl_item_entity = {}
local mcl_item_entity = {}
--basic settings
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.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
item_drop_settings.player_collect_height = 1.0 --added to their pos y value
item_drop_settings.player_collect_height = 0.8 --added to their pos y value
item_drop_settings.collection_safety = false --do this to prevent items from flying away on laggy servers
item_drop_settings.random_item_velocity = true --this sets random item velocity if velocity is 0
item_drop_settings.drop_single_item = false --if true, the drop control drops 1 item instead of the entire stack, and sneak+drop drops the stack
@ -74,103 +96,71 @@ local disable_physics = function(object, luaentity, ignore_check, reset_movement
end
end
minetest.register_globalstep(function(dtime)
tick = not tick
for _,player in pairs(minetest.get_connected_players()) do
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
local name = player:get_player_name()
local pos = player:get_pos()
if tick == true and pool[name] > 0 then
minetest.sound_play("item_drop_pickup", {
pos = pos,
gain = 0.7,
max_hear_distance = 16,
pitch = math.random(70,110)/100
})
if pool[name] > 6 then
pool[name] = 6
else
pool[name] = pool[name] - 1
end
end
local inv = player:get_inventory()
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
--magnet and collection
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
local collected = false
if object:get_luaentity()._magnet_timer >= 0 and object:get_luaentity()._magnet_timer < item_drop_settings.magnet_time and inv and inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
-- Collection
if vector.distance(checkpos, object:get_pos()) <= item_drop_settings.radius_collect and not object:get_luaentity()._removed then
if not object:get_luaentity()._removed then
-- Ignore if itemstring is not set yet
if object:get_luaentity().itemstring ~= "" then
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
minetest.sound_play("item_drop_pickup", {
pos = pos,
max_hear_distance = 16,
gain = 1.0,
}, true)
check_pickup_achievements(object, player)
check_pickup_achievements(object, player)
-- Destroy entity
-- This just prevents this section to be run again because object:remove() doesn't remove the item immediately.
object:get_luaentity().target = checkpos
object:get_luaentity()._removed = true
object:set_velocity({x=0,y=0,z=0})
object:set_acceleration({x=0,y=0,z=0})
object:move_to(checkpos)
pool[name] = pool[name] + 1
minetest.after(0.25, function()
--safety check
if object and object:get_luaentity() then
object:remove()
collected = true
end
-- Magnet
else
object:get_luaentity()._magnet_active = true
object:get_luaentity()._collector_timer = 0
-- Move object to player
disable_physics(object, object:get_luaentity())
local opos = object:get_pos()
local vec = vector.subtract(checkpos, opos)
vec = vector.add(opos, vector.divide(vec, 2))
object:move_to(vec)
--fix eternally falling items
minetest.after(0, function(object)
local lua = object:get_luaentity()
if lua then
object:set_acceleration({x=0, y=0, z=0})
end)
end
end, object)
--this is a safety to prevent items flying away on laggy servers
if item_drop_settings.collection_safety == true then
if object:get_luaentity().init ~= true then
object:get_luaentity().init = true
minetest.after(1, function(args)
local playername = args[1]
local player = minetest.get_player_by_name(playername)
local object = args[2]
local lua = object:get_luaentity()
if player == nil or not player:is_player() or object == nil or lua == nil or lua.itemstring == nil then
return
end
if inv:room_for_item("main", ItemStack(object:get_luaentity().itemstring)) then
inv:add_item("main", ItemStack(object:get_luaentity().itemstring))
if not object:get_luaentity()._removed then
minetest.sound_play("item_drop_pickup", {
pos = pos,
max_hear_distance = 16,
gain = 1.0,
}, true)
end
check_pickup_achievements(object, player)
object:get_luaentity()._removed = true
object:remove()
else
enable_physics(object, object:get_luaentity())
end
end, {player:get_player_name(), object})
end
end
end
end
if not collected then
if object:get_luaentity()._magnet_timer > 1 then
object:get_luaentity()._magnet_timer = -item_drop_settings.magnet_time
object:get_luaentity()._magnet_active = false
elseif object:get_luaentity()._magnet_timer < 0 then
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
end
end
@ -230,12 +220,13 @@ local function get_fortune_drops(fortune_drops, fortune_level)
return drop or {}
end
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
function minetest.handle_node_drops(pos, drops, digger)
-- NOTE: This function override allows digger to be nil.
-- This means there is no digger. This is a special case which allows this function to be called
-- by hand. Creative Mode is intentionally ignored in this case.
local doTileDrops = minetest.settings:get_bool("mcl_doTileDrops", true)
if (digger and digger:is_player() and minetest.is_creative_enabled(digger:get_player_name())) or doTileDrops == false then
return
end
@ -335,6 +326,10 @@ function minetest.handle_node_drops(pos, drops, digger)
z = -z
end
obj:set_velocity({x=1/x, y=obj:get_velocity().y, z=1/z})
obj:get_luaentity().age = item_drop_settings.dug_buffer
obj:get_luaentity()._insta_collect = false
end
end
end
@ -401,6 +396,9 @@ minetest.register_entity(":__builtin:item", {
-- Number of seconds this item entity has existed so far
age = 0,
-- How old it has become in the collection animation
collection_age = 0,
set_item = function(self, itemstring)
self.itemstring = itemstring
if self.itemstring == "" then
@ -566,6 +564,11 @@ minetest.register_entity(":__builtin:item", {
on_step = function(self, dtime)
if self._removed then
self.object:set_properties({
physical = false
})
self.object:set_velocity({x=0,y=0,z=0})
self.object:set_acceleration({x=0,y=0,z=0})
return
end
self.age = self.age + dtime

@ -0,0 +1 @@
Item_Drop_Pickup - https://freesound.org/people/benniknop/sounds/317848/ (License: CC0)

@ -735,7 +735,9 @@ local item_drop = function(self, cooked, looting_level)
end
-- add item if it exists
obj = minetest.add_item(pos, ItemStack(item .. " " .. num))
for x = 1, num do
obj = minetest.add_item(pos, ItemStack(item .. " " .. 1))
end
if obj and obj:get_luaentity() then
@ -2817,6 +2819,10 @@ local do_states = function(self, dtime)
local arrow, ent
local v = 1
if not self.shoot_arrow then
self.firing = true
minetest.after(1, function()
self.firing = false
end)
arrow = minetest.add_entity(p, self.arrow)
ent = arrow:get_luaentity()
if ent.velocity then
@ -4221,6 +4227,11 @@ function mobs:register_arrow(name, def)
switch = 0,
owner_id = def.owner_id,
rotate = def.rotate,
on_punch = function(self)
local vel = self.object:get_velocity()
self.object:set_velocity({x=vel.x * -1, y=vel.y * -1, z=vel.z * -1})
end,
collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0},
automatic_face_movement_dir = def.rotate
and (def.rotate - (pi / 180)) or false,
@ -4283,7 +4294,7 @@ function mobs:register_arrow(name, def)
if self.hit_player or self.hit_mob or self.hit_object then
for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.0)) do
for _,player in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do
if self.hit_player
and player:is_player() then

@ -534,7 +534,9 @@ mobs:register_mob("mobs_mc:enderman", {
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then
-- self:teleport(nil)
--else
if pr:next(1, 8) == 8 then --FIXME: real mc rate
self:teleport(hitter)
end
self.attack=hitter
self.state="attack"
--end

@ -63,6 +63,15 @@ mobs:register_mob("mobs_mc:ghast", {
makes_footstep_sound = false,
instant_death = true,
fire_resistant = true,
do_custom = function(self)
if self.firing == true then
self.base_texture = {"mobs_mc_ghast_firing.png"}
self.object:set_properties({textures=self.base_texture})
else
self.base_texture = {"mobs_mc_ghast.png"}
self.object:set_properties({textures=self.base_texture})
end
end,
})
@ -74,6 +83,7 @@ mobs:register_arrow("mobs_mc:fireball", {
visual_size = {x = 1, y = 1},
textures = {"mcl_fire_fire_charge.png"},
velocity = 15,
collisionbox = {-.5, -.5, -.5, .5, .5, .5},
hit_player = function(self, player)
if rawget(_G, "armor") and armor.last_damage_types then

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -20,9 +20,9 @@ if hb.settings.bar_type == "progress_bar" then
hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_offset_right_x", "number", 15)
hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_offset_right_y", "number", -86)
else
hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_statbar_offset_left_x", "number", -265)
hb.settings.start_offset_left.x = hb.load_setting("hudbars_start_statbar_offset_left_x", "number", -258)
hb.settings.start_offset_left.y = hb.load_setting("hudbars_start_statbar_offset_left_y", "number", -90)
hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_statbar_offset_right_x", "number", 25)
hb.settings.start_offset_right.x = hb.load_setting("hudbars_start_statbar_offset_right_x", "number", 16)
hb.settings.start_offset_right.y = hb.load_setting("hudbars_start_statbar_offset_right_y", "number", -90)
end
-- Modified in MCL2!

@ -74,6 +74,7 @@ function mesecon.is_mvps_unsticky(node, pulldir, stack, stackid)
end
-- Functions to be called on mvps movement
-- See also the callback
function mesecon.register_on_mvps_move(callback)
mesecon.on_mvps_move[#mesecon.on_mvps_move+1] = callback
end
@ -405,17 +406,20 @@ mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_brown")
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_light_blue")
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_pink")
-- Includes node heat when moving them
mesecon.register_on_mvps_move(mesecon.move_hot_nodes)
-- Check for falling after moving node
mesecon.register_on_mvps_move(function(moved_nodes)
for i = 1, #moved_nodes do
local moved_node = moved_nodes[i]
-- Check for falling after moving node
mesecon.on_placenode(moved_node.pos, moved_node.node)
minetest.after(0, function()
minetest.check_for_falling(moved_node.oldpos)
minetest.check_for_falling(moved_node.pos)
end)
-- Callback for on_mvps_move stored in nodedef
local node_def = minetest.registered_nodes[moved_node.node.name]
if node_def and node_def.mesecon and node_def.mesecon.on_mvps_move then
node_def.mesecon.on_mvps_move(moved_node.pos, moved_node.node,

@ -367,6 +367,7 @@ mcl_player.player_register_model("mcl_armor_character.b3d", {
run_walk = {x=440, y=459},
run_walk_mine = {x=461, y=480},
sit_mount = {x=484, y=484},
die = {x=498, y=498},
},
})

@ -1,56 +1,56 @@
# Blender v2.91.0 OBJ File: ''
# Blender v2.92.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
v 3.331104 -1.100076 -1.064829
v 3.331104 1.069925 -1.064830
v 3.331104 1.069925 1.085017
v 3.331104 -1.100076 1.085017
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.001000 1.443749
v 3.782006 1.444249 0.000500
v -3.782006 1.444249 0.000500
v -3.782006 -1.443249 0.000500
v 3.782006 -1.443249 0.000500
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
vt -0.000893 0.835148
vt -0.000893 1.008567
vt 0.486244 1.008567
vt 0.486244 0.835148
vt 0.159016 0.682983
vt 0.159016 0.849928
vt -0.005031 0.849928
vt -0.005031 0.682983
vt -0.000893 0.835148
vt 0.486244 0.835148
vt 0.486244 1.008567
vt -0.000893 1.008567
vt -0.000893 0.835148
vt 0.486244 0.835148
vt 0.486244 1.008567
vt -0.000893 1.008567
vt -0.000893 0.835148
vt -0.000893 1.008567
vt 0.486244 1.008567
vt 0.486244 0.835148
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
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
s 1
f 1/1/1 2/2/1 3/3/1 4/4/1
f 5/5/2 6/6/2 7/7/2 8/8/2
f 9/9/3 10/10/3 11/11/3 12/12/3
f 13/13/4 14/14/4 15/15/4 16/16/4
f 17/17/5 18/18/5 19/19/5 20/20/5

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 736 B

@ -7,10 +7,10 @@ local WATER_ALPHA = 179
local WATER_VISC = 1
local LAVA_VISC = 7
local LIGHT_LAVA = minetest.LIGHT_MAX
local USE_TEXTURE_ALPHA
local USE_TEXTURE_ALPHA = true
if minetest.features.use_texture_alpha_string_modes then
USE_TEXTURE_ALPHA = "blend"
WATER_ALPHA = nil
end
local lava_death_messages = {
@ -40,7 +40,6 @@ minetest.register_node("mcl_core:water_flowing", {
},
sounds = mcl_sounds.node_sound_water_defaults(),
is_ground_content = false,
alpha = WATER_ALPHA,
use_texture_alpha = USE_TEXTURE_ALPHA,
paramtype = "light",
paramtype2 = "flowingliquid",
@ -86,7 +85,6 @@ S("• When water is directly below lava, the water turns into stone."),
},
sounds = mcl_sounds.node_sound_water_defaults(),
is_ground_content = false,
alpha = WATER_ALPHA,
use_texture_alpha = USE_TEXTURE_ALPHA,
paramtype = "light",
walkable = false,

@ -70,7 +70,7 @@ minetest.register_entity("mcl_end:crystal", {
collisionbox = {-1, 0.5, -1, 1, 2.5, 1},
mesh = "mcl_end_crystal.b3d",
textures = {"mcl_end_crystal.png"},
collide_with_objects = true,
collide_with_objects = false,
},
on_punch = crystal_explode,
on_activate = set_crystal_animation,

@ -303,8 +303,8 @@ local flying_bobber_ENTITY={
collisionbox = {0,0,0,0,0,0},
pointable = false,
get_staticdata = get_staticdata,
on_activate = on_activate,
get_staticdata = mcl_throwing.get_staticdata,
on_activate = mcl_throwing.on_activate,
_lastpos={},
_thrower = nil,

@ -1,3 +1,5 @@
mcl_ocean = {}
-- Prismarine (includes sea lantern)
dofile(minetest.get_modpath(minetest.get_current_modname()).."/prismarine.lua")

@ -1,71 +1,494 @@
-- TODO: whenever it becomes possible to fully implement kelp without the
-- plantlike_rooted limitation, please update accordingly.
--
-- TODO: In MC, you can't actually destroy kelp by bucket'ing water in the middle.
-- However, because of the plantlike_rooted hack, we'll just allow it for now.
local S = minetest.get_translator("mcl_ocean")
local mod_doc = minetest.get_modpath("doc") ~= nil
-- List of supported surfaces for seagrass and kelp
local surfaces = {
{ "dirt", "mcl_core:dirt" },
{ "sand", "mcl_core:sand", 1 },
{ "redsand", "mcl_core:redsand", 1 },
{ "gravel", "mcl_core:gravel", 1 },
}
--------------------------------------------------------------------------------
-- local-ify runtime functions
--------------------------------------------------------------------------------
-- objects
local mt_registered_items = minetest.registered_items
local mt_registered_nodes = minetest.registered_nodes
local function get_kelp_top(pos, node)
local size = math.ceil(node.param2 / 16)
local pos_water = table.copy(pos)
pos_water.y = pos_water.y + size
return pos_water, minetest.get_node(pos_water)
-- functions
local mt_log = minetest.log
local mt_add_item = minetest.add_item
local mt_get_item_group = minetest.get_item_group
local mt_get_node = minetest.get_node
local mt_get_node_level = minetest.get_node_level
local mt_get_node_max_level = minetest.get_node_max_level
local mt_get_node_or_nil = minetest.get_node_or_nil
local mt_get_node_timer = minetest.get_node_timer
local mt_get_meta = minetest.get_meta
local mt_hash_node_position = minetest.hash_node_position
local mt_set_node = minetest.set_node
local mt_swap_node = minetest.swap_node
local mt_pos_to_string = minetest.pos_to_string
local mt_is_protected = minetest.is_protected
local mt_record_protection_violation = minetest.record_protection_violation
local mt_is_creative_enabled = minetest.is_creative_enabled
local mt_sound_play = minetest.sound_play
local math_min = math.min
local math_max = math.max
local math_ceil = math.ceil
local math_floor = math.floor
local math_random = math.random
local string_format = string.format
local table_copy = table.copy
local table_insert = table.insert
-- DEBUG: functions
-- local log = minetest.log
-- local chatlog = minetest.chat_send_all
--------------------------------------------------------------------------------
-- Kelp API
--------------------------------------------------------------------------------
local kelp = {}
mcl_ocean.kelp = kelp
-- Kelp minimum and maximum age. Once reached the maximum, kelp no longer grows.
kelp.MIN_AGE = 0
kelp.MAX_AGE = 25
-- Tick interval (in seconds) for updating kelp.
kelp.TICK = 0.2
-- Tick interval (in seconds) to store kelp meta.
kelp.META_TICK = 2
-- Max age queue length
kelp.MAX_AGE_QUEUE = 20
-- The average amount of growth for kelp in a day is 2.16 (https://youtu.be/5Bp4lAjAk3I)
-- Normally, a day lasts 20 minutes, meaning kelp.next_grow() is executed
-- 1200 / TICK times. Per tick probability = (216/100) / (1200/TICK)
-- NOTE: currently, we can't exactly use the same type of randomness MC does, because
-- it has multiple complicated sets of PRNGs.
-- NOTE: Small loss of precision, should be 10 to preserve it.
-- kelp.ROLL_GROWTH_PRECISION = 10
-- kelp.ROLL_GROWTH_NUMERATOR = 216 * kelp.TICK * kelp.ROLL_GROWTH_PRECISION
-- kelp.ROLL_GROWTH_DENOMINATOR = 100 * 1200 * kelp.ROLL_GROWTH_PRECISION
kelp.ROLL_GROWTH_PRECISION = 1
kelp.ROLL_GROWTH_NUMERATOR = 216 * kelp.TICK
kelp.ROLL_GROWTH_DENOMINATOR = 100 * 1200
-- Sounds used to dig and place kelp.
kelp.leaf_sounds = mcl_sounds.node_sound_leaves_defaults()
-- Pool storing nodetimers
kelp.timers_pool = {}
-- Pool storing age, indexed by pos_hash.
kelp.age_pool = {}
-- Queue(List) of hashed positions to save their ages.
-- Invalid ones may still persist in this queue.
kelp.age_queue = {}
-- Stores only valid positions of each hashed postiions.
kelp.age_queue_pos = {}
-- is age in the growable range?
function kelp.is_age_growable(age)
return age >= 0 and age < kelp.MAX_AGE
end
local function get_submerged(node_water)
local def_water = minetest.registered_nodes[node_water.name]
-- Submerged in water?
if minetest.get_item_group(node_water.name, "water") then
if def_water.liquidtype == "source" then
return "source"
elseif def_water.liquidtype == "flowing" then
return "flowing"
end
-- Is this water?
-- Returns the liquidtype, if indeed water.
function kelp.is_submerged(node)
if mt_get_item_group(node.name, "water") ~= 0 then
-- Expected only "source" and "flowing" from water liquids
return mt_registered_nodes[node.name].liquidtype
end
return false
end
local function grow_param2_step(param2, snap_into_grid)
local old_param2 = param2
param2 = param2 + 16
if param2 > 240 then
param2 = 240
-- Is the water downward flowing?
-- (kelp can grow/be placed inside downward flowing water)
function kelp.is_downward_flowing(pos, node, pos_above, node_above, __is_above__)
-- Function params: (pos[, node]) or (node, pos_above) or (node, node_above)
local node = node or mt_get_node(pos)
local result = (math_floor(node.param2 / 8) % 2) == 1
if not (result or __is_above__) then
-- If not, also check node above.
-- (this is needed due a weird quirk in the definition of "downwards flowing"
-- liquids in Minetest)
local pos_above = pos_above or {x=pos.x,y=pos.y+1,z=pos.z}
local node_above = node_above or mt_get_node(pos_above)
result = kelp.is_submerged(node_above)
or kelp.is_downward_flowing(nil, node_above, nil, nil, true)
end
if snap_into_grid and (param2 % 16 ~= 0) then
param2 = param2 - (param2 % 16)
end
return param2, param2 ~= old_param2
return result
end
local function kelp_check_place(pos_above, node_above, def_above)
if minetest.get_item_group(node_above.name, "water") == 0 then
-- Will node fall at that position?
-- This only checks if a node would fall, meaning that node need not be at pos.
function kelp.is_falling(pos, node, is_falling, pos_bottom, node_bottom, def_bottom)
-- Optional params: is_falling, pos_bottom, node_bottom, def_bottom
-- NOTE: Modified from check_single_for_falling in builtin.
-- Please update accordingly.
local nodename = node.name
if is_falling == false or
is_falling == nil and mt_get_item_group(nodename, "falling_node") == 0 then
return false
end
local can_place = false
if (def_above.liquidtype == "source") then
can_place = true
elseif (def_above.liquidtype == "flowing") then
-- Check if bit 3 (downwards flowing) is set
can_place = (math.floor(node_above.param2 / 8) % 2) == 1
if not can_place then
-- If not, also check node above (this is needed due a weird quirk in the definition of
-- "downwards flowing" liquids in Minetest)
local node_above_above = minetest.get_node({x=pos_above.x,y=pos_above.y+1,z=pos_above.z})
local naa_def = minetest.registered_nodes[node_above_above.name]
can_place = naa_def.liquidtype == "source"
if not can_place then
can_place = (naa_def.liquidtype == "flowing") and ((math.floor(node_above_above.param2 / 8) % 2) == 1)
local pos_bottom = pos_bottom or {x = pos.x, y = pos.y - 1, z = pos.z}
-- get_node_or_nil: Only fall if node below is loaded
local node_bottom = node_bottom or mt_get_node_or_nil(pos_bottom)
local nodename_bottom = node_bottom.name
local def_bottom = def_bottom or node_bottom and mt_registered_nodes[nodename_bottom]
if not def_bottom then
return false
end
local same = nodename == nodename_bottom
-- Let leveled nodes fall if it can merge with the bottom node
if same and def_bottom.paramtype2 == "leveled" and
mt_get_node_level(pos_bottom) <
mt_get_node_max_level(pos_bottom) then
return true
end
-- Otherwise only if the bottom node is considered "fall through"
if not same and
(not def_bottom.walkable or def_bottom.buildable_to) and
(mt_get_item_group(nodename, "float") == 0 or
def_bottom.liquidtype == "none") then
return true
end
return can_place
return false
end
local function kelp_on_place(itemstack, placer, pointed_thing)
-- Roll whether to grow kelp or not.
function kelp.roll_growth(numerator, denominator)
-- Optional params: numerator, denominator
return math_random(denominator or kelp.ROLL_GROWTH_DENOMINATOR) <= (numerator or kelp.ROLL_GROWTH_NUMERATOR)
end
-- Roll initial age for kelp.
function kelp.roll_init_age(min, max)
-- Optional params
return math_random(min or kelp.MIN_AGE, (max or kelp.MAX_AGE)-1)
end
-- Converts param2 to kelp height.
function kelp.get_height(param2)
return math_floor(param2 / 16)
end
-- Obtain pos and node of the tip of kelp.
function kelp.get_tip(pos, param2)
-- Optional params: param2
local height = kelp.get_height(param2 or mt_get_node(pos).param2)
local pos_tip = {x=pos.x, y=pos.y, z=pos.z}
pos_tip.y = pos_tip.y + height + 1
return pos_tip, mt_get_node(pos_tip), height
end
-- Obtain position of the first kelp unsubmerged.
function kelp.find_unsubmerged(pos, node, height)
-- Optional params: node, height
local node = node or mt_get_node(pos)
local height = height or kelp.get_height(node.param2)
local walk_pos = {x=pos.x, z=pos.z}
local y = pos.y
for i=1,height do
walk_pos.y = y + i
local walk_node = mt_get_node(walk_pos)
if not kelp.is_submerged(walk_node) then
return walk_pos, walk_node, height, i
end
end
return nil, nil, height, height
end
-- Obtain next param2.
function kelp.next_param2(param2)
return param2+16 - param2 % 16
end
-- Stores age from kelp.age_queue* into their respective meta
function kelp.store_meta()
local count = 0
for _ in pairs(kelp.age_queue_pos) do
count = count + 1
end
-- chatlog(string_format("Storing age metadata: %d in queue", #kelp.age_queue))
-- chatlog(string_format("Storing age metadata: %d valid in queue", count))
for i=1,#kelp.age_queue do
local pos_hash = kelp.age_queue[i]
local pos = kelp.age_queue_pos[pos_hash]
-- queued hashes may no longer point to a valid pos, e.g. kelp is destroyed.
if pos then
mt_get_meta(pos):set_int("mcl_ocean:kelp_age", kelp.age_pool[pos_hash])
end
end
kelp.age_queue = {}
kelp.age_queue_pos = {}
end
-- Store and queue a kelp's age to be saved into meta later.
function kelp.store_age(age, pos, pos_hash)
-- Watched params: pos
-- Optional params: pos_hash
local pos_hash = pos_hash or mt_hash_node_position(pos)
kelp.age_pool[pos_hash] = age
if not kelp.age_queue_pos[pos_hash] then
table_insert(kelp.age_queue, pos_hash)
kelp.age_queue_pos[pos_hash] = pos
return true, pos_hash
end
return false, pos_hash
end
-- Initialise a kelp's age.
function kelp.init_age(pos, age, pos_hash, meta)
-- Watched params: pos
-- Optional params: age, pos_hash, meta
local pos_hash = pos_hash or mt_hash_node_position(pos)
local meta = meta or mt_get_meta(pos)
local age = age
if age then
kelp.store_age(age, pos, pos_hash)
elseif not meta:contains("mcl_ocean:kelp_age") then
age = kelp.roll_init_age()
kelp.store_age(age, pos, pos_hash)
else
age = meta:get_int("mcl_ocean:kelp_age")
if not kelp.age_pool[pos_hash] then
kelp.age_pool[pos_hash] = age
end
end
return age, pos_hash, meta
end
-- Initialise kelp nodetimer.
function kelp.init_timer(pos, pos_hash)
-- Optional params: pos_hash
local pos_hash = pos_hash or mt_hash_node_position(pos)
local timer = kelp.timers_pool[pos_hash]
if not timer then
timer = mt_get_node_timer(pos)
kelp.timers_pool[pos_hash] = timer
end
if not timer:is_started() then
timer:start(kelp.TICK)
end
return pos_hash
end
-- Apply next kelp height.
function kelp.next_height(pos, node, pos_tip, node_tip, submerged, downward_flowing)
-- Modified params: node
-- Optional params: node, set_node, pos_tip, node_tip, submerged, downward_flowing
local node = node or mt_get_node(pos)
local pos_tip = pos_tip
local node_tip = node_tip or (pos_tip and mt_get_node(pos_tip))
if not pos_tip then
pos_tip,node_tip = kelp.get_tip(pos)
end
local downward_flowing = downward_flowing or
(submerged or kelp.is_submerged(node_tip)
and kelp.is_downward_flowing(pos_tip, node_tip))
-- Liquid source: Grow normally.
node.param2 = kelp.next_param2(node.param2)
mt_swap_node(pos, node)
-- Flowing liquid: Grow 1 step, but also turn the tip node into a liquid source.
if downward_flowing then
local alt_liq = mt_registered_nodes[node_tip.name].liquid_alternative_source
if alt_liq then
mt_set_node(pos_tip, {name=alt_liq})
end
end
return node, pos_tip, node_tip, submerged, downward_flowing
end
-- Grow next kelp.
function kelp.next_grow(age, pos, node, pos_hash, pos_tip, node_tip, submerged, downward_flowing)
-- Watched params: pos
-- Modified params: node
-- Optional params: node, pos_hash, pos_tip, node_tip, submerged, downward_flowing
local node = node or mt_get_node(pos)
local pos_hash = pos_hash or mt_hash_node_position(pos)
local pos_tip = pos_tip
local node_tip = node_tip or (pos_tip and mt_get_node(pos_tip))
if not pos_tip then
pos_tip,node_tip = kelp.get_tip(pos)
end
-- New kelp must also be submerged in water.
local downward_flowing = downward_flowing or kelp.is_downward_flowing(pos_tip, node_tip)
if not (submerged or kelp.is_submerged(node_tip)) then
return
end
kelp.next_height(pos, node, pos_tip, node_tip, submerged, downward_flowing)
return kelp.store_age(age, pos, pos_hash), node, pos_hash, pos_tip, node_tip, submerged, downward_flowing
end
-- Drops the items for detached kelps.
function kelp.detach_drop(pos, param2)
-- Optional params: param2
local height = kelp.get_height(param2 or mt_get_node(pos).param2)
local y = pos.y
local walk_pos = {x=pos.x, z=pos.z}
for i=1,height do
walk_pos.y = y+i
mt_add_item(walk_pos, "mcl_ocean:kelp")
end
return true
end
-- Detach the kelp at dig_pos, and drop their items.
-- Synonymous to digging the kelp.
-- NOTE: this is intended for whenever kelp truly becomes segmented plants
-- instead of rooted to the floor. Don't try to remove dig_pos.
function kelp.detach_dig(dig_pos, pos, node, drop)
-- Optional params: drop
local param2 = node.param2
-- pos.y points to the surface, offset needed to point to the first kelp.
local new_height = dig_pos.y - (pos.y+1)
-- Digs the entire kelp.
if new_height <= 0 then
if drop then
kelp.detach_drop(dig_pos, param2)
end
mt_set_node(pos, {
name=mt_registered_nodes[node.name].node_dig_prediction,
param=node.param,
param2=0 })
-- Digs the kelp beginning at a height.
else
if drop then
kelp.detach_drop(dig_pos, param2 - new_height)
end
mt_swap_node(pos, {name=node.name, param=node.param, param2=16*new_height})
end
end
--------------------------------------------------------------------------------
-- Kelp callback functions
--------------------------------------------------------------------------------
function kelp.surface_on_dig(pos, node, digger)
kelp.detach_dig(pos, pos, node, true)
end
function kelp.surface_after_dig_node(pos, node)
return mt_set_node(pos, {name=registred_nodes[node.name].node_dig_prediction})
end
function kelp.surface_on_timer(pos)
local node = mt_get_node(pos)
local pos_hash
-- Update detahed kelps
local dig_pos = kelp.find_unsubmerged(pos, node)
if dig_pos then
pos_hash = mt_hash_node_position(pos)
mt_sound_play(mt_registered_nodes[node.name].sounds.dug, { gain = 0.5, pos = dig_pos }, true)
kelp.detach_dig(dig_pos, pos, node, true)
kelp.store_age(kelp.roll_init_age(), pos, pos_hash)
end
-- Grow kelp on chance
if kelp.roll_growth() then
pos_hash = pos_hash or mt_hash_node_position(pos)
local age = kelp.age_pool[pos_hash]
if kelp.is_age_growable(age) then
kelp.next_grow(age+1, pos, node, pos_hash)
end
end
return true
end
function kelp.surface_on_construct(pos)
local pos_hash = mt_hash_node_position(pos)
kelp.init_age(pos, nil, pos_hash)
kelp.init_timer(pos, pos_hash)
end
function kelp.surface_on_destruct(pos)
local node = mt_get_node(pos)
local pos_hash = mt_hash_node_position(pos)
-- on_falling callback. Activated by pistons for falling nodes too.
if kelp.is_falling(pos, node) then
kelp.detach_drop(pos, node.param2)
end
-- Removes position from queue
kelp.age_queue_pos[pos_hash] = nil
end
function kelp.surface_on_mvps_move(pos, node, oldpos, nodemeta)
-- Pistons moving falling nodes will have already activated on_falling callback.
kelp.detach_dig(pos, pos, node, mt_get_item_group(node.name, "falling_node") ~= 1)
end
-- NOTE: Old ABM implementation.
-- local function surface_unsubmerged_abm(pos, node)
-- local dig_pos = find_unsubmerged(pos, node)
-- if dig_pos then
-- detach_dig(dig_pos, pos, node, true)
-- end
-- return true
-- end
function kelp.kelp_on_place(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" or not placer then
return itemstack
end
@ -73,133 +496,142 @@ local function kelp_on_place(itemstack, placer, pointed_thing)
local player_name = placer:get_player_name()
local pos_under = pointed_thing.under
local pos_above = pointed_thing.above
local node_under = minetest.get_node(pos_under)
local node_above = minetest.get_node(pos_above)
local def_under = minetest.registered_nodes[node_under.name]
local def_above = minetest.registered_nodes[node_above.name]
local node_under = mt_get_node(pos_under)
local nu_name = node_under.name
local def_under = mt_registered_nodes[nu_name]
-- Allow rightclick to override place.
if def_under and def_under.on_rightclick and not placer:get_player_control().sneak then
return def_under.on_rightclick(pos_under, node_under,
placer, itemstack, pointed_thing) or itemstack
end
if minetest.is_protected(pos_under, player_name) or
minetest.is_protected(pos_above, player_name) then
minetest.log("action", player_name
-- Protection
if mt_is_protected(pos_under, player_name) or
mt_is_protected(pos_above, player_name) then
mt_log("action", player_name
.. " tried to place " .. itemstack:get_name()
.. " at protected position "
.. minetest.pos_to_string(pos_under))
minetest.record_protection_violation(pos_under, player_name)
.. mt_pos_to_string(pos_under))
mt_record_protection_violation(pos_under, player_name)
return itemstack
end
local grow_kelp = false
-- Select a kelp node when placed on surface node
if node_under.name == "mcl_core:dirt" then
node_under.name = "mcl_ocean:kelp_dirt"
elseif node_under.name == "mcl_core:sand" then
node_under.name = "mcl_ocean:kelp_sand"
elseif node_under.name == "mcl_core:redsand" then
node_under.name = "mcl_ocean:kelp_redsand"
elseif node_under.name == "mcl_core:gravel" then
node_under.name = "mcl_ocean:kelp_gravel"
elseif minetest.get_item_group(node_under.name, "kelp") == 1 then
-- Place kelp on kelp = grow kelp by 1 node length
node_under.param2, grow_kelp = grow_param2_step(node_under.param2)
if not grow_kelp then
return itemstack
end
else
return itemstack
end
local submerged = false
if grow_kelp then
-- Kelp placed on kelp ...
-- Kelp can be placed on top of another kelp to make it grow
if pos_under.y >= pos_above.y or pos_under.x ~= pos_above.x or pos_under.z ~= pos_above.z then
-- Placed on side or below node, abort
return itemstack
end
-- New kelp top must also be submerged in water
local top_pos, top_node = get_kelp_top(pos_under, node_under)
local top_def = minetest.registered_nodes[top_node.name]
submerged = kelp_check_place(top_pos, top_node, top_def)
if not submerged then
-- Not submerged in water, abort
return itemstack
end
else
-- New kelp placed ...
local pos_tip, node_tip, def_tip, new_kelp
-- Kelp must also be placed on the top/tip side of the surface/kelp
if pos_under.y >= pos_above.y then
-- Placed on side or below node, abort
return itemstack
end
-- Kelp can be placed inside a water source or water flowing downwards on top of a surface node
local can_place = kelp_check_place(pos_above, node_above, def_above)
if not can_place then
-- When placed on kelp.
if mt_get_item_group(nu_name, "kelp") == 1 then
pos_tip,node_tip = kelp.get_tip(pos_under, node_under.param2)
def_tip = mt_registered_nodes[node_tip.name]
-- When placed on surface.
else
new_kelp = false
for _,surface in pairs(kelp.surfaces) do
if nu_name == surface.nodename then
node_under.name = "mcl_ocean:kelp_" ..surface.name
node_under.param2 = 0
new_kelp = true
break
end
end
-- Surface must support kelp
if not new_kelp then
return itemstack
end
node_under.param2 = minetest.registered_items[node_under.name].place_param2 or 16
pos_tip = pos_above
node_tip = mt_get_node(pos_above)
def_tip = mt_registered_nodes[node_tip.name]
end
-- Place or grow kelp
local def_node = minetest.registered_items[node_under.name]
-- New kelp must also be submerged in water.
local downward_flowing = kelp.is_downward_flowing(pos_tip, node_tip)
local submerged = kelp.is_submerged(node_tip)
if not submerged then
return itemstack
end
-- Play sound, place surface/kelp and take away an item
local def_node = mt_registered_items[nu_name]
if def_node.sounds then
minetest.sound_play(def_node.sounds.place, { gain = 0.5, pos = pos_under }, true)
mt_sound_play(def_node.sounds.place, { gain = 0.5, pos = pos_under }, true)
end
minetest.set_node(pos_under, node_under)
if not minetest.is_creative_enabled(player_name) then
kelp.next_height(pos_under, node_under, pos_tip, node_tip, def_tip, submerged, downward_flowing)
if not mt_is_creative_enabled(player_name) then
itemstack:take_item()
end
-- Initialize age and timer when it's a new kelp
local pos_hash = mt_hash_node_position(pos_under)
if new_kelp then
kelp.init_age(pos_under, nil, pos_hash)
kelp.init_timer(pos_under, pos_hash)
else
kelp.store_age(kelp.roll_init_age(), pos_under, pos_hash)
end
return itemstack
end
local get_kelp_height = function(param2)
return math.floor(param2 / 16)
function kelp.lbm_register_nodetimer(pos, node)
local pos_hash = mt_hash_node_position(pos)
kelp.init_age(pos, nil, pos_hash)
kelp.init_timer(pos, pos_hash)
end
minetest.register_craftitem("mcl_ocean:kelp", {
description = S("Kelp"),
_tt_help = S("Grows in water on dirt, sand, gravel"),
_doc_items_create_entry = false,
inventory_image = "mcl_ocean_kelp_item.png",
wield_image = "mcl_ocean_kelp_item.png",
on_place = kelp_on_place,
groups = { deco_block = 1 },
})
-- Kelp nodes: kelp on a surface node
local gstep_time = 0
function kelp.globalstep(dtime)
if #kelp.age_queue > kelp.MAX_AGE_QUEUE then
kelp.store_meta()
end
for s=1, #surfaces do
local def = minetest.registered_nodes[surfaces[s][2]]
local alt
if surfaces[s][3] == 1 then
alt = surfaces[s][2]
gstep_time = gstep_time + dtime
if gstep_time < kelp.META_TICK then
return
end
local sounds = table.copy(def.sounds)
local leaf_sounds = mcl_sounds.node_sound_leaves_defaults()
sounds.dig = leaf_sounds.dig
sounds.dug = leaf_sounds.dug
sounds.place = leaf_sounds.place
local tt_help, doc_longdesc, doc_img, desc
if surfaces[s][1] == "dirt" then
doc_longdesc = S("Kelp grows inside water on top of dirt, sand or gravel.")
desc = S("Kelp")
doc_create = true
doc_img = "mcl_ocean_kelp_item.png"
else
doc_create = false
gstep_time = 0
if #kelp.age_queue > 0 then
kelp.store_meta()
end
minetest.register_node("mcl_ocean:kelp_"..surfaces[s][1], {
_doc_items_entry_name = desc,
_doc_items_longdesc = doc_longdesc,
_doc_items_create_entry = doc_create,
_doc_items_image = doc_img,
end
function kelp.on_shutdown()
if #kelp.age_queue > 0 then
kelp.store_meta()
end
end
--------------------------------------------------------------------------------
-- Kelp registration API
--------------------------------------------------------------------------------
-- List of supported surfaces for seagrass and kelp.
kelp.surfaces = {
{ name="dirt", nodename="mcl_core:dirt", },
{ name="sand", nodename="mcl_core:sand", },
{ name="redsand", nodename="mcl_core:redsand", },
{ name="gravel", nodename="mcl_core:gravel", },
}
kelp.registered_surfaces = {}
-- Commented properties are the ones obtained using register_kelp_surface.
-- If you define your own properties, it overrides the default ones.
kelp.surface_deftemplate = {
drawtype = "plantlike_rooted",
paramtype = "light",
paramtype2 = "leveled",
place_param2 = 16,
tiles = def.tiles,
--tiles = def.tiles,
special_tiles = {
{
image = "mcl_ocean_kelp_plant.png",
@ -207,7 +639,7 @@ for s=1, #surfaces do
tileable_vertical = true,
}
},
inventory_image = "("..def.tiles[1]..")^mcl_ocean_kelp_item.png",
--inventory_image = "("..def.tiles[1]..")^mcl_ocean_kelp_item.png",
wield_image = "mcl_ocean_kelp_item.png",
selection_box = {
type = "fixed",
@ -216,40 +648,99 @@ for s=1, #surfaces do
{ -0.5, 0.5, -0.5, 0.5, 1.5, 0.5 },
},
},
groups = { dig_immediate = 3, deco_block = 1, plant = 1, kelp = 1, falling_node = surfaces[s][3] },
sounds = sounds,
node_dig_prediction = surfaces[s][2],
after_dig_node = function(pos)
minetest.set_node(pos, {name=surfaces[s][2]})
end,
on_dig = function(pos, node, digger)
-- Drop kelp as item; item count depends on height
local dname = ""
if digger then
dname = digger:get_player_name()
end
local creative = minetest.is_creative_enabled(dname)
if not creative then
minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, "mcl_ocean:kelp "..get_kelp_height(node.param2))
end
minetest.node_dig(pos, node, digger)
end,
-- groups.falling_node = is_falling,
groups = { dig_immediate = 3, deco_block = 1, plant = 1, kelp = 1, },
--sounds = sounds,
--node_dig_prediction = nodename,
on_construct = kelp.surface_on_construct,
on_destruct = kelp.surface_on_destruct,
on_dig = kelp.surface_on_dig,
after_dig_node = kelp.surface_after_dig_node,
on_timer = kelp.surface_on_timer,
mesecon = { on_mvps_move = kelp.surface_on_mvps_move, },
drop = "", -- drops are handled in on_dig
_mcl_falling_node_alternative = alt,
--_mcl_falling_node_alternative = is_falling and nodename or nil,
_mcl_hardness = 0,
_mcl_blast_resistance = 0,
})
}
if mod_doc and surfaces[s][1] ~= "dirt" then
doc.add_entry_alias("nodes", "mcl_ocean:kelp_dirt", "nodes", "mcl_ocean:kelp_"..surfaces[s][1])
-- Commented properties are the ones obtained using register_kelp_surface.
kelp.surface_docs = {
-- entry_id_orig = nodename,
_doc_items_entry_name = S("Kelp"),
_doc_items_longdesc = S("Kelp grows inside water on top of dirt, sand or gravel."),
--_doc_items_create_entry = doc_create,
_doc_items_image = "mcl_ocean_kelp_item.png",
}
-- Creates new surfaces.
-- NOTE: surface_deftemplate will be modified in-place.
function kelp.register_kelp_surface(surface, surface_deftemplate, surface_docs)
local name = surface.name
local nodename = surface.nodename
local def = mt_registered_nodes[nodename]
local def_tiles = def.tiles
local surfacename = "mcl_ocean:kelp_"..name
local surface_deftemplate = surface_deftemplate or kelp.surface_deftemplate -- Optional param
local doc_create = surface.doc_create or false
local surface_docs = surface_docs or kelp.surface_docs -- Optional param
if doc_create then
surface_deftemplate._doc_items_entry_name = surface_docs._doc_items_entry_name
surface_deftemplate._doc_items_longdesc = surface_docs._doc_items_longdesc
surface_deftemplate._doc_items_create_entry = true
surface_deftemplate._doc_items_image = surface_docs._doc_items_image
-- Sets the first surface as the docs' entry ID
if not surface_docs.entry_id_orig then
surface_docs.entry_id_orig = nodename
end
elseif mod_doc then
doc.add_entry_alias("nodes", surface_docs.entry_id_orig, "nodes", surfacename)
end
local sounds = table_copy(def.sounds)
sounds.dig = kelp.leaf_sounds.dig
sounds.dug = kelp.leaf_sounds.dug
sounds.place = kelp.leaf_sounds.place
surface_deftemplate.tiles = surface_deftemplate.tiles or def_tiles
surface_deftemplate.inventory_image = surface_deftemplate.inventory_image or "("..def_tiles[1]..")^mcl_ocean_kelp_item.png"
surface_deftemplate.sounds = surface_deftemplate.sound or sounds
local falling_node = mt_get_item_group(nodename, "falling_node")
surface_deftemplate.node_dig_prediction = surface_deftemplate.node_dig_prediction or nodename
surface_deftemplate.groups.falling_node = surface_deftemplate.groups.falling_node or falling_node
surface_deftemplate._mcl_falling_node_alternative = surface_deftemplate._mcl_falling_node_alternative or (falling_node and nodename or nil)
minetest.register_node(surfacename, surface_deftemplate)
end
-- Kelp surfaces nodes ---------------------------------------------------------
-- Dirt must be registered first, for the docs
kelp.register_kelp_surface(kelp.surfaces[1], table_copy(kelp.surface_deftemplate), kelp.surface_docs)
for i=2, #kelp.surfaces do
kelp.register_kelp_surface(kelp.surfaces[i], table_copy(kelp.surface_deftemplate), kelp.surface_docs)
end
-- Kelp item -------------------------------------------------------------------
minetest.register_craftitem("mcl_ocean:kelp", {
description = S("Kelp"),
_tt_help = S("Grows in water on dirt, sand, gravel"),
_doc_items_create_entry = false,
inventory_image = "mcl_ocean_kelp_item.png",
wield_image = "mcl_ocean_kelp_item.png",
on_place = kelp.kelp_on_place,
groups = { deco_block = 1 },
})
if mod_doc then
doc.add_entry_alias("nodes", "mcl_ocean:kelp_dirt", "craftitems", "mcl_ocean:kelp")
doc.add_entry_alias("nodes", kelp.surface_docs.entry_id_orig, "craftitems", "mcl_ocean:kelp")
end
-- Dried kelp stuff
-- Dried kelp ------------------------------------------------------------------
-- TODO: This is supposed to be eaten very fast
minetest.register_craftitem("mcl_ocean:dried_kelp", {
@ -264,13 +755,13 @@ minetest.register_craftitem("mcl_ocean:dried_kelp", {
_mcl_saturation = 0.6,
})
local mod_screwdriver = minetest.get_modpath("screwdriver") ~= nil
local on_rotate
if mod_screwdriver then
on_rotate = screwdriver.rotate_3way
end
minetest.register_node("mcl_ocean:dried_kelp_block", {
description = S("Dried Kelp Block"),
_doc_items_longdesc = S("A decorative block that serves as a great furnace fuel."),
@ -310,32 +801,35 @@ minetest.register_craft({
burntime = 200,
})
-- Grow kelp
minetest.register_abm({
label = "Kelp growth",
-- Global registration ------------------------------------------------------------------------
minetest.register_lbm({
label = "Kelp initialise",
name = "mcl_ocean:kelp_init",
nodenames = { "group:kelp" },
interval = 45,
chance = 12,
catch_up = false,
action = function(pos, node, active_object_count, active_object_count_wider)
local grown
-- Grow kelp by 1 node length if it would grow inside water
node.param2, grown = grow_param2_step(node.param2, true)
local top, top_node = get_kelp_top(pos, node)
local submerged = get_submerged(top_node)
if grown then
if submerged == "source" then
-- Liquid source: Grow normally
minetest.set_node(pos, node)
elseif submerged == "flowing" then
-- Flowing liquid: Grow 1 step, but also turn the top node into a liquid source
minetest.set_node(pos, node)
local def_liq = minetest.registered_nodes[top_node.name]
local alt_liq = def_liq and def_liq.liquid_alternative_source
if alt_liq then
minetest.set_node(top, {name=alt_liq})
end
end
end
end,
run_at_every_load = true, -- so old kelps are also initialised
action = kelp.lbm_register_nodetimer,
})
minetest.register_globalstep(kelp.globalstep)
minetest.register_on_shutdown(kelp.on_shutdown)
-- NOTE: Old ABM implementation.
-- minetest.register_abm({
-- label = "Kelp drops",
-- nodenames = { "group:kelp" },
-- interval = 1.0,
-- chance = 1,
-- catch_up = false,
-- action = surface_unsubmerged_abm,
-- })
--
-- minetest.register_abm({
-- label = "Kelp growth",
-- nodenames = { "group:kelp" },
-- interval = 45,
-- chance = 12,
-- catch_up = false,
-- action = grow_abm,
-- })

@ -4,11 +4,6 @@ local S = minetest.get_translator("mcl_portals")
local SPAWN_MIN = mcl_vars.mg_end_min+70
local SPAWN_MAX = mcl_vars.mg_end_min+98
local PORTAL_ALPHA = 192
if minetest.features.use_texture_alpha_string_modes then
PORTAL_ALPHA = nil
end
local mg_name = minetest.get_mapgen_setting("mg_name")
local destroy_portal = function(pos)
@ -81,7 +76,6 @@ minetest.register_node("mcl_portals:portal_end", {
-- This is 15 in MC.
light_source = 14,
post_effect_color = {a = 192, r = 0, g = 0, b = 0},
alpha = PORTAL_ALPHA,
after_destruct = destroy_portal,
-- This prevents “falling through”
collision_box = {

@ -30,7 +30,6 @@ local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_be
local O_DY, N_DY = O_Y_MAX - O_Y_MIN + 1, N_Y_MAX - N_Y_MIN + 1
-- Alpha and particles
local ALPHA = minetest.features.use_texture_alpha_string_modes and 192
local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none"
local node_particles_levels = { none=0, low=1, medium=2, high=3 }
local PARTICLES = node_particles_levels[node_particles_allowed]
@ -263,7 +262,6 @@ minetest.register_node(PORTAL, {
drop = "",
light_source = 11,
post_effect_color = {a = 180, r = 51, g = 7, b = 89},
alpha = ALPHA,
node_box = {
type = "fixed",
fixed = {

@ -33,3 +33,9 @@ Handle creative mode, and throw params.
* entity_name: the name of the entity to throw
* velocity: (optional) velocity overide (can be nil)
## mcl_throwing.get_staticdata(self)
Must be used in entity def if you want the entity to be saved after unloading mapblock.
## mcl_throwing.on_activate(self, staticdata, dtime_s)
Must be used in entity def if you want the entity to be saved after unloading mapblock.

@ -58,7 +58,7 @@ function mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode,
end
-- Staticdata handling because objects may want to be reloaded
local get_staticdata = function(self)
function mcl_throwing.get_staticdata(self)
local thrower
-- Only save thrower if it's a player name
if type(self._thrower) == "string" then
@ -71,7 +71,7 @@ local get_staticdata = function(self)
return minetest.serialize(data)
end
local on_activate = function(self, staticdata, dtime_s)
function mcl_throwing.on_activate(self, staticdata, dtime_s)
local data = minetest.deserialize(staticdata)
if data then
self._lastpos = data._lastpos

@ -9,8 +9,8 @@ local snowball_ENTITY={
collisionbox = {0,0,0,0,0,0},
pointable = false,
get_staticdata = get_staticdata,
on_activate = on_activate,
get_staticdata = mcl_throwing.get_staticdata,
on_activate = mcl_throwing.on_activate,
_thrower = nil,
_lastpos={},
@ -23,8 +23,8 @@ local egg_ENTITY={
collisionbox = {0,0,0,0,0,0},
pointable = false,
get_staticdata = get_staticdata,
on_activate = on_activate,
get_staticdata = mcl_throwing.get_staticdata,
on_activate = mcl_throwing.on_activate,
_thrower = nil,
_lastpos={},
@ -38,8 +38,8 @@ local pearl_ENTITY={
collisionbox = {0,0,0,0,0,0},
pointable = false,
get_staticdata = get_staticdata,
on_activate = on_activate,
get_staticdata = mcl_throwing.get_staticdata,
on_activate = mcl_throwing.on_activate,
_lastpos={},
_thrower = nil, -- Player ObjectRef of the player who threw the ender pearl

@ -178,7 +178,7 @@ minetest.register_globalstep(function(dtime)
-- Apply animations based on what the player is doing
if player:get_hp() == 0 then
player_set_animation(player, "lay")
player_set_animation(player, "die")
elseif walking and velocity.x > 0.35 or walking and velocity.x < -0.35 or walking and velocity.z > 0.35 or walking and velocity.z < -0.35 then
if player_sneak[name] ~= controls.sneak then
player_anim[name] = nil
@ -253,3 +253,28 @@ minetest.register_on_player_hpchange(function(player, hp_change, reason)
end
return hp_change
end, true)
minetest.register_on_respawnplayer(function(player)
local pos = player:get_pos()
minetest.add_particlespawner({
amount = 50,
time = 0.001,
minpos = vector.add(pos, 0),
maxpos = vector.add(pos, 0),
minvel = vector.new(-5,-5,-5),
maxvel = vector.new(5,5,5),
minexptime = 1.1,
maxexptime = 1.5,
minsize = 1,
maxsize = 2,
collisiondetection = false,
vertical = false,
texture = "mcl_particles_mob_death.png^[colorize:#000000:255",
})
minetest.sound_play("mcl_mobs_mob_poof", {
pos = pos,
gain = 1.0,
max_hear_distance = 8,
}, true)
end)

@ -227,6 +227,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if mcl_skins.skin_count <= 6 then
-- Change skin immediately if there are not many skins
mcl_skins.cycle_skin(player)
if player:get_attach() ~= nil then
mcl_player.player_set_animation(player, "sit")
end
else
-- Show skin selection formspec otherwise
mcl_skins.show_formspec(player:get_player_name())
@ -294,4 +297,3 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end)
minetest.log("action", "[mcl_skins] Mod initialized with "..mcl_skins.skin_count.." custom skin(s)")