petz/petz/misc/behaviours.lua

1144 lines
30 KiB
Lua

local modpath, S = ...
--
-- Helpers Functions
--
petz.lookback = function(self, pos2)
local pos1 = self.object:get_pos()
local vec = {x = pos1.x - pos2.x, y = pos1.y - pos2.y, z = pos1.z - pos2.z}
local yaw = math.atan(vec.z / vec.x) - math.pi / 2
if pos1.x >= pos2.x then
yaw = yaw + math.pi
end
self.object:set_yaw(yaw + math.pi)
end
petz.lookat = function(self, pos2)
local pos1 = self.object:get_pos()
local vec = {x = pos1.x - pos2.x, y = pos1.y - pos2.y, z = pos1.z - pos2.z}
local yaw = math.atan(vec.z / vec.x) - math.pi / 2
if pos1.x >= pos2.x then
yaw = yaw + math.pi
end
self.object:set_yaw(yaw + math.pi)
end
function petz.bh_check_pack(self)
if mobkit.get_closest_entity(self, "petz:"..self.type) then
return true
else
return false
end
end
function petz.get_player_back_pos(player, pos)
local yaw = player:get_look_horizontal()
if yaw then
local dir_x = -math.sin(yaw)
local dir_z = math.cos(yaw)
local back_pos = {
x = pos.x - dir_x,
y = pos.y,
z = pos.z - dir_z,
}
local node = minetest.get_node_or_nil(back_pos)
if node and minetest.registered_nodes[node.name] then
return node.name, back_pos
else
return nil, nil
end
else
return nil, nil
end
end
function mobkit.check_height(self)
local yaw = self.object:get_yaw()
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
local pos = self.object:get_pos()
local ypos = pos.y - self.collisionbox[2] -- just floor level
local pos1 = {x = pos.x + dir_x, y = ypos, z = pos.z + dir_z}
local pos2 = {x = pos.x + dir_x, y = ypos - self.max_height, z = pos.z + dir_z}
local blocking_node, blocking_node_pos = minetest.line_of_sight(pos1, pos2, 1)
if not(blocking_node) then
local height = ypos - blocking_node_pos.y
return height
end
return false
end
function mobkit.check_front_obstacle(self)
local yaw = self.object:get_yaw()
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
local pos = self.object:get_pos()
local nodes_front = 5
if minetest.line_of_sight(
{x = pos.x + dir_x, y = pos.y, z = pos.z + dir_z}, {x = pos.x + dir_x + nodes_front, y = pos.y, z = pos.z + dir_z + nodes_front}, 1) then
return false
end
return true
end
function mobkit.check_is_on_surface(self)
local pos = self.object:get_pos()
if pos.y > 0 then
return true
else
return false
end
end
function petz.is_standing(self)
local velocity = self.object:get_velocity()
local speed = vector.length(velocity)
if speed == 0 then
return true
else
return false
end
end
function petz.is_jumping(self)
if self.isonground == true then
return false
else
return true
end
end
function mobkit.check_ground_suffocation(self)
local spos = mobkit.get_stand_pos(self)
spos.y = spos.y + 0.01
if self.type and mobkit.is_alive(self) and not(self.is_baby) then
local stand_pos = spos
stand_pos.y = spos.y + 0.5
local stand_node_pos = mobkit.get_node_pos(stand_pos)
local stand_node = mobkit.nodeatpos(stand_node_pos)
if stand_node and stand_node.walkable and stand_node.drawtype == "normal" then
local new_y = stand_pos.y + self.jump_height
if new_y <= 30927 then
self.object:set_pos({
x = stand_pos.x,
y = new_y,
z = stand_pos.z
})
end
end
end
end
function petz.set_velocity(self, velocity)
local yaw = self.object:get_yaw() or 0
self.object:set_velocity({
x = (math.sin(yaw) * -velocity.x),
y = velocity.y or 0,
z = (math.cos(yaw) * velocity.z),
})
end
function mobkit.node_name_in(self, where)
local pos = self.object:get_pos()
local yaw = self.object:get_yaw()
if yaw then
local dir_x = -math.sin(yaw)
local dir_z = math.cos(yaw)
local pos2
if where == "front" then
pos2 = {
x = pos.x + dir_x,
y = pos.y,
z = pos.z + dir_z,
}
elseif where == "top" then
pos2= {
x = pos.x,
y = pos.y + 0.5,
z = pos.z,
}
elseif where == "below" then
pos2 = mobkit.get_stand_pos(self)
pos2.y = pos2.y - 0.1
elseif where == "back" then
pos2 = {
x = pos.x - dir_x,
y = pos.y,
z = pos.z - dir_z,
}
elseif where == "self" then
pos2= {
x = pos.x,
y = pos.y - 0.75,
z = pos.z,
}
end
local node = minetest.get_node_or_nil(pos2)
if node and minetest.registered_nodes[node.name] then
return node.name
else
return nil
end
else
return nil
end
end
petz.check_if_climb = function(self)
local node_front_name = mobkit.node_name_in(self, "front")
--minetest.chat_send_player("singleplayer", node_front_name)
local node_top_name= mobkit.node_name_in(self, "top")
--minetest.chat_send_player("singleplayer", node_top_name)
if node_front_name and minetest.registered_nodes[node_front_name]
and node_top_name and minetest.registered_nodes[node_top_name]
and node_top_name == "air"
and (minetest.registered_nodes[node_front_name].groups.wood
or minetest.registered_nodes[node_front_name].groups.leaves
or minetest.registered_nodes[node_front_name].groups.tree) then
return true
else
return false
end
end
petz.pos_front = function(self, pos)
local yaw = self.object:get_yaw()
local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
local pos_front = { -- what is in front of mob?
x = pos.x + dir_x,
y = pos.y - 0.75,
z = pos.z + dir_z
}
return pos_front
end
---
---COMMON BEHAVIOURS
---
--
-- Runaway from predator behaviour
--
function petz.bh_runaway_from_predator(self, pos)
local predator_list = petz.settings[self.type.."_predators"]
if predator_list then
predator_list = petz.str_remove_spaces(predator_list)
local predators = string.split(predator_list, ',')
for i = 1, #predators do --loop thru all preys
--minetest.chat_send_player("singleplayer", "spawn node="..spawn_nodes[i])
--minetest.chat_send_player("singleplayer", "node name="..node.name)
local predator = mobkit.get_closest_entity(self, predators[i]) -- look for predator
if predator then
local predator_pos = predator:get_pos()
if predator and vector.distance(pos, predator_pos) <= self.view_range then
mobkit.hq_runfrom(self, 18, predator)
return true
else
return false
end
end
end
end
end
--
-- Attack Player Behaviour
--
function petz.bh_attack_player(self, pos, prty, player)
if (self.attack_pack) and not(self.warn_attack) then
if petz.bh_check_pack(self) then
self.warn_attack = true
end
end
local werewolf = false
if petz.settings["lycanthropy"] then
if petz.is_werewolf(player) then
werewolf = true
end
end
if (self.tamed == false and werewolf == false) or (self.tamed == true and self.status == "guard" and player:get_player_name() ~= self.owner) then
local player_pos = player:get_pos()
if vector.distance(pos, player_pos) <= self.view_range then -- if player close
if (self.attack_player and not(self.avoid_player)) or (self.warn_attack == true) then --attack player
if self.can_swin then
mobkit.hq_aqua_attack(self, prty, player, 6)
elseif self.can_fly then
mobkit.hq_flyhunt(self, prty, player)
else
mobkit.hq_hunt(self, prty, player) -- try to repel them
end
return true
else
if not(self.can_swin) and not(self.can_fly) then
if self.avoid_player then
mobkit.hq_runfrom(self, prty, player) -- run away from player
return true
else
return false
end
else
return false
end
end
else
return false
end
else
return false
end
end
petz.bh_afraid= function(self, pos)
petz.lookback(self, pos)
local x = self.object:get_velocity().x
local z = self.object:get_velocity().z
self.object:set_velocity({x= x, y= 0, z= z})
--self.object:set_acceleration({x= hvel.x, y= 0, z= hvel.z})
end
--
-- Replace Behaviour
--
function petz.bh_replace(self)
if mokapi.replace(self, "petz_replace", petz.settings.max_hear_distance) then
petz.refill(self) --Refill wool, milk or nothing
end
if self.lay_eggs then
petz.lay_egg(self)
end
end
--
-- Teleport Behaviour
--
function petz.bh_teleport(self, pos, player, player_pos)
local node, back_pos = petz.get_player_back_pos(player, player_pos)
if node and node == "air" then
petz.do_particles_effect(self.object, self.object:get_pos(), "pumpkin")
self.object:set_pos(back_pos)
mobkit.make_sound(self, 'laugh')
end
end
function petz.bh_create_beehive(self, pos)
if not self.create_beehive then
return false
end
local node_name = mobkit.node_name_in(self, "front")
if minetest.get_item_group(node_name, "wood") > 0 or minetest.get_item_group(node_name, "leaves") > 0 then
local minp = {
x = pos.x - (self.max_height*4),
y = pos.y - self.max_height,
z = pos.z - (self.max_height*4),
}
local maxp = {
x = pos.x + (self.max_height*4),
y = pos.y + self.max_height,
z = pos.z + (self.max_height*4),
}
if #minetest.find_nodes_in_area(minp, maxp, {"petz:beehive"}) < 1 then
minetest.set_node(pos, {name= "petz:beehive"})
mokapi.remove_mob(self)
return true
else
return false
end
else
return false
end
end
--
-- Herding Behaviour
--
function petz.bh_herding(self, pos, player)
if not(self.tamed) or not(self.herd) or not(self.herding) then
return false
end
local join_herd = false
local tpos
local ent_obj = mobkit.get_closest_entity(self, "petz:"..self.type) -- look for a herd to join with
if ent_obj then
local ent = ent_obj:get_luaentity()
if ent and ent.herding then
tpos = ent_obj:get_pos()
local distance = vector.distance(pos, tpos)
if distance > petz.settings.herding_members_distance then
join_herd = true
end
end
end
if not join_herd and player then -- search for a shepherd
local player_name = player:get_player_name()
if self.owner == player_name then
local wielded_item = player:get_wielded_item()
local wielded_item_name = wielded_item:get_name()
if wielded_item_name == "petz:shepherd_crook" then
tpos = player:get_pos()
if vector.distance(pos, tpos) > petz.settings.herding_shepherd_distance then -- if player close
join_herd = true
end
end
end
end
if join_herd and tpos then
mobkit.hq_goto(self, 4.5, tpos)
return true
else
return false
end
end
--
-- Breed Behaviour
--
function petz.bh_breed(self, pos)
if self.breed == true and self.is_rut == true and self.is_male == true then --search a couple for a male!
local couple_name = "petz:"..self.type
if self.type == "elephant" then
couple_name = couple_name.."_female"
end
local couple_obj = mobkit.get_closest_entity(self, couple_name) -- look for a couple
if couple_obj then
local couple = couple_obj:get_luaentity()
if couple and couple.is_rut == true and couple.is_pregnant == false and couple.is_male == false then --if couple and female and is not pregnant and is rut
local couple_pos = couple.object:get_pos() --get couple pos
local copulation_distance = petz.settings[self.type.."_copulation_distance"] or 1
if vector.distance(pos, couple_pos) <= copulation_distance then --if close
--Changue some vars
self.is_rut = false
mobkit.remember(self, "is_rut", self.is_rut)
couple.is_rut = false
mobkit.remember(couple, "is_rut", couple.is_rut)
couple.is_pregnant = true
mobkit.remember(couple, "is_pregnant", couple.is_pregnant)
couple.father_genes = mobkit.remember(couple, "father_genes", self.genes)
petz.do_particles_effect(couple.object, couple.object:get_pos(), "pregnant".."_"..couple.type)
end
end
end
end
end
--
-- FOLLOW BEHAVIOURS
-- 2 types: for terrestrial and for flying/aquatic mobs.
--
-- Follow behaviours for terrestrial mobs (2 functions; start & stop)
--
function petz.bh_start_follow(self, pos, player, prty)
if player then
local wielded_item_name = player:get_wielded_item():get_name()
local tpos = player:get_pos()
if mokapi.item_in_itemlist(wielded_item_name, self.follow) and vector.distance(pos, tpos) <= self.view_range then
self.status = mobkit.remember(self, "status", "follow")
if (self.can_fly) or (self.can_swin and self.isinliquid) then
mobkit.hq_followliquidair(self, prty, player)
else
mobkit.hq_follow(self, prty, player)
end
return true
else
return false
end
end
end
function petz.bh_stop_follow(self, player)
if player then
local wielded_item_name = player:get_wielded_item():get_name()
if wielded_item_name ~= self.follow then
petz.ownthing(self)
return true
else
return false
end
else
petz.ownthing(self)
end
end
--
-- Follow Fly/Water Behaviours (2 functions: HQ & LQ)
--
function mobkit.hq_followliquidair(self, prty, player)
local func=function(self)
local pos = mobkit.get_stand_pos(self)
local tpos = player:get_pos()
if self.can_swin then
if not(petz.isinliquid(self)) then
--check if water below, dolphins
local node_name = mobkit.node_name_in(self, "below")
if minetest.get_item_group(node_name, "water") == 0 then
petz.ownthing(self)
return true
end
end
end
if pos and tpos then
local distance = vector.distance(pos, tpos)
if distance < 3 then
return
elseif (distance < self.view_range) then
if mobkit.is_queue_empty_low(self) then
mobkit.lq_followliquidair(self, player)
end
elseif distance >= self.view_range then
petz.ownthing(self)
return true
end
else
return true
end
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_followliquidair(self, target)
local func = function(self)
mobkit.flyto(self, target)
return true
end
mobkit.queue_low(self,func)
end
function mobkit.flyto(self, target)
local pos = self.object:get_pos()
local tpos = target:get_pos()
local tgtbox = target:get_properties().collisionbox
local height = math.abs(tgtbox[3]) + math.abs(tgtbox[6])
--minetest.chat_send_player("singleplayer", tostring(tpos.y))
--minetest.chat_send_player("singleplayer", tostring(height))
tpos.y = tpos.y + 2 * (height)
local dir = vector.direction(pos, tpos)
local velocity = {
x= self.max_speed* dir.x,
y= self.max_speed* dir.y,
z= self.max_speed* dir.z,
}
local new_yaw = minetest.dir_to_yaw(dir)
self.object:set_yaw(new_yaw)
self.object:set_velocity(velocity)
end
--
-- Approach Torch Behaviour
-- for moths (not finished!!!)
--
function mobkit.hq_approach_torch(self, prty, tpos)
local func=function(self)
local pos = self.object:get_pos()
if pos and tpos then
local distance = vector.distance(pos, tpos)
if distance < self.view_range and (distance >= self.view_range) then
if mobkit.is_queue_empty_low(self) then
--mobkit.lq_followliquidair(self, target)
end
elseif distance >= self.view_range then
petz.ownthing(self)
return true
end
else
return true
end
end
mobkit.queue_high(self, func, prty)
end
--
-- WANDER FLY BEHAVIOUR (2 functions: HQ & LQ)
--
function mobkit.hq_wanderfly(self, prty)
local func=function(self)
if mobkit.is_queue_empty_low(self) then
mobkit.lq_dumbfly(self, 0.6)
end
end
mobkit.queue_high(self,func,prty)
end
--3 fly status: ascend, descend and stand right.
--Each 3 seconds:
--1) Search if 'max_height' defined for each mob is reached, if yes: descend or stand.
--2) Check if over water, if yes: ascend.
--3) Check if node in front, if yes: random rotation backwards. This does mobs not stuck.
--4) Random rotation, to avoid mob go too much further.
--5) In each status a chance to change of status, important: more preference for 'ascend'
--than descend, cos this does the mobs stand on air, and climb mountains and trees.
function mobkit.lq_turn2yaw(self, yaw)
local func = function(self)
if mobkit.turn2yaw(self, yaw) then
return true
end
end
mobkit.queue_low(self,func)
end
function mobkit.lq_dumbfly(self, speed_factor)
local timer = petz.settings.fly_check_time
local fly_status = "ascend"
speed_factor = speed_factor or 1
local func = function(self)
timer = timer - self.dtime
if timer < 0 then
--minetest.chat_send_player("singleplayer", tostring(timer))
local velocity
mobkit.animate(self, 'fly')
local random_num = math.random(1, 5)
local yaw = self.object:get_yaw()
local rotation = self.object:get_rotation()
if random_num <= 1 or mobkit.node_name_in(self, "front") ~= "air" then
if yaw then
--minetest.chat_send_player("singleplayer", "test")
local rotation_integer = math.random(0, 4)
local rotation_decimals = math.random()
local new_yaw = yaw + rotation_integer + rotation_decimals
mobkit.lq_turn2yaw(self, new_yaw)
return true --finish this que to start the turn
end
end
local y_impulse = 1
if mobkit.check_front_obstacle(self) and mobkit.node_name_in(self, "top") == "air" then
fly_status = "ascend"
y_impulse = 3
end
height_from_ground = mobkit.check_height(self) --returns 'false' if the mob flies higher that max_height, otherwise returns the height from the ground
--minetest.chat_send_player("singleplayer", tostring(height_from_ground))
if not(height_from_ground) or mobkit.node_name_in(self, "top") ~= "air" then --check if max height, then stand or descend, or a node above the petz
random_num = math.random(1, 100)
if random_num < 70 then
fly_status = "descend"
else
fly_status = "stand"
end
else --check if water below, or near the ground, if yes ascend
local node_name = mobkit.node_name_in(self, "below")
if minetest.get_item_group(node_name, "water") >= 1 then
fly_status = "ascend"
end
if height_from_ground and (height_from_ground < 1) then
fly_status = "ascend"
end
end
--minetest.chat_send_player("singleplayer", status)
--local node_name_in_front = mobkit.node_name_in(self, "front")
if fly_status == "stand" then -- stand
velocity = {
x= self.max_speed* speed_factor,
y= 0.0,
z= self.max_speed* speed_factor,
}
self.object:set_rotation({x= -0.0, y = rotation.y, z= rotation.z})
random_num = math.random(1, 100)
if random_num < 20 and not(height_from_ground) then
fly_status = "descend"
elseif random_num < 40 then
fly_status = "ascend"
end
--minetest.chat_send_player("singleplayer", "stand")
elseif fly_status == "descend" then -- descend
velocity = {
x = self.max_speed* speed_factor,
y = -speed_factor,
z = self.max_speed* speed_factor,
}
self.object:set_rotation({x= 0.16, y = rotation.y, z= rotation.z})
random_num = math.random(1, 100)
if random_num < 20 then
fly_status = "stand"
elseif random_num < 40 then
fly_status = "ascend"
end
--minetest.chat_send_player("singleplayer", "descend")
else --ascend
fly_status = "ascend"
velocity ={
x = self.max_speed * speed_factor,
y = speed_factor * (y_impulse or 1),
z = self.max_speed * speed_factor,
}
self.object:set_rotation({x= -0.16, y = rotation.y, z= rotation.z})
--minetest.chat_send_player("singleplayer", tostring(velocity.x))
--minetest.chat_send_player("singleplayer", "ascend")
end
timer = petz.settings.fly_check_time
petz.set_velocity(self, velocity)
self.fly_velocity = velocity --save the velocity to set in each step, not only each x seconds
return true
else
if self.fly_velocity then
petz.set_velocity(self, self.fly_velocity)
else
petz.set_velocity(self, {x = 0.0, y = 0.0, z = 0.0})
end
end
end
mobkit.queue_low(self,func)
end
--
-- 'Take Off' Behaviour ( 2 funtions)
--
function mobkit.hq_fly(self, prty)
local func=function(self)
mobkit.animate(self, "fly")
mobkit.lq_fly(self)
mobkit.clear_queue_high(self)
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_fly(self)
local func=function(self)
self.object:set_acceleration({ x = 0, y = 1, z = 0 })
end
mobkit.queue_low(self,func)
end
-- Function to recover flying mobs from water
function mobkit.hq_liquid_recovery_flying(self, prty)
local func=function(self)
self.object:set_acceleration({ x = 0.0, y = 0.125, z = 0.0 })
self.object:set_velocity({ x = 1.0, y = 1.0, z = 1.0 })
if not(petz.isinliquid(self)) then
self.object:set_acceleration({ x = 0.0, y = 0.0, z = 0.0 })
return true
end
end
mobkit.queue_high(self, func, prty)
end
--
-- Alight Behaviour ( 2 funtions: HQ & LQ)
--
function mobkit.hq_alight(self, prty)
local func = function(self)
local node_name = mobkit.node_name_in(self, "below")
if node_name == "air" then
mobkit.lq_alight(self)
elseif minetest.get_item_group(node_name, "water") >= 1 then
mobkit.hq_wanderfly(self, 0)
return true
else
--minetest.chat_send_player("singleplayer", "on ground")
mobkit.animate(self, "stand")
mobkit.lq_idle(self, 2400)
self.status = "stand"
return true
end
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_alight(self)
local func=function(self)
--minetest.chat_send_player("singleplayer", "alight")
self.object:set_acceleration({ x = 0, y = -1, z = 0 })
return true
end
mobkit.queue_low(self, func)
end
---
---Fly Attack Behaviour
---
function mobkit.hq_flyhunt(self, prty, tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then return true end
if mobkit.is_queue_empty_low(self) then
local pos = mobkit.get_stand_pos(self)
local opos = tgtobj:get_pos()
local dist = vector.distance(pos, opos)
if dist > self.view_range then
return true
elseif dist > 3 then
mobkit.flyto(self, tgtobj)
else
--minetest.chat_send_player("singleplayer", "hq fly attack")
mobkit.hq_flyattack(self, prty+1, tgtobj)
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.hq_flyattack(self, prty, tgtobj)
local func = function(self)
if not mobkit.is_alive(tgtobj) then
return true
end
if mobkit.is_queue_empty_low(self) then
local pos = self.object:get_pos()
local tpos = mobkit.get_stand_pos(tgtobj)
local dist = vector.distance(pos,tpos)
if dist > 3 then
return true
else
mobkit.lq_flyattack(self, tgtobj)
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.lq_flyattack(self, target)
local func = function(self)
if not mobkit.is_alive(target) then
return true
end
local tgtpos = target:get_pos()
local pos = self.object:get_pos()
-- calculate attack spot
local dist = vector.distance(pos, tgtpos)
if dist <= 1.5 then --bite
target:punch(self.object, 1, self.attack)
local vy = self.object:get_velocity().y -- bounce off
local yaw = self.object:get_yaw()
local dir = minetest.yaw_to_dir(yaw)
self.object:set_velocity({x=dir.x*-3,y=vy,z=dir.z*-3})
mobkit.make_sound(self,'attack') -- play attack sound if defined
if self.attack_kamikaze then
self.hp = 0 --bees must to die!!!
end
else
mobkit.flyto(self, target)
end
mobkit.lq_idle(self, 0.3)
return true
end
mobkit.queue_low(self,func)
end
--
-- ARBOREAL BRAIN
--
function mobkit.hq_climb(self, prty)
local func=function(self)
if not(petz.check_if_climb) then
self.object:set_acceleration({x = 0, y = 0, z = 0 })
mobkit.clear_queue_low(self)
mobkit.clear_queue_high(self)
return true
else
mobkit.animate(self, 'climb')
self.object:set_acceleration({x = 0, y = 0.25, z = 0 })
end
end
mobkit.queue_high(self,func,prty)
end
---
--- Aquatic Behaviours
---
function mobkit.hq_aqua_jump(self, prty)
local func = function(self)
--minetest.chat_send_player("singleplayer", "test")
local vel_impulse = 2.5
local velocity = {
x = self.max_speed * (vel_impulse/3),
y = self.max_speed * vel_impulse,
z = self.max_speed * (vel_impulse/3),
}
petz.set_velocity(self, velocity)
self.object:set_acceleration({x=1.0, y=vel_impulse, z=1.0})
self.status = "jump"
mokapi.make_sound("object", self.object, "petz_splash", petz.settings.max_hear_distance)
minetest.after(0.5, function(self, velocity)
if mobkit.is_alive(self.object) then
self.status = ""
mobkit.clear_queue_high(self)
end
end, self, velocity)
return true
end
mobkit.queue_high(self, func, prty)
end
---
--- Bee Behaviours
---
function mobkit.hq_gotopollen(self, prty, tpos)
local func = function(self)
if self.pollen == true then
--mobkit.clear_queue_low(self)
--mobkit.clear_queue_high(self)
return true
end
mobkit.animate(self, "fly")
mobkit.lq_search_flower(self, tpos)
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_search_flower(self, tpos)
local func = function(self)
local pos = self.object:get_pos()
if not(pos) or not(tpos) then
return true
end
local y_distance = tpos.y - pos.y
local abs_y_distance = math.abs(y_distance)
if (abs_y_distance > 1) and (abs_y_distance < self.view_range) then
petz.set_velocity(self, {x= 0.0, y= y_distance, z= 0.0})
end
if mobkit.drive_to_pos(self, tpos, 1.5, 6.28, 0.5) then
self.pollen = true
petz.do_particles_effect(self.object, self.object:get_pos(), "pollen")
return true
end
end
mobkit.queue_low(self, func)
end
function mobkit.hq_gotobehive(self, prty, pos)
local func = function(self)
if self.pollen == false or not(self.behive) then
return true
end
mobkit.animate(self, "fly")
mobkit.lq_search_behive(self)
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_search_behive(self)
local func = function(self)
local tpos
if self.behive then
tpos = self.behive
else
return true
end
local pos = self.object:get_pos()
local y_distance = tpos.y - pos.y
local abs_y_distance = math.abs(y_distance)
if (abs_y_distance > 1) and (abs_y_distance < self.view_range) then
petz.set_velocity(self, {x= 0.0, y= y_distance, z= 0.0})
end
if mobkit.drive_to_pos(self, tpos, 1.5, 6.28, 1.01) then
if petz.behive_exists(self) then
mokapi.remove_mob(self)
local meta, honey_count, bee_count = petz.get_behive_stats(self.behive)
bee_count = bee_count + 1
meta:set_int("bee_count", bee_count)
honey_count = honey_count + 1
meta:set_int("honey_count", honey_count)
petz.set_infotext_behive(meta, honey_count, bee_count)
self.pollen = false
end
end
end
mobkit.queue_low(self, func)
end
function mobkit.hq_approach_behive(self, pos, prty)
local func = function(self)
if math.abs(pos.x - self.behive.x) <= (self.view_range / 2) or math.abs(pos.z - self.behive.z) <= (self.view_range / 2) then
mobkit.clear_queue_low(self)
mobkit.clear_queue_high(self)
return true
end
mobkit.lq_approach_behive(self)
end
mobkit.queue_high(self, func, prty)
end
function mobkit.lq_approach_behive(self)
local func = function(self)
local tpos
if self.behive then
tpos = self.behive
else
return true
end
local pos = self.object:get_pos()
--local y_distance = tpos.y - pos.y
if mobkit.drive_to_pos(self, tpos, 1.5, 6.28, (self.view_range / 4) ) then
mobkit.clear_queue_high(self)
return true
end
end
mobkit.queue_low(self, func)
end
---
--- DRIVER MOUNT
---
--
-- Helper functions
--
petz.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "default:dirt"
local node_ok = function(pos, fallback)
fallback = fallback or petz.fallback_node
local node = minetest.get_node_or_nil(pos)
if node and minetest.registered_nodes[node.name] then
return node
end
return {name = fallback}
end
local function node_is(pos)
local node = node_ok(pos)
if node.name == "air" then
return "air"
end
if minetest.get_item_group(node.name, "lava") ~= 0 then
return "lava"
end
if minetest.get_item_group(node.name, "liquid") ~= 0 then
return "liquid"
end
if minetest.registered_nodes[node.name].walkable == true then
return "walkable"
end
return "other"
end
local function get_sign(i)
i = i or 0
if i == 0 then
return 0
else
return i / math.abs(i)
end
end
local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
return {x = x, y = y, z = z}
end
local function get_v(v)
return math.sqrt(v.x * v.x + v.z * v.z)
end
function mobkit.hq_mountdriver(self, prty)
local func=function(self)
if not(self.driver) then
return true
else
if mobkit.is_queue_empty_low(self) then
mobkit.lq_mountdriver(self)
end
end
end
mobkit.queue_high(self,func,prty)
end
function mobkit.lq_mountdriver(self)
local auto_drive = false
local func = function(self)
if not(self.driver) then return true end
local rot_steer, rot_view = math.pi/2, 0
if self.player_rotation.y == 90 then
rot_steer, rot_view = 0, math.pi/2
end
local acce_y = 0
local velo
if velo == nil then
velo= {
x= self.max_speed_forward/2,
y= 0,
z= self.max_speed_forward/2,
}
end
local velocity = get_v(velo)
--minetest.chat_send_player("singleplayer", tostring(velocity))
-- process controls
local ctrl = self.driver:get_player_control()
if ctrl.up and ctrl.aux1 then
auto_drive = true
elseif auto_drive and ctrl.sneak then
auto_drive = false
end
if (ctrl.up or auto_drive) and self.isonground then -- move forwards
velocity = velocity + (self.accel/2)
if ctrl.jump then
velo.y = velo.y + (self.jump_height)*4
acce_y = acce_y *1.5
end
elseif ctrl.down and self.isonground then -- move backwards
if self.max_speed_reverse == 0 and velocity == 0 then
return
end
velocity = velocity - (self.accel/4)
if velocity > 0 then
velocity = - velocity
end
elseif ctrl.jump and self.isonground then -- jump
velo.y = velo.y + (self.jump_height)*4
acce_y = acce_y *1.5
else --stand
velocity = 0
mobkit.animate(self, "stand")
return
end
--Gallop
if ctrl.up and ctrl.sneak and not(self.gallop_exhausted) then
if self.gallop == false then
self.gallop = true
mokapi.make_sound("object", self.object, "petz_horse_whinny", petz.settings.max_hear_distance)
mokapi.make_sound("object", self.object, "petz_horse_gallop", petz.settings.max_hear_distance)
end
velocity = velocity + self.accel
end
--minetest.chat_send_player("singleplayer", tostring(velocity))
-- fix mob rotation
local horz = self.driver:get_look_horizontal() or 0
self.object:set_yaw(horz - self.rotate)
-- enforce speed limit forward and reverse
local max_spd = self.max_speed_reverse
if get_sign(velocity) >= 0 then
max_spd = self.max_speed_forward
end
if math.abs(velocity) > max_spd then
velocity = velocity - get_sign(velocity)
end
-- Set position, velocity and acceleration
local new_velo = {x = 0, y = 0, z = 0}
local new_acce = {x = 0, y = mobkit.gravity, z = 0}
new_velo = get_velocity(velocity, self.object:get_yaw() - rot_view, velo.y)
self.object:set_velocity(new_velo)
if not(self.gallop) then
mobkit.animate(self, "walk") -- set animation
else
mobkit.animate(self, "run")
end
new_acce.y = new_acce.y + acce_y
--minetest.chat_send_player("singleplayer", tostring(new_acce.y))
self.object:set_acceleration(new_acce)
return
end
mobkit.queue_low(self, func)
end