Update Mobs Redo to version 1.40
parent
088bb40908
commit
c2684d0eac
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
-- Mobs Api (4th August 2017)
|
-- Mobs Api
|
||||||
|
|
||||||
mobs = {}
|
mobs = {}
|
||||||
mobs.mod = "redo"
|
mobs.mod = "redo"
|
||||||
mobs.version = "20170804"
|
mobs.version = "20171018"
|
||||||
|
|
||||||
|
|
||||||
-- Intllib
|
-- Intllib
|
||||||
|
@ -15,13 +15,21 @@ mobs.intllib = S
|
||||||
-- CMI support check
|
-- CMI support check
|
||||||
local use_cmi = minetest.global_exists("cmi")
|
local use_cmi = minetest.global_exists("cmi")
|
||||||
|
|
||||||
|
|
||||||
-- Invisibility mod check
|
-- Invisibility mod check
|
||||||
mobs.invis = {}
|
mobs.invis = {}
|
||||||
if rawget(_G, "invisibility") then
|
if minetest.global_exists("invisibility") then
|
||||||
mobs.invis = invisibility
|
mobs.invis = invisibility
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- creative check
|
||||||
|
local creative_mode_cache = minetest.settings:get_bool("creative_mode")
|
||||||
|
function mobs.is_creative(name)
|
||||||
|
return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- localize math functions
|
-- localize math functions
|
||||||
local pi = math.pi
|
local pi = math.pi
|
||||||
local square = math.sqrt
|
local square = math.sqrt
|
||||||
|
@ -44,19 +52,27 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- Load settings
|
-- Load settings
|
||||||
local damage_enabled = minetest.setting_getbool("enable_damage")
|
local damage_enabled = minetest.settings:get_bool("enable_damage")
|
||||||
local peaceful_only = minetest.setting_getbool("only_peaceful_mobs")
|
local peaceful_only = minetest.settings:get_bool("only_peaceful_mobs")
|
||||||
local disable_blood = minetest.setting_getbool("mobs_disable_blood")
|
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
||||||
local creative = minetest.setting_getbool("creative_mode")
|
local creative = minetest.settings:get_bool("creative_mode")
|
||||||
local spawn_protected = minetest.setting_getbool("mobs_spawn_protected") ~= false
|
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
|
||||||
local remove_far = minetest.setting_getbool("remove_far_mobs")
|
local remove_far = minetest.settings:get_bool("remove_far_mobs")
|
||||||
local difficulty = tonumber(minetest.setting_get("mob_difficulty")) or 1.0
|
local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0
|
||||||
local show_health = false
|
local show_health = false
|
||||||
local max_per_block = tonumber(minetest.setting_get("max_objects_per_block") or 99)
|
local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99)
|
||||||
|
|
||||||
|
-- Peaceful mode message so players will know there are no monsters
|
||||||
|
if peaceful_only then
|
||||||
|
minetest.register_on_joinplayer(function(player)
|
||||||
|
minetest.chat_send_player(player:get_player_name(),
|
||||||
|
S("** Peaceful Mode Active - No Monsters Will Spawn"))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- calculate aoc range for mob count
|
-- calculate aoc range for mob count
|
||||||
local aosrb = tonumber(minetest.setting_get("active_object_send_range_blocks"))
|
local aosrb = tonumber(minetest.settings:get("active_object_send_range_blocks"))
|
||||||
local abr = tonumber(minetest.setting_get("active_block_range"))
|
local abr = tonumber(minetest.settings:get("active_block_range"))
|
||||||
local aoc_range = max(aosrb, abr) * 16
|
local aoc_range = max(aosrb, abr) * 16
|
||||||
|
|
||||||
-- pathfinding settings
|
-- pathfinding settings
|
||||||
|
@ -104,7 +120,7 @@ end
|
||||||
-- move mob in facing direction
|
-- move mob in facing direction
|
||||||
local set_velocity = function(self, v)
|
local set_velocity = function(self, v)
|
||||||
|
|
||||||
local yaw = (self.object:getyaw() or 0) + self.rotate
|
local yaw = (self.object:get_yaw() or 0) + self.rotate
|
||||||
|
|
||||||
self.object:setvelocity({
|
self.object:setvelocity({
|
||||||
x = sin(yaw) * -v,
|
x = sin(yaw) * -v,
|
||||||
|
@ -114,7 +130,7 @@ local set_velocity = function(self, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- get overall speed of mob
|
-- calculate mob velocity
|
||||||
local get_velocity = function(self)
|
local get_velocity = function(self)
|
||||||
|
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
|
@ -123,7 +139,7 @@ local get_velocity = function(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- set yaw
|
-- set and return valid yaw
|
||||||
local set_yaw = function(self, yaw)
|
local set_yaw = function(self, yaw)
|
||||||
|
|
||||||
if not yaw or yaw ~= yaw then
|
if not yaw or yaw ~= yaw then
|
||||||
|
@ -166,7 +182,7 @@ function mobs:set_animation(self, anim)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- this is a faster way to calculate distance
|
-- calculate distance
|
||||||
local get_distance = function(a, b)
|
local get_distance = function(a, b)
|
||||||
|
|
||||||
local x, y, z = a.x - b.x, a.y - b.y, a.z - b.z
|
local x, y, z = a.x - b.x, a.y - b.y, a.z - b.z
|
||||||
|
@ -252,8 +268,10 @@ local flight_check = function(self, pos_w)
|
||||||
local nod = self.standing_in
|
local nod = self.standing_in
|
||||||
local def = minetest.registered_nodes[nod]
|
local def = minetest.registered_nodes[nod]
|
||||||
|
|
||||||
|
if not def then return false end -- nil check
|
||||||
|
|
||||||
if type(self.fly_in) == "string"
|
if type(self.fly_in) == "string"
|
||||||
and (nod == self.fly_in or def.liquid_alternative_flowing ~= "") then
|
and nod == self.fly_in then
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
@ -261,18 +279,25 @@ local flight_check = function(self, pos_w)
|
||||||
|
|
||||||
for _,fly_in in pairs(self.fly_in) do
|
for _,fly_in in pairs(self.fly_in) do
|
||||||
|
|
||||||
if nod == fly_in or def.liquid_alternative_flowing ~= "" then
|
if nod == fly_in then
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- stops mobs getting stuck inside stairs and plantlike nodes
|
||||||
|
if def.drawtype ~= "airlike"
|
||||||
|
and def.drawtype ~= "liquid"
|
||||||
|
and def.drawtype ~= "flowingliquid" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- particle effects
|
-- custom particle effects
|
||||||
local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow)
|
local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow)
|
||||||
|
|
||||||
radius = radius or 2
|
radius = radius or 2
|
||||||
|
@ -333,7 +358,7 @@ local item_drop = function(self, cooked)
|
||||||
if self.child then return end
|
if self.child then return end
|
||||||
|
|
||||||
local obj, item, num
|
local obj, item, num
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
self.drops = self.drops or {} -- nil check
|
self.drops = self.drops or {} -- nil check
|
||||||
|
|
||||||
|
@ -411,6 +436,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- dropped cooked item if mob died in lava
|
||||||
if cause == "lava" then
|
if cause == "lava" then
|
||||||
item_drop(self, true)
|
item_drop(self, true)
|
||||||
else
|
else
|
||||||
|
@ -419,7 +445,7 @@ local check_for_death = function(self, cause, cmi_cause)
|
||||||
|
|
||||||
mob_sound(self, self.sounds.death)
|
mob_sound(self, self.sounds.death)
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
-- execute custom death function
|
-- execute custom death function
|
||||||
if self.on_die then
|
if self.on_die then
|
||||||
|
@ -499,10 +525,10 @@ local is_at_cliff = function(self)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local yaw = self.object:getyaw()
|
local yaw = self.object:get_yaw()
|
||||||
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_x = -sin(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
|
local dir_z = cos(yaw) * (self.collisionbox[4] + 0.5)
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
local ypos = pos.y + self.collisionbox[2] -- just above floor
|
||||||
|
|
||||||
if minetest.line_of_sight(
|
if minetest.line_of_sight(
|
||||||
|
@ -549,7 +575,7 @@ local do_env_damage = function(self)
|
||||||
update_tag(self)
|
update_tag(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
self.time_of_day = minetest.get_timeofday()
|
self.time_of_day = minetest.get_timeofday()
|
||||||
|
|
||||||
|
@ -559,11 +585,11 @@ local do_env_damage = function(self)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- daylight above ground
|
-- bright light harms mob
|
||||||
if self.light_damage ~= 0
|
if self.light_damage ~= 0
|
||||||
and pos.y > 0
|
-- and pos.y > 0
|
||||||
and self.time_of_day > 0.2
|
-- and self.time_of_day > 0.2
|
||||||
and self.time_of_day < 0.8
|
-- and self.time_of_day < 0.8
|
||||||
and (minetest.get_node_light(pos) or 0) > 12 then
|
and (minetest.get_node_light(pos) or 0) > 12 then
|
||||||
|
|
||||||
self.health = self.health - self.light_damage
|
self.health = self.health - self.light_damage
|
||||||
|
@ -633,7 +659,7 @@ local do_env_damage = function(self)
|
||||||
if check_for_death(self, "dps", {type = "environment",
|
if check_for_death(self, "dps", {type = "environment",
|
||||||
pos = pos, node = self.standing_in}) then return end
|
pos = pos, node = self.standing_in}) then return end
|
||||||
end
|
end
|
||||||
|
--[[
|
||||||
--- suffocation inside solid node
|
--- suffocation inside solid node
|
||||||
if self.suffocation ~= 0
|
if self.suffocation ~= 0
|
||||||
and nodef.walkable == true
|
and nodef.walkable == true
|
||||||
|
@ -645,7 +671,7 @@ local do_env_damage = function(self)
|
||||||
if check_for_death(self, "suffocation", {type = "environment",
|
if check_for_death(self, "suffocation", {type = "environment",
|
||||||
pos = pos, node = self.standing_in}) then return end
|
pos = pos, node = self.standing_in}) then return end
|
||||||
end
|
end
|
||||||
|
]]
|
||||||
check_for_death(self, "", {type = "unknown"})
|
check_for_death(self, "", {type = "unknown"})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -660,6 +686,8 @@ local do_jump = function(self)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.facing_fence = false
|
||||||
|
|
||||||
-- something stopping us while moving?
|
-- something stopping us while moving?
|
||||||
if self.state ~= "stand"
|
if self.state ~= "stand"
|
||||||
and get_velocity(self) > 0.5
|
and get_velocity(self) > 0.5
|
||||||
|
@ -667,8 +695,8 @@ local do_jump = function(self)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
local yaw = self.object:getyaw()
|
local yaw = self.object:get_yaw()
|
||||||
|
|
||||||
-- what is mob standing on?
|
-- what is mob standing on?
|
||||||
pos.y = pos.y + self.collisionbox[2] - 0.2
|
pos.y = pos.y + self.collisionbox[2] - 0.2
|
||||||
|
@ -699,10 +727,11 @@ local do_jump = function(self)
|
||||||
|
|
||||||
--print ("in front:", nod.name, pos.y + 0.5)
|
--print ("in front:", nod.name, pos.y + 0.5)
|
||||||
|
|
||||||
if (minetest.registered_items[nod.name].walkable
|
if self.walk_chance == 0
|
||||||
and not nod.name:find("fence")
|
or minetest.registered_items[nod.name].walkable then
|
||||||
and not nod.name:find("gate"))
|
|
||||||
or self.walk_chance == 0 then
|
if not nod.name:find("fence")
|
||||||
|
and not nod.name:find("gate") then
|
||||||
|
|
||||||
local v = self.object:getvelocity()
|
local v = self.object:getvelocity()
|
||||||
|
|
||||||
|
@ -713,6 +742,9 @@ local do_jump = function(self)
|
||||||
self.object:setvelocity(v)
|
self.object:setvelocity(v)
|
||||||
|
|
||||||
mob_sound(self, self.sounds.jump)
|
mob_sound(self, self.sounds.jump)
|
||||||
|
else
|
||||||
|
self.facing_fence = true
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -731,7 +763,7 @@ local entity_physics = function(pos, radius)
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
|
||||||
obj_pos = objs[n]:getpos()
|
obj_pos = objs[n]:get_pos()
|
||||||
|
|
||||||
dist = get_distance(pos, obj_pos)
|
dist = get_distance(pos, obj_pos)
|
||||||
if dist < 1 then dist = 1 end
|
if dist < 1 then dist = 1 end
|
||||||
|
@ -743,7 +775,7 @@ local entity_physics = function(pos, radius)
|
||||||
objs[n]:punch(objs[n], 1.0, {
|
objs[n]:punch(objs[n], 1.0, {
|
||||||
full_punch_interval = 1.0,
|
full_punch_interval = 1.0,
|
||||||
damage_groups = {fleshy = damage},
|
damage_groups = {fleshy = damage},
|
||||||
}, pos) -- was nil
|
}, pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -798,13 +830,18 @@ local breed = function(self)
|
||||||
collisionbox = self.base_colbox,
|
collisionbox = self.base_colbox,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- jump when fully grown so not to fall into ground
|
-- 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:setvelocity({
|
self.object:setvelocity({
|
||||||
x = 0,
|
x = 0,
|
||||||
y = self.jump_height,
|
y = self.jump_height,
|
||||||
z = 0
|
z = 0
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -822,11 +859,11 @@ local breed = function(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- find another same animal who is also horny and mate if close enough
|
-- find another same animal who is also horny and mate if nearby
|
||||||
if self.horny == true
|
if self.horny == true
|
||||||
and self.hornytimer <= 40 then
|
and self.hornytimer <= 40 then
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
|
effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
|
||||||
|
|
||||||
|
@ -876,14 +913,27 @@ local breed = function(self)
|
||||||
-- spawn baby
|
-- spawn baby
|
||||||
minetest.after(5, function()
|
minetest.after(5, function()
|
||||||
|
|
||||||
|
-- custom breed function
|
||||||
|
if self.on_breed then
|
||||||
|
|
||||||
|
-- when false skip going any further
|
||||||
|
if self.on_breed(self, ent) == false then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
effect(pos, 15, "tnt_smoke.png", 1, 2, 2, 15, 5)
|
||||||
|
end
|
||||||
|
|
||||||
local mob = minetest.add_entity(pos, self.name)
|
local mob = minetest.add_entity(pos, self.name)
|
||||||
local ent2 = mob:get_luaentity()
|
local ent2 = mob:get_luaentity()
|
||||||
local textures = self.base_texture
|
local textures = self.base_texture
|
||||||
|
|
||||||
|
-- using specific child texture (if found)
|
||||||
if self.child_texture then
|
if self.child_texture then
|
||||||
textures = self.child_texture[1]
|
textures = self.child_texture[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- and resize to half height
|
||||||
mob:set_properties({
|
mob:set_properties({
|
||||||
textures = textures,
|
textures = textures,
|
||||||
visual_size = {
|
visual_size = {
|
||||||
|
@ -899,6 +949,7 @@ local breed = function(self)
|
||||||
self.base_colbox[6] * .5,
|
self.base_colbox[6] * .5,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
-- tamed and owned by parents' owner
|
||||||
ent2.child = true
|
ent2.child = true
|
||||||
ent2.tamed = true
|
ent2.tamed = true
|
||||||
ent2.owner = self.owner
|
ent2.owner = self.owner
|
||||||
|
@ -1021,7 +1072,7 @@ local smart_mobs = function(self, s, p, dist, dtime)
|
||||||
s.y = sground.y + 1
|
s.y = sground.y + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local p1 = self.attack:getpos()
|
local p1 = self.attack:get_pos()
|
||||||
|
|
||||||
p1.x = floor(p1.x + 0.5)
|
p1.x = floor(p1.x + 0.5)
|
||||||
p1.y = floor(p1.y + 0.5)
|
p1.y = floor(p1.y + 0.5)
|
||||||
|
@ -1094,7 +1145,7 @@ local smart_mobs = function(self, s, p, dist, dtime)
|
||||||
|
|
||||||
else -- dig 2 blocks to make door toward player direction
|
else -- dig 2 blocks to make door toward player direction
|
||||||
|
|
||||||
local yaw1 = self.object:getyaw() + pi / 2
|
local yaw1 = self.object:get_yaw() + pi / 2
|
||||||
local p1 = {
|
local p1 = {
|
||||||
x = s.x + cos(yaw1),
|
x = s.x + cos(yaw1),
|
||||||
y = s.y,
|
y = s.y,
|
||||||
|
@ -1185,7 +1236,7 @@ local monster_attack = function(self)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local p, sp, dist
|
local p, sp, dist
|
||||||
local player, obj, min_player
|
local player, obj, min_player
|
||||||
local type, name = "", ""
|
local type, name = "", ""
|
||||||
|
@ -1219,8 +1270,8 @@ local monster_attack = function(self)
|
||||||
and (type == "player" or type == "npc"
|
and (type == "player" or type == "npc"
|
||||||
or (type == "animal" and self.attack_animals == true)) then
|
or (type == "animal" and self.attack_animals == true)) then
|
||||||
|
|
||||||
s = self.object:getpos()
|
s = self.object:get_pos()
|
||||||
p = player:getpos()
|
p = player:get_pos()
|
||||||
sp = s
|
sp = s
|
||||||
|
|
||||||
-- aim higher to make looking up hills more realistic
|
-- aim higher to make looking up hills more realistic
|
||||||
|
@ -1259,7 +1310,7 @@ local npc_attack = function(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local p, sp, obj, min_player
|
local p, sp, obj, min_player
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local min_dist = self.view_range + 1
|
local min_dist = self.view_range + 1
|
||||||
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
||||||
|
|
||||||
|
@ -1269,7 +1320,7 @@ local npc_attack = function(self)
|
||||||
|
|
||||||
if obj and obj.type == "monster" then
|
if obj and obj.type == "monster" then
|
||||||
|
|
||||||
p = obj.object:getpos()
|
p = obj.object:get_pos()
|
||||||
|
|
||||||
dist = get_distance(p, s)
|
dist = get_distance(p, s)
|
||||||
|
|
||||||
|
@ -1296,12 +1347,12 @@ local follow_flop = function(self)
|
||||||
and self.state ~= "attack"
|
and self.state ~= "attack"
|
||||||
and self.state ~= "runaway" then
|
and self.state ~= "runaway" then
|
||||||
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local players = minetest.get_connected_players()
|
local players = minetest.get_connected_players()
|
||||||
|
|
||||||
for n = 1, #players do
|
for n = 1, #players do
|
||||||
|
|
||||||
if get_distance(players[n]:getpos(), s) < self.view_range
|
if get_distance(players[n]:get_pos(), s) < self.view_range
|
||||||
and not mobs.invis[ players[n]:get_player_name() ] then
|
and not mobs.invis[ players[n]:get_player_name() ] then
|
||||||
|
|
||||||
self.following = players[n]
|
self.following = players[n]
|
||||||
|
@ -1335,16 +1386,16 @@ local follow_flop = function(self)
|
||||||
-- follow that thing
|
-- follow that thing
|
||||||
if self.following then
|
if self.following then
|
||||||
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local p
|
local p
|
||||||
|
|
||||||
if self.following:is_player() then
|
if self.following:is_player() then
|
||||||
|
|
||||||
p = self.following:getpos()
|
p = self.following:get_pos()
|
||||||
|
|
||||||
elseif self.following.object then
|
elseif self.following.object then
|
||||||
|
|
||||||
p = self.following.object:getpos()
|
p = self.following.object:get_pos()
|
||||||
end
|
end
|
||||||
|
|
||||||
if p then
|
if p then
|
||||||
|
@ -1387,7 +1438,7 @@ local follow_flop = function(self)
|
||||||
|
|
||||||
-- swimmers flop when out of their element, and swim again when back in
|
-- swimmers flop when out of their element, and swim again when back in
|
||||||
if self.fly then
|
if self.fly then
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
if not flight_check(self, s) then
|
if not flight_check(self, s) then
|
||||||
|
|
||||||
self.state = "flop"
|
self.state = "flop"
|
||||||
|
@ -1442,13 +1493,13 @@ local do_states = function(self, dtime)
|
||||||
if random(1, 4) == 1 then
|
if random(1, 4) == 1 then
|
||||||
|
|
||||||
local lp = nil
|
local lp = nil
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local objs = minetest.get_objects_inside_radius(s, 3)
|
local objs = minetest.get_objects_inside_radius(s, 3)
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
|
||||||
if objs[n]:is_player() then
|
if objs[n]:is_player() then
|
||||||
lp = objs[n]:getpos()
|
lp = objs[n]:get_pos()
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1465,8 +1516,6 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
if lp.x > s.x then yaw = yaw + pi end
|
if lp.x > s.x then yaw = yaw + pi end
|
||||||
else
|
else
|
||||||
-- yaw = (random(0, 360) - 180) / 180 * pi
|
|
||||||
|
|
||||||
yaw = yaw + random(-0.5, 0.5)
|
yaw = yaw + random(-0.5, 0.5)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1481,6 +1530,7 @@ local do_states = function(self, dtime)
|
||||||
or self.order ~= "stand" then
|
or self.order ~= "stand" then
|
||||||
|
|
||||||
if self.walk_chance ~= 0
|
if self.walk_chance ~= 0
|
||||||
|
and self.facing_fence ~= true
|
||||||
and random(1, 100) <= self.walk_chance
|
and random(1, 100) <= self.walk_chance
|
||||||
and is_at_cliff(self) == false then
|
and is_at_cliff(self) == false then
|
||||||
|
|
||||||
|
@ -1501,7 +1551,7 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
elseif self.state == "walk" then
|
elseif self.state == "walk" then
|
||||||
|
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local lp = nil
|
local lp = nil
|
||||||
|
|
||||||
-- is there something I need to avoid?
|
-- is there something I need to avoid?
|
||||||
|
@ -1547,8 +1597,6 @@ local do_states = function(self, dtime)
|
||||||
do_jump(self)
|
do_jump(self)
|
||||||
set_velocity(self, self.walk_velocity)
|
set_velocity(self, self.walk_velocity)
|
||||||
else
|
else
|
||||||
-- yaw = (random(0, 360) - 180) / 180 * pi
|
|
||||||
|
|
||||||
yaw = yaw + random(-0.5, 0.5)
|
yaw = yaw + random(-0.5, 0.5)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1569,9 +1617,6 @@ local do_states = function(self, dtime)
|
||||||
-- otherwise randomly turn
|
-- otherwise randomly turn
|
||||||
elseif random(1, 100) <= 30 then
|
elseif random(1, 100) <= 30 then
|
||||||
|
|
||||||
--yaw = random() * 2 * pi
|
|
||||||
-- yaw = (random(0, 360) - 180) / 180 * pi
|
|
||||||
|
|
||||||
yaw = yaw + random(-0.5, 0.5)
|
yaw = yaw + random(-0.5, 0.5)
|
||||||
|
|
||||||
yaw = set_yaw(self.object, yaw)
|
yaw = set_yaw(self.object, yaw)
|
||||||
|
@ -1580,7 +1625,8 @@ local do_states = function(self, dtime)
|
||||||
-- stand for great fall in front
|
-- stand for great fall in front
|
||||||
local temp_is_cliff = is_at_cliff(self)
|
local temp_is_cliff = is_at_cliff(self)
|
||||||
|
|
||||||
if temp_is_cliff
|
if self.facing_fence == true
|
||||||
|
or temp_is_cliff
|
||||||
or random(1, 100) <= 30 then
|
or random(1, 100) <= 30 then
|
||||||
|
|
||||||
set_velocity(self, 0)
|
set_velocity(self, 0)
|
||||||
|
@ -1620,14 +1666,14 @@ local do_states = function(self, dtime)
|
||||||
elseif self.state == "attack" then
|
elseif self.state == "attack" then
|
||||||
|
|
||||||
-- calculate distance from mob and enemy
|
-- calculate distance from mob and enemy
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local p = self.attack:getpos() or s
|
local p = self.attack:get_pos() or s
|
||||||
local dist = get_distance(p, s)
|
local dist = get_distance(p, s)
|
||||||
|
|
||||||
-- stop attacking if player or out of range
|
-- stop attacking if player or out of range
|
||||||
if dist > self.view_range
|
if dist > self.view_range
|
||||||
or not self.attack
|
or not self.attack
|
||||||
or not self.attack:getpos()
|
or not self.attack:get_pos()
|
||||||
or self.attack:get_hp() <= 0
|
or self.attack:get_hp() <= 0
|
||||||
or (self.attack:is_player() and mobs.invis[ self.attack:get_player_name() ]) then
|
or (self.attack:is_player() and mobs.invis[ self.attack:get_player_name() ]) then
|
||||||
|
|
||||||
|
@ -1656,18 +1702,18 @@ local do_states = function(self, dtime)
|
||||||
|
|
||||||
yaw = set_yaw(self.object, yaw)
|
yaw = set_yaw(self.object, yaw)
|
||||||
|
|
||||||
if dist > self.reach then
|
-- start timer when inside reach
|
||||||
|
if dist < self.reach and not self.v_start then
|
||||||
if not self.v_start then
|
|
||||||
|
|
||||||
self.v_start = true
|
self.v_start = true
|
||||||
set_velocity(self, self.run_velocity)
|
|
||||||
self.timer = 0
|
|
||||||
self.blinktimer = 0
|
|
||||||
else
|
|
||||||
self.timer = 0
|
self.timer = 0
|
||||||
self.blinktimer = 0
|
self.blinktimer = 0
|
||||||
|
-- print ("=== explosion timer started", self.explosion_timer)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- walk right up to player when timer active
|
||||||
|
if dist < 1.5 and self.v_start then
|
||||||
|
set_velocity(self, 0)
|
||||||
|
else
|
||||||
set_velocity(self, self.run_velocity)
|
set_velocity(self, self.run_velocity)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1676,9 +1722,8 @@ local do_states = function(self, dtime)
|
||||||
else
|
else
|
||||||
set_animation(self, "walk")
|
set_animation(self, "walk")
|
||||||
end
|
end
|
||||||
else
|
|
||||||
set_velocity(self, 0)
|
if self.v_start then
|
||||||
set_animation(self, "punch")
|
|
||||||
|
|
||||||
self.timer = self.timer + dtime
|
self.timer = self.timer + dtime
|
||||||
self.blinktimer = (self.blinktimer or 0) + dtime
|
self.blinktimer = (self.blinktimer or 0) + dtime
|
||||||
|
@ -1696,9 +1741,11 @@ local do_states = function(self, dtime)
|
||||||
self.blinkstatus = not self.blinkstatus
|
self.blinkstatus = not self.blinkstatus
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.timer > 3 then
|
-- print ("=== explosion timer", self.timer)
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
if self.timer > self.explosion_timer then
|
||||||
|
|
||||||
|
local pos = self.object:get_pos()
|
||||||
local radius = self.explosion_radius or 1
|
local radius = self.explosion_radius or 1
|
||||||
local damage_radius = radius
|
local damage_radius = radius
|
||||||
|
|
||||||
|
@ -1941,16 +1988,17 @@ local do_states = function(self, dtime)
|
||||||
-- play shoot attack sound
|
-- play shoot attack sound
|
||||||
mob_sound(self, self.sounds.shoot_attack)
|
mob_sound(self, self.sounds.shoot_attack)
|
||||||
|
|
||||||
local p = self.object:getpos()
|
local p = self.object:get_pos()
|
||||||
|
|
||||||
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
p.y = p.y + (self.collisionbox[2] + self.collisionbox[5]) / 2
|
||||||
|
|
||||||
|
if minetest.registered_entities[self.arrow] then
|
||||||
|
|
||||||
local obj = minetest.add_entity(p, self.arrow)
|
local obj = minetest.add_entity(p, self.arrow)
|
||||||
local ent = obj:get_luaentity()
|
local ent = obj:get_luaentity()
|
||||||
|
|
||||||
if ent then
|
|
||||||
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
|
local amount = (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) ^ 0.5
|
||||||
local v = ent.velocity or 1 -- or set to default
|
local v = ent.velocity or 1 -- or set to default
|
||||||
|
|
||||||
ent.switch = 1
|
ent.switch = 1
|
||||||
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
|
ent.owner_id = tostring(self.object) -- add unique owner id to arrow
|
||||||
|
|
||||||
|
@ -1961,8 +2009,6 @@ local do_states = function(self, dtime)
|
||||||
vec.z = vec.z * (v / amount)
|
vec.z = vec.z * (v / amount)
|
||||||
|
|
||||||
obj:setvelocity(vec)
|
obj:setvelocity(vec)
|
||||||
else
|
|
||||||
obj:remove() -- arrow entity does not exist
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2020,7 +2066,7 @@ local falling = function(self, pos)
|
||||||
if self.fall_damage == 1
|
if self.fall_damage == 1
|
||||||
and self.object:getvelocity().y == 0 then
|
and self.object:getvelocity().y == 0 then
|
||||||
|
|
||||||
local d = (self.old_y or 0) - self.object:getpos().y
|
local d = (self.old_y or 0) - self.object:get_pos().y
|
||||||
|
|
||||||
if d > 5 then
|
if d > 5 then
|
||||||
|
|
||||||
|
@ -2033,7 +2079,7 @@ local falling = function(self, pos)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.old_y = self.object:getpos().y
|
self.old_y = self.object:get_pos().y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2042,10 +2088,19 @@ end
|
||||||
-- deal damage and effects when mob punched
|
-- deal damage and effects when mob punched
|
||||||
local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
-- mob health check
|
-- custom punch function
|
||||||
if self.health <= 0 then
|
if self.do_punch then
|
||||||
|
|
||||||
|
-- when false skip going any further
|
||||||
|
if self.do_punch(self, hitter, tflp, tool_caps, dir) == false then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- mob health check
|
||||||
|
-- if self.health <= 0 then
|
||||||
|
-- return
|
||||||
|
-- end
|
||||||
|
|
||||||
-- error checking when mod profiling is enabled
|
-- error checking when mod profiling is enabled
|
||||||
if not tool_capabilities then
|
if not tool_capabilities then
|
||||||
|
@ -2055,7 +2110,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
-- is mob protected?
|
-- is mob protected?
|
||||||
if self.protected and hitter:is_player()
|
if self.protected and hitter:is_player()
|
||||||
and minetest.is_protected(self.object:getpos(), hitter:get_player_name()) then
|
and minetest.is_protected(self.object:get_pos(), hitter:get_player_name()) then
|
||||||
minetest.chat_send_player(hitter:get_player_name(), S("Mob has been protected!"))
|
minetest.chat_send_player(hitter:get_player_name(), S("Mob has been protected!"))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -2140,12 +2195,12 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
local s = random(0, #weapon:get_definition().sounds)
|
local s = random(0, #weapon:get_definition().sounds)
|
||||||
|
|
||||||
minetest.sound_play(weapon:get_definition().sounds[s], {
|
minetest.sound_play(weapon:get_definition().sounds[s], {
|
||||||
object = hitter,
|
object = self.object, --hitter,
|
||||||
max_hear_distance = 8
|
max_hear_distance = 8
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
minetest.sound_play("default_punch", {
|
minetest.sound_play("default_punch", {
|
||||||
object = hitter,
|
object = self.object, --hitter,
|
||||||
max_hear_distance = 5
|
max_hear_distance = 5
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -2154,7 +2209,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
if self.blood_amount > 0
|
if self.blood_amount > 0
|
||||||
and not disable_blood then
|
and not disable_blood then
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5
|
pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5
|
||||||
|
|
||||||
|
@ -2204,21 +2259,28 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
-- direction error check
|
-- direction error check
|
||||||
dir = dir or {x = 0, y = 0, z = 0}
|
dir = dir or {x = 0, y = 0, z = 0}
|
||||||
|
|
||||||
|
-- check if tool already has specific knockback value
|
||||||
|
if tool_capabilities.damage_groups["knockback"] then
|
||||||
|
kb = tool_capabilities.damage_groups["knockback"]
|
||||||
|
else
|
||||||
|
kb = kb * 1.5
|
||||||
|
end
|
||||||
|
|
||||||
self.object:setvelocity({
|
self.object:setvelocity({
|
||||||
x = dir.x * kb,
|
x = dir.x * kb,
|
||||||
y = up,
|
y = up,
|
||||||
z = dir.z * kb
|
z = dir.z * kb
|
||||||
})
|
})
|
||||||
|
|
||||||
self.pause_timer = r
|
self.pause_timer = 0.25
|
||||||
end
|
end
|
||||||
end -- END if damage
|
end -- END if damage
|
||||||
|
|
||||||
-- if skittish then run away
|
-- if skittish then run away
|
||||||
if self.runaway == true then
|
if self.runaway == true then
|
||||||
|
|
||||||
local lp = hitter:getpos()
|
local lp = hitter:get_pos()
|
||||||
local s = self.object:getpos()
|
local s = self.object:get_pos()
|
||||||
local vec = {
|
local vec = {
|
||||||
x = lp.x - s.x,
|
x = lp.x - s.x,
|
||||||
y = lp.y - s.y,
|
y = lp.y - s.y,
|
||||||
|
@ -2251,7 +2313,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
|
||||||
do_attack(self, hitter)
|
do_attack(self, hitter)
|
||||||
|
|
||||||
-- alert others to the attack
|
-- alert others to the attack
|
||||||
local objs = minetest.get_objects_inside_radius(hitter:getpos(), self.view_range)
|
local objs = minetest.get_objects_inside_radius(hitter:get_pos(), self.view_range)
|
||||||
local obj = nil
|
local obj = nil
|
||||||
|
|
||||||
for n = 1, #objs do
|
for n = 1, #objs do
|
||||||
|
@ -2331,8 +2393,9 @@ end
|
||||||
-- activate mob and reload settings
|
-- activate mob and reload settings
|
||||||
local mob_activate = function(self, staticdata, def, dtime)
|
local mob_activate = function(self, staticdata, def, dtime)
|
||||||
|
|
||||||
-- remove monsters in peaceful mode, or when no data
|
-- remove monsters in peaceful mode
|
||||||
if (self.type == "monster" and peaceful_only) then
|
if self.type == "monster"
|
||||||
|
and peaceful_only then
|
||||||
|
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
|
|
||||||
|
@ -2406,17 +2469,17 @@ local mob_activate = function(self, staticdata, def, dtime)
|
||||||
self.health = random (self.hp_min, self.hp_max)
|
self.health = random (self.hp_min, self.hp_max)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- rnd: pathfinding init
|
-- pathfinding init
|
||||||
self.path = {}
|
self.path = {}
|
||||||
self.path.way = {} -- path to follow, table of positions
|
self.path.way = {} -- path to follow, table of positions
|
||||||
self.path.lastpos = {x = 0, y = 0, z = 0}
|
self.path.lastpos = {x = 0, y = 0, z = 0}
|
||||||
self.path.stuck = false
|
self.path.stuck = false
|
||||||
self.path.following = false -- currently following path?
|
self.path.following = false -- currently following path?
|
||||||
self.path.stuck_timer = 0 -- if stuck for too long search for path
|
self.path.stuck_timer = 0 -- if stuck for too long search for path
|
||||||
-- end init
|
|
||||||
|
|
||||||
|
-- mob defaults
|
||||||
self.object:set_armor_groups({immortal = 1, fleshy = self.armor})
|
self.object:set_armor_groups({immortal = 1, fleshy = self.armor})
|
||||||
self.old_y = self.object:getpos().y
|
self.old_y = self.object:get_pos().y
|
||||||
self.old_health = self.health
|
self.old_health = self.health
|
||||||
self.sounds.distance = self.sounds.distance or 10
|
self.sounds.distance = self.sounds.distance or 10
|
||||||
self.textures = textures
|
self.textures = textures
|
||||||
|
@ -2425,12 +2488,29 @@ local mob_activate = function(self, staticdata, def, dtime)
|
||||||
self.visual_size = vis_size
|
self.visual_size = vis_size
|
||||||
self.standing_in = ""
|
self.standing_in = ""
|
||||||
|
|
||||||
|
-- check existing nametag
|
||||||
|
if not self.nametag then
|
||||||
|
self.nametag = def.nametag
|
||||||
|
end
|
||||||
|
|
||||||
-- set anything changed above
|
-- set anything changed above
|
||||||
self.object:set_properties(self)
|
self.object:set_properties(self)
|
||||||
set_yaw(self.object, (random(0, 360) - 180) / 180 * pi)
|
set_yaw(self.object, (random(0, 360) - 180) / 180 * pi)
|
||||||
update_tag(self)
|
update_tag(self)
|
||||||
set_animation(self, "stand")
|
set_animation(self, "stand")
|
||||||
|
|
||||||
|
-- run on_spawn function if found
|
||||||
|
if self.on_spawn and not self.on_spawn_run then
|
||||||
|
if self.on_spawn(self) then
|
||||||
|
self.on_spawn_run = true -- if true, set flag to run once only
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- run after_activate
|
||||||
|
if def.after_activate then
|
||||||
|
def.after_activate(self, staticdata, def, dtime)
|
||||||
|
end
|
||||||
|
|
||||||
if use_cmi then
|
if use_cmi then
|
||||||
self._cmi_components = cmi.activate_components(self.serialized_cmi_components)
|
self._cmi_components = cmi.activate_components(self.serialized_cmi_components)
|
||||||
cmi.notify_activate(self.object, dtime)
|
cmi.notify_activate(self.object, dtime)
|
||||||
|
@ -2445,7 +2525,7 @@ local mob_step = function(self, dtime)
|
||||||
cmi.notify_step(self.object, dtime)
|
cmi.notify_step(self.object, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
local yaw = 0
|
local yaw = 0
|
||||||
|
|
||||||
-- when lifetimer expires remove mob (except npc and tamed)
|
-- when lifetimer expires remove mob (except npc and tamed)
|
||||||
|
@ -2490,10 +2570,6 @@ local mob_step = function(self, dtime)
|
||||||
|
|
||||||
self.pause_timer = self.pause_timer - dtime
|
self.pause_timer = self.pause_timer - dtime
|
||||||
|
|
||||||
if self.pause_timer < 1 then
|
|
||||||
self.pause_timer = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2625,7 +2701,6 @@ minetest.register_entity(name, {
|
||||||
attacks_monsters = def.attacks_monsters or false,
|
attacks_monsters = def.attacks_monsters or false,
|
||||||
group_attack = def.group_attack or false,
|
group_attack = def.group_attack or false,
|
||||||
passive = def.passive or false,
|
passive = def.passive or false,
|
||||||
recovery_time = def.recovery_time or 0.5,
|
|
||||||
knock_back = def.knock_back or 3,
|
knock_back = def.knock_back or 3,
|
||||||
blood_amount = def.blood_amount or 5,
|
blood_amount = def.blood_amount or 5,
|
||||||
blood_texture = def.blood_texture or "mobs_blood.png",
|
blood_texture = def.blood_texture or "mobs_blood.png",
|
||||||
|
@ -2657,6 +2732,7 @@ minetest.register_entity(name, {
|
||||||
pathfinding = def.pathfinding,
|
pathfinding = def.pathfinding,
|
||||||
immune_to = def.immune_to or {},
|
immune_to = def.immune_to or {},
|
||||||
explosion_radius = def.explosion_radius,
|
explosion_radius = def.explosion_radius,
|
||||||
|
explosion_timer = def.explosion_timer or 3,
|
||||||
custom_attack = def.custom_attack,
|
custom_attack = def.custom_attack,
|
||||||
double_melee_attack = def.double_melee_attack,
|
double_melee_attack = def.double_melee_attack,
|
||||||
dogshoot_switch = def.dogshoot_switch,
|
dogshoot_switch = def.dogshoot_switch,
|
||||||
|
@ -2666,14 +2742,23 @@ minetest.register_entity(name, {
|
||||||
attack_animals = def.attack_animals or false,
|
attack_animals = def.attack_animals or false,
|
||||||
specific_attack = def.specific_attack,
|
specific_attack = def.specific_attack,
|
||||||
owner_loyal = def.owner_loyal,
|
owner_loyal = def.owner_loyal,
|
||||||
|
facing_fence = false,
|
||||||
_cmi_is_mob = true,
|
_cmi_is_mob = true,
|
||||||
|
|
||||||
|
on_spawn = def.on_spawn,
|
||||||
|
|
||||||
on_blast = def.on_blast or do_tnt,
|
on_blast = def.on_blast or do_tnt,
|
||||||
|
|
||||||
on_step = mob_step,
|
on_step = mob_step,
|
||||||
|
|
||||||
|
do_punch = def.do_punch,
|
||||||
|
|
||||||
on_punch = mob_punch,
|
on_punch = mob_punch,
|
||||||
|
|
||||||
|
on_breed = def.on_breed,
|
||||||
|
|
||||||
|
on_grown = def.on_grown,
|
||||||
|
|
||||||
on_activate = function(self, staticdata, dtime)
|
on_activate = function(self, staticdata, dtime)
|
||||||
return mob_activate(self, staticdata, def, dtime)
|
return mob_activate(self, staticdata, def, dtime)
|
||||||
end,
|
end,
|
||||||
|
@ -2724,7 +2809,7 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
interval, chance, aoc, min_height, max_height, day_toggle, on_spawn)
|
interval, chance, aoc, min_height, max_height, day_toggle, on_spawn)
|
||||||
|
|
||||||
-- chance/spawn number override in minetest.conf for registered mob
|
-- chance/spawn number override in minetest.conf for registered mob
|
||||||
local numbers = minetest.setting_get(name)
|
local numbers = minetest.settings:get(name)
|
||||||
|
|
||||||
if numbers then
|
if numbers then
|
||||||
numbers = numbers:split(",")
|
numbers = numbers:split(",")
|
||||||
|
@ -2838,20 +2923,24 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light,
|
||||||
-- spawn mob half block higher than ground
|
-- spawn mob half block higher than ground
|
||||||
pos.y = pos.y - 0.5
|
pos.y = pos.y - 0.5
|
||||||
|
|
||||||
local mob = minetest.add_entity(pos, name)
|
if minetest.registered_entities[name] then
|
||||||
|
|
||||||
if mob and mob:get_luaentity() then
|
local mob = minetest.add_entity(pos, name)
|
||||||
-- print ("[mobs] Spawned " .. name .. " at "
|
--[[
|
||||||
-- .. minetest.pos_to_string(pos) .. " on "
|
print ("[mobs] Spawned " .. name .. " at "
|
||||||
-- .. node.name .. " near " .. neighbors[1])
|
.. minetest.pos_to_string(pos) .. " on "
|
||||||
if on_spawn and not on_spawn(mob, pos) then
|
.. node.name .. " near " .. neighbors[1])
|
||||||
return
|
]]
|
||||||
|
if on_spawn then
|
||||||
|
|
||||||
|
local ent = mob:get_luaentity()
|
||||||
|
|
||||||
|
on_spawn(ent, pos)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
minetest.log("warning", string.format("[mobs] %s failed to spawn at %s",
|
minetest.log("warning", string.format("[mobs] %s failed to spawn at %s",
|
||||||
name, minetest.pos_to_string(pos)))
|
name, minetest.pos_to_string(pos)))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -2910,13 +2999,13 @@ function mobs:register_arrow(name, def)
|
||||||
automatic_face_movement_dir = def.rotate
|
automatic_face_movement_dir = def.rotate
|
||||||
and (def.rotate - (pi / 180)) or false,
|
and (def.rotate - (pi / 180)) or false,
|
||||||
|
|
||||||
on_activate = def.on_activate or nil,
|
on_activate = def.on_activate,
|
||||||
|
|
||||||
on_step = def.on_step or function(self, dtime)
|
on_step = def.on_step or function(self, dtime)
|
||||||
|
|
||||||
self.timer = self.timer + 1
|
self.timer = self.timer + 1
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
if self.switch == 0
|
if self.switch == 0
|
||||||
or self.timer > 150
|
or self.timer > 150
|
||||||
|
@ -3020,6 +3109,7 @@ function mobs:boom(self, pos, radius)
|
||||||
radius = radius,
|
radius = radius,
|
||||||
damage_radius = radius,
|
damage_radius = radius,
|
||||||
sound = self.sounds.explode,
|
sound = self.sounds.explode,
|
||||||
|
explode_center = true,
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
minetest.sound_play(self.sounds.explode, {
|
minetest.sound_play(self.sounds.explode, {
|
||||||
|
@ -3077,25 +3167,24 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
|
||||||
and within_limits(pos, 0)
|
and within_limits(pos, 0)
|
||||||
and not minetest.is_protected(pos, placer:get_player_name()) then
|
and not minetest.is_protected(pos, placer:get_player_name()) then
|
||||||
|
|
||||||
|
if not minetest.registered_entities[mob] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
pos.y = pos.y + 1
|
pos.y = pos.y + 1
|
||||||
|
|
||||||
local mob = minetest.add_entity(pos, mob)
|
local mob = minetest.add_entity(pos, mob)
|
||||||
local ent = mob:get_luaentity()
|
local ent = mob:get_luaentity()
|
||||||
|
|
||||||
if not ent then
|
-- don't set owner if monster or sneak pressed
|
||||||
mob:remove()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if ent.type ~= "monster"
|
if ent.type ~= "monster"
|
||||||
and not placer:get_player_control().sneak then
|
and not placer:get_player_control().sneak then
|
||||||
-- set owner and tame if not monster
|
|
||||||
ent.owner = placer:get_player_name()
|
ent.owner = placer:get_player_name()
|
||||||
ent.tamed = true
|
ent.tamed = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if not in creative then take item
|
-- if not in creative then take item
|
||||||
if not creative then
|
if not mobs.is_creative(placer:get_player_name()) then
|
||||||
itemstack:take_item()
|
itemstack:take_item()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3211,7 +3300,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
|
||||||
if inv:room_for_item("main", new_stack) then
|
if inv:room_for_item("main", new_stack) then
|
||||||
inv:add_item("main", new_stack)
|
inv:add_item("main", new_stack)
|
||||||
else
|
else
|
||||||
minetest.add_item(clicker:getpos(), new_stack)
|
minetest.add_item(clicker:get_pos(), new_stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
|
@ -3250,18 +3339,17 @@ function mobs:protect(self, clicker)
|
||||||
return true -- false
|
return true -- false
|
||||||
end
|
end
|
||||||
|
|
||||||
if not creative then
|
if not mobs.is_creative(clicker:get_player_name()) then
|
||||||
tool:take_item() -- take 1 protection rune
|
tool:take_item() -- take 1 protection rune
|
||||||
clicker:set_wielded_item(tool)
|
clicker:set_wielded_item(tool)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.protected = true
|
self.protected = true
|
||||||
-- minetest.chat_send_player(name, S("Protected!"))
|
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
pos.y = pos.y + self.collisionbox[2] + 0.5
|
pos.y = pos.y + self.collisionbox[2] + 0.5
|
||||||
|
|
||||||
effect(self.object:getpos(), 25, "mobs_protect_particle.png", 0.5, 4, 2, 15)
|
effect(self.object:get_pos(), 25, "mobs_protect_particle.png", 0.5, 4, 2, 15)
|
||||||
|
|
||||||
mob_sound(self, "mobs_spell")
|
mob_sound(self, "mobs_spell")
|
||||||
|
|
||||||
|
@ -3283,7 +3371,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||||
if follow_holding(self, clicker) then
|
if follow_holding(self, clicker) then
|
||||||
|
|
||||||
-- if not in creative then take item
|
-- if not in creative then take item
|
||||||
if not creative then
|
if not mobs.is_creative(clicker:get_player_name()) then
|
||||||
|
|
||||||
local item = clicker:get_wielded_item()
|
local item = clicker:get_wielded_item()
|
||||||
|
|
||||||
|
@ -3301,9 +3389,11 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||||
|
|
||||||
if self.htimer < 1 then
|
if self.htimer < 1 then
|
||||||
|
|
||||||
|
--[[
|
||||||
minetest.chat_send_player(clicker:get_player_name(),
|
minetest.chat_send_player(clicker:get_player_name(),
|
||||||
S("@1 at full health (@2)",
|
S("@1 at full health (@2)",
|
||||||
self.name:split(":")[2], tostring(self.health)))
|
self.name:split(":")[2], tostring(self.health)))
|
||||||
|
]]
|
||||||
|
|
||||||
self.htimer = 5
|
self.htimer = 5
|
||||||
end
|
end
|
||||||
|
@ -3408,7 +3498,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
update_tag(mob_obj[name])
|
update_tag(mob_obj[name])
|
||||||
|
|
||||||
-- if not in creative then take item
|
-- if not in creative then take item
|
||||||
if not creative then
|
if not mobs.is_creative(name) then
|
||||||
|
|
||||||
mob_sta[name]:take_item()
|
mob_sta[name]:take_item()
|
||||||
|
|
||||||
|
@ -3436,9 +3526,11 @@ function mobs:alias_mob(old_name, new_name)
|
||||||
|
|
||||||
on_step = function(self)
|
on_step = function(self)
|
||||||
|
|
||||||
local pos = self.object:getpos()
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
|
if minetest.registered_entities[new_name] then
|
||||||
minetest.add_entity(pos, new_name)
|
minetest.add_entity(pos, new_name)
|
||||||
|
end
|
||||||
|
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
MOB API (13th July 2017)
|
MOB API (18th October 2017)
|
||||||
|
|
||||||
The mob api is a function that can be called on by other mods to add new animals or monsters into minetest.
|
The mob api is a function that can be called on by other mods to add new animals or monsters into minetest.
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ This functions registers a new mob as a Minetest entity.
|
||||||
'specific_attack' has a table of entity names that monsters can attack {"player", "mobs_animal:chicken"}
|
'specific_attack' has a table of entity names that monsters can attack {"player", "mobs_animal:chicken"}
|
||||||
'hp_min' minimum health
|
'hp_min' minimum health
|
||||||
'hp_max' maximum health (mob health is randomly selected between both)
|
'hp_max' maximum health (mob health is randomly selected between both)
|
||||||
|
'nametag' string containing name of mob to display above entity
|
||||||
'physical' same is in minetest.register_entity()
|
'physical' same is in minetest.register_entity()
|
||||||
'collisionbox' same is in minetest.register_entity()
|
'collisionbox' same is in minetest.register_entity()
|
||||||
'visual' same is in minetest.register_entity()
|
'visual' same is in minetest.register_entity()
|
||||||
|
@ -74,9 +75,7 @@ This functions registers a new mob as a Minetest entity.
|
||||||
'fall_damage' will mob be hurt when falling from height
|
'fall_damage' will mob be hurt when falling from height
|
||||||
'fall_speed' maximum falling velocity of mob (default is -10 and must be below -2)
|
'fall_speed' maximum falling velocity of mob (default is -10 and must be below -2)
|
||||||
'fear_height' when mob walks near a drop then anything over this value makes it stop and turn back (default is 0 to disable)
|
'fear_height' when mob walks near a drop then anything over this value makes it stop and turn back (default is 0 to disable)
|
||||||
'on_die' a function that is called when the mob is killed the parameters are (self, pos)
|
|
||||||
'floats' 1 to float in water, 0 to sink
|
'floats' 1 to float in water, 0 to sink
|
||||||
'on_rightclick' its same as in minetest.register_entity()
|
|
||||||
'pathfinding' set to 1 for mobs to use pathfinder feature to locate player, set to 2 so they can build/break also (only works with dogfight attack)
|
'pathfinding' set to 1 for mobs to use pathfinder feature to locate player, set to 2 so they can build/break also (only works with dogfight attack)
|
||||||
'attack_type' the attack type of a monster
|
'attack_type' the attack type of a monster
|
||||||
'dogfight' follows player in range and attacks when in reach
|
'dogfight' follows player in range and attacks when in reach
|
||||||
|
@ -88,8 +87,8 @@ This functions registers a new mob as a Minetest entity.
|
||||||
'dogshoot_count2_max' number of seconds before switching back to shoot mode.
|
'dogshoot_count2_max' number of seconds before switching back to shoot mode.
|
||||||
'custom_attack' when set this function is called instead of the normal mob melee attack, parameters are (self, to_attack)
|
'custom_attack' when set this function is called instead of the normal mob melee attack, parameters are (self, to_attack)
|
||||||
'double_melee_attack' if false then api will choose randomly between 'punch' and 'punch2' attack animations
|
'double_melee_attack' if false then api will choose randomly between 'punch' and 'punch2' attack animations
|
||||||
'on_blast' is called when an explosion happens near mob when using TNT functions, parameters are (object, damage) and returns (do_damage, do_knockback, drops)
|
|
||||||
'explosion_radius' radius of explosion attack (defaults to 1)
|
'explosion_radius' radius of explosion attack (defaults to 1)
|
||||||
|
'explosion_timer' number of seconds before mob explodes while still inside view range.
|
||||||
'arrow' if the attack_type is "shoot" or "dogshoot" then the entity name of a pre-defined arrow is required, see below for arrow definition.
|
'arrow' if the attack_type is "shoot" or "dogshoot" then the entity name of a pre-defined arrow is required, see below for arrow definition.
|
||||||
'shoot_interval' the minimum shoot interval
|
'shoot_interval' the minimum shoot interval
|
||||||
'shoot_offset' +/- value to position arrow/fireball when fired
|
'shoot_offset' +/- value to position arrow/fireball when fired
|
||||||
|
@ -105,6 +104,19 @@ This functions registers a new mob as a Minetest entity.
|
||||||
'explode' sound when exploding
|
'explode' sound when exploding
|
||||||
'distance' maximum distance sounds are heard from (default is 10)
|
'distance' maximum distance sounds are heard from (default is 10)
|
||||||
|
|
||||||
|
Custom mob functions inside mob registry:
|
||||||
|
|
||||||
|
'on_die' a function that is called when the mob is killed the parameters are (self, pos)
|
||||||
|
'on_rightclick' its same as in minetest.register_entity()
|
||||||
|
'on_blast' is called when an explosion happens near mob when using TNT functions, parameters are (object, damage) and returns (do_damage, do_knockback, drops)
|
||||||
|
'on_spawn' is a custom function that runs on mob spawn with 'self' as variable, return true at end of function to run only once.
|
||||||
|
'after_activate' is a custom function that runs once mob has been activated with the paramaters (self, staticdata, def, dtime)
|
||||||
|
'on_breed' called when two similar mobs breed, paramaters are (parent1, parent2) objects, return false to stop child from being resized and owner/tamed flags and child textures being applied.
|
||||||
|
'on_grown' is called when a child mob has grown up, only paramater is (self).
|
||||||
|
'do_punch' called when mob is punched with paramaters (self, hitter, time_from_last_punch, tool_capabilities, direction), return false to stop punch damage and knockback from taking place.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Mobs can look for specific nodes as they walk and replace them to mimic eating.
|
Mobs can look for specific nodes as they walk and replace them to mimic eating.
|
||||||
|
|
||||||
'replace_what' group if items to replace e.g. {"farming:wheat_8", "farming:carrot_8"}
|
'replace_what' group if items to replace e.g. {"farming:wheat_8", "farming:carrot_8"}
|
||||||
|
@ -135,6 +147,7 @@ can be added to the mob definition under pre-defined mob animation names like:
|
||||||
'fly_start', 'fly_end', 'fly_speed' when mob flies
|
'fly_start', 'fly_end', 'fly_speed' when mob flies
|
||||||
'punch_start', 'punch_end', 'punch_speed' when mob attacks
|
'punch_start', 'punch_end', 'punch_speed' when mob attacks
|
||||||
'punch2_start', 'punch2_end', 'punch2_speed' when mob attacks (alternative)
|
'punch2_start', 'punch2_end', 'punch2_speed' when mob attacks (alternative)
|
||||||
|
'shoot_start', 'shoot_end', shoot_speed' when mob shoots
|
||||||
'die_start', 'die_end', 'die_speed' when mob dies
|
'die_start', 'die_end', 'die_speed' when mob dies
|
||||||
'*_loop' bool value to determine if any set animation loops e.g (die_loop = false)
|
'*_loop' bool value to determine if any set animation loops e.g (die_loop = false)
|
||||||
defaults to true if not set
|
defaults to true if not set
|
||||||
|
|
|
@ -0,0 +1,684 @@
|
||||||
|
|
||||||
|
Mobs Redo API (last updated 18th Oct 2017)
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Welcome to the world of mobs in minetest and hopefully an easy guide to defining
|
||||||
|
your own mobs and having them appear in your worlds.
|
||||||
|
|
||||||
|
|
||||||
|
Registering Mobs
|
||||||
|
----------------
|
||||||
|
|
||||||
|
To register a mob and have it ready for use requires the following function:
|
||||||
|
|
||||||
|
mobs:register_mob(name, definition)
|
||||||
|
|
||||||
|
The 'name' of a mob usually starts with the mod name it's running from followed
|
||||||
|
by it's own name e.g.
|
||||||
|
|
||||||
|
"mobs_monster:sand_monster" or "mymod:totally_awesome_beast"
|
||||||
|
|
||||||
|
... and the 'definition' is a table which holds all of the settings and
|
||||||
|
functions needed for the mob to work properly which contains the following:
|
||||||
|
|
||||||
|
'nametag' contains the name which is shown above mob.
|
||||||
|
'type' holds the type of mob that inhabits your world e.g.
|
||||||
|
"animal" usually docile and walking around.
|
||||||
|
"monster" attacks player or npc on sight.
|
||||||
|
"npc" walk around and will defend themselves if hit first, they
|
||||||
|
kill monsters.
|
||||||
|
'hp_min' has the minimum health value the mob can spawn with.
|
||||||
|
'hp_max' has the maximum health value the mob can spawn with.
|
||||||
|
'armor' holds strength of mob, 100 is normal, lower is more powerful
|
||||||
|
and needs more hits and better weapons to kill.
|
||||||
|
'passive' when true allows animals to defend themselves when hit,
|
||||||
|
otherwise they amble onwards.
|
||||||
|
'walk_velocity' is the speed that your mob can walk around.
|
||||||
|
'run_velocity' is the speed your mob can run with, usually when attacking.
|
||||||
|
'walk_chance' has a 0-100 chance value your mob will walk from standing,
|
||||||
|
set to 0 for jumping mobs only.
|
||||||
|
'jump' when true allows your mob to jump updwards.
|
||||||
|
'jump_height' holds the height your mob can jump, 0 to disable jumping.
|
||||||
|
'step_height' height of a block that your mob can easily walk up onto.
|
||||||
|
'fly' when true allows your mob to fly around instead of walking.
|
||||||
|
'fly_in' holds the node name that the mob flies (or swims) around
|
||||||
|
in e.g. "air" or "default:water_source".
|
||||||
|
'runaway' if true causes animals to turn and run away when hit.
|
||||||
|
'view_range' how many nodes in distance the mob can see a player.
|
||||||
|
'reach' how many nodes in distance a mob can attack a player while
|
||||||
|
standing.
|
||||||
|
'damage' how many health points the mob does to a player or another
|
||||||
|
mob when melee attacking.
|
||||||
|
'knockback' when true has mobs falling backwards when hit, the greater
|
||||||
|
the damage the more they move back.
|
||||||
|
'fear_height' is how high a cliff or edge has to be before the mob stops
|
||||||
|
walking, 0 to turn off height fear.
|
||||||
|
'fall_speed' has the maximum speed the mob can fall at, default is -10.
|
||||||
|
'fall_damage' when true causes falling to inflict damage.
|
||||||
|
'water_damage' holds the damage per second infliced to mobs when standing in
|
||||||
|
water.
|
||||||
|
'lava_damage' holds the damage per second inflicted to mobs when standing
|
||||||
|
in lava or fire.
|
||||||
|
'light_damage' holds the damage per second inflicted to mobs when it's too
|
||||||
|
bright (above 13 light).
|
||||||
|
'suffocation' when true causes mobs to suffocate inside solid blocks.
|
||||||
|
'floats' when set to 1 mob will float in water, 0 has them sink.
|
||||||
|
'follow' mobs follow player when holding any of the items which appear
|
||||||
|
on this table, the same items can be fed to a mob to tame or
|
||||||
|
breed e.g. {"farming:wheat", "default:apple"}
|
||||||
|
|
||||||
|
'reach' is how far the mob can attack player when standing
|
||||||
|
nearby, default is 3 nodes.
|
||||||
|
'docile_by_day' when true has mobs wandering around during daylight
|
||||||
|
hours and only attacking player at night or when
|
||||||
|
provoked.
|
||||||
|
'attacks_monsters' when true has npc's attacking monsters or not.
|
||||||
|
'attack_animal' when true will have monsters attacking animals.
|
||||||
|
'owner_loyal' when true will have tamed mobs attack anything player
|
||||||
|
punches when nearby.
|
||||||
|
'group_attack' when true has same mob type grouping together to attack
|
||||||
|
offender.
|
||||||
|
'attack_type' tells the api what a mob does when attacking the player
|
||||||
|
or another mob:
|
||||||
|
'dogfight' is a melee attack when player is within mob reach.
|
||||||
|
'shoot' has mob shoot pre-defined arrows at player when inside
|
||||||
|
view_range.
|
||||||
|
'dogshoot' has melee attack when inside reach and shoot attack
|
||||||
|
when inside view_range.
|
||||||
|
'explode' causes mob to explode when inside reach.
|
||||||
|
'explosion_radius' has the radius of the explosion which defaults to 1.
|
||||||
|
'explosion_timer' number of seconds before mob explodes while still
|
||||||
|
inside view range.
|
||||||
|
'arrow' holds the pre-defined arrow object to shoot when
|
||||||
|
attacking.
|
||||||
|
'dogshoot_switch' allows switching between attack types by using timers
|
||||||
|
(1 for shoot, 2 for dogfight)
|
||||||
|
'dogshoot_count_max' contains how many seconds before switching from
|
||||||
|
dogfight to shoot.
|
||||||
|
'dogshoot_count_max2' contains how many seconds before switching from shoot
|
||||||
|
to dogfight.
|
||||||
|
'shoot_interval' has the number of seconds between shots.
|
||||||
|
'shoot_offset' holds the y position added as to where the
|
||||||
|
arrow/fireball appears on mob.
|
||||||
|
'specific_attack' has a table of entity names that mob can also attack
|
||||||
|
e.g. {"player", "mobs_animal:chicken"}.
|
||||||
|
'blood_amount' contains the number of blood droplets to appear when
|
||||||
|
mob is hit.
|
||||||
|
'blood_texture' has the texture name to use for droplets e.g.
|
||||||
|
"mobs_blood.png".
|
||||||
|
'pathfinding' set to 1 for mobs to use pathfinder feature to locate
|
||||||
|
player, set to 2 so they can build/break also (only
|
||||||
|
works with dogfight attack).
|
||||||
|
'immune_to' is a table that holds specific damage when being hit by
|
||||||
|
certain items e.g.
|
||||||
|
{"default:sword_wood", 0} -- causes no damage.
|
||||||
|
{"default:gold_lump", -10} -- heals by 10 health points.
|
||||||
|
{"default:coal_block", 20} -- 20 damage when hit on head with coal blocks.
|
||||||
|
|
||||||
|
'makes_footstep_sound' when true you can hear mobs walking.
|
||||||
|
'sounds' this is a table with sounds of the mob
|
||||||
|
'distance' maximum distance sounds can be heard, default is 10.
|
||||||
|
'random' random sound that plays during gameplay.
|
||||||
|
'war_cry' what you hear when mob starts to attack player.
|
||||||
|
'attack' what you hear when being attacked.
|
||||||
|
'shoot_attack' sound played when mob shoots.
|
||||||
|
'damage' sound heard when mob is hurt.
|
||||||
|
'death' played when mob is killed.
|
||||||
|
'jump' played when mob jumps.
|
||||||
|
'explode' sound played when mob explodes.
|
||||||
|
|
||||||
|
'drops' table of items that are dropped when mob is killed, fields are:
|
||||||
|
'name' name of item to drop.
|
||||||
|
'chance' chance of drop, 1 for always, 2 for 1-in-2 chance etc.
|
||||||
|
'min' minimum number of items dropped.
|
||||||
|
'max' maximum number of items dropped.
|
||||||
|
|
||||||
|
'visual' holds the look of the mob you wish to create:
|
||||||
|
'cube' looks like a normal node
|
||||||
|
'sprite' sprite which looks same from all angles.
|
||||||
|
'upright_sprite' flat model standing upright.
|
||||||
|
'wielditem' how it looks when player holds it in hand.
|
||||||
|
'mesh' uses separate object file to define mob.
|
||||||
|
'visual_size' has the size of the mob, defaults to {x = 1, y = 1}
|
||||||
|
'collision_box' has the box in which mob can be interacted with e.g.
|
||||||
|
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}
|
||||||
|
'textures' holds a table list of textures to be used for mob, or you
|
||||||
|
could use multiple lists inside another table for random
|
||||||
|
selection e.g. { {"texture1.png"}, {"texture2.png"} }
|
||||||
|
'child_texture' holds the texture table for when baby mobs are used.
|
||||||
|
'gotten_texture' holds the texture table for when self.gotten value is
|
||||||
|
true, used for milking cows or shearing sheep.
|
||||||
|
'mesh' holds the name of the external object used for mob model
|
||||||
|
e.g. "mobs_cow.b3d"
|
||||||
|
'gotten_mesh" holds the name of the external object used for when
|
||||||
|
self.gotten is true for mobs.
|
||||||
|
'rotate' custom model rotation, 0 = front, 90 = side, 180 = back,
|
||||||
|
270 = other side.
|
||||||
|
'double_melee_attack' when true has the api choose between 'punch' and
|
||||||
|
'punch2' animations.
|
||||||
|
|
||||||
|
'animation' holds a table containing animation names and settings for use with mesh models:
|
||||||
|
'stand_start' start frame for when mob stands still.
|
||||||
|
'stand_end' end frame of stand animation.
|
||||||
|
'stand_speed' speed of animation in frames per second.
|
||||||
|
'walk_start' when mob is walking around.
|
||||||
|
'walk_end'
|
||||||
|
'walk_speed'
|
||||||
|
'run_start' when a mob runs or attacks.
|
||||||
|
'run_end'
|
||||||
|
'run_speed'
|
||||||
|
'fly_start' when a mob is flying.
|
||||||
|
'fly_end'
|
||||||
|
'fly_speed'
|
||||||
|
'punch_start' when a mob melee attacks.
|
||||||
|
'punch_end'
|
||||||
|
'punch_speed'
|
||||||
|
'punch2_start' alternative melee attack animation.
|
||||||
|
'punch2_end'
|
||||||
|
'punch2_speed'
|
||||||
|
'shoot_start' shooting animation.
|
||||||
|
'shoot_end'
|
||||||
|
'shoot_speed'
|
||||||
|
'die_start' death animation
|
||||||
|
'die_end'
|
||||||
|
'die_speed'
|
||||||
|
'die_loop' when set to false stops the animation looping.
|
||||||
|
|
||||||
|
Using '_loop = false' setting will stop any of the above animations from
|
||||||
|
looping.
|
||||||
|
|
||||||
|
'speed_normal' is used for animation speed for compatibility with some
|
||||||
|
older mobs.
|
||||||
|
|
||||||
|
|
||||||
|
Node Replacement
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Mobs can look around for specific nodes as they walk and replace them to mimic
|
||||||
|
eating.
|
||||||
|
|
||||||
|
'replace_what' group of items to replace e.g.
|
||||||
|
{"farming:wheat_8", "farming:carrot_8"}
|
||||||
|
or you can use the specific options of what, with and
|
||||||
|
y offset by using this instead:
|
||||||
|
{
|
||||||
|
{"group:grass", "air", 0},
|
||||||
|
{"default:dirt_with_grass", "default:dirt", -1}
|
||||||
|
}
|
||||||
|
'replace_with' replace with what e.g. "air" or in chickens case "mobs:egg"
|
||||||
|
'replace_rate' how random should the replace rate be (typically 10)
|
||||||
|
'replace_offset' +/- value to check specific node to replace
|
||||||
|
|
||||||
|
'on_replace(self, pos, oldnode, newnode)' is called when mob is about to
|
||||||
|
replace a node.
|
||||||
|
'self' ObjectRef of mob
|
||||||
|
'pos' Position of node to replace
|
||||||
|
'oldnode' Current node
|
||||||
|
'newnode' What the node will become after replacing
|
||||||
|
|
||||||
|
If false is returned, the mob will not replace the node.
|
||||||
|
|
||||||
|
By default, replacing sets self.gotten to true and resets the object
|
||||||
|
properties.
|
||||||
|
|
||||||
|
|
||||||
|
Custom Definition Functions
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Along with the above mob registry settings we can also use custom functions to
|
||||||
|
enhance mob functionality and have them do many interesting things:
|
||||||
|
|
||||||
|
'on_die' a function that is called when the mob is killed the
|
||||||
|
parameters are (self, pos)
|
||||||
|
'on_rightclick' its same as in minetest.register_entity()
|
||||||
|
'on_blast' is called when an explosion happens near mob when using TNT
|
||||||
|
functions, parameters are (object, damage) and returns
|
||||||
|
(do_damage, do_knockback, drops)
|
||||||
|
'on_spawn' is a custom function that runs on mob spawn with 'self' as
|
||||||
|
variable, return true at end of function to run only once.
|
||||||
|
'after_activate' is a custom function that runs once mob has been activated
|
||||||
|
with these paramaters (self, staticdata, def, dtime)
|
||||||
|
'on_breed' called when two similar mobs breed, paramaters are
|
||||||
|
(parent1, parent2) objects, return false to stop child from
|
||||||
|
being resized and owner/tamed flags and child textures being
|
||||||
|
applied. Function itself must spawn new child mob.
|
||||||
|
'on_grown' is called when a child mob has grown up, only paramater is
|
||||||
|
(self).
|
||||||
|
'do_punch' called when mob is punched with paramaters (self, hitter,
|
||||||
|
time_from_last_punch, tool_capabilities, direction), return
|
||||||
|
false to stop punch damage and knockback from taking place.
|
||||||
|
'custom_attack' when set this function is called instead of the normal mob
|
||||||
|
melee attack, parameters are (self, to_attack).
|
||||||
|
'on_die' a function that is called when mob is killed
|
||||||
|
'do_custom' a custom function that is called every tick while mob is
|
||||||
|
active and which has access to all of the self.* variables
|
||||||
|
e.g. (self.health for health or self.standing_in for node
|
||||||
|
status), return with 'false' to skip remainder of mob API.
|
||||||
|
|
||||||
|
|
||||||
|
Internal Variables
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The mob api also has some preset variables and functions that it will remember
|
||||||
|
for each mob.
|
||||||
|
|
||||||
|
'self.health' contains current health of mob (cannot exceed
|
||||||
|
self.hp_max)
|
||||||
|
'self.texture_list' contains list of all mob textures
|
||||||
|
'self.child_texture' contains mob child texture when growing up
|
||||||
|
'self.base_texture' contains current skin texture which was randomly
|
||||||
|
selected from textures list
|
||||||
|
'self.gotten' this is used for obtaining milk from cow and wool from
|
||||||
|
sheep
|
||||||
|
'self.horny' when animal fed enough it is set to true and animal can
|
||||||
|
breed with same animal
|
||||||
|
'self.hornytimer' background timer that controls breeding functions and
|
||||||
|
mob childhood timings
|
||||||
|
'self.child' used for when breeding animals have child, will use
|
||||||
|
child_texture and be half size
|
||||||
|
'self.owner' string used to set owner of npc mobs, typically used for
|
||||||
|
dogs
|
||||||
|
'self.order' set to "follow" or "stand" so that npc will follow owner
|
||||||
|
or stand it's ground
|
||||||
|
'self.nametag' contains the name of the mob which it can show above
|
||||||
|
|
||||||
|
|
||||||
|
Spawning Mobs in World
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
mobs:register_spawn(name, nodes, max_light, min_light, chance,
|
||||||
|
active_object_count, max_height, day_toggle)
|
||||||
|
|
||||||
|
mobs:spawn_specfic(name, nodes, neighbors, min_light, max_light, interval,
|
||||||
|
chance, active_object_count, min_height, max_height, day_toggle, on_spawn)
|
||||||
|
|
||||||
|
These functions register a spawn algorithm for the mob. Without this function
|
||||||
|
the call the mobs won't spawn.
|
||||||
|
|
||||||
|
'name' is the name of the animal/monster
|
||||||
|
'nodes' is a list of nodenames on that the animal/monster can
|
||||||
|
spawn on top of
|
||||||
|
'neighbors' is a list of nodenames on that the animal/monster will
|
||||||
|
spawn beside (default is {"air"} for
|
||||||
|
mobs:register_spawn)
|
||||||
|
'max_light' is the maximum of light
|
||||||
|
'min_light' is the minimum of light
|
||||||
|
'interval' is same as in register_abm() (default is 30 for
|
||||||
|
mobs:register_spawn)
|
||||||
|
'chance' is same as in register_abm()
|
||||||
|
'active_object_count' number of this type of mob to spawn at one time inside
|
||||||
|
map area
|
||||||
|
'min_height' is the minimum height the mob can spawn
|
||||||
|
'max_height' is the maximum height the mob can spawn
|
||||||
|
'day_toggle' true for day spawning, false for night or nil for
|
||||||
|
anytime
|
||||||
|
'on_spawn' is a custom function which runs after mob has spawned
|
||||||
|
and gives self and pos values.
|
||||||
|
|
||||||
|
A simpler way to handle mob spawns has been added with the mobs:spawn(def)
|
||||||
|
command which uses above names to make settings clearer:
|
||||||
|
|
||||||
|
mobs:spawn({name = "mobs_monster:tree_monster",
|
||||||
|
nodes = {"group:leaves"},
|
||||||
|
max_light = 7,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
For each mob that spawns with this function is a field in mobs.spawning_mobs.
|
||||||
|
It tells if the mob should spawn or not. Default is true. So other mods can
|
||||||
|
only use the API of this mod by disabling the spawning of the default mobs in
|
||||||
|
this mod.
|
||||||
|
|
||||||
|
|
||||||
|
Making Arrows
|
||||||
|
-------------
|
||||||
|
|
||||||
|
mobs:register_arrow(name, definition)
|
||||||
|
|
||||||
|
This function registers a arrow for mobs with the attack type shoot.
|
||||||
|
|
||||||
|
'name' is the name of the arrow
|
||||||
|
'definition' is a table with the following values:
|
||||||
|
'visual' same is in minetest.register_entity()
|
||||||
|
'visual_size' same is in minetest.register_entity()
|
||||||
|
'textures' same is in minetest.register_entity()
|
||||||
|
'velocity' the velocity of the arrow
|
||||||
|
'drop' if set to true any arrows hitting a node will drop as item
|
||||||
|
'hit_player' a function that is called when the arrow hits a player;
|
||||||
|
this function should hurt the player, the parameters are
|
||||||
|
(self, player)
|
||||||
|
'hit_mob' a function that is called when the arrow hits a mob;
|
||||||
|
this function should hurt the mob, the parameters are
|
||||||
|
(self, player)
|
||||||
|
'hit_node' a function that is called when the arrow hits a node, the
|
||||||
|
parameters are (self, pos, node)
|
||||||
|
'tail' when set to 1 adds a trail or tail to mob arrows
|
||||||
|
'tail_texture' texture string used for above effect
|
||||||
|
'tail_size' has size for above texture (defaults to between 5 and 10)
|
||||||
|
'expire' contains float value for how long tail appears for
|
||||||
|
(defaults to 0.25)
|
||||||
|
'glow' has value for how brightly tail glows 1 to 10 (default is
|
||||||
|
0 for no glow)
|
||||||
|
'rotate' integer value in degrees to rotate arrow
|
||||||
|
'on_step' is a custom function when arrow is active, nil for
|
||||||
|
default.
|
||||||
|
|
||||||
|
|
||||||
|
Spawn Eggs
|
||||||
|
----------
|
||||||
|
|
||||||
|
mobs:register_egg(name, description, background, addegg, no_creative)
|
||||||
|
|
||||||
|
This function registers a spawn egg which can be used by admin to properly spawn in a mob.
|
||||||
|
|
||||||
|
'name' this is the name of your new mob to spawn e.g. "mob:sheep"
|
||||||
|
'description' the name of the new egg you are creating e.g. "Spawn Sheep"
|
||||||
|
'background' the texture displayed for the egg in inventory
|
||||||
|
'addegg' would you like an egg image in front of your texture (1 = yes,
|
||||||
|
0 = no)
|
||||||
|
'no_creative' when set to true this stops spawn egg appearing in creative
|
||||||
|
mode for destructive mobs like Dungeon Masters.
|
||||||
|
|
||||||
|
|
||||||
|
Explosion Function
|
||||||
|
------------------
|
||||||
|
|
||||||
|
mobs:explosion(pos, radius) -- DEPRECATED!!! use mobs:boom() instead
|
||||||
|
|
||||||
|
mobs:boom(self, pos, radius)
|
||||||
|
'self' mob entity
|
||||||
|
'pos' centre position of explosion
|
||||||
|
'radius' radius of explosion (typically set to 3)
|
||||||
|
|
||||||
|
This function generates an explosion which removes nodes in a specific radius
|
||||||
|
and damages any entity caught inside the blast radius. Protection will limit
|
||||||
|
node destruction but not entity damage.
|
||||||
|
|
||||||
|
|
||||||
|
Capturing Mobs
|
||||||
|
--------------
|
||||||
|
|
||||||
|
mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
|
||||||
|
force_take, replacewith)
|
||||||
|
|
||||||
|
This function is generally called inside the on_rightclick section of the mob
|
||||||
|
api code, it provides a chance of capturing the mob by hand, using the net or
|
||||||
|
lasso items, and can also have the player take the mob by force if tamed and
|
||||||
|
replace with another item entirely.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'clicker' player information
|
||||||
|
'chance_hand' chance of capturing mob by hand (1 to 100) 0 to disable
|
||||||
|
'chance_net' chance of capturing mob using net (1 to 100) 0 to disable
|
||||||
|
'chance_lasso' chance of capturing mob using magic lasso (1 to 100) 0 to
|
||||||
|
disable
|
||||||
|
'force_take' take mob by force, even if tamed (true or false)
|
||||||
|
'replacewith' once captured replace mob with this item instead (overrides
|
||||||
|
new mob eggs with saved information)
|
||||||
|
|
||||||
|
|
||||||
|
Feeding and Taming/Breeding
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
mobs:feed_tame(self, clicker, feed_count, breed, tame)
|
||||||
|
|
||||||
|
This function allows the mob to be fed the item inside self.follow be it apple,
|
||||||
|
wheat or whatever a set number of times and be tamed or bred as a result.
|
||||||
|
Will return true when mob is fed with item it likes.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'clicker' player information
|
||||||
|
'feed_count' number of times mob must be fed to tame or breed
|
||||||
|
'breed' true or false stating if mob can be bred and a child created
|
||||||
|
afterwards
|
||||||
|
'tame' true or false stating if mob can be tamed so player can pick
|
||||||
|
them up
|
||||||
|
|
||||||
|
|
||||||
|
Protecting Mobs
|
||||||
|
---------------
|
||||||
|
|
||||||
|
mobs:protect(self, clicker)
|
||||||
|
|
||||||
|
This function can be used to right-click any tamed mob with mobs:protector item,
|
||||||
|
this will protect the mob from harm inside of a protected area from other
|
||||||
|
players. Will return true when mob right-clicked with mobs:protector item.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'clicker' player information
|
||||||
|
|
||||||
|
|
||||||
|
Riding Mobs
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Mobs can now be ridden by players and the following shows its functions and
|
||||||
|
usage:
|
||||||
|
|
||||||
|
|
||||||
|
mobs:attach(self, player)
|
||||||
|
|
||||||
|
This function attaches a player to the mob so it can be ridden.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'player' player information
|
||||||
|
|
||||||
|
|
||||||
|
mobs:detach(player, offset)
|
||||||
|
|
||||||
|
This function will detach the player currently riding a mob to an offset
|
||||||
|
position.
|
||||||
|
|
||||||
|
'player' player information
|
||||||
|
'offset' position table containing offset values
|
||||||
|
|
||||||
|
|
||||||
|
mobs:drive(self, move_animation, stand_animation, can_fly, dtime)
|
||||||
|
|
||||||
|
This function allows an attached player to move the mob around and animate it at
|
||||||
|
same time.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'move_animation' string containing movement animation e.g. "walk"
|
||||||
|
'stand_animation' string containing standing animation e.g. "stand"
|
||||||
|
'can_fly' if true then jump and sneak controls will allow mob to fly
|
||||||
|
up and down
|
||||||
|
'dtime' tick time used inside drive function
|
||||||
|
|
||||||
|
|
||||||
|
mobs:fly(self, dtime, speed, can_shoot, arrow_entity, move_animation, stand_animation)
|
||||||
|
|
||||||
|
This function allows an attached player to fly the mob around using directional
|
||||||
|
controls.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'dtime' tick time used inside fly function
|
||||||
|
'speed' speed of flight
|
||||||
|
'can_shoot' true if mob can fire arrow (sneak and left mouse button
|
||||||
|
fires)
|
||||||
|
'arrow_entity' name of arrow entity used for firing
|
||||||
|
'move_animation' string containing name of pre-defined animation e.g. "walk"
|
||||||
|
or "fly" etc.
|
||||||
|
'stand_animation' string containing name of pre-defined animation e.g.
|
||||||
|
"stand" or "blink" etc.
|
||||||
|
|
||||||
|
Note: animation names above are from the pre-defined animation lists inside mob
|
||||||
|
registry without extensions.
|
||||||
|
|
||||||
|
|
||||||
|
mobs:set_animation(self, name)
|
||||||
|
|
||||||
|
This function sets the current animation for mob, defaulting to "stand" if not
|
||||||
|
found.
|
||||||
|
|
||||||
|
'self' mob information
|
||||||
|
'name' name of animation
|
||||||
|
|
||||||
|
|
||||||
|
Certain variables need to be set before using the above functions:
|
||||||
|
|
||||||
|
'self.v2' toggle switch used to define below values for the
|
||||||
|
first time
|
||||||
|
'self.max_speed_forward' max speed mob can move forward
|
||||||
|
'self.max_speed_reverse' max speed mob can move backwards
|
||||||
|
'self.accel' acceleration speed
|
||||||
|
'self.terrain_type' integer containing terrain mob can walk on
|
||||||
|
(1 = water, 2 or 3 = land)
|
||||||
|
'self.driver_attach_at' position offset for attaching player to mob
|
||||||
|
'self.driver_eye_offset' position offset for attached player view
|
||||||
|
'self.driver_scale' sets driver scale for mobs larger than {x=1, y=1}
|
||||||
|
|
||||||
|
|
||||||
|
External Settings for "minetest.conf"
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
'enable_damage' if true monsters will attack players (default is true)
|
||||||
|
'only_peaceful_mobs' if true only animals will spawn in game (default is
|
||||||
|
false)
|
||||||
|
'mobs_disable_blood' if false blood effects appear when mob is hit (default
|
||||||
|
is false)
|
||||||
|
'mobs_spawn_protected' if set to false then mobs will not spawn in protected
|
||||||
|
areas (default is true)
|
||||||
|
'remove_far_mobs' if true then mobs that are outside players visual
|
||||||
|
range will be removed (default is false)
|
||||||
|
'mobname' can change specific mob chance rate (0 to disable) and
|
||||||
|
spawn number e.g. mobs_animal:cow = 1000,5
|
||||||
|
'mob_difficulty' sets difficulty level (health and hit damage
|
||||||
|
multiplied by this number), defaults to 1.0.
|
||||||
|
'mob_show_health' if false then punching mob will not show health status
|
||||||
|
(true by default)
|
||||||
|
|
||||||
|
Players can override the spawn chance for each mob registered by adding a line
|
||||||
|
to their minetest.conf file with a new value, the lower the value the more each
|
||||||
|
mob will spawn e.g.
|
||||||
|
|
||||||
|
mobs_animal:sheep_chance 11000
|
||||||
|
mobs_monster:sand_monster_chance 100
|
||||||
|
|
||||||
|
|
||||||
|
Rideable Horse Example Mob
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
mobs:register_mob("mob_horse:horse", {
|
||||||
|
type = "animal",
|
||||||
|
visual = "mesh",
|
||||||
|
visual_size = {x = 1.20, y = 1.20},
|
||||||
|
mesh = "mobs_horse.x",
|
||||||
|
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.25, 0.4},
|
||||||
|
animation = {
|
||||||
|
speed_normal = 15,
|
||||||
|
speed_run = 30,
|
||||||
|
stand_start = 25,
|
||||||
|
stand_end = 75,
|
||||||
|
walk_start = 75,
|
||||||
|
walk_end = 100,
|
||||||
|
run_start = 75,
|
||||||
|
run_end = 100,
|
||||||
|
},
|
||||||
|
textures = {
|
||||||
|
{"mobs_horse.png"},
|
||||||
|
{"mobs_horsepeg.png"},
|
||||||
|
{"mobs_horseara.png"}
|
||||||
|
},
|
||||||
|
fear_height = 3,
|
||||||
|
runaway = true,
|
||||||
|
fly = false,
|
||||||
|
walk_chance = 60,
|
||||||
|
view_range = 5,
|
||||||
|
follow = {"farming:wheat"},
|
||||||
|
passive = true,
|
||||||
|
hp_min = 12,
|
||||||
|
hp_max = 16,
|
||||||
|
armor = 200,
|
||||||
|
lava_damage = 5,
|
||||||
|
fall_damage = 5,
|
||||||
|
water_damage = 1,
|
||||||
|
makes_footstep_sound = true,
|
||||||
|
drops = {
|
||||||
|
{name = "mobs:meat_raw", chance = 1, min = 2, max = 3}
|
||||||
|
},
|
||||||
|
sounds = {
|
||||||
|
random = "horse_neigh.ogg",
|
||||||
|
damage = "horse_whinney.ogg",
|
||||||
|
},
|
||||||
|
|
||||||
|
do_custom = function(self, dtime)
|
||||||
|
|
||||||
|
-- set needed values if not already present
|
||||||
|
if not self.v2 then
|
||||||
|
self.v2 = 0
|
||||||
|
self.max_speed_forward = 6
|
||||||
|
self.max_speed_reverse = 2
|
||||||
|
self.accel = 6
|
||||||
|
self.terrain_type = 3
|
||||||
|
self.driver_attach_at = {x = 0, y = 20, z = -2}
|
||||||
|
self.driver_eye_offset = {x = 0, y = 3, z = 0}
|
||||||
|
self.driver_scale = {x = 1, y = 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if driver present allow control of horse
|
||||||
|
if self.driver then
|
||||||
|
|
||||||
|
mobs.drive(self, "walk", "stand", false, dtime)
|
||||||
|
|
||||||
|
return false -- skip rest of mob functions
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_die = function(self, pos)
|
||||||
|
|
||||||
|
-- drop saddle when horse is killed while riding
|
||||||
|
-- also detach from horse properly
|
||||||
|
if self.driver then
|
||||||
|
minetest.add_item(pos, "mobs:saddle")
|
||||||
|
mobs.detach(self.driver, {x = 1, y = 0, z = 1})
|
||||||
|
end
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
on_rightclick = function(self, clicker)
|
||||||
|
|
||||||
|
-- make sure player is clicking
|
||||||
|
if not clicker or not clicker:is_player() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- feed, tame or heal horse
|
||||||
|
if mobs:feed_tame(self, clicker, 10, true, true) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure tamed horse is being clicked by owner only
|
||||||
|
if self.tamed and self.owner == clicker:get_player_name() then
|
||||||
|
|
||||||
|
local inv = clicker:get_inventory()
|
||||||
|
|
||||||
|
-- detatch player already riding horse
|
||||||
|
if self.driver and clicker == self.driver then
|
||||||
|
|
||||||
|
mobs.detach(clicker, {x = 1, y = 0, z = 1})
|
||||||
|
|
||||||
|
-- add saddle back to inventory
|
||||||
|
if inv:room_for_item("main", "mobs:saddle") then
|
||||||
|
inv:add_item("main", "mobs:saddle")
|
||||||
|
else
|
||||||
|
minetest.add_item(clicker.getpos(), "mobs:saddle")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- attach player to horse
|
||||||
|
elseif not self.driver
|
||||||
|
and clicker:get_wielded_item():get_name() == "mobs:saddle" then
|
||||||
|
|
||||||
|
self.object:set_properties({stepheight = 1.1})
|
||||||
|
mobs.attach(self, clicker)
|
||||||
|
|
||||||
|
-- take saddle from inventory
|
||||||
|
inv:remove_item("main", "mobs:saddle")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- used to capture horse with magic lasso
|
||||||
|
mobs:capture_mob(self, clicker, 0, 0, 80, false, nil)
|
||||||
|
end
|
||||||
|
})
|
|
@ -155,8 +155,8 @@ function mobs.attach(entity, player)
|
||||||
mcl_player.player_set_animation(player, "sit" , 30)
|
mcl_player.player_set_animation(player, "sit" , 30)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--player:set_look_yaw(entity.object:getyaw() - rot_view)
|
--player:set_look_yaw(entity.object:get_yaw() - rot_view)
|
||||||
player:set_look_horizontal(entity.object:getyaw() - rot_view)
|
player:set_look_horizontal(entity.object:get_yaw() - rot_view)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ function mobs.detach(player, offset)
|
||||||
|
|
||||||
mcl_player.player_set_animation(player, "stand" , 30)
|
mcl_player.player_set_animation(player, "stand" , 30)
|
||||||
|
|
||||||
local pos = player:getpos()
|
local pos = player:get_pos()
|
||||||
|
|
||||||
pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z}
|
pos = {x = pos.x + offset.x, y = pos.y + 0.2 + offset.y, z = pos.z + offset.z}
|
||||||
|
|
||||||
|
@ -212,7 +212,6 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- fix mob rotation
|
-- fix mob rotation
|
||||||
-- entity.object:setyaw(entity.driver:get_look_yaw() - entity.rotate)
|
|
||||||
entity.object:setyaw(entity.driver:get_look_horizontal() - entity.rotate)
|
entity.object:setyaw(entity.driver:get_look_horizontal() - entity.rotate)
|
||||||
|
|
||||||
if can_fly then
|
if can_fly then
|
||||||
|
@ -290,7 +289,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set position, velocity and acceleration
|
-- Set position, velocity and acceleration
|
||||||
local p = entity.object:getpos()
|
local p = entity.object:get_pos()
|
||||||
local new_velo = {x = 0, y = 0, z = 0}
|
local new_velo = {x = 0, y = 0, z = 0}
|
||||||
local new_acce = {x = 0, y = -9.8, z = 0}
|
local new_acce = {x = 0, y = -9.8, z = 0}
|
||||||
|
|
||||||
|
@ -344,7 +343,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if math.abs(velo.y) < 1 then
|
if math.abs(velo.y) < 1 then
|
||||||
local pos = entity.object:getpos()
|
local pos = entity.object:get_pos()
|
||||||
pos.y = math.floor(pos.y) + 0.5
|
pos.y = math.floor(pos.y) + 0.5
|
||||||
entity.object:setpos(pos)
|
entity.object:setpos(pos)
|
||||||
velo.y = 0
|
velo.y = 0
|
||||||
|
@ -355,7 +354,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
new_velo = get_velocity(v, entity.object:getyaw() - rot_view, velo.y)
|
new_velo = get_velocity(v, entity.object:get_yaw() - rot_view, velo.y)
|
||||||
new_acce.y = new_acce.y + acce_y
|
new_acce.y = new_acce.y + acce_y
|
||||||
|
|
||||||
entity.object:setvelocity(new_velo)
|
entity.object:setvelocity(new_velo)
|
||||||
|
@ -389,7 +388,6 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
|
||||||
local ctrl = entity.driver:get_player_control()
|
local ctrl = entity.driver:get_player_control()
|
||||||
local velo = entity.object:getvelocity()
|
local velo = entity.object:getvelocity()
|
||||||
local dir = entity.driver:get_look_dir()
|
local dir = entity.driver:get_look_dir()
|
||||||
-- local yaw = entity.driver:get_look_yaw()
|
|
||||||
local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
|
local yaw = entity.driver:get_look_horizontal() + 1.57 -- offset fix between old and new commands
|
||||||
local rot_steer, rot_view = math.pi / 2, 0
|
local rot_steer, rot_view = math.pi / 2, 0
|
||||||
|
|
||||||
|
@ -420,7 +418,7 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
|
||||||
-- firing arrows
|
-- firing arrows
|
||||||
if ctrl.LMB and ctrl.sneak and shoots then
|
if ctrl.LMB and ctrl.sneak and shoots then
|
||||||
|
|
||||||
local pos = entity.object:getpos()
|
local pos = entity.object:get_pos()
|
||||||
local obj = minetest.add_entity({
|
local obj = minetest.add_entity({
|
||||||
x = pos.x + 0 + dir.x * 2.5,
|
x = pos.x + 0 + dir.x * 2.5,
|
||||||
y = pos.y + 1.5 + dir.y,
|
y = pos.y + 1.5 + dir.y,
|
||||||
|
@ -431,7 +429,6 @@ function mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim)
|
||||||
ent.switch = 1 -- for mob specific arrows
|
ent.switch = 1 -- for mob specific arrows
|
||||||
ent.owner_id = tostring(entity.object) -- so arrows dont hurt entity you are riding
|
ent.owner_id = tostring(entity.object) -- so arrows dont hurt entity you are riding
|
||||||
local vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
|
local vec = {x = dir.x * 6, y = dir.y * 6, z = dir.z * 6}
|
||||||
-- local yaw = entity.driver:get_look_yaw()
|
|
||||||
local yaw = entity.driver:get_look_horizontal()
|
local yaw = entity.driver:get_look_horizontal()
|
||||||
obj:setyaw(yaw + math.pi / 2)
|
obj:setyaw(yaw + math.pi / 2)
|
||||||
obj:setvelocity(vec)
|
obj:setvelocity(vec)
|
||||||
|
|
|
@ -22,6 +22,9 @@ Lucky Blocks: 9
|
||||||
|
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
- 1.40- Updated to use newer functions, requires Minetest 0.4.16+ to work.
|
||||||
|
- 1.39- Added 'on_breed', 'on_grown' and 'do_punch' custom functions per mob
|
||||||
|
- 1.38- Better entity checking, nametag setting and on_spawn function added to mob registry, tweaked light damage
|
||||||
- 1.37- Added support for Raymoo's CMI (common mob interface) mod: https://forum.minetest.net/viewtopic.php?f=9&t=15448
|
- 1.37- Added support for Raymoo's CMI (common mob interface) mod: https://forum.minetest.net/viewtopic.php?f=9&t=15448
|
||||||
- 1.36- Death check added, if mob dies in fire/lava/with lava pick then drops are cooked
|
- 1.36- Death check added, if mob dies in fire/lava/with lava pick then drops are cooked
|
||||||
- 1.35- Added owner_loyal flag for owned mobs to attack player enemies, also fixed group_attack
|
- 1.35- Added owner_loyal flag for owned mobs to attack player enemies, also fixed group_attack
|
||||||
|
|
Loading…
Reference in New Issue