diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 9a6e1a68b..679436def 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -10,8 +10,6 @@ local PATHFINDING = "gowp" -- Localize local S = minetest.get_translator("mcl_mobs") -local mob_active_range = tonumber(minetest.settings:get("mcl_mob_active_range")) or 48 - local LOGGING_ON = minetest.settings:get_bool("mcl_logging_mobs_villager",false) local function mcl_log (message) if LOGGING_ON then @@ -34,12 +32,10 @@ local function atan(x) end end --- Load settings +local remove_far = true local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false local spawn_protected = minetest.settings:get_bool("mobs_spawn_protected") ~= false -local remove_far = true --- Shows helpful debug info above each mob -local mobs_debug = minetest.settings:get_bool("mobs_debug", false) +local mobs_debug = minetest.settings:get_bool("mobs_debug", false) -- Shows helpful debug info above each mob local spawn_logging = minetest.settings:get_bool("mcl_logging_mobs_spawn",true) -- Peaceful mode message so players will know there are no monsters @@ -50,59 +46,6 @@ if minetest.settings:get_bool("only_peaceful_mobs", false) then end) end -minetest.register_chatcommand("clearmobs",{ - privs={maphack=true}, - params = "||", - description=S("Removes all spawned mobs except nametagged and tamed ones. all removes all mobs, nametagged only nametagged ones and with the range paramter all mobs in a distance of the current player are removed."), - func=function(n,param) - local p = minetest.get_player_by_name(n) - local num=tonumber(param) - for _,o in pairs(minetest.luaentities) do - if o.is_mob then - if param == "all" or - ( param == "nametagged" and o.nametag ) or - ( param == "" and ( not o.nametag or o.nametag == "" ) and not o.tamed ) or - ( num and num > 0 and vector.distance(p:get_pos(),o.object:get_pos()) <= num ) then - o.object:remove() - end - end - end -end}) - - -function mob_class:player_in_active_range() - for _,p in pairs(minetest.get_connected_players()) do - if vector.distance(self.object:get_pos(),p:get_pos()) <= mob_active_range then return true end - -- slightly larger than the mc 32 since mobs spawn on that circle and easily stand still immediately right after spawning. - end -end - --- Return true if object is in view_range -function mob_class:object_in_range(object) - if not object then - return false - end - local factor - -- Apply view range reduction for special player armor - if object:is_player() then - local factors = mcl_armor.player_view_range_factors[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 - end - - local p1, p2 = self.object:get_pos(), object:get_pos() - return p1 and p2 and (vector.distance(p1, p2) <= dist) -end - --- get node but use fallback for nil or unknown local node_ok = function(pos, fallback) fallback = fallback or mcl_mobs.fallback_node local node = minetest.get_node_or_nil(pos) @@ -112,7 +55,6 @@ local node_ok = function(pos, fallback) return minetest.registered_nodes[fallback] end --- get entity staticdata function mob_class:get_staticdata() for _,p in pairs(minetest.get_connected_players()) do @@ -153,15 +95,12 @@ function mob_class:get_staticdata() return minetest.serialize(tmp) end - --- activate mob and reload settings function mob_class:mob_activate(staticdata, def, dtime) if not self.object:get_pos() or staticdata == "remove" then mcl_burning.extinguish(self.object) self.object:remove() return end - -- remove monsters in peaceful mode if self.type == "monster" and minetest.settings:get_bool("only_peaceful_mobs", false) then mcl_burning.extinguish(self.object) @@ -169,7 +108,6 @@ function mob_class:mob_activate(staticdata, def, dtime) return end - -- load entity variables local tmp = minetest.deserialize(staticdata) if tmp then @@ -178,7 +116,6 @@ function mob_class:mob_activate(staticdata, def, dtime) end end - -- select random texture, set model and size if not self.base_texture then -- compatiblity with old simple mobs textures @@ -196,31 +133,26 @@ function mob_class:mob_activate(staticdata, def, dtime) self.base_selbox = self.selectionbox end - -- for current mobs that dont have this set if not self.base_selbox then self.base_selbox = self.selectionbox or self.base_colbox end - -- set texture, model and size 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 - -- specific texture if gotten if self.gotten == true and def.gotten_texture then textures = def.gotten_texture end - -- specific mesh if gotten if self.gotten == true and def.gotten_mesh then mesh = def.gotten_mesh end - -- set child objects to half size if self.child == true then vis_size = { @@ -257,7 +189,6 @@ function mob_class:mob_activate(staticdata, def, dtime) self.breath = self.breath_max end - -- pathfinding init self.path = {} self.path.way = {} -- path to follow, table of positions self.path.lastpos = {x = 0, y = 0, z = 0} @@ -297,12 +228,10 @@ function mob_class:mob_activate(staticdata, def, dtime) self.blinktimer = 0 self.blinkstatus = false - -- check existing nametag if not self.nametag then self.nametag = def.nametag end if not self.custom_visual_size then - -- Remove saved visual_size on old existing entites. self.visual_size = nil self.base_size = self.visual_size if self.child then @@ -313,17 +242,15 @@ function mob_class:mob_activate(staticdata, def, dtime) end end - -- set anything changed above self.object:set_properties(self) self:set_yaw( (math.random(0, 360) - 180) / 180 * math.pi, 6) self:update_tag() self._current_animation = nil self:set_animation( "stand") - -- run on_spawn function if found if self.on_spawn and not self.on_spawn_run then if self.on_spawn(self) then - self.on_spawn_run = true -- if true, set flag to run once only + self.on_spawn_run = true end end @@ -337,8 +264,6 @@ function mob_class:mob_activate(staticdata, def, dtime) self._run_armor_init = true end - - -- run after_activate if def.after_activate then def.after_activate(self, staticdata, def, dtime) end @@ -350,54 +275,29 @@ function mob_class:on_step(dtime) local pos = self.object:get_pos() if self:check_despawn(pos) then return true end - local v = self.object:get_velocity() local d = 0.85 + if self:check_dying() then d = 0.92 end - if (self.state and self.state=="die" or self:check_for_death()) and not self.animation.die_end then - d = 0.92 - local rot = self.object:get_rotation() - rot.z = ((math.pi/2-rot.z)*.2)+rot.z - self.object:set_rotation(rot) - end - - if not self:player_in_active_range() then - self:set_animation( "stand", true) - local node_under = node_ok(vector.offset(pos,0,-1,0)).name - local acc = self.object:get_acceleration() - 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)) - end - if acc.y == 0 and node_under == "air" then - self:falling(pos) - end - return - end - + local v = self.object:get_velocity() if v then --diffuse object velocity self.object:set_velocity({x = v.x*d, y = v.y, z = v.z*d}) end - self:check_aggro(dtime) - self:check_item_pickup() + if self:falling(pos) then return end + + self:check_suspend() + self:check_aggro(dtime) - self:check_particlespawners(dtime) if not self.fire_resistant then mcl_burning.tick(self.object, dtime, self) -- mcl_burning.tick may remove object immediately if not self.object:get_pos() then return end end - local yaw = 0 + if mobs_debug then self:update_tag() end - if mobs_debug then - self:update_tag() - end - - if self.state == "die" then - return - end + if self.state == "die" then return end if self.jump_sound_cooloff > 0 then self.jump_sound_cooloff = self.jump_sound_cooloff - dtime @@ -405,10 +305,6 @@ function mob_class:on_step(dtime) if self.opinion_sound_cooloff > 0 then self.opinion_sound_cooloff = self.opinion_sound_cooloff - dtime end - if self:falling(pos) then - -- Return if mob died after falling - return - end --Mob following code. self:follow_flop() @@ -441,9 +337,10 @@ function mob_class:on_step(dtime) if self.timer < 1 then return end - self.timer = 0 end + self:check_particlespawners(dtime) + self:check_item_pickup() -- never go over 100 if self.timer > 100 then @@ -485,11 +382,10 @@ function mob_class:on_step(dtime) end self:do_jump() - self:set_armor_texture() - self:check_runaway_from() + local yaw = 0 if self:is_at_water_danger() and self.state ~= "attack" then if math.random(1, 10) <= 6 then self:set_velocity(0) @@ -530,3 +426,22 @@ minetest.register_globalstep(function(dtime) end timer = 0 end) + +minetest.register_chatcommand("clearmobs",{ + privs={maphack=true}, + params = "||", + description=S("Removes all spawned mobs except nametagged and tamed ones. all removes all mobs, nametagged only nametagged ones and with the range paramter all mobs in a distance of the current player are removed."), + func=function(n,param) + local p = minetest.get_player_by_name(n) + local num=tonumber(param) + for _,o in pairs(minetest.luaentities) do + if o.is_mob then + if param == "all" or + ( param == "nametagged" and o.nametag ) or + ( param == "" and ( not o.nametag or o.nametag == "" ) and not o.tamed ) or + ( num and num > 0 and vector.distance(p:get_pos(),o.object:get_pos()) <= num ) then + o.object:remove() + end + end + end +end}) diff --git a/mods/ENTITIES/mcl_mobs/breeding.lua b/mods/ENTITIES/mcl_mobs/breeding.lua index 223e94c35..9284163cd 100644 --- a/mods/ENTITIES/mcl_mobs/breeding.lua +++ b/mods/ENTITIES/mcl_mobs/breeding.lua @@ -34,7 +34,7 @@ function mob_class:feed_tame(clicker, feed_count, breed, tame, notake) return false end -- can eat/tame with item in hand - if self.nofollow or follow_holding(self, clicker) then + if self.nofollow or self:follow_holding(clicker) then local consume_food = false -- tame if not still a baby @@ -310,3 +310,43 @@ function mob_class:check_breeding() end end 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 + local pos = self.object:get_pos() + local particle + if not self.order or self.order == "" or self.order == "sit" then + particle = "mobs_mc_wolf_icon_roam.png" + self.order = "roam" + self.state = "stand" + self.walk_chance = default_walk_chance + self.jump = true + self:set_animation("stand") + -- TODO: Add sitting model + else + particle = "mobs_mc_wolf_icon_sit.png" + self.order = "sit" + self.state = "stand" + self.walk_chance = 0 + self.jump = false + if self.animation.sit_start then + self:set_animation("sit") + else + self:set_animation("stand") + end + end + local pp = vector.new(0,1.4,0) + if p then pp = vector.offset(pp,0,p,0) end + -- 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}, + expirationtime = 1, + size = 4, + texture = particle, + playername = self.owner, + glow = minetest.LIGHT_MAX, + }) +end diff --git a/mods/ENTITIES/mcl_mobs/init.lua b/mods/ENTITIES/mcl_mobs/init.lua index 81ba5521d..5b8ef275b 100644 --- a/mods/ENTITIES/mcl_mobs/init.lua +++ b/mods/ENTITIES/mcl_mobs/init.lua @@ -33,6 +33,7 @@ local DEFAULT_FALL_SPEED = -9.81*1.5 local MAX_MOB_NAME_LENGTH = 30 local old_spawn_icons = minetest.settings:get_bool("mcl_old_spawn_icons",false) +local extended_pet_control = minetest.settings:get_bool("mcl_extended_pet_control",true) local difficulty = tonumber(minetest.settings:get("mob_difficulty")) or 1.0 -- get node but use fallback for nil or unknown @@ -49,8 +50,11 @@ end -- Code to execute before custom on_rightclick handling local on_rightclick_prefix = function(self, clicker) + if not clicker:is_player() then return end local item = clicker:get_wielded_item() - + if extended_pet_control and self.tamed and self.owner == clicker:get_player_name() then + self:toggle_sit(clicker) + end -- Name mob with nametag if not self.ignores_nametag and item:get_name() == "mcl_mobs:nametag" then @@ -71,9 +75,19 @@ local on_rightclick_prefix = function(self, clicker) end end + return false end +local create_mob_on_rightclick = function(on_rightclick) + return function(self, clicker) + local stop = on_rightclick_prefix(self, clicker) + if (not stop) and (on_rightclick) then + on_rightclick(self, clicker) + end + end +end + -- check if within physical map limits (-30911 to 30927) local function within_limits(pos, radius) local wmin, wmax = -30912, 30928 @@ -92,15 +106,6 @@ local function within_limits(pos, radius) return true end - -local create_mob_on_rightclick = function(on_rightclick) - return function(self, clicker) - local stop = on_rightclick_prefix(self, clicker) - if (not stop) and (on_rightclick) then - on_rightclick(self, clicker) - end - end -end mcl_mobs.spawning_mobs = {} -- register mob entity function mcl_mobs.register_mob(name, def) @@ -148,7 +153,7 @@ minetest.register_entity(name, setmetatable({ description = def.description, type = def.type, attack_type = def.attack_type, - fly = def.fly, + fly = def.fly or false, fly_in = def.fly_in or {"air", "__airlike"}, owner = def.owner or "", order = def.order or "", diff --git a/mods/ENTITIES/mcl_mobs/mount.lua b/mods/ENTITIES/mcl_mobs/mount.lua index 0307a5fc0..21c52157a 100644 --- a/mods/ENTITIES/mcl_mobs/mount.lua +++ b/mods/ENTITIES/mcl_mobs/mount.lua @@ -386,7 +386,6 @@ function mcl_mobs.drive(entity, moving_anim, stand_anim, can_fly, dtime) entity.v2 = v end - -- directional flying routine by D00Med (edited by TenPlus1) function mcl_mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_anim) @@ -448,6 +447,10 @@ function mcl_mobs.fly(entity, dtime, speed, shoots, arrow, moving_anim, stand_an end end +mcl_mobs.mob_class.drive = mcl_mobs.drive +mcl_mobs.mob_class.fly = mcl_mobs.fly +mcl_mobs.mob_class.attach = mcl_mobs.attach + function mob_class:on_detach_child(child) if self.detach_child then if self.detach_child(self, child) then diff --git a/mods/ENTITIES/mcl_mobs/physics.lua b/mods/ENTITIES/mcl_mobs/physics.lua index ee0d6d986..46bdd878b 100644 --- a/mods/ENTITIES/mcl_mobs/physics.lua +++ b/mods/ENTITIES/mcl_mobs/physics.lua @@ -10,7 +10,7 @@ local FLOP_HOR_SPEED = 1.5 local PATHFINDING = "gowp" local mobs_debug = minetest.settings:get_bool("mobs_debug", false) 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 -- get node but use fallback for nil or unknown local node_ok = function(pos, fallback) @@ -44,15 +44,44 @@ local function within_limits(pos, radius) return true end --- drop items +function mob_class:player_in_active_range() + for _,p in pairs(minetest.get_connected_players()) do + if vector.distance(self.object:get_pos(),p:get_pos()) <= mob_active_range then return true end + -- slightly larger than the mc 32 since mobs spawn on that circle and easily stand still immediately right after spawning. + end +end + +-- Return true if object is in view_range +function mob_class:object_in_range(object) + if not object then + return false + end + local factor + -- Apply view range reduction for special player armor + if object:is_player() then + local factors = mcl_armor.player_view_range_factors[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 + 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) - -- no drops if disabled by setting if not mobs_drop_items then return end looting_level = looting_level or 0 - -- no drops for child mobs (except monster) if (self.child and self.type ~= "monster") then return end @@ -60,7 +89,7 @@ function mob_class:item_drop(cooked, looting_level) local obj, item, num local pos = self.object:get_pos() - self.drops = self.drops or {} -- nil check + self.drops = self.drops or {} for n = 1, #self.drops do local dropdef = self.drops[n] @@ -91,7 +120,6 @@ function mob_class:item_drop(cooked, looting_level) if num > 0 then item = dropdef.name - -- cook items when true if cooked then local output = minetest.get_craft_result({ @@ -102,7 +130,6 @@ function mob_class:item_drop(cooked, looting_level) end end - -- add item if it exists for x = 1, num do obj = minetest.add_item(pos, ItemStack(item .. " " .. 1)) end @@ -155,8 +182,7 @@ function mob_class:collision() end -- move mob in facing direction -function mob_class:set_velocity( v) - +function mob_class:set_velocity(v) local c_x, c_y = 0, 0 -- can mob be pushed, if so calculate direction @@ -183,7 +209,6 @@ end -- calculate mob velocity function mob_class:get_velocity() - local v = self.object:get_velocity() if v then return (v.x * v.x + v.z * v.z) ^ 0.5 @@ -245,8 +270,6 @@ function mob_class:update_tag() self.object:set_properties({ nametag = tag, }) - - self:update_roll() end local function shortest_term_of_yaw_rotation(self, rot_origin, rot_target, nums) @@ -949,3 +972,29 @@ function mob_class:check_water_flow() return end end + +function mob_class:check_dying() + if ((self.state and self.state=="die") or self:check_for_death()) and not self.animation.die_end then + local rot = self.object:get_rotation() + rot.z = ((math.pi/2-rot.z)*.2)+rot.z + self.object:set_rotation(rot) + return true + end +end + +function mob_class:check_suspend() + if not self:player_in_active_range() then + local pos = self.object:get_pos() + local node_under = node_ok(vector.offset(pos,0,-1,0)).name + local acc = self.object:get_acceleration() + self:set_animation( "stand", true) + 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)) + end + if acc.y == 0 and node_under == "air" then + self:falling(pos) + end + return true + end +end diff --git a/mods/ENTITIES/mobs_mc/wolf.lua b/mods/ENTITIES/mobs_mc/wolf.lua index bc8f126dd..922069508 100644 --- a/mods/ENTITIES/mobs_mc/wolf.lua +++ b/mods/ENTITIES/mobs_mc/wolf.lua @@ -194,41 +194,13 @@ dog.on_rightclick = function(self, clicker) end end else - -- Toggle sitting order - if not self.owner or self.owner == "" then - -- Huh? This wolf has no owner? Let's fix this! This should never happen. + -- Huh? This dog has no owner? Let's fix this! This should never happen. self.owner = clicker:get_player_name() end - - local pos = self.object:get_pos() - local particle - if not self.order or self.order == "" or self.order == "sit" then - particle = "mobs_mc_wolf_icon_roam.png" - self.order = "roam" - self.state = "stand" - self.walk_chance = default_walk_chance - self.jump = true - self:set_animation("stand") - -- TODO: Add sitting model - else - particle = "mobs_mc_wolf_icon_sit.png" - self.order = "sit" - self.state = "stand" - self.walk_chance = 0 - self.jump = false - self:set_animation("sit") + if not minetest.settings:get_bool("mcl_extended_pet_control",true) then + self:toggle_sit(clicker,-0.4) end - -- Display icon to show current order (sit or roam) - minetest.add_particle({ - pos = vector.add(pos, {x=0,y=1,z=0}), - velocity = {x=0,y=0.2,z=0}, - expirationtime = 1, - size = 4, - texture = particle, - playername = self.owner, - glow = minetest.LIGHT_MAX, - }) end end diff --git a/settingtypes.txt b/settingtypes.txt index 78aa9d44b..0d517499a 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -222,6 +222,9 @@ mcl_bookshelf_inventories (Enable bookshelf inventories) bool true # Enable swiftness on enchanted golden apples mcl_enable_fapples (Enable swiftness on enchanted golden apples) bool true +# All tameable mobs listen to the "sit" righclick like dogs +mcl_extended_pet_control (Extended pet control) bool true + [Debugging] # If enabled, this will show the itemstring of an item in the description. mcl_item_id_debug (Item ID Debug) bool false