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 --
----------
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)
self._despawn = self:memorize("_despawn", false)
self.despawn_after = self:memorize("despawn_after", false)
@ -334,7 +350,7 @@ function animalia.set_nametag(self, clicker)
return
end
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)
if not minetest.is_creative_enabled(plyr_name) then
item:take_item()
@ -343,7 +359,6 @@ function animalia.set_nametag(self, clicker)
return true
end
function animalia.initialize_api(self)
self.gender = self:recall("gender") or nil
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)
if item_name then
-- Eat Animation
local offset_h = self.head_data.pivot_h or 0.5
local offset_v = self.head_data.pivot_v or 0.5
local head = self.head_data
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 = {
x = pos.x + sin(yaw) * -offset_h,
y = pos.y + offset_v,
@ -546,6 +562,15 @@ function animalia.mount(self, player, params)
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 --
--------------
@ -668,4 +693,4 @@ animalia.register_biome_group("common", {
min_humidity = 20,
max_humidity = 80,
min_height = 1
})
})

View file

@ -36,6 +36,7 @@ end
local vec_dir = vector.direction
local vec_dist = vector.distance
local vec_divide = vector.divide
local vec_len = vector.length
local vec_normal = vector.normalize
local vec_round = vector.round
@ -50,6 +51,22 @@ local yaw2dir = minetest.yaw_to_dir
-- 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 = {}
if minetest.get_modpath("default")
@ -108,6 +125,38 @@ local function add_break_particle(pos)
})
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 objects = creatura.get_nearby_objects(self, self.name)
local group = {}
@ -118,6 +167,11 @@ local function get_group_positions(self)
return group
end
local function reset_attack_vals(self)
self.punch_cooldown = 0
self.target = nil
end
--------------
-- Movement --
--------------
@ -157,46 +211,32 @@ creatura.register_movement_method("animalia:fly_simple", function(self)
end)
creatura.register_movement_method("animalia:fly_obstacle_avoidance", function(self)
local box = clamp(self.width, 0.5, 1.5)
local steer_to
local steer_timer = 0.25
local init_dist
self:set_gravity(0)
local function func(_self, goal, speed_factor)
local pos = _self.object:get_pos()
if not pos then return end
-- Return true when goal is reached
if vec_dist(pos, goal) < box * 1.33 then
local dist = vec_dist(pos, goal)
init_dist = dist
if dist < clamp(self.width, 0.5, 1) + 1.5 then
_self:halt()
return true
end
steer_timer = steer_timer - self.dtime
if steer_timer <= 0 then
steer_to = get_avoidance_dir(_self)
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)
-- Calculate Movement
steer_timer = (steer_timer > 0 and steer_timer - self.dtime) or 0.25
steer_to = (steer_timer <= 0 and creatura.get_context_steering(self, goal, 4, true)) or steer_to
local speed = abs(_self.speed or 2) * speed_factor or 0.5
local turn_rate = abs(_self.turn_rate or 5)
-- Movement
local yaw_diff = abs(diff(yaw, goal_yaw))
if yaw_diff < pi * 0.25
or steer_to then
_self:set_forward_velocity(speed)
else
_self:set_forward_velocity(speed * 0.33)
end
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
local dist_weight = (init_dist - dist) / init_dist
-- Apply Movement
local dir = (steer_to or vec_dir(pos, goal))
speed = speed - (speed * 0.75) * dist_weight
turn_rate = turn_rate + turn_rate * dist_weight
_self:set_forward_velocity(speed)
_self:set_vertical_velocity(speed * dir.y)
_self:turn_to(dir2yaw(dir), turn_rate)
end
return func
end)
@ -223,7 +263,7 @@ creatura.register_movement_method("animalia:swim_simple", function(self)
if yaw_diff < pi * 0.25 then
_self:set_forward_velocity(speed)
else
_self:set_forward_velocity(speed * 0.33)
_self:set_forward_velocity(speed * 0.66)
end
self:set_vertical_velocity(speed * goal_dir.y)
_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 goal
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
return true
end
@ -307,6 +347,92 @@ function animalia.action_pursue(self, target, timeout, method, speed_factor, ani
self:set_action(func)
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)
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)
@ -357,6 +483,55 @@ function animalia.action_move_flock(self, pos2, timeout, method, speed_factor, a
self:set_action(func)
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)
local timer = time
local function func(_self)
@ -528,7 +703,7 @@ creatura.register_utility("animalia:swim_to_land", function(self)
_self:set_gravity(-9.8)
_self:set_forward_velocity(_self.speed * 0.66)
_self:animate("walk")
if vector.distance(pos, tpos) < 1
if vec_dist(pos, tpos) < 1
or (not _self.in_liquid
and _self.touching_ground) then
return true
@ -569,7 +744,7 @@ creatura.register_utility("animalia:wander_group", function(self)
local center = self.object:get_pos()
if not center then return end
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)
group_tick = group_tick - 1
if group_tick <= 0 then
@ -631,6 +806,7 @@ creatura.register_utility("animalia:aerial_wander", function(self)
local center = self.object:get_pos()
if not center then return end
local height_tick = 0
local move = self.wander_action or creatura.action_move
local function func(_self)
local pos = self.object:get_pos()
if not pos then return end
@ -643,7 +819,7 @@ creatura.register_utility("animalia:aerial_wander", function(self)
if not _self:get_action() then
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)
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
self:set_utility(func)
@ -652,25 +828,24 @@ end)
creatura.register_utility("animalia:fly_to_roost", function(self)
local home = self.home_position
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 pos = _self.object:get_pos()
if not pos then return end
if not home then return true end
if not _self:get_action() then
if abs(pos.x - home.x) < 0.5
and abs(pos.z - home.z) < 0.5 then
local y_diff = abs(pos.y - home.y)
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
if is_home(pos, home) then
roost(_self, 1, "stand")
return
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
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"})
end
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
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)
if not _self:get_action() 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
creatura.action_idle(_self, 1)
end
@ -872,7 +1047,7 @@ creatura.register_utility("animalia:flee_from_target", function(self, target)
local flee_dir = vec_dir(tgt_pos, pos)
local pos2 = _self:get_wander_pos(2, 3, flee_dir)
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
self:set_utility(func)
@ -985,8 +1160,9 @@ creatura.register_utility("animalia:attack_target", function(self, target)
local pos = _self.object:get_pos()
if not pos then return end
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)
if dist > self.tracking_range then reset_attack_vals(self) return true end
local punch_cooldown = self.punch_cooldown or 0
if punch_cooldown > 0 then
punch_cooldown = punch_cooldown - self.dtime
@ -997,16 +1173,40 @@ creatura.register_utility("animalia:attack_target", function(self, target)
and not punch_init then
punch_init = true
animalia.action_punch(_self, target)
self.punch_cooldown = 3
self.punch_cooldown = 1.5
end
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)
end
end
self:set_utility(func)
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)
local mate = animalia.get_nearby_mate(self, self.name)
if not mate then self.breeding = false return end
@ -1050,6 +1250,174 @@ creatura.register_utility("animalia:breed", function(self)
self:set_utility(func)
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
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
_self.object:add_velocity({
x = 0,
y = _self.jump_power + (abs(_self._movement_data.gravity) * 0.33),
y = _self.jump_power,
z = 0
})
elseif not _self.touching_ground then
@ -1229,4 +1597,36 @@ creatura.register_utility("animalia:flop", function(self)
_self:set_gravity(-9.8)
end
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 asin = math.asin
local atan2 = math.atan2
local cos = math.cos
local deg = math.deg
local sin = math.sin
function animalia.initialize_lasso(self)
self.lasso_origin = self:recall("lasso_origin") or nil
if self.lasso_origin then
self.caught_with_lasso = true
if type(self.lasso_origin) == "table"
and minetest.get_item_group(minetest.get_node(self.lasso_origin).name, "fence") > 0 then
local object = minetest.add_entity(self.lasso_origin, "animalia:lasso_fence_ent")
object:get_luaentity().parent = self.object
elseif type(self.lasso_origin) == "string"
and minetest.get_player_by_name(self.lasso_origin) then
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin)
else
self:forget("lasso_origin")
end
end
local function diff(a, b) -- Get difference between 2 angles
return atan2(sin(b - a), cos(b - a))
end
function animalia.set_lasso_visual(self, target)
if not creatura.is_alive(self)
or (self.lasso_visual
and self.lasso_visual:get_luaentity()) then return end
local pos = self.object:get_pos()
local object = minetest.add_entity(pos, "animalia:lasso_visual")
local ent = object:get_luaentity()
self.lasso_visual = object
self.lasso_origin = target
ent.parent = self.object
ent.lasso_origin = target
return object
local vec_add, vec_dir, vec_dist, vec_len = vector.add, vector.direction, vector.distance, vector.length
local dir2yaw, dir2rot = minetest.dir_to_yaw, vector.dir_to_rotation
-- Entities --
local using_lasso = {}
minetest.register_entity("animalia:lasso_entity", {
visual = "mesh",
mesh = "animalia_lasso_entity.b3d",
textures = {"animalia_lasso_entity.png"},
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
function animalia.update_lasso_effects(self)
if not creatura.is_alive(self) then return end
if self.caught_with_lasso
and self.lasso_origin then
local pos = self.object:get_pos()
pos.y = pos.y + (self:get_height() * 0.5)
animalia.set_lasso_visual(self, self.lasso_origin)
if type(self.lasso_origin) == "userdata"
or type(self.lasso_origin) == "string" then
if type(self.lasso_origin) == "string" then
self.lasso_origin = minetest.get_player_by_name(self.lasso_origin)
if not self.lasso_origin then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
return
end
end
self:memorize("lasso_origin", self.lasso_origin:get_player_name())
-- Get distance to lasso player
local player = self.lasso_origin
local lasso_origin = player:get_pos()
lasso_origin.y = lasso_origin.y + 1
local dist = vector.distance(pos, lasso_origin)
if player:get_wielded_item():get_name() ~= "animalia:lasso"
or vector.distance(pos, lasso_origin) > 16 then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
-- Apply physics
if dist > 6
or abs(lasso_origin.y - pos.y) > 8 then
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8))
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
elseif type(self.lasso_origin) == "table" then
self:memorize("lasso_origin", self.lasso_origin)
local lasso_origin = self.lasso_origin
local dist = vector.distance(pos, lasso_origin)
if dist > 6
or abs(lasso_origin.y - pos.y) > 8 then
local p_target = vector.add(pos, vector.multiply(vector.direction(pos, lasso_origin), dist * 0.8))
local g = -0.18
local v = vector.new(0, 0, 0)
v.x = (1.0 + (0.005 * dist)) * (p_target.x - pos.x) / dist
v.y = -((1.0 + (0.03 * dist)) * ((lasso_origin.y - 4) - pos.y) / (dist * (g * dist)))
v.z = (1.0 + (0.005 * dist)) * (p_target.z - pos.z) / dist
self.object:add_velocity(v)
end
local objects = minetest.get_objects_inside_radius(lasso_origin, 1)
local is_lasso_attached = false
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
is_lasso_attached = true
end
end
if not is_lasso_attached then
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
else
local objects = minetest.get_objects_inside_radius(self.lasso_origin, 0.4)
for _, object in ipairs(objects) do
if object
and object:get_luaentity()
and object:get_luaentity().name == "animalia:lasso_fence_ent" then
minetest.add_item(object:get_pos(), "animalia:lasso")
object:remove()
end
end
self.caught_with_lasso = nil
self.lasso_origin = nil
self:forget("lasso_origin")
if self.lasso_visual then
self.lasso_visual:remove()
self.lasso_visual = nil
end
end
end
local pos = self.object:get_pos()
if not creatura.is_alive(self) then return end
if self._lassod_to then
local lasso = self._lassod_to
self._lasso_ent = self._lasso_ent or add_lasso(self, lasso)
if type(lasso) == "string" then
using_lasso[lasso] = self
local name = lasso
lasso = minetest.get_player_by_name(lasso)
if lasso:get_wielded_item():get_name() ~= "animalia:lasso" then
using_lasso[name] = nil
self._lasso_ent:remove()
self._lasso_ent = nil
self._lassod_to = nil
self:forget("_lassod_to")
return
end
local lasso_pos = lasso:get_pos()
local dist = vec_dist(pos, lasso_pos)
local vel = self.object:get_velocity()
if not vel or dist < 8 and self.touching_ground then return end
if vec_len(vel) < 8 then
self.object:add_velocity(get_rope_velocity(pos, lasso_pos, dist))
end
return
elseif type(lasso) == "table" then
local dist = vec_dist(pos, lasso)
local vel = self.object:get_velocity()
if not vel or dist < 8 and self.touching_ground then return end
if vec_len(vel) < 8 then
self.object:add_velocity(get_rope_velocity(pos, lasso, dist))
end
return
end
end
if self._lasso_ent then
self._lasso_ent:remove()
self._lasso_ent = nil
self._lassod_to = nil
self:forget("_lassod_to")
end
end
local function is_lasso_in_use(player)
for _, ent in pairs(minetest.luaentities) do
if ent.name
and ent.name:match("^animalia:") then
if ent.lasso_origin
and type(ent.lasso_origin) == "userdata"
and ent.lasso_origin == player then
return true
end
end
end
return false
end
local function update_lasso_rotation(self)
if not self.parent
or not self.lasso_origin then self.object:remove() return end
local lasso_origin = self.lasso_origin
if type(lasso_origin) == "userdata" then
lasso_origin = lasso_origin:get_pos()
lasso_origin.y = lasso_origin.y + 1
end
local object = self.parent
if not object then return end
local pos = object:get_pos()
pos.y = pos.y + object:get_luaentity():get_height()
local rot = vector.dir_to_rotation(vector.direction(lasso_origin, pos))
self.object:set_pos(lasso_origin)
self.object:set_rotation(rot)
self.object:set_properties({
visual_size = {x = 6, z = 10 * vector.distance(pos, lasso_origin), y = 6}
})
end
minetest.register_entity("animalia:lasso_visual", {
hp_max = 1,
physical = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "mesh",
mesh = "animalia_lasso.b3d",
visual_size = {x = 2, y = 2},
textures = {"animalia_lasso_cube.png"},
is_visible = true,
makes_footstep_sound = false,
glow = 1,
on_step = function(self)
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
})
-- Item
minetest.register_craftitem("animalia:lasso", {
description = "Lasso",
inventory_image = "animalia_lasso.png",
on_secondary_use = function(_, placer, pointed_thing)
if pointed_thing.type == "object" then
if pointed_thing.ref:is_player() then return end
local ent = pointed_thing.ref:get_luaentity()
if not ent.catch_with_lasso then return end
if not ent.caught_with_lasso
and not is_lasso_in_use(placer) then
ent.caught_with_lasso = true
ent.lasso_origin = placer
elseif ent.lasso_origin
and ent.lasso_origin == placer then
ent.caught_with_lasso = nil
ent.lasso_origin = nil
end
end
end,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then
local pos = minetest.get_pointed_thing_position(pointed_thing)
if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then
local objects = minetest.get_objects_inside_radius(placer:get_pos(), 21)
for _, obj in ipairs(objects) do
if obj:get_luaentity()
and obj:get_luaentity().lasso_origin
and obj:get_luaentity().lasso_visual
and type(obj:get_luaentity().lasso_origin) == "userdata"
and obj:get_luaentity().lasso_origin == placer then
obj:get_luaentity().lasso_visual:get_luaentity().lasso_origin = pos
obj:get_luaentity().lasso_origin = pos
local object = minetest.add_entity(pos, "animalia:lasso_fence_ent")
object:get_luaentity().parent = obj
itemstack:take_item(1)
break
end
end
end
end
return itemstack
end
})
description = "Lasso",
inventory_image = "animalia_lasso.png",
on_secondary_use = function(_, placer, pointed)
local ent = pointed.ref and pointed.ref:get_luaentity()
if ent
and (ent.name:match("^animalia:")
or ent.name:match("^monstrum:")) then
if not ent.catch_with_lasso then return end
local name = placer:get_player_name()
if not ent._lassod_to
and not using_lasso[name] then
using_lasso[name] = ent
ent._lassod_to = name
ent:memorize("_lassod_to", name)
elseif ent._lassod_to
and ent._lassod_to == name then
using_lasso[name] = nil
ent._lassod_to = nil
ent:forget("_lassod_to")
end
end
end,
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then
local pos = minetest.get_pointed_thing_position(pointed_thing)
if minetest.get_item_group(minetest.get_node(pos).name, "fence") > 0 then
local name = placer:get_player_name()
local ent = using_lasso[name]
if ent
and ent._lassod_to
and ent._lassod_to == name then
using_lasso[name] = nil
ent._lasso_ent:set_detach()
ent._lasso_ent:set_pos(pos)
ent._lasso_ent:get_luaentity()._attached = pos
ent._lassod_to = pos
ent:memorize("_lassod_to", pos)
local fence_obj = minetest.add_entity(pos, "animalia:tied_lasso_entity")
fence_obj:get_luaentity()._mob = ent.object
fence_obj:get_luaentity()._lasso_obj = ent._lasso_ent
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
})
creatura.register_mob_spawn("animalia:frog", {
chance = 2,
min_radius = 4,
max_radius = 16,
min_light = 0,
min_height = -32,
max_height = 8,
min_group = 2,
max_group = 6,
biomes = frog_biomes,
spawn_cluster = true,
spawn_in_nodes = true,
creatura.register_mob_spawn("animalia:fox", {
chance = 4,
min_group = 1,
max_group = 2,
spawn_on_gen = true,
nodes = {"default:water_source"},
biomes = animalia.registered_biome_groups["boreal"].biomes
})
creatura.register_mob_spawn("animalia:horse", {
@ -80,6 +72,28 @@ creatura.register_mob_spawn("animalia:horse", {
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", {
chance = 3,
min_group = 2,
@ -119,37 +133,6 @@ creatura.register_mob_spawn("animalia:wolf", {
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", {
chance = 3,
min_height = -128,
@ -160,4 +143,70 @@ creatura.register_mob_spawn("animalia:tropical_fish", {
spawn_in_nodes = true,
spawn_on_gen = true,
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)
minetest.register_entity(def.mob .. "_egg_sprite", {
minetest.register_entity(def.mob .. "_egg_entity", {
hp_max = 1,
physical = true,
collisionbox = {0, 0, 0, 0, 0, 0},
@ -36,94 +36,75 @@ local function register_egg(name, def)
textures = {"animalia_egg.png"},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = true,
on_step = function(self)
on_step = function(self, _, moveresult)
local pos = self.object:get_pos()
local objects = minetest.get_objects_inside_radius(pos, 1.5)
local cube = minetest.find_nodes_in_area(
vector.new(pos.x - 0.5, pos.y - 0.5, pos.z - 0.5),
vector.new(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5),
walkable_nodes)
if #objects >= 2 then
if objects[2]:get_armor_groups().fleshy then
objects[2]:punch(self.object, 2.0, {full_punch_interval = 0.1, damage_groups = {fleshy = 1}}, nil)
if not pos then return end
if moveresult.collides then
for _, collision in ipairs(moveresult.collision) do
if collision.type == "nodes" then
minetest.add_particlespawner({
amount = 6,
time = 0.1,
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
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
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
animalia.initialize_api(ent)
animalia.protect_from_despawn(ent)
self.object:remove()
else
self.object:remove()
end
self.object:remove()
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, {
description = def.description,
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},
})
@ -141,6 +122,47 @@ local function register_egg(name, def)
})
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 --
-----------
@ -199,6 +221,26 @@ minetest.register_craft({
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", {
description = "Raw Porkchop",
inventory_image = "animalia_porkchop_raw.png",
@ -480,48 +522,7 @@ minetest.register_craftitem("animalia:net", {
description = "Animal Net",
inventory_image = "animalia_net.png",
stack_max = 1,
on_secondary_use = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "object" then
if pointed_thing.ref:is_player() then return end
local ent = pointed_thing.ref:get_luaentity()
if not ent.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_secondary_use = mob_storage_use,
on_place = function(itemstack, placer, pointed_thing)
local pos = pointed_thing.above
if pos then
@ -580,6 +581,61 @@ minetest.register_node("animalia:guano", {
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 --
--------------
@ -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({
output = "animalia:saddle",
recipe = {

View file

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

View file

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

View file

@ -24,7 +24,7 @@ creatura.register_mob("animalia:bird", {
damage = 0,
speed = 4,
tracking_range = 16,
despawn_after = 100,
despawn_after = 750,
-- Entity Physics
stepheight = 1.1,
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}
},
-- Misc
max_boids = 12,
makes_footstep_sound = true,
catch_with_net = true,
catch_with_lasso = false,
@ -73,7 +74,7 @@ creatura.register_mob("animalia:bird", {
},
follow = follows,
-- Function
wander_action = animalia.action_move_flock,
wander_action = animalia.action_move_boid,
utility_stack = {
{
utility = "animalia:wander_group",
@ -155,7 +156,7 @@ creatura.register_mob("animalia:bird", {
animalia.do_growth(self, 60)
animalia.update_lasso_effects(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 self.texture_no == 1 then
self:play_sound("cardinal")
@ -213,9 +214,7 @@ creatura.register_mob("animalia:bird", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
end
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:bird", "ae2f2f", "f3ac1c")

View file

@ -34,7 +34,7 @@ creatura.register_mob("animalia:cat", {
width = 0.2,
height = 0.4
},
visual_size = {x = 6, y = 6},
visual_size = {x = 10, y = 10},
textures = {
"animalia_cat_1.png",
"animalia_cat_2.png",
@ -58,6 +58,7 @@ creatura.register_mob("animalia:cat", {
},
-- Misc
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -179,7 +180,8 @@ creatura.register_mob("animalia:cat", {
{
utility = "animalia:follow_player",
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 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)
@ -191,13 +193,25 @@ creatura.register_mob("animalia:cat", {
return 0
end
},
{
utility = "animalia:attack_target",
get_score = function(self)
local target = self._target or creatura.get_nearby_object(self, "animalia:rat")
local tgt_pos = target and target:get_pos()
if tgt_pos
and self:is_pos_safe(tgt_pos) then
return 0.7, {self, target}
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}
return 0.8, {self}
end
return 0
end

View file

@ -52,6 +52,7 @@ creatura.register_mob("animalia:chicken", {
},
-- Misc
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -124,19 +125,7 @@ creatura.register_mob("animalia:chicken", {
return 0
end
},
{
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
},
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
@ -148,18 +137,7 @@ creatura.register_mob("animalia:chicken", {
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
animalia.global_utils.basic_flee
},
activate_func = function(self)
animalia.initialize_api(self)
@ -194,10 +172,7 @@ creatura.register_mob("animalia:chicken", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
on_punch = animalia.punch
})
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},
},
-- Misc
step_delay = 0.25,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -123,19 +123,7 @@ creatura.register_mob("animalia:cow", {
return 0
end
},
{
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
},
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
@ -147,18 +135,7 @@ creatura.register_mob("animalia:cow", {
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
animalia.global_utils.basic_flee
},
activate_func = function(self)
animalia.initialize_api(self)
@ -215,10 +192,7 @@ creatura.register_mob("animalia:cow", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
on_punch = animalia.punch
})
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
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -128,7 +129,7 @@ creatura.register_mob("animalia:frog", {
if self.in_liquid then return 0 end
local pos = self.object:get_pos()
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 plyr_name = (target and target:is_player() and target:get_player_name()) or ""
if tgt_pos then

View file

@ -100,15 +100,15 @@ creatura.register_mob("animalia:horse", {
},
animations = {
stand = {range = {x = 1, y = 59}, speed = 10, frame_blend = 0.3, loop = true},
walk = {range = {x = 61, y = 79}, speed = 20, frame_blend = 0.3, loop = true},
run = {range = {x = 81, y = 99}, speed = 30, frame_blend = 0.3, loop = true},
punch_aoe = {range = {x = 101, y = 119}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.2, loop = false},
rear_constant = {range = {x = 121, y = 140}, speed = 20, frame_blend = 0.3, loop = false},
eat = {range = {x = 141, y = 160}, speed = 20, frame_blend = 0.3, loop = false}
walk = {range = {x = 71, y = 89}, speed = 25, frame_blend = 0.3, loop = true},
run = {range = {x = 101, y = 119}, speed = 40, frame_blend = 0.3, loop = true},
punch_aoe = {range = {x = 161, y = 180}, speed = 30, frame_blend = 0.2, loop = false},
rear = {range = {x = 131, y = 150}, speed = 20, frame_blend = 0.2, loop = false},
eat = {range = {x = 191, y = 220}, speed = 30, frame_blend = 0.3, loop = false}
},
-- Misc
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -116,8 +116,7 @@ creatura.register_mob("animalia:horse", {
random = {
name = "animalia_horse_idle",
gain = 1.0,
distance = 8,
variations = 3,
distance = 8
},
hurt = {
name = "animalia_horse_hurt",
@ -140,10 +139,10 @@ creatura.register_mob("animalia:horse", {
},
head_data = {
bone = "Neck.CTRL",
offset = {x = 0, y = 1.45, z = 0.0},
pitch_correction = 25,
offset = {x = 0, y = 1.05, z = 0.0},
pitch_correction = 35,
pivot_h = 1,
pivot_v = 1.5
pivot_v = 1.75
},
-- Function
add_child = function(self, mate)
@ -198,19 +197,7 @@ creatura.register_mob("animalia:horse", {
return 0
end
},
{
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
},
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
@ -263,10 +250,6 @@ creatura.register_mob("animalia:horse", {
animalia.initialize_lasso(self)
set_pattern(self)
self.owner = self:recall("owner") or nil
if self.owner then
self._despawn = nil
self.despawn_after = nil
end
self.rider = nil
self.saddled = self:recall("saddled") or false
self.max_health = self:recall("max_health") or random(30, 45)
@ -333,9 +316,7 @@ creatura.register_mob("animalia:horse", {
end,
on_punch = function(self, puncher, ...)
if self.rider and puncher == self.rider then return end
creatura.basic_punch_func(self, puncher, ...)
if self.hp < 0 then return end
self._puncher = puncher
animalia.punch(self, puncher, ...)
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,
consumable_nodes = destroyable_crops,
birth_count = 2,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
random = {
name = "animalia_pig_idle",
name = "animalia_pig_random",
gain = 1.0,
distance = 8
},
@ -92,14 +93,14 @@ creatura.register_mob("animalia:pig", {
follow = follows,
-- Function
utility_stack = {
[1] = {
{
utility = "animalia:wander",
step_delay = 0.25,
get_score = function(self)
return 0.1, {self, true}
end
},
[2] = {
{
utility = "animalia:eat_from_turf",
step_delay = 0.25,
get_score = function(self)
@ -109,7 +110,7 @@ creatura.register_mob("animalia:pig", {
return 0
end
},
[3] = {
{
utility = "animalia:swim_to_land",
step_delay = 0.25,
get_score = function(self)
@ -119,20 +120,8 @@ creatura.register_mob("animalia:pig", {
return 0
end
},
[4] = {
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] = {
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
get_score = function(self)
@ -142,7 +131,8 @@ creatura.register_mob("animalia:pig", {
end
return 0
end
}
},
animalia.global_utils.basic_flee
},
activate_func = function(self)
animalia.initialize_api(self)
@ -167,10 +157,7 @@ creatura.register_mob("animalia:pig", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
on_punch = animalia.punch
})
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
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
drops = {
@ -98,19 +99,7 @@ creatura.register_mob("animalia:reindeer", {
return 0
end
},
{
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
},
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
@ -122,18 +111,7 @@ creatura.register_mob("animalia:reindeer", {
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
animalia.global_utils.basic_flee
},
activate_func = function(self)
animalia.initialize_api(self)
@ -158,10 +136,7 @@ creatura.register_mob("animalia:reindeer", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
on_punch = animalia.punch
})
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
makes_footstep_sound = true,
flee_puncher = true,
catch_with_net = true,
catch_with_lasso = true,
sounds = {
@ -135,21 +136,7 @@ creatura.register_mob("animalia:sheep", {
return 0
end
},
{
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
},
animalia.global_utils.basic_follow,
{
utility = "animalia:breed",
step_delay = 0.25,
@ -161,18 +148,7 @@ creatura.register_mob("animalia:sheep", {
return 0
end
},
{
utility = "animalia:flee_from_target",
get_score = function(self)
local puncher = self._target
if puncher
and puncher:get_pos() then
return 0.6, {self, puncher}
end
self._target = nil
return 0
end
}
animalia.global_utils.basic_flee
},
activate_func = function(self)
self.collected = self:recall("collected") or false
@ -267,10 +243,7 @@ creatura.register_mob("animalia:sheep", {
end
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
self._target = puncher
end
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:sheep", "f4e6cf", "e1ca9b")

View file

@ -5,6 +5,7 @@
creatura.register_mob("animalia:tropical_fish", {
-- Stats
max_health = 5,
max_breath = 0,
armor_groups = {fleshy = 150},
damage = 0,
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},
},
-- Misc
step_delay = 0.25,
catch_with_net = true,
catch_with_lasso = false,
makes_footstep_sound = false,
@ -82,9 +82,7 @@ creatura.register_mob("animalia:tropical_fish", {
return
end
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
creatura.basic_punch_func(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
end
on_punch = animalia.punch
})
creatura.register_spawn_egg("animalia:tropical_fish", "e28821", "f6e5d2")

View file

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

View file

@ -45,7 +45,7 @@ end
creatura.register_mob("animalia:wolf", {
-- Stats
max_health = 15,
max_health = 25,
armor_groups = {fleshy = 100},
damage = 4,
speed = 5,
@ -60,7 +60,7 @@ creatura.register_mob("animalia:wolf", {
width = 0.35,
height = 0.7
},
visual_size = {x = 9, y = 9},
visual_size = {x = 10, y = 10},
textures = {
"animalia_wolf_1.png",
"animalia_wolf_2.png",
@ -131,7 +131,8 @@ creatura.register_mob("animalia:wolf", {
{
utility = "animalia:follow_player",
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 force = (lasso and lasso ~= false) or owner
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