From 8c38745f6c7b0bf624b181666b33f91999a9ff60 Mon Sep 17 00:00:00 2001 From: kno10 Date: Wed, 2 Oct 2024 21:24:42 +0200 Subject: [PATCH] Making movement work better. --- mods/ENTITIES/mcl_mobs/api.lua | 30 ++- mods/ENTITIES/mcl_mobs/combat.lua | 11 +- mods/ENTITIES/mcl_mobs/effects.lua | 2 +- mods/ENTITIES/mcl_mobs/init.lua | 75 ++----- mods/ENTITIES/mcl_mobs/mount.lua | 2 +- mods/ENTITIES/mcl_mobs/movement.lua | 97 ++++----- mods/ENTITIES/mcl_mobs/physics.lua | 236 ++++++++++++++------- mods/ENTITIES/mobs_mc/blaze.lua | 2 +- mods/ENTITIES/mobs_mc/chicken.lua | 2 +- mods/ENTITIES/mobs_mc/ender_dragon.lua | 2 +- mods/ENTITIES/mobs_mc/ghast.lua | 2 +- mods/ENTITIES/mobs_mc/horse.lua | 4 +- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 10 +- mods/ENTITIES/mobs_mc/spider.lua | 2 +- mods/ENTITIES/mobs_mc/stalker.lua | 68 ++++-- mods/ENTITIES/mobs_mc/wither.lua | 12 +- mods/ENTITIES/mobs_mc/zombie.lua | 2 +- 17 files changed, 317 insertions(+), 242 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index bd9ff445a..d3aebd542 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -28,6 +28,16 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then end) end +function mob_class:safe_remove() + self.removed = true + minetest.after(0,function(obj) + if obj and obj:get_pos() then + mcl_burning.extinguish(obj) + obj:remove() + end + end,self.object) +end + function mob_class:update_tag() --update nametag and/or the debug box local tag if mobs_debug then @@ -206,7 +216,6 @@ function mob_class:mob_activate(staticdata, def, dtime) self.standing_in = NODE_IGNORE self.standing_on = NODE_IGNORE self.standing_under = NODE_IGNORE - self.standing_body = 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 @@ -220,6 +229,8 @@ function mob_class:mob_activate(staticdata, def, dtime) self.blinktimer = 0 self.blinkstatus = false + self.acceleration = vector.zero() + self.nametag = self.nametag or def.nametag self.object:set_properties(self) @@ -299,22 +310,22 @@ end local function on_step_work(self, dtime, moveresult) local pos = self.object:get_pos() - if not pos then return end - if self:check_despawn(pos, dtime) then return true end + if not pos or self.removed then return end + if self:check_despawn(pos, dtime) then return end if self:outside_limits() then return end - -- Update what we know of the mobs environment for physics and movement - self:update_standing() + pos = self:limit_vel_acc_for_large_dtime(pos, dtime, moveresult) -- limit maximum movement to reduce lag effects + self:update_standing(pos, moveresult) -- update what we know of the mobs environment for physics and movement 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 if self:gravity_and_floating(pos, dtime, moveresult) then return end if self:step_damage(dtime, pos) then return end - self:check_water_flow() + self:check_water_flow(dtime, pos) if self.state == "die" then return end self._can_jump_cliff = not self._jumping_cliff and self:can_jump_cliff() - --self:flop() + self:flop() self:smooth_rotation(dtime) if player_in_active_range then @@ -350,6 +361,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) if mobs_debug then self:update_tag() end if not self.object:get_luaentity() then return false end end @@ -416,9 +428,7 @@ local function update_lifetimer(dtime) timer = 0 end -minetest.register_globalstep(function(dtime) - update_lifetimer(dtime) -end) +minetest.register_globalstep(update_lifetimer) minetest.register_chatcommand("clearmobs", { privs = { maphack = true }, diff --git a/mods/ENTITIES/mcl_mobs/combat.lua b/mods/ENTITIES/mcl_mobs/combat.lua index b0aee5a25..df58ce3df 100644 --- a/mods/ENTITIES/mcl_mobs/combat.lua +++ b/mods/ENTITIES/mcl_mobs/combat.lua @@ -3,6 +3,7 @@ local mob_class = mcl_mobs.mob_class local damage_enabled = minetest.settings:get_bool("enable_damage") local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false +local mobs_see_through_opaque = mcl_mobs.see_through_opaque -- pathfinding settings local stuck_timeout = 3 -- how long before mob gets stuck in place and starts searching @@ -89,7 +90,8 @@ function mob_class:smart_mobs(s, p, dist, dtime) self.path.lastpos = vector_copy(s) local use_pathfind = false - local has_lineofsight = self:line_of_sight(vector_offset(s, 0, .5, 0), vector_offset(target_pos, 0, 1.5, 0), self.see_through_opaque or mobs_see_through, false) + local has_lineofsight = self:line_of_sight(vector_offset(s, 0, .5, 0), vector_offset(target_pos, 0, 1.5, 0), + self.see_through_opaque or mobs_see_through_opaque, false) -- im stuck, search for path if not has_lineofsight then @@ -157,12 +159,7 @@ function mob_class:smart_mobs(s, p, dist, dtime) local dropheight = 12 if self.fear_height ~= 0 then dropheight = self.fear_height end - local jumpheight = 0 - if self.jump and self.jump_height >= 4 then - jumpheight = min(ceil(self.jump_height * 0.25), 4) - elseif self.stepheight > 0.5 then - jumpheight = 1 - end + local jumpheight = self.jump and floor(self.jump_height + 0.1) or 0 self.path.way = minetest.find_path(s, p1, 16, jumpheight, dropheight, "A*_noprefetch") self.state = "" diff --git a/mods/ENTITIES/mcl_mobs/effects.lua b/mods/ENTITIES/mcl_mobs/effects.lua index 54e8d3362..d49eb3cd2 100644 --- a/mods/ENTITIES/mcl_mobs/effects.lua +++ b/mods/ENTITIES/mcl_mobs/effects.lua @@ -75,7 +75,7 @@ function mob_class:mob_sound(soundname, is_opinion, fixed_pitch) local sound = soundinfo[soundname] if not sound then return end if is_opinion and self.opinion_sound_cooloff > 0 then return end - local pitch = fixed_pitch + local pitch if not fixed_pitch then pitch = soundinfo.base_pitch or 1 if self.child and not self.sounds_child then pitch = pitch * 1.5 end diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index e1cb45ef1..6cef7e1d2 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -6,6 +6,7 @@ local modname = minetest.get_current_modname() local path = minetest.get_modpath(modname) local S = minetest.get_translator(modname) mcl_mobs.fallback_node = minetest.registered_aliases["mapgen_dirt"] or "mcl_core:dirt" +mcl_mobs.see_through_opaque = minetest.settings:get_bool("mobs_see_through_opaque", false) -- used by the libaries below. -- get node but use fallback for nil or unknown @@ -147,20 +148,25 @@ function mcl_mobs.register_mob(name, def) end end + if type(def.fly_in) == "string" then + def.fly_in = { def.fly_in } + end + local collisionbox = def.collisionbox or {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25} -- Workaround for : -- Increase upper Y limit to avoid mobs glitching through solid nodes. + -- Removed now, as this was supposedly fixed in 5.3.0? -- FIXME: Remove workaround if it's no longer needed. - if collisionbox[5] < 0.79 then - collisionbox[5] = 0.79 - end + --if collisionbox[5] < 0.79 then + -- collisionbox[5] = 0.79 + --end local final_def = { use_texture_alpha = def.use_texture_alpha, 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 def.bone_eye_height or 0, -- how high aproximately the mobs head is from the ground to tell the mob how high to look up at the player 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, @@ -179,7 +185,7 @@ function mcl_mobs.register_mob(name, def) spawn_small_alternative = def.spawn_small_alternative, do_custom = def.do_custom, detach_child = def.detach_child, - jump_height = def.jump_height or 4, -- was 6 + jump_height = def.jump_height or 1, rotate = math.rad(def.rotate or 0), -- 0=front, 90=side, 180=back, 270=side2 lifetimer = def.lifetimer or 57.73, hp_min = scale_difficulty(def.hp_min, 5, 1), @@ -398,11 +404,8 @@ end -- register arrow for shoot attack function mcl_mobs.register_arrow(name, def) - if not name or not def then return end -- errorcheck - minetest.register_entity(name, { - physical = false, visual = def.visual, visual_size = def.visual_size, @@ -426,31 +429,21 @@ function mcl_mobs.register_arrow(name, def) self._puncher = puncher end, collisionbox = def.collisionbox or {0, 0, 0, 0, 0, 0}, - automatic_face_movement_dir = def.rotate - and (def.rotate - (math.pi / 180)) or false, + automatic_face_movement_dir = def.rotate and (def.rotate - (math.pi / 180)) or false, on_activate = def.on_activate, on_step = def.on_step or function(self, dtime) - self.timer = self.timer + dtime - local pos = self.object:get_pos() - - if self.switch == 0 - or self.timer > self._lifetime - or not within_limits(pos, 0) then + if self.switch == 0 or self.timer > self._lifetime or not within_limits(pos, 0) then mcl_burning.extinguish(self.object) self.object:remove(); - return end -- does arrow have a tail (fireball) - if def.tail - and def.tail == 1 - and def.tail_texture then - + if def.tail == 1 and def.tail_texture then minetest.add_particle({ pos = pos, velocity = {x = 0, y = 0, z = 0}, @@ -464,24 +457,17 @@ function mcl_mobs.register_arrow(name, def) end if self.hit_node then - local node = node_ok(pos).name - if minetest.registered_nodes[node].walkable then - self.hit_node(self, pos, node) if self.drop == true then - pos.y = pos.y + 1 - self.lastpos = (self.lastpos or pos) - minetest.add_item(self.lastpos, self.object:get_luaentity().name) end self.object:remove(); - return end end @@ -498,12 +484,8 @@ function mcl_mobs.register_arrow(name, def) end if self.hit_player or self.hit_mob or self.hit_object then - for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do - - if self.hit_player - and object:is_player() then - + if self.hit_player and object:is_player() then self.hit_player(self, object) self.object:remove(); return @@ -544,30 +526,20 @@ end -- * spawn_egg=1: Spawn egg (generic mob, no metadata) -- * spawn_egg=2: Spawn egg (captured/tamed mob, metadata) function mcl_mobs.register_egg(mob_id, desc, background_color, overlay_color, 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 - grp.not_in_creative_inventory = 1 - end + local grp = { spawn_egg = 1 } + if no_creative == true then grp.not_in_creative_inventory = 1 end local invimg = "(spawn_egg.png^[multiply:" .. background_color ..")^(spawn_egg_overlay.png^[multiply:" .. overlay_color .. ")" if old_spawn_icons then - local mobname = mob_id:gsub("mobs_mc:","") - local fn = "mobs_mc_spawn_icon_"..mobname..".png" - if mcl_util.file_exists(minetest.get_modpath("mobs_mc").."/textures/"..fn) then - invimg = fn - end + local fn = "mobs_mc_spawn_icon_" .. mob_id:gsub("mobs_mc:","") .. ".png" + if mcl_util.file_exists(minetest.get_modpath("mobs_mc").."/textures/"..fn) then invimg = fn end end if addegg == 1 then - invimg = "mobs_chicken_egg.png^(" .. invimg .. - "^[mask:mobs_chicken_egg_overlay.png)" + invimg = "mobs_chicken_egg.png^(" .. invimg .. "^[mask:mobs_chicken_egg_overlay.png)" end -- register old stackable mob egg minetest.register_craftitem(mob_id, { - description = desc, inventory_image = invimg, groups = grp, @@ -604,9 +576,6 @@ function mcl_mobs.register_egg(mob_id, desc, background_color, overlay_color, ad local dim = mcl_worlds.pos_to_dimension(placer:get_pos()) local mob_light_lvl = {mcl_mobs:mob_light_lvl(itemstack:get_name(),dim)} - --minetest.log("min light: " .. mob_light_lvl[1]) - --minetest.log("max light: " .. mob_light_lvl[2]) - -- Handle egg conversion local convert_to = (minetest.registered_entities[mob_name] or {})._convert_to if convert_to then mob_name = convert_to end @@ -618,9 +587,7 @@ function mcl_mobs.register_egg(mob_id, desc, background_color, overlay_color, ad return itemstack end - if not minetest.registered_entities[mob_name] then - return itemstack - end + if not minetest.registered_entities[mob_name] then return itemstack end if minetest.settings:get_bool("only_peaceful_mobs", false) and minetest.registered_entities[mob_name].type == "monster" then diff --git a/mods/ENTITIES/mcl_mobs/mount.lua b/mods/ENTITIES/mcl_mobs/mount.lua index fdc499440..826bc5451 100644 --- a/mods/ENTITIES/mcl_mobs/mount.lua +++ b/mods/ENTITIES/mcl_mobs/mount.lua @@ -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 + entity.jump_height + velo.y = velo.y + sqrt(entity.jump_height * 20) acce_y = acce_y + 1 end end diff --git a/mods/ENTITIES/mcl_mobs/movement.lua b/mods/ENTITIES/mcl_mobs/movement.lua index 479e16e4c..f299d7ec0 100644 --- a/mods/ENTITIES/mcl_mobs/movement.lua +++ b/mods/ENTITIES/mcl_mobs/movement.lua @@ -1,7 +1,7 @@ local math, vector, minetest, mcl_mobs = math, vector, minetest, mcl_mobs local mob_class = mcl_mobs.mob_class local DEFAULT_FALL_SPEED = -9.81*1.5 -local FLOP_HEIGHT = 6 +local FLOP_VEL = math.sqrt(1.5 * 20) -- 1.5 blocks local FLOP_HOR_SPEED = 1.5 local CHECK_HERD_FREQUENCY = 4 @@ -12,7 +12,6 @@ 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) -local mobs_see_through_opaque = minetest.settings:get_bool("mobs_see_through_opaque", false) local random = math.random local sin = math.sin @@ -31,7 +30,8 @@ local vector_offset = vector.offset local vector_distance = vector.distance local node_ok = mcl_mobs.node_ok -local see_through_opaque = mcl_mobs.see_through_opaque +local mobs_see_through_opaque = mcl_mobs.see_through_opaque +local line_of_sight = mcl_mobs.line_of_sight -- Stop movement and stand function mob_class:stand() @@ -86,12 +86,12 @@ function mob_class:target_visible(origin) local cbox = self.collisionbox -- TODO also worth testing midway between feet and head? -- to top of entity - if line_of_sight(origin_eye_pos, vector_offset(target_pos, 0, cbox[5], 0), mobs_see_through_opaque, true) then return true end + if line_of_sight(origin_eye_pos, vector_offset(target_pos, 0, cbox[5], 0), self.see_through_opaque or mobs_see_through_opaque, true) then return true end -- to feed of entity if self.attack:is_player() then - if line_of_sight(origin_eye_pos, target_pos, mobs_see_through_opaque, true) then return true end -- Cbox would put feet under ground which interferes with ray + if line_of_sight(origin_eye_pos, target_pos, self.see_through_opaque or mobs_see_through_opaque, true) then return true end -- Cbox would put feet under ground which interferes with ray else - if line_of_sight(origin_eye_pos, vector_offset(target_pos, 0, cbox[2], 0), mobs_see_through_opaque, true) then return true end + if line_of_sight(origin_eye_pos, vector_offset(target_pos, 0, cbox[2], 0), self.see_through_opaque or mobs_see_through_opaque, true) then return true end end --minetest.log("start targ_head_height: " .. dump(targ_head_height)) @@ -111,7 +111,7 @@ end -- check line of sight function mob_class:line_of_sight(pos1, pos2, stepsize) - return line_of_sight(pos1, pos2, mobs_see_through_opaque, true) + return line_of_sight(pos1, pos2, self.see_through_opaque or mobs_see_through_opaque, true) end function mob_class:can_jump_cliff() @@ -169,7 +169,7 @@ function mob_class:is_at_cliff_or_danger() return "free fall" end local height = ypos + 0.4 - blocker.y - local chance = (self.jump_height or 4) * 0.25 / (height * height) + local chance = self.jump_height / (height * height) if height >= self.fear_height and random() < chance then if logging then minetest.log("action", "[mcl_mobs] "..self.name.." avoiding drop of "..height) --.." chance "..chance) @@ -304,17 +304,12 @@ function mob_class:do_jump() return false end - v.y = math.min(v.y, 0) + self.jump_height -- + 0.3 - --if in_water then - -- v.x, v.y, v.z = v.x * 1.2, v.y + self.jump_height * 0.5, v.z * 1.2 - --elseif self._can_jump_cliff then - -- v.x, v.y, v.z = v.x * 2.5, v.y + self.jump_height * 0.1, v.z * 2.5 - --end - if in_water or self._cam_jump_cliff then v.y = v.y + self.jump_height * 0.25 end - + v.y = math.min(v.y, 0) + math.sqrt(self.jump_height * 20) + (in_water or self._can_jump_cliff and 0.5 or 0) v.y = math.min(-self.fall_speed, math.max(v.y, self.fall_speed)) - self:set_animation("jump") -- only when defined self.object:set_velocity(v) + self:set_animation("run") + self:set_animation("jump") -- only when defined + self:set_velocity(self.run_velocity) if self.jump_sound_cooloff <= 0 then self:mob_sound("jump") @@ -454,7 +449,7 @@ function mob_class:check_runaway_from() sp = s 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), mobs_see_through_opaque, false) then + 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 -- aim higher to make looking up hills more realistic min_dist = dist min_player = player @@ -531,29 +526,25 @@ function mob_class:check_follow() end end +-- swimmers flop when out of their element, and swim again when back in function mob_class:flop() - -- swimmers flop when out of their element, and swim again when back in - if self.fly then - local s = self.object:get_pos() - - if self:flight_check(s) == false then - self.state = "flop" - self.object:set_acceleration(vector_new(0, DEFAULT_FALL_SPEED, 0)) - - local p = self.object:get_pos() - local sdef = minetest.registered_nodes[node_ok(vector_offset(p, 0, self.collisionbox[2] - 0.2, 0)).name] - -- Flop on ground - if sdef and sdef.walkable then - if self.object:get_velocity().y < 0.1 then - self:mob_sound("flop") - self.object:set_velocity(vector_new((random() * 2 - 1) * FLOP_HOR_SPEED, FLOP_HEIGHT, (random() * 2 - 1) * FLOP_HOR_SPEED)) - end + if not self.fly then return end + if not self:flight_check() then + self.state = "flop" + self.acceleration.y = DEFAULT_FALL_SPEED + local sdef = self.standing_on + if sdef and sdef.walkable then -- flop on ground + if self.object:get_velocity().y == 0 then + self:mob_sound("flop") + self.object:add_velocity(vector_new(0, FLOP_VEL, 0)) + self:turn_by(TWOPI * random(), 8) + self:set_velocity(FLOP_HOR_SPEED) end - - self:set_animation("stand", true) - elseif self.state == "flop" then - self:stand() end + self:set_animation("stand", true) + elseif self.state == "flop" then + --self:stand() + self.acceleration.y = 0 end end @@ -625,28 +616,33 @@ function mob_class:do_states_walk() end -- facing wall? then turn local facing_wall = false - local cbox = self.collisionbox - local dir_x, dir_z = -sin(yaw - QUARTERPI) * (cbox[4] + 0.5), cos(yaw - QUARTERPI) * (cbox[4] + 0.5) - local nodface = minetest.registered_nodes[minetest.get_node(vector_offset(s, dir_x, cbox[5] - cbox[2], dir_z)).name] - if nodface and nodface.walkable then - dir_x, dir_z = -sin(yaw + QUARTERPI) * (cbox[4] + 0.5), cos(yaw + QUARTERPI) * (cbox[4] + 0.5) - nodface = minetest.registered_nodes[minetest.get_node(vector_offset(s, dir_x, cbox[5] - cbox[2], dir_z)).name] + -- todo: use moveresult collision info here? + if self:get_velocity_xyz() < 0.1 then + facing_wall = true + elseif not facing_wall then + local cbox = self.collisionbox + local dir_x, dir_z = -sin(yaw - QUARTERPI) * (cbox[4] + 0.5), cos(yaw - QUARTERPI) * (cbox[4] + 0.5) + local nodface = minetest.registered_nodes[minetest.get_node(vector_offset(s, dir_x, (cbox[5] - cbox[2]) * 0.5, dir_z)).name] if nodface and nodface.walkable then - facing_wall = true + dir_x, dir_z = -sin(yaw + QUARTERPI) * (cbox[4] + 0.5), cos(yaw + QUARTERPI) * (cbox[4] + 0.5) + nodface = minetest.registered_nodes[minetest.get_node(vector_offset(s, dir_x, (cbox[5] - cbox[2]) * 0.5, dir_z)).name] + if nodface and nodface.walkable then + facing_wall = true + end end end if facing_wall then if logging then minetest.log("action", "[mcl_mobs] "..self.name.." facing a wall, turning.") end - self:turn_by(TWOPI * (random() - 0.5), 6) + self:turn_by(TWOPI * (random() - 0.5), 10) -- otherwise randomly turn elseif random() <= 0.3 then local home = self._home or self._bed if home and random() < 0.1 then self:turn_in_direction(home.x - s.x, home.z - s.z, 8) else - self:turn_by(QUARTERPI * (random() - 0.5), 10) + self:turn_by(QUARTERPI * (random() - 0.5), 20) end end self:set_velocity(self.walk_velocity) @@ -687,9 +683,7 @@ function mob_class:do_states_stand(player_in_active_range) end -- npc's ordered to stand stay standing - if self.order == "stand" or self.order == "sleep" or self.order == "work" then - - else + if self.order ~= "stand" and self.order ~= "sleep" and self.order ~= "work" then if player_in_active_range then if self.walk_chance ~= 0 and self.facing_fence ~= true @@ -709,8 +703,7 @@ end function mob_class:do_states_runaway() self.runaway_timer = self.runaway_timer + 1 -- stop after 5 seconds or when at cliff - if self.runaway_timer > 5 - or self:is_at_cliff_or_danger() then + if self.runaway_timer > 5 or self:is_at_cliff_or_danger() then self.runaway_timer = 0 self:stand() self:turn_by(PI * (random() + 0.5), 8) diff --git a/mods/ENTITIES/mcl_mobs/physics.lua b/mods/ENTITIES/mcl_mobs/physics.lua index 96f312ba6..b2c1331c9 100644 --- a/mods/ENTITIES/mcl_mobs/physics.lua +++ b/mods/ENTITIES/mcl_mobs/physics.lua @@ -2,6 +2,8 @@ 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 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 local ENTITY_CRAMMING_MAX = 24 local CRAMMING_DAMAGE = 3 local DEATH_DELAY = 0.5 @@ -17,6 +19,7 @@ local abs = math.abs local atan2 = math.atan2 local sin = math.sin local cos = math.cos +local sqrt = math.sqrt local node_ok = mcl_mobs.node_ok local PATHFINDING = "gowp" @@ -48,13 +51,25 @@ end -- standing_on: node below -- standing_under: node above -- these may be "nil" (= ignore) and are otherwise already resolved via minetest.registered_nodes -function mob_class:update_standing() - local pos = self.object:get_pos() +function mob_class:update_standing(pos, moveresult) local temp_pos = vector.offset(pos, 0, self.collisionbox[2] + 0.5, 0) -- foot level 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 = minetest.registered_nodes[minetest.get_node(temp_pos).name] or NODE_IGNORE - self.standing_height = pos.y - math.ceil(temp_pos.y + 0.5) + self.head_eye_height * 0.75 + 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 + -- 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*","")) + for _, c in ipairs(moveresult.collisions) do + if c.axis == "y" and c.type == "node" and c.old_velocity.y < 0 then + self.standing_on_node = minetest.get_node(c.node_pos) + self.standing_on = minetest.registered_nodes[self.standing_on_node.name] + break + end + end + end + -- approximate height of head over ground: + self.standing_height = pos.y - math.floor(temp_pos.y + 0.5) - 0.5 + self.head_eye_height * 0.9 temp_pos.y = temp_pos.y + 2 -- at +1 = above self.standing_under = minetest.registered_nodes[minetest.get_node(temp_pos).name] or NODE_IGNORE end @@ -77,28 +92,20 @@ function mob_class:object_in_range(object) factor = factors and factors[self.name] end -- Distance check - local dist - if factor and factor == 0 then - return false - elseif factor then - dist = self.view_range * factor - else - dist = self.view_range + local dist = self.view_range + if factor then + if factor == 0 then return false end + dist = dist * factor end - local p1, p2 = self.object:get_pos(), object:get_pos() return p1 and p2 and (vector.distance(p1, p2) <= dist) end function mob_class:item_drop(cooked, looting_level) - if not mobs_drop_items then return end - looting_level = looting_level or 0 - if (self.child and self.type ~= "monster") then - return - end + if (self.child and self.type ~= "monster") then return end local obj, item, num local pos = self.object:get_pos() @@ -160,7 +167,6 @@ end function mob_class:collision() local pos = self.object:get_pos() if not pos then return 0,0 end - local vel = self.object:get_velocity() local x, z = 0, 0 local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5 for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do @@ -172,7 +178,7 @@ function mob_class:collision() local pos2 = object:get_pos() local vx, vz = pos.x - pos2.x, pos.z - pos2.z - local force = width - (vx*vx+vz*vz)^0.5 + local force = width - sqrt(vx*vx+vz*vz) if force > 0 then force = force * force * (object:is_player() and 2 or 1) -- players push more -- minetest.log("mob push force "..force.." "..tostring(self.name).." by "..tostring(ent and ent.name or "player")) @@ -202,22 +208,30 @@ function mob_class:set_velocity(v) self.target_vel = v end +-- calculate mob velocity (3d) +function mob_class:get_velocity_xyz() + local v = self.object:get_velocity() + if not v then return 0 end + local x, y, z = v.x, v.y, v.z + return sqrt(x*x + y*y + z*z) +end -- calculate mob velocity (2d) function mob_class:get_velocity_xz() local v = self.object:get_velocity() if not v then return 0 end - return (v.x*v.x + v.z*v.z)^0.5 + local x, z = v.x, v.z + return sqrt(x*x + z*z) end -- legacy API mob_class.get_velocity = mob_class.get_velocity_xz -- Relative turn, primarily for random turning -- @param angle number: realative angle, in radians --- @param dtime deprecated: ignored now, because of smooth rotations +-- @param delay number: time needed to turn -- @param dtime deprecated: ignored now, because of smooth rotations -- @return target angle function mob_class:turn_by(angle, delay, dtime) - return self:set_yaw((self.object:get_yaw() or 0) + angle, delay, dtime) + return self:set_yaw((self.object:get_yaw() or 0) + self.rotate + angle, delay, dtime) end -- Turn into a direction (e.g., to the player, or away) -- @param dx number: delta in x axis to target @@ -273,7 +287,7 @@ function mob_class:smooth_rotation(dtime) if not self.target_yaw then return end local delay = self.delay - local initial_yaw = self.object:get_yaw() or 0 + local initial_yaw = (self.object:get_yaw() or 0) + self.rotate local yaw -- resulting yaw for this tick if delay and delay > 1 then local dif = (self.target_yaw - initial_yaw + PI) % TWOPI - PI @@ -286,44 +300,33 @@ function mob_class:smooth_rotation(dtime) if self.shaking then yaw = yaw + (random() * 2 - 1) / 72 * dtime end - if yaw ~= initial_yaw then self.object:set_yaw(yaw) end + if yaw ~= initial_yaw then self.object:set_yaw(yaw - self.rotate) end --update_roll() -- Fleckenstein easter egg end -- Handling of intentional acceleration by the mob -- its best to place environmental effects afterwards --- TODO: have mobs that act faster and that act slower? +-- 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 v = self.object:get_velocity() - local w = min(1, dtime * 10) + local w = min(dtime * 5, 1) v.x, v.z = v.x + w * (x - v.x), v.z + w * (z - v.z) self.object:set_velocity(v) end -- are we flying in what we are suppose to? (taikedz) function mob_class:flight_check() - if not self.standin_in or not self.standing_on then return true end -- nil check + if not self.standing_in or self.standing_in.name == "ignore" then return true end -- unknown? if not self.fly_in then return false end - - local fly_in - if type(self.fly_in) == "string" then - fly_in = { self.fly_in } - elseif type(self.fly_in) == "table" then - fly_in = self.fly_in - else - return false + local nod = self.standing_in.name + -- todo: allow flowers etc. for birds + for _,checknode in pairs(self.fly_in) do + if nod == checknode then return true end end - - for _,checknode in pairs(fly_in) do - if nod == checknode or nod == "ignore" then - return true - end - end - return false end @@ -738,10 +741,9 @@ end function mob_class:check_entity_cramming() local p = self.object:get_pos() if not p then return end - local oo = minetest.get_objects_inside_radius(p,1) local mobs = {} - for i = 1,#oo do - local l = oo[i]:get_luaentity() + for o in minetest.objects_inside_radius(p, 0.5) do + local l = o:get_luaentity() if l and l.is_mob and l.health > 0 then table.insert(mobs,l) end end local clear = #mobs < ENTITY_CRAMMING_MAX @@ -769,34 +771,44 @@ end -- @param moveresult table: minetest engine movement result (collisions) -- @return true if mob died function mob_class:gravity_and_floating(pos, dtime, moveresult) + if self._just_portaled then + self.start_fall_y = nil -- reset fall damage + end if self.fly and self.state ~= "die" then return end - if not self.fall_speed then self.fall_speed = DEFAULT_FALL_SPEED end -- TODO: move to initialization code only? if self.standing_in == NODE_IGNORE then -- not emerged yet, do not fall self.object:set_velocity(vector.zero()) return false end - self.object:set_properties({ nametag = "on: "..self.standing_on.name.."\nin: "..self.standing_in.name.."\n "..tostring(self.standing_height) }) + -- self.object:set_properties({ nametag = "on: "..self.standing_on.name.."\nin: "..self.standing_in.name.."\n "..tostring(self.standing_height) }) -- Gravity - --local acc_y = self.fall_speed - local acc_y = moveresult and moveresult.touching_ground and 0 or self.fall_speed - local visc = 1 + local acc = vector.new(0, not self.fly and moveresult and moveresult.touching_ground and 0 or self.fall_speed, 0) + self.visc = 1 local vel = self.object:get_velocity() or vector.zero() local standbody = self.standing_in if standbody.groups.water then - visc = 0.8 + self.visc = 0.4 if self.floats > 0 then --and minetest.registered_nodes[node_ok(vector.offset(pos, 0, self.collisionbox[5] - 0.25, 0)).name].groups.water then - local w = self.standing_under.groups.water and 0 or self.standing_height -- 0 is submerged, 1 is out - acc_y = self.fall_speed * max(-1, min(1, 2 * w - 1)) -- -1 to +1 - --self.object:set_acceleration(vector.new(0, -self.fall_speed * 0.5, 0)) + local w = (self.standing_under.groups.water and 0 or self.standing_height) -- <1 is submerged, >1 is out + if w > 0.95 and w < 1.05 then + acc.y = 0 -- stabilize floating + else + acc.y = self.fall_speed * max(-1, min(1, w - 1)) -- -1 to +1 + end end + self.start_fall_y = nil -- otherwise might receive fall damage on the next jump? elseif standbody.groups.lava then - visc = 0.7 + self.visc = 0.5 if self.floats_on_lava > 0 then local w = self.standing_under.groups.water and 0 or self.standing_height -- 0 is submerged, 1 is out - acc_y = self.fall_speed * max(-1, min(1, 2 * w - 1)) -- -1 to +1 - --self.object:set_acceleration(vector.new(0, -self.fall_speed * 0.5, 0)) + -- todo: relative to body height? + if w > 0.95 and w < 1.05 then + acc.y = 0 + else + acc.y = self.fall_speed * max(-1, min(1, w - 1)) -- -1 to +1 + end end + self.start_fall_y = nil -- otherwise might receive fall damage on the next jump? else -- fall damage onto solid ground (bouncy ground will yield vel.y > 0) if self.fall_damage == 1 and vel.y == 0 then @@ -819,50 +831,112 @@ function mob_class:gravity_and_floating(pos, dtime, moveresult) end end end - --vel.x, vel.y, vel.z = vel.x * visc, (vel.y + acc_y * dtime) * visc, vel.z * visc + self.acceleration = acc +end + +--- Limit the velocity and acceleration of a mob applied by MTE +-- This is an attempt to solve mobs trampolining on water. +-- The problem is when a large timestep occurs, acceleration and velocity is applied +-- by the minetest engine (MTE) for a long timestep. If a mob enters or leaves water +-- during this time (or a similar transition occurs), this can become wildly inaccurate. +-- A mob slightly above water will fall deep into water, or may fly high into +-- the air because of updrift. +function mob_class:limit_vel_acc_for_large_dtime(pos, dtime, moveresult) + -- hack not in use: + if ACCELERATION_MIX == 0 and dtime < MAX_DTIME then return pos end + local edtime, rdtime = dtime, 0 -- effective dtime and reverted dtime + if dtime >= MAX_DTIME then + edtime, rdtime = MAX_DTIME, dtime - MAX_DTIME + end + + local vel = self.object:get_velocity() + local acc = self.object:get_acceleration() + -- revert excess movement and acceleration from MTE + if rdtime > 0 and not (moveresult and moveresult.collides) then + vel = vel - acc * rdtime + pos = pos - (vel - acc * rdtime * 0.5) * rdtime -- at average velocity during excess + end + -- apply the missing lua part of acceleration: + if ACCELERATION_MIX > 0 and self.acceleration then + local dx, dy, dz = self.acceleration.x, self.acceleration.y, self.acceleration.z + -- use collision information: + if moveresult and moveresult.collisions then + for _, c in ipairs(moveresult.collisions) do + if c.axis == "y" then + if c.old_velocity.y < 0 and dy < 0 then dy = 0 end + if c.old_velocity.y > 0 and dy > 0 then dy = 0 end + elseif c.axis == "x" then + if c.old_velocity.x < 0 and dx < 0 then dx = 0 end + if c.old_velocity.x > 0 and dx > 0 then dx = 0 end + elseif c.axis == "z" then + if c.old_velocity.z < 0 and dz < 0 then dz = 0 end + if c.old_velocity.z > 0 and dz > 0 then dz = 0 end + end + end + end + vel.x = vel.x + dx * edtime * ACCELERATION_MIX + vel.y = vel.y + dy * edtime * ACCELERATION_MIX + vel.z = vel.z + dz * edtime * ACCELERATION_MIX + -- because we cannot check for collission, we simply allow the extra acceleration to lag a timestep: + -- pos = pos + self.acceleration * edtime * 0.5 * rdtime + end + self.object:set_velocity(vel) + self.object:set_pos(pos) + return pos +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 vel.y = max(min(vel.y, -self.fall_speed), self.fall_speed) -- Cap dtime to reduce bopping on water (hence we also do not use minetest acceleration) -- but the minetest engine already applied the current velocity on the full timestep - dtime = min(dtime, 0.01) - -- ideally, we could use: self.object:set_acceleration(vector.new(0, acc_y * visc, 0)) - vel.y = vel.y + acc_y * dtime -- apply acceleration in LUA, with limited dtime + dtime = min(dtime, MAX_DTIME) + + -- Slowdown in liquids: + if self.visc then + -- TODO: only on y, or also apply to vel.x, vel.z, acceleration? + vel.y = vel.y * self.visc^(dtime*10) + -- vel = vel * self.visc^(dtime*10) + end + + -- acceleration: + if self.acceleration and ACCELERATION_MIX < 1 then + self.object:set_acceleration(self.acceleration * (1 - ACCELERATION_MIX)) + -- the remaining part is applied after the dtime step + end - vel.y = vel.y * visc self.object:set_velocity(vel) end -function mob_class:check_water_flow() - -- Add water flowing for mobs from mcl_item_entity - local p = self.object:get_pos() - local node = minetest.get_node_or_nil(p) - local def = node and minetest.registered_nodes[node.name] - +-- Add water flowing for mobs from mcl_item_entity +function mob_class:check_water_flow(dtime, pos) + local def = self.standing_in -- 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. ]] - local vec = flowlib.quick_flow(p, node) + local vec = flowlib.quick_flow(pos, minetest.get_node(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 = 1.39 + local f = 8 -- but we have acceleration ehre, not velocity. Was: 1.39 -- Set new item moving speed into the direciton of the liquid - local newv = vector.multiply(vec, f) - --self.object:set_acceleration(vector.zero()) - self.object:add_velocity(vector.new(newv.x, -0.22, newv.z)) - - self.physical_state = true - self._flowing = true - self.object:set_properties({ physical = true }) + self.acceleration = self.acceleration + vector.new(vec.x * f, -0.22, vec.z * f) + --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 + --elseif self._flowing == true then + -- -- Disable flowing physics if not on/in flowing liquid + -- self._flowing = false + -- return end end diff --git a/mods/ENTITIES/mobs_mc/blaze.lua b/mods/ENTITIES/mobs_mc/blaze.lua index f5dd40470..7bf5a95e6 100644 --- a/mods/ENTITIES/mobs_mc/blaze.lua +++ b/mods/ENTITIES/mobs_mc/blaze.lua @@ -83,7 +83,7 @@ mcl_mobs.register_mob("mobs_mc:blaze", { shoot_offset = 1.0, passive = false, jump = true, - jump_height = 4, + jump_height = 1, fly = true, makes_footstep_sound = false, fear_height = 0, diff --git a/mods/ENTITIES/mobs_mc/chicken.lua b/mods/ENTITIES/mobs_mc/chicken.lua index 1adf47569..c049bc22d 100644 --- a/mods/ENTITIES/mobs_mc/chicken.lua +++ b/mods/ENTITIES/mobs_mc/chicken.lua @@ -22,7 +22,7 @@ mcl_mobs.register_mob("mobs_mc:chicken", { floats = 1, head_swivel = "head.control", bone_eye_height = 4, - head_eye_height = 1.5, + head_eye_height = .5, horizontal_head_height = -.3, curiosity = 10, head_yaw="z", diff --git a/mods/ENTITIES/mobs_mc/ender_dragon.lua b/mods/ENTITIES/mobs_mc/ender_dragon.lua index ea23f57a3..272321296 100644 --- a/mods/ENTITIES/mobs_mc/ender_dragon.lua +++ b/mods/ENTITIES/mobs_mc/ender_dragon.lua @@ -77,7 +77,7 @@ mcl_mobs.register_mob("mobs_mc:enderdragon", { damage = 10, knock_back = false, jump = true, - jump_height = 14, + jump_height = 10, fly = true, makes_footstep_sound = false, dogshoot_switch = 1, diff --git a/mods/ENTITIES/mobs_mc/ghast.lua b/mods/ENTITIES/mobs_mc/ghast.lua index 81855d0b6..a1b4277d8 100644 --- a/mods/ENTITIES/mobs_mc/ghast.lua +++ b/mods/ENTITIES/mobs_mc/ghast.lua @@ -59,7 +59,7 @@ mcl_mobs.register_mob("mobs_mc:ghast", { dogshoot_count_max =1, passive = false, jump = true, - jump_height = 4, + jump_height = 1, floats=1, fly = true, makes_footstep_sound = false, diff --git a/mods/ENTITIES/mobs_mc/horse.lua b/mods/ENTITIES/mobs_mc/horse.lua index 4f2708f2d..88fc15875 100644 --- a/mods/ENTITIES/mobs_mc/horse.lua +++ b/mods/ENTITIES/mobs_mc/horse.lua @@ -158,7 +158,7 @@ local horse = { floats = 1, makes_footstep_sound = true, jump = true, - jump_height = 5.75, -- can clear 2.5 blocks + jump_height = 2.5, -- can clear 2.5 blocks drops = { {name = "mcl_mobitems:leather", chance = 1, @@ -560,7 +560,7 @@ donkey.collisionbox = { horse.collisionbox[6] * d, } donkey.jump = true -donkey.jump_height = 3.75 -- can clear 1 block height +donkey.jump_height = 1 -- can clear 1 block height mcl_mobs.register_mob("mobs_mc:donkey", donkey) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 57eb5a859..3e87ce7ea 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -134,7 +134,7 @@ local slime_big = { walk_velocity = 1.9, run_velocity = 1.9, walk_chance = 0, - jump_height = 5.2, + jump_height = 1, fear_height = 0, spawn_small_alternative = "mobs_mc:slime_small", on_die = spawn_children_on_die("mobs_mc:slime_small", 1.0, 1.5), @@ -156,7 +156,6 @@ slime_small.damage = 3 slime_small.reach = 2.25 slime_small.walk_velocity = 1.8 slime_small.run_velocity = 1.8 -slime_small.jump_height = 4.3 slime_small.spawn_small_alternative = "mobs_mc:slime_tiny" slime_small.on_die = spawn_children_on_die("mobs_mc:slime_tiny", 0.6, 1.0) mcl_mobs.register_mob("mobs_mc:slime_small", slime_small) @@ -181,7 +180,6 @@ slime_tiny.drops = { } slime_tiny.walk_velocity = 1.7 slime_tiny.run_velocity = 1.7 -slime_tiny.jump_height = 3 slime_tiny.spawn_small_alternative = nil slime_tiny.on_die = nil @@ -363,7 +361,7 @@ local magma_cube_big = { attack_type = "dogfight", passive = false, jump = true, - jump_height = 8, + jump_height = 4, walk_chance = 0, fear_height = 0, spawn_small_alternative = "mobs_mc:magma_cube_small", @@ -386,7 +384,7 @@ magma_cube_small.damage = 3 magma_cube_small.reach = 2.1 magma_cube_small.walk_velocity = .8 magma_cube_small.run_velocity = 2.0 -magma_cube_small.jump_height = 6 +magma_cube_small.jump_height = 2 magma_cube_small.damage = 4 magma_cube_small.reach = 2.75 magma_cube_small.armor = 66 @@ -407,7 +405,7 @@ magma_cube_tiny.collisionbox = {-0.2505, -0.01, -0.2505, 0.2505, 0.50, 0.2505, r magma_cube_tiny.visual_size = {x=3.125, y=3.125} magma_cube_tiny.walk_velocity = 1.02 magma_cube_tiny.run_velocity = 1.02 -magma_cube_tiny.jump_height = 4 +magma_cube_tiny.jump_height = 1 magma_cube_tiny.damage = 3 magma_cube_tiny.reach = 2 magma_cube_tiny.armor = 50 diff --git a/mods/ENTITIES/mobs_mc/spider.lua b/mods/ENTITIES/mobs_mc/spider.lua index 7fd8909ba..23dfa1df4 100644 --- a/mods/ENTITIES/mobs_mc/spider.lua +++ b/mods/ENTITIES/mobs_mc/spider.lua @@ -86,7 +86,7 @@ local spider = { walk_velocity = 1.3, run_velocity = 2.4, jump = true, - jump_height = 4, + jump_height = 1, view_range = 16, floats = 1, drops = { diff --git a/mods/ENTITIES/mobs_mc/stalker.lua b/mods/ENTITIES/mobs_mc/stalker.lua index a2557af55..18c1472ea 100644 --- a/mods/ENTITIES/mobs_mc/stalker.lua +++ b/mods/ENTITIES/mobs_mc/stalker.lua @@ -2,16 +2,34 @@ local S = minetest.get_translator("mobs_mc") ---################### ---################### STALKER ---################### +-- foliage and grass palettes, loaded from mcl_maps +local palettes = {} + +local function load_json_file(name) + local file = assert(io.open(name, "r")) + local data = minetest.parse_json(file:read("*all")) + file:close() + return data +end +local mapmodpath = minetest.get_modpath("mcl_maps") +if mapmodpath then + for k,v in pairs(load_json_file(mapmodpath .. "/palettes_grass.json")) do + palettes[k] = v + end + for k,v in pairs(load_json_file(mapmodpath .. "/palettes_foliage.json")) do + palettes[k] = v + end + for k,v in pairs(load_json_file(mapmodpath .. "/palettes_water.json")) do + palettes[k] = v + end +end local function get_texture(self, prev) local standing_on = self.standing_on local texture local texture_suff = "" - if standing_on and standing_on.groups.solid then + if standing_on and (standing_on.walkable or standing_on.groups.liquid) then local tiles = standing_on.tiles if tiles then local tile = tiles[1] @@ -27,21 +45,47 @@ local function get_texture(self, prev) if not color then color = minetest.colorspec_to_colorstring(standing_on.color) end + -- handle param2 + if standing_on.palette and self.standing_on_node then + local param2 + if standing_on.paramtype2 == "color" then + param2 = self.standing_on_node.param2 + elseif standing_on.paramtype2 == "colorfacedir" then + param2 = math.floor(self.standing_on_node.param2 / 8) + elseif standing_on.paramtype2 == "colorwallmounted" then + param2 = math.floor(self.standing_on_node.param2 / 32) + elseif standing_on.paramtype2 == "color4dir" then + param2 = math.floor(self.standing_on_node.param2 / 64) + elseif standing_on.paramtype2 == "colordegrotate" then + param2 = math.floor(self.standing_on_node.param2 / 8) + end + local palette = palettes[standing_on.palette] + local oldcol = color + if param2 and palette then + local c = palette[param2 + 1] + if c then color = minetest.rgba(c[1], c[2], c[3], c[4]) end + end + end if color then - texture_suff = "^[multiply:" .. color .. "^[hsl:0:0:20" + texture_suff = "^[multiply:" .. color .. "^[contrast:20:10" --"^[hsl:0:0:20" end end end if not texture or texture == "" then - if prev then return prev end + -- try to keep last texture when, e.g., falling + if prev and (not (not self.attack)) == (string.find(prev, "vl_mobs_starker_overlay_angry.png") ~= nil) then + return prev + end texture = "vl_stalker_default.png" - end - texture = texture:gsub("([\\^:\\[])","\\%1") -- escape texture modifiers - texture = "([combine:16x24:0,0=(" .. texture .. "):0,16=(" .. texture ..")".. texture_suff - if self.attack then - texture = texture .. ")^vl_mobs_stalker_overlay_angry.png" + if texture_suff then texture = texture .. texture_suff end else - texture = texture .. ")^vl_mobs_stalker_overlay.png" + texture = texture:gsub("([\\^:\\[])", "\\%1") -- escape texture modifiers + texture = "(vl_stalker_default.png^[combine:16x24:0,0=(" .. texture .. "):0,16=(" .. texture .. ")" .. texture_suff .. ")" + end + if self.attack then + texture = texture .. "^vl_mobs_stalker_overlay_angry.png" + else + texture = texture .. "^vl_mobs_stalker_overlay.png" end return texture end diff --git a/mods/ENTITIES/mobs_mc/wither.lua b/mods/ENTITIES/mobs_mc/wither.lua index 252873629..0915a2605 100644 --- a/mods/ENTITIES/mobs_mc/wither.lua +++ b/mods/ENTITIES/mobs_mc/wither.lua @@ -13,14 +13,6 @@ local anti_troll = minetest.settings:get_bool("wither_anti_troll_measures", fals local WITHER_INIT_BOOM = 7 local WITHER_MELEE_COOLDOWN = 3 -local function atan(x) - if not x or x ~= x then - return 0 - else - return math.atan(x) - end -end - --################### --################### WITHER --################### @@ -96,7 +88,7 @@ mcl_mobs.register_mob("mobs_mc:wither", { distance = 60, }, jump = true, - jump_height = 10, + jump_height = 5, fly = true, makes_footstep_sound = false, dogshoot_switch = 1, -- unused @@ -260,7 +252,7 @@ mcl_mobs.register_mob("mobs_mc:wither", { z = p.z - s.z } - local yaw = (atan(vec.z / vec.x) +math.pi/ 2) - self.rotate + local yaw = (atan2(vec.z, vec.x) +math.pi/ 2) - self.rotate if p.x > s.x then yaw = yaw +math.pi end yaw = self:set_yaw( yaw, 0, dtime) diff --git a/mods/ENTITIES/mobs_mc/zombie.lua b/mods/ENTITIES/mobs_mc/zombie.lua index 83eae82ad..5df87c9a6 100644 --- a/mods/ENTITIES/mobs_mc/zombie.lua +++ b/mods/ENTITIES/mobs_mc/zombie.lua @@ -85,7 +85,7 @@ local zombie = { fear_height = 4, pathfinding = 1, jump = true, - jump_height = 4, + jump_height = 1, group_attack = { "mobs_mc:zombie", "mobs_mc:baby_zombie", "mobs_mc:husk", "mobs_mc:baby_husk" }, drops = drops_zombie, animation = {