Update 0.6.3

This commit is contained in:
ElCeejo 2023-12-28 21:28:05 -08:00
parent 8954aa3493
commit 20c55da709
42 changed files with 1423 additions and 693 deletions

20
.luacheckrc Normal file
View File

@ -0,0 +1,20 @@
max_line_length = 120
globals = {
"minetest",
"VoxelArea",
"mob_core",
"creatura",
"animalia",
"farming",
"mcl_player",
"player_api"
}
read_globals = {
"vector",
"ItemStack",
table = {fields = {"copy"}}
}
ignore = {"212/self", "212/this"}

View File

@ -83,13 +83,13 @@ local function activate_nametag(self)
})
end
local animate_player = {}
animalia.animate_player = {}
if minetest.get_modpath("default")
and minetest.get_modpath("player_api") then
animate_player = player_api.set_animation
animalia.animate_player = player_api.set_animation
elseif minetest.get_modpath("mcl_player") then
animate_player = mcl_player.player_set_animation
animalia.animate_player = mcl_player.player_set_animation
end
-----------------------
@ -100,7 +100,7 @@ function animalia.rotate_to_pitch(self)
local rot = self.object:get_rotation()
if self._anim == "fly" then
local vel = vec_normal(self.object:get_velocity())
local step = math.min(self.dtime * 5, abs(diff(rot.x, vel.y)) % (pi2))
local step = min(self.dtime * 5, abs(diff(rot.x, vel.y)) % (pi2))
local n_rot = interp_angle(rot.x, vel.y, step)
self.object:set_rotation({
x = clamp(n_rot, -0.75, 0.75),
@ -249,8 +249,8 @@ end
function animalia.particle_spawner(pos, texture, type, min_pos, max_pos)
type = type or "float"
min_pos = min_pos or vec_sub(pos, 2)
max_pos = max_pos or vec_add(pos, 2)
min_pos = min_pos or vec_sub(pos, 1)
max_pos = max_pos or vec_add(pos, 1)
if type == "float" then
minetest.add_particlespawner({
amount = 16,
@ -384,6 +384,7 @@ function animalia.set_nametag(self, clicker)
end
function animalia.initialize_api(self)
-- Set Gender
self.gender = self:recall("gender") or nil
if not self.gender then
local genders = {"male", "female"}
@ -391,10 +392,14 @@ function animalia.initialize_api(self)
-- Reset Texture ID
self.texture_no = nil
end
-- Taming/Breeding
self.food = self:recall("food") or 0
self.gotten = self:recall("gotten") or false
self.breeding = false
self.breeding_cooldown = self:recall("breeding_cooldown") or 0
-- Textures/Scale
activate_nametag(self)
if self.growth_scale then
self:memorize("growth_scale", self.growth_scale) -- This is for spawning children
@ -580,12 +585,11 @@ function animalia.mount(self, player, params)
})
player:set_eye_offset()
if minetest.get_modpath("player_api") then
animate_player(player, "stand", 30)
animalia.animate_player(player, "stand", 30)
if player_api.player_attached then
player_api.player_attached[plyr_name] = false
end
end
self.rider = nil
return
end
if minetest.get_modpath("player_api") then
@ -593,10 +597,10 @@ function animalia.mount(self, player, params)
end
self.rider = player
player:set_attach(self.object, "Torso", params.pos, params.rot)
player:set_eye_offset({x = 0, y = 25, z = 0}, {x = 0, y = 15, z = 15})
player:set_eye_offset({x = 0, y = 20, z = 5}, {x = 0, y = 15, z = 15})
self:clear_utility()
minetest.after(0.4, function()
animate_player(player, "sit" , 30)
animalia.animate_player(player, "sit" , 30)
end)
end
@ -630,6 +634,18 @@ function animalia.eat_crop(self, pos)
return true
end
function animalia.eat_turf(mob, pos)
for name, sub_name in pairs(mob.consumable_nodes) do
if minetest.get_node(pos).name == name then
--add_break_particle(turf_pos)
minetest.set_node(pos, {name = sub_name})
mob.collected = mob:memorize("collected", false)
--creatura.action_idle(mob, 1, "eat")
return true
end
end
end
--------------
-- Spawning --
--------------

File diff suppressed because it is too large Load Diff

View File

@ -447,6 +447,8 @@ minetest.register_craftitem("animalia:libri_animalia", {
description = "Libri Animalia",
inventory_image = "animalia_libri_animalia.png",
stack_max = 1,
groups = {book = 1},
on_place = function(itemstack, player)
local meta = itemstack:get_meta()
if meta:get_string("pages") ~= "" then meta:set_string("pages", "") end

View File

@ -2,7 +2,9 @@
-- Spawning --
--------------
local function is_value_in_table(tbl, val)
local random = math.random
local function table_contains(tbl, val)
for _, v in pairs(tbl) do
if v == val then
return true
@ -11,13 +13,13 @@ local function is_value_in_table(tbl, val)
return false
end
local common_spawn_chance = tonumber(minetest.settings:get("animalia_common_chance")) or 30000
local common_spawn_chance = tonumber(minetest.settings:get("animalia_common_chance")) or 45000
local ambient_spawn_chance = tonumber(minetest.settings:get("animalia_ambient_chance")) or 6000
local ambient_spawn_chance = tonumber(minetest.settings:get("animalia_ambient_chance")) or 9000
local pest_spawn_chance = tonumber(minetest.settings:get("animalia_pest_chance")) or 2000
local pest_spawn_chance = tonumber(minetest.settings:get("animalia_pest_chance")) or 3000
local predator_spawn_chance = tonumber(minetest.settings:get("animalia_predator_chance")) or 30000
local predator_spawn_chance = tonumber(minetest.settings:get("animalia_predator_chance")) or 45000
-- Get Biomes --
@ -44,6 +46,9 @@ end)
creatura.register_abm_spawn("animalia:chicken", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 3,
@ -62,9 +67,11 @@ creatura.register_abm_spawn("animalia:cat", {
neighbors = {"group:wood"}
})
creatura.register_abm_spawn("animalia:cow", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 3,
@ -86,6 +93,9 @@ creatura.register_abm_spawn("animalia:fox", {
creatura.register_abm_spawn("animalia:horse", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 3,
@ -119,6 +129,9 @@ creatura.register_abm_spawn("animalia:owl", {
creatura.register_abm_spawn("animalia:pig", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 2,
@ -129,6 +142,9 @@ creatura.register_abm_spawn("animalia:pig", {
creatura.register_abm_spawn("animalia:reindeer", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 6,
@ -139,6 +155,9 @@ creatura.register_abm_spawn("animalia:reindeer", {
creatura.register_abm_spawn("animalia:sheep", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 3,
@ -150,6 +169,9 @@ creatura.register_abm_spawn("animalia:sheep", {
creatura.register_abm_spawn("animalia:turkey", {
chance = common_spawn_chance,
chance_on_load = 64,
spawn_active = true,
spawn_on_load = true,
min_height = 0,
max_height = 1024,
min_group = 3,
@ -234,12 +256,12 @@ creatura.register_on_spawn("animalia:frog", function(self, pos)
local biome_data = minetest.get_biome_data(pos)
local biome_name = minetest.get_biome_name(biome_data.biome)
if is_value_in_table(animalia.registered_biome_groups["tropical"].biomes, biome_name) then
if table_contains(animalia.registered_biome_groups["tropical"].biomes, biome_name) then
self:set_mesh(3)
elseif is_value_in_table(animalia.registered_biome_groups["temperate"].biomes, biome_name)
or is_value_in_table(animalia.registered_biome_groups["boreal"].biomes, biome_name) then
elseif table_contains(animalia.registered_biome_groups["temperate"].biomes, biome_name)
or table_contains(animalia.registered_biome_groups["boreal"].biomes, biome_name) then
self:set_mesh(1)
elseif is_value_in_table(animalia.registered_biome_groups["grassland"].biomes, biome_name) then
elseif table_contains(animalia.registered_biome_groups["grassland"].biomes, biome_name) then
self:set_mesh(2)
else
self.object:remove()
@ -259,3 +281,94 @@ creatura.register_abm_spawn("animalia:tropical_fish", {
nodes = {"group:water"},
neighbors = {"group:coral"}
})
-- World Gen Spawning
minetest.register_node("animalia:spawner", {
description = "???",
drawtype = "airlike",
walkable = false,
pointable = false,
sunlight_propagates = true,
groups = {oddly_breakable_by_hand = 1, not_in_creative_inventory = 1}
})
minetest.register_decoration({
name = "animalia:world_gen_spawning",
deco_type = "simple",
place_on = {"group:stone", "group:sand", "group:soil"},
sidelen = 1,
fill_ratio = 0.0001, -- One node per chunk
decoration = "animalia:spawner"
})
local function do_on_spawn(pos, obj)
local name = obj and obj:get_luaentity().name
if not name then return end
local spawn_functions = creatura.registered_on_spawns[name] or {}
if #spawn_functions > 0 then
for _, func in ipairs(spawn_functions) do
func(obj:get_luaentity(), pos)
if not obj:get_yaw() then break end
end
end
end
minetest.register_abm({
label = "[animalia] World Gen Spawning",
nodenames = {"animalia:spawner"},
interval = 10, -- TODO: Set this to 1 if world is singleplayer and just started
chance = 16,
action = function(pos, _, active_object_count)
minetest.remove_node(pos)
if active_object_count > 8 then return end
local spawnable_mobs = {}
local current_biome = minetest.get_biome_name(minetest.get_biome_data(pos).biome)
local spawn_definitions = creatura.registered_mob_spawns
for mob, def in pairs(spawn_definitions) do
if mob:match("^animalia:")
and def.biomes
and table_contains(def.biomes, current_biome) then
table.insert(spawnable_mobs, mob)
end
end
if #spawnable_mobs > 0 then
local mob_to_spawn = spawnable_mobs[math.random(#spawnable_mobs)]
local spawn_definition = creatura.registered_mob_spawns[mob_to_spawn]
local group_size = random(spawn_definition.min_group or 1, spawn_definition.max_group or 1)
local obj
if group_size > 1 then
local offset
local spawn_pos
for _ = 1, group_size do
offset = group_size * 0.5
spawn_pos = creatura.get_ground_level({
x = pos.x + random(-offset, offset),
y = pos.y,
z = pos.z + random(-offset, offset)
}, 3)
if not creatura.is_pos_moveable(spawn_pos, 0.5, 0.5) then
spawn_pos = pos
end
obj = minetest.add_entity(spawn_pos, mob_to_spawn)
do_on_spawn(spawn_pos, obj)
end
else
obj = minetest.add_entity(pos, mob_to_spawn)
do_on_spawn(pos, obj)
end
end
end
})

View File

@ -3,11 +3,20 @@ local mod_storage = minetest.get_mod_storage()
local data = {
spawn_points = minetest.deserialize(mod_storage:get_string("spawn_points")) or {},
libri_font_size = minetest.deserialize(mod_storage:get_string("libri_font_size")) or {},
bound_horse = minetest.deserialize(mod_storage:get_string("bound_horse")) or {}
}
local function save()
mod_storage:set_string("spawn_points", minetest.serialize(data.spawn_points))
mod_storage:set_string("libri_font_size", minetest.serialize(data.libri_font_size))
for name, bound_data in pairs(data.bound_horse) do
if bound_data
and bound_data.obj then
data.bound_horse[name].obj = nil
end
end
mod_storage:set_string("bound_horse", minetest.serialize(data.bound_horse))
end
minetest.register_on_shutdown(save)

View File

@ -6,6 +6,7 @@ local storage = dofile(path .. "/api/storage.lua")
animalia.spawn_points = storage.spawn_points
animalia.libri_font_size = storage.libri_font_size
animalia.bound_horse = storage.bound_horse
animalia.pets = {}
@ -79,12 +80,10 @@ minetest.register_on_mods_loaded(function()
or minetest.get_item_group(name, "food_wheat") > 0)
and not name:find("seed") then
table.insert(animalia.food_wheat, name)
return
end
if name:match(":seed_")
or name:match("_seed") then
table.insert(animalia.food_seeds, name)
return
end
end
end)
@ -105,6 +104,7 @@ animalia.animals = {
"animalia:fox",
"animalia:frog",
"animalia:horse",
"animalia:opossum",
"animalia:owl",
"animalia:pig",
"animalia:rat",

View File

@ -63,8 +63,10 @@ creatura.register_mob("animalia:chicken", {
{name = "animalia:feather", min = 1, max = 3, chance = 2}
},
-- Behavior Parameters
is_herding_mob = true,
-- Animalia Props
group_wander = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,

View File

@ -2,9 +2,6 @@
-- Cow --
---------
local random = math.random
creatura.register_mob("animalia:cow", {
-- Engine Props
visual_size = {x = 10, y = 10},
@ -65,7 +62,7 @@ creatura.register_mob("animalia:cow", {
},
animations = {
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 71, y = 89}, speed = 20, frame_blend = 0.3, loop = true},
walk = {range = {x = 71, y = 89}, speed = 15, frame_blend = 0.3, loop = true},
run = {range = {x = 71, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
},
follow = animalia.food_wheat,
@ -75,6 +72,10 @@ creatura.register_mob("animalia:cow", {
},
fancy_collide = false,
-- Behavior Parameters
is_grazing_mob = true,
is_herding_mob = true,
-- Animalia Props
flee_puncher = true,
catch_with_net = true,
@ -100,16 +101,6 @@ creatura.register_mob("animalia:cow", {
return 0.1, {self}
end
},
{
utility = "animalia:eat_turf",
step_delay = 0.25,
get_score = function(self)
if random(64) < 2 then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
@ -183,7 +174,7 @@ creatura.register_mob("animalia:cow", {
if inv:room_for_item("main", {name = "animalia:bucket_milk"}) then
clicker:get_inventory():add_item("main", "animalia:bucket_milk")
else
local pos = self:get_pos("floor")
local pos = self.object:get_pos()
pos.y = pos.y + 0.5
minetest.add_item(pos, {name = "animalia:bucket_milk"})
end

View File

@ -77,8 +77,10 @@ creatura.register_mob("animalia:fox", {
"animalia:poultry_raw"
},
-- Behavior Parameters
is_skittish_mob = true,
-- Animalia Props
skittish_wander = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,

View File

@ -5,9 +5,79 @@
local random = math.random
local vec_add = vector.add
local vec_dir = vector.direction
local vec_dist = vector.distance
local vec_sub = vector.subtract
local dir2yaw = minetest.dir_to_yaw
local function get_food_pos(self)
local _, pos = animalia.get_dropped_food(self)
return pos
end
local function eat_dropped_food(self)
local pos = self.object:get_pos()
if not pos then return end
local food = animalia.get_dropped_food(self, nil, self.width + 1)
local food_ent = food and food:get_luaentity()
if food_ent then
local food_pos = food:get_pos()
local stack = ItemStack(food_ent.itemstring)
if stack
and stack:get_count() > 1 then
stack:take_item()
food_ent.itemstring = stack:to_string()
else
food:remove()
end
self.object:set_yaw(dir2yaw(vec_dir(pos, food_pos)))
animalia.add_food_particle(self, stack:get_name())
if self.on_eat_drop then
self:on_eat_drop()
end
return true
end
end
local function get_bug_pos(self)
local pos = self.object:get_pos()
if not pos then return end
local food = minetest.find_nodes_in_area(
vec_sub(pos, 3),
vec_add(pos, 3),
self.follow
) or {}
return #food > 0 and food[1]
end
local function eat_bug(self)
local pos = self.object:get_pos()
if not pos then return end
local bug = get_bug_pos(self)
if not bug then return end
local dir = vec_dir(pos, bug)
local dist = vec_dist(pos, bug)
local frame = math.floor(dist * 10)
self.object:set_yaw(dir2yaw(dir))
animalia.move_head(self, dir2yaw(dir), dir.y)
creatura.action_idle(self, 0.4, "tongue_" .. frame)
minetest.remove_node(bug)
return true
end
local function poison_effect(object)
object:punch(object, 1.0, {
full_punch_interval = 1.0,
@ -67,15 +137,10 @@ local utility_stacks = {
end
},
{
utility = "animalia:eat_bug",
utility = "animalia:walk_to_pos_and_interact",
get_score = function(self)
local pos = self.object:get_pos()
if not pos then return end
if random(12) < 2 then
local food = minetest.find_nodes_in_area(vec_sub(pos, 1.5), vec_add(pos, 1.5), self.follow)
if food[1] then
return 0.3, {self, food[1]}
end
if math.random(2) < 2 then
return 0.3, {self, get_bug_pos, eat_bug, nil, 0}
end
return 0
end
@ -158,22 +223,16 @@ local utility_stacks = {
end
},
{
utility = "animalia:walk_to_food",
utility = "animalia:walk_to_pos_and_interact",
get_score = function(self)
local cooldown = self.eat_cooldown or 0
if cooldown > 0 then
self.eat_cooldown = cooldown - 1
return 0
end
local food_item = animalia.get_dropped_food(self)
if food_item then
return 0.3, {self, food_item}
if math.random(8) < 2 then
return 0.3, {self, get_food_pos, eat_dropped_food, nil, 12}
end
return 0
end
},
{
utility = "animalia:warn_attack_target",
utility = "animalia:attack_target",
get_score = function(self)
local target = creatura.get_nearby_player(self) or creatura.get_nearby_object(self, "animalia:rat")
if target then
@ -330,6 +389,18 @@ local head_data = {
}
}
local follow = {
{
"butterflies:butterfly_white",
"butterflies:butterfly_violet",
"butterflies:butterfly_red"
},
{
"animalia:rat_raw"
},
{}
}
creatura.register_mob("animalia:frog", {
-- Engine Props
visual_size = {x = 10, y = 10},
@ -374,9 +445,7 @@ creatura.register_mob("animalia:frog", {
height = 0.3
},
animations = {},
follow = {
"animalia:rat_raw"
},
follow = {},
drops = {},
fancy_collide = false,
bouyancy_multiplier = 0,
@ -431,6 +500,7 @@ creatura.register_mob("animalia:frog", {
end
elseif mesh_no == 2 then
self.object:set_armor_groups({fleshy = 50})
self.warn_before_attack = true
end
end,
@ -441,6 +511,10 @@ creatura.register_mob("animalia:frog", {
if self:timer(random(5, 15)) then
self:play_sound("random")
end
if not self.mesh_vars_set then
self.follow = follow[self.mesh_no]
end
end,
death_func = function(self)

View File

@ -4,18 +4,110 @@
local random = math.random
local follows = {}
-- Horse Inventory
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_items) do
if (name:match(":wheat")
or minetest.get_item_group(name, "food_wheat") > 0)
and not name:find("seed") then
table.insert(follows, name)
local form_obj = {}
local function create_horse_inventory(self)
if not self.owner then return end
local inv_name = "animalia:horse_" .. self.owner
local inv = minetest.create_detached_inventory(inv_name, {
allow_move = function(_, _, _, _, _, count)
return count
end,
allow_put = function(_, _, _, stack)
return stack:get_count()
end,
allow_take = function(_, _, _, stack)
return stack:get_count()
end
})
inv:set_size("main", 12)
inv:set_width("main", 4)
return inv
end
local function serialize_horse_inventory(self)
if not self.owner then return end
local inv_name = "animalia:horse_" .. self.owner
local inv = minetest.get_inventory({type = "detached", name = inv_name})
if not inv then return end
local list = inv:get_list("main")
local stored = {}
for k, item in ipairs(list) do
local itemstr = item:to_string()
if itemstr ~= "" then
stored[k] = itemstr
end
end
self._inventory = self:memorize("_inventory", minetest.serialize(stored))
end
local function get_form(self, player_name)
local inv = create_horse_inventory(self)
if inv
and self._inventory then
inv:set_list("main", minetest.deserialize(self._inventory))
end
local frame_range = self.animations["stand"].range
local frame_loop = frame_range.x .. "," .. frame_range.y
local texture = self:get_props().textures[1]
local form = {
"formspec_version[3]",
"size[10.5,10]",
"image[0,0;10.5,5.25;animalia_form_horse_bg.png]",
"model[0,0.5;5,3.5;mob_mesh;animalia_horse.b3d;" .. texture .. ";-10,-130;false;false;" .. frame_loop .. ";15]",
"list[detached:animalia:horse_" .. player_name .. ";main;5.4,0.5;4,3;]",
"list[current_player;main;0.4,4.9;8,4;]",
"listring[current_player;main]"
}
return table.concat(form, "")
end
local function close_form(player)
local name = player:get_player_name()
if form_obj[name] then
form_obj[name] = nil
minetest.remove_detached_inventory("animalia:horse_" .. name)
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local name = player:get_player_name()
if not form_obj[name] or not form_obj[name]:get_yaw() then
return
end
local obj = form_obj[name]
if formname == "animalia:horse_forms" then
local ent = obj and obj:get_luaentity()
if not ent then return end
if fields.quit or fields.key_enter then
form_obj[name] = nil
serialize_horse_inventory(ent)
minetest.remove_detached_inventory("animlaia:horse_" .. name)
end
end
if formname == "animalia:horse_inv" then
local ent = obj and obj:get_luaentity()
if not ent then return end
if fields.quit or fields.key_enter then
form_obj[name] = nil
serialize_horse_inventory(ent)
minetest.remove_detached_inventory("animalia:horse_" .. name)
end
end
end)
minetest.register_on_leaveplayer(close_form)
-- Pattern
local patterns = {
"animalia_horse_pattern_1.png",
"animalia_horse_pattern_2.png",
@ -26,11 +118,11 @@ local avlbl_colors = {
[1] = {
"animalia_horse_2.png",
"animalia_horse_3.png",
"animalia_horse_6.png"
"animalia_horse_5.png"
},
[2] = {
"animalia_horse_1.png",
"animalia_horse_6.png"
"animalia_horse_5.png"
},
[3] = {
"animalia_horse_2.png",
@ -43,10 +135,6 @@ local avlbl_colors = {
[5] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
},
[6] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
}
}
@ -71,6 +159,8 @@ local function set_pattern(self)
})
end
-- Definition
creatura.register_mob("animalia:horse", {
-- Engine Props
visual_size = {x = 10, y = 10},
@ -80,8 +170,7 @@ creatura.register_mob("animalia:horse", {
"animalia_horse_2.png",
"animalia_horse_3.png",
"animalia_horse_4.png",
"animalia_horse_5.png",
"animalia_horse_6.png"
"animalia_horse_5.png"
},
makes_footstep_sound = true,
@ -119,20 +208,23 @@ creatura.register_mob("animalia:horse", {
},
animations = {
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 71, y = 89}, speed = 25, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 89}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
punch_aoe = {range = {x = 161, y = 180}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 131, y = 150}, speed = 20, frame_blend = 0.2, loop = false},
eat = {range = {x = 191, y = 220}, speed = 30, frame_blend = 0.3, loop = false}
punch_aoe = {range = {x = 170, y = 205}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 130, y = 160}, speed = 20, frame_blend = 0.2, loop = false},
eat = {range = {x = 210, y = 240}, speed = 30, frame_blend = 0.3, loop = false}
},
follow = follows,
follow = animalia.food_wheat,
drops = {
{name = "animalia:leather", min = 1, max = 4, chance = 2}
},
fancy_collide = false,
-- Behavior Parameters
is_grazing_mob = true,
is_herding_mob = true,
-- Animalia Props
group_wander = true,
catch_with_net = true,
catch_with_lasso = true,
consumable_nodes = {
@ -141,8 +233,8 @@ creatura.register_mob("animalia:horse", {
},
head_data = {
bone = "Neck.CTRL",
offset = {x = 0, y = 1.05, z = 0.0},
pitch_correction = 35,
offset = {x = 0, y = 1.4, z = 0.0},
pitch_correction = 15,
pivot_h = 1,
pivot_v = 1.75
},
@ -154,16 +246,6 @@ creatura.register_mob("animalia:horse", {
return 0.1, {self}
end
},
{
utility = "animalia:eat_turf",
step_delay = 0.25,
get_score = function(self)
if random(64) < 2 then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
@ -187,19 +269,19 @@ creatura.register_mob("animalia:horse", {
end
},
{
utility = "animalia:flee_from_target_defend",
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._puncher
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
return 0.6, {self, puncher, true}
end
self._puncher = nil
return 0
end
},
{
utility = "animalia:tame_horse",
utility = "animalia:horse_taming",
get_score = function(self)
local rider = not self.owner and self.rider
if rider
@ -212,6 +294,7 @@ creatura.register_mob("animalia:horse", {
{
utility = "animalia:mount_horse",
get_score = function(self)
if not self.owner then return 0 end
local owner = self.owner and minetest.get_player_by_name(self.owner)
local rider = owner == self.rider and self.rider
if rider
@ -280,7 +363,13 @@ creatura.register_mob("animalia:horse", {
animalia.initialize_api(self)
animalia.initialize_lasso(self)
set_pattern(self)
self.owner = self:recall("owner") or nil
if self.owner then
self._inventory = self:recall("_inventory")
end
self.rider = nil
self.saddled = self:recall("saddled") or false
self.max_health = self:recall("max_health") or random(30, 45)
@ -300,6 +389,11 @@ creatura.register_mob("animalia:horse", {
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
animalia.random_sound(self)
if self.owner
and animalia.bound_horse[self.owner] then
animalia.bound_horse[self.owner].last_pos = self.object:get_pos()
end
end,
death_func = function(self)
@ -315,22 +409,31 @@ creatura.register_mob("animalia:horse", {
if animalia.feed(self, clicker, false, true) then
return
end
local owner = self.owner
local name = clicker and clicker:get_player_name()
if owner and name ~= owner then return end
if animalia.set_nametag(self, clicker) then
return
end
local wielded_name = clicker:get_wielded_item():get_name()
if wielded_name == "" then
animalia.mount(self, clicker, {rot = {x = -75, y = 180, z = 0}, pos = {x = 0, y = 0.6, z = 0.5}})
if wielded_name == "animalia:saddle" then
self:set_saddle(true)
return
end
if clicker:get_player_control().sneak
and owner then
minetest.show_formspec(name, "animalia:horse_forms", get_form(self, name))
form_obj[name] = self.object
elseif wielded_name == "" then
animalia.mount(self, clicker, {rot = {x = -65, y = 180, z = 0}, pos = {x = 0, y = 0.75, z = 0.6}})
if self.saddled then
self:initiate_utility("animalia:mount", self, clicker)
end
return
end
if wielded_name == "animalia:saddle" then
self:set_saddle(true)
end
end,
@ -344,6 +447,16 @@ creatura.register_mob("animalia:horse", {
return
end
animalia.punch(self, puncher, ...)
end,
on_detach_child = function(self, child)
if child
and self.rider == child then
self.rider = nil
child:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
child:set_properties({visual_size = {x = 1, y = 1}})
animalia.animate_player(child, "stand", 30)
end
end
})

212
mobs/opossum.lua Normal file
View File

@ -0,0 +1,212 @@
---------
-- Fox --
---------
local vec_dir, vec_dist = vector.direction, vector.distance
local dir2yaw = minetest.dir_to_yaw
local function get_food_pos(self)
local _, pos = animalia.get_dropped_food(self)
return pos
end
local function eat_dropped_food(self)
local pos = self.object:get_pos()
if not pos then return end
local food = animalia.get_dropped_food(self, nil, self.width + 1)
local food_ent = food and food:get_luaentity()
if food_ent then
local food_pos = food:get_pos()
local stack = ItemStack(food_ent.itemstring)
if stack
and stack:get_count() > 1 then
stack:take_item()
food_ent.itemstring = stack:to_string()
else
food:remove()
end
self.object:set_yaw(dir2yaw(vec_dir(pos, food_pos)))
animalia.add_food_particle(self, stack:get_name())
if self.on_eat_drop then
self:on_eat_drop()
end
return true
end
end
creatura.register_mob("animalia:opossum", {
-- Engine Props
visual_size = {x = 10, y = 10},
mesh = "animalia_opossum.b3d",
textures = {
"animalia_opossum.png"
},
makes_footstep_sound = false,
-- Creatura Props
max_health = 5,
armor_groups = {fleshy = 100},
damage = 2,
speed = 4,
tracking_range = 16,
max_boids = 0,
despawn_after = 500,
stepheight = 1.1,
sound = {},
hitbox = {
width = 0.25,
height = 0.4
},
animations = {
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 100, y = 119}, speed = 45, frame_blend = 0.3, loop = true},
feint = {range = {x = 130, y = 130}, speed = 45, frame_blend = 0.3, loop = false}
},
follow = {
"animalia:song_bird_egg",
"animalia:rat_raw",
"animalia:mutton_raw",
"animalia:beef_raw",
"animalia:porkchop_raw",
"animalia:poultry_raw"
},
-- Behavior Parameters
is_skittish_mob = true,
-- Animalia Props
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
head_data = {
offset = {x = 0, y = 0.18, z = 0},
pitch_correction = -67,
pivot_h = 0.65,
pivot_v = 0.65
},
-- Functions
utility_stack = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.3, {self}
end
return 0
end
},
{
utility = "animalia:attack_target",
get_score = function(self)
local target = self._target or creatura.get_nearby_object(self, {"animalia:rat"})
local tgt_pos = target and target:get_pos()
if tgt_pos
and self:is_pos_safe(tgt_pos) then
return 0.4, {self, target}
end
return 0
end
},
{
utility = "animalia:idle",
get_score = function(self)
local target = self._puncher or creatura.get_nearby_player(self)
local pos, tgt_pos = self.object:get_pos(), target and target:get_pos()
if not pos then return end
if not tgt_pos then self._puncher = nil return 0 end
local sneaking = target:get_player_control().sneak
if not sneaking then
local dist = vec_dist(pos, tgt_pos)
local score = (self.tracking_range - dist) / self.tracking_range
self._puncher = target
return score / 3, {self, 5, "feint"}
end
self._puncher = nil
return 0
end
},
{
utility = "animalia:walk_to_pos_and_interact",
get_score = function(self)
if math.random(14) < 2 then
return 0.7, {self, get_food_pos, eat_dropped_food, nil, 12}
end
return 0
end
},
{
utility = "animalia:follow_player",
get_score = function(self)
local lasso_tgt = self._lassod_to
local lasso = type(lasso_tgt) == "string" and minetest.get_player_by_name(lasso_tgt)
if lasso
and lasso:get_pos() then
return 0.6, {self, lasso, true}
end
return 0
end
},
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name) then
return 0.7, {self}
end
return 0
end
}
},
on_eat_drop = function(self)
animalia.protect_from_despawn(self)
end,
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
end,
step_func = function(self)
animalia.step_timers(self)
animalia.head_tracking(self, 0.5, 0.75)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
end,
death_func = animalia.death_func,
on_rightclick = function(self, clicker)
if animalia.feed(self, clicker, true, true) then
return
end
if animalia.set_nametag(self, clicker) then
return
end
end,
on_punch = animalia.punch
})
creatura.register_spawn_item("animalia:opossum", {
col1 = "d0602d",
col2 = "c9c9c9"
})

View File

@ -4,8 +4,46 @@
local abs = math.abs
local vec_dir = vector.direction
local vec_dist = vector.distance
local dir2yaw = minetest.dir_to_yaw
local function get_food_pos(self)
local _, pos = animalia.get_dropped_food(self)
return pos
end
local function eat_dropped_food(self)
local pos = self.object:get_pos()
if not pos then return end
local food = animalia.get_dropped_food(self, nil, self.width + 1)
local food_ent = food and food:get_luaentity()
if food_ent then
local food_pos = food:get_pos()
local stack = ItemStack(food_ent.itemstring)
if stack
and stack:get_count() > 1 then
stack:take_item()
food_ent.itemstring = stack:to_string()
else
food:remove()
end
self.object:set_yaw(dir2yaw(vec_dir(pos, food_pos)))
animalia.add_food_particle(self, stack:get_name())
if self.on_eat_drop then
self:on_eat_drop()
end
return true
end
end
local function get_home_pos(self)
local pos = self.object:get_pos()
if not pos then return end
@ -128,16 +166,10 @@ creatura.register_mob("animalia:owl", {
end
},
{
utility = "animalia:fly_to_food",
utility = "animalia:fly_to_pos_and_interact",
get_score = function(self)
local cooldown = self.eat_cooldown or 0
if cooldown > 0 then
self.eat_cooldown = cooldown - 1
return 0
end
local food_item = animalia.get_dropped_food(self, "animalia:rat_raw")
if food_item then
return 0.3, {self, food_item}
if math.random(1) < 2 then
return 0.3, {self, get_food_pos, eat_dropped_food, nil, 12}
end
return 0
end

View File

@ -61,6 +61,9 @@ creatura.register_mob("animalia:pig", {
{name = "animalia:porkchop_raw", min = 1, max = 3, chance = 1}
},
-- Behavior Parameters
is_herding_mob = true,
-- Animalia Props
flee_puncher = true,
catch_with_net = true,

View File

@ -75,6 +75,9 @@ creatura.register_mob("animalia:rat", {
{name = "animalia:rat_raw", min = 1, max = 1, chance = 1}
},
-- Behavior Parameters
is_skittish_mob = true,
-- Animalia Props
flee_puncher = true,
catch_with_net = true,

View File

@ -2,8 +2,6 @@
-- Reindeer --
--------------
local random = math.random
creatura.register_mob("animalia:reindeer", {
-- Engine Props
visual_size = {x = 10, y = 10},
@ -20,7 +18,23 @@ creatura.register_mob("animalia:reindeer", {
max_boids = 4,
despawn_after = 500,
stepheight = 1.1,
--sound = {},
sounds = {
random = {
name = "animalia_reindeer",
gain = 0.5,
distance = 8
},
hurt = {
name = "animalia_reindeer_hurt",
gain = 0.5,
distance = 8
},
death = {
name = "animalia_reindeer_death",
gain = 0.5,
distance = 8
}
},
hitbox = {
width = 0.45,
height = 0.9
@ -37,8 +51,11 @@ creatura.register_mob("animalia:reindeer", {
{name = "animalia:leather", min = 1, max = 3, chance = 2}
},
-- Behavior Parameters
is_grazing_mob = true,
is_herding_mob = true,
-- Animalia Props
group_wander = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
@ -53,7 +70,7 @@ creatura.register_mob("animalia:reindeer", {
}
},
head_data = {
offset = {x = 0, y = 0.7, z = 0},
offset = {x = 0, y = 0.55, z = 0},
pitch_correction = -45,
pivot_h = 1,
pivot_v = 1
@ -68,16 +85,6 @@ creatura.register_mob("animalia:reindeer", {
return 0.1, {self}
end
},
{
utility = "animalia:eat_turf",
step_delay = 0.25,
get_score = function(self)
if random(64) < 2 then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
@ -113,6 +120,7 @@ creatura.register_mob("animalia:reindeer", {
animalia.head_tracking(self)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
animalia.random_sound(self)
end,
death_func = animalia.death_func,

View File

@ -66,8 +66,8 @@ creatura.register_mob("animalia:sheep", {
},
animations = {
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 100, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 89}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 100, y = 119}, speed = 30, frame_blend = 0.3, loop = true},
eat = {range = {x = 130, y = 150}, speed = 20, frame_blend = 0.3, loop = false}
},
follow = animalia.food_wheat,
@ -76,8 +76,11 @@ creatura.register_mob("animalia:sheep", {
minetest.get_modpath("wool") and {name = "wool:white", min = 1, max = 3, chance = 2} or nil
},
-- Behavior Parameters
is_grazing_mob = true,
is_herding_mob = true,
-- Animalia Props
group_wander = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
@ -101,16 +104,6 @@ creatura.register_mob("animalia:sheep", {
return 0.1, {self}
end
},
{
utility = "animalia:eat_turf",
step_delay = 0.25,
get_score = function(self)
if random(64) < 2 then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
@ -177,7 +170,7 @@ creatura.register_mob("animalia:sheep", {
local tool = clicker:get_wielded_item()
local tool_name = tool:get_name()
local creative = minetest.is_creative_enabled(clicker)
local creative = minetest.is_creative_enabled(clicker:get_player_name())
if tool_name == "animalia:shears" then
if not minetest.get_modpath("wool") then

View File

@ -29,7 +29,7 @@ creatura.register_mob("animalia:tropical_fish", {
max_boids = 6,
boid_seperation = 0.3,
despawn_after = 200,
max_fall = 3,
max_fall = 0,
stepheight = 1.1,
hitbox = {
width = 0.15,
@ -39,7 +39,11 @@ creatura.register_mob("animalia:tropical_fish", {
swim = {range = {x = 1, y = 20}, speed = 20, frame_blend = 0.3, loop = true},
flop = {range = {x = 30, y = 40}, speed = 20, frame_blend = 0.3, loop = true},
},
bouyancy_multiplier = 0,
liquid_submergence = 1,
liquid_drag = 0,
-- Animalia Behaviors
is_aquatic_mob = true,
-- Animalia Props
flee_puncher = false,
@ -54,18 +58,7 @@ creatura.register_mob("animalia:tropical_fish", {
get_score = function(self)
return 0.1, {self}
end
},
{
utility = "animalia:flop",
step_delay = 0.25,
get_score = function(self)
if not self.in_liquid then
self:hurt(1)
return 1, {self}
end
return 0
end
},
}
},
activate_func = function(self)

View File

@ -75,8 +75,11 @@ creatura.register_mob("animalia:wolf", {
},
follow = follow,
-- Behavior Parameters
is_skittish_mob = true,
is_herding_mob = true,
-- Animalia Props
skittish_wander = true,
assist_owner = true,
flee_puncher = false,
catch_with_net = true,

Binary file not shown.

BIN
models/animalia_opossum.b3d Normal file

Binary file not shown.

Binary file not shown.

BIN
sounds/morbiu.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

20
storage.lua Normal file
View File

@ -0,0 +1,20 @@
local mod_storage = minetest.get_mod_storage()
local data = {
bound_horse = minetest.deserialize(mod_storage:get_string("bound_horse")) or {},
}
local function save()
mod_storage:set_string("bound_horse", minetest.serialize(data.bound_horse))
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB