Harvest Update
15
.luacheckrc
|
@ -1,15 +0,0 @@
|
|||
max_line_length = 120
|
||||
|
||||
globals = {
|
||||
"minetest",
|
||||
"animalia",
|
||||
"creatura",
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
"vector",
|
||||
"ItemStack",
|
||||
table = {fields = {"copy"}}
|
||||
}
|
||||
|
||||
ignore = {"212/self", "212/this"}
|
35
api/api.lua
|
@ -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
|
||||
})
|
||||
})
|
|
@ -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
|
||||
}
|
||||
}
|
586
api/lasso.lua
|
@ -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
|
||||
})
|
||||
|
|
137
api/spawning.lua
|
@ -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"}
|
||||
})
|
297
craftitems.lua
|
@ -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 = {
|
||||
|
|
5
init.lua
|
@ -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",
|
||||
}
|
||||
|
||||
|
|
277
mobs/bat.lua
|
@ -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")
|
|
@ -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")
|
||||
|
|
20
mobs/cat.lua
|
@ -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
|
||||
|
|
|
@ -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")
|
34
mobs/cow.lua
|
@ -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
|
@ -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")
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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")
|
33
mobs/pig.lua
|
@ -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
|
@ -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")
|
|
@ -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")
|
|
@ -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")
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
|
@ -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)
|
||||
|
|
BIN
models/animalia_fox.b3d
Normal file
BIN
models/animalia_lasso_entity.b3d
Normal file
BIN
models/animalia_owl.b3d
Normal file
BIN
models/animalia_rat.b3d
Normal file
BIN
sounds/pig/animalia_pig_hurt.ogg
Normal file
BIN
sounds/pig/animalia_pig_random.1.ogg
Normal file
BIN
sounds/pig/animalia_pig_random.2.ogg
Normal file
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 1 KiB |
BIN
textures/animalia_lasso_entity.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.3 KiB |
BIN
textures/fox/animalia_fox_1.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
textures/items/animalia_crate.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
textures/items/animalia_crate_side.png
Normal file
After Width: | Height: | Size: 851 B |
BIN
textures/items/animalia_guano.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6 KiB |
BIN
textures/items/animalia_rat_cooked.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
textures/items/animalia_rat_raw.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
textures/owl/animalia_owl.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
textures/rat/animalia_rat_1.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
textures/rat/animalia_rat_2.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
textures/rat/animalia_rat_3.png
Normal file
After Width: | Height: | Size: 6.5 KiB |