Harvest Update

This commit is contained in:
ElCeejo 2022-10-17 17:23:26 -07:00
parent d1453b9501
commit 4642fb63fd
56 changed files with 1689 additions and 972 deletions

View file

@ -1,15 +0,0 @@
max_line_length = 120
globals = {
"minetest",
"animalia",
"creatura",
}
read_globals = {
"vector",
"ItemStack",
table = {fields = {"copy"}}
}
ignore = {"212/self", "212/this"}

View file

@ -315,6 +315,22 @@ end
-- Mobs -- -- Mobs --
---------- ----------
function animalia.get_dropped_food(self, item)
local pos = self.object:get_pos()
if not pos then return end
local objects = minetest.get_objects_inside_radius(pos, self.tracking_range)
for _, object in ipairs(objects) do
local ent = object:get_luaentity()
if ent
and ent.name == "__builtin:item"
and ent.itemstring
and ((item and ent.itemstring:match(item))
or self:follow_item(ItemStack(ent.itemstring))) then
return object, object:get_pos()
end
end
end
function animalia.protect_from_despawn(self) function animalia.protect_from_despawn(self)
self._despawn = self:memorize("_despawn", false) self._despawn = self:memorize("_despawn", false)
self.despawn_after = self:memorize("despawn_after", false) self.despawn_after = self:memorize("despawn_after", false)
@ -334,7 +350,7 @@ function animalia.set_nametag(self, clicker)
return return
end end
self.nametag = self:memorize("nametag", name) self.nametag = self:memorize("nametag", name)
self.despawn_after = self:memorize("despawn_after", nil) self.despawn_after = self:memorize("despawn_after", false)
activate_nametag(self) activate_nametag(self)
if not minetest.is_creative_enabled(plyr_name) then if not minetest.is_creative_enabled(plyr_name) then
item:take_item() item:take_item()
@ -343,7 +359,6 @@ function animalia.set_nametag(self, clicker)
return true return true
end end
function animalia.initialize_api(self) function animalia.initialize_api(self)
self.gender = self:recall("gender") or nil self.gender = self:recall("gender") or nil
if not self.gender then if not self.gender then
@ -448,8 +463,9 @@ function animalia.feed(self, clicker, breed, tame)
local item, item_name = self:follow_wielded_item(clicker) local item, item_name = self:follow_wielded_item(clicker)
if item_name then if item_name then
-- Eat Animation -- Eat Animation
local offset_h = self.head_data.pivot_h or 0.5 local head = self.head_data
local offset_v = self.head_data.pivot_v or 0.5 local offset_h = (head and head.pivot_h) or 0.5
local offset_v = (head and head.pivot_v) or 0.5
local head_pos = { local head_pos = {
x = pos.x + sin(yaw) * -offset_h, x = pos.x + sin(yaw) * -offset_h,
y = pos.y + offset_v, y = pos.y + offset_v,
@ -546,6 +562,15 @@ function animalia.mount(self, player, params)
end) end)
end end
function animalia.punch(self, puncher, ...)
creatura.basic_punch_func(self, puncher, ...)
self._puncher = puncher
if self.flee_puncher
and (self:get_utility() or "") ~= "animalia:flee_from_target" then
self:clear_utility()
end
end
-------------- --------------
-- Spawning -- -- Spawning --
-------------- --------------
@ -668,4 +693,4 @@ animalia.register_biome_group("common", {
min_humidity = 20, min_humidity = 20,
max_humidity = 80, max_humidity = 80,
min_height = 1 min_height = 1
}) })

View file

@ -36,6 +36,7 @@ end
local vec_dir = vector.direction local vec_dir = vector.direction
local vec_dist = vector.distance local vec_dist = vector.distance
local vec_divide = vector.divide
local vec_len = vector.length local vec_len = vector.length
local vec_normal = vector.normalize local vec_normal = vector.normalize
local vec_round = vector.round local vec_round = vector.round
@ -50,6 +51,22 @@ local yaw2dir = minetest.yaw_to_dir
-- Local Tools -- -- Local Tools --
----------------- -----------------
local farming_enabled = minetest.get_modpath("farming") and farming.registered_plants
if farming_enabled then
minetest.register_on_mods_loaded(function()
for name, def in pairs(minetest.registered_nodes) do
local item_string = name:sub(1, #name - 2)
local item_name = item_string:split(":")[2]
if farming.registered_plants[item_string]
or farming.registered_plants[item_name] then
def.groups.crop = 2
end
minetest.register_node(":" .. name, def)
end
end)
end
local animate_player = {} local animate_player = {}
if minetest.get_modpath("default") if minetest.get_modpath("default")
@ -108,6 +125,38 @@ local function add_break_particle(pos)
}) })
end end
local function add_eat_particle(self, item_name)
local pos, yaw = self.object:get_pos(), self.object:get_yaw()
if not pos then return end
local head = self.head_data
local offset_h = (head and head.pivot_h) or self.width
local offset_v = (head and head.pivot_v) or self.height
local head_pos = {
x = pos.x + sin(yaw) * -offset_h,
y = pos.y + offset_v,
z = pos.z + cos(yaw) * offset_h
}
local def = minetest.registered_items[item_name]
local image = def.inventory_image
if def.tiles then
image = def.tiles[1].name or def.tiles[1]
end
if image then
local crop = "^[sheet:4x4:" .. random(4) .. "," .. random(4)
minetest.add_particlespawner({
pos = head_pos,
time = 0.5,
amount = 12,
collisiondetection = true,
collision_removal = true,
vel = {min = {x = -1, y = 1, z = -1}, max = {x = 1, y = 2, z = 1}},
acc = {x = 0, y = -9.8, z = 0},
size = {min = 1, max = 2},
texture = image .. crop
})
end
end
local function get_group_positions(self) local function get_group_positions(self)
local objects = creatura.get_nearby_objects(self, self.name) local objects = creatura.get_nearby_objects(self, self.name)
local group = {} local group = {}
@ -118,6 +167,11 @@ local function get_group_positions(self)
return group return group
end end
local function reset_attack_vals(self)
self.punch_cooldown = 0
self.target = nil
end
-------------- --------------
-- Movement -- -- Movement --
-------------- --------------
@ -157,46 +211,32 @@ creatura.register_movement_method("animalia:fly_simple", function(self)
end) end)
creatura.register_movement_method("animalia:fly_obstacle_avoidance", function(self) creatura.register_movement_method("animalia:fly_obstacle_avoidance", function(self)
local box = clamp(self.width, 0.5, 1.5)
local steer_to local steer_to
local steer_timer = 0.25 local steer_timer = 0.25
local init_dist
self:set_gravity(0) self:set_gravity(0)
local function func(_self, goal, speed_factor) local function func(_self, goal, speed_factor)
local pos = _self.object:get_pos() local pos = _self.object:get_pos()
if not pos then return end if not pos then return end
-- Return true when goal is reached local dist = vec_dist(pos, goal)
if vec_dist(pos, goal) < box * 1.33 then init_dist = dist
if dist < clamp(self.width, 0.5, 1) + 1.5 then
_self:halt() _self:halt()
return true return true
end end
steer_timer = steer_timer - self.dtime -- Calculate Movement
if steer_timer <= 0 then steer_timer = (steer_timer > 0 and steer_timer - self.dtime) or 0.25
steer_to = get_avoidance_dir(_self) steer_to = (steer_timer <= 0 and creatura.get_context_steering(self, goal, 4, true)) or steer_to
end
-- Get movement direction
local goal_dir = vec_dir(pos, goal)
if steer_to then
steer_to.y = goal_dir.y
goal_dir = steer_to
end
local yaw = _self.object:get_yaw()
local goal_yaw = dir2yaw(goal_dir)
local speed = abs(_self.speed or 2) * speed_factor or 0.5 local speed = abs(_self.speed or 2) * speed_factor or 0.5
local turn_rate = abs(_self.turn_rate or 5) local turn_rate = abs(_self.turn_rate or 5)
-- Movement local dist_weight = (init_dist - dist) / init_dist
local yaw_diff = abs(diff(yaw, goal_yaw)) -- Apply Movement
if yaw_diff < pi * 0.25 local dir = (steer_to or vec_dir(pos, goal))
or steer_to then speed = speed - (speed * 0.75) * dist_weight
_self:set_forward_velocity(speed) turn_rate = turn_rate + turn_rate * dist_weight
else _self:set_forward_velocity(speed)
_self:set_forward_velocity(speed * 0.33) _self:set_vertical_velocity(speed * dir.y)
end _self:turn_to(dir2yaw(dir), turn_rate)
self:set_vertical_velocity(speed * goal_dir.y)
_self:turn_to(goal_yaw, turn_rate)
if _self.touching_ground
or _self.in_liquid then
_self.object:add_velocity({x = 0, y = 2, z = 0})
end
end end
return func return func
end) end)
@ -223,7 +263,7 @@ creatura.register_movement_method("animalia:swim_simple", function(self)
if yaw_diff < pi * 0.25 then if yaw_diff < pi * 0.25 then
_self:set_forward_velocity(speed) _self:set_forward_velocity(speed)
else else
_self:set_forward_velocity(speed * 0.33) _self:set_forward_velocity(speed * 0.66)
end end
self:set_vertical_velocity(speed * goal_dir.y) self:set_vertical_velocity(speed * goal_dir.y)
_self:turn_to(goal_yaw, turn_rate) _self:turn_to(goal_yaw, turn_rate)
@ -280,7 +320,7 @@ function animalia.action_pursue(self, target, timeout, method, speed_factor, ani
local timer = timeout or 4 local timer = timeout or 4
local goal local goal
local function func(_self) local function func(_self)
local target_alive, line_of_sight, tgt_pos = self:get_target(target) local target_alive, line_of_sight, tgt_pos = _self:get_target(target)
if not target_alive then if not target_alive then
return true return true
end end
@ -307,6 +347,92 @@ function animalia.action_pursue(self, target, timeout, method, speed_factor, ani
self:set_action(func) self:set_action(func)
end end
function animalia.action_pursue_glide(self, target, timeout, method, speed_factor, anim)
local timer = timeout or 4
local goal
local speed_x = speed_factor
local function func(_self)
local target_alive, line_of_sight, tgt_pos = _self:get_target(target)
if not target_alive then
return true
end
goal = goal or tgt_pos
timer = timer - _self.dtime
self:animate(anim or "walk")
if line_of_sight
and vec_dist(goal, tgt_pos) > 3 then
goal = tgt_pos
end
local vel = self.object:get_velocity()
if vel.y < 0 and speed_x < speed_factor + 0.5 then speed_x = speed_x + self.dtime * 0.5 end
if vel.y >= 0 and speed_x > speed_factor then speed_x = speed_x - self.dtime * 0.25 end
if timer <= 0
or _self:move_to(goal, method or "animalia:fly_obstacle_avoidance", speed_x) then
return true
end
end
self:set_action(func)
end
function animalia.action_flight_attack(self, target, timeout)
local anim = self.animations["fly_punch"]
local anim_len = (anim.range.y - anim.range.x) / anim.speed
local anim_time = 0
local timer = timeout or 12
local cooldown = 0
local speed_x = 0.5
local goal
local function func(_self)
local pos = _self.stand_pos
if timer <= 0 then return true end
local target_alive, los, tgt_pos = _self:get_target(target)
if not target_alive then return true end
local dist = vec_dist(pos, tgt_pos)
if dist > 32 then return true end
local vel = self.object:get_velocity()
if vel.y < 0 and speed_x < 1 then speed_x = speed_x + self.dtime * 0.5 end
if vel.y >= 0 and speed_x > 0.5 then speed_x = speed_x - self.dtime end
if anim_time > 0 then
_self:animate("fly_punch")
anim_time = anim_time - _self.dtime
else
if speed_x > 0.6 then
_self:animate("glide")
else
_self:animate("fly")
end
end
if cooldown > 0 then
goal = goal or _self:get_wander_pos_3d(3, 6, nil, 1)
cooldown = cooldown - _self.dtime
else
goal = nil
cooldown = 0
end
if goal
and _self:move_to(goal, "animalia:fly_obstacle_avoidance", speed_x) then
goal = nil
end
if not goal
and _self:move_to(tgt_pos, "animalia:fly_obstacle_avoidance", speed_x) then
if dist < _self.width + 1 then
_self:punch_target(target)
cooldown = timeout / 3
anim_time = anim_len
end
end
timer = timer - _self.dtime
end
self:set_action(func)
end
function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, anim, boid_steer) function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, anim, boid_steer)
local old_boids = (self._movement_data and self._movement_data.boids) or {} local old_boids = (self._movement_data and self._movement_data.boids) or {}
local boids = (#old_boids > 2 and old_boids) or creatura.get_boid_members(self.object:get_pos(), 12, self.name) local boids = (#old_boids > 2 and old_boids) or creatura.get_boid_members(self.object:get_pos(), 12, self.name)
@ -357,6 +483,55 @@ function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, a
self:set_action(func) self:set_action(func)
end end
function animalia.action_move_boid(self, pos2, timeout, method, speed_factor, anim, water)
local timer = timeout or 4
local goal
local function func(_self)
local pos, vel = self.object:get_pos(), self.object:get_velocity()
if not pos then return end
local move_data = self._movement_data or {}
-- Tick down timer
timer = timer - _self.dtime
-- Check if goal is safe
local safe = true
local max_fall = (_self.max_fall or 0) > 0 and _self.max_fall
if max_fall then
safe = _self:is_pos_safe(goal)
end
-- Boid calculation
local boid_dir, boids = move_data.boid_dir or creatura.get_boid_dir(self)
if boid_dir then
local heading = vec_dir(pos, pos2)
boid_dir.y = boid_dir.y + heading.y / 2
goal = vec_add(pos, vec_multi(boid_dir, self.width + 1))
if max_fall then
goal = creatura.get_ground_level(goal, 2)
end
if boids then
for _, obj in ipairs(boids) do
local ent = obj and obj:get_luaentity()
if ent then
ent._movement_data.boid_dir = boid_dir
end
end
end
else
goal = pos2
end
local steer_dir = creatura.get_context_steering(self, goal, 1, water)
goal = (steer_dir and vec_add(pos, steer_dir)) or goal
-- Main movement
if timer <= 0
or not safe
or _self:move_to(goal, method or "creatura:obstacle_avoidance", speed_factor or 0.5) then
return true
end
self:animate(anim or "walk")
self._movement_data.boid_dir = nil
end
self:set_action(func)
end
function animalia.action_float(self, time, anim) function animalia.action_float(self, time, anim)
local timer = time local timer = time
local function func(_self) local function func(_self)
@ -528,7 +703,7 @@ creatura.register_utility("animalia:swim_to_land", function(self)
_self:set_gravity(-9.8) _self:set_gravity(-9.8)
_self:set_forward_velocity(_self.speed * 0.66) _self:set_forward_velocity(_self.speed * 0.66)
_self:animate("walk") _self:animate("walk")
if vector.distance(pos, tpos) < 1 if vec_dist(pos, tpos) < 1
or (not _self.in_liquid or (not _self.in_liquid
and _self.touching_ground) then and _self.touching_ground) then
return true return true
@ -569,7 +744,7 @@ creatura.register_utility("animalia:wander_group", function(self)
local center = self.object:get_pos() local center = self.object:get_pos()
if not center then return end if not center then return end
local group_tick = 500 local group_tick = 500
local move = self.wander_action or animalia.action_move_flock local move = self.wander_action or animalia.action_move_boid
local function func(_self) local function func(_self)
group_tick = group_tick - 1 group_tick = group_tick - 1
if group_tick <= 0 then if group_tick <= 0 then
@ -631,6 +806,7 @@ creatura.register_utility("animalia:aerial_wander", function(self)
local center = self.object:get_pos() local center = self.object:get_pos()
if not center then return end if not center then return end
local height_tick = 0 local height_tick = 0
local move = self.wander_action or creatura.action_move
local function func(_self) local function func(_self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
@ -643,7 +819,7 @@ creatura.register_utility("animalia:aerial_wander", function(self)
if not _self:get_action() then if not _self:get_action() then
local move_dir = (vec_dist(pos, center) > 8 and vec_dir(pos, center)) or nil local move_dir = (vec_dist(pos, center) > 8 and vec_dir(pos, center)) or nil
local pos2 = _self:get_wander_pos_3d(2, 5, move_dir) local pos2 = _self:get_wander_pos_3d(2, 5, move_dir)
animalia.action_move_flock(_self, pos2, 3, "animalia:fly_simple", 1, "fly", true) move(_self, pos2, 3, "animalia:fly_simple", 1, "fly", true)
end end
end end
self:set_utility(func) self:set_utility(func)
@ -652,25 +828,24 @@ end)
creatura.register_utility("animalia:fly_to_roost", function(self) creatura.register_utility("animalia:fly_to_roost", function(self)
local home = self.home_position local home = self.home_position
local roost = self.roost_action or creatura.action_idle local roost = self.roost_action or creatura.action_idle
local is_home = self.is_roost or function(pos, home_pos)
if abs(pos.x - home_pos.x) < 0.5
and abs(pos.z - home_pos.z) < 0.5
and abs(pos.y - home_pos.y) < 0.75 then
return true
end
return false
end
local function func(_self) local function func(_self)
local pos = _self.object:get_pos() local pos = _self.object:get_pos()
if not pos then return end if not pos then return end
if not home then return true end if not home then return true end
if not _self:get_action() then if not _self:get_action() then
if abs(pos.x - home.x) < 0.5 if is_home(pos, home) then
and abs(pos.z - home.z) < 0.5 then roost(_self, 1, "stand")
local y_diff = abs(pos.y - home.y) return
if y_diff < 0.7 then
roost(_self, 1, "stand")
return
end
if y_diff <= 2
and not minetest.line_of_sight(pos, home) then
self.home_positon = nil
self:forget("home_position")
end
end end
creatura.action_move(_self, home, 3, "animalia:fly_simple", 1, "fly") creatura.action_move(_self, home, 3, "animalia:fly_obstacle_avoidance", 1, "fly")
end end
end end
self:set_utility(func) self:set_utility(func)
@ -714,7 +889,7 @@ creatura.register_utility("animalia:aquatic_wander_school", function(self)
water_nodes = minetest.find_nodes_in_area(vec_sub(center, 4), vec_add(center, 4), {"group:water"}) water_nodes = minetest.find_nodes_in_area(vec_sub(center, 4), vec_add(center, 4), {"group:water"})
end end
if not _self:get_action() then if not _self:get_action() then
animalia.action_move_flock(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_simple", 1, "swim", true) animalia.action_move_boid(_self, water_nodes[random(#water_nodes)], 3, "animalia:swim_simple", 1, "swim")
end end
end end
self:set_utility(func) self:set_utility(func)
@ -844,7 +1019,7 @@ creatura.register_utility("animalia:follow_player", function(self, player, force
local dist = vec_dist(pos, plyr_pos) local dist = vec_dist(pos, plyr_pos)
if not _self:get_action() then if not _self:get_action() then
if dist > width + 1 then if dist > width + 1 then
animalia.action_pursue(_self, player, 3, "creatura:obstacle_avoidance", 0.75) animalia.action_pursue(_self, player, 3, "creatura:context_based_steering", 0.75)
else else
creatura.action_idle(_self, 1) creatura.action_idle(_self, 1)
end end
@ -872,7 +1047,7 @@ creatura.register_utility("animalia:flee_from_target", function(self, target)
local flee_dir = vec_dir(tgt_pos, pos) local flee_dir = vec_dir(tgt_pos, pos)
local pos2 = _self:get_wander_pos(2, 3, flee_dir) local pos2 = _self:get_wander_pos(2, 3, flee_dir)
local anim = (_self.animations["run"] and "run") or "walk" local anim = (_self.animations["run"] and "run") or "walk"
creatura.action_move(_self, pos2, 2, "creatura:obstacle_avoidance", 1, anim) creatura.action_move(_self, pos2, 2, "creatura:context_based_steering", 1, anim)
end end
end end
self:set_utility(func) self:set_utility(func)
@ -985,8 +1160,9 @@ creatura.register_utility("animalia:attack_target", function(self, target)
local pos = _self.object:get_pos() local pos = _self.object:get_pos()
if not pos then return end if not pos then return end
local tgt_alive, _, tgt_pos = _self:get_target(target) local tgt_alive, _, tgt_pos = _self:get_target(target)
if not tgt_alive then return true end if not tgt_alive then reset_attack_vals(self) return true end
local dist = vec_dist(pos, tgt_pos) local dist = vec_dist(pos, tgt_pos)
if dist > self.tracking_range then reset_attack_vals(self) return true end
local punch_cooldown = self.punch_cooldown or 0 local punch_cooldown = self.punch_cooldown or 0
if punch_cooldown > 0 then if punch_cooldown > 0 then
punch_cooldown = punch_cooldown - self.dtime punch_cooldown = punch_cooldown - self.dtime
@ -997,16 +1173,40 @@ creatura.register_utility("animalia:attack_target", function(self, target)
and not punch_init then and not punch_init then
punch_init = true punch_init = true
animalia.action_punch(_self, target) animalia.action_punch(_self, target)
self.punch_cooldown = 3 self.punch_cooldown = 1.5
end end
if not _self:get_action() then if not _self:get_action() then
if punch_init then return true end if punch_init then reset_attack_vals(self) return true end
animalia.action_pursue(_self, target, 3, "creatura:pathfind", 0.75) animalia.action_pursue(_self, target, 3, "creatura:pathfind", 0.75)
end end
end end
self:set_utility(func) self:set_utility(func)
end) end)
creatura.register_utility("animalia:glide_attack_target", function(self, target)
local hidden_timer = 1
local attack_init = false
local function func(_self)
local pos, yaw = _self.object:get_pos(), _self.object:get_yaw()
if not pos then return end
local target_alive, los, tgt_pos = _self:get_target(target)
if not target_alive then
_self._target = nil
return true
end
if not _self:get_action() then
if attack_init then return true end
local dist = vec_dist(pos, tgt_pos)
if dist > 14 then
creatura.action_move(_self, tgt_pos, 3, "animalia:fly_obstacle_avoidance", 0.5, "fly")
else
animalia.action_flight_attack(_self, target, 12)
end
end
end
self:set_utility(func)
end)
creatura.register_utility("animalia:breed", function(self) creatura.register_utility("animalia:breed", function(self)
local mate = animalia.get_nearby_mate(self, self.name) local mate = animalia.get_nearby_mate(self, self.name)
if not mate then self.breeding = false return end if not mate then self.breeding = false return end
@ -1050,6 +1250,174 @@ creatura.register_utility("animalia:breed", function(self)
self:set_utility(func) self:set_utility(func)
end) end)
creatura.register_utility("animalia:fly_to_food", function(self, food_item)
local eat_init = false
local function func(_self)
local pos, tgt_pos = _self.object:get_pos(), food_item and food_item:get_pos()
if not pos then return end
if not tgt_pos and not eat_init then return true end
local dist = vec_dist(pos, tgt_pos or pos)
if dist < 1
and not eat_init then
eat_init = true
local food_ent = food_item:get_luaentity()
local stack = ItemStack(food_ent.itemstring)
if stack
and stack:get_count() > 1 then
stack:take_item()
food_ent.itemstring = stack:to_string()
else
food_item:remove()
end
self.object:get_yaw(dir2yaw(vec_dir(pos, tgt_pos)))
add_eat_particle(self, "animalia:rat_raw")
creatura.action_idle(_self, 1, "eat")
self.eat_cooldown = 60
if self.on_eat_drop then
self:on_eat_drop()
end
end
if not _self:get_action() then
if eat_init then return true end
creatura.action_move(_self, tgt_pos, 3, "animalia:fly_simple", 1, "fly")
end
end
self:set_utility(func)
end)
creatura.register_utility("animalia:walk_to_food", function(self, food_item)
local eat_init = false
local function func(_self)
local pos, tgt_pos = _self.object:get_pos(), food_item and food_item:get_pos()
if not pos then return end
if not tgt_pos and not eat_init then return true end
local dist = vec_dist(pos, tgt_pos or pos)
if dist < 1
and not eat_init then
eat_init = true
local food_ent = food_item:get_luaentity()
local stack = ItemStack(food_ent.itemstring)
if stack
and stack:get_count() > 1 then
stack:take_item()
food_ent.itemstring = stack:to_string()
else
food_item:remove()
end
self.object:get_yaw(dir2yaw(vec_dir(pos, tgt_pos)))
add_eat_particle(self, "animalia:rat_raw")
local anim = (self.animations["eat"] and "eat") or "stand"
creatura.action_idle(_self, 1, anim)
self.eat_cooldown = 60
if self.on_eat_drop then
self:on_eat_drop()
end
end
if not _self:get_action() then
if eat_init then return true end
creatura.action_move(_self, tgt_pos, 3, "creatura:context_based_steering", 0.5, "walk")
end
end
self:set_utility(func)
end)
-- Pest Behavior
creatura.register_utility("animalia:eat_crop", function(self)
local center = self.object:get_pos()
if not center then return end
local width = self.width
local timeout = 8
local nodes = minetest.find_nodes_in_area(vec_sub(center, 6), vec_add(center, 6), "group:crop") or {}
local pos2
local anim_init = false
local function func(_self)
local pos = _self.object:get_pos()
if not pos then return end
if #nodes < 1 then return true end
if not _self:get_action() then
if anim_init then return true end
pos2 = pos2 or nodes[random(#nodes)]
local node_name = minetest.get_node(pos2).name
local dist = vec_dist(pos, pos2)
if dist < width + 0.5 then
local new_name = node_name:sub(1, #node_name - 1) .. (tonumber(node_name:sub(-1)) or 2) - 1
local new_def = minetest.registered_nodes[new_name]
if not new_def then return true end
local p2 = new_def.place_param2 or 1
minetest.set_node(pos2, {name = new_name, param2 = p2})
add_eat_particle(self, new_name)
anim_init = true
creatura.action_idle(_self, 0.5, "eat")
else
creatura.action_move(_self, pos2, 4, "creatura:context_based_steering")
end
end
timeout = timeout - _self.dtime
if timeout <= 0 then return true end
end
self:set_utility(func)
end)
local function take_food_from_chest(self, pos)
local inv = minetest.get_inventory({type = "node", pos = pos})
if inv
and inv:get_list("main") then
for i, stack in ipairs(inv:get_list("main")) do
local item_name = stack:get_name()
local def = minetest.registered_items[item_name]
for group in pairs(def.groups) do
if group:match("food_") then
stack:take_item()
inv:set_stack("main", i, stack)
add_eat_particle(self, item_name)
return true
end
end
end
end
end
creatura.register_utility("animalia:steal_from_chest", function(self)
local center = self.object:get_pos()
if not center then return end
local width = self.width
local timeout = 8
local nodes = minetest.find_nodes_with_meta(vec_sub(center, 6), vec_add(center, 6)) or {}
local pos2
for _, node_pos in ipairs(nodes) do
local meta = minetest.get_meta(node_pos)
if meta:get_string("owner") == "" then
local inv = minetest.get_inventory({type = "node", pos = node_pos})
if inv
and inv:get_list("main") then
pos2 = node_pos
end
end
end
local anim_init = false
local function func(_self)
local pos = _self.object:get_pos()
if not pos then return end
if not pos2 then return true end
if not _self:get_action() then
if anim_init then return true end
local dist = vec_dist(pos, pos2)
if dist < width + 1.1 then
anim_init = true
if take_food_from_chest(self, pos2) then
creatura.action_idle(_self, 0.5, "eat")
end
else
creatura.action_move(_self, pos2, 2, "creatura:context_based_steering")
end
end
timeout = timeout - _self.dtime
if timeout <= 0 then return true end
end
self:set_utility(func)
end)
-- Domesticated Behavior -- Domesticated Behavior
creatura.register_utility("animalia:stay", function(self) creatura.register_utility("animalia:stay", function(self)
@ -1189,7 +1557,7 @@ creatura.register_utility("animalia:mount_horse", function(self, player)
and vel.y < 1 then and vel.y < 1 then
_self.object:add_velocity({ _self.object:add_velocity({
x = 0, x = 0,
y = _self.jump_power + (abs(_self._movement_data.gravity) * 0.33), y = _self.jump_power,
z = 0 z = 0
}) })
elseif not _self.touching_ground then elseif not _self.touching_ground then
@ -1229,4 +1597,36 @@ creatura.register_utility("animalia:flop", function(self)
_self:set_gravity(-9.8) _self:set_gravity(-9.8)
end end
self:set_utility(func) self:set_utility(func)
end) end)
-- Global Utilities
animalia.global_utils = {
["basic_follow"] = {
utility = "animalia:follow_player",
get_score = function(self)
local lasso_tgt = self._lassod_to
local lasso = type(lasso_tgt) == "string" and minetest.get_player_by_name(lasso_tgt)
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)
or force) then
return 0.4, {self, player, force}
end
return 0
end
},
["basic_flee"] = {
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._puncher
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._puncher = nil
return 0
end
}
}

View file

@ -3,359 +3,253 @@
----------- -----------
local abs = math.abs local abs = math.abs
local asin = math.asin
local atan2 = math.atan2
local cos = math.cos
local deg = math.deg
local sin = math.sin
function animalia.initialize_lasso(self) local function diff(a, b) -- Get difference between 2 angles
self.lasso_origin = self:recall("lasso_origin") or nil return atan2(sin(b - a), cos(b - a))
if self.lasso_origin then
self.caught_with_lasso = true
if type(self.lasso_origin) == "table"
and minetest.get_item_group(minetest.get_node(self.lasso_origin).name, "fence") > 0 then
local object = minetest.add_entity(self.lasso_origin, "animalia:lasso_fence_ent")
object:get_luaentity().parent = self.object
elseif type(self.lasso_origin) == "string"
and minetest.get_player_by_name(self.lasso_origin) then
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin)
else
self:forget("lasso_origin")
end
end
end end
function animalia.set_lasso_visual(self, target) local vec_add, vec_dir, vec_dist, vec_len = vector.add, vector.direction, vector.distance, vector.length
if not creatura.is_alive(self) local dir2yaw, dir2rot = minetest.dir_to_yaw, vector.dir_to_rotation
or (self.lasso_visual
and self.lasso_visual:get_luaentity()) then return end -- Entities --
local pos = self.object:get_pos()
local object = minetest.add_entity(pos, "animalia:lasso_visual") local using_lasso = {}
local ent = object:get_luaentity()
self.lasso_visual = object minetest.register_entity("animalia:lasso_entity", {
self.lasso_origin = target visual = "mesh",
ent.parent = self.object mesh = "animalia_lasso_entity.b3d",
ent.lasso_origin = target textures = {"animalia_lasso_entity.png"},
return object pointable = false,
on_activate = function(self)
self.object:set_armor_groups({immortal = 1})
end,
_scale = 1,
on_step = function(self, dtime)
local pos, parent = self.object:get_pos(), (self.object:get_attach() or self._attached)
local pointed_ent = self._point_to and self._point_to:get_luaentity()
local point_to = self._point_to and self._point_to:get_pos()
if not pos or not parent or not point_to then self.object:remove() return end
if type(parent) == "string" then
parent = minetest.get_player_by_name(parent)
local tgt_pos = parent:get_pos()
local dist = vec_dist(pos, tgt_pos)
if dist > 0.5 then
self.object:set_pos(tgt_pos)
else
self.object:move_to(tgt_pos)
end
self.object:set_rotation(dir2rot(vec_dir(tgt_pos, point_to)))
elseif parent.x then
point_to.y = point_to.y + pointed_ent.height * 0.5
self.object:set_rotation(dir2rot(vec_dir(pos, point_to)))
else
self.object:remove()
return
end
local size = vec_dist(pos, point_to)
if abs(size - self._scale) > 0.1 then
self.object:set_properties({
visual_size = {x = 1, y = 1, z = size}
})
self._scale = size
end
end
})
local function remove_from_fence(self)
local pos = self.object:get_pos()
local mob = self._mob and self._mob:get_luaentity()
if not mob then
self.object:remove()
return
end
mob._lassod_to = nil
mob:forget("_lassod_to")
mob._lasso_ent:remove()
local dirs = {
{x = 0.5, y = 0, z = 0},
{x = -0.5, y = 0, z = 0},
{x = 0, y = 0.5, z = 0},
{x = 0, y = -0.5, z = 0},
{x = 0, y = 0, z = 0.5},
{x = 0, y = 0, z = -0.5}
}
for i = 1, 6 do
local i_pos = vec_add(pos, dirs[i])
if not creatura.get_node_def(i_pos).walkable then
minetest.add_item(i_pos, "animalia:lasso")
break
end
end
self.object:remove()
end
minetest.register_entity("animalia:tied_lasso_entity", {
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
visual = "cube",
visual_size = {x = 0.3, y = 0.3},
mesh = "model",
textures = {
"animalia_tied_lasso_entity.png",
"animalia_tied_lasso_entity.png",
"animalia_tied_lasso_entity.png",
"animalia_tied_lasso_entity.png",
"animalia_tied_lasso_entity.png",
"animalia_tied_lasso_entity.png",
},
on_activate = function(self)
self.object:set_armor_groups({immortal = 1})
end,
on_step = function(self)
local mob = self._mob and self._mob:get_luaentity()
if not mob then remove_from_fence(self) return end
end,
on_rightclick = remove_from_fence,
on_punch = remove_from_fence
})
-- API --
local function add_lasso(self, origin)
local pos = self.object:get_pos()
if not pos then return end
local object = minetest.add_entity(pos, "animalia:lasso_entity")
local ent = object and object:get_luaentity()
if not ent then return end
-- Attachment point of entity
ent._attached = origin
if type(origin) == "string" then
local player = minetest.get_player_by_name(origin)
--object:set_attach(player)
else
object:set_pos(origin)
end
self._lassod_to = origin
ent._point_to = self.object
self:memorize("_lassod_to", origin)
return object
end
local function get_rope_velocity(pos1, pos2, dist)
local force = dist / 10
local vel = vector.new((pos2.x - pos1.x) * force, ((pos2.y - pos1.y) / (24 + dist)), (pos2.z - pos1.z) * force)
return vel
end
function animalia.initialize_lasso(self)
self._lassod_to = self:recall("_lassod_to") or self:recall("lasso_origin")
if self._lassod_to then
local origin = self._lassod_to
if type(origin) == "table"
and minetest.get_item_group(minetest.get_node(origin).name, "fence") > 0 then
local object = minetest.add_entity(origin, "animalia:tied_lasso_entity")
object:get_luaentity()._mob = self.object
self._lasso_ent = add_lasso(self, origin)
elseif type(origin) == "string" then
self._lassod_to = origin
self._lasso_ent = add_lasso(self, origin)
else
self:forget("_lassod_to")
end
end
end end
function animalia.update_lasso_effects(self) function animalia.update_lasso_effects(self)
if not creatura.is_alive(self) then return end local pos = self.object:get_pos()
if self.caught_with_lasso if not creatura.is_alive(self) then return end
and self.lasso_origin then if self._lassod_to then
local pos = self.object:get_pos() local lasso = self._lassod_to
pos.y = pos.y + (self:get_height() * 0.5) self._lasso_ent = self._lasso_ent or add_lasso(self, lasso)
animalia.set_lasso_visual(self, self.lasso_origin) if type(lasso) == "string" then
if type(self.lasso_origin) == "userdata" using_lasso[lasso] = self
or type(self.lasso_origin) == "string" then local name = lasso
if type(self.lasso_origin) == "string" then lasso = minetest.get_player_by_name(lasso)
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin) if lasso:get_wielded_item():get_name() ~= "animalia:lasso" then
if not self.lasso_origin then using_lasso[name] = nil
self.caught_with_lasso = nil self._lasso_ent:remove()
self.lasso_origin = nil self._lasso_ent = nil
self:forget("lasso_origin") self._lassod_to = nil
if self.lasso_visual then self:forget("_lassod_to")
self.lasso_visual:remove() return
self.lasso_visual = nil end
end local lasso_pos = lasso:get_pos()
return local dist = vec_dist(pos, lasso_pos)
end local vel = self.object:get_velocity()
end if not vel or dist < 8 and self.touching_ground then return end
self:memorize("lasso_origin", self.lasso_origin:get_player_name()) if vec_len(vel) < 8 then
-- Get distance to lasso player self.object:add_velocity(get_rope_velocity(pos, lasso_pos, dist))
local player = self.lasso_origin end
local lasso_origin = player:get_pos() return
lasso_origin.y = lasso_origin.y + 1 elseif type(lasso) == "table" then
local dist = vector.distance(pos, lasso_origin) local dist = vec_dist(pos, lasso)
if player:get_wielded_item():get_name() ~= "animalia:lasso" local vel = self.object:get_velocity()
or vector.distance(pos, lasso_origin) > 16 then if not vel or dist < 8 and self.touching_ground then return end
self.caught_with_lasso = nil if vec_len(vel) < 8 then
self.lasso_origin = nil self.object:add_velocity(get_rope_velocity(pos, lasso, dist))
self:forget("lasso_origin") end
if self.lasso_visual then return
self.lasso_visual:remove() end
self.lasso_visual = nil end
end if self._lasso_ent then
end self._lasso_ent:remove()
-- Apply physics self._lasso_ent = nil
if dist > 6 self._lassod_to = nil
or abs(lasso_origin.y - pos.y) > 8 then self:forget("_lassod_to")
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8)) end
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
elseif type(self.lasso_origin) == "table" then
self:memorize("lasso_origin", self.lasso_origin)
local lasso_origin = self.lasso_origin
local dist = vector.distance(pos, lasso_origin)
if dist > 6
or abs(lasso_origin.y - pos.y) > 8 then
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8))
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
local objects = minetest.get_objects_inside_radius(lasso_origin, 1)
local is_lasso_attached = false
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
is_lasso_attached = true
end
end
if not is_lasso_attached then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
else
local objects = minetest.get_objects_inside_radius(self.lasso_origin, 0.4)
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
minetest.add_item(object:get_pos(), "animalia:lasso")
object:remove()
end
end
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
end
end end
local function is_lasso_in_use(player) -- Item
for _, ent in pairs(minetest.luaentities) do
if ent.name
and ent.name:match("^animalia:") then
if ent.lasso_origin
and type(ent.lasso_origin) == "userdata"
and ent.lasso_origin == player then
return true
end
end
end
return false
end
local function update_lasso_rotation(self)
if not self.parent
or not self.lasso_origin then self.object:remove() return end
local lasso_origin = self.lasso_origin
if type(lasso_origin) == "userdata" then
lasso_origin = lasso_origin:get_pos()
lasso_origin.y = lasso_origin.y + 1
end
local object = self.parent
if not object then return end
local pos = object:get_pos()
pos.y = pos.y + object:get_luaentity():get_height()
local rot = vector.dir_to_rotation(vector.direction(lasso_origin, pos))
self.object:set_pos(lasso_origin)
self.object:set_rotation(rot)
self.object:set_properties({
visual_size = {x = 6, z = 10 * vector.distance(pos, lasso_origin), y = 6}
})
end
minetest.register_entity("animalia:lasso_visual", {
hp_max = 1,
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "mesh",
mesh = "animalia_lasso.b3d",
visual_size = {x = 2, y = 2},
textures = {"animalia_lasso_cube.png"},
is_visible = true,
makes_footstep_sound = false,
glow = 1,
on_step = function(self)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
or (self.parent
and (not creatura.is_alive(self.parent)
or not self.parent:get_luaentity().caught_with_lasso)) then
self.object:remove()
return
end
update_lasso_rotation(self)
end
})
minetest.register_entity("animalia:frog_tongue_visual", {
hp_max = 1,
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "mesh",
mesh = "animalia_lasso.b3d",
visual_size = {x = 2, y = 2},
textures = {"animalia_frog_tongue.png"},
is_visible = true,
makes_footstep_sound = false,
on_step = function(self)
self.object:set_armor_groups({immortal = 1})
if not self.parent
or not self.lasso_origin
or (self.parent
and (not creatura.is_alive(self.parent)
or not self.parent:get_luaentity().caught_with_lasso)) then
self.object:remove()
return
end
update_lasso_rotation(self)
end
})
minetest.register_entity("animalia:lasso_fence_ent", {
physical = false,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
visual = "cube",
visual_size = {x = 0.3, y = 0.3},
mesh = "model",
textures = {
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
"animalia_lasso_cube.png",
},
makes_footstep_sound = false,
on_step = function(self)
if not self.parent
or not self.parent:get_luaentity()
or not self.parent:get_luaentity().lasso_origin then
self.object:remove()
return
end
local pos = self.object:get_pos()
local node = minetest.get_node(pos)
if not minetest.registered_nodes[node.name].walkable
or minetest.get_item_group(node.name, "fence") < 1 then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
minetest.add_item(self.object:get_pos(), "animalia:lasso")
self.object:remove()
return
end
end,
on_rightclick = function(self)
if self.parent then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
end
local dirs = {
vector.new(1, 0, 0),
vector.new(-1, 0, 0),
vector.new(0, 1, 0),
vector.new(0, -1, 0),
vector.new(0, 0, 1),
vector.new(0, 0, -1),
}
for i = 1, 6 do
local pos = vector.add(self.object:get_pos(), dirs[i])
local name = minetest.get_node(pos).name
if not minetest.registered_nodes[name].walkable then
minetest.add_item(pos, "animalia:lasso")
break
end
end
self.object:remove()
end,
on_punch = function(self)
if self.parent then
local ent = self.parent:get_luaentity()
ent.lasso_origin = ent:memorize("lasso_origin", nil)
ent.caught_with_lasso = nil
if ent.lasso_visual then
ent.lasso_visual:remove()
ent.lasso_visual = nil
end
end
local dirs = {
vector.new(1, 0, 0),
vector.new(-1, 0, 0),
vector.new(0, 1, 0),
vector.new(0, -1, 0),
vector.new(0, 0, 1),
vector.new(0, 0, -1),
}
for i = 1, 6 do
local pos = vector.add(self.object:get_pos(), dirs[i])
local name = minetest.get_node(pos).name
if not minetest.registered_nodes[name].walkable then
minetest.add_item(pos, "animalia:lasso")
break
end
end
self.object:remove()
end
})
minetest.register_craftitem("animalia:lasso", { minetest.register_craftitem("animalia:lasso", {
description = "Lasso", description = "Lasso",
inventory_image = "animalia_lasso.png", inventory_image = "animalia_lasso.png",
on_secondary_use = function(_, placer, pointed_thing) on_secondary_use = function(_, placer, pointed)
if pointed_thing.type == "object" then local ent = pointed.ref and pointed.ref:get_luaentity()
if pointed_thing.ref:is_player() then return end if ent
local ent = pointed_thing.ref:get_luaentity() and (ent.name:match("^animalia:")
if not ent.catch_with_lasso then return end or ent.name:match("^monstrum:")) then
if not ent.caught_with_lasso if not ent.catch_with_lasso then return end
and not is_lasso_in_use(placer) then local name = placer:get_player_name()
ent.caught_with_lasso = true if not ent._lassod_to
ent.lasso_origin = placer and not using_lasso[name] then
elseif ent.lasso_origin using_lasso[name] = ent
and ent.lasso_origin == placer then ent._lassod_to = name
ent.caught_with_lasso = nil ent:memorize("_lassod_to", name)
ent.lasso_origin = nil elseif ent._lassod_to
end and ent._lassod_to == name then
end using_lasso[name] = nil
end, ent._lassod_to = nil
on_place = function(itemstack, placer, pointed_thing) ent:forget("_lassod_to")
if pointed_thing.type == "node" then end
local pos = minetest.get_pointed_thing_position(pointed_thing) end
if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then end,
local objects = minetest.get_objects_inside_radius(placer:get_pos(), 21) on_place = function(itemstack, placer, pointed_thing)
for _, obj in ipairs(objects) do if pointed_thing.type == "node" then
if obj:get_luaentity() local pos = minetest.get_pointed_thing_position(pointed_thing)
and obj:get_luaentity().lasso_origin if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then
and obj:get_luaentity().lasso_visual local name = placer:get_player_name()
and type(obj:get_luaentity().lasso_origin) == "userdata" local ent = using_lasso[name]
and obj:get_luaentity().lasso_origin == placer then if ent
obj:get_luaentity().lasso_visual:get_luaentity().lasso_origin = pos and ent._lassod_to
obj:get_luaentity().lasso_origin = pos and ent._lassod_to == name then
local object = minetest.add_entity(pos, "animalia:lasso_fence_ent") using_lasso[name] = nil
object:get_luaentity().parent = obj ent._lasso_ent:set_detach()
itemstack:take_item(1) ent._lasso_ent:set_pos(pos)
break ent._lasso_ent:get_luaentity()._attached = pos
end ent._lassod_to = pos
end ent:memorize("_lassod_to", pos)
end local fence_obj = minetest.add_entity(pos, "animalia:tied_lasso_entity")
end fence_obj:get_luaentity()._mob = ent.object
return itemstack fence_obj:get_luaentity()._lasso_obj = ent._lasso_ent
end itemstack:take_item(1)
}) end
end
end
return itemstack
end
})

View file

@ -56,20 +56,12 @@ creatura.register_mob_spawn("animalia:cow", {
biomes = animalia.registered_biome_groups["grassland"].biomes biomes = animalia.registered_biome_groups["grassland"].biomes
}) })
creatura.register_mob_spawn("animalia:frog", { creatura.register_mob_spawn("animalia:fox", {
chance = 2, chance = 4,
min_radius = 4, min_group = 1,
max_radius = 16, max_group = 2,
min_light = 0,
min_height = -32,
max_height = 8,
min_group = 2,
max_group = 6,
biomes = frog_biomes,
spawn_cluster = true,
spawn_in_nodes = true,
spawn_on_gen = true, spawn_on_gen = true,
nodes = {"default:water_source"}, biomes = animalia.registered_biome_groups["boreal"].biomes
}) })
creatura.register_mob_spawn("animalia:horse", { creatura.register_mob_spawn("animalia:horse", {
@ -80,6 +72,28 @@ creatura.register_mob_spawn("animalia:horse", {
biomes = animalia.registered_biome_groups["grassland"].biomes biomes = animalia.registered_biome_groups["grassland"].biomes
}) })
creatura.register_abm_spawn("animalia:rat", {
chance = 2000,
interval = 30,
min_height = -1,
max_height = 1024,
min_group = 1,
max_group = 3,
spawn_in_nodes = true,
nodes = {"group:crop"}
})
creatura.register_abm_spawn("animalia:owl", {
chance = 30000,
interval = 60,
min_height = 3,
max_height = 1024,
min_group = 1,
max_group = 1,
spawn_cap = 1,
nodes = {"group:leaves"}
})
creatura.register_mob_spawn("animalia:pig", { creatura.register_mob_spawn("animalia:pig", {
chance = 3, chance = 3,
min_group = 2, min_group = 2,
@ -119,37 +133,6 @@ creatura.register_mob_spawn("animalia:wolf", {
biomes = animalia.registered_biome_groups["boreal"].biomes biomes = animalia.registered_biome_groups["boreal"].biomes
}) })
creatura.register_mob_spawn("animalia:bird", {
chance = 1,
min_light = 0,
min_group = 12,
max_group = 16,
biomes = animalia.registered_biome_groups["common"].biomes,
spawn_cluster = true,
nodes = {"group:leaves"}
})
creatura.register_on_spawn("animalia:bird", function(self, pos)
local node = minetest.get_node(pos)
if node.name == "air" then
minetest.set_node(pos, {name = "animalia:nest_song_bird"})
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"
)
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", {x = pos.x, y = pos.y + 1, z = pos.z})
self.despawn_after = self:memorize("despawn_after", nil)
end
end
end)
creatura.register_mob_spawn("animalia:tropical_fish", { creatura.register_mob_spawn("animalia:tropical_fish", {
chance = 3, chance = 3,
min_height = -128, min_height = -128,
@ -160,4 +143,70 @@ creatura.register_mob_spawn("animalia:tropical_fish", {
spawn_in_nodes = true, spawn_in_nodes = true,
spawn_on_gen = true, spawn_on_gen = true,
nodes = {"default:water_source"} nodes = {"default:water_source"}
})
-- Ambient Spawning
creatura.register_abm_spawn("animalia:bat", {
chance = 10000,
interval = 30,
min_light = 0,
min_height = -31000,
max_height = 1,
min_group = 3,
max_group = 5,
spawn_cap = 6,
nodes = {"group:stone"}
})
creatura.register_abm_spawn("animalia:bird", {
chance = 15000,
interval = 60,
min_light = 0,
min_height = 1,
max_height = 1024,
min_group = 12,
max_group = 16,
spawn_cap = 12,
nodes = {"group:leaves"}
})
creatura.register_on_spawn("animalia:bird", function(self, pos)
local nests = minetest.find_nodes_in_area_under_air(
{x = pos.x - 12, y = pos.y - 12, z = pos.z - 12},
{x = pos.x + 12, y = pos.y + 12, z = pos.z + 12},
"animalia:nest_song_bird"
)
if nests[1] then
self.home_position = self:memorize("home_position", nests[1])
return
end
local node = minetest.get_node(pos)
if node.name == "air" then
minetest.set_node(pos, {name = "animalia:nest_song_bird"})
self.home_position = self:memorize("home_position", pos)
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"
)
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", {x = pos.x, y = pos.y + 1, z = pos.z})
end
end
end)
creatura.register_abm_spawn("animalia:frog", {
chance = 7500,
interval = 60,
min_light = 0,
min_height = -1,
max_height = 8,
min_group = 2,
max_group = 4,
neighbors = {"group:water"},
nodes = {"group:soil"}
}) })

View file

@ -27,7 +27,7 @@ end
local function register_egg(name, def) local function register_egg(name, def)
minetest.register_entity(def.mob .. "_egg_sprite", { minetest.register_entity(def.mob .. "_egg_entity", {
hp_max = 1, hp_max = 1,
physical = true, physical = true,
collisionbox = {0, 0, 0, 0, 0, 0}, collisionbox = {0, 0, 0, 0, 0, 0},
@ -36,94 +36,75 @@ local function register_egg(name, def)
textures = {"animalia_egg.png"}, textures = {"animalia_egg.png"},
initial_sprite_basepos = {x = 0, y = 0}, initial_sprite_basepos = {x = 0, y = 0},
is_visible = true, is_visible = true,
on_step = function(self) on_step = function(self, _, moveresult)
local pos = self.object:get_pos() local pos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(pos, 1.5) if not pos then return end
local cube = minetest.find_nodes_in_area( if moveresult.collides then
vector.new(pos.x - 0.5, pos.y - 0.5, pos.z - 0.5), for _, collision in ipairs(moveresult.collision) do
vector.new(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5), if collision.type == "nodes" then
walkable_nodes) minetest.add_particlespawner({
if #objects >= 2 then amount = 6,
if objects[2]:get_armor_groups().fleshy then time = 0.1,
objects[2]:punch(self.object, 2.0, {full_punch_interval = 0.1, damage_groups = {fleshy = 1}}, nil) 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 = {x = -1, y = 2, z = -1},
maxvel = {x = 1, y = 5, z = 1},
minacc = {x = 0, y = -9.8, z = 0},
maxacc = {x = 0, y = -9.8, z = 0},
collisiondetection = true,
collision_removal = true,
texture = "animalia_egg_fragment.png"
})
break
elseif collision.type == "object" then
collision.object:punch(self.object, 2.0, {full_punch_interval = 0.1, damage_groups = {fleshy = 1}}, nil)
break
end
end end
end
if #cube >= 1 then
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",
})
if random(1, 3) < 2 then if random(1, 3) < 2 then
local object = minetest.add_entity(pos, def.mob) local object = minetest.add_entity(pos, def.mob)
local ent = object:get_luaentity() local ent = object and object:get_luaentity()
ent.growth_scale = 0.7 ent.growth_scale = 0.7
animalia.initialize_api(ent) animalia.initialize_api(ent)
animalia.protect_from_despawn(ent) animalia.protect_from_despawn(ent)
self.object:remove()
else
self.object:remove()
end end
self.object:remove()
end end
end end
}) })
local function mobs_shoot_egg(item, player)
local pos = player:get_pos()
minetest.sound_play("default_place_node_hard", {
pos = pos,
gain = 1.0,
max_hear_distance = 5,
})
local vel = 19
local gravity = 9
local obj = minetest.add_entity({
x = pos.x,
y = pos.y +1.5,
z = pos.z
}, def.mob .. "_egg_sprite")
local ent = obj:get_luaentity()
local dir = player:get_look_dir()
ent.velocity = vel -- needed for api internal timing
ent.switch = 1 -- needed so that egg doesn't despawn straight away
obj:set_velocity({
x = dir.x * vel,
y = dir.y * vel,
z = dir.z * vel
})
obj:set_acceleration({
x = dir.x * -3,
y = -gravity,
z = dir.z * -3
})
-- pass player name to egg for chick ownership
local ent2 = obj:get_luaentity()
ent2.playername = player:get_player_name()
item:take_item()
return item
end
minetest.register_craftitem(name, { minetest.register_craftitem(name, {
description = def.description, description = def.description,
inventory_image = def.inventory_image .. ".png", inventory_image = def.inventory_image .. ".png",
on_use = mobs_shoot_egg, on_use = function(itemstack, player)
local pos = player:get_pos()
minetest.sound_play("default_place_node_hard", {
pos = pos,
gain = 1.0,
max_hear_distance = 5,
})
local vel = 19
local gravity = 9
local object = minetest.add_entity({
x = pos.x,
y = pos.y + 1.5,
z = pos.z
}, def.mob .. "_egg_entity")
local ent = object and object:get_luaentity()
local dir = player:get_look_dir()
obj:set_velocity({
x = dir.x * vel,
y = dir.y * vel,
z = dir.z * vel
})
obj:set_acceleration({
x = dir.x * -3,
y = -gravity,
z = dir.z * -3
})
itemstack:take_item()
return itemstack
end,
groups = {food_egg = 1, flammable = 2}, groups = {food_egg = 1, flammable = 2},
}) })
@ -141,6 +122,47 @@ local function register_egg(name, def)
}) })
end end
local function mob_storage_use(itemstack, player, pointed)
local ent = pointed.ref and pointed.ref:get_luaentity()
if ent
and (ent.name:match("^animalia:")
or ent.name:match("^monstrum:")) then
local desc = itemstack:get_short_description()
if itemstack:get_count() > 1 then
local name = itemstack:get_name()
local inv = player:get_inventory()
if inv:room_for_item("main", {name = name}) then
itemstack:take_item(1)
inv:add_item("main", name)
end
return itemstack
end
local plyr_name = player:get_player_name()
local meta = itemstack:get_meta()
local mob = meta:get_string("mob") or ""
local staticdata = meta:get_string("staticdata") or ""
if mob == "" then
animalia.protect_from_despawn(ent)
meta:set_string("mob", ent.name)
meta:set_string("staticdata", ent:get_staticdata())
local ent_name = correct_name(ent.name)
local ent_gender = correct_name(ent.gender)
desc = desc .. " \n" .. color("#a9a9a9", ent_name) .. "\n" .. color("#a9a9a9", ent_gender)
if ent.trust
and ent.trust[plyr_name] then
desc = desc .. "\n Trust: " .. color("#a9a9a9", ent.trust[plyr_name])
end
meta:set_string("description", desc)
player:set_wielded_item(itemstack)
ent.object:remove()
return itemstack
else
minetest.chat_send_player(plyr_name,
"This " .. desc .. " already contains a " .. correct_name(mob))
end
end
end
----------- -----------
-- Drops -- -- Drops --
----------- -----------
@ -199,6 +221,26 @@ minetest.register_craft({
output = "animalia:mutton_cooked", output = "animalia:mutton_cooked",
}) })
minetest.register_craftitem("animalia:rat_raw", {
description = "Raw Rat",
inventory_image = "animalia_rat_raw.png",
on_use = minetest.item_eat(1),
groups = {flammable = 2, meat = 1, food_meat = 1},
})
minetest.register_craftitem("animalia:rat_cooked", {
description = "Cooked Rat",
inventory_image = "animalia_rat_cooked.png",
on_use = minetest.item_eat(2),
groups = {flammable = 2, meat = 1, food_meat = 1},
})
minetest.register_craft({
type = "cooking",
recipe = "animalia:rat_raw",
output = "animalia:rat_cooked",
})
minetest.register_craftitem("animalia:porkchop_raw", { minetest.register_craftitem("animalia:porkchop_raw", {
description = "Raw Porkchop", description = "Raw Porkchop",
inventory_image = "animalia_porkchop_raw.png", inventory_image = "animalia_porkchop_raw.png",
@ -480,48 +522,7 @@ minetest.register_craftitem("animalia:net", {
description = "Animal Net", description = "Animal Net",
inventory_image = "animalia_net.png", inventory_image = "animalia_net.png",
stack_max = 1, stack_max = 1,
on_secondary_use = function(itemstack, placer, pointed_thing) on_secondary_use = mob_storage_use,
if pointed_thing.type == "object" then
if pointed_thing.ref:is_player() then return end
local ent = pointed_thing.ref:get_luaentity()
if not ent.name:match("^animalia:") or not ent.catch_with_net then
return
end
local ent_name = correct_name(ent.name)
local ent_gender = correct_name(ent.gender)
local meta = itemstack:get_meta()
if not meta:get_string("mob") or meta:get_string("mob") == "" then
if placer:get_wielded_item():get_count() > 1 then
if placer:get_inventory():room_for_item("main", {name = "animalia:net"}) then
itemstack:take_item(1)
placer:get_inventory():add_item("main", "animalia:net")
return itemstack
else
return
end
end
meta:set_string("mob", ent.name)
meta:set_string("staticdata", ent:get_staticdata())
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 Trust: " .. color("#a9a9a9", ent.trust[placer:get_player_name()])
end
meta:set_string("description", desc)
placer:set_wielded_item(itemstack)
animalia.protect_from_despawn(ent)
ent.object:remove()
return itemstack
else
minetest.chat_send_player(placer:get_player_name(),
"This Net already contains a " ..
correct_name(
meta:get_string("mob")))
return
end
end
end,
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above local pos = pointed_thing.above
if pos then if pos then
@ -580,6 +581,61 @@ minetest.register_node("animalia:guano", {
end end
end end
}) })
minetest.register_node("animalia:crate", {
description = "Animal Crate",
tiles = {"animalia_crate.png", "animalia_crate.png", "animalia_crate_side.png"},
groups = {choppy = 2},
stack_max = 1,
on_secondary_use = mob_storage_use,
preserve_metadata = function(_, _, oldmeta, drops)
for _, stack in pairs(drops) do
if stack:get_name() == "animalia:crate" then
local meta = stack:get_meta()
meta:set_string("mob", oldmeta["mob"])
meta:set_string("staticdata", oldmeta["staticdata"])
meta:set_string("description", oldmeta["description"])
end
end
end,
after_place_node = function(pos, placer, itemstack)
local meta = itemstack:get_meta()
local mob = meta:get_string("mob")
if mob ~= "" then
local nmeta = minetest.get_meta(pos)
nmeta:set_string("mob", mob)
nmeta:set_string("infotext", "Contains a " .. correct_name((mob)))
nmeta:set_string("staticdata", meta:get_string("staticdata"))
nmeta:set_string("description", meta:get_string("description"))
itemstack:take_item()
placer:set_wielded_item(itemstack)
end
end,
on_rightclick = function(pos, _, clicker)
if minetest.is_protected(pos, clicker:get_player_name()) then
return
end
local meta = minetest.get_meta(pos)
local mob = meta:get_string("mob")
local staticdata = meta:get_string("staticdata")
if mob ~= "" then
local above = {
x = pos.x,
y = pos.y + 1,
z = pos.z
}
if creatura.get_node_def(above).walkable then
return
end
minetest.add_entity(above, mob, staticdata)
meta:set_string("mob", nil)
meta:set_string("infotext", nil)
meta:set_string("staticdata", nil)
meta:set_string("description", "Animal Crate")
end
end
})
-------------- --------------
-- Crafting -- -- Crafting --
-------------- --------------
@ -652,6 +708,15 @@ minetest.register_craft({
} }
}) })
minetest.register_craft({
output = "animalia:crate",
recipe = {
{"group:wood", "group:wood", "group:wood"},
{"group:wood", "animalia:net", "group:wood"},
{"group:wood", "group:wood", "group:wood"}
}
})
minetest.register_craft({ minetest.register_craft({
output = "animalia:saddle", output = "animalia:saddle",
recipe = { recipe = {

View file

@ -42,13 +42,16 @@ animalia.animals = {
"animalia:cat", "animalia:cat",
"animalia:chicken", "animalia:chicken",
"animalia:cow", "animalia:cow",
"animalia:tropical_fish", "animalia:fox",
"animalia:frog", "animalia:frog",
"animalia:horse", "animalia:horse",
"animalia:owl",
"animalia:pig", "animalia:pig",
"animalia:rat",
"animalia:reindeer", "animalia:reindeer",
"animalia:sheep", "animalia:sheep",
"animalia:turkey", "animalia:turkey",
"animalia:tropical_fish",
"animalia:wolf", "animalia:wolf",
} }

View file

@ -2,119 +2,76 @@
-- Bat -- -- Bat --
--------- ---------
local guano_accumulation = minetest.settings:get_bool("guano_accumulation")
-- Math --
local function clamp(val, min, max)
if val < min then
val = min
elseif max < val then
val = max
end
return val
end
local random = math.random
local floor = math.floor
-- Vector Math --
local vec_dist = vector.distance local vec_dist = vector.distance
local vec_add = vector.add
local function vec_raise(v, n) local function get_home_pos(self)
return {x = v.x, y = v.y + n, z = v.z} local pos = self.object:get_pos()
end if not pos then return end
local nodes = minetest.find_nodes_in_area(
--------------- vector.subtract(pos, 16),
-- Utilities -- vector.add(pos, 16),
--------------- {"group:leaves", "group:stone"}
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 home_dist
local roosts = {} local new_home
for i = 1, #walkable do for _, n_pos in ipairs(nodes or {}) do
local i_pos = walkable[i] local dist = vec_dist(pos, n_pos)
local n_pos = { if not home_dist
x = i_pos.x, or dist < home_dist then
y = i_pos.y - 1, n_pos.y = n_pos.y - 1
z = i_pos.z if creatura.get_node_def(n_pos).name == "air" then
} home_dist = dist
if creatura.get_node_def(n_pos).name == "air" new_home = n_pos
and minetest.line_of_sight(pos, n_pos) then end
table.insert(roosts, n_pos)
end end
end end
return roosts[random(#roosts)] if new_home then
end self.home_position = self:memorize("home_position", new_home)
end
local function is_node_walkable(name)
local def = minetest.registered_nodes[name]
return def and def.walkable
end end
creatura.register_mob("animalia:bat", { creatura.register_mob("animalia:bat", {
-- Stats -- Engine Props
max_health = 5, visual = "mesh",
armor_groups = {fleshy = 200}, visual_size = {x = 10, y = 10},
damage = 0,
speed = 4,
tracking_range = 16,
despawn_after = 2500,
-- Entity Physics
stepheight = 1.1,
max_fall = 0,
turn_rate = 12,
-- Visuals
mesh = "animalia_bat.b3d", mesh = "animalia_bat.b3d",
textures = {
"animalia_bat_1.png",
"animalia_bat_2.png",
"animalia_bat_3.png",
},
makes_footstep_sound = false,
stepheight = 1.1,
-- Creatura Props
max_health = 5,
armor_groups = {fleshy = 100},
damage = 0,
speed = 6,
tracking_range = 8,
max_boids = 2,
despawn_after = 500,
max_fall = 0,
hitbox = { hitbox = {
width = 0.15, width = 0.15,
height = 0.3 height = 0.3
}, },
visual_size = {x = 7, y = 7},
textures = {
"animalia_bat_1.png",
"animalia_bat_2.png",
"animalia_bat_3.png"
},
animations = { animations = {
stand = {range = {x = 1, y = 40}, speed = 10, frame_blend = 0.3, loop = true}, 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}, walk = {range = {x = 51, y = 69}, speed = 30, frame_blend = 0.3, loop = true},
fly = {range = {x = 100, y = 140}, speed = 80, frame_blend = 0.3, loop = true}, fly = {range = {x = 81, y = 99}, speed = 80, frame_blend = 0.3, loop = true},
cling = {range = {x = 150, y = 150}, speed = 1, frame_blend = 0, loop = false} cling = {range = {x = 110, y = 110}, speed = 1, frame_blend = 0, loop = false}
}, },
-- Misc
sounds = {
random = {
name = "animalia_bat",
gain = 0.5,
distance = 16,
variations = 2
},
},
catch_with_net = true,
catch_with_lasso = false,
follow = { follow = {
"butterflies:butterfly_red", "butterflies:butterfly_red",
"butterflies:butterfly_white", "butterflies:butterfly_white",
"butterflies:butterfly_violet" "butterflies:butterfly_violet"
}, },
-- Function fancy_collide = false,
bouyancy_multiplier = 1,
hydrodynamics_multiplier = 1,
roost_action = animalia.action_cling, roost_action = animalia.action_cling,
utility_stack = { utility_stack = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
{ {
utility = "animalia:aerial_wander", utility = "animalia:aerial_wander",
step_delay = 0.25, step_delay = 0.25,
@ -128,119 +85,101 @@ creatura.register_mob("animalia:bat", {
local dist = vec_dist(pos, plyr_pos) local dist = vec_dist(pos, plyr_pos)
self._target = player self._target = player
self.is_landed = false self.is_landed = false
return (12 - (dist + trust)) * 0.1, {self} return (self.tracking_range - dist) / self.tracking_range, {self}
end end
if self.in_liquid return 0.1, {self}
or not self.is_landed then
return 0.2, {self}
end
return 0
end end
}, },
{ {
utility = "animalia:fly_to_land", utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self) get_score = function(self)
if self.is_landed if self.in_liquid then
and not self.touching_ground
and not self.in_liquid
and creatura.sensor_floor(self, 3, true) > 2 then
return 0.3, {self} return 0.3, {self}
end end
return 0 return 0
end end
}, },
[4] = { {
utility = "animalia:fly_to_roost", utility = "animalia:fly_to_roost",
get_score = function(self) get_score = function(self)
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
local home = animalia.is_day and self.home_position local home = animalia.is_day and self.home_position
if home if (home
and home.x and home.x
and vec_dist(pos, home) < 8 then and vec_dist(pos, home) < 8)
or self.is_landed then
return 0.6, {self} return 0.6, {self}
end end
return 0 return 0
end end
} }
}, },
-- Animalia Props
catch_with_net = true,
catch_with_lasso = false,
-- Functions
is_home = function(pos, home_pos)
local dist = vec_dist(pos, home_pos)
if dist < 4 then
local above = {x = pos.x, y = pos.y + 1, z = pos.z}
if creatura.get_node_def(above).walkable
or dist < 1 then
return true
end
end
return false
end,
activate_func = function(self) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
animalia.initialize_lasso(self)
self.home_position = self:recall("home_position") or nil self.home_position = self:recall("home_position") or nil
local home_pos = self.home_position
self.is_landed = self:recall("is_landed") or false self.is_landed = self:recall("is_landed") or false
self.trust = self:recall("trust") or {} self.trust = self:recall("trust") or {}
if not self.home_position then if not home_pos
local roost = get_roost(self.object:get_pos(), 8) or not creatura.get_node_def(home_pos).walkable then
if roost then get_home_pos(self)
self.home_position = self:memorize("home_position", roost)
end
end end
end, end,
step_func = function(self) step_func = function(self)
animalia.step_timers(self) animalia.step_timers(self)
--animalia.head_tracking(self, 0.75, 0.75)
animalia.do_growth(self, 60) animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
animalia.rotate_to_pitch(self) animalia.rotate_to_pitch(self)
local pos = self.object:get_pos() animalia.random_sound(self)
if not pos then return end if not self.is_landed
if self:timer(random(10,15)) then or not self.touching_ground then
if random(4) < 2 then self.speed = 4
self.is_landed = not self.is_landed else
end self.speed = 1
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
end
end end
if self._anim == "fly" then if self:timer(10)
local vel_y = vector.normalize(self.object:get_velocity()).y and math.random(10) < 2 then
local rot = self.object:get_rotation() local anim = self._anim or ""
local n_rot = rot.x + (vel_y - rot.x) * 0.2 if anim == "cling" then
self.object:set_rotation({ local colony = creatura.get_nearby_objects(self, self.name)
x = clamp(n_rot, -0.75, 0.75), local pos = self.object:get_pos()
y = rot.y, if not pos then return end
z = rot.z local center = pos
}) if #colony > 0 then
end local pos_sum = center
if self:timer(random(3, 4)) then local pos_ttl = 1
self:play_sound("random") for _, object in ipairs(colony) do
if guano_accumulation local obj_pos = object and object:get_pos()
and random(16) < 2 if obj_pos then
and self:get_utility() == "animalia:fly_to_roost" then pos_sum = vector.add(pos_sum, obj_pos)
pos = { pos_ttl = pos_ttl + 1
x = floor(pos.x + 0.5),
y = floor(pos.y + 0.5),
z = floor(pos.z + 0.5)
}
if not is_node_walkable(minetest.get_node(vec_raise(pos, 1)).name) then
return
end
local fail_safe = 1
while not is_node_walkable(minetest.get_node(pos).name)
and fail_safe < 16 do
pos.y = pos.y - 1
end
if is_node_walkable(minetest.get_node(pos).name) then
if minetest.get_node(vec_raise(pos, 1)).name ~= "animalia:guano" then
minetest.set_node(vec_raise(pos, 1), {name = "animalia:guano"})
else
local nodes = minetest.find_nodes_in_area_under_air(
vector.subtract(pos, 3),
vec_add(pos, 3),
animalia.walkable_nodes
)
if #nodes > 0 then
pos = nodes[random(#nodes)]
if minetest.get_node(vec_raise(pos, 1)).name ~= "animalia:guano" then
minetest.set_node(vec_raise(pos, 1), {name = "animalia:guano"})
end
end end
end end
center = vector.divide(pos_sum, pos_ttl)
end
center = creatura.get_ground_level(center, 8)
if center.y < pos.y then
local under = {x = center.x, y = center.y - 1, z = center.z}
if creatura.get_node_def(under).walkable
and not minetest.is_protected(center, "") then
minetest.set_node(center, {name = "animalia:guano"})
end
end end
end end
end end
@ -259,9 +198,7 @@ creatura.register_mob("animalia:bat", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
end
}) })
creatura.register_spawn_egg("animalia:bat", "392517", "321b0b") creatura.register_spawn_egg("animalia:bat", "392517", "321b0b")

View file

@ -24,7 +24,7 @@ creatura.register_mob("animalia:bird", {
damage = 0, damage = 0,
speed = 4, speed = 4,
tracking_range = 16, tracking_range = 16,
despawn_after = 100, despawn_after = 750,
-- Entity Physics -- Entity Physics
stepheight = 1.1, stepheight = 1.1,
max_fall = 0, max_fall = 0,
@ -48,6 +48,7 @@ creatura.register_mob("animalia:bird", {
fly = {range = {x = 120, y = 140}, speed = 80, frame_blend = 0.3, loop = true} fly = {range = {x = 120, y = 140}, speed = 80, frame_blend = 0.3, loop = true}
}, },
-- Misc -- Misc
max_boids = 12,
makes_footstep_sound = true, makes_footstep_sound = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = false, catch_with_lasso = false,
@ -73,7 +74,7 @@ creatura.register_mob("animalia:bird", {
}, },
follow = follows, follow = follows,
-- Function -- Function
wander_action = animalia.action_move_flock, wander_action = animalia.action_move_boid,
utility_stack = { utility_stack = {
{ {
utility = "animalia:wander_group", utility = "animalia:wander_group",
@ -155,7 +156,7 @@ creatura.register_mob("animalia:bird", {
animalia.do_growth(self, 60) animalia.do_growth(self, 60)
animalia.update_lasso_effects(self) animalia.update_lasso_effects(self)
animalia.rotate_to_pitch(self) animalia.rotate_to_pitch(self)
if self:timer(random(10,15)) then if self:timer(random(6,12)) then
if animalia.is_day then if animalia.is_day then
if self.texture_no == 1 then if self.texture_no == 1 then
self:play_sound("cardinal") self:play_sound("cardinal")
@ -213,9 +214,7 @@ creatura.register_mob("animalia:bird", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
end
}) })
creatura.register_spawn_egg("animalia:bird", "ae2f2f", "f3ac1c") creatura.register_spawn_egg("animalia:bird", "ae2f2f", "f3ac1c")

View file

@ -34,7 +34,7 @@ creatura.register_mob("animalia:cat", {
width = 0.2, width = 0.2,
height = 0.4 height = 0.4
}, },
visual_size = {x = 6, y = 6}, visual_size = {x = 10, y = 10},
textures = { textures = {
"animalia_cat_1.png", "animalia_cat_1.png",
"animalia_cat_2.png", "animalia_cat_2.png",
@ -58,6 +58,7 @@ creatura.register_mob("animalia:cat", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -179,7 +180,8 @@ creatura.register_mob("animalia:cat", {
{ {
utility = "animalia:follow_player", utility = "animalia:follow_player",
get_score = function(self) get_score = function(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin local lasso_tgt = self._lassod_to
local lasso = type(lasso_tgt) == "string" and minetest.get_player_by_name(lasso_tgt)
local trust = (self.owner and self.trust[self.owner]) or 0 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 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 force = (lasso and lasso ~= false) or (owner and owner ~= false)
@ -191,13 +193,25 @@ creatura.register_mob("animalia:cat", {
return 0 return 0
end end
}, },
{
utility = "animalia:attack_target",
get_score = function(self)
local target = self._target or creatura.get_nearby_object(self, "animalia:rat")
local tgt_pos = target and target:get_pos()
if tgt_pos
and self:is_pos_safe(tgt_pos) then
return 0.7, {self, target}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
get_score = function(self) get_score = function(self)
if self.breeding if self.breeding
and animalia.get_nearby_mate(self, self.name) then and animalia.get_nearby_mate(self, self.name) then
return 0.7, {self} return 0.8, {self}
end end
return 0 return 0
end end

View file

@ -52,6 +52,7 @@ creatura.register_mob("animalia:chicken", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -124,19 +125,7 @@ creatura.register_mob("animalia:chicken", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(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.3, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
@ -148,18 +137,7 @@ creatura.register_mob("animalia:chicken", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_flee
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) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
@ -194,10 +172,7 @@ creatura.register_mob("animalia:chicken", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:chicken", "c6c6c6", "d22222") creatura.register_spawn_egg("animalia:chicken", "c6c6c6", "d22222")

View file

@ -59,7 +59,7 @@ creatura.register_mob("animalia:cow", {
run = {range = {x = 61, y = 79}, speed = 30, frame_blend = 0.3, loop = true}, run = {range = {x = 61, y = 79}, speed = 30, frame_blend = 0.3, loop = true},
}, },
-- Misc -- Misc
step_delay = 0.25, flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -123,19 +123,7 @@ creatura.register_mob("animalia:cow", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(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.4, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
@ -147,18 +135,7 @@ creatura.register_mob("animalia:cow", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_flee
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) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
@ -215,10 +192,7 @@ creatura.register_mob("animalia:cow", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:cow", "cac3a1" ,"464438") creatura.register_spawn_egg("animalia:cow", "cac3a1" ,"464438")

169
mobs/fox.lua Normal file
View file

@ -0,0 +1,169 @@
----------
-- Wolf --
----------
creatura.register_mob("animalia:fox", {
-- Stats
max_health = 15,
armor_groups = {fleshy = 100},
damage = 4,
speed = 5,
tracking_range = 24,
despawn_after = 2000,
-- Entity Physics
stepheight = 1.1,
max_fall = 3,
-- Visuals
mesh = "animalia_fox.b3d",
hitbox = {
width = 0.35,
height = 0.7
},
visual_size = {x = 10, y = 10},
textures = {
"animalia_fox_1.png",
},
animations = {
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},
},
-- Misc
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
follow = {
"animalia:rat_raw",
"animalia:mutton_raw",
"animalia:beef_raw",
"animalia:porkchop_raw",
"animalia:poultry_raw"
},
head_data = {
offset = {x = 0, y = 0.18, z = 0},
pitch_correction = -67,
pivot_h = 0.65,
pivot_v = 0.65
},
-- Function
on_eat_drop = function(self)
animalia.protect_from_despawn(self)
end,
utility_stack = {
{
utility = "animalia:wander_skittish",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.3, {self}
end
return 0
end
},
{
utility = "animalia:attack_target",
get_score = function(self)
local target = self._target or creatura.get_nearby_object(self, {"animalia:rat", "animalia:chicken"})
local tgt_pos = target and target:get_pos()
if tgt_pos
and self:is_pos_safe(tgt_pos) then
return 0.4, {self, target}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local target = self._puncher or creatura.get_nearby_player(self)
local pos, tgt_pos = self.object:get_pos(), target and target:get_pos()
if not pos then return end
if not tgt_pos then self._puncher = nil return 0 end
local sneaking = target:get_player_control().sneak
if not sneaking then
local dist = vector.distance(pos, tgt_pos)
local score = (self.tracking_range - dist) / self.tracking_range
self._puncher = target
return score / 2, {self, target}
end
self._puncher = nil
return 0
end
},
{
utility = "animalia:walk_to_food",
get_score = function(self)
local cooldown = self.eat_cooldown or 0
if cooldown > 0 then
self.eat_cooldown = cooldown - 1
return 0
end
local food_item = animalia.get_dropped_food(self)
if food_item then
return 0.7, {self, food_item}
end
return 0
end
},
{
utility = "animalia:follow_player",
get_score = function(self)
local lasso_tgt = self._lassod_to
local lasso = type(lasso_tgt) == "string" and minetest.get_player_by_name(lasso_tgt)
if lasso
and lasso:get_pos() then
return 0.6, {self, lasso, true}
end
return 0
end
},
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
if self.breeding
and animalia.get_nearby_mate(self, self.name) then
return 0.7, {self}
end
return 0
end
}
},
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
end,
step_func = function(self)
animalia.step_timers(self)
animalia.head_tracking(self, 0.5, 0.75)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
self:initiate_utility("animalia:die", self)
end
end,
on_rightclick = function(self, clicker)
if not clicker:is_player() then return end
local name = clicker:get_player_name()
local passive = true
if animalia.feed(self, clicker, passive, passive) then
return
end
if animalia.set_nametag(self, clicker) then
return
end
end,
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:fox", "d0602d" ,"c9c9c9")

View file

@ -45,6 +45,7 @@ creatura.register_mob("animalia:frog", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -128,7 +129,7 @@ creatura.register_mob("animalia:frog", {
if self.in_liquid then return 0 end if self.in_liquid then return 0 end
local pos = self.object:get_pos() local pos = self.object:get_pos()
if not pos then return end if not pos then return end
local target = self._target or creatura.get_nearby_player(self) local target = self._puncher or self._target or creatura.get_nearby_player(self)
local tgt_pos = target and target:get_pos() local tgt_pos = target and target:get_pos()
local plyr_name = (target and target:is_player() and target:get_player_name()) or "" local plyr_name = (target and target:is_player() and target:get_player_name()) or ""
if tgt_pos then if tgt_pos then

View file

@ -100,15 +100,15 @@ creatura.register_mob("animalia:horse", {
}, },
animations = { animations = {
stand = {range = {x = 1, y = 59}, speed = 10, 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}, walk = {range = {x = 71, y = 89}, speed = 25, frame_blend = 0.3, loop = true},
run = {range = {x = 81, y = 99}, speed = 30, frame_blend = 0.3, loop = true}, run = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
punch_aoe = {range = {x = 101, y = 119}, speed = 30, frame_blend = 0.2, loop = false}, punch_aoe = {range = {x = 161, y = 180}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.2, loop = false}, rear = {range = {x = 131, y = 150}, 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 = 191, y = 220}, speed = 30, frame_blend = 0.3, loop = false}
eat = {range = {x = 141, y = 160}, speed = 20, frame_blend = 0.3, loop = false}
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -116,8 +116,7 @@ creatura.register_mob("animalia:horse", {
random = { random = {
name = "animalia_horse_idle", name = "animalia_horse_idle",
gain = 1.0, gain = 1.0,
distance = 8, distance = 8
variations = 3,
}, },
hurt = { hurt = {
name = "animalia_horse_hurt", name = "animalia_horse_hurt",
@ -140,10 +139,10 @@ creatura.register_mob("animalia:horse", {
}, },
head_data = { head_data = {
bone = "Neck.CTRL", bone = "Neck.CTRL",
offset = {x = 0, y = 1.45, z = 0.0}, offset = {x = 0, y = 1.05, z = 0.0},
pitch_correction = 25, pitch_correction = 35,
pivot_h = 1, pivot_h = 1,
pivot_v = 1.5 pivot_v = 1.75
}, },
-- Function -- Function
add_child = function(self, mate) add_child = function(self, mate)
@ -198,19 +197,7 @@ creatura.register_mob("animalia:horse", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(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.4, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
@ -263,10 +250,6 @@ creatura.register_mob("animalia:horse", {
animalia.initialize_lasso(self) animalia.initialize_lasso(self)
set_pattern(self) set_pattern(self)
self.owner = self:recall("owner") or nil self.owner = self:recall("owner") or nil
if self.owner then
self._despawn = nil
self.despawn_after = nil
end
self.rider = nil self.rider = nil
self.saddled = self:recall("saddled") or false self.saddled = self:recall("saddled") or false
self.max_health = self:recall("max_health") or random(30, 45) self.max_health = self:recall("max_health") or random(30, 45)
@ -333,9 +316,7 @@ creatura.register_mob("animalia:horse", {
end, end,
on_punch = function(self, puncher, ...) on_punch = function(self, puncher, ...)
if self.rider and puncher == self.rider then return end if self.rider and puncher == self.rider then return end
creatura.basic_punch_func(self, puncher, ...) animalia.punch(self, puncher, ...)
if self.hp < 0 then return end
self._puncher = puncher
end end
}) })

217
mobs/owl.lua Normal file
View file

@ -0,0 +1,217 @@
---------
-- Owl --
---------
local follows = {}
minetest.register_on_mods_loaded(function()
for name in pairs(minetest.registered_items) do
if name:match(":seed_")
or name:match("_seed") then
table.insert(follows, name)
end
end
end)
local random = math.random
local vec_dist = vector.distance
local function get_home_pos(self)
local pos = self.object:get_pos()
if not pos then return end
local leaves = minetest.find_nodes_in_area_under_air(
vector.subtract(pos, 16),
vector.add(pos, 16),
"group:leaves"
)
local home_dist
local new_home
for _, leaf_pos in ipairs(leaves or {}) do
local dist = vec_dist(pos, leaf_pos)
if not home_dist
or dist < home_dist then
home_dist = dist
new_home = leaf_pos
end
end
if new_home then
new_home.y = new_home.y + 1
self.home_position = self:memorize("home_position", new_home)
end
end
creatura.register_mob("animalia:owl", {
-- Stats
max_health = 10,
armor_groups = {fleshy = 100},
damage = 2,
speed = 5,
tracking_range = 32,
despawn_after = 1000,
-- Entity Physics
stepheight = 1.1,
max_fall = 0,
turn_rate = 4,
-- Visuals
mesh = "animalia_owl.b3d",
hitbox = {
width = 0.15,
height = 0.3
},
visual_size = {x = 10, y = 10},
textures = {
"animalia_owl.png"
},
animations = {
stand = {range = {x = 1, y = 60}, speed = 20, frame_blend = 0.3, loop = true},
fly = {range = {x = 71, y = 89}, speed = 30, frame_blend = 0.3, loop = true},
glide = {range = {x = 101, y = 119}, speed = 20, frame_blend = 0.2, loop = true},
fly_punch = {range = {x = 131, y = 149}, speed = 20, frame_blend = 0.1, loop = false},
eat = {range = {x = 161, y = 179}, speed = 20, frame_blend = 0.1, loop = false}
},
-- Misc
makes_footstep_sound = true,
catch_with_net = true,
catch_with_lasso = false,
--sounds = {},
follow = {"animalia:rat_raw"},
-- Function
on_eat_drop = function(self)
animalia.protect_from_despawn(self)
get_home_pos(self)
end,
is_home = function(pos, home_pos)
if abs(pos.x - home_pos.x) < 0.5
and abs(pos.z - home_pos.z) < 0.5 then
if abs(pos.y - home_pos.y) < 0.75 then
return true
else
local under = {x = home_pos.x, y = home_pos.y, z = home_pos.z}
local name = minetest.get_node(under).name
if minetest.get_node_group(name, "leaves") > 0 then
return true
end
end
end
return false
end,
wander_action = creatura.action_move,
utility_stack = {
{
utility = "animalia:aerial_wander",
step_delay = 0.25,
get_score = function(self)
if not self.is_landed
or self.in_liquid then
return 0.1, {self}
end
return 0
end
},
{
utility = "animalia:fly_to_roost",
get_score = function(self)
local pos = self.object:get_pos()
if not pos then return end
local player = creatura.get_nearby_player(self)
local plyr_pos = player and player:get_pos()
if plyr_pos then
local dist = vector.distance(pos, plyr_pos)
if dist < 3 then
return 0
end
end
local home = animalia.is_day and self.home_position
if home
and vec_dist(pos, home) < 8 then
return 0.6, {self}
end
return 0
end
},
{
utility = "animalia:fly_to_food",
get_score = function(self)
local cooldown = self.eat_cooldown or 0
if cooldown > 0 then
self.eat_cooldown = cooldown - 1
return 0
end
local food_item = animalia.get_dropped_food(self, "animalia:rat_raw")
if food_item then
return 0.7, {self, food_item}
end
return 0
end
},
{
utility = "animalia:glide_attack_target",
get_score = function(self)
local target = self._target or creatura.get_nearby_object(self, {"animalia:rat", "animalia:bird"})
local tgt_pos = target and target:get_pos()
if tgt_pos then
return 0.4, {self, target}
end
return 0
end
},
},
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
self._tp2home = self:recall("_tp2home") or nil
self.home_position = self:recall("home_position") or nil
local home_pos = self.home_position
if self._tp2home
and home_pos then
self.object:set_pos(home_pos)
end
self.is_landed = self:recall("is_landed") or false
if not home_pos
or creatura.get_node_def(home_pos).walkable then
get_home_pos(self)
end
end,
step_func = function(self)
animalia.step_timers(self)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
animalia.rotate_to_pitch(self)
if not self.is_landed
or not self.touching_ground then
self.speed = 5
else
self.speed = 1
end
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
self:initiate_utility("animalia:die", self)
end
end,
deactivate_func = function(self)
if self:get_utility()
and self:get_utility() == "animalia:fly_to_roost" then
local pos = self.home_position
local node = minetest.get_node_or_nil(pos)
if node
and not creatura.get_node_def(node.name).walkable
and minetest.get_natural_light(pos) > 0 then
self:memorize("_tp2home", true)
end
end
end,
on_rightclick = function(self, clicker)
if animalia.feed(self, clicker, false, false) then
return
end
if animalia.set_nametag(self, clicker) then
return
end
end,
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:owl", "412918", "735b46")

View file

@ -67,11 +67,12 @@ creatura.register_mob("animalia:pig", {
makes_footstep_sound = true, makes_footstep_sound = true,
consumable_nodes = destroyable_crops, consumable_nodes = destroyable_crops,
birth_count = 2, birth_count = 2,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
random = { random = {
name = "animalia_pig_idle", name = "animalia_pig_random",
gain = 1.0, gain = 1.0,
distance = 8 distance = 8
}, },
@ -92,14 +93,14 @@ creatura.register_mob("animalia:pig", {
follow = follows, follow = follows,
-- Function -- Function
utility_stack = { utility_stack = {
[1] = { {
utility = "animalia:wander", utility = "animalia:wander",
step_delay = 0.25, step_delay = 0.25,
get_score = function(self) get_score = function(self)
return 0.1, {self, true} return 0.1, {self, true}
end end
}, },
[2] = { {
utility = "animalia:eat_from_turf", utility = "animalia:eat_from_turf",
step_delay = 0.25, step_delay = 0.25,
get_score = function(self) get_score = function(self)
@ -109,7 +110,7 @@ creatura.register_mob("animalia:pig", {
return 0 return 0
end end
}, },
[3] = { {
utility = "animalia:swim_to_land", utility = "animalia:swim_to_land",
step_delay = 0.25, step_delay = 0.25,
get_score = function(self) get_score = function(self)
@ -119,20 +120,8 @@ creatura.register_mob("animalia:pig", {
return 0 return 0
end end
}, },
[4] = { animalia.global_utils.basic_follow,
utility = "animalia:follow_player", {
get_score = function(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.4, {self, player}
end
return 0
end
},
[5] = {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
get_score = function(self) get_score = function(self)
@ -142,7 +131,8 @@ creatura.register_mob("animalia:pig", {
end end
return 0 return 0
end end
} },
animalia.global_utils.basic_flee
}, },
activate_func = function(self) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
@ -167,10 +157,7 @@ creatura.register_mob("animalia:pig", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:pig", "e0b1a7" ,"cc9485") creatura.register_spawn_egg("animalia:pig", "e0b1a7" ,"cc9485")

120
mobs/rat.lua Normal file
View file

@ -0,0 +1,120 @@
----------
-- Mice --
----------
creatura.register_mob("animalia:rat", {
-- Stats
max_health = 5,
armor_groups = {fleshy = 100},
damage = 0,
speed = 3,
tracking_range = 12,
despawn_after = 2500,
-- Entity Physics
stepheight = 1.1,
max_fall = 0,
turn_rate = 12,
bouyancy_multiplier = 0.5,
-- Visuals
mesh = "animalia_rat.b3d",
hitbox = {
width = 0.15,
height = 0.3
},
visual_size = {x = 10, y = 10},
textures = {
"animalia_rat_1.png",
"animalia_rat_2.png",
"animalia_rat_3.png"
},
animations = {
stand = {range = {x = 1, y = 39}, speed = 20, frame_blend = 0.3, loop = true},
walk = {range = {x = 51, y = 69}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 81, y = 99}, speed = 45, frame_blend = 0.3, loop = true},
eat = {range = {x = 111, y = 119}, speed = 20, frame_blend = 0.1, loop = false}
},
-- Misc
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = false,
makes_footstep_sound = false,
drops = {
{name = "animalia:rat_raw", min = 1, max = 1, chance = 1}
},
-- Function
utility_stack = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self}
end
},
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
if self.in_liquid then
return 0.3, {self}
end
return 0
end
},
{
utility = "animalia:eat_crop",
get_score = function(self)
if math.random(6) < 2
or self:get_utility() == "animalia:eat_crop" then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:steal_from_chest",
get_score = function(self)
if math.random(12) < 2
or self:get_utility() == "animalia:steal_from_chest" then
return 0.2, {self}
end
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local target = creatura.get_nearby_object(self, {"animalia:fox", "animalia:cat"})
if not target then
target = creatura.get_nearby_player(self)
end
if target
and target:get_pos() then
return 0.6, {self, target}
end
return 0
end
}
},
activate_func = function(self)
animalia.initialize_api(self)
animalia.initialize_lasso(self)
end,
step_func = function(self)
animalia.step_timers(self)
animalia.do_growth(self, 60)
animalia.update_lasso_effects(self)
end,
death_func = function(self)
if self:get_utility() ~= "animalia:die" then
self:initiate_utility("animalia:die", self)
end
end,
on_rightclick = function(self, clicker)
if animalia.set_nametag(self, clicker) then
return
end
end,
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:rat", "605a55", "ff936f")

View file

@ -44,6 +44,7 @@ creatura.register_mob("animalia:reindeer", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
drops = { drops = {
@ -98,19 +99,7 @@ creatura.register_mob("animalia:reindeer", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(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.4, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
@ -122,18 +111,7 @@ creatura.register_mob("animalia:reindeer", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_flee
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) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
@ -158,10 +136,7 @@ creatura.register_mob("animalia:reindeer", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:reindeer", "cac3a1" ,"464438") creatura.register_spawn_egg("animalia:reindeer", "413022" ,"d5c0a3")

View file

@ -72,6 +72,7 @@ creatura.register_mob("animalia:sheep", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -135,21 +136,7 @@ creatura.register_mob("animalia:sheep", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(self)
if self.lasso_origin
and type(self.lasso_origin) == "userdata" then
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.4, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
step_delay = 0.25, step_delay = 0.25,
@ -161,18 +148,7 @@ creatura.register_mob("animalia:sheep", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_flee
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) activate_func = function(self)
self.collected = self:recall("collected") or false self.collected = self:recall("collected") or false
@ -267,10 +243,7 @@ creatura.register_mob("animalia:sheep", {
end end
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:sheep", "f4e6cf", "e1ca9b") creatura.register_spawn_egg("animalia:sheep", "f4e6cf", "e1ca9b")

View file

@ -5,6 +5,7 @@
creatura.register_mob("animalia:tropical_fish", { creatura.register_mob("animalia:tropical_fish", {
-- Stats -- Stats
max_health = 5, max_health = 5,
max_breath = 0,
armor_groups = {fleshy = 150}, armor_groups = {fleshy = 150},
damage = 0, damage = 0,
speed = 2, speed = 2,
@ -33,7 +34,6 @@ creatura.register_mob("animalia:tropical_fish", {
flop = {range = {x = 30, y = 40}, speed = 20, frame_blend = 0.3, loop = true}, flop = {range = {x = 30, y = 40}, speed = 20, frame_blend = 0.3, loop = true},
}, },
-- Misc -- Misc
step_delay = 0.25,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = false, catch_with_lasso = false,
makes_footstep_sound = false, makes_footstep_sound = false,
@ -82,9 +82,7 @@ creatura.register_mob("animalia:tropical_fish", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
end
}) })
creatura.register_spawn_egg("animalia:tropical_fish", "e28821", "f6e5d2") creatura.register_spawn_egg("animalia:tropical_fish", "e28821", "f6e5d2")

View file

@ -42,6 +42,7 @@ creatura.register_mob("animalia:turkey", {
}, },
-- Misc -- Misc
makes_footstep_sound = true, makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true, catch_with_net = true,
catch_with_lasso = true, catch_with_lasso = true,
sounds = { sounds = {
@ -113,19 +114,7 @@ creatura.register_mob("animalia:turkey", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_follow,
utility = "animalia:follow_player",
get_score = function(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.3, {self, player}
end
return 0
end
},
{ {
utility = "animalia:breed", utility = "animalia:breed",
get_score = function(self) get_score = function(self)
@ -136,18 +125,7 @@ creatura.register_mob("animalia:turkey", {
return 0 return 0
end end
}, },
{ animalia.global_utils.basic_flee
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) activate_func = function(self)
animalia.initialize_api(self) animalia.initialize_api(self)
@ -182,10 +160,7 @@ creatura.register_mob("animalia:turkey", {
return return
end end
end, end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage) on_punch = animalia.punch
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
}) })
creatura.register_spawn_egg("animalia:turkey", "352b22", "2f2721") creatura.register_spawn_egg("animalia:turkey", "352b22", "2f2721")

View file

@ -45,7 +45,7 @@ end
creatura.register_mob("animalia:wolf", { creatura.register_mob("animalia:wolf", {
-- Stats -- Stats
max_health = 15, max_health = 25,
armor_groups = {fleshy = 100}, armor_groups = {fleshy = 100},
damage = 4, damage = 4,
speed = 5, speed = 5,
@ -60,7 +60,7 @@ creatura.register_mob("animalia:wolf", {
width = 0.35, width = 0.35,
height = 0.7 height = 0.7
}, },
visual_size = {x = 9, y = 9}, visual_size = {x = 10, y = 10},
textures = { textures = {
"animalia_wolf_1.png", "animalia_wolf_1.png",
"animalia_wolf_2.png", "animalia_wolf_2.png",
@ -131,7 +131,8 @@ creatura.register_mob("animalia:wolf", {
{ {
utility = "animalia:follow_player", utility = "animalia:follow_player",
get_score = function(self) get_score = function(self)
local lasso = type(self.lasso_origin or {}) == "userdata" and self.lasso_origin local lasso_tgt = self._lassod_to
local lasso = type(lasso_tgt) == "string" and minetest.get_player_by_name(lasso_tgt)
local owner = self.owner and self.order == "follow" and minetest.get_player_by_name(self.owner) 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 force = (lasso and lasso ~= false) or owner
local player = (force and (owner or lasso)) or creatura.get_nearby_player(self) local player = (force and (owner or lasso)) or creatura.get_nearby_player(self)

Binary file not shown.

BIN
models/animalia_fox.b3d Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
models/animalia_owl.b3d Normal file

Binary file not shown.

BIN
models/animalia_rat.b3d Normal file

Binary file not shown.

Binary file not shown.

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: 1.8 KiB

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 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: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB