Compare commits
237 Commits
new_mapgen
...
master
Author | SHA1 | Date |
---|---|---|
cora | e322a9e23a | |
MysticTempest | dd1a58b01e | |
cora | 87c9969801 | |
PrairieAstronomer | fec5650711 | |
PrairieAstronomer | 5abfa555eb | |
PrairieAstronomer | dead4069b0 | |
PrairieAstronomer | 4bc67a174b | |
PrairieAstronomer | c71b036e6a | |
PrairieAstronomer | 046698c64f | |
cora | e80eebd989 | |
cora | 31b8ea26a2 | |
cora | fd6f2be485 | |
cora | 07e0a90051 | |
cora | f073d4d420 | |
cora | 89aaf6b709 | |
cora | f09b578034 | |
cora | 0ce1a92282 | |
cora | 135ee97b21 | |
cora | 51cf92a909 | |
cora | 2d47ad3e5f | |
cora | c28d700caf | |
cora | ba861d7b74 | |
cora | 9b8b7ce6b4 | |
cora | 046b3a4ce2 | |
cora | 354d17a14c | |
cora | 11265b60de | |
Mikita Wiśniewski | 7f3ba7d4a2 | |
cora | 88e87bccff | |
cora | a1209b14a1 | |
cora | 729159f631 | |
kabou | baf8e0b79c | |
chmodsayshello | 00dba67cd8 | |
kabou | 872b708465 | |
kabou | 74e70b674e | |
kabou | 14c882f982 | |
kabou | 8ae605165b | |
kabou | aca4aca79b | |
kabou | bacc7613b5 | |
kabou | 8a4b8707fa | |
kabou | a8c231da34 | |
cora | 4d342b8365 | |
cora | 12a943e222 | |
cora | 8d0afede37 | |
cora | 0288581407 | |
cora | 3774044f86 | |
cora | 46dbf8c0ab | |
cora | 7c263c6a18 | |
MysticTempest | 44b1d583a7 | |
cora | 1565999134 | |
cora | 5a25e42fd3 | |
cora | 421995deb3 | |
kabou | 4e3a2a7b4c | |
cora | e8e565fc06 | |
chmodsayshello | 6cb08a3c87 | |
chmodsayshello | 31a8ddabb8 | |
chmodsayshello | 6806ea311d | |
cora | ea2b53b231 | |
cora | e1ed990f58 | |
cora | e4c5f81524 | |
kay27 | 53042b6f48 | |
cora | fbe048087f | |
Elias Fleckenstein | 34e5bb0334 | |
Elias Fleckenstein | c05a2d3a9d | |
cora | 40d2e3b2b1 | |
cora | f1fc84b31b | |
cora | 85fb33aa4c | |
AFCMS | f9a2dacdd4 | |
AFCMS | 00c70014c7 | |
3raven | f4020ebd31 | |
kay27 | 74322ead49 | |
kay27 | 1a83f50505 | |
kay27 | 206c98e354 | |
kay27 | 69e83d5c0a | |
kay27 | d3dfd13f78 | |
kay27 | e28ccd9a80 | |
kay27 | a5fba06a2c | |
1F616EMO | 6c36c83a18 | |
1F616EMO | 48a4e069f9 | |
1F616EMO | 60e04438e0 | |
1F616EMO | 0b01d299ea | |
1F616EMO | ebdf944dda | |
1F616EMO | 794e10df4e | |
cora | 1cc8a7f8df | |
cora | 6a2fe2eb4f | |
cora | 6674684998 | |
kabou | 1266396e1d | |
kabou | f5abc28190 | |
AFCMS | f8f6ea22c8 | |
cora | b0b8ef3921 | |
cora | be6d2db7d4 | |
cora | dc40ed18b3 | |
cora | 1b99de73d2 | |
NO11 | c97e0cd631 | |
NO11 | 8c7a8a61d2 | |
NO11 | 6bdaa9f2d1 | |
cora | 8b8a133381 | |
kabou | dceb48bf94 | |
cora | e10c06ba98 | |
AFCMS | 8a47a195f6 | |
AFCMS | d0b60e2399 | |
AFCMS | 3ca40cd4e4 | |
cora | 0e8a87befa | |
kabou | 920b8b9654 | |
cora | dab80c45fd | |
kabou | f1a494ea62 | |
kabou | 64bb50dfd5 | |
kabou | 9edb40b5c5 | |
kabou | b0ae135b3c | |
cora | b13835dd6f | |
chmodsayshello | 3699ca5535 | |
chmodsayshello | 9c652df8a2 | |
chmodsayshello | 390802a344 | |
cora | a27abae045 | |
cora | 61a999fe5a | |
cora | 85afc8bd53 | |
kabou | ed8995acec | |
cora | 38f1db7a04 | |
chmodsayshello | f1c60a48e0 | |
chmodsayshello | c97fc42b68 | |
chmodsayshello | 92cd3381ad | |
chmodsayshello | f7a5862df2 | |
chmodsayshello | ba8e072265 | |
chmodsayshello | f9d8b61dc1 | |
chmodsayshello | dd727510ba | |
cora | a4e8c0b884 | |
Nils Dagsson Moskopp | 057051aa6d | |
cora | 83aebb8b99 | |
cora | deb2e1c50b | |
cora | 7d9cbd5f84 | |
cora | deb2c4ab50 | |
cora | 64ec36fe36 | |
Nils Dagsson Moskopp | cbf3dc49aa | |
cora | 6bc676545b | |
chmodsayshello | 77c2f9371e | |
cora | 4cdb1130af | |
cora | 5f126c4686 | |
cora | dd12417529 | |
Nils Dagsson Moskopp | 67ae203772 | |
Nils Dagsson Moskopp | 5ba36c08b6 | |
Nils Dagsson Moskopp | 56db877360 | |
Nils Dagsson Moskopp | e1d67a2095 | |
Nils Dagsson Moskopp | a2dd8c935d | |
Nils Dagsson Moskopp | 4fda54b0d1 | |
Nils Dagsson Moskopp | 9a53761b08 | |
Alexander Minges | 9b614c115c | |
Alexander Minges | faf3f60cff | |
cora | 1bcbdfbc4c | |
cora | b6ab815adc | |
cora | 511b7030e1 | |
cora | a83a2e9aba | |
cora | 0c03d420b8 | |
AFCMS | 8396dfe7e3 | |
cora | 231b658c3f | |
kay27 | dc4ccf91cc | |
cora | 8bf1d2b235 | |
cora | 3cb9947cf4 | |
cora | d1cd46e197 | |
cora | 33097a7656 | |
cora | 9ad4222f35 | |
cora | feb1fcc5b4 | |
cora | 6976ffca62 | |
Nils Dagsson Moskopp | 34b5002fc8 | |
cora | e63e3b3cbd | |
NO411 | 2aa04519dd | |
NO411 | e790bf90f4 | |
NO411 | b108f58b2f | |
cora | 8e904e2ca9 | |
cora | bb593159f1 | |
cora | 83c91aba93 | |
cora | e7970ecce5 | |
kabou | b96fb2af17 | |
kabou | 152e552458 | |
cora | f807ac5c70 | |
kabou | ace0dc00c7 | |
cora | 85d1f61188 | |
kabou | f3b28df6cc | |
kabou | f37f8b6bca | |
kabou | 2ba801dfc7 | |
kabou | bba3aabb59 | |
kabou | 19eb31f389 | |
kabou | 541a805a48 | |
kabou | cd12e1d78c | |
kabou | 4335d0d659 | |
kabou | de16eb3c5a | |
cora | 6851fa759e | |
cora | 7f1bb7af92 | |
cora | 53715212a2 | |
cora | c146426c5c | |
cora | dc24f45cfa | |
cora | d2861c5955 | |
cora | 1e4494e85d | |
cora | 4eae95fa47 | |
cora | ef7ebda90c | |
kabou | 1b99b73894 | |
kabou | 14da059ce7 | |
cora | 04f0ea260d | |
NO11 | 5974b6f609 | |
NO411 | 148be4ea39 | |
NO411 | 6afe7cfb58 | |
cora | 8e24e6edfe | |
AFCMS | 909b77ce4d | |
cora | 1dde51dd0b | |
NO11 | 63a156c30c | |
cora | 1c9f0c3238 | |
cora | 50e99f470e | |
NO411 | aeff7cf1a4 | |
cora | bc723616ea | |
kabou | 46ee5aaa59 | |
cora | 3dd4eec4e8 | |
NO411 | 019dd45381 | |
NO411 | d481f7b720 | |
NO411 | c94964d10a | |
kabou | a9a3f01a0e | |
kabou | ae6bea73fd | |
kabou | 2002872af8 | |
kabou | 8518ce2c19 | |
NO411 | 6158e4e50d | |
NO411 | 7c0a48bebf | |
NO411 | 5bdf83cbfc | |
NO411 | 976cfba53a | |
NO411 | fc9e83c059 | |
NO411 | 60d877b718 | |
cora | 81a1b9973a | |
kabou | 9eba0e4860 | |
kabou | 90311da514 | |
kabou | e9ff2ba32a | |
cora | 0b89149fe2 | |
cora | 7df6c8739e | |
cora | cd725137ae | |
NO411 | 0f8f5a41d2 | |
NO411 | db68c0e26b | |
NO11 | 627da6d305 | |
cora | 1803cc560d | |
kabou | 3f787f8305 | |
epCode | 9534624b21 | |
epCode | 4483f4b6b6 | |
NO11 | a44846a82c |
|
@ -41,6 +41,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `flammable=-1` Does not get destroyed by fire
|
||||
* `fire_encouragement`: How quickly this block catches fire
|
||||
* `fire_flammability`: How fast the block will burn away
|
||||
* `path_creation_possible=1`: Node can be turned into grass path by using a shovel on it
|
||||
* `spreading_dirt_type=1`: A dirt-type block with a cover (e.g. grass) which may spread to neighbor dirt blocks
|
||||
* `dirtifies_below_solid=1`: This node turns into dirt immediately when a solid or dirtifier node is placed on top
|
||||
* `dirtifier=1`: This node turns nodes the above group into dirt when placed above
|
||||
|
@ -56,6 +57,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `no_eat_delay=1`: Only for foodstuffs. When eating this, all eating delays are ignored.
|
||||
* `can_eat_when_full=1`: Only for foodstuffs. This item can be eaten when the user has a full hunger bar
|
||||
* `attached_node_facedir=1`: Like `attached_node`, but for facedir nodes
|
||||
* `supported_node=1`: Like `attached_node`, but can be placed on any nodes that do not have the `drawtype="airlike"` attribute.
|
||||
* `cauldron`: Cauldron. 1: Empty. 2-4: Water height
|
||||
* `anvil`: Anvil. 1: No damage. 2-3: Higher damage levels
|
||||
* `no_rename=1`: Item cannot be renamed by anvil
|
||||
|
@ -71,6 +73,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `coral_block=X`: Coral block (1 = alive, 2 = dead)
|
||||
* `coral_species=X`: Specifies the species of a coral; equal X means equal species
|
||||
* `set_on_fire=X`: Sets any (not fire-resistant) mob or player on fire for X seconds when touching
|
||||
* `compostability=X`: Item can be used on a composter block; X (1-100) is the % chance of adding a level of compost
|
||||
|
||||
#### Footnotes
|
||||
|
||||
|
@ -99,6 +102,7 @@ Please read <http://minecraft.gamepedia.com/Breaking> to learn how digging times
|
|||
* `water_bucket=1`: Bucket containing a liquid of group “water”
|
||||
* `enchantability=X`: How good the enchantments are the item gets (1 equals book)
|
||||
* `enchanted=1`: The item is already enchanted, meaning that it can't be enchanted using an enchanting table
|
||||
* `cobble=1`: Cobblestone of any kind
|
||||
|
||||
### Material groups
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
|
||||
Developed by many people. Not developed or endorsed by Mojang AB.
|
||||
|
||||
Version: 0.72.0
|
||||
Version: 0.75 (in development)
|
||||
|
||||
### Gameplay
|
||||
You start in a randomly-generated world made entirely of cubes. You can explore
|
||||
|
@ -66,7 +66,7 @@ Use the `/giveme` chat command to obtain them. See the in-game help for
|
|||
an explanation.
|
||||
|
||||
## Installation
|
||||
This game requires [Minetest](http://minetest.net) to run (version 5.3.0 or
|
||||
This game requires [Minetest](http://minetest.net) to run (version 5.4.1 or
|
||||
later). So you need to install Minetest first. Only stable versions of Minetest
|
||||
are officially supported.
|
||||
There is no support for running MineClone2 in development versions of Minetest.
|
||||
|
|
|
@ -1,29 +1,93 @@
|
|||
-- Overrides the builtin minetest.check_single_for_falling.
|
||||
-- We need to do this in order to handle nodes in mineclone specific groups
|
||||
-- "supported_node" and "attached_node_facedir".
|
||||
--
|
||||
-- Nodes in group "supported_node" can be placed on any node that does not
|
||||
-- have the "airlike" drawtype. Carpets are an example of this type.
|
||||
|
||||
local vector = vector
|
||||
|
||||
local facedir_to_dir = minetest.facedir_to_dir
|
||||
local get_item_group = minetest.get_item_group
|
||||
local remove_node = minetest.remove_node
|
||||
local get_node = minetest.get_node
|
||||
local get_meta = minetest.get_meta
|
||||
local registered_nodes = minetest.registered_nodes
|
||||
local get_node_drops = minetest.get_node_drops
|
||||
local add_item = minetest.add_item
|
||||
|
||||
-- drop_attached_node(p)
|
||||
--
|
||||
-- This function is copied verbatim from minetest/builtin/game/falling.lua
|
||||
-- We need this to do the exact same dropping node handling in our override
|
||||
-- minetest.check_single_for_falling() function as in the builtin function.
|
||||
--
|
||||
local function drop_attached_node(p)
|
||||
local n = get_node(p)
|
||||
local drops = get_node_drops(n, "")
|
||||
local def = registered_nodes[n.name]
|
||||
if def and def.preserve_metadata then
|
||||
local oldmeta = get_meta(p):to_table().fields
|
||||
-- Copy pos and node because the callback can modify them.
|
||||
local pos_copy = vector.new(p)
|
||||
local node_copy = {name=n.name, param1=n.param1, param2=n.param2}
|
||||
local drop_stacks = {}
|
||||
for k, v in pairs(drops) do
|
||||
drop_stacks[k] = ItemStack(v)
|
||||
end
|
||||
drops = drop_stacks
|
||||
def.preserve_metadata(pos_copy, node_copy, oldmeta, drops)
|
||||
end
|
||||
if def and def.sounds and def.sounds.fall then
|
||||
core.sound_play(def.sounds.fall, {pos = p}, true)
|
||||
end
|
||||
remove_node(p)
|
||||
for _, item in pairs(drops) do
|
||||
local pos = {
|
||||
x = p.x + math.random()/2 - 0.25,
|
||||
y = p.y + math.random()/2 - 0.25,
|
||||
z = p.z + math.random()/2 - 0.25,
|
||||
}
|
||||
add_item(pos, item)
|
||||
end
|
||||
end
|
||||
|
||||
-- minetest.check_single_for_falling(pos)
|
||||
--
|
||||
-- * causes an unsupported `group:falling_node` node to fall and causes an
|
||||
-- unattached `group:attached_node` or `group:attached_node_facedir` node
|
||||
-- or unsupported `group:supported_node` node to drop.
|
||||
-- * does not spread these updates to neighbours.
|
||||
--
|
||||
-- Returns true if the node at <pos> has spawned a falling node or has been
|
||||
-- dropped as item(s).
|
||||
--
|
||||
local original_function = minetest.check_single_for_falling
|
||||
|
||||
function minetest.check_single_for_falling(pos)
|
||||
local ret_o = original_function(pos)
|
||||
local ret = false
|
||||
local node = minetest.get_node(pos)
|
||||
if original_function(pos) then
|
||||
return true
|
||||
end
|
||||
|
||||
local node = get_node(pos)
|
||||
if get_item_group(node.name, "attached_node_facedir") ~= 0 then
|
||||
local dir = facedir_to_dir(node.param2)
|
||||
if dir then
|
||||
if get_item_group(get_node(vector.add(pos, dir)).name, "solid") == 0 then
|
||||
remove_node(pos)
|
||||
local drops = minetest.get_node_drops(node.name, "")
|
||||
for dr=1, #drops do
|
||||
minetest.add_item(pos, drops[dr])
|
||||
end
|
||||
ret = true
|
||||
drop_attached_node(pos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret_o or ret
|
||||
end
|
||||
|
||||
if get_item_group(node.name, "supported_node") ~= 0 then
|
||||
local def = registered_nodes[get_node(vector.offset(pos, 0, -1, 0)).name]
|
||||
if def and def.drawtype == "airlike" then
|
||||
drop_attached_node(pos)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
|
@ -24,9 +24,240 @@ mcl_vars.inventory_header = ""
|
|||
-- Tool wield size
|
||||
mcl_vars.tool_wield_scale = { x = 1.8, y = 1.8, z = 1 }
|
||||
|
||||
-- Mapgen variables
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local singlenode = mg_name == "singlenode"
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_vars.MAP_BLOCKSIZE = math.max(1, minetest.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, minetest.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 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 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 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)
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_vars.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_vars.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Realm Barrier (h=11), to allow escaping the End
|
||||
- End (h>=256)
|
||||
- Void (h>=1000)
|
||||
- Nether (h=128)
|
||||
- Void (h>=1000)
|
||||
]]
|
||||
|
||||
-- Overworld
|
||||
mcl_vars.mg_overworld_min = -62
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min + 4
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min + 10
|
||||
mcl_vars.mg_lava = true
|
||||
mcl_vars.mg_bedrock_is_rough = true
|
||||
|
||||
elseif singlenode then
|
||||
mcl_vars.mg_overworld_min = -66
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
ground = tonumber(ground)
|
||||
if not ground then
|
||||
ground = 8
|
||||
end
|
||||
mcl_vars.mg_overworld_min = ground - 3
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
end
|
||||
|
||||
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_nether_max = mcl_vars.mg_nether_min + 128
|
||||
mcl_vars.mg_bedrock_nether_bottom_min = mcl_vars.mg_nether_min
|
||||
mcl_vars.mg_bedrock_nether_top_max = mcl_vars.mg_nether_max
|
||||
if not superflat then
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min + 4
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max - 4
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
mcl_vars.mg_bedrock_nether_bottom_max = mcl_vars.mg_bedrock_nether_bottom_min
|
||||
mcl_vars.mg_bedrock_nether_top_min = mcl_vars.mg_bedrock_nether_top_max
|
||||
mcl_vars.mg_lava_nether_max = mcl_vars.mg_nether_min + 2
|
||||
end
|
||||
if mg_name == "flat" then
|
||||
if superflat then
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_bedrock_nether_bottom_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_bedrock_nether_bottom_max + 52
|
||||
else
|
||||
mcl_vars.mg_flat_nether_floor = mcl_vars.mg_lava_nether_max + 4
|
||||
mcl_vars.mg_flat_nether_ceiling = mcl_vars.mg_lava_nether_max + 52
|
||||
end
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
mcl_vars.mg_end_min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
mcl_vars.mg_end_max_official = mcl_vars.mg_end_min + minecraft_height_limit
|
||||
mcl_vars.mg_end_max = mcl_vars.mg_overworld_min - 2000
|
||||
mcl_vars.mg_end_platform_pos = { x = 100, y = mcl_vars.mg_end_min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_vars.mg_realm_barrier_overworld_end_max = mcl_vars.mg_end_max
|
||||
mcl_vars.mg_realm_barrier_overworld_end_min = mcl_vars.mg_end_max - 11
|
||||
|
||||
-- Use MineClone 2-style dungeons
|
||||
mcl_vars.mg_dungeons = true
|
||||
|
||||
-- Set default stack sizes
|
||||
minetest.nodedef_default.stack_max = 64
|
||||
minetest.craftitemdef_default.stack_max = 64
|
||||
|
||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
local chunks = {} -- intervals of chunks generated
|
||||
function mcl_vars.add_chunk(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
local prev
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then -- we've found it
|
||||
if (n == d[2]) or (n >= d[1]) then return end -- already here
|
||||
if n == d[1]-1 then -- right before:
|
||||
if prev and (prev[2] == n-1) then
|
||||
prev[2] = d[2]
|
||||
table.remove(chunks, i)
|
||||
return
|
||||
end
|
||||
d[1] = n
|
||||
return
|
||||
end
|
||||
if prev and (prev[2] == n-1) then --join to previous
|
||||
prev[2] = n
|
||||
return
|
||||
end
|
||||
table.insert(chunks, i, {n, n}) -- insert new interval before i
|
||||
return
|
||||
end
|
||||
prev = d
|
||||
end
|
||||
chunks[#chunks+1] = {n, n}
|
||||
end
|
||||
function mcl_vars.is_generated(pos)
|
||||
local n = mcl_vars.get_chunk_number(pos) -- unsigned int
|
||||
for i, d in pairs(chunks) do
|
||||
if n <= d[2] then
|
||||
return (n >= d[1])
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- "Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
-- p: Position, if it's wrong, {name="error"} node will return.
|
||||
-- force: optional (default: false) - Do the maximum to still read the node within us_timeout.
|
||||
-- us_timeout: optional (default: 244 = 0.000244 s = 1/80/80/80), set it at least to 3000000 to let mapgen to finish its job.
|
||||
--
|
||||
-- returns node definition, eg. {name="air"}. Unfortunately still can return {name="ignore"}.
|
||||
function mcl_vars.get_node(p, force, us_timeout)
|
||||
-- check initial circumstances
|
||||
if not p or not p.x or not p.y or not p.z then return {name="error"} end
|
||||
|
||||
-- try common way
|
||||
local node = minetest.get_node(p)
|
||||
if node.name ~= "ignore" then
|
||||
return node
|
||||
end
|
||||
|
||||
-- copy table to get sure it won't changed by other threads
|
||||
local pos = {x=p.x,y=p.y,z=p.z}
|
||||
|
||||
-- try LVM
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
if node.name ~= "ignore" or not force then
|
||||
return node
|
||||
end
|
||||
|
||||
-- all ways failed - need to emerge (or forceload if generated)
|
||||
local us_timeout = us_timeout or 244
|
||||
if mcl_vars.is_generated(pos) then
|
||||
minetest.chat_send_all("IMPOSSIBLE! Please report this to MCL2 issue tracker!")
|
||||
minetest.forceload_block(pos)
|
||||
else
|
||||
minetest.emerge_area(pos, pos)
|
||||
end
|
||||
|
||||
local t = minetest.get_us_time()
|
||||
|
||||
node = minetest.get_node(pos)
|
||||
|
||||
while (not node or node.name == "ignore") and (minetest.get_us_time() - t < us_timeout) do
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
|
||||
return node
|
||||
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||
end
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
# mcl_mapgen
|
||||
------------
|
||||
Helps to avoid problems caused by 'chunk-in-shell' feature of mapgen.cpp.
|
||||
|
||||
It also queues your generators to run them in proper order:
|
||||
|
||||
### mcl_mapgen.register_on_generated(lvm_callback_function, order_number)
|
||||
-------------------------------------------------------------------------
|
||||
Replacement of engine API function `minetest.register_on_generated(function(vm_context))`
|
||||
|
||||
It is still unsafe. Cavegen part can and will overwrite outer 1-block layer of the chunk which is expected to be generated.
|
||||
|
||||
Nodes marked as `is_ground_content` could be overwritten. Air and water are usually 'ground content' too.
|
||||
For Minetest 5.4 it doesn't recommended to place blocks within lvm callback function.
|
||||
|
||||
See https://git.minetest.land/MineClone2/MineClone2/issues/1395
|
||||
|
||||
* `lvm_callback_function`: chunk callback LVM function definition:
|
||||
* `function(vm_context)`:
|
||||
* `vm_context` will pass into next lvm callback function from the queue!
|
||||
* `vm_context`: a table which already contains some LVM data as the fields, and some of them can be added in your lvm callback function:
|
||||
* `vm`: curent voxel manipulator object itself;
|
||||
* `chunkseed`: seed of this mapchunk;
|
||||
* `minp` & `maxp`: minimum and maximum chunk position;
|
||||
* `emin` & `emax`: minimum and maximum chunk position WITH SHELL AROUND IT;
|
||||
* `area`: voxel area, can be helpful to access data;
|
||||
* `data`: LVM buffer data array, data loads into it before the callbacks;
|
||||
* `write`: set it to true in your lvm callback functionm, if you changed `data` and want to write it;
|
||||
* `param2_data`: LVM buffer data array of `param2`, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
|
||||
* `vm_context.param2_data = vm_context.param2_data or vm_context.vm:get_param2_data(vm_context.lvm_param2_buffer)`
|
||||
* `write_param2`: set it to true in your lvm callback function, if you used `param2_data` and want to write it;
|
||||
* `light`: LVM buffer data array of light, *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - you load it yourself:
|
||||
* `vm_context.light = vm_context.light or vm_context.vm.get_light_data(vm_context.lvm_light_buffer)`
|
||||
* `write_light`: set it to true in your lvm callback function, if you used `light` and want to write it;
|
||||
* `lvm_param2_buffer`: static `param2` buffer pointer, used to load `param2_data` array;
|
||||
* `shadow`: set it to false to disable shadow propagation;
|
||||
* `heightmap`: mapgen object contanting y coordinates of ground level,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.heightmap = vm_context.heightmap or minetest.get_mapgen_object('heightmap')`
|
||||
* `biomemap`: mapgen object contanting biome IDs of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.biomemap = vm_context.biomemap or minetest.get_mapgen_object('biomemap')`
|
||||
* `heatmap`: mapgen object contanting temperature values of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.heatmap = vm_context.heatmap or minetest.get_mapgen_object('heatmap')`
|
||||
* `humiditymap`: mapgen object contanting humidity values of nodes,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.humiditymap = vm_context.humiditymap or minetest.get_mapgen_object('humiditymap')`
|
||||
* `gennotify`: mapgen object contanting mapping table of structures, see Minetest Lua API for explanation,
|
||||
* *NO ANY DATA LOADS INTO IT BEFORE THE CALLBACKS* - load it yourself:
|
||||
* `vm_context.gennotify = vm_context.gennotify or minetest.get_mapgen_object('gennotify')`
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block_lvm(lvm_callback_function, order_number)
|
||||
-----------------------------------------------------------------------------
|
||||
Registers lvm callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
|
||||
`vm_context` passes into lvm callback function.
|
||||
* `lvm_callback_function`: the block callback LVM function definition - same as for chunks - see definition example above;
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen_block(node_callback_function, order_number)
|
||||
--------------------------------------------------------------------------
|
||||
Registers node_callback function to be called when current block (usually 16x16x16 nodes) generation is REALLY 100% finished.
|
||||
* `node_callback_function`: node callback function definition:
|
||||
* `function(minp, maxp, seed)`:
|
||||
* `minp` & `maxp`: minimum and maximum block position;
|
||||
* `seed`: seed of this mapblock;
|
||||
* `order_number` (optional): the less, the earlier,
|
||||
* e.g. `mcl_mapgen.order.BUILDINGS` or `mcl_mapgen.order.LARGE_BUILDINGS`
|
||||
|
||||
### mcl_mapgen.register_mapgen(callback_function, order_number)
|
||||
---------------------------------------------------------------
|
||||
Registers callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
|
||||
For LVM it's the most frustrating function from this mod.
|
||||
|
||||
It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
|
||||
Don't use it for accessing mapgen objects please.
|
||||
|
||||
To use VM you have to run `vm_context.vm = mcl_mapgen.get_voxel_manip(vm_context.emin, vm_context.emax)`.
|
||||
* `callback_function`: callback function definition:
|
||||
* `function(minp, maxp, seed, vm_context)`:
|
||||
* `minp` & `maxp`: minimum and maximum block position;
|
||||
* `seed`: seed of this mapblock;
|
||||
* `vm_context`: a table - see description above.
|
||||
* `order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.register_mapgen_lvm(lvm_callback_function, order_number)
|
||||
-----------------------------------------------------------------------
|
||||
Registers lvm callback function to be called when current chunk generation is REALLY 100% finished.
|
||||
|
||||
It's the most frustrating function from this mod. It can't provide you access to mapgen objects. They are probably gone long ago.
|
||||
|
||||
Don't use it for accessing mapgen objects please.
|
||||
|
||||
`vm_context` passes into lvm callback function.
|
||||
* `lvm_callback_function`: the block callback LVM function definition - same as above;
|
||||
* `order_number` (optional): the less, the earlier.
|
||||
|
||||
### mcl_mapgen.get_far_node(pos)
|
||||
--------------------------------
|
||||
Returns node if it is generated, otherwise returns `{name = "ignore"}`.
|
||||
|
||||
### mcl_mapgen.clamp_to_chunk(x, size)
|
||||
--------------------------------------
|
||||
Returns new `x`, slighty tuned to make structure of size `size` be within single chunk side of 80 nodes.
|
||||
|
||||
### function mcl_mapgen.get_chunk_beginning(x)
|
||||
----------------------------------------------
|
||||
Returns chunk beginning of `x`. It is the same as `minp.axis` for per-chunk callbacks, but we don't always have `minp`.
|
||||
|
||||
## Constants:
|
||||
* `mcl_mapgen.EDGE_MIN`, `mcl_mapgen.EDGE_MAX` - world edges, min & max.
|
||||
* `mcl_mapgen.seed`, `mcl_mapgen.name` - mapgen seed & name.
|
||||
* `mcl_mapgen.v6`, `mcl_mapgen.superflat`, `mcl_mapgen.singlenode` - is mapgen v6, superflat, singlenode.
|
||||
* `mcl_mapgen.normal` is mapgen normal (not superflat or singlenode).
|
|
@ -1,574 +0,0 @@
|
|||
mcl_mapgen = {}
|
||||
|
||||
local order = { -- mcl_mapgen.order...
|
||||
DEFAULT = 5000,
|
||||
CHORUS = 100000,
|
||||
BUILDINGS = 200000,
|
||||
VILLAGES = 900000,
|
||||
DUNGEONS = 950000,
|
||||
STRONGHOLDS = 999999,
|
||||
OCEAN_MONUMENT = 1000000,
|
||||
LARGE_BUILDINGS = 2000000,
|
||||
}
|
||||
|
||||
-- Begin of Compatibility stuff
|
||||
|
||||
local function unsigned(v)
|
||||
if v < 0 then
|
||||
v = 0x100000000 - (math.abs(v) % 0x100000000)
|
||||
end
|
||||
return v % 0x100000000
|
||||
end
|
||||
|
||||
if bit == nil then
|
||||
bit = {}
|
||||
function bit.bxor(a, b)
|
||||
local a = unsigned(a)
|
||||
local b = unsigned(b)
|
||||
local c = 0
|
||||
for n = 31, 0, -1 do
|
||||
local mask = math.floor(2^n)
|
||||
if (a >= mask) ~= (b >= mask) then
|
||||
c = c + mask
|
||||
end
|
||||
a = a % mask
|
||||
b = b % mask
|
||||
end
|
||||
return c
|
||||
end
|
||||
end
|
||||
|
||||
if vector.metatable == nil then
|
||||
function math.round(x)
|
||||
if x >= 0 then
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
return math.ceil(x - 0.5)
|
||||
end
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/vector.lua")
|
||||
end
|
||||
|
||||
-- End of compatibility stuff
|
||||
|
||||
local math_floor = math.floor
|
||||
local math_max = math.max
|
||||
local minetest_get_node = minetest.get_node
|
||||
local minetest_get_voxel_manip = minetest.get_voxel_manip
|
||||
local minetest_log = minetest.log
|
||||
local minetest_pos_to_string = minetest.pos_to_string
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_mapgen.CS = math_max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
mcl_mapgen.BS = math_max(1, core.MAP_BLOCKSIZE or 16)
|
||||
mcl_mapgen.LIMIT = math_max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000)
|
||||
mcl_mapgen.MAX_LIMIT = 31000 -- MAX_MAP_GENERATION_LIMIT, https://github.com/minetest/minetest/issues/10428
|
||||
mcl_mapgen.OFFSET = - math_floor(mcl_mapgen.CS / 2)
|
||||
mcl_mapgen.OFFSET_NODES = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
mcl_mapgen.CS_NODES = mcl_mapgen.CS * mcl_mapgen.BS
|
||||
mcl_mapgen.LAST_BLOCK = mcl_mapgen.CS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_BLOCK = mcl_mapgen.BS - 1
|
||||
mcl_mapgen.LAST_NODE_IN_CHUNK = mcl_mapgen.CS_NODES - 1
|
||||
mcl_mapgen.HALF_CS_NODES = math_floor(mcl_mapgen.CS_NODES / 2)
|
||||
mcl_mapgen.HALF_BS = math_floor(mcl_mapgen.BS / 2)
|
||||
mcl_mapgen.CS_3D = mcl_mapgen.CS^3
|
||||
mcl_mapgen.CHUNK_WITH_SHELL = mcl_mapgen.CS + 2
|
||||
mcl_mapgen.CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL^3
|
||||
|
||||
local central_chunk_min_pos = mcl_mapgen.OFFSET * mcl_mapgen.BS
|
||||
local central_chunk_max_pos = central_chunk_min_pos + mcl_mapgen.CS_NODES - 1
|
||||
|
||||
local ccfmin = central_chunk_min_pos - mcl_mapgen.BS -- Fullminp/fullmaxp of central chunk, in nodes
|
||||
local ccfmax = central_chunk_max_pos + mcl_mapgen.BS
|
||||
|
||||
local mapgen_limit_b = math_floor(math.min(mcl_mapgen.LIMIT, mcl_mapgen.MAX_LIMIT) / mcl_mapgen.BS)
|
||||
local mapgen_limit_min = - mapgen_limit_b * mcl_mapgen.BS
|
||||
local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_mapgen.BS - 1
|
||||
|
||||
local numcmin = math_max(math_floor((ccfmin - mapgen_limit_min) / mcl_mapgen.CS_NODES), 0) -- Number of complete chunks from central chunk
|
||||
local numcmax = math_max(math_floor((mapgen_limit_max - ccfmax) / mcl_mapgen.CS_NODES), 0) -- fullminp/fullmaxp to effective mapgen limits.
|
||||
|
||||
mcl_mapgen.EDGE_MIN = central_chunk_min_pos - numcmin * mcl_mapgen.CS_NODES
|
||||
mcl_mapgen.EDGE_MAX = central_chunk_max_pos + numcmax * mcl_mapgen.CS_NODES
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] World edges: mcl_mapgen.EDGE_MIN = " .. tostring(mcl_mapgen.EDGE_MIN) .. ", mcl_mapgen.EDGE_MAX = " .. tostring(mcl_mapgen.EDGE_MAX))
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Mapgen variables
|
||||
local overworld, end_, nether = {}, {}, {}
|
||||
local seed = minetest.get_mapgen_setting("seed")
|
||||
mcl_mapgen.seed = seed
|
||||
mcl_mapgen.name = minetest.get_mapgen_setting("mg_name")
|
||||
mcl_mapgen.v6 = mcl_mapgen.name == "v6"
|
||||
mcl_mapgen.flat = mcl_mapgen.name == "flat"
|
||||
mcl_mapgen.superflat = mcl_mapgen.flat and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
mcl_mapgen.singlenode = mcl_mapgen.name == "singlenode"
|
||||
mcl_mapgen.normal = not mcl_mapgen.superflat and not mcl_mapgen.singlenode
|
||||
local flat, superflat, singlenode, normal = mcl_mapgen.flat, mcl_mapgen.superflat, mcl_mapgen.singlenode, mcl_mapgen.normal
|
||||
|
||||
minetest_log("action", "[mcl_mapgen] Mapgen mode: " .. (normal and "normal" or (superflat and "superflat" or (flat and "flat" or "singlenode"))))
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- Generator queues
|
||||
local queue_unsafe_engine = {}
|
||||
local queue_chunks_nodes = {}
|
||||
local queue_chunks_lvm = {}
|
||||
local queue_blocks_nodes = {}
|
||||
local queue_blocks_lvm = {}
|
||||
|
||||
-- Requirements. 0 means 'none', greater than 0 means 'required'
|
||||
local block = 0
|
||||
local queue_blocks_lvm_counter = 0
|
||||
local lvm_chunk = 0
|
||||
local param2 = 0
|
||||
local nodes_block = 0
|
||||
local nodes_chunk = 0
|
||||
local safe_functions = 0
|
||||
|
||||
local BS, CS = mcl_mapgen.BS, mcl_mapgen.CS -- Mapblock size (in nodes), Mapchunk size (in blocks)
|
||||
local offset = mcl_mapgen.OFFSET -- Central mapchunk offset (in blocks)
|
||||
local CS_NODES = mcl_mapgen.CS_NODES
|
||||
local LAST_BLOCK = mcl_mapgen.LAST_BLOCK
|
||||
local LAST_NODE_IN_BLOCK = mcl_mapgen.LAST_NODE_IN_BLOCK
|
||||
local LAST_NODE_IN_CHUNK = mcl_mapgen.LAST_NODE_IN_CHUNK
|
||||
local HALF_CS_NODES = mcl_mapgen.HALF_CS_NODES
|
||||
local CS_3D = mcl_mapgen.CS_3D
|
||||
local CHUNK_WITH_SHELL = mcl_mapgen.CHUNK_WITH_SHELL
|
||||
local CHUNK_WITH_SHELL_3D = mcl_mapgen.CHUNK_WITH_SHELL_3D
|
||||
|
||||
local DEFAULT_ORDER = order.DEFAULT
|
||||
|
||||
function mcl_mapgen.register_on_generated(callback_function, order)
|
||||
queue_unsafe_engine[#queue_unsafe_engine+1] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_unsafe_engine, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen(callback_function, order)
|
||||
nodes_chunk = nodes_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_nodes[nodes_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_lvm(callback_function, order)
|
||||
lvm_chunk = lvm_chunk + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_chunks_lvm[lvm_chunk] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_chunks_lvm, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block(callback_function, order)
|
||||
block = block + 1
|
||||
nodes_block = nodes_block + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_nodes[nodes_block] = {i = order or DEFAULT_ORDER, f = callback_function}
|
||||
table.sort(queue_blocks_nodes, function(a, b) return (a.i <= b.i) end)
|
||||
end
|
||||
function mcl_mapgen.register_mapgen_block_lvm(callback_function, order)
|
||||
block = block + 1
|
||||
queue_blocks_lvm_counter = queue_blocks_lvm_counter + 1
|
||||
safe_functions = safe_functions + 1
|
||||
queue_blocks_lvm[queue_blocks_lvm_counter] = {order = order or DEFAULT_ORDER, callback_function = callback_function}
|
||||
table.sort(queue_blocks_lvm, function(a, b) return (a.order <= b.order) end)
|
||||
end
|
||||
|
||||
local vm_context -- here will be many references and flags, like: param2, light_data, heightmap, biomemap, heatmap, humiditymap, gennotify, write_lvm, write_param2, shadow
|
||||
local data, param2_data, light, area
|
||||
local lvm_buffer, lvm_param2_buffer, lvm_light_buffer = {}, {}, {} -- Static buffer pointers
|
||||
|
||||
local all_blocks_in_chunk = {}
|
||||
for x = -1, LAST_BLOCK+1 do
|
||||
for y = -1, LAST_BLOCK+1 do
|
||||
for z = -1, LAST_BLOCK+1 do
|
||||
all_blocks_in_chunk[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * y + z) + x] = vector.new(x, y, z)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local chunk_scan_range = {
|
||||
[-CS_NODES] = {-1 , -1 },
|
||||
[ 0 ] = {-1 , LAST_BLOCK+1},
|
||||
[ CS_NODES] = {LAST_BLOCK+1, LAST_BLOCK+1},
|
||||
}
|
||||
|
||||
local function is_chunk_finished(minp)
|
||||
local center = vector.add(minp, HALF_CS_NODES)
|
||||
for check_x = center.x - CS_NODES, center.x + CS_NODES, CS_NODES do
|
||||
for check_y = center.y - CS_NODES, center.y + CS_NODES, CS_NODES do
|
||||
for check_z = center.z - CS_NODES, center.z + CS_NODES, CS_NODES do
|
||||
local pos = vector.new(check_x, check_y, check_z)
|
||||
if pos ~= center then
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
if node.name == "ignore" then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function uint32_t(v)
|
||||
if v >= 0 then
|
||||
return v % 0x100000000
|
||||
end
|
||||
return 0x100000000 - (math.abs(v) % 0x100000000)
|
||||
end
|
||||
|
||||
local function get_block_seed(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
return uint32_t(uint32_t(23 * pos.x) + uint32_t(42123 * pos.y) + uint32_t(38134234 * pos.z) + current_seed)
|
||||
end
|
||||
|
||||
local function get_block_seed2(pos, current_seed)
|
||||
local current_seed = current_seed or uint32_t(tonumber(seed))
|
||||
local n = uint32_t(uint32_t(1619 * pos.x) + uint32_t(31337 * pos.y) + uint32_t(52591 * pos.z) + uint32_t(1013 * current_seed))
|
||||
n = bit.bxor(bit.rshift(n, 13), n)
|
||||
local seed = uint32_t((n * uint32_t(n * n * 60493 + 19990303) + 1376312589))
|
||||
return seed
|
||||
end
|
||||
|
||||
local function get_block_seed3(pos, current_seed)
|
||||
local current_seed = uint32_t(current_seed or uint32_t(tonumber(seed)))
|
||||
local x = uint32_t((pos.x + 32768) * 13)
|
||||
local y = uint32_t((pos.y + 32767) * 13873)
|
||||
local z = uint32_t((pos.z + 76705) * 115249)
|
||||
local seed = uint32_t(bit.bxor(current_seed, x, y, z))
|
||||
return seed
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, chunkseed)
|
||||
local minp, maxp, chunkseed = minp, maxp, chunkseed
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
data = vm:get_data(lvm_buffer)
|
||||
area = VoxelArea:new({MinEdge=emin, MaxEdge=emax})
|
||||
vm_context = {
|
||||
data = data,
|
||||
param2_data = param2_data,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
vm = vm,
|
||||
emin = emin,
|
||||
emax = emax,
|
||||
minp = minp,
|
||||
maxp = maxp,
|
||||
chunkseed = chunkseed,
|
||||
}
|
||||
|
||||
local current_blocks = {}
|
||||
local current_chunks = {}
|
||||
if safe_functions > 0 then
|
||||
local ready_blocks = table.copy(all_blocks_in_chunk)
|
||||
local p0 = vector.new(minp)
|
||||
local center = vector.add(p0, HALF_CS_NODES)
|
||||
for x = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for y = -CS_NODES, CS_NODES, CS_NODES do
|
||||
for z = -CS_NODES, CS_NODES, CS_NODES do
|
||||
if x ~= 0 or y ~= 0 or z ~= 0 then
|
||||
local offset = vector.new(x, y, z)
|
||||
local pos = center + offset
|
||||
minetest_get_voxel_manip():read_from_map(pos, pos)
|
||||
local node = minetest_get_node(pos)
|
||||
local is_generated = node.name ~= "ignore"
|
||||
if is_generated then
|
||||
local adjacent_chunk_pos = p0 + offset
|
||||
if is_chunk_finished(adjacent_chunk_pos) then
|
||||
current_chunks[#current_chunks + 1] = adjacent_chunk_pos
|
||||
end
|
||||
else
|
||||
local scan_range_x = chunk_scan_range[x]
|
||||
for cut_x = scan_range_x[1], scan_range_x[2] do
|
||||
local scan_range_y = chunk_scan_range[y]
|
||||
for cut_y = scan_range_y[1], scan_range_y[2] do
|
||||
local scan_range_z = chunk_scan_range[z]
|
||||
for cut_z = scan_range_z[1], scan_range_z[2] do
|
||||
ready_blocks[CHUNK_WITH_SHELL * (CHUNK_WITH_SHELL * cut_y + cut_z) + cut_x] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local number_of_blocks = 0
|
||||
for k, offset in pairs(ready_blocks) do
|
||||
if queue_blocks_lvm_counter > 0 or nodes_block > 0 then
|
||||
local block_minp = p0 + vector.multiply(offset, BS)
|
||||
local block_maxp = vector.add(block_minp, LAST_NODE_IN_BLOCK)
|
||||
local blockseed = get_block_seed3(block_minp)
|
||||
vm_context.minp, vm_context.maxp, vm_context.blockseed = block_minp, block_maxp, blockseed
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_lvm) do
|
||||
v.callback_function(vm_context)
|
||||
end
|
||||
if nodes_block > 0 then
|
||||
current_blocks[#current_blocks + 1] = { minp = block_minp, maxp = block_maxp, blockseed = blockseed }
|
||||
end
|
||||
end
|
||||
number_of_blocks = number_of_blocks + 1
|
||||
end
|
||||
if number_of_blocks == CHUNK_WITH_SHELL_3D then
|
||||
current_chunks[#current_chunks + 1] = p0
|
||||
end
|
||||
end
|
||||
|
||||
if #queue_unsafe_engine > 0 then
|
||||
vm_context.minp, vm_context.maxp = minp, maxp
|
||||
-- * U N S A F E --
|
||||
-- mcl_mapgen.register_on_generated(function(vm_context), order_number) --
|
||||
-- * U N S A F E --
|
||||
for _, v in pairs(queue_unsafe_engine) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(vm_context.param2_data)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
elseif vm_context.calc_lighting then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
end
|
||||
end
|
||||
|
||||
for i, chunk_minp in pairs(current_chunks) do
|
||||
local chunk_maxp = vector.add(chunk_minp, LAST_NODE_IN_CHUNK)
|
||||
local current_chunk_seed = get_block_seed3(vector.subtract(chunk_minp, BS))
|
||||
area = VoxelArea:new({MinEdge=minp, MaxEdge=maxp})
|
||||
vm_context = {
|
||||
data = data,
|
||||
param2_data = param2_data,
|
||||
light = light,
|
||||
area = area,
|
||||
lvm_buffer = lvm_buffer,
|
||||
lvm_param2_buffer = lvm_param2_buffer,
|
||||
lvm_light_buffer = lvm_light_buffer,
|
||||
emin = chunk_minp,
|
||||
emax = chunk_maxp,
|
||||
minp = chunk_minp,
|
||||
maxp = chunk_maxp,
|
||||
chunkseed = current_chunk_seed,
|
||||
}
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_lvm(function(vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_lvm) do
|
||||
v.f(vm_context)
|
||||
end
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed, vm_context), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_chunks_nodes) do
|
||||
v.f(chunk_minp, chunk_maxp, current_chunk_seed, vm_context)
|
||||
end
|
||||
if vm_context.write or vm_context.write_param2 or vm_context.write_light then
|
||||
if vm_context.write then
|
||||
vm:set_data(data)
|
||||
end
|
||||
if vm_context.write_param2 then
|
||||
vm:set_param2_data(param2_data)
|
||||
end
|
||||
if vm_context.write_light then
|
||||
vm:set_light_data(light)
|
||||
end
|
||||
-- caused error from torches (?)
|
||||
-- vm:calc_lighting(minp, maxp, vm_context.shadow or true)
|
||||
vm:write_to_map()
|
||||
vm:update_liquids()
|
||||
elseif vm_context.calc_lighting then
|
||||
vm:calc_lighting(minp, maxp, (vm_context.shadow ~= nil) or true)
|
||||
end
|
||||
end
|
||||
|
||||
for _, b in pairs(current_blocks) do
|
||||
-- --
|
||||
-- mcl_mapgen.register_mapgen_block(function(minp, maxp, blockseed), order_number) --
|
||||
-- --
|
||||
for _, v in pairs(queue_blocks_nodes) do
|
||||
v.f(b.minp, b.maxp, b.blockseed)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_generated = mcl_mapgen.register_chunk_generator
|
||||
|
||||
function mcl_mapgen.get_far_node(p)
|
||||
local p = p
|
||||
local node = minetest_get_node(p)
|
||||
if node.name ~= "ignore" then return node end
|
||||
minetest_get_voxel_manip():read_from_map(p, p)
|
||||
return minetest_get_node(p)
|
||||
end
|
||||
|
||||
local function coordinate_to_block(x)
|
||||
return math_floor(x / BS)
|
||||
end
|
||||
|
||||
local function coordinate_to_chunk(x)
|
||||
return math_floor((coordinate_to_block(x) - offset) / CS)
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_block(pos)
|
||||
return {
|
||||
x = coordinate_to_block(pos.x),
|
||||
y = coordinate_to_block(pos.y),
|
||||
z = coordinate_to_block(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_mapgen.pos_to_chunk(pos)
|
||||
return {
|
||||
x = coordinate_to_chunk(pos.x),
|
||||
y = coordinate_to_chunk(pos.y),
|
||||
z = coordinate_to_chunk(pos.z)
|
||||
}
|
||||
end
|
||||
|
||||
local k_positive = math.ceil(mcl_mapgen.MAX_LIMIT / mcl_mapgen.CS_NODES)
|
||||
local k_positive_z = k_positive * 2
|
||||
local k_positive_y = k_positive_z * k_positive_z
|
||||
|
||||
function mcl_mapgen.get_chunk_number(pos) -- unsigned int
|
||||
local c = mcl_mapgen.pos_to_chunk(pos)
|
||||
return
|
||||
(c.y + k_positive) * k_positive_y +
|
||||
(c.z + k_positive) * k_positive_z +
|
||||
c.x + k_positive
|
||||
end
|
||||
|
||||
mcl_mapgen.minecraft_height_limit = 256
|
||||
|
||||
mcl_mapgen.bedrock_is_rough = normal
|
||||
|
||||
-- Overworld
|
||||
overworld.min = -62
|
||||
if superflat then
|
||||
mcl_mapgen.ground = tonumber(minetest.get_mapgen_setting("mgflat_ground_level")) or 8
|
||||
overworld.min = mcl_mapgen.ground - 3
|
||||
end
|
||||
-- if singlenode then mcl_mapgen.overworld.min = -66 end -- DONT KNOW WHY
|
||||
overworld.max = mcl_mapgen.EDGE_MAX
|
||||
|
||||
overworld.bedrock_min = overworld.min
|
||||
overworld.bedrock_max = overworld.bedrock_min + (mcl_mapgen.bedrock_is_rough and 4 or 0)
|
||||
|
||||
mcl_mapgen.lava = normal
|
||||
overworld.lava_max = overworld.min + (normal and 10 or 0)
|
||||
|
||||
|
||||
-- The Nether (around Y = -29000)
|
||||
nether.min = -29067 -- Carefully chosen to be at a mapchunk border
|
||||
nether.max = nether.min + 128
|
||||
nether.bedrock_bottom_min = nether.min
|
||||
nether.bedrock_top_max = nether.max
|
||||
if not superflat then
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min + 4
|
||||
nether.bedrock_top_min = nether.bedrock_top_max - 4
|
||||
nether.lava_max = nether.min + 31
|
||||
else
|
||||
-- Thin bedrock in classic superflat mapgen
|
||||
nether.bedrock_bottom_max = nether.bedrock_bottom_min
|
||||
nether.bedrock_top_min = nether.bedrock_top_max
|
||||
nether.lava_max = nether.min + 2
|
||||
end
|
||||
if superflat then
|
||||
nether.flat_floor = nether.bedrock_bottom_max + 4
|
||||
nether.flat_ceiling = nether.bedrock_bottom_max + 52
|
||||
elseif flat then
|
||||
nether.flat_floor = nether.lava_max + 4
|
||||
nether.flat_ceiling = nether.lava_max + 52
|
||||
end
|
||||
|
||||
-- The End (surface at ca. Y = -27000)
|
||||
end_.min = -27073 -- Carefully chosen to be at a mapchunk border
|
||||
end_.max = overworld.min - 2000
|
||||
end_.platform_pos = { x = 100, y = end_.min + 74, z = 0 }
|
||||
|
||||
-- Realm barrier used to safely separate the End from the void below the Overworld
|
||||
mcl_mapgen.realm_barrier_overworld_end_max = end_.max
|
||||
mcl_mapgen.realm_barrier_overworld_end_min = end_.max - 11
|
||||
|
||||
-- Use MineClone 2-style dungeons for normal mapgen
|
||||
mcl_mapgen.dungeons = normal
|
||||
|
||||
mcl_mapgen.overworld = overworld
|
||||
mcl_mapgen.end_ = end_
|
||||
mcl_mapgen["end"] = mcl_mapgen.end_
|
||||
mcl_mapgen.nether = nether
|
||||
|
||||
mcl_mapgen.order = order
|
||||
|
||||
function mcl_mapgen.get_voxel_manip(vm_context)
|
||||
if vm_context.vm then
|
||||
return vm
|
||||
end
|
||||
vm_context.vm = minetest.get_voxel_manip(vm_context.emin, vm_context.emax)
|
||||
vm_context.emin, vm_context.emax = vm_context.vm:read_from_map(vm_context.emin, vm_context.emax)
|
||||
vm_context.area = VoxelArea:new({MinEdge=vm_context.emin, MaxEdge=vm_context.emax})
|
||||
return vm_context.vm
|
||||
end
|
||||
|
||||
function mcl_mapgen.clamp_to_chunk(x, size)
|
||||
if not size then
|
||||
minetest.log("warning", "[mcl_mapgen] Couldn't clamp " .. tostring(x) .. " - missing size")
|
||||
return x
|
||||
end
|
||||
if size > CS_NODES then
|
||||
minetest.log("warning", "[mcl_mapgen] Couldn't clamp " .. tostring(x) .. " - given size " .. tostring(size) .. " greater than chunk size " .. tostring(mcl_mapgen.CS_NODES))
|
||||
return x
|
||||
end
|
||||
local offset_in_chunk = (x + central_chunk_min_pos) % CS_NODES
|
||||
local x2_in_chunk = offset_in_chunk + size
|
||||
if x2_in_chunk <= CS_NODES then
|
||||
return x
|
||||
end
|
||||
local overflow = x2_in_chunk - CS_NODES
|
||||
if overflow > size / 2 then
|
||||
local next_x = x + (size - overflow)
|
||||
if next_x < mcl_mapgen.EDGE_MAX then
|
||||
return next_x
|
||||
end
|
||||
end
|
||||
return x - overflow
|
||||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_beginning(x)
|
||||
if tonumber(x) then
|
||||
return x - ((x + central_chunk_min_pos) % CS_NODES)
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x),
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y),
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_mapgen.get_chunk_ending(x)
|
||||
if tonumber(x) then
|
||||
return mcl_mapgen.get_chunk_beginning(x) + LAST_NODE_IN_CHUNK
|
||||
end
|
||||
if x.x then
|
||||
return {
|
||||
x = mcl_mapgen.get_chunk_beginning(x.x) + LAST_NODE_IN_CHUNK,
|
||||
y = mcl_mapgen.get_chunk_beginning(x.y) + LAST_NODE_IN_CHUNK,
|
||||
z = mcl_mapgen.get_chunk_beginning(x.z) + LAST_NODE_IN_CHUNK
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
mcl_mapgen.get_block_seed = get_block_seed
|
||||
mcl_mapgen.get_block_seed2 = get_block_seed2
|
||||
mcl_mapgen.get_block_seed3 = get_block_seed3
|
|
@ -1,4 +0,0 @@
|
|||
name = mcl_mapgen
|
||||
author = kay27
|
||||
description = MineClone 2/5 MapGen Basic Stuff
|
||||
depends = mcl_init
|
|
@ -1,362 +0,0 @@
|
|||
--[[
|
||||
Vector helpers
|
||||
Note: The vector.*-functions must be able to accept old vectors that had no metatables
|
||||
]]
|
||||
|
||||
-- localize functions
|
||||
local setmetatable = setmetatable
|
||||
|
||||
vector = {}
|
||||
|
||||
local metatable = {}
|
||||
vector.metatable = metatable
|
||||
|
||||
local xyz = {"x", "y", "z"}
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__index(v, key)
|
||||
return rawget(v, xyz[key]) or vector[key]
|
||||
end
|
||||
|
||||
-- only called when rawget(v, key) returns nil
|
||||
function metatable.__newindex(v, key, value)
|
||||
rawset(v, xyz[key] or key, value)
|
||||
end
|
||||
|
||||
-- constructors
|
||||
|
||||
local function fast_new(x, y, z)
|
||||
return setmetatable({x = x, y = y, z = z}, metatable)
|
||||
end
|
||||
|
||||
function vector.new(a, b, c)
|
||||
if a and b and c then
|
||||
return fast_new(a, b, c)
|
||||
end
|
||||
|
||||
-- deprecated, use vector.copy and vector.zero directly
|
||||
if type(a) == "table" then
|
||||
return vector.copy(a)
|
||||
else
|
||||
assert(not a, "Invalid arguments for vector.new()")
|
||||
return vector.zero()
|
||||
end
|
||||
end
|
||||
|
||||
function vector.zero()
|
||||
return fast_new(0, 0, 0)
|
||||
end
|
||||
|
||||
function vector.copy(v)
|
||||
assert(v.x and v.y and v.z, "Invalid vector passed to vector.copy()")
|
||||
return fast_new(v.x, v.y, v.z)
|
||||
end
|
||||
|
||||
function vector.from_string(s, init)
|
||||
local x, y, z, np = string.match(s, "^%s*%(%s*([^%s,]+)%s*[,%s]%s*([^%s,]+)%s*[,%s]" ..
|
||||
"%s*([^%s,]+)%s*[,%s]?%s*%)()", init)
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
z = tonumber(z)
|
||||
if not (x and y and z) then
|
||||
return nil
|
||||
end
|
||||
return fast_new(x, y, z), np
|
||||
end
|
||||
|
||||
function vector.to_string(v)
|
||||
return string.format("(%g, %g, %g)", v.x, v.y, v.z)
|
||||
end
|
||||
metatable.__tostring = vector.to_string
|
||||
|
||||
function vector.equals(a, b)
|
||||
return a.x == b.x and
|
||||
a.y == b.y and
|
||||
a.z == b.z
|
||||
end
|
||||
metatable.__eq = vector.equals
|
||||
|
||||
-- unary operations
|
||||
|
||||
function vector.length(v)
|
||||
return math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
|
||||
end
|
||||
-- Note: we can not use __len because it is already used for primitive table length
|
||||
|
||||
function vector.normalize(v)
|
||||
local len = vector.length(v)
|
||||
if len == 0 then
|
||||
return fast_new(0, 0, 0)
|
||||
else
|
||||
return vector.divide(v, len)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.floor(v)
|
||||
return vector.apply(v, math.floor)
|
||||
end
|
||||
|
||||
function vector.round(v)
|
||||
return fast_new(
|
||||
math.round(v.x),
|
||||
math.round(v.y),
|
||||
math.round(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.apply(v, func)
|
||||
return fast_new(
|
||||
func(v.x),
|
||||
func(v.y),
|
||||
func(v.z)
|
||||
)
|
||||
end
|
||||
|
||||
function vector.distance(a, b)
|
||||
local x = a.x - b.x
|
||||
local y = a.y - b.y
|
||||
local z = a.z - b.z
|
||||
return math.sqrt(x * x + y * y + z * z)
|
||||
end
|
||||
|
||||
function vector.direction(pos1, pos2)
|
||||
return vector.subtract(pos2, pos1):normalize()
|
||||
end
|
||||
|
||||
function vector.angle(a, b)
|
||||
local dotp = vector.dot(a, b)
|
||||
local cp = vector.cross(a, b)
|
||||
local crossplen = vector.length(cp)
|
||||
return math.atan2(crossplen, dotp)
|
||||
end
|
||||
|
||||
function vector.dot(a, b)
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||
end
|
||||
|
||||
function vector.cross(a, b)
|
||||
return fast_new(
|
||||
a.y * b.z - a.z * b.y,
|
||||
a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x
|
||||
)
|
||||
end
|
||||
|
||||
function metatable.__unm(v)
|
||||
return fast_new(-v.x, -v.y, -v.z)
|
||||
end
|
||||
|
||||
-- add, sub, mul, div operations
|
||||
|
||||
function vector.add(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x + b,
|
||||
a.y + b,
|
||||
a.z + b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__add(a, b)
|
||||
return fast_new(
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.subtract(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x - b,
|
||||
a.y - b,
|
||||
a.z - b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__sub(a, b)
|
||||
return fast_new(
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.multiply(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x * b.x,
|
||||
a.y * b.y,
|
||||
a.z * b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__mul(a, b)
|
||||
if type(a) == "table" then
|
||||
return fast_new(
|
||||
a.x * b,
|
||||
a.y * b,
|
||||
a.z * b
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a * b.x,
|
||||
a * b.y,
|
||||
a * b.z
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.divide(a, b)
|
||||
if type(b) == "table" then
|
||||
return fast_new(
|
||||
a.x / b.x,
|
||||
a.y / b.y,
|
||||
a.z / b.z
|
||||
)
|
||||
else
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
end
|
||||
function metatable.__div(a, b)
|
||||
-- scalar/vector makes no sense
|
||||
return fast_new(
|
||||
a.x / b,
|
||||
a.y / b,
|
||||
a.z / b
|
||||
)
|
||||
end
|
||||
|
||||
-- misc stuff
|
||||
|
||||
function vector.offset(v, x, y, z)
|
||||
return fast_new(
|
||||
v.x + x,
|
||||
v.y + y,
|
||||
v.z + z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.sort(a, b)
|
||||
return fast_new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z)),
|
||||
fast_new(math.max(a.x, b.x), math.max(a.y, b.y), math.max(a.z, b.z))
|
||||
end
|
||||
|
||||
function vector.check(v)
|
||||
return getmetatable(v) == metatable
|
||||
end
|
||||
|
||||
local function sin(x)
|
||||
if x % math.pi == 0 then
|
||||
return 0
|
||||
else
|
||||
return math.sin(x)
|
||||
end
|
||||
end
|
||||
|
||||
local function cos(x)
|
||||
if x % math.pi == math.pi / 2 then
|
||||
return 0
|
||||
else
|
||||
return math.cos(x)
|
||||
end
|
||||
end
|
||||
|
||||
function vector.rotate_around_axis(v, axis, angle)
|
||||
local cosangle = cos(angle)
|
||||
local sinangle = sin(angle)
|
||||
axis = vector.normalize(axis)
|
||||
-- https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
|
||||
local dot_axis = vector.multiply(axis, vector.dot(axis, v))
|
||||
local cross = vector.cross(v, axis)
|
||||
return vector.new(
|
||||
cross.x * sinangle + (v.x - dot_axis.x) * cosangle + dot_axis.x,
|
||||
cross.y * sinangle + (v.y - dot_axis.y) * cosangle + dot_axis.y,
|
||||
cross.z * sinangle + (v.z - dot_axis.z) * cosangle + dot_axis.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.rotate(v, rot)
|
||||
local sinpitch = sin(-rot.x)
|
||||
local sinyaw = sin(-rot.y)
|
||||
local sinroll = sin(-rot.z)
|
||||
local cospitch = cos(rot.x)
|
||||
local cosyaw = cos(rot.y)
|
||||
local cosroll = math.cos(rot.z)
|
||||
-- Rotation matrix that applies yaw, pitch and roll
|
||||
local matrix = {
|
||||
{
|
||||
sinyaw * sinpitch * sinroll + cosyaw * cosroll,
|
||||
sinyaw * sinpitch * cosroll - cosyaw * sinroll,
|
||||
sinyaw * cospitch,
|
||||
},
|
||||
{
|
||||
cospitch * sinroll,
|
||||
cospitch * cosroll,
|
||||
-sinpitch,
|
||||
},
|
||||
{
|
||||
cosyaw * sinpitch * sinroll - sinyaw * cosroll,
|
||||
cosyaw * sinpitch * cosroll + sinyaw * sinroll,
|
||||
cosyaw * cospitch,
|
||||
},
|
||||
}
|
||||
-- Compute matrix multiplication: `matrix` * `v`
|
||||
return vector.new(
|
||||
matrix[1][1] * v.x + matrix[1][2] * v.y + matrix[1][3] * v.z,
|
||||
matrix[2][1] * v.x + matrix[2][2] * v.y + matrix[2][3] * v.z,
|
||||
matrix[3][1] * v.x + matrix[3][2] * v.y + matrix[3][3] * v.z
|
||||
)
|
||||
end
|
||||
|
||||
function vector.dir_to_rotation(forward, up)
|
||||
forward = vector.normalize(forward)
|
||||
local rot = vector.new(math.asin(forward.y), -math.atan2(forward.x, forward.z), 0)
|
||||
if not up then
|
||||
return rot
|
||||
end
|
||||
assert(vector.dot(forward, up) < 0.000001,
|
||||
"Invalid vectors passed to vector.dir_to_rotation().")
|
||||
up = vector.normalize(up)
|
||||
-- Calculate vector pointing up with roll = 0, just based on forward vector.
|
||||
local forwup = vector.rotate(vector.new(0, 1, 0), rot)
|
||||
-- 'forwup' and 'up' are now in a plane with 'forward' as normal.
|
||||
-- The angle between them is the absolute of the roll value we're looking for.
|
||||
rot.z = vector.angle(forwup, up)
|
||||
|
||||
-- Since vector.angle never returns a negative value or a value greater
|
||||
-- than math.pi, rot.z has to be inverted sometimes.
|
||||
-- To determine wether this is the case, we rotate the up vector back around
|
||||
-- the forward vector and check if it worked out.
|
||||
local back = vector.rotate_around_axis(up, forward, -rot.z)
|
||||
|
||||
-- We don't use vector.equals for this because of floating point imprecision.
|
||||
if (back.x - forwup.x) * (back.x - forwup.x) +
|
||||
(back.y - forwup.y) * (back.y - forwup.y) +
|
||||
(back.z - forwup.z) * (back.z - forwup.z) > 0.0000001 then
|
||||
rot.z = -rot.z
|
||||
end
|
||||
return rot
|
||||
end
|
|
@ -1,107 +0,0 @@
|
|||
# mcl_time v2.2
|
||||
## by kay27 for MineClone 5
|
||||
---------------------------
|
||||
This mod counts time when all players sleep or some area is inactive.
|
||||
|
||||
It depends very much on `time_speed` configuration variable, which could be changed 'on the fly' by a chat command:
|
||||
* `/set time_speed 72`
|
||||
|
||||
If `time_speed` set to 0, this mod logs warnings and returns zeroes.
|
||||
|
||||
### mcl_time.get_seconds_irl()
|
||||
------------------------------
|
||||
Returns: Integer value of realtime (not in-game) seconds since world creation.
|
||||
|
||||
Usually this value grow smoothly. But when you skip the night being in the bed, or leave some area for some time, you may experience value jumps. That's basically the idea of this mod.
|
||||
|
||||
### mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
-------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen if the area was active and we didn't skip the nights.
|
||||
|
||||
Arguments:
|
||||
* `last_time` - you pass last known for you value of `seconds_irl`
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would probably happen if the area was active all the time and we didn't skip the nights.
|
||||
* Integer value of in-real-life (not in-game) seconds since world creation.
|
||||
|
||||
### mcl_time.touch(pos)
|
||||
-----------------------
|
||||
This function 'toches' node at position `pos` by writing `_t` meta variable of `seconds_irl`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
--------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `0`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
-------------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `1`.
|
||||
|
||||
### mcl_time.get_number_of_times_at_pos_or_nil(pos, interval, chance)
|
||||
---------------------------------------------------------------------
|
||||
Returns the number of how many times something would probably happen for node at pos `pos` if the area was active and we didn't skip the nights.
|
||||
It reads and updates meta variable `_t` from position `pos` and uses it as previous `seconds_irl`, so we don't need to remember it.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
* `interval` and `chance` - interval and chance like from ABM setup
|
||||
|
||||
Returns:
|
||||
* Integer number of how many times something would happen to the node at position `pos` if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `nil`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos(pos)
|
||||
-----------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `0`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
|
||||
----------------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `1`.
|
||||
|
||||
### mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
|
||||
----------------------------------------------------
|
||||
Returns the number of how many in-real-life seconds would be passed for the node at position `pos`, if the area was active all the time and we didn't skip the nights.
|
||||
It uses node meta variable `_t` to calculate this value.
|
||||
|
||||
Argunments:
|
||||
* `pos` - node position
|
||||
|
||||
Returns:
|
||||
* Integer number of how many in-real-life seconds would be passed for the node at position `pos, if the area was active all the time and we didn't skip the nights.
|
||||
* For unclear conditions, like missing meta or zero `time_speed`, this function will return `nil`.
|
||||
|
|
@ -1,163 +0,0 @@
|
|||
mcl_time = {}
|
||||
|
||||
local time_update_interval = 2
|
||||
local retry_on_fail_interval = 500
|
||||
local default_time_speed = 72
|
||||
local save_to_storage_interval = 600
|
||||
local meta_name = "_t"
|
||||
|
||||
local current_time_update_interval = time_update_interval
|
||||
|
||||
local storage = minetest.get_mod_storage()
|
||||
local seconds_irl_public = tonumber(storage:get_string("seconds_irl")) or -2
|
||||
local last_save_seconds_irl = seconds_irl_public
|
||||
local next_save_seconds_irl = last_save_seconds_irl + save_to_storage_interval
|
||||
|
||||
local previous_seconds_irl = -2
|
||||
local time_speed_is_ok = true
|
||||
|
||||
local function get_seconds_irl()
|
||||
local time_speed = tonumber(minetest.settings:get("time_speed") or default_time_speed)
|
||||
if time_speed < 1 then
|
||||
if time_speed_is_ok then
|
||||
minetest.log("warning", "[mcl_time] time_speed < 1 - please increase to make mcl_time api work (default: " .. default_time_speed .. ")")
|
||||
time_speed_is_ok = false
|
||||
end
|
||||
return 0
|
||||
else
|
||||
if not time_speed_is_ok then
|
||||
minetest.log("warning", "[mcl_time] time_speed is now " .. time_speed)
|
||||
time_speed_is_ok = true
|
||||
end
|
||||
end
|
||||
local irl_multiplier = 86400 / time_speed
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
local seconds_irl
|
||||
if not day_count or not timeofday then
|
||||
seconds_irl = seconds_irl_public
|
||||
else
|
||||
local days_ig = 0.0 + day_count + timeofday
|
||||
seconds_irl = days_ig * irl_multiplier
|
||||
end
|
||||
|
||||
if previous_seconds_irl == seconds_irl then
|
||||
current_time_update_interval = math.min(current_time_update_interval * 2, retry_on_fail_interval)
|
||||
minetest.log("warning", "[mcl_time] Time doesn't change! seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. " - increasing update interval to " .. tostring(current_time_update_interval))
|
||||
else
|
||||
previous_seconds_irl = seconds_irl
|
||||
if current_time_update_interval ~= time_update_interval then
|
||||
current_time_update_interval = time_update_interval
|
||||
minetest.log("action", "[mcl_time] Time is changing again: seconds_irl=" .. tostring(seconds_irl)
|
||||
.. ", day_count = " .. tostring(day_count) .. ", timeofday=" .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval))
|
||||
end
|
||||
end
|
||||
|
||||
if last_save_seconds_irl >= next_save_seconds_irl then
|
||||
storage:set_string("seconds_irl", tostring(seconds_irl))
|
||||
next_save_seconds_irl = seconds_irl + save_to_storage_interval
|
||||
end
|
||||
|
||||
return math.floor(seconds_irl)
|
||||
end
|
||||
|
||||
seconds_irl_public = get_seconds_irl()
|
||||
|
||||
function mcl_time.get_seconds_irl()
|
||||
return seconds_irl_public
|
||||
end
|
||||
|
||||
local function time_runner()
|
||||
seconds_irl_public = get_seconds_irl()
|
||||
minetest.after(current_time_update_interval, time_runner)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times(last_time, interval, chance)
|
||||
if not last_time then return 0, seconds_irl_publicend end
|
||||
if seconds_irl_public < 2 then return 0, seconds_irl_public end
|
||||
if not interval then return 0, seconds_irl_public end
|
||||
if not chance then return 0, seconds_irl_public end
|
||||
if interval < 1 then return 0, seconds_irl_public end
|
||||
if chance < 1 then return 0, seconds_irl_public end
|
||||
local number_of_intervals = (seconds_irl_public - last_time) / interval
|
||||
if number_of_intervals < 1 then return 0, seconds_irl_public end
|
||||
local average_chance = (1 + chance) / 2
|
||||
local number_of_times = math.floor(number_of_intervals / average_chance)
|
||||
return number_of_times, seconds_irl_public
|
||||
end
|
||||
|
||||
local get_number_of_times = mcl_time.get_number_of_times
|
||||
|
||||
function mcl_time.touch(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos(pos, interval, chance)
|
||||
if not pos then return 0 end
|
||||
if not time_speed_is_ok then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local number_of_times = (last_time <= 0) and 0 or get_number_of_times(last_time, interval, chance)
|
||||
return number_of_times
|
||||
end
|
||||
|
||||
local get_number_of_times_at_pos = mcl_time.get_number_of_times_at_pos
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos_or_1(pos, interval, chance)
|
||||
return math.max(get_number_of_times_at_pos(pos, interval, chance), 1)
|
||||
end
|
||||
|
||||
function mcl_time.get_number_of_times_at_pos_or_nil(pos, interval, chance)
|
||||
local number_of_times_at_pos = get_number_of_times_at_pos(pos, interval, chance)
|
||||
if number_of_times_at_pos > 0 then
|
||||
return number_of_times_at_pos
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos(pos)
|
||||
if not pos then return 0 end
|
||||
if not time_speed_is_ok then return 0 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local irl_seconds_passed = (last_time <= 0) and 0 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_1(pos)
|
||||
if not pos then return 1 end
|
||||
if not time_speed_is_ok then return 1 end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
local irl_seconds_passed = (last_time <= 0) and 1 or (seconds_irl_public - last_time)
|
||||
return irl_seconds_passed
|
||||
end
|
||||
|
||||
function mcl_time.get_irl_seconds_passed_at_pos_or_nil(pos)
|
||||
if not pos then return end
|
||||
if not time_speed_is_ok then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local last_time = meta:get_int(meta_name)
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
if last_time <= 0 then return end
|
||||
local delta_time = seconds_irl_public - last_time
|
||||
if delta_time <= 0 then return end
|
||||
meta:set_int(meta_name, seconds_irl_public)
|
||||
return delta_time
|
||||
end
|
||||
|
||||
time_runner()
|
||||
local day_count = minetest.get_day_count()
|
||||
local timeofday = minetest.get_timeofday()
|
||||
minetest.log("action", "[mcl_time] time runner started, current in-real-life seconds: " .. seconds_irl_public
|
||||
.. ", time_speed: " .. tostring(minetest.settings:get("time_speed"))
|
||||
.. ", day_count: " .. tostring(day_count)
|
||||
.. ", timeofday: " .. tostring(timeofday)
|
||||
.. ", update_interval=" .. tostring(current_time_update_interval)
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_time
|
||||
author = kay27
|
||||
description = This mod counts time when all players sleep or some area is inactive
|
|
@ -5,25 +5,25 @@ local get_connected_players = minetest.get_connected_players
|
|||
-- For a given position, returns a 2-tuple:
|
||||
-- 1st return value: true if pos is in void
|
||||
-- 2nd return value: true if it is in the deadly part of the void
|
||||
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
||||
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max+128
|
||||
function mcl_worlds.is_in_void(pos)
|
||||
local y = pos.y
|
||||
local void = not ((y < max1 and y > min1) or (y < max2 and y > min2) or (y < max3 and y > min3))
|
||||
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_end_max and pos.y > mcl_vars.mg_end_min))
|
||||
|
||||
local void_deadly = false
|
||||
local deadly_tolerance = 64 -- the player must be this many nodes “deep” into the void to be damaged
|
||||
if void then
|
||||
-- Overworld → Void → End → Void → Nether → Void
|
||||
if y < min1 and y > max2 then
|
||||
void_deadly = y < min1 - deadly_tolerance
|
||||
elseif y < min2 and y > max3 then
|
||||
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
|
||||
-- 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 = (y < min2 - deadly_tolerance) and (y > max3 + deadly_tolerance)
|
||||
elseif y < min3 then
|
||||
void_deadly = y < min3 - deadly_tolerance
|
||||
void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance)
|
||||
elseif pos.y < mcl_vars.mg_nether_min then
|
||||
void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance
|
||||
end
|
||||
end
|
||||
return void, void_deadly
|
||||
|
@ -35,12 +35,12 @@ end
|
|||
-- If the Y coordinate is not located in any dimension, it will return:
|
||||
-- nil, "void"
|
||||
function mcl_worlds.y_to_layer(y)
|
||||
if y >= min1 then
|
||||
return y - min1, "overworld"
|
||||
elseif y >= min3 and y <= max3 then
|
||||
return y - min3, "nether"
|
||||
elseif y >= min2 and y <= max2 then
|
||||
return y - min2, "end"
|
||||
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
|
||||
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"
|
||||
else
|
||||
return nil, "void"
|
||||
end
|
||||
|
@ -61,25 +61,25 @@ local pos_to_dimension = mcl_worlds.pos_to_dimension
|
|||
-- MineClone 2.
|
||||
-- mc_dimension is one of "overworld", "nether", "end" (default: "overworld").
|
||||
function mcl_worlds.layer_to_y(layer, mc_dimension)
|
||||
if not mc_dimension or mc_dimension == "overworld" then
|
||||
return layer + min1
|
||||
if mc_dimension == "overworld" or mc_dimension == nil then
|
||||
return layer + mcl_vars.mg_overworld_min
|
||||
elseif mc_dimension == "nether" then
|
||||
return layer + min3
|
||||
return layer + mcl_vars.mg_nether_min
|
||||
elseif mc_dimension == "end" then
|
||||
return layer + min2
|
||||
return layer + mcl_vars.mg_end_min
|
||||
end
|
||||
end
|
||||
|
||||
-- Takes a position and returns true if this position can have weather
|
||||
function mcl_worlds.has_weather(pos)
|
||||
-- Weather in the Overworld and the high part of the void below
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
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 <= max3 + 138 and pos.y >= min3 - 10
|
||||
return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10
|
||||
end
|
||||
|
||||
-- Takes a position (pos) and returns true if compasses are working here
|
||||
|
@ -89,7 +89,7 @@ function mcl_worlds.compass_works(pos)
|
|||
if dim == "nether" or dim == "end" then
|
||||
return false
|
||||
elseif dim == "void" then
|
||||
return pos.y <= max1 and pos.y >= min1 - 64
|
||||
return pos.y <= mcl_vars.mg_overworld_max and pos.y >= mcl_vars.mg_overworld_min - 64
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
@ -152,3 +152,23 @@ minetest.register_globalstep(function(dtime)
|
|||
dimtimer = 0
|
||||
end
|
||||
end)
|
||||
|
||||
function mcl_worlds.get_cloud_parameters()
|
||||
if minetest.get_mapgen_setting("mg_name") == "valleys" then
|
||||
return {
|
||||
height = 384, --valleys has a much higher average elevation thus often "normal" landscape ends up in the clouds
|
||||
speed = {x=-2, z=0},
|
||||
thickness=5,
|
||||
color="#FFF0FEF",
|
||||
ambient = "#201060",
|
||||
}
|
||||
else
|
||||
-- MC-style clouds: Layer 127, thickness 4, fly to the “West”
|
||||
return {
|
||||
height = mcl_worlds.layer_to_y(127),
|
||||
speed = {x=-2, z=0},
|
||||
thickness = 4,
|
||||
color = "#FFF0FEF",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
name = mcl_worlds
|
||||
author = Wuzzy
|
||||
description = Utility functions for worlds and the “dimensions”.
|
||||
depends = mcl_mapgen
|
||||
depends = mcl_init
|
||||
|
||||
|
|
|
@ -131,17 +131,6 @@ function mcl_burning.set_on_fire(obj, burn_time)
|
|||
if obj:is_player() then
|
||||
mcl_burning.update_hud(obj)
|
||||
end
|
||||
|
||||
-- FIXME: does this code make sense? It removes attached fire luaentities from
|
||||
-- another object that happen to be at the same position.
|
||||
local fire_luaentity = fire_entity:get_luaentity()
|
||||
for _, other in pairs(minetest.get_objects_inside_radius(fire_entity:get_pos(), 0)) do
|
||||
local other_luaentity = other:get_luaentity()
|
||||
if other_luaentity and other_luaentity.name == "mcl_burning:fire" and other_luaentity ~= fire_luaentity then
|
||||
other:remove()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_burning.extinguish(obj)
|
||||
|
|
|
@ -57,7 +57,7 @@ minetest.register_on_joinplayer(function(player)
|
|||
local storage = {}
|
||||
local burn_data = player:get_meta():get_string("mcl_burning:data")
|
||||
if burn_data ~= "" then
|
||||
storage = minetest.deserialize(burn_data)
|
||||
storage = minetest.deserialize(burn_data) or storage
|
||||
end
|
||||
mcl_burning.storage[player] = storage
|
||||
if storage.burn_time and storage.burn_time > 0 then
|
||||
|
@ -67,6 +67,13 @@ end)
|
|||
|
||||
local function on_leaveplayer(player)
|
||||
local storage = mcl_burning.storage[player]
|
||||
if not storage then
|
||||
-- For some unexplained reasons, mcl_burning.storage can be `nil` here.
|
||||
-- Logging this exception to assist in finding the cause of this.
|
||||
minetest.log("warning", "on_leaveplayer: missing mcl_burning.storage "
|
||||
.. "for player " .. player:get_player_name())
|
||||
storage = {}
|
||||
end
|
||||
storage.fire_hud_id = nil
|
||||
player:get_meta():set_string("mcl_burning:data", minetest.serialize(storage))
|
||||
mcl_burning.storage[player] = nil
|
||||
|
@ -98,8 +105,7 @@ minetest.register_entity("mcl_burning:fire", {
|
|||
glow = -1,
|
||||
backface_culling = false,
|
||||
},
|
||||
animation_frame = 0,
|
||||
animation_timer = 0,
|
||||
_mcl_animation_timer = 0,
|
||||
on_activate = function(self)
|
||||
self.object:set_sprite({x = 0, y = 0}, animation_frames, 1.0 / animation_frames)
|
||||
end,
|
||||
|
@ -115,9 +121,9 @@ minetest.register_entity("mcl_burning:fire", {
|
|||
return
|
||||
end
|
||||
if parent:is_player() then
|
||||
self.animation_timer = self.animation_timer + dtime
|
||||
if self.animation_timer >= 0.1 then
|
||||
self.animation_timer = 0
|
||||
self._mcl_animation_timer = self._mcl_animation_timer + dtime
|
||||
if self._mcl_animation_timer >= 0.1 then
|
||||
self._mcl_animation_timer = 0
|
||||
mcl_burning.update_hud(parent)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -418,7 +418,11 @@ minetest.register_entity(":__builtin:item", {
|
|||
end
|
||||
local stack = ItemStack(itemstring)
|
||||
if minetest.get_item_group(stack:get_name(), "compass") > 0 then
|
||||
stack:set_name("mcl_compass:16")
|
||||
if string.find(stack:get_name(), "_lodestone") then
|
||||
stack:set_name("mcl_compass:18_lodestone")
|
||||
else
|
||||
stack:set_name("mcl_compass:18")
|
||||
end
|
||||
itemstring = stack:to_string()
|
||||
self.itemstring = itemstring
|
||||
end
|
||||
|
|
|
@ -222,8 +222,8 @@ local collision = function(self)
|
|||
|
||||
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
|
||||
|
||||
if object:is_player()
|
||||
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
|
||||
local ent = object:get_luaentity()
|
||||
if object:is_player() or (ent and ent._cmi_is_mob and object ~= self.object) then
|
||||
|
||||
local pos2 = object:get_pos()
|
||||
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
|
||||
|
@ -2833,6 +2833,10 @@ local do_states = function(self, dtime)
|
|||
end
|
||||
ent.switch = 1
|
||||
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
|
||||
|
||||
-- important for mcl_shields
|
||||
ent._shooter = self.object
|
||||
ent._saved_shooter_pos = self.object:get_pos()
|
||||
end
|
||||
|
||||
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
|
||||
|
@ -4078,7 +4082,6 @@ end
|
|||
|
||||
-- make explosion with protection and tnt mod check
|
||||
function mobs:boom(self, pos, strength, fire)
|
||||
self.object:remove()
|
||||
if mod_explosions then
|
||||
if mobs_griefing and not minetest.is_protected(pos, "") then
|
||||
mcl_explosions.explode(pos, strength, { drop_chance = 1.0, fire = fire }, self.object)
|
||||
|
@ -4088,6 +4091,9 @@ function mobs:boom(self, pos, strength, fire)
|
|||
else
|
||||
mobs:safe_boom(self, pos, strength)
|
||||
end
|
||||
|
||||
-- delete the object after it punched the player to avoid nil entities in e.g. mcl_shields!!
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = mcl_mobs
|
||||
author = PilzAdam
|
||||
description = Adds a mob API for mods to add animals or monsters, etc.
|
||||
depends = mcl_mapgen, mcl_particles
|
||||
depends = mcl_particles
|
||||
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience
|
||||
|
|
|
@ -3,22 +3,57 @@ local get_node = minetest.get_node
|
|||
local get_item_group = minetest.get_item_group
|
||||
local get_node_light = minetest.get_node_light
|
||||
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
||||
local new_vector = vector.new
|
||||
local math_random = math.random
|
||||
local get_biome_name = minetest.get_biome_name
|
||||
local max = math.max
|
||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||
local vector_distance = vector.distance
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
|
||||
local math_random = math.random
|
||||
local math_floor = math.floor
|
||||
local math_ceil = math.ceil
|
||||
local math_cos = math.cos
|
||||
local math_sin = math.sin
|
||||
local math_round = function(x) return (x > 0) and math_floor(x + 0.5) or math_ceil(x - 0.5) end
|
||||
|
||||
--local vector_distance = vector.distance
|
||||
local vector_new = vector.new
|
||||
local vector_floor = vector.floor
|
||||
|
||||
local table_copy = table.copy
|
||||
local table_remove = table.remove
|
||||
|
||||
local pairs = pairs
|
||||
|
||||
-- range for mob count
|
||||
local aoc_range = 32
|
||||
--[[
|
||||
|
||||
THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
||||
--do mobs spawn?
|
||||
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
|
||||
|
||||
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 3,
|
||||
spread = {
|
||||
x = 301,
|
||||
y = 50,
|
||||
z = 304,
|
||||
},
|
||||
seed = 100,
|
||||
octaves = 3,
|
||||
persistence = 0.5,
|
||||
}
|
||||
|
||||
-- THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
||||
-- Also used for missing parameter
|
||||
-- Please update the list when adding new biomes!
|
||||
|
||||
local list_of_all_biomes = {
|
||||
|
||||
-- underground:
|
||||
|
||||
underground:
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)]
|
||||
"JungleEdge_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
|
@ -29,7 +64,8 @@ underground:
|
|||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
|
||||
ocean:
|
||||
-- ocean:
|
||||
|
||||
"RoofedForest_ocean",
|
||||
"JungleEdgeM_ocean",
|
||||
"BirchForestM_ocean",
|
||||
|
@ -91,13 +127,15 @@ ocean:
|
|||
"Taiga_deep_ocean",
|
||||
"JungleM_ocean",
|
||||
|
||||
water or beach?
|
||||
-- water or beach?
|
||||
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
|
||||
beach:
|
||||
-- beach:
|
||||
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
|
@ -112,11 +150,13 @@ beach:
|
|||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
|
||||
dimension biome:
|
||||
-- dimension biome:
|
||||
|
||||
"Nether",
|
||||
"End",
|
||||
|
||||
Overworld regular:
|
||||
-- Overworld regular:
|
||||
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
|
@ -149,32 +189,16 @@ Overworld regular:
|
|||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
]]--
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
|
||||
-- count how many mobs of one type are inside an area
|
||||
|
||||
local count_mobs = function(pos,mobtype)
|
||||
-- count how many mobs are in an area
|
||||
local function count_mobs(pos)
|
||||
local num = 0
|
||||
local objs = get_objects_inside_radius(pos, aoc_range)
|
||||
for n = 1, #objs do
|
||||
local obj = objs[n]:get_luaentity()
|
||||
if obj and obj.name and obj._cmi_is_mob then
|
||||
-- count hostile mobs only
|
||||
if mobtype == "hostile" then
|
||||
if obj.spawn_class == "hostile" then
|
||||
num = num + 1
|
||||
end
|
||||
-- count passive mobs only
|
||||
else
|
||||
for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do
|
||||
if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then
|
||||
num = num + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return num
|
||||
end
|
||||
|
||||
|
@ -215,11 +239,73 @@ WARNING: BIOME INTEGRATION NEEDED -> How to get biome through lua??
|
|||
|
||||
--this is where all of the spawning information is kept
|
||||
local spawn_dictionary = {}
|
||||
local summary_chance = 0
|
||||
|
||||
function mobs:spawn_setup(def)
|
||||
if not mobs_spawn then return end
|
||||
|
||||
if not def then
|
||||
minetest.log("warning", "Empty mob spawn setup definition")
|
||||
return
|
||||
end
|
||||
|
||||
local name = def.name
|
||||
if not name then
|
||||
minetest.log("warning", "Missing mob name")
|
||||
return
|
||||
end
|
||||
|
||||
local dimension = def.dimension or "overworld"
|
||||
local type_of_spawning = def.type_of_spawning or "ground"
|
||||
local biomes = def.biomes or list_of_all_biomes
|
||||
local min_light = def.min_light or 0
|
||||
local max_light = def.max_light or (minetest.LIGHT_MAX + 1)
|
||||
local chance = def.chance or 1000
|
||||
local aoc = def.aoc or aoc_range
|
||||
local min_height = def.min_height or mcl_mapgen.overworld.min
|
||||
local max_height = def.max_height or mcl_mapgen.overworld.max
|
||||
local day_toggle = def.day_toggle
|
||||
local on_spawn = def.on_spawn
|
||||
local check_position = def.check_position
|
||||
|
||||
-- chance/spawn number override in minetest.conf for registered mob
|
||||
local numbers = minetest.settings:get(name)
|
||||
if numbers then
|
||||
numbers = numbers:split(",")
|
||||
chance = tonumber(numbers[1]) or chance
|
||||
aoc = tonumber(numbers[2]) or aoc
|
||||
if chance == 0 then
|
||||
minetest.log("warning", string.format("[mobs] %s has spawning disabled", name))
|
||||
return
|
||||
end
|
||||
minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
if chance < 1 then
|
||||
chance = 1
|
||||
minetest.log("warning", "Chance shouldn't be less than 1 (mob name: " .. name ..")")
|
||||
end
|
||||
|
||||
spawn_dictionary[#spawn_dictionary + 1] = {
|
||||
name = name,
|
||||
dimension = dimension,
|
||||
type_of_spawning = type_of_spawning,
|
||||
biomes = biomes,
|
||||
min_light = min_light,
|
||||
max_light = max_light,
|
||||
chance = chance,
|
||||
aoc = aoc,
|
||||
min_height = min_height,
|
||||
max_height = max_height,
|
||||
day_toggle = day_toggle,
|
||||
check_position = check_position,
|
||||
on_spawn = on_spawn,
|
||||
}
|
||||
summary_chance = summary_chance + chance
|
||||
end
|
||||
|
||||
function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_light, max_light, interval, chance, aoc, min_height, max_height, day_toggle, on_spawn)
|
||||
|
||||
--print(dump(biomes))
|
||||
|
||||
-- Do mobs spawn at all?
|
||||
if not mobs_spawn then
|
||||
return
|
||||
|
@ -238,180 +324,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
|
|||
return
|
||||
end
|
||||
|
||||
minetest.log("action",
|
||||
string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
--[[
|
||||
local spawn_action
|
||||
spawn_action = function(pos, node, active_object_count, active_object_count_wider, name)
|
||||
|
||||
local orig_pos = table.copy(pos)
|
||||
-- is mob actually registered?
|
||||
if not mobs.spawning_mobs[name]
|
||||
or not minetest.registered_entities[name] then
|
||||
minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!")
|
||||
return
|
||||
end
|
||||
|
||||
-- additional custom checks for spawning mob
|
||||
if mobs:spawn_abm_check(pos, node, name) == true then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!")
|
||||
return
|
||||
end
|
||||
|
||||
-- count nearby mobs in same spawn class
|
||||
local entdef = minetest.registered_entities[name]
|
||||
local spawn_class = entdef and entdef.spawn_class
|
||||
if not spawn_class then
|
||||
if entdef.type == "monster" then
|
||||
spawn_class = "hostile"
|
||||
else
|
||||
spawn_class = "passive"
|
||||
end
|
||||
end
|
||||
local in_class_cap = count_mobs(pos, "!"..spawn_class) < MOB_CAP[spawn_class]
|
||||
-- do not spawn if too many of same mob in area
|
||||
if active_object_count_wider >= max_per_block -- large-range mob cap
|
||||
or (not in_class_cap) -- spawn class mob cap
|
||||
or count_mobs(pos, name) >= aoc then -- per-mob mob cap
|
||||
-- too many entities
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!")
|
||||
return
|
||||
end
|
||||
|
||||
-- if toggle set to nil then ignore day/night check
|
||||
if day_toggle ~= nil then
|
||||
|
||||
local tod = (minetest.get_timeofday() or 0) * 24000
|
||||
|
||||
if tod > 4500 and tod < 19500 then
|
||||
-- daylight, but mob wants night
|
||||
if day_toggle == false then
|
||||
-- mob needs night
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!")
|
||||
return
|
||||
end
|
||||
else
|
||||
-- night time but mob wants day
|
||||
if day_toggle == true then
|
||||
-- mob needs day
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- spawn above node
|
||||
pos.y = pos.y + 1
|
||||
|
||||
-- only spawn away from player
|
||||
local objs = minetest.get_objects_inside_radius(pos, 24)
|
||||
|
||||
for n = 1, #objs do
|
||||
|
||||
if objs[n]:is_player() then
|
||||
-- player too close
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- mobs cannot spawn in protected areas when enabled
|
||||
if not spawn_protected
|
||||
and minetest.is_protected(pos, "") then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!")
|
||||
return
|
||||
end
|
||||
|
||||
-- are we spawning within height limits?
|
||||
if pos.y > max_height
|
||||
or pos.y < min_height then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!")
|
||||
return
|
||||
end
|
||||
|
||||
-- are light levels ok?
|
||||
local light = minetest.get_node_light(pos)
|
||||
if not light
|
||||
or light > max_light
|
||||
or light < min_light then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!")
|
||||
return
|
||||
end
|
||||
|
||||
-- do we have enough space to spawn mob?
|
||||
local ent = minetest.registered_entities[name]
|
||||
local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1]))
|
||||
local min_x, max_x
|
||||
if width_x % 2 == 0 then
|
||||
max_x = math.floor(width_x/2)
|
||||
min_x = -(max_x-1)
|
||||
else
|
||||
max_x = math.floor(width_x/2)
|
||||
min_x = -max_x
|
||||
end
|
||||
|
||||
local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3]))
|
||||
local min_z, max_z
|
||||
if width_z % 2 == 0 then
|
||||
max_z = math.floor(width_z/2)
|
||||
min_z = -(max_z-1)
|
||||
else
|
||||
max_z = math.floor(width_z/2)
|
||||
min_z = -max_z
|
||||
end
|
||||
|
||||
local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1)
|
||||
|
||||
for y = 0, max_y do
|
||||
for x = min_x, max_x do
|
||||
for z = min_z, max_z do
|
||||
local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z}
|
||||
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
|
||||
-- inside block
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!")
|
||||
if ent.spawn_small_alternative ~= nil and (not minetest.registered_nodes[node_ok(pos).name].walkable) then
|
||||
minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative)
|
||||
spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- tweak X/Y/Z spawn pos
|
||||
if width_x % 2 == 0 then
|
||||
pos.x = pos.x + 0.5
|
||||
end
|
||||
if width_z % 2 == 0 then
|
||||
pos.z = pos.z + 0.5
|
||||
end
|
||||
pos.y = pos.y - 0.5
|
||||
|
||||
local mob = minetest.add_entity(pos, name)
|
||||
minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos))
|
||||
|
||||
if on_spawn then
|
||||
|
||||
local ent = mob:get_luaentity()
|
||||
|
||||
on_spawn(ent, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider)
|
||||
spawn_action(pos, node, active_object_count, active_object_count_wider, name)
|
||||
end
|
||||
]]--
|
||||
|
||||
local entdef = minetest.registered_entities[name]
|
||||
local spawn_class
|
||||
if entdef.type == "monster" then
|
||||
spawn_class = "hostile"
|
||||
else
|
||||
spawn_class = "passive"
|
||||
minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
--load information into the spawn dictionary
|
||||
|
@ -423,106 +336,34 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
|
|||
spawn_dictionary[key]["biomes"] = biomes
|
||||
spawn_dictionary[key]["min_light"] = min_light
|
||||
spawn_dictionary[key]["max_light"] = max_light
|
||||
spawn_dictionary[key]["interval"] = interval
|
||||
spawn_dictionary[key]["chance"] = chance
|
||||
spawn_dictionary[key]["aoc"] = aoc
|
||||
spawn_dictionary[key]["min_height"] = min_height
|
||||
spawn_dictionary[key]["max_height"] = max_height
|
||||
spawn_dictionary[key]["day_toggle"] = day_toggle
|
||||
--spawn_dictionary[key]["on_spawn"] = spawn_abm_action
|
||||
spawn_dictionary[key]["spawn_class"] = spawn_class
|
||||
|
||||
--[[
|
||||
minetest.register_abm({
|
||||
label = name .. " spawning",
|
||||
nodenames = nodes,
|
||||
neighbors = neighbors,
|
||||
interval = interval,
|
||||
chance = floor(max(1, chance * mobs_spawn_chance)),
|
||||
catch_up = false,
|
||||
action = spawn_abm_action,
|
||||
})
|
||||
]]--
|
||||
summary_chance = summary_chance + chance
|
||||
end
|
||||
|
||||
-- compatibility with older mob registration
|
||||
-- we're going to forget about this for now -j4i
|
||||
--[[
|
||||
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle)
|
||||
|
||||
mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30,
|
||||
chance, active_object_count, -31000, max_height, day_toggle)
|
||||
end
|
||||
]]--
|
||||
|
||||
|
||||
--Don't disable this yet-j4i
|
||||
-- MarkBu's spawn function
|
||||
|
||||
function mobs:spawn(def)
|
||||
--does nothing for now
|
||||
--[[
|
||||
local name = def.name
|
||||
local nodes = def.nodes or {"group:soil", "group:stone"}
|
||||
local neighbors = def.neighbors or {"air"}
|
||||
local min_light = def.min_light or 0
|
||||
local max_light = def.max_light or 15
|
||||
local interval = def.interval or 30
|
||||
local chance = def.chance or 5000
|
||||
local active_object_count = def.active_object_count or 1
|
||||
local min_height = def.min_height or -31000
|
||||
local max_height = def.max_height or 31000
|
||||
local day_toggle = def.day_toggle
|
||||
local on_spawn = def.on_spawn
|
||||
|
||||
mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval,
|
||||
chance, active_object_count, min_height, max_height, day_toggle, on_spawn)
|
||||
]]--
|
||||
end
|
||||
|
||||
|
||||
|
||||
local axis
|
||||
--inner and outer part of square donut radius
|
||||
local inner = 1
|
||||
local outer = 65
|
||||
local int = {-1,1}
|
||||
local position_calculation = function(pos)
|
||||
|
||||
pos = vector.floor(pos)
|
||||
|
||||
--this is used to determine the axis buffer from the player
|
||||
axis = math.random(0,1)
|
||||
|
||||
--cast towards the direction
|
||||
if axis == 0 then --x
|
||||
pos.x = pos.x + math.random(inner,outer)*int[math.random(1,2)]
|
||||
pos.z = pos.z + math.random(-outer,outer)
|
||||
else --z
|
||||
pos.z = pos.z + math.random(inner,outer)*int[math.random(1,2)]
|
||||
pos.x = pos.x + math.random(-outer,outer)
|
||||
end
|
||||
return(pos)
|
||||
end
|
||||
|
||||
--[[
|
||||
local decypher_limits_dictionary = {
|
||||
["overworld"] = {mcl_vars.mg_overworld_min,mcl_vars.mg_overworld_max},
|
||||
["nether"] = {mcl_vars.mg_nether_min, mcl_vars.mg_nether_max},
|
||||
["end"] = {mcl_vars.mg_end_min, mcl_vars.mg_end_max}
|
||||
local two_pi = 2 * math.pi
|
||||
local function get_next_mob_spawn_pos(pos)
|
||||
local distance = math_random(25, 32)
|
||||
local angle = math_random() * two_pi
|
||||
return {
|
||||
x = math_round(pos.x + distance * math_cos(angle)),
|
||||
y = pos.y,
|
||||
z = math_round(pos.z + distance * math_sin(angle))
|
||||
}
|
||||
]]--
|
||||
end
|
||||
|
||||
local function decypher_limits(posy)
|
||||
--local min_max_table = decypher_limits_dictionary[dimension]
|
||||
--return min_max_table[1],min_max_table[2]
|
||||
posy = math.floor(posy)
|
||||
posy = math_floor(posy)
|
||||
return posy - 32, posy + 32
|
||||
end
|
||||
|
||||
--a simple helper function for mob_spawn
|
||||
local function biome_check(biome_list, biome_goal)
|
||||
for _,data in ipairs(biome_list) do
|
||||
for _, data in pairs(biome_list) do
|
||||
if data == biome_goal then
|
||||
return true
|
||||
end
|
||||
|
@ -531,115 +372,111 @@ local function biome_check(biome_list, biome_goal)
|
|||
return false
|
||||
end
|
||||
|
||||
|
||||
--todo mob limiting
|
||||
--MAIN LOOP
|
||||
local function is_farm_animal(n)
|
||||
return n == "mobs_mc:pig" or n == "mobs_mc:cow" or n == "mobs_mc:sheep" or n == "mobs_mc:chicken" or n == "mobs_mc:horse" or n == "mobs_mc:donkey"
|
||||
end
|
||||
|
||||
if mobs_spawn then
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer >= 8 then
|
||||
timer = 0
|
||||
for _,player in pairs(minetest.get_connected_players()) do
|
||||
for i = 1,math_random(3,8) do
|
||||
repeat -- after this line each "break" means "continue"
|
||||
local player_pos = player:get_pos()
|
||||
|
||||
local _,dimension = mcl_worlds.y_to_layer(player_pos.y)
|
||||
|
||||
if dimension == "void" or dimension == "default" then
|
||||
break -- ignore void and unloaded area
|
||||
end
|
||||
|
||||
local min,max = decypher_limits(player_pos.y)
|
||||
|
||||
local goal_pos = position_calculation(player_pos)
|
||||
|
||||
local spawning_position_list = find_nodes_in_area_under_air(new_vector(goal_pos.x,min,goal_pos.z), vector.new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"})
|
||||
|
||||
--couldn't find node
|
||||
if #spawning_position_list <= 0 then
|
||||
break
|
||||
end
|
||||
local perlin_noise
|
||||
|
||||
local function spawn_a_mob(pos, dimension, y_min, y_max)
|
||||
local dimension = dimension or mcl_worlds.pos_to_dimension(pos)
|
||||
local goal_pos = get_next_mob_spawn_pos(pos)
|
||||
local spawning_position_list = find_nodes_in_area_under_air(
|
||||
{x = goal_pos.x, y = y_min, z = goal_pos.z},
|
||||
{x = goal_pos.x, y = y_max, z = goal_pos.z},
|
||||
{"group:solid", "group:water", "group:lava"}
|
||||
)
|
||||
if #spawning_position_list <= 0 then return end
|
||||
local spawning_position = spawning_position_list[math_random(1, #spawning_position_list)]
|
||||
|
||||
--Prevent strange behavior/too close to player
|
||||
if not spawning_position or vector_distance(player_pos, spawning_position) < 15 then
|
||||
break
|
||||
end
|
||||
--hard code mob limit in area to 5 for now
|
||||
if count_mobs(spawning_position) >= 5 then return end
|
||||
|
||||
local gotten_node = get_node(spawning_position).name
|
||||
|
||||
if not gotten_node or gotten_node == "air" then --skip air nodes
|
||||
break
|
||||
end
|
||||
|
||||
local gotten_biome = minetest.get_biome_data(spawning_position)
|
||||
|
||||
if not gotten_biome then
|
||||
break --skip if in unloaded area
|
||||
end
|
||||
|
||||
if not gotten_node or not gotten_biome then return end
|
||||
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
|
||||
|
||||
--grab random mob
|
||||
local mob_def = spawn_dictionary[math.random(1,#spawn_dictionary)]
|
||||
|
||||
if not mob_def then
|
||||
break --skip if something ridiculous happens (nil mob def)
|
||||
end
|
||||
|
||||
--skip if not correct dimension
|
||||
if mob_def.dimension ~= dimension then
|
||||
break
|
||||
end
|
||||
|
||||
--skip if not in correct biome
|
||||
if not biome_check(mob_def.biomes, gotten_biome) then
|
||||
break
|
||||
end
|
||||
|
||||
--add this so mobs don't spawn inside nodes
|
||||
spawning_position.y = spawning_position.y + 1
|
||||
|
||||
if spawning_position.y < mob_def.min_height or spawning_position.y > mob_def.max_height then
|
||||
break
|
||||
end
|
||||
|
||||
--only need to poll for node light if everything else worked
|
||||
local gotten_light = get_node_light(spawning_position)
|
||||
|
||||
--don't spawn if not in light limits
|
||||
if gotten_light < mob_def.min_light or gotten_light > mob_def.max_light then
|
||||
break
|
||||
end
|
||||
|
||||
local is_water = get_item_group(gotten_node, "water") ~= 0
|
||||
local is_lava = get_item_group(gotten_node, "lava") ~= 0
|
||||
local is_ground = not (is_water or is_lava)
|
||||
local is_grass = minetest.get_item_group(gotten_node,"grass_block") ~= 0
|
||||
local has_bed = minetest.find_node_near(pos,25,{"group:bed"})
|
||||
|
||||
if mob_def.type_of_spawning == "ground" and is_water then
|
||||
break
|
||||
end
|
||||
|
||||
if mob_def.type_of_spawning == "ground" and is_lava then
|
||||
break
|
||||
end
|
||||
|
||||
--finally do the heavy check (for now) of mobs in area
|
||||
if count_mobs(spawning_position, mob_def.spawn_class) >= mob_def.aoc then
|
||||
break
|
||||
end
|
||||
|
||||
--adjust the position for water and lava mobs
|
||||
if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then
|
||||
if not is_ground then
|
||||
spawning_position.y = spawning_position.y - 1
|
||||
end
|
||||
|
||||
local mob_def
|
||||
|
||||
--create a disconnected clone of the spawn dictionary
|
||||
--prevents memory leak
|
||||
local mob_library_worker_table = table_copy(spawn_dictionary)
|
||||
|
||||
--grab mob that fits into the spawning location
|
||||
--randomly grab a mob, don't exclude any possibilities
|
||||
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
|
||||
local noise = perlin_noise:get_3d(spawning_position)
|
||||
local current_summary_chance = summary_chance
|
||||
while #mob_library_worker_table > 0 do
|
||||
local mob_chance_offset = (math_round(noise * current_summary_chance + 12345) % current_summary_chance) + 1
|
||||
local mob_index = 1
|
||||
local mob_chance = mob_library_worker_table[mob_index].chance
|
||||
local step_chance = mob_chance
|
||||
while step_chance < mob_chance_offset do
|
||||
mob_index = mob_index + 1
|
||||
mob_chance = mob_library_worker_table[mob_index].chance
|
||||
step_chance = step_chance + mob_chance
|
||||
end
|
||||
local mob_def = mob_library_worker_table[mob_index]
|
||||
local mob_type = minetest.registered_entities[mob_def.name].type
|
||||
if mob_def
|
||||
and spawning_position.y >= mob_def.min_height
|
||||
and spawning_position.y <= mob_def.max_height
|
||||
and mob_def.dimension == dimension
|
||||
and biome_check(mob_def.biomes, gotten_biome)
|
||||
and gotten_light >= mob_def.min_light
|
||||
and gotten_light <= mob_def.max_light
|
||||
and (is_ground or mob_def.type_of_spawning ~= "ground")
|
||||
and (mob_def.check_position and mob_def.check_position(spawning_position) or true)
|
||||
and (not is_farm_animal(mob_def.name) or is_grass)
|
||||
and (mob_type ~= "npc" or has_bed)
|
||||
then
|
||||
--everything is correct, spawn mob
|
||||
minetest.add_entity(spawning_position, mob_def.name)
|
||||
until true --this is a safety catch
|
||||
local object = minetest.add_entity(spawning_position, mob_def.name)
|
||||
if object then
|
||||
return mob_def.on_spawn and mob_def.on_spawn(object, pos)
|
||||
end
|
||||
end
|
||||
current_summary_chance = current_summary_chance - mob_chance
|
||||
table_remove(mob_library_worker_table, mob_index)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--MAIN LOOP
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer < 10 then return end
|
||||
timer = 0
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local pos = player:get_pos()
|
||||
local dimension = mcl_worlds.pos_to_dimension(pos)
|
||||
-- ignore void and unloaded area
|
||||
if dimension ~= "void" and dimension ~= "default" then
|
||||
local y_min, y_max = decypher_limits(pos.y)
|
||||
for i = 1, math_random(1, 4) do
|
||||
spawn_a_mob(pos, dimension, y_min, y_max)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
local dim = {"x", "z"}
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local function load_schem(filename)
|
||||
local file = io.open(modpath .. "/schems/" .. filename, "r")
|
||||
local data = minetest.deserialize(file:read())
|
||||
file:close()
|
||||
return data
|
||||
end
|
||||
|
||||
local wither_spawn_schems = {}
|
||||
|
||||
for _, d in pairs(dim) do
|
||||
wither_spawn_schems[d] = load_schem("wither_spawn_" .. d .. ".we")
|
||||
end
|
||||
|
||||
local function check_schem(pos, schem)
|
||||
for _, n in pairs(schem) do
|
||||
if minetest.get_node(vector.add(pos, n)).name ~= n.name then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function remove_schem(pos, schem)
|
||||
for _, n in pairs(schem) do
|
||||
minetest.remove_node(vector.add(pos, n))
|
||||
end
|
||||
end
|
||||
|
||||
local function wither_spawn(pos)
|
||||
for _, d in pairs(dim) do
|
||||
for i = 0, 2 do
|
||||
local p = vector.add(pos, {x = 0, y = -2, z = 0, [d] = -i})
|
||||
local schem = wither_spawn_schems[d]
|
||||
if check_schem(p, schem) then
|
||||
remove_schem(p, schem)
|
||||
minetest.add_entity(vector.add(p, {x = 0, y = 1, z = 0, [d] = 1}), "mobs_mc:wither")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local old_onplace=minetest.registered_nodes[mobs_mc.items.head_wither_skeleton].on_place
|
||||
minetest.registered_nodes[mobs_mc.items.head_wither_skeleton].on_place=function(itemstack,placer,pointed)
|
||||
minetest.after(0, wither_spawn, pointed.above)
|
||||
old_onplace(itemstack,placer,pointed)
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_wither_spawning
|
||||
description = Wither Spawning for MineClone2
|
||||
author = Fleckenstein
|
||||
depends = mobs_mc, mcl_heads
|
|
@ -0,0 +1 @@
|
|||
return {{["y"] = 1, ["x"] = 0, ["name"] = "mcl_nether:soul_sand", ["z"] = 0}, {["y"] = 2, ["x"] = 0, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 0, ["param2"] = 2, ["param1"] = 15}, {["y"] = 0, ["x"] = 1, ["name"] = "mcl_nether:soul_sand", ["z"] = 0}, {["y"] = 1, ["x"] = 1, ["name"] = "mcl_nether:soul_sand", ["z"] = 0}, {["y"] = 2, ["x"] = 1, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 0, ["param2"] = 2, ["param1"] = 15}, {["y"] = 1, ["x"] = 2, ["name"] = "mcl_nether:soul_sand", ["z"] = 0}, {["y"] = 2, ["x"] = 2, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 0, ["param2"] = 2, ["param1"] = 15}}
|
|
@ -0,0 +1 @@
|
|||
return {{["y"] = 0, ["x"] = 0, ["name"] = "mcl_nether:soul_sand", ["z"] = 1}, {["y"] = 1, ["x"] = 0, ["name"] = "mcl_nether:soul_sand", ["z"] = 0}, {["y"] = 1, ["x"] = 0, ["name"] = "mcl_nether:soul_sand", ["z"] = 1}, {["y"] = 1, ["x"] = 0, ["name"] = "mcl_nether:soul_sand", ["z"] = 2}, {["y"] = 2, ["x"] = 0, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 0, ["param2"] = 1, ["param1"] = 15}, {["y"] = 2, ["x"] = 0, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 1, ["param2"] = 1, ["param1"] = 15}, {["y"] = 2, ["x"] = 0, ["name"] = "mcl_heads:wither_skeleton", ["z"] = 2, ["param2"] = 1, ["param1"] = 15}}
|
|
@ -169,6 +169,7 @@ mobs_mc.follow = {
|
|||
dog = { mobs_mc.items.rabbit_raw, mobs_mc.items.rabbit_cooked, mobs_mc.items.mutton_raw, mobs_mc.items.mutton_cooked, mobs_mc.items.beef_raw, mobs_mc.items.beef_cooked, mobs_mc.items.chicken_raw, mobs_mc.items.chicken_cooked, mobs_mc.items.rotten_flesh,
|
||||
-- Mobs Redo items
|
||||
"mobs:meat", "mobs:meat_raw" },
|
||||
villager = { "mcl_farming:bread" },
|
||||
}
|
||||
|
||||
-- Contents for replace_what
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
-- NOTE: Most strings intentionally not marked for translation, other mods already have these items.
|
||||
-- TODO: Remove this file eventually, most items are already outsourced in other mods.
|
||||
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
local c = mobs_mc.is_item_variable_overridden
|
||||
|
||||
|
@ -234,8 +234,8 @@ end
|
|||
if c("ender_eye") and c("blaze_powder") and c("blaze_rod") then
|
||||
minetest.register_craft({
|
||||
type = "shapeless",
|
||||
output = 'mobs_mc:ender_eye',
|
||||
recipe = { 'mobs_mc:blaze_powder', 'mobs_mc:blaze_rod'},
|
||||
output = "mobs_mc:ender_eye",
|
||||
recipe = { "mobs_mc:blaze_powder", "mobs_mc:blaze_rod"},
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -525,7 +525,7 @@ if c("totem") then
|
|||
inventory_image = "mcl_totems_totem.png",
|
||||
wield_image = "mcl_totems_totem.png",
|
||||
stack_max = 1,
|
||||
groups = {combat_item=1},
|
||||
groups = {combat_item = 1, offhand_item = 1},
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ Origin of those models:
|
|||
* `mobs_mc_mushroom_brown.png` (CC0)
|
||||
|
||||
* “Spawn egg” textures (`mobs_mc_spawn_icon_*`) by 22i
|
||||
* Llama decor (carpet) textures (`mobs_mc_llama_decor_*`) by erlehmann and rudzik8
|
||||
* Any other texture not mentioned here are licensed under the MIT License
|
||||
|
||||
## Sounds
|
||||
|
|
|
@ -106,22 +106,42 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"flat",
|
||||
"IcePlainsSpikes",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"MegaTaiga",
|
||||
"MegaSpruceTaiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHills_beach",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+",
|
||||
"ExtremeHills+_snowtop",
|
||||
"StoneBeach",
|
||||
"Plains",
|
||||
"Plains_beach",
|
||||
"SunflowerPlains",
|
||||
"Taiga",
|
||||
"Taiga_beach",
|
||||
"Forest",
|
||||
"Forest_beach",
|
||||
"FlowerForest",
|
||||
"FlowerForest_beach",
|
||||
"BirchForest",
|
||||
"BirchForestM",
|
||||
"RoofedForest",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"SavannaM",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"Swampland",
|
||||
"Swampland_shore"
|
||||
},
|
||||
9,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -151,22 +151,42 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"flat",
|
||||
"IcePlainsSpikes",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"MegaTaiga",
|
||||
"MegaSpruceTaiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHills_beach",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+",
|
||||
"ExtremeHills+_snowtop",
|
||||
"StoneBeach",
|
||||
"Plains",
|
||||
"Plains_beach",
|
||||
"SunflowerPlains",
|
||||
"Taiga",
|
||||
"Taiga_beach",
|
||||
"Forest",
|
||||
"Forest_beach",
|
||||
"FlowerForest",
|
||||
"FlowerForest_beach",
|
||||
"BirchForest",
|
||||
"BirchForestM",
|
||||
"RoofedForest",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"SavannaM",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"Swampland",
|
||||
"Swampland_shore"
|
||||
},
|
||||
9,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -395,8 +395,9 @@ mobs:register_mob("mobs_mc:enderman", {
|
|||
local node = minetest.get_node(take_pos)
|
||||
-- Don't destroy protected stuff.
|
||||
if not minetest.is_protected(take_pos, "") then
|
||||
local dug = minetest.dig_node(take_pos)
|
||||
if dug then
|
||||
minetest.remove_node(take_pos)
|
||||
local dug = minetest.get_node_or_nil(take_pos)
|
||||
if dug and dug.name == "air" then
|
||||
if mobs_mc.enderman_replace_on_take[node.name] then
|
||||
self._taken_node = mobs_mc.enderman_replace_on_take[node.name]
|
||||
else
|
||||
|
|
|
@ -520,22 +520,42 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"flat",
|
||||
"IcePlainsSpikes",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"MegaTaiga",
|
||||
"MegaSpruceTaiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHills_beach",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+",
|
||||
"ExtremeHills+_snowtop",
|
||||
"StoneBeach",
|
||||
"Plains",
|
||||
"Plains_beach",
|
||||
"SunflowerPlains",
|
||||
"Taiga",
|
||||
"Taiga_beach",
|
||||
"Forest",
|
||||
"Forest_beach",
|
||||
"FlowerForest",
|
||||
"FlowerForest_beach",
|
||||
"BirchForest",
|
||||
"BirchForestM",
|
||||
"RoofedForest",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"SavannaM",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"Swampland",
|
||||
"Swampland_shore"
|
||||
},
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -42,7 +42,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
{"blank.png", "blank.png", "mobs_mc_llama_gray.png"},
|
||||
{"blank.png", "blank.png", "mobs_mc_llama_white.png"},
|
||||
{"blank.png", "blank.png", "mobs_mc_llama.png"},
|
||||
-- TODO: Add llama carpet textures (Pixel Perfection seems to use verbatim copy from Minecraft :-( )
|
||||
},
|
||||
visual_size = {x=3, y=3},
|
||||
makes_footstep_sound = true,
|
||||
|
@ -140,7 +139,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
if self.tamed and not self.child and self.owner == clicker:get_player_name() then
|
||||
|
||||
-- Place carpet
|
||||
--[[ TODO: Re-enable this code when carpet textures arrived.
|
||||
if minetest.get_item_group(item:get_name(), "carpet") == 1 and not self.carpet then
|
||||
for group, carpetdata in pairs(carpets) do
|
||||
if minetest.get_item_group(item:get_name(), group) == 1 then
|
||||
|
@ -170,7 +168,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
-- detatch player already riding llama
|
||||
if self.driver and clicker == self.driver then
|
||||
|
@ -190,8 +187,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
end
|
||||
end,
|
||||
|
||||
--[[
|
||||
TODO: Enable this code when carpet textures arrived.
|
||||
on_breed = function(parent1, parent2)
|
||||
-- When breeding, make sure the child has no carpet
|
||||
local pos = parent1.object:get_pos()
|
||||
|
@ -213,7 +208,6 @@ mobs:register_mob("mobs_mc:llama", {
|
|||
return false
|
||||
end
|
||||
end,
|
||||
]]
|
||||
|
||||
})
|
||||
|
||||
|
@ -229,6 +223,12 @@ mobs:spawn_specific(
|
|||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
},
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -188,22 +188,42 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"flat",
|
||||
"IcePlainsSpikes",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"MegaTaiga",
|
||||
"MegaSpruceTaiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHills_beach",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+",
|
||||
"ExtremeHills+_snowtop",
|
||||
"StoneBeach",
|
||||
"Plains",
|
||||
"Plains_beach",
|
||||
"SunflowerPlains",
|
||||
"Taiga",
|
||||
"Taiga_beach",
|
||||
"Forest",
|
||||
"Forest_beach",
|
||||
"FlowerForest",
|
||||
"FlowerForest_beach",
|
||||
"BirchForest",
|
||||
"BirchForestM",
|
||||
"RoofedForest",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"SavannaM",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"Swampland",
|
||||
"Swampland_shore"
|
||||
},
|
||||
9,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -116,15 +116,14 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"Desert",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
|
|
|
@ -309,22 +309,42 @@ mobs:spawn_specific(
|
|||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"flat",
|
||||
"IcePlainsSpikes",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ColdTaiga_beach",
|
||||
"ColdTaiga_beach_water",
|
||||
"MegaTaiga",
|
||||
"MegaSpruceTaiga",
|
||||
"ExtremeHills",
|
||||
"ExtremeHills_beach",
|
||||
"ExtremeHillsM",
|
||||
"ExtremeHills+",
|
||||
"ExtremeHills+_snowtop",
|
||||
"StoneBeach",
|
||||
"Plains",
|
||||
"Plains_beach",
|
||||
"SunflowerPlains",
|
||||
"Taiga",
|
||||
"Taiga_beach",
|
||||
"Forest",
|
||||
"Forest_beach",
|
||||
"FlowerForest",
|
||||
"FlowerForest_beach",
|
||||
"BirchForest",
|
||||
"BirchForestM",
|
||||
"RoofedForest",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
"SavannaM",
|
||||
"Jungle",
|
||||
"Jungle_shore",
|
||||
"JungleM",
|
||||
"JungleM_shore",
|
||||
"JungleEdge",
|
||||
"JungleEdgeM",
|
||||
"Swampland",
|
||||
"Swampland_shore"
|
||||
},
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
|
|
|
@ -124,6 +124,10 @@ mobs:register_mob("mobs_mc:snowman", {
|
|||
local pos = self.object:get_pos()
|
||||
minetest.sound_play("mcl_tools_shears_cut", {pos = pos}, true)
|
||||
|
||||
if minetest.registered_items["mcl_farming:pumpkin_face"] then
|
||||
minetest.add_item({x=pos.x, y=pos.y+1.4, z=pos.z}, "mcl_farming:pumpkin_face")
|
||||
end
|
||||
|
||||
-- Wear out
|
||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
||||
item:add_wear(mobs_mc.misc.shears_wear)
|
||||
|
|
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 936 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 966 B |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
@ -62,9 +62,15 @@ if minetest.get_mapgen_setting("mg_name") == "v6" then
|
|||
end
|
||||
|
||||
local professions = {
|
||||
unemployed = {
|
||||
name = N("Unemployed"),
|
||||
texture = "mobs_mc_villager.png",
|
||||
trades = nil,
|
||||
},
|
||||
farmer = {
|
||||
name = N("Farmer"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
jobsite = "mcl_composters:composter",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_farming:wheat_item", 18, 22, }, E1 },
|
||||
|
@ -74,18 +80,21 @@ local professions = {
|
|||
},
|
||||
|
||||
{
|
||||
{ { "mcl_farming:pumpkin_face", 8, 13 }, E1 },
|
||||
{ { "mcl_farming:pumpkin", 8, 13 }, E1 },
|
||||
{ E1, { "mcl_farming:pumpkin_pie", 2, 3} },
|
||||
{ E1, { "mcl_core:apple", 2, 3} },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_farming:melon", 7, 12 }, E1 },
|
||||
{ E1, { "mcl_core:apple", 5, 7 }, },
|
||||
{ E1, {"mcl_farming:cookie", 5, 7 }, },
|
||||
},
|
||||
|
||||
{
|
||||
{ E1, { "mcl_farming:cookie", 6, 10 } },
|
||||
{ E1, { "mcl_cake:cake", 1, 1 } },
|
||||
{ E1, { "mcl_mushrooms:mushroom_stew", 6, 10 } }, --FIXME: expert level farmer is supposed to sell sus stews.
|
||||
},
|
||||
{
|
||||
{ E1, { "mcl_farming:carrot_item_gold", 3, 10 } },
|
||||
{ E1, { "mcl_potions:speckled_melon", 4, 1 } },
|
||||
TRADE_V6_BIRCH_SAPLING,
|
||||
TRADE_V6_DARK_OAK_SAPLING,
|
||||
TRADE_V6_ACACIA_SAPLING,
|
||||
|
@ -95,32 +104,81 @@ local professions = {
|
|||
fisherman = {
|
||||
name = N("Fisherman"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
jobsite = "mcl_barrels:barrel_closed",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_fishing:fish_raw", 6, 6, "mcl_core:emerald", 1, 1 },{ "mcl_fishing:fish_cooked", 6, 6 } },
|
||||
{ { "mcl_mobitems:string", 15, 20 }, E1 },
|
||||
{ { "mcl_core:emerald", 3, 11 }, { "mcl_fishing:fishing_rod_enchanted", 1, 1} },
|
||||
{ { "mcl_core:coal_lump", 15, 10 }, E1 },
|
||||
-- FIXME missing: bucket of cod + fish should be cod.
|
||||
},
|
||||
{
|
||||
{ { "mcl_fishing:fish_raw", 6, 15,}, E1 },
|
||||
{ { "mcl_fishing:salmon_raw", 6, 6, "mcl_core:emerald", 1, 1 },{ "mcl_fishing:salmon_cooked", 6, 6 } },
|
||||
-- FIXME missing campfire
|
||||
-- {{ "mcl_core:emerald", 1, 2 },{"mcl_campfires:campfire",1,1} },
|
||||
},
|
||||
{
|
||||
{ { "mcl_fishing:salmon_raw", 6, 13,}, E1 },
|
||||
{ { "mcl_core:emerald", 7, 22 }, { "mcl_fishing:fishing_rod_enchanted", 1, 1} },
|
||||
},
|
||||
{
|
||||
{ { "mcl_fishing:clownfish_raw", 6, 6,}, E1 },
|
||||
},
|
||||
{
|
||||
{ { "mcl_fishing:pufferfish_raw", 4, 4,}, E1 },
|
||||
|
||||
{ { "mcl_boats:boat", 1, 1,}, E1 },
|
||||
{ { "mcl_boats:boat_acacia", 1, 1,}, E1 },
|
||||
{ { "mcl_boats:boat_spruce", 1, 1,}, E1 },
|
||||
{ { "mcl_boats:boat_dark_oak", 1, 1,}, E1 },
|
||||
{ { "mcl_boats:boat_birch", 1, 1,}, E1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
fletcher = {
|
||||
name = N("Fletcher"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
jobsite = "mcl_fletching_table:fletching_table",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_mobitems:string", 15, 20 }, E1 },
|
||||
{ E1, { "mcl_bows:arrow", 8, 12 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:gravel", 10, 10, "mcl_core:emerald", 1, 1 }, { "mcl_core:flint", 6, 10 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:flint", 26, 26 }, E1 },
|
||||
{ { "mcl_core:emerald", 2, 3 }, { "mcl_bows:bow", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_mobitems:string", 14, 14 }, E1 },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_bows:crossbow", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_mobitems:string", 24, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 7, 21 } , { "mcl_bows:bow_enchanted", 1, 1 } },
|
||||
},
|
||||
{
|
||||
--FIXME: supposed to be tripwire hook{ { "tripwirehook", 24, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 8, 22 } , { "mcl_bows:crossbow_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:healing_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:harming_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:night_vision_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:swiftness_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:slowness_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:leaping_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:poison_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:regeneration_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:invisibility_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:water_breathing_arrow", 5, 5 } },
|
||||
{ { "mcl_core:emerald", 2, 2, "mcl_bows:arrow", 5, 5 }, { "mcl_potions:fire_resistance_arrow", 5, 5 } },
|
||||
},
|
||||
}
|
||||
},
|
||||
shepherd ={
|
||||
name = N("Shepherd"),
|
||||
texture = "mobs_mc_villager_farmer.png",
|
||||
jobsite = "mcl_loom:loom",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_wool:white", 16, 22 }, E1 },
|
||||
|
@ -150,179 +208,262 @@ local professions = {
|
|||
librarian = {
|
||||
name = N("Librarian"),
|
||||
texture = "mobs_mc_villager_librarian.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: lectern
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||
{ { "mcl_books:book", 8, 10 }, E1 },
|
||||
{ { "mcl_core:emerald", 10, 12 }, { "mcl_compass:compass", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 3, 4 }, { "mcl_books:bookshelf", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 9, 9 }, { "mcl_books:bookshelf", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 5, 64, "mcl_books:book", 1, 1 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_books:written_book", 2, 2 }, E1 },
|
||||
{ { "mcl_core:emerald", 10, 12 }, { "mcl_clock:clock", 1, 1 } },
|
||||
{ E1, { "mcl_core:glass", 3, 5 } },
|
||||
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 5, 64, "mcl_books:book", 1, 1 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ E1, { "mcl_lanterns:lantern_floor", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ E1, { "mcl_core:glass", 3, 5 } },
|
||||
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ { "mcl_dye:black", 5, 5 }, E1 },
|
||||
{ { "mcl_core:emerald", 5, 64, "mcl_books:book", 1, 1 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ E1, { "mcl_core:glass", 4, 4 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:emerald", 5, 64 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ E1, { "mcl_books:writable_book", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 5, 64, "mcl_books:book", 1, 1 }, { "mcl_enchanting:book_enchanted", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 4, 4 }, { "mcl_compass:compass", 1 ,1 }},
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_clock:clock", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:emerald", 20, 22 }, { "mcl_mobs:nametag", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 20, 20 }, { "mcl_mobs:nametag", 1, 1 } },
|
||||
}
|
||||
},
|
||||
},
|
||||
cartographer = {
|
||||
name = N("Cartographer"),
|
||||
texture = "mobs_mc_villager_librarian.png",
|
||||
jobsite = "mcl_cartography_table:cartography_table",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:paper", 24, 36 }, E1 },
|
||||
{ { "mcl_core:paper", 24, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_maps:empty_map", 1, 1 } },
|
||||
},
|
||||
{
|
||||
-- compass subject to special checks
|
||||
{ { "xpanes:pane_natural_flat", 1, 1 }, E1 },
|
||||
--{ { "mcl_core:emerald", 13, 13, "mcl_compass:compass", 1, 1 }, { "FIXME:ocean explorer map" 1, 1} },
|
||||
},
|
||||
|
||||
{
|
||||
-- subject to special checks
|
||||
{ { "mcl_compass:compass", 1, 1 }, E1 },
|
||||
--{ { "mcl_core:emerald", 13, 13, "mcl_compass:compass", 1, 1 }, { "FIXME:woodland explorer map" 1, 1} },
|
||||
},
|
||||
|
||||
{
|
||||
-- TODO: replace with empty map
|
||||
{ { "mcl_core:emerald", 7, 11}, { "mcl_maps:filled_map", 1, 1 } },
|
||||
},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_itemframes:item_frame", 1, 1 }},
|
||||
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_white", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_grey", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_silver", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_black", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_red", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_green", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_cyan", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_blue", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_magenta", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_orange", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_purple", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_brown", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_pink", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_lime", 1, 1 }},
|
||||
{ { "mcl_core:emerald", 7, 7}, { "mcl_banners:banner_item_light_blue", 1, 1 }},
|
||||
},
|
||||
{
|
||||
--{ { "mcl_core:emerald", 8, 8}, { "FIXME: globe banner pattern", 1, 1 } },
|
||||
},
|
||||
-- TODO: special maps
|
||||
},
|
||||
},
|
||||
armorer = {
|
||||
name = N("Armorer"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
jobsite = "mcl_core:lava_source", --FIXME: blast furnace
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 4, 6 }, { "mcl_armor:helmet_iron", 1, 1 } },
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_armor:helmet_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 9 }, { "mcl_armor:chestplate_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 7, 7 }, { "mcl_armor:leggings_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 4, 4 }, { "mcl_armor:boots_iron", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 10, 14 }, { "mcl_armor:chestplate_iron", 1, 1 } },
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_armor:leggings_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 1, 1 }, { "mcl_armor:boots_chain", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_buckets:bucket_lava", 1, 1 }, E1 },
|
||||
{ { "mcl_core:diamond", 1, 1 }, E1 },
|
||||
{ { "mcl_core:emerald", 1, 1 }, { "mcl_armor:helmet_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 4, 4 }, { "mcl_armor:chestplate_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_shields:shield", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
{ { "mcl_core:emerald", 16, 19 }, { "mcl_armor:chestplate_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 19, 33 }, { "mcl_armor:leggings_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 13, 27 }, { "mcl_armor:boots_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_armor:boots_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 11 }, { "mcl_armor:leggings_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_armor:helmet_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 11, 15 }, { "mcl_armor:chestplate_chain", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 13, 27 }, { "mcl_armor:helmet_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 21, 35 }, { "mcl_armor:chestplate_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
leatherworker = {
|
||||
name = N("Leatherworker"),
|
||||
texture = "mobs_mc_villager_butcher.png",
|
||||
jobsite = "mcl_cauldrons:cauldron",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_mobitems:leather", 9, 12 }, E1 },
|
||||
{ { "mcl_core:emerald", 2, 4 }, { "mcl_armor:leggings_leather", 2, 4 } },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_armor:leggings_leather", 2, 4 } },
|
||||
{ { "mcl_core:emerald", 7, 7 }, { "mcl_armor:chestplate_leather", 2, 4 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:emerald", 7, 12 }, { "mcl_armor:chestplate_leather_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:flint", 26, 26 }, E1 },
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_armor:helmet_leather", 2, 4 } },
|
||||
{ { "mcl_core:emerald", 4, 4 }, { "mcl_armor:boots_leather", 2, 4 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_mobitems:rabbit_hide", 9, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 7, 7 }, { "mcl_armor:chestplate_leather", 1, 1 } },
|
||||
},
|
||||
{
|
||||
--{ { "FIXME: scute", 4, 4 }, E1 },
|
||||
{ { "mcl_core:emerald", 8, 10 }, { "mcl_mobitems:saddle", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:emerald", 6, 6 }, { "mcl_mobitems:saddle", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_armor:helmet_leather", 2, 4 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
butcher = {
|
||||
name = N("Butcher"),
|
||||
texture = "mobs_mc_villager_butcher.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: smoker
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_mobitems:beef", 14, 18 }, E1 },
|
||||
{ { "mcl_mobitems:chicken", 14, 18 }, E1 },
|
||||
{ { "mcl_mobitems:beef", 14, 14 }, E1 },
|
||||
{ { "mcl_mobitems:chicken", 7, 7 }, E1 },
|
||||
{ { "mcl_mobitems:rabbit", 4, 4 }, E1 },
|
||||
{ E1, { "mcl_mobitems:rabbit_stew", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||
{ E1, { "mcl_mobitems:cooked_beef", 5, 7 } },
|
||||
{ E1, { "mcl_mobitems:cooked_chicken", 6, 8 } },
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
{ E1, { "mcl_mobitems:cooked_porkchop", 5, 5 } },
|
||||
{ E1, { "mcl_mobitems:cooked_chicken", 8, 8 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_mobitems:mutton", 7, 7 }, E1 },
|
||||
{ { "mcl_mobitems:beef", 10, 10 }, E1 },
|
||||
},
|
||||
{
|
||||
{ { "mcl_mobitems:mutton", 7, 7 }, E1 },
|
||||
{ { "mcl_mobitems:beef", 10, 10 }, E1 },
|
||||
},
|
||||
{
|
||||
--{ { "FIXME: Sweet Berries", 10, 10 }, E1 },
|
||||
},
|
||||
},
|
||||
},
|
||||
weapon_smith = {
|
||||
name = N("Weapon Smith"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: grindstone
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 6, 8 }, { "mcl_tools:axe_iron", 1, 1 } },
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_tools:axe_iron", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 7, 21 }, { "mcl_tools:sword_iron_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 9, 10 }, { "mcl_tools:sword_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:flint", 7, 9 }, E1 },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:diamond", 7, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 17, 31 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:sword_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 9, 12 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 13, 27 }, { "mcl_tools:sword_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
tool_smith = {
|
||||
name = N("Tool Smith"),
|
||||
texture = "mobs_mc_villager_smith.png",
|
||||
jobsite = "mcl_villages:stonebrickcarved", --FIXME: smithing table
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_core:coal_lump", 16, 24 }, E1 },
|
||||
{ { "mcl_core:emerald", 5, 7 }, { "mcl_tools:shovel_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:coal_lump", 15, 15 }, E1 },
|
||||
{ E1, { "mcl_tools:axe_stone", 1, 1 } },
|
||||
{ E1, { "mcl_tools:shovel_stone", 1, 1 } },
|
||||
{ E1, { "mcl_tools:pick_stone", 1, 1 } },
|
||||
{ E1, { "mcl_farming:hoe_stone", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:iron_ingot", 7, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 9, 11 }, { "mcl_tools:pick_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:iron_ingot", 4, 4 }, E1 },
|
||||
--{ { "mcl_core:emerald", 36, 36 }, { "FIXME: Bell", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_core:diamond", 3, 4 }, E1 },
|
||||
{ { "mcl_core:emerald", 12, 15 }, { "mcl_tools:pick_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:flint", 30, 30 }, E1 },
|
||||
{ { "mcl_core:emerald", 6, 20 }, { "mcl_tools:axe_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 7, 21 }, { "mcl_tools:shovel_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 8, 22 }, { "mcl_tools:pick_iron_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 4, 4 }, { "mcl_farming:hoe_diamond", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:diamond", 1, 1 }, E1 },
|
||||
{ { "mcl_core:emerald", 17, 31 }, { "mcl_tools:axe_diamond_enchanted", 1, 1 } },
|
||||
{ { "mcl_core:emerald", 10, 24 }, { "mcl_tools:shovel_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
{
|
||||
{ { "mcl_core:emerald", 18, 32 }, { "mcl_tools:pick_diamond_enchanted", 1, 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
cleric = {
|
||||
name = N("Cleric"),
|
||||
texture = "mobs_mc_villager_priest.png",
|
||||
jobsite = "mcl_brewing:stand",
|
||||
trades = {
|
||||
{
|
||||
{ { "mcl_mobitems:rotten_flesh", 36, 40 }, E1 },
|
||||
{ { "mcl_core:gold_ingot", 8, 10 }, E1 },
|
||||
{ { "mcl_mobitems:rotten_flesh", 32, 32 }, E1 },
|
||||
{ E1, { "mesecons:redstone", 2, 2 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ E1, { "mesecons:redstone", 1, 4 } },
|
||||
{ E1, { "mcl_dye:blue", 1, 2 } },
|
||||
{ { "mcl_core:gold_ingot", 3, 3 }, E1 },
|
||||
{ E1, { "mcl_dye:blue", 1, 1 } },
|
||||
},
|
||||
|
||||
{
|
||||
{ E1, { "mcl_nether:glowstone", 1, 3 } },
|
||||
{ { "mcl_core:emerald", 4, 7 }, { "mcl_throwing:ender_pearl", 1, 1 } },
|
||||
{ { "mcl_mobitems:rabbit_foot", 2, 2 }, E1 },
|
||||
{ E1, { "mcl_nether:glowstone", 4, 4 } },
|
||||
},
|
||||
{
|
||||
--{ { "FIXME: scute", 4, 4 }, E1 },
|
||||
{ { "mcl_potions:glass_bottle", 9, 9 }, E1 },
|
||||
{ { "mcl_core:emerald", 5, 5 }, { "mcl_throwing:ender_pearl", 1, 1 } },
|
||||
TRADE_V6_RED_SANDSTONE,
|
||||
},
|
||||
|
||||
{
|
||||
{ { "mcl_nether:nether_wart_item", 22, 22 }, E1 },
|
||||
{ { "mcl_core:emerald", 3, 3 }, { "mcl_experience:bottle", 1, 1 } },
|
||||
|
@ -347,6 +488,42 @@ local stand_still = function(self)
|
|||
self.jump = false
|
||||
end
|
||||
|
||||
local function set_velocity(self, v)
|
||||
local yaw = (self.object:get_yaw() or 0) + self.rotate
|
||||
self.object:set_velocity({
|
||||
x = (math.sin(yaw) * -v),
|
||||
y = self.object:get_velocity().y,
|
||||
z = (math.cos(yaw) * v),
|
||||
})
|
||||
end
|
||||
|
||||
local function go_to_pos(entity,b)
|
||||
local s=entity.object:get_pos()
|
||||
local v = { x = b.x - s.x, z = b.z - s.z }
|
||||
local yaw = (math.atan(v.z / v.x) + math.pi / 2) - entity.rotate
|
||||
if b.x > s.x then yaw = yaw + math.pi end
|
||||
entity.object:set_yaw(yaw)
|
||||
set_velocity(entity,entity.follow_velocity)
|
||||
if vector.distance(b,s) < 5 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function go_home(entity)
|
||||
entity.state = "go_home"
|
||||
local b=entity.bed
|
||||
if not b then return end
|
||||
if go_to_pos(entity,b) then
|
||||
entity.state = "stand"
|
||||
set_velocity(entity,0)
|
||||
entity.object:set_pos(b)
|
||||
local n=minetest.get_node(b)
|
||||
if n and n.name ~= "mcl_beds:bed_red_bottom" then
|
||||
entity.bed=nil --the stormtroopers have killed uncle owen
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local update_max_tradenum = function(self)
|
||||
if not self._trades then
|
||||
return
|
||||
|
@ -987,11 +1164,19 @@ mobs:register_mob("mobs_mc:villager", {
|
|||
die_end = 220,
|
||||
die_loop = false,
|
||||
},
|
||||
follow = mobs_mc.follow.villager,
|
||||
view_range = 16,
|
||||
fear_height = 4,
|
||||
jump = true,
|
||||
walk_chance = DEFAULT_WALK_CHANCE,
|
||||
on_rightclick = function(self, clicker)
|
||||
if clicker:get_wielded_item():get_name() == "mcl_farming:bread" then
|
||||
if mobs:feed_tame(self, clicker, 1, true, true) then return end
|
||||
if mobs:protect(self, clicker) then return end
|
||||
end
|
||||
if self.child then
|
||||
return
|
||||
end
|
||||
-- Initiate trading
|
||||
local name = clicker:get_player_name()
|
||||
self._trading_players[name] = true
|
||||
|
@ -1033,6 +1218,11 @@ mobs:register_mob("mobs_mc:villager", {
|
|||
if not self._player_scan_timer then
|
||||
self._player_scan_timer = 0
|
||||
end
|
||||
|
||||
if self.bed and ( self.state == "go_home" or vector.distance(self.object:get_pos(),self.bed) > 50 ) then
|
||||
go_home(self)
|
||||
end
|
||||
|
||||
self._player_scan_timer = self._player_scan_timer + dtime
|
||||
-- Check infrequently to keep CPU load low
|
||||
if self._player_scan_timer > PLAYER_SCAN_INTERVAL then
|
||||
|
|
|
@ -197,7 +197,6 @@ mobs:spawn_specific(
|
|||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
|
@ -290,7 +289,6 @@ mobs:spawn_specific(
|
|||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
|
@ -342,9 +340,6 @@ mobs:spawn_specific(
|
|||
"ground",
|
||||
{
|
||||
"Desert",
|
||||
"SavannaM",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
|
@ -359,9 +354,6 @@ mobs:spawn_specific(
|
|||
"ground",
|
||||
{
|
||||
"Desert",
|
||||
"SavannaM",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
|
|
|
@ -233,15 +233,15 @@ mobs_mc.override.spawn_height = {
|
|||
water = tonumber(minetest.settings:get("water_level")) or 0, -- Water level in the Overworld
|
||||
|
||||
-- Overworld boundaries (inclusive)
|
||||
overworld_min = mcl_mapgen.overworld.min,
|
||||
overworld_max = mcl_mapgen.overworld.max,
|
||||
overworld_min = mcl_vars.mg_overworld_min,
|
||||
overworld_max = mcl_vars.mg_overworld_max,
|
||||
|
||||
-- Nether boundaries (inclusive)
|
||||
nether_min = mcl_mapgen.nether.min,
|
||||
nether_max = mcl_mapgen.nether.max,
|
||||
nether_min = mcl_vars.mg_nether_min,
|
||||
nether_max = mcl_vars.mg_nether_max,
|
||||
|
||||
-- End boundaries (inclusive)
|
||||
end_min = mcl_mapgen.end_.min,
|
||||
end_max = mcl_mapgen.end_.max,
|
||||
end_min = mcl_vars.mg_end_min,
|
||||
end_max = mcl_vars.mg_end_max,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +1,66 @@
|
|||
mcl_weather.nether_dust = {}
|
||||
mcl_weather.nether_dust.particles_count = 99
|
||||
mcl_weather.nether_dust.particlespawners = {}
|
||||
|
||||
-- calculates coordinates and draw particles for Nether dust
|
||||
function mcl_weather.nether_dust.add_dust_particles(player)
|
||||
for i=mcl_weather.nether_dust.particles_count, 1,-1 do
|
||||
local rpx, rpy, rpz = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
minetest.add_particle({
|
||||
pos = {x = rpx, y = rpy - math.random(6, 18), z = rpz},
|
||||
velocity = {x = math.random(-30,30)*0.01, y = math.random(-15,15)*0.01, z = math.random(-30,30)*0.01},
|
||||
acceleration = {x = math.random(-50,50)*0.02, y = math.random(-20,20)*0.02, z = math.random(-50,50)*0.02},
|
||||
expirationtime = 3,
|
||||
size = math.random(6,20)*0.01,
|
||||
local psdef= {
|
||||
amount = 150,
|
||||
time = 0,
|
||||
minpos = vector.new(-15,-15,-15),
|
||||
maxpos =vector.new(15,15,15),
|
||||
minvel = vector.new(-0.3,-0.15,-1),
|
||||
maxvel = vector.new(0.3,0.15,0.3),
|
||||
minacc = vector.new(-1,-0.4,-1),
|
||||
maxacc = vector.new(1,0.4,1),
|
||||
minexptime = 1,
|
||||
maxexptime = 10,
|
||||
minsize = 0.2,
|
||||
maxsize = 0.7,
|
||||
collisiondetection = false,
|
||||
collision_removal = false,
|
||||
object_collision = false,
|
||||
vertical = false,
|
||||
glow = math.random(0,minetest.LIGHT_MAX),
|
||||
texture = "mcl_particles_nether_dust"..tostring(i%3+1)..".png",
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
vertical = false
|
||||
}
|
||||
|
||||
local function check_player(player)
|
||||
local name=player:get_player_name()
|
||||
if mcl_worlds.has_dust(player:get_pos()) and not mcl_weather.nether_dust.particlespawners[name] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer < 0.7 then return end
|
||||
timer = 0
|
||||
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
if not mcl_worlds.has_dust(player:get_pos()) then
|
||||
return false
|
||||
mcl_weather.nether_dust.add_particlespawners = function(player)
|
||||
local name=player:get_player_name()
|
||||
mcl_weather.nether_dust.particlespawners[name]={}
|
||||
psdef.playername = name
|
||||
psdef.attached = player
|
||||
psdef.glow = math.random(0,minetest.LIGHT_MAX)
|
||||
for i=1,3 do
|
||||
psdef.texture="mcl_particles_nether_dust"..i..".png"
|
||||
mcl_weather.nether_dust.particlespawners[name][i]=minetest.add_particlespawner(psdef)
|
||||
end
|
||||
mcl_weather.nether_dust.add_dust_particles(player)
|
||||
end
|
||||
|
||||
mcl_weather.nether_dust.delete_particlespawners = function(player)
|
||||
local name=player:get_player_name()
|
||||
if mcl_weather.nether_dust.particlespawners[name] then
|
||||
for i=1,3 do
|
||||
minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i])
|
||||
end
|
||||
mcl_weather.nether_dust.particlespawners[name]=nil
|
||||
end
|
||||
end
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
||||
if check_player(player) then
|
||||
return mcl_weather.nether_dust.add_particlespawners(player)
|
||||
end
|
||||
mcl_weather.nether_dust.delete_particlespawners(player)
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
if check_player(player) then
|
||||
mcl_weather.nether_dust.add_particlespawners(player)
|
||||
end
|
||||
end)
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
mcl_weather.nether_dust.delete_particlespawners(player)
|
||||
end)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
local PARTICLES_COUNT_RAIN = 30
|
||||
local PARTICLES_COUNT_THUNDER = 45
|
||||
local PARTICLES_COUNT_RAIN = 100
|
||||
local PARTICLES_COUNT_THUNDER = 300
|
||||
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
|
@ -19,6 +19,45 @@ mcl_weather.rain = {
|
|||
|
||||
init_done = false,
|
||||
}
|
||||
local update_sound={}
|
||||
local vel=math.random(0,3)
|
||||
local falling_speed=math.random(10,15)
|
||||
local size = math.random(1,3)
|
||||
local psdef= {
|
||||
amount = mcl_weather.rain.particles_count,
|
||||
time=0,
|
||||
minpos = vector.new(-6,3,-6),
|
||||
maxpos = vector.new(6,15,6),
|
||||
minvel = vector.new(-vel,-falling_speed,-vel),
|
||||
maxvel = vector.new(vel,-falling_speed+vel,vel),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,-0.4,0),
|
||||
minexptime = 0.5,
|
||||
maxexptime = 2,
|
||||
minsize = size,
|
||||
maxsize= size*2,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
local psdef_backsplash= {
|
||||
amount = 10,
|
||||
time=0,
|
||||
minpos = vector.new(-3,-1,-3),
|
||||
maxpos = vector.new(3,0,3),
|
||||
minvel = vector.new(-vel,falling_speed*2,-vel),
|
||||
maxvel = vector.new(vel,falling_speed*2+vel,vel),
|
||||
minacc = vector.new(0,0,0),
|
||||
maxacc = vector.new(0,0,0),
|
||||
minexptime = 0.1,
|
||||
maxexptime = 0.2,
|
||||
minsize = size*0.1,
|
||||
maxsize= size*0.5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
}
|
||||
local textures = {"weather_pack_rain_raindrop_1.png", "weather_pack_rain_raindrop_2.png", "weather_pack_rain_raindrop_1.png"}
|
||||
|
||||
function mcl_weather.rain.sound_handler(player)
|
||||
return minetest.sound_play("weather_rain", {
|
||||
|
@ -44,44 +83,20 @@ function mcl_weather.rain.set_sky_box()
|
|||
end
|
||||
end
|
||||
|
||||
-- creating manually parctiles instead of particles spawner because of easier to control
|
||||
-- spawn position.
|
||||
-- no no no NO NO f*.. no. no manual particle creatin' PLS!! this sends EVERY particle over the net.
|
||||
function mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
for i=mcl_weather.rain.particles_count, 1,-1 do
|
||||
local random_pos_x, random_pos_y, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
if mcl_weather.is_outdoor({x=random_pos_x, y=random_pos_y, z=random_pos_z}) then
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x=0, y=-10, z=0},
|
||||
acceleration = {x=0, y=-30, z=0},
|
||||
expirationtime = 1.0,
|
||||
size = math.random(0.5, 3),
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = true,
|
||||
texture = mcl_weather.rain.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.particles_count
|
||||
for k,v in pairs(textures) do
|
||||
psdef.texture=v
|
||||
mcl_weather.add_spawner_player(player,"rain"..k,psdef)
|
||||
end
|
||||
psdef_backsplash.texture=textures[math.random(1,#textures)]
|
||||
local l=mcl_weather.add_spawner_player(player,"rainbacksplash",psdef_backsplash)
|
||||
if l then
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
function mcl_weather.rain.get_texture()
|
||||
local texture_name
|
||||
local random_number = math.random()
|
||||
if random_number > 0.33 then
|
||||
texture_name = "weather_pack_rain_raindrop_1.png"
|
||||
elseif random_number > 0.66 then
|
||||
texture_name = "weather_pack_rain_raindrop_2.png"
|
||||
else
|
||||
texture_name = "weather_pack_rain_raindrop_3.png"
|
||||
end
|
||||
return texture_name;
|
||||
end
|
||||
|
||||
-- register player for rain weather.
|
||||
-- basically needs for origin sky reference and rain sound controls.
|
||||
function mcl_weather.rain.add_player(player)
|
||||
|
@ -89,6 +104,7 @@ function mcl_weather.rain.add_player(player)
|
|||
local player_meta = {}
|
||||
player_meta.origin_sky = {player:get_sky()}
|
||||
mcl_weather.players[player:get_player_name()] = player_meta
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -99,26 +115,15 @@ function mcl_weather.rain.remove_player(player)
|
|||
if player_meta and player_meta.origin_sky then
|
||||
player:set_clouds({color="#FFF0F0E5"})
|
||||
mcl_weather.players[player:get_player_name()] = nil
|
||||
update_sound[player:get_player_name()]=true
|
||||
end
|
||||
end
|
||||
|
||||
mcl_worlds.register_on_dimension_change(function(player, dimension)
|
||||
if dimension ~= "overworld" and dimension ~= "void" then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
elseif dimension == "overworld" then
|
||||
mcl_weather.rain.update_sound(player)
|
||||
if mcl_weather.rain.raining then
|
||||
mcl_weather.rain.add_rain_particles(player)
|
||||
mcl_weather.rain.add_player(player)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- adds and removes rain sound depending how much rain particles around player currently exist.
|
||||
-- have few seconds delay before each check to avoid on/off sound too often
|
||||
-- when player stay on 'edge' where sound should play and stop depending from random raindrop appearance.
|
||||
function mcl_weather.rain.update_sound(player)
|
||||
if not update_sound[player:get_player_name()] then return end
|
||||
local player_meta = mcl_weather.players[player:get_player_name()]
|
||||
if player_meta then
|
||||
if player_meta.sound_updated and player_meta.sound_updated + 5 > minetest.get_gametime() then
|
||||
|
@ -136,6 +141,7 @@ function mcl_weather.rain.update_sound(player)
|
|||
|
||||
player_meta.sound_updated = minetest.get_gametime()
|
||||
end
|
||||
update_sound[player:get_player_name()]=false
|
||||
end
|
||||
|
||||
-- rain sound removed from player.
|
||||
|
@ -158,6 +164,7 @@ function mcl_weather.rain.clear()
|
|||
for _, player in pairs(get_connected_players()) do
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.rain.remove_player(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -177,8 +184,10 @@ function mcl_weather.rain.make_weather()
|
|||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
||||
local pos=player:get_pos()
|
||||
if mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(pos) or not mcl_weather.is_outdoor(pos) then
|
||||
mcl_weather.rain.remove_sound(player)
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.rain.add_player(player)
|
||||
|
@ -190,8 +199,12 @@ end
|
|||
-- Switch the number of raindrops: "thunder" for many raindrops, otherwise for normal raindrops
|
||||
function mcl_weather.rain.set_particles_mode(mode)
|
||||
if mode == "thunder" then
|
||||
psdef.amount=PARTICLES_COUNT_THUNDER
|
||||
psdef_backsplash.amount=PARTICLES_COUNT_THUNDER
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_THUNDER
|
||||
else
|
||||
psdef.amount=PARTICLES_COUNT_RAIN
|
||||
psdef_backsplash.amount=PARTICLES_COUNT_RAIN
|
||||
mcl_weather.rain.particles_count = PARTICLES_COUNT_RAIN
|
||||
end
|
||||
end
|
||||
|
|
|
@ -240,8 +240,7 @@ local function initsky(player)
|
|||
mcl_weather.skycolor.force_update = true
|
||||
end
|
||||
|
||||
-- MC-style clouds: Layer 127, thickness 4, fly to the “West”
|
||||
player:set_clouds({height=mcl_worlds.layer_to_y(127), speed={x=-2, z=0}, thickness=4, color="#FFF0FEF"})
|
||||
player:set_clouds(mcl_worlds:get_cloud_parameters() or {height=mcl_worlds.layer_to_y(127), speed={x=-2, z=0}, thickness=4, color="#FFF0FEF"})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(initsky)
|
||||
|
|
|
@ -5,30 +5,25 @@ mcl_weather.snow = {}
|
|||
mcl_weather.snow.particles_count = 15
|
||||
mcl_weather.snow.init_done = false
|
||||
|
||||
-- calculates coordinates and draw particles for snow weather
|
||||
function mcl_weather.snow.add_snow_particles(player)
|
||||
mcl_weather.rain.last_rp_count = 0
|
||||
for i=mcl_weather.snow.particles_count, 1,-1 do
|
||||
local random_pos_x, _, random_pos_z = mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
local random_pos_y = math.random() + math.random(player:get_pos().y - 1, player:get_pos().y + 7)
|
||||
if minetest.get_node_light({x=random_pos_x, y=random_pos_y, z=random_pos_z}, 0.5) == 15 then
|
||||
mcl_weather.rain.last_rp_count = mcl_weather.rain.last_rp_count + 1
|
||||
minetest.add_particle({
|
||||
pos = {x=random_pos_x, y=random_pos_y, z=random_pos_z},
|
||||
velocity = {x = math.random(-100,100)*0.001, y = math.random(-300,-100)*0.004, z = math.random(-100,100)*0.001},
|
||||
acceleration = {x = 0, y=0, z = 0},
|
||||
expirationtime = 8.0,
|
||||
size = 1,
|
||||
local psdef= {
|
||||
amount = 99,
|
||||
time = 0, --stay on til we turn it off
|
||||
minpos = vector.new(-15,-5,-15),
|
||||
maxpos =vector.new(15,10,15),
|
||||
minvel = vector.new(0,-1,0),
|
||||
maxvel = vector.new(0,-4,0),
|
||||
minacc = vector.new(0,-1,0),
|
||||
maxacc = vector.new(0,-4,0),
|
||||
minexptime = 1,
|
||||
maxexptime = 1,
|
||||
minsize = 0.5,
|
||||
maxsize = 5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
object_collision = false,
|
||||
vertical = false,
|
||||
texture = mcl_weather.snow.get_texture(),
|
||||
playername = player:get_player_name()
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
object_collision = true,
|
||||
vertical = true,
|
||||
glow = 1
|
||||
}
|
||||
|
||||
function mcl_weather.snow.set_sky_box()
|
||||
mcl_weather.skycolor.add_layer(
|
||||
|
@ -48,6 +43,7 @@ end
|
|||
function mcl_weather.snow.clear()
|
||||
mcl_weather.skycolor.remove_layer("weather-pack-snow-sky")
|
||||
mcl_weather.snow.init_done = false
|
||||
mcl_weather.remove_all_spawners()
|
||||
end
|
||||
|
||||
-- Simple random texture getter
|
||||
|
@ -74,10 +70,14 @@ minetest.register_globalstep(function(dtime)
|
|||
end
|
||||
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
|
||||
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos()) or not mcl_weather.is_outdoor(player:get_pos())) then
|
||||
mcl_weather.remove_spawners_player(player)
|
||||
return false
|
||||
end
|
||||
mcl_weather.snow.add_snow_particles(player)
|
||||
for i=1,2 do
|
||||
psdef.texture="weather_pack_snow_snowflake"..i..".png"
|
||||
mcl_weather.add_spawner_player(player,"snow"..i,psdef)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
|
|
@ -47,6 +47,35 @@ local function save_weather()
|
|||
end
|
||||
minetest.register_on_shutdown(save_weather)
|
||||
|
||||
local particlespawners={}
|
||||
function mcl_weather.add_spawner_player(pl,id,ps)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then
|
||||
particlespawners[name] = {}
|
||||
end
|
||||
if not particlespawners[name][id] then
|
||||
ps.playername =name
|
||||
ps.attached = pl
|
||||
particlespawners[name][id]=minetest.add_particlespawner(ps)
|
||||
return particlespawners[name][id]
|
||||
end
|
||||
end
|
||||
function mcl_weather.remove_spawners_player(pl)
|
||||
local name=pl:get_player_name()
|
||||
if not particlespawners[name] then return end
|
||||
for k,v in pairs(particlespawners[name]) do
|
||||
minetest.delete_particlespawner(v)
|
||||
end
|
||||
particlespawners[name] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
function mcl_weather.remove_all_spawners()
|
||||
for k,v in pairs(minetest.get_connected_players()) do
|
||||
mcl_weather.remove_spawners_player(v)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_weather.get_rand_end_time(min_duration, max_duration)
|
||||
local r
|
||||
if min_duration and max_duration then
|
||||
|
@ -92,36 +121,6 @@ function mcl_weather.is_underwater(player)
|
|||
return false
|
||||
end
|
||||
|
||||
-- trying to locate position for particles by player look direction for performance reason.
|
||||
-- it is costly to generate many particles around player so goal is focus mainly on front view.
|
||||
function mcl_weather.get_random_pos_by_player_look_dir(player)
|
||||
local look_dir = player:get_look_dir()
|
||||
local player_pos = player:get_pos()
|
||||
|
||||
local random_pos_x, random_pos_y, random_pos_z
|
||||
|
||||
if look_dir.x > 0 then
|
||||
if look_dir.z > 0 then
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 2.5, player_pos.x + 5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||
end
|
||||
else
|
||||
if look_dir.z > 0 then
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 2.5, player_pos.z + 5)
|
||||
else
|
||||
random_pos_x = math.random() + math.random(player_pos.x - 5, player_pos.x + 2.5)
|
||||
random_pos_z = math.random() + math.random(player_pos.z - 5, player_pos.z + 2.5)
|
||||
end
|
||||
end
|
||||
|
||||
random_pos_y = math.random() + math.random(player_pos.y + 10, player_pos.y + 15)
|
||||
return random_pos_x, random_pos_y, random_pos_z
|
||||
end
|
||||
|
||||
local t, wci = 0, mcl_weather.check_interval
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
|
|
@ -31,6 +31,14 @@ doc.sub.items.register_factoid("nodes", "groups", function(itemstring, def)
|
|||
return ""
|
||||
end)
|
||||
|
||||
-- usable by shovels
|
||||
doc.sub.items.register_factoid("nodes", "groups", function(itemstring, def)
|
||||
if def.groups.path_creation_possible then
|
||||
return S("This block can be turned into grass path with a shovel.")
|
||||
end
|
||||
return ""
|
||||
end)
|
||||
|
||||
-- soil
|
||||
doc.sub.items.register_factoid("nodes", "groups", function(itemstring, def)
|
||||
local datastring = ""
|
||||
|
|
|
@ -21,9 +21,13 @@ minetest.register_chatcommand("awards", {
|
|||
description = S("Show, clear, disable or enable your achievements"),
|
||||
func = function(name, param)
|
||||
if param == "clear" then
|
||||
if awards.player(name).disabled ~= nil then
|
||||
minetest.chat_send_player(name, S("Awards are disabled, enable them first by using /awards enable!"))
|
||||
else
|
||||
awards.clear_player(name)
|
||||
minetest.chat_send_player(name,
|
||||
S("All your awards and statistics have been cleared. You can now start again."))
|
||||
end
|
||||
elseif param == "disable" then
|
||||
awards.disable(name)
|
||||
minetest.chat_send_player(name, S("You have disabled your achievements."))
|
||||
|
@ -31,11 +35,19 @@ minetest.register_chatcommand("awards", {
|
|||
awards.enable(name)
|
||||
minetest.chat_send_player(name, S("You have enabled your achievements."))
|
||||
elseif param == "c" then
|
||||
if awards.player(name).disabled ~= nil then
|
||||
minetest.chat_send_player(name, S("Awards are disabled, enable them first by using /awards enable!"))
|
||||
else
|
||||
awards.show_to(name, name, nil, true)
|
||||
end
|
||||
else
|
||||
if awards.player(name).disabled ~= nil then
|
||||
minetest.chat_send_player(name, S("Awards are disabled, enable them first by using /awards enable!"))
|
||||
else
|
||||
awards.show_to(name, name, nil, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_privilege("achievements", {
|
||||
|
|
|
@ -61,3 +61,4 @@ Achievement “@1” does not exist.=Auszeichnung »@1« existiert nicht.
|
|||
Write something in chat.=Schreiben Sie etwas in den Chat.
|
||||
Write @1 chat messages.=Schreiben Sie @1 Chatnachrichten.
|
||||
@1/@2 chat messages=@1/@2 Chatnachrichten
|
||||
Awards are disabled, enable them first by using /awards enable!=Ihre Auszeichnungen sind aktuell deaktiviert, bitte aktivieren Sie diese zuerst indem Sie /awards enable ausführen bevor Sie diesen Befehl erneut verwenden!
|
|
@ -61,3 +61,4 @@ Achievement “@1” does not exist.=
|
|||
@1 has made the achievement @2=
|
||||
Mine a block: @1=
|
||||
Mine blocks: @1×@2=
|
||||
Awards are disabled, enable them first by using /awards enable!=
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
local refresh_interval = .63
|
||||
local huds = {}
|
||||
local default_debug = 3
|
||||
local after = minetest.after
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local get_biome_name = minetest.get_biome_name
|
||||
local get_biome_data = minetest.get_biome_data
|
||||
local format = string.format
|
||||
|
||||
local min1, min2, min3 = mcl_mapgen.overworld.min, mcl_mapgen.end_.min, mcl_mapgen.nether.min
|
||||
local max1, max2, max3 = mcl_mapgen.overworld.max, mcl_mapgen.end_.max, mcl_mapgen.nether.max + 128
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
local modpath = minetest.get_modpath(modname)
|
||||
local S = minetest.get_translator(modname)
|
||||
local storage = minetest.get_mod_storage()
|
||||
local player_dbg = minetest.deserialize(storage:get_string("player_dbg") or "return {}") or {}
|
||||
|
||||
local function get_text(pos, bits)
|
||||
local bits = bits
|
||||
if bits == 0 then return "" end
|
||||
local y = pos.y
|
||||
if y >= min1 then
|
||||
y = y - min1
|
||||
elseif y >= min3 and y <= max3 then
|
||||
y = y - min3
|
||||
elseif y >= min2 and y <= max2 then
|
||||
y = y - min2
|
||||
end
|
||||
local biome_data = get_biome_data(pos)
|
||||
local biome_name = biome_data and get_biome_name(biome_data.biome) or "No biome"
|
||||
local text
|
||||
if bits == 1 then
|
||||
text = biome_name
|
||||
elseif bits == 2 then
|
||||
text = format("x:%.1f y:%.1f z:%.1f", pos.x, y, pos.z)
|
||||
elseif bits == 3 then
|
||||
text = format("%s x:%.1f y:%.1f z:%.1f", biome_name, pos.x, y, pos.z)
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local function info()
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local name = player:get_player_name()
|
||||
local pos = player:get_pos()
|
||||
local text = get_text(pos, player_dbg[name] or default_debug)
|
||||
local hud = huds[name]
|
||||
if not hud then
|
||||
local def = {
|
||||
hud_elem_type = "text",
|
||||
alignment = {x = 1, y = -1},
|
||||
scale = {x = 100, y = 100},
|
||||
position = {x = 0.0073, y = 0.989},
|
||||
text = text,
|
||||
style = 5,
|
||||
["number"] = 0xcccac0,
|
||||
z_index = 0,
|
||||
}
|
||||
local def_bg = table.copy(def)
|
||||
def_bg.offset = {x = 2, y = 1}
|
||||
def_bg["number"] = 0
|
||||
def_bg.z_index = -1
|
||||
huds[name] = {
|
||||
player:hud_add(def),
|
||||
player:hud_add(def_bg),
|
||||
text,
|
||||
}
|
||||
elseif text ~= hud[3] then
|
||||
hud[3] = text
|
||||
player:hud_change(huds[name][1], "text", text)
|
||||
player:hud_change(huds[name][2], "text", text)
|
||||
end
|
||||
end
|
||||
after(refresh_interval, info)
|
||||
end
|
||||
|
||||
minetest.register_on_authplayer(function(name, ip, is_success)
|
||||
if is_success then
|
||||
huds[name] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_chatcommand("debug",{
|
||||
description = S("Set debug bit mask: 0 = disable, 1 = biome name, 2 = coordinates, 3 = all"),
|
||||
func = function(name, params)
|
||||
local dbg = math.floor(tonumber(params) or default_debug)
|
||||
if dbg < 0 or dbg > 3 then
|
||||
minetest.chat_send_player(name, S("Error! Possible values are integer numbers from @1 to @2", 0, 3))
|
||||
return
|
||||
end
|
||||
if dbg == default_dbg then
|
||||
player_dbg[name] = nil
|
||||
else
|
||||
player_dbg[name] = dbg
|
||||
end
|
||||
minetest.chat_send_player(name, S("Debug bit mask set to @1", dbg))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
storage:set_string("player_dbg", minetest.serialize(player_dbg))
|
||||
end)
|
||||
|
||||
info()
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: mcl_info
|
||||
Set debug bit mask: 0 @= disable, 1 @= biome name, 2 @= coordinates, 3 @= all=Установка отладочной битовой маски: 0 @= отключить, 1 @= биом, 2 @= координаты, 3 @= всё
|
||||
Error! Possible values are integer numbers from @1 to @2=Ошибка! Допустимые значения - целые числа от @1 до @2
|
||||
Debug bit mask set to @1=Отладочной битовой маске присвоено значение @1
|
|
@ -1,4 +0,0 @@
|
|||
# textdomain: mcl_info
|
||||
Set debug bit mask: 0 @= disable, 1 @= biome name, 2 @= coordinates, 3 @= all=
|
||||
Error! Possible values are integer numbers from @1 to @2=
|
||||
Debug bit mask set to @1=
|
|
@ -1,3 +0,0 @@
|
|||
name = mcl_info
|
||||
description = Prints biome name and player position
|
||||
optional_depends = mcl_mapgen
|
|
@ -339,14 +339,6 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
|||
if name == "inv" then
|
||||
inv_bg = "crafting_inventory_creative_survival.png"
|
||||
|
||||
-- Show armor and player image
|
||||
local player_preview
|
||||
if minetest.settings:get_bool("3d_player_preview", true) then
|
||||
player_preview = mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")
|
||||
else
|
||||
player_preview = "image[3.9,1.4;1.2333,2.4666;"..mcl_player.player_get_preview(player).."]"
|
||||
end
|
||||
|
||||
-- Background images for armor slots (hide if occupied)
|
||||
local armor_slot_imgs = ""
|
||||
local inv = player:get_inventory()
|
||||
|
@ -363,6 +355,10 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
|||
armor_slot_imgs = armor_slot_imgs .. "image[5.5,2.75;1,1;mcl_inventory_empty_armor_slot_boots.png]"
|
||||
end
|
||||
|
||||
if inv:get_stack("offhand", 1):is_empty() then
|
||||
armor_slot_imgs = armor_slot_imgs .. "image[1.5,2.025;1,1;mcl_inventory_empty_armor_slot_shield.png]"
|
||||
end
|
||||
|
||||
local stack_size = get_stack_size(player)
|
||||
|
||||
-- Survival inventory slots
|
||||
|
@ -377,9 +373,11 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
|||
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(5.5,2.75,1,1)..
|
||||
"list[current_player;offhand;1.5,2.025;1,1]"..
|
||||
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
|
||||
armor_slot_imgs..
|
||||
-- player preview
|
||||
player_preview..
|
||||
mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")..
|
||||
-- crafting guide button
|
||||
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]"..
|
||||
"tooltip[__mcl_craftguide;"..F(S("Recipe book")).."]"..
|
||||
|
|
|
@ -60,14 +60,6 @@ local function set_inventory(player, armor_change_only)
|
|||
inv:set_width("craft", 2)
|
||||
inv:set_size("craft", 4)
|
||||
|
||||
-- Show armor and player image
|
||||
local player_preview
|
||||
if minetest.settings:get_bool("3d_player_preview", true) then
|
||||
player_preview = mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "")
|
||||
else
|
||||
player_preview = "image[1.1,0.2;2,4;"..mcl_player.player_get_preview(player).."]"
|
||||
end
|
||||
|
||||
local armor_slots = {"helmet", "chestplate", "leggings", "boots"}
|
||||
local armor_slot_imgs = ""
|
||||
for a=1,4 do
|
||||
|
@ -76,9 +68,13 @@ local function set_inventory(player, armor_change_only)
|
|||
end
|
||||
end
|
||||
|
||||
if inv:get_stack("offhand", 1):is_empty() then
|
||||
armor_slot_imgs = armor_slot_imgs .. "image[3,2;1,1;mcl_inventory_empty_armor_slot_shield.png]"
|
||||
end
|
||||
|
||||
local form = "size[9,8.75]"..
|
||||
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
|
||||
player_preview..
|
||||
mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "")..
|
||||
--armor
|
||||
"list[current_player;armor;0,0;1,1;1]"..
|
||||
"list[current_player;armor;0,1;1,1;2]"..
|
||||
|
@ -88,6 +84,8 @@ local function set_inventory(player, armor_change_only)
|
|||
mcl_formspec.get_itemslot_bg(0,1,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(0,2,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(0,3,1,1)..
|
||||
"list[current_player;offhand;3,2;1,1]"..
|
||||
mcl_formspec.get_itemslot_bg(3,2,1,1)..
|
||||
armor_slot_imgs..
|
||||
-- craft and inventory
|
||||
"label[0,4;"..F(minetest.colorize("#313131", S("Inventory"))).."]"..
|
||||
|
@ -148,8 +146,10 @@ end)
|
|||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
--init inventory
|
||||
player:get_inventory():set_width("main", 9)
|
||||
player:get_inventory():set_size("main", 36)
|
||||
local inv = player:get_inventory()
|
||||
inv:set_width("main", 9)
|
||||
inv:set_size("main", 36)
|
||||
inv:set_size("offhand", 1)
|
||||
|
||||
--set hotbar size
|
||||
player:hud_set_hotbar_itemcount(9)
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
local minetest, math = minetest, math
|
||||
mcl_offhand = {}
|
||||
|
||||
local max_offhand_px = 128
|
||||
-- only supports up to 128px textures
|
||||
|
||||
function mcl_offhand.get_offhand(player)
|
||||
return player:get_inventory():get_stack("offhand", 1)
|
||||
end
|
||||
|
||||
local function offhand_get_wear(player)
|
||||
return mcl_offhand.get_offhand(player):get_wear()
|
||||
end
|
||||
|
||||
local function offhand_get_count(player)
|
||||
return mcl_offhand.get_offhand(player):get_count()
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player, last_login)
|
||||
mcl_offhand[player] = {
|
||||
hud = {},
|
||||
last_wear = offhand_get_wear(player),
|
||||
last_count = offhand_get_count(player),
|
||||
}
|
||||
end)
|
||||
|
||||
local function remove_hud(player, hud)
|
||||
local offhand_hud = mcl_offhand[player].hud[hud]
|
||||
if offhand_hud then
|
||||
player:hud_remove(offhand_hud)
|
||||
mcl_offhand[player].hud[hud] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function rgb_to_hex(r, g, b)
|
||||
return string.format("%02x%02x%02x", r, g, b)
|
||||
end
|
||||
|
||||
local function update_wear_bar(player, itemstack)
|
||||
local wear_bar_percent = (65535 - offhand_get_wear(player)) / 65535
|
||||
|
||||
local color = {255, 255, 255}
|
||||
local wear = itemstack:get_wear() / 65535;
|
||||
local wear_i = math.min(math.floor(wear * 600), 511);
|
||||
wear_i = math.min(wear_i + 10, 511);
|
||||
if wear_i <= 255 then
|
||||
color = {wear_i, 255, 0}
|
||||
else
|
||||
color = {255, 511 - wear_i, 0}
|
||||
end
|
||||
local wear_bar = mcl_offhand[player].hud.wear_bar
|
||||
player:hud_change(wear_bar, "text", "mcl_wear_bar.png^[colorize:#" .. rgb_to_hex(color[1], color[2], color[3]))
|
||||
player:hud_change(wear_bar, "scale", {x = 40 * wear_bar_percent, y = 3})
|
||||
player:hud_change(wear_bar, "offset", {x = -320 - (20 - player:hud_get(wear_bar).scale.x / 2), y = -13})
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local itemstack = mcl_offhand.get_offhand(player)
|
||||
local offhand_item = itemstack:get_name()
|
||||
local offhand_hud = mcl_offhand[player].hud
|
||||
if offhand_item ~= "" then
|
||||
local item_texture = minetest.registered_items[offhand_item].inventory_image .. "^[resize:" .. max_offhand_px .. "x" .. max_offhand_px
|
||||
local position = {x = 0.5, y = 1}
|
||||
local offset = {x = -320, y = -32}
|
||||
|
||||
if not offhand_hud.slot then
|
||||
offhand_hud.slot = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = position,
|
||||
offset = offset,
|
||||
scale = {x = 2.75, y = 2.75},
|
||||
text = "mcl_offhand_slot.png",
|
||||
z_index = 0,
|
||||
})
|
||||
end
|
||||
if not offhand_hud.item then
|
||||
offhand_hud.item = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = position,
|
||||
offset = offset,
|
||||
scale = {x = 0.4, y = 0.4},
|
||||
text = item_texture,
|
||||
z_index = 1,
|
||||
})
|
||||
else
|
||||
player:hud_change(offhand_hud.item, "text", item_texture)
|
||||
end
|
||||
if not offhand_hud.wear_bar_bg and minetest.registered_tools[offhand_item] then
|
||||
if offhand_get_wear(player) > 0 then
|
||||
local texture = "mcl_wear_bar.png^[colorize:#000000"
|
||||
offhand_hud.wear_bar_bg = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = {x = 0.5, y = 1},
|
||||
offset = {x = -320, y = -13},
|
||||
scale = {x = 40, y = 3},
|
||||
text = texture,
|
||||
z_index = 2,
|
||||
})
|
||||
offhand_hud.wear_bar = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
position = {x = 0.5, y = 1},
|
||||
offset = {x = -320, y = -13},
|
||||
scale = {x = 10, y = 3},
|
||||
text = texture,
|
||||
z_index = 3,
|
||||
})
|
||||
update_wear_bar(player, itemstack)
|
||||
end
|
||||
end
|
||||
|
||||
if not offhand_hud.item_count and offhand_get_count(player) > 1 then
|
||||
offhand_hud.item_count = player:hud_add({
|
||||
hud_elem_type = "text",
|
||||
position = {x = 0.5, y = 1},
|
||||
offset = {x = -298, y = -18},
|
||||
scale = {x = 1, y = 1},
|
||||
alignment = {x = -1, y = 0},
|
||||
text = offhand_get_count(player),
|
||||
z_index = 4,
|
||||
number = 0xFFFFFF,
|
||||
})
|
||||
end
|
||||
|
||||
if offhand_hud.wear_bar then
|
||||
if offhand_hud.last_wear ~= offhand_get_wear(player) then
|
||||
update_wear_bar(player, itemstack)
|
||||
offhand_hud.last_wear = offhand_get_wear(player)
|
||||
end
|
||||
if offhand_get_wear(player) <= 0 or not minetest.registered_tools[offhand_item] then
|
||||
remove_hud(player, "wear_bar_bg")
|
||||
remove_hud(player, "wear_bar")
|
||||
end
|
||||
end
|
||||
|
||||
if offhand_hud.item_count then
|
||||
if offhand_hud.last_count ~= offhand_get_count(player) then
|
||||
player:hud_change(offhand_hud.item_count, "text", offhand_get_count(player))
|
||||
offhand_hud.last_count = offhand_get_count(player)
|
||||
end
|
||||
if offhand_get_count(player) <= 1 then
|
||||
remove_hud(player, "item_count")
|
||||
end
|
||||
end
|
||||
|
||||
elseif offhand_hud.slot then
|
||||
for index, _ in pairs(mcl_offhand[player].hud) do
|
||||
remove_hud(player, index)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||
if action == "move" and inventory_info.to_list == "offhand" then
|
||||
local itemstack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index)
|
||||
if not (minetest.get_item_group(itemstack:get_name(), "offhand_item") > 0) then
|
||||
return 0
|
||||
else
|
||||
return itemstack:get_stack_max()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||
local from_offhand = inventory_info.from_list == "offhand"
|
||||
local to_offhand = inventory_info.to_list == "offhand"
|
||||
if action == "move" and from_offhand or to_offhand then
|
||||
mcl_inventory.update_inventory_formspec(player)
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_offhand
|
||||
author = NO11
|
||||
depends = mcl_inventory
|
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 168 B |
|
@ -1,220 +0,0 @@
|
|||
--[[ This mod registers 3 nodes:
|
||||
- One node for the horizontal-facing dropper (mcl_droppers:dropper)
|
||||
- One node for the upwards-facing droppers (mcl_droppers:dropper_up)
|
||||
- One node for the downwards-facing droppers (mcl_droppers:dropper_down)
|
||||
|
||||
3 node definitions are needed because of the way the textures are defined.
|
||||
All node definitions share a lot of code, so this is the reason why there
|
||||
are so many weird tables below.
|
||||
]]
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-- For after_place_node
|
||||
local function setup_dropper(pos)
|
||||
-- Set formspec and inventory
|
||||
local form = "size[9,8.75]"..
|
||||
"background[-0.19,-0.25;9.41,9.49;crafting_inventory_9_slots.png]"..
|
||||
"label[0,4.0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Inventory"))).."]"..
|
||||
"list[current_player;main;0,4.5;9,3;9]"..
|
||||
"list[current_player;main;0,7.74;9,1;]"..
|
||||
"label[3,0;"..minetest.formspec_escape(minetest.colorize("#313131", S("Dropper"))).."]"..
|
||||
"list[context;main;3,0.5;3,3;]"..
|
||||
"listring[context;main]"..
|
||||
"listring[current_player;main]"
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", form)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 9)
|
||||
end
|
||||
|
||||
local function orientate_dropper(pos, placer)
|
||||
-- Not placed by player
|
||||
if not placer then return end
|
||||
|
||||
-- Pitch in degrees
|
||||
local pitch = placer:get_look_vertical() * (180 / math.pi)
|
||||
|
||||
if pitch > 55 then
|
||||
minetest.swap_node(pos, {name="mcl_droppers:dropper_up"})
|
||||
elseif pitch < -55 then
|
||||
minetest.swap_node(pos, {name="mcl_droppers:dropper_down"})
|
||||
end
|
||||
end
|
||||
|
||||
local on_rotate
|
||||
if minetest.get_modpath("screwdriver") then
|
||||
on_rotate = screwdriver.rotate_simple
|
||||
end
|
||||
|
||||
-- Shared core definition table
|
||||
local dropperdef = {
|
||||
is_ground_content = false,
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local meta2 = meta:to_table()
|
||||
meta:from_table(oldmetadata)
|
||||
local inv = meta:get_inventory()
|
||||
for i=1, inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i)
|
||||
if not stack:is_empty() then
|
||||
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
|
||||
minetest.add_item(p, stack)
|
||||
end
|
||||
end
|
||||
meta:from_table(meta2)
|
||||
end,
|
||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
local name = player:get_player_name()
|
||||
if minetest.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return 0
|
||||
else
|
||||
return count
|
||||
end
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
local name = player:get_player_name()
|
||||
if minetest.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return 0
|
||||
else
|
||||
return stack:get_count()
|
||||
end
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local name = player:get_player_name()
|
||||
if minetest.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return 0
|
||||
else
|
||||
return stack:get_count()
|
||||
end
|
||||
end,
|
||||
_mcl_blast_resistance = 3.5,
|
||||
_mcl_hardness = 3.5,
|
||||
mesecons = {effector = {
|
||||
-- Drop random item when triggered
|
||||
action_on = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local droppos
|
||||
if node.name == "mcl_droppers:dropper" then
|
||||
droppos = vector.subtract(pos, minetest.facedir_to_dir(node.param2))
|
||||
elseif node.name == "mcl_droppers:dropper_up" then
|
||||
droppos = {x=pos.x, y=pos.y+1, z=pos.z}
|
||||
elseif node.name == "mcl_droppers:dropper_down" then
|
||||
droppos = {x=pos.x, y=pos.y-1, z=pos.z}
|
||||
end
|
||||
local dropnode = minetest.get_node(droppos)
|
||||
-- Do not drop into solid nodes, unless they are containers
|
||||
local dropnodedef = minetest.registered_nodes[dropnode.name]
|
||||
if dropnodedef.walkable and not dropnodedef.groups.container then
|
||||
return
|
||||
end
|
||||
local stacks = {}
|
||||
for i=1,inv:get_size("main") do
|
||||
local stack = inv:get_stack("main", i)
|
||||
if not stack:is_empty() then
|
||||
table.insert(stacks, {stack = stack, stackpos = i})
|
||||
end
|
||||
end
|
||||
if #stacks >= 1 then
|
||||
local r = math.random(1, #stacks)
|
||||
local stack = stacks[r].stack
|
||||
local dropitem = ItemStack(stack)
|
||||
dropitem:set_count(1)
|
||||
local stack_id = stacks[r].stackpos
|
||||
|
||||
-- If it's a container, attempt to put it into the container
|
||||
local dropped = mcl_util.move_item_container(pos, droppos, nil, stack_id)
|
||||
-- No container?
|
||||
if not dropped and not dropnodedef.groups.container then
|
||||
-- Drop item normally
|
||||
minetest.add_item(droppos, dropitem)
|
||||
stack:take_item()
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
end
|
||||
end
|
||||
end,
|
||||
rules = mesecon.rules.alldirs,
|
||||
}},
|
||||
on_rotate = on_rotate,
|
||||
}
|
||||
|
||||
-- Horizontal dropper
|
||||
|
||||
local horizontal_def = table.copy(dropperdef)
|
||||
horizontal_def.description = S("Dropper")
|
||||
horizontal_def._doc_items_longdesc = S("A dropper is a redstone component and a container with 9 inventory slots which, when supplied with redstone power, drops an item or puts it into a container in front of it.")
|
||||
horizontal_def._doc_items_usagehelp = S("Droppers can be placed in 6 possible directions, items will be dropped out of the hole. Use the dropper to access its inventory. Supply it with redstone energy once to make the dropper drop or transfer a random item.")
|
||||
|
||||
function horizontal_def.after_place_node(pos, placer, itemstack, pointed_thing)
|
||||
setup_dropper(pos)
|
||||
orientate_dropper(pos, placer)
|
||||
end
|
||||
|
||||
horizontal_def.tiles = {
|
||||
"default_furnace_top.png", "default_furnace_bottom.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "mcl_droppers_dropper_front_horizontal.png",
|
||||
}
|
||||
horizontal_def.paramtype2 = "facedir"
|
||||
horizontal_def.groups = {pickaxey=1, container=2, material_stone=1}
|
||||
|
||||
minetest.register_node("mcl_droppers:dropper", horizontal_def)
|
||||
|
||||
-- Down dropper
|
||||
local down_def = table.copy(dropperdef)
|
||||
down_def.description = S("Downwards-Facing Dropper")
|
||||
down_def.after_place_node = setup_dropper
|
||||
down_def.tiles = {
|
||||
"default_furnace_top.png", "mcl_droppers_dropper_front_vertical.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
}
|
||||
down_def.groups = {pickaxey=1, container=2,not_in_creative_inventory=1, material_stone=1}
|
||||
down_def._doc_items_create_entry = false
|
||||
down_def.drop = "mcl_droppers:dropper"
|
||||
minetest.register_node("mcl_droppers:dropper_down", down_def)
|
||||
|
||||
-- Up dropper
|
||||
-- The up dropper is almost identical to the down dropper, it only differs in textures
|
||||
local up_def = table.copy(down_def)
|
||||
up_def.description = S("Upwards-Facing Dropper")
|
||||
up_def.tiles = {
|
||||
"mcl_droppers_dropper_front_vertical.png", "default_furnace_bottom.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
"default_furnace_side.png", "default_furnace_side.png",
|
||||
}
|
||||
minetest.register_node("mcl_droppers:dropper_up", up_def)
|
||||
|
||||
|
||||
|
||||
-- Ladies and gentlemen, I present to you: the crafting recipe!
|
||||
minetest.register_craft({
|
||||
output = "mcl_droppers:dropper",
|
||||
recipe = {
|
||||
{"mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble",},
|
||||
{"mcl_core:cobble", "", "mcl_core:cobble",},
|
||||
{"mcl_core:cobble", "mesecons:redstone", "mcl_core:cobble",},
|
||||
}
|
||||
})
|
||||
|
||||
-- Add entry aliases for the Help
|
||||
if minetest.get_modpath("doc") then
|
||||
doc.add_entry_alias("nodes", "mcl_droppers:dropper", "nodes", "mcl_droppers:dropper_down")
|
||||
doc.add_entry_alias("nodes", "mcl_droppers:dropper", "nodes", "mcl_droppers:dropper_up")
|
||||
end
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update dropper formspecs (0.51.0)",
|
||||
name = "mcl_droppers:update_formspecs_0_51_0",
|
||||
nodenames = { "mcl_droppers:dropper", "mcl_droppers:dropper_down", "mcl_droppers:dropper_up" },
|
||||
action = function(pos, node)
|
||||
minetest.registered_nodes[node.name].on_construct(pos)
|
||||
minetest.log("action", "[mcl_droppers] Node formspec updated at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
})
|
||||
|
|
@ -47,8 +47,6 @@ end
|
|||
|
||||
-- For nodes which ignore sticky sides.
|
||||
-- They can't be pulled by sticky pistons and don't interact with slime blocks.
|
||||
-- TODO: This has NOT any actual effect so far. The actual functionality
|
||||
-- still needs to be implemented.
|
||||
function mesecon.register_mvps_unsticky(nodename, get_unsticky)
|
||||
if get_unsticky == nil then
|
||||
get_unsticky = true
|
||||
|
@ -66,9 +64,6 @@ function mesecon.is_mvps_unsticky(node, pulldir, stack, stackid)
|
|||
if type(get_unsticky) == "function" then
|
||||
get_unsticky = get_unsticky(node, pulldir, stack, stackid)
|
||||
end
|
||||
if get_unsticky == nil then
|
||||
get_unsticky = false
|
||||
end
|
||||
|
||||
return get_unsticky
|
||||
end
|
||||
|
@ -211,8 +206,16 @@ function mesecon.mvps_push(pos, dir, maximum, player_name, piston_pos)
|
|||
end
|
||||
|
||||
function mesecon.mvps_pull_single(pos, dir, maximum, player_name, piston_pos)
|
||||
local nodes = mesecon.mvps_get_stack(pos, dir, maximum, player_name, piston_pos)
|
||||
|
||||
if not nodes then return end
|
||||
-- ensure sticky pistons; even without slimeblocks attached adhere to the unpullable rule.
|
||||
for id, n in ipairs(nodes) do
|
||||
if not mesecon.is_mvps_unsticky(n.node, dir, nodes, id) then
|
||||
return mesecon.mvps_push_or_pull(pos, vector.multiply(dir, -1), dir, maximum, player_name, piston_pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- pos: pos of mvps; stackdir: direction of building the stack
|
||||
-- movedir: direction of actual movement
|
||||
|
@ -357,13 +360,14 @@ function mesecon.mvps_move_objects(pos, dir, nodestack)
|
|||
end
|
||||
end
|
||||
|
||||
-- Unmovable by design
|
||||
-- Unmovable by design: nodes
|
||||
mesecon.register_mvps_stopper("mcl_core:barrier")
|
||||
mesecon.register_mvps_stopper("mcl_core:realm_barrier")
|
||||
mesecon.register_mvps_stopper("mcl_core:void")
|
||||
mesecon.register_mvps_stopper("mcl_core:bedrock")
|
||||
mesecon.register_mvps_stopper("mcl_core:obsidian")
|
||||
mesecon.register_mvps_stopper("mcl_chests:ender_chest")
|
||||
mesecon.register_mvps_stopper("mcl_chests:ender_chest_small")
|
||||
mesecon.register_mvps_stopper("mcl_mobspawners:spawner")
|
||||
mesecon.register_mvps_stopper("mesecons_commandblock:commandblock_off")
|
||||
mesecon.register_mvps_stopper("mesecons_commandblock:commandblock_on")
|
||||
|
@ -371,9 +375,18 @@ mesecon.register_mvps_stopper("mcl_portals:portal")
|
|||
mesecon.register_mvps_stopper("mcl_portals:portal_end")
|
||||
mesecon.register_mvps_stopper("mcl_portals:end_portal_frame")
|
||||
mesecon.register_mvps_stopper("mcl_portals:end_portal_frame_eye")
|
||||
mesecon.register_mvps_stopper("mcl_enchanting:table")
|
||||
mesecon.register_mvps_stopper("mcl_jukebox:jukebox")
|
||||
mesecon.register_mvps_stopper("mesecons_solarpanel:solar_panel_on")
|
||||
mesecon.register_mvps_stopper("mesecons_solarpanel:solar_panel_off")
|
||||
mesecon.register_mvps_stopper("mesecons_solarpanel:solar_panel_inverted_on")
|
||||
mesecon.register_mvps_stopper("mesecons_solarpanel:solar_panel_inverted_off")
|
||||
mesecon.register_mvps_stopper("mcl_banners:hanging_banner")
|
||||
mesecon.register_mvps_stopper("mcl_banners:standing_banner")
|
||||
|
||||
-- Unmovable by technical restrictions.
|
||||
-- Open formspec would screw up if node is destroyed (minor problem)
|
||||
-- Would screw up on/off state of trapped chest (big problem)
|
||||
mesecon.register_mvps_stopper("mcl_furnaces:furnace")
|
||||
mesecon.register_mvps_stopper("mcl_furnaces:furnace_active")
|
||||
mesecon.register_mvps_stopper("mcl_hoppers:hopper")
|
||||
|
@ -387,9 +400,39 @@ mesecon.register_mvps_stopper("mcl_dispensers:dispenser_down")
|
|||
mesecon.register_mvps_stopper("mcl_anvils:anvil")
|
||||
mesecon.register_mvps_stopper("mcl_anvils:anvil_damage_1")
|
||||
mesecon.register_mvps_stopper("mcl_anvils:anvil_damage_2")
|
||||
-- Would screw up on/off state of trapped chest (big problem)
|
||||
mesecon.register_mvps_stopper("mcl_chests:chest")
|
||||
mesecon.register_mvps_stopper("mcl_chests:chest_small")
|
||||
mesecon.register_mvps_stopper("mcl_chests:chest_left")
|
||||
mesecon.register_mvps_stopper("mcl_chests:chest_right")
|
||||
mesecon.register_mvps_stopper("mcl_chests:trapped_chest")
|
||||
mesecon.register_mvps_stopper("mcl_chests:trapped_chest_small")
|
||||
mesecon.register_mvps_stopper("mcl_chests:trapped_chest_left")
|
||||
mesecon.register_mvps_stopper("mcl_chests:trapped_chest_right")
|
||||
mesecon.register_mvps_stopper("mcl_signs:wall_sign")
|
||||
mesecon.register_mvps_stopper("mcl_signs:standing_sign")
|
||||
mesecon.register_mvps_stopper("mcl_signs:standing_sign22_5")
|
||||
mesecon.register_mvps_stopper("mcl_signs:standing_sign45")
|
||||
mesecon.register_mvps_stopper("mcl_signs:standing_sign67_5")
|
||||
mesecon.register_mvps_stopper("mcl_barrels:barrel_open")
|
||||
mesecon.register_mvps_stopper("mcl_barrels:barrel_closed")
|
||||
|
||||
-- Glazed terracotta: unpullable
|
||||
|
||||
-- Unmovable by design: objects
|
||||
mesecon.register_mvps_unmov("mcl_enchanting:book")
|
||||
mesecon.register_mvps_unmov("mcl_chests:chest")
|
||||
mesecon.register_mvps_unmov("mcl_banners:hanging_banner")
|
||||
mesecon.register_mvps_unmov("mcl_banners:standing_banner")
|
||||
mesecon.register_mvps_unmov("mcl_signs:text")
|
||||
mesecon.register_mvps_unmov("mcl_mobspawners:doll")
|
||||
mesecon.register_mvps_unmov("mcl_armor_stand:armor_entity")
|
||||
mesecon.register_mvps_unmov("mcl_itemframes:item")
|
||||
mesecon.register_mvps_unmov("mcl_itemframes:map")
|
||||
mesecon.register_mvps_unmov("mcl_paintings:painting")
|
||||
mesecon.register_mvps_unmov("mcl_end:crystal")
|
||||
|
||||
|
||||
-- Unpullable by design: nodes
|
||||
-- Glazed Terracotta
|
||||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_red")
|
||||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_orange")
|
||||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_yellow")
|
||||
|
@ -406,6 +449,446 @@ mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_black")
|
|||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_brown")
|
||||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_light_blue")
|
||||
mesecon.register_mvps_unsticky("mcl_colorblocks:glazed_terracotta_pink")
|
||||
-- Beds
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_black_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_black_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_blue_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_blue_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_brown_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_brown_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_cyan_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_cyan_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_green_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_green_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_grey_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_grey_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_light_blue_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_light_blue_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_lime_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_lime_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_magenta_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_magenta_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_orange_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_orange_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_pink_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_pink_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_purple_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_purple_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_red_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_red_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_silver_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_silver_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_white_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_white_bottom")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_yellow_top")
|
||||
mesecon.register_mvps_unsticky("mcl_beds:bed_yellow_bottom")
|
||||
-- Buttons
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_stone_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_stone_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_wood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_wood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_acaciawood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_acaciawood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_birchwood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_birchwood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_darkwood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_darkwood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_sprucewood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_sprucewood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_junglewood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_button:button_junglewood_on")
|
||||
-- Cactus, Sugarcane & Vines
|
||||
mesecon.register_mvps_unsticky("mcl_core:cactus")
|
||||
mesecon.register_mvps_unsticky("mcl_core:reeds")
|
||||
mesecon.register_mvps_unsticky("mcl_core:vine")
|
||||
-- Cake
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_1")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_2")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_3")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_4")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_5")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake_6")
|
||||
mesecon.register_mvps_unsticky("mcl_cake:cake")
|
||||
-- Carpet
|
||||
mesecon.register_mvps_unsticky("mcl_wool:black_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:blue_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:brown_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:cyan_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:green_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:grey_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:light_blue_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:lime_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:orange_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:magenta_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:pink_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:purple_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:red_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:silver_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:white_carpet")
|
||||
mesecon.register_mvps_unsticky("mcl_wool:yellow_carpet")
|
||||
-- Carved & Jack O'Lantern Pumpkins, Pumpkin & Melon
|
||||
mesecon.register_mvps_unsticky("mcl_farming:pumpkin_face")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:pumpkin_face_light")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:pumpkin")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:melon")
|
||||
-- Chorus Plant & Flower
|
||||
mesecon.register_mvps_unsticky("mcl_end:chorus_plant")
|
||||
mesecon.register_mvps_unsticky("mcl_end:chorus_flower")
|
||||
-- Cobweb
|
||||
mesecon.register_mvps_unsticky("mcl_core:cobweb")
|
||||
-- Cocoa
|
||||
mesecon.register_mvps_unsticky("mcl_cocoas:cocoa_1")
|
||||
mesecon.register_mvps_unsticky("mcl_cocoas:cocoa_2")
|
||||
mesecon.register_mvps_unsticky("mcl_cocoas:cocoa_3")
|
||||
-- Doors
|
||||
mesecon.register_mvps_unsticky("mcl_doors:wooden_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:wooden_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:wooden_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:wooden_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:iron_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:iron_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:iron_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:iron_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:acacia_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:acacia_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:acacia_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:acacia_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:birch_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:birch_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:birch_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:birch_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:dark_oak_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:dark_oak_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:dark_oak_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:dark_oak_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:spruce_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:spruce_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:spruce_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:spruce_door_b_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:jungle_door_t_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:jungle_door_b_1")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:jungle_door_t_2")
|
||||
mesecon.register_mvps_unsticky("mcl_doors:jungle_door_b_2")
|
||||
-- Dragon Egg
|
||||
mesecon.register_mvps_unsticky("mcl_end:dragon_egg")
|
||||
-- Fire
|
||||
mesecon.register_mvps_unsticky("mcl_fire:fire")
|
||||
mesecon.register_mvps_unsticky("mcl_fire:eternal_fire")
|
||||
-- Flower Pots
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_allium")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_azure_bluet")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_blue_orchid")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_dandelion")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_fern")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_oxeye_daisy")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_poppy")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_tulip_orange")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_tulip_pink")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_tulip_red")
|
||||
mesecon.register_mvps_unsticky("mcl_flowerpots:flower_pot_tulip_white")
|
||||
-- Flowers, Lilypad & Dead Bush
|
||||
mesecon.register_mvps_unsticky("mcl_core:deadbush")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:allium")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:azure_bluet")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:blue_orchid")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:dandelion")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:double_fern")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:double_fern_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:fern")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:lilac")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:lilac_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:oxeye_daisy")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:peony")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:peony_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:poppy")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:rose_bush")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:rose_bush_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:sunflower")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:sunflower_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:tallgrass")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:double_grass")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:double_grass_top")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:tulip_orange")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:tulip_pink")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:tulip_red")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:tulip_white")
|
||||
mesecon.register_mvps_unsticky("mcl_flowers:waterlily")
|
||||
-- Heads
|
||||
mesecon.register_mvps_unsticky("mcl_heads:creeper")
|
||||
mesecon.register_mvps_unsticky("mcl_heads:skeleton")
|
||||
mesecon.register_mvps_unsticky("mcl_heads:steve")
|
||||
mesecon.register_mvps_unsticky("mcl_heads:wither_skeleton")
|
||||
mesecon.register_mvps_unsticky("mcl_heads:zombie")
|
||||
-- Item Frame
|
||||
mesecon.register_mvps_unsticky("mcl_itemframes:item_frame")
|
||||
-- Ladder
|
||||
mesecon.register_mvps_unsticky("mcl_core:ladder")
|
||||
-- Lava & Water
|
||||
mesecon.register_mvps_unsticky("mcl_core:lava_source")
|
||||
mesecon.register_mvps_unsticky("mcl_core:lava_flowing")
|
||||
mesecon.register_mvps_unsticky("mcl_core:water_source")
|
||||
mesecon.register_mvps_unsticky("mcl_core:water_flowing")
|
||||
mesecon.register_mvps_unsticky("mclx_core:river_water_source")
|
||||
mesecon.register_mvps_unsticky("mclx_core:river_water_flowing")
|
||||
-- Leaves
|
||||
mesecon.register_mvps_unsticky("mcl_core:leaves")
|
||||
mesecon.register_mvps_unsticky("mcl_core:acacialeaves")
|
||||
mesecon.register_mvps_unsticky("mcl_core:birchleaves")
|
||||
mesecon.register_mvps_unsticky("mcl_core:darkleaves")
|
||||
mesecon.register_mvps_unsticky("mcl_core:spruceleaves")
|
||||
mesecon.register_mvps_unsticky("mcl_core:jungleleaves")
|
||||
-- Lever
|
||||
mesecon.register_mvps_unsticky("mesecons_walllever:wall_lever_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_walllever:wall_lever_on")
|
||||
-- Mushrooms, Nether Wart & Amethyst
|
||||
mesecon.register_mvps_unsticky("mcl_mushroom:mushroom_brown")
|
||||
mesecon.register_mvps_unsticky("mcl_mushroom:mushroom_red")
|
||||
mesecon.register_mvps_unsticky("mcl_nether:nether_wart_0")
|
||||
mesecon.register_mvps_unsticky("mcl_nether:nether_wart_1")
|
||||
mesecon.register_mvps_unsticky("mcl_nether:nether_wart_2")
|
||||
mesecon.register_mvps_unsticky("mcl_nether:nether_wart")
|
||||
mesecon.register_mvps_unsticky("mcl_amethyst:amethyst_cluster")
|
||||
mesecon.register_mvps_unsticky("mcl_amethyst:budding_amethyst_block")
|
||||
-- Pressure Plates
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_wood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_wood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_stone_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_stone_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_acaciawood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_acaciawoood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_birchwood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_birchwood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_darkwood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_darkwood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_sprucekwood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_sprucewood_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_junglewood_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_pressureplates:pressure_plate_junglewood_off")
|
||||
-- Redstone Comparators
|
||||
mesecon.register_mvps_unsticky("mcl_comparators:comparator_on_sub")
|
||||
mesecon.register_mvps_unsticky("mcl_comparators:comparator_off_sub")
|
||||
mesecon.register_mvps_unsticky("mcl_comparators:comparator_on_comp")
|
||||
mesecon.register_mvps_unsticky("mcl_comparators:comparator_off_comp")
|
||||
-- Redstone Dust
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00000000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00000000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10000000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10000000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01000000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01000000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11000000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11000000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00100000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00100000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10100000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10100000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00010000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00010000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10010000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10010000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10001000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10001000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11001000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11001000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10101000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10101000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10011000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10011000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111000_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111000_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01000100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01000100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11000100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11000100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11001100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11001100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111100_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111100_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00100010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00100010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10100010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10100010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10101010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10101010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111010_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111010_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01100110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11100110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11101110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111110_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111110_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00010001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00010001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10010001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10010001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10011001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10011001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111001_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111001_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01010101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11010101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11011101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111101_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111101_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_00110011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10110011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_10111011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111011_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111011_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110111_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_01110111_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110111_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11110111_off")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111111_on")
|
||||
mesecon.register_mvps_unsticky("mesecons:wire_11111111_off")
|
||||
-- Redstone Repeater
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_off_1")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_off_2")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_off_3")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_off_4")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_on_1")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_on_2")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_on_3")
|
||||
mesecon.register_mvps_unsticky("mesecons_delayer:delayer_on_4")
|
||||
-- Redstone Torch
|
||||
mesecon.register_mvps_unsticky("mesecons_torch:mesecon_torch_on")
|
||||
mesecon.register_mvps_unsticky("mesecons_torch:mesecon_torch_off")
|
||||
mesecon.register_mvps_unsticky("mesecons_torch:mesecon_torch_on_wall")
|
||||
mesecon.register_mvps_unsticky("mesecons_torch:mesecon_torch_off_wall")
|
||||
-- Sea Pickle
|
||||
mesecon.register_mvps_unsticky("mcl_ocean:sea_pickle_1_dead_brain_coral_block")
|
||||
mesecon.register_mvps_unsticky("mcl_ocean:sea_pickle_2_dead_brain_coral_block")
|
||||
mesecon.register_mvps_unsticky("mcl_ocean:sea_pickle_3_dead_brain_coral_block")
|
||||
mesecon.register_mvps_unsticky("mcl_ocean:sea_pickle_4_dead_brain_coral_block")
|
||||
-- Shulker chests
|
||||
mesecon.register_mvps_unsticky("mcl_chests:black_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:blue_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:brown_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:cyan_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:green_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:grey_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:light_blue_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:lime_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:orange_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:magenta_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:pink_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:purple_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:red_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:silver_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:white_shulker_box_small")
|
||||
mesecon.register_mvps_unsticky("mcl_chests:yellow_shulker_box_small")
|
||||
-- Snow
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_2")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_3")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_4")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_5")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_6")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_7")
|
||||
mesecon.register_mvps_unsticky("mcl_core:snow_8")
|
||||
-- Torch
|
||||
mesecon.register_mvps_unsticky("mcl_torches:torch")
|
||||
mesecon.register_mvps_unsticky("mcl_torches:torch_wall")
|
||||
-- Wheat
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_2")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_3")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_4")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_5")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_6")
|
||||
mesecon.register_mvps_unsticky("mcl_farming:wheat_7")
|
||||
|
||||
-- Includes node heat when moving them
|
||||
mesecon.register_on_mvps_move(mesecon.move_hot_nodes)
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
local interval = 10
|
||||
local chance = 5
|
||||
|
||||
local function grow(pos, node)
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
local next_gen = def._mcl_amethyst_next_grade
|
||||
if not next_gen then return end
|
||||
|
||||
local dir = minetest.wallmounted_to_dir(node.param2)
|
||||
local ba_pos = vector.add(pos, dir)
|
||||
local ba_node = minetest.get_node(ba_pos)
|
||||
if ba_node.name ~= "mcl_amethyst:budding_amethyst_block" then return end
|
||||
|
||||
local swap_result = table.copy(node)
|
||||
swap_result.name = next_gen
|
||||
minetest.swap_node(pos, swap_result)
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Amethyst Bud Growth",
|
||||
nodenames = {"group:amethyst_buds"},
|
||||
neighbors = {"mcl_amethyst:budding_amethyst_block"},
|
||||
interval = interval,
|
||||
chance = chance,
|
||||
action = grow,
|
||||
})
|
||||
|
||||
local all_directions = {
|
||||
vector.new(1, 0, 0),
|
||||
vector.new(0, 1, 0),
|
||||
vector.new(0, 0, 1),
|
||||
vector.new(-1, 0, 0),
|
||||
vector.new(0, -1, 0),
|
||||
vector.new(0, 0, -1),
|
||||
}
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Spawn Amethyst Bud",
|
||||
nodenames = {"mcl_amethyst:budding_amethyst_block"},
|
||||
neighbors = {"air", "group:water"},
|
||||
interval = 20,
|
||||
chance = 2,
|
||||
action = function(pos)
|
||||
local check_pos = vector.add(all_directions[math.random(1, #all_directions)], pos)
|
||||
local check_node = minetest.get_node(check_pos)
|
||||
local check_node_name = check_node.name
|
||||
if check_node_name ~= "air" and minetest.get_item_group(check_node_name, "water") == 0 then return end
|
||||
local param2 = minetest.dir_to_wallmounted(vector.subtract(pos, check_pos))
|
||||
local new_node = {name = "mcl_amethyst:small_amethyst_bud", param2 = param2}
|
||||
minetest.swap_node(check_pos, new_node)
|
||||
end,
|
||||
})
|
|
@ -0,0 +1,220 @@
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
local sounds = mcl_sounds.node_sound_glass_defaults({
|
||||
footstep = {name = "mcl_amethyst_amethyst_walk", gain = 0.4},
|
||||
dug = {name = "mcl_amethyst_amethyst_break", gain = 0.44},
|
||||
})
|
||||
|
||||
-- Amethyst block
|
||||
minetest.register_node("mcl_amethyst:amethyst_block",{
|
||||
description = S("Block of Amethyst"),
|
||||
_doc_items_longdesc = S("The Block of Amethyst is a decoration block crafted from amethyst shards."),
|
||||
tiles = {"mcl_amethyst_amethyst_block.png"},
|
||||
groups = {pickaxey = 1, building_block = 1},
|
||||
sounds = sounds,
|
||||
is_ground_content = true,
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_blast_resistance = 1.5,
|
||||
})
|
||||
|
||||
minetest.register_node("mcl_amethyst:budding_amethyst_block",{
|
||||
description = S("Budding Amethyst"),
|
||||
_doc_items_longdesc = S("The Budding Amethyst can grow amethyst"),
|
||||
tiles = {"mcl_amethyst_budding_amethyst.png"},
|
||||
drop = "",
|
||||
groups = {
|
||||
pickaxey = 1,
|
||||
building_block = 1,
|
||||
dig_by_piston = 1,
|
||||
},
|
||||
sounds = sounds,
|
||||
is_ground_content = true,
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_blast_resistance = 1.5,
|
||||
})
|
||||
|
||||
mcl_wip.register_wip_item("mcl_amethyst:budding_amethyst_block")
|
||||
|
||||
-- Amethyst Shard
|
||||
minetest.register_craftitem("mcl_amethyst:amethyst_shard",{
|
||||
description = S("Amethyst Shard"),
|
||||
_doc_items_longdesc = S("An amethyst shard is a crystalline mineral."),
|
||||
inventory_image = "mcl_amethyst_amethyst_shard.png",
|
||||
groups = {craftitem = 1},
|
||||
})
|
||||
|
||||
-- Calcite
|
||||
minetest.register_node("mcl_amethyst:calcite",{
|
||||
description = S("Calcite"),
|
||||
_doc_items_longdesc = S("Calcite can be found as part of amethyst geodes."),
|
||||
tiles = {"mcl_amethyst_calcite_block.png"},
|
||||
groups = {pickaxey = 1, building_block = 1},
|
||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||
is_ground_content = true,
|
||||
_mcl_hardness = 0.75,
|
||||
_mcl_blast_resistance = 0.75,
|
||||
})
|
||||
|
||||
-- Tinied Glass
|
||||
minetest.register_node("mcl_amethyst:tinted_glass",{
|
||||
description = S("Tinted Glass"),
|
||||
_doc_items_longdesc = S("Tinted Glass is a type of glass which blocks lights while it is visually transparent."),
|
||||
tiles = {"mcl_amethyst_tinted_glass.png"},
|
||||
_mcl_hardness = 0.3,
|
||||
_mcl_blast_resistance = 0.3,
|
||||
drawtype = "glasslike",
|
||||
use_texture_alpha = "blend",
|
||||
sunlight_propagates = false,
|
||||
groups = {handy = 1, building_block = 1, deco_block = 1},
|
||||
sounds = mcl_sounds.node_sound_glass_defaults(),
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
-- Amethyst Cluster
|
||||
local bud_def = {
|
||||
{
|
||||
size = "small",
|
||||
description = S("Small Amethyst Bud"),
|
||||
long_desc = S("Small Amethyst Bud is the first growth of amethyst bud."),
|
||||
light_source = 3,
|
||||
next_stage = "mcl_amethyst:medium_amethyst_bud",
|
||||
selection_box = { -4/16, -7/16, -4/16, 4/16, -3/16, 4/16 },
|
||||
},
|
||||
{
|
||||
size = "medium",
|
||||
description = S("Medium Amethyst Bud"),
|
||||
long_desc = S("Medium Amethyst Bud is the second growth of amethyst bud."),
|
||||
light_source = 4,
|
||||
next_stage = "mcl_amethyst:large_amethyst_bud",
|
||||
selection_box = { -4.5/16, -8/16, -4.5/16, 4.5/16, -2/16, 4.5/16 },
|
||||
},
|
||||
{
|
||||
size = "large",
|
||||
description = S("Large Amethyst Bud"),
|
||||
long_desc = S("Large Amethyst Bud is the third growth of amethyst bud."),
|
||||
light_source = 5,
|
||||
next_stage = "mcl_amethyst:amethyst_cluster",
|
||||
selection_box = { -4.5/16, -8/16, -4.5/16, 4.5/16, -1/16, 4.5/16 },
|
||||
},
|
||||
}
|
||||
|
||||
for _, def in pairs(bud_def) do
|
||||
local size = def.size
|
||||
local name = "mcl_amethyst:" .. size .. "_amethyst_bud"
|
||||
local tile = "mcl_amethyst_amethyst_bud_" .. size .. ".png"
|
||||
local inventory_image = "mcl_amethyst_amethyst_bud_" .. size .. ".png"
|
||||
minetest.register_node(name, {
|
||||
description = def.description,
|
||||
_doc_items_longdesc = def.longdesc,
|
||||
drop = "",
|
||||
tiles = {tile},
|
||||
inventory_image = inventory_image,
|
||||
paramtype1 = "light",
|
||||
paramtype2 = "wallmounted",
|
||||
drawtype = "plantlike",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
light_source = def.light_source,
|
||||
groups = {
|
||||
dig_by_water = 1,
|
||||
destroy_by_lava_flow = 1,
|
||||
dig_by_piston = 1,
|
||||
pickaxey = 1,
|
||||
deco_block = 1,
|
||||
amethyst_buds = 1,
|
||||
attached_node = 1,
|
||||
},
|
||||
sounds = sounds,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = def.selection_box
|
||||
},
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_blast_resistance = 1.5,
|
||||
_mcl_silk_touch_drop = true,
|
||||
_mcl_amethyst_next_grade = def.next_stage,
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_node("mcl_amethyst:amethyst_cluster",{
|
||||
description = S("Amethyst Cluster"),
|
||||
_doc_items_longdesc = S("Amethyst Cluster is the final growth of amethyst bud."),
|
||||
drop = {
|
||||
max_items = 1,
|
||||
items = {
|
||||
{
|
||||
tools = {"~mcl_tools:pick_"},
|
||||
items = {"mcl_amethyst:amethyst_shard 4"},
|
||||
},
|
||||
{
|
||||
items = {"mcl_amethyst:amethyst_shard 2"},
|
||||
},
|
||||
}
|
||||
},
|
||||
tiles = {"mcl_amethyst_amethyst_cluster.png",},
|
||||
inventory_image = "mcl_amethyst_amethyst_cluster.png",
|
||||
paramtype2 = "wallmounted",
|
||||
drawtype = "plantlike",
|
||||
paramtype1 = "light",
|
||||
use_texture_alpha = "clip",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
light_source = 7,
|
||||
groups = {
|
||||
dig_by_water = 1,
|
||||
destroy_by_lava_flow = 1,
|
||||
dig_by_piston = 1,
|
||||
pickaxey = 1,
|
||||
deco_block = 1,
|
||||
attached_node = 1,
|
||||
},
|
||||
sounds = sounds,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = { -4.8/16, -8/16, -4.8/16, 4.8/16, 3.9/16, 4.8/16 },
|
||||
},
|
||||
_mcl_hardness = 1.5,
|
||||
_mcl_blast_resistance = 1.5,
|
||||
_mcl_silk_touch_drop = true,
|
||||
})
|
||||
|
||||
-- Register Crafts
|
||||
minetest.register_craft({
|
||||
output = "mcl_amethyst:amethyst_block",
|
||||
recipe = {
|
||||
{"mcl_amethyst:amethyst_shard", "mcl_amethyst:amethyst_shard"},
|
||||
{"mcl_amethyst:amethyst_shard", "mcl_amethyst:amethyst_shard"},
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "mcl_amethyst:tinted_glass 2",
|
||||
recipe = {
|
||||
{"", "mcl_amethyst:amethyst_shard", ""},
|
||||
{"mcl_amethyst:amethyst_shard", "mcl_core:glass", "mcl_amethyst:amethyst_shard",},
|
||||
{"", "mcl_amethyst:amethyst_shard", ""},
|
||||
},
|
||||
})
|
||||
|
||||
if minetest.get_modpath("mcl_spyglass") then
|
||||
minetest.clear_craft({output = "mcl_spyglass:spyglass",})
|
||||
local function craft_spyglass(ingot)
|
||||
minetest.register_craft({
|
||||
output = "mcl_spyglass:spyglass",
|
||||
recipe = {
|
||||
{"mcl_amethyst:amethyst_shard"},
|
||||
{ingot},
|
||||
{ingot},
|
||||
}
|
||||
})
|
||||
end
|
||||
if minetest.get_modpath("mcl_copper") then
|
||||
craft_spyglass("mcl_copper:copper_ingot")
|
||||
else
|
||||
craft_spyglass("mcl_core:iron_ingot")
|
||||
end
|
||||
end
|
||||
|
||||
-- Amethyst Growing
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/grow.lua")
|
|
@ -0,0 +1,19 @@
|
|||
# textdomain: mcl_amethyst
|
||||
Amethyst Cluster=Agrégat d'améthyste
|
||||
Amethyst Cluster is the final growth of amethyst bud.=L'agrégat d'améthyste est le stade final de la croissance du bourgeon d'améthyste.
|
||||
Amethyst Shard=Éclat d'améthyste
|
||||
An amethyst shard is a crystalline mineral.=Un éclat d'améthyste est un minéral cristallin.
|
||||
Block of Amethyst=Bloc d'améthyste
|
||||
Budding Amethyst=Améthyste bourgeonante
|
||||
Calcite=Calcite
|
||||
Calcite can be found as part of amethyst geodes.=La calcite peut être trouvée dans les géodes d'améthyste.
|
||||
Large Amethyst Bud=Grand bourgeon d'améthyste
|
||||
Large Amethyst Bud is the third growth of amethyst bud.=Le grand bourgeon d'améthyste est le troisième stade de la croissance du bourgeon d'améthyste.
|
||||
Medium Amethyst Bud=Bourgeon d'améthyste moyen
|
||||
Medium Amethyst Bud is the second growth of amethyst bud.=Le bourgeon d'améthyste moyen est le deuxième stade de la croissance du bourgeon d'améthyste.
|
||||
Small Amethyst Bud=Petit bourgeon d'améthyste
|
||||
Small Amethyst Bud is the first growth of amethyst bud.=Le petit bourgeon d'améthyste est le premier stade de la croissance du bourgeon d'améthyste.
|
||||
The Block of Amethyst is a decoration block crafted from amethyst shards.=Le bloc d'améthyste est un bloc décoratif fabriqué à partir d'éclats d'améthyste.
|
||||
The Budding Amethyst can grow amethyst=L'améthyste bourgeonante peut faire croître de l'améthyste.
|
||||
Tinted Glass=Verre teinté
|
||||
Tinted Glass is a type of glass which blocks lights while it is visually transparent.=Le verre teinté est un type de verre qui bloque la lumière tout en étant visuellement transparent.
|
|
@ -0,0 +1,19 @@
|
|||
# textdomain: mcl_amethyst
|
||||
Amethyst Cluster=Аметистовая друза
|
||||
Amethyst Cluster is the final growth of amethyst bud.=Аметистовая друза - это последняя 4-я стадия роста аметистового бутона.
|
||||
Amethyst Shard=Осколок аметиста
|
||||
An amethyst shard is a crystalline mineral.=Осколок аметиста - это кристаллический минерал, получаемый в результате разрушения кластеров аметиста.
|
||||
Block of Amethyst=Аметистовый блок
|
||||
Budding Amethyst=Растущий аметист
|
||||
Calcite=Кальцит
|
||||
Calcite can be found as part of amethyst geodes.=Кальцит можно найти в составе аметистовых жеод.
|
||||
Large Amethyst Bud=Большой росток аметиста
|
||||
Large Amethyst Bud is the third growth of amethyst bud.=Большой росток - третья стадия роста аметиста.
|
||||
Medium Amethyst Bud=Средний росток аметиста
|
||||
Medium Amethyst Bud is the second growth of amethyst bud.=Средний росток - вторая стадия роста аметиста.
|
||||
Small Amethyst Bud=Маленький росток аметиста
|
||||
Small Amethyst Bud is the first growth of amethyst bud.=Маленький росток - первая стадия роста аметиста.
|
||||
The Block of Amethyst is a decoration block crafted from amethyst shards.=Блок аметиста - декоративный блок, скрафченный из осколков аметиста.
|
||||
The Budding Amethyst can grow amethyst=Растущий аметист может вырастить аметист
|
||||
Tinted Glass=Тонированное стекло
|
||||
Tinted Glass is a type of glass which blocks lights while it is visually transparent.=Тонированное стекло блокирует свет, но визуально прозрачно.
|
|
@ -0,0 +1,19 @@
|
|||
# textdomain: mcl_amethyst
|
||||
Amethyst Cluster=
|
||||
Amethyst Cluster is the final growth of amethyst bud.=
|
||||
Amethyst Shard=
|
||||
An amethyst shard is a crystalline mineral.=
|
||||
Block of Amethyst=
|
||||
Budding Amethyst=
|
||||
Calcite=
|
||||
Calcite can be found as part of amethyst geodes.=
|
||||
Large Amethyst Bud=
|
||||
Large Amethyst Bud is the third growth of amethyst bud.=
|
||||
Medium Amethyst Bud=
|
||||
Medium Amethyst Bud is the second growth of amethyst bud.=
|
||||
Small Amethyst Bud=
|
||||
Small Amethyst Bud is the first growth of amethyst bud.=
|
||||
The Block of Amethyst is a decoration block crafted from amethyst shards.=
|
||||
The Budding Amethyst can grow amethyst=
|
||||
Tinted Glass=
|
||||
Tinted Glass is a type of glass which blocks lights while it is visually transparent.=
|
|
@ -0,0 +1,5 @@
|
|||
name = mcl_amethyst
|
||||
author = Emojiminetest, kay27
|
||||
description = Amethyst related stuff
|
||||
depends = mcl_init, mcl_core, mcl_wip
|
||||
optional_depends = mcl_spyglass, mcl_copper
|
|
@ -0,0 +1 @@
|
|||
Nova_Wostra Creative Commons Attribution-Share Alike 4.0 International License https://creativecommons.org/licenses/by-sa/4.0/
|
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 6.6 KiB |