Rewrite the head swivel code math

This commit is contained in:
kno10 2024-11-11 17:29:07 +01:00 committed by the-real-herowl
parent 4e8c8f1cde
commit c6c77766e3
28 changed files with 243 additions and 236 deletions

@ -5,7 +5,11 @@ local validate_vector = mcl_util.validate_vector
local active_particlespawners = {}
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
local DEFAULT_FALL_SPEED = -9.81*1.5
local PI_THIRD = math.pi / 3 -- 60 degrees
local PI = math.pi
local TWOPI = math.pi * 2
local PI_HALF = math.pi * 0.5 -- 90 degrees
local MAX_PITCH = math.pi * 0.45 -- about 80 degrees
local MAX_YAW = math.pi * 0.66 -- about 120 degrees
local PATHFINDING = "gowp"
@ -348,13 +352,8 @@ function mob_class:check_head_swivel(dtime)
local locked_object = self._locked_object
if locked_object and (locked_object:is_player() or locked_object:get_luaentity()) and locked_object:get_hp() > 0 then
local _locked_object_eye_height = 1.5
if locked_object:is_player() then
_locked_object_eye_height = locked_object:get_properties().eye_height
elseif locked_object:get_luaentity() then
_locked_object_eye_height = locked_object:get_luaentity().head_eye_height
end
if _locked_object_eye_height then
local _locked_object_eye_height = (locked_object:is_player() and locked_object:get_properties().eye_height * 0.8) -- food in hands of player
or (locked_object:get_luaentity() and locked_object:get_luaentity().head_eye_height) or 1.5
local self_rot = self.object:get_rotation()
-- If a mob is attached, should we really be messing with what they are looking at?
-- Should this be excluded?
@ -363,43 +362,52 @@ function mob_class:check_head_swivel(dtime)
end
local ps = self.object:get_pos()
ps.y = ps.y + self.head_eye_height * .7
ps.y = ps.y + self.head_eye_height -- why here, instead of below? * .7
local pt = locked_object:get_pos()
pt.y = pt.y + _locked_object_eye_height
local dir = vector.direction(ps, pt)
local mob_yaw = self_rot.y + math.atan2(dir.x, dir.z) + self.head_yaw_offset
local mob_pitch = math.asin(-dir.y) * self.head_pitch_multiplier
local dir = vector.direction(ps, pt) -- is (pt-ps):normalize()
local mob_yaw = math.atan2(dir.x, dir.z)
local mob_pitch = -math.asin(dir.y) * (self.head_pitch_multiplier or 1) -- allow axis inversion
if (mob_yaw < -PI_THIRD or mob_yaw > PI_THIRD) and not (self.attack and self.state == "attack" and not self.runaway) then
newr = vector.multiply(oldr, 0.9)
elseif self.attack and self.state == "attack" and not self.runaway then
mob_yaw = mob_yaw + self_rot.y -- to relative orientation
while mob_yaw > PI do mob_yaw = mob_yaw - TWOPI end
while mob_yaw < -PI do mob_yaw = mob_yaw + TWOPI end
mob_yaw = mob_yaw * 0.8 -- lessen the effect so it become less staring
local max_yaw = self.head_max_yaw or MAX_YAW
mob_yaw = (mob_yaw < -max_yaw and -max_yaw) or (mob_yaw < max_yaw and mob_yaw) or max_yaw -- avoid twisting the neck
mob_pitch = mob_pitch * 0.8 -- make it less obvious that this is computed
local max_pitch = self.head_max_pitch or MAX_PITCH
mob_pitch = (mob_pitch < -max_pitch and -max_pitch) or (mob_pitch < max_pitch and mob_pitch) or max_pitch
local smoothing = (self.state == "attack" and self.attack and 0.25) or 0.05
local old_pitch = oldr.x
local old_yaw = (self.head_yaw == "y" and oldr.y or -oldr.z) - self.head_yaw_offset
-- to -pi:+pi range, so we rotate over 0 when interpolating:
while old_yaw > PI do old_yaw = old_yaw - TWOPI end
while old_yaw < -PI do old_yaw = old_yaw + TWOPI end
mob_pitch, mob_yaw = (mob_pitch-old_pitch)*smoothing+old_pitch, (mob_yaw-old_yaw)*smoothing+old_yaw
-- apply the yaw to the mob
mob_yaw = mob_yaw + self.head_yaw_offset
if self.head_yaw == "y" then
newr = vector.new(mob_pitch, mob_yaw, 0)
elseif self.head_yaw == "z" then
newr = vector.new(mob_pitch, 0, -mob_yaw)
newr = vector.new(mob_pitch, 0, -mob_yaw) -- z yaw is opposite direction
end
else
if self.head_yaw == "y" then
newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, (mob_yaw-oldr.y)*.3+oldr.y, 0)
elseif self.head_yaw == "z" then
newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, 0, ((mob_yaw-oldr.y)*.3+oldr.y)*-3)
end
end
end
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)
elseif math.abs(oldr.x) + math.abs(oldr.y) + math.abs(oldr.z) > 0.05 then
newr = vector.multiply(oldr, 0.9) -- smooth stop looking
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
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, vector.zero()) then return end
if self.object.get_bone_override then -- minetest >= 5.9
self.object:set_bone_override(self.head_swivel, {
position = { vec = newp, absolute = true },
rotation = { vec = newr, absolute = true } })
position = { vec = self.head_bone_position, absolute = true },
rotation = { vec = newr, absolute = true, interpolation = 0.1 } })
else -- minetest < 5.9
-- old API uses degrees not radians
self.object:set_bone_position(self.head_swivel, newp, vector.apply(newr, math.deg))
-- old API uses degrees not radians and absolute positions
self.object:set_bone_position(self.head_swivel, self.head_bone_position, vector.apply(newr, math.deg))
end
end

@ -143,11 +143,12 @@ function mcl_mobs.register_mob(name, def)
head_swivel = def.head_swivel or nil, -- bool to activate this function
head_yaw_offset = math.rad(def.head_yaw_offset or 0), -- for wonkey model bones
head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch
bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset
head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player
head_eye_height = def.head_eye_height or 1, -- how high approximately the mobs eyes are from the ground to tell the mob how high to look up at the player
head_max_yaw = def.head_max_yaw, -- how far the mob may turn the head
head_max_pitch = def.head_max_pitch, -- how far up and down the mob may pitch the head
head_bone_position = def.head_bone_position or { 0, def.bone_eye_height or 1.4, def.horizontal_head_height or 0},
curiosity = def.curiosity or 1, -- how often mob will look at player on idle
head_yaw = def.head_yaw or "y", -- axis to rotate head on
horizontal_head_height = def.horizontal_head_height or 0,
wears_armor = def.wears_armor, -- a number value used to index texture slot for armor
stepheight = def.stepheight or 0.6,
name = name,

@ -761,6 +761,8 @@ function mob_class:check_follow()
self:set_velocity(self.follow_velocity)
if self.walk_chance ~= 0 then
self:set_animation( "run")
else
self:set_animation( "stand")
end
else
self:set_velocity(0)

@ -12,9 +12,8 @@ local axolotl = {
xp_max = 7,
head_swivel = "head.control",
bone_eye_height = -1,
head_eye_height = -0.5,
horizontal_head_height = 0,
head_eye_height = 0.5,
head_bone_position = vector.new( 0, -1, 0 ), -- for minetest <= 5.8
curiosity = 10,
head_yaw="z",

@ -26,14 +26,14 @@ mcl_mobs.register_mob("mobs_mc:blaze", {
xp_min = 10,
xp_max = 10,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.79, 0.3},
rotate = -180,
rotate = 180,
head_yaw_offset = 180,
visual = "mesh",
mesh = "mobs_mc_blaze.b3d",
head_swivel = "head.control",
bone_eye_height = 4,
head_eye_height = 3.5,
head_eye_height = 1.4,
head_bone_position = vector.new( 0, 4, 0 ), -- for minetest <= 5.8
curiosity = 10,
head_yaw_offset = 180,
head_pitch_multiplier=-1,
textures = {
{"mobs_mc_blaze.png"},

@ -21,9 +21,8 @@ mcl_mobs.register_mob("mobs_mc:chicken", {
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.69, 0.2},
floats = 1,
head_swivel = "head.control",
bone_eye_height = 4,
head_eye_height = 1.5,
horizontal_head_height = -.3,
head_eye_height = 0.5,
head_bone_position = vector.new(0, 4, -.3), -- for minetest <= 5.8
curiosity = 10,
head_yaw="z",
visual_size = {x=1,y=1},

@ -22,9 +22,8 @@ local cow_def = {
"blank.png",
}, },
head_swivel = "head.control",
bone_eye_height = 10,
head_eye_height = 1.1,
horizontal_head_height=-1.8,
head_bone_position = vector.new( 0, 10, 0 ), -- for minetest <= 5.8
curiosity = 2,
head_yaw="z",
makes_footstep_sound = true,

@ -25,7 +25,8 @@ mcl_mobs.register_mob("mobs_mc:iron_golem", {
visual = "mesh",
mesh = "mobs_mc_iron_golem.b3d",
head_swivel = "head.control",
bone_eye_height = 3.38,
head_eye_height = 2.5,
head_bone_position = vector.new( 0, 3.38, 0 ), -- for minetest <= 5.8
curiosity = 10,
textures = {
{"mobs_mc_iron_golem.png"},

@ -60,11 +60,10 @@ mcl_mobs.register_mob("mobs_mc:llama", {
spawn_in_group = 4, -- was 6 nerfed until we can cap them properly locally. this is a group size, not a per spawn attempt
head_swivel = "head.control",
bone_eye_height = 11,
head_eye_height = 3,
horizontal_head_height=0,
curiosity = 60,
head_eye_height = 1.5,
head_yaw = "z",
head_bone_position = vector.new( 0, 11, 0 ), -- for minetest <= 5.8
curiosity = 60,
hp_min = 15,
hp_max = 30,

@ -37,9 +37,8 @@ local ocelot = {
xp_min = 1,
xp_max = 3,
head_swivel = "head.control",
bone_eye_height = 6.2,
head_eye_height = 0.4,
horizontal_head_height=-0,
head_bone_position = vector.new( 0, 6.2, 0 ), -- for minetest <= 5.8
head_yaw="z",
curiosity = 4,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 0.69, 0.3},

@ -136,8 +136,7 @@ mcl_mobs.register_mob("mobs_mc:parrot", {
xp_min = 1,
xp_max = 3,
head_swivel = "head.control",
bone_eye_height = 1.1,
horizontal_head_height=0,
head_bone_position = vector.new( 0, 1.1, 0 ), -- for minetest <= 5.8
curiosity = 10,
collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.89, 0.25},
visual = "mesh",

@ -20,9 +20,8 @@ mcl_mobs.register_mob("mobs_mc:pig", {
"blank.png", -- saddle
}},
head_swivel = "head.control",
bone_eye_height = 7.5,
head_eye_height = 0.8,
horizontal_head_height=-1,
head_eye_height = 0.7,
head_bone_position = vector.new( 0, 7.5, -1 ), -- for minetest <= 5.8
curiosity = 3,
head_yaw="z",
makes_footstep_sound = true,

@ -252,7 +252,7 @@ local zombified_piglin = {
damage = 9,
reach = 2,
head_swivel = "head.control",
bone_eye_height = 2.4,
head_bone_position = vector.new( 0, 2.4, 0 ), -- for minetest <= 5.8
head_eye_height = 1.4,
curiosity = 15,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3}, -- same
@ -325,6 +325,7 @@ mcl_mobs.register_mob("mobs_mc:zombified_piglin", zombified_piglin)
local baby_zombified_piglin = table.copy(zombified_piglin)
baby_zombified_piglin.description = S("Baby Zombie Piglin")
baby_zombified_piglin.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
baby_zombified_piglin.head_eye_height = 0.8
baby_zombified_piglin.xp_min = 13
baby_zombified_piglin.xp_max = 13
baby_zombified_piglin.textures = {

@ -25,9 +25,8 @@ mcl_mobs.register_mob("mobs_mc:polar_bear", {
{"mobs_mc_polarbear.png"},
},
head_swivel = "head.control",
bone_eye_height = 2.6,
head_eye_height = 1,
horizontal_head_height = 0,
head_bone_position = vector.new( 0, 2.6, 0 ), -- for minetest <= 5.8
curiosity = 20,
head_yaw="z",
visual_size = {x=3.0, y=3.0},

@ -16,9 +16,8 @@ local rabbit = {
xp_max = 3,
collisionbox = {-0.2, -0.01, -0.2, 0.2, 0.49, 0.2},
head_swivel = "head.control",
bone_eye_height = 2,
head_eye_height = 0.5,
horizontal_head_height = -.3,
head_eye_height = 0.35,
head_bone_position = vector.new( 0, 2, -.3 ), -- for minetest <= 5.8
curiosity = 20,
head_yaw="z",
visual = "mesh",

@ -65,9 +65,8 @@ mcl_mobs.register_mob("mobs_mc:sheep", {
xp_max = 3,
collisionbox = {-0.45, -0.01, -0.45, 0.45, 1.29, 0.45},
head_swivel = "head.control",
bone_eye_height = 3.3,
head_eye_height = 1.1,
horizontal_head_height=-.7,
head_eye_height = 1.0,
head_bone_position = vector.new( 0, 3.3, -.7 ), -- for minetest <= 5.8
curiosity = 6,
head_yaw="z",
visual = "mesh",

@ -26,7 +26,8 @@ local skeleton = {
pathfinding = 1,
group_attack = true,
head_swivel = "Head_Control",
bone_eye_height = 2.38,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 2.38, 0 ), -- for minetest <= 5.8
curiosity = 6,
visual = "mesh",
mesh = "mobs_mc_skeleton.b3d",

@ -25,7 +25,8 @@ mcl_mobs.register_mob("mobs_mc:witherskeleton", {
visual = "mesh",
mesh = "mobs_mc_witherskeleton.b3d",
head_swivel = "head.control",
bone_eye_height = 2.38,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 2.38, 0 ), -- for minetest <= 5.8
curiosity = 60,
textures = {
{

@ -63,7 +63,8 @@ local spider = {
end
end,
head_swivel = "Head_Control",
bone_eye_height = 1,
head_eye_height = 0.6,
head_bone_position = vector.new( 0, 1, 0 ), -- for minetest <= 5.8
curiosity = 10,
head_yaw="z",
collisionbox = {-0.7, -0.01, -0.7, 0.7, 0.89, 0.7},

@ -75,8 +75,8 @@ mcl_mobs.register_mob("mobs_mc:stalker", {
visual = "mesh",
mesh = "vl_stalker.b3d",
-- head_swivel = "Head_Control",
bone_eye_height = 2.35,
head_eye_height = 1.8;
head_eye_height = 1.2;
head_bone_position = vector.new( 0, 2.35, 0 ), -- for minetest <= 5.8
curiosity = 2,
textures = {
{get_texture({}),

@ -2110,8 +2110,8 @@ mcl_mobs.register_mob("mobs_mc:villager", {
hp_min = 20,
hp_max = 20,
head_swivel = "head.control",
bone_eye_height = 6.3,
head_eye_height = 2.2,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 6.3, 0 ), -- for minetest <= 5.8
curiosity = 10,
runaway = true,
collisionbox = {-0.3, -0.01, -0.3, 0.3, 1.94, 0.3},

@ -25,8 +25,8 @@ mcl_mobs.register_mob("mobs_mc:evoker", {
xp_min = 10,
xp_max = 10,
head_swivel = "head.control",
bone_eye_height = 6.3,
head_eye_height = 2.2,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 6.3, 0 ), -- for minetest <= 5.8
curiosity = 10,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.95, 0.4},
visual = "mesh",

@ -34,8 +34,8 @@ mcl_mobs.register_mob("mobs_mc:illusioner", {
"mcl_bows_bow.png",
}, },
head_swivel = "head.control",
bone_eye_height = 2.2,
head_eye_height = 2.2,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 2.2, 0 ), -- for minetest <= 5.8
curiosity = 10,
sounds = {
-- TODO: more sounds

@ -24,8 +24,8 @@ mcl_mobs.register_mob("mobs_mc:vindicator", {
visual = "mesh",
mesh = "mobs_mc_vindicator.b3d",
head_swivel = "head.control",
bone_eye_height = 2.2,
head_eye_height = 2.2,
head_eye_height = 1.5,
head_bone_position = vector.new( 0, 2.2, 0 ), -- for minetest <= 5.8
curiosity = 10,
textures = {
{

@ -40,7 +40,7 @@ mcl_mobs.register_mob("mobs_mc:villager_zombie", {
visual = "mesh",
mesh = "mobs_mc_villager_zombie.b3d",
head_swivel = "Head_Control",
bone_eye_height = 2.35,
head_bone_position = vector.new( 0, 2.35, 0 ), -- for minetest <= 5.8
curiosity = 2,
textures = {
{"mobs_mc_zombie_butcher.png"},

@ -27,8 +27,8 @@ local wolf = {
},
makes_footstep_sound = true,
head_swivel = "head.control",
bone_eye_height = 3.5,
head_eye_height = 1.1,
head_eye_height = 0.5,
head_bone_position = vector.new( 0, 3.5, 0 ), -- for minetest <= 5.8
horizontal_head_height=0,
curiosity = 3,
head_yaw="z",

@ -54,8 +54,8 @@ local zombie = {
xp_min = 5,
xp_max = 5,
head_swivel = "head.control",
bone_eye_height = 6.3,
head_eye_height = 2.2,
head_eye_height = 1.4,
head_bone_position = vector.new( 0, 6.3, 0 ), -- for minetest <= 5.8
curiosity = 7,
head_pitch_multiplier=-1,
breath_max = -1,
@ -110,6 +110,7 @@ mcl_mobs.register_mob("mobs_mc:zombie", zombie)
local baby_zombie = table.copy(zombie)
baby_zombie.description = S("Baby Zombie")
baby_zombie.head_eye_height = 0.8
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.98, 0.25}
baby_zombie.xp_min = 12
baby_zombie.xp_max = 12