mirror of
https://github.com/ElCeejo/animalia.git
synced 2025-09-06 21:25:48 -04:00
Harvest Update
This commit is contained in:
parent
d1453b9501
commit
4642fb63fd
56 changed files with 1689 additions and 972 deletions
35
api/api.lua
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
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
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"}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue