mirror of
https://codeberg.org/tenplus1/mobs_redo.git
synced 2025-07-20 01:00:22 +02:00
Compare commits
21 Commits
c06d071220
...
deee28fc59
Author | SHA1 | Date | |
---|---|---|---|
deee28fc59 | |||
ab44080ff8 | |||
9f46182bb4 | |||
2535b5636e | |||
2d014a75c4 | |||
db3831dccf | |||
29b2204f7c | |||
7fbfd9d59c | |||
e50d04a6aa | |||
33589ebda0 | |||
6670938c3d | |||
f131806008 | |||
49325c9c8d | |||
8012250258 | |||
ec44aa91c4 | |||
f58841ab3e | |||
350fc3647c | |||
70c68f6ebc | |||
c023ecc36f | |||
9be934ec25 | |||
f6e16a5503 |
456
api.lua
456
api.lua
@ -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)
|
||||||
|
9
api.txt
9
api.txt
@ -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
|
||||||
|
30
crafts.lua
30
crafts.lua
@ -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"}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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?
|
||||||
|
4
mod.conf
4
mod.conf
@ -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.
|
||||||
|
57
mount.lua
57
mount.lua
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user