This commit is contained in:
ElCeejo 2022-08-12 22:17:42 -07:00
parent 78e7b8bb44
commit eccc33cea5
108 changed files with 4818 additions and 5250 deletions

View file

@ -16,10 +16,41 @@ end)
-- Math --
local pi = math.pi
local random = math.random
local abs = math.abs
local atan2 = math.atan2
local cos = math.cos
local deg = math.deg
local min = math.min
local pi = math.pi
local pi2 = pi * 2
local rad = math.rad
local random = math.random
local sin = math.sin
local sqrt = math.sqrt
local function diff(a, b) -- Get difference between 2 angles
return atan2(sin(b - a), cos(b - a))
end
local function interp_angle(a, b, w)
local cs = (1 - w) * cos(a) + w * cos(b)
local sn = (1 - w) * sin(a) + w * sin(b)
return atan2(sn, cs)
end
local function lerp_step(a, b, dtime, rate)
return min(dtime * rate, abs(diff(a, b)) % (pi2))
end
local function clamp(val, _min, _max)
if val < _min then
val = _min
elseif _max < val then
val = _max
end
return val
end
-- Vector Math --
@ -27,6 +58,7 @@ local vec_dir = vector.direction
local vec_add = vector.add
local vec_sub = vector.subtract
local vec_multi = vector.multiply
local vec_normal = vector.normalize
local vec_divide = vector.divide
local vec_len = vector.length
@ -39,9 +71,15 @@ local yaw2dir = minetest.yaw_to_dir
local creative = minetest.settings:get_bool("creative_mode")
---------------------
-- Local Utilities --
---------------------
------------
-- Common --
------------
function animalia.get_average_pos(vectors)
local sum = {x = 0, y = 0, z = 0}
for _, vec in pairs(vectors) do sum = vec_add(sum, vec) end
return vec_divide(sum, #vectors)
end
function animalia.correct_name(str)
if str then
@ -52,9 +90,233 @@ end
local correct_name = animalia.correct_name
----------------------
-- Global Utilities --
----------------------
---------------------
-- Local Utilities --
---------------------
local function activate_nametag(self)
self.nametag = self:recall("nametag") or nil
if not self.nametag then return end
self.object:set_properties({
nametag = self.nametag,
nametag_color = "#FFFFFF"
})
end
local animate_player = {}
if minetest.get_modpath("default")
and minetest.get_modpath("player_api") then
animate_player = player_api.set_animation
elseif minetest.get_modpath("mcl_player") then
animate_player = mcl_player.set_animation
end
-----------------------
-- Dynamic Animation --
-----------------------
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 n_rot = interp_angle(rot.x, vel.y, step)
self.object:set_rotation({
x = clamp(n_rot, -0.75, 0.75),
y = rot.y,
z = rot.z
})
elseif rot.x ~= 0 then
self.object:set_rotation({
x = 0,
y = rot.y,
z = rot.z
})
end
end
function animalia.move_head(self, tyaw, pitch)
local data = self.head_data
if not data then return end
local yaw = self.object:get_yaw()
local pitch_offset = data.pitch_correction or 0
local bone = data.bone or "Head.CTRL"
local _, rot = self.object:get_bone_position(bone)
if not rot then return end
local n_yaw = (tyaw ~= yaw and diff(tyaw, yaw) / 2) or 0
if abs(deg(n_yaw)) > 45 then n_yaw = 0 end
local dir = yaw2dir(n_yaw)
dir.y = pitch or 0
local n_pitch = (sqrt(dir.x^2 + dir.y^2) / dir.z)
if abs(deg(n_pitch)) > 45 then n_pitch = 0 end
if self.dtime then
local yaw_w = lerp_step(rad(rot.z), tyaw, self.dtime, 3)
n_yaw = interp_angle(rad(rot.z), n_yaw, yaw_w)
local rad_offset = rad(pitch_offset)
local pitch_w = lerp_step(rad(rot.x), n_pitch + rad_offset, self.dtime, 3)
n_pitch = interp_angle(rad(rot.x), n_pitch + rad_offset, pitch_w)
end
local pitch_max = pitch_offset + 45
local pitch_min = pitch_offset - 45
self.object:set_bone_position(bone, data.offset,
{x = clamp(deg(n_pitch), pitch_min, pitch_max), y = 0, z = clamp(deg(n_yaw), -45, 45)})
end
function animalia.head_tracking(self)
if not self.head_data then return end
-- Calculate Head Position
local yaw = self.object:get_yaw()
local pos = self.object:get_pos()
if not pos then return end
local y_dir = yaw2dir(yaw)
local offset_h = self.head_data.pivot_h
local offset_v = self.head_data.pivot_v
pos = {
x = pos.x + y_dir.x * offset_h,
y = pos.y + offset_v,
z = pos.z + y_dir.z * offset_h
}
local vel = self.object:get_velocity()
if vec_len(vel) > 2 then
self.head_tracking = nil
animalia.move_head(self, yaw, 0)
return
end
local player = self.head_tracking
local plyr_pos = player and player:get_pos()
if plyr_pos then
plyr_pos.y = plyr_pos.y + 1.4
local dir = vec_dir(pos, plyr_pos)
local tyaw = dir2yaw(dir)
if abs(diff(yaw, tyaw)) > pi / 10
and self._anim == "stand" then
self:turn_to(tyaw, 1)
end
animalia.move_head(self, tyaw, dir.y)
return
elseif self:timer(random(6, 12)) then
local players = creatura.get_nearby_players(self, 6)
self.head_tracking = #players > 0 and players[random(#players)]
end
animalia.move_head(self, yaw, 0)
end
---------------
-- Utilities --
---------------
function animalia.alias_mob(old_mob, new_mob)
minetest.register_entity(":" .. old_mob, {
on_activate = function(self)
local pos = self.object:get_pos()
minetest.add_entity(pos, new_mob)
self.object:remove()
end,
})
end
------------------------
-- Environment Access --
------------------------
function animalia.set_nametag(self, clicker)
local item = clicker:get_wielded_item()
if item
and item:get_name() ~= "animalia:nametag" then
return
end
local name = item:get_meta():get_string("name")
if not name
or name == "" then
return
end
self.nametag = self:memorize("nametag", name)
self.despawn_after = self:memorize("despawn_after", nil)
activate_nametag(self)
if not creative then
item:take_item()
clicker:set_wielded_item(item)
end
return true
end
function animalia.get_group_positions(name, pos, radius)
local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius))
local group = {}
for i = 1, #objects do
local object = objects[i]
if object
and object:get_luaentity()
and object:get_luaentity().name == name then
table.insert(group, object:get_pos())
end
end
return group
end
function animalia.get_group(self)
local pos = self.object:get_pos()
local radius = self.tracking_range
local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius))
local group = {}
for i = 1, #objects do
local object = objects[i]
if object
and object ~= self.object
and object:get_luaentity()
and object:get_luaentity().name == self.name then
table.insert(group, object)
end
end
return group
end
function animalia.get_nearby_mate(self, name)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
for _, object in ipairs(objects) do
if creatura.is_alive(object)
and not object:is_player()
and object:get_luaentity().name == name
and object:get_luaentity().gender ~= self.gender
and object:get_luaentity().breeding then
return object
end
end
end
function animalia.find_collision(self, dir)
local pos = self.object:get_pos()
local pos2 = vec_add(pos, vec_multi(dir, 16))
local ray = minetest.raycast(pos, pos2, false, false)
for pointed_thing in ray do
if pointed_thing.type == "node" then
return pointed_thing.under
end
end
return nil
end
function animalia.random_drop_item(item, chance)
if random(chance) < 2 then
local object = minetest.add_item(ItemStack(item))
object:add_velocity({
x = random(-2, 2),
y = 1.5,
z = random(-2, 2)
})
end
end
function animalia.protect_from_despawn(self)
self._despawn = self:memorize("_despawn", false)
self.despawn_after = self:memorize("despawn_after", false)
end
---------------
-- Particles --
---------------
function animalia.particle_spawner(pos, texture, type, min_pos, max_pos)
type = type or "float"
@ -101,79 +363,17 @@ function animalia.particle_spawner(pos, texture, type, min_pos, max_pos)
end
end
function animalia.get_average_pos(vectors)
local sum = {x = 0, y = 0, z = 0}
for _, vec in pairs(vectors) do sum = vec_add(sum, vec) end
return vec_divide(sum, #vectors)
end
----------------------
-- Entity Utilities --
----------------------
function animalia.get_group_positions(name, pos, radius)
local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius))
local group = {}
for i = 1, #objects do
local object = objects[i]
if object
and object:get_luaentity()
and object:get_luaentity().name == name then
table.insert(group, object:get_pos())
end
end
return group
end
function animalia.get_group(self)
local pos = self.object:get_pos()
local radius = self.tracking_range
local objects = minetest.get_objects_in_area(vec_sub(pos, radius), vec_add(pos, radius))
local group = {}
for i = 1, #objects do
local object = objects[i]
if object
and object ~= self.object
and object:get_luaentity()
and object:get_luaentity().name == self.name then
table.insert(group, object)
end
end
return group
end
function animalia.get_nearby_mate(self, name)
local objects = minetest.get_objects_inside_radius(self:get_center_pos(), self.tracking_range)
for _, object in ipairs(objects) do
if creatura.is_alive(object)
and not object:is_player()
and object:get_luaentity().name == name
and object:get_luaentity().gender ~= self.gender
and object:get_luaentity().breeding then
return object
end
end
end
-------------------
-- Mob Functions --
-------------------
local function activate_nametag(self)
self.nametag = self:recall("nametag") or nil
if not self.nametag then return end
self.object:set_properties({
nametag = self.nametag,
nametag_color = "#FFFFFF"
})
end
--------------
-- Entities --
--------------
function animalia.initialize_api(self)
self.gender = self:recall("gender") or nil
if not self.gender then
local genders = {"male", "female"}
self.gender = self:memorize("gender", genders[random(2)])
-- Reset Texture ID
self.texture_no = nil
end
self.food = self:recall("food") or 0
self.gotten = self:recall("gotten") or false
@ -185,31 +385,34 @@ function animalia.initialize_api(self)
end
self.growth_scale = self:recall("growth_scale") or 1
self:set_scale(self.growth_scale)
if self.growth_scale < 0.8
and self.child_textures then
if not self.texture_no then
self.texture_no = random(#self.child_textures)
local child_textures = self.growth_scale < 0.8 and self.child_textures
local textures = (not child_textures and self[self.gender .. "_textures"]) or self.textures
if child_textures then
if not self.texture_no
or self.texture_no > #child_textures then
self.texture_no = random(#child_textures)
end
self:set_texture(self.texture_no, self.child_textures)
return
elseif self.growth_scale > 0.7
and self.male_textures
and self.female_textures then
self:set_texture(self.texture_no, child_textures)
elseif textures then
if not self.texture_no then
self.texture_no = random(#self[self.gender .. "_textures"])
self.texture_no = random(#textures)
end
self:set_texture(self.texture_no, self[self.gender .. "_textures"])
self:set_texture(self.texture_no, textures)
return
end
end
function animalia.step_timers(self)
self.breeding_cooldown = (self.breeding_cooldown or 30) - self.dtime
local breed_cd = self.breeding_cooldown or 30
local trust_cd = self.trust_cooldown or 0
self.breeding_cooldown = (breed_cd > 0 and breed_cd - self.dtime) or 0
self.trust_cooldown = (trust_cd > 0 and trust_cd - self.dtime) or 0
if self.breeding
and self.breeding_cooldown <= 30 then
self.breeding = false
end
self:memorize("breeding_cooldown", self.breeding_cooldown)
self:memorize("trust_cooldown", self.trust_cooldown)
end
function animalia.do_growth(self, interval)
@ -244,160 +447,14 @@ function animalia.do_growth(self, interval)
end
end
function animalia.set_nametag(self, clicker)
local item = clicker:get_wielded_item()
if item
and item:get_name() ~= "animalia:nametag" then
return
function animalia.add_trust(self, player, amount)
self.trust_cooldown = 60
local plyr_name = player:get_player_name()
local trust = self.trust[plyr_name] or 0
if trust > 4 then return end
self.trust[plyr_name] = trust + (amount or 1)
self:memorize("trust", self.trust)
end
local name = item:get_meta():get_string("name")
if not name
or name == "" then
return
end
self.nametag = self:memorize("nametag", name)
self.despawn_after = self:memorize("despawn_after", nil)
activate_nametag(self)
if not creative then
item:take_item()
clicker:set_wielded_item(item)
end
return true
end
-----------------------
-- Dynamic Animation --
-----------------------
local function clamp_bone_rot(n) -- Fixes issues with bones jittering when yaw clamps
if n < -180 then
n = n + 360
elseif n > 180 then
n = n - 360
end
if n < -60 then
n = -60
elseif n > 60 then
n = 60
end
return n
end
local function interp_bone_rot(a, b, w) -- Smoothens bone movement
if abs(a - b) > deg(pi) then
if a < b then
return ((a + (b - a) * w) + (deg(pi) * 2))
elseif a > b then
return ((a + (b - a) * w) - (deg(pi) * 2))
end
end
return a + (b - a) * w
end
function animalia.move_head(self, tyaw, pitch)
local data = self.head_data
local _, rot = self.object:get_bone_position(data.bone or "Head.CTRL")
local yaw = self.object:get_yaw()
local look_yaw = clamp_bone_rot(deg(yaw - tyaw))
local look_pitch = 0
if pitch then
look_pitch = clamp_bone_rot(deg(pitch))
end
if tyaw ~= yaw then
look_yaw = look_yaw * 0.66
end
yaw = interp_bone_rot(rot.z, look_yaw, 0.1)
local ptch = interp_bone_rot(rot.x, look_pitch + data.pitch_correction, 0.1)
self.object:set_bone_position(data.bone or "Head.CTRL", data.offset, {x = ptch, y = yaw, z = yaw})
end
function animalia.head_tracking(self)
if not self.head_data then return end
local yaw = self.object:get_yaw()
local pos = self.object:get_pos()
local v = vec_add(pos, vec_multi(yaw2dir(yaw), self.head_data.pivot_h))
pos.x = v.x
pos.y = pos.y + self.head_data.pivot_v
pos.z = v.z
--[[minetest.add_particle({
pos = pos,
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
expirationtime = 0.1,
size = 8,
collisiondetection = false,
vertical = false,
texture = "mob_core_green_particle.png",
playername = "singleplayer"
})]]
local vel = self.object:get_velocity()
if abs(yaw - self.last_yaw) < 0.1 then
animalia.move_head(self, yaw)
else
animalia.move_head(self, self._tyaw)
end
if not self.head_tracking
and self:timer(3)
and random(4) < 2 then
local objects = minetest.get_objects_inside_radius(pos, 6)
for _, object in ipairs(objects) do
if object:is_player() then
self.head_tracking = object
break
end
end
else
if not creatura.is_valid(self.head_tracking) then
self.head_tracking = nil
self.head_tracking_turn = nil
return
end
local ppos = self.head_tracking:get_pos()
ppos.y = ppos.y + 1.4
local dir = vec_dir(pos, ppos)
local tyaw = dir2yaw(dir)
if self:timer(1)
and abs(yaw - tyaw) > 1
and abs(yaw - tyaw) < 5.3
and self.head_tracking_turn then
self.head_tracking = nil
self.head_tracking_turn = nil
dir.y = 0
return
elseif not self.head_tracking_turn then
self.head_tracking_turn = tyaw
end
if self.head_tracking_turn
and self._anim == "stand" then
self:turn_to(self.head_tracking_turn, 2)
end
animalia.move_head(self, tyaw, dir.y)
end
end
-----------------------
-- World Interaction --
-----------------------
function animalia.random_drop_item(item, chance)
if random(chance) < 2 then
local object = minetest.add_item(ItemStack(item))
object:add_velocity({
x = random(-2, 2),
y = 1.5,
z = random(-2, 2)
})
end
end
function animalia.protect_from_despawn(self)
self._despawn = self:memorize("_despawn", false)
self.despawn_after = self:memorize("despawn_after", false)
end
------------------------
-- Player Interaction --
------------------------
function animalia.feed(self, player, tame, breed)
local item, item_name = self:follow_wielded_item(player)
@ -448,15 +505,6 @@ function animalia.feed(self, player, tame, breed)
return false
end
local animate_player = {}
if minetest.get_modpath("default")
and minetest.get_modpath("player_api") then
animate_player = player_api.set_animation
elseif minetest.get_modpath("mcl_player") then
animate_player = mcl_player.set_animation
end
function animalia.mount(self, player, params)
if not creatura.is_alive(player) then
return
@ -490,7 +538,8 @@ function animalia.mount(self, player, params)
and player_api then
animate_player(player, "sit", 30)
end
end) self.rider = player
end)
self.rider = player
local mob_size = self.object:get_properties().visual_size
local player_size = player:get_properties().visual_size
player:set_attach(self.object, "Torso", params.pos, params.rot)
@ -500,37 +549,7 @@ function animalia.mount(self, player, params)
y = player_size.y / mob_size.y
}
})
player:set_eye_offset({x = 0, y = 15, z = 0}, {x = 0, y = 15, z = 15})
end
-------------
-- Sensors --
-------------
function animalia.find_collision(self, dir)
local pos = self.object:get_pos()
local pos2 = vec_add(pos, vec_multi(dir, 16))
local ray = minetest.raycast(pos, pos2, false, false)
for pointed_thing in ray do
if pointed_thing.type == "node" then
return pointed_thing.under
end
end
return nil
end
----------
-- Misc --
----------
function animalia.alias_mob(old_mob, new_mob)
minetest.register_entity(":" .. old_mob, {
on_activate = function(self)
local pos = self.object:get_pos()
minetest.add_entity(pos, new_mob)
self.object:remove()
end,
})
player:set_eye_offset({x = 0, y = 25, z = 0}, {x = 0, y = 15, z = 15})
end
--------------
@ -728,19 +747,17 @@ function animalia.get_item_list(list, offset_x, offset_y) -- Creates a visual li
local spacing = 0.3
local total_scale = size + spacing
local max_horiz = 3
local max_verti = 6
local form = {}
for i = 1, #list do
local vert_multi = math.floor((i - 1) / max_horiz)
local horz_multi = (total_scale * max_horiz) * vert_multi
table.insert(form, "item_image[" .. offset_x + ((total_scale * i) - horz_multi) .. "," .. offset_y + (total_scale * vert_multi ).. ";" .. size .. "," .. size .. ";" .. list[i] .. "]")
local pos_x = offset_x + ((total_scale * i) - horz_multi)
local pos_y = offset_y + (total_scale * vert_multi )
table.insert(form, "item_image[" .. pos_x .. "," .. pos_y .. ";" .. size .. "," .. size .. ";" .. list[i] .. "]")
end
return table.concat(form, "")
end
-- Libri should list: Spawn Biomes, Drops, Food, Taming Method, Catchability, and Lassoability
local function get_inventory_cube(name)
local def = minetest.registered_nodes[name]
local tiles
@ -1126,7 +1143,8 @@ local function offset_info_text(offset_x, offset_y, tbl)
if string.len(str) < 30 then
center_offset = (30 - string.len(str)) * 0.05
end
table.insert(info_text, "label[" .. offset_x + center_offset .. "," .. offset_y + i * 0.25 .. ";" .. minetest.colorize("#383329", tbl[i] .. "\n") .. "]")
str = minetest.colorize("#383329", str .. "\n")
table.insert(info_text, "label[" .. offset_x + center_offset .. "," .. offset_y + i * 0.25 .. ";" .. str .. "]")
end
return table.concat(info_text, "")
end
@ -1135,8 +1153,9 @@ local function get_libri_page(mob_name, player_name)
local def = minetest.registered_entities[mob_name]
local animal_info = libri_animal_info[mob_name]
-- Get Inventory Cube and Mob Texture
local biome_groups = animalia.registered_biome_groups
local biome_group = spawn_biomes[mob_name]
local spawn_biome = animalia.registered_biome_groups[biome_group].biomes[animalia_libri_info[player_name].biome_idx] or "grassland"
local spawn_biome = biome_groups[biome_group].biomes[animalia_libri_info[player_name].biome_idx] or "grassland"
local invcube
if not minetest.registered_biomes[spawn_biome]
or not minetest.registered_biomes[spawn_biome].node_top then
@ -1212,8 +1231,8 @@ local function update_libri(player_name, mob_name)
else
texture_idx = texture_idx + 1
end
local spawn_biomes = animalia.registered_biome_groups[spawn_biomes[mob_name]].biomes
if biome_idx >= #spawn_biomes then
local wild_biomes = animalia.registered_biome_groups[spawn_biomes[mob_name]].biomes
if biome_idx >= #wild_biomes then
biome_idx = 1
else
biome_idx = biome_idx + 1
@ -1223,7 +1242,7 @@ local function update_libri(player_name, mob_name)
biome_idx = biome_idx,
name = mob_name
}
minetest.show_formspec(player_name, "animalia:libri_" .. string.split(mob_name, ":")[2], get_libri_page(mob_name, player_name))
minetest.show_formspec(player_name, "animalia:libri_" .. mob_name:split(":")[2], get_libri_page(mob_name, player_name))
minetest.after(4, function()
update_libri(player_name, mob_name)
end)
@ -1234,7 +1253,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "animalia:libri_main" then
animalia_libri_info[player_name] = {}
for i = 1, #animalia.animals do
local name = string.split(animalia.animals[i], ":")[2]
local name = animalia.animals[i]:split(":")[2]
if fields["pg_" .. name] then
-- Get data for mob and biome visuals
animalia_libri_info[player_name] = {

File diff suppressed because it is too large Load diff

View file

@ -182,7 +182,7 @@ minetest.register_entity("animalia:lasso_visual", {
is_visible = true,
makes_footstep_sound = false,
glow = 1,
on_step = function(self, dtime)
on_step = function(self)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
@ -206,7 +206,7 @@ minetest.register_entity("animalia:frog_tongue_visual", {
textures = {"animalia_frog_tongue.png"},
is_visible = true,
makes_footstep_sound = false,
on_step = function(self, dtime)
on_step = function(self)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
@ -319,7 +319,7 @@ minetest.register_entity("animalia:lasso_fence_ent", {
minetest.register_craftitem("animalia:lasso", {
description = "Lasso",
inventory_image = "animalia_lasso.png",
on_secondary_use = function(itemstack, placer, pointed_thing)
on_secondary_use = function(_, 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()

View file

@ -8,7 +8,8 @@ for i = 1, #animalia.mobs do
minetest.register_entity(":" .. old_mob, {
on_activate = mob_core.on_activate
})
minetest.register_alias_force("better_fauna:spawn_" .. new_mob:split(":")[2], "animalia:spawn_" .. new_mob:split(":")[2])
minetest.register_alias_force("better_fauna:spawn_" .. new_mob:split(":")[2],
"animalia:spawn_" .. new_mob:split(":")[2])
end
minetest.register_globalstep(function(dtime)
@ -16,8 +17,9 @@ minetest.register_globalstep(function(dtime)
for _, mob in pairs(mobs) do
if mob
and mob.name:match("better_fauna:") then
if mob.name:find("lasso_fence_ent") then
local pos = mob.object:get_pos()
if not pos then return end
if mob.name:find("lasso_fence_ent") then
if pos then
minetest.add_entity(pos, "animalia:lasso_fence_ent")
end
@ -33,7 +35,6 @@ minetest.register_globalstep(function(dtime)
local new_name = ent:split(":")[2]
local old_name = mob.name:split(":")[2]
if new_name == old_name then
local pos = mob.object:get_pos()
if pos then
local new_mob = minetest.add_entity(pos, ent)
local mem = nil

View file

@ -18,8 +18,6 @@ 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])
@ -128,7 +126,6 @@ creatura.register_mob_spawn("animalia:bird", {
biomes = animalia.registered_biome_groups["common"].biomes,
spawn_cluster = true,
nodes = {"group:leaves"}
})
creatura.register_on_spawn("animalia:bird", function(self, pos)
@ -138,11 +135,15 @@ creatura.register_on_spawn("animalia:bird", function(self, pos)
self.home_position = self:memorize("home_position", pos)
self.despawn_after = self:memorize("despawn_after", nil)
else
local nodes = minetest.find_nodes_in_area_under_air({x = pos.x - 3, y = pos.y - 3, z = pos.z - 3}, {x = pos.x + 3, y = pos.y + 7, z = pos.z + 3}, "group:leaves")
local nodes = minetest.find_nodes_in_area_under_air(
{x = pos.x - 3, y = pos.y - 3, z = pos.z - 3},
{x = pos.x + 3, y = pos.y + 7, z = pos.z + 3},
"group:leaves"
)
if nodes[1] then
pos = nodes[1]
minetest.set_node({x = pos.x, y = pos.y + 1, z = pos.z}, {name = "animalia:nest_song_bird"})
self.home_position = self:memorize("home_position", nodes[1])
self.home_position = self:memorize("home_position", {x = pos.x, y = pos.y + 1, z = pos.z})
self.despawn_after = self:memorize("despawn_after", nil)
end
end
@ -163,11 +164,7 @@ creatura.register_mob_spawn("animalia:tropical_fish", {
-- 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)
local function is_value_in_table(tbl, val)
for _, v in pairs(tbl) do
if v == val then
return true
@ -176,24 +173,11 @@ function is_value_in_table(tbl, val)
return false
end
function get_biome_name(pos)
local 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
@ -278,7 +262,8 @@ minetest.register_on_generated(function(minp, maxp)
and #spawnable_mobs > 0 then
local mob = spawnable_mobs[random(#spawnable_mobs)]
local spawn_def = creatura.registered_mob_spawns[mob]
table.insert(animalia.spawn_queue, {pos = center, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)})
table.insert(animalia.spawn_queue,
{pos = center, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)})
table.insert(animalia.spawn_points, center)
end
spawn_added = true
@ -305,10 +290,10 @@ minetest.register_globalstep(function(dtime)
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
for _, object in ipairs(objects) do
local ent = object and object:get_luaentity()
if ent
and ent.name:find("animalia:") then
spawn = false
break
end
@ -316,7 +301,8 @@ minetest.register_globalstep(function(dtime)
end
if spawn then
local spawn_def = creatura.registered_mob_spawns[mob]
table.insert(animalia.spawn_queue, {pos = point, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)})
table.insert(animalia.spawn_queue,
{pos = point, mob = mob, group = random(spawn_def.min_group, spawn_def.max_group)})
end
end
end
@ -337,7 +323,7 @@ local function spawn_queued()
local pos = queue[i].pos
if queue[i].group > 4
or creatura.registered_mob_spawns[queue[i].mob].spawn_cluster then
pos = get_ground_level(pos)
pos = creatura.get_ground_level(pos, 4)
minetest.add_node(pos, {name = "creatura:spawn_node"})
local meta = minetest.get_meta(pos)
meta:set_string("mob", queue[i].mob)
@ -349,7 +335,7 @@ local function spawn_queued()
y = pos.y,
z = pos.z + random(-3, 3)
}
pos = get_ground_level(pos)
pos = creatura.get_ground_level(pos, 4)
minetest.add_node(pos, {name = "creatura:spawn_node"})
local meta = minetest.get_meta(pos)
meta:set_string("mob", queue[i].mob)

View file

@ -4,12 +4,10 @@
local random = math.random
local function vec_raise(v, n)
return {x = v.x, y = v.y + n, z = v.z}
end
local walkable_nodes = {}
local color = minetest.colorize
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_nodes) do
if name ~= "air" and name ~= "ignore" then
@ -27,7 +25,7 @@ local function correct_name(str)
end
end
function register_egg(name, def)
local function register_egg(name, def)
minetest.register_entity(def.mob .. "_egg_sprite", {
hp_max = 1,
@ -38,7 +36,7 @@ function register_egg(name, def)
textures = {"animalia_egg.png"},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
on_step = function(self, dtime)
on_step = function(self)
local pos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(pos, 1.5)
local cube = minetest.find_nodes_in_area(
@ -77,7 +75,7 @@ function register_egg(name, def)
end
})
local function mobs_shoot_egg(item, player, pointed_thing)
local function mobs_shoot_egg(item, player)
local pos = player:get_pos()
minetest.sound_play("default_place_node_hard", {
@ -241,6 +239,26 @@ minetest.register_craft({
output = "animalia:poultry_cooked",
})
minetest.register_craftitem("animalia:venison_raw", {
description = "Raw Venison",
inventory_image = "animalia_venison_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2, meat = 1, food_meat = 1},
})
minetest.register_craftitem("animalia:venison_raw_cooked", {
description = "Venison Steak",
inventory_image = "animalia_venison_cooked.png",
on_use = minetest.item_eat(10),
groups = {flammable = 2, meat = 1, food_meat = 1},
})
minetest.register_craft({
type = "cooking",
recipe = "animalia:venison_raw",
output = "animalia:venison_cooked",
})
register_egg("animalia:chicken_egg", {
description = "Chicken Egg",
inventory_image = "animalia_egg",
@ -259,7 +277,7 @@ minetest.register_craftitem("animalia:bucket_milk", {
groups = {food_milk = 1, flammable = 3},
})
function grow_crops(pos, nodename)
local function grow_crops(pos, nodename)
local checkname = nodename:sub(1, string.len(nodename) - 1)
if minetest.registered_nodes[checkname .. "1"]
and minetest.registered_nodes[checkname .. "2"]
@ -328,7 +346,11 @@ minetest.register_craftitem("animalia:bucket_guano", {
if pos
and not minetest.is_protected(pos, placer:get_player_name()) then
if guano_fert then
local nodes = minetest.find_nodes_in_area_under_air(vector.subtract(pos, 5), vector.add(pos, 5), {"group:grass", "group:plant", "group:flora"})
local nodes = minetest.find_nodes_in_area_under_air(
vector.subtract(pos, 5),
vector.add(pos, 5),
{"group:grass", "group:plant", "group:flora"}
)
if #nodes > 0 then
for n = 1, #nodes do
grow_crops(nodes[n], minetest.get_node(nodes[n]).name)
@ -383,6 +405,7 @@ minetest.register_craftitem("animalia:cat_toy", {
description = "Cat Toy",
inventory_image = "animalia_cat_toy.png",
wield_image = "animalia_cat_toy.png^[transformFYR90",
stack_max = 1
})
local nametag = {}
@ -472,11 +495,11 @@ minetest.register_craftitem("animalia:net", {
end
meta:set_string("mob", ent.name)
meta:set_string("staticdata", ent:get_staticdata())
local desc = "Animal Net \n" .. minetest.colorize("#a9a9a9", ent_name) .. "\n" .. minetest.colorize("#a9a9a9", ent_gender)
local desc = "Animal Net \n" .. color("#a9a9a9", ent_name) .. "\n" .. color("#a9a9a9", ent_gender)
if ent.name == "animalia:cat"
and ent.trust
and ent.trust[placer:get_player_name()] then
desc = desc .. "\n" .. minetest.colorize("#a9a9a9", ent.trust[placer:get_player_name()])
desc = desc .. "\n" .. color("#a9a9a9", ent.trust[placer:get_player_name()])
end
meta:set_string("description", desc)
placer:set_wielded_item(itemstack)
@ -538,9 +561,8 @@ minetest.register_node("animalia:guano", {
{-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
},
},
groups = {crumbly = 3, falling_node = 1},
groups = {crumbly = 3, falling_node = 1, not_in_creative_inventory = 1},
on_punch = function(pos, _, player)
local item = player:get_wielded_item()
local item_name = player:get_wielded_item():get_name()
if item_name:find("bucket")
and item_name:find("empty") then
@ -631,7 +653,6 @@ minetest.register_craftitem("animalia:libri_animalia", {
if pointed_thing and pointed_thing.type == "object" then return end
local meta = itemstack:get_meta()
local pages = minetest.deserialize(meta:get_string("pages"))
local desc = meta:get_string("description")
if not pages
or #pages < 1 then return end
animalia.show_libri_main_form(player, pages)
@ -640,7 +661,6 @@ minetest.register_craftitem("animalia:libri_animalia", {
if pointed_thing and pointed_thing.type == "object" then return end
local meta = itemstack:get_meta()
local pages = minetest.deserialize(meta:get_string("pages"))
local desc = meta:get_string("description")
if not pages
or #pages < 1 then return end
animalia.show_libri_main_form(player, pages)
@ -742,7 +762,7 @@ minetest.register_craft({
}
})
minetest.register_on_craft(function(itemstack, player, old_craft_grid)
minetest.register_on_craft(function(itemstack, _, old_craft_grid)
if itemstack:get_name() == "animalia:libri_animalia"
and itemstack:get_count() > 1 then
for _, old_libri in pairs(old_craft_grid) do

View file

@ -1,5 +1,4 @@
animalia = {}
better_fauna = animalia
animalia.pets = {}
@ -49,7 +48,7 @@ animalia.animals = {
}
for i = 1, #animalia.animals do
local name = string.split(animalia.animals[i], ":")[2]
local name = animalia.animals[i]:split(":")[2]
dofile(path.."/mobs/" .. name .. ".lua")
end

View file

@ -2,30 +2,6 @@
-- Bat --
---------
local function get_ceiling_positions(pos, range)
local walkable = minetest.find_nodes_in_area(
{x = pos.x + range, y = pos.y + range, z = pos.z + range},
{x = pos.x - range, y = pos.y, z = pos.z - range},
animalia.walkable_nodes
)
if #walkable < 1 then return {} end
local output = {}
for i = 1, #walkable do
local i_pos = walkable[i]
local under = {
x = i_pos.x,
y = i_pos.y - 1,
z = i_pos.z
}
if minetest.get_node(under).name == "air"
and minetest.registered_nodes[minetest.get_node(i_pos).name].walkable then
table.insert(output, i_pos)
end
end
return output
end
local guano_accumulation = minetest.settings:get_bool("guano_accumulation")
-- Math --
@ -51,6 +27,33 @@ local function vec_raise(v, n)
return {x = v.x, y = v.y + n, z = v.z}
end
---------------
-- Utilities --
---------------
local function get_roost(pos, range)
local walkable = minetest.find_nodes_in_area(
{x = pos.x + range, y = pos.y + range, z = pos.z + range},
{x = pos.x - range, y = pos.y, z = pos.z - range},
animalia.walkable_nodes
)
if #walkable < 1 then return end
local roosts = {}
for i = 1, #walkable do
local i_pos = walkable[i]
local n_pos = {
x = i_pos.x,
y = i_pos.y - 1,
z = i_pos.z
}
if creatura.get_node_def(n_pos).name == "air"
and minetest.line_of_sight(pos, n_pos) then
table.insert(roosts, n_pos)
end
end
return roosts[random(#roosts)]
end
local function is_node_walkable(name)
local def = minetest.registered_nodes[name]
return def and def.walkable
@ -84,7 +87,7 @@ creatura.register_mob("animalia:bat", {
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 50, y = 90}, speed = 30, frame_blend = 0.3, loop = true},
fly = {range = {x = 100, y = 140}, speed = 80, frame_blend = 0.3, loop = true},
latch = {range = {x = 150, y = 150}, speed = 1, frame_blend = 0, loop = false}
cling = {range = {x = 150, y = 150}, speed = 1, frame_blend = 0, loop = false}
},
-- Misc
sounds = {
@ -103,80 +106,63 @@ creatura.register_mob("animalia:bat", {
"butterflies:butterfly_violet"
},
-- Function
step_delay = 0.25,
roost_action = animalia.action_cling,
utility_stack = {
[1] = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
if self.is_landed then
return 0.1, {self}
end
return 0
end
},
[2] = {
utility = "animalia:aerial_swarm",
{
utility = "animalia:aerial_wander",
step_delay = 0.25,
get_score = function(self)
if self:get_utility() == "animalia:return_to_home"
or self:get_utility() == "animalia:wander" then
local pos = self.object:get_pos()
if not pos then return end
local player = creatura.get_nearby_player(self)
if player
and player:get_pos()
and not player:get_player_control().sneak then
local dist = vector.distance(pos, player:get_pos())
self._nearby_player = player
local plyr_pos = player and not player:get_player_control().sneak and player:get_pos()
if plyr_pos then
local trust = self.trust[player:get_player_name() or ""] or 0
local dist = vec_dist(pos, plyr_pos)
self._target = player
self.is_landed = false
return (12 - dist) * 0.1, {self, 1}
end
return (12 - (dist + trust)) * 0.1, {self}
end
if self.in_liquid
or not self.is_landed then
return 0.11, {self, 1}
return 0.2, {self}
end
return 0
end
},
[3] = {
utility = "animalia:land",
{
utility = "animalia:fly_to_land",
get_score = function(self)
if not self.is_landed
and not self.touching_ground then
return 0.12, {self}
if self.is_landed
and not self.touching_ground
and not self.in_liquid
and creatura.sensor_floor(self, 3, true) > 2 then
return 0.3, {self}
end
return 0
end
},
[4] = {
utility = "animalia:return_to_home",
utility = "animalia:fly_to_roost",
get_score = function(self)
if not self.home_position then return 0 end
local player = self._nearby_player
if player
and player:get_pos() then
local pos = self.object:get_pos()
local dist = vector.distance(pos, player:get_pos())
if dist < 9 then
return 0
end
end
local time = (minetest.get_timeofday() * 24000) or 0
local is_day = time < 19500 and time > 4500
if is_day then
if not pos then return end
local home = animalia.is_day and self.home_position
if home
and home.x
and vec_dist(pos, home) < 8 then
return 0.6, {self}
end
return 0
end
},
[5] = {
utility = "animalia:find_home",
get_score = function(self)
if self.home_position then return 0 end
local pos = self.object:get_pos()
local range = self.tracking_range
local ceiling = get_ceiling_positions(pos, range / 2)
if not ceiling[1] then return 0 end
return 1, {self}
end
}
},
activate_func = function(self)
@ -184,32 +170,40 @@ creatura.register_mob("animalia:bat", {
animalia.initialize_lasso(self)
self.home_position = self:recall("home_position") or nil
self.is_landed = self:recall("is_landed") or false
self.stamina = self:recall("stamina") or 30
self.trust = self:recall("trust") or {}
if not self.home_position then
local roost = get_roost(self.object:get_pos(), 8)
if roost then
self.home_position = self:memorize("home_position", roost)
end
end
end,
step_func = function(self)
animalia.step_timers(self)
--animalia.head_tracking(self, 0.75, 0.75)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if self.stamina > 0 then
if not self.is_landed then
self.stamina = self:memorize("stamina", self.stamina - self.dtime)
else
self.stamina = self:memorize("stamina", self.stamina + self.dtime)
animalia.rotate_to_pitch(self)
local pos = self.object:get_pos()
if not pos then return end
if self:timer(random(10,15)) then
if random(4) < 2 then
self.is_landed = not self.is_landed
end
if not self.home_position
or creatura.get_node_def(self.home_position).walkable then
local roost = get_roost(pos, 8)
if roost then
self.home_position = self:memorize("home_position", roost)
end
if self.stamina > 25
and self.is_landed then
self.is_landed = self:memorize("is_landed", false)
end
else
self.stamina = self:memorize("stamina", self.stamina + self.dtime)
self.is_landed = self:memorize("is_landed", true)
end
if self._anim == "fly" then
local vel_y = self.object:get_velocity().y
local vel_y = vector.normalize(self.object:get_velocity()).y
local rot = self.object:get_rotation()
local n_rot = rot.x + (vel_y - rot.x) * 0.2
self.object:set_rotation({
x = clamp(vel_y * 0.25, -0.75, 0.75),
x = clamp(n_rot, -0.75, 0.75),
y = rot.y,
z = rot.z
})
@ -218,8 +212,7 @@ creatura.register_mob("animalia:bat", {
self:play_sound("random")
if guano_accumulation
and random(16) < 2
and self:get_utility() == "animalia:return_to_home" then
local pos = self.object:get_pos()
and self:get_utility() == "animalia:fly_to_roost" then
pos = {
x = floor(pos.x + 0.5),
y = floor(pos.y + 0.5),
@ -229,7 +222,7 @@ creatura.register_mob("animalia:bat", {
return
end
local fail_safe = 1
while not is_node_walkable(minetest.get_node(floor_pos).name)
while not is_node_walkable(minetest.get_node(pos).name)
and fail_safe < 16 do
pos.y = pos.y - 1
end
@ -260,6 +253,7 @@ creatura.register_mob("animalia:bat", {
end,
on_rightclick = function(self, clicker)
if animalia.feed(self, clicker, false, false) then
animalia.add_trust(self, clicker, 1)
return
end
if animalia.set_nametag(self, clicker) then

View file

@ -5,7 +5,7 @@
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
for name in pairs(minetest.registered_items) do
if name:match(":seed_")
or name:match("_seed") then
table.insert(follows, name)
@ -15,14 +15,7 @@ end)
local random = math.random
local function clamp(val, min, max)
if val < min then
val = min
elseif max < val then
val = max
end
return val
end
local vec_dist = vector.distance
creatura.register_mob("animalia:bird", {
-- Stats
@ -34,7 +27,7 @@ creatura.register_mob("animalia:bird", {
despawn_after = 100,
-- Entity Physics
stepheight = 1.1,
max_fall = 100,
max_fall = 0,
turn_rate = 6,
boid_seperation = 0.4,
-- Visuals
@ -55,6 +48,7 @@ creatura.register_mob("animalia:bird", {
fly = {range = {x = 120, y = 140}, speed = 80, frame_blend = 0.3, loop = true}
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = false,
sounds = {
@ -79,63 +73,54 @@ creatura.register_mob("animalia:bird", {
},
follow = follows,
-- Function
wander_action = animalia.action_move_flock,
utility_stack = {
{
utility = "animalia:boid_wander",
utility = "animalia:wander_group",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
{
utility = "animalia:aerial_flock",
utility = "animalia:aerial_wander",
step_delay = 0.25,
get_score = function(self)
if not self.is_landed then
return 0.11, {self, 1}
else
local pos = self.object:get_pos()
if self.in_liquid then
self.stamina = self:memorize("stamina", 30)
self.is_landed = false
return 0.15, {self, 0.5}
end
local player = creatura.get_nearby_player(self)
if player
and player:get_pos() then
local dist = vector.distance(pos, player:get_pos())
self.is_landed = false
return (16 - dist) * 0.1, {self, 0.5}
end
if not self.is_landed
or self.in_liquid then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:land",
utility = "animalia:fly_to_land",
get_score = function(self)
if self.is_landed
and not self.touching_ground
and not self.in_liquid then
return 0.12, {self}
and not self.in_liquid
and creatura.sensor_floor(self, 3, true) > 2 then
return 0.3, {self}
end
return 0
end
},
{
utility = "animalia:return_to_nest",
utility = "animalia:fly_to_roost",
get_score = function(self)
if not self.home_position then
return 0
end
local player = self._nearby_player
local pos = self.object:get_pos()
if not pos then return end
local player = creatura.get_nearby_player(self)
if player
and player:get_pos() then
local pos = self.object:get_pos()
local dist = vector.distance(pos, player:get_pos())
if dist < 3 then
return 0
end
end
if not animalia.is_day then
local home = not animalia.is_day and self.home_position
if home
and vec_dist(pos, home) < 8 then
return 0.6, {self}
end
return 0
@ -152,10 +137,13 @@ creatura.register_mob("animalia:bird", {
self.object:set_pos(self.home_position)
end
self.is_landed = self:recall("is_landed") or false
self.stamina = self:recall("stamina") or 40
if not self.home_position then
local pos = self.object:get_pos()
local nests = minetest.find_nodes_in_area_under_air(vector.add(pos, 4), vector.subtract(pos, 4), {"animalia:nest_song_bird"})
local nests = minetest.find_nodes_in_area_under_air(
vector.add(pos, 4),
vector.subtract(pos, 4),
{"animalia:nest_song_bird"}
)
if nests[1]
and minetest.get_natural_light(nests[1]) > 0 then
self.home_position = self:memorize("home_position", nests[1])
@ -166,8 +154,9 @@ creatura.register_mob("animalia:bird", {
animalia.step_timers(self)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if animalia.is_day
and self:timer(random(10,15)) then
animalia.rotate_to_pitch(self)
if self:timer(random(10,15)) then
if animalia.is_day then
if self.texture_no == 1 then
self:play_sound("cardinal")
elseif self.texture_no == 2 then
@ -176,28 +165,21 @@ creatura.register_mob("animalia:bird", {
self:play_sound("goldfinch")
end
end
if self._anim == "fly" then
local vel_y = self.object:get_velocity().y
local rot = self.object:get_rotation()
self.object:set_rotation({
x = clamp(vel_y * 0.25, -0.75, 0.75),
y = rot.y,
z = rot.z
})
if random(4) < 2 then
self.is_landed = not self.is_landed
end
if self.stamina > 0 then
if not self.is_landed then
self.stamina = self:memorize("stamina", self.stamina - self.dtime)
else
self.stamina = self:memorize("stamina", self.stamina + self.dtime)
local home = self.home_position
if home
and creatura.get_node_def(home).name ~= "animalia:nest_song_bird" then
local nodes = minetest.find_nodes_in_area_under_air(
{x = home.x, y = home.y - 12, z = home.z},
{x = home.x, y = home.y + 12, z = home.z},
{"animalia:nest_song_bird"}
)
if nodes[1] then
self.home_position = self:memorize("home_position", nodes[1])
end
if self.stamina > 25
and self.is_landed then
self.is_landed = self:memorize("is_landed", false)
end
else
self.stamina = self:memorize("stamina", self.stamina + self.dtime)
self.is_landed = self:memorize("is_landed", true)
end
if not self.is_landed
or not self.touching_ground then
@ -238,3 +220,12 @@ creatura.register_mob("animalia:bird", {
})
creatura.register_spawn_egg("animalia:bird", "ae2f2f", "f3ac1c")
minetest.register_abm({
label = "animalia:nest_cleanup",
nodenames = "animalia:nest_song_bird",
interval = 900,
action = function(pos)
minetest.remove_node(pos)
end
})

View file

@ -2,6 +2,10 @@
-- Cat --
---------
local random = math.random
local vec_dist = vector.distance
local follow = {
"animalia:poultry_raw"
}
@ -20,6 +24,7 @@ creatura.register_mob("animalia:cat", {
damage = 1,
speed = 5,
tracking_range = 24,
turn_rate = 9,
despawn_after = 2000,
-- Entity Physics
stepheight = 1.1,
@ -34,16 +39,25 @@ creatura.register_mob("animalia:cat", {
"animalia_cat_1.png",
"animalia_cat_2.png",
"animalia_cat_3.png",
"animalia_cat_4.png"
"animalia_cat_4.png",
"animalia_cat_5.png",
"animalia_cat_6.png",
"animalia_cat_7.png",
"animalia_cat_8.png",
"animalia_cat_9.png",
"animalia_cat_ash.png",
"animalia_cat_birch.png",
},
animations = {
stand = {range = {x = 1, y = 39}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 50, y = 90}, speed = 45, frame_blend = 0.3, loop = true},
run = {range = {x = 100, y = 130}, speed = 50, frame_blend = 0.3, loop = true},
sit = {range = {x = 140, y = 180}, speed = 10, frame_blend = 0.3, loop = true},
smack = {range = {x = 190, y = 210}, speed = 40, frame_blend = 0.1, loop = true},
walk = {range = {x = 41, y = 59}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 42, y = 59}, speed = 30, frame_blend = 0.3, loop = true},
play = {range = {x = 61, y = 79}, speed = 30, frame_blend = 0.3, loop = false},
sit = {range = {x = 81, y = 99}, speed = 10, frame_blend = 0.3, loop = true},
smack = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.1, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -70,7 +84,7 @@ creatura.register_mob("animalia:cat", {
},
follow = follow,
head_data = {
offset = {x = 0, y = 0.22, z = 0},
offset = {x = 0, y = 0.18, z = 0},
pitch_correction = -20,
pivot_h = 0.65,
pivot_v = 0.65
@ -79,7 +93,6 @@ creatura.register_mob("animalia:cat", {
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
self._path = {}
self.interact_sound_cooldown = 0
self.trust_cooldown = self:recall("trust_cooldown") or 0
self.order = self:recall("order") or "wander"
@ -93,94 +106,94 @@ creatura.register_mob("animalia:cat", {
end
end,
utility_stack = {
[1] = {
utility = "animalia:skittish_wander",
{
utility = "animalia:wander_skittish",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
[2] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.9, {self}
return 0.3, {self}
end
return 0
end
},
[3] = {
utility = "animalia:find_and_break_glass_vessels",
{
utility = "animalia:destroy_nearby_vessel",
step_delay = 0.25,
get_score = function(self)
return math.random(10) * 0.01, {self}
if random(24) < 2 then
return 0.2, {self}
end
return 0
end
},
[4] = {
utility = "animalia:walk_ahead_of_player",
{
utility = "animalia:bother_player",
step_delay = 0.25,
get_score = function(self)
local player = creatura.get_nearby_player(self)
if player
and player:get_player_name() then
local trust = 0
if not self.trust[player:get_player_name()] then
self.trust[player:get_player_name()] = 0
self:memorize("trust", self.trust)
else
trust = self.trust[player:get_player_name()]
end
self._nearby_player = player
if trust > 3 then
return math.random(10) * 0.01, {self, player}
else
return 0
end
if random(24) > 1 then return 0 end
local owner = self.owner and minetest.get_player_by_name(self.owner)
local pos = self.object:get_pos()
if not pos then return end
local trust = self.trust[self.owner] or 0
if trust > 3
and owner
and vec_dist(pos, owner:get_pos()) < self.tracking_range then
return 0.2, {self, owner}
end
return 0
end
},
[5] = {
utility = "animalia:sit",
{
utility = "animalia:stay",
step_delay = 0.25,
get_score = function(self)
if self.order == "sit"
and self.trust[self.owner] > 7 then
return 0.8, {self}
local trust = (self.owner and self.trust[self.owner]) or 0
if trust < 5 then return 0 end
local order = self.order or "wander"
if order == "sit" then
return 0.5, {self}
end
return 0
end
},
[6] = {
{
utility = "animalia:play_with_player",
step_delay = 0.25,
get_score = function(self)
if self.trust_cooldown > 0 then return 0 end
local owner = self.owner and minetest.get_player_by_name(self.owner)
if owner
and owner:get_wielded_item():get_name() == "animalia:cat_toy" then
return 0.6, {self, owner}
end
return 0
end
},
{
utility = "animalia:follow_player",
get_score = function(self)
if self.order == "follow"
and minetest.get_player_by_name(self.owner)
and self.trust[self.owner] > 7 then
return 1, {self, minetest.get_player_by_name(self.owner)}
end
local trust = 0
local player = self._nearby_player
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local trust = (self.owner and self.trust[self.owner]) or 0
local owner = self.owner and self.order == "follow" and trust > 4 and minetest.get_player_by_name(self.owner)
local force = (lasso and lasso ~= false) or (owner and owner ~= false)
local player = (force and (owner or lasso)) or creatura.get_nearby_player(self)
if player
and player:get_player_name() then
if not self.trust[player:get_player_name()] then
self.trust[player:get_player_name()] = 0
self:memorize("trust", self.trust)
else
trust = self.trust[player:get_player_name()]
end
else
return 0
end
if player:get_velocity()
and vector.length(player:get_velocity()) < 2
and self:follow_wielded_item(player)
and trust >= 4 then
return 0.6, {self, player}
elseif player:get_wielded_item():get_name() == "animalia:cat_toy" then
return 0.6, {self, player, true}
and self:follow_wielded_item(player) then
return 0.6, {self, player, force}
end
return 0
end
},
[7] = {
utility = "animalia:mammal_breed",
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name) then
@ -196,9 +209,6 @@ creatura.register_mob("animalia:cat", {
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if self:timer(1) then
if self.trust_cooldown > 0 then
self.trust_cooldown = self:memorize("trust_cooldown", self.trust_cooldown - 1)
end
if self.interact_sound_cooldown > 0 then
self.interact_sound_cooldown = self.interact_sound_cooldown - 1
end
@ -234,20 +244,6 @@ creatura.register_mob("animalia:cat", {
self.trust[clicker:get_player_name()] = 0
self:memorize("trust", self.trust)
end
-- Increase trust by playing
if item_name == "animalia:cat_toy"
and self:get_utility() == "animalia:follow_player" then
if trust < 10 then
self.trust[clicker:get_player_name()] = trust + 1
self:memorize("trust", self.trust)
animalia.particle_spawner(pos, "creatura_particle_green.png", "float", minppos, maxppos)
if self.interact_sound_cooldown <= 0 then
self.sounds["purr"].gain = 1
self.interact_sound_cooldown = 3
self:play_sound("purr")
end
end
end
-- Purr to indicate trust level (louder = more trust)
if clicker:get_player_control().sneak then
if self.interact_sound_cooldown <= 0 then
@ -261,7 +257,7 @@ creatura.register_mob("animalia:cat", {
or clicker:get_player_name() ~= self.owner then
return
end
if trust <= 7 then
if trust <= 5 then
if self.interact_sound_cooldown <= 0 then
self.interact_sound_cooldown = 3
self:play_sound("random")
@ -276,11 +272,19 @@ creatura.register_mob("animalia:cat", {
end
local order = self.order
if order == "wander" then
minetest.chat_send_player(clicker:get_player_name(), "Wolf is following")
self.order = "follow"
self:initiate_utility("animalia:follow_player", self, clicker, true)
self:set_utility_score(0.7)
elseif order == "follow" then
minetest.chat_send_player(clicker:get_player_name(), "Wolf is sitting")
self.order = "sit"
self:initiate_utility("animalia:stay", self)
self:set_utility_score(0.5)
else
minetest.chat_send_player(clicker:get_player_name(), "Wolf is wandering")
self.order = "wander"
self:set_utility_score(0)
end
self:memorize("order", self.order)
end

View file

@ -5,7 +5,7 @@
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
for name in pairs(minetest.registered_items) do
if name:match(":seed_")
or name:match("_seed") then
table.insert(follows, name)
@ -19,7 +19,7 @@ creatura.register_mob("animalia:chicken", {
armor_groups = {fleshy = 150},
damage = 0,
speed = 4,
tracking_range = 16,
tracking_range = 4,
despawn_after = 1500,
-- Entity Physics
stepheight = 1.1,
@ -42,12 +42,13 @@ creatura.register_mob("animalia:chicken", {
"animalia_rooster_2.png",
"animalia_rooster_3.png"
},
child_textures = {"animalia_chick.png"},
child_textures = {"animalia_chicken_child.png"},
animations = {
stand = {range = {x = 0, y = 0}, speed = 1, frame_blend = 0.3, loop = true},
walk = {range = {x = 10, y = 30}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 10, y = 30}, speed = 45, frame_blend = 0.3, loop = true},
fall = {range = {x = 40, y = 60}, speed = 70, frame_blend = 0.3, loop = true},
stand = {range = {x = 1, y = 39}, speed = 20, frame_blend = 0.3, loop = true},
walk = {range = {x = 41, y = 59}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 41, y = 59}, speed = 45, frame_blend = 0.3, loop = true},
eat = {range = {x = 61, y = 89}, speed = 45, frame_blend = 0.3, loop = true},
fall = {range = {x = 91, y = 99}, speed = 70, frame_blend = 0.3, loop = true}
},
-- Misc
catch_with_net = true,
@ -75,61 +76,86 @@ creatura.register_mob("animalia:chicken", {
},
follow = follows,
head_data = {
offset = {x = 0, y = 0.15, z = 0},
pitch_correction = 55,
offset = {x = 0, y = 0.45, z = 0},
pitch_correction = 40,
pivot_h = 0.25,
pivot_v = 0.55
},
-- Function
add_child = function(self)
local pos = self.object:get_pos()
if not pos then return end
minetest.add_particlespawner({
amount = 6,
time = 0.25,
minpos = {x = pos.x - 7/16, y = pos.y - 5/16, z = pos.z - 7/16},
maxpos = {x = pos.x + 7/16, y = pos.y - 5/16, z = pos.z + 7/16},
minvel = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
collisiondetection = true,
texture = "animalia_egg_fragment.png",
})
local object = minetest.add_entity(pos, self.name)
local ent = object:get_luaentity()
ent.growth_scale = 0.7
animalia.initialize_api(ent)
animalia.protect_from_despawn(ent)
end,
utility_stack = {
[1] = {
utility = "animalia:wander",
{
utility = "animalia:wander_group",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
return 0.1, {self}
end
},
[2] = {
utility = "animalia:resist_fall",
get_score = function(self)
if not self.touching_ground then
return 0.11, {self}
end
return 0
end
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.5, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.3, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:bird_breed",
{
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.9, {self}
return 0.4, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
},
activate_func = function(self)
@ -141,6 +167,10 @@ creatura.register_mob("animalia:chicken", {
animalia.head_tracking(self, 0.75, 0.75)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if self.fall_start then
self:set_gravity(-4.9)
self:animate("fall")
end
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
@ -158,8 +188,7 @@ creatura.register_mob("animalia:chicken", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:flee_from_player", self, puncher)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -2,10 +2,12 @@
-- Cow --
---------
local random = math.random
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
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
@ -51,11 +53,12 @@ creatura.register_mob("animalia:cow", {
"animalia_cow_4.png"
},
animations = {
stand = {range = {x = 1, y = 60}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 110}, speed = 40, frame_blend = 0.3, loop = true},
run = {range = {x = 70, y = 110}, speed = 60, frame_blend = 0.3, loop = true},
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 61, y = 79}, speed = 30, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -82,77 +85,85 @@ creatura.register_mob("animalia:cow", {
},
follow = follows,
consumable_nodes = {
{
name = "default:dirt_with_grass",
replacement = "default:dirt"
},
{
name = "default:dry_dirt_with_dry_grass",
replacement = "default:dry_dirt"
}
["default:dirt_with_grass"] = "default:dirt",
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
},
head_data = {
offset = {x = 0, y = 0.5, z = 0},
pitch_correction = -45,
offset = {x = 0, y = 0.7, z = 0.0},
pitch_correction = -65,
pivot_h = 0.75,
pivot_v = 1
},
-- Function
utility_stack = {
[1] = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
[2] = {
utility = "animalia:eat_from_turf",
get_score = function(self)
if math.random(25) < 2 then
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
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.3, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:mammal_breed",
{
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.9, {self}
return 0.5, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
},
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
self.gotten = self:recall("gotten") or false
self.collected = self:recall("collected") or false
end,
step_func = function(self)
animalia.step_timers(self)
@ -181,7 +192,7 @@ creatura.register_mob("animalia:cow", {
return
end
if self.gotten then
if self.collected then
minetest.chat_send_player(name, "This Cow has already been milked.")
return
end
@ -199,15 +210,14 @@ creatura.register_mob("animalia:cow", {
minetest.add_item(pos, {name = "animalia:bucket_milk"})
end
self.gotten = self:memorize("gotten", true)
self.collected = self:memorize("collected", true)
return
end
animalia.add_libri_page(self, clicker, {name = "cow", form = "pg_cow;Cows"})
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:flee_from_player", self, puncher)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -4,7 +4,9 @@
local random = math.random
local vec_add = vector.add
local vec_dist = vector.distance
local vec_sub = vector.subtract
creatura.register_mob("animalia:frog", {
-- Stats
@ -16,9 +18,10 @@ creatura.register_mob("animalia:frog", {
despawn_after = 2500,
-- Entity Physics
stepheight = 1.1,
max_fall = 100,
max_fall = 0,
turn_rate = 10,
bouyancy_multiplier = 0,
hydrodynamics_multiplier = 0.3,
-- Visuals
mesh = "animalia_frog.b3d",
hitbox = {
@ -37,9 +40,11 @@ creatura.register_mob("animalia:frog", {
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true},
float = {range = {x = 90, y = 90}, speed = 1, frame_blend = 0.3, loop = true},
swim = {range = {x = 90, y = 110}, speed = 50, frame_blend = 0.3, loop = true},
walk = {range = {x = 50, y = 80}, speed = 50, frame_blend = 0.3, loop = true}
walk = {range = {x = 50, y = 80}, speed = 50, frame_blend = 0.3, loop = true},
run = {range = {x = 50, y = 80}, speed = 60, frame_blend = 0.3, loop = true}
},
-- Misc
step_delay = 0.25,
makes_footstep_sound = true,
catch_with_net = true,
catch_with_lasso = true,
@ -64,81 +69,91 @@ creatura.register_mob("animalia:frog", {
},
-- Function
utility_stack = {
[1] = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
[2] = {
utility = "animalia:wander_water_surface",
{
utility = "animalia:aquatic_wander",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.11, {self}
end
return 0
end
},
[3] = {
utility = "animalia:eat_bug_nodes",
get_score = function(self)
local pos = self.object:get_pos()
if math.random(12) * 0.01 then
local food = minetest.find_nodes_in_area(vector.subtract(pos, 1.5), vector.add(pos, 1.5), self.follow)
if food[1] then
return 0.2, {self}
end
end
return 0
end
},
[4] = {
utility = "animalia:flop",
{
utility = "animalia:eat_bug",
get_score = function(self)
if not self.in_liquid
and self.growth_scale <= 0.6 then
return 1
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
end
return 0
end
},
[5] = {
utility = "animalia:breed_water_surface",
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name)
and self.in_liquid then
return 1
return 1, {self}
end
return 0
end
},
[6] = {
utility = "animalia:flee_from_player",
{
utility = "animalia:flop",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then return 0 end
local player = creatura.get_nearby_player(self)
if player
and player:get_player_name() then
local trust = self.trust[player:get_player_name()] or 0
self._nearby_player = player -- stored to memory to avoid calling get_nearby_player again
return (10 - (vec_dist(self.object:get_pos(), player:get_pos()) + trust)) * 0.1, {self, player}
if not self.in_liquid
and self.growth_scale <= 0.6 then
return 1, {self}
end
return 0
end
},
[7] = {
utility = "animalia:flee_to_water",
{
utility = "animalia:flee_from_target",
get_score = function(self)
if self.in_liquid then return 0 end
local pos = self.object:get_pos()
local water = minetest.find_nodes_in_area(vector.subtract(pos, 1.5), vector.add(pos, 1.5), {"default:water_source"})
if not pos then return end
local target = self._target or creatura.get_nearby_player(self)
local tgt_pos = target and target:get_pos()
local plyr_name = (target and target:is_player() and target:get_player_name()) or ""
if tgt_pos then
local trust = self.trust[plyr_name] or 0
self._target = target -- stored to memory to avoid calling get_nearby_player again
return (10 - (vec_dist(pos, tgt_pos) + trust)) * 0.1, {self, target}
end
return 0
end
},
{
utility = "animalia:run_to_pos",
get_score = function(self)
if self.in_liquid then return 0 end
local pos = self.object:get_pos()
if not pos then return end
local water = minetest.find_nodes_in_area(vec_sub(pos, 1.5), vec_add(pos, 1.5), {"group:water"})
if not water[1] then return 0 end
local player = self._nearby_player
if player
and player:get_player_name() then
local trust = self.trust[player:get_player_name()] or 0
return (10 - (vec_dist(self.object:get_pos(), player:get_pos()) + trust)) * 0.1, {self, player}
local player = self._target
local plyr_name = player and player:is_player() and player:get_player_name()
if plyr_name then
local plyr_pos = player and player:get_pos()
local trust = self.trust[plyr_name] or 0
return (10 - (vec_dist(pos, plyr_pos) + trust)) * 0.1, {self, water[1]}
end
return 0
end
@ -177,14 +192,7 @@ creatura.register_mob("animalia:frog", {
end,
on_rightclick = function(self, clicker)
if animalia.feed(self, clicker, false, true) then
local name = clicker:get_player_name()
if self.trust[name] then
self.trust[name] = self.trust[name] + 1
else
self.trust[name] = 1
end
if self.trust[name] > 5 then self.trust[name] = 5 end
self:memorize("trust", self.trust)
animalia.add_trust(self, clicker, 1)
return
end
if animalia.set_nametag(self, clicker) then

View file

@ -7,7 +7,7 @@ local random = math.random
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
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
@ -16,42 +16,59 @@ minetest.register_on_mods_loaded(function()
end
end)
local function set_pattern(self)
local types = {
"spots",
"patches"
local patterns = {
"animalia_horse_pattern_1.png",
"animalia_horse_pattern_2.png",
"animalia_horse_pattern_3.png"
}
if self:recall("pattern")
and not self:recall("pattern"):find("better_fauna") then
local pattern = self:recall("pattern")
local avlbl_colors = {
[1] = {
"animalia_horse_2.png",
"animalia_horse_3.png",
"animalia_horse_6.png"
},
[2] = {
"animalia_horse_1.png",
"animalia_horse_6.png"
},
[3] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
},
[4] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
},
[5] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
},
[6] = {
"animalia_horse_2.png",
"animalia_horse_1.png"
}
}
local function set_pattern(self)
local pattern_no = self:recall("pattern_no")
if pattern_no and pattern_no < 1 then return end
if not pattern_no then
if random(3) < 2 then
pattern_no = self:memorize("pattern_no", random(#patterns))
else
self:memorize("pattern_no", 0)
return
end
end
local colors = avlbl_colors[self.texture_no]
local color_no = self:recall("color_no") or self:memorize("color_no", random(#colors))
if not colors[color_no] then return end
local pattern = "(" .. patterns[pattern_no] .. "^[mask:" .. colors[color_no] .. ")"
local texture = self.object:get_properties().textures[1]
self.object:set_properties({
textures = {texture .. "^" .. pattern}
})
else
local type = types[random(#types)]
local overlay = "(animalia_horse_".. type ..".png)"
if type == "patches" then
local colors = {
"brown",
"white"
}
if self.texture_no < 1 then
table.insert(colors, "black")
else
table.remove(colors, 1)
end
overlay = "(animalia_horse_".. colors[random(#colors)] .."_patches.png)"
end
if random(100) > 50 then
overlay = "transparency.png"
end
local texture = self.object:get_properties().textures[1]
self.object:set_properties({
textures = {texture .. "^" .. overlay}
})
self:memorize("pattern", overlay)
end
end
creatura.register_mob("animalia:horse", {
@ -82,14 +99,16 @@ creatura.register_mob("animalia:horse", {
"animalia_horse_6.png"
},
animations = {
stand = {range = {x = 1, y = 60}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 70, y = 110}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 120, y = 140}, speed = 30, frame_blend = 0.3, loop = true},
rear = {range = {x = 150, y = 180}, speed = 27, frame_blend = 0.2, loop = false},
rear_constant = {range = {x = 160, y = 170}, speed = 20, frame_blend = 0.3, loop = true},
eat = {range = {x = 190, y = 220}, speed = 20, frame_blend = 0.3, loop = false}
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 81, y = 99}, speed = 30, frame_blend = 0.3, loop = true},
punch_aoe = {range = {x = 101, y = 119}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.2, loop = false},
rear_constant = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.3, loop = false},
eat = {range = {x = 141, y = 160}, speed = 20, frame_blend = 0.3, loop = false}
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -116,71 +135,101 @@ creatura.register_mob("animalia:horse", {
},
follow = follows,
consumable_nodes = {
{
name = "default:dirt_with_grass",
replacement = "default:dirt"
},
{
name = "default:dry_dirt_with_dry_grass",
replacement = "default:dry_dirt"
}
["default:dirt_with_grass"] = "default:dirt",
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
},
head_data = {
bone = "Neck.CTRL",
offset = {x = 0, y = 1.2, z = 0.15},
pitch_correction = 45,
offset = {x = 0, y = 1.45, z = 0.0},
pitch_correction = 25,
pivot_h = 1,
pivot_v = 1.5
},
-- Function
wander_action = animalia.action_move_flock,
utility_stack = {
[1] = {
utility = "animalia:boid_wander",
{
utility = "animalia:wander_group",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
return 0.1, {self}
end
},
[2] = {
utility = "animalia:eat_from_turf",
{
utility = "animalia:eat_turf",
step_delay = 0.25,
get_score = function(self)
return math.random(11) * 0.01, {self}
if random(64) < 2 then
return 0.2, {self}
end
return 0
end
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.95, {self}
return 0.3, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:horse_breed",
{
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.9, {self}
return 0.5, {self}
end
return 0
end
},
[6] = {
utility = "animalia:mount",
{
utility = "animalia:flee_from_target_defend",
get_score = function(self)
if self.rider
and self.saddled then
return 1, {self, self.rider}
local puncher = self._puncher
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._puncher = nil
return 0
end
},
{
utility = "animalia:tame_horse",
get_score = function(self)
local rider = not self.owner and self.rider
if rider
and rider:get_pos() then
return 0.7, {self}
end
return 0
end
},
{
utility = "animalia:mount_horse",
get_score = function(self)
local owner = self.owner and minetest.get_player_by_name(self.owner)
local rider = owner == self.rider and self.rider
if rider
and rider:get_pos() then
return 0.8, {self, rider}
end
return 0
end
@ -219,43 +268,6 @@ creatura.register_mob("animalia:horse", {
animalia.head_tracking(self)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if self.breaking
and self:timer(1) then
local pos = self:get_center_pos()
if not minetest.get_player_by_name(self.breaker) then
self.breaking = nil
self.breaker = nil
else
local yaw = self.object:get_yaw()
local yaw2 = minetest.get_player_by_name(self.breaker):get_look_horizontal()
if math.abs(yaw - yaw2) > 5.8
or math.abs(yaw - yaw2) < 0.5 then
self.breaking_progress = self.breaking_progress + 1
else
self.breaking_progress = self.breaking_progress - 1
end
self:initiate_utility("animalia:horse_breaking", self)
if self.breaking_progress < -5
or minetest.get_player_by_name(self.breaker):get_player_control().sneak then
animalia.mount(self, minetest.get_player_by_name(self.breaker))
creatura.action_idle(self, 0.5, "rear")
self.breaking = nil
self.breaker = nil
self.breaking_progress = nil
elseif self.breaking_progress > 5 then
animalia.mount(self, minetest.get_player_by_name(self.breaker))
self.owner = self:memorize("owner", self.breaker)
animalia.protect_from_despawn(self)
self.breaking = nil
self.breaker = nil
self.breaking_progress = nil
local prt_pos = vector.new(pos.x, pos.y + 2, pos.z)
local minppos = vector.add(prt_pos, 1)
local maxppos = vector.subtract(prt_pos, 1)
animalia.particle_spawner(prt_pos, "creatura_particle_green.png", "float", minppos, maxppos)
end
end
end
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
@ -275,7 +287,7 @@ creatura.register_mob("animalia:horse", {
and self.owner == clicker:get_player_name() then
if self.saddled
and tool_name == "" then
animalia.mount(self, clicker, {rot = {x = -60, y = 180, z = 0}, pos = {x = 0, y = 1.1, z = 0.5}})
animalia.mount(self, clicker, {rot = {x = -75, y = 180, z = 0}, pos = {x = 0, y = 0.6, z = 0.5}})
self:initiate_utility("animalia:mount", self, clicker)
elseif tool_name == "animalia:saddle" then
self.saddled = self:memorize("saddled", true)
@ -293,16 +305,14 @@ creatura.register_mob("animalia:horse", {
elseif not self.owner
and tool_name == "" then
animalia.mount(self, clicker, {rot = {x = -60, y = 180, z = 0}, pos = {x = 0, y = 1.1, z = 0.5}})
self.breaking = true
self.breaker = clicker:get_player_name()
self.breaking_progress = 0
end
animalia.add_libri_page(self, clicker, {name = "horse", form = "pg_horse;Horses"})
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:boid_flee_from_player", self, puncher, true)
self:set_utility_score(1)
on_punch = function(self, puncher, ...)
if self.rider and puncher == self.rider then return end
creatura.basic_punch_func(self, puncher, ...)
if self.hp < 0 then return end
self._puncher = puncher
end
})

View file

@ -5,7 +5,7 @@
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
for name in pairs(minetest.registered_items) do
if name:match(":carrot")
and (minetest.get_item_group(name, "food") > 0
or minetest.get_item_group(name, "food_carrot") > 0) then
@ -64,6 +64,7 @@ creatura.register_mob("animalia:pig", {
run = {range = {x = 1, y = 20}, speed = 45, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
consumable_nodes = destroyable_crops,
birth_count = 2,
catch_with_net = true,
@ -93,24 +94,27 @@ creatura.register_mob("animalia:pig", {
utility_stack = {
[1] = {
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
[2] = {
utility = "animalia:eat_from_turf",
step_delay = 0.25,
get_score = function(self)
if math.random(25) < 2 then
return 0.1, {self}
return 0.2, {self}
end
return 0
end
},
[3] = {
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.3, {self}
end
return 0
end
@ -118,24 +122,23 @@ creatura.register_mob("animalia:pig", {
[4] = {
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:mammal_breed",
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.9, {self}
return 0.5, {self}
end
return 0
end
@ -166,8 +169,7 @@ creatura.register_mob("animalia:pig", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:flee_from_player", self, puncher)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -5,7 +5,7 @@
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
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
@ -43,6 +43,7 @@ creatura.register_mob("animalia:reindeer", {
run = {range = {x = 70, y = 110}, speed = 50, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
drops = {
@ -68,54 +69,68 @@ creatura.register_mob("animalia:reindeer", {
},
-- Function
utility_stack = {
[1] = {
utility = "animalia:boid_wander",
{
utility = "animalia:wander_group",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
[2] = {
utility = "animalia:eat_from_turf",
get_score = function(self)
if math.random(25) < 2 then
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
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.3, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:mammal_breed",
{
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.9, {self}
return 0.5, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
},
activate_func = function(self)
@ -144,8 +159,7 @@ creatura.register_mob("animalia:reindeer", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:boid_flee_from_player", self, puncher, true)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -2,10 +2,12 @@
-- Sheep --
-----------
local random = math.random
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
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
@ -69,6 +71,7 @@ creatura.register_mob("animalia:sheep", {
run = {range = {x = 70, y = 110}, speed = 50, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -94,14 +97,8 @@ creatura.register_mob("animalia:sheep", {
},
follow = follows,
consumable_nodes = {
{
name = "default:dirt_with_grass",
replacement = "default:dirt"
},
{
name = "default:dry_dirt_with_dry_grass",
replacement = "default:dry_dirt"
}
["default:dirt_with_grass"] = "default:dirt",
["default:dry_dirt_with_dry_grass"] = "default:dry_dirt"
},
head_data = {
offset = {x = 0, y = 0.41, z = 0},
@ -111,67 +108,83 @@ creatura.register_mob("animalia:sheep", {
},
-- Function
utility_stack = {
[1] = {
utility = "animalia:wander",
{
utility = "animalia:wander_group",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
[2] = {
utility = "animalia:eat_from_turf",
get_score = function(self)
if math.random(25) < 2 then
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
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.3, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
return 0.4, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:mammal_breed",
{
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.9, {self}
return 0.5, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
},
activate_func = function(self)
self.gotten = self:recall("gotten") or false
self.collected = self:recall("collected") or false
self.dye_color = self:recall("dye_color") or "white"
self.dye_hex = self:recall("dye_hex") or ""
if self.dye_color ~= "white"
and not self.gotten then
and not self.collected then
self.object:set_properties({
textures = {"animalia_sheep.png^(animalia_sheep_wool.png^[colorize:" .. self.dye_hex .. ")"},
})
end
if self.gotten then
if self.collected then
self.object:set_properties({
textures = {"animalia_sheep.png"},
})
@ -202,7 +215,7 @@ creatura.register_mob("animalia:sheep", {
local tool = clicker:get_wielded_item()
local tool_name = tool:get_name()
if tool_name == "animalia:shears"
and not self.gotten
and not self.collected
and self.growth_scale > 0.9 then
if not minetest.get_modpath("wool") then
return
@ -213,7 +226,7 @@ creatura.register_mob("animalia:sheep", {
ItemStack( "wool:" .. self.dye_color .. " " .. math.random(1, 3) )
)
self.gotten = self:memorize("gotten", true)
self.collected = self:memorize("collected", true)
self.dye_color = self:memorize("dye_color", "white")
self.dye_hex = self:memorize("dye_hex", "#abababc000")
@ -227,9 +240,9 @@ creatura.register_mob("animalia:sheep", {
end
for _, color in ipairs(palette) do
if tool_name:find("dye:")
and not self.gotten
and not self.collected
and self.growth_scale > 0.9 then
local dye = string.split(tool_name, ":")[2]
local dye = tool_name:split(":")[2]
if color[1] == dye then
self.dye_color = self:memorize("dye_color", color[1])
@ -256,8 +269,7 @@ creatura.register_mob("animalia:sheep", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:boid_flee_from_player", self, puncher, true)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -12,7 +12,7 @@ creatura.register_mob("animalia:tropical_fish", {
despawn_after = 2500,
-- Entity Physics
stepheight = 0.1,
max_fall = 8,
max_fall = 0,
turn_rate = 8,
boid_seperation = 0.3,
bouyancy_multiplier = 0,
@ -33,19 +33,22 @@ creatura.register_mob("animalia:tropical_fish", {
flop = {range = {x = 30, y = 40}, speed = 20, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = false,
makes_footstep_sound = false,
-- Function
utility_stack = {
{
utility = "animalia:schooling",
utility = "animalia:aquatic_wander_school",
step_delay = 0.25,
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)

View file

@ -5,7 +5,7 @@
local follows = {}
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_items) do
for name in pairs(minetest.registered_items) do
if name:match(":seed_")
or name:match("_seed") then
table.insert(follows, name)
@ -41,6 +41,7 @@ creatura.register_mob("animalia:turkey", {
fall = {range = {x = 70, y = 90}, speed = 30, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -72,55 +73,78 @@ creatura.register_mob("animalia:turkey", {
pivot_v = 0.65
},
-- Function
add_child = function(self)
local pos = self.object:get_pos()
if not pos then return end
minetest.add_particlespawner({
amount = 6,
time = 0.25,
minpos = {x = pos.x - 7/16, y = pos.y - 5/16, z = pos.z - 7/16},
maxpos = {x = pos.x + 7/16, y = pos.y - 5/16, z = pos.z + 7/16},
minvel = vector.new(-1, 2, -1),
maxvel = vector.new(1, 5, 1),
minacc = vector.new(0, -9.81, 0),
maxacc = vector.new(0, -9.81, 0),
collisiondetection = true,
texture = "animalia_egg_fragment.png",
})
local object = minetest.add_entity(pos, self.name)
local ent = object:get_luaentity()
ent.growth_scale = 0.7
animalia.initialize_api(ent)
animalia.protect_from_despawn(ent)
end,
wander_action = creatura.action_move,
utility_stack = {
[1] = {
utility = "animalia:wander",
{
utility = "animalia:wander_group",
get_score = function(self)
return 0.1, {self, true}
return 0.1, {self}
end
},
[2] = {
utility = "animalia:resist_fall",
get_score = function(self)
if not self.touching_ground then
return 0.11, {self}
end
return 0
end
},
[3] = {
utility = "animalia:swim_to_land",
{
utility = "animalia:swim_to_Land",
get_score = function(self)
if self.in_liquid then
return 1, {self}
return 0.5, {self}
end
return 0
end
},
[4] = {
{
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.8, {self, self.lasso_origin, true}
end
local player = creatura.get_nearby_player(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local force = lasso and lasso ~= false
local player = (force and lasso) or creatura.get_nearby_player(self)
if player
and self:follow_wielded_item(player) then
return 0.8, {self, player}
return 0.3, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:bird_breed",
{
utility = "animalia:breed",
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name) then
return 0.9, {self}
return 0.4, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
},
activate_func = function(self)
@ -132,6 +156,10 @@ creatura.register_mob("animalia:turkey", {
animalia.head_tracking(self, 0.75, 0.75)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
if self.fall_start then
self:set_gravity(-4.9)
self:animate("fall")
end
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
@ -149,8 +177,7 @@ creatura.register_mob("animalia:turkey", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self:initiate_utility("animalia:flee_from_player", self, puncher)
self:set_utility_score(1)
self._target = puncher
end
})

View file

@ -2,7 +2,20 @@
-- Wolf --
----------
local vec_dist = vector.distance
local function shared_owner(obj1, obj2)
if not obj1 or not obj2 then return false end
obj1 = creatura.is_valid(obj1)
obj2 = creatura.is_valid(obj2)
if obj1
and obj2
and obj1:get_luaentity()
and obj2:get_luaentity() then
obj1 = obj1:get_luaentity()
obj2 = obj2:get_luaentity()
return obj1.owner and obj2.owner and obj1.owner == obj2.owner
end
return false
end
local follow = {
"animalia:mutton_raw",
@ -40,6 +53,7 @@ creatura.register_mob("animalia:wolf", {
despawn_after = 2000,
-- Entity Physics
stepheight = 1.1,
max_fall = 3,
-- Visuals
mesh = "animalia_wolf.b3d",
hitbox = {
@ -47,117 +61,91 @@ creatura.register_mob("animalia:wolf", {
height = 0.7
},
visual_size = {x = 9, y = 9},
textures = {"animalia_wolf.png"},
textures = {
"animalia_wolf_1.png",
"animalia_wolf_2.png",
"animalia_wolf_3.png",
"animalia_wolf_4.png"
},
animations = {
stand = {range = {x = 30, y = 49}, speed = 10, frame_blend = 0.3, loop = true},
sit = {range = {x = 60, y = 90}, speed = 20, frame_blend = 0.3, loop = true},
walk = {range = {x = 1, y = 20}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 1, y = 20}, speed = 45, frame_blend = 0.3, loop = true},
leap = {range = {x = 100, y = 100}, speed = 1, frame_blend = 0.15, loop = false}
stand = {range = {x = 1, y = 39}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 41, y = 59}, speed = 30, frame_blend = 0.3, loop = true},
run = {range = {x = 41, y = 59}, speed = 45, frame_blend = 0.3, loop = true},
sit = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = true,
assist_owner = true,
follow = follow,
head_data = {
offset = {x = 0, y = 0.22, z = 0},
pitch_correction = -25,
offset = {x = 0, y = 0.33, z = 0},
pitch_correction = -67,
pivot_h = 0.65,
pivot_v = 0.65
},
-- Function
utility_stack = {
[1] = {
utility = "animalia:skittish_boid_wander",
{
utility = "animalia:wander_skittish",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
return 0.1, {self}
end
},
[2] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.9, {self}
return 0.3, {self}
end
return 0
end
},
[3] = {
utility = "animalia:attack",
{
utility = "animalia:attack_target",
get_score = function(self)
local target = creatura.get_nearby_entity(self, "animalia:sheep")
local player = self._nearby_player
local is_attacking = self:get_utility() == "animalia:attack"
if player
and player:get_player_name() then
if is_value_in_table(self.enemies, player:get_player_name()) then
local nearby_players = creatura.get_nearby_players(self)
local nearby_allies = creatura.get_nearby_entities(self, self.name)
if #nearby_players < #nearby_allies then
target = player
end
end
end
if target then
if is_attacking
and self._utility_data.args[2]
and self._utility_data.args[2] == target then
return 0
end
return 0.85, {self, target}
local order = self.order or "wander"
if order ~= "wander" then return 0 end
local target = self._target or creatura.get_nearby_object(self, "animalia:sheep")
if target
and not shared_owner(self, target) then
return 0.4, {self, target}
end
return 0
end
},
[4] = {
utility = "animalia:flee_from_player",
{
utility = "animalia:stay",
step_delay = 0.25,
get_score = function(self)
local player = self._nearby_player
if player
and player:get_player_name() then
if is_value_in_table(self.enemies, player:get_player_name()) then
local nearby_players = creatura.get_nearby_players(self)
local nearby_allies = creatura.get_nearby_entities(self, self.name)
if #nearby_players >= #nearby_allies then
return 0.86, {self, player}
end
end
local order = self.order or "wander"
if order == "sit" then
return 0.5, {self}
end
return 0
end
},
[5] = {
utility = "animalia:sit",
get_score = function(self)
if self.order == "sit" then
return 0.8, {self}
end
return 0
end
},
[6] = {
{
utility = "animalia:follow_player",
get_score = function(self)
local trust = 0
local player = self._nearby_player
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
return 0.7, {self, self.lasso_origin, true}
elseif player
and self:follow_wielded_item(player) then
return 0.7, {self, player}
end
if self.order == "follow"
and self.owner
and minetest.get_player_by_name(self.owner) then
return 1, {self, minetest.get_player_by_name(self.owner), true}
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin
local owner = self.owner and self.order == "follow" and minetest.get_player_by_name(self.owner)
local force = (lasso and lasso ~= false) or owner
local player = (force and (owner or lasso)) or creatura.get_nearby_player(self)
if player
and (self:follow_wielded_item(player)
or force) then
return 0.6, {self, player, force}
end
return 0
end
},
[7] = {
utility = "animalia:mammal_breed",
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name) then
@ -170,7 +158,6 @@ creatura.register_mob("animalia:wolf", {
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
self._path = {}
self.order = self:recall("order") or "wander"
self.owner = self:recall("owner") or nil
self.enemies = self:recall("enemies") or {}
@ -194,10 +181,9 @@ creatura.register_mob("animalia:wolf", {
end,
on_rightclick = function(self, clicker)
if not clicker:is_player() then return end
local name = clicker:get_player_name()
local passive = true
if is_value_in_table(self.enemies, clicker:get_player_name()) then
passive = false
end
if is_value_in_table(self.enemies, name) then passive = false end
if animalia.feed(self, clicker, passive, passive) then
return
end
@ -205,21 +191,21 @@ creatura.register_mob("animalia:wolf", {
return
end
if self.owner
and clicker:get_player_name() == self.owner
and name == self.owner
and clicker:get_player_control().sneak then
local order = self.order
if order == "wander" then
minetest.chat_send_player(clicker:get_player_name(), "Wolf is following")
minetest.chat_send_player(name, "Wolf is following")
self.order = "follow"
self:initiate_utility("animalia:follow_player", self, clicker, true)
self:set_utility_score(1)
self:set_utility_score(0.7)
elseif order == "follow" then
minetest.chat_send_player(clicker:get_player_name(), "Wolf is sitting")
minetest.chat_send_player(name, "Wolf is sitting")
self.order = "sit"
self:initiate_utility("animalia:sit", self)
self:set_utility_score(0.8)
self:initiate_utility("animalia:stay", self)
self:set_utility_score(0.5)
else
minetest.chat_send_player(clicker:get_player_name(), "Wolf is wandering")
minetest.chat_send_player(name, "Wolf is wandering")
self.order = "wander"
self:set_utility_score(0)
end
@ -229,24 +215,24 @@ creatura.register_mob("animalia:wolf", {
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
if puncher:is_player() then
local name = puncher:is_player() and puncher:get_player_name()
if name then
if self.owner
and puncher:get_player_name() == self.owner then
and name == self.owner then
return
elseif not is_value_in_table(self.enemies, puncher:get_player_name()) then
table.insert(self.enemies, puncher:get_player_name())
elseif not is_value_in_table(self.enemies, name) then
table.insert(self.enemies, name)
if #self.enemies > 15 then
table.remove(self.enemies, 1)
end
self.enemies = self:memorize("enemies", self.enemies)
else
table.remove(self.enemies, 1)
table.insert(self.enemies, puncher:get_player_name())
table.insert(self.enemies, name)
self.enemies = self:memorize("enemies", self.enemies)
end
end
self:initiate_utility("animalia:attack", self, puncher, true)
self:set_utility_score(1)
self._target = puncher
end,
deactivate_func = function(self)
if self.owner then

View file

@ -2,5 +2,6 @@ name = animalia
depends = creatura
optional_depends = default, mcl_player
description = Adds unique and consistantly designed Animals
release = 11481
author = ElCeejo
title = Animalia

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 B

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 885 B

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 840 B

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Some files were not shown because too many files have changed in this diff Show more