Mob motion improvements
* mods/ENTITIES/mcl_mobs/api.lua (on_step): Cease calling slow_mob or testing always_clime, and call motion_step each tick. * mods/ENTITIES/mcl_mobs/effects.lua (set_animation_speed): Don't integrate velocity. * mods/ENTITIES/mcl_mobs/init.lua (mcl_mobs): Adjust default jump height and fall speed to match Minecraft values. Specify default values of water_friction and water_velocity. (on_activate): Clear acc_dir and acc_speed. * mods/ENTITIES/mcl_mobs/movement.lua (do_jump): Set jumping flag if mob should jump. (follow_player): Reduce target distance to blocks. (do_states_stand, do_states_fly, swim_or_jump, do_states_swim): Remove calls to slow_mob. (climb): Delete function. * mods/ENTITIES/mcl_mobs/pathfinding.lua (check_gowp): Clear acceleration when halting mob. * mods/ENTITIES/mcl_mobs/physics.lua (collision): Optimize slightly and don't set fire to objects. (slow_mob): Delete function. (set_velocity): Set directional acceleration. (do_env_damage): Clear directional acceleration ignore when in unloaded block. (falling): Don't implement mob floating here. (check_water_flow): Just return water flow vectors. (check_dying): Clear directional acceleration. (pow_by_step, scale_speed, accelerate_relative, jump_actual) (jump_fluid, horiz_collision, clamp, check_collision) (motion_step): New functions. * mods/ENTITIES/mobs_mc/blaze.lua: * mods/ENTITIES/mobs_mc/chicken.lua: * mods/ENTITIES/mobs_mc/horse.lua: * mods/ENTITIES/mobs_mc/parrot.lua: * mods/ENTITIES/mobs_mc/zombie.lua: Adjust various constants to match Minecraft. * mods/ITEMS/mcl_enchanting/enchantments.lua (depth_strider_level): New function.
This commit is contained in:
parent
44fc00b66b
commit
c161afa948
@ -393,10 +393,6 @@ function mob_class:on_step(dtime, moveresult)
|
||||
|
||||
self:update_tag()
|
||||
|
||||
if not should_drive or self.steer_class ~= "follow_item" then
|
||||
self:slow_mob ()
|
||||
end
|
||||
|
||||
if not (moveresult and moveresult.touching_ground) and self:falling(pos) then return end
|
||||
|
||||
-- Get nodes early for use in other functions
|
||||
@ -415,6 +411,7 @@ function mob_class:on_step(dtime, moveresult)
|
||||
local pos_head = vector.offset(p, 0, cbox[5] - 0.5, 0)
|
||||
self.head_in = mcl_mobs.node_ok(pos_head, "air").name
|
||||
|
||||
self:motion_step (dtime, moveresult)
|
||||
self:falling (pos)
|
||||
|
||||
if self.force_step then
|
||||
@ -505,12 +502,6 @@ function mob_class:on_step(dtime, moveresult)
|
||||
if self:env_damage (dtime, pos) then return end
|
||||
if self:do_states(dtime) then return end
|
||||
|
||||
--mobs that can climb over stuff
|
||||
if self.always_climb
|
||||
and self:node_infront_ok(pos, 0).name ~= "air" then
|
||||
self:climb()
|
||||
end
|
||||
|
||||
if self.jump_sound_cooloff > 0 then
|
||||
self.jump_sound_cooloff = self.jump_sound_cooloff - dtime
|
||||
end
|
||||
|
@ -394,9 +394,6 @@ function mob_class:set_animation_speed(custom_speed)
|
||||
self.object:set_animation_frame_speed(25)
|
||||
end
|
||||
end
|
||||
if self.acc and mcl_mobs.check_vector(self.acc) then
|
||||
self.object:add_velocity(self.acc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -39,7 +39,7 @@ mcl_mobs.mob_class = {
|
||||
swims_in = { "mcl_core:water_source", "mclx_core:river_water_source", 'mcl_core:water_flowing', 'mclx_core:river_water_flowing' },
|
||||
owner = "",
|
||||
order = "",
|
||||
jump_height = 4, -- was 6
|
||||
jump_height = 8.4,
|
||||
rotate = 0, -- 0=front, 90=side, 180=back, 270=side2
|
||||
xp_min = 0,
|
||||
xp_max = 0,
|
||||
@ -58,7 +58,7 @@ mcl_mobs.mob_class = {
|
||||
_mcl_freeze_damage = 2,
|
||||
suffocation = true,
|
||||
fall_damage = 1,
|
||||
fall_speed = -9.81 * 1.5,
|
||||
fall_speed = -1.6, -- Accelerate by 1.6 m/s per Minecraft tick.
|
||||
drops = {},
|
||||
armor = 100,
|
||||
sounds = {},
|
||||
@ -72,6 +72,8 @@ mcl_mobs.mob_class = {
|
||||
shoot_offset = 0,
|
||||
floats = 1,
|
||||
floats_on_lava = 0,
|
||||
water_friction = 0.8,
|
||||
water_velocity = 0.4,
|
||||
replace_offset = 0,
|
||||
replace_delay = 0,
|
||||
timer = 0,
|
||||
@ -321,6 +323,8 @@ function mcl_mobs.register_mob(name, def)
|
||||
collide_with_objects = false,
|
||||
})
|
||||
self._physics_factors = {}
|
||||
self.acc_dir = vector.zero ()
|
||||
self.acc_speed = 0
|
||||
|
||||
self._timers = {}
|
||||
return self:mob_activate(staticdata, dtime)
|
||||
|
@ -356,7 +356,6 @@ function mob_class:drive_controls(moving_anim, stand_anim, can_fly, dtime)
|
||||
local s = get_sign(self.v)
|
||||
self.v = self.v - 0.02 * s
|
||||
if s ~= get_sign(self.v) then
|
||||
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.v = 0
|
||||
return
|
||||
|
@ -419,43 +419,8 @@ function mob_class:do_jump()
|
||||
and minetest.get_item_group(nod.name, "fence_gate") == 0
|
||||
and minetest.get_item_group(nod.name, "wall") == 0
|
||||
then
|
||||
local dir_x, dir_z = self:forward_directions()
|
||||
-- Extensive testing to get this to work ...
|
||||
local v = vector.new(dir_x, self.jump_height + 0.5 * 10, dir_z)
|
||||
|
||||
if not in_water and self:can_jump_cliff() then
|
||||
v = vector.multiply(v, vector.new(2.8, 1, 2.8))
|
||||
end
|
||||
|
||||
-- ensure we don't turn if we are trying to jump up something
|
||||
self.order = "jump"
|
||||
self:set_animation("jump")
|
||||
walk_log("jump at: " .. minetest.pos_to_string(self.object:get_pos()))
|
||||
|
||||
self.object:set_velocity(v)
|
||||
self.object:set_acceleration(vector.new(v.x, 1, v.z))
|
||||
|
||||
-- when in air move forward
|
||||
minetest.after(0.3, function(self, v)
|
||||
if (not self.object) or (not self.object:get_luaentity()) or (self.state == "die") then
|
||||
return
|
||||
end
|
||||
walk_log("move forward at: " .. minetest.pos_to_string(self.object:get_pos()))
|
||||
self.object:set_acceleration(vector.new(v.x * 5, DEFAULT_FALL_SPEED, v.z * 5))
|
||||
|
||||
if self.order == "jump" then
|
||||
self.order = ""
|
||||
if self.state == "stand" then
|
||||
self:set_velocity(self.walk_velocity)
|
||||
self:set_state("walk")
|
||||
self:set_animation("walk")
|
||||
end
|
||||
end
|
||||
end, self, v)
|
||||
|
||||
if self:check_timer("jump_sound_cooloff", self.jump_sound_cooloff) then
|
||||
self:mob_sound("jump")
|
||||
end
|
||||
else
|
||||
self.facing_fence = true
|
||||
end
|
||||
@ -682,8 +647,7 @@ function mob_class:follow_player()
|
||||
if p.x > s.x then yaw = yaw +math.pi end
|
||||
self:set_yaw( yaw, 2.35)
|
||||
-- anyone but standing npc's can move along
|
||||
if dist > 3
|
||||
and self.order ~= "stand" then
|
||||
if dist > 2 and self.order ~= "stand" then
|
||||
self:set_velocity(self.follow_velocity)
|
||||
if self.walk_chance ~= 0 then
|
||||
self:set_animation( "run")
|
||||
@ -893,7 +857,6 @@ function mob_class:do_states_stand()
|
||||
if self.order == "sleep" then
|
||||
self:set_animation("stand")
|
||||
self:set_velocity(0)
|
||||
self:slow_mob()
|
||||
return
|
||||
end
|
||||
|
||||
@ -934,11 +897,9 @@ function mob_class:do_states_stand()
|
||||
if self.order == "sit" then
|
||||
self:set_animation("sit")
|
||||
self:set_velocity(0)
|
||||
self:slow_mob()
|
||||
else
|
||||
self:set_animation("stand")
|
||||
self:set_velocity(0)
|
||||
self:slow_mob()
|
||||
end
|
||||
|
||||
--walk_log("stand in " .. self.standing_in .. ", on " .. self.standing_on)
|
||||
@ -1020,13 +981,11 @@ function mob_class:do_states_fly()
|
||||
|
||||
if self:should_flap() then
|
||||
fly_log("flapping?")
|
||||
self:slow_mob()
|
||||
self:set_animation("walk")
|
||||
else
|
||||
self:set_velocity(0)
|
||||
self:set_state("stand")
|
||||
self:set_animation("stand")
|
||||
self:slow_mob()
|
||||
fly_log("standing or floating?")
|
||||
end
|
||||
else
|
||||
@ -1137,7 +1096,6 @@ function mob_class:swim_or_jump()
|
||||
--self.object:set_acceleration({ x = 0, y = -1.5, z = 0 })
|
||||
self.object:set_acceleration({ x = 0, y = DEFAULT_FALL_SPEED, z = 0 })
|
||||
--local dir_x, dir_z = self:forward_directions()
|
||||
self:slow_mob()
|
||||
--self.object:set_velocity(vector.new(dir_x, -1, dir_z))
|
||||
self:set_animation("walk")
|
||||
self:set_state("swim")
|
||||
@ -1222,7 +1180,6 @@ function mob_class:do_states_swim()
|
||||
if self.facing_fence == true or facing_solid or math.random(1, 100) <= 30 then
|
||||
self:set_state("stand")
|
||||
self:turn_away(3)
|
||||
self:slow_mob()
|
||||
if self.object:get_velocity().y < 0.1 then
|
||||
self:set_animation("stand")
|
||||
else
|
||||
@ -1286,17 +1243,3 @@ function mob_class:check_smooth_rotation(dtime)
|
||||
end
|
||||
-- end rotation
|
||||
end
|
||||
|
||||
--this is a generic climb function
|
||||
function mob_class:climb()
|
||||
local current_velocity = self.object:get_velocity()
|
||||
local goal_velocity = {x=0, y=3, z=0}
|
||||
local new_velocity_addition = vector.subtract(goal_velocity,current_velocity)
|
||||
new_velocity_addition.x = 0
|
||||
new_velocity_addition.z = 0
|
||||
|
||||
--smooths out mobs a bit
|
||||
if vector.length(new_velocity_addition) >= 0.0001 then
|
||||
self.object:add_velocity(new_velocity_addition)
|
||||
end
|
||||
end
|
||||
|
@ -225,6 +225,7 @@ function mob_class:check_gowp()
|
||||
self.order = "stand"
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
self.acc_dir = vector.zero ()
|
||||
if self.callback_arrived then return self.callback_arrived(self) end
|
||||
return true
|
||||
end
|
||||
@ -257,6 +258,7 @@ function mob_class:check_gowp()
|
||||
self._pf_last_failed = os.time()
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
self.acc_dir = vector.zero ()
|
||||
return
|
||||
end
|
||||
self:go_to_pos(self.current_target["pos"])
|
||||
|
@ -155,18 +155,12 @@ function mob_class:collision()
|
||||
if not pos then return {0,0} end
|
||||
local x = 0
|
||||
local z = 0
|
||||
local cbox = self.object:get_properties().collisionbox
|
||||
local cbox = self.initial_properties.collisionbox
|
||||
local width = -cbox[1] + cbox[4]
|
||||
|
||||
for object in minetest.objects_inside_radius(pos, width) do
|
||||
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
|
||||
local ent = object:get_luaentity()
|
||||
if (self.pushable and object:is_player()) or
|
||||
(self.mob_pushable and ent and ent.is_mob and object ~= self.object) then
|
||||
|
||||
if object:is_player() and mcl_burning.is_burning(self.object) then
|
||||
mcl_burning.set_on_fire(object, 4)
|
||||
end
|
||||
|
||||
if (self.pushable and object:is_player())
|
||||
or (self.mob_pushable and ent and ent.is_mob and object ~= self.object) then
|
||||
local pos2 = object:get_pos()
|
||||
local vec = {x = pos.x - pos2.x, z = pos.z - pos2.z}
|
||||
local force = width - vector.distance(
|
||||
@ -178,43 +172,22 @@ function mob_class:collision()
|
||||
end
|
||||
end
|
||||
|
||||
return({x,z})
|
||||
end
|
||||
|
||||
function mob_class:slow_mob()
|
||||
local d = 0.80
|
||||
if self:check_dying() then d = 0.92 end
|
||||
|
||||
if self.object then
|
||||
local v = self.object:get_velocity()
|
||||
if v then
|
||||
--diffuse object velocity
|
||||
local y = v.y
|
||||
if y > 0 then
|
||||
y = y * d
|
||||
end
|
||||
|
||||
self.object:set_velocity({ x = v.x * d, y = y, z = v.z * d })
|
||||
end
|
||||
end
|
||||
return x, z
|
||||
end
|
||||
|
||||
-- move mob in facing direction
|
||||
function mob_class:set_velocity(v)
|
||||
local c_x, c_y = 0, 0
|
||||
-- can mob be pushed, if so calculate direction
|
||||
if self.pushable or self.mob_pushable then
|
||||
c_x, c_y = unpack(self:collision())
|
||||
end
|
||||
-- halt mob if it has been ordered to stay
|
||||
if self.order == "stand" or self.order == "sit" then
|
||||
self.acc=vector.new(0,0,0)
|
||||
return
|
||||
self.acc_speed = 0
|
||||
self.acc_dir.z = 0
|
||||
return
|
||||
end
|
||||
local yaw = (self.object:get_yaw() or 0) + self.rotate
|
||||
local vv = self.object:get_velocity()
|
||||
if vv and yaw then
|
||||
self.acc = vector.new(((math.sin(yaw) * -v) + c_x) * .4, 0, ((math.cos(yaw) * v) + c_y) * .4)
|
||||
self.acc_speed = v
|
||||
self.acc_dir.z = v
|
||||
end
|
||||
end
|
||||
|
||||
@ -263,8 +236,6 @@ local function shortest_term_of_yaw_rotation(_, rot_origin, rot_target, nums)
|
||||
return 1
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- set and return valid yaw
|
||||
function mob_class:set_yaw(yaw, delay, dtime)
|
||||
if self.noyaw then return end
|
||||
@ -613,6 +584,7 @@ function mob_class:do_env_damage()
|
||||
-- don't fall when on ignore, just stand still
|
||||
if self.standing_in == "ignore" then
|
||||
self.object:set_velocity({x = 0, y = 0, z = 0})
|
||||
self.acc_dir = vector.zero ()
|
||||
-- wither rose effect
|
||||
elseif self.standing_in == "mcl_flowers:wither_rose" then
|
||||
mcl_potions.give_effect_by_level("withering", self.object, 2, 2)
|
||||
@ -871,38 +843,14 @@ function mob_class:falling(pos)
|
||||
return
|
||||
end
|
||||
|
||||
local v = self.object:get_velocity()
|
||||
-- floating in water (or falling)
|
||||
if v.y > 0 and v.y < -self.fall_speed then
|
||||
-- when moving up, always use gravity
|
||||
self.object:set_acceleration(vector.new(0, self.fall_speed, 0))
|
||||
elseif v.y <= 0 and v.y > self.fall_speed then
|
||||
-- fall downwards at set speed
|
||||
self.object:set_acceleration(vector.new(0, self.fall_speed, 0))
|
||||
else
|
||||
-- stop accelerating once max fall speed hit
|
||||
self.object:set_acceleration(vector.zero())
|
||||
end
|
||||
if self._just_portaled then
|
||||
self.reset_fall_damage = 1
|
||||
return false -- mob has teleported through portal - it's 99% not falling
|
||||
end
|
||||
|
||||
if minetest.registered_nodes[mcl_mobs.node_ok(pos).name].groups.lava then
|
||||
if self.floats_on_lava == 1 then
|
||||
self.object:set_acceleration(vector.new(0, -self.fall_speed / (math.max(1, v.y) ^ 2), 0))
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.registered_nodes[mcl_mobs.node_ok(pos).name].name == "mcl_powder_snow:powder_snow" then
|
||||
self.reset_fall_damage = 1
|
||||
end
|
||||
-- in water then float up
|
||||
if minetest.registered_nodes[mcl_mobs.node_ok(pos).name].groups.water then
|
||||
local cbox = self.object:get_properties().collisionbox
|
||||
if self.floats == 1 and minetest.registered_nodes[mcl_mobs.node_ok(vector.offset(pos,0,cbox[5] -0.25,0)).name].groups.water then
|
||||
self.object:set_acceleration(vector.new(0, -self.fall_speed / (math.max(1, v.y) ^ 2), 0))
|
||||
end
|
||||
else if minetest.registered_nodes[mcl_mobs.node_ok(pos).name].groups.water then
|
||||
-- Reset fall damage when falling into water first.
|
||||
self.reset_fall_damage = 1
|
||||
else
|
||||
@ -928,41 +876,26 @@ function mob_class:falling(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:check_water_flow()
|
||||
-- Add water flowing for mobs from mcl_item_entity
|
||||
function mob_class:check_water_flow ()
|
||||
local p, node, nn, def
|
||||
p = self.object:get_pos()
|
||||
node = minetest.get_node_or_nil(p)
|
||||
p = self.object:get_pos ()
|
||||
node = minetest.get_node_or_nil (p)
|
||||
if node then
|
||||
nn = node.name
|
||||
def = minetest.registered_nodes[nn]
|
||||
end
|
||||
-- Move item around on flowing liquids
|
||||
if def and def.liquidtype == "flowing" then
|
||||
--[[ Get flowing direction (function call from flowlib), if there's a liquid.
|
||||
NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7.
|
||||
Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]]
|
||||
-- Get flowing direction (function call from flowlib),
|
||||
-- if there's a liquid. NOTE: According to
|
||||
-- Qwertymine, flowlib.quickflow is only reliable for
|
||||
-- liquids with a flowing distance of 7. Luckily,
|
||||
-- this is exactly what we need if we only care about
|
||||
-- water, which has this flowing distance.
|
||||
local vec = flowlib.quick_flow(p, node)
|
||||
-- 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 = 1.39
|
||||
-- Set new item moving speed into the direciton of the liquid
|
||||
local newv = vector.multiply(vec, f)
|
||||
self.object:set_acceleration({x = 0, y = 0, z = 0})
|
||||
self.object:set_velocity({x = newv.x, y = -0.22, z = newv.z})
|
||||
self.physical_state = true
|
||||
self._flowing = true
|
||||
self.object:set_properties({
|
||||
physical = true
|
||||
})
|
||||
return
|
||||
end
|
||||
elseif self._flowing == true then
|
||||
-- Disable flowing physics if not on/in flowing liquid
|
||||
self._flowing = false
|
||||
return
|
||||
return vector.normalize (vec)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function mob_class:check_dying(reason, cmi_cause)
|
||||
@ -987,6 +920,7 @@ function mob_class:check_suspend()
|
||||
if acc.y > 0 or node_under ~= "air" then
|
||||
self.object:set_acceleration(vector.new(0,0,0))
|
||||
self.object:set_velocity(vector.new(0,0,0))
|
||||
self.object:acc_dir = vector.zero ()
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -1017,3 +951,224 @@ function mob_class:remove_physics_factor (field, id)
|
||||
self._physics_factors[field][id] = nil
|
||||
apply_physics_factors (self, field, id)
|
||||
end
|
||||
|
||||
-- Mob motion routines.
|
||||
|
||||
--- Constants. These remain constant for the duration of the game but
|
||||
--- are adjusted so as to reflect the global step time.
|
||||
|
||||
-- TODO: read floating point settings.
|
||||
-- local step_length = minetest.settings:get ("dedicated_server_step")
|
||||
-- step_length = tonumber (step_length) or 0.09
|
||||
-- local step_length = 0.05
|
||||
|
||||
local function pow_by_step (value, dtime)
|
||||
return math.pow (value, dtime / 0.05)
|
||||
end
|
||||
|
||||
local AIR_DRAG = 0.98
|
||||
local AIR_FRICTION = 0.91
|
||||
local WATER_DRAG = 0.8
|
||||
local LAVA_FRICTION = 0.5
|
||||
local LAVA_SPEED = 0.4
|
||||
local BASE_SLIPPERY = 0.98
|
||||
local BASE_FRICTION = 0.6
|
||||
local LIQUID_FORCE = 0.28
|
||||
local BASE_FRICTION3 = math.pow (0.6, 3)
|
||||
|
||||
local function scale_speed (speed, friction)
|
||||
local f = BASE_FRICTION3 / (friction * friction * friction)
|
||||
return speed * f
|
||||
end
|
||||
|
||||
function mob_class:accelerate_relative (acc, speed)
|
||||
local yaw = self.object:get_yaw ()
|
||||
acc = vector.length (acc) == 1 and acc or vector.normalize (acc)
|
||||
-- vector.rotate_around_axis is surprisingly inefficient.
|
||||
-- local rv = vector.rotate_around_axis (acc, {x = 0, y = 1, z = 0,}, yaw)
|
||||
local s = -math.sin (yaw)
|
||||
local c = math.cos (yaw)
|
||||
local rv = vector.new (acc.x * c + acc.z * s, 0, acc.z * c - acc.x * s)
|
||||
return vector.multiply (rv, speed)
|
||||
end
|
||||
|
||||
function mob_class:jump_actual (v)
|
||||
self.order = ""
|
||||
-- TODO: animation
|
||||
v = {x = v.x, y = self.jump_height, z = v.z,}
|
||||
if self:can_jump_cliff () then
|
||||
v = vector.multiply (v, vector.new (2.8, 1, 2.8))
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
function mob_class:jump_fluid (v)
|
||||
self.order = ""
|
||||
v = {x = v.x, y = 0.8, z = v.z,}
|
||||
return v
|
||||
end
|
||||
|
||||
local function horiz_collision (v, moveresult)
|
||||
for _, item in ipairs (moveresult.collisions) do
|
||||
if item.type == "node"
|
||||
and (item.axis == "x" or item.axis == "z") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return moveresult.collides and not (moveresult.standing_on_object or moveresult.touching_ground)
|
||||
end
|
||||
|
||||
--- TODO: correct direct invocations of set_acceleration and the like
|
||||
--- TODO: flying and swimming mobs
|
||||
--- TODO: correct uses of fall_speed and other modified fields
|
||||
--- TODO: centralized motion control
|
||||
|
||||
local function clamp (num, min, max)
|
||||
return math.min (max, math.max (num, min))
|
||||
end
|
||||
|
||||
function mob_class:check_collision ()
|
||||
-- can mob be pushed, if so calculate direction
|
||||
if self.pushable or self.mob_pushable then
|
||||
local c_x, c_y = self:collision ()
|
||||
self.object:add_velocity ({x = c_x, y = 0, z = c_y})
|
||||
end
|
||||
end
|
||||
|
||||
function mob_class:motion_step (dtime, moveresult)
|
||||
local standin = minetest.registered_nodes[self.standing_in]
|
||||
local standon = minetest.registered_nodes[self.standing_on]
|
||||
local acc_dir = self.acc_dir
|
||||
local acc_speed = self.acc_speed
|
||||
local fall_speed = self.fall_speed
|
||||
local touching_ground = moveresult.touching_ground or moveresult.standing_on_object
|
||||
local jumping = self.order == "jump"
|
||||
local p
|
||||
local h_scale
|
||||
local climbing = false
|
||||
|
||||
self:check_dying ()
|
||||
self:check_collision ()
|
||||
|
||||
p = pow_by_step (AIR_DRAG, dtime)
|
||||
acc_dir.x = acc_dir.x * p
|
||||
acc_dir.z = acc_dir.z * p
|
||||
|
||||
f = AIR_FRICTION
|
||||
local v = self.object:get_velocity ()
|
||||
|
||||
-- If standing on a climable block and jumping or impeded
|
||||
-- horizontally, begin climbing, and prevent fall speed from
|
||||
-- exceeding 3.0 blocks/s.
|
||||
if (self.always_climb and horiz_collision (v, moveresult))
|
||||
or standin.climbable or standon.climbable then
|
||||
if v.y < -3.0 then
|
||||
v.y = -3.0
|
||||
end
|
||||
v.x = clamp (v.x, -3.0, 3.0)
|
||||
v.z = clamp (v.z, -3.0, 3.0)
|
||||
if jumping or horiz_collision (v, moveresult) then
|
||||
v.y = 4.0
|
||||
jumping = false
|
||||
self.order = ""
|
||||
end
|
||||
climbing = true
|
||||
self.reset_fall_damage = 1
|
||||
end
|
||||
|
||||
local water_vec = self:check_water_flow ()
|
||||
|
||||
if standin.groups.water then
|
||||
local friction = self.water_friction
|
||||
local speed = self.water_velocity
|
||||
|
||||
-- Apply depth strider.
|
||||
local level = math.min (3, mcl_enchanting.depth_strider_level (self))
|
||||
level = touching_ground and level or level / 2
|
||||
if level > 0 then
|
||||
local delta = BASE_FRICTION * AIR_FRICTION - friction
|
||||
friction = friction + delta * level / 3
|
||||
delta = acc_speed - speed
|
||||
speed = speed + delta * level / 3
|
||||
end
|
||||
|
||||
-- TODO: apply Dolphin's Grace.
|
||||
|
||||
-- Adjust speed by friction.
|
||||
local r, z = pow_by_step (friction, dtime), friction
|
||||
h_scale = (1 - r) / (1 - z)
|
||||
speed = speed * h_scale
|
||||
|
||||
local fv = self:accelerate_relative (acc_dir, speed)
|
||||
p = pow_by_step (WATER_DRAG, dtime)
|
||||
|
||||
-- Apply friction.
|
||||
v = vector.new (v.x * r, v.y * p, v.z * r)
|
||||
|
||||
-- Apply the new velocity in whole.
|
||||
v.y = v.y + fall_speed * (1 - p) / (1 - WATER_DRAG)
|
||||
v = vector.add (v, fv)
|
||||
elseif standin.groups.lava then
|
||||
local speed = LAVA_SPEED
|
||||
local r, z = pow_by_step (LAVA_FRICTION, dtime), LAVA_FRICTION
|
||||
h_scale = (1 - r) / (1 - z)
|
||||
speed = speed * h_scale
|
||||
local fv = self:accelerate_relative (acc_dir, speed)
|
||||
v = vector.multiply (v, r)
|
||||
v.y = v.y + fall_speed * h_scale
|
||||
v = vector.add (v, fv)
|
||||
else
|
||||
-- If not standing on air, apply slippery to a base value of
|
||||
-- 0.6.
|
||||
local slippery = standon.groups.slippery
|
||||
local friction
|
||||
if slippery and slippery > 0 then
|
||||
friction = BASE_SLIPPERY
|
||||
else
|
||||
friction = BASE_FRICTION
|
||||
end
|
||||
|
||||
-- Apply friction, relative movement, and speed.
|
||||
local speed
|
||||
|
||||
if touching_ground or climbing then
|
||||
speed = scale_speed (acc_speed, friction)
|
||||
else
|
||||
speed = 0.04 -- 0.04 blocks/s
|
||||
end
|
||||
friction = friction * AIR_FRICTION
|
||||
|
||||
-- Adjust speed by friction.
|
||||
local r, z = pow_by_step (friction, dtime), friction
|
||||
h_scale = (1 - r) / (1 - z)
|
||||
speed = speed * h_scale
|
||||
|
||||
local fv = self:accelerate_relative (acc_dir, speed)
|
||||
local new_y = v.y + fall_speed * (1 - p) / (1 - AIR_DRAG)
|
||||
v = vector.new (v.x * r, new_y * p, v.z * r)
|
||||
|
||||
-- Apply the new velocity in whole.
|
||||
v = vector.add (v, fv)
|
||||
end
|
||||
|
||||
if water_vec ~= nil and vector.length (water_vec) ~= 0 then
|
||||
v.x = v.x + water_vec.x * LIQUID_FORCE * h_scale
|
||||
v.z = v.z + water_vec.z * LIQUID_FORCE * h_scale
|
||||
end
|
||||
|
||||
if self.gravity_drag and v.y < 0 and not touching_ground then
|
||||
local f = pow_by_step (self.gravity_drag, dtime)
|
||||
v.y = v.y * f
|
||||
end
|
||||
|
||||
if touching_ground and jumping then
|
||||
if standin.groups.water or standin.groups.lava then
|
||||
v = self:jump_fluid (v)
|
||||
else
|
||||
v = self:jump_actual (v)
|
||||
end
|
||||
end
|
||||
|
||||
self.object:set_velocity (v)
|
||||
end
|
||||
|
@ -79,6 +79,7 @@ mcl_mobs.register_mob("mobs_mc:blaze", {
|
||||
fire_damage = 0,
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
gravity_drag = 0.6,
|
||||
light_damage = 0,
|
||||
view_range = 16,
|
||||
attack_type = "dogshoot",
|
||||
|
@ -51,7 +51,7 @@ mcl_mobs.register_mob("mobs_mc:chicken", {
|
||||
looting = "common",},
|
||||
},
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
gravity_drag = 0.6,
|
||||
sounds = {
|
||||
random = "mobs_mc_chicken_buck",
|
||||
damage = "mobs_mc_chicken_hurt",
|
||||
|
@ -149,7 +149,7 @@ local horse = {
|
||||
floats = 1,
|
||||
makes_footstep_sound = true,
|
||||
jump = true,
|
||||
jump_height = 5.75,
|
||||
jump_height = 15,
|
||||
drops = { base_drop },
|
||||
should_drive = function (self)
|
||||
return self._saddle and mob_class.should_drive (self)
|
||||
@ -498,7 +498,7 @@ local donkey = table.merge(horse, {
|
||||
horse.collisionbox[6] * d,
|
||||
},
|
||||
jump = true,
|
||||
jump_height = 3.75,
|
||||
jump_height = 15,
|
||||
})
|
||||
|
||||
mcl_mobs.register_mob("mobs_mc:donkey", donkey)
|
||||
|
@ -166,8 +166,8 @@ mcl_mobs.register_mob("mobs_mc:parrot", {
|
||||
-- TODO: more unused animations between 45 and 130
|
||||
},
|
||||
fall_damage = 0,
|
||||
fall_speed = -2.25,
|
||||
attack_type = "dogfight",
|
||||
gravity_drag = 0.6,
|
||||
floats = 1,
|
||||
physical = true,
|
||||
walk_velocity = 0.5,
|
||||
|
@ -89,7 +89,7 @@ local zombie = {
|
||||
fear_height = 4,
|
||||
pathfinding = 1,
|
||||
jump = true,
|
||||
jump_height = 4,
|
||||
jump_height = 8.4,
|
||||
group_attack = { "mobs_mc:zombie", "mobs_mc:baby_zombie", "mobs_mc:husk", "mobs_mc:baby_husk" },
|
||||
drops = drops_zombie,
|
||||
animation = {
|
||||
|
@ -107,6 +107,11 @@ mcl_player.register_globalstep_slow(function(player)
|
||||
end
|
||||
end)
|
||||
|
||||
function mcl_enchanting.depth_strider_level (mob)
|
||||
-- TODO: depth strider for mobs.
|
||||
return 0
|
||||
end
|
||||
|
||||
-- implemented via on_enchant
|
||||
mcl_enchanting.enchantments.efficiency = {
|
||||
name = S("Efficiency"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user