Update Mobs Redo (1.41)

This commit is contained in:
Wuzzy 2018-05-29 17:00:30 +02:00
parent 34292ece10
commit c1cc790d9d
3 changed files with 221 additions and 99 deletions

View file

@ -3,7 +3,7 @@
mobs = {}
mobs.mod = "redo"
mobs.version = "20180328"
mobs.version = "20180523"
local MAX_MOB_NAME_LENGTH = 30
@ -61,9 +61,9 @@ local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
local creative = minetest.settings:get_bool("creative_mode")
local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false
local remove_far = minetest.settings:get_bool("remove_far_mobs")
local remove_far = false
local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0
local show_health = false --minetest.settings:get_bool("mob_show_health") ~= false
local show_health = false
local max_per_block = tonumber(minetest.settings:get("max_objects_per_block") or 99)
local mob_chance_multiplier = tonumber(minetest.settings:get("mob_chance_multiplier") or 1)
@ -126,6 +126,12 @@ end
-- move mob in facing direction
local set_velocity = function(self, v)
-- do not move if mob has been ordered to stay
if self.order == "stand" then
self.object:setvelocity({x = 0, y = 0, z = 0})
return
end
local yaw = (self.object:get_yaw() or 0) + self.rotate
self.object:setvelocity({
@ -146,15 +152,28 @@ end
-- set and return valid yaw
local set_yaw = function(self, yaw)
local set_yaw = function(self, yaw, delay)
if not yaw or yaw ~= yaw then
yaw = 0
end
self:setyaw(yaw)
delay = delay or 0
if delay == 0 then
self.object:set_yaw(yaw)
return yaw
end
self.target_yaw = yaw
self.delay = delay
return self.target_yaw
end
-- global function to set mob yaw
function mobs:yaw(self, yaw, delay)
set_yaw(self, yaw, delay)
end
@ -332,9 +351,8 @@ end
local update_tag = function(self)
--DISABLED IN MCL2
--[[
--[=[
local col = "#00FF00"
local qua = self.hp_max / 4
@ -349,11 +367,10 @@ local update_tag = function(self)
if self.health <= floor(qua) then
col = "#FF0000"
end
]]
]=]
self.object:set_properties({
nametag = self.nametag,
-- No nametag coloring
})
end
@ -566,7 +583,7 @@ local node_ok = function(pos, fallback)
return node
end
return minetest.registered_nodes[fallback] -- {name = fallback}
return minetest.registered_nodes[fallback]
end
@ -694,7 +711,8 @@ local do_jump = function(self)
if not self.jump
or self.jump_height == 0
or self.fly
or self.child then
or self.child
or self.order == "stand" then
return false
end
@ -753,9 +771,19 @@ local do_jump = function(self)
self.object:setvelocity(v)
if get_velocity(self) > 0 then
-- when in air move forward
minetest.after(0.3, function(self, v)
-- self.object:setvelocity({
self.object:set_acceleration({
x = v.x * 2,--1.5,
y = 0,
z = v.z * 2,--1.5
})
end, self, v)
if get_velocity(self) > 0 then
mob_sound(self, self.sounds.jump)
end
end
else
self.facing_fence = true
end
@ -1058,13 +1086,18 @@ local day_docile = function(self)
end
-- path finding and smart mob routine by rnd
local los_switcher = false
local height_switcher = false
-- path finding and smart mob routine by rnd, line_of_sight and other edits by Elkien3
local smart_mobs = function(self, s, p, dist, dtime)
local s1 = self.path.lastpos
local target_pos = self.attack:get_pos()
-- is it becoming stuck?
if abs(s1.x - s.x) + abs(s1.z - s.z) < 1.5 then
if abs(s1.x - s.x) + abs(s1.z - s.z) < .5 then
self.path.stuck_timer = self.path.stuck_timer + dtime
else
self.path.stuck_timer = 0
@ -1072,12 +1105,64 @@ local smart_mobs = function(self, s, p, dist, dtime)
self.path.lastpos = {x = s.x, y = s.y, z = s.z}
-- im stuck, search for path
if (self.path.stuck_timer > stuck_timeout and not self.path.following)
or (self.path.stuck_timer > stuck_path_timeout and self.path.following) then
local use_pathfind = false
local has_lineofsight = minetest.line_of_sight(
{x = s.x, y = (s.y) + .5, z = s.z},
{x = target_pos.x, y = (target_pos.y) + 1.5, z = target_pos.z}, .2)
-- im stuck, search for path
if not has_lineofsight then
if los_switcher == true then
use_pathfind = true
los_switcher = false
end -- cannot see target!
else
if los_switcher == false then
los_switcher = true
use_pathfind = false
minetest.after(1, function(self)
if has_lineofsight then self.path.following = false end
end, self)
end -- can see target!
end
if (self.path.stuck_timer > stuck_timeout and not self.path.following) then
use_pathfind = true
self.path.stuck_timer = 0
minetest.after(1, function(self)
if has_lineofsight then self.path.following = false end
end, self)
end
if (self.path.stuck_timer > stuck_path_timeout and self.path.following) then
use_pathfind = true
self.path.stuck_timer = 0
minetest.after(1, function(self)
if has_lineofsight then self.path.following = false end
end, self)
end
if math.abs(vector.subtract(s,target_pos).y) > self.stepheight then
if height_switcher then
use_pathfind = true
height_switcher = false
end
else
if not height_switcher then
use_pathfind = false
height_switcher = true
end
end
if use_pathfind then
-- lets try find a path, first take care of positions
-- since pathfinder is very sensitive
local sheight = self.collisionbox[5] - self.collisionbox[2]
@ -1105,17 +1190,25 @@ local smart_mobs = function(self, s, p, dist, dtime)
local dropheight = 6
if self.fear_height ~= 0 then dropheight = self.fear_height end
-- self.path.way = minetest.find_path(s, p1, 16, 2, 6, "Dijkstra")
self.path.way = minetest.find_path(s, p1, 16, self.stepheight, dropheight, "A*_noprefetch")
-- attempt to unstick mob that is "daydreaming"
--[[ BUT NOT IN MINECLONE2, SILLY!
self.object:setpos({
x = s.x + 0.1 * (random() * 2 - 1),
y = s.y + 1,
z = s.z + 0.1 * (random() * 2 - 1)
--[[
-- show path using particles
if self.path.way and #self.path.way > 0 then
print ("-- path length:" .. tonumber(#self.path.way))
for _,pos in pairs(self.path.way) do
minetest.add_particle({
pos = pos,
velocity = {x=0, y=0, z=0},
acceleration = {x=0, y=0, z=0},
expirationtime = 1,
size = 4,
collisiondetection = false,
vertical = false,
texture = "heart.png",
})
]]
end
end
]]
self.state = ""
do_attack(self, self.attack)
@ -1221,7 +1314,6 @@ local smart_mobs = function(self, s, p, dist, dtime)
else
-- yay i found path
mob_sound(self, self.sounds.war_cry)
set_velocity(self, self.walk_velocity)
-- follow path now that it has it
@ -1296,28 +1388,24 @@ local monster_attack = function(self)
and (type == "player" or type == "npc"
or (type == "animal" and self.attack_animals == true)) then
s = self.object:get_pos()
p = player:get_pos()
sp = s
dist = get_distance(p, s)
-- aim higher to make looking up hills more realistic
p.y = p.y + 1
sp.y = sp.y + 1
dist = get_distance(p, s)
if dist < self.view_range then
-- field of view check goes here
-- choose closest player to attack
if line_of_sight(self, sp, p, 2) == true
and dist < min_dist then
if dist < min_dist
and line_of_sight(self, sp, p, 2) == true then
min_dist = dist
min_player = player
end
end
end
end
-- attack player
if min_player then
@ -1347,10 +1435,16 @@ local npc_attack = function(self)
if obj and obj.type == "monster" then
p = obj.object:get_pos()
sp = s
dist = get_distance(p, s)
if dist < min_dist then
-- aim higher to make looking up hills more realistic
p.y = p.y + 1
sp.y = sp.y + 1
if dist < min_dist
and line_of_sight(self, sp, p, 2) == true then
min_dist = dist
min_player = obj.object
end
@ -1374,7 +1468,7 @@ local specific_runaway = function(list, what)
-- found entity on list to attack?
for no = 1, #list do
if list[no] == what or list[no] == "player" then
if list[no] == what then
return true
end
end
@ -1424,7 +1518,6 @@ local runaway_from = function(self)
if name ~= "" and name ~= self.name
and specific_runaway(self.runaway_from, name) then
s = self.object:get_pos()
p = player:get_pos()
sp = s
@ -1434,18 +1527,15 @@ local runaway_from = function(self)
dist = get_distance(p, s)
if dist < self.view_range then
-- field of view check goes here
-- choose closest player/mpb to runaway from
if line_of_sight(self, sp, p, 2) == true
and dist < min_dist then
if dist < min_dist
and line_of_sight(self, sp, p, 2) == true then
min_dist = dist
min_player = player
end
end
end
end
if min_player then
@ -1462,7 +1552,7 @@ local runaway_from = function(self)
yaw = yaw + pi
end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 4)
self.state = "runaway"
self.runaway_timer = 3
self.following = nil
@ -1548,7 +1638,7 @@ local follow_flop = function(self)
if p.x > s.x then yaw = yaw + pi end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 6)
-- anyone but standing npc's can move along
if dist > self.reach
@ -1652,7 +1742,7 @@ local do_states = function(self, dtime)
yaw = yaw + random(-0.5, 0.5)
end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 8)
end
set_velocity(self, 0)
@ -1671,14 +1761,14 @@ local do_states = function(self, dtime)
self.state = "walk"
set_animation(self, "walk")
-- fly up/down randomly for flying mobs
--[[ fly up/down randomly for flying mobs
if self.fly and random(1, 100) <= self.walk_chance then
local v = self.object:getvelocity()
local ud = random(-1, 2) / 9
self.object:setvelocity({x = v.x, y = ud, z = v.z})
end
end--]]
end
end
@ -1726,7 +1816,7 @@ local do_states = function(self, dtime)
if lp.x > s.x then yaw = yaw + pi end
-- look towards land and jump/move in that direction
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 6)
do_jump(self)
set_velocity(self, self.walk_velocity)
else
@ -1745,14 +1835,14 @@ local do_states = function(self, dtime)
if lp.x > s.x then yaw = yaw + pi end
end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 8)
-- otherwise randomly turn
elseif random(1, 100) <= 30 then
yaw = yaw + random(-0.5, 0.5)
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 8)
end
-- stand for great fall in front
@ -1818,6 +1908,7 @@ local do_states = function(self, dtime)
self.v_start = false
self.timer = 0
self.blinktimer = 0
self.path.way = nil
return
end
@ -1833,7 +1924,7 @@ local do_states = function(self, dtime)
if p.x > s.x then yaw = yaw + pi end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw)
local node_break_radius = self.explosion_radius or 1
local entity_damage_radius = self.explosion_damage_radius
@ -1903,7 +1994,7 @@ local do_states = function(self, dtime)
if minetest.find_node_near(pos, 1, {"group:water"})
or minetest.is_protected(pos, "") then
node_break_radius = 0
node_break_radius = 1
end
self.object:remove()
@ -2021,7 +2112,7 @@ local do_states = function(self, dtime)
if p.x > s.x then yaw = yaw + pi end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw)
-- move towards enemy if beyond mob reach
if dist > self.reach then
@ -2124,7 +2215,7 @@ local do_states = function(self, dtime)
if p.x > s.x then yaw = yaw + pi end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw)
set_velocity(self, 0)
@ -2199,7 +2290,6 @@ local falling = function(self, pos)
end
-- in water then float up
-- if minetest.registered_nodes[node_ok(pos).name].groups.liquid then
if minetest.registered_nodes[node_ok(pos).name].groups.water then
if self.floats == 1 then
@ -2400,7 +2490,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
end) ]]
-- knock back effect (only on full punch)
if self.knock_back > 0
if self.knock_back
and tflp >= punch_interval then
local v = self.object:getvelocity()
@ -2451,7 +2541,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
yaw = yaw + pi
end
yaw = set_yaw(self.object, yaw)
yaw = set_yaw(self, yaw, 6)
self.state = "runaway"
self.runaway_timer = 0
self.following = nil
@ -2671,7 +2761,7 @@ local mob_activate = function(self, staticdata, def, dtime)
-- set anything changed above
self.object:set_properties(self)
set_yaw(self.object, (random(0, 360) - 180) / 180 * pi)
set_yaw(self, (random(0, 360) - 180) / 180 * pi, 6)
update_tag(self)
set_animation(self, "stand")
@ -2741,6 +2831,46 @@ local mob_step = function(self, dtime)
falling(self, pos)
-- smooth rotation by ThomasMonroe314
if self.delay and self.delay > 0 then
local yaw = self.object:get_yaw()
if self.delay == 1 then
yaw = self.target_yaw
else
local dif = abs(yaw - self.target_yaw)
if yaw > self.target_yaw then
if dif > pi then
dif = 2 * pi - dif -- need to add
yaw = yaw + dif / self.delay
else
yaw = yaw - dif / self.delay -- need to subtract
end
elseif yaw < self.target_yaw then
if dif > pi then
dif = 2 * pi - dif
yaw = yaw - dif / self.delay -- need to subtract
else
yaw = yaw + dif / self.delay -- need to add
end
end
if yaw > (pi * 2) then yaw = yaw - (pi * 2) end
if yaw < 0 then yaw = yaw + (pi * 2) end
end
self.delay = self.delay - 1
self.object:set_yaw(yaw)
end
-- end rotation
-- knockback timer
if self.pause_timer > 0 then
@ -2775,9 +2905,6 @@ local mob_step = function(self, dtime)
self.timer = 1
end
-- node replace check (cow eats grass etc.)
replace(self, pos)
-- mob plays random sound at times
if random(1, 100) == 1 then
mob_sound(self, self.sounds.random)
@ -2791,7 +2918,11 @@ local mob_step = function(self, dtime)
self.env_damage_timer = 0
-- check for environmental damage (water, fire, lava etc.)
do_env_damage(self)
-- node replace check (cow eats grass etc.)
replace(self, pos)
end
monster_attack(self)
@ -2851,7 +2982,7 @@ minetest.register_entity(name, {
hp_min = max(1, (def.hp_min or 5) * difficulty),
hp_max = max(1, (def.hp_max or 10) * difficulty),
physical = true,
collisionbox = def.collisionbox,
collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25},
selectionbox = def.selectionbox or def.collisionbox,
visual = def.visual,
visual_size = def.visual_size or {x = 1, y = 1},
@ -2880,7 +3011,7 @@ minetest.register_entity(name, {
attacks_monsters = def.attacks_monsters or false,
group_attack = def.group_attack or false,
passive = def.passive or false,
knock_back = def.knock_back or 3,
knock_back = def.knock_back ~= false,
blood_amount = def.blood_amount or 5,
blood_texture = def.blood_texture or "mobs_blood.png",
shoot_offset = def.shoot_offset or 0,
@ -3337,7 +3468,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
local grp = {spawn_egg = 1}
-- do NOT add this egg to creative inventory (e.g. dungeon master)
if no_creative == true then
if creative and no_creative == true then
grp.not_in_creative_inventory = 1
end
@ -3401,7 +3532,6 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
minetest.register_craftitem(mob, {
description = desc,
inventory_image = invimg,
groups = grp,
@ -3438,7 +3568,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
end
if not minetest.registered_entities[mob] then
return
return itemstack
end
pos.y = pos.y + 1
@ -3452,6 +3582,7 @@ function mobs:register_egg(mob, desc, background, addegg, no_creative)
ent.owner = placer:get_player_name()
ent.tamed = true
end
-- set nametag
local nametag = itemstack:get_meta():get_string("name")
if nametag ~= "" then
@ -3478,8 +3609,7 @@ end
-- capture critter (thanks to blert2112 for idea)
function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso, force_take, replacewith)
return false
-- DISABLED IN MCL2
--[=[
--[=[ DISABLED IN MCL2
if self.child
or not clicker:is_player()
or not clicker:get_inventory() then
@ -3588,8 +3718,7 @@ function mobs:capture_mob(self, clicker, chance_hand, chance_net, chance_lasso,
mob_sound(self, "default_place_node_hard")
else
elseif chance ~= 0 then
minetest.chat_send_player(name, S("Missed!"))
mob_sound(self, "mobs_swing")
@ -3603,7 +3732,6 @@ end
-- protect tamed mob with rune item
function mobs:protect(self, clicker)
local name = clicker:get_player_name()
local tool = clicker:get_wielded_item()
@ -3644,7 +3772,6 @@ local mob_sta = {}
-- feeding, taming and breeding (thanks blert2112)
function mobs:feed_tame(self, clicker, feed_count, breed, tame)
if not self.follow then
return false
end
@ -3670,14 +3797,12 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
self.health = self.hp_max
if self.htimer < 1 then
-- DISABLED IN MCL2
--[=[
minetest.chat_send_player(clicker:get_player_name(),
S("@1 at full health (@2)",
self.name:split(":")[2], tostring(self.health)))
]=]
self.htimer = 5
end
end
@ -3751,9 +3876,9 @@ function mobs:feed_tame(self, clicker, feed_count, breed, tame)
end
return false
end
-- DISABLED IN MCL2
--[=[
-- inspired by blockmen's nametag mod
@ -3799,11 +3924,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- reset external variables
mob_obj[name] = nil
mob_sta[name] = nil
end
end)
]=]
-- compatibility function for old entities to new modpack entities
function mobs:alias_mob(old_name, new_name)
@ -3817,10 +3942,8 @@ function mobs:alias_mob(old_name, new_name)
on_step = function(self)
local pos = self.object:get_pos()
if minetest.registered_entities[new_name] then
minetest.add_entity(pos, new_name)
minetest.add_entity(self.object:get_pos(), new_name)
end
self.object:remove()

View file

@ -46,8 +46,6 @@ functions needed for the mob to work properly which contains the following:
in e.g. "air" or "default:water_source".
'runaway' if true causes animals to turn and run away when hit.
'view_range' how many nodes in distance the mob can see a player.
'reach' how many nodes in distance a mob can attack a player while
standing.
'damage' how many health points the mob does to a player or another
mob when melee attacking.
'knock_back' when true has mobs falling backwards when hit, the greater
@ -565,8 +563,8 @@ External Settings for "minetest.conf"
is false)
'mobs_spawn_protected' if set to false then mobs will not spawn in protected
areas (default is true)
'remove_far_mobs' if true then mobs that are outside players visual
range will be removed (default is false)
'remove_far_mobs' if true then untamed mobs that are outside players
visual range will be removed (default is true)
'mobname' can change specific mob chance rate (0 to disable) and
spawn number e.g. mobs_animal:cow = 1000,5
'mob_difficulty' sets difficulty level (health and hit damage

View file

@ -22,6 +22,7 @@ Lucky Blocks: 9
Changelog:
- 1.41- Mob pathfinding has been updated thanks to Elkien3
- 1.40- Updated to use newer functions, requires Minetest 0.4.16+ to work.
- 1.39- Added 'on_breed', 'on_grown' and 'do_punch' custom functions per mob
- 1.38- Better entity checking, nametag setting and on_spawn function added to mob registry, tweaked light damage