forked from VoxeLibre/VoxeLibre
Merge branch 'master' of https://git.minetest.land/Wuzzy/MineClone2
This commit is contained in:
commit
a3ccb54376
|
@ -85,3 +85,12 @@ Report all bugs and missing Minecraft features here:
|
|||
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
||||
|
||||
<ircs://irc.freenode.net:6697/#mineclone2>
|
||||
|
||||
## Creating releases
|
||||
* Launch MineClone2 to make sure it still runs
|
||||
* Update the version number in README.md
|
||||
* Use `git tag <version number>` to tag the latest commit with the version number
|
||||
* Push to repo (don't forget `--tags`!)
|
||||
* Update ContentDB (https://content.minetest.net/packages/Wuzzy/mineclone2/)
|
||||
* Update first post in forum thread (https://forum.minetest.net/viewtopic.php?f=50&t=16407)
|
||||
* Post release announcement and changelog in forums
|
||||
|
|
|
@ -20,7 +20,6 @@ For these features, no easy Lua workaround could be found.
|
|||
## Interface
|
||||
- Inventory: Hold down right mouse button while holding an item stack to drop items into the slots as you move the mouse. Makes crafting MUCH faster
|
||||
- Sneak+Leftclick on crafting output crafts as many items as possible and immediately puts it into the player inventory ([issue 5211](https://github.com/minetest/minetest/issues/5211))
|
||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Required for large chests
|
||||
- Sneak+click puts items in different inventories depending on the item type (maybe group-based)? Required for sneak-clicking to armor slots
|
||||
|
||||
## Workaround theoretically possible
|
||||
|
@ -35,6 +34,7 @@ For these features, a workaround (or hack ;-)) by using Lua is theoretically pos
|
|||
- Set frequency in which players lose breath. 2 seconds are hardcoded in Minetest, in Minecraft it's 1 second
|
||||
- Set damage frequency of `damage_per_second`. In Minecraft many things damage players every half-second rather than every second
|
||||
- Possible to damage players directly when they are with the head inside. This allows to add Minecraft-like suffocation
|
||||
- Sneak+click on inventory slot should be able to put items into additional “fallback inventories” if the first inventory is full. Useful for large chests
|
||||
|
||||
#### Nice-to-haye
|
||||
- Utility function to rotate pillar-like nodes, requiring only 3 possible orientations (X, Y, Z). Basically this is `minetest.rotate_node` but with less orientations; the purpur pillar would mess up if a mirrored rotation would be possible. This is already implemented in MCL2, See `mcl_util` for more infos
|
||||
|
|
|
@ -32,6 +32,10 @@ local STEP_LENGTH = 0.3
|
|||
-- How many rays to compute entity exposure to explosion
|
||||
local N_EXPOSURE_RAYS = 16
|
||||
|
||||
-- Nodes having a blast resistance of this value or higher are treated as
|
||||
-- indestructible
|
||||
local INDESTRUCT_BLASTRES = 1000000
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
-- Store blast resistance values by content ids to improve performance.
|
||||
for name, def in pairs(minetest.registered_nodes) do
|
||||
|
@ -135,14 +139,21 @@ end
|
|||
-- strength - The strength of each ray
|
||||
-- raydirs - The directions for each ray
|
||||
-- radius - The maximum distance each ray will go
|
||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||
-- fire - If true, 1/3 of destroyed nodes become fire
|
||||
-- info - Table containing information about explosion
|
||||
-- puncher - object that punches other objects (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||
-- fire - If true, 1/3 nodes become fire
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
-- max_blast_resistance - The explosion will treat all non-indestructible nodes
|
||||
-- as having a blast resistance of no more than this
|
||||
-- value
|
||||
--
|
||||
-- Note that this function has been optimized, it contains code which has been
|
||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||
-- measured to give a significant performance increase.
|
||||
local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire, puncher, creative_enabled)
|
||||
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
local vm = minetest.get_voxel_manip()
|
||||
|
||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||
|
@ -164,39 +175,49 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
local data = vm:get_data()
|
||||
local destroy = {}
|
||||
|
||||
local drop_chance = info.drop_chance
|
||||
local fire = info.fire
|
||||
local max_blast_resistance = info.max_blast_resistance
|
||||
|
||||
-- Trace rays for environment destruction
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
local rdir_z = raydirs[i].z
|
||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||
if info.griefing then
|
||||
for i = 1, #raydirs do
|
||||
local rpos_x = pos.x
|
||||
local rpos_y = pos.y
|
||||
local rpos_z = pos.z
|
||||
local rdir_x = raydirs[i].x
|
||||
local rdir_y = raydirs[i].y
|
||||
local rdir_z = raydirs[i].z
|
||||
local rstr = (0.7 + math.random() * 0.6) * strength
|
||||
|
||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
for r = 0, math.ceil(radius * (1.0 / STEP_LENGTH)) do
|
||||
local npos_x = math.floor(rpos_x + 0.5)
|
||||
local npos_y = math.floor(rpos_y + 0.5)
|
||||
local npos_z = math.floor(rpos_z + 0.5)
|
||||
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
|
||||
npos_x - emin_x + 1
|
||||
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||
local cid = data[idx]
|
||||
local br = node_blastres[cid]
|
||||
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||
br = max_blast_resistance
|
||||
end
|
||||
|
||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||
|
||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||
rpos_y = rpos_y + STEP_LENGTH * rdir_y
|
||||
rpos_z = rpos_z + STEP_LENGTH * rdir_z
|
||||
|
||||
if rstr <= 0 then
|
||||
break
|
||||
end
|
||||
rstr = rstr - 0.75 * STEP_LENGTH - (br + 0.3) * STEP_LENGTH
|
||||
|
||||
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
||||
destroy[hash] = idx
|
||||
if rstr <= 0 then
|
||||
break
|
||||
end
|
||||
|
||||
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
|
||||
destroy[hash] = idx
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -327,7 +348,7 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
|
||||
-- Remove destroyed blocks and drop items
|
||||
for hash, idx in pairs(destroy) do
|
||||
local do_drop = not creative_enabled and math.random() <= drop_chance
|
||||
local do_drop = math.random() <= drop_chance
|
||||
local on_blast = node_on_blast[data[idx]]
|
||||
local remove = true
|
||||
|
||||
|
@ -377,7 +398,6 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
|||
-- Log explosion
|
||||
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
||||
' with strength ' .. strength .. ' and radius ' .. radius)
|
||||
|
||||
end
|
||||
|
||||
-- Create an explosion with strength at pos.
|
||||
|
@ -385,16 +405,24 @@ end
|
|||
-- Parameters:
|
||||
-- pos - The position where the explosion originates from
|
||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
||||
-- info - Table containing information about explosion.
|
||||
-- info - Table containing information about explosion
|
||||
-- puncher - object that is reported as source of punches/damage (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||
-- explosion (defaults to 1.0 / strength)
|
||||
-- no_sound - If true then the explosion will not play a sound
|
||||
-- no_particle - If true then the explosion will not create particles
|
||||
-- explosion (default: 1.0 / strength)
|
||||
-- max_blast_resistance - If specified the explosion will treat all
|
||||
-- non-indestructible nodes as having a blast resistance
|
||||
-- of no more than this value
|
||||
-- sound - If true, the explosion will play a sound (default: true)
|
||||
-- particles - If true, the explosion will create particles (default: true)
|
||||
-- fire - If true, 1/3 nodes become fire (default: false)
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||
if info == nil then
|
||||
info = {}
|
||||
end
|
||||
|
||||
-- The maximum blast radius (in the air)
|
||||
local radius = math.ceil(1.3 * strength / (0.3 * 0.75) * 0.3)
|
||||
|
||||
|
@ -403,13 +431,31 @@ function mcl_explosions.explode(pos, strength, info, puncher)
|
|||
end
|
||||
local shape = sphere_shapes[radius]
|
||||
|
||||
local creative_enabled = minetest.is_creative_enabled("")
|
||||
trace_explode(pos, strength, shape, radius, (info and info.drop_chance) or 1 / strength, info.fire == true, puncher, creative_enabled)
|
||||
-- Default values
|
||||
if info.drop_chance == nil then info.drop_chance = 1 / strength end
|
||||
if info.particles == nil then info.particles = true end
|
||||
if info.sound == nil then info.sound = true end
|
||||
if info.fire == nil then info.fire = false end
|
||||
if info.griefing == nil then info.griefing = true end
|
||||
if info.max_blast_resistance == nil then
|
||||
info.max_blast_resistance = INDESTRUCT_BLASTRES
|
||||
end
|
||||
|
||||
if not (info and info.no_particle) then
|
||||
-- For backwards compatibility
|
||||
if info.no_particle then info.particles = false end
|
||||
if info.no_sound then info.sound = false end
|
||||
|
||||
-- Dont do drops in creative mode
|
||||
if minetest.is_creative_enabled("") then
|
||||
info.drop_chance = 0
|
||||
end
|
||||
|
||||
trace_explode(pos, strength, shape, radius, info, puncher)
|
||||
|
||||
if info.particles then
|
||||
add_particles(pos, radius)
|
||||
end
|
||||
if not (info and info.no_sound) then
|
||||
if info.sound then
|
||||
minetest.sound_play("tnt_explode", {
|
||||
pos = pos, gain = 1.0,
|
||||
max_hear_distance = strength * 16
|
||||
|
|
|
@ -25,6 +25,7 @@ mcl_vars.inventory_header = ""
|
|||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local minecraft_height_limit = 256
|
||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
||||
local singlenode = mg_name == "singlenode"
|
||||
|
||||
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
||||
|
@ -45,7 +46,7 @@ local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_
|
|||
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
|
||||
|
||||
if not superflat then
|
||||
if not superflat and not singlenode then
|
||||
-- Normal mode
|
||||
--[[ Realm stacking (h is for height)
|
||||
- Overworld (h>=256)
|
||||
|
@ -66,6 +67,14 @@ if not superflat then
|
|||
mcl_vars.mg_lava = true
|
||||
mcl_vars.mg_bedrock_is_rough = true
|
||||
|
||||
elseif singlenode then
|
||||
mcl_vars.mg_overworld_min = -66
|
||||
mcl_vars.mg_overworld_max_official = mcl_vars.mg_overworld_min + minecraft_height_limit
|
||||
mcl_vars.mg_bedrock_overworld_min = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_overworld_max = mcl_vars.mg_bedrock_overworld_min
|
||||
mcl_vars.mg_lava = false
|
||||
mcl_vars.mg_lava_overworld_max = mcl_vars.mg_overworld_min
|
||||
mcl_vars.mg_bedrock_is_rough = false
|
||||
else
|
||||
-- Classic superflat
|
||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
||||
|
@ -128,3 +137,4 @@ minetest.craftitemdef_default.stack_max = 64
|
|||
|
||||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
|
|
|
@ -395,4 +395,13 @@ function mcl_util.generate_on_place_plant_function(condition)
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
-- adjust the y level of an object to the center of its collisionbox
|
||||
-- used to get the origin position of entity explosions
|
||||
function mcl_util.get_object_center(obj)
|
||||
local collisionbox = obj:get_properties().collisionbox
|
||||
local pos = obj:get_pos()
|
||||
local ymin = collisionbox[2]
|
||||
local ymax = collisionbox[5]
|
||||
pos.y = pos.y + (ymax - ymin) / 2.0
|
||||
return pos
|
||||
end
|
||||
|
|
|
@ -789,18 +789,16 @@ local check_for_death = function(self, cause, cmi_cause)
|
|||
local puncher = cmi_cause.puncher
|
||||
if puncher then
|
||||
wielditem = puncher:get_wielded_item()
|
||||
|
||||
if mod_experience and ((not self.child) or self.type ~= "animal") then
|
||||
mcl_experience.throw_experience(self.object:get_pos(), math.random(self.xp_min, self.xp_max))
|
||||
end
|
||||
end
|
||||
end
|
||||
local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.has_enchantment(wielditem, "fire_aspect")
|
||||
local looting = mcl_enchanting.get_enchantment(wielditem, "looting")
|
||||
item_drop(self, cooked, looting)
|
||||
end
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
if mod_experience and ((not self.child) or self.type ~= "animal") then
|
||||
mcl_experience.throw_experience(pos, math.random(self.xp_min, self.xp_max))
|
||||
end
|
||||
end
|
||||
|
||||
-- execute custom death function
|
||||
|
@ -2258,7 +2256,6 @@ local dogswitch = function(self, dtime)
|
|||
return self.dogshoot_switch
|
||||
end
|
||||
|
||||
|
||||
-- execute current state (stand, walk, run, attacks)
|
||||
-- returns true if mob has died
|
||||
local do_states = function(self, dtime)
|
||||
|
@ -2550,7 +2547,7 @@ local do_states = function(self, dtime)
|
|||
|
||||
if mod_explosions then
|
||||
if mobs_griefing and not minetest.is_protected(pos, "") then
|
||||
mcl_explosions.explode(self.object:get_pos(), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
||||
mcl_explosions.explode(mcl_util.get_object_center(self.object), self.explosion_strength, { drop_chance = 1.0 }, self.object)
|
||||
else
|
||||
minetest.sound_play(self.sounds.explode, {
|
||||
pos = pos,
|
||||
|
|
|
@ -71,7 +71,7 @@ mobs:register_mob("mobs_mc:creeper", {
|
|||
if self._forced_explosion_countdown_timer ~= nil then
|
||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||
if self._forced_explosion_countdown_timer <= 0 then
|
||||
mobs:boom(self, self.object:get_pos(), self.explosion_strength)
|
||||
mobs:boom(self, mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||
self.object:remove()
|
||||
end
|
||||
end
|
||||
|
|
|
@ -962,6 +962,7 @@ mobs:register_mob("mobs_mc:villager", {
|
|||
walk_velocity = 1.2,
|
||||
run_velocity = 2.4,
|
||||
drops = {},
|
||||
can_despawn = false,
|
||||
-- TODO: sounds
|
||||
animation = {
|
||||
stand_speed = 25,
|
||||
|
|
|
@ -26,7 +26,7 @@ S("An arrow fired from a bow has a regular damage of 1-9. At full charge, there'
|
|||
S("Arrows might get stuck on solid blocks and can be retrieved again. They are also capable of pushing wooden buttons."),
|
||||
_doc_items_usagehelp = S("To use arrows as ammunition for a bow, just put them anywhere in your inventory, they will be used up automatically. To use arrows as ammunition for a dispenser, place them in the dispenser's inventory. To retrieve an arrow that sticks in a block, simply walk close to it."),
|
||||
inventory_image = "mcl_bows_arrow_inv.png",
|
||||
groups = { ammo=1, ammo_bow=1 },
|
||||
groups = { ammo=1, ammo_bow=1, ammo_bow_regular=1 },
|
||||
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
|
||||
-- Shoot arrow
|
||||
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
|
||||
|
@ -166,7 +166,7 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
|||
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||
for _,obj in ipairs(objects) do
|
||||
if obj:is_player() then
|
||||
if not minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
if self._collectable and not minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
if obj:get_inventory():room_for_item("main", "mcl_bows:arrow") then
|
||||
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
||||
minetest.sound_play("item_drop_pickup", {
|
||||
|
|
|
@ -33,7 +33,7 @@ local bow_load = {}
|
|||
-- Another player table, this one stores the wield index of the bow being charged
|
||||
local bow_index = {}
|
||||
|
||||
mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack)
|
||||
mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
|
||||
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
||||
if power == nil then
|
||||
power = BOW_MAX_SPEED --19
|
||||
|
@ -63,6 +63,7 @@ mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damag
|
|||
le._is_critical = is_critical
|
||||
le._startpos = pos
|
||||
le._knockback = knockback
|
||||
le._collectable = collectable
|
||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||
if shooter ~= nil and shooter:is_player() then
|
||||
if obj:get_luaentity().player == "" then
|
||||
|
@ -91,6 +92,7 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
|||
local arrow_stack, arrow_stack_id = get_arrow(player)
|
||||
local arrow_itemstring
|
||||
local has_infinity_enchantment = mcl_enchanting.has_enchantment(player:get_wielded_item(), "infinity")
|
||||
local infinity_used = false
|
||||
|
||||
if minetest.is_creative_enabled(player:get_player_name()) then
|
||||
if arrow_stack then
|
||||
|
@ -103,7 +105,9 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
|||
return false
|
||||
end
|
||||
arrow_itemstring = arrow_stack:get_name()
|
||||
if not has_infinity_enchantment then
|
||||
if has_infinity_enchantment and minetest.get_item_group(arrow_itemstring, "ammo_bow_regular") > 0 then
|
||||
infinity_used = true
|
||||
else
|
||||
arrow_stack:take_item()
|
||||
end
|
||||
local inv = player:get_inventory()
|
||||
|
@ -116,7 +120,7 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
|||
local dir = player:get_look_dir()
|
||||
local yaw = player:get_look_horizontal()
|
||||
|
||||
mcl_bows.shoot_arrow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item())
|
||||
mcl_bows.shoot_arrow(arrow_itemstring, {x=playerpos.x,y=playerpos.y+1.5,z=playerpos.z}, dir, yaw, player, power, damage, is_critical, player:get_wielded_item(), not infinity_used)
|
||||
return true
|
||||
end
|
||||
|
||||
|
|
|
@ -2,25 +2,14 @@ local S = minetest.get_translator("mcl_chests")
|
|||
local mod_doc = minetest.get_modpath("doc")
|
||||
|
||||
-- Chest Entity
|
||||
local entity_animations = {}
|
||||
local animate_chests = (minetest.settings:get_bool("animated_chests") ~= false)
|
||||
local entity_animation_speed = 25
|
||||
|
||||
do
|
||||
local names = {"open", "opened", "close", "closed"}
|
||||
local following = {["open"] = "opened", ["close"] = "closed"}
|
||||
local durations = {10, 0, 10, 5}
|
||||
local anim_start = 0
|
||||
for index, name in ipairs(names) do
|
||||
local duration = durations[index]
|
||||
local anim_end = anim_start + duration
|
||||
entity_animations[name] = {
|
||||
bounds = {x = anim_start, y = anim_end},
|
||||
sched_anim = following[name],
|
||||
sched_time = duration / entity_animation_speed
|
||||
}
|
||||
anim_start = anim_end
|
||||
end
|
||||
end
|
||||
local entity_animations = {
|
||||
["open"] = {x = 0, y = 10},
|
||||
["open_partly"] = {x = 0, y = 7},
|
||||
["close"] = {x = 10, y = 20},
|
||||
["close_partly"] = {x = 13, y = 20},
|
||||
}
|
||||
|
||||
minetest.register_entity("mcl_chests:chest", {
|
||||
initial_properties = {
|
||||
|
@ -33,21 +22,19 @@ minetest.register_entity("mcl_chests:chest", {
|
|||
|
||||
set_animation = function(self, animname)
|
||||
local anim = entity_animations[animname]
|
||||
self.object:set_animation(anim.bounds, entity_animation_speed, 0, false)
|
||||
if anim.sched_anim then
|
||||
self.sched_anim = anim.sched_anim
|
||||
self.sched_time = anim.sched_time
|
||||
end
|
||||
if not anim then return end
|
||||
self.object:set_animation(anim, entity_animation_speed, 0, false)
|
||||
end,
|
||||
|
||||
open = function(self, playername)
|
||||
open = function(self, playername, partly)
|
||||
self.players[playername] = true
|
||||
if not self.is_open then
|
||||
self.is_open = true
|
||||
self:set_animation("open")
|
||||
self:set_animation(partly and "open_partly" or "open")
|
||||
minetest.sound_play(self.sound_prefix .. "_open", {
|
||||
pos = self.node_pos,
|
||||
})
|
||||
self.is_open = true
|
||||
self.opened_partly = partly
|
||||
end
|
||||
end,
|
||||
|
||||
|
@ -58,11 +45,12 @@ minetest.register_entity("mcl_chests:chest", {
|
|||
for _ in pairs(playerlist) do
|
||||
return
|
||||
end
|
||||
self.is_open = false
|
||||
self:set_animation("close")
|
||||
self:set_animation(self.opened_partly and "close_partly" or "close")
|
||||
minetest.sound_play(self.sound_prefix .. "_close", {
|
||||
pos = self.node_pos,
|
||||
})
|
||||
self.is_open = false
|
||||
self.opened_partly = false
|
||||
end
|
||||
end,
|
||||
|
||||
|
@ -100,23 +88,12 @@ minetest.register_entity("mcl_chests:chest", {
|
|||
|
||||
on_activate = function(self)
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
self:set_animation("closed")
|
||||
self.players = {}
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
local sched_anim, sched_time = self.sched_anim, self.sched_time
|
||||
if not self:check() then
|
||||
self.object:remove()
|
||||
elseif sched_anim and sched_time then
|
||||
sched_time = sched_time - dtime
|
||||
if sched_time < 0 then
|
||||
self:set_animation(sched_anim)
|
||||
self.sched_time = nil
|
||||
self.sched_anim = nil
|
||||
else
|
||||
self.sched_time = sched_time
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
@ -149,8 +126,8 @@ local function create_entity(pos, node_name, textures, param2, double, sound_pre
|
|||
return luaentity
|
||||
end
|
||||
|
||||
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix)
|
||||
local dir = minetest.facedir_to_dir(param2)
|
||||
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir)
|
||||
local dir = dir or minetest.facedir_to_dir(param2)
|
||||
local entity_pos = get_entity_pos(pos, dir, double)
|
||||
return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir, entity_pos)
|
||||
end
|
||||
|
@ -175,11 +152,22 @@ Value:
|
|||
If player is using a chest: { pos = <chest node position> }
|
||||
Otherwise: nil ]]
|
||||
local open_chests = {}
|
||||
|
||||
local function back_is_blocked(pos, dir)
|
||||
pos = vector.add(pos, dir)
|
||||
local def = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
pos.y = pos.y + 1
|
||||
local def2 = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
return not def or def.groups.opaque == 1 or not def2 or def2.groups.opaque == 1
|
||||
end
|
||||
-- To be called if a player opened a chest
|
||||
local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh)
|
||||
local name = player:get_player_name()
|
||||
open_chests[name] = {pos = pos, node_name = node_name, textures = textures, param2 = param2, double = double, sound = sound, mesh = mesh}
|
||||
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh):open(name)
|
||||
if animate_chests then
|
||||
local dir = minetest.facedir_to_dir(param2)
|
||||
find_or_create_entity(pos, node_name, textures, param2, double, sound, mesh, dir):open(name, back_is_blocked(pos, dir) or double and back_is_blocked(mcl_util.get_double_container_neighbor_pos(pos, param2, node_name:sub(-4)), dir))
|
||||
end
|
||||
end
|
||||
|
||||
-- Simple protection checking functions
|
||||
|
@ -238,7 +226,9 @@ local player_chest_close = function(player)
|
|||
if open_chest == nil then
|
||||
return
|
||||
end
|
||||
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh):close(name)
|
||||
if animate_chests then
|
||||
find_or_create_entity(open_chest.pos, open_chest.node_name, open_chest.textures, open_chest.param2, open_chest.double, open_chest.sound, open_chest.mesh):close(name)
|
||||
end
|
||||
chest_update_after_close(open_chest.pos)
|
||||
|
||||
open_chests[name] = nil
|
||||
|
|
|
@ -147,6 +147,17 @@ minetest.register_craftitem("mcl_core:apple", {
|
|||
local gapple_hunger_restore = minetest.item_eat(4)
|
||||
|
||||
local function eat_gapple(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type == "node" then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
elseif pointed_thing.type == "object" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local regen_duration, absorbtion_factor = 5, 1
|
||||
if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then
|
||||
regen_duration, absorbtion_factor = 20, 4
|
||||
|
|
|
@ -219,6 +219,16 @@ end
|
|||
|
||||
minetest.register_node("mcl_enchanting:table", {
|
||||
description = S("Enchanting Table"),
|
||||
_tt_help = S("Spend experience, and lapis to enchant various items."),
|
||||
_doc_items_longdesc = S("Enchanting Tables will let you enchant armors, tools, weapons, and books with various abilities. But, at the cost of some experience, and lapis lazuli."),
|
||||
_doc_items_usagehelp =
|
||||
S("Rightclick the Enchanting Table to open the enchanting menu.").."\n"..
|
||||
S("Place a tool, armor, weapon or book into the top left slot, and then place 1-3 Lapis Lazuli in the slot to the right.").."\n".."\n"..
|
||||
S("After placing your items in the slots, the enchanting options will be shown. Hover over the options to read what is available to you.").."\n"..
|
||||
S("These options are randomized, and dependent on experience level; but the enchantment strength can be increased.").."\n".."\n"..
|
||||
S("To increase the enchantment strength, place bookshelves around the enchanting table. However, you will need to keep 1 air node between the table, & the bookshelves to empower the enchanting table.").."\n".."\n"..
|
||||
S("After finally selecting your enchantment; left-click on the selection, and you will see both the lapis lazuli and your experience levels consumed. And, an enchanted item left in its place."),
|
||||
_doc_items_hidden = false,
|
||||
drawtype = "nodebox",
|
||||
tiles = {"mcl_enchanting_table_top.png", "mcl_enchanting_table_bottom.png", "mcl_enchanting_table_side.png", "mcl_enchanting_table_side.png", "mcl_enchanting_table_side.png", "mcl_enchanting_table_side.png"},
|
||||
node_box = {
|
||||
|
|
|
@ -448,3 +448,34 @@ minetest.register_node("mcl_flowers:waterlily", {
|
|||
|
||||
-- Legacy support
|
||||
minetest.register_alias("mcl_core:tallgrass", "mcl_flowers:tallgrass")
|
||||
|
||||
-- mcimport support: re-adds missing double_plant tops in mcimported worlds.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
local mod_mcimport = minetest.get_modpath("mcimport") ~= nil
|
||||
local fix_doubleplants = minetest.settings:get_bool("fix_doubleplants", true)
|
||||
|
||||
|
||||
if mod_mcimport and mg_name == "singlenode" and fix_doubleplants == true then
|
||||
local flowernames = { "peony", "rose_bush", "lilac", "sunflower", "double_fern", "double_grass" }
|
||||
for c=1, 6 do
|
||||
local flowername = flowernames[c]
|
||||
end
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Add double plant tops.",
|
||||
name = "mcl_flowers:double_plant_topper",
|
||||
run_at_every_load = true,
|
||||
nodenames = { "mcl_flowers:peony", "mcl_flowers:rose_bush", "mcl_flowers:lilac", "mcl_flowers:sunflower", "mcl_flowers:double_fern", "mcl_flowers:double_grass" },
|
||||
action = function(pos, node)
|
||||
for c=1, 6 do
|
||||
local flowername = flowernames[c]
|
||||
local bottom = pos
|
||||
local top = { x = bottom.x, y = bottom.y + 1, z = bottom.z }
|
||||
if node.name == "mcl_flowers:"..flowername then
|
||||
minetest.set_node(top, {name = "mcl_flowers:"..flowername.."_top"})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ if mcl_vars.mg_dungeons == false then
|
|||
return
|
||||
end
|
||||
|
||||
if mg_name ~= "singlenode" then
|
||||
-- Get loot for dungeon chests
|
||||
local get_loot = function()
|
||||
local loottable = {
|
||||
|
@ -396,3 +397,4 @@ minetest.register_on_generated(function(minp, maxp)
|
|||
end
|
||||
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
MCL_Villages:
|
||||
============================
|
||||
A fork of Rochambeau's "Settlements" mod converted for use in MineClone2.
|
||||
|
||||
--------------
|
||||
Using the mod:
|
||||
--------------
|
||||
This mod adds settlements on world generation.
|
||||
|
||||
And, in Creative Mode; also comes with a debug tool for spawning in villages.
|
||||
|
||||
|
||||
-------------
|
||||
MCL2 Credits:
|
||||
-------------
|
||||
Code forked from: https://github.com/MysticTempest/settlements/tree/mcl_villages
|
||||
Commit: e24b4be
|
||||
================================================================================
|
||||
Basic conversion of Settlements mod for compatibility with MineClone2, plus new schematics: MysticTempest
|
||||
|
||||
Seed-based Village Generation, multi-threading, bugfixes: kay27
|
||||
|
||||
|
||||
|
||||
=========================
|
||||
version: 0.1 alpha
|
||||
|
||||
License of source code: WTFPL
|
||||
-----------------------------
|
||||
(c) Copyright Rochambeau (2018)
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
|
||||
Credits:
|
||||
--------------
|
||||
This mod is based on "ruins" by BlockMen
|
||||
|
||||
Completely new schematics for MineClone2:
|
||||
MysticTempest - CC-BY-SA 4.0
|
||||
|
|
@ -0,0 +1,357 @@
|
|||
--[[
|
||||
-------------------------------------------------------------------------------
|
||||
-- build schematic, replace material, rotation
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.build_schematic(vm, data, va, pos, building, replace_wall, name)
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = minetest.get_node_or_nil(pos)
|
||||
if not platform_material then
|
||||
return
|
||||
end
|
||||
platform_material = platform_material.name
|
||||
-- pick random material
|
||||
local material = wallmaterial[math.random(1,#wallmaterial)]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return(schematic)"
|
||||
-- replace material
|
||||
if replace_wall == "y" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass",
|
||||
platform_material)
|
||||
|
||||
-- Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
-- schem_lua = schem_lua:gsub("mcl_core:junglewood",
|
||||
-- "settlements:junglewood")
|
||||
--
|
||||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
local width = schematic["size"]["x"]
|
||||
local depth = schematic["size"]["z"]
|
||||
local height = schematic["size"]["y"]
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
local rotation = possible_rotations[ math.random( #possible_rotations ) ]
|
||||
settlements.foundation(
|
||||
pos,
|
||||
width,
|
||||
depth,
|
||||
height,
|
||||
rotation)
|
||||
vm:set_data(data)
|
||||
-- place schematic
|
||||
|
||||
minetest.place_schematic_on_vmanip(
|
||||
vm,
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
vm:write_to_map(true)
|
||||
end]]
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize settlement_info
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_settlement_info(pr)
|
||||
local count_buildings = {}
|
||||
|
||||
-- count_buildings table reset
|
||||
for k,v in pairs(schematic_table) do
|
||||
-- local name = schematic_table[v]["name"]
|
||||
count_buildings[v["name"]] = 0
|
||||
end
|
||||
|
||||
-- randomize number of buildings
|
||||
local number_of_buildings = pr:next(10, 25)
|
||||
local number_built = 1
|
||||
settlements.debug("Village ".. number_of_buildings)
|
||||
|
||||
return count_buildings, number_of_buildings, number_built
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill settlement_info with LVM
|
||||
--------------------------------------------------------------------------------
|
||||
function settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface, surface_material = settlements.find_surface_lvm(center, minp)
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- initialize all settlement_info table
|
||||
local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr)
|
||||
-- first building is townhall in the center
|
||||
building_all_info = schematic_table[1]
|
||||
local rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
-- add to settlement info table
|
||||
local index = 1
|
||||
settlement_info[index] = {
|
||||
pos = center_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
-- increase index for following buildings
|
||||
index = index + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
local x, z, r = center_surface.x, center_surface.z, building_all_info["hsize"]
|
||||
-- draw j circles around center and increase radius by math.random(2,5)
|
||||
for j = 1,20 do
|
||||
if number_built < number_of_buildings then
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math.pi / 180
|
||||
local ptx, ptz = x + r * math.cos( angle ), z + r * math.sin( angle )
|
||||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local pos_surface, surface_material = settlements.find_surface_lvm(pos1, minp)
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(schematic_table, pr)
|
||||
-- pick schematic
|
||||
local size = #randomized_schematic_table
|
||||
for i = size, 1, -1 do
|
||||
-- already enough buildings of that type?
|
||||
if count_buildings[randomized_schematic_table[i]["name"]] < randomized_schematic_table[i]["max_num"]*number_of_buildings then
|
||||
building_all_info = randomized_schematic_table[i]
|
||||
-- check distance to other buildings
|
||||
local distance_to_other_buildings_ok = settlements.check_distance(settlement_info, pos_surface, building_all_info["hsize"])
|
||||
if distance_to_other_buildings_ok then
|
||||
-- count built houses
|
||||
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
||||
|
||||
rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
number_built = number_built + 1
|
||||
settlement_info[index] = {
|
||||
pos = pos_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
index = index + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if number_of_buildings == number_built then
|
||||
break
|
||||
end
|
||||
end
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill settlement_info
|
||||
--------------------------------------------------------------------------------
|
||||
function settlements.create_site_plan(maxp, minp, pr)
|
||||
local settlement_info = {}
|
||||
local building_all_info
|
||||
local possible_rotations = {"0", "90", "180", "270"}
|
||||
-- find center of chunk
|
||||
local center = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
-- find center_surface of chunk
|
||||
local center_surface , surface_material = settlements.find_surface(center)
|
||||
-- go build settlement around center
|
||||
if not center_surface then return false end
|
||||
|
||||
-- add settlement to list
|
||||
table.insert(settlements_in_world, center_surface)
|
||||
-- save list to file
|
||||
settlements.save()
|
||||
-- initialize all settlement_info table
|
||||
local count_buildings, number_of_buildings, number_built = settlements.initialize_settlement_info(pr)
|
||||
-- first building is townhall in the center
|
||||
building_all_info = schematic_table[1]
|
||||
local rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
-- add to settlement info table
|
||||
local index = 1
|
||||
settlement_info[index] = {
|
||||
pos = center_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
--increase index for following buildings
|
||||
index = index + 1
|
||||
-- now some buildings around in a circle, radius = size of town center
|
||||
local x, z, r = center_surface.x, center_surface.z, building_all_info["hsize"]
|
||||
-- draw j circles around center and increase radius by math.random(2,5)
|
||||
for j = 1,20 do
|
||||
if number_built < number_of_buildings then
|
||||
-- set position on imaginary circle
|
||||
for j = 0, 360, 15 do
|
||||
local angle = j * math.pi / 180
|
||||
local ptx, ptz = x + r * math.cos( angle ), z + r * math.sin( angle )
|
||||
ptx = settlements.round(ptx, 0)
|
||||
ptz = settlements.round(ptz, 0)
|
||||
local pos1 = { x=ptx, y=center_surface.y+50, z=ptz}
|
||||
local pos_surface, surface_material = settlements.find_surface(pos1)
|
||||
if not pos_surface then break end
|
||||
|
||||
local randomized_schematic_table = shuffle(schematic_table, pr)
|
||||
-- pick schematic
|
||||
local size = #randomized_schematic_table
|
||||
for i = size, 1, -1 do
|
||||
-- already enough buildings of that type?
|
||||
if count_buildings[randomized_schematic_table[i]["name"]] < randomized_schematic_table[i]["max_num"]*number_of_buildings then
|
||||
building_all_info = randomized_schematic_table[i]
|
||||
-- check distance to other buildings
|
||||
local distance_to_other_buildings_ok = settlements.check_distance(settlement_info, pos_surface, building_all_info["hsize"])
|
||||
if distance_to_other_buildings_ok then
|
||||
-- count built houses
|
||||
count_buildings[building_all_info["name"]] = count_buildings[building_all_info["name"]] +1
|
||||
rotation = possible_rotations[ pr:next(1, #possible_rotations ) ]
|
||||
number_built = number_built + 1
|
||||
settlement_info[index] = {
|
||||
pos = pos_surface,
|
||||
name = building_all_info["name"],
|
||||
hsize = building_all_info["hsize"],
|
||||
rotat = rotation,
|
||||
surface_mat = surface_material
|
||||
}
|
||||
index = index + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if number_of_buildings == number_built then
|
||||
break
|
||||
end
|
||||
end
|
||||
r = r + pr:next(2,5)
|
||||
end
|
||||
end
|
||||
settlements.debug("really ".. number_built)
|
||||
return settlement_info
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.place_schematics_lvm(settlement_info, pr)
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local pos = settlement_info[i]["pos"]
|
||||
local rotation = settlement_info[i]["rotat"]
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = settlement_info[i]["surface_mat"]
|
||||
platform_material_name = minetest.get_name_from_content_id(platform_material)
|
||||
-- pick random material
|
||||
local material = wallmaterial[pr:next(1,#wallmaterial)]
|
||||
--
|
||||
local building = building_all_info["mts"]
|
||||
local replace_wall = building_all_info["rplc"]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return(schematic)"
|
||||
-- replace material
|
||||
if replace_wall == "y" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material_name)
|
||||
|
||||
--[[ Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
schem_lua = schem_lua:gsub("mcl_core:junglewood", "settlements:junglewood")
|
||||
--]]
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
|
||||
minetest.place_schematic_on_vmanip(
|
||||
vm,
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate settlement_info and place schematics
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.place_schematics(settlement_info, pr)
|
||||
local building_all_info
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local pos = settlement_info[i]["pos"]
|
||||
local rotation = settlement_info[i]["rotat"]
|
||||
-- get building node material for better integration to surrounding
|
||||
local platform_material = settlement_info[i]["surface_mat"]
|
||||
--platform_material_name = minetest.get_name_from_content_id(platform_material)
|
||||
-- pick random material
|
||||
local material = wallmaterial[pr:next(1,#wallmaterial)]
|
||||
--
|
||||
local building = building_all_info["mts"]
|
||||
local replace_wall = building_all_info["rplc"]
|
||||
-- schematic conversion to lua
|
||||
local schem_lua = minetest.serialize_schematic(building,
|
||||
"lua",
|
||||
{lua_use_comments = false, lua_num_indent_spaces = 0}).." return(schematic)"
|
||||
-- replace material
|
||||
if replace_wall == "y" then
|
||||
schem_lua = schem_lua:gsub("mcl_core:cobble", material)
|
||||
end
|
||||
schem_lua = schem_lua:gsub("mcl_core:dirt_with_grass", platform_material)
|
||||
|
||||
--[[ Disable special junglewood for now.
|
||||
-- special material for spawning npcs
|
||||
schem_lua = schem_lua:gsub("mcl_core:junglewood", "settlements:junglewood")
|
||||
--]]
|
||||
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_wood_outer", "mcl_stairs:slab_wood")
|
||||
schem_lua = schem_lua:gsub("mcl_stairs:stair_stone_rough_outer", "air")
|
||||
|
||||
-- format schematic string
|
||||
local schematic = loadstring(schem_lua)()
|
||||
-- build foundation for the building an make room above
|
||||
-- place schematic
|
||||
minetest.place_schematic(
|
||||
pos,
|
||||
schematic,
|
||||
rotation,
|
||||
nil,
|
||||
true)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,83 @@
|
|||
-- switch for debugging
|
||||
settlements.debug = function(message)
|
||||
-- minetest.chat_send_all(message)
|
||||
-- minetest.log("warning", "[mcl_villages] "..message)
|
||||
minetest.log("verbose", "[mcl_villages] "..message)
|
||||
end
|
||||
|
||||
-- switch for lvm
|
||||
settlements.lvm = false
|
||||
|
||||
settlements.last_settlement = os.time()
|
||||
|
||||
-- material to replace cobblestone with
|
||||
wallmaterial = {
|
||||
"mcl_core:junglewood",
|
||||
"mcl_core:sprucewood",
|
||||
"mcl_core:wood",
|
||||
"mcl_core:birchwood",
|
||||
"mcl_core:acaciawood",
|
||||
"mcl_core:stonebrick",
|
||||
"mcl_core:cobble",
|
||||
"mcl_core:sandstonecarved",
|
||||
"mcl_core:sandstone",
|
||||
"mcl_core:sandstonesmooth2"
|
||||
}
|
||||
settlements.surface_mat = {}
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.grundstellungen()
|
||||
settlements.surface_mat = settlements.Set {
|
||||
"mcl_core:dirt_with_grass",
|
||||
--"mcl_core:dry_dirt_with_grass",
|
||||
"mcl_core:dirt_with_grass_snow",
|
||||
--"mcl_core:dirt_with_dry_grass",
|
||||
"mcl_core:podzol",
|
||||
"mcl_core:sand",
|
||||
"mcl_core:redsand",
|
||||
--"mcl_core:silver_sand",
|
||||
"mcl_core:snowblock"
|
||||
}
|
||||
end
|
||||
--
|
||||
-- possible surfaces where buildings can be built
|
||||
--
|
||||
|
||||
--
|
||||
-- path to schematics
|
||||
--
|
||||
schem_path = settlements.modpath.."/schematics/"
|
||||
--
|
||||
-- list of schematics
|
||||
--
|
||||
schematic_table = {
|
||||
{name = "large_house", mts = schem_path.."large_house.mts", hwidth = 11, hdepth = 12, hheight = 9, hsize = 14, max_num = 0.08, rplc = "n"},
|
||||
{name = "blacksmith", mts = schem_path.."blacksmith.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.050, rplc = "n"},
|
||||
{name = "church", mts = schem_path.."church.mts", hwidth = 13, hdepth = 13, hheight = 14, hsize = 15, max_num = 0.04, rplc = "n"},
|
||||
{name = "farm", mts = schem_path.."farm.mts", hwidth = 7, hdepth = 7, hheight = 13, hsize = 13, max_num = 0.1, rplc = "n"},
|
||||
{name = "lamp", mts = schem_path.."lamp.mts", hwidth = 3, hdepth = 3, hheight = 13, hsize = 10, max_num = 0.1, rplc = "n"},
|
||||
{name = "library", mts = schem_path.."library.mts", hwidth = 12, hdepth = 12, hheight = 8, hsize = 13, max_num = 0.04, rplc = "n"},
|
||||
{name = "medium_house", mts = schem_path.."medium_house.mts", hwidth = 8, hdepth = 12, hheight = 8, hsize = 14, max_num = 0.09, rplc = "n"},
|
||||
{name = "small_house", mts = schem_path.."small_house.mts", hwidth = 9, hdepth = 7, hheight = 8, hsize = 13, max_num = 0.7, rplc = "n"},
|
||||
{name = "tavern", mts = schem_path.."tavern.mts", hwidth = 11, hdepth = 10, hheight = 10, hsize = 13, max_num = 0.050, rplc = "n"},
|
||||
{name = "well", mts = schem_path.."well.mts", hwidth = 6, hdepth = 8, hheight = 6, hsize = 10, max_num = 0.045, rplc = "n"},
|
||||
}
|
||||
--
|
||||
-- list of settlements, load on server start up
|
||||
--
|
||||
settlements_in_world = {}
|
||||
--
|
||||
-- min_distance between settlements
|
||||
--
|
||||
settlements.min_dist_settlements = 64
|
||||
--
|
||||
-- maximum allowed difference in height for building a sttlement
|
||||
--
|
||||
max_height_difference = 56
|
||||
--
|
||||
--
|
||||
--
|
||||
half_map_chunk_size = 40
|
||||
quarter_map_chunk_size = 20
|
|
@ -0,0 +1,30 @@
|
|||
--
|
||||
function settlements.convert_mts_to_lua()
|
||||
local building = schem_path.."townhall.mts"
|
||||
local str = minetest.serialize_schematic(building, "lua", {lua_use_comments = true, lua_num_indent_spaces = 0}).." return(schematic)"
|
||||
local schematic = loadstring(str)()
|
||||
local file = io.open(schem_path.."church"..".lua", "w")
|
||||
file:write(dump(schematic))
|
||||
file:close()
|
||||
print(dump(schematic))
|
||||
end
|
||||
|
||||
|
||||
|
||||
function settlements.mts_save()
|
||||
local f = assert(io.open(schem_path.."hut.lua", "r"))
|
||||
local content = f:read("*all").." return(schematic2)"
|
||||
f:close()
|
||||
|
||||
local schematic2 = loadstring("schematic2 = "..content)()
|
||||
local seb = minetest.serialize_schematic(schematic2, "mts", {})
|
||||
local filename = schem_path .. "hut2" .. ".mts"
|
||||
filename = filename:gsub("\"", "\\\""):gsub("\\", "\\\\")
|
||||
local file, err = io.open(filename, "wb")
|
||||
if err == nil and seb then
|
||||
file:write(seb)
|
||||
file:flush()
|
||||
file:close()
|
||||
end
|
||||
print("Wrote: " .. filename)
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
mcl_core
|
||||
mcl_farming?
|
||||
mobs_mc?
|
|
@ -0,0 +1,153 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground_lvm(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local c_dirt = minetest.get_content_id("mcl_core:dirt")
|
||||
local c_stone = minetest.get_content_id("mcl_core:stone")
|
||||
--
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = c_dirt
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then mat = c_stone end
|
||||
--minetest.swap_node(p2, {name="mcl_core:"..mat})
|
||||
local vi = va:index(p2.x, p2.y, p2.z)
|
||||
data[vi] = mat
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
-- return data
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to fill empty space below baseplate when building on a hill
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.ground(pos, pr) -- role model: Wendelsteinkircherl, Brannenburg
|
||||
local p2 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local mat = "mcl_core:dirt"
|
||||
p2.y = p2.y-1
|
||||
while true do
|
||||
cnt = cnt+1
|
||||
if cnt > 20 then break end
|
||||
if cnt>pr:next(2,4) then
|
||||
mat = "mcl_core:stone"
|
||||
end
|
||||
minetest.swap_node(p2, {name=mat})
|
||||
p2.y = p2.y-1
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform_lvm(settlement_info, pr)
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local fheight
|
||||
local fwidth
|
||||
local fdepth
|
||||
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"]
|
||||
then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180"
|
||||
then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight do
|
||||
for xi = 0,fwidth-1 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground_lvm(p, pr)
|
||||
else
|
||||
--break --todo
|
||||
-- write ground
|
||||
local vi = va:index(pos.x+xi, pos.y+yi, pos.z+zi)
|
||||
if data[vi] ~= c_air
|
||||
--local node = minetest.get_node_or_nil({x=p5.x+xi, y=p5.y+yi, z=p5.z+zi})
|
||||
--if node then
|
||||
--if node.name ~= "air"
|
||||
then
|
||||
--minetest.swap_node({x=pos.x+xi, y=pos.y+yi, z=pos.z+zi},{name="air"})
|
||||
data[vi] = c_air
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function clear space above baseplate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.terraform(settlement_info, pr)
|
||||
local fheight
|
||||
local fwidth
|
||||
local fdepth
|
||||
local schematic_data
|
||||
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
-- pick right schematic_info to current built_house
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"]
|
||||
then
|
||||
schematic_data = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
local pos = settlement_info[i]["pos"]
|
||||
if settlement_info[i]["rotat"] == "0" or settlement_info[i]["rotat"] == "180"
|
||||
then
|
||||
fwidth = schematic_data["hwidth"]
|
||||
fdepth = schematic_data["hdepth"]
|
||||
else
|
||||
fwidth = schematic_data["hdepth"]
|
||||
fdepth = schematic_data["hwidth"]
|
||||
end
|
||||
--fheight = schematic_data["hheight"] * 3 -- remove trees and leaves above
|
||||
fheight = schematic_data["hheight"] -- remove trees and leaves above
|
||||
--
|
||||
-- now that every info is available -> create platform and clear space above
|
||||
--
|
||||
for xi = 0,fwidth-1 do
|
||||
for zi = 0,fdepth-1 do
|
||||
for yi = 0,fheight *3 do
|
||||
if yi == 0 then
|
||||
local p = {x=pos.x+xi, y=pos.y, z=pos.z+zi}
|
||||
settlements.ground(p, pr)
|
||||
else
|
||||
-- write ground
|
||||
local p = {x=pos.x+xi, y=pos.y+yi, z=pos.z+zi}
|
||||
minetest.forceload_block(p)
|
||||
local node = minetest.get_node_or_nil(p)
|
||||
if node then
|
||||
if node.name ~= "air"
|
||||
then
|
||||
minetest.swap_node(p,{name="air"})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,235 @@
|
|||
-- eclipse debugging lines
|
||||
--require("debugger")(idehost, ideport, idekey)
|
||||
|
||||
--zerobrane debugging lines
|
||||
--package.cpath = package.cpath .. ";/usr/share/lua/5.2/?.so"
|
||||
--package.path = package.path .. ";/usr/share/zbstudio/lualibs/mobdebug/?.lua"
|
||||
--require('mobdebug').start()
|
||||
|
||||
settlements = {}
|
||||
settlements.modpath = minetest.get_modpath("mcl_villages");
|
||||
|
||||
dofile(settlements.modpath.."/const.lua")
|
||||
dofile(settlements.modpath.."/utils.lua")
|
||||
dofile(settlements.modpath.."/foundation.lua")
|
||||
dofile(settlements.modpath.."/buildings.lua")
|
||||
dofile(settlements.modpath.."/paths.lua")
|
||||
dofile(settlements.modpath.."/convert_lua_mts.lua")
|
||||
--
|
||||
-- load settlements on server
|
||||
--
|
||||
settlements_in_world = settlements.load()
|
||||
settlements.grundstellungen()
|
||||
|
||||
--[[ Disable custom node spawning.
|
||||
--
|
||||
-- register block for npc spawn
|
||||
--
|
||||
minetest.register_node("settlements:junglewood", {
|
||||
description = "special junglewood floor",
|
||||
tiles = {"default_junglewood.png"},
|
||||
groups = {choppy=3, wood=2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
--[[ Enable for testing, but use MineClone2's own spawn code if/when merging.
|
||||
--
|
||||
-- register inhabitants
|
||||
--
|
||||
if minetest.get_modpath("mobs_mc") ~= nil then
|
||||
mobs:register_spawn("mobs_mc:villager", --name
|
||||
{"mcl_core:stonebrickcarved"}, --nodes
|
||||
15, --max_light
|
||||
0, --min_light
|
||||
20, --chance
|
||||
7, --active_object_count
|
||||
31000, --max_height
|
||||
nil) --day_toggle
|
||||
end
|
||||
--]]
|
||||
|
||||
--
|
||||
-- on map generation, try to build a settlement
|
||||
--
|
||||
local function build_a_settlement_no_delay(minp, maxp, blockseed)
|
||||
local settlement_info
|
||||
local pr = PseudoRandom(blockseed)
|
||||
--
|
||||
-- fill settlement_info with buildings and their data
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
-- get LVM of current chunk
|
||||
local vm, data, va, emin, emax = settlements.getlvm(minp, maxp)
|
||||
settlement_info = settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
else
|
||||
settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
end
|
||||
if not settlement_info then return end
|
||||
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
if settlements.lvm == true then
|
||||
settlements.terraform_lvm(settlement_info, pr)
|
||||
else
|
||||
settlements.terraform(settlement_info, pr)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
if settlements.lvm == true then
|
||||
settlements.paths_lvm(settlement_info, minp)
|
||||
else
|
||||
settlements.paths(settlement_info)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and place schematics
|
||||
if settlements.lvm == true then
|
||||
vm:set_data(data)
|
||||
settlements.place_schematics_lvm(settlement_info, pr)
|
||||
vm:write_to_map(true)
|
||||
else
|
||||
settlements.place_schematics(settlement_info, pr)
|
||||
end
|
||||
|
||||
-- evaluate settlement_info and initialize furnaces and chests
|
||||
settlements.initialize_nodes(settlement_info, pr)
|
||||
end
|
||||
|
||||
local function ecb_build_a_settlement(blockpos, action, calls_remaining, param)
|
||||
if calls_remaining <= 0 then
|
||||
build_a_settlement_no_delay(param.minp, param.maxp, param.blockseed)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp, blockseed)
|
||||
-- needed for manual and automated settlement building
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
|
||||
-- randomly try to build settlements
|
||||
if blockseed % 77 ~= 17 then return end
|
||||
|
||||
-- don't build settlement underground
|
||||
if maxp.y < 0 then return end
|
||||
|
||||
-- don't build settlements too close to each other
|
||||
local center_of_chunk = {
|
||||
x=maxp.x-half_map_chunk_size,
|
||||
y=maxp.y-half_map_chunk_size,
|
||||
z=maxp.z-half_map_chunk_size
|
||||
}
|
||||
local dist_ok = settlements.check_distance_other_settlements(center_of_chunk)
|
||||
if dist_ok == false then return end
|
||||
|
||||
-- don't build settlements on (too) uneven terrain
|
||||
local height_difference = settlements.evaluate_heightmap(minp, maxp)
|
||||
if height_difference > max_height_difference then return end
|
||||
|
||||
minetest.emerge_area(vector.subtract(minp,24), vector.add(maxp,24), ecb_build_a_settlement, {minp = vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed})
|
||||
-- old way - wait 3 seconds:
|
||||
-- minetest.after(3, ecb_build_a_settlement, nil, 1, 0, {minp = vector.new(minp), maxp=vector.new(maxp), blockseed=blockseed})
|
||||
end)
|
||||
|
||||
--
|
||||
-- manually place buildings, for debugging only
|
||||
--
|
||||
minetest.register_craftitem("mcl_villages:tool", {
|
||||
description = "mcl_villages build tool",
|
||||
inventory_image = "default_tool_woodshovel.png",
|
||||
|
||||
--[[ Disable on_use for now.
|
||||
-- build single house
|
||||
--
|
||||
on_use = function(itemstack, placer, pointed_thing)
|
||||
local center_surface = pointed_thing.under
|
||||
if center_surface then
|
||||
local building_all_info = {name = "blacksmith",
|
||||
mts = schem_path.."blacksmith.mts",
|
||||
hsize = 13,
|
||||
max_num = 0.9,
|
||||
rplc = "n"}
|
||||
settlements.build_schematic(center_surface,
|
||||
building_all_info["mts"],
|
||||
building_all_info["rplc"],
|
||||
building_all_info["name"])
|
||||
|
||||
-- settlements.convert_mts_to_lua()
|
||||
-- settlements.mts_save()
|
||||
end
|
||||
end,
|
||||
--]]
|
||||
--
|
||||
-- build ssettlement
|
||||
--
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local pr = PseudoRandom(math.rand(0,32767))
|
||||
-- enable debug routines
|
||||
local center_surface = pointed_thing.under
|
||||
if center_surface then
|
||||
local minp = {
|
||||
x=center_surface.x-half_map_chunk_size,
|
||||
y=center_surface.y-half_map_chunk_size,
|
||||
z=center_surface.z-half_map_chunk_size
|
||||
}
|
||||
local maxp = {
|
||||
x=center_surface.x+half_map_chunk_size,
|
||||
y=center_surface.y+half_map_chunk_size,
|
||||
z=center_surface.z+half_map_chunk_size
|
||||
}
|
||||
--
|
||||
-- get LVM of current chunk
|
||||
--
|
||||
local vm, data, va, emin, emax = settlements.getlvm(minp, maxp)
|
||||
--
|
||||
-- fill settlement_info with buildings and their data
|
||||
--
|
||||
local start_time = os.time()
|
||||
local settlement_info
|
||||
if settlements.lvm == true then
|
||||
settlement_info = settlements.create_site_plan_lvm(maxp, minp, pr)
|
||||
else
|
||||
settlement_info = settlements.create_site_plan(maxp, minp, pr)
|
||||
end
|
||||
if not settlement_info then return end
|
||||
--
|
||||
-- evaluate settlement_info and prepair terrain
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
settlements.terraform_lvm(settlement_info, pr)
|
||||
else
|
||||
settlements.terraform(settlement_info, pr)
|
||||
end
|
||||
|
||||
--
|
||||
-- evaluate settlement_info and build paths between buildings
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
settlements.paths_lvm(settlement_info, minp)
|
||||
else
|
||||
settlements.paths(settlement_info)
|
||||
end
|
||||
--
|
||||
-- evaluate settlement_info and place schematics
|
||||
--
|
||||
if settlements.lvm == true then
|
||||
vm:set_data(data)
|
||||
settlements.place_schematics_lvm(pr)
|
||||
vm:write_to_map(true)
|
||||
else
|
||||
settlements.place_schematics()
|
||||
end
|
||||
|
||||
--
|
||||
-- evaluate settlement_info and initialize furnaces and chests
|
||||
--
|
||||
settlements.initialize_nodes(settlement_info, pr)
|
||||
local end_time = os.time()
|
||||
minetest.chat_send_all("Time ".. end_time - start_time)
|
||||
--
|
||||
--settlements.convert_mts_to_lua()
|
||||
--settlements.mts_save()
|
||||
|
||||
end
|
||||
end
|
||||
})
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths_lvm(settlement_info, minp)
|
||||
local c_grasspath = minetest.get_content_id("mcl_core:grass_path")
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface_lvm(starting_point, minp)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
local vi = va:index(surface_point.x, surface_point.y, surface_point.z)
|
||||
data[vi] = c_grasspath
|
||||
|
||||
--minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--end
|
||||
--return data
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- generate paths between buildings
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.paths(settlement_info)
|
||||
local starting_point
|
||||
local end_point
|
||||
local distance
|
||||
--for k,v in pairs(settlement_info) do
|
||||
starting_point = settlement_info[1]["pos"]
|
||||
for o,p in pairs(settlement_info) do
|
||||
|
||||
end_point = settlement_info[o]["pos"]
|
||||
if starting_point ~= end_point
|
||||
then
|
||||
-- loop until end_point is reched (distance == 0)
|
||||
while true do
|
||||
|
||||
-- define surrounding pos to starting_point
|
||||
local north_p = {x=starting_point.x+1, y=starting_point.y, z=starting_point.z}
|
||||
local south_p = {x=starting_point.x-1, y=starting_point.y, z=starting_point.z}
|
||||
local west_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z+1}
|
||||
local east_p = {x=starting_point.x, y=starting_point.y, z=starting_point.z-1}
|
||||
-- measure distance to end_point
|
||||
local dist_north_p_to_end = math.sqrt(
|
||||
((north_p.x - end_point.x)*(north_p.x - end_point.x))+
|
||||
((north_p.z - end_point.z)*(north_p.z - end_point.z))
|
||||
)
|
||||
local dist_south_p_to_end = math.sqrt(
|
||||
((south_p.x - end_point.x)*(south_p.x - end_point.x))+
|
||||
((south_p.z - end_point.z)*(south_p.z - end_point.z))
|
||||
)
|
||||
local dist_west_p_to_end = math.sqrt(
|
||||
((west_p.x - end_point.x)*(west_p.x - end_point.x))+
|
||||
((west_p.z - end_point.z)*(west_p.z - end_point.z))
|
||||
)
|
||||
local dist_east_p_to_end = math.sqrt(
|
||||
((east_p.x - end_point.x)*(east_p.x - end_point.x))+
|
||||
((east_p.z - end_point.z)*(east_p.z - end_point.z))
|
||||
)
|
||||
-- evaluate which pos is closer to the end_point
|
||||
if dist_north_p_to_end <= dist_south_p_to_end and
|
||||
dist_north_p_to_end <= dist_west_p_to_end and
|
||||
dist_north_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = north_p
|
||||
distance = dist_north_p_to_end
|
||||
|
||||
elseif dist_south_p_to_end <= dist_north_p_to_end and
|
||||
dist_south_p_to_end <= dist_west_p_to_end and
|
||||
dist_south_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = south_p
|
||||
distance = dist_south_p_to_end
|
||||
|
||||
elseif dist_west_p_to_end <= dist_north_p_to_end and
|
||||
dist_west_p_to_end <= dist_south_p_to_end and
|
||||
dist_west_p_to_end <= dist_east_p_to_end
|
||||
then
|
||||
starting_point = west_p
|
||||
distance = dist_west_p_to_end
|
||||
|
||||
elseif dist_east_p_to_end <= dist_north_p_to_end and
|
||||
dist_east_p_to_end <= dist_south_p_to_end and
|
||||
dist_east_p_to_end <= dist_west_p_to_end
|
||||
then
|
||||
starting_point = east_p
|
||||
distance = dist_east_p_to_end
|
||||
end
|
||||
-- find surface of new starting point
|
||||
local surface_point, surface_mat = settlements.find_surface(starting_point)
|
||||
-- replace surface node with mcl_core:grass_path
|
||||
if surface_point
|
||||
then
|
||||
minetest.swap_node(surface_point,{name="mcl_core:grass_path"})
|
||||
-- don't set y coordinate, surface might be too low or high
|
||||
starting_point.x = surface_point.x
|
||||
starting_point.z = surface_point.z
|
||||
end
|
||||
if distance <= 1 or
|
||||
starting_point == end_point
|
||||
then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
|
@ -0,0 +1,424 @@
|
|||
local c_dirt_with_grass = minetest.get_content_id("mcl_core:dirt_with_grass")
|
||||
local c_dirt_with_snow = minetest.get_content_id("mcl_core:dirt_with_grass_snow")
|
||||
--local c_dirt_with_dry_grass = minetest.get_content_id("mcl_core:dirt_with_dry_grass")
|
||||
local c_podzol = minetest.get_content_id("mcl_core:podzol")
|
||||
local c_sand = minetest.get_content_id("mcl_core:sand")
|
||||
local c_desert_sand = minetest.get_content_id("mcl_core:redsand")
|
||||
--local c_silver_sand = minetest.get_content_id("mcl_core:silver_sand")
|
||||
--
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_snow = minetest.get_content_id("mcl_core:snowblock")
|
||||
local c_fern_1 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_fern_2 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_fern_3 = minetest.get_content_id("mcl_flowers:fern")
|
||||
local c_rose = minetest.get_content_id("mcl_flowers:poppy")
|
||||
local c_viola = minetest.get_content_id("mcl_flowers:blue_orchid")
|
||||
local c_geranium = minetest.get_content_id("mcl_flowers:allium")
|
||||
local c_tulip = minetest.get_content_id("mcl_flowers:tulip_orange")
|
||||
local c_dandelion_y = minetest.get_content_id("mcl_flowers:dandelion")
|
||||
local c_dandelion_w = minetest.get_content_id("mcl_flowers:oxeye_daisy")
|
||||
local c_bush_leaves = minetest.get_content_id("mcl_core:leaves")
|
||||
local c_bush_stem = minetest.get_content_id("mcl_core:tree")
|
||||
local c_a_bush_leaves = minetest.get_content_id("mcl_core:acacialeaves")
|
||||
local c_a_bush_stem = minetest.get_content_id("mcl_core:acaciatree")
|
||||
local c_water_source = minetest.get_content_id("mcl_core:water_source")
|
||||
local c_water_flowing = minetest.get_content_id("mcl_core:water_flowing")
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to copy tables
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.shallowCopy(original)
|
||||
local copy = {}
|
||||
for key, value in pairs(original) do
|
||||
copy[key] = value
|
||||
end
|
||||
return copy
|
||||
end
|
||||
--
|
||||
--
|
||||
--
|
||||
function settlements.round(num, numDecimalPlaces)
|
||||
local mult = 10^(numDecimalPlaces or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface_lvm(pos, minp)
|
||||
--ab hier altes verfahren
|
||||
local p6 = vector.new(pos)
|
||||
local surface_mat = {
|
||||
c_dirt_with_grass,
|
||||
c_dirt_with_snow,
|
||||
--c_dirt_with_dry_grass,
|
||||
c_podzol,
|
||||
c_sand,
|
||||
c_desert_sand
|
||||
}
|
||||
local cnt = 0
|
||||
local itter -- count up or down
|
||||
local cnt_max = 200
|
||||
-- starting point for looking for surface
|
||||
local vi = va:index(p6.x, p6.y, p6.z)
|
||||
if data[vi] == nil then return nil end
|
||||
local tmp = minetest.get_name_from_content_id(data[vi])
|
||||
if data[vi] == c_air then
|
||||
itter = -1
|
||||
else
|
||||
itter = 1
|
||||
end
|
||||
while cnt < cnt_max do
|
||||
cnt = cnt+1
|
||||
local vi = va:index(p6.x, p6.y, p6.z)
|
||||
-- local tmp = minetest.get_name_from_content_id(data[vi])
|
||||
-- if vi == nil
|
||||
-- then
|
||||
-- return nil
|
||||
-- end
|
||||
for i, mats in ipairs(surface_mat) do
|
||||
local node_check = va:index(p6.x, p6.y+1, p6.z)
|
||||
if node_check and vi and data[vi] == mats and
|
||||
(data[node_check] ~= c_water_source and
|
||||
data[node_check] ~= c_water_flowing
|
||||
)
|
||||
then
|
||||
local tmp = minetest.get_name_from_content_id(data[node_check])
|
||||
return p6, mats
|
||||
end
|
||||
end
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then return nil end
|
||||
end
|
||||
return nil --]]
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- function to find surface block y coordinate
|
||||
-- returns surface postion
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.find_surface(pos)
|
||||
local p6 = vector.new(pos)
|
||||
local cnt = 0
|
||||
local itter -- count up or down
|
||||
local cnt_max = 200
|
||||
-- check, in which direction to look for surface
|
||||
local surface_node = minetest.get_node_or_nil(p6)
|
||||
if surface_node and string.find(surface_node.name,"air") then
|
||||
itter = -1
|
||||
else
|
||||
itter = 1
|
||||
end
|
||||
-- go through nodes an find surface
|
||||
while cnt < cnt_max do
|
||||
cnt = cnt+1
|
||||
minetest.forceload_block(p6)
|
||||
surface_node = minetest.get_node_or_nil(p6)
|
||||
|
||||
if not surface_node then
|
||||
-- Load the map at pos and try again
|
||||
minetest.get_voxel_manip():read_from_map(p6, p6)
|
||||
surface_node = minetest.get_node(p6)
|
||||
if surface_node.name == "ignore" then
|
||||
settlements.debug("find_surface1: nil or ignore")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- if surface_node == nil or surface_node.name == "ignore" then
|
||||
-- --return nil
|
||||
-- local fl = minetest.forceload_block(p6)
|
||||
-- if not fl then
|
||||
--
|
||||
-- return nil
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- Check Surface_node and Node above
|
||||
--
|
||||
if settlements.surface_mat[surface_node.name] then
|
||||
local surface_node_plus_1 = minetest.get_node_or_nil({ x=p6.x, y=p6.y+1, z=p6.z})
|
||||
if surface_node_plus_1 and surface_node and
|
||||
(string.find(surface_node_plus_1.name,"air") or
|
||||
string.find(surface_node_plus_1.name,"snow") or
|
||||
string.find(surface_node_plus_1.name,"fern") or
|
||||
string.find(surface_node_plus_1.name,"flower") or
|
||||
string.find(surface_node_plus_1.name,"bush") or
|
||||
string.find(surface_node_plus_1.name,"tree") or
|
||||
string.find(surface_node_plus_1.name,"grass"))
|
||||
then
|
||||
settlements.debug("find_surface7: " ..surface_node.name.. " " .. surface_node_plus_1.name)
|
||||
return p6, surface_node.name
|
||||
else
|
||||
settlements.debug("find_surface2: wrong surface+1")
|
||||
end
|
||||
else
|
||||
settlements.debug("find_surface3: wrong surface "..surface_node.name.." at pos "..minetest.pos_to_string(p6))
|
||||
end
|
||||
|
||||
p6.y = p6.y + itter
|
||||
if p6.y < 0 then
|
||||
settlements.debug("find_surface4: y<0")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
settlements.debug("find_surface5: cnt_max overflow")
|
||||
return nil
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance for new building
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance(settlement_info, building_pos, building_size)
|
||||
local distance
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
distance = math.sqrt(
|
||||
((building_pos.x - built_house["pos"].x)*(building_pos.x - built_house["pos"].x))+
|
||||
((building_pos.z - built_house["pos"].z)*(building_pos.z - built_house["pos"].z)))
|
||||
if distance < building_size or
|
||||
distance < built_house["hsize"]
|
||||
then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- save list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.save()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "w")
|
||||
if file then
|
||||
file:write(minetest.serialize(settlements_in_world))
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- load list of generated settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.load()
|
||||
local file = io.open(minetest.get_worldpath().."/settlements.txt", "r")
|
||||
if file then
|
||||
local table = minetest.deserialize(file:read("*all"))
|
||||
if type(table) == "table" then
|
||||
return table
|
||||
end
|
||||
end
|
||||
return {}
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- check distance to other settlements
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.check_distance_other_settlements(center_new_chunk)
|
||||
-- local min_dist_settlements = 300
|
||||
for i, pos in ipairs(settlements_in_world) do
|
||||
local distance = vector.distance(center_new_chunk, pos)
|
||||
-- minetest.chat_send_all("dist ".. distance)
|
||||
if distance < settlements.min_dist_settlements then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- fill chests
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.fill_chest(pos, pr)
|
||||
-- find chests within radius
|
||||
--local chestpos = minetest.find_node_near(pos, 6, {"mcl_core:chest"})
|
||||
local chestpos = pos
|
||||
-- initialize chest (mts chests don't have meta)
|
||||
local meta = minetest.get_meta(chestpos)
|
||||
if meta:get_string("infotext") ~= "Chest" then
|
||||
-- For MineClone2 0.70 or before
|
||||
-- minetest.registered_nodes["mcl_chests:chest"].on_construct(chestpos)
|
||||
--
|
||||
-- For MineClone2 after commit 09ab1482b5 (the new entity chests)
|
||||
minetest.registered_nodes["mcl_chests:chest_small"].on_construct(chestpos)
|
||||
end
|
||||
-- fill chest
|
||||
local inv = minetest.get_inventory( {type="node", pos=chestpos} )
|
||||
-- always
|
||||
inv:add_item("main", "mcl_core:apple "..pr:next(1,3))
|
||||
-- low value items
|
||||
if pr:next(0,1) < 1 then
|
||||
inv:add_item("main", "mcl_farming:bread "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_core:iron_ingot "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:melon_item "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:carrot_item "..pr:next(0,3))
|
||||
--[[
|
||||
-- additional fillings when farmin mod enabled
|
||||
if minetest.get_modpath("farming") ~= nil and farming.mod == "redo" then
|
||||
if pr:next(0,1) < 1 then
|
||||
inv:add_item("main", "mcl_farming:melon_item "..pr:next(0,3))
|
||||
inv:add_item("main", "mcl_farming:carrot_item "..pr:next(0,3))
|
||||
inv:add_item("main", "farming:corn "..pr:next(0,3))
|
||||
end
|
||||
end
|
||||
--]]
|
||||
end
|
||||
-- medium value items
|
||||
if pr:next(0,3) < 1 then
|
||||
inv:add_item("main", "mcl_tools:pick_iron "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_tools:pick_stone "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_fire:flint_and_steel "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_buckets:bucket_empty "..pr:next(0,1))
|
||||
inv:add_item("main", "mcl_tools:sword_iron "..pr:next(0,1))
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_furnace(pos)
|
||||
-- find chests within radius
|
||||
local furnacepos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_furnaces:furnace"})
|
||||
-- initialize furnacepos (mts furnacepos don't have meta)
|
||||
if furnacepos
|
||||
then
|
||||
local meta = minetest.get_meta(furnacepos)
|
||||
if meta:get_string("infotext") ~= "furnace"
|
||||
then
|
||||
minetest.registered_nodes["mcl_furnaces:furnace"].on_construct(furnacepos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize anvil
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.initialize_anvil(pos)
|
||||
-- find chests within radius
|
||||
local anvilpos = minetest.find_node_near(pos,
|
||||
7, --radius
|
||||
{"mcl_anvils:anvil"})
|
||||
-- initialize anvilpos (mts anvilpos don't have meta)
|
||||
if anvilpos
|
||||
then
|
||||
local meta = minetest.get_meta(anvilpos)
|
||||
if meta:get_string("infotext") ~= "anvil"
|
||||
then
|
||||
minetest.registered_nodes["mcl_anvils:anvil"].on_construct(anvilpos)
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- initialize furnace, chests, anvil
|
||||
-------------------------------------------------------------------------------
|
||||
local building_all_info
|
||||
function settlements.initialize_nodes(settlement_info, pr)
|
||||
for i, built_house in ipairs(settlement_info) do
|
||||
for j, schem in ipairs(schematic_table) do
|
||||
if settlement_info[i]["name"] == schem["name"] then
|
||||
building_all_info = schem
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local width = building_all_info["hwidth"]
|
||||
local depth = building_all_info["hdepth"]
|
||||
local height = building_all_info["hheight"]
|
||||
|
||||
local p = settlement_info[i]["pos"]
|
||||
for yi = 1,height do
|
||||
for xi = 0,width do
|
||||
for zi = 0,depth do
|
||||
local ptemp = {x=p.x+xi, y=p.y+yi, z=p.z+zi}
|
||||
local node = minetest.get_node(ptemp)
|
||||
if node.name == "mcl_furnaces:furnace" or
|
||||
node.name == "mcl_chests:chest" or
|
||||
node.name == "mcl_anvils:anvil" then
|
||||
minetest.registered_nodes[node.name].on_construct(ptemp)
|
||||
end
|
||||
-- when chest is found -> fill with stuff
|
||||
if node.name == "mcl_chests:chest" then
|
||||
minetest.after(3, settlements.fill_chest, ptemp, pr)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- randomize table
|
||||
-------------------------------------------------------------------------------
|
||||
function shuffle(tbl, pr)
|
||||
local table = settlements.shallowCopy(tbl)
|
||||
local size = #table
|
||||
for i = size, 1, -1 do
|
||||
local rand = pr:next(1, size)
|
||||
table[i], table[rand] = table[rand], table[i]
|
||||
end
|
||||
return table
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- evaluate heightmap
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.evaluate_heightmap()
|
||||
local heightmap = minetest.get_mapgen_object("heightmap")
|
||||
-- max height and min height, initialize with impossible values for easier first time setting
|
||||
local max_y = -50000
|
||||
local min_y = 50000
|
||||
-- only evaluate the center square of heightmap 40 x 40
|
||||
local square_start = 1621
|
||||
local square_end = 1661
|
||||
for j = 1 , 40, 1 do
|
||||
for i = square_start, square_end, 1 do
|
||||
-- skip buggy heightmaps, return high value
|
||||
if heightmap[i] == -31000 or
|
||||
heightmap[i] == 31000
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
if heightmap[i] < min_y
|
||||
then
|
||||
min_y = heightmap[i]
|
||||
end
|
||||
if heightmap[i] > max_y
|
||||
then
|
||||
max_y = heightmap[i]
|
||||
end
|
||||
end
|
||||
-- set next line
|
||||
square_start = square_start + 80
|
||||
square_end = square_end + 80
|
||||
end
|
||||
-- return the difference between highest and lowest pos in chunk
|
||||
local height_diff = max_y - min_y
|
||||
-- filter buggy heightmaps
|
||||
if height_diff <= 1
|
||||
then
|
||||
return max_height_difference + 1
|
||||
end
|
||||
-- debug info
|
||||
settlements.debug("heightdiff ".. height_diff)
|
||||
return height_diff
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- get LVM of current chunk
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.getlvm(minp, maxp)
|
||||
local vm = minetest.get_voxel_manip()
|
||||
local emin, emax = vm:read_from_map(minp, maxp)
|
||||
local va = VoxelArea:new{
|
||||
MinEdge = emin,
|
||||
MaxEdge = emax
|
||||
}
|
||||
local data = vm:get_data()
|
||||
return vm, data, va, emin, emax
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- get LVM of current chunk
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.setlvm(vm, data)
|
||||
-- Write data
|
||||
vm:set_data(data)
|
||||
vm:write_to_map(true)
|
||||
end
|
||||
-------------------------------------------------------------------------------
|
||||
-- Set array to list
|
||||
-- https://stackoverflow.com/questions/656199/search-for-an-item-in-a-lua-list
|
||||
-------------------------------------------------------------------------------
|
||||
function settlements.Set (list)
|
||||
local set = {}
|
||||
for _, l in ipairs(list) do set[l] = true end
|
||||
return set
|
||||
end
|
|
@ -15,7 +15,11 @@ end
|
|||
-- Probability for every newly generated mapchunk to get corridors
|
||||
local probability_railcaves_in_mapchunk = P(0.33333)
|
||||
setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_mapchunk"))
|
||||
if setting then
|
||||
-- Extra check to prevent mod griefing in singlenode, mcimported worlds.
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if mg_name == "singlenode" then
|
||||
probability_railcaves_in_mapchunk = P(0)
|
||||
elseif setting then
|
||||
probability_railcaves_in_mapchunk = P(setting)
|
||||
end
|
||||
|
||||
|
|
|
@ -91,6 +91,9 @@ flame_sound (Flame sound) bool true
|
|||
# Form: Image height / Image width
|
||||
fire_animation_frames (Fire Animation Frames) int 8
|
||||
|
||||
# Whether to animate chests when open / close
|
||||
animated_chests (Animated chests) bool true
|
||||
|
||||
[Experimental]
|
||||
# Whether ice is translucent. If disabled, ice is fully opaque.
|
||||
#
|
||||
|
@ -126,3 +129,7 @@ mcl_superflat_classic (Classic superflat map generation) bool false
|
|||
# WARNING: This setting has quite poor performance and can slow down your
|
||||
# game by a lot.
|
||||
mcl_node_particles (Block particles detail level) enum none high,medium,low,none
|
||||
|
||||
|
||||
# If enabled, will run an LBM to fix the top 1/2 of double plants in mcimported worlds; defaults to true.
|
||||
fix_doubleplants (Mcimport double plant fixes) bool true
|
||||
|
|
Loading…
Reference in New Issue