luacheck and other improvements
This commit is contained in:
parent
a5cfaed843
commit
98600c87de
|
@ -1,5 +1,4 @@
|
|||
local mob_class = mcl_mobs.mob_class
|
||||
local mob_class_meta = {__index = mcl_mobs.mob_class}
|
||||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
|
@ -152,19 +151,17 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
|
||||
self.base_selbox = self.base_selbox or self.selectionbox or self.base_colbox
|
||||
|
||||
local textures = self.base_texture
|
||||
local mesh = self.base_mesh
|
||||
local vis_size = self.base_size
|
||||
local colbox = self.base_colbox
|
||||
local selbox = self.base_selbox
|
||||
self.textures = self.gotten and def.gotten_texture or self.base_texture
|
||||
self.mesh = self.gotten and def.gotten_mesh or self.base_mesh
|
||||
self.visual_size = self.base_size
|
||||
self.collisionbox = self.base_colbox
|
||||
self.selectionbox = self.base_selbox
|
||||
|
||||
if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end
|
||||
if self.gotten == true and def.gotten_mesh then mesh = def.gotten_mesh end
|
||||
if self.child == true then
|
||||
vis_size = { x = self.base_size.x * .5, y = self.base_size.y * .5 }
|
||||
if def.child_texture then textures = def.child_texture[1] end
|
||||
if self.child then
|
||||
self.visual_size = { x = self.base_size.x * .5, y = self.base_size.y * .5 }
|
||||
self.textures = def.child_texture and def.child_texture[1] or self.textures
|
||||
|
||||
colbox = {
|
||||
self.collisionbox = {
|
||||
self.base_colbox[1] * .5,
|
||||
self.base_colbox[2] * .5,
|
||||
self.base_colbox[3] * .5,
|
||||
|
@ -172,7 +169,7 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
self.base_colbox[5] * .5,
|
||||
self.base_colbox[6] * .5
|
||||
}
|
||||
selbox = {
|
||||
self.selectionbox = {
|
||||
self.base_selbox[1] * .5,
|
||||
self.base_selbox[2] * .5,
|
||||
self.base_selbox[3] * .5,
|
||||
|
@ -182,8 +179,8 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
}
|
||||
end
|
||||
|
||||
if self.health == 0 then self.health = math.random(self.hp_min, self.hp_max) end
|
||||
if self.breath == nil then self.breath = self.breath_max end
|
||||
self.health = (self.health and self.health > 0 and self.health) or math.random(self.hp_min, self.hp_max)
|
||||
self.breath = self.breath or self.breath_max
|
||||
|
||||
self.path = {}
|
||||
self.path.way = {} -- path to follow, table of positions
|
||||
|
@ -206,14 +203,9 @@ function mob_class:mob_activate(staticdata, def, dtime)
|
|||
self.old_y = self.object:get_pos().y
|
||||
self.old_health = self.health
|
||||
self.sounds.distance = self.sounds.distance or 10
|
||||
self.textures = textures
|
||||
self.mesh = mesh
|
||||
self.collisionbox = colbox
|
||||
self.selectionbox = selbox
|
||||
self.visual_size = vis_size
|
||||
self.standing_in = NODE_IGNORE
|
||||
self.standing_on = NODE_IGNORE
|
||||
self.standing_under = NODE_IGNORE
|
||||
self.standing_in = mcl_mobs.NODE_IGNORE
|
||||
self.standing_on = mcl_mobs.NODE_IGNORE
|
||||
self.standing_under = mcl_mobs.NODE_IGNORE
|
||||
self.standing_depth = 0
|
||||
self.state = self.state or "stand"
|
||||
self.jump_sound_cooloff = 0 -- used to prevent jump sound from being played too often in short time
|
||||
|
@ -317,6 +309,7 @@ local function on_step_work(self, dtime, moveresult)
|
|||
local player_in_active_range = self:player_in_active_range()
|
||||
-- The following functions return true when the mob died and we should stop processing
|
||||
if self:check_suspend(player_in_active_range) then return end
|
||||
-- initializes self.acceleration:
|
||||
if self:gravity_and_floating(pos, dtime, moveresult) then return end -- keep early, for gravity!
|
||||
if self:check_dying() then return end
|
||||
if self:step_damage(dtime, pos) then return end
|
||||
|
@ -360,7 +353,7 @@ local function on_step_work(self, dtime, moveresult)
|
|||
self:smooth_acceleration(dtime)
|
||||
local cx, cz = self:collision()
|
||||
self.object:add_velocity(vector.new(cx, 0, cz))
|
||||
self:update_vel_acc(dtime)
|
||||
self:update_vel_acc(dtime) -- applies self.acceleration
|
||||
if mobs_debug then self:update_tag() end
|
||||
if not self.object:get_luaentity() then return false end
|
||||
end
|
||||
|
@ -398,8 +391,12 @@ function mob_class:on_step(dtime, moveresult)
|
|||
-- allow crash in development mode
|
||||
if DEVELOPMENT then return on_step_work(self, dtime, moveresult) end
|
||||
-- Removed as bundled Lua (5.1 doesn't support xpcall)
|
||||
--local status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime)
|
||||
local status, retVal = pcall(on_step_work, self, dtime, moveresult)
|
||||
local status, retVal
|
||||
if xpcall then
|
||||
status, retVal = xpcall(on_step_work, on_step_error_handler, self, dtime, moveresult)
|
||||
else
|
||||
status, retVal = pcall(on_step_work, self, dtime, moveresult)
|
||||
end
|
||||
if status then return retVal end
|
||||
warn_user_error()
|
||||
local pos = self.object:get_pos()
|
||||
|
@ -488,16 +485,16 @@ minetest.register_chatcommand("clearmobs", {
|
|||
elseif mob_type == "passive" and o.type ~= "monster" and o.type ~= "npc" then
|
||||
--minetest.log("Match - passive")
|
||||
mob_match = true
|
||||
else
|
||||
--minetest.log("No match for type.")
|
||||
--else
|
||||
-- minetest.log("No match for type.")
|
||||
end
|
||||
elseif mob_name and (o.name == mob_name or string.find(o.name, mob_name)) then
|
||||
--minetest.log("Match - mob_name = ".. tostring(o.name))
|
||||
mob_match = true
|
||||
else
|
||||
--minetest.log("No match - o.type = ".. tostring(o.type))
|
||||
--minetest.log("No match - mob_name = ".. tostring(o.name))
|
||||
--minetest.log("No match - mob_type = ".. tostring(mob_name))
|
||||
--else
|
||||
-- minetest.log("No match - o.type = ".. tostring(o.type))
|
||||
-- minetest.log("No match - mob_name = ".. tostring(o.name))
|
||||
-- minetest.log("No match - mob_type = ".. tostring(mob_name))
|
||||
end
|
||||
|
||||
if mob_match then
|
||||
|
|
|
@ -5,7 +5,7 @@ local HORNY_TIME = 30
|
|||
local HORNY_AGAIN_TIME = 30 -- was 300 or 15*20
|
||||
local CHILD_GROW_TIME = 60
|
||||
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false)
|
||||
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager", false)
|
||||
|
||||
local LOG_MODULE = "[mcl_mobs]"
|
||||
local function mcl_log (message)
|
||||
|
@ -29,18 +29,13 @@ end
|
|||
|
||||
-- feeding, taming and breeding (thanks blert2112)
|
||||
function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
||||
if not self.follow then
|
||||
return false
|
||||
end
|
||||
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then
|
||||
return false
|
||||
end
|
||||
if not self.follow then return false end
|
||||
if clicker:get_wielded_item():get_definition()._mcl_not_consumable then return false end
|
||||
-- can eat/tame with item in hand
|
||||
if self.nofollow or self:follow_holding(clicker) then
|
||||
local consume_food = false
|
||||
|
||||
-- tame if not still a baby
|
||||
|
||||
if tame and not self.child then
|
||||
if not self.owner or self.owner == "" then
|
||||
self.tamed = true
|
||||
|
@ -50,7 +45,6 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
|||
end
|
||||
|
||||
-- increase health
|
||||
|
||||
if self.health < self.hp_max and not consume_food then
|
||||
consume_food = true
|
||||
self.health = math.min(self.health + 4, self.hp_max)
|
||||
|
@ -58,15 +52,13 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake)
|
|||
end
|
||||
|
||||
-- make children grow quicker
|
||||
|
||||
if not consume_food and self.child == true then
|
||||
if not consume_food and self.child then
|
||||
consume_food = true
|
||||
-- deduct 10% of the time to adulthood
|
||||
self.hornytimer = self.hornytimer + ((CHILD_GROW_TIME - self.hornytimer) * 0.1)
|
||||
end
|
||||
|
||||
-- breed animals
|
||||
|
||||
if breed and not consume_food and self.hornytimer == 0 and not self.horny then
|
||||
self.food = (self.food or 0) + 1
|
||||
consume_food = true
|
||||
|
@ -102,24 +94,15 @@ end
|
|||
-- Spawn a child
|
||||
function mcl_mobs.spawn_child(pos, mob_type)
|
||||
local child = minetest.add_entity(pos, mob_type)
|
||||
if not child then
|
||||
return
|
||||
end
|
||||
if not child then return end
|
||||
|
||||
local ent = child:get_luaentity()
|
||||
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
|
||||
|
||||
ent.child = true
|
||||
|
||||
local textures
|
||||
-- using specific child texture (if found)
|
||||
if ent.child_texture then
|
||||
textures = ent.child_texture[1]
|
||||
end
|
||||
mcl_mobs.effect(pos, 15, "mcl_particles_smoke.png", 1, 2, 2, 15, 5)
|
||||
|
||||
-- and resize to half height
|
||||
child:set_properties({
|
||||
textures = textures,
|
||||
textures = ent.child_texture and ent.child_texture[1],
|
||||
visual_size = {
|
||||
x = ent.base_size.x * .5,
|
||||
y = ent.base_size.y * .5,
|
||||
|
@ -151,16 +134,12 @@ end
|
|||
|
||||
-- find two animals of same type and breed if nearby and horny
|
||||
function mob_class:check_breeding()
|
||||
|
||||
--mcl_log("In breed function")
|
||||
-- child takes a long time before growing into adult
|
||||
if self.child == true then
|
||||
|
||||
-- When a child, hornytimer is used to count age until adulthood
|
||||
self.hornytimer = self.hornytimer + 1
|
||||
|
||||
if self.hornytimer >= CHILD_GROW_TIME then
|
||||
|
||||
self.child = false
|
||||
self.hornytimer = 0
|
||||
|
||||
|
@ -177,11 +156,7 @@ function mob_class:check_breeding()
|
|||
self.on_grown(self)
|
||||
else
|
||||
-- jump when fully grown so as not to fall into ground
|
||||
self.object:set_velocity({
|
||||
x = 0,
|
||||
y = self.jump_height,
|
||||
z = 0
|
||||
})
|
||||
self.object:set_velocity(vector.new(0, self.jump_height, 0))
|
||||
end
|
||||
|
||||
self.animation = nil
|
||||
|
@ -189,121 +164,79 @@ function mob_class:check_breeding()
|
|||
self._current_animation = nil -- Mobs Redo does nothing otherwise
|
||||
self:set_animation(anim)
|
||||
end
|
||||
|
||||
return
|
||||
else
|
||||
-- horny animal can mate for HORNY_TIME seconds,
|
||||
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
|
||||
if self.horny == true then
|
||||
self.hornytimer = self.hornytimer + 1
|
||||
end
|
||||
-- horny animal can mate for HORNY_TIME seconds,
|
||||
-- afterwards horny animal cannot mate again for HORNY_AGAIN_TIME seconds
|
||||
if self.horny == true then
|
||||
self.hornytimer = self.hornytimer + 1
|
||||
|
||||
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
|
||||
self.hornytimer = 0
|
||||
self.horny = false
|
||||
end
|
||||
if self.hornytimer >= HORNY_TIME + HORNY_AGAIN_TIME then
|
||||
self.hornytimer = 0
|
||||
self.horny = false
|
||||
end
|
||||
end
|
||||
|
||||
-- find another same animal who is also horny and mate if nearby
|
||||
if self.horny == true
|
||||
and self.hornytimer <= HORNY_TIME then
|
||||
|
||||
if self.horny and self.hornytimer <= HORNY_TIME then
|
||||
mcl_log("In breed function. All good. Do the magic.")
|
||||
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
mcl_mobs.effect({x = pos.x, y = pos.y + 1, z = pos.z}, 8, "heart.png", 3, 4, 1, 0.1)
|
||||
mcl_mobs.effect(vector.new(pos.x, pos.y + 1, pos.z), 8, "heart.png", 3, 4, 1, 0.1)
|
||||
|
||||
local objs = minetest.get_objects_inside_radius(pos, 3)
|
||||
local num = 0
|
||||
local ent = nil
|
||||
|
||||
for n = 1, #objs do
|
||||
|
||||
ent = objs[n]:get_luaentity()
|
||||
local ent = objs[n]:get_luaentity()
|
||||
|
||||
-- check for same animal with different colour
|
||||
local canmate = false
|
||||
|
||||
if ent then
|
||||
|
||||
if ent.name == self.name then
|
||||
canmate = true
|
||||
else
|
||||
local entname = string.split(ent.name,":")
|
||||
local selfname = string.split(self.name,":")
|
||||
|
||||
if entname[1] == selfname[1] then
|
||||
entname = string.split(entname[2],"_")
|
||||
selfname = string.split(selfname[2],"_")
|
||||
|
||||
if entname[1] == selfname[1] then
|
||||
canmate = true
|
||||
end
|
||||
if entname[1] == selfname[1] then canmate = true end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if canmate then mcl_log("In breed function. Can mate.") end
|
||||
|
||||
if ent
|
||||
and canmate == true
|
||||
and ent.horny == true
|
||||
and ent.hornytimer <= HORNY_TIME then
|
||||
if ent and canmate and ent.horny and ent.hornytimer <= HORNY_TIME then
|
||||
num = num + 1
|
||||
end
|
||||
|
||||
-- found your mate? then have a baby
|
||||
if num > 1 then
|
||||
|
||||
self.hornytimer = HORNY_TIME + 1
|
||||
ent.hornytimer = HORNY_TIME + 1
|
||||
|
||||
-- spawn baby
|
||||
|
||||
|
||||
minetest.after(5, function(parent1, parent2, pos)
|
||||
if not parent1.object:get_luaentity() then
|
||||
return
|
||||
end
|
||||
if not parent2.object:get_luaentity() then
|
||||
return
|
||||
end
|
||||
if not parent1.object:get_luaentity() then return end
|
||||
if not parent2.object:get_luaentity() then return end
|
||||
|
||||
mcl_experience.throw_xp(pos, math.random(1, 7) + (parent1._luck or 0) + (parent2._luck or 0))
|
||||
|
||||
-- custom breed function
|
||||
if parent1.on_breed then
|
||||
-- when false, skip going any further
|
||||
if parent1.on_breed(parent1, parent2) == false then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if parent1.on_breed and not parent1.on_breed(parent1, parent2) then return end
|
||||
pos = vector.round(pos)
|
||||
local child = mcl_mobs.spawn_child(pos, parent1.name)
|
||||
if not child then return end
|
||||
|
||||
local ent_c = child:get_luaentity()
|
||||
|
||||
|
||||
-- Use texture of one of the parents
|
||||
local p = math.random(1, 2)
|
||||
if p == 1 then
|
||||
ent_c.base_texture = parent1.base_texture
|
||||
else
|
||||
ent_c.base_texture = parent2.base_texture
|
||||
end
|
||||
child:set_properties({
|
||||
textures = ent_c.base_texture
|
||||
})
|
||||
ent_c.base_texture = math.random(1, 2) == 1 and parent1.base_texture or parent2.base_texture
|
||||
child:set_properties({ textures = ent_c.base_texture })
|
||||
|
||||
-- tamed and owned by parents' owner
|
||||
ent_c.tamed = true
|
||||
ent_c.owner = parent1.owner
|
||||
end, self, ent, pos)
|
||||
|
||||
num = 0
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -311,9 +244,7 @@ function mob_class:check_breeding()
|
|||
end
|
||||
|
||||
function mob_class:toggle_sit(clicker,p)
|
||||
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then
|
||||
return
|
||||
end
|
||||
if not self.tamed or self.child or self.owner ~= clicker:get_player_name() then return end
|
||||
local pos = self.object:get_pos()
|
||||
local particle
|
||||
if not self.order or self.order == "" or self.order == "sit" then
|
||||
|
@ -341,7 +272,7 @@ function mob_class:toggle_sit(clicker,p)
|
|||
-- Display icon to show current order (sit or roam)
|
||||
minetest.add_particle({
|
||||
pos = vector.add(pos, pp),
|
||||
velocity = {x=0,y=0.2,z=0},
|
||||
velocity = vector.new(0, 0.2, 0),
|
||||
expirationtime = 1,
|
||||
size = 4,
|
||||
texture = particle,
|
||||
|
|
|
@ -27,10 +27,12 @@ local vector_offset = vector.offset
|
|||
local vector_new = vector.new
|
||||
local vector_copy = vector.copy
|
||||
local vector_distance = vector.distance
|
||||
local vector_zero = vector.zero
|
||||
local node_ok = mcl_mobs.node_ok -- TODO: remove
|
||||
|
||||
-- check if daytime and also if mob is docile during daylight hours
|
||||
function mob_class:day_docile()
|
||||
return self.docile_by_day == true and self.time_of_day > 0.2 and self.time_of_day < 0.8
|
||||
return self.docile_by_day and self.time_of_day > 0.2 and self.time_of_day < 0.8
|
||||
end
|
||||
|
||||
-- get this mob to attack the object
|
||||
|
@ -60,7 +62,7 @@ local function entity_physics(pos, radius)
|
|||
if dist < 1 then dist = 1 end
|
||||
|
||||
local damage = floor((4 / dist) * radius)
|
||||
local ent = objs[n]:get_luaentity()
|
||||
--local ent = objs[n]:get_luaentity()
|
||||
|
||||
-- punches work on entities AND players
|
||||
objs[n]:punch(objs[n], 1.0, {
|
||||
|
@ -143,7 +145,7 @@ function mob_class:smart_mobs(s, p, dist, dtime)
|
|||
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]
|
||||
--local sheight = self.collisionbox[5] - self.collisionbox[2]
|
||||
|
||||
-- round position to center of node to avoid stuck in walls
|
||||
-- also adjust height for player models!
|
||||
|
@ -381,7 +383,7 @@ function mob_class:npc_attack()
|
|||
p.y = p.y + 1
|
||||
sp.y = sp.y + 1
|
||||
|
||||
if dist < min_dist and self:line_of_sight( sp, p, 2) == true then
|
||||
if dist < min_dist and self:line_of_sight(sp, p, 2) == true then
|
||||
min_dist = dist
|
||||
min_player = obj.object
|
||||
end
|
||||
|
@ -605,7 +607,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
|||
local v = self.object:get_velocity()
|
||||
if not v then return end
|
||||
local r = 1.4 - min(punch_interval, 1.4)
|
||||
local kb = r * (abs(v.x)+abs(v.z))
|
||||
local kb = r * sqrt(v.x*v.x+v.z*v.z)
|
||||
local up = 2.625
|
||||
|
||||
if die then kb = kb * 1.25 end
|
||||
|
@ -633,7 +635,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
|||
kb = kb + (abs(hv.x) + abs(hv.z)) * r
|
||||
end
|
||||
elseif luaentity and luaentity._knockback and die == false then
|
||||
kb = kb + luaentity._knockback
|
||||
kb = kb + luaentity._knockback * 0.25
|
||||
elseif luaentity and luaentity._knockback and die == true then
|
||||
kb = kb + luaentity._knockback * 0.25
|
||||
end
|
||||
|
@ -695,11 +697,8 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
|||
local alert_pos = hitter:get_pos()
|
||||
if alert_pos then
|
||||
local objs = minetest.get_objects_inside_radius(alert_pos, self.view_range)
|
||||
local obj = nil
|
||||
|
||||
for n = 1, #objs do
|
||||
obj = objs[n]:get_luaentity()
|
||||
|
||||
local obj = objs[n]:get_luaentity()
|
||||
if obj then
|
||||
-- only alert members of same mob or friends
|
||||
if obj.group_attack
|
||||
|
@ -768,17 +767,16 @@ function mob_class:do_states_attack(dtime)
|
|||
if self.timer > 100 then self.timer = 1 end
|
||||
|
||||
local s = self.object:get_pos()
|
||||
if not s then return end
|
||||
local p = self.attack:get_pos()
|
||||
if not s or not p then return end
|
||||
|
||||
local p = self.attack:get_pos() or s
|
||||
local yaw = self.object:get_yaw() or 0
|
||||
|
||||
-- stop attacking if player invisible or out of range
|
||||
if not self.attack
|
||||
or not self.attack:get_pos()
|
||||
or not self:object_in_range(self.attack)
|
||||
or self.attack:get_hp() <= 0
|
||||
or (self.attack:is_player() and mcl_mobs.invis[ self.attack:get_player_name() ]) then
|
||||
or (self.attack:is_player() and mcl_mobs.invis[self.attack:get_player_name()]) then
|
||||
|
||||
clear_aggro(self)
|
||||
return
|
||||
|
@ -955,7 +953,7 @@ function mob_class:do_states_attack(dtime)
|
|||
self.path.stuck_timer = 0
|
||||
self.path.following = false -- not stuck anymore
|
||||
|
||||
self:set_velocity( 0)
|
||||
self:set_velocity(0)
|
||||
|
||||
local attack_frequency = self.attack_frequency or 1
|
||||
|
||||
|
@ -997,21 +995,23 @@ function mob_class:do_states_attack(dtime)
|
|||
or (self.attack_type == "dogshoot" and (dist > self.reach or dist < self.avoid_distance and self.shooter_avoid_enemy) and self:dogswitch() == 0) then
|
||||
local vec = vector_new(p.x - s.x, p.y - s.y - 1, p.z - s.z)
|
||||
local dist = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)
|
||||
self:turn_in_direction(vec.x, vec.z, 1)
|
||||
local dir = -atan2(p.x - s.x, p.z - s.z)
|
||||
self:set_yaw(dir, 4)
|
||||
|
||||
if self.strafes then
|
||||
if not self.strafe_direction then self.strafe_direction = HALFPI end
|
||||
if random(40) == 1 then self.strafe_direction = self.strafe_direction * -1 end
|
||||
if not self.strafe_direction then self.strafe_direction = math.random(0, 1) * 2 - 1 end
|
||||
if random(50) == 1 then self.strafe_direction = -self.strafe_direction end
|
||||
|
||||
local dir = -atan2(p.x - s.x, p.z - s.z)
|
||||
self.acceleration.x = self.acceleration.x - sin(dir + self.strafe_direction) * 8
|
||||
self.acceleration.z = self.acceleration.z + cos(dir + self.strafe_direction) * 8
|
||||
--stay away from player so as to shoot them
|
||||
if self.avoid_distance and dist < self.avoid_distance and self.shooter_avoid_enemy then
|
||||
local f = (self.avoid_distance - dist) / self.avoid_distance
|
||||
--self:set_velocity(f * self.walk_velocity) --self.object:add_velocity(vector_new(-sin(dir) * f, 0, cos(dir) * f))
|
||||
self.acceleration.x = self.acceleration.x - sin(dir) * f * 8
|
||||
self.acceleration.z = self.acceleration.z + cos(dir) * f * 8
|
||||
if self.avoid_distance and self.shooter_avoid_enemy then
|
||||
local f = (dist - self.avoid_distance) / self.avoid_distance
|
||||
f = math.max(-1, math.min(1, f))
|
||||
f = f * math.abs(f)
|
||||
self:set_velocity(f * self.walk_velocity, (1 - math.abs(f)) * self.strafe_direction * self.walk_velocity * 1.5)
|
||||
elseif dist > 1 then
|
||||
self:set_velocity(self.walk_velocity)
|
||||
else
|
||||
self:set_velocity(0)
|
||||
end
|
||||
else
|
||||
self:set_velocity(0)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
local math, tonumber, vector, minetest, mcl_mobs = math, tonumber, vector, minetest, mcl_mobs
|
||||
local mob_class = mcl_mobs.mob_class
|
||||
local validate_vector = mcl_util.validate_vector
|
||||
--local validate_vector = mcl_util.validate_vector
|
||||
|
||||
local active_particlespawners = {}
|
||||
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
||||
|
@ -128,7 +128,7 @@ function mob_class:remove_texture_mod(mod)
|
|||
table.insert(remove, i)
|
||||
end
|
||||
end
|
||||
for i=#remove, 1 do
|
||||
for i=#remove, 1, -1 do
|
||||
table.remove(self.texture_mods, remove[i])
|
||||
end
|
||||
self.object:set_texture_mod(full_mod)
|
||||
|
@ -207,7 +207,7 @@ function mob_class:set_animation(anim, fixed_frame)
|
|||
elseif not self.object:get_attach() then
|
||||
self.jockey = nil
|
||||
end
|
||||
|
||||
|
||||
if self.state == "die" and anim ~= "die" and anim ~= "stand" then return end
|
||||
|
||||
if self.fly and self:flight_check() and anim == "walk" then anim = "fly" end
|
||||
|
@ -275,7 +275,8 @@ function mob_class:check_head_swivel(dtime)
|
|||
|
||||
who_are_you_looking_at(self, dtime)
|
||||
|
||||
local newr, oldp, oldr = vector.zero(), nil, nil
|
||||
local newr = vector.zero()
|
||||
local oldp, oldr
|
||||
if self.object.get_bone_override then -- minetest >= 5.9
|
||||
local ov = self.object:get_bone_override(self.head_swivel)
|
||||
oldp, oldr = ov.position.vec, ov.rotation.vec
|
||||
|
@ -327,7 +328,7 @@ function mob_class:check_head_swivel(dtime)
|
|||
elseif not locked_object and math.abs(oldr.y) > 0.05 and math.abs(oldr.x) < 0.05 then
|
||||
newr = vector.multiply(oldr, 0.9)
|
||||
end
|
||||
|
||||
|
||||
-- 0.02 is about 1.14 degrees tolerance, to update less often
|
||||
local newp = vector.new(0, self.bone_eye_height, self.horizontal_head_height)
|
||||
if math.abs(oldr.x-newr.x) + math.abs(oldr.y-newr.y) + math.abs(oldr.z-newr.z) < 0.02 and vector.equals(oldp, newp) then return end
|
||||
|
|
|
@ -38,7 +38,7 @@ local function line_of_sight(origin, target, see_through_opaque, liquids)
|
|||
end
|
||||
mcl_mobs.line_of_sight = line_of_sight
|
||||
|
||||
local NODE_IGNORE = { name = "ignore", groups = {} } -- fallback for unknown nodes
|
||||
mcl_mobs.NODE_IGNORE = { name = "ignore", groups = {} } -- fallback for unknown nodes
|
||||
|
||||
--api and helpers
|
||||
-- effects: sounds and particles mostly
|
||||
|
@ -417,7 +417,6 @@ function mcl_mobs.register_arrow(name, def)
|
|||
hit_object = def.hit_object,
|
||||
homing = def.homing,
|
||||
drop = def.drop or false, -- drops arrow as registered item when true
|
||||
collisionbox = {0, 0, 0, 0, 0, 0}, -- remove box around arrows
|
||||
timer = 0,
|
||||
switch = 0,
|
||||
_lifetime = def._lifetime or 7,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
local minetest, mcl_mobs = minetest, mcl_mobs
|
||||
local mob_class = mcl_mobs.mob_class
|
||||
--- Item and armor management
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime)
|
|||
-- jump
|
||||
if ctrl.jump then
|
||||
if velo.y == 0 then
|
||||
velo.y = velo.y + sqrt(entity.jump_height * 20)
|
||||
velo.y = velo.y + math.sqrt(entity.jump_height * 20)
|
||||
acce_y = acce_y + 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ local CHECK_HERD_FREQUENCY = 4
|
|||
|
||||
local PATHFINDING = "gowp"
|
||||
|
||||
local node_snow = "mcl_core:snow"
|
||||
local NODE_SNOW = "mcl_core:snow"
|
||||
|
||||
local logging = minetest.settings:get_bool("mcl_logging_mobs_movement", true)
|
||||
local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
|
||||
|
@ -16,7 +16,6 @@ local mobs_griefing = minetest.settings:get_bool("mobs_griefing", true)
|
|||
local random = math.random
|
||||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
local abs = math.abs
|
||||
local floor = math.floor
|
||||
local PI = math.pi
|
||||
local TWOPI = 2 * math.pi
|
||||
|
@ -24,12 +23,9 @@ local HALFPI = 0.5 * math.pi
|
|||
local QUARTERPI = 0.25 * math.pi
|
||||
|
||||
local vector_new = vector.new
|
||||
local vector_zero = vector.zero
|
||||
local vector_copy = vector.copy
|
||||
local vector_offset = vector.offset
|
||||
local vector_distance = vector.distance
|
||||
|
||||
local node_ok = mcl_mobs.node_ok
|
||||
local mobs_see_through_opaque = mcl_mobs.see_through_opaque
|
||||
local line_of_sight = mcl_mobs.line_of_sight
|
||||
|
||||
|
@ -286,24 +282,25 @@ function mob_class:do_jump()
|
|||
local nod = minetest.get_node(vector_offset(pos, dir_x, 0.5, dir_z)).name
|
||||
local ndef = minetest.registered_nodes[nod.name]
|
||||
-- thin blocks that do not need to be jumped
|
||||
if nod.name == node_snow or (ndef and ndef.groups.carpet or 0) > 0 then return false end
|
||||
|
||||
-- this is used to detect if there's a block on top of the block in front of the mob.
|
||||
-- If there is, there is no point in jumping as we won't manage.
|
||||
local node_top = minetest.get_node(vector_offset(pos, dir_x, 1.5, dir_z)).name
|
||||
-- TODO: also check above the mob itself?
|
||||
|
||||
-- we don't attempt to jump if there's a stack of blocks blocking, unless attacking
|
||||
local ntdef = minetest.registered_nodes[node_top]
|
||||
if ntdef and ntdef.walkable == true and not (self.attack and self.state == "attack") then return false end
|
||||
|
||||
if nod.name == NODE_SNOW or (ndef and ndef.groups.carpet or 0) > 0 then return false end
|
||||
-- nothing to jump on?
|
||||
if self.walk_chance ~= 0 and not (ndef and ndef.walkable) and not self._can_jump_cliff then return false end
|
||||
|
||||
-- facing a fence? jumping will not help (FIXME: consider jump height)
|
||||
if (ndef.groups.fence or 0) ~= 0 or (ndef.groups.fence_gate or 0) ~= 0 or (ndef.groups.wall or 0) ~= 0 then
|
||||
self.facing_fence = true
|
||||
return false
|
||||
end
|
||||
|
||||
-- this is used to detect if there's a block on top of the block in front of the mob.
|
||||
-- If there is, there is no point in jumping as we won't manage.
|
||||
local node_top = minetest.get_node(vector_offset(pos, dir_x, 1.5, dir_z)).name
|
||||
-- TODO: also check above the mob itself, and check the full mob height?
|
||||
|
||||
-- we don't attempt to jump if there's a stack of blocks blocking, unless attacking
|
||||
local ntdef = minetest.registered_nodes[node_top]
|
||||
-- TODO: snow, carpet?
|
||||
if ntdef and ntdef.walkable == true --[[and not (self.attack and self.state == "attack")]] then return false end
|
||||
|
||||
v.y = math.min(v.y, 0) + math.sqrt(self.jump_height * 20 + (in_water or self._can_jump_cliff and 10 or 0))
|
||||
v.y = math.min(-self.fall_speed, math.max(v.y, self.fall_speed))
|
||||
self.object:set_velocity(v)
|
||||
|
@ -385,7 +382,6 @@ function mob_class:replace_node(pos)
|
|||
on_replace_return = self.on_replace(self, pos, oldnode, newnode)
|
||||
end
|
||||
|
||||
|
||||
if on_replace_return ~= false then
|
||||
if mobs_griefing then
|
||||
minetest.after(self.replace_delay, function()
|
||||
|
@ -416,40 +412,32 @@ function mob_class:check_runaway_from()
|
|||
if not self.runaway_from and self.state ~= "flop" then return end
|
||||
|
||||
local s = self.object:get_pos()
|
||||
local p, sp, dist
|
||||
local player, obj, min_player
|
||||
local type, name = "", ""
|
||||
local min_dist = self.view_range + 1
|
||||
local min_dist, min_player = self.view_range + 1, nil
|
||||
local objs = minetest.get_objects_inside_radius(s, self.view_range)
|
||||
|
||||
for n = 1, #objs do
|
||||
local name, player = "", nil
|
||||
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 = ""
|
||||
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
|
||||
name = ""
|
||||
else
|
||||
player = objs[n]
|
||||
type = "player"
|
||||
name = "player"
|
||||
end
|
||||
else
|
||||
obj = objs[n]:get_luaentity()
|
||||
local 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
|
||||
dist = vector_distance(p, s)
|
||||
if name ~= "" and name ~= self.name and specific_runaway(self.runaway_from, name) then
|
||||
local p = player:get_pos()
|
||||
local dist = vector_distance(p, s)
|
||||
-- choose closest player/mpb to runaway from
|
||||
if dist < min_dist and line_of_sight(vector_offset(sp, 0, 1, 0), vector_offset(p, 0, 1, 0), self.see_through_opaque or mobs_see_through_opaque, false) then
|
||||
if dist < min_dist and line_of_sight(vector_offset(s, 0, 1, 0), vector_offset(p, 0, 1, 0), self.see_through_opaque or mobs_see_through_opaque, false) then
|
||||
-- aim higher to make looking up hills more realistic
|
||||
min_dist = dist
|
||||
min_player = player
|
||||
|
@ -458,7 +446,7 @@ function mob_class:check_runaway_from()
|
|||
end
|
||||
|
||||
if min_player then
|
||||
local lp = player:get_pos()
|
||||
local lp = min_player:get_pos()
|
||||
self:turn_in_direction(s.x - lp.x, s.z - lp.z, 4) -- away from player
|
||||
self.state = "runaway"
|
||||
self.runaway_timer = 3
|
||||
|
@ -474,10 +462,9 @@ function mob_class:check_follow()
|
|||
and self.state ~= "attack"
|
||||
and self.order ~= "sit"
|
||||
and self.state ~= "runaway" then
|
||||
local s = self.object:get_pos()
|
||||
local players = minetest.get_connected_players()
|
||||
for n = 1, #players do
|
||||
if (self:object_in_range(players[n])) and not mcl_mobs.invis[ players[n]:get_player_name() ] then
|
||||
if self:object_in_range(players[n]) and not mcl_mobs.invis[players[n]:get_player_name()] then
|
||||
self.following = players[n]
|
||||
break
|
||||
end
|
||||
|
@ -592,7 +579,7 @@ function mob_class:do_states_walk()
|
|||
-- Better way to find shore - copied from upstream
|
||||
local lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -5, -0.5, -5), vector_offset(s, 5, 1, 5), {"group:solid"})
|
||||
if #lp == 0 then
|
||||
local lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -10, -0.5, -10), vector_offset(s, 10, 1, 10), {"group:solid"})
|
||||
lp = minetest.find_nodes_in_area_under_air(vector_offset(s, -10, -0.5, -10), vector_offset(s, 10, 1, 10), {"group:solid"})
|
||||
end
|
||||
-- TODO: use node with smallest change in yaw instead of random?
|
||||
lp = #lp > 0 and lp[random(#lp)]
|
||||
|
@ -617,7 +604,7 @@ function mob_class:do_states_walk()
|
|||
-- facing wall? then turn
|
||||
local facing_wall = false
|
||||
-- todo: use moveresult collision info here?
|
||||
if moveresult and moveresult.collides and self:get_velocity_xyz() < 0.1 then
|
||||
if self.collides and self:get_velocity_xyz() < 0.1 then
|
||||
facing_wall = true
|
||||
else --if not facing_wall then
|
||||
local cbox = self.collisionbox
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs
|
||||
local mob_class = mcl_mobs.mob_class
|
||||
local validate_vector = mcl_util.validate_vector
|
||||
--local validate_vector = mcl_util.validate_vector
|
||||
|
||||
local MAX_DTIME = 0.25 -- todo: make user configurable?
|
||||
local ACCELERATION_MIX = 1.0 -- how much of acceleration to handle in Lua instead of MTE todo: make user configurable
|
||||
|
@ -20,9 +20,10 @@ local atan2 = math.atan2
|
|||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
local sqrt = math.sqrt
|
||||
local node_ok = mcl_mobs.node_ok
|
||||
--local node_ok = mcl_mobs.node_ok
|
||||
local NODE_IGNORE = mcl_mobs.NODE_IGNORE
|
||||
|
||||
local PATHFINDING = "gowp"
|
||||
--local PATHFINDING = "gowp"
|
||||
local mobs_drop_items = minetest.settings:get_bool("mobs_drop_items") ~= false
|
||||
local mob_active_range = tonumber(minetest.settings:get("mcl_mob_active_range")) or 48
|
||||
|
||||
|
@ -53,10 +54,11 @@ end
|
|||
-- these may be "nil" (= ignore) and are otherwise already resolved via minetest.registered_nodes
|
||||
function mob_class:update_standing(pos, moveresult)
|
||||
local temp_pos = vector.offset(pos, 0, self.collisionbox[2] + 0.5, 0) -- foot level
|
||||
self.collides = moveresult and moveresult.collides
|
||||
self.standing_in = minetest.registered_nodes[minetest.get_node(temp_pos).name] or NODE_IGNORE
|
||||
temp_pos.y = temp_pos.y - 1.5 -- below
|
||||
self.standing_on_node = minetest.get_node(temp_pos) -- to allow access to param2 in, e.g., stalker
|
||||
self.standing_on = standing_on or minetest.registered_nodes[self.standing_on_node.name] or NODE_IGNORE
|
||||
self.standing_on = self.standing_on_node and minetest.registered_nodes[self.standing_on_node.name] or NODE_IGNORE
|
||||
-- sometimes, we may be colliding with a node *not* below us, effectively standing on it instead (e.g., a corner)
|
||||
if not self.standing_on.walkable and moveresult and moveresult.collisions then
|
||||
-- to inspect: minetest.log("action", dump(moveresult):gsub(" *\n\\s*",""))
|
||||
|
@ -103,13 +105,10 @@ end
|
|||
|
||||
function mob_class:item_drop(cooked, looting_level)
|
||||
if not mobs_drop_items then return end
|
||||
if self.child and self.type ~= "monster" then return end
|
||||
looting_level = looting_level or 0
|
||||
|
||||
if (self.child and self.type ~= "monster") then return end
|
||||
|
||||
local obj, item, num
|
||||
local pos = self.object:get_pos()
|
||||
|
||||
self.drops = self.drops or {}
|
||||
|
||||
for n = 1, #self.drops do
|
||||
|
@ -139,7 +138,7 @@ function mob_class:item_drop(cooked, looting_level)
|
|||
end
|
||||
|
||||
if num > 0 then
|
||||
item = dropdef.name
|
||||
local item = dropdef.name
|
||||
|
||||
if cooked then
|
||||
local output = minetest.get_craft_result({method = "cooking", width = 1, items = {item}})
|
||||
|
@ -149,8 +148,7 @@ function mob_class:item_drop(cooked, looting_level)
|
|||
end
|
||||
|
||||
for x = 1, num do
|
||||
obj = minetest.add_item(pos, ItemStack(item .. " 1"))
|
||||
|
||||
local obj = minetest.add_item(pos, ItemStack(item .. " 1"))
|
||||
if obj and obj:get_luaentity() then
|
||||
obj:set_velocity(vector.new((random() - 0.5) * 1.5, 6, (random() - 0.5) * 1.5))
|
||||
elseif obj then
|
||||
|
@ -191,8 +189,11 @@ function mob_class:collision()
|
|||
end
|
||||
|
||||
-- move mob in facing direction
|
||||
function mob_class:set_velocity(v)
|
||||
-- @param v number: Velocity in direction the mob is facing
|
||||
-- @param o number, optional: Orthogonal velocity, for strafing
|
||||
function mob_class:set_velocity(v, o)
|
||||
self.target_vel = v
|
||||
self.target_orth = o
|
||||
end
|
||||
|
||||
-- calculate mob velocity (3d)
|
||||
|
@ -245,7 +246,7 @@ function mob_class:set_yaw(yaw, delay, dtime)
|
|||
end
|
||||
|
||||
-- name tag easter egg, test engine capabilities for rolling
|
||||
local function update_roll()
|
||||
--[[local function update_roll(self)
|
||||
local is_Fleckenstein = self.nametag == "Fleckenstein"
|
||||
if not is_Fleckenstein and not self.is_Fleckenstein then return end
|
||||
|
||||
|
@ -266,7 +267,7 @@ local function update_roll()
|
|||
self.object:set_pos(pos)
|
||||
end
|
||||
self.is_Fleckenstein = is_Fleckenstein
|
||||
end
|
||||
end]]
|
||||
|
||||
-- Improved smooth rotation
|
||||
-- @param dtime number: timestep length
|
||||
|
@ -288,7 +289,7 @@ function mob_class:smooth_rotation(dtime)
|
|||
yaw = yaw + (random() * 2 - 1) / 72 * dtime
|
||||
end
|
||||
if yaw ~= initial_yaw then self.object:set_yaw(yaw - self.rotate) end
|
||||
--update_roll() -- Fleckenstein easter egg
|
||||
--update_roll(self) -- Fleckenstein easter egg
|
||||
end
|
||||
|
||||
-- Handling of intentional acceleration by the mob
|
||||
|
@ -296,11 +297,13 @@ end
|
|||
-- TODO: have mobs that acccelerate faster and that accelerate slower?
|
||||
-- @param dtime number: timestep length
|
||||
function mob_class:smooth_acceleration(dtime)
|
||||
local yaw = self.target_yaw or (self.object:get_yaw() or 0) + self.rotate
|
||||
local vel = self.target_vel or 0
|
||||
local x, z = -sin(yaw) * vel, cos(yaw) * vel
|
||||
local yaw = self.move_yaw or self.target_yaw or (self.object:get_yaw() or 0) + self.rotate
|
||||
local vel = self.target_vel or 0 -- can also stop
|
||||
local x, z = -sin(yaw), cos(yaw)
|
||||
local orth = self.target_orth or 0 -- strafing
|
||||
x, z = x * vel + z * orth, z * vel + x * orth
|
||||
local v = self.object:get_velocity()
|
||||
local w = min(dtime * 5, 1)
|
||||
local w = 10 * min(dtime, 0.1) -- 0.1 time to fully change direction / accelerate
|
||||
v.x, v.z = v.x + w * (x - v.x), v.z + w * (z - v.z)
|
||||
self.object:set_velocity(v)
|
||||
end
|
||||
|
@ -874,7 +877,6 @@ function mob_class:limit_vel_acc_for_large_dtime(pos, dtime, moveresult)
|
|||
end
|
||||
|
||||
--- Update velocity and acceleration at the end of our movement logic
|
||||
--
|
||||
function mob_class:update_vel_acc(dtime)
|
||||
local vel = self.object:get_velocity()
|
||||
--vel.x, vel.y, vel.z = vel.x * visc, (vel.y + acc.y * dtime) * visc, vel.z * visc
|
||||
|
@ -913,7 +915,7 @@ function mob_class:check_water_flow(dtime, pos)
|
|||
-- Just to make sure we don't manipulate the speed for no reason
|
||||
if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then
|
||||
-- Minecraft Wiki: Flowing speed is "about 1.39 meters per second"
|
||||
local f = 8 -- but we have acceleration ehre, not velocity. Was: 1.39
|
||||
local f = 10 -- but we have acceleration here, not velocity. Was: 1.39
|
||||
-- Set new item moving speed into the direciton of the liquid
|
||||
self.acceleration = self.acceleration + vector.new(vec.x * f, -0.22, vec.z * f)
|
||||
--self.physical_state = true
|
||||
|
|
Loading…
Reference in New Issue