forked from MineClone5/MineClone5
Merge testing into compatibility
This commit is contained in:
commit
07c5fb7399
|
@ -27,19 +27,35 @@ Any Pull Request that isn't a bug fix can be closed within a week unless it rece
|
|||
|
||||
Start coding!
|
||||
|
||||
Refer to Minetest Lua API, Developer Wiki and other documentation.
|
||||
Refer to [Minetest Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt), [Developer Wiki](https://dev.minetest.net/), [MineClone 5 Wiki](https://git.minetest.land/MineClone5/MineClone5/wiki/) and other documentation.
|
||||
|
||||
Follow Lua code style guidelines. Use tabs, not spaces for indentation (tab size = 8). Never use `minetest.env`.
|
||||
Follow [Lua code style guidelines](https://dev.minetest.net/Lua_code_style_guidelines). Use tabs, not spaces for indentation (tab size = 8). Never use `minetest.env`.
|
||||
|
||||
Check your code works as expected.
|
||||
|
||||
Commit & push your changes to a new branch (not master, one change per branch)
|
||||
Commit & push your changes to a new branch (not master, one change per a branch).
|
||||
|
||||
Commit messages should use the present tense and be descriptive.
|
||||
|
||||
Once you are happy with your changes, submit a pull request.
|
||||
|
||||
A pull-request is considered merge-able when:
|
||||
A pull-request is considered merge-able when it looks good to one person from the community.
|
||||
|
||||
Please invite other developers to review your contribution when you know they are online. If there is no any reaction during 24 hours after posting the invitation and pinging developers - you are welcome to do a self-review and merge the request.
|
||||
|
||||
If someone else's contribution looks good to you - you are free to merge it ASAP.
|
||||
|
||||
Different git branches are welcomed! Releases by different people are welcomed! Releases from different branches are welcomed! Frequent releases are welcomed!
|
||||
|
||||
It is nice not to block other developers by your work and don't dictate them what to do, unsless they really want that. Git branches and forks are recommended to avoid conflicts at development stage.
|
||||
|
||||
It is nice to try splitting big features into small steps.
|
||||
|
||||
It is nice to create an issue for any work and mention the issue in the commit text, like `#123 Fix blast resistance of cactus`, where `#123` is the issue number.
|
||||
|
||||
Actually, it looks like we all love what we do, so any stupid situations should be carefully discussed before merging into upstreams. But nothing prevents us from releasing controversial stuff through dedicated branches. Release your contribution when you need more feedback.
|
||||
|
||||
Feel free to break the rules if you're sure you have to.
|
||||
|
||||
#### Contributors
|
||||
|
||||
|
|
|
@ -18,12 +18,7 @@ local S = minetest.get_translator("extra_mobs")
|
|||
--################### fox
|
||||
--###################
|
||||
|
||||
local followitem = ""
|
||||
if minetest.get_modpath("mc_sweet_berry") then
|
||||
followitem = "mc_sweet_berry:sweet_berry"
|
||||
else
|
||||
followitem = nil
|
||||
end
|
||||
local followitem = "mcl_farming:sweet_berry"
|
||||
|
||||
local fox = {
|
||||
type = "monster",
|
||||
|
@ -123,35 +118,30 @@ local fox = {
|
|||
mobs:register_mob("extra_mobs:fox", fox)
|
||||
|
||||
-- spawning
|
||||
mobs:spawn_specific(
|
||||
"extra_mobs:fox",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ExtremeHillsM",
|
||||
"BirchForestM",
|
||||
},
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
30,
|
||||
6000,
|
||||
3,
|
||||
mobs_mc.spawn_height.water,
|
||||
mobs_mc.spawn_height.overworld_max)
|
||||
mobs:spawn_setup({
|
||||
name = "extra_mobs:fox",
|
||||
biomes = {
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"ColdTaiga",
|
||||
"SunflowerPlains",
|
||||
"RoofedForest",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"ExtremeHillsM",
|
||||
"BirchForestM",
|
||||
},
|
||||
interval = 30,
|
||||
chance = 6000,
|
||||
min_height = mobs_mc.spawn_height.water,
|
||||
})
|
||||
|
||||
--mobs:spawn_specific("extra_mobs:fox", "overworld", "ground", 0, minetest.LIGHT_MAX+1, 30, 6000, 3, 0, 500)
|
||||
--[[
|
||||
|
|
|
@ -213,20 +213,36 @@ baby_strider.child = 1
|
|||
mobs:register_mob("extra_mobs:baby_strider", baby_strider)
|
||||
|
||||
-- Regular spawning in the Nether
|
||||
mobs:spawn_specific(
|
||||
"extra_mobs:strider",
|
||||
"nether",
|
||||
"lava",
|
||||
{
|
||||
"Nether"
|
||||
},
|
||||
0,
|
||||
minetest.LIGHT_MAX+1,
|
||||
30,
|
||||
6000,
|
||||
3,
|
||||
mobs_mc.spawn_height.nether_min,
|
||||
mobs_mc.spawn_height.nether_max)
|
||||
|
||||
mobs:spawn_setup({
|
||||
name = "extra_mobs:strider",
|
||||
type_of_spawning = "lava",
|
||||
dimension = "nether",
|
||||
biomes = {
|
||||
"Nether"
|
||||
},
|
||||
min_height = mcl_mapgen.nether.min,
|
||||
max_height = mcl_mapgen.nether.max,
|
||||
chance = 2000,
|
||||
check_position = function(pos)
|
||||
return minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z}).name:find("lava")
|
||||
end
|
||||
})
|
||||
|
||||
mobs:spawn_setup({
|
||||
name = "extra_mobs:baby_strider",
|
||||
type_of_spawning = "lava",
|
||||
dimension = "nether",
|
||||
biomes = {
|
||||
"Nether"
|
||||
},
|
||||
min_height = mcl_mapgen.nether.min,
|
||||
max_height = mcl_mapgen.nether.max,
|
||||
chance = 100,
|
||||
check_position = function(pos)
|
||||
return minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z}).name:find("lava")
|
||||
end
|
||||
})
|
||||
|
||||
-- spawn eggs
|
||||
mobs:register_egg("extra_mobs:strider", S("Strider"), "extra_mobs_spawn_icon_strider.png", 0)
|
||||
|
|
|
@ -801,20 +801,6 @@ function mobs.mob_step(self, dtime)
|
|||
return false
|
||||
end
|
||||
|
||||
|
||||
--DEBUG TIME!
|
||||
--REMEMBER TO MOVE THIS AFTER DEATH CHECK
|
||||
|
||||
--if self.has_head then
|
||||
-- mobs.do_head_logic(self,dtime)
|
||||
--end
|
||||
|
||||
|
||||
|
||||
--if true then--DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG
|
||||
-- return
|
||||
--end
|
||||
|
||||
--despawn mechanism
|
||||
--don't despawned tamed or bred mobs
|
||||
if not self.tamed and not self.bred then
|
||||
|
@ -833,7 +819,7 @@ function mobs.mob_step(self, dtime)
|
|||
self.object:set_texture_mod("^[colorize:red:120")
|
||||
--fix double death sound
|
||||
if self.health > 0 then
|
||||
mobs.play_sound(self,"damage")
|
||||
mobs.play_sound(self, "damage")
|
||||
end
|
||||
end
|
||||
self.old_health = self.health
|
||||
|
@ -863,7 +849,7 @@ function mobs.mob_step(self, dtime)
|
|||
return
|
||||
end
|
||||
|
||||
mobs.random_sound_handling(self,dtime)
|
||||
mobs.random_sound_handling(self, dtime)
|
||||
|
||||
--mobs drowning mechanic
|
||||
if not self.breathes_in_water then
|
||||
|
@ -893,14 +879,40 @@ function mobs.mob_step(self, dtime)
|
|||
end
|
||||
end
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
local node = minetest_get_node(pos).name
|
||||
|
||||
--water damage
|
||||
if self.water_damage and self.water_damage ~= 0 then
|
||||
local pos = self.object:get_pos()
|
||||
local node = minetest_get_node(pos).name
|
||||
if minetest_get_item_group(node, "water") ~= 0 then
|
||||
if self.water_damage and self.water_damage ~= 0 and minetest_get_item_group(node, "water") ~= 0 then
|
||||
self.water_counter = (self.water_counter or 0) + dtime
|
||||
if self.water_counter >= 1 then
|
||||
mobs.smoke_effect(self)
|
||||
self.health = self.health - self.water_damage
|
||||
self:teleport()
|
||||
self.water_counter = 0
|
||||
end
|
||||
end
|
||||
|
||||
--lava damage
|
||||
local lava_damage = self.lava_damage
|
||||
if lava_damage and lava_damage ~= 0 and minetest_get_item_group(node, "lava") ~= 0 then
|
||||
self.lava_counter = (self.lava_counter or 0) + dtime
|
||||
if self.lava_counter >= 1 then
|
||||
minetest.sound_play("default_punch", {
|
||||
object = self.object,
|
||||
max_hear_distance = 5
|
||||
}, true)
|
||||
--[[ if not mcl_burning.is_burning(self.object) then
|
||||
mcl_burning.set_on_fire(self.object, 1.1)
|
||||
else
|
||||
]] self.object:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = self.lava_damage}
|
||||
}, nil)
|
||||
-- end
|
||||
self.lava_counter = 0
|
||||
self.health = self.health - lava_damage
|
||||
self:teleport()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -211,26 +211,6 @@ mobs.teleport = function(self, target)
|
|||
end
|
||||
end
|
||||
|
||||
--a function used for despawning mobs
|
||||
mobs.check_for_player_within_area = function(self, radius)
|
||||
local pos1 = self.object:get_pos()
|
||||
if not pos1 then return end
|
||||
--get players in radius
|
||||
for _,player in pairs(minetest_get_connected_players()) do
|
||||
if player and player:get_hp() > 0 then
|
||||
local pos2 = player:get_pos()
|
||||
local distance = vector_distance(pos1,pos2)
|
||||
if distance < radius then
|
||||
--found a player
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
--did not find a player
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--a simple helper function for mobs following
|
||||
mobs.get_2d_distance = function(pos1,pos2)
|
||||
pos1.y = 0
|
||||
|
|
|
@ -5,9 +5,27 @@ local minetest_settings = minetest.settings
|
|||
-- CMI support check
|
||||
local use_cmi = minetest.global_exists("cmi")
|
||||
|
||||
local vector_distance = vector.distance
|
||||
local minetest_get_connected_players = minetest.get_connected_players
|
||||
local math_random = math.random
|
||||
|
||||
mobs.can_despawn = function(self)
|
||||
return (not self.tamed and not self.bred and not self.nametag and
|
||||
not mobs.check_for_player_within_area(self, 64));
|
||||
if self.tamed or self.bred or self.nametag then return false end
|
||||
local mob_pos = self.object:get_pos()
|
||||
if not mob_pos then return true end
|
||||
local distance = 999
|
||||
for _, player in pairs(minetest_get_connected_players()) do
|
||||
if player and player:get_hp() > 0 then
|
||||
local player_pos = player:get_pos()
|
||||
local new_distance = vector_distance(player_pos, mob_pos)
|
||||
if new_distance < distance then
|
||||
distance = new_distance
|
||||
if distance < 33 then return false end
|
||||
if distance < 128 and math_random(1, 42) ~= 11 then return false end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- get entity staticdata
|
||||
|
|
|
@ -6,11 +6,14 @@ local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air
|
|||
local get_biome_name = minetest.get_biome_name
|
||||
local get_objects_inside_radius = minetest.get_objects_inside_radius
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
|
||||
local minetest_get_perlin = minetest.get_perlin
|
||||
|
||||
local math_random = math.random
|
||||
local math_floor = math.floor
|
||||
--local max = math.max
|
||||
local math_ceil = math.ceil
|
||||
local math_cos = math.cos
|
||||
local math_sin = math.sin
|
||||
local math_round = function(x) return (x > 0) and math_floor(x + 0.5) or math_ceil(x - 0.5) end
|
||||
|
||||
--local vector_distance = vector.distance
|
||||
local vector_new = vector.new
|
||||
|
@ -22,151 +25,171 @@ local table_remove = table.remove
|
|||
local pairs = pairs
|
||||
|
||||
-- range for mob count
|
||||
local aoc_range = 48
|
||||
local aoc_range = 32
|
||||
|
||||
--do mobs spawn?
|
||||
local mobs_spawn = minetest.settings:get_bool("mobs_spawn", true) ~= false
|
||||
|
||||
--[[
|
||||
|
||||
THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
||||
local noise_params = {
|
||||
offset = 0,
|
||||
scale = 3,
|
||||
spread = {
|
||||
x = 301,
|
||||
y = 50,
|
||||
z = 304,
|
||||
},
|
||||
seed = 100,
|
||||
octaves = 3,
|
||||
persistence = 0.5,
|
||||
}
|
||||
|
||||
underground:
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",local spawning_position = spawning_position_list[math.random(1,#spawning_position_list)]
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
-- THIS IS THE BIG LIST OF ALL BIOMES - used for programming/updating mobs
|
||||
-- Also used for missing parameter
|
||||
-- Please update the list when adding new biomes!
|
||||
|
||||
ocean:
|
||||
"RoofedForest_ocean",
|
||||
"JungleEdgeM_ocean",
|
||||
"BirchForestM_ocean",
|
||||
"BirchForest_ocean",
|
||||
"IcePlains_deep_ocean",
|
||||
"Jungle_deep_ocean",
|
||||
"Savanna_ocean",
|
||||
"MesaPlateauF_ocean",
|
||||
"ExtremeHillsM_deep_ocean",
|
||||
"Savanna_deep_ocean",
|
||||
"SunflowerPlains_ocean",
|
||||
"Swampland_deep_ocean",
|
||||
"Swampland_ocean",
|
||||
"MegaSpruceTaiga_deep_ocean",
|
||||
"ExtremeHillsM_ocean",
|
||||
"JungleEdgeM_deep_ocean",
|
||||
"SunflowerPlains_deep_ocean",
|
||||
"BirchForest_deep_ocean",
|
||||
"IcePlainsSpikes_ocean",
|
||||
"Mesa_ocean",
|
||||
"StoneBeach_ocean",
|
||||
"Plains_deep_ocean",
|
||||
"JungleEdge_deep_ocean",
|
||||
"SavannaM_deep_ocean",
|
||||
"Desert_deep_ocean",
|
||||
"Mesa_deep_ocean",
|
||||
"ColdTaiga_deep_ocean",
|
||||
"Plains_ocean",
|
||||
"MesaPlateauFM_ocean",
|
||||
"Forest_deep_ocean",
|
||||
"JungleM_deep_ocean",
|
||||
"FlowerForest_deep_ocean",
|
||||
"MushroomIsland_ocean",
|
||||
"MegaTaiga_ocean",
|
||||
"StoneBeach_deep_ocean",
|
||||
"IcePlainsSpikes_deep_ocean",
|
||||
"ColdTaiga_ocean",
|
||||
"SavannaM_ocean",
|
||||
"MesaPlateauF_deep_ocean",
|
||||
"MesaBryce_deep_ocean",
|
||||
"ExtremeHills+_deep_ocean",
|
||||
"ExtremeHills_ocean",
|
||||
"MushroomIsland_deep_ocean",
|
||||
"Forest_ocean",
|
||||
"MegaTaiga_deep_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"MesaBryce_ocean",
|
||||
"MegaSpruceTaiga_ocean",
|
||||
"ExtremeHills+_ocean",
|
||||
"Jungle_ocean",
|
||||
"RoofedForest_deep_ocean",
|
||||
"IcePlains_ocean",
|
||||
"FlowerForest_ocean",
|
||||
"ExtremeHills_deep_ocean",
|
||||
"MesaPlateauFM_deep_ocean",
|
||||
"Desert_ocean",
|
||||
"Taiga_ocean",
|
||||
"BirchForestM_deep_ocean",
|
||||
"Taiga_deep_ocean",
|
||||
"JungleM_ocean",
|
||||
local list_of_all_biomes = {
|
||||
|
||||
water or beach?
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
-- underground:
|
||||
|
||||
beach:
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
|
||||
dimension biome:
|
||||
"Nether",
|
||||
"End",
|
||||
-- ocean:
|
||||
|
||||
Overworld regular:
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
]]--
|
||||
"RoofedForest_ocean",
|
||||
"JungleEdgeM_ocean",
|
||||
"BirchForestM_ocean",
|
||||
"BirchForest_ocean",
|
||||
"IcePlains_deep_ocean",
|
||||
"Jungle_deep_ocean",
|
||||
"Savanna_ocean",
|
||||
"MesaPlateauF_ocean",
|
||||
"ExtremeHillsM_deep_ocean",
|
||||
"Savanna_deep_ocean",
|
||||
"SunflowerPlains_ocean",
|
||||
"Swampland_deep_ocean",
|
||||
"Swampland_ocean",
|
||||
"MegaSpruceTaiga_deep_ocean",
|
||||
"ExtremeHillsM_ocean",
|
||||
"JungleEdgeM_deep_ocean",
|
||||
"SunflowerPlains_deep_ocean",
|
||||
"BirchForest_deep_ocean",
|
||||
"IcePlainsSpikes_ocean",
|
||||
"Mesa_ocean",
|
||||
"StoneBeach_ocean",
|
||||
"Plains_deep_ocean",
|
||||
"JungleEdge_deep_ocean",
|
||||
"SavannaM_deep_ocean",
|
||||
"Desert_deep_ocean",
|
||||
"Mesa_deep_ocean",
|
||||
"ColdTaiga_deep_ocean",
|
||||
"Plains_ocean",
|
||||
"MesaPlateauFM_ocean",
|
||||
"Forest_deep_ocean",
|
||||
"JungleM_deep_ocean",
|
||||
"FlowerForest_deep_ocean",
|
||||
"MushroomIsland_ocean",
|
||||
"MegaTaiga_ocean",
|
||||
"StoneBeach_deep_ocean",
|
||||
"IcePlainsSpikes_deep_ocean",
|
||||
"ColdTaiga_ocean",
|
||||
"SavannaM_ocean",
|
||||
"MesaPlateauF_deep_ocean",
|
||||
"MesaBryce_deep_ocean",
|
||||
"ExtremeHills+_deep_ocean",
|
||||
"ExtremeHills_ocean",
|
||||
"MushroomIsland_deep_ocean",
|
||||
"Forest_ocean",
|
||||
"MegaTaiga_deep_ocean",
|
||||
"JungleEdge_ocean",
|
||||
"MesaBryce_ocean",
|
||||
"MegaSpruceTaiga_ocean",
|
||||
"ExtremeHills+_ocean",
|
||||
"Jungle_ocean",
|
||||
"RoofedForest_deep_ocean",
|
||||
"IcePlains_ocean",
|
||||
"FlowerForest_ocean",
|
||||
"ExtremeHills_deep_ocean",
|
||||
"MesaPlateauFM_deep_ocean",
|
||||
"Desert_ocean",
|
||||
"Taiga_ocean",
|
||||
"BirchForestM_deep_ocean",
|
||||
"Taiga_deep_ocean",
|
||||
"JungleM_ocean",
|
||||
|
||||
-- water or beach?
|
||||
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
|
||||
-- beach:
|
||||
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
|
||||
-- dimension biome:
|
||||
|
||||
"Nether",
|
||||
"End",
|
||||
|
||||
-- Overworld regular:
|
||||
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
}
|
||||
|
||||
-- count how many mobs are in an area
|
||||
local function count_mobs(pos)
|
||||
|
@ -216,11 +239,74 @@ WARNING: BIOME INTEGRATION NEEDED -> How to get biome through lua??
|
|||
|
||||
--this is where all of the spawning information is kept
|
||||
local spawn_dictionary = {}
|
||||
local summary_chance = 0
|
||||
|
||||
function mobs:spawn_setup(def)
|
||||
if not mobs_spawn then return end
|
||||
|
||||
if not def then
|
||||
minetest.log("warning", "Empty mob spawn setup definition")
|
||||
return
|
||||
end
|
||||
|
||||
local name = def.name
|
||||
if not name then
|
||||
minetest.log("warning", "Missing mob name")
|
||||
return
|
||||
end
|
||||
|
||||
local dimension = def.dimension or "overworld"
|
||||
local type_of_spawning = def.type_of_spawning or "ground"
|
||||
local biomes = def.biomes or list_of_all_biomes
|
||||
local min_light = def.min_light or 0
|
||||
local max_light = def.max_light or (minetest.LIGHT_MAX + 1)
|
||||
local chance = def.chance or 1000
|
||||
local aoc = def.aoc or aoc_range
|
||||
local min_height = def.min_height or mcl_mapgen.overworld.min
|
||||
local max_height = def.max_height or mcl_mapgen.overworld.max
|
||||
local day_toggle = def.day_toggle
|
||||
local on_spawn = def.on_spawn
|
||||
local check_position = def.check_position
|
||||
|
||||
-- chance/spawn number override in minetest.conf for registered mob
|
||||
local numbers = minetest.settings:get(name)
|
||||
if numbers then
|
||||
numbers = numbers:split(",")
|
||||
chance = tonumber(numbers[1]) or chance
|
||||
aoc = tonumber(numbers[2]) or aoc
|
||||
if chance == 0 then
|
||||
minetest.log("warning", string.format("[mobs] %s has spawning disabled", name))
|
||||
return
|
||||
end
|
||||
minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
if chance < 1 then
|
||||
chance = 1
|
||||
minetest.log("warning", "Chance shouldn't be less than 1 (mob name: " .. name ..")")
|
||||
end
|
||||
|
||||
spawn_dictionary[#spawn_dictionary + 1] = {
|
||||
name = name,
|
||||
dimension = dimension,
|
||||
type_of_spawning = type_of_spawning,
|
||||
biomes = biomes,
|
||||
min_light = min_light,
|
||||
max_light = max_light,
|
||||
chance = chance,
|
||||
aoc = aoc,
|
||||
min_height = min_height,
|
||||
max_height = max_height,
|
||||
day_toggle = day_toggle,
|
||||
check_position = check_position,
|
||||
on_spawn = on_spawn,
|
||||
}
|
||||
summary_chance = summary_chance + chance
|
||||
minetest.log("warning", minetest.serialize(spawn_dictionary))
|
||||
end
|
||||
|
||||
function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_light, max_light, interval, chance, aoc, min_height, max_height, day_toggle, on_spawn)
|
||||
|
||||
--print(dump(biomes))
|
||||
|
||||
-- Do mobs spawn at all?
|
||||
if not mobs_spawn then
|
||||
return
|
||||
|
@ -239,179 +325,7 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
|
|||
return
|
||||
end
|
||||
|
||||
minetest.log("action",
|
||||
string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
--[[
|
||||
local function spawn_action(pos, node, active_object_count, active_object_count_wider, name)
|
||||
|
||||
local orig_pos = table.copy(pos)
|
||||
-- is mob actually registered?
|
||||
if not mobs.spawning_mobs[name]
|
||||
or not minetest.registered_entities[name] then
|
||||
minetest.log("warning", "Mob spawn of "..name.." failed, unknown entity or mob is not registered for spawning!")
|
||||
return
|
||||
end
|
||||
|
||||
-- additional custom checks for spawning mob
|
||||
if mobs:spawn_abm_check(pos, node, name) == true then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, ABM check rejected!")
|
||||
return
|
||||
end
|
||||
|
||||
-- count nearby mobs in same spawn class
|
||||
local entdef = minetest.registered_entities[name]
|
||||
local spawn_class = entdef and entdef.spawn_class
|
||||
if not spawn_class then
|
||||
if entdef.type == "monster" then
|
||||
spawn_class = "hostile"
|
||||
else
|
||||
spawn_class = "passive"
|
||||
end
|
||||
end
|
||||
local in_class_cap = count_mobs(pos, "!"..spawn_class) < MOB_CAP[spawn_class]
|
||||
-- do not spawn if too many of same mob in area
|
||||
if active_object_count_wider >= max_per_block -- large-range mob cap
|
||||
or (not in_class_cap) -- spawn class mob cap
|
||||
or count_mobs(pos, name) >= aoc then -- per-mob mob cap
|
||||
-- too many entities
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too crowded!")
|
||||
return
|
||||
end
|
||||
|
||||
-- if toggle set to nil then ignore day/night check
|
||||
if day_toggle then
|
||||
|
||||
local tod = (minetest.get_timeofday() or 0) * 24000
|
||||
|
||||
if tod > 4500 and tod < 19500 then
|
||||
-- daylight, but mob wants night
|
||||
if day_toggle == false then
|
||||
-- mob needs night
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs light!")
|
||||
return
|
||||
end
|
||||
else
|
||||
-- night time but mob wants day
|
||||
if day_toggle == true then
|
||||
-- mob needs day
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, mob needs daylight!")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- spawn above node
|
||||
pos.y = pos.y + 1
|
||||
|
||||
-- only spawn away from player
|
||||
local objs = minetest.get_objects_inside_radius(pos, 24)
|
||||
|
||||
for n = 1, #objs do
|
||||
|
||||
if objs[n]:is_player() then
|
||||
-- player too close
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, player too close!")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- mobs cannot spawn in protected areas when enabled
|
||||
if not spawn_protected
|
||||
and minetest.is_protected(pos, "") then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, position is protected!")
|
||||
return
|
||||
end
|
||||
|
||||
-- are we spawning within height limits?
|
||||
if pos.y > max_height
|
||||
or pos.y < min_height then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, out of height limit!")
|
||||
return
|
||||
end
|
||||
|
||||
-- are light levels ok?
|
||||
local light = minetest.get_node_light(pos)
|
||||
if not light
|
||||
or light > max_light
|
||||
or light < min_light then
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, bad light!")
|
||||
return
|
||||
end
|
||||
|
||||
-- do we have enough space to spawn mob?
|
||||
local ent = minetest.registered_entities[name]
|
||||
local width_x = max(1, math.ceil(ent.collisionbox[4] - ent.collisionbox[1]))
|
||||
local min_x, max_x
|
||||
if width_x % 2 == 0 then
|
||||
max_x = math.floor(width_x/2)
|
||||
min_x = -(max_x-1)
|
||||
else
|
||||
max_x = math.floor(width_x/2)
|
||||
min_x = -max_x
|
||||
end
|
||||
|
||||
local width_z = max(1, math.ceil(ent.collisionbox[6] - ent.collisionbox[3]))
|
||||
local min_z, max_z
|
||||
if width_z % 2 == 0 then
|
||||
max_z = math.floor(width_z/2)
|
||||
min_z = -(max_z-1)
|
||||
else
|
||||
max_z = math.floor(width_z/2)
|
||||
min_z = -max_z
|
||||
end
|
||||
|
||||
local max_y = max(0, math.ceil(ent.collisionbox[5] - ent.collisionbox[2]) - 1)
|
||||
|
||||
for y = 0, max_y do
|
||||
for x = min_x, max_x do
|
||||
for z = min_z, max_z do
|
||||
local pos2 = {x = pos.x+x, y = pos.y+y, z = pos.z+z}
|
||||
if minetest.registered_nodes[node_ok(pos2).name].walkable == true then
|
||||
-- inside block
|
||||
minetest.log("info", "Mob spawn of "..name.." at "..minetest.pos_to_string(pos).." failed, too little space!")
|
||||
if ent.spawn_small_alternative and (not minetest.registered_nodes[node_ok(pos).name].walkable) then
|
||||
minetest.log("info", "Trying to spawn smaller alternative mob: "..ent.spawn_small_alternative)
|
||||
spawn_action(orig_pos, node, active_object_count, active_object_count_wider, ent.spawn_small_alternative)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- tweak X/Y/Z spawn pos
|
||||
if width_x % 2 == 0 then
|
||||
pos.x = pos.x + 0.5
|
||||
end
|
||||
if width_z % 2 == 0 then
|
||||
pos.z = pos.z + 0.5
|
||||
end
|
||||
pos.y = pos.y - 0.5
|
||||
|
||||
local mob = minetest.add_entity(pos, name)
|
||||
minetest.log("action", "Mob spawned: "..name.." at "..minetest.pos_to_string(pos))
|
||||
|
||||
if on_spawn then
|
||||
|
||||
local ent = mob:get_luaentity()
|
||||
|
||||
on_spawn(ent, pos)
|
||||
end
|
||||
end
|
||||
|
||||
local function spawn_abm_action(pos, node, active_object_count, active_object_count_wider)
|
||||
spawn_action(pos, node, active_object_count, active_object_count_wider, name)
|
||||
end
|
||||
]]--
|
||||
|
||||
local entdef = minetest.registered_entities[name]
|
||||
local spawn_class
|
||||
if entdef.type == "monster" then
|
||||
spawn_class = "hostile"
|
||||
else
|
||||
spawn_class = "passive"
|
||||
minetest.log("action", string.format("[mobs] Chance setting for %s changed to %s (total: %s)", name, chance, aoc))
|
||||
end
|
||||
|
||||
--load information into the spawn dictionary
|
||||
|
@ -423,107 +337,34 @@ function mobs:spawn_specific(name, dimension, type_of_spawning, biomes, min_ligh
|
|||
spawn_dictionary[key]["biomes"] = biomes
|
||||
spawn_dictionary[key]["min_light"] = min_light
|
||||
spawn_dictionary[key]["max_light"] = max_light
|
||||
spawn_dictionary[key]["interval"] = interval
|
||||
spawn_dictionary[key]["chance"] = chance
|
||||
spawn_dictionary[key]["aoc"] = aoc
|
||||
spawn_dictionary[key]["min_height"] = min_height
|
||||
spawn_dictionary[key]["max_height"] = max_height
|
||||
spawn_dictionary[key]["day_toggle"] = day_toggle
|
||||
--spawn_dictionary[key]["on_spawn"] = spawn_abm_action
|
||||
spawn_dictionary[key]["spawn_class"] = spawn_class
|
||||
|
||||
--[[
|
||||
minetest.register_abm({
|
||||
label = name .. " spawning",
|
||||
nodenames = nodes,
|
||||
neighbors = neighbors,
|
||||
interval = interval,
|
||||
chance = floor(max(1, chance * mobs_spawn_chance)),
|
||||
catch_up = false,
|
||||
action = spawn_abm_action,
|
||||
})
|
||||
]]--
|
||||
summary_chance = summary_chance + chance
|
||||
end
|
||||
|
||||
-- compatibility with older mob registration
|
||||
-- we're going to forget about this for now -j4i
|
||||
--[[
|
||||
function mobs:register_spawn(name, nodes, max_light, min_light, chance, active_object_count, max_height, day_toggle)
|
||||
|
||||
mobs:spawn_specific(name, nodes, {"air"}, min_light, max_light, 30,
|
||||
chance, active_object_count, -31000, max_height, day_toggle)
|
||||
local two_pi = 2 * math.pi
|
||||
local function get_next_mob_spawn_pos(pos)
|
||||
local distance = math_random(25, 32)
|
||||
local angle = math_random() * two_pi
|
||||
return {
|
||||
x = math_round(pos.x + distance * math_cos(angle)),
|
||||
y = pos.y,
|
||||
z = math_round(pos.z + distance * math_sin(angle))
|
||||
}
|
||||
end
|
||||
]]--
|
||||
|
||||
|
||||
--Don't disable this yet-j4i
|
||||
-- MarkBu's spawn function
|
||||
|
||||
function mobs:spawn(def)
|
||||
--does nothing for now
|
||||
--[[
|
||||
local name = def.name
|
||||
local nodes = def.nodes or {"group:soil", "group:stone"}
|
||||
local neighbors = def.neighbors or {"air"}
|
||||
local min_light = def.min_light or 0
|
||||
local max_light = def.max_light or 15
|
||||
local interval = def.interval or 30
|
||||
local chance = def.chance or 5000
|
||||
local active_object_count = def.active_object_count or 1
|
||||
local min_height = def.min_height or -31000
|
||||
local max_height = def.max_height or 31000
|
||||
local day_toggle = def.day_toggle
|
||||
local on_spawn = def.on_spawn
|
||||
|
||||
mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, interval,
|
||||
chance, active_object_count, min_height, max_height, day_toggle, on_spawn)
|
||||
]]--
|
||||
end
|
||||
|
||||
|
||||
|
||||
local axis
|
||||
--inner and outer part of square donut radius
|
||||
local inner = 15
|
||||
local outer = 64
|
||||
local int = {-1,1}
|
||||
|
||||
local function position_calculation(pos)
|
||||
|
||||
pos = vector_floor(pos)
|
||||
|
||||
--this is used to determine the axis buffer from the player
|
||||
axis = math_random(0,1)
|
||||
|
||||
--cast towards the direction
|
||||
if axis == 0 then --x
|
||||
pos.x = pos.x + math_random(inner,outer)*int[math_random(1,2)]
|
||||
pos.z = pos.z + math_random(-outer,outer)
|
||||
else --z
|
||||
pos.z = pos.z + math_random(inner,outer)*int[math_random(1,2)]
|
||||
pos.x = pos.x + math_random(-outer,outer)
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
--[[
|
||||
local decypher_limits_dictionary = {
|
||||
["overworld"] = {mcl_vars.mg_overworld_min,mcl_vars.mg_overworld_max},
|
||||
["nether"] = {mcl_vars.mg_nether_min, mcl_vars.mg_nether_max},
|
||||
["end"] = {mcl_vars.mg_end_min, mcl_vars.mg_end_max}
|
||||
}
|
||||
]]--
|
||||
|
||||
local function decypher_limits(posy)
|
||||
--local min_max_table = decypher_limits_dictionary[dimension]
|
||||
--return min_max_table[1],min_max_table[2]
|
||||
posy = math_floor(posy)
|
||||
return posy - 32, posy + 32
|
||||
end
|
||||
|
||||
--a simple helper function for mob_spawn
|
||||
local function biome_check(biome_list, biome_goal)
|
||||
for _,data in ipairs(biome_list) do
|
||||
for _, data in pairs(biome_list) do
|
||||
if data == biome_goal then
|
||||
return true
|
||||
end
|
||||
|
@ -533,176 +374,102 @@ local function biome_check(biome_list, biome_goal)
|
|||
end
|
||||
|
||||
|
||||
--todo mob limiting
|
||||
--MAIN LOOP
|
||||
|
||||
if mobs_spawn then
|
||||
|
||||
local perlin_noise
|
||||
|
||||
local function spawn_a_mob(pos, dimension, y_min, y_max)
|
||||
local dimension = dimension or mcl_worlds.pos_to_dimension(pos)
|
||||
local goal_pos = get_next_mob_spawn_pos(pos)
|
||||
local spawning_position_list = find_nodes_in_area_under_air(
|
||||
{x = goal_pos.x, y = y_min, z = goal_pos.z},
|
||||
{x = goal_pos.x, y = y_max, z = goal_pos.z},
|
||||
{"group:solid", "group:water", "group:lava"}
|
||||
)
|
||||
if #spawning_position_list <= 0 then return end
|
||||
local spawning_position = spawning_position_list[math_random(1, #spawning_position_list)]
|
||||
|
||||
--hard code mob limit in area to 5 for now
|
||||
if count_mobs(spawning_position) >= 5 then return end
|
||||
|
||||
local gotten_node = get_node(spawning_position).name
|
||||
local gotten_biome = minetest.get_biome_data(spawning_position)
|
||||
if not gotten_node or not gotten_biome then return end
|
||||
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
|
||||
|
||||
--add this so mobs don't spawn inside nodes
|
||||
spawning_position.y = spawning_position.y + 1
|
||||
|
||||
--only need to poll for node light if everything else worked
|
||||
local gotten_light = get_node_light(spawning_position)
|
||||
|
||||
local is_water = get_item_group(gotten_node, "water") ~= 0
|
||||
local is_lava = get_item_group(gotten_node, "lava") ~= 0
|
||||
local is_ground = not (is_water or is_lava)
|
||||
if not is_ground then
|
||||
spawning_position.y = spawning_position.y - 1
|
||||
end
|
||||
|
||||
local mob_def
|
||||
|
||||
--create a disconnected clone of the spawn dictionary
|
||||
--prevents memory leak
|
||||
local mob_library_worker_table = table_copy(spawn_dictionary)
|
||||
|
||||
--grab mob that fits into the spawning location
|
||||
--randomly grab a mob, don't exclude any possibilities
|
||||
perlin_noise = perlin_noise or minetest_get_perlin(noise_params)
|
||||
local noise = perlin_noise:get_3d(spawning_position)
|
||||
local current_summary_chance = summary_chance
|
||||
while #mob_library_worker_table > 0 do
|
||||
local mob_chance_offset = (math_round(noise * current_summary_chance + 12345) % current_summary_chance) + 1
|
||||
local mob_index = 1
|
||||
local mob_chance = mob_library_worker_table[mob_index].chance
|
||||
local step_chance = mob_chance
|
||||
while step_chance < mob_chance_offset do
|
||||
mob_index = mob_index + 1
|
||||
mob_chance = mob_library_worker_table[mob_index].chance
|
||||
step_chance = step_chance + mob_chance
|
||||
end
|
||||
local mob_def = mob_library_worker_table[mob_index]
|
||||
if mob_def
|
||||
and spawning_position.y >= mob_def.min_height
|
||||
and spawning_position.y <= mob_def.max_height
|
||||
and mob_def.dimension == dimension
|
||||
and biome_check(mob_def.biomes, gotten_biome)
|
||||
and gotten_light >= mob_def.min_light
|
||||
and gotten_light <= mob_def.max_light
|
||||
and (is_ground or mob_def.type_of_spawning ~= "ground")
|
||||
and (mob_def.check_position and mob_def.check_position(spawning_position) or true)
|
||||
then
|
||||
--everything is correct, spawn mob
|
||||
local object = minetest.add_entity(spawning_position, mob_def.name)
|
||||
if object then
|
||||
return mob_def.on_spawn and mob_def.on_spawn(object, pos)
|
||||
end
|
||||
end
|
||||
current_summary_chance = current_summary_chance - mob_chance
|
||||
table_remove(mob_library_worker_table, mob_index)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--MAIN LOOP
|
||||
|
||||
local timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer >= 10 then
|
||||
timer = 0
|
||||
for _,player in pairs(get_connected_players()) do
|
||||
-- after this line each "break" means "continue"
|
||||
local do_mob_spawning = true
|
||||
repeat
|
||||
--don't need to get these variables more than once
|
||||
--they happen in a single server step
|
||||
|
||||
local player_pos = player:get_pos()
|
||||
local dimension = mcl_worlds.pos_to_dimension(player_pos)
|
||||
|
||||
if dimension == "void" or dimension == "default" then
|
||||
break -- ignore void and unloaded area
|
||||
end
|
||||
|
||||
local min, max = decypher_limits(player_pos.y)
|
||||
|
||||
for i = 1, math_random(1,4) do
|
||||
-- after this line each "break" means "continue"
|
||||
local do_mob_algorithm = true
|
||||
repeat
|
||||
|
||||
local goal_pos = position_calculation(player_pos)
|
||||
|
||||
local spawning_position_list = find_nodes_in_area_under_air(vector_new(goal_pos.x,min,goal_pos.z), vector_new(goal_pos.x,max,goal_pos.z), {"group:solid", "group:water", "group:lava"})
|
||||
|
||||
--couldn't find node
|
||||
if #spawning_position_list <= 0 then
|
||||
break
|
||||
end
|
||||
|
||||
local spawning_position = spawning_position_list[math_random(1,#spawning_position_list)]
|
||||
|
||||
--Prevent strange behavior --- this is commented out: /too close to player --fixed with inner circle
|
||||
if not spawning_position then -- or vector_distance(player_pos, spawning_position) < 15
|
||||
break
|
||||
end
|
||||
|
||||
--hard code mob limit in area to 5 for now
|
||||
if count_mobs(spawning_position) >= 5 then
|
||||
break
|
||||
end
|
||||
|
||||
local gotten_node = get_node(spawning_position).name
|
||||
|
||||
if not gotten_node or gotten_node == "air" then --skip air nodes
|
||||
break
|
||||
end
|
||||
|
||||
local gotten_biome = minetest.get_biome_data(spawning_position)
|
||||
|
||||
if not gotten_biome then
|
||||
break --skip if in unloaded area
|
||||
end
|
||||
|
||||
gotten_biome = get_biome_name(gotten_biome.biome) --makes it easier to work with
|
||||
|
||||
--add this so mobs don't spawn inside nodes
|
||||
spawning_position.y = spawning_position.y + 1
|
||||
|
||||
--only need to poll for node light if everything else worked
|
||||
local gotten_light = get_node_light(spawning_position)
|
||||
|
||||
local is_water = get_item_group(gotten_node, "water") ~= 0
|
||||
local is_lava = get_item_group(gotten_node, "lava") ~= 0
|
||||
|
||||
local mob_def = nil
|
||||
|
||||
--create a disconnected clone of the spawn dictionary
|
||||
--prevents memory leak
|
||||
local mob_library_worker_table = table_copy(spawn_dictionary)
|
||||
|
||||
--grab mob that fits into the spawning location
|
||||
--randomly grab a mob, don't exclude any possibilities
|
||||
local repeat_mob_search = true
|
||||
repeat
|
||||
|
||||
--do not infinite loop
|
||||
if #mob_library_worker_table <= 0 then
|
||||
--print("breaking infinite loop")
|
||||
break
|
||||
end
|
||||
|
||||
local skip = false
|
||||
|
||||
--use this for removing table elements of mobs that do not match
|
||||
local temp_index = math_random(1,#mob_library_worker_table)
|
||||
|
||||
local temp_def = mob_library_worker_table[temp_index]
|
||||
|
||||
--skip if something ridiculous happens (nil mob def)
|
||||
--something truly horrible has happened if skip gets
|
||||
--activated at this point
|
||||
if not temp_def then
|
||||
skip = true
|
||||
end
|
||||
|
||||
if not skip and (spawning_position.y < temp_def.min_height or spawning_position.y > temp_def.max_height) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
--skip if not correct dimension
|
||||
if not skip and (temp_def.dimension ~= dimension) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
--skip if not in correct biome
|
||||
if not skip and (not biome_check(temp_def.biomes, gotten_biome)) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
--don't spawn if not in light limits
|
||||
if not skip and (gotten_light < temp_def.min_light or gotten_light > temp_def.max_light) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
--skip if not in correct spawning type
|
||||
if not skip and (temp_def.type_of_spawning == "ground" and is_water) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
if not skip and (temp_def.type_of_spawning == "ground" and is_lava) then
|
||||
skip = true
|
||||
end
|
||||
|
||||
--found a mob, exit out of loop
|
||||
if not skip then
|
||||
--minetest.log("warning", "found mob:"..temp_def.name)
|
||||
--print("found mob:"..temp_def.name)
|
||||
mob_def = table_copy(temp_def)
|
||||
break
|
||||
else
|
||||
--minetest.log("warning", "deleting temp index "..temp_index)
|
||||
--print("deleting temp index")
|
||||
table_remove(mob_library_worker_table, temp_index)
|
||||
end
|
||||
|
||||
until repeat_mob_search == false --this is needed to sort through mobs randomly
|
||||
|
||||
|
||||
--catch if went through all mobs and something went horribly wrong
|
||||
--could not find a valid mob to spawn that fits the environment
|
||||
if not mob_def then
|
||||
break
|
||||
end
|
||||
|
||||
--adjust the position for water and lava mobs
|
||||
if mob_def.type_of_spawning == "water" or mob_def.type_of_spawning == "lava" then
|
||||
spawning_position.y = spawning_position.y - 1
|
||||
end
|
||||
|
||||
--print("spawning: " .. mob_def.name)
|
||||
|
||||
--everything is correct, spawn mob
|
||||
minetest.add_entity(spawning_position, mob_def.name)
|
||||
|
||||
break
|
||||
until do_mob_algorithm == false --this is a safety catch
|
||||
end
|
||||
|
||||
break
|
||||
until do_mob_spawning == false --this is a performance catch
|
||||
if timer < 10 then return end
|
||||
timer = 0
|
||||
for _, player in pairs(get_connected_players()) do
|
||||
local pos = player:get_pos()
|
||||
local dimension = mcl_worlds.pos_to_dimension(pos)
|
||||
-- ignore void and unloaded area
|
||||
if dimension ~= "void" and dimension ~= "default" then
|
||||
local y_min, y_max = decypher_limits(pos.y)
|
||||
for i = 1, math_random(1, 4) do
|
||||
spawn_a_mob(pos, dimension, y_min, y_max)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
--################### SILVERFISH
|
||||
--###################
|
||||
|
||||
local PLAYER_SCAN_RADIUS = 5
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
mobs:register_mob("mobs_mc:silverfish", {
|
||||
|
@ -46,6 +48,20 @@ mobs:register_mob("mobs_mc:silverfish", {
|
|||
view_range = 16,
|
||||
attack_type = "punch",
|
||||
damage = 1,
|
||||
do_custom = function(self, dtime)
|
||||
self.do_custom_time = (self.do_custom_time or 0) + dtime
|
||||
if self.do_custom_time < 1.5 then return end
|
||||
self.do_custom_time = 0
|
||||
local selfpos = self.object:get_pos()
|
||||
local objects = minetest.get_objects_inside_radius(selfpos, PLAYER_SCAN_RADIUS)
|
||||
for _, obj in pairs(objects) do
|
||||
if obj:is_player() then
|
||||
self.attacking = obj
|
||||
mobs.group_attack_initialization(self)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
mobs:register_egg("mobs_mc:silverfish", S("Silverfish"), "mobs_mc_spawn_icon_silverfish.png", 0)
|
||||
|
|
|
@ -9,6 +9,95 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
|||
--################### ZOMBIE
|
||||
--###################
|
||||
|
||||
local husk_biomes = {
|
||||
"Desert",
|
||||
"SavannaM",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
}
|
||||
|
||||
local zombie_biomes = {
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"StoneBeach_underground",
|
||||
"MesaBryce_underground",
|
||||
"Mesa_underground",
|
||||
"RoofedForest_underground",
|
||||
"Jungle_underground",
|
||||
"Swampland_underground",
|
||||
"MushroomIsland_underground",
|
||||
"BirchForest_underground",
|
||||
"Plains_underground",
|
||||
"MesaPlateauF_underground",
|
||||
"ExtremeHills_underground",
|
||||
"MegaSpruceTaiga_underground",
|
||||
"BirchForestM_underground",
|
||||
"SavannaM_underground",
|
||||
"MesaPlateauFM_underground",
|
||||
"Desert_underground",
|
||||
"Savanna_underground",
|
||||
"Forest_underground",
|
||||
"SunflowerPlains_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
}
|
||||
|
||||
local drops_common = {
|
||||
{name = mobs_mc.items.rotten_flesh,
|
||||
chance = 1,
|
||||
|
@ -166,230 +255,36 @@ baby_husk.child = 1
|
|||
|
||||
mobs:register_mob("mobs_mc:baby_husk", baby_husk)
|
||||
|
||||
|
||||
-- Spawning
|
||||
|
||||
mobs:spawn_specific(
|
||||
"mobs_mc:zombie",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"StoneBeach_underground",
|
||||
"MesaBryce_underground",
|
||||
"Mesa_underground",
|
||||
"RoofedForest_underground",
|
||||
"Jungle_underground",
|
||||
"Swampland_underground",
|
||||
"MushroomIsland_underground",
|
||||
"BirchForest_underground",
|
||||
"Plains_underground",
|
||||
"MesaPlateauF_underground",
|
||||
"ExtremeHills_underground",
|
||||
"MegaSpruceTaiga_underground",
|
||||
"BirchForestM_underground",
|
||||
"SavannaM_underground",
|
||||
"MesaPlateauFM_underground",
|
||||
"Desert_underground",
|
||||
"Savanna_underground",
|
||||
"Forest_underground",
|
||||
"SunflowerPlains_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
30,
|
||||
6000,
|
||||
4,
|
||||
mobs_mc.spawn_height.overworld_min,
|
||||
mobs_mc.spawn_height.overworld_max)
|
||||
mobs:spawn_setup({
|
||||
name = "mobs_mc:zombie",
|
||||
biomes = zombie_biomes,
|
||||
max_light = 7,
|
||||
chance = 2000,
|
||||
})
|
||||
|
||||
-- Baby zombie is 20 times less likely than regular zombies
|
||||
mobs:spawn_specific(
|
||||
"mobs_mc:baby_zombie",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"FlowerForest_underground",
|
||||
"JungleEdge_underground",
|
||||
"StoneBeach_underground",
|
||||
"MesaBryce_underground",
|
||||
"Mesa_underground",
|
||||
"RoofedForest_underground",
|
||||
"Jungle_underground",
|
||||
"Swampland_underground",
|
||||
"MushroomIsland_underground",
|
||||
"BirchForest_underground",
|
||||
"Plains_underground",
|
||||
"MesaPlateauF_underground",
|
||||
"ExtremeHills_underground",
|
||||
"MegaSpruceTaiga_underground",
|
||||
"BirchForestM_underground",
|
||||
"SavannaM_underground",
|
||||
"MesaPlateauFM_underground",
|
||||
"Desert_underground",
|
||||
"Savanna_underground",
|
||||
"Forest_underground",
|
||||
"SunflowerPlains_underground",
|
||||
"ColdTaiga_underground",
|
||||
"IcePlains_underground",
|
||||
"IcePlainsSpikes_underground",
|
||||
"MegaTaiga_underground",
|
||||
"Taiga_underground",
|
||||
"ExtremeHills+_underground",
|
||||
"JungleM_underground",
|
||||
"ExtremeHillsM_underground",
|
||||
"JungleEdgeM_underground",
|
||||
"Mesa",
|
||||
"FlowerForest",
|
||||
"Swampland",
|
||||
"Taiga",
|
||||
"ExtremeHills",
|
||||
"Jungle",
|
||||
"Savanna",
|
||||
"BirchForest",
|
||||
"MegaSpruceTaiga",
|
||||
"MegaTaiga",
|
||||
"ExtremeHills+",
|
||||
"Forest",
|
||||
"Plains",
|
||||
"Desert",
|
||||
"ColdTaiga",
|
||||
"MushroomIsland",
|
||||
"IcePlainsSpikes",
|
||||
"SunflowerPlains",
|
||||
"IcePlains",
|
||||
"RoofedForest",
|
||||
"ExtremeHills+_snowtop",
|
||||
"MesaPlateauFM_grasstop",
|
||||
"JungleEdgeM",
|
||||
"ExtremeHillsM",
|
||||
"JungleM",
|
||||
"BirchForestM",
|
||||
"MesaPlateauF",
|
||||
"MesaPlateauFM",
|
||||
"MesaPlateauF_grasstop",
|
||||
"MesaBryce",
|
||||
"JungleEdge",
|
||||
"SavannaM",
|
||||
"FlowerForest_beach",
|
||||
"Forest_beach",
|
||||
"StoneBeach",
|
||||
"ColdTaiga_beach_water",
|
||||
"Taiga_beach",
|
||||
"Savanna_beach",
|
||||
"Plains_beach",
|
||||
"ExtremeHills_beach",
|
||||
"ColdTaiga_beach",
|
||||
"Swampland_shore",
|
||||
"MushroomIslandShore",
|
||||
"JungleM_shore",
|
||||
"Jungle_shore",
|
||||
"MesaPlateauFM_sandlevel",
|
||||
"MesaPlateauF_sandlevel",
|
||||
"MesaBryce_sandlevel",
|
||||
"Mesa_sandlevel",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
30,
|
||||
60000,
|
||||
4,
|
||||
mobs_mc.spawn_height.overworld_min,
|
||||
mobs_mc.spawn_height.overworld_max)
|
||||
mobs:spawn_setup({
|
||||
name = "mobs_mc:baby_zombie",
|
||||
biomes = zombie_biomes,
|
||||
max_lignt = 7,
|
||||
chance = 100,
|
||||
})
|
||||
|
||||
mobs:spawn_setup({
|
||||
name = "mobs_mc:husk",
|
||||
biomes = husk_biomes,
|
||||
max_light = 7,
|
||||
chance = 2000,
|
||||
})
|
||||
|
||||
mobs:spawn_specific(
|
||||
"mobs_mc:husk",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"Desert",
|
||||
"SavannaM",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
30,
|
||||
6500,
|
||||
4,
|
||||
mobs_mc.spawn_height.overworld_min,
|
||||
mobs_mc.spawn_height.overworld_max)
|
||||
mobs:spawn_specific(
|
||||
"mobs_mc:baby_husk",
|
||||
"overworld",
|
||||
"ground",
|
||||
{
|
||||
"Desert",
|
||||
"SavannaM",
|
||||
"Savanna",
|
||||
"Savanna_beach",
|
||||
},
|
||||
0,
|
||||
7,
|
||||
30,
|
||||
65000,
|
||||
4,
|
||||
mobs_mc.spawn_height.overworld_min,
|
||||
mobs_mc.spawn_height.overworld_max)
|
||||
mobs:spawn_setup({
|
||||
name = "mobs_mc:baby_husk",
|
||||
biomes = husk_biomes,
|
||||
max_light = 7,
|
||||
chance = 100,
|
||||
})
|
||||
|
||||
-- Spawn eggs
|
||||
mobs:register_egg("mobs_mc:husk", S("Husk"), "mobs_mc_spawn_icon_husk.png", 0)
|
||||
|
|
|
@ -38,11 +38,14 @@ local function damage_explosion(self, damagemulitplier)
|
|||
for _,obj in pairs(objects) do
|
||||
if obj:is_player() then
|
||||
mcl_util.deal_damage(obj, damagemulitplier - vector.distance(self.object:get_pos(), obj:get_pos()), {type = "explosion"})
|
||||
elseif obj:get_luaentity()._cmi_is_mob then
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damagemulitplier - vector.distance(self.object:get_pos(), obj:get_pos())},
|
||||
}, self.object:get_velocity())
|
||||
else
|
||||
local entity = obj:get_luaentity()
|
||||
if entity and entity._cmi_is_mob then
|
||||
obj:punch(self.object, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups={fleshy=damagemulitplier - vector.distance(self.object:get_pos(), obj:get_pos())},
|
||||
}, self.object:get_velocity())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -388,6 +388,12 @@ end
|
|||
["mcl_core:whirlpool_source"] = -BUBBLE_COLUMN_SPEED,
|
||||
["mcl_core:bubble_column_source"] = BUBBLE_COLUMN_SPEED,
|
||||
}
|
||||
local bubble_source_fast_switch_from_to = {
|
||||
["mcl_nether:soul_sand"] = "mcl_core:bubble_column_source",
|
||||
["mcl_core:bubble_column_source"] = "mcl_core:bubble_column_source",
|
||||
["mcl_nether:magma"] = "mcl_core:whirlpool_source",
|
||||
["mcl_core:whirlpool_source"] = "mcl_core:whirlpool_source",
|
||||
}
|
||||
minetest.register_abm({
|
||||
label = "Process bubble columns and whirlpools",
|
||||
nodenames = {"mcl_core:whirlpool_source", "mcl_core:bubble_column_source"},
|
||||
|
@ -399,7 +405,7 @@ end
|
|||
local check = nether_node_to_check[name]
|
||||
local below = minetest.get_node({x = x, y = y - 1, z = z}).name
|
||||
if below ~= name and below ~= check then
|
||||
minetest.swap_node(pos, {name = "mcl_core:water_source"})
|
||||
minetest.swap_node(pos, {name = bubble_source_fast_switch_from_to[below] or "mcl_core:water_source"})
|
||||
return
|
||||
end
|
||||
local upper_pos = {x = x, y = y + 1, z = z}
|
||||
|
|
|
@ -746,6 +746,13 @@ minetest.register_abm({
|
|||
return
|
||||
end
|
||||
|
||||
if lower_node_name == OBSIDIAN and pos.y >= mcl_mapgen.overworld.min and random(1, 200) == 19 then
|
||||
local pigman_obj = minetest.add_entity(pos, "mobs_mc:pigman")
|
||||
if pigman_obj then
|
||||
teleport_cooloff(pigman_obj)
|
||||
end
|
||||
end
|
||||
|
||||
local o = node.param2 -- orientation
|
||||
|
||||
local closer_node_name = get_node({x = pos.x - 1 + o, y = pos.y, z = pos.z - o}).name
|
||||
|
|
|
@ -436,8 +436,7 @@ local function build_a_village(minp, maxp, pr, placer)
|
|||
end
|
||||
|
||||
-- Disable natural generation in singlenode.
|
||||
if mg_name ~= "singlenode" then
|
||||
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||
if not mcl_mapgen.singlenode then
|
||||
local scan_last_node = mcl_mapgen.LAST_BLOCK * mcl_mapgen.BS - 1
|
||||
local scan_offset = mcl_mapgen.BS
|
||||
mcl_mapgen.register_mapgen(function(minp, maxp, chunkseed)
|
||||
|
|
|
@ -2,7 +2,6 @@ mcl_playerplus = {
|
|||
elytra = {},
|
||||
}
|
||||
|
||||
local player_velocity_old = {x=0, y=0, z=0}
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local dir_to_yaw = minetest.dir_to_yaw
|
||||
local get_item_group = minetest.get_item_group
|
||||
|
@ -341,9 +340,6 @@ minetest.register_globalstep(function(dtime)
|
|||
set_bone_position_conditional(player,"Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90))
|
||||
end
|
||||
|
||||
player_velocity_old = player:get_velocity() or player:get_player_velocity()
|
||||
|
||||
|
||||
-- controls right and left arms pitch when shooting a bow or blocking
|
||||
if mcl_shields.is_blocking(player) == 2 then
|
||||
set_bone_position_conditional(player, "Arm_Right_Pitch_Control", vector.new(-3, 5.785, 0), vector.new(20, -20, 0))
|
||||
|
@ -472,6 +468,7 @@ minetest.register_globalstep(function(dtime)
|
|||
local bubble_column_head = node_head == "mcl_core:bubble_column_source"
|
||||
fly_pos.y = player_pos_for_bubble_columns[name].y + (bubble_column_head and time or time/10)
|
||||
player:set_pos(fly_pos)
|
||||
player:add_velocity({x = 0, y = -player_velocity.y / 2, z = 0})
|
||||
player_pos_for_bubble_columns[name] = fly_pos
|
||||
end
|
||||
else
|
||||
|
@ -485,6 +482,7 @@ minetest.register_globalstep(function(dtime)
|
|||
if stands_on == "mcl_nether:magma" then
|
||||
fly_pos.y = math.floor(fly_pos.y) + (control.sneak and 0.51 or 0.5)
|
||||
player:set_pos(fly_pos)
|
||||
player:add_velocity({x = 0, y = -player_velocity.y / 2, z = 0})
|
||||
player_pos_for_bubble_columns[name] = fly_pos
|
||||
else
|
||||
fly_pos.y = player_pos_for_bubble_columns[name].y - (whirlpool_head and time/2 or time/5)
|
||||
|
@ -492,9 +490,11 @@ minetest.register_globalstep(function(dtime)
|
|||
if will_stand_on == "mcl_nether:magma" then
|
||||
fly_pos.y = math.floor(fly_pos.y) + (control.sneak and 0.51 or 0.5)
|
||||
player:set_pos(fly_pos)
|
||||
player:add_velocity({x = 0, y = -player_velocity.y / 2, z = 0})
|
||||
player_pos_for_bubble_columns[name] = fly_pos
|
||||
elseif will_stand_on == "mcl_core:whirlpool_source" then
|
||||
player:set_pos(fly_pos)
|
||||
player:add_velocity({x = 0, y = -player_velocity.y / 2, z = 0})
|
||||
player_pos_for_bubble_columns[name] = fly_pos
|
||||
else
|
||||
player_pos_for_bubble_columns[name] = nil
|
||||
|
|
Loading…
Reference in New Issue