VoxeLibre/mods/ENTITIES/mcl_mobs/breeding.lua

354 lines
8.3 KiB
Lua

local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
local mob_class = mcl_mobs.mob_class
local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 30 -- was 300 or 15*20
local CHILD_GROW_TIME = 60
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
local LOG_MODULE = "[mcl_mobs]"
local function mcl_log (message)
if LOGGING_ON and message then
minetest.log(LOG_MODULE .. " " .. message)
end
end
-- No-op in MCL2 (capturing mobs is not possible).
-- Provided for compability with Mobs Redo
function mcl_mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, force_take, replacewith)
return false
end
-- No-op in MCL2 (protecting mobs is not possible).
function mcl_mobs:protect(self, clicker)
return false
end
-- feeding, taming and breeding (thanks blert2112)
function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
if not self.follow then
return false
end
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then
return false
end
-- can eat/tame with item in hand
if self.nofollow or self:follow_holding(clicker) then
local consume_food = false
-- tame if not still a baby
if tame and not self.child then
if not self.owner or self.owner == "" then
self.tamed = true
self.owner = clicker:get_player_name()
consume_food = true
end
end
-- increase health
if self.health < self.hp_max and not consume_food then
consume_food = true
self.health = math.min(self.health + 4, self.hp_max)
if self.htimer < 1 then
self.htimer = 5
end
self.object:set_hp(self.health)
end
-- make children grow quicker
if not consume_food and self.child == true then
consume_food = true
-- deduct 10% of the time to adulthood
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
end
-- breed animals
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
self.food = (self.food or 0) + 1
consume_food = true
if self.food >= feed_count then
self.food = 0
self.horny = true
self.persistent = true
end
end
self:update_tag()
-- play a sound if the animal used the item and take the item if not in creative
if consume_food then
-- don't consume food if clicker is in creative
if not minetest.is_creative_enabled(clicker:get_player_name()) and not notake then
local item = clicker:get_wielded_item()
item:take_item()
clicker:set_wielded_item(item)
end
-- always play the eat sound if food is used, even in creative
self:mob_sound("eat", nil, true)
else
-- make sound when the mob doesn't want food
self:mob_sound("random", true)
end
return true
end
return false
end
-- Spawn a child
function mcl_mobs.spawn_child(pos, mob_type)
local child = minetest.add_entity(pos, mob_type)
if not child then
return
end
local ent = child:get_luaentity()
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
ent.child = true
local textures
-- using specific child texture (if found)
if ent.child_texture then
textures = ent.child_texture[1]
end
-- and resize to half height
child:set_properties({
textures = textures,
visual_size = {
x = ent.base_size.x * .5,
y = ent.base_size.y * .5,
},
collisionbox = {
ent.base_colbox[1] * .5,
ent.base_colbox[2] * .5,
ent.base_colbox[3] * .5,
ent.base_colbox[4] * .5,
ent.base_colbox[5] * .5,
ent.base_colbox[6] * .5,
},
selectionbox = {
ent.base_selbox[1] * .5,
ent.base_selbox[2] * .5,
ent.base_selbox[3] * .5,
ent.base_selbox[4] * .5,
ent.base_selbox[5] * .5,
ent.base_selbox[6] * .5,
},
})
ent.animation = ent._child_animations
ent._current_animation = nil
ent:set_animation("stand")
return child
end
-- find two animals of same type and breed if nearby and horny
function mob_class:check_breeding()
--mcl_log("In breed function")
-- child takes a long time before growing into adult
if self.child == true then
-- When a child, hornytimer is used to count age until adulthood
self.hornytimer = self.hornytimer + 1
if self.hornytimer >= CHILD_GROW_TIME then
self.child = false
self.hornytimer = 0
self.object:set_properties({
textures = self.base_texture,
mesh = self.base_mesh,
visual_size = self.base_size,
collisionbox = self.base_colbox,
selectionbox = self.base_selbox,
})
-- custom function when child grows up
if self.on_grown then
self.on_grown(self)
else
-- jump when fully grown so as not to fall into ground
self.object:set_velocity({
x = 0,
y = self.jump_height,
z = 0
})
end
self.animation = nil
local anim = self._current_animation
self._current_animation = nil -- Mobs Redo does nothing otherwise
self:set_animation(anim)
end
return
else
-- horny animal can mate for HORNY_TIME seconds,
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
if self.horny == true then
self.hornytimer = self.hornytimer + 1
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
self.hornytimer = 0
self.horny = false
end
end
end
-- find another same animal who is also horny and mate if nearby
if self.horny == true
and self.hornytimer <= HORNY_TIME then
mcl_log("In breed function. All good. Do the magic.")
local pos = self.object:get_pos()
mcl_mobs.effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
local objs = minetest.get_objects_inside_radius(pos, 3)
local num = 0
local ent = nil
for n = 1, #objs do
ent = objs[n]:get_luaentity()
-- check for same animal with different colour
local canmate = false
if ent then
if ent.name == self.name then
canmate = true
else
local entname = string.split(ent.name,":")
local selfname = string.split(self.name,":")
if entname[1] == selfname[1] then
entname = string.split(entname[2],"_")
selfname = string.split(selfname[2],"_")
if entname[1] == selfname[1] then
canmate = true
end
end
end
end
if canmate then mcl_log("In breed function. Can mate.") end
if ent
and canmate == true
and ent.horny == true
and ent.hornytimer <= HORNY_TIME then
num = num + 1
end
-- found your mate? then have a baby
if num > 1 then
self.hornytimer = HORNY_TIME + 1
ent.hornytimer = HORNY_TIME + 1
-- spawn baby
minetest.after(5, function(parent1, parent2, pos)
if not parent1.object:get_luaentity() then
return
end
if not parent2.object:get_luaentity() then
return
end
mcl_experience.throw_xp(pos, math.random(1, 7))
-- custom breed function
if parent1.on_breed then
-- when false, skip going any further
if parent1.on_breed(parent1, parent2) == false then
return
end
end
local child = mcl_mobs.spawn_child(pos, parent1.name)
local ent_c = child:get_luaentity()
-- Use texture of one of the parents
local p = math.random(1, 2)
if p == 1 then
ent_c.base_texture = parent1.base_texture
else
ent_c.base_texture = parent2.base_texture
end
child:set_properties({
textures = ent_c.base_texture
})
-- tamed and owned by parents' owner
ent_c.tamed = true
ent_c.owner = parent1.owner
end, self, ent, pos)
num = 0
break
end
end
end
end
function mob_class:toggle_sit(clicker,p)
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then
return
end
local pos = self.object:get_pos()
local particle
if not self.order or self.order == "" or self.order == "sit" then
particle = "mobs_mc_wolf_icon_roam.png"
self.order = "roam"
self.state = "stand"
self.walk_chance = 50
self.jump = true
self:set_animation("stand")
-- TODO: Add sitting model
else
particle = "mobs_mc_wolf_icon_sit.png"
self.order = "sit"
self.state = "stand"
self.walk_chance = 0
self.jump = false
if self.animation.sit_start then
self:set_animation("sit")
else
self:set_animation("stand")
end
end
local pp = vector.new(0,1.4,0)
if p then pp = vector.offset(pp,0,p,0) end
-- Display icon to show current order (sit or roam)
minetest.add_particle({
pos = vector.add(pos, pp),
velocity = {x=0,y=0.2,z=0},
expirationtime = 1,
size = 4,
texture = particle,
playername = self.owner,
glow = minetest.LIGHT_MAX,
})
end