New Mobs, Switch to Creatura

This commit is contained in:
ElCeejo 2022-02-10 18:00:06 -08:00 committed by GitHub
parent 1450e131fa
commit e773fab121
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 6144 additions and 3247 deletions

File diff suppressed because it is too large Load diff

1582
api/behaviors.lua Normal file

File diff suppressed because it is too large Load diff

360
api/lasso.lua Normal file
View file

@ -0,0 +1,360 @@
-----------
-- Lasso --
-----------
local abs = math.abs
function animalia.initialize_lasso(self)
self.lasso_origin = self:recall("lasso_origin") or nil
if self.lasso_origin then
self.caught_with_lasso = true
if type(self.lasso_origin) == "table"
and minetest.get_item_group(minetest.get_node(self.lasso_origin).name, "fence") > 0 then
local object = minetest.add_entity(self.lasso_origin, "animalia:lasso_fence_ent")
object:get_luaentity().parent = self.object
elseif type(self.lasso_origin) == "string"
and minetest.get_player_by_name(self.lasso_origin) then
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin)
else
self:forget("lasso_origin")
end
end
end
function animalia.set_lasso_visual(self, target)
if not creatura.is_alive(self)
or (self.lasso_visual
and self.lasso_visual:get_luaentity()) then return end
local pos = self.object:get_pos()
local object = minetest.add_entity(pos, "animalia:lasso_visual")
local ent = object:get_luaentity()
self.lasso_visual = object
self.lasso_origin = target
ent.parent = self.object
ent.lasso_origin = target
return object
end
function animalia.update_lasso_effects(self)
if not creatura.is_alive(self) then return end
if self.caught_with_lasso
and self.lasso_origin then
local pos = self.object:get_pos()
pos.y = pos.y + (self:get_height() * 0.5)
animalia.set_lasso_visual(self, self.lasso_origin)
if type(self.lasso_origin) == "userdata"
or type(self.lasso_origin) == "string" then
if type(self.lasso_origin) == "string" then
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin)
if not self.lasso_origin then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
return
end
end
self:memorize("lasso_origin", self.lasso_origin:get_player_name())
-- Get distance to lasso player
local player = self.lasso_origin
local lasso_origin = player:get_pos()
lasso_origin.y = lasso_origin.y + 1
local dist = vector.distance(pos, lasso_origin)
if player:get_wielded_item():get_name() ~= "animalia:lasso"
or vector.distance(pos, lasso_origin) > 16 then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
-- Apply physics
if dist > 6
or abs(lasso_origin.y - pos.y) > 8 then
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8))
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
elseif type(self.lasso_origin) == "table" then
self:memorize("lasso_origin", self.lasso_origin)
local lasso_origin = self.lasso_origin
local dist = vector.distance(pos, lasso_origin)
if dist > 6
or abs(lasso_origin.y - pos.y) > 8 then
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8))
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
local objects = minetest.get_objects_inside_radius(lasso_origin, 1)
local is_lasso_attached = false
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
is_lasso_attached = true
end
end
if not is_lasso_attached then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
else
local objects = minetest.get_objects_inside_radius(self.lasso_origin, 0.4)
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
minetest.add_item(object:get_pos(), "animalia:lasso")
object:remove()
end
end
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
end
end
local function is_lasso_in_use(player)
for _, ent in pairs(minetest.luaentities) do
if ent.name
and ent.name:match("^animalia:") then
if ent.lasso_origin
and type(ent.lasso_origin) == "userdata"
and ent.lasso_origin == player then
return true
end
end
end
return false
end
local function update_lasso_rotation(self)
if not self.parent
or not self.lasso_origin then self.object:remove() return end
local lasso_origin = self.lasso_origin
if type(lasso_origin) == "userdata" then
lasso_origin = lasso_origin:get_pos()
lasso_origin.y = lasso_origin.y + 1
end
local object = self.parent
if not object then return end
local pos = object:get_pos()
pos.y = pos.y + object:get_luaentity():get_height()
local rot = vector.dir_to_rotation(vector.direction(lasso_origin, pos))
self.object:set_pos(lasso_origin)
self.object:set_rotation(rot)
self.object:set_properties({
visual_size = {x = 6, z = 10 * vector.distance(pos, lasso_origin), y = 6}
})
end
minetest.register_entity("animalia:lasso_visual", {
hp_max = 1,
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "mesh",
mesh = "animalia_lasso.b3d",
visual_size = {x = 2, y = 2},
textures = {"animalia_lasso_cube.png"},
is_visible = true,
makes_footstep_sound = false,
glow = 1,
on_step = function(self, dtime)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
or (self.parent
and (not creatura.is_alive(self.parent)
or not self.parent:get_luaentity().caught_with_lasso)) then
self.object:remove()
return
end
update_lasso_rotation(self)
end
})
minetest.register_entity("animalia:frog_tongue_visual", {
hp_max = 1,
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "mesh",
mesh = "animalia_lasso.b3d",
visual_size = {x = 2, y = 2},
textures = {"animalia_frog_tongue.png"},
is_visible = true,
makes_footstep_sound = false,
on_step = function(self, dtime)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
or (self.parent
and (not creatura.is_alive(self.parent)
or not self.parent:get_luaentity().caught_with_lasso)) then
self.object:remove()
return
end
update_lasso_rotation(self)
end
})
minetest.register_entity("animalia:lasso_fence_ent", {
physical = false,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
visual = "cube",
visual_size = {x = 0.3, y = 0.3},
mesh = "model",
textures = {
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
},
makes_footstep_sound = false,
on_step = function(self)
if not self.parent
or not self.parent:get_luaentity()
or not self.parent:get_luaentity().lasso_origin then
self.object:remove()
return
end
local pos = self.object:get_pos()
local node = minetest.get_node(pos)
if not minetest.registered_nodes[node.name].walkable
or minetest.get_item_group(node.name, "fence") < 1 then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
minetest.add_item(self.object:get_pos(), "animalia:lasso")
self.object:remove()
return
end
end,
on_rightclick = function(self)
if self.parent then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
end
local dirs = {
vector.new(1, 0, 0),
vector.new(-1, 0, 0),
vector.new(0, 1, 0),
vector.new(0, -1, 0),
vector.new(0, 0, 1),
vector.new(0, 0, -1),
}
for i = 1, 6 do
local pos = vector.add(self.object:get_pos(), dirs[i])
local name = minetest.get_node(pos).name
if not minetest.registered_nodes[name].walkable then
minetest.add_item(pos, "animalia:lasso")
break
end
end
self.object:remove()
end,
on_punch = function(self)
if self.parent then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
end
local dirs = {
vector.new(1, 0, 0),
vector.new(-1, 0, 0),
vector.new(0, 1, 0),
vector.new(0, -1, 0),
vector.new(0, 0, 1),
vector.new(0, 0, -1),
}
for i = 1, 6 do
local pos = vector.add(self.object:get_pos(), dirs[i])
local name = minetest.get_node(pos).name
if not minetest.registered_nodes[name].walkable then
minetest.add_item(pos, "animalia:lasso")
break
end
end
self.object:remove()
end
})
minetest.register_craftitem("animalia:lasso", {
description = "Lasso",
inventory_image = "animalia_lasso.png",
on_secondary_use = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "object" then
if pointed_thing.ref:is_player() then return end
local ent = pointed_thing.ref:get_luaentity()
if not ent.caught_with_lasso
and not is_lasso_in_use(placer) then
ent.caught_with_lasso = true
ent.lasso_origin = placer
elseif ent.lasso_origin
and ent.lasso_origin == placer then
ent.caught_with_lasso = nil
ent.lasso_origin = nil
end
end
end,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then
local pos = minetest.get_pointed_thing_position(pointed_thing)
if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then
local objects = minetest.get_objects_inside_radius(placer:get_pos(), 21)
for _, obj in ipairs(objects) do
if obj:get_luaentity()
and obj:get_luaentity().lasso_origin
and obj:get_luaentity().lasso_visual
and type(obj:get_luaentity().lasso_origin) == "userdata"
and obj:get_luaentity().lasso_origin == placer then
obj:get_luaentity().lasso_visual:get_luaentity().lasso_origin = pos
obj:get_luaentity().lasso_origin = pos
local object = minetest.add_entity(pos, "animalia:lasso_fence_ent")
object:get_luaentity().parent = obj
itemstack:take_item(1)
break
end
end
end
end
return itemstack
end
})

316
api/spawning.lua Normal file
View file

@ -0,0 +1,316 @@
--------------
-- Spawning --
--------------
local random = math.random
local path = minetest.get_modpath("animalia")
local storage = dofile(path .. "/api/storage.lua")
animalia.spawn_points = storage.spawn_points
-- Get Biomes --
local chicken_biomes = {}
local frog_biomes = {}
local pig_biomes = {}
local wolf_biomes = {}
local function insert_all(tbl, tbl2)
for i = 1, #tbl2 do
table.insert(tbl, tbl2[i])
end
end
minetest.register_on_mods_loaded(function()
insert_all(chicken_biomes, animalia.registered_biome_groups["grassland"].biomes)
insert_all(chicken_biomes, animalia.registered_biome_groups["tropical"].biomes)
insert_all(pig_biomes, animalia.registered_biome_groups["temperate"].biomes)
insert_all(pig_biomes, animalia.registered_biome_groups["boreal"].biomes)
insert_all(frog_biomes, animalia.registered_biome_groups["swamp"].biomes)
insert_all(frog_biomes, animalia.registered_biome_groups["tropical"].biomes)
end)
creatura.register_mob_spawn("animalia:bat", {
chance = 2,
min_radius = 4,
max_radius = 16,
min_light = 0,
min_height = -512,
max_height = 0,
min_group = 3,
max_group = 5,
biomes = animalia.registered_biome_groups["cave"].biomes,
spawn_in_nodes = true,
nodes = {"air", "ignore"}
})
creatura.register_mob_spawn("animalia:chicken", {
chance = 3,
min_group = 3,
max_group = 5,
biomes = chicken_biomes
})
creatura.register_mob_spawn("animalia:cow", {
chance = 3,
min_group = 3,
max_group = 4,
biomes = animalia.registered_biome_groups["grassland"].biomes
})
creatura.register_mob_spawn("animalia:frog", {
chance = 2,
min_radius = 4,
max_radius = 16,
min_light = 0,
min_height = -32,
max_height = 8,
min_group = 2,
max_group = 6,
biomes = frog_biomes,
spawn_cluster = true,
spawn_in_nodes = true,
nodes = {"default:water_source"},
send_debug = true
})
creatura.register_mob_spawn("animalia:horse", {
chance = 3,
min_group = 4,
max_group = 5,
biomes = animalia.registered_biome_groups["grassland"].biomes
})
creatura.register_mob_spawn("animalia:pig", {
chance = 3,
min_group = 2,
max_group = 4,
biomes = pig_biomes
})
creatura.register_mob_spawn("animalia:reindeer", {
chance = 4,
min_group = 6,
max_group = 12,
biomes = animalia.registered_biome_groups["boreal"].biomes
})
creatura.register_mob_spawn("animalia:sheep", {
chance = 3,
min_group = 3,
max_group = 6,
biomes = animalia.registered_biome_groups["grassland"].biomes
})
creatura.register_mob_spawn("animalia:turkey", {
chance = 2,
min_group = 3,
max_group = 4,
biomes = animalia.registered_biome_groups["boreal"].biomes
})
creatura.register_mob_spawn("animalia:wolf", {
chance = 3,
min_group = 2,
max_group = 3,
biomes = animalia.registered_biome_groups["boreal"].biomes
})
creatura.register_mob_spawn("animalia:bird", {
chance = 4,
min_light = 0,
min_group = 12,
max_group = 16,
biomes = animalia.registered_biome_groups["common"].biomes,
spawn_cluster = true,
spawn_in_nodes = true,
nodes = {"air", "ignore"}
})
creatura.register_mob_spawn("animalia:tropical_fish", {
chance = 3,
min_height = -128,
max_height = 256,
min_group = 8,
max_group = 12,
spawn_cluster = true,
spawn_in_nodes = true,
nodes = {"default:water_source"}
})
---------------------
-- Mapgen Spawning --
---------------------
local function vec_raise(v, n)
return {x = v.x, y = v.y + n, z = v.z}
end
function is_value_in_table(tbl, val)
for _, v in pairs(tbl) do
if v == val then
return true
end
end
return false
end
function get_biome_name(pos)
if not pos then return end
return minetest.get_biome_name(minetest.get_biome_data(pos).biome)
end
function get_ground_level(pos)
local node = minetest.get_node(pos)
local node_def = minetest.registered_nodes[node.name]
local height = 0
while node_def.walkable
and height < 4 do
height = height + 1
node = minetest.get_node(vec_raise(pos, height))
node_def = minetest.registered_nodes[node.name]
end
return vec_raise(pos, height)
end
local function dist_to_nearest_player(pos)
local dist
for _, player in pairs(minetest.get_connected_players()) do
local player_pos = player:get_pos()
if player_pos
and (not dist
or dist > vector.distance(pos, player_pos)) then
dist = vector.distance(pos, player_pos)
end
end
return dist or 100
end
local function get_spawnable_mobs(pos)
local biome = get_biome_name(pos)
if not biome then return end
local spawnable = {}
for k, v in pairs(creatura.registered_mob_spawns) do
if (not v.biomes
or is_value_in_table(v.biomes, biome))
and k:match("^animalia:")
and not v.spawn_in_nodes then
table.insert(spawnable, k)
end
end
return spawnable
end
local mapgen_spawning = minetest.settings:get_bool("animalia_mapgen_spawning") or true
animalia.chunks_since_last_spawn = 0
local chunk_spawn_add_int = tonumber(minetest.settings:get("chunk_spawn_add_int")) or 6
animalia.spawn_queue = {}
minetest.register_on_generated(function(minp, maxp)
if not mapgen_spawning then return end
animalia.chunks_since_last_spawn = animalia.chunks_since_last_spawn + 1
local heightmap = minetest.get_mapgen_object("heightmap")
if not heightmap then return end
local pos = {
x = minp.x + math.floor((maxp.x - minp.x) / 2),
y = minp.y,
z = minp.z + math.floor((maxp.z - minp.z) / 2)
}
local hm_i = (pos.x - minp.x + 1) + (((pos.z - minp.z)) * 80)
pos.y = heightmap[hm_i]
if animalia.chunks_since_last_spawn > chunk_spawn_add_int
and pos.y > 0 then
local heightmap = minetest.get_mapgen_object("heightmap")
if not heightmap then return end
local center = {
x = math.floor(minp.x + ((maxp.x - minp.x) * 0.5) + 0.5),
y = minp.y,
z = math.floor(minp.z + ((maxp.z - minp.z) * 0.5) + 0.5),
}
local light = minetest.get_natural_light(center)
while center.y < maxp.y
and light < 10 do
center.y = center.y + 1
light = minetest.get_natural_light(center)
end
local spawnable_mobs = get_spawnable_mobs(center)
if spawnable_mobs then
local mob = spawnable_mobs[random(#spawnable_mobs)]
table.insert(animalia.spawn_queue, {pos = center, mob = mob, group = random(3, 4)})
table.insert(animalia.spawn_points, center)
end
animalia.chunks_since_last_spawn = 0
end
end)
local respawn_interval = 15
minetest.register_globalstep(function(dtime)
respawn_interval = respawn_interval - dtime
if respawn_interval <= 0 then
if #animalia.spawn_points > 0 then
for i = 1, #animalia.spawn_points do
local point = animalia.spawn_points[i]
if dist_to_nearest_player(point) < 48
and minetest.get_node_or_nil(point) then
local spawnable_mobs = get_spawnable_mobs(point)
if spawnable_mobs then
local mob = spawnable_mobs[random(#spawnable_mobs)]
local objects = minetest.get_objects_inside_radius(point, 32)
local spawn = true
if #objects > 0 then
for i = 1, #objects do
local object = objects[i]
if object:get_luaentity()
and object:get_luaentity().name:find("animalia:") then
spawn = false
break
end
end
end
if spawn then
table.insert(animalia.spawn_queue, {pos = point, mob = mob, group = random(3, 4)})
end
end
end
end
end
respawn_interval = 15
end
end)
local chunk_spawn_queue_int = tonumber(minetest.settings:get("chunk_spawn_queue_int")) or 16
local function spawn_queued()
if not mapgen_spawning then return end
local queue = animalia.spawn_queue
if #queue > 0 then
for i = #queue, 1, -1 do
if queue[i].mob then
local pos = queue[i].pos
for _ = 1, queue[i].group do
pos = {
x = pos.x + random(-3, 3),
y = pos.y,
z = pos.z + random(-3, 3)
}
pos = get_ground_level(pos)
minetest.add_node(pos, {name = "creatura:spawn_node"})
local meta = minetest.get_meta(pos)
meta:set_string("mob", queue[i].mob)
end
end
table.remove(animalia.spawn_queue, i)
end
end
minetest.after(chunk_spawn_queue_int, spawn_queued)
end
minetest.after(chunk_spawn_queue_int, spawn_queued)

20
api/storage.lua Normal file
View file

@ -0,0 +1,20 @@
local mod_storage = minetest.get_mod_storage()
local data = {
spawn_points = minetest.deserialize(mod_storage:get_string("spawn_points")) or {},
}
local function save()
mod_storage:set_string("spawn_points", minetest.serialize(data.spawn_points))
end
minetest.register_on_shutdown(save)
minetest.register_on_leaveplayer(save)
local function periodic_save()
save()
minetest.after(120, periodic_save)
end
minetest.after(120, periodic_save)
return data