forked from VoxeLibre/VoxeLibre
Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
Lizzy Fleckenstein | 8f735cc644 | |
Lizzy Fleckenstein | 422076f761 | |
Lizzy Fleckenstein | 9ce59d4438 | |
Lizzy Fleckenstein | 99357d467c | |
Lizzy Fleckenstein | 018fc64a27 | |
Lizzy Fleckenstein | b53329b452 | |
Lizzy Fleckenstein | c27dea59b0 | |
Lizzy Fleckenstein | 80c6b547e5 | |
Lizzy Fleckenstein | 0de53a9dcb | |
Lizzy Fleckenstein | 67dd48b06c | |
Lizzy Fleckenstein | 34c31cac1f | |
Lizzy Fleckenstein | 788b6dc080 | |
Lizzy Fleckenstein | 200ce76c70 | |
Lizzy Fleckenstein | ca94a1c354 |
4
API.md
4
API.md
|
@ -17,10 +17,6 @@ Items can have these fields:
|
|||
anvil.
|
||||
See `mcl_banners` for an example.
|
||||
|
||||
Tools can have these fields:
|
||||
* `_mcl_diggroups`: Specifies the digging groups that a tool can dig and how
|
||||
efficiently. See `_mcl_autogroup` for more information.
|
||||
|
||||
All nodes can have these fields:
|
||||
|
||||
* `_mcl_hardness`: Hardness of the block, ranges from 0 to infinity (represented by -1). Determines digging times. Default: 0
|
||||
|
|
|
@ -33,10 +33,10 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
|
|||
keepInventory = false
|
||||
|
||||
# Performance settings
|
||||
# dedicated_server_step = 0.001
|
||||
# abm_interval = 0.25
|
||||
# max_objects_per_block = 4096
|
||||
# max_packets_per_iteration = 10096
|
||||
dedicated_server_step = 0.001
|
||||
abm_interval = 0.25
|
||||
max_objects_per_block = 4096
|
||||
max_packets_per_iteration = 10096
|
||||
|
||||
# Clientmodding to support official client
|
||||
enable_client_modding = true
|
||||
|
|
|
@ -4,11 +4,6 @@ Specifically, this mod has 2 purposes:
|
|||
1) Automatically adding the group “solid” for blocks considered “solid” in Minecraft.
|
||||
2) Generating digging time group for all nodes based on node metadata (it's complicated)
|
||||
|
||||
This mod also requires another mod called “mcl_autogroup” to function properly.
|
||||
“mcl_autogroup” exposes the API used to register digging groups, while this mod
|
||||
uses those digging groups to set the digging time groups for all the nodes and
|
||||
tools.
|
||||
|
||||
See init.lua for more infos.
|
||||
|
||||
The leading underscore in the name “_mcl_autogroup” was added to force Minetest to load this mod as late as possible.
|
||||
|
|
|
@ -1,358 +1,169 @@
|
|||
--[[
|
||||
This mod implements a HACK to make 100% sure the digging times of all tools
|
||||
match Minecraft's perfectly. The digging times system of Minetest is very
|
||||
different, so this weird group trickery has to be used. In Minecraft, each
|
||||
block has a hardness and the actual Minecraft digging time is determined by
|
||||
this:
|
||||
--[[ Mining times. Yeah, mining times … Alright, this is going to be FUN!
|
||||
|
||||
This mod does include a HACK to make 100% sure the digging times of all tools match Minecraft's perfectly.
|
||||
The digging times system of Minetest is very different, so this weird group trickery has to be used.
|
||||
In Minecraft, each block has a hardness and the actual Minecraft digging time is determined by this:
|
||||
1) The block's hardness
|
||||
2) The tool being used (the tool speed and its efficiency level)
|
||||
3) Whether the tool is considered as "eligible" for the block
|
||||
2) The tool being used
|
||||
3) Whether the tool is considered as “eligible” for the block
|
||||
(e.g. only diamond pick eligible for obsidian)
|
||||
See Minecraft Wiki <http://minecraft.gamepedia.com/Minecraft_Wiki> for more information.
|
||||
|
||||
See Minecraft Wiki <http://minecraft.gamepedia.com/Minecraft_Wiki> for more
|
||||
information.
|
||||
In MineClone 2, all diggable node have the hardness set in the custom field “_mcl_hardness” (0 by default).
|
||||
The nodes are also required to specify the “eligible” tools in groups like “pickaxey”, “shovely”, etc.
|
||||
This mod then calculates the real digging time based on the node meta data. The real digging times
|
||||
are then added into mcl_autogroup.digtimes where the table indices are group rating and the values are the
|
||||
digging times in seconds. These digging times can be then added verbatim into the tool definitions.
|
||||
|
||||
How the mod is used
|
||||
===================
|
||||
Example:
|
||||
mcl_autogroup.digtimes.pickaxey_dig_diamond[1] = 0.2
|
||||
|
||||
In MineClone 2, all diggable nodes have the hardness set in the custom field
|
||||
"_mcl_hardness" (0 by default). These values are used together with digging
|
||||
groups by this mod to create the correct digging times for nodes. Digging
|
||||
groups are registered using the following code:
|
||||
→ This means that when a node has been assigned the group “pickaxey_dig_diamond=1”, it can be dug by the
|
||||
diamond pickaxe in 0.2 seconds.
|
||||
|
||||
mcl_autogroup.register_diggroup("shovely")
|
||||
mcl_autogroup.register_diggroup("pickaxey", {
|
||||
levels = { "wood", "gold", "stone", "iron", "diamond" }
|
||||
})
|
||||
|
||||
The first line registers a simple digging group. The second line registers a
|
||||
digging group with 5 different levels (in this case one for each material of a
|
||||
pickaxes).
|
||||
|
||||
Nodes indicate that they belong to a particular digging group by being member of
|
||||
the digging group in their node definition. "mcl_core:dirt" for example has
|
||||
shovely=1 in its groups. If the digging group has multiple levels the value of
|
||||
the group indicates which digging level the node requires.
|
||||
"mcl_core:stone_with_gold" for example has pickaxey=4 because it requires a
|
||||
pickaxe of level 4 be mined.
|
||||
This strange setup with mcl_autogroup has been done to minimize the amount of required digging times
|
||||
a single tool needs to use. If this is not being done, the loading time will increase considerably
|
||||
(>10s).
|
||||
|
||||
For tools to be able to dig nodes of digging groups they need to use the have
|
||||
the custom field "_mcl_diggroups" function to get the groupcaps. The value of
|
||||
this field is a table which defines which groups the tool can dig and how
|
||||
efficiently.
|
||||
]]
|
||||
|
||||
_mcl_diggroups = {
|
||||
handy = { speed = 1, level = 1, uses = 0 },
|
||||
pickaxey = { speed = 1, level = 0, uses = 0 },
|
||||
}
|
||||
local materials = { "wood", "gold", "stone", "iron", "diamond" }
|
||||
local basegroups = { "pickaxey", "axey", "shovely" }
|
||||
local minigroups = { "handy", "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" }
|
||||
local divisors = {
|
||||
["wood"] = 2,
|
||||
["gold"] = 12,
|
||||
["stone"] = 4,
|
||||
["iron"] = 6,
|
||||
["diamond"] = 8,
|
||||
["handy"] = 1,
|
||||
["shearsy"] = 15,
|
||||
["swordy"] = 1.5,
|
||||
["shearsy_wool"] = 5,
|
||||
["swordy_cobweb"] = 15,
|
||||
}
|
||||
local max_efficiency_level = 5
|
||||
|
||||
The "uses" field indicate how many uses (0 for infinite) a tool has when used on
|
||||
the specified digging group. The "speed" field is a multiplier to the dig speed
|
||||
on that digging group.
|
||||
mcl_autogroup = {}
|
||||
mcl_autogroup.digtimes = {}
|
||||
mcl_autogroup.creativetimes = {} -- Copy of digtimes, except that all values are 0. Used for creative mode
|
||||
|
||||
The "level" field indicates which levels of the group the tool can harvest. A
|
||||
level of 0 means that the tool cannot harvest blocks of that node. A level of 1
|
||||
or above means that the tool can harvest nodes with that level or below. See
|
||||
"mcl_tools/init.lua" for examples on how "_mcl_diggroups" is used in practice.
|
||||
|
||||
Information about the mod
|
||||
=========================
|
||||
|
||||
The mod is split up into two parts, mcl_autogroup and _mcl_autogroup.
|
||||
mcl_autogroup contains the API functions used to register custom digging groups.
|
||||
_mcl_autogroup contains most of the code. The leading underscore in the name
|
||||
"_mcl_autogroup" is used to force Minetest to load that part of the mod as late
|
||||
as possible. Minetest loads mods in reverse alphabetical order.
|
||||
|
||||
This also means that it is very important that no mod adds _mcl_autogroup as a
|
||||
dependency.
|
||||
--]]
|
||||
|
||||
assert(minetest.get_modpath("mcl_autogroup"), "This mod requires the mod mcl_autogroup to function")
|
||||
|
||||
-- Returns a table containing the unique "_mcl_hardness" for nodes belonging to
|
||||
-- each diggroup.
|
||||
local function get_hardness_values_for_groups()
|
||||
local maps = {}
|
||||
local values = {}
|
||||
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||
maps[g] = {}
|
||||
values[g] = {}
|
||||
end
|
||||
|
||||
for _, ndef in pairs(minetest.registered_nodes) do
|
||||
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||
if ndef.groups[g] ~= nil then
|
||||
maps[g][ndef._mcl_hardness or 0] = true
|
||||
end
|
||||
for m=1, #materials do
|
||||
for g=1, #basegroups do
|
||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m]] = {}
|
||||
mcl_autogroup.creativetimes[basegroups[g].."_dig_"..materials[m]] = {}
|
||||
for e=1, max_efficiency_level do
|
||||
mcl_autogroup.digtimes[basegroups[g].."_dig_"..materials[m].."_efficiency_"..e] = {}
|
||||
end
|
||||
end
|
||||
|
||||
for g, map in pairs(maps) do
|
||||
for k, _ in pairs(map) do
|
||||
table.insert(values[g], k)
|
||||
end
|
||||
end
|
||||
|
||||
for g, _ in pairs(mcl_autogroup.registered_diggroups) do
|
||||
table.sort(values[g])
|
||||
end
|
||||
return values
|
||||
end
|
||||
|
||||
-- Returns a table containing a table indexed by "_mcl_hardness_value" to get
|
||||
-- its index in the list of unique hardnesses for each diggroup.
|
||||
local function get_hardness_lookup_for_groups(hardness_values)
|
||||
local map = {}
|
||||
for g, values in pairs(hardness_values) do
|
||||
map[g] = {}
|
||||
for k, v in pairs(values) do
|
||||
map[g][v] = k
|
||||
end
|
||||
for g=1, #minigroups do
|
||||
mcl_autogroup.digtimes[minigroups[g].."_dig"] = {}
|
||||
mcl_autogroup.creativetimes[minigroups[g].."_dig"] = {}
|
||||
for e=1, max_efficiency_level do
|
||||
mcl_autogroup.digtimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
||||
mcl_autogroup.creativetimes[minigroups[g].."_dig_efficiency_"..e] = {}
|
||||
end
|
||||
return map
|
||||
end
|
||||
|
||||
-- Array of unique hardness values for each group which affects dig time.
|
||||
local hardness_values = get_hardness_values_for_groups()
|
||||
|
||||
-- Map indexed by hardness values which return the index of that value in
|
||||
-- hardness_value. Used for quick lookup.
|
||||
local hardness_lookup = get_hardness_lookup_for_groups(hardness_values)
|
||||
|
||||
local function compute_creativetimes(group)
|
||||
local creativetimes = {}
|
||||
|
||||
for index, hardness in pairs(hardness_values[group]) do
|
||||
table.insert(creativetimes, 0)
|
||||
end
|
||||
|
||||
return creativetimes
|
||||
end
|
||||
|
||||
-- Get the list of digging times for using a specific tool on a specific
|
||||
-- diggroup.
|
||||
--
|
||||
-- Parameters:
|
||||
-- group - the group which it is digging
|
||||
-- can_harvest - if the tool can harvest the block
|
||||
-- speed - dig speed multiplier for tool (default 1)
|
||||
-- efficiency - efficiency level for the tool if applicable
|
||||
local function get_digtimes(group, can_harvest, speed, efficiency)
|
||||
local speed = speed or 1
|
||||
if efficiency then
|
||||
speed = speed + efficiency * efficiency + 1
|
||||
end
|
||||
|
||||
local digtimes = {}
|
||||
|
||||
for index, hardness in pairs(hardness_values[group]) do
|
||||
local digtime = (hardness or 0) / speed
|
||||
if can_harvest then
|
||||
digtime = digtime * 1.5
|
||||
else
|
||||
digtime = digtime * 5
|
||||
end
|
||||
|
||||
if digtime <= 0.05 then
|
||||
digtime = 0
|
||||
else
|
||||
digtime = math.ceil(digtime * 20) / 20
|
||||
end
|
||||
table.insert(digtimes, digtime)
|
||||
end
|
||||
|
||||
return digtimes
|
||||
end
|
||||
|
||||
-- Get one groupcap field for using a specific tool on a specific group.
|
||||
local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
||||
return {
|
||||
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
||||
uses = uses,
|
||||
maxlevel = 0,
|
||||
}
|
||||
end
|
||||
|
||||
-- Add the groupcaps from a field in "_mcl_diggroups" to the groupcaps of a
|
||||
-- tool.
|
||||
local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency)
|
||||
for g, capsdef in pairs(groupcaps_def) do
|
||||
local mult = capsdef.speed or 1
|
||||
local uses = capsdef.uses
|
||||
local def = mcl_autogroup.registered_diggroups[g]
|
||||
local max_level = def.levels and #def.levels or 1
|
||||
|
||||
assert(capsdef.level, toolname .. ' is missing level for ' .. g)
|
||||
local level = math.min(capsdef.level, max_level)
|
||||
|
||||
if def.levels then
|
||||
groupcaps[g .. "_dig_default"] = get_groupcap(g, false, mult, efficiency, uses)
|
||||
if level > 0 then
|
||||
groupcaps[g .. "_dig_" .. def.levels[level]] = get_groupcap(g, true, mult, efficiency, uses)
|
||||
end
|
||||
else
|
||||
groupcaps[g .. "_dig"] = get_groupcap(g, level > 0, mult, efficiency, uses)
|
||||
end
|
||||
end
|
||||
return groupcaps
|
||||
end
|
||||
|
||||
-- Checks if the given node would drop its useful drop if dug by a given tool.
|
||||
-- Returns true if it will yield its useful drop, false otherwise.
|
||||
function mcl_autogroup.can_harvest(nodename, toolname)
|
||||
local ndef = minetest.registered_nodes[nodename]
|
||||
|
||||
if minetest.get_item_group(nodename, "dig_immediate") >= 2 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Check if it can be dug by tool
|
||||
local tdef = minetest.registered_tools[toolname]
|
||||
if tdef and tdef._mcl_diggroups then
|
||||
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||
if ndef.groups[g] then
|
||||
if ndef.groups[g] <= gdef.level then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if it can be dug by hand
|
||||
local tdef = minetest.registered_tools[""]
|
||||
if tdef then
|
||||
for g, gdef in pairs(tdef._mcl_diggroups) do
|
||||
if ndef.groups[g] then
|
||||
if ndef.groups[g] <= gdef.level then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Get one groupcap field for using a specific tool on a specific group.
|
||||
local function get_groupcap(group, can_harvest, multiplier, efficiency, uses)
|
||||
return {
|
||||
times = get_digtimes(group, can_harvest, multiplier, efficiency),
|
||||
uses = uses,
|
||||
maxlevel = 0,
|
||||
}
|
||||
end
|
||||
|
||||
-- Returns the tool_capabilities from a tool definition or a default set of
|
||||
-- tool_capabilities
|
||||
local function get_tool_capabilities(tdef)
|
||||
if tdef.tool_capabilities then
|
||||
return tdef.tool_capabilities
|
||||
end
|
||||
|
||||
-- If the damage group and punch interval from hand is not included,
|
||||
-- then the user will not be able to attack with the tool.
|
||||
local hand_toolcaps = minetest.registered_tools[""].tool_capabilities
|
||||
return {
|
||||
full_punch_interval = hand_toolcaps.full_punch_interval,
|
||||
damage_groups = hand_toolcaps.damage_groups
|
||||
}
|
||||
end
|
||||
|
||||
-- Get the groupcaps for a tool. This function returns "groupcaps" table of
|
||||
-- digging which should be put in the "tool_capabilities" of the tool definition
|
||||
-- or in the metadata of an enchanted tool.
|
||||
--
|
||||
-- Parameters:
|
||||
-- toolname - Name of the tool being enchanted (like "mcl_tools:diamond_pickaxe")
|
||||
-- efficiency - The efficiency level the tool is enchanted with (default 0)
|
||||
--
|
||||
-- NOTE:
|
||||
-- This function can only be called after mod initialization. Otherwise a mod
|
||||
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||
-- loading order.
|
||||
function mcl_autogroup.get_groupcaps(toolname, efficiency)
|
||||
local tdef = minetest.registered_tools[toolname]
|
||||
local groupcaps = table.copy(get_tool_capabilities(tdef).groupcaps or {})
|
||||
add_groupcaps(toolname, groupcaps, tdef._mcl_diggroups, efficiency)
|
||||
return groupcaps
|
||||
end
|
||||
|
||||
-- Get the wear from using a tool on a digging group.
|
||||
--
|
||||
-- Parameters
|
||||
-- toolname - Name of the tool used
|
||||
-- diggroup - The name of the diggroup the tool is used on
|
||||
--
|
||||
-- NOTE:
|
||||
-- This function can only be called after mod initialization. Otherwise a mod
|
||||
-- would have to add _mcl_autogroup as a dependency which would break the mod
|
||||
-- loading order.
|
||||
function mcl_autogroup.get_wear(toolname, diggroup)
|
||||
local tdef = minetest.registered_tools[toolname]
|
||||
local uses = tdef._mcl_diggroups[diggroup].uses
|
||||
return math.ceil(65535 / uses)
|
||||
end
|
||||
|
||||
local overwrite = function()
|
||||
for nname, ndef in pairs(minetest.registered_nodes) do
|
||||
local groups_changed = false
|
||||
local newgroups = table.copy(ndef.groups)
|
||||
if (nname ~= "ignore" and ndef.diggable) then
|
||||
-- Automatically assign the "solid" group for solid nodes
|
||||
-- Automatically assign the “solid” group for solid nodes
|
||||
if (ndef.walkable == nil or ndef.walkable == true)
|
||||
and (ndef.collision_box == nil or ndef.collision_box.type == "regular")
|
||||
and (ndef.node_box == nil or ndef.node_box.type == "regular")
|
||||
and (ndef.groups.not_solid == 0 or ndef.groups.not_solid == nil) then
|
||||
newgroups.solid = 1
|
||||
groups_changed = true
|
||||
end
|
||||
-- Automatically assign the "opaque" group for opaque nodes
|
||||
-- Automatically assign the “opaque” group for opaque nodes
|
||||
if (not (ndef.paramtype == "light" or ndef.sunlight_propagates)) and
|
||||
(ndef.groups.not_opaque == 0 or ndef.groups.not_opaque == nil) then
|
||||
newgroups.opaque = 1
|
||||
groups_changed = true
|
||||
end
|
||||
|
||||
local creative_breakable = false
|
||||
local function calculate_group(hardness, material, diggroup, newgroups, actual_rating, expected_rating, efficiency)
|
||||
local time, validity_factor
|
||||
if actual_rating >= expected_rating then
|
||||
-- Valid tool
|
||||
validity_factor = 1.5
|
||||
else
|
||||
-- Wrong tool (higher digging time)
|
||||
validity_factor = 5
|
||||
end
|
||||
local speed_multiplier = divisors[material]
|
||||
if efficiency then
|
||||
speed_multiplier = speed_multiplier + efficiency * efficiency + 1
|
||||
end
|
||||
time = (hardness * validity_factor) / speed_multiplier
|
||||
if time <= 0.05 then
|
||||
time = 0
|
||||
else
|
||||
time = math.ceil(time * 20) / 20
|
||||
end
|
||||
table.insert(mcl_autogroup.digtimes[diggroup], time)
|
||||
if not efficiency then
|
||||
table.insert(mcl_autogroup.creativetimes[diggroup], 0)
|
||||
end
|
||||
newgroups[diggroup] = #mcl_autogroup.digtimes[diggroup]
|
||||
return newgroups
|
||||
end
|
||||
|
||||
-- Assign groups used for digging this node depending on
|
||||
-- the registered digging groups
|
||||
for g, gdef in pairs(mcl_autogroup.registered_diggroups) do
|
||||
creative_breakable = true
|
||||
local index = hardness_lookup[g][ndef._mcl_hardness or 0]
|
||||
if ndef.groups[g] then
|
||||
if gdef.levels then
|
||||
newgroups[g .. "_dig_default"] = index
|
||||
-- Hack in digging times
|
||||
local hardness = ndef._mcl_hardness
|
||||
if not hardness then
|
||||
hardness = 0
|
||||
end
|
||||
|
||||
for i = ndef.groups[g], #gdef.levels do
|
||||
newgroups[g .. "_dig_" .. gdef.levels[i]] = index
|
||||
-- Handle pickaxey, axey and shovely
|
||||
for _, basegroup in pairs(basegroups) do
|
||||
if (hardness ~= -1 and ndef.groups[basegroup]) then
|
||||
for g=1,#materials do
|
||||
local diggroup = basegroup.."_dig_"..materials[g]
|
||||
newgroups = calculate_group(hardness, materials[g], diggroup, newgroups, g, ndef.groups[basegroup])
|
||||
for e=1,max_efficiency_level do
|
||||
newgroups = calculate_group(hardness, materials[g], diggroup .. "_efficiency_" .. e, newgroups, g, ndef.groups[basegroup], e)
|
||||
end
|
||||
else
|
||||
newgroups[g .. "_dig"] = index
|
||||
groups_changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for m=1, #minigroups do
|
||||
local minigroup = minigroups[m]
|
||||
if hardness ~= -1 then
|
||||
local diggroup = minigroup.."_dig"
|
||||
-- actual rating
|
||||
local ar = ndef.groups[minigroup]
|
||||
if ar == nil then
|
||||
ar = 0
|
||||
end
|
||||
if (minigroup == "handy")
|
||||
or
|
||||
(ndef.groups.shearsy_wool and minigroup == "shearsy_wool" and ndef.groups.wool)
|
||||
or
|
||||
(ndef.groups.swordy_cobweb and minigroup == "swordy_cobweb" and nname == "mcl_core:cobweb")
|
||||
or
|
||||
(ndef.groups[minigroup] and minigroup ~= "swordy_cobweb" and minigroup ~= "shearsy_wool") then
|
||||
newgroups = calculate_group(hardness, minigroup, diggroup, newgroups, ar, 1)
|
||||
for e=1,max_efficiency_level do
|
||||
newgroups = calculate_group(hardness, minigroup, diggroup .. "_efficiency_" .. e, newgroups, ar, 1, e)
|
||||
end
|
||||
groups_changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Automatically assign the node to the
|
||||
-- creative_breakable group if it belongs to any digging
|
||||
-- group.
|
||||
newgroups["creative_breakable"] = 1
|
||||
|
||||
minetest.override_item(nname, {
|
||||
groups = newgroups
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
for tname, tdef in pairs(minetest.registered_tools) do
|
||||
-- Assign groupcaps for digging the registered digging groups
|
||||
-- depending on the _mcl_diggroups in the tool definition
|
||||
if tdef._mcl_diggroups then
|
||||
local toolcaps = table.copy(get_tool_capabilities(tdef))
|
||||
toolcaps.groupcaps = mcl_autogroup.get_groupcaps(tname)
|
||||
|
||||
minetest.override_item(tname, {
|
||||
tool_capabilities = toolcaps
|
||||
})
|
||||
if groups_changed then
|
||||
minetest.override_item(nname, {
|
||||
groups = newgroups
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
name = _mcl_autogroup
|
||||
author = ryvnf
|
||||
author = Wuzzy
|
||||
description = MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
local Object = {}
|
||||
|
||||
-- Define a getter that caches the result for the next time it is called
|
||||
-- This is a static method (self = the class); in this class system static methods start with __ by convention
|
||||
function Object:__cache_getter(name, func)
|
||||
-- cache key: prevent overriding the getter function itself
|
||||
local key = "_" .. name
|
||||
-- add a function to the class
|
||||
self[name] = function(self)
|
||||
-- check if the value is present in the cache
|
||||
local value = self[key]
|
||||
|
||||
-- `== nil` instead of `not value` to allow caching boolean values
|
||||
if value == nil then
|
||||
-- call the getter function
|
||||
value = func(self)
|
||||
end
|
||||
|
||||
-- store result in cache
|
||||
self[key] = value
|
||||
|
||||
-- return result
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
-- Define a getter / setter
|
||||
-- If no argument is specified, it will act as a getter, else as a setter
|
||||
-- The specified function MUST return the new value, if it returns nil, nil will be used as new value
|
||||
-- Optionally works in combination with a previously defined cache getter and only really makes sense in that context
|
||||
function Object:__setter(name, func)
|
||||
-- since the function is overridden, we need to store the old one in case a cache getter is defined
|
||||
local cache_getter = self[name]
|
||||
-- use same key as cache getter to modify getter cache if present
|
||||
local key = "_" .. name
|
||||
|
||||
self[name] = function(self, new)
|
||||
-- check whether an argument was specified
|
||||
if new == nil then
|
||||
if cache_getter then
|
||||
-- call the cache getter if present
|
||||
return cache_getter(self)
|
||||
else
|
||||
-- return the value else
|
||||
return self[key]
|
||||
end
|
||||
end
|
||||
|
||||
-- call the setter and set the new value to the result
|
||||
self[key] = func(self, new)
|
||||
end
|
||||
end
|
||||
|
||||
-- Define a comparator function
|
||||
-- Acts like a setter, except that it does not set the new value but rather compares the present and specified values and returns whether they are equal or not
|
||||
-- Incompatible with setter
|
||||
-- The function is optional. The == operator is used else.
|
||||
function Object:__comparator(name, func)
|
||||
local cache_getter = self[name]
|
||||
local key = "_" .. name
|
||||
|
||||
self[name] = function(self, expected)
|
||||
-- the current value is needed everytime, no matter whether there is an argument or not
|
||||
local actual
|
||||
|
||||
if cache_getter then
|
||||
-- call the cache getter if present
|
||||
actual = cache_getter(self)
|
||||
else
|
||||
-- use the value else
|
||||
actual = self[key]
|
||||
end
|
||||
|
||||
-- act as a getter if there is no argument
|
||||
if expected == nil then
|
||||
return actual
|
||||
end
|
||||
|
||||
if func then
|
||||
-- if a function as specified, call it
|
||||
return func(actual, expected)
|
||||
else
|
||||
-- else, use the == operator to compare the expected value to the actual
|
||||
return actual == expected
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Override an already existing function in a way that the old function is called
|
||||
-- If nil is returned, the old function is called. Else the return value is returned. (Only the first return value is taken into concern here, multiple are supported tho)
|
||||
-- This works even if it is applied to the instance of a class when the function is defined by the class
|
||||
-- It also works with overriding functions that are located in superclasses
|
||||
function Object:__override(name, func)
|
||||
-- store the old function
|
||||
local old_func = self[name]
|
||||
|
||||
-- redefine the function with variable arguments
|
||||
self[name] = function(...)
|
||||
-- call the new function and store the return values in a table
|
||||
local rvals = {func(...)}
|
||||
-- if nil was returned, fall back to the old function
|
||||
if rvals[1] == nil then
|
||||
-- if present, call the return function with the values the new function returned (converted back to a tuple)
|
||||
return old_func(...)
|
||||
else
|
||||
-- return the values from the new function else
|
||||
return unpack(rvals)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Works like override except that the new function does not modify the output of the old function but rather the input
|
||||
-- The new function can decide with what arguments by returing them, including the `self` reference
|
||||
-- If the "self" arg is not returned the old function is not called
|
||||
-- Note that this way the new function cannot change the return value of the old function
|
||||
function Object:__pipe(name, func)
|
||||
local old_func = self[name]
|
||||
|
||||
self[name] = function(self, ...)
|
||||
local rvals = {func(self, ...)}
|
||||
-- check if self was returned properly
|
||||
if rvals[1] then
|
||||
-- if present, call the return function with the values the new function returned (converted back to a tuple)
|
||||
return old_func(unpack(rvals))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Make class available as table to distribute the Object table
|
||||
class = setmetatable({Object = Object}, {
|
||||
-- Create a new class by calling class() with an optional superclass argument
|
||||
__call = function(super)
|
||||
return setmetatable({}, {
|
||||
-- Create a new instance of the class when the class is called
|
||||
__call = function(_class, ...)
|
||||
-- Check whether the first argument is an instance of the class
|
||||
-- If that is the case, just return it - this is to allow "making sure something is the instance of a class" by calling the constructor
|
||||
local argtbl = {...}
|
||||
local first_arg = args[1]
|
||||
if first_arg and type(first_arg) == "table" and inst.CLASS = _class then
|
||||
return inst
|
||||
end
|
||||
-- set the metatable and remember which class the object belongs to
|
||||
local instance = setmetatable({CLASS = _class}, {
|
||||
__index = _class,
|
||||
})
|
||||
-- call the constructor if present
|
||||
if instance.constructor then
|
||||
instance:constructor(...)
|
||||
end
|
||||
-- return the created instance
|
||||
return instance
|
||||
end,
|
||||
-- Object as superclass of all classes that dont have a different one
|
||||
__index = super or Object,
|
||||
})
|
||||
end
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
name = class
|
||||
author = Fleckenstein
|
||||
description = A class system for MineClone2
|
|
@ -1,28 +0,0 @@
|
|||
--[[
|
||||
This is one part of a mod to replicate the digging times from Minecraft. This
|
||||
part only exposes a function to register digging groups. The rest of the mod is
|
||||
implemented and documented in the _mcl_autogroup.
|
||||
|
||||
The mod is split up into two parts, mcl_autogroup and _mcl_autogroup.
|
||||
mcl_autogroup contains the API functions used to register custom digging groups.
|
||||
_mcl_autogroup contains most of the code. The leading underscore in the name
|
||||
"_mcl_autogroup" is used to force Minetest to load that part of the mod as late
|
||||
as possible. Minetest loads mods in reverse alphabetical order.
|
||||
--]]
|
||||
mcl_autogroup = {}
|
||||
mcl_autogroup.registered_diggroups = {}
|
||||
|
||||
assert(minetest.get_modpath("_mcl_autogroup"), "This mod requires the mod _mcl_autogroup to function")
|
||||
|
||||
-- Register a group as a digging group.
|
||||
--
|
||||
-- Parameters:
|
||||
-- group - Name of the group to register as a digging group
|
||||
-- def - Table with information about the diggroup (defaults to {} if unspecified)
|
||||
--
|
||||
-- Values in def:
|
||||
-- level - If specified it is an array containing the names of the different
|
||||
-- digging levels the digging group supports.
|
||||
function mcl_autogroup.register_diggroup(group, def)
|
||||
mcl_autogroup.registered_diggroups[group] = def or {}
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_autogroup
|
||||
author = ryvnf
|
||||
description = MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
|
@ -117,10 +117,6 @@ function mcl_burning.damage(obj)
|
|||
end
|
||||
|
||||
function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||
if obj:get_hp() < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.fire_resistant then
|
||||
return
|
||||
|
@ -149,7 +145,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
|||
end
|
||||
|
||||
if old_burn_time <= burn_time then
|
||||
--[[local sound_id = mcl_burning.get(obj, "int", "sound_id")
|
||||
local sound_id = mcl_burning.get(obj, "int", "sound_id")
|
||||
if sound_id == 0 then
|
||||
sound_id = minetest.sound_play("fire_fire", {
|
||||
object = obj,
|
||||
|
@ -157,7 +153,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
|||
max_hear_distance = 16,
|
||||
loop = true,
|
||||
}) + 1
|
||||
end]]--
|
||||
end
|
||||
|
||||
local hud_id
|
||||
if obj:is_player() then
|
||||
|
@ -167,7 +163,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
|||
hud_elem_type = "image",
|
||||
position = {x = 0.5, y = 0.5},
|
||||
scale = {x = -100, y = -100},
|
||||
text = "mcl_burning_hud_flame_animated.png",
|
||||
text = "fire_basic_flame.png",
|
||||
z_index = 1000,
|
||||
}) + 1
|
||||
end
|
||||
|
@ -175,7 +171,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
|||
mcl_burning.set(obj, "float", "burn_time", burn_time)
|
||||
mcl_burning.set(obj, "string", "reason", reason)
|
||||
mcl_burning.set(obj, "int", "hud_id", hud_id)
|
||||
--mcl_burning.set(obj, "int", "sound_id", sound_id)
|
||||
mcl_burning.set(obj, "int", "sound_id", sound_id)
|
||||
|
||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||
local minp, maxp = mcl_burning.get_collisionbox(obj)
|
||||
|
@ -198,8 +194,8 @@ end
|
|||
|
||||
function mcl_burning.extinguish(obj)
|
||||
if mcl_burning.is_burning(obj) then
|
||||
--local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1
|
||||
--minetest.sound_stop(sound_id)
|
||||
local sound_id = mcl_burning.get(obj, "int", "sound_id") - 1
|
||||
minetest.sound_stop(sound_id)
|
||||
|
||||
if obj:is_player() then
|
||||
local hud_id = mcl_burning.get(obj, "int", "hud_id") - 1
|
||||
|
@ -210,7 +206,7 @@ function mcl_burning.extinguish(obj)
|
|||
mcl_burning.set(obj, "float", "burn_time")
|
||||
mcl_burning.set(obj, "float", "damage_timer")
|
||||
mcl_burning.set(obj, "int", "hud_id")
|
||||
--mcl_burning.set(obj, "int", "sound_id")
|
||||
mcl_burning.set(obj, "int", "sound_id")
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
MCLDamageSource = class()
|
||||
|
||||
function MCLDamageSource:constructor(tbl)
|
||||
if tbl then
|
||||
for k, v in pairs(tbl) do
|
||||
self[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MCLDamageSource:from_mt(reason)
|
||||
|
||||
end
|
||||
|
||||
MCLDamageSource:__getter("direct_object", function(self)
|
||||
local obj = self.raw_source_object
|
||||
if not obj then
|
||||
return
|
||||
end
|
||||
return mcl_object_mgr.get(obj)
|
||||
end)
|
||||
|
||||
MCLDamageSource:__getter("source_object", function(self)
|
||||
local direct = self:direct_object()
|
||||
if not direct then
|
||||
return
|
||||
end
|
||||
return direct.source_object or direct
|
||||
end)
|
|
@ -0,0 +1,44 @@
|
|||
MCLEntity = class(MCLObject)
|
||||
|
||||
MCLEntity:__getter("meta", MCLMetadata)
|
||||
|
||||
local last_inv_id = 0
|
||||
|
||||
MCLEntity:__getter("inventory", function(self)
|
||||
local info = self.inventory_info
|
||||
if not info then
|
||||
return
|
||||
end
|
||||
self.inventory_id = "mcl_entity:" .. last_inv_id
|
||||
last_inv_id = last_inv_id + 1
|
||||
local inv = minetest.create_detached_inventory(self.inventory_id, self.inventory_callbacks)
|
||||
for list, size in pairs(data.sizes) do
|
||||
inv:set_size(list, size)
|
||||
end
|
||||
for list, liststr in pairs(data.lists) do
|
||||
inv:set_list(list, liststr)
|
||||
end
|
||||
return inv
|
||||
end)
|
||||
|
||||
function MCLEntity:on_activate(staticdata)
|
||||
local data = minetest.deserialize(staticdata)
|
||||
if data then
|
||||
self:meta():from_table(data)
|
||||
self.inventory_info = data.inventory
|
||||
end
|
||||
end
|
||||
|
||||
function MCLEntity:get_staticdata()
|
||||
local data = self:meta():to_table()
|
||||
local inventory_info = self.inventory_info
|
||||
|
||||
if inventory_info then
|
||||
data.inventory = {
|
||||
sizes = inventory_info.sizes,
|
||||
lists = self:inventory():get_lists()
|
||||
}
|
||||
end
|
||||
|
||||
return minetest.serialize(data)
|
||||
end
|
|
@ -0,0 +1,103 @@
|
|||
MCLEquipment = class()
|
||||
|
||||
function MCLEquipment:constructor(inv, idx)
|
||||
self.inv = inv
|
||||
self.idx = idx
|
||||
end
|
||||
|
||||
MCLEquipment:__cache_getter("has_main", function(self)
|
||||
return self.inv and self.idx and self.inv:get_list("main") and true or false
|
||||
end)
|
||||
|
||||
MCLEquipment:__cache_getter("has_right", function(self)
|
||||
return self.inv and self.inv:get_list("right_hand") and true or false
|
||||
end)
|
||||
|
||||
MCLEquipment:__cache_getter("has_left", function(self)
|
||||
return self.inv and self.inv:get_list("left_hand") and true or false
|
||||
end)
|
||||
|
||||
MCLEquipment:__cache_getter("has_armor", function(self)
|
||||
return self.inv and self.inv:get_list("armor") and true or false
|
||||
end)
|
||||
|
||||
function MCLEquipment:mainhand()
|
||||
if self:has_main() then
|
||||
return self.inv:get_stack("main", self.idx)
|
||||
elseif self:has_right() then
|
||||
return self.inv:get_stack("right_hand", 1)
|
||||
else
|
||||
return ItemStack()
|
||||
end
|
||||
end
|
||||
|
||||
MCLEquipment:__setter("mainhand", function(self, new)
|
||||
if self:has_main() then
|
||||
self.inv:set_stack("main", self.idx, stack)
|
||||
elseif self:has_right() then
|
||||
self.inv:set_stack("right_hand", 1, stack)
|
||||
end
|
||||
end)
|
||||
|
||||
function MCLEquipment:offhand()
|
||||
if self:has_left() then
|
||||
return self.inv:get_stack("left_hand", 1)
|
||||
else
|
||||
return ItemStack()
|
||||
end
|
||||
end
|
||||
|
||||
MCLEquipment:__setter("offhand", function(self, new)
|
||||
if self:has_left() then
|
||||
self.inv:set_stack("left_hand", 1, new)
|
||||
end
|
||||
end)
|
||||
|
||||
function MCLEquipment:__armor(idx, name)
|
||||
self[name] = function(self)
|
||||
if self:has_armor() then
|
||||
return self.inv:get_stack("armor", idx)
|
||||
else
|
||||
return ItemStack()
|
||||
end
|
||||
end
|
||||
|
||||
self:__setter(name, function(self, new)
|
||||
if self:has_armor() then
|
||||
self.inv:set_stack("armor", idx, new)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local armor_slots = {"helmet", "chestplace", "leggings", "boots"}
|
||||
|
||||
for i, name in ipairs(armor_slots) do
|
||||
MCLEquipment:__armor(idx, name)
|
||||
end
|
||||
|
||||
local function insert(tbl, key, stack)
|
||||
if stack:get_name() ~= "" then
|
||||
tbl[key] = stack
|
||||
end
|
||||
end
|
||||
|
||||
function MCLEquipment:get_armor()
|
||||
local tbl = {}
|
||||
if self:has_armor() then
|
||||
for i, name in ipairs(armor_slots) do
|
||||
insert(tbl, name, self.inv:get_stack("armor", i))
|
||||
end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
function MCLEquipment:get_all()
|
||||
local tbl = {}
|
||||
insert(tbl, "mainhand", self:mainhand())
|
||||
insert(tbl, "offhand", self:offhand())
|
||||
for k, v in pairs(self:get_armor()) do
|
||||
tbl[k] = v
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
mcl_gamerules = {
|
||||
__defaults = {},
|
||||
__rules = {},
|
||||
}
|
||||
|
||||
setmetatable(mcl_gamerules, {__index = mcl_gamerules.__rules})
|
||||
|
||||
local worldpath = minetest.get_worldpath()
|
||||
|
||||
function mcl_gamerules.__load()
|
||||
local file = io.open(worldpath .. "gamerules.json", "r")
|
||||
if file then
|
||||
local contents = file:read("*all")
|
||||
file:close()
|
||||
local data = minetest.parse_json(contents)
|
||||
local rules = mcl_gamerules.__rules
|
||||
for rule, default in pairs(mcl_gamerules.__defaults) do
|
||||
local value = data[rule]
|
||||
if value == nil then
|
||||
value = default
|
||||
end
|
||||
rules[rule] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_gamerules.__save()
|
||||
local file = io.open(worldpath .. "gamerules.json", "w")
|
||||
file:write(minetest.write_json(mcl_gamerules.__rules, true))
|
||||
file:close()
|
||||
end
|
||||
|
||||
function mcl_gamerules.__set(rule, value)
|
||||
if not mcl_gamerules.__defaults[rule] then
|
||||
return false
|
||||
end
|
||||
mcl_gamerules.__rules[rule] = value
|
||||
mcl_gamerules.__save()
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_gamerules.__register(rule, default)
|
||||
mcl_gamerules.__defaults[rule] = default
|
||||
end
|
||||
|
||||
mcl_gamerules.__register("announceAdvancements", true)
|
||||
mcl_gamerules.__register("commandBlockOutput", true)
|
||||
mcl_gamerules.__register("doDaylightCycle", true)
|
||||
mcl_gamerules.__register("doFireTick", true)
|
||||
mcl_gamerules.__register("doImmediateRespawn", false)
|
||||
mcl_gamerules.__register("doMobLoot", true)
|
||||
mcl_gamerules.__register("doMobSpawning", true)
|
||||
mcl_gamerules.__register("doTileDrops", true)
|
||||
mcl_gamerules.__register("doWeatherCycle", true)
|
||||
mcl_gamerules.__register("drowningDamage", true)
|
||||
mcl_gamerules.__register("fallDamage", true)
|
||||
mcl_gamerules.__register("fireDamage", true)
|
||||
mcl_gamerules.__register("keepInventory", false)
|
||||
mcl_gamerules.__register("logAdminCommands", true)
|
||||
mcl_gamerules.__register("mobGriefing", true)
|
||||
mcl_gamerules.__register("naturalRegeneration", true)
|
||||
mcl_gamerules.__register("pvp", true)
|
||||
mcl_gamerules.__register("showDeathMessages", true)
|
||||
mcl_gamerules.__register("tntExplodes", true)
|
||||
|
||||
minetest.register_on_mods_loaded(mcl_gamerules.__load)
|
|
@ -0,0 +1,32 @@
|
|||
mcl_groupcache = {
|
||||
cache = {},
|
||||
}
|
||||
|
||||
local function check_insert(item, group, cache)
|
||||
if minetest.get_item_group(item, group) ~= 0 then
|
||||
table.insert(cache, item)
|
||||
end
|
||||
end
|
||||
|
||||
local old_register_item = minetest.register_item
|
||||
|
||||
function minetest.register_item(name, def)
|
||||
old_register_item(name, def)
|
||||
for group, cache in pairs(mcl_groupcache.cache) do
|
||||
check_insert(item, group, cache)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_groupcache.init_cache(group)
|
||||
local cache = {}
|
||||
for item in pairs(minetest.registered_items) do
|
||||
check_insert(item, group, cache)
|
||||
end
|
||||
return cache
|
||||
end
|
||||
|
||||
function mcl_groupcache.get_items_in_group(group)
|
||||
local cache = mcl_groupcache.cache[group] or mcl_groupcache.init_cache(group)
|
||||
mcl_groupcache.cache[group] = cache
|
||||
return cache
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_groupcache
|
||||
author = Fleckenstein
|
||||
description = Keep track of items with certain groups
|
|
@ -33,26 +33,25 @@ mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16)
|
|||
mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000)
|
||||
local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2)
|
||||
mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
local chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1
|
||||
local central_chunk_max_pos = central_chunk_min_pos + chunk_size_in_nodes - 1
|
||||
local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE)
|
||||
local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes
|
||||
local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize)
|
||||
return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
|
@ -71,7 +70,7 @@ function mcl_vars.pos_to_chunk(pos)
|
|||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
MCLItemStack = class()
|
||||
|
||||
function MCLItemStack:constructor(stack)
|
||||
self.stack = stack
|
||||
end
|
||||
|
||||
MCLItemStack:__getter("enchantments", function(self)
|
||||
return mcl_enchanting.get_enchantments(self.stack)
|
||||
end)
|
||||
MCLItemStack:__comparator("enchantments", mcl_types.match_enchantments)
|
||||
|
||||
function MCLItemStack:meta()
|
||||
return self.stack:get_meta()
|
||||
end
|
||||
MCLItemStack:__comparator("meta", mcl_types.match_meta)
|
||||
|
||||
function MCLItemStack:get_enchantment(name)
|
||||
return self:enchantments()[name] or 0
|
||||
end
|
||||
|
||||
function MCLItemStack:has_enchantment(name)
|
||||
return self:get_enchantment(name) > 0
|
||||
end
|
||||
|
||||
function MCLItemStack:total_durability()
|
||||
end
|
||||
|
||||
function MCLItemStack:durability()
|
||||
local def = self.stack:get_definition()
|
||||
if def then
|
||||
local base_uses = def._durability
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function MCLItemStack:use_durability()
|
||||
end
|
||||
|
||||
function MCLItemStack:restore_durability()
|
||||
end
|
||||
|
||||
function MCLItemStack:get_group()
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
MCLMetadata = class()
|
||||
|
||||
function MCLMetadata:constructor()
|
||||
self.fields = {}
|
||||
end
|
||||
|
||||
for _type, default in pairs({string = "", float = 0.0, int = 0}) do
|
||||
MCLMetadata["set_" .. _type] = function(name, value) do
|
||||
if value == default then
|
||||
value = nil
|
||||
end
|
||||
self.fields[name] = value
|
||||
end
|
||||
MCLMetadata["get_" .. _type] = function(name) do
|
||||
return self.fields[name] or default
|
||||
end
|
||||
end
|
||||
|
||||
function MCLMetadata:to_table()
|
||||
return table.copy(self)
|
||||
end
|
||||
|
||||
function MCLMetadata:from_table(tbl)
|
||||
self.fields = table.copy(tbl.fields)
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
MCLMob = class(MCLEntity)
|
||||
|
||||
function MCLMob:get_hp()
|
||||
self:meta():get_float("hp")
|
||||
end
|
||||
|
||||
function MCLMob:set_hp()
|
||||
self:meta():set_float("hp", hp)
|
||||
end
|
||||
|
||||
function MCLMob:on_damage(damage, source)
|
||||
MCLEntity.on_damage(self, damage, source)
|
||||
|
||||
local new_hp = self:get_hp()
|
||||
if new_hp <= 0 and new_hp + damage > 0 then
|
||||
self:on_death(source)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,105 @@
|
|||
MCLObject = class()
|
||||
|
||||
function MCLObject:constructor(obj)
|
||||
self.object = obj.object or obj
|
||||
self.IS_MCL_OBJECT = true
|
||||
end
|
||||
|
||||
function MCLObject:on_punch(hitter, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
local source = MCLDamageSource({is_punch = true, raw_source_object = hitter})
|
||||
|
||||
local knockback = {
|
||||
hitter = hitter,
|
||||
time_from_last_punch = time_from_last_punch,
|
||||
tool_capabilities = tool_capabilities,
|
||||
dir = dir,
|
||||
}
|
||||
|
||||
self:damage(damage, source, knockback)
|
||||
return true
|
||||
end
|
||||
|
||||
-- use this function to deal regular damage to an object (do NOT use :punch() unless toolcaps need to be handled)
|
||||
function MCLObject:damage(damage, source, knockback)
|
||||
damage = self:damage_modifier(damage, source) or damage
|
||||
self:set_hp(self:get_hp() - damage)
|
||||
|
||||
if type(knockback) == "table" then
|
||||
knockback = self:calculate_knockback(
|
||||
knockback.hitter,
|
||||
knockback.time_from_last_punch,
|
||||
knockback.tool_capabilities,
|
||||
knockback.dir or vector.direction(knockback.hitter:get_pos(), self.object:get_pos(),
|
||||
knockback.distance or vector.distance(knockback.hitter:get_pos(), self.object:get_pos(),
|
||||
damage,
|
||||
source)
|
||||
end
|
||||
|
||||
table.insert(self.damage_info, {
|
||||
damage = damage,
|
||||
source = source,
|
||||
knockback = knockback,
|
||||
})
|
||||
|
||||
return damage
|
||||
end
|
||||
|
||||
function MCLObject:wield_index()
|
||||
end
|
||||
|
||||
MCLObject:__getter("equipment", function(self)
|
||||
return MCLEquipment(self:inventory(), self:wield_index())
|
||||
end)
|
||||
|
||||
function MCLObject:get_hp()
|
||||
return self.object:get_hp()
|
||||
end
|
||||
|
||||
function MCLObject:set_hp(hp)
|
||||
self.object:set_hp(hp)
|
||||
end
|
||||
|
||||
function MCLObject:death_drop(inventory, listname, index, stack)
|
||||
minetest.add_item(self.object:get_pos(), stack)
|
||||
inventory:set_stack(listname, index, nil)
|
||||
end
|
||||
|
||||
function MCLObject:on_death(source)
|
||||
local inventory = self:inventory()
|
||||
if inventory then
|
||||
for listname, list in pairs(inventory:get_lists()) do
|
||||
for index, stack in pairs(list) do
|
||||
if stack:get_name() ~= "" and then
|
||||
self:death_drop(inventory, listname, index, stack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MCLObject:damage_modifier(damage, source)
|
||||
if self.invulnerable and not source.bypasses_invulnerability then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function MCLObject:on_damage(damage, source, knockback)
|
||||
end
|
||||
|
||||
MCLObject.calculate_knockback = minetest.calculate_knockback
|
||||
|
||||
function minetest.calculate_knockback()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MCLObject:on_step()
|
||||
local damage_info = self.damage_info
|
||||
if damage_info then
|
||||
self.damage_info = nil
|
||||
self:on_damage(damage_info.damage, damage_info.source)
|
||||
|
||||
if damage_info.knockback then
|
||||
self.object:add_velocity(damage_info.knockback)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,121 @@
|
|||
mcl_object_mgr = {
|
||||
players = {}
|
||||
}
|
||||
|
||||
-- functions
|
||||
|
||||
function mcl_object_mgr.get(obj)
|
||||
local rval
|
||||
|
||||
if mcl_object_mgr.is_mcl_object(obj) then
|
||||
rval = obj
|
||||
elseif mcl_object_mgr.is_player(obj) then
|
||||
rval = mcl_object_mgr.get_player(obj)
|
||||
elseif mcl_object_mgr.is_entity(obj) then
|
||||
rval = mcl_object_mgr.get_entity(obj)
|
||||
end
|
||||
|
||||
return assert(rval, "No matching MCLObject found. This is most likely an error caused by custom mods.")
|
||||
end
|
||||
|
||||
function mcl_object_mgr.is_mcl_object(obj)
|
||||
return type(obj) == "table" and obj.IS_MCL_OBJECT
|
||||
end
|
||||
|
||||
function mcl_object_mgr.is_player(obj)
|
||||
return type(obj) == "string" or type(obj) == "userdata" and obj:is_player()
|
||||
end
|
||||
|
||||
function mcl_object_mgr.is_is_entity(obj)
|
||||
return type(obj) == "table" and obj.object or type(obj) == "userdata" and obj:get_luaentity()
|
||||
end
|
||||
|
||||
function mcl_object_mgr.get_entity(ent)
|
||||
if type(ent) == "userdata" then
|
||||
ent = ent:get_luaentity()
|
||||
end
|
||||
return ent.mcl_entity
|
||||
end
|
||||
|
||||
function mcl_object_mgr.get_player(name)
|
||||
if type(name) == "userdata" then
|
||||
name = name:get_player_name()
|
||||
end
|
||||
return mcl_player_mgr.players[name]
|
||||
end
|
||||
|
||||
-- entity wrappers
|
||||
|
||||
local function add_entity_wrapper(def, name)
|
||||
def[name] = function(luaentity, ...)
|
||||
local func = self.mcl_entity[name]
|
||||
if func then
|
||||
return func(self.mcl_entity, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_object_mgr.register_entity(name, initial_properties, base_class)
|
||||
local def = {
|
||||
initial_properties = initial_properties,
|
||||
|
||||
on_activate = function(self, ...)
|
||||
local entity = base_class(self.object)
|
||||
self.mcl_entity = entity
|
||||
if entity.on_activate then
|
||||
entity:on_activate(...)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
add_entity_wrapper(def, "on_deactivate")
|
||||
add_entity_wrapper(def, "on_step")
|
||||
add_entity_wrapper(def, "on_punch")
|
||||
add_entity_wrapper(def, "on_death")
|
||||
add_entity_wrapper(def, "on_rightclick")
|
||||
add_entity_wrapper(def, "on_attach_child")
|
||||
add_entity_wrapper(def, "on_detach_child")
|
||||
add_entity_wrapper(def, "on_detach")
|
||||
add_entity_wrapper(def, "get_staticdata")
|
||||
|
||||
minetest.register_entity(name, def)
|
||||
end
|
||||
|
||||
-- player wrappers
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
mcl_player_mgr.players[name] = MCLPlayer(player)
|
||||
mcl_player_mgr.players[name]:on_join()
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
mcl_player_mgr.players[name]:on_leave()
|
||||
mcl_player_mgr.players[name] = nil
|
||||
end)
|
||||
|
||||
local function add_player_wrapper(wrapper, regfunc)
|
||||
minetest[regfunc or "register_" .. wrapper .. "player"](function(player, ...)
|
||||
local mclplayer = mcl_player_mgr.players[player:get_player_name()]
|
||||
local func = mclplayer[funcname or wrapper]
|
||||
if func then
|
||||
func(mclplayer, ...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
add_player_wrapper("on_punch")
|
||||
add_player_wrapper("on_rightclick")
|
||||
add_player_wrapper("on_death", "register_on_dieplayer")
|
||||
add_player_wrapper("on_respawn")
|
||||
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
||||
if not reason.auto then
|
||||
local mclplayer = mcl_object_mgr.get(player)
|
||||
local source = MCLDamageSource():from_mt(reason)
|
||||
|
||||
mclplayer:damage(hp_change, source)
|
||||
return true
|
||||
end
|
||||
end, true)
|
|
@ -0,0 +1,19 @@
|
|||
MCLPlayer = class(MCLObject)
|
||||
|
||||
MCLPlayer:__cache_getter("meta", function(self)
|
||||
return self.object:get_meta()
|
||||
end)
|
||||
|
||||
MCLPlayer:__cache_getter("inventory", function(self)
|
||||
return self.object:get_inventory()
|
||||
end)
|
||||
|
||||
MCLPlayer:__override_pipe("death_drop", function(self, inventory, listname, index, stack)
|
||||
if not mcl_gamerules.keepInventory then
|
||||
return self, inventory, listname, index, stack
|
||||
end
|
||||
end)
|
||||
|
||||
function MCLPlayer:on_damage(damage, source, knockback)
|
||||
MCLObject.on_damage(self, damage, source, knockback)
|
||||
end
|
|
@ -418,3 +418,31 @@ function mcl_util.get_color(colorstr)
|
|||
return colorstr, hex
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.registration_function(tbl, func)
|
||||
return function(name, def)
|
||||
if func then
|
||||
local res = func(name, def)
|
||||
if res == false then
|
||||
return
|
||||
elseif res ~= nil then
|
||||
def = res
|
||||
end
|
||||
end
|
||||
tbl[name] = def
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.rand(pr, ...)
|
||||
return pr and pr:next(...) or math.random(...)
|
||||
end
|
||||
|
||||
function mcl_util.rand_bool(probability, pr)
|
||||
if probability >= 1 then
|
||||
return true
|
||||
elseif probability <= 0 then
|
||||
return false
|
||||
else
|
||||
return mcl_util.rand(pr, 0, 32767) < probability * 32768
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ mcl_worlds = {}
|
|||
function mcl_worlds.is_in_void(pos)
|
||||
local void =
|
||||
not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or
|
||||
(pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or
|
||||
(pos.y < mcl_vars.mg_nether_max and pos.y > mcl_vars.mg_nether_min) or
|
||||
(pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min))
|
||||
|
||||
local void_deadly = false
|
||||
|
@ -15,11 +15,11 @@ function mcl_worlds.is_in_void(pos)
|
|||
-- Overworld → Void → End → Void → Nether → Void
|
||||
if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then
|
||||
void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance
|
||||
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then
|
||||
elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max then
|
||||
-- The void between End and Nether. Like usual, but here, the void
|
||||
-- *above* the Nether also has a small tolerance area, so player
|
||||
-- can fly above the Nether without getting hurt instantly.
|
||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance)
|
||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max + deadly_tolerance)
|
||||
elseif pos.y < mcl_vars.mg_nether_min then
|
||||
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
||||
end
|
||||
|
@ -35,7 +35,7 @@ end
|
|||
function mcl_worlds.y_to_layer(y)
|
||||
if y >= mcl_vars.mg_overworld_min then
|
||||
return y - mcl_vars.mg_overworld_min, "overworld"
|
||||
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then
|
||||
elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max then
|
||||
return y - mcl_vars.mg_nether_min, "nether"
|
||||
elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then
|
||||
return y - mcl_vars.mg_end_min, "end"
|
||||
|
@ -73,7 +73,7 @@ end
|
|||
-- Takes a position and returns true if this position can have Nether dust
|
||||
function mcl_worlds.has_dust(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
|
||||
return pos.y <= mcl_vars.mg_nether_max + 64 and pos.y >= mcl_vars.mg_nether_min - 64
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if compasses are working here
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
mcl_loottables.register_entry = mcl_util.registration_function(mcl_loottables.entries)
|
||||
mcl_loottables.register_table = mcl_util.registration_function(mcl_loottables.tables, function(name, def)
|
||||
local function set_parents(parent)
|
||||
for _, child in ipairs(parent.children or parent.entries or parent.pools or {}) do
|
||||
child.parent = parent
|
||||
set_parents(child)
|
||||
end
|
||||
end
|
||||
set_parents(def)
|
||||
end)
|
||||
|
||||
function mcl_loottables.get_entry_type(entry)
|
||||
return mcl_loottables.entries[entry.type]
|
||||
end
|
||||
|
||||
function mcl_loottables.get_candidates(entries, data, func)
|
||||
local candidates = {}
|
||||
for _, entry in ipairs(entries) do
|
||||
local success = mcl_predicates.do_predicates(entry.conditions, data)
|
||||
|
||||
if success then
|
||||
local children = entry.children
|
||||
|
||||
if children then
|
||||
table.insert_all(candidates, mcl_loottables.get_candidates(children, data, mcl_loottables.get_entry_type(entry).preprocess))
|
||||
else
|
||||
table.insert(candidates, entry)
|
||||
end
|
||||
end
|
||||
|
||||
if func and func(success, data) then
|
||||
break
|
||||
end
|
||||
end
|
||||
return candidates
|
||||
end
|
||||
|
||||
function mcl_loottables.do_item_modifiers(itemstack, node, data)
|
||||
if node then
|
||||
mcl_item_modifiers.do_item_modifiers(itemstack, node.functions, data)
|
||||
mcl_loottables.do_item_modifiers(itemstack, node.parent, data)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_loottables.do_pools(pools, functions, data)
|
||||
local luck = data.luck or 0
|
||||
local stacks = {}
|
||||
for _, pool in ipairs(pools or {}) do
|
||||
if mcl_predicates.do_predicates(pool.conditions, data) do
|
||||
local rolls = mcl_numbers.get_number(pool.rolls, data) + mcl_numbers.get_number(pool.bonus_rolls, data) * luck
|
||||
for i = 1, rolls do
|
||||
local candidates = mcl_loottables.get_candidates(pool.entries, data)
|
||||
|
||||
if #candidates > 0 then
|
||||
local total_weight = 0
|
||||
local weights = {}
|
||||
for _, candidate in ipairs(candidates)
|
||||
total_weight = total_weight + math.floor((candidate.weight or 1) + (candidate.quality or 0) * luck)
|
||||
table.insert(weights, total_weight)
|
||||
end
|
||||
|
||||
local selected
|
||||
local rnd = mcl_util.rand(data.pr, 0, weight - 1)
|
||||
for i, w in ipairs(weights) do
|
||||
if rnd < w then
|
||||
selected = candidates[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local pool_stacks = mcl_loottables.get_entry_type(entry).process(selected, data)
|
||||
|
||||
for _, stack in ipairs(pool_stacks) do
|
||||
mcl_item_modifiers.do_item_modifiers(stack, selected, data)
|
||||
end
|
||||
table.insert_all(stacks, pool_stacks)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return stacks
|
||||
end
|
||||
|
||||
function mcl_loottables.get_loot(def, data)
|
||||
if type(def) == "string" then
|
||||
def = mcl_loottables.tables[def]
|
||||
end
|
||||
return mcl_loottables.do_pools(def.pools)
|
||||
end
|
||||
|
||||
function mcl_loottables.drop_loot(def, data)
|
||||
local loot = mcl_loottables.get_loot(def, data)
|
||||
local old_loot = table.copy(loot)
|
||||
for _, stack in ipairs(old_loot) do
|
||||
local max_stack = stack:get_stack_max()
|
||||
while max_stack < stack:get_count() do
|
||||
table.insert(loot, stack:take_items(max_stack))
|
||||
end
|
||||
end
|
||||
return loot
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
mcl_loottables.register_entry("mcl_loottables:alternatives", {
|
||||
preprocess = function(success, data)
|
||||
return success
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:group", {
|
||||
preprocess = function(success, data)
|
||||
return false
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:sequence", {
|
||||
preprocess = function(success, data)
|
||||
return not success
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:tag", function(entry, data)
|
||||
local stacks = mcl_groupcache.get_items_in_group(entry.name)
|
||||
if entry.expand then
|
||||
stacks = {stacks[pr:next(1, #stacks)]}
|
||||
end
|
||||
return stacks
|
||||
end)
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:loot_table", {
|
||||
process = function(entry, data)
|
||||
return mcl_loottables.get_loot(entry.name, data)
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:empty", {
|
||||
process = function(entry, data)
|
||||
return {}
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:item", {
|
||||
process = function(entry, data)
|
||||
return {item = ItemStack(entry.name)}
|
||||
end,
|
||||
})
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
mcl_loottables = {
|
||||
tables = {},
|
||||
entries = {},
|
||||
}
|
||||
|
||||
local modpath = minetest.get_modpath("mcl_loottables")
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
dofile(modpath .. "/entries.lua")
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_loottables
|
||||
author = Fleckenstein
|
||||
description = Provides Minecraft-like loot table definitions
|
||||
depends = mcl_util, mcl_predicates, mcl_item_modifiers, mcl_groupcache
|
|
@ -0,0 +1,19 @@
|
|||
mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers)
|
||||
|
||||
function mcl_numbers.get_number(provider, data)
|
||||
if type(provider) == "number" then
|
||||
return provider
|
||||
else
|
||||
mcl_numbers.providers[data.type](provider, data)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_numbers.match_bounds(actual, expected, data)
|
||||
if type(expected) == "table" then
|
||||
expected = {
|
||||
min = mcl_numbers.get_number(expected.min, data),
|
||||
max = mcl_numbers.get_number(expected.max, data)
|
||||
}
|
||||
end
|
||||
return mcl_util.match_bounds(actual, expected)
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
mcl_numbers = {
|
||||
providers = {},
|
||||
}
|
||||
|
||||
dofile(minetest.get_modpath("mcl_numbers") .. "/api.lua")
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:constant", function(provider)
|
||||
return provider.value
|
||||
end)
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:uniform", function(provider, data)
|
||||
return mcl_util.rand(data.pr, mcl_numbers.get_number(provider.min, data), mcl_numbers.get_number(provider.max, data))
|
||||
end)
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:binomial", function(provider, data)
|
||||
local n = mcl_numbers.get_number(provider.n, data)
|
||||
local num = 0
|
||||
for i = 1, n do
|
||||
if mcl_util.rand_bool(mcl_numbers.get_number(provider.p, data), data.pr) then
|
||||
num = num + 1
|
||||
end
|
||||
end
|
||||
return num
|
||||
end)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_numbers
|
||||
author = Fleckenstein
|
||||
description = Minecraft-like number providers
|
||||
depends = mcl_util
|
|
@ -0,0 +1,15 @@
|
|||
mcl_predicates.register_predicate = mcl_util.registration_function(mcl_predicates.predicates)
|
||||
|
||||
function mcl_predicates.do_predicates(predicates, data, or_mode)
|
||||
or_mode = or_mode or false
|
||||
for _, func in ipairs(predicates) do
|
||||
if type(func) == "string" then
|
||||
func = mcl_predicates.predicates[func]
|
||||
end
|
||||
local failure = func and not func(def, data) or false
|
||||
if or_mode ~= failure then
|
||||
return or_mode
|
||||
end
|
||||
end
|
||||
return not or_mode or #predicates == 0
|
||||
end
|
|
@ -0,0 +1,104 @@
|
|||
mcl_predicates = {
|
||||
predicates = {},
|
||||
}
|
||||
|
||||
local modpath = minetest.get_modpath("mcl_predicates")
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
|
||||
mcl_predicates.register_predicate("alternative", function(predicate, data)
|
||||
return mcl_predicates.do_predicates(predicate.terms, data, true)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("match_node", function(predicate, data)
|
||||
return mcl_types.match_node(data.node or minetest.get_node(data.pos), predicate, data.pos, data.nodemeta)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("damage_source_properties", function(predicate, data)
|
||||
-- ToDo: damage source abstraction
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("entity_properties", function(predicate, data)
|
||||
local entity = predicate.entity
|
||||
if not entity or (entity ~= "this" and entity ~= "killer" and entity ~= "killer_player") then
|
||||
return false
|
||||
end
|
||||
|
||||
local ref = data[entity]
|
||||
if not ref then
|
||||
return false
|
||||
end
|
||||
|
||||
-- ToDo: entity / player abstraction
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("entity_scores", function(predicate, data)
|
||||
-- ToDo: scoreboards
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("inverted", function(predicate, data)
|
||||
return not mcl_predicates.do_predicates({predicate.term}, data)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("killed_by_player", function(predicate, data)
|
||||
return not predicate.inverse ~= not data.killer_player
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("location_check", function(predicate, data)
|
||||
local pos = vector.add(data.pos, vector.new(predicate.offset_x or 0, predicate.offset_y or 0, predicate.offset_z or 0))
|
||||
return mcl_location(pos, data.nodemeta):match(predicate.predicate)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("match_tool", function(predicate, data)
|
||||
return mcl_predicates.match_tool(data.tool, predicate.predicate)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("random_chance", function(predicate, data)
|
||||
return mcl_util.rand_bool(predicate.chance, data.pr)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("random_chance_with_looting", function(predicate, data)
|
||||
local chance = predicate.chance -- + (looting_level * looting_multiplier)
|
||||
|
||||
-- ToDo: entity / player abstraction
|
||||
return mcl_util.rand_bool(chance, data.pr)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("reference", function(predicate, data)
|
||||
-- ToDo: needs research
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("survives_explosion", function(predicate, data)
|
||||
return mcl_util.rand_bool(data.drop_chance or 1, data.pr)
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("table_bonus", function(predicate, data)
|
||||
-- ToDo: entity / player abstraction
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("time_check", function(predicate, data)
|
||||
-- ToDo: needs research
|
||||
return nil
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("weather_check", function(predicate, data)
|
||||
local weather = mcl_weather.get_weather()
|
||||
|
||||
if predicate.thundering then
|
||||
return weather == "thunder"
|
||||
elseif predicate.raining then
|
||||
return weather == "rain"
|
||||
else
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
mcl_predicates.register_predicate("value_check", function(predicate, data)
|
||||
local value = mcl_numbers.get_number(predicate.value, data)
|
||||
return mcl_numbers.check_in_bounds(value, predicate.range, data)
|
||||
end)
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_predicates
|
||||
author = Fleckenstein
|
||||
description = Provides MC-like predicates
|
||||
depends = mcl_util, mcl_numbers
|
|
@ -0,0 +1,88 @@
|
|||
mcl_types = {}
|
||||
|
||||
function mcl_types.match_bounds(actual, expected)
|
||||
if type(expected) == "table" then
|
||||
return actual <= expected.max and actual >= expected.min
|
||||
else
|
||||
return actual == expected
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_types.match_meta(actual, expected)
|
||||
for k, v in pairs(expected) do
|
||||
if actual:get_string(k) ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_types.match_vector(actual, expected)
|
||||
for k, v in pairs(expected) do
|
||||
if not mcl_types.match_bounds(actual[k], expected[k]) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_types.match_enchantments(actual, expected)
|
||||
for _, v in ipairs(expected) do
|
||||
if not mcl_types.match_bounds(actual[v.enchantment] or 0, v.levels or {min = 1, max = math.huge}) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_types.match_item(actual, expected)
|
||||
actual = actual or ItemStack()
|
||||
|
||||
if expected.item and actual:get_name() ~= expected.item then
|
||||
return false
|
||||
elseif expected.group and minetest.get_item_group(actual:get_name(), expected.group) == 0 then
|
||||
return false
|
||||
elseif expected.count and not mcl_types.match_bounds(actual:get_count(), expected.count) then
|
||||
return false
|
||||
elseif expected.wear and not mcl_types.match_bounds(actual:get_wear(), expected.wear) then
|
||||
return false
|
||||
elseif expected.enchantments and not mcl_types.match_enchantments(mcl_enchanting.get_enchantments(actual), expected.enchantments) then
|
||||
return false
|
||||
elseif expected.meta and not mcl_types.match_meta(actual:get_meta(), expected.meta) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_types.match_node(actual, expected, pos, meta)
|
||||
if expected.node and actual.name ~= expected.node then
|
||||
return false
|
||||
elseif expected.group and minetest.get_item_group(actual.name, expected.group) == 0 then
|
||||
return false
|
||||
elseif expected.param1 and actual.param1 ~= compare.param1 then
|
||||
return false
|
||||
elseif expected.param2 and actual.param2 ~= compare.param2 then
|
||||
return false
|
||||
elseif expected.meta and not mcl_types.match_meta(meta or minetest.get_meta(pos), expected.meta) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_types.match_pos(actual, expected, meta)
|
||||
if expected.pos and not mcl_types.match_vector(actual, expected.pos) then
|
||||
return false
|
||||
elseif expected.dimension and mcl_worlds.pos_to_dimension(actual) ~= expected.dimension then
|
||||
return false
|
||||
elseif expected.biome and minetest.get_biome_name(minetest.get_biome_data(actual).biome) ~= expected.biome then
|
||||
return false
|
||||
elseif expected.node and not mcl_types.match_node(minetest.get_node(actual), expected.node, actual, meta) then
|
||||
return false
|
||||
elseif expected.light and not mcl_types.match_bounds(minetest.get_node_light(actual), expected.light) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_types
|
||||
author = Fleckenstein
|
||||
description = Offers compare functions for many types, used for MineClone2 datapacks
|
||||
depends =
|
|
@ -0,0 +1,2 @@
|
|||
name = DATA
|
||||
description = Meta-modpack containing the datapack system for MineClone 2
|
|
@ -165,6 +165,66 @@ minetest.register_globalstep(function(dtime)
|
|||
end
|
||||
end)
|
||||
|
||||
local minigroups = { "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" }
|
||||
local basegroups = { "pickaxey", "axey", "shovely" }
|
||||
local materials = { "wood", "gold", "stone", "iron", "diamond" }
|
||||
|
||||
-- Checks if the given node would drop its useful drop if dug by a tool
|
||||
-- with the given tool capabilities. Returns true if it will yield its useful
|
||||
-- drop, false otherwise.
|
||||
local check_can_drop = function(node_name, tool_capabilities)
|
||||
local handy = minetest.get_item_group(node_name, "handy")
|
||||
local dig_immediate = minetest.get_item_group(node_name, "dig_immediate")
|
||||
if handy == 1 or dig_immediate == 2 or dig_immediate == 3 then
|
||||
return true
|
||||
else
|
||||
local toolgroupcaps
|
||||
if tool_capabilities then
|
||||
toolgroupcaps = tool_capabilities.groupcaps
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
-- Compare node groups with tool capabilities
|
||||
for m=1, #minigroups do
|
||||
local minigroup = minigroups[m]
|
||||
local g = minetest.get_item_group(node_name, minigroup)
|
||||
if g ~= 0 then
|
||||
local plus = minigroup .. "_dig"
|
||||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for b=1, #basegroups do
|
||||
local basegroup = basegroups[b]
|
||||
local g = minetest.get_item_group(node_name, basegroup)
|
||||
if g ~= 0 then
|
||||
for m=g, #materials do
|
||||
local plus = basegroup .. "_dig_"..materials[m]
|
||||
if toolgroupcaps[plus] then
|
||||
return true
|
||||
end
|
||||
for e=1,5 do
|
||||
local effplus = plus .. "_efficiency_" .. e
|
||||
if toolgroupcaps[effplus] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Stupid workaround to get drops from a drop table:
|
||||
-- Create a temporary table in minetest.registered_nodes that contains the proper drops,
|
||||
-- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition
|
||||
|
@ -221,20 +281,17 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
|
||||
-- Check if node will yield its useful drop by the digger's tool
|
||||
local dug_node = minetest.get_node(pos)
|
||||
local tooldef
|
||||
local toolcaps
|
||||
local tool
|
||||
if digger ~= nil then
|
||||
tool = digger:get_wielded_item()
|
||||
tooldef = minetest.registered_tools[tool:get_name()]
|
||||
toolcaps = tool:get_tool_capabilities()
|
||||
|
||||
if not mcl_autogroup.can_harvest(dug_node.name, tool:get_name()) then
|
||||
if not check_can_drop(dug_node.name, toolcaps) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local diggroups = tooldef and tooldef._mcl_diggroups
|
||||
local shearsy_level = diggroups and diggroups.shearsy and diggroups.shearsy.level
|
||||
|
||||
--[[ Special node drops when dug by shears by reading _mcl_shears_drop or with a silk touch tool reading _mcl_silk_touch_drop
|
||||
from the node definition.
|
||||
Definition of _mcl_shears_drop / _mcl_silk_touch_drop:
|
||||
|
@ -246,7 +303,7 @@ function minetest.handle_node_drops(pos, drops, digger)
|
|||
|
||||
local silk_touch_drop = false
|
||||
local nodedef = minetest.registered_nodes[dug_node.name]
|
||||
if shearsy_level and shearsy_level > 0 and nodedef._mcl_shears_drop then
|
||||
if toolcaps ~= nil and toolcaps.groupcaps and toolcaps.groupcaps.shearsy_dig and nodedef._mcl_shears_drop then
|
||||
if nodedef._mcl_shears_drop == true then
|
||||
drops = { dug_node.name }
|
||||
else
|
||||
|
|
|
@ -2826,7 +2826,7 @@ local falling = function(self, pos)
|
|||
end
|
||||
|
||||
if mcl_portals ~= nil then
|
||||
if mcl_portals.nether_portal_cooloff(self.object) then
|
||||
if mcl_portals.nether_portal_cooloff[self.object] then
|
||||
return false -- mob has teleported through Nether portal - it's 99% not falling
|
||||
end
|
||||
end
|
||||
|
@ -2856,18 +2856,6 @@ local falling = function(self, pos)
|
|||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
end
|
||||
|
||||
if minetest.registered_nodes[node_ok(pos).name].groups.lava then
|
||||
|
||||
if self.floats_on_lava == 1 then
|
||||
|
||||
self.object:set_acceleration({
|
||||
x = 0,
|
||||
y = -self.fall_speed / (max(1, v.y) ^ 2),
|
||||
z = 0
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- in water then float up
|
||||
if minetest.registered_nodes[node_ok(pos).name].groups.water then
|
||||
|
||||
|
@ -3785,7 +3773,6 @@ minetest.register_entity(name, {
|
|||
knock_back = def.knock_back ~= false,
|
||||
shoot_offset = def.shoot_offset or 0,
|
||||
floats = def.floats or 1, -- floats in water by default
|
||||
floats_on_lava = def.floats_on_lava or 0,
|
||||
replace_rate = def.replace_rate,
|
||||
replace_what = def.replace_what,
|
||||
replace_with = def.replace_with,
|
||||
|
|
|
@ -450,7 +450,7 @@ mobs:spawn_specific("mobs_mc:donkey", mobs_mc.spawn.grassland_savanna, {"air"},
|
|||
|
||||
-- spawn eggs
|
||||
mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
|
||||
mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
|
||||
--mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
|
||||
--mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
|
||||
mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
|
||||
mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB |
|
@ -960,7 +960,7 @@ mobs:register_mob("mobs_mc:villager", {
|
|||
"mobs_mc_villager_smith.png", --hat
|
||||
},
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
walk_velocity = 1.2,
|
||||
run_velocity = 2.4,
|
||||
|
|
|
@ -28,7 +28,7 @@ mobs:register_mob("mobs_mc:evoker", {
|
|||
"blank.png", --no hat
|
||||
-- TODO: Attack glow
|
||||
} },
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
damage = 6,
|
||||
walk_velocity = 0.2,
|
||||
|
|
|
@ -36,7 +36,7 @@ mobs:register_mob("mobs_mc:illusioner", {
|
|||
-- TODO: more sounds
|
||||
distance = 16,
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
walk_velocity = 0.6,
|
||||
run_velocity = 2,
|
||||
jump = true,
|
||||
|
|
|
@ -30,7 +30,7 @@ mobs:register_mob("mobs_mc:vindicator", {
|
|||
-- TODO: Glow when attacking (mobs_mc_vindicator.png)
|
||||
},
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
damage = 13,
|
||||
reach = 2,
|
||||
|
|
|
@ -45,7 +45,7 @@ mobs:register_mob("mobs_mc:villager_zombie", {
|
|||
{"mobs_mc_zombie_smith.png"},
|
||||
{"mobs_mc_zombie_villager.png"}
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
damage = 3,
|
||||
reach = 2,
|
||||
|
|
|
@ -25,7 +25,7 @@ mobs:register_mob("mobs_mc:witch", {
|
|||
textures = {
|
||||
{"mobs_mc_witch.png"},
|
||||
},
|
||||
visual_size = {x=2.75, y=2.75},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
damage = 2,
|
||||
reach = 2,
|
||||
|
|
|
@ -38,7 +38,6 @@ mcl_weather.reg_weathers["none"] = {
|
|||
local storage = minetest.get_mod_storage()
|
||||
-- Save weather into mod storage, so it can be loaded after restarting the server
|
||||
local save_weather = function()
|
||||
if not mcl_weather.end_time then return end
|
||||
storage:set_string("mcl_weather_state", mcl_weather.state)
|
||||
storage:set_int("mcl_weather_end_time", mcl_weather.end_time)
|
||||
minetest.log("verbose", "[mcl_weather] Weather data saved: state="..mcl_weather.state.." end_time="..mcl_weather.end_time)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
mesecons
|
||||
mcl_sounds
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1,3 +1,2 @@
|
|||
name = mcl_comparators
|
||||
depends = mcl_wip, mesecons, mcl_sounds
|
||||
optional_depends = doc, screwdriver
|
||||
depends = mcl_wip
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
mcl_init
|
||||
mcl_formspec
|
||||
mesecons
|
||||
mcl_sounds
|
||||
mcl_tnt
|
||||
mcl_worlds
|
||||
mcl_core
|
||||
mcl_nether
|
||||
mcl_armor_stand
|
||||
mcl_armor
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_dispensers
|
||||
depends = mcl_init, mcl_formspec, mesecons, mcl_sounds, mcl_tnt, mcl_worlds, mcl_core, mcl_nether, mcl_armor_stand, mcl_armor
|
||||
optional_depends = doc, screwdriver
|
|
@ -0,0 +1,6 @@
|
|||
mcl_init
|
||||
mcl_formspec
|
||||
mesecons
|
||||
mcl_util
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_droppers
|
||||
depends = mcl_init, mcl_formspec, mesecons, mcl_util
|
||||
optional_depends = doc, screwdriver
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
mcl_util
|
|
@ -1,2 +0,0 @@
|
|||
name = mcl_observers
|
||||
depends = mesecons, mcl_util
|
|
@ -0,0 +1,3 @@
|
|||
mcl_sounds
|
||||
mcl_core
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons
|
||||
depends = mcl_sounds, mcl_core
|
||||
optional_depends = doc
|
|
@ -0,0 +1 @@
|
|||
mesecons
|
|
@ -1,2 +0,0 @@
|
|||
name = mesecons_alias
|
||||
depends = mesecons
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_button
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -0,0 +1,3 @@
|
|||
mesecons
|
||||
doc?
|
||||
doc_items?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_commandblock
|
||||
depends = mesecons
|
||||
optional_depends = doc, doc_items
|
|
@ -0,0 +1,3 @@
|
|||
mesecons
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_delayer
|
||||
depends = mesecons
|
||||
optional_depends = doc, screwdriver
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_lightstone
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -0,0 +1 @@
|
|||
mesecons
|
|
@ -1,2 +0,0 @@
|
|||
name = mesecons_mvps
|
||||
depends = mesecons
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
mcl_particles
|
|
@ -1,2 +0,0 @@
|
|||
name = mesecons_noteblock
|
||||
depends = mesecons, mcl_particles
|
|
@ -0,0 +1,5 @@
|
|||
mesecons
|
||||
mesecons_mvps
|
||||
mcl_mobitems
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_pistons
|
||||
depends = mesecons, mesecons_mvps, mcl_mobitems
|
||||
optional_depends = doc, screwdriver
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_pressureplates
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_solarpanel
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -0,0 +1,3 @@
|
|||
mesecons
|
||||
mcl_torches
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_torch
|
||||
depends = mesecons, mcl_torches
|
||||
optional_depends = doc
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_walllever
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -0,0 +1,2 @@
|
|||
mesecons
|
||||
doc?
|
|
@ -1,3 +0,0 @@
|
|||
name = mesecons_wires
|
||||
depends = mesecons
|
||||
optional_depends = doc
|
|
@ -9,7 +9,6 @@ local modpath = minetest.get_modpath(minetest.get_current_modname())
|
|||
armor = {
|
||||
timer = 0,
|
||||
elements = {"head", "torso", "legs", "feet"},
|
||||
physics = {"jump","speed","gravity"},
|
||||
formspec = "size[8,8.5]image[2,0.75;2,4;armor_preview]"
|
||||
.."list[current_player;main;0,4.5;8,4;]"
|
||||
.."list[current_player;craft;4,1;3,3;]"
|
||||
|
@ -18,7 +17,6 @@ armor = {
|
|||
.."listring[current_player;craft]",
|
||||
textures = {},
|
||||
default_skin = "character",
|
||||
last_damage_types = {},
|
||||
}
|
||||
|
||||
if minetest.get_modpath("mcl_skins") then
|
||||
|
@ -33,7 +31,7 @@ elseif minetest.get_modpath("wardrobe") then
|
|||
skin_mod = "wardrobe"
|
||||
end
|
||||
|
||||
function armor.on_armor_use(itemstack, user, pointed_thing)
|
||||
function mcl_armor.rightclick_equip(itemstack, user, pointed_thing)
|
||||
if not user or user:is_player() == false then
|
||||
return itemstack
|
||||
end
|
||||
|
@ -149,8 +147,8 @@ armor.set_player_armor = function(self, player)
|
|||
if level then
|
||||
local texture = def.texture or item:gsub("%:", "_")
|
||||
local enchanted_addition = (mcl_enchanting.is_enchanted(item) and mcl_enchanting.overlay or "")
|
||||
table.insert(textures, "("..texture..".png"..enchanted_addition..")")
|
||||
preview = "(player.png^[opacity:0^"..texture.."_preview.png"..enchanted_addition..")"..(preview and "^"..preview or "")
|
||||
table.insert(textures, texture..".png"..enchanted_addition)
|
||||
preview = "player.png^[opacity:0^"..texture.."_preview.png"..enchanted_addition..""..(preview and "^"..preview or "")
|
||||
armor_level = armor_level + level
|
||||
items = items + 1
|
||||
mcl_armor_points = mcl_armor_points + (def.groups["mcl_armor_points"] or 0)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
local old_damage_modifier = MCLObject.damage_modifier
|
||||
|
||||
function MCLObject:damage_modifier(damage, source)
|
||||
local damage_old = old_damage_modifier(damage, source)
|
||||
if damage_old then
|
||||
return damage_old
|
||||
end
|
||||
|
||||
if damage < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if source.bypasses_armor and source.bypasses_magic then
|
||||
return
|
||||
end
|
||||
|
||||
local uses = math.max(1, math.floor(math.abs(damage) / 4))
|
||||
|
||||
local source_object = source:source_object()
|
||||
local equipment = self:equipment()
|
||||
|
||||
local points = self:base_armor_points()
|
||||
local toughness = 0
|
||||
local protection_factor = 0
|
||||
local thorns_damage_regular = 0
|
||||
local thorns_damage_irregular = 0
|
||||
local thorns_pieces = {}
|
||||
|
||||
for location, rawstack in pairs(equipment:get_armor()) do
|
||||
local stack = MCLItemStack(rawstack)
|
||||
|
||||
if not source.bypasses_armor then
|
||||
points = points + stack:group("armor_points")
|
||||
toughness = toughness + stack:group("armor_toughness")
|
||||
|
||||
stack:use_durability(uses)
|
||||
equipment[location](equipment, rawstack)
|
||||
end
|
||||
|
||||
if not source.bypasses_magic then
|
||||
protection_factor = protection_factor + 1 * stack:get_enchantment("protection")
|
||||
|
||||
if source.is_explosion then
|
||||
protection_factor = protection_factor + 2 * stack:get_enchantment("blast_protection")
|
||||
end
|
||||
|
||||
if source.is_fire then
|
||||
protection_factor = protection_factor + 2 * stack:get_enchantment("fire_protection")
|
||||
end
|
||||
|
||||
if source.is_projectile then
|
||||
protection_factor = protection_factor + 2 * stack:get_enchantment("projectile_protection")
|
||||
end
|
||||
|
||||
if source.is_fall then
|
||||
protection_factor = protection_factor + 3 * stack:get_enchantment("feather_falling")
|
||||
end
|
||||
end
|
||||
|
||||
if source_object then
|
||||
local thorns_level = stack:get_enchantment("thorns")
|
||||
|
||||
if thorns_level > 0 then
|
||||
local do_irregular_damage = thorns_level > 10
|
||||
|
||||
if do_irregular_damage or thorns_damage_regular < 4 and math.random() < thorns_level * 0.15 then
|
||||
if do_irregular_damage then
|
||||
thorns_damage_irregular = thorns_damage_irregular + thorns_level - 10
|
||||
else
|
||||
thorns_damage_regular = math.min(4, thorns_damage_regular + math.random(4))
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(thorns_pieces, {location = location, stack = stack})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- https://minecraft.gamepedia.com/Armor#Damage_protection
|
||||
damage = damage * (1 - math.min(20, math.max((points / 5), points - damage / (2 + (toughness / 4)))) / 25)
|
||||
|
||||
-- https://minecraft.gamepedia.com/Armor#Enchantments
|
||||
damage = damage * (1 - math.min(20, protection_factor) / 25)
|
||||
|
||||
local thorns_damage = thorns_damage_regular + thorns_damage_irregular
|
||||
|
||||
if thorns_damage > 0 and source_object ~= self then
|
||||
local thorns_damage_source = MCLDamageSource({direct_object = self, source_object = source_object, is_thorns = true})
|
||||
local thorns_knockback = {hitter = self}
|
||||
|
||||
source_object:damage(thorns_damage, thorns_damage_source, thorns_knockback)
|
||||
|
||||
local piece = thorns_pieces[math.random(#thorns_pieces)]
|
||||
local mclstack = piece.stack
|
||||
mclstack:use_durability(2)
|
||||
equipment[piece.location](equipment, mclstack.stack)
|
||||
end
|
||||
|
||||
return math.floor(damage + 0.5)
|
||||
end
|
||||
|
||||
function MCLObject:base_armor_points()
|
||||
return 0
|
||||
end
|
|
@ -0,0 +1,160 @@
|
|||
local S = minetest.get_translator("mcl_armor")
|
||||
|
||||
mcl_enchanting.enchantments.protection = {
|
||||
name = S("Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_points = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {blast_protection = true, fire_protection = true, projectile_protection = true},
|
||||
weight = 10,
|
||||
description = S("Reduces most types of damage by 4% for each level."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 12}, {12, 23}, {23, 34}, {34, 45}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.blast_protection = {
|
||||
name = S("Blast Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_points = true},
|
||||
secondary = {},
|
||||
disallow = {},
|
||||
incompatible = {fire_protection = true, protection = true, projectile_protection = true},
|
||||
weight = 2,
|
||||
description = S("Reduces explosion damage and knockback."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{5, 13}, {13, 21}, {21, 29}, {29, 37}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.fire_protection = {
|
||||
name = S("Fire Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_points = true},
|
||||
secondary = {},
|
||||
disallow = {},
|
||||
incompatible = {blast_protection = true, protection = true, projectile_protection = true},
|
||||
weight = 5,
|
||||
description = S("Reduces fire damage."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{10, 18}, {18, 26}, {26, 34}, {34, 42}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.projectile_protection = {
|
||||
name = S("Projectile Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_points = true},
|
||||
secondary = {},
|
||||
disallow = {},
|
||||
incompatible = {blast_protection = true, fire_protection = true, protection = true},
|
||||
weight = 5,
|
||||
description = S("Reduces projectile damage."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 16}, {11, 26}, {21, 36}, {31, 46}, {41, 56}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.feather_falling = {
|
||||
name = S("Feather Falling"),
|
||||
max_level = 4,
|
||||
primary = {armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {},
|
||||
weight = 5,
|
||||
description = S("Reduces fall damage."),curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.thorns = {
|
||||
name = S("Thorns"),
|
||||
max_level = 3,
|
||||
primary = {armor_points = true},
|
||||
secondary = {},
|
||||
disallow = {},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Reflects some of the damage taken when hit, at the cost of reducing durability with each proc."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{10, 61}, {30, 71}, {50, 81}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.curse_of_binding = {
|
||||
name = S("Curse of Binding"),
|
||||
max_level = 1,
|
||||
primary = {},
|
||||
secondary = {armor = true},
|
||||
disallow = {},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Item cannot be removed from armor slots except due to death, breaking or in Creative Mode."),
|
||||
curse = true,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = true,
|
||||
power_range_table = {{25, 50}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.frost_walker = {
|
||||
name = S("Frost Walker"),
|
||||
max_level = 2,
|
||||
primary = {},
|
||||
secondary = {boots = true},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {depth_strider = true},
|
||||
weight = 2,
|
||||
description = S("Turns water beneath the player into frosted ice and prevents the damage from magma blocks."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = true,
|
||||
power_range_table = {{10, 25}, {20, 35}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
walkover.register_global(function(pos, _, player)
|
||||
local boots = MCLItemStack(mcl_object_mgr.get(player):equipment():boots())
|
||||
if not boots:has_enchantment("frost_walker") then
|
||||
return
|
||||
end
|
||||
local radius = boots:get_enchantment("frost_walker") + 2
|
||||
local minp = {x = pos.x - radius, y = pos.y, z = pos.z - radius}
|
||||
local maxp = {x = pos.x + radius, y = pos.y, z = pos.z + radius}
|
||||
local positions = minetest.find_nodes_in_area_under_air(minp, maxp, "mcl_core:water_source")
|
||||
for _, p in ipairs(positions) do
|
||||
if vector.distance(pos, p) <= radius then
|
||||
minetest.set_node(p, {name = "mcl_core:frosted_ice_0"})
|
||||
end
|
||||
end
|
||||
end)
|
|
@ -1,13 +1,68 @@
|
|||
local S = minetest.get_translator("mcl_armor")
|
||||
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/armor.lua")
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/alias.lua")
|
||||
mcl_armor = {
|
||||
elements = {
|
||||
{
|
||||
name = "helmet",
|
||||
description = S("Helmet"),
|
||||
durability = 0.6875,
|
||||
recipe = function(m)
|
||||
return {
|
||||
{ m, m, m},
|
||||
{ m, "", m},
|
||||
{"", "", ""},
|
||||
}
|
||||
end,
|
||||
},
|
||||
{
|
||||
name = "chestplate",
|
||||
description = S("Chestplate"),
|
||||
durability = 1.0,
|
||||
recipe = function(m)
|
||||
return {
|
||||
{ m, "", m},
|
||||
{ m, m, m},
|
||||
{ m, m, m},
|
||||
}
|
||||
end,
|
||||
},
|
||||
{
|
||||
name = "leggings",
|
||||
description = S("Leggings"),
|
||||
durability = 0.9375,
|
||||
recipe = function(m)
|
||||
return {
|
||||
{ m, m, m},
|
||||
{ m, "", m},
|
||||
{ m, "", m},
|
||||
}
|
||||
end,
|
||||
},
|
||||
{
|
||||
name = "boots",
|
||||
description = S("Boots"),
|
||||
durability = 0.8125,
|
||||
recipe = function(m)
|
||||
return {
|
||||
{ m, "", m},
|
||||
{ m, "", m},
|
||||
}
|
||||
end,
|
||||
},
|
||||
},
|
||||
longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive."),
|
||||
usagehelp = S("To equip it, put it on the corresponding armor slot in your inventory menu."),
|
||||
}
|
||||
|
||||
local modpath = minetest.get_modpath("mcl_armor")
|
||||
|
||||
dofile(modpath .. "/damage.lua")
|
||||
dofile(modpath .. "/alias.lua")
|
||||
dofile(modpath .. "/items.lua")
|
||||
dofile(modpath .. "/enchantments.lua")
|
||||
|
||||
-- Regisiter Head Armor
|
||||
|
||||
local longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive.")
|
||||
local usage = S("To equip it, put it on the corresponding armor slot in your inventory menu.")
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_leather", {
|
||||
description = S("Leather Cap"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
|
@ -323,70 +378,3 @@ local craft_ingreds = {
|
|||
diamond = { "mcl_core:diamond" },
|
||||
chain = { nil, "mcl_core:iron_nugget"} ,
|
||||
}
|
||||
|
||||
for k, v in pairs(craft_ingreds) do
|
||||
-- material
|
||||
local m = v[1]
|
||||
-- cooking result
|
||||
local c = v[2]
|
||||
if m ~= nil then
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:helmet_"..k,
|
||||
recipe = {
|
||||
{m, m, m},
|
||||
{m, "", m},
|
||||
{"", "", ""},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:chestplate_"..k,
|
||||
recipe = {
|
||||
{m, "", m},
|
||||
{m, m, m},
|
||||
{m, m, m},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:leggings_"..k,
|
||||
recipe = {
|
||||
{m, m, m},
|
||||
{m, "", m},
|
||||
{m, "", m},
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:boots_"..k,
|
||||
recipe = {
|
||||
{m, "", m},
|
||||
{m, "", m},
|
||||
},
|
||||
})
|
||||
end
|
||||
if c ~= nil then
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:helmet_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:chestplate_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:leggings_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:boots_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
local S = minetest.get_translator("mcl_armor")
|
||||
|
||||
function mcl_armor.register_set(def)
|
||||
local modname = minetest.get_current_modname()
|
||||
local sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_" .. def.material,
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_" .. def.material,
|
||||
}
|
||||
|
||||
for _, elem in pairs(mcl_armor.elements) do
|
||||
local item_name = elem.name .. "_" .. def.name
|
||||
local full_name = modname .. ":" .. item_name
|
||||
|
||||
minetest.register_tool(full_name, {
|
||||
description = def.custom_descriptions[elem.name] or def.description .. " " .. elem.description,
|
||||
_doc_items_longdesc = mcl_armor.longdesc,
|
||||
_doc_items_usagehelp = mcl_armor.usagehelp,
|
||||
inventory_image = modname .. "_inv_" .. item_name .. ".png",
|
||||
groups = {[elem.name] = 1, armor_points = 1, armor = 1, enchantability = def.enchantability}, -- ToDo: armor_points
|
||||
sounds = sounds,
|
||||
on_place = mcl_armor.rightclick_equip,
|
||||
on_secondary_use = mcl_armor.rightclick_equip,
|
||||
_durability = def.durability * elem.durability,
|
||||
_repair_material = def.craft_item,
|
||||
})
|
||||
|
||||
if def.craft_material then
|
||||
minetest.register_craft({
|
||||
output = full_name,
|
||||
recipe = elem.recipe(def.craft_material),
|
||||
})
|
||||
end
|
||||
|
||||
if def.cook_material then
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = def.cook_material,
|
||||
recipe = full_name,
|
||||
cooktime = 10,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcl_armor.register_set {
|
||||
name = "iron",
|
||||
description = S("Iron"),
|
||||
durability = 240,
|
||||
enchantability =
|
||||
craft_material = "mcl_core:iron_ingot",
|
||||
cook_material = "mcl_core:iron_nugget",
|
||||
}
|
|
@ -16,17 +16,23 @@ local dir_to_pitch = function(dir)
|
|||
end
|
||||
|
||||
local random_arrow_positions = function(positions, placement)
|
||||
local min = 0
|
||||
local max = 0
|
||||
if positions == 'x' then
|
||||
return math.random(-4, 4)
|
||||
min = -4
|
||||
max = 4
|
||||
elseif positions == 'y' then
|
||||
return math.random(0, 10)
|
||||
min = 0
|
||||
max = 10
|
||||
end
|
||||
if placement == 'front' and positions == 'z' then
|
||||
return 3
|
||||
min = 3
|
||||
max = 3
|
||||
elseif placement == 'back' and positions == 'z' then
|
||||
return -3
|
||||
min = -3
|
||||
max = -3
|
||||
end
|
||||
return 0
|
||||
return math.random(max, min)
|
||||
end
|
||||
|
||||
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
|
||||
|
@ -298,8 +304,8 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
else
|
||||
self._attach_parent = 'Body'
|
||||
end
|
||||
self._z_rotation = math.random(-30, 30)
|
||||
self._y_rotation = math.random( -30, 30)
|
||||
self._z_rotation = math.random(30, -30)
|
||||
self._y_rotation = math.random(30, -30)
|
||||
self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions('z', placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation})
|
||||
minetest.after(150, function()
|
||||
self.object:remove()
|
||||
|
@ -331,8 +337,8 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||
end
|
||||
end
|
||||
mcl_burning.extinguish(self.object)
|
||||
if not obj:is_player() then
|
||||
mcl_burning.extinguish(self.object)
|
||||
self.object:remove()
|
||||
end
|
||||
return
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
mcl_core
|
||||
mclx_core?
|
||||
mcl_sounds
|
||||
doc?
|
|
@ -1,3 +1 @@
|
|||
name = mcl_cauldrons
|
||||
depends = mcl_core, mcl_sounds
|
||||
optional_depends = mclx_core, doc
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
mcl_init
|
||||
mcl_formspec
|
||||
mcl_core
|
||||
mcl_sounds
|
||||
mcl_end
|
||||
mesecons
|
||||
doc?
|
||||
screwdriver?
|
|
@ -1050,6 +1050,12 @@ minetest.register_on_joinplayer(function(player)
|
|||
inv:set_size("enderchest", 9*3)
|
||||
end)
|
||||
|
||||
function MCLPlayer:__override_pipe("death_drop", function(self, inventory, listname, index, stack)
|
||||
if listname ~= "enderchest" then
|
||||
return self, inventory, listname, index, stack
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_craft({
|
||||
output = 'mcl_chests:ender_chest',
|
||||
recipe = {
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_chests
|
||||
depends = mcl_init, mcl_formspec, mcl_core, mcl_sounds, mcl_end, mesecons
|
||||
optional_depends = doc, screwdriver
|
|
@ -0,0 +1,4 @@
|
|||
mcl_init
|
||||
mcl_worlds
|
||||
mesecons
|
||||
doc?
|
|
@ -0,0 +1 @@
|
|||
A fantasy clock item roughly shows the time of day.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue