Merge pull request 'fork get-compass-image-fix branch' (#5) from MineClone2/MineClone2:get-compass-image-fix into kabou_lodestonefix_fork
Reviewed-on: #5
|
@ -102,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”
|
* `water_bucket=1`: Bucket containing a liquid of group “water”
|
||||||
* `enchantability=X`: How good the enchantments are the item gets (1 equals book)
|
* `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
|
* `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
|
### Material groups
|
||||||
|
|
||||||
|
|
|
@ -1,180 +1,204 @@
|
||||||
--lua locals
|
--lua locals
|
||||||
local get_node = minetest.get_node
|
local get_node = minetest.get_node
|
||||||
local get_item_group = minetest.get_item_group
|
local get_item_group = minetest.get_item_group
|
||||||
local get_node_light = minetest.get_node_light
|
local get_node_light = minetest.get_node_light
|
||||||
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
||||||
local new_vector = vector.new
|
local get_biome_name = minetest.get_biome_name
|
||||||
|
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local minetest_get_perlin = minetest.get_perlin
|
||||||
|
|
||||||
local math_random = math.random
|
local math_random = math.random
|
||||||
local get_biome_name = minetest.get_biome_name
|
local math_floor = math.floor
|
||||||
local max = math.max
|
local math_ceil = math.ceil
|
||||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
local math_cos = math.cos
|
||||||
local vector_distance = vector.distance
|
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
|
-- range for mob count
|
||||||
local aoc_range = 32
|
local aoc_range = 32
|
||||||
--[[
|
|
||||||
|
|
||||||
THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
|
||||||
|
|
||||||
underground:
|
|
||||||
"FlowerForest_underground",
|
|
||||||
"JungleEdge_underground",local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)]
|
|
||||||
"ColdTaiga_underground",
|
|
||||||
"IcePlains_underground",
|
|
||||||
"IcePlainsSpikes_underground",
|
|
||||||
"MegaTaiga_underground",
|
|
||||||
"Taiga_underground",
|
|
||||||
"ExtremeHills+_underground",
|
|
||||||
"JungleM_underground",
|
|
||||||
"ExtremeHillsM_underground",
|
|
||||||
"JungleEdgeM_underground",
|
|
||||||
|
|
||||||
ocean:
|
|
||||||
"RoofedForest_ocean",
|
|
||||||
"JungleEdgeM_ocean",
|
|
||||||
"BirchForestM_ocean",
|
|
||||||
"BirchForest_ocean",
|
|
||||||
"IcePlains_deep_ocean",
|
|
||||||
"Jungle_deep_ocean",
|
|
||||||
"Savanna_ocean",
|
|
||||||
"MesaPlateauF_ocean",
|
|
||||||
"ExtremeHillsM_deep_ocean",
|
|
||||||
"Savanna_deep_ocean",
|
|
||||||
"SunflowerPlains_ocean",
|
|
||||||
"Swampland_deep_ocean",
|
|
||||||
"Swampland_ocean",
|
|
||||||
"MegaSpruceTaiga_deep_ocean",
|
|
||||||
"ExtremeHillsM_ocean",
|
|
||||||
"JungleEdgeM_deep_ocean",
|
|
||||||
"SunflowerPlains_deep_ocean",
|
|
||||||
"BirchForest_deep_ocean",
|
|
||||||
"IcePlainsSpikes_ocean",
|
|
||||||
"Mesa_ocean",
|
|
||||||
"StoneBeach_ocean",
|
|
||||||
"Plains_deep_ocean",
|
|
||||||
"JungleEdge_deep_ocean",
|
|
||||||
"SavannaM_deep_ocean",
|
|
||||||
"Desert_deep_ocean",
|
|
||||||
"Mesa_deep_ocean",
|
|
||||||
"ColdTaiga_deep_ocean",
|
|
||||||
"Plains_ocean",
|
|
||||||
"MesaPlateauFM_ocean",
|
|
||||||
"Forest_deep_ocean",
|
|
||||||
"JungleM_deep_ocean",
|
|
||||||
"FlowerForest_deep_ocean",
|
|
||||||
"MushroomIsland_ocean",
|
|
||||||
"MegaTaiga_ocean",
|
|
||||||
"StoneBeach_deep_ocean",
|
|
||||||
"IcePlainsSpikes_deep_ocean",
|
|
||||||
"ColdTaiga_ocean",
|
|
||||||
"SavannaM_ocean",
|
|
||||||
"MesaPlateauF_deep_ocean",
|
|
||||||
"MesaBryce_deep_ocean",
|
|
||||||
"ExtremeHills+_deep_ocean",
|
|
||||||
"ExtremeHills_ocean",
|
|
||||||
"MushroomIsland_deep_ocean",
|
|
||||||
"Forest_ocean",
|
|
||||||
"MegaTaiga_deep_ocean",
|
|
||||||
"JungleEdge_ocean",
|
|
||||||
"MesaBryce_ocean",
|
|
||||||
"MegaSpruceTaiga_ocean",
|
|
||||||
"ExtremeHills+_ocean",
|
|
||||||
"Jungle_ocean",
|
|
||||||
"RoofedForest_deep_ocean",
|
|
||||||
"IcePlains_ocean",
|
|
||||||
"FlowerForest_ocean",
|
|
||||||
"ExtremeHills_deep_ocean",
|
|
||||||
"MesaPlateauFM_deep_ocean",
|
|
||||||
"Desert_ocean",
|
|
||||||
"Taiga_ocean",
|
|
||||||
"BirchForestM_deep_ocean",
|
|
||||||
"Taiga_deep_ocean",
|
|
||||||
"JungleM_ocean",
|
|
||||||
|
|
||||||
water or beach?
|
|
||||||
"MesaPlateauFM_sandlevel",
|
|
||||||
"MesaPlateauF_sandlevel",
|
|
||||||
"MesaBryce_sandlevel",
|
|
||||||
"Mesa_sandlevel",
|
|
||||||
|
|
||||||
beach:
|
|
||||||
"FlowerForest_beach",
|
|
||||||
"Forest_beach",
|
|
||||||
"StoneBeach",
|
|
||||||
"ColdTaiga_beach_water",
|
|
||||||
"Taiga_beach",
|
|
||||||
"Savanna_beach",
|
|
||||||
"Plains_beach",
|
|
||||||
"ExtremeHills_beach",
|
|
||||||
"ColdTaiga_beach",
|
|
||||||
"Swampland_shore",
|
|
||||||
"MushroomIslandShore",
|
|
||||||
"JungleM_shore",
|
|
||||||
"Jungle_shore",
|
|
||||||
|
|
||||||
dimension biome:
|
|
||||||
"Nether",
|
|
||||||
"End",
|
|
||||||
|
|
||||||
Overworld regular:
|
|
||||||
"Mesa",
|
|
||||||
"FlowerForest",
|
|
||||||
"Swampland",
|
|
||||||
"Taiga",
|
|
||||||
"ExtremeHills",
|
|
||||||
"Jungle",
|
|
||||||
"Savanna",
|
|
||||||
"BirchForest",
|
|
||||||
"MegaSpruceTaiga",
|
|
||||||
"MegaTaiga",
|
|
||||||
"ExtremeHills+",
|
|
||||||
"Forest",
|
|
||||||
"Plains",
|
|
||||||
"Desert",
|
|
||||||
"ColdTaiga",
|
|
||||||
"MushroomIsland",
|
|
||||||
"IcePlainsSpikes",
|
|
||||||
"SunflowerPlains",
|
|
||||||
"IcePlains",
|
|
||||||
"RoofedForest",
|
|
||||||
"ExtremeHills+_snowtop",
|
|
||||||
"MesaPlateauFM_grasstop",
|
|
||||||
"JungleEdgeM",
|
|
||||||
"ExtremeHillsM",
|
|
||||||
"JungleM",
|
|
||||||
"BirchForestM",
|
|
||||||
"MesaPlateauF",
|
|
||||||
"MesaPlateauFM",
|
|
||||||
"MesaPlateauF_grasstop",
|
|
||||||
"MesaBryce",
|
|
||||||
"JungleEdge",
|
|
||||||
"SavannaM",
|
|
||||||
]]--
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--do mobs spawn?
|
||||||
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
|
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)
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
"FlowerForest_underground",
|
||||||
|
"JungleEdge_underground",
|
||||||
|
"ColdTaiga_underground",
|
||||||
|
"IcePlains_underground",
|
||||||
|
"IcePlainsSpikes_underground",
|
||||||
|
"MegaTaiga_underground",
|
||||||
|
"Taiga_underground",
|
||||||
|
"ExtremeHills+_underground",
|
||||||
|
"JungleM_underground",
|
||||||
|
"ExtremeHillsM_underground",
|
||||||
|
"JungleEdgeM_underground",
|
||||||
|
|
||||||
|
-- ocean:
|
||||||
|
|
||||||
|
"RoofedForest_ocean",
|
||||||
|
"JungleEdgeM_ocean",
|
||||||
|
"BirchForestM_ocean",
|
||||||
|
"BirchForest_ocean",
|
||||||
|
"IcePlains_deep_ocean",
|
||||||
|
"Jungle_deep_ocean",
|
||||||
|
"Savanna_ocean",
|
||||||
|
"MesaPlateauF_ocean",
|
||||||
|
"ExtremeHillsM_deep_ocean",
|
||||||
|
"Savanna_deep_ocean",
|
||||||
|
"SunflowerPlains_ocean",
|
||||||
|
"Swampland_deep_ocean",
|
||||||
|
"Swampland_ocean",
|
||||||
|
"MegaSpruceTaiga_deep_ocean",
|
||||||
|
"ExtremeHillsM_ocean",
|
||||||
|
"JungleEdgeM_deep_ocean",
|
||||||
|
"SunflowerPlains_deep_ocean",
|
||||||
|
"BirchForest_deep_ocean",
|
||||||
|
"IcePlainsSpikes_ocean",
|
||||||
|
"Mesa_ocean",
|
||||||
|
"StoneBeach_ocean",
|
||||||
|
"Plains_deep_ocean",
|
||||||
|
"JungleEdge_deep_ocean",
|
||||||
|
"SavannaM_deep_ocean",
|
||||||
|
"Desert_deep_ocean",
|
||||||
|
"Mesa_deep_ocean",
|
||||||
|
"ColdTaiga_deep_ocean",
|
||||||
|
"Plains_ocean",
|
||||||
|
"MesaPlateauFM_ocean",
|
||||||
|
"Forest_deep_ocean",
|
||||||
|
"JungleM_deep_ocean",
|
||||||
|
"FlowerForest_deep_ocean",
|
||||||
|
"MushroomIsland_ocean",
|
||||||
|
"MegaTaiga_ocean",
|
||||||
|
"StoneBeach_deep_ocean",
|
||||||
|
"IcePlainsSpikes_deep_ocean",
|
||||||
|
"ColdTaiga_ocean",
|
||||||
|
"SavannaM_ocean",
|
||||||
|
"MesaPlateauF_deep_ocean",
|
||||||
|
"MesaBryce_deep_ocean",
|
||||||
|
"ExtremeHills+_deep_ocean",
|
||||||
|
"ExtremeHills_ocean",
|
||||||
|
"MushroomIsland_deep_ocean",
|
||||||
|
"Forest_ocean",
|
||||||
|
"MegaTaiga_deep_ocean",
|
||||||
|
"JungleEdge_ocean",
|
||||||
|
"MesaBryce_ocean",
|
||||||
|
"MegaSpruceTaiga_ocean",
|
||||||
|
"ExtremeHills+_ocean",
|
||||||
|
"Jungle_ocean",
|
||||||
|
"RoofedForest_deep_ocean",
|
||||||
|
"IcePlains_ocean",
|
||||||
|
"FlowerForest_ocean",
|
||||||
|
"ExtremeHills_deep_ocean",
|
||||||
|
"MesaPlateauFM_deep_ocean",
|
||||||
|
"Desert_ocean",
|
||||||
|
"Taiga_ocean",
|
||||||
|
"BirchForestM_deep_ocean",
|
||||||
|
"Taiga_deep_ocean",
|
||||||
|
"JungleM_ocean",
|
||||||
|
|
||||||
|
-- water or beach?
|
||||||
|
|
||||||
|
"MesaPlateauFM_sandlevel",
|
||||||
|
"MesaPlateauF_sandlevel",
|
||||||
|
"MesaBryce_sandlevel",
|
||||||
|
"Mesa_sandlevel",
|
||||||
|
|
||||||
|
-- beach:
|
||||||
|
|
||||||
|
"FlowerForest_beach",
|
||||||
|
"Forest_beach",
|
||||||
|
"StoneBeach",
|
||||||
|
"ColdTaiga_beach_water",
|
||||||
|
"Taiga_beach",
|
||||||
|
"Savanna_beach",
|
||||||
|
"Plains_beach",
|
||||||
|
"ExtremeHills_beach",
|
||||||
|
"ColdTaiga_beach",
|
||||||
|
"Swampland_shore",
|
||||||
|
"MushroomIslandShore",
|
||||||
|
"JungleM_shore",
|
||||||
|
"Jungle_shore",
|
||||||
|
|
||||||
|
-- dimension biome:
|
||||||
|
|
||||||
|
"Nether",
|
||||||
|
"End",
|
||||||
|
|
||||||
|
-- Overworld regular:
|
||||||
|
|
||||||
|
"Mesa",
|
||||||
|
"FlowerForest",
|
||||||
|
"Swampland",
|
||||||
|
"Taiga",
|
||||||
|
"ExtremeHills",
|
||||||
|
"Jungle",
|
||||||
|
"Savanna",
|
||||||
|
"BirchForest",
|
||||||
|
"MegaSpruceTaiga",
|
||||||
|
"MegaTaiga",
|
||||||
|
"ExtremeHills+",
|
||||||
|
"Forest",
|
||||||
|
"Plains",
|
||||||
|
"Desert",
|
||||||
|
"ColdTaiga",
|
||||||
|
"MushroomIsland",
|
||||||
|
"IcePlainsSpikes",
|
||||||
|
"SunflowerPlains",
|
||||||
|
"IcePlains",
|
||||||
|
"RoofedForest",
|
||||||
|
"ExtremeHills+_snowtop",
|
||||||
|
"MesaPlateauFM_grasstop",
|
||||||
|
"JungleEdgeM",
|
||||||
|
"ExtremeHillsM",
|
||||||
|
"JungleM",
|
||||||
|
"BirchForestM",
|
||||||
|
"MesaPlateauF",
|
||||||
|
"MesaPlateauFM",
|
||||||
|
"MesaPlateauF_grasstop",
|
||||||
|
"MesaBryce",
|
||||||
|
"JungleEdge",
|
||||||
|
"SavannaM",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- count how many mobs are in an area
|
||||||
|
local function count_mobs(pos)
|
||||||
local num = 0
|
local num = 0
|
||||||
local objs = get_objects_inside_radius(pos, aoc_range)
|
for _,object in pairs(get_objects_inside_radius(pos, aoc_range)) do
|
||||||
for n = 1, #objs do
|
if object and object:get_luaentity() and object:get_luaentity()._cmi_is_mob then
|
||||||
local obj = objs[n]:get_luaentity()
|
num = num + 1
|
||||||
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
|
|
||||||
num = num + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return num
|
return num
|
||||||
end
|
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
|
--this is where all of the spawning information is kept
|
||||||
local spawn_dictionary = {}
|
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)
|
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?
|
-- Do mobs spawn at all?
|
||||||
if not mobs_spawn then
|
if not mobs_spawn then
|
||||||
return
|
return
|
||||||
|
@ -238,180 +324,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.log("action",
|
minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||||
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"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--load information into the spawn dictionary
|
--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]["biomes"] = biomes
|
||||||
spawn_dictionary[key]["min_light"] = min_light
|
spawn_dictionary[key]["min_light"] = min_light
|
||||||
spawn_dictionary[key]["max_light"] = max_light
|
spawn_dictionary[key]["max_light"] = max_light
|
||||||
spawn_dictionary[key]["interval"] = interval
|
|
||||||
spawn_dictionary[key]["chance"] = chance
|
spawn_dictionary[key]["chance"] = chance
|
||||||
spawn_dictionary[key]["aoc"] = aoc
|
spawn_dictionary[key]["aoc"] = aoc
|
||||||
spawn_dictionary[key]["min_height"] = min_height
|
spawn_dictionary[key]["min_height"] = min_height
|
||||||
spawn_dictionary[key]["max_height"] = max_height
|
spawn_dictionary[key]["max_height"] = max_height
|
||||||
spawn_dictionary[key]["day_toggle"] = day_toggle
|
spawn_dictionary[key]["day_toggle"] = day_toggle
|
||||||
--spawn_dictionary[key]["on_spawn"] = spawn_abm_action
|
|
||||||
spawn_dictionary[key]["spawn_class"] = spawn_class
|
|
||||||
|
|
||||||
--[[
|
summary_chance = summary_chance + chance
|
||||||
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,
|
|
||||||
})
|
|
||||||
]]--
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- compatibility with older mob registration
|
local two_pi = 2 * math.pi
|
||||||
-- we're going to forget about this for now -j4i
|
local function get_next_mob_spawn_pos(pos)
|
||||||
--[[
|
local distance = math_random(25, 32)
|
||||||
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle)
|
local angle = math_random() * two_pi
|
||||||
|
return {
|
||||||
mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30,
|
x = math_round(pos.x + distance * math_cos(angle)),
|
||||||
chance, active_object_count, -31000, max_height, day_toggle)
|
y = pos.y,
|
||||||
|
z = math_round(pos.z + distance * math_sin(angle))
|
||||||
|
}
|
||||||
end
|
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 function decypher_limits(posy)
|
local function decypher_limits(posy)
|
||||||
--local min_max_table = decypher_limits_dictionary[dimension]
|
posy = math_floor(posy)
|
||||||
--return min_max_table[1],min_max_table[2]
|
|
||||||
posy = math.floor(posy)
|
|
||||||
return posy - 32, posy + 32
|
return posy - 32, posy + 32
|
||||||
end
|
end
|
||||||
|
|
||||||
--a simple helper function for mob_spawn
|
--a simple helper function for mob_spawn
|
||||||
local function biome_check(biome_list, biome_goal)
|
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
|
if data == biome_goal then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -531,125 +372,111 @@ local function biome_check(biome_list, biome_goal)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function is_farm_animal(n)
|
||||||
--todo mob limiting
|
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"
|
||||||
--MAIN LOOP
|
end
|
||||||
|
|
||||||
if mobs_spawn then
|
if mobs_spawn then
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|
||||||
|
--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
|
||||||
|
local gotten_biome = minetest.get_biome_data(spawning_position)
|
||||||
|
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
|
||||||
|
|
||||||
|
--add this so mobs don't spawn inside nodes
|
||||||
|
spawning_position.y = spawning_position.y + 1
|
||||||
|
|
||||||
|
--only need to poll for node light if everything else worked
|
||||||
|
local gotten_light = get_node_light(spawning_position)
|
||||||
|
|
||||||
|
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 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
|
||||||
|
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
|
local timer = 0
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
timer = timer + dtime
|
timer = timer + dtime
|
||||||
if timer >= 8 then
|
if timer < 10 then return end
|
||||||
timer = 0
|
timer = 0
|
||||||
for _,player in pairs(minetest.get_connected_players()) do
|
for _, player in pairs(get_connected_players()) do
|
||||||
for i = 1,math_random(3,8) do
|
local pos = player:get_pos()
|
||||||
repeat -- after this line each "break" means "continue"
|
local dimension = mcl_worlds.pos_to_dimension(pos)
|
||||||
local player_pos = player:get_pos()
|
-- ignore void and unloaded area
|
||||||
|
if dimension ~= "void" and dimension ~= "default" then
|
||||||
local _,dimension = mcl_worlds.y_to_layer(player_pos.y)
|
local y_min, y_max = decypher_limits(pos.y)
|
||||||
|
for i = 1, math_random(1, 4) do
|
||||||
if dimension == "void" or dimension == "default" then
|
spawn_a_mob(pos, dimension, y_min, y_max)
|
||||||
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 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
|
|
||||||
|
|
||||||
local gotten_node = get_node(spawning_position)
|
|
||||||
local gotten_node_name = gotten_node.name
|
|
||||||
local gotten_node_def = minetest.registered_nodes[gotten_node_name]
|
|
||||||
|
|
||||||
if not gotten_node_name or not gotten_node_def or gotten_node_name == "air" then --skip air nodes
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
if gotten_node_def.use_texture_alpha and gotten_node_def.use_texture_alpha ~= "opaque" then
|
|
||||||
break
|
|
||||||
end --don't spawn on nonopaque nodes
|
|
||||||
|
|
||||||
local leaf = minetest.get_item_group(gotten_node_name,"leaves")
|
|
||||||
if leaf ~= 0 then
|
|
||||||
break end --don't spawn on treetops
|
|
||||||
|
|
||||||
local gotten_biome = minetest.get_biome_data(spawning_position)
|
|
||||||
|
|
||||||
if not gotten_biome then
|
|
||||||
break --skip if in unloaded area
|
|
||||||
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_name, "water") ~= 0
|
|
||||||
local is_lava = get_item_group(gotten_node_name, "lava") ~= 0
|
|
||||||
|
|
||||||
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
|
|
||||||
spawning_position.y = spawning_position.y - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
--everything is correct, spawn mob
|
|
||||||
minetest.add_entity(spawning_position, mob_def.name)
|
|
||||||
until true --this is a safety catch
|
|
||||||
end
|
end
|
||||||
end
|
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}}
|
|
@ -116,15 +116,14 @@ mobs:spawn_specific(
|
||||||
"overworld",
|
"overworld",
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
|
"Desert",
|
||||||
"FlowerForest",
|
"FlowerForest",
|
||||||
"Swampland",
|
|
||||||
"Taiga",
|
"Taiga",
|
||||||
"ExtremeHills",
|
"ExtremeHills",
|
||||||
"BirchForest",
|
"BirchForest",
|
||||||
"MegaSpruceTaiga",
|
"MegaSpruceTaiga",
|
||||||
"MegaTaiga",
|
"MegaTaiga",
|
||||||
"ExtremeHills+",
|
"ExtremeHills+",
|
||||||
"Forest",
|
|
||||||
"Plains",
|
"Plains",
|
||||||
"ColdTaiga",
|
"ColdTaiga",
|
||||||
"SunflowerPlains",
|
"SunflowerPlains",
|
||||||
|
|
|
@ -924,6 +924,35 @@ minetest.register_on_joinplayer(function(player)
|
||||||
inv:set_size("offered", 1)
|
inv:set_size("offered", 1)
|
||||||
end)
|
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_home(entity)
|
||||||
|
local b=entity.bed
|
||||||
|
local s=entity.object:get_pos()
|
||||||
|
if not b then return end
|
||||||
|
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)
|
||||||
|
entity.state = "go_home"
|
||||||
|
if vector.distance(b,s) < 10 then
|
||||||
|
entity.state = "stand"
|
||||||
|
set_velocity(entity,0)
|
||||||
|
local n=minetest.get_node(b)
|
||||||
|
if n and n.name ~= "mcl_beds:bed_red_bottom" then
|
||||||
|
entity.bed=nil --bed is gone, make villager homeless
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
||||||
|
|
||||||
mobs:register_mob("mobs_mc:villager", {
|
mobs:register_mob("mobs_mc:villager", {
|
||||||
|
@ -1029,6 +1058,9 @@ mobs:register_mob("mobs_mc:villager", {
|
||||||
_player_scan_timer = 0,
|
_player_scan_timer = 0,
|
||||||
_trading_players = {}, -- list of playernames currently trading with villager (open formspec)
|
_trading_players = {}, -- list of playernames currently trading with villager (open formspec)
|
||||||
do_custom = function(self, dtime)
|
do_custom = function(self, dtime)
|
||||||
|
if self.bed and ( self.state == "go_home" or vector.distance(self.object:get_pos(),self.bed) > 50 ) then
|
||||||
|
go_home(self)
|
||||||
|
end
|
||||||
-- Stand still if player is nearby.
|
-- Stand still if player is nearby.
|
||||||
if not self._player_scan_timer then
|
if not self._player_scan_timer then
|
||||||
self._player_scan_timer = 0
|
self._player_scan_timer = 0
|
||||||
|
|
|
@ -197,7 +197,6 @@ mobs:spawn_specific(
|
||||||
"ExtremeHills+",
|
"ExtremeHills+",
|
||||||
"Forest",
|
"Forest",
|
||||||
"Plains",
|
"Plains",
|
||||||
"Desert",
|
|
||||||
"ColdTaiga",
|
"ColdTaiga",
|
||||||
"MushroomIsland",
|
"MushroomIsland",
|
||||||
"IcePlainsSpikes",
|
"IcePlainsSpikes",
|
||||||
|
@ -290,7 +289,6 @@ mobs:spawn_specific(
|
||||||
"ExtremeHills+",
|
"ExtremeHills+",
|
||||||
"Forest",
|
"Forest",
|
||||||
"Plains",
|
"Plains",
|
||||||
"Desert",
|
|
||||||
"ColdTaiga",
|
"ColdTaiga",
|
||||||
"MushroomIsland",
|
"MushroomIsland",
|
||||||
"IcePlainsSpikes",
|
"IcePlainsSpikes",
|
||||||
|
@ -342,9 +340,6 @@ mobs:spawn_specific(
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"Desert",
|
"Desert",
|
||||||
"SavannaM",
|
|
||||||
"Savanna",
|
|
||||||
"Savanna_beach",
|
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
7,
|
7,
|
||||||
|
@ -359,9 +354,6 @@ mobs:spawn_specific(
|
||||||
"ground",
|
"ground",
|
||||||
{
|
{
|
||||||
"Desert",
|
"Desert",
|
||||||
"SavannaM",
|
|
||||||
"Savanna",
|
|
||||||
"Savanna_beach",
|
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
7,
|
7,
|
||||||
|
|
|
@ -28,7 +28,7 @@ local function check_player(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_weather.nether_dust.add_particlespawners = function(player)
|
mcl_weather.nether_dust.add_particlespawners = function(player)
|
||||||
local name=player:get_player_name(name)
|
local name=player:get_player_name()
|
||||||
mcl_weather.nether_dust.particlespawners[name]={}
|
mcl_weather.nether_dust.particlespawners[name]={}
|
||||||
psdef.playername = name
|
psdef.playername = name
|
||||||
psdef.attached = player
|
psdef.attached = player
|
||||||
|
@ -40,7 +40,7 @@ mcl_weather.nether_dust.add_particlespawners = function(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_weather.nether_dust.delete_particlespawners = function(player)
|
mcl_weather.nether_dust.delete_particlespawners = function(player)
|
||||||
local name=player:get_player_name(name)
|
local name=player:get_player_name()
|
||||||
if mcl_weather.nether_dust.particlespawners[name] then
|
if mcl_weather.nether_dust.particlespawners[name] then
|
||||||
for i=1,3 do
|
for i=1,3 do
|
||||||
minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i])
|
minetest.delete_particlespawner(mcl_weather.nether_dust.particlespawners[name][i])
|
||||||
|
|
|
@ -21,9 +21,13 @@ minetest.register_chatcommand("awards", {
|
||||||
description = S("Show, clear, disable or enable your achievements"),
|
description = S("Show, clear, disable or enable your achievements"),
|
||||||
func = function(name, param)
|
func = function(name, param)
|
||||||
if param == "clear" then
|
if param == "clear" then
|
||||||
awards.clear_player(name)
|
if awards.player(name).disabled ~= nil then
|
||||||
minetest.chat_send_player(name,
|
minetest.chat_send_player(name, S("Awards are disabled, enable them first by using /awards enable!"))
|
||||||
S("All your awards and statistics have been cleared. You can now start again."))
|
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
|
elseif param == "disable" then
|
||||||
awards.disable(name)
|
awards.disable(name)
|
||||||
minetest.chat_send_player(name, S("You have disabled your achievements."))
|
minetest.chat_send_player(name, S("You have disabled your achievements."))
|
||||||
|
@ -31,9 +35,17 @@ minetest.register_chatcommand("awards", {
|
||||||
awards.enable(name)
|
awards.enable(name)
|
||||||
minetest.chat_send_player(name, S("You have enabled your achievements."))
|
minetest.chat_send_player(name, S("You have enabled your achievements."))
|
||||||
elseif param == "c" then
|
elseif param == "c" then
|
||||||
awards.show_to(name, name, nil, true)
|
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
|
else
|
||||||
awards.show_to(name, name, nil, false)
|
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
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
|
@ -61,3 +61,4 @@ Achievement “@1” does not exist.=Auszeichnung »@1« existiert nicht.
|
||||||
Write something in chat.=Schreiben Sie etwas in den Chat.
|
Write something in chat.=Schreiben Sie etwas in den Chat.
|
||||||
Write @1 chat messages.=Schreiben Sie @1 Chatnachrichten.
|
Write @1 chat messages.=Schreiben Sie @1 Chatnachrichten.
|
||||||
@1/@2 chat messages=@1/@2 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=
|
@1 has made the achievement @2=
|
||||||
Mine a block: @1=
|
Mine a block: @1=
|
||||||
Mine blocks: @1×@2=
|
Mine blocks: @1×@2=
|
||||||
|
Awards are disabled, enable them first by using /awards enable!=
|
||||||
|
|
|
@ -339,14 +339,6 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
||||||
if name == "inv" then
|
if name == "inv" then
|
||||||
inv_bg = "crafting_inventory_creative_survival.png"
|
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)
|
-- Background images for armor slots (hide if occupied)
|
||||||
local armor_slot_imgs = ""
|
local armor_slot_imgs = ""
|
||||||
local inv = player:get_inventory()
|
local inv = player:get_inventory()
|
||||||
|
@ -385,7 +377,7 @@ function mcl_inventory.set_creative_formspec(player, start_i, pagenum, inv_size,
|
||||||
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
|
mcl_formspec.get_itemslot_bg(1.5,2.025,1,1)..
|
||||||
armor_slot_imgs..
|
armor_slot_imgs..
|
||||||
-- player preview
|
-- player preview
|
||||||
player_preview..
|
mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")..
|
||||||
-- crafting guide button
|
-- crafting guide button
|
||||||
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]"..
|
"image_button[9,1;1,1;craftguide_book.png;__mcl_craftguide;]"..
|
||||||
"tooltip[__mcl_craftguide;"..F(S("Recipe book")).."]"..
|
"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_width("craft", 2)
|
||||||
inv:set_size("craft", 4)
|
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_slots = {"helmet", "chestplate", "leggings", "boots"}
|
||||||
local armor_slot_imgs = ""
|
local armor_slot_imgs = ""
|
||||||
for a=1,4 do
|
for a=1,4 do
|
||||||
|
@ -82,7 +74,7 @@ local function set_inventory(player, armor_change_only)
|
||||||
|
|
||||||
local form = "size[9,8.75]"..
|
local form = "size[9,8.75]"..
|
||||||
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
|
"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
|
--armor
|
||||||
"list[current_player;armor;0,0;1,1;1]"..
|
"list[current_player;armor;0,0;1,1;1]"..
|
||||||
"list[current_player;armor;0,1;1,1;2]"..
|
"list[current_player;armor;0,1;1,1;2]"..
|
||||||
|
|
|
@ -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,
|
|
||||||
})
|
|
||||||
|
|
|
@ -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 |
After Width: | Height: | Size: 6.2 KiB |
|
@ -87,16 +87,6 @@ mcl_armor.register_set({
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
|
|
||||||
--WARNING: 2d preview is deprecated and will be removed soon
|
|
||||||
--specify textures that will be shown in player inventory then you disabled the 3d player inventory preview
|
|
||||||
--its similar to how works the textures field
|
|
||||||
previews = {
|
|
||||||
head = "dummy_texture.png", --default: "<modname>_helmet_<material>_preview.png"
|
|
||||||
torso = "dummy_texture.png", --default: "<modname>_chestplate_<material>_preview.png"
|
|
||||||
legs = "dummy_texture.png", --default: "<modname>_leggings_<material>_preview.png"
|
|
||||||
feet = "dummy_texture.png", --default: "<modname>_boots_<material>_preview.png"
|
|
||||||
},
|
|
||||||
|
|
||||||
--inventory textures aren't definable using a table similar to textures or previews
|
--inventory textures aren't definable using a table similar to textures or previews
|
||||||
--you are forced to use the default texture names which are:
|
--you are forced to use the default texture names which are:
|
||||||
--head: "<modname>_inv_helmet_<material>.png
|
--head: "<modname>_inv_helmet_<material>.png
|
||||||
|
|
|
@ -94,7 +94,6 @@ function mcl_armor.register_set(def)
|
||||||
local on_unequip_callbacks = def.on_unequip_callbacks or {}
|
local on_unequip_callbacks = def.on_unequip_callbacks or {}
|
||||||
local on_break_callbacks = def.on_break_callbacks or {}
|
local on_break_callbacks = def.on_break_callbacks or {}
|
||||||
local textures = def.textures or {}
|
local textures = def.textures or {}
|
||||||
local previews = def.previews or {}
|
|
||||||
local durabilities = def.durabilities or {}
|
local durabilities = def.durabilities or {}
|
||||||
local element_groups = def.element_groups or {}
|
local element_groups = def.element_groups or {}
|
||||||
|
|
||||||
|
@ -134,7 +133,6 @@ function mcl_armor.register_set(def)
|
||||||
_on_break = on_break_callbacks[name] or def.on_break,
|
_on_break = on_break_callbacks[name] or def.on_break,
|
||||||
_mcl_armor_element = name,
|
_mcl_armor_element = name,
|
||||||
_mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png",
|
_mcl_armor_texture = textures[name] or modname .. "_" .. itemname .. ".png",
|
||||||
_mcl_armor_preview = previews[name] or modname .. "_" .. itemname .. "_preview.png",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if def.craft_material then
|
if def.craft_material then
|
||||||
|
@ -221,17 +219,6 @@ function mcl_armor.update(obj)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local preview = def._mcl_armor_preview
|
|
||||||
|
|
||||||
if obj:is_player() and preview then
|
|
||||||
if type(preview) == "function" then
|
|
||||||
preview = preview(obj, itemstack)
|
|
||||||
end
|
|
||||||
if preview then
|
|
||||||
info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points")
|
info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points")
|
||||||
|
|
||||||
local mob_range_mob = def._mcl_armor_mob_range_mob
|
local mob_range_mob = def._mcl_armor_mob_range_mob
|
||||||
|
@ -254,8 +241,6 @@ function mcl_armor.update(obj)
|
||||||
info.texture = info.texture or "blank.png"
|
info.texture = info.texture or "blank.png"
|
||||||
|
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
info.preview = info.preview or "blank.png"
|
|
||||||
|
|
||||||
mcl_armor.update_player(obj, info)
|
mcl_armor.update_player(obj, info)
|
||||||
else
|
else
|
||||||
local luaentity = obj:get_luaentity()
|
local luaentity = obj:get_luaentity()
|
||||||
|
|
|
@ -63,7 +63,7 @@ mcl_player.player_register_model("mcl_armor_character_female.b3d", {
|
||||||
})
|
})
|
||||||
|
|
||||||
function mcl_armor.update_player(player, info)
|
function mcl_armor.update_player(player, info)
|
||||||
mcl_player.player_set_armor(player, info.texture, info.preview)
|
mcl_player.player_set_armor(player, info.texture)
|
||||||
|
|
||||||
local meta = player:get_meta()
|
local meta = player:get_meta()
|
||||||
meta:set_int("mcl_armor:armor_points", info.points)
|
meta:set_int("mcl_armor:armor_points", info.points)
|
||||||
|
|
Before Width: | Height: | Size: 156 B |
Before Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 140 B |
Before Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 210 B |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 149 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 190 B |
Before Width: | Height: | Size: 162 B |
Before Width: | Height: | Size: 147 B |
Before Width: | Height: | Size: 133 B |
Before Width: | Height: | Size: 197 B |
Before Width: | Height: | Size: 171 B |
Before Width: | Height: | Size: 168 B |
Before Width: | Height: | Size: 165 B |
|
@ -10,3 +10,4 @@ local modpath = minetest.get_modpath("mcl_beds")
|
||||||
dofile(modpath .. "/functions.lua")
|
dofile(modpath .. "/functions.lua")
|
||||||
dofile(modpath .. "/api.lua")
|
dofile(modpath .. "/api.lua")
|
||||||
dofile(modpath .. "/beds.lua")
|
dofile(modpath .. "/beds.lua")
|
||||||
|
dofile(modpath .. "/respawn_anchor.lua")
|
|
@ -40,3 +40,4 @@ You will fall asleep when all players are in bed.=Sie werden einschlafen, wenn a
|
||||||
You will fall asleep when @1% of all players are in bed.=Sie werden einschlafen, wenn @1% der Spieler im Bett sind.
|
You will fall asleep when @1% of all players are in bed.=Sie werden einschlafen, wenn @1% der Spieler im Bett sind.
|
||||||
You're in bed.=Sie sind im Bett.
|
You're in bed.=Sie sind im Bett.
|
||||||
Allows you to sleep=Zum Einschafen
|
Allows you to sleep=Zum Einschafen
|
||||||
|
Respawn Anchor=Seelenanker
|
|
@ -40,3 +40,4 @@ You will fall asleep when all players are in bed.=
|
||||||
You will fall asleep when @1% of all players are in bed.=
|
You will fall asleep when @1% of all players are in bed.=
|
||||||
You're in bed.=
|
You're in bed.=
|
||||||
Allows you to sleep=
|
Allows you to sleep=
|
||||||
|
Respawn Anchor=
|
||||||
|
|
|
@ -2,4 +2,4 @@ name = mcl_beds
|
||||||
author = BlockMen
|
author = BlockMen
|
||||||
description =
|
description =
|
||||||
depends = playerphysics
|
depends = playerphysics
|
||||||
optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc
|
optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc, mesecon
|
|
@ -0,0 +1,96 @@
|
||||||
|
--TODO: Add sounds for the respawn anchor (charge sounds etc.)
|
||||||
|
|
||||||
|
--Nether ends at y -29077
|
||||||
|
--Nether roof at y -28933
|
||||||
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
--local mod_doc = minetest.get_modpath("doc") -> maybe add documentation ?
|
||||||
|
|
||||||
|
for i=0,4 do
|
||||||
|
local nodebox_uncharged = { --Reused the composter nodebox, since it is basicly the same
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, -0.5, -0.5, -0.375, 0.5, 0.5}, -- Left wall
|
||||||
|
{ 0.375, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Right wall
|
||||||
|
{-0.375, -0.5, 0.375, 0.375, 0.5, 0.5}, -- Back wall
|
||||||
|
{-0.375, -0.5, -0.5, 0.375, 0.5, -0.375}, -- Front wall
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, -0.47, 0.5}, -- Bottom level, -0.47 because -0.5 is so low that you can see the texture of the block below through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local nodebox_charged = { --Reused the composter nodebox, since it is basicly the same
|
||||||
|
type = "fixed",
|
||||||
|
fixed = {
|
||||||
|
{-0.5, -0.5, -0.5, -0.375, 0.5, 0.5}, -- Left wall
|
||||||
|
{ 0.375, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Right wall
|
||||||
|
{-0.375, -0.5, 0.375, 0.375, 0.5, 0.5}, -- Back wall
|
||||||
|
{-0.375, -0.5, -0.5, 0.375, 0.5, -0.375}, -- Front wall
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, -- Bottom level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local function rightclick(pos, node, player, itemstack)
|
||||||
|
if itemstack.get_name(itemstack) == "mcl_nether:glowstone" and i ~= 4 then
|
||||||
|
minetest.set_node(pos, {name="mcl_beds:respawn_anchor_charged_" .. i+1})
|
||||||
|
itemstack:take_item()
|
||||||
|
elseif mcl_worlds.pos_to_dimension(pos) ~= "nether" then
|
||||||
|
if node.name ~= "mcl_beds:respawn_anchor" then --only charged respawn anchors are exploding in the overworld & end in minecraft
|
||||||
|
mcl_explosions.explode(pos, 5, {drop_chance = 0, fire = true})
|
||||||
|
end
|
||||||
|
elseif string.match(node.name, "mcl_beds:respawn_anchor_charged_") then
|
||||||
|
minetest.chat_send_player(player.get_player_name(player), S"New respawn position set!")
|
||||||
|
mcl_spawn.set_spawn_pos(player, pos, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if i == 0 then
|
||||||
|
minetest.register_node("mcl_beds:respawn_anchor",{
|
||||||
|
description=S("Respawn Anchor"),
|
||||||
|
tiles = {
|
||||||
|
"respawn_anchor_top_off.png",
|
||||||
|
"respawn_anchor_bottom.png",
|
||||||
|
"respawn_anchor_side0.png"
|
||||||
|
},
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = nodebox_uncharged,
|
||||||
|
on_rightclick = rightclick,
|
||||||
|
groups = {pickaxey=1, material_stone=1},
|
||||||
|
_mcl_hardness = 22.5,
|
||||||
|
sounds= mcl_sounds.node_sound_stone_defaults(),
|
||||||
|
})
|
||||||
|
mesecon.register_mvps_stopper("mcl_beds:respawn_anchor")
|
||||||
|
else
|
||||||
|
minetest.register_node("mcl_beds:respawn_anchor_charged_"..i,{
|
||||||
|
description=S("Respawn Anchor"),
|
||||||
|
tiles = {
|
||||||
|
"portal.png",
|
||||||
|
"respawn_anchor_bottom.png",
|
||||||
|
"respawn_anchor_side"..i ..".png"
|
||||||
|
},
|
||||||
|
drawtype = "nodebox",
|
||||||
|
node_box = nodebox_charged,
|
||||||
|
on_rightclick = rightclick,
|
||||||
|
groups = {pickaxey=1, material_stone=1, not_in_creative_inventory=1},
|
||||||
|
_mcl_hardness = 22.5,
|
||||||
|
sounds= mcl_sounds.node_sound_stone_defaults(),
|
||||||
|
drop = {
|
||||||
|
max_items = 1,
|
||||||
|
items = {
|
||||||
|
{items = {"mcl_beds:respawn_anchor"}},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
light_source = (4 * i) - 1
|
||||||
|
})
|
||||||
|
mesecon.register_mvps_stopper("mcl_beds:respawn_anchor_charged_"..i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_craft({ --TODO: Please change this crafting recipe once crying obsidian is implemented!
|
||||||
|
output = "mcl_beds:respawn_anchor",
|
||||||
|
recipe = {
|
||||||
|
{"mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian"},
|
||||||
|
{"mcl_nether:glowstone", "mcl_nether:glowstone", "mcl_nether:glowstone"},
|
||||||
|
{"mcl_core:obsidian", "mcl_core:obsidian", "mcl_core:obsidian"}
|
||||||
|
}
|
||||||
|
})
|
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 6.4 KiB |
|
@ -338,7 +338,10 @@ minetest.register_node("mcl_books:bookshelf", {
|
||||||
tiles = {"mcl_books_bookshelf_top.png", "mcl_books_bookshelf_top.png", "default_bookshelf.png"},
|
tiles = {"mcl_books_bookshelf_top.png", "mcl_books_bookshelf_top.png", "default_bookshelf.png"},
|
||||||
stack_max = 64,
|
stack_max = 64,
|
||||||
is_ground_content = false,
|
is_ground_content = false,
|
||||||
groups = {handy=1,axey=1, flammable=3,building_block=1, material_wood=1, fire_encouragement=30, fire_flammability=20},
|
groups = {
|
||||||
|
handy=1, axey=1, deco_block=1, material_wood=1,
|
||||||
|
flammable=3, fire_encouragement=30, fire_flammability=20
|
||||||
|
},
|
||||||
drop = "mcl_books:book 3",
|
drop = "mcl_books:book 3",
|
||||||
sounds = wood_sound,
|
sounds = wood_sound,
|
||||||
_mcl_blast_resistance = 1.5,
|
_mcl_blast_resistance = 1.5,
|
||||||
|
|
|
@ -959,7 +959,7 @@ minetest.register_craft({
|
||||||
output = "mcl_brewing:stand_000",
|
output = "mcl_brewing:stand_000",
|
||||||
recipe = {
|
recipe = {
|
||||||
{ "", "mcl_mobitems:blaze_rod", "" },
|
{ "", "mcl_mobitems:blaze_rod", "" },
|
||||||
{ "mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble" },
|
{ "group:cobble", "group:cobble", "group:cobble" },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# mcl_compass
|
||||||
|
|
||||||
|
# Compass API
|
||||||
|
|
||||||
|
##mcl_compass.stereotype = "mcl_compass:" .. stereotype_frame
|
||||||
|
Default compass craftitem. This is also the image that is shown in the inventory.
|
||||||
|
|
||||||
|
##mcl_compass/init.lua:function mcl_compass.get_compass_itemname(pos, dir, itemstack)
|
||||||
|
Returns the itemname of a compass with needle direction matching the
|
||||||
|
current compass position.
|
||||||
|
|
||||||
|
pos: position of the compass;
|
||||||
|
dir: rotational orientation of the compass;
|
||||||
|
itemstack: the compass including its optional lodestone metadata.
|
||||||
|
|
||||||
|
##mcl_compass/init.lua:function mcl_compass.get_compass_image(pos, dir)
|
||||||
|
-- Returns partial itemname of a compass with needle direction matching compass position.
|
||||||
|
-- Legacy compatibility function for mods using older api.
|
||||||
|
|
||||||
|
|
|
@ -2,113 +2,244 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
mcl_compass = {}
|
mcl_compass = {}
|
||||||
|
|
||||||
|
local compass_types = {
|
||||||
|
{
|
||||||
|
name = "compass",
|
||||||
|
desc = S("Compass"),
|
||||||
|
tt = S("Points to the world origin"),
|
||||||
|
longdesc = S("Compasses are tools which point to the world origin (X=0, Z=0) or the spawn point in the Overworld."),
|
||||||
|
usagehelp = S("A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "compass_lodestone",
|
||||||
|
desc = S("Lodestone Compass"),
|
||||||
|
tt = S("Points to a lodestone"),
|
||||||
|
longdesc = S("Lodestone compasses resemble regular compasses, but they point to a specific lodestone."),
|
||||||
|
usagehelp = S("A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Number of dynamic compass images (and items registered.)
|
||||||
local compass_frames = 32
|
local compass_frames = 32
|
||||||
|
|
||||||
--Not sure spawn point should be dymanic (is it in mc?)
|
-- The image/item that is craftable and shown in inventories.
|
||||||
--local default_spawn_settings = minetest.settings:get("static_spawnpoint")
|
local stereotype_frame = 18
|
||||||
|
|
||||||
-- Timer for random compass spinning
|
-- random compass spinning tick in seconds.
|
||||||
local random_timer = 0
|
-- Increase if there are performance problems.
|
||||||
local random_timer_trigger = 0.5 -- random compass spinning tick in seconds. Increase if there are performance problems
|
local spin_timer_tick = 0.5
|
||||||
|
|
||||||
local random_frame = math.random(0, compass_frames-1)
|
-- Local aliases to globals for better lua performance
|
||||||
|
local m_deg = math.deg
|
||||||
|
local m_atan2 = math.atan2
|
||||||
|
local m_floor = math.floor
|
||||||
|
local m_rnd = math.random
|
||||||
|
local vec_new = vector.new
|
||||||
|
local string_find = string.find
|
||||||
|
local string_to_pos = minetest.string_to_pos
|
||||||
|
local get_connected_players = minetest.get_connected_players
|
||||||
|
local get_item_group = minetest.get_item_group
|
||||||
|
local setting_get_pos = minetest.setting_get_pos
|
||||||
|
local compass_works = mcl_worlds.compass_works
|
||||||
|
local y_to_layer = mcl_worlds.y_to_layer
|
||||||
|
|
||||||
function mcl_compass.get_compass_image(pos, dir)
|
-- Initialize random compass frame for spinning compass. It is updated in
|
||||||
-- Compasses do not work in certain zones
|
-- the compass globalstep function.
|
||||||
if mcl_worlds.compass_works(pos) then
|
local random_frame = m_rnd(0, compass_frames-1)
|
||||||
local spawn = {x=0,y=0,z=0}
|
|
||||||
local ssp = minetest.setting_get_pos("static_spawnpoint")
|
local function get_far_node(pos, itemstack) --code from minetest dev wiki: https://dev.minetest.net/minetest.get_node, some edits have been made to add a cooldown for force loads
|
||||||
if ssp then
|
local node = minetest.get_node(pos)
|
||||||
spawn = ssp
|
if node.name == "ignore" then
|
||||||
if type(spawn) ~= "table" or type(spawn.x) ~= "number" or type(spawn.y) ~= "number" or type(spawn.z) ~= "number" then
|
local tstamp = tonumber(itemstack:get_meta():get_string("last_forceload"))
|
||||||
spawn = {x=0,y=0,z=0}
|
if tstamp == nil then --this is only relevant for new lodestone compasses, the ones that have never performes a forceload yet
|
||||||
end
|
itemstack:get_meta():set_string("last_forceload", tostring(os.time(os.date("!*t"))))
|
||||||
|
tstamp = tonumber(os.time(os.date("!*t")))
|
||||||
|
end
|
||||||
|
if tonumber(os.time(os.date("!*t"))) - tstamp > 180 then --current time in secounds - old time in secounds, if it is over 180 (3 mins): forceload
|
||||||
|
itemstack:get_meta():set_string("last_forceload", tostring(os.time(os.date("!*t"))))
|
||||||
|
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||||
|
node = minetest.get_node(pos)
|
||||||
|
else
|
||||||
|
node = {name="mcl_compass:lodestone"} --cooldown not over yet, pretend like there is something...
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get compass needle angle.
|
||||||
|
-- Returns the angle that the compass needle should point at expressed in
|
||||||
|
-- 360 degrees divided by the number of possible compass image frames..
|
||||||
|
--
|
||||||
|
-- pos: position of the compass;
|
||||||
|
-- target: position that the needle points towards;
|
||||||
|
-- dir: rotational direction of the compass.
|
||||||
|
--
|
||||||
|
local function get_compass_angle(pos, target, dir)
|
||||||
|
local angle_north = m_deg(m_atan2(target.x - pos.x, target.z - pos.z))
|
||||||
|
if angle_north < 0 then angle_north = angle_north + 360 end
|
||||||
|
local angle_dir = -m_deg(dir)
|
||||||
|
local angle_relative = (angle_north - angle_dir + 180) % 360
|
||||||
|
return m_floor((angle_relative/11.25) + 0.5) % compass_frames
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get compass image frame.
|
||||||
|
-- Returns the compass image frame with the needle direction matching the
|
||||||
|
-- compass' current position.
|
||||||
|
--
|
||||||
|
-- pos: position of the compass;
|
||||||
|
-- dir: rotational direction of the compass.
|
||||||
|
-- itemstack: the compass including its optional lodestone metadata.
|
||||||
|
--
|
||||||
|
local function get_compass_frame(pos, dir, itemstack)
|
||||||
|
if not string_find(itemstack:get_name(), "_lodestone") then -- normal compass
|
||||||
|
-- Compasses only work in the overworld
|
||||||
|
if compass_works(pos) then
|
||||||
|
local spawn_pos = setting_get_pos("static_spawnpoint")
|
||||||
|
or vec_new(0, 0, 0)
|
||||||
|
return get_compass_angle(pos, spawn_pos, dir)
|
||||||
|
else
|
||||||
|
return random_frame
|
||||||
|
end
|
||||||
|
else -- lodestone compass
|
||||||
|
local lpos_str = itemstack:get_meta():get_string("pointsto")
|
||||||
|
local lpos = string_to_pos(lpos_str)
|
||||||
|
if not lpos then
|
||||||
|
minetest.log("warning", "mcl_compass: invalid lodestone position!")
|
||||||
|
return random_frame
|
||||||
|
end
|
||||||
|
local _, l_dim = y_to_layer(lpos.y)
|
||||||
|
local _, p_dim = y_to_layer(pos.y)
|
||||||
|
-- compass and lodestone must be in the same dimension
|
||||||
|
if l_dim == p_dim then
|
||||||
|
--check if lodestone still exists
|
||||||
|
if get_far_node(lpos, itemstack).name == "mcl_compass:lodestone" then
|
||||||
|
return get_compass_angle(pos, lpos, dir)
|
||||||
|
else -- lodestone got destroyed
|
||||||
|
return random_frame
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return random_frame
|
||||||
end
|
end
|
||||||
local angle_north = math.deg(math.atan2(spawn.x - pos.x, spawn.z - pos.z))
|
|
||||||
if angle_north < 0 then angle_north = angle_north + 360 end
|
|
||||||
local angle_dir = -math.deg(dir)
|
|
||||||
local angle_relative = (angle_north - angle_dir + 180) % 360
|
|
||||||
return math.floor((angle_relative/11.25) + 0.5) % compass_frames
|
|
||||||
else
|
|
||||||
return random_frame
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_globalstep(function(dtime)
|
-- Export stereotype item for other mods to use
|
||||||
random_timer = random_timer + dtime
|
mcl_compass.stereotype = "mcl_compass:" .. stereotype_frame
|
||||||
|
|
||||||
if random_timer >= random_timer_trigger then
|
--- Get partial compass itemname.
|
||||||
random_frame = (random_frame + math.random(-1, 1)) % compass_frames
|
-- Returns partial itemname of a compass with needle direction matching compass position.
|
||||||
random_timer = 0
|
-- Legacy compatibility function for mods using older api.
|
||||||
|
--
|
||||||
|
function mcl_compass.get_compass_image(pos, dir)
|
||||||
|
minetest.log("warning", "mcl_compass: deprecated function " ..
|
||||||
|
"get_compass_image() called, use get_compass_itemname().")
|
||||||
|
local itemstack = ItemStack(mcl_compass.stereotype)
|
||||||
|
return get_compass_frame(pos, dir, itemstack)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get compass itemname.
|
||||||
|
-- Returns the itemname of a compass with needle direction matching the
|
||||||
|
-- current compass position.
|
||||||
|
--
|
||||||
|
-- pos: position of the compass;
|
||||||
|
-- dir: rotational orientation of the compass;
|
||||||
|
-- itemstack: the compass including its optional lodestone metadata.
|
||||||
|
--
|
||||||
|
function mcl_compass.get_compass_itemname(pos, dir, itemstack)
|
||||||
|
if not itemstack then
|
||||||
|
minetest.log("warning", "mcl_compass.get_compass_image called without itemstack!")
|
||||||
|
return "mcl_compass:" .. stereotype_frame
|
||||||
end
|
end
|
||||||
for i,player in pairs(minetest.get_connected_players()) do
|
local frame = get_compass_frame(pos, dir, itemstack)
|
||||||
local function has_compass(player)
|
if itemstack:get_meta():get_string("pointsto") ~= "" then
|
||||||
for _,stack in pairs(player:get_inventory():get_list("main")) do
|
return "mcl_compass:" .. frame .. "_lodestone"
|
||||||
if minetest.get_item_group(stack:get_name(), "compass") ~= 0 then
|
else
|
||||||
return true
|
return "mcl_compass:" .. frame
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
|
||||||
if has_compass(player) then
|
|
||||||
local pos = player:get_pos()
|
|
||||||
local compass_image = mcl_compass.get_compass_image(pos, player:get_look_horizontal())
|
|
||||||
|
|
||||||
for j,stack in pairs(player:get_inventory():get_list("main")) do
|
-- Timer for randomly spinning compass.
|
||||||
if minetest.get_item_group(stack:get_name(), "compass") ~= 0 and
|
-- Gets updated and checked in the globalstep function.
|
||||||
minetest.get_item_group(stack:get_name(), "compass")-1 ~= compass_image then
|
local spin_timer = 0
|
||||||
local itemname = "mcl_compass:"..compass_image
|
|
||||||
stack:set_name(itemname)
|
-- Compass globalstep function.
|
||||||
player:get_inventory():set_stack("main", j, stack)
|
-- * updates random spin counter and random frame of spinning compasses;
|
||||||
|
-- * updates all compasses in player's inventories to match the correct
|
||||||
|
-- needle orientations for their current positions.
|
||||||
|
--
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
spin_timer = spin_timer + dtime
|
||||||
|
if spin_timer >= spin_timer_tick then
|
||||||
|
random_frame = (random_frame + m_rnd(-1, 1)) % compass_frames
|
||||||
|
spin_timer = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local compass_nr, compass_frame
|
||||||
|
local pos, dir, inv
|
||||||
|
for _, player in pairs(get_connected_players()) do
|
||||||
|
pos = player:get_pos()
|
||||||
|
dir = player:get_look_horizontal()
|
||||||
|
inv = player:get_inventory()
|
||||||
|
for j, stack in pairs(inv:get_list("main")) do
|
||||||
|
compass_nr = get_item_group(stack:get_name(), "compass")
|
||||||
|
if compass_nr ~= 0 then
|
||||||
|
-- check if current compass image still matches true orientation
|
||||||
|
compass_frame = get_compass_frame(pos, dir, stack)
|
||||||
|
if compass_nr - 1 ~= compass_frame then
|
||||||
|
|
||||||
|
if string_find(stack:get_name(), "_lodestone") then
|
||||||
|
stack:set_name("mcl_compass:" .. compass_frame .. "_lodestone")
|
||||||
|
else
|
||||||
|
stack:set_name("mcl_compass:" .. compass_frame)
|
||||||
|
end
|
||||||
|
inv:set_stack("main", j, stack)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local images = {}
|
--
|
||||||
for frame = 0, compass_frames-1 do
|
-- Node and craftitem definitions
|
||||||
local s = string.format("%02d", frame)
|
--
|
||||||
table.insert(images, "mcl_compass_compass_"..s..".png")
|
|
||||||
end
|
|
||||||
|
|
||||||
local doc_mod = minetest.get_modpath("doc")
|
local doc_mod = minetest.get_modpath("doc")
|
||||||
|
|
||||||
local stereotype_frame = 18
|
for _, item in pairs(compass_types) do
|
||||||
for i,img in ipairs(images) do
|
local name_fmt, img_fmt
|
||||||
local inv = 1
|
if item.name == "compass" then
|
||||||
if i == stereotype_frame then
|
name_fmt = "mcl_compass:%d"
|
||||||
inv = 0
|
img_fmt = "mcl_compass_compass_%02d.png"
|
||||||
|
elseif item.name == "compass_lodestone" then
|
||||||
|
name_fmt = "mcl_compass:%d_lodestone"
|
||||||
|
img_fmt = "mcl_compass_compass_%02d.png^[colorize:purple:50"
|
||||||
end
|
end
|
||||||
local use_doc, longdesc, tt
|
for i = 0, compass_frames - 1 do
|
||||||
--Why is there no usage help? This should be fixed.
|
local def = {
|
||||||
--local usagehelp
|
description = item.desc,
|
||||||
use_doc = i == stereotype_frame
|
_tt_help = item.tt,
|
||||||
if use_doc then
|
inventory_image = string.format(img_fmt, i),
|
||||||
tt = S("Points to the world origin")
|
wield_image = string.format(img_fmt, i),
|
||||||
longdesc = S("Compasses are tools which point to the world origin (X=0, Z=0) or the spawn point in the Overworld.")
|
groups = {compass = i + 1, tool = 1, disable_repair = 1},
|
||||||
end
|
}
|
||||||
local itemstring = "mcl_compass:"..(i-1)
|
if i == stereotype_frame then
|
||||||
minetest.register_craftitem(itemstring, {
|
def._doc_items_longdesc = item.longdesc
|
||||||
description = S("Compass"),
|
def._doc_items_usagehelp = item.usagehelp
|
||||||
_tt_help = tt,
|
else
|
||||||
_doc_items_create_entry = use_doc,
|
def._doc_items_create_entry = false
|
||||||
_doc_items_longdesc = longdesc,
|
def.groups.not_in_creative_inventory = 1
|
||||||
--_doc_items_usagehelp = usagehelp,
|
end
|
||||||
inventory_image = img,
|
local itemstring = string.format(name_fmt, i)
|
||||||
wield_image = img,
|
minetest.register_craftitem(itemstring, table.copy(def))
|
||||||
stack_max = 64,
|
|
||||||
groups = {not_in_creative_inventory=inv, compass=i, tool=1, disable_repair=1 }
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Help aliases. Makes sure the lookup tool works correctly
|
-- Help aliases. Makes sure the lookup tool works correctly
|
||||||
if not use_doc and doc_mod then
|
if doc_mod and i ~= stereotype_frame then
|
||||||
doc.add_entry_alias("craftitems", "mcl_compass:"..(stereotype_frame-1), "craftitems", itemstring)
|
doc.add_entry_alias("craftitems", "mcl_compass:"..(stereotype_frame), "craftitems", itemstring)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
output = "mcl_compass:"..stereotype_frame,
|
output = "mcl_compass:" .. stereotype_frame,
|
||||||
recipe = {
|
recipe = {
|
||||||
{"", "mcl_core:iron_ingot", ""},
|
{"", "mcl_core:iron_ingot", ""},
|
||||||
{"mcl_core:iron_ingot", "mesecons:redstone", "mcl_core:iron_ingot"},
|
{"mcl_core:iron_ingot", "mesecons:redstone", "mcl_core:iron_ingot"},
|
||||||
|
@ -116,9 +247,41 @@ minetest.register_craft({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_alias("mcl_compass:compass", "mcl_compass:"..stereotype_frame)
|
minetest.register_alias("mcl_compass:compass", "mcl_compass:" .. stereotype_frame)
|
||||||
|
|
||||||
-- Export stereotype item for other mods to use
|
|
||||||
mcl_compass.stereotype = "mcl_compass:"..tostring(stereotype_frame)
|
|
||||||
|
|
||||||
|
|
||||||
|
minetest.register_node("mcl_compass:lodestone",{
|
||||||
|
description=S("Lodestone"),
|
||||||
|
on_rightclick = function(pos, node, player, itemstack)
|
||||||
|
local name = itemstack.get_name(itemstack)
|
||||||
|
if string_find(name,"mcl_compass:") then
|
||||||
|
if name ~= "mcl_compass:lodestone" then
|
||||||
|
itemstack:get_meta():set_string("pointsto", minetest.pos_to_string(pos))
|
||||||
|
local dir = player:get_look_horizontal()
|
||||||
|
local frame = get_compass_frame(pos, dir, itemstack)
|
||||||
|
itemstack:set_name("mcl_compass:" .. frame .. "_lodestone")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
tiles = {
|
||||||
|
"lodestone_top.png",
|
||||||
|
"lodestone_bottom.png",
|
||||||
|
"lodestone_side1.png",
|
||||||
|
"lodestone_side2.png",
|
||||||
|
"lodestone_side3.png",
|
||||||
|
"lodestone_side4.png"
|
||||||
|
},
|
||||||
|
groups = {pickaxey=1, material_stone=1},
|
||||||
|
_mcl_hardness = 1.5,
|
||||||
|
_mcl_blast_resistance = 6,
|
||||||
|
sounds = mcl_sounds.node_sound_stone_defaults()
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_compass:lodestone",
|
||||||
|
recipe = {
|
||||||
|
{"mcl_core:stonebrickcarved","mcl_core:stonebrickcarved","mcl_core:stonebrickcarved"},
|
||||||
|
{"mcl_core:stonebrickcarved", "mcl_core:diamondblock", "mcl_core:stonebrickcarved"},
|
||||||
|
{"mcl_core:stonebrickcarved", "mcl_core:stonebrickcarved", "mcl_core:stonebrickcarved"}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Kompasse sind Werkzeuge, die zum Ursprungspunkt der Welt (X@=0, Z@=0) oder zum Einstiegspunkt der Welt zeigen.
|
|
||||||
Compass=Kompass
|
Compass=Kompass
|
||||||
Points to the world origin=Zeigt zum Startpunkt der Welt
|
Points to the world origin=Zeigt zum Startpunkt der Welt
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Kompasse sind Werkzeuge, die zum Ursprungspunkt der Welt (X@=0, Z@=0) oder zum Einstiegspunkt der Welt zeigen.
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=Ein Kompass zeigt immer zum Weltspawn in der Oberwelt. In sämtlichen anderen Dimensionen dreht er sich zufällig.
|
||||||
|
Lodestone Compass=Leitstein Kompass
|
||||||
|
Points to a lodestone=Zeigt zu einem Leitstein
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=Leitstein Kompasse ähneln normalen Kompassen, aber sie zeigen zu einen spezifischen Leitstein.
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=Ein Leitstein Kompass kann mit einem normalen Kompass erstellt werden indem man ihn auf einem Leitstein benutzt. Nachdem er ein Leitstein Kompass geworden ist, wird er immer zu seinem Leitstein zeigen, sofern sie in der selben Dimension sind. Wenn sie nicht in der selben Dimension sind, dreht sich der Leitstein Kompass zufällig, wie ein normaler Kompass außerhalb der Oberwelt. Ein Leitstein Kompass kann mit einem anderem Leitstein verknüpft werden.
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Las brújulas son herramientas que apuntan al origen del mundo (X @ = 0, Z @ = 0) o al punto de generación en el mundo.
|
|
||||||
Compass=Brújula
|
Compass=Brújula
|
||||||
|
Points to the world origin=
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Las brújulas son herramientas que apuntan al origen del mundo (X @ = 0, Z @ = 0) o al punto de generación en el mundo.
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Les boussoles sont des outils qui pointent vers l'origine du monde (X@=0,Z@=0) ou le point d'apparition dans l'Overworld.
|
|
||||||
Compass=Boussole
|
Compass=Boussole
|
||||||
Points to the world origin=Pointe vers l'origine mondiale
|
Points to the world origin=Pointe vers l'origine mondiale
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Les boussoles sont des outils qui pointent vers l'origine du monde (X@=0,Z@=0) ou le point d'apparition dans l'Overworld.
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Kompasy to narzędzia które wskazują na punkt początku świata (X@=0, Z@=0) lub na miejsce odrodzenia na Powierzchni.
|
|
||||||
Compass=Kompas
|
Compass=Kompas
|
||||||
Points to the world origin=Wskazuje na początek świata
|
Points to the world origin=Wskazuje na początek świata
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Kompasy to narzędzia które wskazują na punkt początku świata (X@=0, Z@=0) lub na miejsce odrodzenia na Powierzchni.
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Компас - инструмент, показывающий на начало мира (X@=0, Z@=0) или на точку возрождения в Верхнем Мире.
|
|
||||||
Compass=Компас
|
Compass=Компас
|
||||||
Points to the world origin=Указывает на начало мира
|
Points to the world origin=Указывает на начало мира
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=Компас - инструмент, показывающий на начало мира (X@=0, Z@=0) или на точку возрождения в Верхнем Мире.
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=指南針是指向世界原點(X@=0,Z@=0)或主世界的出生點的工具。
|
|
||||||
Compass=指南針
|
Compass=指南針
|
||||||
Points to the world origin=指向世界原點
|
Points to the world origin=指向世界原點
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=指南針是指向世界原點(X@=0,Z@=0)或主世界的出生點的工具。
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
# textdomain: mcl_compass
|
# textdomain: mcl_compass
|
||||||
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=
|
|
||||||
Compass=
|
Compass=
|
||||||
Points to the world origin=
|
Points to the world origin=
|
||||||
|
Compasses are tools which point to the world origin (X@=0, Z@=0) or the spawn point in the Overworld.=
|
||||||
|
A Compass always points to the world spawn point when the player is in the overworld. In other dimensions, it spins randomly.=
|
||||||
|
Lodestone Compass=
|
||||||
|
Points to a lodestone=
|
||||||
|
Lodestone compasses resemble regular compasses, but they point to a specific lodestone.=
|
||||||
|
A Lodestone compass can be made from an ordinary compass by using it on a lodestone. After becoming a lodestone compass, it always points to its linked lodestone, provided that they are in the same dimension. If not in the same dimension, the lodestone compass spins randomly, similarly to a regular compass when outside the overworld. A lodestone compass can be relinked with another lodestone.=
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name = mcl_compass
|
name = mcl_compass
|
||||||
description = A compass item which points towards the world origin.
|
description = A compass item which points towards the world origin.
|
||||||
depends = mcl_core, mcl_worlds, mesecons
|
depends = mcl_core, mcl_worlds, mesecons, mcl_sounds
|
||||||
optional_depends = doc
|
optional_depends = doc
|
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 6.3 KiB |
|
@ -0,0 +1,7 @@
|
||||||
|
# MineClone2 Copper
|
||||||
|
|
||||||
|
### by NO11
|
||||||
|
|
||||||
|
Adds copper ore, blocks and items.
|
||||||
|
|
||||||
|
![screenshot](./screenshot.png)
|
|
@ -0,0 +1,76 @@
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:block_raw",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:raw_copper", "mcl_copper:raw_copper", "mcl_copper:raw_copper" },
|
||||||
|
{ "mcl_copper:raw_copper", "mcl_copper:raw_copper", "mcl_copper:raw_copper" },
|
||||||
|
{ "mcl_copper:raw_copper", "mcl_copper:raw_copper", "mcl_copper:raw_copper" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:block",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:copper_ingot", "mcl_copper:copper_ingot" },
|
||||||
|
{ "mcl_copper:copper_ingot", "mcl_copper:copper_ingot" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:block_cut 4",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block", "mcl_copper:block" },
|
||||||
|
{ "mcl_copper:block", "mcl_copper:block" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:block_exposed_cut 4",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block_exposed", "mcl_copper:block_exposed" },
|
||||||
|
{ "mcl_copper:block_exposed", "mcl_copper:block_exposed" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:block_oxidized_cut 4",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block_oxidized", "mcl_copper:block_oxidized" },
|
||||||
|
{ "mcl_copper:block_oxidized", "mcl_copper:block_oxidized" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:mcl_copper:block_weathered_cut 4",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block_weathered", "mcl_copper:block_weathered" },
|
||||||
|
{ "mcl_copper:block_weathered", "mcl_copper:block_weathered" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:copper_ingot 4",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_copper:raw_copper 9",
|
||||||
|
recipe = {
|
||||||
|
{ "mcl_copper:block_raw" },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "cooking",
|
||||||
|
output = "mcl_copper:copper_ingot",
|
||||||
|
recipe = "mcl_copper:raw_copper",
|
||||||
|
cooktime = 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "cooking",
|
||||||
|
output = "mcl_copper:copper_ingot",
|
||||||
|
recipe = "mcl_copper:stone_with_copper",
|
||||||
|
cooktime = 10,
|
||||||
|
})
|
|
@ -0,0 +1,181 @@
|
||||||
|
--local deepslate_mod = minetest.get_modpath("mcl_deepslate")
|
||||||
|
|
||||||
|
local function register_oxidation_abm(abm_name, node_name, oxidized_variant)
|
||||||
|
minetest.register_abm({
|
||||||
|
label = abm_name,
|
||||||
|
nodenames = {node_name},
|
||||||
|
interval = 500,
|
||||||
|
chance = 3,
|
||||||
|
action = function(pos, node)
|
||||||
|
minetest.swap_node(pos, {name = oxidized_variant, param2 = node.param2})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local stairs = {
|
||||||
|
{"stair", "exposed", "_inner", "cut_inner"},
|
||||||
|
{"stair", "weathered", "_inner", "exposed_cut_inner"},
|
||||||
|
{"stair", "exposed", "_outer", "cut_outer"},
|
||||||
|
{"stair", "weathered", "_outer", "exposed_cut_outer"},
|
||||||
|
{"stair", "oxidized", "_outer", "weathered_cut_outer"},
|
||||||
|
{"stair", "oxidized", "_inner", "weathered_cut_inner"},
|
||||||
|
{"slab", "exposed", "","cut"},
|
||||||
|
{"slab", "oxidized", "","weathered_cut"},
|
||||||
|
{"slab", "weathered", "","exposed_cut"},
|
||||||
|
{"slab", "exposed", "_top","cut_top"},
|
||||||
|
{"slab", "oxidized", "_top", "weathered_cut_top"},
|
||||||
|
{"slab", "weathered", "_top","exposed_cut_top"},
|
||||||
|
{"slab", "exposed", "_double","cut_double"},
|
||||||
|
{"slab", "oxidized", "_double","weathered_cut_double"},
|
||||||
|
{"slab", "weathered", "_double","exposed_cut_double"},
|
||||||
|
{"stair", "exposed", "","cut"},
|
||||||
|
{"stair", "oxidized", "", "weathered_cut"},
|
||||||
|
{"stair", "weathered", "", "exposed_cut"},
|
||||||
|
}]]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local function anti_oxidation_particles(pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = 8,
|
||||||
|
time = 1,
|
||||||
|
minpos = {x = pos.x - 1, y = pos.y - 1, z = pos.z - 1},
|
||||||
|
maxpos = {x = pos.x + 1, y = pos.y + 1, z = pos.z + 1},
|
||||||
|
minvel = {x = 0, y = 0, z = 0},
|
||||||
|
maxvel = {x = 0, y = 0, z = 0},
|
||||||
|
minacc = {x = 0, y = 0, z = 0},
|
||||||
|
maxacc = {x = 0, y = 0, z = 0},
|
||||||
|
minexptime = 0.5,
|
||||||
|
maxexptime = 1,
|
||||||
|
minsize = 1,
|
||||||
|
maxsize = 2.5,
|
||||||
|
collisiondetection = false,
|
||||||
|
vertical = false,
|
||||||
|
texture = "mcl_copper_anti_oxidation_particle.png",
|
||||||
|
glow = 5,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function add_wear(placer, itemstack)
|
||||||
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
|
local tool = itemstack:get_name()
|
||||||
|
local wear = mcl_autogroup.get_wear(tool, "axey")
|
||||||
|
itemstack:add_wear(wear)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function anti_oxidation(itemstack, placer, pointed_thing)
|
||||||
|
if pointed_thing.type ~= "node" then return end
|
||||||
|
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
local noddef = minetest.registered_nodes[minetest.get_node(pointed_thing.under).name]
|
||||||
|
|
||||||
|
if not placer:get_player_control().sneak and noddef.on_rightclick then
|
||||||
|
return minetest.item_place(itemstack, placer, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
|
||||||
|
minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
if noddef._mcl_stripped_variant == nil then
|
||||||
|
for _, c in pairs(stairs) do
|
||||||
|
if noddef.name == "mcl_stairs:"..c[1].."_copper_"..c[2].."_cut"..c[3] then
|
||||||
|
minetest.swap_node(pointed_thing.under, {name="mcl_stairs:"..c[1].."_copper_"..c[4], param2=node.param2})
|
||||||
|
anti_oxidation_particles(pointed_thing)
|
||||||
|
add_wear(placer, itemstack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if noddef._mcl_anti_oxidation_variant ~= nil then
|
||||||
|
minetest.swap_node(pointed_thing.under, {name=noddef._mcl_anti_oxidation_variant, param2=node.param2})
|
||||||
|
anti_oxidation_particles(pointed_thing)
|
||||||
|
add_wear(placer, itemstack)
|
||||||
|
end
|
||||||
|
elseif noddef._mcl_stripped_variant ~= nil then
|
||||||
|
minetest.swap_node(pointed_thing.under, {name=noddef._mcl_stripped_variant, param2=node.param2})
|
||||||
|
add_wear(placer, itemstack)
|
||||||
|
else
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function register_axe_override(axe_name)
|
||||||
|
minetest.override_item("mcl_tools:axe_"..axe_name, {
|
||||||
|
on_place = anti_oxidation,
|
||||||
|
})
|
||||||
|
end]]
|
||||||
|
|
||||||
|
--[[ Commented out for now because there the discussion how to handle this is ongoing
|
||||||
|
local stonelike = {"mcl_core:stone", "mcl_core:diorite", "mcl_core:andesite", "mcl_core:granite"}
|
||||||
|
if not deepslate_mod then
|
||||||
|
if minetest.settings:get_bool("mcl_generate_ores", true) then
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "mcl_copper:stone_with_copper",
|
||||||
|
wherein = stonelike,
|
||||||
|
clust_scarcity = 830,
|
||||||
|
clust_num_ores = 5,
|
||||||
|
clust_size = 3,
|
||||||
|
y_min = mcl_vars.mg_overworld_min,
|
||||||
|
y_max = mcl_worlds.layer_to_y(39),
|
||||||
|
})
|
||||||
|
minetest.register_ore({
|
||||||
|
ore_type = "scatter",
|
||||||
|
ore = "mcl_copper:stone_with_copper",
|
||||||
|
wherein = stonelike,
|
||||||
|
clust_scarcity = 1660,
|
||||||
|
clust_num_ores = 4,
|
||||||
|
clust_size = 2,
|
||||||
|
y_min = mcl_worlds.layer_to_y(40),
|
||||||
|
y_max = mcl_worlds.layer_to_y(63),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--]]
|
||||||
|
local block_oxidation = {
|
||||||
|
{"", "_exposed"},
|
||||||
|
{"_cut", "_exposed_cut"},
|
||||||
|
{"_exposed", "_weathered"},
|
||||||
|
{"_exposed_cut", "_weathered_cut"},
|
||||||
|
{"_weathered", "_oxidized"},
|
||||||
|
{"_weathered_cut", "_oxidized_cut"}
|
||||||
|
}
|
||||||
|
|
||||||
|
local stair_oxidation = {
|
||||||
|
{"slab", "cut", "exposed_cut"},
|
||||||
|
{"slab", "exposed_cut", "weathered_cut"},
|
||||||
|
{"slab", "weathered_cut", "oxidized_cut"},
|
||||||
|
{"slab", "cut_top", "exposed_cut_top"},
|
||||||
|
{"slab", "exposed_cut_top", "weathered_cut_top"},
|
||||||
|
{"slab", "weathered_cut_top", "oxidized_cut_double"},
|
||||||
|
{"slab", "cut_double", "exposed_cut_double"},
|
||||||
|
{"slab", "exposed_cut_double", "weathered_cut_double"},
|
||||||
|
{"slab", "weathered_cut_double", "oxidized_cut_double"},
|
||||||
|
{"stair", "cut", "exposed_cut"},
|
||||||
|
{"stair", "exposed_cut", "weathered_cut"},
|
||||||
|
{"stair", "weathered_cut", "oxidized_cut"},
|
||||||
|
{"stair", "cut_inner", "exposed_cut_inner"},
|
||||||
|
{"stair", "exposed_cut_inner", "weathered_cut_inner"},
|
||||||
|
{"stair", "weathered_cut_inner", "oxidized_cut_inner"},
|
||||||
|
{"stair", "cut_outer", "exposed_cut_outer"},
|
||||||
|
{"stair", "exposed_cut_outer", "weathered_cut_outer"},
|
||||||
|
{"stair", "weathered_cut_outer", "oxidized_cut_outer"}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, b in pairs(block_oxidation) do
|
||||||
|
register_oxidation_abm("Copper oxidation", "mcl_copper:block"..b[1], "mcl_copper:block"..b[2])
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, s in pairs(stair_oxidation) do
|
||||||
|
register_oxidation_abm("Copper oxidation", "mcl_stairs:"..s[1].."_copper_"..s[2], "mcl_stairs:"..s[1].."_copper_"..s[3])
|
||||||
|
end
|
||||||
|
|
||||||
|
--local axes = {"wood", "stone", "iron", "gold", "diamond"}
|
||||||
|
--[[
|
||||||
|
for _, axe in pairs(axes) do
|
||||||
|
register_axe_override(axe)
|
||||||
|
end
|
||||||
|
]]
|
|
@ -0,0 +1,6 @@
|
||||||
|
local path = minetest.get_modpath("mcl_copper")
|
||||||
|
|
||||||
|
dofile(path .. "/nodes.lua")
|
||||||
|
dofile(path .. "/items.lua")
|
||||||
|
dofile(path .. "/crafting.lua")
|
||||||
|
dofile(path .. "/functions.lua")
|
|
@ -0,0 +1,15 @@
|
||||||
|
local S = minetest.get_translator("mcl_copper")
|
||||||
|
|
||||||
|
minetest.register_craftitem("mcl_copper:copper_ingot", {
|
||||||
|
description = S("Copper Ingot"),
|
||||||
|
_doc_items_longdesc = S("Molten Raw Copper. It is used to craft blocks."),
|
||||||
|
inventory_image = "mcl_copper_ingot.png",
|
||||||
|
groups = { craftitem = 1 },
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craftitem("mcl_copper:raw_copper", {
|
||||||
|
description = S("Raw Copper"),
|
||||||
|
_doc_items_longdesc = S("Raw Copper. Mine a Copper Ore to get it."),
|
||||||
|
inventory_image = "mcl_copper_raw.png",
|
||||||
|
groups = { craftitem = 1 },
|
||||||
|
})
|
|
@ -0,0 +1,37 @@
|
||||||
|
# textdomain: mcl_copper
|
||||||
|
A block of copper is mostly a decorative block.=Ein Kupferblock wird meistens als dekorativer Block verwendet.
|
||||||
|
A block used for compact raw copper storage.=Ein Block für die kompakte Lagerung von Rohkupfer.
|
||||||
|
Block of Copper=Kupferblock
|
||||||
|
Block of Raw Copper=Rohkupferblock
|
||||||
|
Copper Ingot=Kupfer Barren
|
||||||
|
Copper Ore=Kupfererz
|
||||||
|
Cut copper is a decorative block.=Ein Geschnittener Kupferblock ist ein dekorativer Block.
|
||||||
|
Cut Copper=Geschnittener Kupferblock
|
||||||
|
Double Slab of Cut Copper=Doppelte Geschnittene Kupferstufe
|
||||||
|
Double Slab of Exposed Cut Copper=Doppelte Angelaufene Geschnittene Kupferstufe
|
||||||
|
Double Slab of Oxidized Cut Copper=Doppelte Oxidierte Geschnittene Kupferstufe
|
||||||
|
Double Slab of Weathered Cut Copper=Doppelte Verwitterte Geschnittene Kupferstufe
|
||||||
|
Exposed copper is a decorative block.=Ein Angelaufener Kupferblock ist ein dekorativer Block.
|
||||||
|
Exposed Copper=Angelaufener Kupferblock
|
||||||
|
Exposed cut copper is a decorative block.=Ein Angelaufener geschnittener Kupferblock ist ein dekorativer Block.
|
||||||
|
Exposed Cut Copper=Angelaufener geschnittener Kupferblock
|
||||||
|
Molten Raw Copper. It is used to craft blocks.=Geschmolzenes Rohkupfer. Es wird verwendet, um Blöcke herzustellen.
|
||||||
|
Oxidized copper is a decorative block.=Ein Oxidierter Kupferblockist ist ein dekorativer Block.
|
||||||
|
Oxidized Copper=Oxidierter Kupferblock
|
||||||
|
Oxidized cut copper is a decorative block.=Ein Oxidierter geschnittener Kupferblock ist ein dekorativer Block.
|
||||||
|
Oxidized Cut Copper=Oxidierter geschnittener Kupferblock
|
||||||
|
Raw Copper. Mine a Copper Ore to get it.=Bauen sie ein Kupfererz ab, um es zu erhalten.
|
||||||
|
Raw Copper=Rohkupfer
|
||||||
|
Slab of Cut Copper=Geschnittene Kupferstufe
|
||||||
|
Slab of Exposed Cut Copper=Angelaufene Geschnittene Kupferstufe
|
||||||
|
Slab of Oxidized Cut Copper=Oxidierte Geschnittene Kupferstufe
|
||||||
|
Slab of Weathered Cut Copper=Verwitterte Geschnittene Kupferstufe
|
||||||
|
Some copper contained in stone, it is pretty common and can be found below sea level.=Stein, in dem etwas Kupfer enthalten ist. Es ist ziemlich häufig und kann unter dem Meeresspiegel gefunden werden.
|
||||||
|
Stairs of Cut Copper=Geschnittene Kupfertreppe
|
||||||
|
Stairs of Exposed Cut Copper=Angelaufene Geschnittene Kupfertreppe
|
||||||
|
Stairs of Oxidized Cut Copper=Oxidierte Geschnittene Kupfertreppe
|
||||||
|
Stairs of Weathered Cut Copper=Verwitterte Geschnittene Kupfertreppe
|
||||||
|
Weathered copper is a decorative block.=Ein Verwitterter Kupferblock ist ein dekorativer Block.
|
||||||
|
Weathered Copper=Verwitterter Kupferblock
|
||||||
|
Weathered cut copper is a decorative block.=Ein Verwitterter geschnittener Kupferblock ist ein dekorativer Block.
|
||||||
|
Weathered Cut Copper=Verwitterter geschnittener Kupferblock
|