Merge branch 'master' of https://git.minetest.land/Wuzzy/MineClone2
This commit is contained in:
commit
a3ccb54376
38 changed files with 1741 additions and 100 deletions
|
@ -85,3 +85,12 @@ Report all bugs and missing Minecraft features here:
|
||||||
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
We have an IRC channel! Join us on #mineclone2 in freenode.net.
|
||||||
|
|
||||||
<ircs://irc.freenode.net:6697/#mineclone2>
|
<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
|
## 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
|
- 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+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
|
- 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
|
## 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 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
|
- 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
|
- 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
|
#### 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
|
- 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
|
-- How many rays to compute entity exposure to explosion
|
||||||
local N_EXPOSURE_RAYS = 16
|
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()
|
minetest.register_on_mods_loaded(function()
|
||||||
-- Store blast resistance values by content ids to improve performance.
|
-- Store blast resistance values by content ids to improve performance.
|
||||||
for name, def in pairs(minetest.registered_nodes) do
|
for name, def in pairs(minetest.registered_nodes) do
|
||||||
|
@ -135,14 +139,21 @@ end
|
||||||
-- strength - The strength of each ray
|
-- strength - The strength of each ray
|
||||||
-- raydirs - The directions for each ray
|
-- raydirs - The directions for each ray
|
||||||
-- radius - The maximum distance each ray will go
|
-- radius - The maximum distance each ray will go
|
||||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
-- info - Table containing information about explosion
|
||||||
-- fire - If true, 1/3 of destroyed nodes become fire
|
|
||||||
-- puncher - object that punches other objects (optional)
|
-- 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
|
-- Note that this function has been optimized, it contains code which has been
|
||||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||||
-- measured to give a significant performance increase.
|
-- 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 vm = minetest.get_voxel_manip()
|
||||||
|
|
||||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||||
|
@ -164,7 +175,12 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
local data = vm:get_data()
|
local data = vm:get_data()
|
||||||
local destroy = {}
|
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
|
-- Trace rays for environment destruction
|
||||||
|
if info.griefing then
|
||||||
for i = 1, #raydirs do
|
for i = 1, #raydirs do
|
||||||
local rpos_x = pos.x
|
local rpos_x = pos.x
|
||||||
local rpos_y = pos.y
|
local rpos_y = pos.y
|
||||||
|
@ -183,6 +199,10 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
|
|
||||||
local cid = data[idx]
|
local cid = data[idx]
|
||||||
local br = node_blastres[cid]
|
local br = node_blastres[cid]
|
||||||
|
if br < INDESTRUCT_BLASTRES and br > max_blast_resistance then
|
||||||
|
br = max_blast_resistance
|
||||||
|
end
|
||||||
|
|
||||||
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
|
||||||
|
|
||||||
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
rpos_x = rpos_x + STEP_LENGTH * rdir_x
|
||||||
|
@ -200,6 +220,7 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Entities in radius of explosion
|
-- Entities in radius of explosion
|
||||||
local punch_radius = 2 * strength
|
local punch_radius = 2 * strength
|
||||||
|
@ -327,7 +348,7 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
|
|
||||||
-- Remove destroyed blocks and drop items
|
-- Remove destroyed blocks and drop items
|
||||||
for hash, idx in pairs(destroy) do
|
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 on_blast = node_on_blast[data[idx]]
|
||||||
local remove = true
|
local remove = true
|
||||||
|
|
||||||
|
@ -377,7 +398,6 @@ local function trace_explode(pos, strength, raydirs, radius, drop_chance, fire,
|
||||||
-- Log explosion
|
-- Log explosion
|
||||||
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
minetest.log('action', 'Explosion at ' .. minetest.pos_to_string(pos) ..
|
||||||
' with strength ' .. strength .. ' and radius ' .. radius)
|
' with strength ' .. strength .. ' and radius ' .. radius)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create an explosion with strength at pos.
|
-- Create an explosion with strength at pos.
|
||||||
|
@ -385,16 +405,24 @@ end
|
||||||
-- Parameters:
|
-- Parameters:
|
||||||
-- pos - The position where the explosion originates from
|
-- pos - The position where the explosion originates from
|
||||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
-- 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)
|
-- puncher - object that is reported as source of punches/damage (optional)
|
||||||
--
|
--
|
||||||
-- Values in info:
|
-- Values in info:
|
||||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||||
-- explosion (defaults to 1.0 / strength)
|
-- explosion (default: 1.0 / strength)
|
||||||
-- no_sound - If true then the explosion will not play a sound
|
-- max_blast_resistance - If specified the explosion will treat all
|
||||||
-- no_particle - If true then the explosion will not create particles
|
-- 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)
|
-- 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)
|
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||||
|
if info == nil then
|
||||||
|
info = {}
|
||||||
|
end
|
||||||
|
|
||||||
-- The maximum blast radius (in the air)
|
-- The maximum blast radius (in the air)
|
||||||
local radius = math.ceil(1.3 * strength / (0.3 * 0.75) * 0.3)
|
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
|
end
|
||||||
local shape = sphere_shapes[radius]
|
local shape = sphere_shapes[radius]
|
||||||
|
|
||||||
local creative_enabled = minetest.is_creative_enabled("")
|
-- Default values
|
||||||
trace_explode(pos, strength, shape, radius, (info and info.drop_chance) or 1 / strength, info.fire == true, puncher, creative_enabled)
|
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)
|
add_particles(pos, radius)
|
||||||
end
|
end
|
||||||
if not (info and info.no_sound) then
|
if info.sound then
|
||||||
minetest.sound_play("tnt_explode", {
|
minetest.sound_play("tnt_explode", {
|
||||||
pos = pos, gain = 1.0,
|
pos = pos, gain = 1.0,
|
||||||
max_hear_distance = strength * 16
|
max_hear_distance = strength * 16
|
||||||
|
|
|
@ -25,6 +25,7 @@ mcl_vars.inventory_header = ""
|
||||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
local minecraft_height_limit = 256
|
local minecraft_height_limit = 256
|
||||||
local superflat = mg_name == "flat" and minetest.get_mapgen_setting("mcl_superflat_classic") == "true"
|
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
|
-- Calculate mapgen_edge_min/mapgen_edge_max
|
||||||
mcl_vars.chunksize = math.max(1, tonumber(minetest.get_mapgen_setting("chunksize")) or 5)
|
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_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
|
||||||
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * 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
|
-- Normal mode
|
||||||
--[[ Realm stacking (h is for height)
|
--[[ Realm stacking (h is for height)
|
||||||
- Overworld (h>=256)
|
- Overworld (h>=256)
|
||||||
|
@ -66,6 +67,14 @@ if not superflat then
|
||||||
mcl_vars.mg_lava = true
|
mcl_vars.mg_lava = true
|
||||||
mcl_vars.mg_bedrock_is_rough = 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
|
else
|
||||||
-- Classic superflat
|
-- Classic superflat
|
||||||
local ground = minetest.get_mapgen_setting("mgflat_ground_level")
|
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)
|
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
|
|
||||||
|
|
|
@ -395,4 +395,13 @@ function mcl_util.generate_on_place_plant_function(condition)
|
||||||
end
|
end
|
||||||
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
|
local puncher = cmi_cause.puncher
|
||||||
if puncher then
|
if puncher then
|
||||||
wielditem = puncher:get_wielded_item()
|
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
|
||||||
end
|
end
|
||||||
local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.has_enchantment(wielditem, "fire_aspect")
|
local cooked = mcl_burning.is_burning(self.object) or mcl_enchanting.has_enchantment(wielditem, "fire_aspect")
|
||||||
local looting = mcl_enchanting.get_enchantment(wielditem, "looting")
|
local looting = mcl_enchanting.get_enchantment(wielditem, "looting")
|
||||||
item_drop(self, cooked, looting)
|
item_drop(self, cooked, looting)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- execute custom death function
|
-- execute custom death function
|
||||||
|
@ -2258,7 +2256,6 @@ local dogswitch = function(self, dtime)
|
||||||
return self.dogshoot_switch
|
return self.dogshoot_switch
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- execute current state (stand, walk, run, attacks)
|
-- execute current state (stand, walk, run, attacks)
|
||||||
-- returns true if mob has died
|
-- returns true if mob has died
|
||||||
local do_states = function(self, dtime)
|
local do_states = function(self, dtime)
|
||||||
|
@ -2550,7 +2547,7 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if mod_explosions then
|
if mod_explosions then
|
||||||
if mobs_griefing and not minetest.is_protected(pos, "") 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
|
else
|
||||||
minetest.sound_play(self.sounds.explode, {
|
minetest.sound_play(self.sounds.explode, {
|
||||||
pos = pos,
|
pos = pos,
|
||||||
|
|
|
@ -71,7 +71,7 @@ mobs:register_mob("mobs_mc:creeper", {
|
||||||
if self._forced_explosion_countdown_timer ~= nil then
|
if self._forced_explosion_countdown_timer ~= nil then
|
||||||
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
self._forced_explosion_countdown_timer = self._forced_explosion_countdown_timer - dtime
|
||||||
if self._forced_explosion_countdown_timer <= 0 then
|
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()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -962,6 +962,7 @@ mobs:register_mob("mobs_mc:villager", {
|
||||||
walk_velocity = 1.2,
|
walk_velocity = 1.2,
|
||||||
run_velocity = 2.4,
|
run_velocity = 2.4,
|
||||||
drops = {},
|
drops = {},
|
||||||
|
can_despawn = false,
|
||||||
-- TODO: sounds
|
-- TODO: sounds
|
||||||
animation = {
|
animation = {
|
||||||
stand_speed = 25,
|
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."),
|
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."),
|
_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",
|
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)
|
_on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir)
|
||||||
-- Shoot arrow
|
-- Shoot arrow
|
||||||
local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51))
|
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)
|
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||||
for _,obj in ipairs(objects) do
|
for _,obj in ipairs(objects) do
|
||||||
if obj:is_player() then
|
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
|
if obj:get_inventory():room_for_item("main", "mcl_bows:arrow") then
|
||||||
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
obj:get_inventory():add_item("main", "mcl_bows:arrow")
|
||||||
minetest.sound_play("item_drop_pickup", {
|
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
|
-- Another player table, this one stores the wield index of the bow being charged
|
||||||
local bow_index = {}
|
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")
|
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
||||||
if power == nil then
|
if power == nil then
|
||||||
power = BOW_MAX_SPEED --19
|
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._is_critical = is_critical
|
||||||
le._startpos = pos
|
le._startpos = pos
|
||||||
le._knockback = knockback
|
le._knockback = knockback
|
||||||
|
le._collectable = collectable
|
||||||
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||||
if shooter ~= nil and shooter:is_player() then
|
if shooter ~= nil and shooter:is_player() then
|
||||||
if obj:get_luaentity().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_stack, arrow_stack_id = get_arrow(player)
|
||||||
local arrow_itemstring
|
local arrow_itemstring
|
||||||
local has_infinity_enchantment = mcl_enchanting.has_enchantment(player:get_wielded_item(), "infinity")
|
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 minetest.is_creative_enabled(player:get_player_name()) then
|
||||||
if arrow_stack then
|
if arrow_stack then
|
||||||
|
@ -103,7 +105,9 @@ local player_shoot_arrow = function(itemstack, player, power, damage, is_critica
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
arrow_itemstring = arrow_stack:get_name()
|
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()
|
arrow_stack:take_item()
|
||||||
end
|
end
|
||||||
local inv = player:get_inventory()
|
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 dir = player:get_look_dir()
|
||||||
local yaw = player:get_look_horizontal()
|
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
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,25 +2,14 @@ local S = minetest.get_translator("mcl_chests")
|
||||||
local mod_doc = minetest.get_modpath("doc")
|
local mod_doc = minetest.get_modpath("doc")
|
||||||
|
|
||||||
-- Chest Entity
|
-- Chest Entity
|
||||||
local entity_animations = {}
|
local animate_chests = (minetest.settings:get_bool("animated_chests") ~= false)
|
||||||
local entity_animation_speed = 25
|
local entity_animation_speed = 25
|
||||||
|
local entity_animations = {
|
||||||
do
|
["open"] = {x = 0, y = 10},
|
||||||
local names = {"open", "opened", "close", "closed"}
|
["open_partly"] = {x = 0, y = 7},
|
||||||
local following = {["open"] = "opened", ["close"] = "closed"}
|
["close"] = {x = 10, y = 20},
|
||||||
local durations = {10, 0, 10, 5}
|
["close_partly"] = {x = 13, y = 20},
|
||||||
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
|
|
||||||
|
|
||||||
minetest.register_entity("mcl_chests:chest", {
|
minetest.register_entity("mcl_chests:chest", {
|
||||||
initial_properties = {
|
initial_properties = {
|
||||||
|
@ -33,21 +22,19 @@ minetest.register_entity("mcl_chests:chest", {
|
||||||
|
|
||||||
set_animation = function(self, animname)
|
set_animation = function(self, animname)
|
||||||
local anim = entity_animations[animname]
|
local anim = entity_animations[animname]
|
||||||
self.object:set_animation(anim.bounds, entity_animation_speed, 0, false)
|
if not anim then return end
|
||||||
if anim.sched_anim then
|
self.object:set_animation(anim, entity_animation_speed, 0, false)
|
||||||
self.sched_anim = anim.sched_anim
|
|
||||||
self.sched_time = anim.sched_time
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
open = function(self, playername)
|
open = function(self, playername, partly)
|
||||||
self.players[playername] = true
|
self.players[playername] = true
|
||||||
if not self.is_open then
|
if not self.is_open then
|
||||||
self.is_open = true
|
self:set_animation(partly and "open_partly" or "open")
|
||||||
self:set_animation("open")
|
|
||||||
minetest.sound_play(self.sound_prefix .. "_open", {
|
minetest.sound_play(self.sound_prefix .. "_open", {
|
||||||
pos = self.node_pos,
|
pos = self.node_pos,
|
||||||
})
|
})
|
||||||
|
self.is_open = true
|
||||||
|
self.opened_partly = partly
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -58,11 +45,12 @@ minetest.register_entity("mcl_chests:chest", {
|
||||||
for _ in pairs(playerlist) do
|
for _ in pairs(playerlist) do
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.is_open = false
|
self:set_animation(self.opened_partly and "close_partly" or "close")
|
||||||
self:set_animation("close")
|
|
||||||
minetest.sound_play(self.sound_prefix .. "_close", {
|
minetest.sound_play(self.sound_prefix .. "_close", {
|
||||||
pos = self.node_pos,
|
pos = self.node_pos,
|
||||||
})
|
})
|
||||||
|
self.is_open = false
|
||||||
|
self.opened_partly = false
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -100,23 +88,12 @@ minetest.register_entity("mcl_chests:chest", {
|
||||||
|
|
||||||
on_activate = function(self)
|
on_activate = function(self)
|
||||||
self.object:set_armor_groups({immortal = 1})
|
self.object:set_armor_groups({immortal = 1})
|
||||||
self:set_animation("closed")
|
|
||||||
self.players = {}
|
self.players = {}
|
||||||
end,
|
end,
|
||||||
|
|
||||||
on_step = function(self, dtime)
|
on_step = function(self, dtime)
|
||||||
local sched_anim, sched_time = self.sched_anim, self.sched_time
|
|
||||||
if not self:check() then
|
if not self:check() then
|
||||||
self.object:remove()
|
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
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
@ -149,8 +126,8 @@ local function create_entity(pos, node_name, textures, param2, double, sound_pre
|
||||||
return luaentity
|
return luaentity
|
||||||
end
|
end
|
||||||
|
|
||||||
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix)
|
local function find_or_create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir)
|
||||||
local dir = minetest.facedir_to_dir(param2)
|
local dir = dir or minetest.facedir_to_dir(param2)
|
||||||
local entity_pos = get_entity_pos(pos, dir, double)
|
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)
|
return find_entity(entity_pos) or create_entity(pos, node_name, textures, param2, double, sound_prefix, mesh_prefix, dir, entity_pos)
|
||||||
end
|
end
|
||||||
|
@ -175,11 +152,22 @@ Value:
|
||||||
If player is using a chest: { pos = <chest node position> }
|
If player is using a chest: { pos = <chest node position> }
|
||||||
Otherwise: nil ]]
|
Otherwise: nil ]]
|
||||||
local open_chests = {}
|
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
|
-- To be called if a player opened a chest
|
||||||
local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh)
|
local player_chest_open = function(player, pos, node_name, textures, param2, double, sound, mesh)
|
||||||
local name = player:get_player_name()
|
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}
|
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
|
end
|
||||||
|
|
||||||
-- Simple protection checking functions
|
-- Simple protection checking functions
|
||||||
|
@ -238,7 +226,9 @@ local player_chest_close = function(player)
|
||||||
if open_chest == nil then
|
if open_chest == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
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)
|
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)
|
chest_update_after_close(open_chest.pos)
|
||||||
|
|
||||||
open_chests[name] = nil
|
open_chests[name] = nil
|
||||||
|
|
|
@ -147,6 +147,17 @@ minetest.register_craftitem("mcl_core:apple", {
|
||||||
local gapple_hunger_restore = minetest.item_eat(4)
|
local gapple_hunger_restore = minetest.item_eat(4)
|
||||||
|
|
||||||
local function eat_gapple(itemstack, placer, pointed_thing)
|
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
|
local regen_duration, absorbtion_factor = 5, 1
|
||||||
if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then
|
if itemstack:get_name() == "mcl_core:apple_gold_enchanted" then
|
||||||
regen_duration, absorbtion_factor = 20, 4
|
regen_duration, absorbtion_factor = 20, 4
|
||||||
|
|
|
@ -219,6 +219,16 @@ end
|
||||||
|
|
||||||
minetest.register_node("mcl_enchanting:table", {
|
minetest.register_node("mcl_enchanting:table", {
|
||||||
description = S("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",
|
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"},
|
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 = {
|
node_box = {
|
||||||
|
|
|
@ -448,3 +448,34 @@ minetest.register_node("mcl_flowers:waterlily", {
|
||||||
|
|
||||||
-- Legacy support
|
-- Legacy support
|
||||||
minetest.register_alias("mcl_core:tallgrass", "mcl_flowers:tallgrass")
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if mg_name ~= "singlenode" then
|
||||||
-- Get loot for dungeon chests
|
-- Get loot for dungeon chests
|
||||||
local get_loot = function()
|
local get_loot = function()
|
||||||
local loottable = {
|
local loottable = {
|
||||||
|
@ -396,3 +397,4 @@ minetest.register_on_generated(function(minp, maxp)
|
||||||
end
|
end
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
end
|
||||||
|
|
45
mods/MAPGEN/mcl_villages/README.txt
Normal file
45
mods/MAPGEN/mcl_villages/README.txt
Normal file
|
@ -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
|
||||||
|
|
357
mods/MAPGEN/mcl_villages/buildings.lua
Normal file
357
mods/MAPGEN/mcl_villages/buildings.lua
Normal file
|
@ -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
|
83
mods/MAPGEN/mcl_villages/const.lua
Normal file
83
mods/MAPGEN/mcl_villages/const.lua
Normal file
|
@ -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
|
30
mods/MAPGEN/mcl_villages/convert_lua_mts.lua
Normal file
30
mods/MAPGEN/mcl_villages/convert_lua_mts.lua
Normal file
|
@ -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
|
3
mods/MAPGEN/mcl_villages/depends.txt
Normal file
3
mods/MAPGEN/mcl_villages/depends.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mcl_core
|
||||||
|
mcl_farming?
|
||||||
|
mobs_mc?
|
153
mods/MAPGEN/mcl_villages/foundation.lua
Normal file
153
mods/MAPGEN/mcl_villages/foundation.lua
Normal file
|
@ -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
|
235
mods/MAPGEN/mcl_villages/init.lua
Normal file
235
mods/MAPGEN/mcl_villages/init.lua
Normal file
|
@ -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
|
||||||
|
})
|
||||||
|
|
180
mods/MAPGEN/mcl_villages/paths.lua
Normal file
180
mods/MAPGEN/mcl_villages/paths.lua
Normal file
|
@ -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
|
BIN
mods/MAPGEN/mcl_villages/schematics/blacksmith.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/blacksmith.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/church.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/church.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/farm.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/farm.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/lamp.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/lamp.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/large_house.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/large_house.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/library.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/library.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/medium_house.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/medium_house.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/small_house.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/small_house.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/tavern.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/tavern.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/schematics/well.mts
Normal file
BIN
mods/MAPGEN/mcl_villages/schematics/well.mts
Normal file
Binary file not shown.
BIN
mods/MAPGEN/mcl_villages/screenshot.png
Normal file
BIN
mods/MAPGEN/mcl_villages/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 MiB |
BIN
mods/MAPGEN/mcl_villages/screenshot_2.png
Normal file
BIN
mods/MAPGEN/mcl_villages/screenshot_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
424
mods/MAPGEN/mcl_villages/utils.lua
Normal file
424
mods/MAPGEN/mcl_villages/utils.lua
Normal file
|
@ -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
|
-- Probability for every newly generated mapchunk to get corridors
|
||||||
local probability_railcaves_in_mapchunk = P(0.33333)
|
local probability_railcaves_in_mapchunk = P(0.33333)
|
||||||
setting = tonumber(minetest.settings:get("tsm_railcorridors_probability_railcaves_in_mapchunk"))
|
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)
|
probability_railcaves_in_mapchunk = P(setting)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,9 @@ flame_sound (Flame sound) bool true
|
||||||
# Form: Image height / Image width
|
# Form: Image height / Image width
|
||||||
fire_animation_frames (Fire Animation Frames) int 8
|
fire_animation_frames (Fire Animation Frames) int 8
|
||||||
|
|
||||||
|
# Whether to animate chests when open / close
|
||||||
|
animated_chests (Animated chests) bool true
|
||||||
|
|
||||||
[Experimental]
|
[Experimental]
|
||||||
# Whether ice is translucent. If disabled, ice is fully opaque.
|
# 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
|
# WARNING: This setting has quite poor performance and can slow down your
|
||||||
# game by a lot.
|
# game by a lot.
|
||||||
mcl_node_particles (Block particles detail level) enum none high,medium,low,none
|
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
|
||||||
|
|
Reference in a new issue