Compare commits

...

8 Commits

8 changed files with 155 additions and 118 deletions

View File

@ -128,7 +128,7 @@ functions needed for the mob to work properly which contains the following:
arrow/fireball appears on mob. arrow/fireball appears on mob.
'specific_attack' has a table of entity names that mob can also attack 'specific_attack' has a table of entity names that mob can also attack
e.g. {"player", "mobs_animal:chicken"}. e.g. {"player", "mobs_animal:chicken"}.
'runaway_from' contains a table with mob names to run away from, add 'runaway_from' contains a table with mob/node names to run away from, add
"player" to list to runaway from player also. "player" to list to runaway from player also.
'pathfinding' set to 1 for mobs to use pathfinder feature to locate 'pathfinding' set to 1 for mobs to use pathfinder feature to locate
player, set to 2 so they can build/break also (only player, set to 2 so they can build/break also (only
@ -262,7 +262,10 @@ functions needed for the mob to work properly which contains the following:
'custom_visual_size' will not reset visual_size from the base class on reload 'custom_visual_size' will not reset visual_size from the base class on reload
'noyaw' If true this mob will not automatically change yaw 'noyaw' If true this mob will not automatically change yaw
'particlespawners' Table of particlespawners attached to the mob. This is implemented in a coord safe manner i.e. spawners are only sent to players within the player_transfer_distance (and automatically removed). This enables infinitely lived particlespawners. 'particlespawners' Table of particlespawners attached to the mob. This is implemented in a coord safe manner i.e. spawners are only sent to players within the player_transfer_distance (and automatically removed). This enables infinitely lived particlespawners.
'attack_frequency' Attack frequency in seconds. If unset, this defaults to 1. Implemented for melee only atm. 'attack_frequency' Attack frequency in seconds. If unset, this defaults to 1. Implemented for melee only atm.
'avoid_from' contains a table with mob/node names to avoid from, add
"player" to list to avoid from player also.
mobs:gopath(self,target,callback_arrived) pathfind a way to target and run callback on arrival mobs:gopath(self,target,callback_arrived) pathfind a way to target and run callback on arrival
@ -449,6 +452,16 @@ Create death particles at pos with the given collisionbox.
mcl_mobs.spawn(pos,name/entity name) mcl_mobs.spawn(pos,name/entity name)
mcl_mobs:is_object_in_view(object_list, object_range, node_range, turn_around)
Returns 'true' if an object (mob or node) is in the field of view.
'object_list' list of mob and/or node names
'object_range' maximum distance to a mob from object_list
'node_range' maximum distance to a node from object_list
'turn_around' true or false
Making Arrows Making Arrows
------------- -------------

View File

@ -289,6 +289,7 @@ function mcl_mobs.register_mob(name, def)
noyaw = def.noyaw or false, noyaw = def.noyaw or false,
particlespawners = def.particlespawners, particlespawners = def.particlespawners,
spawn_check = def.spawn_check, spawn_check = def.spawn_check,
avoid_from = def.avoid_from,
-- End of MCL2 extensions -- End of MCL2 extensions
on_spawn = def.on_spawn, on_spawn = def.on_spawn,
on_blast = def.on_blast or function(self,damage) on_blast = def.on_blast or function(self,damage)

View File

@ -509,6 +509,81 @@ function mob_class:do_jump()
return false return false
end end
local function in_list(list, what)
return type(list) == "table" and table.indexof(list, what) ~= -1
end
function mob_class:is_object_in_view(object_list, object_range, node_range, turn_around)
local s = self.object:get_pos()
local min_dist = object_range + 1
local objs = minetest.get_objects_inside_radius(s, object_range)
local object_pos = nil
for n = 1, #objs do
local name = ""
local object = objs[n]
if object:is_player() then
if not (mcl_mobs.invis[ object:get_player_name() ]
or self.owner == object:get_player_name()
or (not self:object_in_range(object))) then
name = "player"
if not (name ~= self.name
and in_list(object_list, name)) then
local item = object:get_wielded_item()
name = item:get_name() or ""
end
end
else
local obj = object:get_luaentity()
if obj then
object = obj.object
name = obj.name or ""
end
end
-- find specific mob to avoid or runaway from
if name ~= "" and name ~= self.name
and in_list(object_list, name) then
local p = object:get_pos()
local dist = vector.distance(p, s)
-- choose closest player/mob to avoid or runaway from
if dist < min_dist
-- aim higher to make looking up hills more realistic
and self:line_of_sight(vector.offset(s, 0,1,0), vector.offset(p, 0,1,0)) == true then
min_dist = dist
object_pos = p
end
end
end
if not object_pos then
-- find specific node to avoid or runaway from
local p = minetest.find_node_near(s, node_range, object_list, true)
local dist = p and vector.distance(p, s)
if dist and dist < min_dist
and self:line_of_sight(s, p) == true then
min_dist = dist
object_pos = p
end
end
if object_pos and turn_around then
local vec = vector.subtract(object_pos, s)
yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate
if object_pos.x > s.x then yaw = yaw + math.pi end
yaw = self:set_yaw(yaw, 4)
end
return object_pos ~= nil
end
-- should mob follow what I'm holding ? -- should mob follow what I'm holding ?
function mob_class:follow_holding(clicker) function mob_class:follow_holding(clicker)
if self.nofollow then return false end if self.nofollow then return false end
@ -526,14 +601,8 @@ function mob_class:follow_holding(clicker)
return true return true
-- multiple items -- multiple items
elseif t == "table" then elseif t == "table" and in_list(self.follow, item:get_name()) then
return true
for no = 1, #self.follow do
if self.follow[no] == item:get_name() then
return true
end
end
end end
return false return false
@ -593,104 +662,14 @@ function mob_class:replace_node(pos)
end end
end end
-- specific runaway
local specific_runaway = function(list, what)
if type(list) ~= "table" then
list = {}
end
-- no list so do not run
if list == nil then
return false
end
-- found entity on list to attack?
for no = 1, #list do
if list[no] == what then
return true
end
end
return false
end
-- find someone to runaway from -- find someone to runaway from
function mob_class:check_runaway_from() function mob_class:check_runaway_from()
if not self.runaway_from and self.state ~= "flop" then if not self.runaway_from and self.state ~= "flop" then
return return
end end
local s = self.object:get_pos() if self:is_object_in_view(self.runaway_from, self.view_range, self.view_range / 2, true) then
local p, sp, dist self.shaking = self.shaking or 5
local player, obj, min_player
local type, name = "", ""
local min_dist = self.view_range + 1
local objs = minetest.get_objects_inside_radius(s, self.view_range)
for n = 1, #objs do
if objs[n]:is_player() then
if mcl_mobs.invis[ objs[n]:get_player_name() ]
or self.owner == objs[n]:get_player_name()
or (not self:object_in_range(objs[n])) then
type = ""
else
player = objs[n]
type = "player"
name = "player"
end
else
obj = objs[n]:get_luaentity()
if obj then
player = obj.object
type = obj.type
name = obj.name or ""
end
end
-- find specific mob to runaway from
if name ~= "" and name ~= self.name
and specific_runaway(self.runaway_from, name) then
p = player:get_pos()
sp = s
-- aim higher to make looking up hills more realistic
p.y = p.y + 1
sp.y = sp.y + 1
dist = vector.distance(p, s)
-- choose closest player/mpb to runaway from
if dist < min_dist
and self:line_of_sight(sp, p, 2) == true then
min_dist = dist
min_player = player
end
end
end
if min_player then
local lp = player:get_pos()
local vec = {
x = lp.x - s.x,
y = lp.y - s.y,
z = lp.z - s.z
}
local yaw = (atan(vec.z / vec.x) + 3 *math.pi/ 2) - self.rotate
if lp.x > s.x then
yaw = yaw + math.pi
end
yaw = self:set_yaw( yaw, 4)
self.state = "runaway" self.state = "runaway"
self.runaway_timer = 3 self.runaway_timer = 3
self.following = nil self.following = nil
@ -914,23 +893,20 @@ function mob_class:do_states_walk()
end end
end end
-- A danger is near but mob is not inside
else
-- Randomly turn
if math.random(1, 100) <= 30 then
yaw = yaw + math.random(-0.5, 0.5)
yaw = self:set_yaw( yaw, 8)
end
end end
end
yaw = self:set_yaw( yaw, 8) if not is_in_danger then
local distance = self.avoid_distance or self.view_range / 2
-- find specific node to avoid
if self:is_object_in_view(self.avoid_from, distance, distance, true) then
self.shaking = self.shaking or 2
self:set_velocity(self.walk_velocity)
-- otherwise randomly turn -- otherwise randomly turn
elseif math.random(1, 100) <= 30 then elseif math.random(1, 100) <= 30 then
yaw = yaw + math.random(-0.5, 0.5) yaw = yaw + math.random(-0.5, 0.5)
yaw = self:set_yaw( yaw, 8) yaw = self:set_yaw(yaw, 8)
end
end end
-- stand for great fall or danger or fence in front -- stand for great fall or danger or fence in front
@ -938,6 +914,7 @@ function mob_class:do_states_walk()
if is_in_danger then if is_in_danger then
cliff_or_danger = self:is_at_cliff_or_danger() cliff_or_danger = self:is_at_cliff_or_danger()
end end
if self.facing_fence == true if self.facing_fence == true
or cliff_or_danger or cliff_or_danger
or math.random(1, 100) <= 30 then or math.random(1, 100) <= 30 then
@ -1086,6 +1063,12 @@ function mob_class:check_smooth_rotation(dtime)
self.delay = self.delay - 1 self.delay = self.delay - 1
if self.shaking then if self.shaking then
yaw = yaw + (math.random() * 2 - 1) * 5 * dtime yaw = yaw + (math.random() * 2 - 1) * 5 * dtime
if type(self.shaking) == "number" then
self.shaking = self.shaking - dtime
if self.shaking <= 0 then
self.shaking = nil
end
end
end end
self.object:set_yaw(yaw) self.object:set_yaw(yaw)
--self:update_roll() --self:update_roll()

View File

@ -40,6 +40,17 @@ local hoglin = {
makes_footstep_sound = true, makes_footstep_sound = true,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 2.8, run_velocity = 2.8,
avoid_from = {
"mcl_crimson:warped_fungus",
"mcl_flowerpots:flower_pot_warped_fungus",
"mcl_portals:portal",
"mcl_beds:respawn_anchor",
"mcl_beds:respawn_anchor_charged_1",
"mcl_beds:respawn_anchor_charged_2",
"mcl_beds:respawn_anchor_charged_3",
"mcl_beds:respawn_anchor_charged_4",
},
follow = {"mcl_crimson:crimson_fungus"},
drops = { drops = {
{name = "mobs_mcitems:leather", {name = "mobs_mcitems:leather",
chance = 1, chance = 1,
@ -87,9 +98,26 @@ local hoglin = {
attack_animals = true, attack_animals = true,
} }
mcl_mobs.register_mob("mobs_mc:hoglin", hoglin)
local zoglin = table.copy(hoglin) local zoglin = table.copy(hoglin)
hoglin.on_rightclick = function(self, clicker)
-- local item = clicker:get_wielded_item()
if self:feed_tame(clicker, 1, true, false) then return end
-- if mcl_mobs:protect(self, clicker) then return end
end
hoglin.on_breed = function(parent1, parent2)
local pos = parent1.object:get_pos()
local child = mcl_mobs.spawn_child(pos, parent1.name)
if child then
local ent_c = child:get_luaentity()
-- ent_c.tamed = true
ent_c.owner = parent1.owner
return false
end
end,
mcl_mobs.register_mob("mobs_mc:hoglin", hoglin)
zoglin.description = S("Zoglin") zoglin.description = S("Zoglin")
zoglin.fire_resistant = 1 zoglin.fire_resistant = 1
zoglin.textures = {"extra_mobs_zoglin.png"} zoglin.textures = {"extra_mobs_zoglin.png"}

View File

@ -42,6 +42,7 @@ local rabbit = {
makes_footstep_sound = false, makes_footstep_sound = false,
walk_velocity = 1, walk_velocity = 1,
run_velocity = 3.7, run_velocity = 3.7,
avoid_from = {"mobs_mc:wolf"},
follow_velocity = 1.1, follow_velocity = 1.1,
floats = 1, floats = 1,
runaway = true, runaway = true,

View File

@ -46,6 +46,7 @@ local skeleton = {
}, },
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.0, run_velocity = 2.0,
runaway_from = {"mobs_mc:wolf"},
damage = 2, damage = 2,
reach = 2, reach = 2,
drops = { drops = {

View File

@ -44,6 +44,7 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", {
}, },
walk_velocity = 1.2, walk_velocity = 1.2,
run_velocity = 2.0, run_velocity = 2.0,
runaway_from = {"mobs_mc:wolf"},
damage = 7, damage = 7,
reach = 2, reach = 2,
drops = { drops = {

View File

@ -97,7 +97,16 @@ local wolf = {
jump = true, jump = true,
attacks_monsters = true, attacks_monsters = true,
attack_animals = true, attack_animals = true,
specific_attack = { "player", "mobs_mc:sheep" }, specific_attack = {
"player",
"mobs_mc:sheep",
"mobs_mc:rabbit",
-- TODO: "mobs_mc:fox",
"mobs_mc:skeleton",
"mobs_mc:stray",
"mobs_mc:witherskeleton",
},
avoid_from = { "mobs_mc:llama" },
} }
mcl_mobs.register_mob("mobs_mc:wolf", wolf) mcl_mobs.register_mob("mobs_mc:wolf", wolf)