1
0
mirror of https://codeberg.org/tenplus1/mobs_redo.git synced 2025-07-20 01:00:22 +02:00

Compare commits

...

21 Commits

Author SHA1 Message Date
deee28fc59 added 'arrow_override' function to mob definition 2021-08-01 18:58:21 +01:00
ab44080ff8 do not despawn tamed monsters 2021-07-31 08:35:53 +01:00
9f46182bb4 remove need for default mod 2021-07-22 09:48:56 +01:00
2535b5636e add support for MarkBu's pathfinder mod 2021-07-22 09:34:21 +01:00
2d014a75c4 tweak "stand" mobs velocity 2021-07-21 19:38:41 +01:00
db3831dccf update api.txt 2021-07-14 15:53:20 +01:00
29b2204f7c add 'mobs_spawn_monster_protected' switch (thanks 0siribix) 2021-07-14 15:43:02 +01:00
7fbfd9d59c fix "stand" mobs fall jitter 2021-07-13 16:56:53 +01:00
e50d04a6aa fix facing fence jump bug 2021-06-14 09:30:03 +01:00
33589ebda0 improve pathfinding level 2 digging/building, add infotext, stop mob attack spin, tweak & tidy code 2021-06-13 09:39:59 +01:00
6670938c3d add mob height check for glitching through blocks 2021-06-11 22:25:00 +01:00
f131806008 add 'mob_smooth_rotate' setting 2021-06-01 14:17:25 +01:00
49325c9c8d fix weapon sound selection 2021-05-27 15:42:21 +01:00
8012250258 nil check for mount 2021-05-21 17:46:10 +01:00
ec44aa91c4 add 'damage_group' and 'damage_texture_modifier' settings to mob definition 2021-05-15 09:33:35 +01:00
f58841ab3e show current texture for mob reset stick 2021-05-10 14:57:21 +01:00
350fc3647c add extra settings to arrow definition 2021-05-04 08:02:43 +01:00
70c68f6ebc change so only players can push mobs 2021-04-18 09:05:16 +01:00
c023ecc36f reduce shapeless crafts 2021-04-13 21:09:34 +01:00
9be934ec25 make it possible to use advanced protector on normally protected mob 2021-04-13 12:41:09 +01:00
f6e16a5503 return actual damage position (created particle py), check for nil damage groups 2021-04-11 17:23:22 +01:00
8 changed files with 313 additions and 255 deletions

456
api.lua
View File

@ -8,7 +8,7 @@ local use_cmi = minetest.global_exists("cmi")
mobs = { mobs = {
mod = "redo", mod = "redo",
version = "20210407", version = "20210801",
intllib = S, intllib = S,
invis = minetest.global_exists("invisibility") and invisibility or {} invis = minetest.global_exists("invisibility") and invisibility or {}
} }
@ -28,8 +28,7 @@ local rad = math.rad
local atann = math.atan local atann = math.atan
local atan = function(x) local atan = function(x)
if not x or x ~= x then if not x or x ~= x then
--error("atan bassed NaN") return 0 -- NaN
return 0
else else
return atann(x) return atann(x)
end end
@ -57,6 +56,7 @@ local disable_blood = settings:get_bool("mobs_disable_blood")
local mobs_drop_items = settings:get_bool("mobs_drop_items") ~= false local mobs_drop_items = settings:get_bool("mobs_drop_items") ~= false
local mobs_griefing = settings:get_bool("mobs_griefing") ~= false local mobs_griefing = settings:get_bool("mobs_griefing") ~= false
local spawn_protected = settings:get_bool("mobs_spawn_protected") ~= false local spawn_protected = settings:get_bool("mobs_spawn_protected") ~= false
local spawn_monster_protected = settings:get_bool("mobs_spawn_monster_protected") ~= false
local remove_far = settings:get_bool("remove_far_mobs") ~= false local remove_far = settings:get_bool("remove_far_mobs") ~= false
local mob_area_spawn = settings:get_bool("mob_area_spawn") local mob_area_spawn = settings:get_bool("mob_area_spawn")
local difficulty = tonumber(settings:get("mob_difficulty")) or 1.0 local difficulty = tonumber(settings:get("mob_difficulty")) or 1.0
@ -66,9 +66,9 @@ local mob_nospawn_range = tonumber(settings:get("mob_nospawn_range") or 12)
local active_limit = tonumber(settings:get("mob_active_limit") or 0) local active_limit = tonumber(settings:get("mob_active_limit") or 0)
local mob_chance_multiplier = tonumber(settings:get("mob_chance_multiplier") or 1) local mob_chance_multiplier = tonumber(settings:get("mob_chance_multiplier") or 1)
local peaceful_player_enabled = settings:get_bool("enable_peaceful_player") local peaceful_player_enabled = settings:get_bool("enable_peaceful_player")
local mob_smooth_rotate = settings:get_bool("mob_smooth_rotate") ~= false
local active_mobs = 0 local active_mobs = 0
-- Peaceful mode message so players will know there are no monsters -- Peaceful mode message so players will know there are no monsters
if peaceful_only then if peaceful_only then
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
@ -83,7 +83,7 @@ local aoc_range = tonumber(settings:get("active_block_range")) * 16
-- pathfinding settings -- pathfinding settings
local enable_pathfinding = true local enable_pathfinding = true
local stuck_timeout = 3 -- how long before stuck mod starts searching local stuck_timeout = 3 -- how long before stuck mod starts searching
local stuck_path_timeout = 10 -- how long will mob follow path before giving up local stuck_path_timeout = 5 -- how long will mob follow path before giving up
-- default nodes -- default nodes
local node_fire = "fire:basic_flame" local node_fire = "fire:basic_flame"
@ -224,10 +224,7 @@ function mob_class:collision()
for _,object in ipairs(minetest.get_objects_inside_radius(pos, width)) do for _,object in ipairs(minetest.get_objects_inside_radius(pos, width)) do
if object:is_player() if object:is_player() then
or (object:get_luaentity()
and object:get_luaentity()._cmi_is_mob == true
and object ~= self.object) then
local pos2 = object:get_pos() local pos2 = object:get_pos()
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z} local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
@ -277,7 +274,9 @@ function mob_class:set_velocity(v)
-- halt mob if it has been ordered to stay -- halt mob if it has been ordered to stay
if self.order == "stand" then if self.order == "stand" then
self.object:set_velocity({x = 0, y = 0, z = 0}) local vel = self.object:get_velocity() or {y = 0}
self.object:set_velocity({x = 0, y = vel.y, z = 0})
return return
end end
@ -339,10 +338,12 @@ function mob_class:set_yaw(yaw, delay)
yaw = 0 yaw = 0
end end
delay = delay or 0 delay = mob_smooth_rotate and (delay or 0) or 0
if delay == 0 then if delay == 0 then
self.object:set_yaw(yaw) self.object:set_yaw(yaw)
return yaw return yaw
end end
@ -404,7 +405,6 @@ function mob_class:set_animation(anim, force)
0, self.animation[anim .. "_loop"] ~= false) 0, self.animation[anim .. "_loop"] ~= false)
end end
-- above function exported for mount.lua
function mobs:set_animation(entity, anim) function mobs:set_animation(entity, anim)
entity.set_animation(entity, anim) entity.set_animation(entity, anim)
end end
@ -591,7 +591,7 @@ function mob_class:attempt_flight_correction(override)
local escape_direction = vdirection(pos, escape_target) local escape_direction = vdirection(pos, escape_target)
self.object:set_velocity( self.object:set_velocity(
vmultiply(escape_direction, 1)) --self.run_velocity)) vmultiply(escape_direction, 1))
return true return true
end end
@ -643,7 +643,7 @@ function mobs:yaw_to_pos(self, target, rot)
end end
-- if stay near set then check periodically for nodes and turn towards them -- if stay near set then periodically check for nodes and turn towards them
function mob_class:do_stay_near() function mob_class:do_stay_near()
if not self.stay_near then return false end if not self.stay_near then return false end
@ -740,9 +740,15 @@ function mob_class:update_tag()
col = "#FF0000" col = "#FF0000"
end end
-- build infotext
self.infotext = "Health: " .. self.health .. " / " .. self.hp_max
.. "\n" .. "Owner: " .. self.owner
-- set changes
self.object:set_properties({ self.object:set_properties({
nametag = self.nametag, nametag = self.nametag,
nametag_color = col nametag_color = col,
infotext = self.infotext
}) })
end end
@ -790,10 +796,7 @@ function mob_class:item_drop()
end end
-- only drop rare items (drops.min = 0) if killed by player -- only drop rare items (drops.min = 0) if killed by player
if death_by_player then if death_by_player or self.drops[n].min ~= 0 then
obj = minetest.add_item(pos, ItemStack(item .. " " .. num))
elseif self.drops[n].min ~= 0 then
obj = minetest.add_item(pos, ItemStack(item .. " " .. num)) obj = minetest.add_item(pos, ItemStack(item .. " " .. num))
end end
@ -868,18 +871,17 @@ function mob_class:check_for_death(cmi_cause)
end end
-- backup nametag so we can show health stats -- backup nametag so we can show health stats
if not self.nametag2 then -- if not self.nametag2 then
self.nametag2 = self.nametag or "" -- self.nametag2 = self.nametag or ""
end -- end
if show_health -- if show_health
and (cmi_cause and cmi_cause.type == "punch") then -- and (cmi_cause and cmi_cause.type == "punch") then
self.htimer = 2
self.nametag = "" .. self.health .. " / " .. self.hp_max
-- self.htimer = 2
-- self.nametag = "♥ " .. self.health .. " / " .. self.hp_max
self:update_tag() self:update_tag()
end -- end
return false return false
end end
@ -1049,13 +1051,13 @@ function mob_class:do_env_damage()
end end
-- reset nametag after showing health stats -- reset nametag after showing health stats
if self.htimer < 1 and self.nametag2 then -- if self.htimer < 1 and self.nametag2 then
self.nametag = self.nametag2 -- self.nametag = self.nametag2
self.nametag2 = nil -- self.nametag2 = nil
self:update_tag() self:update_tag()
end -- end
local pos = self.object:get_pos() ; if not pos then return end local pos = self.object:get_pos() ; if not pos then return end
@ -1070,17 +1072,20 @@ function mob_class:do_env_damage()
end end
-- particle appears at random mob height -- particle appears at random mob height
pos.y = pos.y + random(self.collisionbox[2], self.collisionbox[5]) local py = {
x = pos.x,
y = pos.y + random(self.collisionbox[2], self.collisionbox[5]),
z = pos.z
}
local nodef = minetest.registered_nodes[self.standing_in] local nodef = minetest.registered_nodes[self.standing_in]
-- water -- water
if self.water_damage ~= 0 if self.water_damage ~= 0 and nodef.groups.water then
and nodef.groups.water then
self.health = self.health - self.water_damage self.health = self.health - self.water_damage
effect(pos, 5, "bubble.png", nil, nil, 1, nil) effect(py, 5, "bubble.png", nil, nil, 1, nil)
if self:check_for_death({type = "environment", if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then pos = pos, node = self.standing_in}) then
@ -1088,12 +1093,11 @@ function mob_class:do_env_damage()
end end
-- lava damage -- lava damage
elseif self.lava_damage ~= 0 elseif self.lava_damage ~= 0 and nodef.groups.lava then
and nodef.groups.lava then
self.health = self.health - self.lava_damage self.health = self.health - self.lava_damage
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true) effect(py, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
if self:check_for_death({type = "environment", pos = pos, if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then node = self.standing_in, hot = true}) then
@ -1101,12 +1105,11 @@ function mob_class:do_env_damage()
end end
-- fire damage -- fire damage
elseif self.fire_damage ~= 0 elseif self.fire_damage ~= 0 and nodef.groups.fire then
and nodef.groups.fire then
self.health = self.health - self.fire_damage self.health = self.health - self.fire_damage
effect(pos, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true) effect(py, 15, "fire_basic_flame.png", 1, 5, 1, 0.2, 15, true)
if self:check_for_death({type = "environment", pos = pos, if self:check_for_death({type = "environment", pos = pos,
node = self.standing_in, hot = true}) then node = self.standing_in, hot = true}) then
@ -1115,11 +1118,11 @@ function mob_class:do_env_damage()
-- damage_per_second node check (not fire and lava) -- damage_per_second node check (not fire and lava)
elseif nodef.damage_per_second ~= 0 elseif nodef.damage_per_second ~= 0
and nodef.groups.lava == 0 and nodef.groups.fire == 0 then and nodef.groups.lava == nil and nodef.groups.fire == nil then
self.health = self.health - nodef.damage_per_second self.health = self.health - nodef.damage_per_second
effect(pos, 5, "tnt_smoke.png") effect(py, 5, "tnt_smoke.png")
if self:check_for_death({type = "environment", if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then pos = pos, node = self.standing_in}) then
@ -1132,7 +1135,7 @@ function mob_class:do_env_damage()
self.health = self.health - self.air_damage self.health = self.health - self.air_damage
effect(pos, 3, "bubble.png", 1, 1, 1, 0.2) effect(py, 3, "bubble.png", 1, 1, 1, 0.2)
if self:check_for_death({type = "environment", if self:check_for_death({type = "environment",
pos = pos, node = self.standing_in}) then pos = pos, node = self.standing_in}) then
@ -1150,7 +1153,7 @@ function mob_class:do_env_damage()
self.health = self.health - self.light_damage self.health = self.health - self.light_damage
effect(pos, 5, "tnt_smoke.png") effect(py, 5, "tnt_smoke.png")
if self:check_for_death({type = "light"}) then if self:check_for_death({type = "light"}) then
return true return true
@ -1235,58 +1238,58 @@ function mob_class:do_jump()
local blocked = minetest.registered_nodes[nodt.name].walkable local blocked = minetest.registered_nodes[nodt.name].walkable
--print("standing on:", self.standing_on, pos.y - 0.25) -- are we facing a fence or wall
--print("in front:", nod.name, pos.y + 0.5) if nod.name:find("fence") or nod.name:find("gate") or nod.name:find("wall") then
--print("in front above:", nodt.name, pos.y + 1.5) self.facing_fence = true
end
--[[
print("on: " .. self.standing_on
.. ", front: " .. nod.name
.. ", front above: " .. nodt.name
.. ", blocked: " .. (blocked and "yes" or "no")
.. ", fence: " .. (self.facing_fence and "yes" or "no")
)
]]
-- jump if standing on solid node (not snow) and not blocked
if (self.walk_chance == 0 or minetest.registered_items[nod.name].walkable)
and not blocked and not self.facing_fence and nod.name ~= node_snow then
-- jump if standing on solid node (not snow) and not blocked above local v = self.object:get_velocity()
if (self.walk_chance == 0
or minetest.registered_items[nod.name].walkable)
and not blocked
and nod.name ~= node_snow then
if not nod.name:find("fence") v.y = self.jump_height
and not nod.name:find("gate")
and not nod.name:find("wall") then
local v = self.object:get_velocity() self:set_animation("jump") -- only when defined
v.y = self.jump_height self.object:set_velocity(v)
self:set_animation("jump") -- only when defined -- when in air move forward
minetest.after(0.3, function(self, v)
self.object:set_velocity(v) if self.object:get_luaentity() then
-- when in air move forward self.object:set_acceleration({
minetest.after(0.3, function(self, v) x = v.x * 2,
y = 0,
if self.object:get_luaentity() then z = v.z * 2
})
self.object:set_acceleration({
x = v.x * 2,
y = 0,
z = v.z * 2
})
end
end, self, v)
if self:get_velocity() > 0 then
self:mob_sound(self.sounds.jump)
end end
end, self, v)
return true if self:get_velocity() > 0 then
else self:mob_sound(self.sounds.jump)
self.facing_fence = true
end end
self.jump_count = 0
return true
end end
-- if blocked against a block/wall for 5 counts then turn -- if blocked for 3 counts then turn
if not self.following if not self.following and (self.facing_fence or blocked) then
and (self.facing_fence or blocked) then
self.jump_count = (self.jump_count or 0) + 1 self.jump_count = (self.jump_count or 0) + 1
if self.jump_count > 4 then if self.jump_count > 2 then
local yaw = self.object:get_yaw() or 0 local yaw = self.object:get_yaw() or 0
local turn = random(0, 2) + 1.35 local turn = random(0, 2) + 1.35
@ -1357,7 +1360,7 @@ end
-- Thanks Wuzzy for the following editable settings -- Thanks Wuzzy for the following editable settings
local HORNY_TIME = 30 local HORNY_TIME = 30
local HORNY_AGAIN_TIME = 300 local HORNY_AGAIN_TIME = 60 * 5 -- 5 minutes
local CHILD_GROW_TIME = 60 * 20 -- 20 minutes local CHILD_GROW_TIME = 60 * 20 -- 20 minutes
-- find two animals of same type and breed if nearby and horny -- find two animals of same type and breed if nearby and horny
@ -1385,16 +1388,15 @@ function mob_class:breed()
if self.on_grown then if self.on_grown then
self.on_grown(self) self.on_grown(self)
else else
-- jump when fully grown so as not to fall into ground
-- self.object:set_velocity({
-- x = 0,
-- y = self.jump_height,
-- z = 0
-- })
local pos = self.object:get_pos() ; if not pos then return end local pos = self.object:get_pos() ; if not pos then return end
local ent = self.object:get_luaentity() local ent = self.object:get_luaentity()
pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4 pos.y = pos.y + (ent.collisionbox[2] * -1) - 0.4
self.object:set_pos(pos) self.object:set_pos(pos)
-- jump slightly when fully grown so as not to fall into ground
self.object:set_velocity({x = 0, y = 0.5, z = 0 })
end end
end end
@ -1617,7 +1619,43 @@ end
local los_switcher = false local los_switcher = false
local height_switcher = false local height_switcher = false
local can_dig_drop = function(pos)
if minetest.is_protected(pos, "") then
return false
end
local node = node_ok(pos, "air").name
local ndef = minetest.registered_nodes[node]
if node ~= "ignore"
and ndef
and ndef.drawtype ~= "airlike"
and not ndef.groups.level
and not ndef.groups.unbreakable
and not ndef.groups.liquid then
local drops = minetest.get_node_drops(node)
for _, item in ipairs(drops) do
minetest.add_item({
x = pos.x - 0.5 + random(),
y = pos.y - 0.5 + random(),
z = pos.z - 0.5 + random()
}, item)
end
minetest.remove_node(pos)
return true
end
return false
end
local pathfinder_mod = minetest.get_modpath("pathfinder")
-- path finding and smart mob routine by rnd, -- path finding and smart mob routine by rnd,
-- line_of_sight and other edits by Elkien3 -- line_of_sight and other edits by Elkien3
function mob_class:smart_mobs(s, p, dist, dtime) function mob_class:smart_mobs(s, p, dist, dtime)
@ -1746,13 +1784,18 @@ function mob_class:smart_mobs(s, p, dist, dtime)
jumpheight = 1 jumpheight = 1
end end
self.path.way = minetest.find_path(s, p1, 16, jumpheight, if pathfinder_mod then
dropheight, "Dijkstra") self.path.way = pathfinder.find_path(s, p1, self, dtime)
else
self.path.way = minetest.find_path(s, p1, 16, jumpheight,
dropheight, "Dijkstra")
end
--[[ --[[
-- show path using particles -- show path using particles
if self.path.way and #self.path.way > 0 then if self.path.way and #self.path.way > 0 then
print("-- path length:" .. tonumber(#self.path.way)) print("-- path length:" .. tonumber(#self.path.way))
for _,pos in pairs(self.path.way) do for _,pos in pairs(self.path.way) do
minetest.add_particle({ minetest.add_particle({
pos = pos, pos = pos,
@ -1782,8 +1825,8 @@ function mob_class:smart_mobs(s, p, dist, dtime)
-- lets make way by digging/building if not accessible -- lets make way by digging/building if not accessible
if self.pathfinding == 2 and mobs_griefing then if self.pathfinding == 2 and mobs_griefing then
-- is player higher than mob? -- is player more than 1 block higher than mob?
if s.y < p1.y then if p1.y > (s.y + 1) then
-- build upwards -- build upwards
if not minetest.is_protected(s, "") then if not minetest.is_protected(s, "") then
@ -1791,8 +1834,7 @@ function mob_class:smart_mobs(s, p, dist, dtime)
local ndef1 = minetest.registered_nodes[self.standing_in] local ndef1 = minetest.registered_nodes[self.standing_in]
if ndef1 and (ndef1.buildable_to or ndef1.groups.liquid) then if ndef1 and (ndef1.buildable_to or ndef1.groups.liquid) then
minetest.set_node(s, {name = mobs.fallback_node})
minetest.set_node(s, {name = mobs.fallback_node})
end end
end end
@ -1802,27 +1844,19 @@ function mob_class:smart_mobs(s, p, dist, dtime)
s.y = s.y + sheight s.y = s.y + sheight
-- remove one block above to make room to jump -- remove one block above to make room to jump
if not minetest.is_protected(s, "") then can_dig_drop(s)
local node1 = node_ok(s, "air").name
local ndef1 = minetest.registered_nodes[node1]
if node1 ~= "air"
and node1 ~= "ignore"
and ndef1
and not ndef1.groups.level
and not ndef1.groups.unbreakable
and not ndef1.groups.liquid then
minetest.set_node(s, {name = "air"})
minetest.add_item(s, ItemStack(node1))
end
end
s.y = s.y - sheight s.y = s.y - sheight
self.object:set_pos({x = s.x, y = s.y + 2, z = s.z}) self.object:set_pos({x = s.x, y = s.y + 2, z = s.z})
-- is player more than 1 block lower than mob
elseif p1.y < (s.y - 1) then
-- dig down
s.y = s.y - self.collisionbox[4] - 0.2
can_dig_drop(s)
else -- dig 2 blocks to make door toward player direction else -- dig 2 blocks to make door toward player direction
local yaw1 = self.object:get_yaw() + pi / 2 local yaw1 = self.object:get_yaw() + pi / 2
@ -1832,37 +1866,12 @@ function mob_class:smart_mobs(s, p, dist, dtime)
z = s.z + sin(yaw1) z = s.z + sin(yaw1)
} }
if not minetest.is_protected(p1, "") then -- dig bottom node first incase of door
can_dig_drop(p1)
local node1 = node_ok(p1, "air").name p1.y = p1.y + 1
local ndef1 = minetest.registered_nodes[node1]
if node1 ~= "air" can_dig_drop(p1)
and node1 ~= "ignore"
and ndef1
and not ndef1.groups.level
and not ndef1.groups.unbreakable
and not ndef1.groups.liquid then
minetest.add_item(p1, ItemStack(node1))
minetest.set_node(p1, {name = "air"})
end
p1.y = p1.y + 1
node1 = node_ok(p1, "air").name
ndef1 = minetest.registered_nodes[node1]
if node1 ~= "air"
and node1 ~= "ignore"
and ndef1
and not ndef1.groups.level
and not ndef1.groups.unbreakable
and not ndef1.groups.liquid then
minetest.add_item(p1, ItemStack(node1))
minetest.set_node(p1, {name = "air"})
end
end
end end
end end
@ -2594,7 +2603,10 @@ function mob_class:do_states(dtime)
self:smart_mobs(s, p, dist, dtime) self:smart_mobs(s, p, dist, dtime)
end end
if self.at_cliff then -- distance padding to stop spinning mob
local pad = abs(p.x - s.x) + abs(p.z - s.z)
if self.at_cliff or pad < 0.2 then
self:set_velocity(0) self:set_velocity(0)
self:set_animation("stand") self:set_animation("stand")
@ -2612,7 +2624,6 @@ function mob_class:do_states(dtime)
self:set_animation("walk") self:set_animation("walk")
end end
end end
else -- rnd: if inside reach range else -- rnd: if inside reach range
self.path.stuck = false self.path.stuck = false
@ -2648,9 +2659,11 @@ function mob_class:do_states(dtime)
self.attack = attached self.attack = attached
end end
local dgroup = self.damage_group or "fleshy"
self.attack:punch(self.object, 1.0, { self.attack:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = self.damage} damage_groups = {[dgroup] = self.damage}
}, nil) }, nil)
end end
end end
@ -2690,6 +2703,12 @@ function mob_class:do_states(dtime)
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()
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
-- check for custom override for arrow
if self.arrow_override then
self.arrow_override(ent)
end
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
@ -2757,11 +2776,7 @@ function mob_class:falling(pos)
end end
-- fall at set speed -- fall at set speed
self.object:set_acceleration({ self.object:set_acceleration({x = 0, y = fall_speed, z = 0})
x = 0,
y = fall_speed,
z = 0
})
end end
@ -2784,8 +2799,9 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
-- error checking when mod profiling is enabled -- error checking when mod profiling is enabled
if not tool_capabilities then if not tool_capabilities then
minetest.log("warning",
"[mobs] Mod profiling enabled, damage not enabled") minetest.log("warning", "[mobs] Mod profiling enabled, damage not enabled")
return true return true
end end
@ -2861,6 +2877,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
if self.immune_to[n][1] == weapon_def.name then if self.immune_to[n][1] == weapon_def.name then
damage = self.immune_to[n][2] or 0 damage = self.immune_to[n][2] or 0
break break
-- if "all" then no tools deal damage unless it's specified in list -- if "all" then no tools deal damage unless it's specified in list
@ -2873,13 +2890,14 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
-- healing -- healing
if damage <= -1 then if damage <= -1 then
self.health = self.health - floor(damage) self.health = self.health - floor(damage)
return true return true
end end
if use_cmi if use_cmi
and cmi.notify_punch( and cmi.notify_punch(self.object, hitter, tflp, tool_capabilities, dir, damage) then
self.object, hitter, tflp, tool_capabilities, dir, damage) then
return true return true
end end
@ -2898,10 +2916,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
end end
end end
if tr then if tr and weapon_def.original_description then
if weapon_def.original_description then toolranks.new_afteruse(weapon, hitter, nil, {wear = wear})
toolranks.new_afteruse(weapon, hitter, nil, {wear = wear})
end
else else
weapon:add_wear(wear) weapon:add_wear(wear)
end end
@ -2911,21 +2927,11 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
-- only play hit sound and show blood effects if damage is 1 or over -- only play hit sound and show blood effects if damage is 1 or over
if damage >= 1 then if damage >= 1 then
-- weapon sounds -- select tool use sound if found, or fallback to default
if weapon_def.sounds then local snd = weapon_def.sound and weapon_def.sound.use
or "default_punch"
local s = random(0, #weapon_def.sounds) minetest.sound_play(snd, {object = self.object, max_hear_distance = 8}, true)
minetest.sound_play(weapon_def.sounds[s], {
object = self.object,
max_hear_distance = 8
}, true)
else
minetest.sound_play("default_punch", {
object = self.object,
max_hear_distance = 5
}, true)
end
-- blood_particles -- blood_particles
if not disable_blood and self.blood_amount > 0 then if not disable_blood and self.blood_amount > 0 then
@ -2934,8 +2940,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
local blood = self.blood_texture local blood = self.blood_texture
local amount = self.blood_amount local amount = self.blood_amount
pos.y = pos.y + (-self.collisionbox[2] pos.y = pos.y + (-self.collisionbox[2] + self.collisionbox[5]) * .5
+ self.collisionbox[5]) * .5
-- lots of damage = more blood :) -- lots of damage = more blood :)
if damage > 10 then if damage > 10 then
@ -2948,7 +2953,6 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
end end
effect(pos, amount, blood, 1, 2, 1.75, nil, nil, true) effect(pos, amount, blood, 1, 2, 1.75, nil, nil, true)
end end
-- do damage -- do damage
@ -2958,29 +2962,13 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
local hot = tool_capabilities and tool_capabilities.damage_groups local hot = tool_capabilities and tool_capabilities.damage_groups
and tool_capabilities.damage_groups.fire and tool_capabilities.damage_groups.fire
if self:check_for_death({type = "punch", if self:check_for_death({type = "punch", puncher = hitter, hot = hot}) then
puncher = hitter, hot = hot}) then
return true return true
end end
--[[ add healthy afterglow when hit (causes lag with large textures)
minetest.after(0.1, function()
if not self.object:get_luaentity() then return end
self.object:set_texture_mod("^[colorize:#c9900070")
minetest.after(0.3, function()
if not self.object:get_luaentity() then return end
self.object:set_texture_mod(self.texture_mods)
end)
end) ]]
end -- END if damage end -- END if damage
-- knock back effect (only on full punch) -- knock back effect (only on full punch)
if self.knock_back if self.knock_back and tflp >= punch_interval then
and tflp >= punch_interval then
local v = self.object:get_velocity() local v = self.object:get_velocity()
@ -3002,11 +2990,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir, damage)
-- use tool knockback value or default -- use tool knockback value or default
kb = tool_capabilities.damage_groups["knockback"] or kb kb = tool_capabilities.damage_groups["knockback"] or kb
self.object:set_velocity({ self.object:set_velocity({x = dir.x * kb, y = up, z = dir.z * kb})
x = dir.x * kb,
y = up,
z = dir.z * kb
})
self.pause_timer = 0.25 self.pause_timer = 0.25
end end
@ -3253,10 +3237,8 @@ function mob_class:mob_activate(staticdata, def, dtime)
local armor local armor
if type(self.armor) == "table" then if type(self.armor) == "table" then
armor = table_copy(self.armor) armor = table_copy(self.armor)
-- armor.immortal = 1
else else
-- armor = {immortal = 1, fleshy = self.armor} armor = {fleshy = self.armor} -- immortal = 1
armor = {fleshy = self.armor}
end end
self.object:set_armor_groups(armor) self.object:set_armor_groups(armor)
@ -3287,7 +3269,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
self.object:set_texture_mod(self.texture_mods) self.object:set_texture_mod(self.texture_mods)
-- set 5.x flag to remove monsters when map area unloaded -- set 5.x flag to remove monsters when map area unloaded
if remove_far and self.type == "monster" then if remove_far and self.type == "monster" and not self.tamed then
self.static_save = false self.static_save = false
end end
@ -3354,23 +3336,7 @@ end
-- main mob function -- main mob function
function mob_class:on_step(dtime, moveresult) function mob_class:on_step(dtime, moveresult)
--[[ moveresult contains this for physical mobs if self.state == "die" then return end
{
touching_ground = boolean,
collides = boolean,
standing_on_object = boolean,
collisions = {
{
type = string, -- "node" or "object",
axis = string, -- "x", "y" or "z"
node_pos = vector, -- if type is "node"
object = ObjectRef, -- if type is "object"
old_velocity = vector,
new_velocity = vector,
}}
}]]
if self.state == "die" then return end ----------------
if use_cmi then if use_cmi then
cmi.notify_step(self.object, dtime) cmi.notify_step(self.object, dtime)
@ -3559,6 +3525,13 @@ function mobs:register_mob(name, def)
mobs.spawning_mobs[name] = {} mobs.spawning_mobs[name] = {}
local collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25}
-- quick fix to stop mobs glitching through nodes if too small
if -collisionbox[2] + collisionbox[5] < 1.01 then
collisionbox[5] = collisionbox[2] + 0.99
end
minetest.register_entity(name, setmetatable({ minetest.register_entity(name, setmetatable({
stepheight = def.stepheight, stepheight = def.stepheight,
@ -3580,8 +3553,8 @@ minetest.register_entity(name, setmetatable({
lifetimer = def.lifetimer, lifetimer = def.lifetimer,
hp_min = max(1, (def.hp_min or 5) * difficulty), hp_min = max(1, (def.hp_min or 5) * difficulty),
hp_max = max(1, (def.hp_max or 10) * difficulty), hp_max = max(1, (def.hp_max or 10) * difficulty),
collisionbox = def.collisionbox, collisionbox = collisionbox, --def.collisionbox,
selectionbox = def.selectionbox or def.collisionbox, selectionbox = def.selectionbox or collisionbox, --def.collisionbox,
visual = def.visual, visual = def.visual,
visual_size = def.visual_size, visual_size = def.visual_size,
mesh = def.mesh, mesh = def.mesh,
@ -3590,6 +3563,8 @@ minetest.register_entity(name, setmetatable({
walk_velocity = def.walk_velocity, walk_velocity = def.walk_velocity,
run_velocity = def.run_velocity, run_velocity = def.run_velocity,
damage = max(0, (def.damage or 0) * difficulty), damage = max(0, (def.damage or 0) * difficulty),
damage_group = def.damage_group,
damage_texture_modifier = def.damage_texture_modifier,
light_damage = def.light_damage, light_damage = def.light_damage,
light_damage_min = def.light_damage_min, light_damage_min = def.light_damage_min,
light_damage_max = def.light_damage_max, light_damage_max = def.light_damage_max,
@ -3604,6 +3579,7 @@ minetest.register_entity(name, setmetatable({
armor = def.armor, armor = def.armor,
on_rightclick = def.on_rightclick, on_rightclick = def.on_rightclick,
arrow = def.arrow, arrow = def.arrow,
arrow_override = def.arrow_override,
shoot_interval = def.shoot_interval, shoot_interval = def.shoot_interval,
sounds = def.sounds, sounds = def.sounds,
animation = def.animation, animation = def.animation,
@ -3887,11 +3863,13 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
local numbers = settings:get(name) local numbers = settings:get(name)
if numbers then if numbers then
numbers = numbers:split(",") numbers = numbers:split(",")
chance = tonumber(numbers[1]) or chance chance = tonumber(numbers[1]) or chance
aoc = tonumber(numbers[2]) or aoc aoc = tonumber(numbers[2]) or aoc
if chance == 0 then if chance == 0 then
minetest.log("warning", minetest.log("warning",
string.format("[mobs] %s has spawning disabled", name)) string.format("[mobs] %s has spawning disabled", name))
return return
@ -3995,8 +3973,10 @@ function mobs:spawn_specific(name, nodes, neighbors, min_light, max_light, inter
return return
end end
-- mobs cannot spawn in protected areas when enabled -- check if mob can spawn inside protected areas
if not spawn_protected if (spawn_protected == false
or (spawn_monster_protected == false
and minetest.registered_entities[name].type == "monster"))
and minetest.is_protected(pos, "") then and minetest.is_protected(pos, "") then
--print("--- inside protected area", name) --print("--- inside protected area", name)
return return
@ -4123,7 +4103,10 @@ function mobs:register_arrow(name, def)
minetest.register_entity(name, { minetest.register_entity(name, {
physical = false, physical = def.physical or false,
collide_with_objects = def.collide_with_objects or false,
static_save = false,
visual = def.visual, visual = def.visual,
visual_size = def.visual_size, visual_size = def.visual_size,
textures = def.textures, textures = def.textures,
@ -4282,7 +4265,7 @@ function mobs:boom(self, pos, radius)
radius = radius, radius = radius,
damage_radius = radius, damage_radius = radius,
sound = self.sounds and self.sounds.explode, sound = self.sounds and self.sounds.explode,
explode_center = true, explode_center = true
}) })
else else
mobs:safe_boom(self, pos, radius) mobs:safe_boom(self, pos, radius)
@ -4614,7 +4597,8 @@ function mobs:protect(self, clicker)
return true return true
end end
if self.protected then if (self.protected and tool_name == "mobs:protector")
or (self.protected == 2 and tool_name == "mobs:protector2") then
minetest.chat_send_player(name, S("Already protected!")) minetest.chat_send_player(name, S("Already protected!"))
return true return true
end end
@ -4671,14 +4655,14 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
self.health = self.hp_max self.health = self.hp_max
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
end end
self.object:set_hp(self.health) self.object:set_hp(self.health)
@ -4716,6 +4700,7 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
end end
self.tamed = true self.tamed = true
self.static_save = true
if not self.owner or self.owner == "" then if not self.owner or self.owner == "" then
self.owner = clicker:get_player_name() self.owner = clicker:get_player_name()
@ -4820,14 +4805,13 @@ function mobs:alias_mob(old_name, new_name)
-- entity -- entity
minetest.register_entity(":" .. old_name, { minetest.register_entity(":" .. old_name, {
physical = false, physical = false, static_save = false,
on_activate = function(self, staticdata) on_activate = function(self, staticdata)
if minetest.registered_entities[new_name] then if minetest.registered_entities[new_name] then
minetest.add_entity(self.object:get_pos(), minetest.add_entity(self.object:get_pos(), new_name, staticdata)
new_name, staticdata)
end end
remove_mob(self) remove_mob(self)

View File

@ -56,6 +56,8 @@ functions needed for the mob to work properly which contains the following:
'view_range' how many nodes in distance the mob can see a player. 'view_range' how many nodes in distance the mob can see a player.
'damage' how many health points the mob does to a player or another 'damage' how many health points the mob does to a player or another
mob when melee attacking. mob when melee attacking.
'damage_group' group in which damage is dealt, dedaults to "fleshy".
'damage_texture_modifier' applies texture modifier on hit e.g "^[brighten"
'knock_back' when true has mobs falling backwards when hit, the greater 'knock_back' when true has mobs falling backwards when hit, the greater
the damage the more they move back. the damage the more they move back.
'fear_height' is how high a cliff or edge has to be before the mob stops 'fear_height' is how high a cliff or edge has to be before the mob stops
@ -121,6 +123,8 @@ functions needed for the mob to work properly which contains the following:
continue chasing. continue chasing.
'arrow' holds the pre-defined arrow object to shoot when 'arrow' holds the pre-defined arrow object to shoot when
attacking. attacking.
'arrow_override' function that allows tweaking of arrow entity from
inside mob definition (self) passed to function.
'dogshoot_switch' allows switching between attack types by using timers 'dogshoot_switch' allows switching between attack types by using timers
(1 for shoot, 2 for dogfight) (1 for shoot, 2 for dogfight)
'dogshoot_count_max' contains how many seconds before switching from 'dogshoot_count_max' contains how many seconds before switching from
@ -465,6 +469,8 @@ This function registers a arrow for mobs with the attack type shoot.
'visual' same is in minetest.register_entity() 'visual' same is in minetest.register_entity()
'visual_size' same is in minetest.register_entity() 'visual_size' same is in minetest.register_entity()
'textures' same is in minetest.register_entity() 'textures' same is in minetest.register_entity()
'physical' same is in minetest.register_entity() [default: false]
'collide_with_objects' same as above
'velocity' the velocity of the arrow 'velocity' the velocity of the arrow
'drop' if set to true any arrows hitting a node will drop as item '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; 'hit_player' a function that is called when the arrow hits a player;
@ -695,6 +701,8 @@ External Settings for "minetest.conf"
is false) is false)
'mobs_spawn_protected' if set to false then mobs will not spawn in protected 'mobs_spawn_protected' if set to false then mobs will not spawn in protected
areas (default is true) areas (default is true)
'mobs_spawn_monster_protected' if set to false then monsters will not spawn in
protected areas (default is true)
'remove_far_mobs' if true then untamed mobs that are outside players 'remove_far_mobs' if true then untamed mobs that are outside players
visual range will be removed (default is true) visual range will be removed (default is true)
'mobname' can change specific mob chance rate (0 to disable) and 'mobname' can change specific mob chance rate (0 to disable) and
@ -718,6 +726,7 @@ External Settings for "minetest.conf"
'mob_area_spawn' When true will check surrounding area the size of the 'mob_area_spawn' When true will check surrounding area the size of the
mob for obstructions before spawning, otherwise it mob for obstructions before spawning, otherwise it
defaults to checking the height of the mob only. defaults to checking the height of the mob only.
'mob_smooth_rotate' Enables smooth rotation when mobs turn by default.
Players can override the spawn chance for each mob registered by adding a line 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 to their minetest.conf file with a new value, the lower the value the more each

View File

@ -10,9 +10,8 @@ minetest.register_craftitem("mobs:nametag", {
if minetest.get_modpath("dye") and minetest.get_modpath("farming") then if minetest.get_modpath("dye") and minetest.get_modpath("farming") then
minetest.register_craft({ minetest.register_craft({
type = "shapeless",
output = "mobs:nametag", output = "mobs:nametag",
recipe = {"default:paper", "dye:black", "farming:string"} recipe = {{"default:paper", "dye:black", "farming:string"}}
}) })
end end
@ -149,7 +148,7 @@ minetest.register_craft({
-- make sure we can register fences -- make sure we can register fences
if default.register_fence then if minetest.get_modpath("default") and default.register_fence then
-- mob fence (looks like normal fence but collision is 2 high) -- mob fence (looks like normal fence but collision is 2 high)
default.register_fence("mobs:fence_wood", { default.register_fence("mobs:fence_wood", {
@ -165,6 +164,7 @@ default.register_fence("mobs:fence_wood", {
} }
} }
}) })
end
-- mob fence top (has enlarged collisionbox to stop mobs getting over) -- mob fence top (has enlarged collisionbox to stop mobs getting over)
minetest.register_node("mobs:fence_top", { minetest.register_node("mobs:fence_top", {
@ -197,8 +197,6 @@ minetest.register_craft({
} }
}) })
end
-- items that can be used as fuel -- items that can be used as fuel
minetest.register_craft({ minetest.register_craft({
@ -299,12 +297,18 @@ minetest.register_tool(":mobs:mob_reset_stick", {
tex_obj = obj tex_obj = obj
-- get base texture
local bt = tex_obj:get_luaentity().base_texture[1]
if type(bt) ~= "string" then
bt = ""
end
local name = user:get_player_name() local name = user:get_player_name()
local tex = ""
minetest.show_formspec(name, "mobs_texture", "size[8,4]" minetest.show_formspec(name, "mobs_texture", "size[8,4]"
.. "field[0.5,1;7.5,0;name;" .. "field[0.5,1;7.5,0;name;"
.. minetest.formspec_escape(S("Enter texture:")) .. ";" .. tex .. "]" .. minetest.formspec_escape(S("Enter texture:")) .. ";" .. bt .. "]"
.. "button_exit[2.5,3.5;3,1;mob_texture_change;" .. "button_exit[2.5,3.5;3,1;mob_texture_change;"
.. minetest.formspec_escape(S("Change")) .. "]") .. minetest.formspec_escape(S("Change")) .. "]")
end end
@ -355,17 +359,17 @@ minetest.register_node("mobs:meatblock", {
tiles = {"mobs_meat_top.png", "mobs_meat_bottom.png", "mobs_meat_side.png"}, tiles = {"mobs_meat_top.png", "mobs_meat_bottom.png", "mobs_meat_side.png"},
paramtype2 = "facedir", paramtype2 = "facedir",
groups = {choppy = 1, oddly_breakable_by_hand = 1, flammable = 2}, groups = {choppy = 1, oddly_breakable_by_hand = 1, flammable = 2},
sounds = default.node_sound_leaves_defaults(), sounds = default and default.node_sound_leaves_defaults(),
on_place = minetest.rotate_node, on_place = minetest.rotate_node,
on_use = minetest.item_eat(20), on_use = minetest.item_eat(20)
}) })
minetest.register_craft({ minetest.register_craft({
output = "mobs:meatblock", output = "mobs:meatblock",
type = "shapeless", -- type = "shapeless",
recipe = { recipe = {
"group:food_meat", "group:food_meat", "group:food_meat", {"group:food_meat", "group:food_meat", "group:food_meat"},
"group:food_meat", "group:food_meat", "group:food_meat", {"group:food_meat", "group:food_meat", "group:food_meat"},
"group:food_meat", "group:food_meat", "group:food_meat" {"group:food_meat", "group:food_meat", "group:food_meat"}
} }
}) })

View File

@ -1,4 +1,4 @@
default default?
tnt? tnt?
dye? dye?
farming? farming?
@ -7,3 +7,4 @@ intllib?
lucky_block? lucky_block?
cmi? cmi?
toolranks? toolranks?
pathfinder?

View File

@ -1,4 +1,4 @@
name = mobs name = mobs
depends = default depends =
optional_depends = tnt, dye, farming, invisibility, intllib, lucky_block, cmi, toolranks optional_depends = default, tnt, dye, farming, invisibility, intllib, lucky_block, cmi, toolranks, pathfinder
description = Adds a mob api for mods to add animals or monsters etc. description = Adds a mob api for mods to add animals or monsters etc.

View File

@ -22,6 +22,7 @@ end
local function node_is(pos) local function node_is(pos)
local node = node_ok(pos) local node = node_ok(pos)
if node.name == "air" then if node.name == "air" then
@ -69,6 +70,7 @@ end
local function force_detach(player) local function force_detach(player)
local attached_to = player:get_attach() local attached_to = player:get_attach()
if not attached_to then if not attached_to then
@ -97,7 +99,9 @@ minetest.register_on_leaveplayer(function(player)
end) end)
minetest.register_on_shutdown(function() minetest.register_on_shutdown(function()
local players = minetest.get_connected_players() local players = minetest.get_connected_players()
for i = 1, #players do for i = 1, #players do
force_detach(players[i]) force_detach(players[i])
end end
@ -112,6 +116,7 @@ end)
-- Just for correct detaching -- Just for correct detaching
local function find_free_pos(pos) local function find_free_pos(pos)
local check = { local check = {
{x = 1, y = 0, z = 0}, {x = 1, y = 0, z = 0},
{x = 1, y = 1, z = 0}, {x = 1, y = 1, z = 0},
@ -124,10 +129,14 @@ local function find_free_pos(pos)
} }
for _, c in pairs(check) do for _, c in pairs(check) do
local npos = {x = pos.x + c.x, y = pos.y + c.y, z = pos.z + c.z} local npos = {x = pos.x + c.x, y = pos.y + c.y, z = pos.z + c.z}
local node = minetest.get_node_or_nil(npos) local node = minetest.get_node_or_nil(npos)
if node and node.name then if node and node.name then
local def = minetest.registered_nodes[node.name] local def = minetest.registered_nodes[node.name]
if def and not def.walkable and if def and not def.walkable and
def.liquidtype == "none" then def.liquidtype == "none" then
return npos return npos
@ -141,6 +150,7 @@ end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
function mobs.attach(entity, player) function mobs.attach(entity, player)
entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0} entity.player_rotation = entity.player_rotation or {x = 0, y = 0, z = 0}
entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0} entity.driver_attach_at = entity.driver_attach_at or {x = 0, y = 0, z = 0}
entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0} entity.driver_eye_offset = entity.driver_eye_offset or {x = 0, y = 0, z = 0}
@ -154,6 +164,7 @@ function mobs.attach(entity, player)
local attach_at = entity.driver_attach_at local attach_at = entity.driver_attach_at
local eye_offset = entity.driver_eye_offset local eye_offset = entity.driver_eye_offset
entity.driver = player entity.driver = player
force_detach(player) force_detach(player)
@ -170,6 +181,7 @@ function mobs.attach(entity, player)
}) })
minetest.after(0.2, function() minetest.after(0.2, function()
if player and player:is_player() then if player and player:is_player() then
player_api.set_animation(player, "sit", 30) player_api.set_animation(player, "sit", 30)
end end
@ -183,9 +195,13 @@ function mobs.detach(player)
force_detach(player) force_detach(player)
minetest.after(0.1, function() minetest.after(0.1, function()
if player and player:is_player() then if player and player:is_player() then
local pos = find_free_pos(player:get_pos()) local pos = find_free_pos(player:get_pos())
pos.y = pos.y + 0.5 pos.y = pos.y + 0.5
player:set_pos(pos) player:set_pos(pos)
end end
end) end)
@ -193,8 +209,8 @@ end
function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
local yaw = entity.object:get_yaw() or 0
local yaw = entity.object:get_yaw() or 0
local rot_view = 0 local rot_view = 0
if entity.player_rotation.y == 90 then if entity.player_rotation.y == 90 then
@ -208,14 +224,17 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- process controls -- process controls
if entity.driver then if entity.driver then
local ctrl = entity.driver:get_player_control() local ctrl = entity.driver:get_player_control()
-- move forwards -- move forwards
if ctrl.up then if ctrl.up then
entity.v = entity.v + entity.accel / 10 entity.v = entity.v + entity.accel / 10
-- move backwards -- move backwards
elseif ctrl.down then elseif ctrl.down then
if entity.max_speed_reverse == 0 and entity.v == 0 then if entity.max_speed_reverse == 0 and entity.v == 0 then
return return
end end
@ -225,7 +244,9 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- mob rotation -- mob rotation
local horz local horz
if entity.alt_turn == true then if entity.alt_turn == true then
horz = yaw horz = yaw
if ctrl.left then if ctrl.left then
@ -243,21 +264,29 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
if can_fly then if can_fly then
-- fly up -- fly up
if ctrl.jump then if ctrl.jump then
velo.y = velo.y + 1 velo.y = velo.y + 1
if velo.y > entity.accel then velo.y = entity.accel end if velo.y > entity.accel then velo.y = entity.accel end
elseif velo.y > 0 then elseif velo.y > 0 then
velo.y = velo.y - 0.1 velo.y = velo.y - 0.1
if velo.y < 0 then velo.y = 0 end if velo.y < 0 then velo.y = 0 end
end end
-- fly down -- fly down
if ctrl.sneak then if ctrl.sneak then
velo.y = velo.y - 1 velo.y = velo.y - 1
if velo.y < -entity.accel then velo.y = -entity.accel end if velo.y < -entity.accel then velo.y = -entity.accel end
elseif velo.y < 0 then elseif velo.y < 0 then
velo.y = velo.y + 0.1 velo.y = velo.y + 0.1
if velo.y > 0 then velo.y = 0 end if velo.y > 0 then velo.y = 0 end
end end
else else
@ -274,6 +303,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- if not moving then set animation and return -- if not moving then set animation and return
if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then if entity.v == 0 and velo.x == 0 and velo.y == 0 and velo.z == 0 then
if stand_anim then if stand_anim then
mobs:set_animation(entity, stand_anim) mobs:set_animation(entity, stand_anim)
end end
@ -292,8 +322,10 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
entity.v = entity.v - 0.02 * s entity.v = entity.v - 0.02 * s
if s ~= get_sign(entity.v) then if s ~= get_sign(entity.v) then
entity.object:set_velocity({x = 0, y = 0, z = 0}) entity.object:set_velocity({x = 0, y = 0, z = 0})
entity.v = 0 entity.v = 0
return return
end end
@ -310,6 +342,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
-- Set position, velocity and acceleration -- Set position, velocity and acceleration
local p = entity.object:get_pos() local p = entity.object:get_pos()
if not p then return end if not p then return end
local new_acce = {x = 0, y = -9.81, z = 0} local new_acce = {x = 0, y = -9.81, z = 0}
@ -320,18 +353,23 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
local v = entity.v local v = entity.v
if ni == "air" then if ni == "air" then
if can_fly == true then if can_fly == true then
new_acce.y = 0 new_acce.y = 0
end end
elseif ni == "liquid" or ni == "lava" then elseif ni == "liquid" or ni == "lava" then
if ni == "lava" and entity.lava_damage ~= 0 then if ni == "lava" and entity.lava_damage ~= 0 then
entity.lava_counter = (entity.lava_counter or 0) + dtime entity.lava_counter = (entity.lava_counter or 0) + dtime
if entity.lava_counter > 1 then if entity.lava_counter > 1 then
minetest.sound_play("default_punch", { minetest.sound_play("default_punch", {
object = entity.object, object = entity.object,
max_hear_distance = 5 max_hear_distance = 5
}) }, true)
entity.object:punch(entity.object, 1.0, { entity.object:punch(entity.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
@ -343,11 +381,14 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end end
local terrain_type = entity.terrain_type local terrain_type = entity.terrain_type
if terrain_type == 2 or terrain_type == 3 then if terrain_type == 2 or terrain_type == 3 then
new_acce.y = 0 new_acce.y = 0
p.y = p.y + 1 p.y = p.y + 1
if node_is(p) == "liquid" then if node_is(p) == "liquid" then
if velo.y >= 5 then if velo.y >= 5 then
velo.y = 5 velo.y = 5
elseif velo.y < 0 then elseif velo.y < 0 then
@ -357,7 +398,9 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end end
else else
if abs(velo.y) < 1 then if abs(velo.y) < 1 then
local pos = entity.object:get_pos() local pos = entity.object:get_pos()
if not pos then return end if not pos then return end
pos.y = floor(pos.y) + 0.5 pos.y = floor(pos.y) + 0.5
@ -371,6 +414,7 @@ function mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
end end
local new_velo = get_velocity(v, yaw - rot_view, velo.y) local new_velo = get_velocity(v, yaw - rot_view, velo.y)
new_acce.y = new_acce.y + acce_y new_acce.y = new_acce.y + acce_y
entity.object:set_velocity(new_velo) entity.object:set_velocity(new_velo)
@ -382,11 +426,14 @@ end
-- directional flying routine by D00Med (edited by TenPlus1) -- directional flying routine by D00Med (edited by TenPlus1)
function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim) function mobs.fly(entity, _, 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:get_velocity() local velo = entity.object:get_velocity()
local dir = entity.driver:get_look_dir() local dir = entity.driver:get_look_dir()
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
if not ctrl or not velo then return end
if ctrl.up then if ctrl.up then
entity.object:set_velocity({ entity.object:set_velocity({
x = dir.x * speed, x = dir.x * speed,
@ -395,6 +442,7 @@ function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
}) })
elseif ctrl.down then elseif ctrl.down then
entity.object:set_velocity({ entity.object:set_velocity({
x = -dir.x * speed, x = -dir.x * speed,
y = dir.y * speed + 2, y = dir.y * speed + 2,
@ -409,6 +457,7 @@ function mobs.fly(entity, _, 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:get_pos() 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,
@ -416,11 +465,15 @@ function mobs.fly(entity, _, speed, shoots, arrow, moving_anim, stand_anim)
z = pos.z + 0 + dir.z * 2.5}, arrow) z = pos.z + 0 + dir.z * 2.5}, arrow)
local ent = obj:get_luaentity() local ent = obj:get_luaentity()
if ent then if ent then
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}
yaw = entity.driver:get_look_horizontal() yaw = entity.driver:get_look_horizontal()
obj:set_yaw(yaw + pi / 2) obj:set_yaw(yaw + pi / 2)
obj:set_velocity(vec) obj:set_velocity(vec)
else else

View File

@ -23,7 +23,8 @@ Lucky Blocks: 9
Changelog: Changelog:
- 1.55 - Add 'peaceful_player' privelage and setting so mobs don't attack specific players (thanks sfence) - 1.56 - Added arrow_override function to mob definition to tweak arrow entity settings, tamed monsters no longer despawn when outside loaded map area.
- 1.55 - Add 'peaceful_player' privelage and setting so mobs don't attack specific players (thanks sfence), add support for MarkBu's pathfinder mod, remove need for default mod
- 1.54 - Simplified animal breeding function, added editable settings (thanks Wuzzy), Child mobs now take 20 mins to grow up, reverted to simple mob spawning with setting to use area checks, on_flop added, air_damage added. - 1.54 - Simplified animal breeding function, added editable settings (thanks Wuzzy), Child mobs now take 20 mins to grow up, reverted to simple mob spawning with setting to use area checks, on_flop added, air_damage added.
- 1.53 - Added 'on_map_load' settings to mobs:spawn so that mobs will only spawn when new areas of map are loaded. - 1.53 - Added 'on_map_load' settings to mobs:spawn so that mobs will only spawn when new areas of map are loaded.
- 1.52 - Added 'mob_active_limit' in settings to set number of mobs in game, - 1.52 - Added 'mob_active_limit' in settings to set number of mobs in game,

View File

@ -13,6 +13,9 @@ mobs_griefing (Griefing Mobs) bool true
# If false then Mobs no longer spawn inside player protected areas # If false then Mobs no longer spawn inside player protected areas
mobs_spawn_protected (Spawn Mobs in protected areas) bool true mobs_spawn_protected (Spawn Mobs in protected areas) bool true
# If false then Monsters no longer spawn inside player protected areas
mobs_spawn_monster_protected (Spawn Monsters in protected areas) bool true
# If true Mobs will be removed once a map chunk is out of view # If true Mobs will be removed once a map chunk is out of view
remove_far_mobs (Remove far Mobs) bool true remove_far_mobs (Remove far Mobs) bool true
@ -39,3 +42,6 @@ mob_area_spawn (Mob Area Spawn) bool false
# Enable peaceful player attack prevention # Enable peaceful player attack prevention
enable_peaceful_player (Mobs do not attack peaceful player without reason) bool false enable_peaceful_player (Mobs do not attack peaceful player without reason) bool false
# Enable mobs smooth rotation
mob_smooth_rotate (Smooth rotation for mobs) bool true